import { useEffect, useMemo, useRef, useState, type DragEvent, type MutableRefObject } from "react"; import { ArrowDown, ArrowUp, DownloadSimple, Eye, EyeSlash, FolderPlus, Lock, LockOpen, Plus, SlidersHorizontal, Stack, Trash, TextT } from "@phosphor-icons/react"; import { commandIds } from "@commands/ids"; import type { ImageDocument } from "@core/document"; import type { Layer } from "@core/layer"; import type { ColorAdjustment } from "@core/adjustment-layer"; import type { TextLayer, TextStyle } from "@core/text-layer"; import { builtInTextFonts } from "@core/text-layer"; import { getLayerMask } from "@core/layer-mask-utils"; import type { ArtboardId } from "@core/id"; import { createDocumentReadIndex, type DocumentReadIndex } from "@editor/document-indexes"; import type { MaskEditState, SelectionState } from "@editor/state"; import type { AppStore } from "@editor/store"; import { resolveLayerDrop } from "@input/index"; import type { DocumentActions } from "@app/document-actions"; import { addAdjustmentLayer, addArtboard, addEmptyLayer, addGroupLayer, addLayerMask, addTextLayer, deleteSelection, groupLayers, moveLayer } from "@operations/document/layerActions"; import { MaskOperationButtons, MaskStatus } from "./layers/MaskControls"; import { LayerThumbnail } from "./layers/LayerThumbnail"; import { createLayerThumbnailIndex, type LayerThumbnailModel } from "./layers/thumbnailModel"; export type LayersSheetProps = { document: ImageDocument; selection: SelectionState; maskEdit?: MaskEditState; open: boolean; dispatch: AppStore["dispatch"]; documentActions: DocumentActions; }; export function LayersSheet({ document, selection, maskEdit, open, dispatch, documentActions }: LayersSheetProps) { const draggedLayerId = useRef(undefined); const [editingTitle, setEditingTitle] = useState(); return ( ); } function LayersSheetBody({ document, selection, maskEdit, draggedLayerId, editingTitle, setEditingTitle, dispatch, documentActions, }: Omit & { draggedLayerId: MutableRefObject; editingTitle: EditingTitle | undefined; setEditingTitle: (editingTitle: EditingTitle | undefined) => void; }) { const documentIndex = useMemo(() => createDocumentReadIndex(document), [document]); const selectedArtboardId = selection.artboardId ?? document.artboards[0]?.id; const selectedLayerId = selection.layerIds[0]; const selectedLayer = selectedLayerId ? documentIndex.layerInfoById.get(selectedLayerId) : undefined; const canGroup = Boolean(selection.artboardId && selection.layerIds.length > 0); const canUngroup = selectedLayer?.layer.type === "group"; const maskLayerIds = documentIndex.maskLayerIds; const thumbnailByLayerId = useMemo(() => createLayerThumbnailIndex(document, documentIndex.assetById, maskLayerIds), [document, documentIndex, maskLayerIds]); return ( <>
{selectedLayer?.layer.type === "adjustment" ? : null} {selectedLayer?.layer.type === "text" ? : null}
{document.artboards.map((artboard) => { const displayLayerCount = documentIndex.displayLayerCountByArtboardId.get(artboard.id) ?? 0; return (
{ if (draggedLayerId.current) event.preventDefault(); }} onDrop={(event) => { event.preventDefault(); if (draggedLayerId.current) dispatch(commandIds.documentMoveLayer, { layerId: draggedLayerId.current, toArtboardId: artboard.id, toIndex: artboard.layers.length }); draggedLayerId.current = undefined; }} > {editingTitle?.type === "artboard" && editingTitle.id === artboard.id ? ( setEditingTitle({ ...editingTitle, draft })} onCancel={() => setEditingTitle(undefined)} onCommit={() => { dispatch(commandIds.documentRenameArtboard, { id: artboard.id, name: editingTitle.draft }); setEditingTitle(undefined); }} /> ) : ( )} {displayLayerCount}
{displayLayerCount === 0 ? (
No layers yet
) : ( artboard.layers.map((layer) => ( )) )}
); })}
); } function TextInspector({ layer, dispatch }: { layer: TextLayer; dispatch: AppStore["dispatch"] }) { const [content, setContent] = useState(layer.content); const [style, setStyle] = useState({ ...layer.style }); useEffect(() => { setContent(layer.content); setStyle({ ...layer.style }); }, [layer.id, layer.content, layer.style]); const commit = () => dispatch(commandIds.documentSetTextLayer, { layerId: layer.id, content, style }); return