@pixerate/editor-react 0.68.0 → 0.68.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -841,7 +841,7 @@ var PaintLayersPanel = ({ controller, className }) => {
|
|
|
841
841
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "w-14 text-slate-400", children: "Blend" }),
|
|
842
842
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("select", { "aria-label": "Layer blend", value: active.blend, onChange: (e) => attempt(() => controller.updateLayer(active.id, { blend: e.target.value })), className: "flex-1 rounded bg-slate-800 px-1 py-0.5", children: [
|
|
843
843
|
active.type === "group" && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "pass-through", children: "Pass through" }),
|
|
844
|
-
import_paint_editor7.
|
|
844
|
+
import_paint_editor7.BLEND_MENU_GROUPS.map((g) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("optgroup", { label: g.label, children: g.modes.map((m) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: m.id, title: m.description, children: m.label }, m.id)) }, g.label))
|
|
845
845
|
] })
|
|
846
846
|
] }),
|
|
847
847
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex gap-1", children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/paint-editor/index.ts","../../src/paint-editor/usePaintEditor.ts","../../src/paint-editor/PaintCanvas.tsx","../../src/paint-editor/PaintToolbar.tsx","../../src/paint-editor/shared.tsx","../../src/paint-editor/BrushPanel.tsx","../../src/paint-editor/PaperPanel.tsx","../../src/paint-editor/ColorPanel.tsx","../../src/paint-editor/PaintLayersPanel.tsx","../../src/paint-editor/PaintEditor.tsx"],"sourcesContent":["export * from './usePaintEditor';\nexport * from './PaintCanvas';\nexport * from './PaintToolbar';\nexport * from './BrushPanel';\nexport * from './PaperPanel';\nexport * from './ColorPanel';\nexport * from './PaintLayersPanel';\nexport * from './PaintEditor';\nexport { PaintSlider } from './shared';\n","import { useMemo, useState, useSyncExternalStore } from 'react';\nimport { PaintEditorController, type PaintEditorOptions, type PaintEditorState } from '@pixerate/editor/paint-editor';\n\nexport interface UsePaintEditorReturn {\n controller: PaintEditorController;\n /** The controller's snapshot (a new object after every change). */\n state: PaintEditorState;\n}\n\n/**\n * Creates a `PaintEditorController` once (from `options`, read on the first render) or uses the\n * one given, and re-renders on every change.\n */\nexport function usePaintEditor(options: PaintEditorOptions | PaintEditorController = {}): UsePaintEditorReturn {\n const [controller] = useState(() => (options instanceof PaintEditorController ? options : new PaintEditorController(options)));\n const state = usePaintEditorState(controller);\n return useMemo(() => ({ controller, state }), [controller, state]);\n}\n\n/** Subscribes to a controller's state. */\nexport function usePaintEditorState(controller: PaintEditorController): PaintEditorState {\n return useSyncExternalStore(\n (notify) => controller.subscribe(notify),\n () => controller.getState(),\n () => controller.getState()\n );\n}\n","import React, { useEffect, useMemo, useRef, useState } from 'react';\nimport {\n PaintCanvasPresenter,\n PaintGesture,\n fitZoom,\n guideOverlay,\n handlePaintShortcut,\n viewCssTransform,\n type PaintEditorController,\n type PaintTool,\n} from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\n\nexport interface PaintCanvasProps {\n controller: PaintEditorController;\n /** The active tool (default brush). */\n tool?: PaintTool;\n /** Draw the symmetry axes and perspective lines (default true). */\n showGuides?: boolean;\n /** Fit the canvas in the viewport on mount (default true). */\n fitOnMount?: boolean;\n /** Called with a refusal (hidden or locked layer). */\n onError?: (message: string | null) => void;\n className?: string;\n}\n\n/**\n * The painting surface: a document-sized canvas the compositor draws into (only changed tiles are\n * uploaded), shown through the view's zoom, pan, rotation and mirroring as a CSS transform (the\n * pixels never resample). Pointer input goes through `PaintGesture`: coalesced samples, a predicted\n * tail drawn as a thin preview, palm rejection, middle-button pan, wheel zoom and Shift+wheel\n * rotation. Guides and floating reference images are drawn on top.\n */\nexport const PaintCanvas: React.FC<PaintCanvasProps> = ({ controller, tool = 'brush', showGuides = true, fitOnMount = true, onError, className }) => {\n const state = usePaintEditorState(controller);\n const viewport = useRef<HTMLDivElement>(null);\n const canvas = useRef<HTMLCanvasElement>(null);\n const [size, setSize] = useState({ width: 800, height: 600 });\n const measured = useRef(false);\n const [predicted, setPredicted] = useState<Array<{ x: number; y: number }>>([]);\n const presenter = useMemo(() => new PaintCanvasPresenter(controller), [controller]);\n const gesture = useMemo(\n () =>\n new PaintGesture(controller, () => {\n const r = viewport.current?.getBoundingClientRect();\n return { left: r?.left ?? 0, top: r?.top ?? 0, width: r?.width || size.width, height: r?.height || size.height };\n }),\n // The box reads the element when called; `size` is only the jsdom fallback.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [controller]\n );\n gesture.tool = tool;\n const { canvas: doc } = state.document;\n\n useEffect(() => {\n const el = viewport.current;\n if (!el || typeof ResizeObserver === 'undefined') return;\n const ro = new ResizeObserver(() => {\n if (!el.clientWidth || !el.clientHeight) return;\n measured.current = true;\n setSize({ width: el.clientWidth, height: el.clientHeight });\n });\n ro.observe(el);\n return () => ro.disconnect();\n }, []);\n\n // Fit once per canvas size, after the viewport has been measured (or at once where it cannot be).\n const fitted = useRef<string | null>(null);\n useEffect(() => {\n const key = `${doc.width}x${doc.height}`;\n if (!fitOnMount || fitted.current === key) return;\n if (typeof ResizeObserver !== 'undefined' && !measured.current) return;\n fitted.current = key;\n controller.setView({ zoom: fitZoom(doc, size), pan: { x: 0, y: 0 } });\n }, [controller, doc, size, fitOnMount]);\n\n // Upload changed tiles whenever the state changes.\n useEffect(() => {\n const ctx = canvas.current?.getContext('2d');\n if (ctx && typeof ctx.createImageData === 'function') presenter.render(ctx as never);\n else controller.takeDirty();\n }, [state, presenter, controller]);\n\n // Wheel needs a non-passive listener to prevent page scroll (see GOTCHAS).\n useEffect(() => {\n const el = viewport.current;\n if (!el) return;\n const onWheel = (e: WheelEvent) => {\n e.preventDefault();\n gesture.wheel(e);\n };\n el.addEventListener('wheel', onWheel, { passive: false });\n return () => el.removeEventListener('wheel', onWheel);\n }, [gesture]);\n\n const report = () => onError?.(gesture.error);\n const transform = viewCssTransform(state.view, doc, size);\n const lines = showGuides ? guideOverlay(controller) : [];\n\n return (\n <div\n ref={viewport}\n tabIndex={0}\n role=\"application\"\n aria-label=\"Paint canvas\"\n data-testid=\"paint-canvas\"\n className={`relative overflow-hidden bg-slate-950 outline-none touch-none select-none ${className ?? ''}`}\n style={{ cursor: tool === 'pan' ? 'grab' : tool === 'eyedropper' ? 'copy' : 'crosshair' }}\n onPointerDown={(e) => {\n viewport.current?.focus();\n if (gesture.down(e.nativeEvent)) (e.target as Element).setPointerCapture?.(e.pointerId);\n report();\n }}\n onPointerMove={(e) => {\n gesture.move(e.nativeEvent);\n if (gesture.predicted.length || predicted.length) setPredicted(gesture.predicted.map((p) => ({ x: p.x, y: p.y })));\n }}\n onPointerUp={(e) => {\n gesture.up(e.nativeEvent);\n setPredicted([]);\n }}\n onPointerCancel={() => {\n gesture.cancel();\n setPredicted([]);\n }}\n onKeyDown={(e) => {\n if (handlePaintShortcut(controller, gesture, e)) e.preventDefault();\n }}\n >\n <canvas\n ref={canvas}\n width={doc.width}\n height={doc.height}\n className=\"absolute left-0 top-0 shadow-2xl\"\n style={{ transform, transformOrigin: '0 0', imageRendering: state.view.zoom > 2 ? 'pixelated' : 'auto' }}\n />\n <svg className=\"absolute left-0 top-0 pointer-events-none overflow-visible\" width={doc.width} height={doc.height} style={{ transform, transformOrigin: '0 0' }} aria-hidden=\"true\">\n {lines.map((l, i) => (\n <line\n key={i}\n x1={l.from.x}\n y1={l.from.y}\n x2={l.to.x}\n y2={l.to.y}\n stroke={l.kind === 'symmetry' ? '#22d3ee' : '#f472b6'}\n strokeOpacity={l.kind === 'symmetry' ? 0.8 : 0.35}\n strokeWidth={1 / state.view.zoom}\n strokeDasharray={l.kind === 'symmetry' ? `${6 / state.view.zoom} ${4 / state.view.zoom}` : undefined}\n />\n ))}\n {predicted.length > 0 && (\n <polyline points={predicted.map((p) => `${p.x},${p.y}`).join(' ')} fill=\"none\" stroke={state.color} strokeOpacity={0.5} strokeWidth={Math.max(1, state.brush.tip.size / 2)} strokeLinecap=\"round\" />\n )}\n </svg>\n {state.guides.references\n .filter((r) => r.visible)\n .map((r) => (\n <ReferencePanel key={r.id} controller={controller} id={r.id} />\n ))}\n <div className=\"absolute bottom-1 right-2 text-[10px] text-slate-500 pointer-events-none\" data-testid=\"paint-view-status\">\n {Math.round(state.view.zoom * 100)}% · {Math.round(state.view.rotation)}°{state.view.mirror ? ' · mirrored' : ''}\n </div>\n </div>\n );\n};\n\n/** A floating reference image: drag its title bar to move it, click the image to pick a colour. */\nconst ReferencePanel: React.FC<{ controller: PaintEditorController; id: string }> = ({ controller, id }) => {\n const state = usePaintEditorState(controller);\n const ref = state.guides.references.find((r) => r.id === id);\n const drag = useRef<{ x: number; y: number; ox: number; oy: number } | null>(null);\n if (!ref) return null;\n const h = (ref.height / ref.width) * ref.displayWidth;\n return (\n <div\n className=\"absolute rounded border border-slate-700 bg-slate-900/95 shadow-xl\"\n style={{ left: ref.x, top: ref.y, width: ref.displayWidth }}\n data-testid=\"paint-reference\"\n onPointerDown={(e) => e.stopPropagation()}\n >\n <div\n className=\"flex items-center justify-between px-1.5 py-0.5 text-[10px] text-slate-300 cursor-move\"\n onPointerDown={(e) => {\n drag.current = { x: e.clientX, y: e.clientY, ox: ref.x, oy: ref.y };\n (e.target as Element).setPointerCapture?.(e.pointerId);\n }}\n onPointerMove={(e) => {\n const d = drag.current;\n if (d) controller.updateReferenceImage(id, { x: d.ox + e.clientX - d.x, y: d.oy + e.clientY - d.y });\n }}\n onPointerUp={() => (drag.current = null)}\n >\n <span className=\"truncate\">{ref.name}</span>\n <button type=\"button\" aria-label={`Hide ${ref.name}`} className=\"px-1 text-slate-400 hover:text-white\" onClick={() => controller.updateReferenceImage(id, { visible: false })}>\n ×\n </button>\n </div>\n <img\n src={ref.src}\n alt={ref.name}\n draggable={false}\n width={ref.displayWidth}\n height={h}\n className=\"block cursor-copy\"\n onClick={(e) => {\n const rect = (e.target as HTMLElement).getBoundingClientRect();\n const k = ref.width / (rect.width || ref.displayWidth);\n controller.setColor(controller.pickReferenceColor(id, Math.min(ref.width - 1, (e.clientX - rect.left) * k), Math.min(ref.height - 1, (e.clientY - rect.top) * k)));\n }}\n />\n </div>\n );\n};\n","import React, { useRef } from 'react';\nimport { PAINT_TOOLS, SYMMETRY_MODES, decodeImageBlob, downloadBytes, type PaintEditorController, type PaintTool, type SymmetryMode } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, button, chip, useAttempt } from './shared';\n\nexport interface PaintToolbarProps {\n controller: PaintEditorController;\n tool: PaintTool;\n onToolChange: (tool: PaintTool) => void;\n /** Base name of saved and exported files (default `painting`). */\n fileName?: string;\n className?: string;\n}\n\n/**\n * Tools (brush, eyedropper, pan, rotate view), undo / redo, view rotation, mirroring and reset,\n * the symmetry and perspective guides, the tracing image and reference images, the drawing hand,\n * and file actions: save / open JSON, export PNG, JPEG and PSD.\n */\nexport const PaintToolbar: React.FC<PaintToolbarProps> = ({ controller, tool, onToolChange, fileName = 'painting', className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const openRef = useRef<HTMLInputElement>(null);\n const tracingRef = useRef<HTMLInputElement>(null);\n const refRef = useRef<HTMLInputElement>(null);\n const { symmetry, perspective, tracing } = state.guides;\n const { canvas } = state.document;\n\n const exportImage = (format: 'image/png' | 'image/jpeg') =>\n attempt(async () => downloadBytes(await controller.exportImage({ format }), `${fileName}.${format === 'image/png' ? 'png' : 'jpg'}`, format));\n\n return (\n <div className={`flex flex-wrap items-center gap-1.5 text-xs text-slate-200 ${className ?? ''}`} role=\"toolbar\" aria-label=\"Paint toolbar\" data-testid=\"paint-toolbar\">\n {PAINT_TOOLS.map((t) => (\n <button key={t.id} type=\"button\" aria-pressed={tool === t.id} title={`${t.label} (${t.key.toUpperCase()})`} className={chip(tool === t.id)} onClick={() => onToolChange(t.id)}>\n {t.label}\n </button>\n ))}\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} disabled={!state.canUndo} title={state.undoLabel ? `Undo ${state.undoLabel}` : 'Undo'} onClick={() => controller.undo()}>\n Undo\n </button>\n <button type=\"button\" className={button} disabled={!state.canRedo} title={state.redoLabel ? `Redo ${state.redoLabel}` : 'Redo'} onClick={() => controller.redo()}>\n Redo\n </button>\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} aria-label=\"Rotate view left\" onClick={() => controller.setView({ rotation: state.view.rotation - 15 })}>\n ⟲\n </button>\n <button type=\"button\" className={button} aria-label=\"Rotate view right\" onClick={() => controller.setView({ rotation: state.view.rotation + 15 })}>\n ⟳\n </button>\n <button type=\"button\" className={chip(state.view.mirror)} aria-pressed={state.view.mirror} onClick={() => controller.setView({ mirror: !state.view.mirror })}>\n Mirror view\n </button>\n <button type=\"button\" className={button} onClick={() => controller.resetView()}>\n Reset view\n </button>\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <label className=\"flex items-center gap-1\">\n Symmetry\n <select\n aria-label=\"Symmetry\"\n value={symmetry.mode}\n onChange={(e) => controller.setSymmetry({ mode: e.target.value as SymmetryMode, center: symmetry.mode === 'off' ? { x: canvas.width / 2, y: canvas.height / 2 } : symmetry.center })}\n className=\"rounded bg-slate-800 px-1 py-0.5\"\n >\n {SYMMETRY_MODES.map((m) => (\n <option key={m} value={m}>\n {m}\n </option>\n ))}\n </select>\n </label>\n {symmetry.mode === 'kaleidoscope' && (\n <input\n type=\"number\"\n aria-label=\"Kaleidoscope segments\"\n min={2}\n max={32}\n value={symmetry.segments}\n onChange={(e) => controller.setSymmetry({ segments: Number(e.target.value) })}\n className=\"w-12 rounded bg-slate-800 px-1 py-0.5\"\n />\n )}\n <button\n type=\"button\"\n className={chip(perspective.enabled)}\n aria-pressed={perspective.enabled}\n onClick={() =>\n attempt(() =>\n controller.setPerspective(\n perspective.enabled ? { enabled: false } : { enabled: true, points: perspective.points.length ? perspective.points : [{ x: canvas.width / 2, y: canvas.height * 0.4 }] }\n )\n )\n }\n >\n Perspective\n </button>\n {perspective.enabled && (\n <select\n aria-label=\"Vanishing points\"\n value={perspective.points.length}\n onChange={(e) => {\n const n = Number(e.target.value);\n const y = canvas.height * 0.4;\n const pts = n === 1 ? [{ x: canvas.width / 2, y }] : n === 2 ? [{ x: -canvas.width * 0.5, y }, { x: canvas.width * 1.5, y }] : [{ x: -canvas.width * 0.5, y }, { x: canvas.width * 1.5, y }, { x: canvas.width / 2, y: canvas.height * 3 }];\n attempt(() => controller.setPerspective({ points: pts }));\n }}\n className=\"rounded bg-slate-800 px-1 py-0.5\"\n >\n <option value={1}>1-point</option>\n <option value={2}>2-point</option>\n <option value={3}>3-point</option>\n </select>\n )}\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} onClick={() => tracingRef.current?.click()}>\n Tracing image…\n </button>\n {tracing && (\n <>\n <input\n type=\"range\"\n aria-label=\"Tracing opacity\"\n min={0}\n max={1}\n step={0.05}\n value={tracing.opacity}\n onChange={(e) => controller.updateTracing({ opacity: Number(e.target.value) })}\n className=\"w-16 accent-indigo-500\"\n />\n <button type=\"button\" className={chip(tracing.sampleColors)} aria-pressed={tracing.sampleColors} onClick={() => controller.updateTracing({ sampleColors: !tracing.sampleColors })}>\n Trace colours\n </button>\n <button type=\"button\" className={chip(tracing.visible)} aria-pressed={tracing.visible} onClick={() => controller.updateTracing({ visible: !tracing.visible })}>\n Show tracing\n </button>\n <button type=\"button\" className={button} onClick={() => controller.clearTracingImage()}>\n Remove tracing\n </button>\n </>\n )}\n <button type=\"button\" className={button} onClick={() => refRef.current?.click()}>\n Reference…\n </button>\n <button type=\"button\" className={button} title=\"Which hand holds the pen (palm rejection)\" onClick={() => controller.setHand(state.hand === 'right' ? 'left' : 'right')}>\n {state.hand === 'right' ? 'Right-handed' : 'Left-handed'}\n </button>\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} onClick={() => attempt(() => downloadBytes(JSON.stringify(controller.toJSON()), `${fileName}.paint.json`, 'application/json'))}>\n Save\n </button>\n <button type=\"button\" className={button} onClick={() => openRef.current?.click()}>\n Open…\n </button>\n <button type=\"button\" className={button} onClick={() => exportImage('image/png')}>\n PNG\n </button>\n <button type=\"button\" className={button} onClick={() => exportImage('image/jpeg')}>\n JPEG\n </button>\n <button type=\"button\" className={button} onClick={() => attempt(() => downloadBytes(controller.exportPsd().bytes, `${fileName}.psd`, 'image/vnd.adobe.photoshop'))}>\n PSD\n </button>\n <input\n ref={openRef}\n type=\"file\"\n accept=\".json,application/json\"\n aria-label=\"Open painting\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.loadJSON(JSON.parse(await f.text())));\n e.target.value = '';\n }}\n />\n <input\n ref={tracingRef}\n type=\"file\"\n accept=\"image/*\"\n aria-label=\"Load tracing image\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.setTracingImage({ pixels: await decodeImageBlob(f) }));\n e.target.value = '';\n }}\n />\n <input\n ref={refRef}\n type=\"file\"\n accept=\"image/*\"\n aria-label=\"Add reference image\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.addReferenceImage({ pixels: await decodeImageBlob(f), name: f.name }));\n e.target.value = '';\n }}\n />\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useEffect, useRef, useState } from 'react';\nimport type { SliderControl } from '@pixerate/editor/paint-editor';\n\nexport const chip = (on: boolean) => `px-2 py-1 rounded text-[11px] ${on ? 'bg-indigo-600 text-white' : 'bg-slate-800 text-slate-300 hover:text-white'}`;\nexport const button = 'px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-200 hover:bg-slate-700 disabled:opacity-40';\nexport const panel = 'flex flex-col gap-2 text-xs text-slate-200';\n\n/** Draws RGBA pixels into a canvas (nothing without a 2D context, as in jsdom). */\nexport const PixelCanvas: React.FC<{ pixels: { width: number; height: number; data: Uint8ClampedArray } | null; label: string; className?: string; style?: React.CSSProperties }> = ({ pixels, label, className, style }) => {\n const ref = useRef<HTMLCanvasElement>(null);\n useEffect(() => {\n const canvas = ref.current;\n const ctx = canvas?.getContext('2d');\n if (!canvas || !ctx || !pixels || typeof ctx.createImageData !== 'function') return;\n canvas.width = pixels.width;\n canvas.height = pixels.height;\n const img = ctx.createImageData(pixels.width, pixels.height);\n img.data.set(pixels.data);\n ctx.putImageData(img, 0, 0);\n }, [pixels]);\n return <canvas ref={ref} role=\"img\" aria-label={label} className={className} style={style} width={pixels?.width} height={pixels?.height} />;\n};\n\nconst fmt = (c: SliderControl, v: number) => (c.step >= 1 ? String(Math.round(v)) : v.toFixed(2));\n\n/**\n * A labelled range input. `onChange` runs while dragging; `onCommit` (if given) runs once on\n * release (the native `change` event), for settings that are undo steps.\n */\nexport const PaintSlider: React.FC<{ control: SliderControl; value: number; onChange?: (v: number) => void; onCommit?: (v: number) => void }> = ({ control, value, onChange, onCommit }) => {\n const [draft, setDraft] = useState<number | null>(null);\n const ref = useRef<HTMLInputElement>(null);\n const commit = useRef(onCommit);\n commit.current = onCommit;\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const done = () => {\n commit.current?.(Number(el.value));\n setDraft(null);\n };\n el.addEventListener('change', done);\n return () => el.removeEventListener('change', done);\n }, []);\n const shown = draft ?? value;\n return (\n <label className=\"flex flex-col gap-0.5\" data-path={control.path}>\n <span className=\"flex justify-between text-slate-400\">\n <span>{control.label}</span>\n <span className=\"font-mono\">{fmt(control, shown)}</span>\n </span>\n <input\n ref={ref}\n type=\"range\"\n aria-label={control.label}\n min={control.min}\n max={control.max}\n step={control.step}\n value={shown}\n onChange={(e) => {\n const v = Number(e.target.value);\n if (onCommit) setDraft(v);\n onChange?.(v);\n }}\n className=\"w-full accent-indigo-500\"\n />\n </label>\n );\n};\n\n/** Runs `fn`, turning a thrown error into a message. */\nexport function useAttempt(): [string | null, (fn: () => unknown) => void, (msg: string | null) => void] {\n const [error, setError] = useState<string | null>(null);\n const attempt = (fn: () => unknown) => {\n try {\n setError(null);\n const r = fn();\n if (r && typeof (r as Promise<unknown>).catch === 'function') (r as Promise<unknown>).catch((e) => setError(e instanceof Error ? e.message : String(e)));\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n }\n };\n return [error, attempt, setError];\n}\n\nexport const ErrorLine: React.FC<{ error: string | null }> = ({ error }) =>\n error ? (\n <p role=\"alert\" className=\"text-[11px] text-rose-400\">\n {error}\n </p>\n ) : null;\n\n/** A colour input that commits once when the picker closes (the native `change` event). */\nexport const CommitColorInput: React.FC<{ value: string; label: string; onCommit: (v: string) => void; className?: string }> = ({ value, label, onCommit, className }) => {\n const ref = useRef<HTMLInputElement>(null);\n const commit = useRef(onCommit);\n commit.current = onCommit;\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const done = () => commit.current(el.value);\n el.addEventListener('change', done);\n return () => el.removeEventListener('change', done);\n }, []);\n return <input ref={ref} type=\"color\" aria-label={label} defaultValue={value} key={value} className={className} />;\n};\n","import React, { useMemo, useRef, useState } from 'react';\nimport { BRUSH_ROTATIONS, BRUSH_SLIDERS, downloadBytes, patchPath, readPath, type BrushRotation, type PaintEditorController } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, PaintSlider, PixelCanvas, button, panel, useAttempt } from './shared';\n\nexport interface BrushPanelProps {\n controller: PaintEditorController;\n /** Thumbnail size in px (default 112 × 32). */\n thumbnailWidth?: number;\n thumbnailHeight?: number;\n className?: string;\n}\n\n/**\n * The brush library (thumbnails rendered from a test stroke on the current paper, grouped by\n * category) and the active brush's settings: size, opacity, flow, hardness, spacing, roundness,\n * angle, paper grain, position and pressure smoothing, dynamics and rotation mode. Save the edited\n * brush, import and export libraries as JSON.\n */\nexport const BrushPanel: React.FC<BrushPanelProps> = ({ controller, thumbnailWidth = 112, thumbnailHeight = 32, className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const [saveName, setSaveName] = useState('');\n const fileRef = useRef<HTMLInputElement>(null);\n const { brush, brushes } = state;\n const paper = state.document.paper;\n const thumbs = useMemo(\n () => new Map(brushes.map((b) => [b.id, controller.brushThumbnail(b.id, { width: thumbnailWidth, height: thumbnailHeight, color: '#26324a' })])),\n // Thumbnails follow the library and the paper.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [controller, brushes, paper, thumbnailWidth, thumbnailHeight]\n );\n const slug = (name: string) => name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 60) || 'brush';\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"brush-panel\">\n <div className=\"grid grid-cols-2 gap-1\" role=\"listbox\" aria-label=\"Brushes\">\n {brushes.map((b) => (\n <button\n key={b.id}\n type=\"button\"\n role=\"option\"\n aria-selected={brush.id === b.id}\n title={`${b.name} (${b.category})`}\n className={`flex flex-col items-start gap-0.5 rounded p-1 text-left ${brush.id === b.id ? 'bg-indigo-600/30 ring-1 ring-indigo-500' : 'bg-slate-900 hover:bg-slate-800'}`}\n onClick={() => controller.setBrush({ id: b.id })}\n >\n <PixelCanvas pixels={thumbs.get(b.id) ?? null} label={`${b.name} thumbnail`} className=\"rounded\" style={{ width: '100%', aspectRatio: `${thumbnailWidth} / ${thumbnailHeight}` }} />\n <span className=\"truncate text-[10px] text-slate-300\">{b.name}</span>\n </button>\n ))}\n </div>\n <div className=\"flex flex-col gap-1.5\">\n {BRUSH_SLIDERS.map((c) => (\n <PaintSlider key={c.path} control={c} value={readPath(brush, c.path)} onChange={(v) => controller.setBrush(patchPath(brush as never, c.path, v) as never)} />\n ))}\n <label className=\"flex items-center justify-between gap-2\">\n <span className=\"text-slate-400\">Rotation</span>\n <select aria-label=\"Brush rotation\" value={brush.rotation} onChange={(e) => controller.setBrush({ rotation: e.target.value as BrushRotation })} className=\"rounded bg-slate-800 px-1 py-0.5\">\n {BRUSH_ROTATIONS.map((r) => (\n <option key={r} value={r}>\n {r === 'stroke' ? 'Follow stroke' : r === 'barrel' ? 'Pen barrel' : 'Fixed'}\n </option>\n ))}\n </select>\n </label>\n <label className=\"flex items-center gap-2\">\n <input type=\"checkbox\" checked={brush.tip.pressureSize} onChange={(e) => controller.setBrush({ tip: { pressureSize: e.target.checked } })} /> Pressure → size\n </label>\n <label className=\"flex items-center gap-2\">\n <input type=\"checkbox\" checked={brush.tip.pressureOpacity} onChange={(e) => controller.setBrush({ tip: { pressureOpacity: e.target.checked } })} /> Pressure → opacity\n </label>\n </div>\n <div className=\"flex flex-wrap items-center gap-1\">\n <input value={saveName} placeholder=\"Brush name\" aria-label=\"Brush name\" onChange={(e) => setSaveName(e.target.value)} className=\"w-28 rounded bg-slate-800 px-1.5 py-0.5\" />\n <button type=\"button\" className={button} disabled={!saveName.trim()} onClick={() => attempt(() => (controller.saveBrush({ id: slug(saveName), name: saveName.trim() }), setSaveName('')))}>\n Save brush\n </button>\n <button type=\"button\" className={button} onClick={() => attempt(() => downloadBytes(JSON.stringify(controller.exportBrushes(), null, 2), 'brushes.json', 'application/json'))}>\n Export\n </button>\n <button type=\"button\" className={button} onClick={() => fileRef.current?.click()}>\n Import…\n </button>\n <input\n ref={fileRef}\n type=\"file\"\n accept=\".json,application/json\"\n aria-label=\"Import brushes\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.importBrushes(JSON.parse(await f.text())));\n e.target.value = '';\n }}\n />\n </div>\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useMemo } from 'react';\nimport { PAPER_FAMILIES, PAPER_LIBRARY, PAPER_SLIDERS, patchPath, readPath, renderPaper, type PaintEditorController } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { CommitColorInput, ErrorLine, PaintSlider, PixelCanvas, panel, useAttempt } from './shared';\n\nexport interface PaperPanelProps {\n controller: PaintEditorController;\n className?: string;\n}\n\nconst SWATCH = { x: 0, y: 0, width: 64, height: 40 };\n\n/**\n * The paper library by family (each a generated grain preview) and the current paper's colour,\n * grain depth, scale, shading and contrast, plus the wet-media properties stored for later.\n * Each change is one undo step (sliders commit on release).\n */\nexport const PaperPanel: React.FC<PaperPanelProps> = ({ controller, className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const paper = state.document.paper;\n const previews = useMemo(() => new Map(PAPER_LIBRARY.map((p) => [p.preset, { ...SWATCH, data: renderPaper({ ...p, shading: Math.max(0.8, p.shading) }, SWATCH) }])), []);\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"paper-panel\">\n {PAPER_FAMILIES.map((family) => (\n <div key={family}>\n <div className=\"mb-0.5 text-[10px] uppercase tracking-wide text-slate-500\">{family}</div>\n <div className=\"flex flex-wrap gap-1\" role=\"listbox\" aria-label={`${family} papers`}>\n {PAPER_LIBRARY.filter((p) => p.family === family).map((p) => (\n <button\n key={p.preset}\n type=\"button\"\n role=\"option\"\n aria-selected={paper.preset === p.preset}\n title={p.name}\n className={`rounded p-0.5 ${paper.preset === p.preset ? 'ring-2 ring-indigo-500' : 'ring-1 ring-slate-700 hover:ring-slate-500'}`}\n onClick={() => attempt(() => controller.setPaper({ preset: p.preset }))}\n >\n <PixelCanvas pixels={previews.get(p.preset) ?? null} label={p.name} style={{ width: 48, height: 30 }} />\n </button>\n ))}\n </div>\n </div>\n ))}\n <div className=\"text-slate-300\">{paper.name}</div>\n <label className=\"flex items-center justify-between\">\n <span className=\"text-slate-400\">Colour</span>\n <CommitColorInput label=\"Paper colour\" value={paper.color} onCommit={(v) => attempt(() => controller.setPaper({ color: v }))} className=\"h-6 w-10 rounded bg-transparent\" />\n </label>\n {PAPER_SLIDERS.map((c) => (\n <PaintSlider key={c.path} control={c} value={readPath(paper, c.path)} onCommit={(v) => attempt(() => controller.setPaper(patchPath(paper as never, c.path, v) as never))} />\n ))}\n <label className=\"flex items-center gap-2\">\n <input type=\"checkbox\" checked={paper.tiling === 'mirror'} onChange={(e) => attempt(() => controller.setPaper({ tiling: e.target.checked ? 'mirror' : 'repeat' }))} /> Mirror tiling\n </label>\n <button type=\"button\" className=\"self-start px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-200 hover:bg-slate-700\" onClick={() => attempt(() => controller.setPaper({ seed: paper.seed + 1 }))}>\n New sheet\n </button>\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useMemo, useRef, useState } from 'react';\nimport {\n HARMONY_KINDS,\n MIXING_PAD_HEIGHT,\n MIXING_PAD_WIDTH,\n hsvToRgb,\n hueToWheel,\n parseHexColor,\n renderColorWheel,\n rgbToHexColor,\n rgbToHsv,\n wheelPick,\n wheelPoint,\n type ColorWheel,\n type HarmonyKind,\n type PaintEditorController,\n} from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, PixelCanvas, button, chip, panel, useAttempt } from './shared';\n\nexport interface ColorPanelProps {\n controller: PaintEditorController;\n /** Wheel diameter in px (default 168). */\n wheelSize?: number;\n /** Show the mixing pad (default true). */\n mixingPad?: boolean;\n className?: string;\n}\n\ntype PadTool = 'paint' | 'knife' | 'pick';\n\n/**\n * Colour: a hue wheel (painter's RYB or RGB) with the chosen harmony marked on it, saturation and\n * value, the paint and second colours, harmony chips, swatches, and a mixing pad to paint on,\n * smear with a palette knife (pigment mixing) and pick from.\n */\nexport const ColorPanel: React.FC<ColorPanelProps> = ({ controller, wheelSize = 168, mixingPad = true, className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const [wheel, setWheel] = useState<ColorWheel>('ryb');\n const [kind, setKind] = useState<HarmonyKind>('complementary');\n const [padTool, setPadTool] = useState<PadTool>('paint');\n const padPoints = useRef<Array<{ x: number; y: number; pressure?: number }> | null>(null);\n const ring = useMemo(() => renderColorWheel(wheelSize, wheel), [wheelSize, wheel]);\n const color = state.color;\n const harmony = useMemo(() => controller.harmony(kind, { color, wheel }), [controller, kind, color, wheel]);\n const [r, g, b] = parseHexColor(color);\n const hsv = rgbToHsv(r, g, b);\n const pad = useMemo(() => ({ width: MIXING_PAD_WIDTH, height: MIXING_PAD_HEIGHT, data: controller.mixingPad.pixels() }), [controller, state.mixingPadVersion]);\n const R = wheelSize / 2;\n const mid = R * 0.82;\n const setHsv = (s: number, v: number) => controller.setColor(rgbToHexColor(...hsvToRgb(hsv.h, s, v)));\n\n const padPoint = (e: React.PointerEvent) => {\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n const kx = MIXING_PAD_WIDTH / (rect.width || MIXING_PAD_WIDTH);\n const ky = MIXING_PAD_HEIGHT / (rect.height || MIXING_PAD_HEIGHT);\n const x = Math.min(MIXING_PAD_WIDTH, Math.max(0, (e.clientX - rect.left) * kx));\n const y = Math.min(MIXING_PAD_HEIGHT, Math.max(0, (e.clientY - rect.top) * ky));\n return e.pointerType === 'pen' && e.pressure > 0 ? { x, y, pressure: e.pressure } : { x, y };\n };\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"color-panel\">\n <div className=\"relative self-center\" style={{ width: wheelSize, height: wheelSize }}>\n <div\n role=\"slider\"\n aria-label=\"Hue wheel\"\n aria-valuemin={0}\n aria-valuemax={360}\n aria-valuenow={Math.round(hueToWheel(hsv.h, wheel))}\n tabIndex={0}\n className=\"absolute inset-0 cursor-crosshair\"\n onPointerDown={(e) => {\n const rect = e.currentTarget.getBoundingClientRect();\n controller.setColor(wheelPick(e.clientX - rect.left - R, e.clientY - rect.top - R, wheel, color));\n }}\n >\n <PixelCanvas pixels={ring} label=\"Colour wheel\" style={{ width: wheelSize, height: wheelSize }} />\n </div>\n <svg className=\"pointer-events-none absolute inset-0\" width={wheelSize} height={wheelSize} aria-hidden=\"true\">\n {harmony.map((h, i) => {\n const p = wheelPoint(h.angle, mid);\n return <circle key={i} cx={R + p.x} cy={R + p.y} r={i === 0 ? 7 : 5} fill={h.color} stroke=\"#fff\" strokeWidth={i === 0 ? 2 : 1} />;\n })}\n </svg>\n <div className=\"absolute rounded-full border border-slate-700\" style={{ left: R - R * 0.45, top: R - R * 0.45, width: R * 0.9, height: R * 0.9, background: color }} />\n </div>\n <div className=\"flex items-center gap-2\">\n <input type=\"color\" aria-label=\"Paint colour\" value={color} onChange={(e) => controller.setColor(e.target.value)} className=\"h-7 w-9 rounded bg-transparent\" />\n <input type=\"color\" aria-label=\"Second colour\" value={state.secondaryColor} onChange={(e) => controller.setSecondaryColor(e.target.value)} className=\"h-5 w-7 rounded bg-transparent\" />\n <button type=\"button\" className={button} title=\"Swap colours (X)\" onClick={() => controller.swapColors()}>\n Swap\n </button>\n <input\n aria-label=\"Hex colour\"\n defaultValue={color}\n key={color}\n onBlur={(e) => attempt(() => controller.setColor(e.target.value.startsWith('#') ? e.target.value : `#${e.target.value}`))}\n className=\"w-20 rounded bg-slate-800 px-1.5 py-0.5 font-mono\"\n />\n </div>\n <label className=\"flex items-center gap-2\">\n <span className=\"w-16 text-slate-400\">Saturation</span>\n <input type=\"range\" aria-label=\"Saturation\" min={0} max={1} step={0.01} value={hsv.s} onChange={(e) => setHsv(Number(e.target.value), hsv.v)} className=\"flex-1 accent-indigo-500\" />\n </label>\n <label className=\"flex items-center gap-2\">\n <span className=\"w-16 text-slate-400\">Value</span>\n <input type=\"range\" aria-label=\"Value\" min={0} max={1} step={0.01} value={hsv.v} onChange={(e) => setHsv(hsv.s, Number(e.target.value))} className=\"flex-1 accent-indigo-500\" />\n </label>\n <div className=\"flex items-center gap-1\">\n <select aria-label=\"Harmony\" value={kind} onChange={(e) => setKind(e.target.value as HarmonyKind)} className=\"rounded bg-slate-800 px-1 py-0.5\">\n {HARMONY_KINDS.map((k) => (\n <option key={k} value={k}>\n {k}\n </option>\n ))}\n </select>\n <button type=\"button\" className={chip(wheel === 'ryb')} aria-pressed={wheel === 'ryb'} onClick={() => setWheel('ryb')}>\n RYB\n </button>\n <button type=\"button\" className={chip(wheel === 'rgb')} aria-pressed={wheel === 'rgb'} onClick={() => setWheel('rgb')}>\n RGB\n </button>\n </div>\n <div className=\"flex flex-wrap gap-1\" aria-label=\"Harmony colours\">\n {harmony.map((h, i) => (\n <button key={i} type=\"button\" aria-label={`Use ${h.color}`} title={h.color} className=\"h-6 w-6 rounded ring-1 ring-slate-700\" style={{ background: h.color }} onClick={() => controller.setColor(h.color)} />\n ))}\n <button type=\"button\" className={button} onClick={() => harmony.forEach((h) => controller.addSwatch(h.color))}>\n + swatches\n </button>\n </div>\n <div className=\"flex flex-wrap gap-1\" role=\"listbox\" aria-label=\"Swatches\">\n {state.swatches.map((s, i) => (\n <button\n key={i}\n type=\"button\"\n role=\"option\"\n aria-selected={s.color === color}\n aria-label={s.name ?? s.color}\n title={`${s.name ?? s.color} (right-click to remove)`}\n className=\"h-5 w-5 rounded ring-1 ring-slate-700\"\n style={{ background: s.color }}\n onClick={() => controller.setColor(s.color)}\n onContextMenu={(e) => {\n e.preventDefault();\n controller.removeSwatch(i);\n }}\n />\n ))}\n <button type=\"button\" className={button} aria-label=\"Add swatch\" onClick={() => controller.addSwatch(color)}>\n +\n </button>\n </div>\n {mixingPad && (\n <div className=\"flex flex-col gap-1\" data-testid=\"mixing-pad\">\n <div className=\"flex items-center gap-1\">\n <span className=\"text-slate-400\">Mixing pad</span>\n {(['paint', 'knife', 'pick'] as const).map((t) => (\n <button key={t} type=\"button\" aria-pressed={padTool === t} className={chip(padTool === t)} onClick={() => setPadTool(t)}>\n {t === 'paint' ? 'Paint' : t === 'knife' ? 'Knife' : 'Pick'}\n </button>\n ))}\n <button type=\"button\" className={button} onClick={() => controller.clearMixingPad()}>\n Clear\n </button>\n </div>\n <div\n role=\"application\"\n aria-label=\"Mixing pad\"\n className=\"touch-none cursor-crosshair\"\n onPointerDown={(e) => {\n const p = padPoint(e);\n if (padTool === 'pick') {\n attempt(() => controller.mixingPadPick(p.x, p.y, { setColor: true }));\n return;\n }\n padPoints.current = [p];\n (e.target as Element).setPointerCapture?.(e.pointerId);\n }}\n onPointerMove={(e) => padPoints.current?.push(padPoint(e))}\n onPointerUp={() => {\n const pts = padPoints.current;\n padPoints.current = null;\n if (pts?.length) attempt(() => controller.mixingPadStroke(pts, { tool: padTool === 'knife' ? 'knife' : 'paint' }));\n }}\n >\n <PixelCanvas pixels={pad} label=\"Mixing pad pixels\" className=\"w-full rounded\" style={{ aspectRatio: `${MIXING_PAD_WIDTH} / ${MIXING_PAD_HEIGHT}` }} />\n </div>\n </div>\n )}\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useState } from 'react';\nimport { BLEND_MODES, type BlendMode, type PaintEditorController, type PaintLayerInfo } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, button, chip, panel, useAttempt } from './shared';\n\nexport interface PaintLayersPanelProps {\n controller: PaintEditorController;\n className?: string;\n}\n\n/** Siblings of a layer, bottom first, and its index among them. */\nfunction siblingIndex(layers: PaintLayerInfo[], l: PaintLayerInfo): { index: number; count: number } {\n const sibs = layers.filter((x) => x.parentId === l.parentId).reverse();\n return { index: sibs.findIndex((x) => x.id === l.id), count: sibs.length };\n}\n\n/**\n * The layer stack, top first: visibility, names (double-click to rename), the active layer's\n * opacity, blend mode and locks, and new layer / group, duplicate, move up / down, merge down and\n * delete. Every change is one undo step.\n */\nexport const PaintLayersPanel: React.FC<PaintLayersPanelProps> = ({ controller, className }) => {\n usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const [renaming, setRenaming] = useState<string | null>(null);\n const layers = controller.listLayers();\n const active = layers.find((l) => l.active) ?? null;\n const move = (delta: number) => {\n if (!active) return;\n const { index, count } = siblingIndex(layers, active);\n const to = Math.min(count - 1, Math.max(0, index + delta));\n if (to !== index) attempt(() => controller.moveLayer(active.id, to));\n };\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"paint-layers-panel\">\n <div className=\"flex flex-wrap gap-1\">\n <button type=\"button\" className={button} onClick={() => attempt(() => controller.addLayer())}>\n New layer\n </button>\n <button type=\"button\" className={button} onClick={() => attempt(() => controller.addLayer({ type: 'group' }))}>\n New group\n </button>\n <button type=\"button\" className={button} disabled={!active} onClick={() => active && attempt(() => controller.duplicateLayer(active.id))}>\n Duplicate\n </button>\n <button type=\"button\" className={button} disabled={!active} aria-label=\"Move layer up\" onClick={() => move(1)}>\n ↑\n </button>\n <button type=\"button\" className={button} disabled={!active} aria-label=\"Move layer down\" onClick={() => move(-1)}>\n ↓\n </button>\n <button type=\"button\" className={button} disabled={!active} onClick={() => active && attempt(() => controller.mergeDown(active.id))}>\n Merge down\n </button>\n <button type=\"button\" className={button} disabled={!active || layers.length < 2} onClick={() => active && attempt(() => controller.removeLayer(active.id))}>\n Delete\n </button>\n </div>\n <ul role=\"tree\" aria-label=\"Layers\" className=\"flex flex-col gap-0.5\">\n {layers.map((l) => (\n <li\n key={l.id}\n role=\"treeitem\"\n aria-selected={l.active}\n className={`flex items-center gap-1.5 rounded px-1.5 py-1 cursor-pointer ${l.active ? 'bg-indigo-600/30 ring-1 ring-indigo-500' : 'hover:bg-slate-800'}`}\n style={{ paddingLeft: 6 + l.depth * 12 }}\n onClick={() => controller.setActiveLayer(l.id)}\n >\n <button\n type=\"button\"\n aria-label={l.visible ? `Hide ${l.name}` : `Show ${l.name}`}\n className={`w-5 text-[11px] ${l.visible ? 'text-slate-200' : 'text-slate-600'}`}\n onClick={(e) => {\n e.stopPropagation();\n attempt(() => controller.updateLayer(l.id, { visible: !l.visible }));\n }}\n >\n {l.visible ? '●' : '○'}\n </button>\n {renaming === l.id ? (\n <input\n autoFocus\n aria-label=\"Layer name\"\n defaultValue={l.name}\n className=\"flex-1 rounded bg-slate-800 px-1\"\n onClick={(e) => e.stopPropagation()}\n onBlur={(e) => {\n setRenaming(null);\n if (e.target.value.trim() && e.target.value !== l.name) attempt(() => controller.updateLayer(l.id, { name: e.target.value }));\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter') (e.target as HTMLInputElement).blur();\n if (e.key === 'Escape') setRenaming(null);\n }}\n />\n ) : (\n <span className=\"flex-1 truncate\" onDoubleClick={() => setRenaming(l.id)}>\n {l.type === 'group' ? '▸ ' : ''}\n {l.name}\n </span>\n )}\n {l.locks.pixels || l.locks.all ? <span title=\"Locked\">🔒</span> : null}\n </li>\n ))}\n </ul>\n {active && (\n <div className=\"flex flex-col gap-1.5\">\n <label className=\"flex items-center gap-2\">\n <span className=\"w-14 text-slate-400\">Opacity</span>\n <input\n type=\"range\"\n aria-label=\"Layer opacity\"\n min={0}\n max={1}\n step={0.01}\n value={active.opacity}\n onChange={(e) => attempt(() => controller.updateLayer(active.id, { opacity: Number(e.target.value) }))}\n className=\"flex-1 accent-indigo-500\"\n />\n </label>\n <label className=\"flex items-center gap-2\">\n <span className=\"w-14 text-slate-400\">Blend</span>\n <select aria-label=\"Layer blend\" value={active.blend} onChange={(e) => attempt(() => controller.updateLayer(active.id, { blend: e.target.value as BlendMode }))} className=\"flex-1 rounded bg-slate-800 px-1 py-0.5\">\n {active.type === 'group' && <option value=\"pass-through\">Pass through</option>}\n {BLEND_MODES.map((m) => (\n <option key={m.id} value={m.id}>\n {m.label}\n </option>\n ))}\n </select>\n </label>\n <div className=\"flex gap-1\">\n {(['pixels', 'transparency'] as const).map((k) => (\n <button key={k} type=\"button\" aria-pressed={Boolean(active.locks[k])} className={chip(Boolean(active.locks[k]))} onClick={() => attempt(() => controller.updateLayer(active.id, { locks: { [k]: !active.locks[k] } }))}>\n {k === 'pixels' ? 'Lock pixels' : 'Lock transparency'}\n </button>\n ))}\n <button type=\"button\" aria-pressed={active.clipped} className={chip(active.clipped)} onClick={() => attempt(() => controller.updateLayer(active.id, { clipped: !active.clipped }))}>\n Clip\n </button>\n </div>\n </div>\n )}\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useState } from 'react';\nimport type { PaintEditorController, PaintTool } from '@pixerate/editor/paint-editor';\nimport { BrushPanel } from './BrushPanel';\nimport { ColorPanel } from './ColorPanel';\nimport { PaintCanvas } from './PaintCanvas';\nimport { PaintLayersPanel } from './PaintLayersPanel';\nimport { PaintToolbar } from './PaintToolbar';\nimport { PaperPanel } from './PaperPanel';\nimport { chip } from './shared';\n\nexport interface PaintEditorProps {\n controller: PaintEditorController;\n /** Base name of saved and exported files (default `painting`). */\n fileName?: string;\n /** Height of the editor (default 720 px). */\n height?: number | string;\n className?: string;\n}\n\ntype SideTab = 'color' | 'paper' | 'layers';\n\n/**\n * The paint editor: toolbar, brush library on the left, the canvas, and colour (wheel,\n * harmonies, swatches, mixing pad), paper and layers on the right.\n */\nexport const PaintEditor: React.FC<PaintEditorProps> = ({ controller, fileName, height = 720, className }) => {\n const [tool, setTool] = useState<PaintTool>('brush');\n const [tab, setTab] = useState<SideTab>('color');\n const [error, setError] = useState<string | null>(null);\n return (\n <div className={`flex flex-col gap-2 rounded-xl border border-slate-800 bg-slate-900 p-2 ${className ?? ''}`} style={{ height }} data-testid=\"paint-editor\">\n <PaintToolbar controller={controller} tool={tool} onToolChange={setTool} fileName={fileName} />\n <div className=\"flex min-h-0 flex-1 gap-2\">\n <BrushPanel controller={controller} className=\"w-60 shrink-0 overflow-y-auto pr-1\" />\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <PaintCanvas controller={controller} tool={tool} onError={setError} className=\"flex-1 rounded-lg\" />\n {error && (\n <p role=\"alert\" className=\"mt-1 text-[11px] text-rose-400\">\n {error}\n </p>\n )}\n </div>\n <div className=\"flex w-64 shrink-0 flex-col gap-2 overflow-y-auto pr-1\">\n <div className=\"flex gap-1\" role=\"tablist\" aria-label=\"Paint panels\">\n {(['color', 'paper', 'layers'] as const).map((t) => (\n <button key={t} type=\"button\" role=\"tab\" aria-selected={tab === t} className={chip(tab === t)} onClick={() => setTab(t)}>\n {t === 'color' ? 'Colour' : t === 'paper' ? 'Paper' : 'Layers'}\n </button>\n ))}\n </div>\n {tab === 'color' && <ColorPanel controller={controller} />}\n {tab === 'paper' && <PaperPanel controller={controller} />}\n {tab === 'layers' && <PaintLayersPanel controller={controller} />}\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAAwD;AACxD,0BAAsF;AAY/E,SAAS,eAAe,UAAsD,CAAC,GAAyB;AAC7G,QAAM,CAAC,UAAU,QAAI,uBAAS,MAAO,mBAAmB,4CAAwB,UAAU,IAAI,0CAAsB,OAAO,CAAE;AAC7H,QAAM,QAAQ,oBAAoB,UAAU;AAC5C,aAAO,sBAAQ,OAAO,EAAE,YAAY,MAAM,IAAI,CAAC,YAAY,KAAK,CAAC;AACnE;AAGO,SAAS,oBAAoB,YAAqD;AACvF,aAAO;AAAA,IACL,CAAC,WAAW,WAAW,UAAU,MAAM;AAAA,IACvC,MAAM,WAAW,SAAS;AAAA,IAC1B,MAAM,WAAW,SAAS;AAAA,EAC5B;AACF;;;AC1BA,IAAAA,gBAA4D;AAC5D,IAAAC,uBASO;AAuHD;AAhGC,IAAM,cAA0C,CAAC,EAAE,YAAY,OAAO,SAAS,aAAa,MAAM,aAAa,MAAM,SAAS,UAAU,MAAM;AACnJ,QAAM,QAAQ,oBAAoB,UAAU;AAC5C,QAAM,eAAW,sBAAuB,IAAI;AAC5C,QAAM,aAAS,sBAA0B,IAAI;AAC7C,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAS,EAAE,OAAO,KAAK,QAAQ,IAAI,CAAC;AAC5D,QAAM,eAAW,sBAAO,KAAK;AAC7B,QAAM,CAAC,WAAW,YAAY,QAAI,wBAA0C,CAAC,CAAC;AAC9E,QAAM,gBAAY,uBAAQ,MAAM,IAAI,0CAAqB,UAAU,GAAG,CAAC,UAAU,CAAC;AAClF,QAAM,cAAU;AAAA,IACd,MACE,IAAI,kCAAa,YAAY,MAAM;AACjC,YAAM,IAAI,SAAS,SAAS,sBAAsB;AAClD,aAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,KAAK,OAAO,QAAQ,GAAG,UAAU,KAAK,OAAO;AAAA,IACjH,CAAC;AAAA;AAAA;AAAA,IAGH,CAAC,UAAU;AAAA,EACb;AACA,UAAQ,OAAO;AACf,QAAM,EAAE,QAAQ,IAAI,IAAI,MAAM;AAE9B,+BAAU,MAAM;AACd,UAAM,KAAK,SAAS;AACpB,QAAI,CAAC,MAAM,OAAO,mBAAmB,YAAa;AAClD,UAAM,KAAK,IAAI,eAAe,MAAM;AAClC,UAAI,CAAC,GAAG,eAAe,CAAC,GAAG,aAAc;AACzC,eAAS,UAAU;AACnB,cAAQ,EAAE,OAAO,GAAG,aAAa,QAAQ,GAAG,aAAa,CAAC;AAAA,IAC5D,CAAC;AACD,OAAG,QAAQ,EAAE;AACb,WAAO,MAAM,GAAG,WAAW;AAAA,EAC7B,GAAG,CAAC,CAAC;AAGL,QAAM,aAAS,sBAAsB,IAAI;AACzC,+BAAU,MAAM;AACd,UAAM,MAAM,GAAG,IAAI,KAAK,IAAI,IAAI,MAAM;AACtC,QAAI,CAAC,cAAc,OAAO,YAAY,IAAK;AAC3C,QAAI,OAAO,mBAAmB,eAAe,CAAC,SAAS,QAAS;AAChE,WAAO,UAAU;AACjB,eAAW,QAAQ,EAAE,UAAM,8BAAQ,KAAK,IAAI,GAAG,KAAK,EAAE,GAAG,GAAG,GAAG,EAAE,EAAE,CAAC;AAAA,EACtE,GAAG,CAAC,YAAY,KAAK,MAAM,UAAU,CAAC;AAGtC,+BAAU,MAAM;AACd,UAAM,MAAM,OAAO,SAAS,WAAW,IAAI;AAC3C,QAAI,OAAO,OAAO,IAAI,oBAAoB,WAAY,WAAU,OAAO,GAAY;AAAA,QAC9E,YAAW,UAAU;AAAA,EAC5B,GAAG,CAAC,OAAO,WAAW,UAAU,CAAC;AAGjC,+BAAU,MAAM;AACd,UAAM,KAAK,SAAS;AACpB,QAAI,CAAC,GAAI;AACT,UAAM,UAAU,CAAC,MAAkB;AACjC,QAAE,eAAe;AACjB,cAAQ,MAAM,CAAC;AAAA,IACjB;AACA,OAAG,iBAAiB,SAAS,SAAS,EAAE,SAAS,MAAM,CAAC;AACxD,WAAO,MAAM,GAAG,oBAAoB,SAAS,OAAO;AAAA,EACtD,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,SAAS,MAAM,UAAU,QAAQ,KAAK;AAC5C,QAAM,gBAAY,uCAAiB,MAAM,MAAM,KAAK,IAAI;AACxD,QAAM,QAAQ,iBAAa,mCAAa,UAAU,IAAI,CAAC;AAEvD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,UAAU;AAAA,MACV,MAAK;AAAA,MACL,cAAW;AAAA,MACX,eAAY;AAAA,MACZ,WAAW,6EAA6E,aAAa,EAAE;AAAA,MACvG,OAAO,EAAE,QAAQ,SAAS,QAAQ,SAAS,SAAS,eAAe,SAAS,YAAY;AAAA,MACxF,eAAe,CAAC,MAAM;AACpB,iBAAS,SAAS,MAAM;AACxB,YAAI,QAAQ,KAAK,EAAE,WAAW,EAAG,CAAC,EAAE,OAAmB,oBAAoB,EAAE,SAAS;AACtF,eAAO;AAAA,MACT;AAAA,MACA,eAAe,CAAC,MAAM;AACpB,gBAAQ,KAAK,EAAE,WAAW;AAC1B,YAAI,QAAQ,UAAU,UAAU,UAAU,OAAQ,cAAa,QAAQ,UAAU,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE,EAAE,EAAE,CAAC;AAAA,MACnH;AAAA,MACA,aAAa,CAAC,MAAM;AAClB,gBAAQ,GAAG,EAAE,WAAW;AACxB,qBAAa,CAAC,CAAC;AAAA,MACjB;AAAA,MACA,iBAAiB,MAAM;AACrB,gBAAQ,OAAO;AACf,qBAAa,CAAC,CAAC;AAAA,MACjB;AAAA,MACA,WAAW,CAAC,MAAM;AAChB,gBAAI,0CAAoB,YAAY,SAAS,CAAC,EAAG,GAAE,eAAe;AAAA,MACpE;AAAA,MAEA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,OAAO,IAAI;AAAA,YACX,QAAQ,IAAI;AAAA,YACZ,WAAU;AAAA,YACV,OAAO,EAAE,WAAW,iBAAiB,OAAO,gBAAgB,MAAM,KAAK,OAAO,IAAI,cAAc,OAAO;AAAA;AAAA,QACzG;AAAA,QACA,6CAAC,SAAI,WAAU,8DAA6D,OAAO,IAAI,OAAO,QAAQ,IAAI,QAAQ,OAAO,EAAE,WAAW,iBAAiB,MAAM,GAAG,eAAY,QACzK;AAAA,gBAAM,IAAI,CAAC,GAAG,MACb;AAAA,YAAC;AAAA;AAAA,cAEC,IAAI,EAAE,KAAK;AAAA,cACX,IAAI,EAAE,KAAK;AAAA,cACX,IAAI,EAAE,GAAG;AAAA,cACT,IAAI,EAAE,GAAG;AAAA,cACT,QAAQ,EAAE,SAAS,aAAa,YAAY;AAAA,cAC5C,eAAe,EAAE,SAAS,aAAa,MAAM;AAAA,cAC7C,aAAa,IAAI,MAAM,KAAK;AAAA,cAC5B,iBAAiB,EAAE,SAAS,aAAa,GAAG,IAAI,MAAM,KAAK,IAAI,IAAI,IAAI,MAAM,KAAK,IAAI,KAAK;AAAA;AAAA,YARtF;AAAA,UASP,CACD;AAAA,UACA,UAAU,SAAS,KAClB,4CAAC,cAAS,QAAQ,UAAU,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,KAAK,GAAG,GAAG,MAAK,QAAO,QAAQ,MAAM,OAAO,eAAe,KAAK,aAAa,KAAK,IAAI,GAAG,MAAM,MAAM,IAAI,OAAO,CAAC,GAAG,eAAc,SAAQ;AAAA,WAEtM;AAAA,QACC,MAAM,OAAO,WACX,OAAO,CAAC,MAAM,EAAE,OAAO,EACvB,IAAI,CAAC,MACJ,4CAAC,kBAA0B,YAAwB,IAAI,EAAE,MAApC,EAAE,EAAsC,CAC9D;AAAA,QACH,6CAAC,SAAI,WAAU,4EAA2E,eAAY,qBACnG;AAAA,eAAK,MAAM,MAAM,KAAK,OAAO,GAAG;AAAA,UAAE;AAAA,UAAK,KAAK,MAAM,MAAM,KAAK,QAAQ;AAAA,UAAE;AAAA,UAAE,MAAM,KAAK,SAAS,mBAAgB;AAAA,WAChH;AAAA;AAAA;AAAA,EACF;AAEJ;AAGA,IAAM,iBAA8E,CAAC,EAAE,YAAY,GAAG,MAAM;AAC1G,QAAM,QAAQ,oBAAoB,UAAU;AAC5C,QAAM,MAAM,MAAM,OAAO,WAAW,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAC3D,QAAM,WAAO,sBAAgE,IAAI;AACjF,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,IAAK,IAAI,SAAS,IAAI,QAAS,IAAI;AACzC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,OAAO,EAAE,MAAM,IAAI,GAAG,KAAK,IAAI,GAAG,OAAO,IAAI,aAAa;AAAA,MAC1D,eAAY;AAAA,MACZ,eAAe,CAAC,MAAM,EAAE,gBAAgB;AAAA,MAExC;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,eAAe,CAAC,MAAM;AACpB,mBAAK,UAAU,EAAE,GAAG,EAAE,SAAS,GAAG,EAAE,SAAS,IAAI,IAAI,GAAG,IAAI,IAAI,EAAE;AAClE,cAAC,EAAE,OAAmB,oBAAoB,EAAE,SAAS;AAAA,YACvD;AAAA,YACA,eAAe,CAAC,MAAM;AACpB,oBAAM,IAAI,KAAK;AACf,kBAAI,EAAG,YAAW,qBAAqB,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,GAAG,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,CAAC;AAAA,YACrG;AAAA,YACA,aAAa,MAAO,KAAK,UAAU;AAAA,YAEnC;AAAA,0DAAC,UAAK,WAAU,YAAY,cAAI,MAAK;AAAA,cACrC,4CAAC,YAAO,MAAK,UAAS,cAAY,QAAQ,IAAI,IAAI,IAAI,WAAU,wCAAuC,SAAS,MAAM,WAAW,qBAAqB,IAAI,EAAE,SAAS,MAAM,CAAC,GAAG,kBAE/K;AAAA;AAAA;AAAA,QACF;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,KAAK,IAAI;AAAA,YACT,KAAK,IAAI;AAAA,YACT,WAAW;AAAA,YACX,OAAO,IAAI;AAAA,YACX,QAAQ;AAAA,YACR,WAAU;AAAA,YACV,SAAS,CAAC,MAAM;AACd,oBAAM,OAAQ,EAAE,OAAuB,sBAAsB;AAC7D,oBAAM,IAAI,IAAI,SAAS,KAAK,SAAS,IAAI;AACzC,yBAAW,SAAS,WAAW,mBAAmB,IAAI,KAAK,IAAI,IAAI,QAAQ,IAAI,EAAE,UAAU,KAAK,QAAQ,CAAC,GAAG,KAAK,IAAI,IAAI,SAAS,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC;AAAA,YACnK;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EACF;AAEJ;;;ACpNA,IAAAC,gBAA8B;AAC9B,IAAAC,uBAA2I;;;ACD3I,IAAAC,gBAAmD;AAoB1C,IAAAC,sBAAA;AAjBF,IAAM,OAAO,CAAC,OAAgB,iCAAiC,KAAK,6BAA6B,8CAA8C;AAC/I,IAAM,SAAS;AACf,IAAM,QAAQ;AAGd,IAAM,cAAuK,CAAC,EAAE,QAAQ,OAAO,WAAW,MAAM,MAAM;AAC3N,QAAM,UAAM,sBAA0B,IAAI;AAC1C,+BAAU,MAAM;AACd,UAAM,SAAS,IAAI;AACnB,UAAM,MAAM,QAAQ,WAAW,IAAI;AACnC,QAAI,CAAC,UAAU,CAAC,OAAO,CAAC,UAAU,OAAO,IAAI,oBAAoB,WAAY;AAC7E,WAAO,QAAQ,OAAO;AACtB,WAAO,SAAS,OAAO;AACvB,UAAM,MAAM,IAAI,gBAAgB,OAAO,OAAO,OAAO,MAAM;AAC3D,QAAI,KAAK,IAAI,OAAO,IAAI;AACxB,QAAI,aAAa,KAAK,GAAG,CAAC;AAAA,EAC5B,GAAG,CAAC,MAAM,CAAC;AACX,SAAO,6CAAC,YAAO,KAAU,MAAK,OAAM,cAAY,OAAO,WAAsB,OAAc,OAAO,QAAQ,OAAO,QAAQ,QAAQ,QAAQ;AAC3I;AAEA,IAAM,MAAM,CAAC,GAAkB,MAAe,EAAE,QAAQ,IAAI,OAAO,KAAK,MAAM,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC;AAMxF,IAAM,cAAmI,CAAC,EAAE,SAAS,OAAO,UAAU,SAAS,MAAM;AAC1L,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAwB,IAAI;AACtD,QAAM,UAAM,sBAAyB,IAAI;AACzC,QAAM,aAAS,sBAAO,QAAQ;AAC9B,SAAO,UAAU;AACjB,+BAAU,MAAM;AACd,UAAM,KAAK,IAAI;AACf,QAAI,CAAC,GAAI;AACT,UAAM,OAAO,MAAM;AACjB,aAAO,UAAU,OAAO,GAAG,KAAK,CAAC;AACjC,eAAS,IAAI;AAAA,IACf;AACA,OAAG,iBAAiB,UAAU,IAAI;AAClC,WAAO,MAAM,GAAG,oBAAoB,UAAU,IAAI;AAAA,EACpD,GAAG,CAAC,CAAC;AACL,QAAM,QAAQ,SAAS;AACvB,SACE,8CAAC,WAAM,WAAU,yBAAwB,aAAW,QAAQ,MAC1D;AAAA,kDAAC,UAAK,WAAU,uCACd;AAAA,mDAAC,UAAM,kBAAQ,OAAM;AAAA,MACrB,6CAAC,UAAK,WAAU,aAAa,cAAI,SAAS,KAAK,GAAE;AAAA,OACnD;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,MAAK;AAAA,QACL,cAAY,QAAQ;AAAA,QACpB,KAAK,QAAQ;AAAA,QACb,KAAK,QAAQ;AAAA,QACb,MAAM,QAAQ;AAAA,QACd,OAAO;AAAA,QACP,UAAU,CAAC,MAAM;AACf,gBAAM,IAAI,OAAO,EAAE,OAAO,KAAK;AAC/B,cAAI,SAAU,UAAS,CAAC;AACxB,qBAAW,CAAC;AAAA,QACd;AAAA,QACA,WAAU;AAAA;AAAA,IACZ;AAAA,KACF;AAEJ;AAGO,SAAS,aAAyF;AACvG,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAwB,IAAI;AACtD,QAAM,UAAU,CAAC,OAAsB;AACrC,QAAI;AACF,eAAS,IAAI;AACb,YAAM,IAAI,GAAG;AACb,UAAI,KAAK,OAAQ,EAAuB,UAAU,WAAY,CAAC,EAAuB,MAAM,CAAC,MAAM,SAAS,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC,CAAC;AAAA,IACzJ,SAAS,GAAG;AACV,eAAS,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;AAAA,IACrD;AAAA,EACF;AACA,SAAO,CAAC,OAAO,SAAS,QAAQ;AAClC;AAEO,IAAM,YAAgD,CAAC,EAAE,MAAM,MACpE,QACE,6CAAC,OAAE,MAAK,SAAQ,WAAU,6BACvB,iBACH,IACE;AAGC,IAAM,mBAAkH,CAAC,EAAE,OAAO,OAAO,UAAU,UAAU,MAAM;AACxK,QAAM,UAAM,sBAAyB,IAAI;AACzC,QAAM,aAAS,sBAAO,QAAQ;AAC9B,SAAO,UAAU;AACjB,+BAAU,MAAM;AACd,UAAM,KAAK,IAAI;AACf,QAAI,CAAC,GAAI;AACT,UAAM,OAAO,MAAM,OAAO,QAAQ,GAAG,KAAK;AAC1C,OAAG,iBAAiB,UAAU,IAAI;AAClC,WAAO,MAAM,GAAG,oBAAoB,UAAU,IAAI;AAAA,EACpD,GAAG,CAAC,CAAC;AACL,SAAO,6CAAC,WAAM,KAAU,MAAK,SAAQ,cAAY,OAAO,cAAc,OAAmB,aAAP,KAA6B;AACjH;;;ADvEQ,IAAAC,sBAAA;AAfD,IAAM,eAA4C,CAAC,EAAE,YAAY,MAAM,cAAc,WAAW,YAAY,UAAU,MAAM;AACjI,QAAM,QAAQ,oBAAoB,UAAU;AAC5C,QAAM,CAAC,OAAO,OAAO,IAAI,WAAW;AACpC,QAAM,cAAU,sBAAyB,IAAI;AAC7C,QAAM,iBAAa,sBAAyB,IAAI;AAChD,QAAM,aAAS,sBAAyB,IAAI;AAC5C,QAAM,EAAE,UAAU,aAAa,QAAQ,IAAI,MAAM;AACjD,QAAM,EAAE,OAAO,IAAI,MAAM;AAEzB,QAAM,cAAc,CAAC,WACnB,QAAQ,gBAAY,oCAAc,MAAM,WAAW,YAAY,EAAE,OAAO,CAAC,GAAG,GAAG,QAAQ,IAAI,WAAW,cAAc,QAAQ,KAAK,IAAI,MAAM,CAAC;AAE9I,SACE,8CAAC,SAAI,WAAW,8DAA8D,aAAa,EAAE,IAAI,MAAK,WAAU,cAAW,iBAAgB,eAAY,iBACpJ;AAAA,qCAAY,IAAI,CAAC,MAChB,6CAAC,YAAkB,MAAK,UAAS,gBAAc,SAAS,EAAE,IAAI,OAAO,GAAG,EAAE,KAAK,KAAK,EAAE,IAAI,YAAY,CAAC,KAAK,WAAW,KAAK,SAAS,EAAE,EAAE,GAAG,SAAS,MAAM,aAAa,EAAE,EAAE,GACzK,YAAE,SADQ,EAAE,EAEf,CACD;AAAA,IACD,6CAAC,UAAK,WAAU,8BAA6B;AAAA,IAC7C,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,UAAU,CAAC,MAAM,SAAS,OAAO,MAAM,YAAY,QAAQ,MAAM,SAAS,KAAK,QAAQ,SAAS,MAAM,WAAW,KAAK,GAAG,kBAElK;AAAA,IACA,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,UAAU,CAAC,MAAM,SAAS,OAAO,MAAM,YAAY,QAAQ,MAAM,SAAS,KAAK,QAAQ,SAAS,MAAM,WAAW,KAAK,GAAG,kBAElK;AAAA,IACA,6CAAC,UAAK,WAAU,8BAA6B;AAAA,IAC7C,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,cAAW,oBAAmB,SAAS,MAAM,WAAW,QAAQ,EAAE,UAAU,MAAM,KAAK,WAAW,GAAG,CAAC,GAAG,oBAElJ;AAAA,IACA,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,cAAW,qBAAoB,SAAS,MAAM,WAAW,QAAQ,EAAE,UAAU,MAAM,KAAK,WAAW,GAAG,CAAC,GAAG,oBAEnJ;AAAA,IACA,6CAAC,YAAO,MAAK,UAAS,WAAW,KAAK,MAAM,KAAK,MAAM,GAAG,gBAAc,MAAM,KAAK,QAAQ,SAAS,MAAM,WAAW,QAAQ,EAAE,QAAQ,CAAC,MAAM,KAAK,OAAO,CAAC,GAAG,yBAE9J;AAAA,IACA,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,SAAS,MAAM,WAAW,UAAU,GAAG,wBAEhF;AAAA,IACA,6CAAC,UAAK,WAAU,8BAA6B;AAAA,IAC7C,8CAAC,WAAM,WAAU,2BAA0B;AAAA;AAAA,MAEzC;AAAA,QAAC;AAAA;AAAA,UACC,cAAW;AAAA,UACX,OAAO,SAAS;AAAA,UAChB,UAAU,CAAC,MAAM,WAAW,YAAY,EAAE,MAAM,EAAE,OAAO,OAAuB,QAAQ,SAAS,SAAS,QAAQ,EAAE,GAAG,OAAO,QAAQ,GAAG,GAAG,OAAO,SAAS,EAAE,IAAI,SAAS,OAAO,CAAC;AAAA,UACnL,WAAU;AAAA,UAET,8CAAe,IAAI,CAAC,MACnB,6CAAC,YAAe,OAAO,GACpB,eADU,CAEb,CACD;AAAA;AAAA,MACH;AAAA,OACF;AAAA,IACC,SAAS,SAAS,kBACjB;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAW;AAAA,QACX,KAAK;AAAA,QACL,KAAK;AAAA,QACL,OAAO,SAAS;AAAA,QAChB,UAAU,CAAC,MAAM,WAAW,YAAY,EAAE,UAAU,OAAO,EAAE,OAAO,KAAK,EAAE,CAAC;AAAA,QAC5E,WAAU;AAAA;AAAA,IACZ;AAAA,IAEF;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAW,KAAK,YAAY,OAAO;AAAA,QACnC,gBAAc,YAAY;AAAA,QAC1B,SAAS,MACP;AAAA,UAAQ,MACN,WAAW;AAAA,YACT,YAAY,UAAU,EAAE,SAAS,MAAM,IAAI,EAAE,SAAS,MAAM,QAAQ,YAAY,OAAO,SAAS,YAAY,SAAS,CAAC,EAAE,GAAG,OAAO,QAAQ,GAAG,GAAG,OAAO,SAAS,IAAI,CAAC,EAAE;AAAA,UACzK;AAAA,QACF;AAAA,QAEH;AAAA;AAAA,IAED;AAAA,IACC,YAAY,WACX;AAAA,MAAC;AAAA;AAAA,QACC,cAAW;AAAA,QACX,OAAO,YAAY,OAAO;AAAA,QAC1B,UAAU,CAAC,MAAM;AACf,gBAAM,IAAI,OAAO,EAAE,OAAO,KAAK;AAC/B,gBAAM,IAAI,OAAO,SAAS;AAC1B,gBAAM,MAAM,MAAM,IAAI,CAAC,EAAE,GAAG,OAAO,QAAQ,GAAG,EAAE,CAAC,IAAI,MAAM,IAAI,CAAC,EAAE,GAAG,CAAC,OAAO,QAAQ,KAAK,EAAE,GAAG,EAAE,GAAG,OAAO,QAAQ,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,OAAO,QAAQ,KAAK,EAAE,GAAG,EAAE,GAAG,OAAO,QAAQ,KAAK,EAAE,GAAG,EAAE,GAAG,OAAO,QAAQ,GAAG,GAAG,OAAO,SAAS,EAAE,CAAC;AAC1O,kBAAQ,MAAM,WAAW,eAAe,EAAE,QAAQ,IAAI,CAAC,CAAC;AAAA,QAC1D;AAAA,QACA,WAAU;AAAA,QAEV;AAAA,uDAAC,YAAO,OAAO,GAAG,qBAAO;AAAA,UACzB,6CAAC,YAAO,OAAO,GAAG,qBAAO;AAAA,UACzB,6CAAC,YAAO,OAAO,GAAG,qBAAO;AAAA;AAAA;AAAA,IAC3B;AAAA,IAEF,6CAAC,UAAK,WAAU,8BAA6B;AAAA,IAC7C,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,SAAS,MAAM,WAAW,SAAS,MAAM,GAAG,iCAErF;AAAA,IACC,WACC,8EACE;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,cAAW;AAAA,UACX,KAAK;AAAA,UACL,KAAK;AAAA,UACL,MAAM;AAAA,UACN,OAAO,QAAQ;AAAA,UACf,UAAU,CAAC,MAAM,WAAW,cAAc,EAAE,SAAS,OAAO,EAAE,OAAO,KAAK,EAAE,CAAC;AAAA,UAC7E,WAAU;AAAA;AAAA,MACZ;AAAA,MACA,6CAAC,YAAO,MAAK,UAAS,WAAW,KAAK,QAAQ,YAAY,GAAG,gBAAc,QAAQ,cAAc,SAAS,MAAM,WAAW,cAAc,EAAE,cAAc,CAAC,QAAQ,aAAa,CAAC,GAAG,2BAEnL;AAAA,MACA,6CAAC,YAAO,MAAK,UAAS,WAAW,KAAK,QAAQ,OAAO,GAAG,gBAAc,QAAQ,SAAS,SAAS,MAAM,WAAW,cAAc,EAAE,SAAS,CAAC,QAAQ,QAAQ,CAAC,GAAG,0BAE/J;AAAA,MACA,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,SAAS,MAAM,WAAW,kBAAkB,GAAG,4BAExF;AAAA,OACF;AAAA,IAEF,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,SAAS,MAAM,OAAO,SAAS,MAAM,GAAG,6BAEjF;AAAA,IACA,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,OAAM,6CAA4C,SAAS,MAAM,WAAW,QAAQ,MAAM,SAAS,UAAU,SAAS,OAAO,GACnK,gBAAM,SAAS,UAAU,iBAAiB,eAC7C;AAAA,IACA,6CAAC,UAAK,WAAU,8BAA6B;AAAA,IAC7C,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,SAAS,MAAM,QAAQ,UAAM,oCAAc,KAAK,UAAU,WAAW,OAAO,CAAC,GAAG,GAAG,QAAQ,eAAe,kBAAkB,CAAC,GAAG,kBAEzK;AAAA,IACA,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,SAAS,MAAM,QAAQ,SAAS,MAAM,GAAG,wBAElF;AAAA,IACA,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,SAAS,MAAM,YAAY,WAAW,GAAG,iBAElF;AAAA,IACA,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,SAAS,MAAM,YAAY,YAAY,GAAG,kBAEnF;AAAA,IACA,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,SAAS,MAAM,QAAQ,UAAM,oCAAc,WAAW,UAAU,EAAE,OAAO,GAAG,QAAQ,QAAQ,2BAA2B,CAAC,GAAG,iBAEpK;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,MAAK;AAAA,QACL,QAAO;AAAA,QACP,cAAW;AAAA,QACX,WAAU;AAAA,QACV,UAAU,CAAC,MAAM;AACf,gBAAM,IAAI,EAAE,OAAO,QAAQ,CAAC;AAC5B,cAAI,EAAG,SAAQ,YAAY,WAAW,SAAS,KAAK,MAAM,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;AAC1E,YAAE,OAAO,QAAQ;AAAA,QACnB;AAAA;AAAA,IACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,MAAK;AAAA,QACL,QAAO;AAAA,QACP,cAAW;AAAA,QACX,WAAU;AAAA,QACV,UAAU,CAAC,MAAM;AACf,gBAAM,IAAI,EAAE,OAAO,QAAQ,CAAC;AAC5B,cAAI,EAAG,SAAQ,YAAY,WAAW,gBAAgB,EAAE,QAAQ,UAAM,sCAAgB,CAAC,EAAE,CAAC,CAAC;AAC3F,YAAE,OAAO,QAAQ;AAAA,QACnB;AAAA;AAAA,IACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,MAAK;AAAA,QACL,QAAO;AAAA,QACP,cAAW;AAAA,QACX,WAAU;AAAA,QACV,UAAU,CAAC,MAAM;AACf,gBAAM,IAAI,EAAE,OAAO,QAAQ,CAAC;AAC5B,cAAI,EAAG,SAAQ,YAAY,WAAW,kBAAkB,EAAE,QAAQ,UAAM,sCAAgB,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,CAAC;AAC3G,YAAE,OAAO,QAAQ;AAAA,QACnB;AAAA;AAAA,IACF;AAAA,IACA,6CAAC,aAAU,OAAc;AAAA,KAC3B;AAEJ;;;AE5MA,IAAAC,gBAAiD;AACjD,IAAAC,uBAAmI;AAqCzH,IAAAC,sBAAA;AAnBH,IAAM,aAAwC,CAAC,EAAE,YAAY,iBAAiB,KAAK,kBAAkB,IAAI,UAAU,MAAM;AAC9H,QAAM,QAAQ,oBAAoB,UAAU;AAC5C,QAAM,CAAC,OAAO,OAAO,IAAI,WAAW;AACpC,QAAM,CAAC,UAAU,WAAW,QAAI,wBAAS,EAAE;AAC3C,QAAM,cAAU,sBAAyB,IAAI;AAC7C,QAAM,EAAE,OAAO,QAAQ,IAAI;AAC3B,QAAM,QAAQ,MAAM,SAAS;AAC7B,QAAM,aAAS;AAAA,IACb,MAAM,IAAI,IAAI,QAAQ,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,WAAW,eAAe,EAAE,IAAI,EAAE,OAAO,gBAAgB,QAAQ,iBAAiB,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC;AAAA;AAAA;AAAA,IAG/I,CAAC,YAAY,SAAS,OAAO,gBAAgB,eAAe;AAAA,EAC9D;AACA,QAAM,OAAO,CAAC,SAAiB,KAAK,YAAY,EAAE,QAAQ,eAAe,GAAG,EAAE,QAAQ,YAAY,EAAE,EAAE,MAAM,GAAG,EAAE,KAAK;AAEtH,SACE,8CAAC,SAAI,WAAW,GAAG,KAAK,IAAI,aAAa,EAAE,IAAI,eAAY,eACzD;AAAA,iDAAC,SAAI,WAAU,0BAAyB,MAAK,WAAU,cAAW,WAC/D,kBAAQ,IAAI,CAAC,MACZ;AAAA,MAAC;AAAA;AAAA,QAEC,MAAK;AAAA,QACL,MAAK;AAAA,QACL,iBAAe,MAAM,OAAO,EAAE;AAAA,QAC9B,OAAO,GAAG,EAAE,IAAI,KAAK,EAAE,QAAQ;AAAA,QAC/B,WAAW,2DAA2D,MAAM,OAAO,EAAE,KAAK,4CAA4C,iCAAiC;AAAA,QACvK,SAAS,MAAM,WAAW,SAAS,EAAE,IAAI,EAAE,GAAG,CAAC;AAAA,QAE/C;AAAA,uDAAC,eAAY,QAAQ,OAAO,IAAI,EAAE,EAAE,KAAK,MAAM,OAAO,GAAG,EAAE,IAAI,cAAc,WAAU,WAAU,OAAO,EAAE,OAAO,QAAQ,aAAa,GAAG,cAAc,MAAM,eAAe,GAAG,GAAG;AAAA,UAClL,6CAAC,UAAK,WAAU,uCAAuC,YAAE,MAAK;AAAA;AAAA;AAAA,MATzD,EAAE;AAAA,IAUT,CACD,GACH;AAAA,IACA,8CAAC,SAAI,WAAU,yBACZ;AAAA,yCAAc,IAAI,CAAC,MAClB,6CAAC,eAAyB,SAAS,GAAG,WAAO,+BAAS,OAAO,EAAE,IAAI,GAAG,UAAU,CAAC,MAAM,WAAW,aAAS,gCAAU,OAAgB,EAAE,MAAM,CAAC,CAAU,KAAtI,EAAE,IAAuI,CAC5J;AAAA,MACD,8CAAC,WAAM,WAAU,2CACf;AAAA,qDAAC,UAAK,WAAU,kBAAiB,sBAAQ;AAAA,QACzC,6CAAC,YAAO,cAAW,kBAAiB,OAAO,MAAM,UAAU,UAAU,CAAC,MAAM,WAAW,SAAS,EAAE,UAAU,EAAE,OAAO,MAAuB,CAAC,GAAG,WAAU,oCACvJ,+CAAgB,IAAI,CAAC,MACpB,6CAAC,YAAe,OAAO,GACpB,gBAAM,WAAW,kBAAkB,MAAM,WAAW,eAAe,WADzD,CAEb,CACD,GACH;AAAA,SACF;AAAA,MACA,8CAAC,WAAM,WAAU,2BACf;AAAA,qDAAC,WAAM,MAAK,YAAW,SAAS,MAAM,IAAI,cAAc,UAAU,CAAC,MAAM,WAAW,SAAS,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,QAAQ,EAAE,CAAC,GAAG;AAAA,QAAE;AAAA,SAC/I;AAAA,MACA,8CAAC,WAAM,WAAU,2BACf;AAAA,qDAAC,WAAM,MAAK,YAAW,SAAS,MAAM,IAAI,iBAAiB,UAAU,CAAC,MAAM,WAAW,SAAS,EAAE,KAAK,EAAE,iBAAiB,EAAE,OAAO,QAAQ,EAAE,CAAC,GAAG;AAAA,QAAE;AAAA,SACrJ;AAAA,OACF;AAAA,IACA,8CAAC,SAAI,WAAU,qCACb;AAAA,mDAAC,WAAM,OAAO,UAAU,aAAY,cAAa,cAAW,cAAa,UAAU,CAAC,MAAM,YAAY,EAAE,OAAO,KAAK,GAAG,WAAU,2CAA0C;AAAA,MAC3K,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,UAAU,CAAC,SAAS,KAAK,GAAG,SAAS,MAAM,QAAQ,OAAO,WAAW,UAAU,EAAE,IAAI,KAAK,QAAQ,GAAG,MAAM,SAAS,KAAK,EAAE,CAAC,GAAG,YAAY,EAAE,EAAE,GAAG,wBAE3L;AAAA,MACA,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,SAAS,MAAM,QAAQ,UAAM,oCAAc,KAAK,UAAU,WAAW,cAAc,GAAG,MAAM,CAAC,GAAG,gBAAgB,kBAAkB,CAAC,GAAG,oBAE/K;AAAA,MACA,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,SAAS,MAAM,QAAQ,SAAS,MAAM,GAAG,0BAElF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL,MAAK;AAAA,UACL,QAAO;AAAA,UACP,cAAW;AAAA,UACX,WAAU;AAAA,UACV,UAAU,CAAC,MAAM;AACf,kBAAM,IAAI,EAAE,OAAO,QAAQ,CAAC;AAC5B,gBAAI,EAAG,SAAQ,YAAY,WAAW,cAAc,KAAK,MAAM,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;AAC/E,cAAE,OAAO,QAAQ;AAAA,UACnB;AAAA;AAAA,MACF;AAAA,OACF;AAAA,IACA,6CAAC,aAAU,OAAc;AAAA,KAC3B;AAEJ;;;ACpGA,IAAAC,gBAA+B;AAC/B,IAAAC,uBAA2H;AAyBnH,IAAAC,sBAAA;AAhBR,IAAM,SAAS,EAAE,GAAG,GAAG,GAAG,GAAG,OAAO,IAAI,QAAQ,GAAG;AAO5C,IAAM,aAAwC,CAAC,EAAE,YAAY,UAAU,MAAM;AAClF,QAAM,QAAQ,oBAAoB,UAAU;AAC5C,QAAM,CAAC,OAAO,OAAO,IAAI,WAAW;AACpC,QAAM,QAAQ,MAAM,SAAS;AAC7B,QAAM,eAAW,uBAAQ,MAAM,IAAI,IAAI,mCAAc,IAAI,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,GAAG,QAAQ,UAAM,kCAAY,EAAE,GAAG,GAAG,SAAS,KAAK,IAAI,KAAK,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAEvK,SACE,8CAAC,SAAI,WAAW,GAAG,KAAK,IAAI,aAAa,EAAE,IAAI,eAAY,eACxD;AAAA,wCAAe,IAAI,CAAC,WACnB,8CAAC,SACC;AAAA,mDAAC,SAAI,WAAU,6DAA6D,kBAAO;AAAA,MACnF,6CAAC,SAAI,WAAU,wBAAuB,MAAK,WAAU,cAAY,GAAG,MAAM,WACvE,6CAAc,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM,EAAE,IAAI,CAAC,MACrD;AAAA,QAAC;AAAA;AAAA,UAEC,MAAK;AAAA,UACL,MAAK;AAAA,UACL,iBAAe,MAAM,WAAW,EAAE;AAAA,UAClC,OAAO,EAAE;AAAA,UACT,WAAW,iBAAiB,MAAM,WAAW,EAAE,SAAS,2BAA2B,4CAA4C;AAAA,UAC/H,SAAS,MAAM,QAAQ,MAAM,WAAW,SAAS,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AAAA,UAEtE,uDAAC,eAAY,QAAQ,SAAS,IAAI,EAAE,MAAM,KAAK,MAAM,OAAO,EAAE,MAAM,OAAO,EAAE,OAAO,IAAI,QAAQ,GAAG,GAAG;AAAA;AAAA,QARjG,EAAE;AAAA,MAST,CACD,GACH;AAAA,SAhBQ,MAiBV,CACD;AAAA,IACD,6CAAC,SAAI,WAAU,kBAAkB,gBAAM,MAAK;AAAA,IAC5C,8CAAC,WAAM,WAAU,qCACf;AAAA,mDAAC,UAAK,WAAU,kBAAiB,oBAAM;AAAA,MACvC,6CAAC,oBAAiB,OAAM,gBAAe,OAAO,MAAM,OAAO,UAAU,CAAC,MAAM,QAAQ,MAAM,WAAW,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC,GAAG,WAAU,mCAAkC;AAAA,OAC5K;AAAA,IACC,mCAAc,IAAI,CAAC,MAClB,6CAAC,eAAyB,SAAS,GAAG,WAAO,+BAAS,OAAO,EAAE,IAAI,GAAG,UAAU,CAAC,MAAM,QAAQ,MAAM,WAAW,aAAS,gCAAU,OAAgB,EAAE,MAAM,CAAC,CAAU,CAAC,KAArJ,EAAE,IAAsJ,CAC3K;AAAA,IACD,8CAAC,WAAM,WAAU,2BACf;AAAA,mDAAC,WAAM,MAAK,YAAW,SAAS,MAAM,WAAW,UAAU,UAAU,CAAC,MAAM,QAAQ,MAAM,WAAW,SAAS,EAAE,QAAQ,EAAE,OAAO,UAAU,WAAW,SAAS,CAAC,CAAC,GAAG;AAAA,MAAE;AAAA,OACxK;AAAA,IACA,6CAAC,YAAO,MAAK,UAAS,WAAU,2FAA0F,SAAS,MAAM,QAAQ,MAAM,WAAW,SAAS,EAAE,MAAM,MAAM,OAAO,EAAE,CAAC,CAAC,GAAG,uBAEvM;AAAA,IACA,6CAAC,aAAU,OAAc;AAAA,KAC3B;AAEJ;;;AC9DA,IAAAC,gBAAiD;AACjD,IAAAC,uBAeO;AAgDD,IAAAC,sBAAA;AA5BC,IAAM,aAAwC,CAAC,EAAE,YAAY,YAAY,KAAK,YAAY,MAAM,UAAU,MAAM;AACrH,QAAM,QAAQ,oBAAoB,UAAU;AAC5C,QAAM,CAAC,OAAO,OAAO,IAAI,WAAW;AACpC,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAqB,KAAK;AACpD,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAsB,eAAe;AAC7D,QAAM,CAAC,SAAS,UAAU,QAAI,wBAAkB,OAAO;AACvD,QAAM,gBAAY,sBAAkE,IAAI;AACxF,QAAM,WAAO,uBAAQ,UAAM,uCAAiB,WAAW,KAAK,GAAG,CAAC,WAAW,KAAK,CAAC;AACjF,QAAM,QAAQ,MAAM;AACpB,QAAM,cAAU,uBAAQ,MAAM,WAAW,QAAQ,MAAM,EAAE,OAAO,MAAM,CAAC,GAAG,CAAC,YAAY,MAAM,OAAO,KAAK,CAAC;AAC1G,QAAM,CAAC,GAAG,GAAG,CAAC,QAAI,oCAAc,KAAK;AACrC,QAAM,UAAM,+BAAS,GAAG,GAAG,CAAC;AAC5B,QAAM,UAAM,uBAAQ,OAAO,EAAE,OAAO,uCAAkB,QAAQ,wCAAmB,MAAM,WAAW,UAAU,OAAO,EAAE,IAAI,CAAC,YAAY,MAAM,gBAAgB,CAAC;AAC7J,QAAM,IAAI,YAAY;AACtB,QAAM,MAAM,IAAI;AAChB,QAAM,SAAS,CAAC,GAAW,MAAc,WAAW,aAAS,oCAAc,OAAG,+BAAS,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC;AAEpG,QAAM,WAAW,CAAC,MAA0B;AAC1C,UAAM,OAAQ,EAAE,cAA8B,sBAAsB;AACpE,UAAM,KAAK,yCAAoB,KAAK,SAAS;AAC7C,UAAM,KAAK,0CAAqB,KAAK,UAAU;AAC/C,UAAM,IAAI,KAAK,IAAI,uCAAkB,KAAK,IAAI,IAAI,EAAE,UAAU,KAAK,QAAQ,EAAE,CAAC;AAC9E,UAAM,IAAI,KAAK,IAAI,wCAAmB,KAAK,IAAI,IAAI,EAAE,UAAU,KAAK,OAAO,EAAE,CAAC;AAC9E,WAAO,EAAE,gBAAgB,SAAS,EAAE,WAAW,IAAI,EAAE,GAAG,GAAG,UAAU,EAAE,SAAS,IAAI,EAAE,GAAG,EAAE;AAAA,EAC7F;AAEA,SACE,8CAAC,SAAI,WAAW,GAAG,KAAK,IAAI,aAAa,EAAE,IAAI,eAAY,eACzD;AAAA,kDAAC,SAAI,WAAU,wBAAuB,OAAO,EAAE,OAAO,WAAW,QAAQ,UAAU,GACjF;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,cAAW;AAAA,UACX,iBAAe;AAAA,UACf,iBAAe;AAAA,UACf,iBAAe,KAAK,UAAM,iCAAW,IAAI,GAAG,KAAK,CAAC;AAAA,UAClD,UAAU;AAAA,UACV,WAAU;AAAA,UACV,eAAe,CAAC,MAAM;AACpB,kBAAM,OAAO,EAAE,cAAc,sBAAsB;AACnD,uBAAW,aAAS,gCAAU,EAAE,UAAU,KAAK,OAAO,GAAG,EAAE,UAAU,KAAK,MAAM,GAAG,OAAO,KAAK,CAAC;AAAA,UAClG;AAAA,UAEA,uDAAC,eAAY,QAAQ,MAAM,OAAM,gBAAe,OAAO,EAAE,OAAO,WAAW,QAAQ,UAAU,GAAG;AAAA;AAAA,MAClG;AAAA,MACA,6CAAC,SAAI,WAAU,wCAAuC,OAAO,WAAW,QAAQ,WAAW,eAAY,QACpG,kBAAQ,IAAI,CAAC,GAAG,MAAM;AACrB,cAAM,QAAI,iCAAW,EAAE,OAAO,GAAG;AACjC,eAAO,6CAAC,YAAe,IAAI,IAAI,EAAE,GAAG,IAAI,IAAI,EAAE,GAAG,GAAG,MAAM,IAAI,IAAI,GAAG,MAAM,EAAE,OAAO,QAAO,QAAO,aAAa,MAAM,IAAI,IAAI,KAAzG,CAA4G;AAAA,MAClI,CAAC,GACH;AAAA,MACA,6CAAC,SAAI,WAAU,iDAAgD,OAAO,EAAE,MAAM,IAAI,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,YAAY,MAAM,GAAG;AAAA,OACvK;AAAA,IACA,8CAAC,SAAI,WAAU,2BACb;AAAA,mDAAC,WAAM,MAAK,SAAQ,cAAW,gBAAe,OAAO,OAAO,UAAU,CAAC,MAAM,WAAW,SAAS,EAAE,OAAO,KAAK,GAAG,WAAU,kCAAiC;AAAA,MAC7J,6CAAC,WAAM,MAAK,SAAQ,cAAW,iBAAgB,OAAO,MAAM,gBAAgB,UAAU,CAAC,MAAM,WAAW,kBAAkB,EAAE,OAAO,KAAK,GAAG,WAAU,kCAAiC;AAAA,MACtL,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,OAAM,oBAAmB,SAAS,MAAM,WAAW,WAAW,GAAG,kBAE1G;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,cAAW;AAAA,UACX,cAAc;AAAA,UAEd,QAAQ,CAAC,MAAM,QAAQ,MAAM,WAAW,SAAS,EAAE,OAAO,MAAM,WAAW,GAAG,IAAI,EAAE,OAAO,QAAQ,IAAI,EAAE,OAAO,KAAK,EAAE,CAAC;AAAA,UACxH,WAAU;AAAA;AAAA,QAFL;AAAA,MAGP;AAAA,OACF;AAAA,IACA,8CAAC,WAAM,WAAU,2BACf;AAAA,mDAAC,UAAK,WAAU,uBAAsB,wBAAU;AAAA,MAChD,6CAAC,WAAM,MAAK,SAAQ,cAAW,cAAa,KAAK,GAAG,KAAK,GAAG,MAAM,MAAM,OAAO,IAAI,GAAG,UAAU,CAAC,MAAM,OAAO,OAAO,EAAE,OAAO,KAAK,GAAG,IAAI,CAAC,GAAG,WAAU,4BAA2B;AAAA,OACrL;AAAA,IACA,8CAAC,WAAM,WAAU,2BACf;AAAA,mDAAC,UAAK,WAAU,uBAAsB,mBAAK;AAAA,MAC3C,6CAAC,WAAM,MAAK,SAAQ,cAAW,SAAQ,KAAK,GAAG,KAAK,GAAG,MAAM,MAAM,OAAO,IAAI,GAAG,UAAU,CAAC,MAAM,OAAO,IAAI,GAAG,OAAO,EAAE,OAAO,KAAK,CAAC,GAAG,WAAU,4BAA2B;AAAA,OAChL;AAAA,IACA,8CAAC,SAAI,WAAU,2BACb;AAAA,mDAAC,YAAO,cAAW,WAAU,OAAO,MAAM,UAAU,CAAC,MAAM,QAAQ,EAAE,OAAO,KAAoB,GAAG,WAAU,oCAC1G,6CAAc,IAAI,CAAC,MAClB,6CAAC,YAAe,OAAO,GACpB,eADU,CAEb,CACD,GACH;AAAA,MACA,6CAAC,YAAO,MAAK,UAAS,WAAW,KAAK,UAAU,KAAK,GAAG,gBAAc,UAAU,OAAO,SAAS,MAAM,SAAS,KAAK,GAAG,iBAEvH;AAAA,MACA,6CAAC,YAAO,MAAK,UAAS,WAAW,KAAK,UAAU,KAAK,GAAG,gBAAc,UAAU,OAAO,SAAS,MAAM,SAAS,KAAK,GAAG,iBAEvH;AAAA,OACF;AAAA,IACA,8CAAC,SAAI,WAAU,wBAAuB,cAAW,mBAC9C;AAAA,cAAQ,IAAI,CAAC,GAAG,MACf,6CAAC,YAAe,MAAK,UAAS,cAAY,OAAO,EAAE,KAAK,IAAI,OAAO,EAAE,OAAO,WAAU,yCAAwC,OAAO,EAAE,YAAY,EAAE,MAAM,GAAG,SAAS,MAAM,WAAW,SAAS,EAAE,KAAK,KAA3L,CAA8L,CAC5M;AAAA,MACD,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,SAAS,MAAM,QAAQ,QAAQ,CAAC,MAAM,WAAW,UAAU,EAAE,KAAK,CAAC,GAAG,wBAE/G;AAAA,OACF;AAAA,IACA,8CAAC,SAAI,WAAU,wBAAuB,MAAK,WAAU,cAAW,YAC7D;AAAA,YAAM,SAAS,IAAI,CAAC,GAAG,MACtB;AAAA,QAAC;AAAA;AAAA,UAEC,MAAK;AAAA,UACL,MAAK;AAAA,UACL,iBAAe,EAAE,UAAU;AAAA,UAC3B,cAAY,EAAE,QAAQ,EAAE;AAAA,UACxB,OAAO,GAAG,EAAE,QAAQ,EAAE,KAAK;AAAA,UAC3B,WAAU;AAAA,UACV,OAAO,EAAE,YAAY,EAAE,MAAM;AAAA,UAC7B,SAAS,MAAM,WAAW,SAAS,EAAE,KAAK;AAAA,UAC1C,eAAe,CAAC,MAAM;AACpB,cAAE,eAAe;AACjB,uBAAW,aAAa,CAAC;AAAA,UAC3B;AAAA;AAAA,QAZK;AAAA,MAaP,CACD;AAAA,MACD,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,cAAW,cAAa,SAAS,MAAM,WAAW,UAAU,KAAK,GAAG,eAE7G;AAAA,OACF;AAAA,IACC,aACC,8CAAC,SAAI,WAAU,uBAAsB,eAAY,cAC/C;AAAA,oDAAC,SAAI,WAAU,2BACb;AAAA,qDAAC,UAAK,WAAU,kBAAiB,wBAAU;AAAA,QACzC,CAAC,SAAS,SAAS,MAAM,EAAY,IAAI,CAAC,MAC1C,6CAAC,YAAe,MAAK,UAAS,gBAAc,YAAY,GAAG,WAAW,KAAK,YAAY,CAAC,GAAG,SAAS,MAAM,WAAW,CAAC,GACnH,gBAAM,UAAU,UAAU,MAAM,UAAU,UAAU,UAD1C,CAEb,CACD;AAAA,QACD,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,SAAS,MAAM,WAAW,eAAe,GAAG,mBAErF;AAAA,SACF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,cAAW;AAAA,UACX,WAAU;AAAA,UACV,eAAe,CAAC,MAAM;AACpB,kBAAM,IAAI,SAAS,CAAC;AACpB,gBAAI,YAAY,QAAQ;AACtB,sBAAQ,MAAM,WAAW,cAAc,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU,KAAK,CAAC,CAAC;AACpE;AAAA,YACF;AACA,sBAAU,UAAU,CAAC,CAAC;AACtB,YAAC,EAAE,OAAmB,oBAAoB,EAAE,SAAS;AAAA,UACvD;AAAA,UACA,eAAe,CAAC,MAAM,UAAU,SAAS,KAAK,SAAS,CAAC,CAAC;AAAA,UACzD,aAAa,MAAM;AACjB,kBAAM,MAAM,UAAU;AACtB,sBAAU,UAAU;AACpB,gBAAI,KAAK,OAAQ,SAAQ,MAAM,WAAW,gBAAgB,KAAK,EAAE,MAAM,YAAY,UAAU,UAAU,QAAQ,CAAC,CAAC;AAAA,UACnH;AAAA,UAEA,uDAAC,eAAY,QAAQ,KAAK,OAAM,qBAAoB,WAAU,kBAAiB,OAAO,EAAE,aAAa,GAAG,qCAAgB,MAAM,sCAAiB,GAAG,GAAG;AAAA;AAAA,MACvJ;AAAA,OACF;AAAA,IAEF,6CAAC,aAAU,OAAc;AAAA,KAC3B;AAEJ;;;ACnMA,IAAAC,gBAAgC;AAChC,IAAAC,uBAA6F;AAmCvF,IAAAC,sBAAA;AAzBN,SAAS,aAAa,QAA0B,GAAqD;AACnG,QAAM,OAAO,OAAO,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ;AACrE,SAAO,EAAE,OAAO,KAAK,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,KAAK,OAAO;AAC3E;AAOO,IAAM,mBAAoD,CAAC,EAAE,YAAY,UAAU,MAAM;AAC9F,sBAAoB,UAAU;AAC9B,QAAM,CAAC,OAAO,OAAO,IAAI,WAAW;AACpC,QAAM,CAAC,UAAU,WAAW,QAAI,wBAAwB,IAAI;AAC5D,QAAM,SAAS,WAAW,WAAW;AACrC,QAAM,SAAS,OAAO,KAAK,CAAC,MAAM,EAAE,MAAM,KAAK;AAC/C,QAAM,OAAO,CAAC,UAAkB;AAC9B,QAAI,CAAC,OAAQ;AACb,UAAM,EAAE,OAAO,MAAM,IAAI,aAAa,QAAQ,MAAM;AACpD,UAAM,KAAK,KAAK,IAAI,QAAQ,GAAG,KAAK,IAAI,GAAG,QAAQ,KAAK,CAAC;AACzD,QAAI,OAAO,MAAO,SAAQ,MAAM,WAAW,UAAU,OAAO,IAAI,EAAE,CAAC;AAAA,EACrE;AAEA,SACE,8CAAC,SAAI,WAAW,GAAG,KAAK,IAAI,aAAa,EAAE,IAAI,eAAY,sBACzD;AAAA,kDAAC,SAAI,WAAU,wBACb;AAAA,mDAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,SAAS,MAAM,QAAQ,MAAM,WAAW,SAAS,CAAC,GAAG,uBAE9F;AAAA,MACA,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,SAAS,MAAM,QAAQ,MAAM,WAAW,SAAS,EAAE,MAAM,QAAQ,CAAC,CAAC,GAAG,uBAE/G;AAAA,MACA,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,UAAU,CAAC,QAAQ,SAAS,MAAM,UAAU,QAAQ,MAAM,WAAW,eAAe,OAAO,EAAE,CAAC,GAAG,uBAE1I;AAAA,MACA,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,UAAU,CAAC,QAAQ,cAAW,iBAAgB,SAAS,MAAM,KAAK,CAAC,GAAG,oBAE/G;AAAA,MACA,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,UAAU,CAAC,QAAQ,cAAW,mBAAkB,SAAS,MAAM,KAAK,EAAE,GAAG,oBAElH;AAAA,MACA,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,UAAU,CAAC,QAAQ,SAAS,MAAM,UAAU,QAAQ,MAAM,WAAW,UAAU,OAAO,EAAE,CAAC,GAAG,wBAErI;AAAA,MACA,6CAAC,YAAO,MAAK,UAAS,WAAW,QAAQ,UAAU,CAAC,UAAU,OAAO,SAAS,GAAG,SAAS,MAAM,UAAU,QAAQ,MAAM,WAAW,YAAY,OAAO,EAAE,CAAC,GAAG,oBAE5J;AAAA,OACF;AAAA,IACA,6CAAC,QAAG,MAAK,QAAO,cAAW,UAAS,WAAU,yBAC3C,iBAAO,IAAI,CAAC,MACX;AAAA,MAAC;AAAA;AAAA,QAEC,MAAK;AAAA,QACL,iBAAe,EAAE;AAAA,QACjB,WAAW,gEAAgE,EAAE,SAAS,4CAA4C,oBAAoB;AAAA,QACtJ,OAAO,EAAE,aAAa,IAAI,EAAE,QAAQ,GAAG;AAAA,QACvC,SAAS,MAAM,WAAW,eAAe,EAAE,EAAE;AAAA,QAE7C;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,cAAY,EAAE,UAAU,QAAQ,EAAE,IAAI,KAAK,QAAQ,EAAE,IAAI;AAAA,cACzD,WAAW,mBAAmB,EAAE,UAAU,mBAAmB,gBAAgB;AAAA,cAC7E,SAAS,CAAC,MAAM;AACd,kBAAE,gBAAgB;AAClB,wBAAQ,MAAM,WAAW,YAAY,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,cACrE;AAAA,cAEC,YAAE,UAAU,WAAM;AAAA;AAAA,UACrB;AAAA,UACC,aAAa,EAAE,KACd;AAAA,YAAC;AAAA;AAAA,cACC,WAAS;AAAA,cACT,cAAW;AAAA,cACX,cAAc,EAAE;AAAA,cAChB,WAAU;AAAA,cACV,SAAS,CAAC,MAAM,EAAE,gBAAgB;AAAA,cAClC,QAAQ,CAAC,MAAM;AACb,4BAAY,IAAI;AAChB,oBAAI,EAAE,OAAO,MAAM,KAAK,KAAK,EAAE,OAAO,UAAU,EAAE,KAAM,SAAQ,MAAM,WAAW,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,MAAM,CAAC,CAAC;AAAA,cAC9H;AAAA,cACA,WAAW,CAAC,MAAM;AAChB,oBAAI,EAAE,QAAQ,QAAS,CAAC,EAAE,OAA4B,KAAK;AAC3D,oBAAI,EAAE,QAAQ,SAAU,aAAY,IAAI;AAAA,cAC1C;AAAA;AAAA,UACF,IAEA,8CAAC,UAAK,WAAU,mBAAkB,eAAe,MAAM,YAAY,EAAE,EAAE,GACpE;AAAA,cAAE,SAAS,UAAU,YAAO;AAAA,YAC5B,EAAE;AAAA,aACL;AAAA,UAED,EAAE,MAAM,UAAU,EAAE,MAAM,MAAM,6CAAC,UAAK,OAAM,UAAS,uBAAE,IAAU;AAAA;AAAA;AAAA,MAxC7D,EAAE;AAAA,IAyCT,CACD,GACH;AAAA,IACC,UACC,8CAAC,SAAI,WAAU,yBACb;AAAA,oDAAC,WAAM,WAAU,2BACf;AAAA,qDAAC,UAAK,WAAU,uBAAsB,qBAAO;AAAA,QAC7C;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,cAAW;AAAA,YACX,KAAK;AAAA,YACL,KAAK;AAAA,YACL,MAAM;AAAA,YACN,OAAO,OAAO;AAAA,YACd,UAAU,CAAC,MAAM,QAAQ,MAAM,WAAW,YAAY,OAAO,IAAI,EAAE,SAAS,OAAO,EAAE,OAAO,KAAK,EAAE,CAAC,CAAC;AAAA,YACrG,WAAU;AAAA;AAAA,QACZ;AAAA,SACF;AAAA,MACA,8CAAC,WAAM,WAAU,2BACf;AAAA,qDAAC,UAAK,WAAU,uBAAsB,mBAAK;AAAA,QAC3C,8CAAC,YAAO,cAAW,eAAc,OAAO,OAAO,OAAO,UAAU,CAAC,MAAM,QAAQ,MAAM,WAAW,YAAY,OAAO,IAAI,EAAE,OAAO,EAAE,OAAO,MAAmB,CAAC,CAAC,GAAG,WAAU,2CACxK;AAAA,iBAAO,SAAS,WAAW,6CAAC,YAAO,OAAM,gBAAe,0BAAY;AAAA,UACpE,iCAAY,IAAI,CAAC,MAChB,6CAAC,YAAkB,OAAO,EAAE,IACzB,YAAE,SADQ,EAAE,EAEf,CACD;AAAA,WACH;AAAA,SACF;AAAA,MACA,8CAAC,SAAI,WAAU,cACX;AAAA,SAAC,UAAU,cAAc,EAAY,IAAI,CAAC,MAC1C,6CAAC,YAAe,MAAK,UAAS,gBAAc,QAAQ,OAAO,MAAM,CAAC,CAAC,GAAG,WAAW,KAAK,QAAQ,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,SAAS,MAAM,QAAQ,MAAM,WAAW,YAAY,OAAO,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,GAClN,gBAAM,WAAW,gBAAgB,uBADvB,CAEb,CACD;AAAA,QACD,6CAAC,YAAO,MAAK,UAAS,gBAAc,OAAO,SAAS,WAAW,KAAK,OAAO,OAAO,GAAG,SAAS,MAAM,QAAQ,MAAM,WAAW,YAAY,OAAO,IAAI,EAAE,SAAS,CAAC,OAAO,QAAQ,CAAC,CAAC,GAAG,kBAEpL;AAAA,SACF;AAAA,OACF;AAAA,IAEF,6CAAC,aAAU,OAAc;AAAA,KAC3B;AAEJ;;;ACnJA,IAAAC,gBAAgC;AA+B1B,IAAAC,sBAAA;AANC,IAAM,cAA0C,CAAC,EAAE,YAAY,UAAU,SAAS,KAAK,UAAU,MAAM;AAC5G,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAoB,OAAO;AACnD,QAAM,CAAC,KAAK,MAAM,QAAI,wBAAkB,OAAO;AAC/C,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAwB,IAAI;AACtD,SACE,8CAAC,SAAI,WAAW,2EAA2E,aAAa,EAAE,IAAI,OAAO,EAAE,OAAO,GAAG,eAAY,gBAC3I;AAAA,iDAAC,gBAAa,YAAwB,MAAY,cAAc,SAAS,UAAoB;AAAA,IAC7F,8CAAC,SAAI,WAAU,6BACb;AAAA,mDAAC,cAAW,YAAwB,WAAU,sCAAqC;AAAA,MACnF,8CAAC,SAAI,WAAU,gCACb;AAAA,qDAAC,eAAY,YAAwB,MAAY,SAAS,UAAU,WAAU,qBAAoB;AAAA,QACjG,SACC,6CAAC,OAAE,MAAK,SAAQ,WAAU,kCACvB,iBACH;AAAA,SAEJ;AAAA,MACA,8CAAC,SAAI,WAAU,0DACb;AAAA,qDAAC,SAAI,WAAU,cAAa,MAAK,WAAU,cAAW,gBAClD,WAAC,SAAS,SAAS,QAAQ,EAAY,IAAI,CAAC,MAC5C,6CAAC,YAAe,MAAK,UAAS,MAAK,OAAM,iBAAe,QAAQ,GAAG,WAAW,KAAK,QAAQ,CAAC,GAAG,SAAS,MAAM,OAAO,CAAC,GACnH,gBAAM,UAAU,WAAW,MAAM,UAAU,UAAU,YAD3C,CAEb,CACD,GACH;AAAA,QACC,QAAQ,WAAW,6CAAC,cAAW,YAAwB;AAAA,QACvD,QAAQ,WAAW,6CAAC,cAAW,YAAwB;AAAA,QACvD,QAAQ,YAAY,6CAAC,oBAAiB,YAAwB;AAAA,SACjE;AAAA,OACF;AAAA,KACF;AAEJ;","names":["import_react","import_paint_editor","import_react","import_paint_editor","import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_paint_editor","import_jsx_runtime","import_react","import_paint_editor","import_jsx_runtime","import_react","import_paint_editor","import_jsx_runtime","import_react","import_paint_editor","import_jsx_runtime","import_react","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../../src/paint-editor/index.ts","../../src/paint-editor/usePaintEditor.ts","../../src/paint-editor/PaintCanvas.tsx","../../src/paint-editor/PaintToolbar.tsx","../../src/paint-editor/shared.tsx","../../src/paint-editor/BrushPanel.tsx","../../src/paint-editor/PaperPanel.tsx","../../src/paint-editor/ColorPanel.tsx","../../src/paint-editor/PaintLayersPanel.tsx","../../src/paint-editor/PaintEditor.tsx"],"sourcesContent":["export * from './usePaintEditor';\nexport * from './PaintCanvas';\nexport * from './PaintToolbar';\nexport * from './BrushPanel';\nexport * from './PaperPanel';\nexport * from './ColorPanel';\nexport * from './PaintLayersPanel';\nexport * from './PaintEditor';\nexport { PaintSlider } from './shared';\n","import { useMemo, useState, useSyncExternalStore } from 'react';\nimport { PaintEditorController, type PaintEditorOptions, type PaintEditorState } from '@pixerate/editor/paint-editor';\n\nexport interface UsePaintEditorReturn {\n controller: PaintEditorController;\n /** The controller's snapshot (a new object after every change). */\n state: PaintEditorState;\n}\n\n/**\n * Creates a `PaintEditorController` once (from `options`, read on the first render) or uses the\n * one given, and re-renders on every change.\n */\nexport function usePaintEditor(options: PaintEditorOptions | PaintEditorController = {}): UsePaintEditorReturn {\n const [controller] = useState(() => (options instanceof PaintEditorController ? options : new PaintEditorController(options)));\n const state = usePaintEditorState(controller);\n return useMemo(() => ({ controller, state }), [controller, state]);\n}\n\n/** Subscribes to a controller's state. */\nexport function usePaintEditorState(controller: PaintEditorController): PaintEditorState {\n return useSyncExternalStore(\n (notify) => controller.subscribe(notify),\n () => controller.getState(),\n () => controller.getState()\n );\n}\n","import React, { useEffect, useMemo, useRef, useState } from 'react';\nimport {\n PaintCanvasPresenter,\n PaintGesture,\n fitZoom,\n guideOverlay,\n handlePaintShortcut,\n viewCssTransform,\n type PaintEditorController,\n type PaintTool,\n} from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\n\nexport interface PaintCanvasProps {\n controller: PaintEditorController;\n /** The active tool (default brush). */\n tool?: PaintTool;\n /** Draw the symmetry axes and perspective lines (default true). */\n showGuides?: boolean;\n /** Fit the canvas in the viewport on mount (default true). */\n fitOnMount?: boolean;\n /** Called with a refusal (hidden or locked layer). */\n onError?: (message: string | null) => void;\n className?: string;\n}\n\n/**\n * The painting surface: a document-sized canvas the compositor draws into (only changed tiles are\n * uploaded), shown through the view's zoom, pan, rotation and mirroring as a CSS transform (the\n * pixels never resample). Pointer input goes through `PaintGesture`: coalesced samples, a predicted\n * tail drawn as a thin preview, palm rejection, middle-button pan, wheel zoom and Shift+wheel\n * rotation. Guides and floating reference images are drawn on top.\n */\nexport const PaintCanvas: React.FC<PaintCanvasProps> = ({ controller, tool = 'brush', showGuides = true, fitOnMount = true, onError, className }) => {\n const state = usePaintEditorState(controller);\n const viewport = useRef<HTMLDivElement>(null);\n const canvas = useRef<HTMLCanvasElement>(null);\n const [size, setSize] = useState({ width: 800, height: 600 });\n const measured = useRef(false);\n const [predicted, setPredicted] = useState<Array<{ x: number; y: number }>>([]);\n const presenter = useMemo(() => new PaintCanvasPresenter(controller), [controller]);\n const gesture = useMemo(\n () =>\n new PaintGesture(controller, () => {\n const r = viewport.current?.getBoundingClientRect();\n return { left: r?.left ?? 0, top: r?.top ?? 0, width: r?.width || size.width, height: r?.height || size.height };\n }),\n // The box reads the element when called; `size` is only the jsdom fallback.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [controller]\n );\n gesture.tool = tool;\n const { canvas: doc } = state.document;\n\n useEffect(() => {\n const el = viewport.current;\n if (!el || typeof ResizeObserver === 'undefined') return;\n const ro = new ResizeObserver(() => {\n if (!el.clientWidth || !el.clientHeight) return;\n measured.current = true;\n setSize({ width: el.clientWidth, height: el.clientHeight });\n });\n ro.observe(el);\n return () => ro.disconnect();\n }, []);\n\n // Fit once per canvas size, after the viewport has been measured (or at once where it cannot be).\n const fitted = useRef<string | null>(null);\n useEffect(() => {\n const key = `${doc.width}x${doc.height}`;\n if (!fitOnMount || fitted.current === key) return;\n if (typeof ResizeObserver !== 'undefined' && !measured.current) return;\n fitted.current = key;\n controller.setView({ zoom: fitZoom(doc, size), pan: { x: 0, y: 0 } });\n }, [controller, doc, size, fitOnMount]);\n\n // Upload changed tiles whenever the state changes.\n useEffect(() => {\n const ctx = canvas.current?.getContext('2d');\n if (ctx && typeof ctx.createImageData === 'function') presenter.render(ctx as never);\n else controller.takeDirty();\n }, [state, presenter, controller]);\n\n // Wheel needs a non-passive listener to prevent page scroll (see GOTCHAS).\n useEffect(() => {\n const el = viewport.current;\n if (!el) return;\n const onWheel = (e: WheelEvent) => {\n e.preventDefault();\n gesture.wheel(e);\n };\n el.addEventListener('wheel', onWheel, { passive: false });\n return () => el.removeEventListener('wheel', onWheel);\n }, [gesture]);\n\n const report = () => onError?.(gesture.error);\n const transform = viewCssTransform(state.view, doc, size);\n const lines = showGuides ? guideOverlay(controller) : [];\n\n return (\n <div\n ref={viewport}\n tabIndex={0}\n role=\"application\"\n aria-label=\"Paint canvas\"\n data-testid=\"paint-canvas\"\n className={`relative overflow-hidden bg-slate-950 outline-none touch-none select-none ${className ?? ''}`}\n style={{ cursor: tool === 'pan' ? 'grab' : tool === 'eyedropper' ? 'copy' : 'crosshair' }}\n onPointerDown={(e) => {\n viewport.current?.focus();\n if (gesture.down(e.nativeEvent)) (e.target as Element).setPointerCapture?.(e.pointerId);\n report();\n }}\n onPointerMove={(e) => {\n gesture.move(e.nativeEvent);\n if (gesture.predicted.length || predicted.length) setPredicted(gesture.predicted.map((p) => ({ x: p.x, y: p.y })));\n }}\n onPointerUp={(e) => {\n gesture.up(e.nativeEvent);\n setPredicted([]);\n }}\n onPointerCancel={() => {\n gesture.cancel();\n setPredicted([]);\n }}\n onKeyDown={(e) => {\n if (handlePaintShortcut(controller, gesture, e)) e.preventDefault();\n }}\n >\n <canvas\n ref={canvas}\n width={doc.width}\n height={doc.height}\n className=\"absolute left-0 top-0 shadow-2xl\"\n style={{ transform, transformOrigin: '0 0', imageRendering: state.view.zoom > 2 ? 'pixelated' : 'auto' }}\n />\n <svg className=\"absolute left-0 top-0 pointer-events-none overflow-visible\" width={doc.width} height={doc.height} style={{ transform, transformOrigin: '0 0' }} aria-hidden=\"true\">\n {lines.map((l, i) => (\n <line\n key={i}\n x1={l.from.x}\n y1={l.from.y}\n x2={l.to.x}\n y2={l.to.y}\n stroke={l.kind === 'symmetry' ? '#22d3ee' : '#f472b6'}\n strokeOpacity={l.kind === 'symmetry' ? 0.8 : 0.35}\n strokeWidth={1 / state.view.zoom}\n strokeDasharray={l.kind === 'symmetry' ? `${6 / state.view.zoom} ${4 / state.view.zoom}` : undefined}\n />\n ))}\n {predicted.length > 0 && (\n <polyline points={predicted.map((p) => `${p.x},${p.y}`).join(' ')} fill=\"none\" stroke={state.color} strokeOpacity={0.5} strokeWidth={Math.max(1, state.brush.tip.size / 2)} strokeLinecap=\"round\" />\n )}\n </svg>\n {state.guides.references\n .filter((r) => r.visible)\n .map((r) => (\n <ReferencePanel key={r.id} controller={controller} id={r.id} />\n ))}\n <div className=\"absolute bottom-1 right-2 text-[10px] text-slate-500 pointer-events-none\" data-testid=\"paint-view-status\">\n {Math.round(state.view.zoom * 100)}% · {Math.round(state.view.rotation)}°{state.view.mirror ? ' · mirrored' : ''}\n </div>\n </div>\n );\n};\n\n/** A floating reference image: drag its title bar to move it, click the image to pick a colour. */\nconst ReferencePanel: React.FC<{ controller: PaintEditorController; id: string }> = ({ controller, id }) => {\n const state = usePaintEditorState(controller);\n const ref = state.guides.references.find((r) => r.id === id);\n const drag = useRef<{ x: number; y: number; ox: number; oy: number } | null>(null);\n if (!ref) return null;\n const h = (ref.height / ref.width) * ref.displayWidth;\n return (\n <div\n className=\"absolute rounded border border-slate-700 bg-slate-900/95 shadow-xl\"\n style={{ left: ref.x, top: ref.y, width: ref.displayWidth }}\n data-testid=\"paint-reference\"\n onPointerDown={(e) => e.stopPropagation()}\n >\n <div\n className=\"flex items-center justify-between px-1.5 py-0.5 text-[10px] text-slate-300 cursor-move\"\n onPointerDown={(e) => {\n drag.current = { x: e.clientX, y: e.clientY, ox: ref.x, oy: ref.y };\n (e.target as Element).setPointerCapture?.(e.pointerId);\n }}\n onPointerMove={(e) => {\n const d = drag.current;\n if (d) controller.updateReferenceImage(id, { x: d.ox + e.clientX - d.x, y: d.oy + e.clientY - d.y });\n }}\n onPointerUp={() => (drag.current = null)}\n >\n <span className=\"truncate\">{ref.name}</span>\n <button type=\"button\" aria-label={`Hide ${ref.name}`} className=\"px-1 text-slate-400 hover:text-white\" onClick={() => controller.updateReferenceImage(id, { visible: false })}>\n ×\n </button>\n </div>\n <img\n src={ref.src}\n alt={ref.name}\n draggable={false}\n width={ref.displayWidth}\n height={h}\n className=\"block cursor-copy\"\n onClick={(e) => {\n const rect = (e.target as HTMLElement).getBoundingClientRect();\n const k = ref.width / (rect.width || ref.displayWidth);\n controller.setColor(controller.pickReferenceColor(id, Math.min(ref.width - 1, (e.clientX - rect.left) * k), Math.min(ref.height - 1, (e.clientY - rect.top) * k)));\n }}\n />\n </div>\n );\n};\n","import React, { useRef } from 'react';\nimport { PAINT_TOOLS, SYMMETRY_MODES, decodeImageBlob, downloadBytes, type PaintEditorController, type PaintTool, type SymmetryMode } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, button, chip, useAttempt } from './shared';\n\nexport interface PaintToolbarProps {\n controller: PaintEditorController;\n tool: PaintTool;\n onToolChange: (tool: PaintTool) => void;\n /** Base name of saved and exported files (default `painting`). */\n fileName?: string;\n className?: string;\n}\n\n/**\n * Tools (brush, eyedropper, pan, rotate view), undo / redo, view rotation, mirroring and reset,\n * the symmetry and perspective guides, the tracing image and reference images, the drawing hand,\n * and file actions: save / open JSON, export PNG, JPEG and PSD.\n */\nexport const PaintToolbar: React.FC<PaintToolbarProps> = ({ controller, tool, onToolChange, fileName = 'painting', className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const openRef = useRef<HTMLInputElement>(null);\n const tracingRef = useRef<HTMLInputElement>(null);\n const refRef = useRef<HTMLInputElement>(null);\n const { symmetry, perspective, tracing } = state.guides;\n const { canvas } = state.document;\n\n const exportImage = (format: 'image/png' | 'image/jpeg') =>\n attempt(async () => downloadBytes(await controller.exportImage({ format }), `${fileName}.${format === 'image/png' ? 'png' : 'jpg'}`, format));\n\n return (\n <div className={`flex flex-wrap items-center gap-1.5 text-xs text-slate-200 ${className ?? ''}`} role=\"toolbar\" aria-label=\"Paint toolbar\" data-testid=\"paint-toolbar\">\n {PAINT_TOOLS.map((t) => (\n <button key={t.id} type=\"button\" aria-pressed={tool === t.id} title={`${t.label} (${t.key.toUpperCase()})`} className={chip(tool === t.id)} onClick={() => onToolChange(t.id)}>\n {t.label}\n </button>\n ))}\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} disabled={!state.canUndo} title={state.undoLabel ? `Undo ${state.undoLabel}` : 'Undo'} onClick={() => controller.undo()}>\n Undo\n </button>\n <button type=\"button\" className={button} disabled={!state.canRedo} title={state.redoLabel ? `Redo ${state.redoLabel}` : 'Redo'} onClick={() => controller.redo()}>\n Redo\n </button>\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} aria-label=\"Rotate view left\" onClick={() => controller.setView({ rotation: state.view.rotation - 15 })}>\n ⟲\n </button>\n <button type=\"button\" className={button} aria-label=\"Rotate view right\" onClick={() => controller.setView({ rotation: state.view.rotation + 15 })}>\n ⟳\n </button>\n <button type=\"button\" className={chip(state.view.mirror)} aria-pressed={state.view.mirror} onClick={() => controller.setView({ mirror: !state.view.mirror })}>\n Mirror view\n </button>\n <button type=\"button\" className={button} onClick={() => controller.resetView()}>\n Reset view\n </button>\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <label className=\"flex items-center gap-1\">\n Symmetry\n <select\n aria-label=\"Symmetry\"\n value={symmetry.mode}\n onChange={(e) => controller.setSymmetry({ mode: e.target.value as SymmetryMode, center: symmetry.mode === 'off' ? { x: canvas.width / 2, y: canvas.height / 2 } : symmetry.center })}\n className=\"rounded bg-slate-800 px-1 py-0.5\"\n >\n {SYMMETRY_MODES.map((m) => (\n <option key={m} value={m}>\n {m}\n </option>\n ))}\n </select>\n </label>\n {symmetry.mode === 'kaleidoscope' && (\n <input\n type=\"number\"\n aria-label=\"Kaleidoscope segments\"\n min={2}\n max={32}\n value={symmetry.segments}\n onChange={(e) => controller.setSymmetry({ segments: Number(e.target.value) })}\n className=\"w-12 rounded bg-slate-800 px-1 py-0.5\"\n />\n )}\n <button\n type=\"button\"\n className={chip(perspective.enabled)}\n aria-pressed={perspective.enabled}\n onClick={() =>\n attempt(() =>\n controller.setPerspective(\n perspective.enabled ? { enabled: false } : { enabled: true, points: perspective.points.length ? perspective.points : [{ x: canvas.width / 2, y: canvas.height * 0.4 }] }\n )\n )\n }\n >\n Perspective\n </button>\n {perspective.enabled && (\n <select\n aria-label=\"Vanishing points\"\n value={perspective.points.length}\n onChange={(e) => {\n const n = Number(e.target.value);\n const y = canvas.height * 0.4;\n const pts = n === 1 ? [{ x: canvas.width / 2, y }] : n === 2 ? [{ x: -canvas.width * 0.5, y }, { x: canvas.width * 1.5, y }] : [{ x: -canvas.width * 0.5, y }, { x: canvas.width * 1.5, y }, { x: canvas.width / 2, y: canvas.height * 3 }];\n attempt(() => controller.setPerspective({ points: pts }));\n }}\n className=\"rounded bg-slate-800 px-1 py-0.5\"\n >\n <option value={1}>1-point</option>\n <option value={2}>2-point</option>\n <option value={3}>3-point</option>\n </select>\n )}\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} onClick={() => tracingRef.current?.click()}>\n Tracing image…\n </button>\n {tracing && (\n <>\n <input\n type=\"range\"\n aria-label=\"Tracing opacity\"\n min={0}\n max={1}\n step={0.05}\n value={tracing.opacity}\n onChange={(e) => controller.updateTracing({ opacity: Number(e.target.value) })}\n className=\"w-16 accent-indigo-500\"\n />\n <button type=\"button\" className={chip(tracing.sampleColors)} aria-pressed={tracing.sampleColors} onClick={() => controller.updateTracing({ sampleColors: !tracing.sampleColors })}>\n Trace colours\n </button>\n <button type=\"button\" className={chip(tracing.visible)} aria-pressed={tracing.visible} onClick={() => controller.updateTracing({ visible: !tracing.visible })}>\n Show tracing\n </button>\n <button type=\"button\" className={button} onClick={() => controller.clearTracingImage()}>\n Remove tracing\n </button>\n </>\n )}\n <button type=\"button\" className={button} onClick={() => refRef.current?.click()}>\n Reference…\n </button>\n <button type=\"button\" className={button} title=\"Which hand holds the pen (palm rejection)\" onClick={() => controller.setHand(state.hand === 'right' ? 'left' : 'right')}>\n {state.hand === 'right' ? 'Right-handed' : 'Left-handed'}\n </button>\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} onClick={() => attempt(() => downloadBytes(JSON.stringify(controller.toJSON()), `${fileName}.paint.json`, 'application/json'))}>\n Save\n </button>\n <button type=\"button\" className={button} onClick={() => openRef.current?.click()}>\n Open…\n </button>\n <button type=\"button\" className={button} onClick={() => exportImage('image/png')}>\n PNG\n </button>\n <button type=\"button\" className={button} onClick={() => exportImage('image/jpeg')}>\n JPEG\n </button>\n <button type=\"button\" className={button} onClick={() => attempt(() => downloadBytes(controller.exportPsd().bytes, `${fileName}.psd`, 'image/vnd.adobe.photoshop'))}>\n PSD\n </button>\n <input\n ref={openRef}\n type=\"file\"\n accept=\".json,application/json\"\n aria-label=\"Open painting\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.loadJSON(JSON.parse(await f.text())));\n e.target.value = '';\n }}\n />\n <input\n ref={tracingRef}\n type=\"file\"\n accept=\"image/*\"\n aria-label=\"Load tracing image\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.setTracingImage({ pixels: await decodeImageBlob(f) }));\n e.target.value = '';\n }}\n />\n <input\n ref={refRef}\n type=\"file\"\n accept=\"image/*\"\n aria-label=\"Add reference image\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.addReferenceImage({ pixels: await decodeImageBlob(f), name: f.name }));\n e.target.value = '';\n }}\n />\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useEffect, useRef, useState } from 'react';\nimport type { SliderControl } from '@pixerate/editor/paint-editor';\n\nexport const chip = (on: boolean) => `px-2 py-1 rounded text-[11px] ${on ? 'bg-indigo-600 text-white' : 'bg-slate-800 text-slate-300 hover:text-white'}`;\nexport const button = 'px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-200 hover:bg-slate-700 disabled:opacity-40';\nexport const panel = 'flex flex-col gap-2 text-xs text-slate-200';\n\n/** Draws RGBA pixels into a canvas (nothing without a 2D context, as in jsdom). */\nexport const PixelCanvas: React.FC<{ pixels: { width: number; height: number; data: Uint8ClampedArray } | null; label: string; className?: string; style?: React.CSSProperties }> = ({ pixels, label, className, style }) => {\n const ref = useRef<HTMLCanvasElement>(null);\n useEffect(() => {\n const canvas = ref.current;\n const ctx = canvas?.getContext('2d');\n if (!canvas || !ctx || !pixels || typeof ctx.createImageData !== 'function') return;\n canvas.width = pixels.width;\n canvas.height = pixels.height;\n const img = ctx.createImageData(pixels.width, pixels.height);\n img.data.set(pixels.data);\n ctx.putImageData(img, 0, 0);\n }, [pixels]);\n return <canvas ref={ref} role=\"img\" aria-label={label} className={className} style={style} width={pixels?.width} height={pixels?.height} />;\n};\n\nconst fmt = (c: SliderControl, v: number) => (c.step >= 1 ? String(Math.round(v)) : v.toFixed(2));\n\n/**\n * A labelled range input. `onChange` runs while dragging; `onCommit` (if given) runs once on\n * release (the native `change` event), for settings that are undo steps.\n */\nexport const PaintSlider: React.FC<{ control: SliderControl; value: number; onChange?: (v: number) => void; onCommit?: (v: number) => void }> = ({ control, value, onChange, onCommit }) => {\n const [draft, setDraft] = useState<number | null>(null);\n const ref = useRef<HTMLInputElement>(null);\n const commit = useRef(onCommit);\n commit.current = onCommit;\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const done = () => {\n commit.current?.(Number(el.value));\n setDraft(null);\n };\n el.addEventListener('change', done);\n return () => el.removeEventListener('change', done);\n }, []);\n const shown = draft ?? value;\n return (\n <label className=\"flex flex-col gap-0.5\" data-path={control.path}>\n <span className=\"flex justify-between text-slate-400\">\n <span>{control.label}</span>\n <span className=\"font-mono\">{fmt(control, shown)}</span>\n </span>\n <input\n ref={ref}\n type=\"range\"\n aria-label={control.label}\n min={control.min}\n max={control.max}\n step={control.step}\n value={shown}\n onChange={(e) => {\n const v = Number(e.target.value);\n if (onCommit) setDraft(v);\n onChange?.(v);\n }}\n className=\"w-full accent-indigo-500\"\n />\n </label>\n );\n};\n\n/** Runs `fn`, turning a thrown error into a message. */\nexport function useAttempt(): [string | null, (fn: () => unknown) => void, (msg: string | null) => void] {\n const [error, setError] = useState<string | null>(null);\n const attempt = (fn: () => unknown) => {\n try {\n setError(null);\n const r = fn();\n if (r && typeof (r as Promise<unknown>).catch === 'function') (r as Promise<unknown>).catch((e) => setError(e instanceof Error ? e.message : String(e)));\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n }\n };\n return [error, attempt, setError];\n}\n\nexport const ErrorLine: React.FC<{ error: string | null }> = ({ error }) =>\n error ? (\n <p role=\"alert\" className=\"text-[11px] text-rose-400\">\n {error}\n </p>\n ) : null;\n\n/** A colour input that commits once when the picker closes (the native `change` event). */\nexport const CommitColorInput: React.FC<{ value: string; label: string; onCommit: (v: string) => void; className?: string }> = ({ value, label, onCommit, className }) => {\n const ref = useRef<HTMLInputElement>(null);\n const commit = useRef(onCommit);\n commit.current = onCommit;\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const done = () => commit.current(el.value);\n el.addEventListener('change', done);\n return () => el.removeEventListener('change', done);\n }, []);\n return <input ref={ref} type=\"color\" aria-label={label} defaultValue={value} key={value} className={className} />;\n};\n","import React, { useMemo, useRef, useState } from 'react';\nimport { BRUSH_ROTATIONS, BRUSH_SLIDERS, downloadBytes, patchPath, readPath, type BrushRotation, type PaintEditorController } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, PaintSlider, PixelCanvas, button, panel, useAttempt } from './shared';\n\nexport interface BrushPanelProps {\n controller: PaintEditorController;\n /** Thumbnail size in px (default 112 × 32). */\n thumbnailWidth?: number;\n thumbnailHeight?: number;\n className?: string;\n}\n\n/**\n * The brush library (thumbnails rendered from a test stroke on the current paper, grouped by\n * category) and the active brush's settings: size, opacity, flow, hardness, spacing, roundness,\n * angle, paper grain, position and pressure smoothing, dynamics and rotation mode. Save the edited\n * brush, import and export libraries as JSON.\n */\nexport const BrushPanel: React.FC<BrushPanelProps> = ({ controller, thumbnailWidth = 112, thumbnailHeight = 32, className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const [saveName, setSaveName] = useState('');\n const fileRef = useRef<HTMLInputElement>(null);\n const { brush, brushes } = state;\n const paper = state.document.paper;\n const thumbs = useMemo(\n () => new Map(brushes.map((b) => [b.id, controller.brushThumbnail(b.id, { width: thumbnailWidth, height: thumbnailHeight, color: '#26324a' })])),\n // Thumbnails follow the library and the paper.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [controller, brushes, paper, thumbnailWidth, thumbnailHeight]\n );\n const slug = (name: string) => name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 60) || 'brush';\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"brush-panel\">\n <div className=\"grid grid-cols-2 gap-1\" role=\"listbox\" aria-label=\"Brushes\">\n {brushes.map((b) => (\n <button\n key={b.id}\n type=\"button\"\n role=\"option\"\n aria-selected={brush.id === b.id}\n title={`${b.name} (${b.category})`}\n className={`flex flex-col items-start gap-0.5 rounded p-1 text-left ${brush.id === b.id ? 'bg-indigo-600/30 ring-1 ring-indigo-500' : 'bg-slate-900 hover:bg-slate-800'}`}\n onClick={() => controller.setBrush({ id: b.id })}\n >\n <PixelCanvas pixels={thumbs.get(b.id) ?? null} label={`${b.name} thumbnail`} className=\"rounded\" style={{ width: '100%', aspectRatio: `${thumbnailWidth} / ${thumbnailHeight}` }} />\n <span className=\"truncate text-[10px] text-slate-300\">{b.name}</span>\n </button>\n ))}\n </div>\n <div className=\"flex flex-col gap-1.5\">\n {BRUSH_SLIDERS.map((c) => (\n <PaintSlider key={c.path} control={c} value={readPath(brush, c.path)} onChange={(v) => controller.setBrush(patchPath(brush as never, c.path, v) as never)} />\n ))}\n <label className=\"flex items-center justify-between gap-2\">\n <span className=\"text-slate-400\">Rotation</span>\n <select aria-label=\"Brush rotation\" value={brush.rotation} onChange={(e) => controller.setBrush({ rotation: e.target.value as BrushRotation })} className=\"rounded bg-slate-800 px-1 py-0.5\">\n {BRUSH_ROTATIONS.map((r) => (\n <option key={r} value={r}>\n {r === 'stroke' ? 'Follow stroke' : r === 'barrel' ? 'Pen barrel' : 'Fixed'}\n </option>\n ))}\n </select>\n </label>\n <label className=\"flex items-center gap-2\">\n <input type=\"checkbox\" checked={brush.tip.pressureSize} onChange={(e) => controller.setBrush({ tip: { pressureSize: e.target.checked } })} /> Pressure → size\n </label>\n <label className=\"flex items-center gap-2\">\n <input type=\"checkbox\" checked={brush.tip.pressureOpacity} onChange={(e) => controller.setBrush({ tip: { pressureOpacity: e.target.checked } })} /> Pressure → opacity\n </label>\n </div>\n <div className=\"flex flex-wrap items-center gap-1\">\n <input value={saveName} placeholder=\"Brush name\" aria-label=\"Brush name\" onChange={(e) => setSaveName(e.target.value)} className=\"w-28 rounded bg-slate-800 px-1.5 py-0.5\" />\n <button type=\"button\" className={button} disabled={!saveName.trim()} onClick={() => attempt(() => (controller.saveBrush({ id: slug(saveName), name: saveName.trim() }), setSaveName('')))}>\n Save brush\n </button>\n <button type=\"button\" className={button} onClick={() => attempt(() => downloadBytes(JSON.stringify(controller.exportBrushes(), null, 2), 'brushes.json', 'application/json'))}>\n Export\n </button>\n <button type=\"button\" className={button} onClick={() => fileRef.current?.click()}>\n Import…\n </button>\n <input\n ref={fileRef}\n type=\"file\"\n accept=\".json,application/json\"\n aria-label=\"Import brushes\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.importBrushes(JSON.parse(await f.text())));\n e.target.value = '';\n }}\n />\n </div>\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useMemo } from 'react';\nimport { PAPER_FAMILIES, PAPER_LIBRARY, PAPER_SLIDERS, patchPath, readPath, renderPaper, type PaintEditorController } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { CommitColorInput, ErrorLine, PaintSlider, PixelCanvas, panel, useAttempt } from './shared';\n\nexport interface PaperPanelProps {\n controller: PaintEditorController;\n className?: string;\n}\n\nconst SWATCH = { x: 0, y: 0, width: 64, height: 40 };\n\n/**\n * The paper library by family (each a generated grain preview) and the current paper's colour,\n * grain depth, scale, shading and contrast, plus the wet-media properties stored for later.\n * Each change is one undo step (sliders commit on release).\n */\nexport const PaperPanel: React.FC<PaperPanelProps> = ({ controller, className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const paper = state.document.paper;\n const previews = useMemo(() => new Map(PAPER_LIBRARY.map((p) => [p.preset, { ...SWATCH, data: renderPaper({ ...p, shading: Math.max(0.8, p.shading) }, SWATCH) }])), []);\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"paper-panel\">\n {PAPER_FAMILIES.map((family) => (\n <div key={family}>\n <div className=\"mb-0.5 text-[10px] uppercase tracking-wide text-slate-500\">{family}</div>\n <div className=\"flex flex-wrap gap-1\" role=\"listbox\" aria-label={`${family} papers`}>\n {PAPER_LIBRARY.filter((p) => p.family === family).map((p) => (\n <button\n key={p.preset}\n type=\"button\"\n role=\"option\"\n aria-selected={paper.preset === p.preset}\n title={p.name}\n className={`rounded p-0.5 ${paper.preset === p.preset ? 'ring-2 ring-indigo-500' : 'ring-1 ring-slate-700 hover:ring-slate-500'}`}\n onClick={() => attempt(() => controller.setPaper({ preset: p.preset }))}\n >\n <PixelCanvas pixels={previews.get(p.preset) ?? null} label={p.name} style={{ width: 48, height: 30 }} />\n </button>\n ))}\n </div>\n </div>\n ))}\n <div className=\"text-slate-300\">{paper.name}</div>\n <label className=\"flex items-center justify-between\">\n <span className=\"text-slate-400\">Colour</span>\n <CommitColorInput label=\"Paper colour\" value={paper.color} onCommit={(v) => attempt(() => controller.setPaper({ color: v }))} className=\"h-6 w-10 rounded bg-transparent\" />\n </label>\n {PAPER_SLIDERS.map((c) => (\n <PaintSlider key={c.path} control={c} value={readPath(paper, c.path)} onCommit={(v) => attempt(() => controller.setPaper(patchPath(paper as never, c.path, v) as never))} />\n ))}\n <label className=\"flex items-center gap-2\">\n <input type=\"checkbox\" checked={paper.tiling === 'mirror'} onChange={(e) => attempt(() => controller.setPaper({ tiling: e.target.checked ? 'mirror' : 'repeat' }))} /> Mirror tiling\n </label>\n <button type=\"button\" className=\"self-start px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-200 hover:bg-slate-700\" onClick={() => attempt(() => controller.setPaper({ seed: paper.seed + 1 }))}>\n New sheet\n </button>\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useMemo, useRef, useState } from 'react';\nimport {\n HARMONY_KINDS,\n MIXING_PAD_HEIGHT,\n MIXING_PAD_WIDTH,\n hsvToRgb,\n hueToWheel,\n parseHexColor,\n renderColorWheel,\n rgbToHexColor,\n rgbToHsv,\n wheelPick,\n wheelPoint,\n type ColorWheel,\n type HarmonyKind,\n type PaintEditorController,\n} from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, PixelCanvas, button, chip, panel, useAttempt } from './shared';\n\nexport interface ColorPanelProps {\n controller: PaintEditorController;\n /** Wheel diameter in px (default 168). */\n wheelSize?: number;\n /** Show the mixing pad (default true). */\n mixingPad?: boolean;\n className?: string;\n}\n\ntype PadTool = 'paint' | 'knife' | 'pick';\n\n/**\n * Colour: a hue wheel (painter's RYB or RGB) with the chosen harmony marked on it, saturation and\n * value, the paint and second colours, harmony chips, swatches, and a mixing pad to paint on,\n * smear with a palette knife (pigment mixing) and pick from.\n */\nexport const ColorPanel: React.FC<ColorPanelProps> = ({ controller, wheelSize = 168, mixingPad = true, className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const [wheel, setWheel] = useState<ColorWheel>('ryb');\n const [kind, setKind] = useState<HarmonyKind>('complementary');\n const [padTool, setPadTool] = useState<PadTool>('paint');\n const padPoints = useRef<Array<{ x: number; y: number; pressure?: number }> | null>(null);\n const ring = useMemo(() => renderColorWheel(wheelSize, wheel), [wheelSize, wheel]);\n const color = state.color;\n const harmony = useMemo(() => controller.harmony(kind, { color, wheel }), [controller, kind, color, wheel]);\n const [r, g, b] = parseHexColor(color);\n const hsv = rgbToHsv(r, g, b);\n const pad = useMemo(() => ({ width: MIXING_PAD_WIDTH, height: MIXING_PAD_HEIGHT, data: controller.mixingPad.pixels() }), [controller, state.mixingPadVersion]);\n const R = wheelSize / 2;\n const mid = R * 0.82;\n const setHsv = (s: number, v: number) => controller.setColor(rgbToHexColor(...hsvToRgb(hsv.h, s, v)));\n\n const padPoint = (e: React.PointerEvent) => {\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n const kx = MIXING_PAD_WIDTH / (rect.width || MIXING_PAD_WIDTH);\n const ky = MIXING_PAD_HEIGHT / (rect.height || MIXING_PAD_HEIGHT);\n const x = Math.min(MIXING_PAD_WIDTH, Math.max(0, (e.clientX - rect.left) * kx));\n const y = Math.min(MIXING_PAD_HEIGHT, Math.max(0, (e.clientY - rect.top) * ky));\n return e.pointerType === 'pen' && e.pressure > 0 ? { x, y, pressure: e.pressure } : { x, y };\n };\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"color-panel\">\n <div className=\"relative self-center\" style={{ width: wheelSize, height: wheelSize }}>\n <div\n role=\"slider\"\n aria-label=\"Hue wheel\"\n aria-valuemin={0}\n aria-valuemax={360}\n aria-valuenow={Math.round(hueToWheel(hsv.h, wheel))}\n tabIndex={0}\n className=\"absolute inset-0 cursor-crosshair\"\n onPointerDown={(e) => {\n const rect = e.currentTarget.getBoundingClientRect();\n controller.setColor(wheelPick(e.clientX - rect.left - R, e.clientY - rect.top - R, wheel, color));\n }}\n >\n <PixelCanvas pixels={ring} label=\"Colour wheel\" style={{ width: wheelSize, height: wheelSize }} />\n </div>\n <svg className=\"pointer-events-none absolute inset-0\" width={wheelSize} height={wheelSize} aria-hidden=\"true\">\n {harmony.map((h, i) => {\n const p = wheelPoint(h.angle, mid);\n return <circle key={i} cx={R + p.x} cy={R + p.y} r={i === 0 ? 7 : 5} fill={h.color} stroke=\"#fff\" strokeWidth={i === 0 ? 2 : 1} />;\n })}\n </svg>\n <div className=\"absolute rounded-full border border-slate-700\" style={{ left: R - R * 0.45, top: R - R * 0.45, width: R * 0.9, height: R * 0.9, background: color }} />\n </div>\n <div className=\"flex items-center gap-2\">\n <input type=\"color\" aria-label=\"Paint colour\" value={color} onChange={(e) => controller.setColor(e.target.value)} className=\"h-7 w-9 rounded bg-transparent\" />\n <input type=\"color\" aria-label=\"Second colour\" value={state.secondaryColor} onChange={(e) => controller.setSecondaryColor(e.target.value)} className=\"h-5 w-7 rounded bg-transparent\" />\n <button type=\"button\" className={button} title=\"Swap colours (X)\" onClick={() => controller.swapColors()}>\n Swap\n </button>\n <input\n aria-label=\"Hex colour\"\n defaultValue={color}\n key={color}\n onBlur={(e) => attempt(() => controller.setColor(e.target.value.startsWith('#') ? e.target.value : `#${e.target.value}`))}\n className=\"w-20 rounded bg-slate-800 px-1.5 py-0.5 font-mono\"\n />\n </div>\n <label className=\"flex items-center gap-2\">\n <span className=\"w-16 text-slate-400\">Saturation</span>\n <input type=\"range\" aria-label=\"Saturation\" min={0} max={1} step={0.01} value={hsv.s} onChange={(e) => setHsv(Number(e.target.value), hsv.v)} className=\"flex-1 accent-indigo-500\" />\n </label>\n <label className=\"flex items-center gap-2\">\n <span className=\"w-16 text-slate-400\">Value</span>\n <input type=\"range\" aria-label=\"Value\" min={0} max={1} step={0.01} value={hsv.v} onChange={(e) => setHsv(hsv.s, Number(e.target.value))} className=\"flex-1 accent-indigo-500\" />\n </label>\n <div className=\"flex items-center gap-1\">\n <select aria-label=\"Harmony\" value={kind} onChange={(e) => setKind(e.target.value as HarmonyKind)} className=\"rounded bg-slate-800 px-1 py-0.5\">\n {HARMONY_KINDS.map((k) => (\n <option key={k} value={k}>\n {k}\n </option>\n ))}\n </select>\n <button type=\"button\" className={chip(wheel === 'ryb')} aria-pressed={wheel === 'ryb'} onClick={() => setWheel('ryb')}>\n RYB\n </button>\n <button type=\"button\" className={chip(wheel === 'rgb')} aria-pressed={wheel === 'rgb'} onClick={() => setWheel('rgb')}>\n RGB\n </button>\n </div>\n <div className=\"flex flex-wrap gap-1\" aria-label=\"Harmony colours\">\n {harmony.map((h, i) => (\n <button key={i} type=\"button\" aria-label={`Use ${h.color}`} title={h.color} className=\"h-6 w-6 rounded ring-1 ring-slate-700\" style={{ background: h.color }} onClick={() => controller.setColor(h.color)} />\n ))}\n <button type=\"button\" className={button} onClick={() => harmony.forEach((h) => controller.addSwatch(h.color))}>\n + swatches\n </button>\n </div>\n <div className=\"flex flex-wrap gap-1\" role=\"listbox\" aria-label=\"Swatches\">\n {state.swatches.map((s, i) => (\n <button\n key={i}\n type=\"button\"\n role=\"option\"\n aria-selected={s.color === color}\n aria-label={s.name ?? s.color}\n title={`${s.name ?? s.color} (right-click to remove)`}\n className=\"h-5 w-5 rounded ring-1 ring-slate-700\"\n style={{ background: s.color }}\n onClick={() => controller.setColor(s.color)}\n onContextMenu={(e) => {\n e.preventDefault();\n controller.removeSwatch(i);\n }}\n />\n ))}\n <button type=\"button\" className={button} aria-label=\"Add swatch\" onClick={() => controller.addSwatch(color)}>\n +\n </button>\n </div>\n {mixingPad && (\n <div className=\"flex flex-col gap-1\" data-testid=\"mixing-pad\">\n <div className=\"flex items-center gap-1\">\n <span className=\"text-slate-400\">Mixing pad</span>\n {(['paint', 'knife', 'pick'] as const).map((t) => (\n <button key={t} type=\"button\" aria-pressed={padTool === t} className={chip(padTool === t)} onClick={() => setPadTool(t)}>\n {t === 'paint' ? 'Paint' : t === 'knife' ? 'Knife' : 'Pick'}\n </button>\n ))}\n <button type=\"button\" className={button} onClick={() => controller.clearMixingPad()}>\n Clear\n </button>\n </div>\n <div\n role=\"application\"\n aria-label=\"Mixing pad\"\n className=\"touch-none cursor-crosshair\"\n onPointerDown={(e) => {\n const p = padPoint(e);\n if (padTool === 'pick') {\n attempt(() => controller.mixingPadPick(p.x, p.y, { setColor: true }));\n return;\n }\n padPoints.current = [p];\n (e.target as Element).setPointerCapture?.(e.pointerId);\n }}\n onPointerMove={(e) => padPoints.current?.push(padPoint(e))}\n onPointerUp={() => {\n const pts = padPoints.current;\n padPoints.current = null;\n if (pts?.length) attempt(() => controller.mixingPadStroke(pts, { tool: padTool === 'knife' ? 'knife' : 'paint' }));\n }}\n >\n <PixelCanvas pixels={pad} label=\"Mixing pad pixels\" className=\"w-full rounded\" style={{ aspectRatio: `${MIXING_PAD_WIDTH} / ${MIXING_PAD_HEIGHT}` }} />\n </div>\n </div>\n )}\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useState } from 'react';\nimport { BLEND_MENU_GROUPS, type BlendMode, type PaintEditorController, type PaintLayerInfo } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, button, chip, panel, useAttempt } from './shared';\n\nexport interface PaintLayersPanelProps {\n controller: PaintEditorController;\n className?: string;\n}\n\n/** Siblings of a layer, bottom first, and its index among them. */\nfunction siblingIndex(layers: PaintLayerInfo[], l: PaintLayerInfo): { index: number; count: number } {\n const sibs = layers.filter((x) => x.parentId === l.parentId).reverse();\n return { index: sibs.findIndex((x) => x.id === l.id), count: sibs.length };\n}\n\n/**\n * The layer stack, top first: visibility, names (double-click to rename), the active layer's\n * opacity, blend mode and locks, and new layer / group, duplicate, move up / down, merge down and\n * delete. Every change is one undo step.\n */\nexport const PaintLayersPanel: React.FC<PaintLayersPanelProps> = ({ controller, className }) => {\n usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const [renaming, setRenaming] = useState<string | null>(null);\n const layers = controller.listLayers();\n const active = layers.find((l) => l.active) ?? null;\n const move = (delta: number) => {\n if (!active) return;\n const { index, count } = siblingIndex(layers, active);\n const to = Math.min(count - 1, Math.max(0, index + delta));\n if (to !== index) attempt(() => controller.moveLayer(active.id, to));\n };\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"paint-layers-panel\">\n <div className=\"flex flex-wrap gap-1\">\n <button type=\"button\" className={button} onClick={() => attempt(() => controller.addLayer())}>\n New layer\n </button>\n <button type=\"button\" className={button} onClick={() => attempt(() => controller.addLayer({ type: 'group' }))}>\n New group\n </button>\n <button type=\"button\" className={button} disabled={!active} onClick={() => active && attempt(() => controller.duplicateLayer(active.id))}>\n Duplicate\n </button>\n <button type=\"button\" className={button} disabled={!active} aria-label=\"Move layer up\" onClick={() => move(1)}>\n ↑\n </button>\n <button type=\"button\" className={button} disabled={!active} aria-label=\"Move layer down\" onClick={() => move(-1)}>\n ↓\n </button>\n <button type=\"button\" className={button} disabled={!active} onClick={() => active && attempt(() => controller.mergeDown(active.id))}>\n Merge down\n </button>\n <button type=\"button\" className={button} disabled={!active || layers.length < 2} onClick={() => active && attempt(() => controller.removeLayer(active.id))}>\n Delete\n </button>\n </div>\n <ul role=\"tree\" aria-label=\"Layers\" className=\"flex flex-col gap-0.5\">\n {layers.map((l) => (\n <li\n key={l.id}\n role=\"treeitem\"\n aria-selected={l.active}\n className={`flex items-center gap-1.5 rounded px-1.5 py-1 cursor-pointer ${l.active ? 'bg-indigo-600/30 ring-1 ring-indigo-500' : 'hover:bg-slate-800'}`}\n style={{ paddingLeft: 6 + l.depth * 12 }}\n onClick={() => controller.setActiveLayer(l.id)}\n >\n <button\n type=\"button\"\n aria-label={l.visible ? `Hide ${l.name}` : `Show ${l.name}`}\n className={`w-5 text-[11px] ${l.visible ? 'text-slate-200' : 'text-slate-600'}`}\n onClick={(e) => {\n e.stopPropagation();\n attempt(() => controller.updateLayer(l.id, { visible: !l.visible }));\n }}\n >\n {l.visible ? '●' : '○'}\n </button>\n {renaming === l.id ? (\n <input\n autoFocus\n aria-label=\"Layer name\"\n defaultValue={l.name}\n className=\"flex-1 rounded bg-slate-800 px-1\"\n onClick={(e) => e.stopPropagation()}\n onBlur={(e) => {\n setRenaming(null);\n if (e.target.value.trim() && e.target.value !== l.name) attempt(() => controller.updateLayer(l.id, { name: e.target.value }));\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter') (e.target as HTMLInputElement).blur();\n if (e.key === 'Escape') setRenaming(null);\n }}\n />\n ) : (\n <span className=\"flex-1 truncate\" onDoubleClick={() => setRenaming(l.id)}>\n {l.type === 'group' ? '▸ ' : ''}\n {l.name}\n </span>\n )}\n {l.locks.pixels || l.locks.all ? <span title=\"Locked\">🔒</span> : null}\n </li>\n ))}\n </ul>\n {active && (\n <div className=\"flex flex-col gap-1.5\">\n <label className=\"flex items-center gap-2\">\n <span className=\"w-14 text-slate-400\">Opacity</span>\n <input\n type=\"range\"\n aria-label=\"Layer opacity\"\n min={0}\n max={1}\n step={0.01}\n value={active.opacity}\n onChange={(e) => attempt(() => controller.updateLayer(active.id, { opacity: Number(e.target.value) }))}\n className=\"flex-1 accent-indigo-500\"\n />\n </label>\n <label className=\"flex items-center gap-2\">\n <span className=\"w-14 text-slate-400\">Blend</span>\n <select aria-label=\"Layer blend\" value={active.blend} onChange={(e) => attempt(() => controller.updateLayer(active.id, { blend: e.target.value as BlendMode }))} className=\"flex-1 rounded bg-slate-800 px-1 py-0.5\">\n {active.type === 'group' && <option value=\"pass-through\">Pass through</option>}\n {BLEND_MENU_GROUPS.map((g) => (\n <optgroup key={g.label} label={g.label}>\n {g.modes.map((m) => (\n <option key={m.id} value={m.id} title={m.description}>\n {m.label}\n </option>\n ))}\n </optgroup>\n ))}\n </select>\n </label>\n <div className=\"flex gap-1\">\n {(['pixels', 'transparency'] as const).map((k) => (\n <button key={k} type=\"button\" aria-pressed={Boolean(active.locks[k])} className={chip(Boolean(active.locks[k]))} onClick={() => attempt(() => controller.updateLayer(active.id, { locks: { [k]: !active.locks[k] } }))}>\n {k === 'pixels' ? 'Lock pixels' : 'Lock transparency'}\n </button>\n ))}\n <button type=\"button\" aria-pressed={active.clipped} className={chip(active.clipped)} onClick={() => attempt(() => controller.updateLayer(active.id, { clipped: !active.clipped }))}>\n Clip\n </button>\n </div>\n </div>\n )}\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useState } from 'react';\nimport type { PaintEditorController, PaintTool } from '@pixerate/editor/paint-editor';\nimport { BrushPanel } from './BrushPanel';\nimport { ColorPanel } from './ColorPanel';\nimport { PaintCanvas } from './PaintCanvas';\nimport { PaintLayersPanel } from './PaintLayersPanel';\nimport { PaintToolbar } from './PaintToolbar';\nimport { PaperPanel } from './PaperPanel';\nimport { chip } from './shared';\n\nexport interface PaintEditorProps {\n controller: PaintEditorController;\n /** Base name of saved and exported files (default `painting`). */\n fileName?: string;\n /** Height of the editor (default 720 px). */\n height?: number | string;\n className?: string;\n}\n\ntype SideTab = 'color' | 'paper' | 'layers';\n\n/**\n * The paint editor: toolbar, brush library on the left, the canvas, and colour (wheel,\n * harmonies, swatches, mixing pad), paper and layers on the right.\n */\nexport const PaintEditor: React.FC<PaintEditorProps> = ({ controller, fileName, height = 720, className }) => {\n const [tool, setTool] = useState<PaintTool>('brush');\n const [tab, setTab] = useState<SideTab>('color');\n const [error, setError] = useState<string | null>(null);\n return (\n <div className={`flex flex-col gap-2 rounded-xl border border-slate-800 bg-slate-900 p-2 ${className ?? ''}`} style={{ height }} data-testid=\"paint-editor\">\n <PaintToolbar controller={controller} tool={tool} onToolChange={setTool} fileName={fileName} />\n <div className=\"flex min-h-0 flex-1 gap-2\">\n <BrushPanel controller={controller} className=\"w-60 shrink-0 overflow-y-auto pr-1\" />\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <PaintCanvas controller={controller} tool={tool} onError={setError} className=\"flex-1 rounded-lg\" />\n {error && (\n <p role=\"alert\" className=\"mt-1 text-[11px] text-rose-400\">\n {error}\n </p>\n )}\n </div>\n <div className=\"flex w-64 shrink-0 flex-col gap-2 overflow-y-auto pr-1\">\n <div className=\"flex gap-1\" role=\"tablist\" aria-label=\"Paint panels\">\n {(['color', 'paper', 'layers'] as const).map((t) => (\n <button key={t} type=\"button\" role=\"tab\" aria-selected={tab === t} className={chip(tab === t)} onClick={() => setTab(t)}>\n {t === 'color' ? 'Colour' : t === 'paper' ? 'Paper' : 'Layers'}\n </button>\n ))}\n </div>\n {tab === 'color' && <ColorPanel controller={controller} />}\n {tab === 'paper' && <PaperPanel controller={controller} />}\n {tab === 'layers' && <PaintLayersPanel controller={controller} />}\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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","names":["import_react","import_paint_editor","import_react","import_paint_editor","import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_paint_editor","import_jsx_runtime","import_react","import_paint_editor","import_jsx_runtime","import_react","import_paint_editor","import_jsx_runtime","import_react","import_paint_editor","import_jsx_runtime","import_react","import_jsx_runtime"]}
|
|
@@ -728,7 +728,7 @@ var ColorPanel = ({ controller, wheelSize = 168, mixingPad = true, className })
|
|
|
728
728
|
|
|
729
729
|
// src/paint-editor/PaintLayersPanel.tsx
|
|
730
730
|
import { useState as useState6 } from "react";
|
|
731
|
-
import {
|
|
731
|
+
import { BLEND_MENU_GROUPS } from "@pixerate/editor/paint-editor";
|
|
732
732
|
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
733
733
|
function siblingIndex(layers, l) {
|
|
734
734
|
const sibs = layers.filter((x) => x.parentId === l.parentId).reverse();
|
|
@@ -825,7 +825,7 @@ var PaintLayersPanel = ({ controller, className }) => {
|
|
|
825
825
|
/* @__PURE__ */ jsx7("span", { className: "w-14 text-slate-400", children: "Blend" }),
|
|
826
826
|
/* @__PURE__ */ jsxs7("select", { "aria-label": "Layer blend", value: active.blend, onChange: (e) => attempt(() => controller.updateLayer(active.id, { blend: e.target.value })), className: "flex-1 rounded bg-slate-800 px-1 py-0.5", children: [
|
|
827
827
|
active.type === "group" && /* @__PURE__ */ jsx7("option", { value: "pass-through", children: "Pass through" }),
|
|
828
|
-
|
|
828
|
+
BLEND_MENU_GROUPS.map((g) => /* @__PURE__ */ jsx7("optgroup", { label: g.label, children: g.modes.map((m) => /* @__PURE__ */ jsx7("option", { value: m.id, title: m.description, children: m.label }, m.id)) }, g.label))
|
|
829
829
|
] })
|
|
830
830
|
] }),
|
|
831
831
|
/* @__PURE__ */ jsxs7("div", { className: "flex gap-1", children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/paint-editor/usePaintEditor.ts","../../src/paint-editor/PaintCanvas.tsx","../../src/paint-editor/PaintToolbar.tsx","../../src/paint-editor/shared.tsx","../../src/paint-editor/BrushPanel.tsx","../../src/paint-editor/PaperPanel.tsx","../../src/paint-editor/ColorPanel.tsx","../../src/paint-editor/PaintLayersPanel.tsx","../../src/paint-editor/PaintEditor.tsx"],"sourcesContent":["import { useMemo, useState, useSyncExternalStore } from 'react';\nimport { PaintEditorController, type PaintEditorOptions, type PaintEditorState } from '@pixerate/editor/paint-editor';\n\nexport interface UsePaintEditorReturn {\n controller: PaintEditorController;\n /** The controller's snapshot (a new object after every change). */\n state: PaintEditorState;\n}\n\n/**\n * Creates a `PaintEditorController` once (from `options`, read on the first render) or uses the\n * one given, and re-renders on every change.\n */\nexport function usePaintEditor(options: PaintEditorOptions | PaintEditorController = {}): UsePaintEditorReturn {\n const [controller] = useState(() => (options instanceof PaintEditorController ? options : new PaintEditorController(options)));\n const state = usePaintEditorState(controller);\n return useMemo(() => ({ controller, state }), [controller, state]);\n}\n\n/** Subscribes to a controller's state. */\nexport function usePaintEditorState(controller: PaintEditorController): PaintEditorState {\n return useSyncExternalStore(\n (notify) => controller.subscribe(notify),\n () => controller.getState(),\n () => controller.getState()\n );\n}\n","import React, { useEffect, useMemo, useRef, useState } from 'react';\nimport {\n PaintCanvasPresenter,\n PaintGesture,\n fitZoom,\n guideOverlay,\n handlePaintShortcut,\n viewCssTransform,\n type PaintEditorController,\n type PaintTool,\n} from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\n\nexport interface PaintCanvasProps {\n controller: PaintEditorController;\n /** The active tool (default brush). */\n tool?: PaintTool;\n /** Draw the symmetry axes and perspective lines (default true). */\n showGuides?: boolean;\n /** Fit the canvas in the viewport on mount (default true). */\n fitOnMount?: boolean;\n /** Called with a refusal (hidden or locked layer). */\n onError?: (message: string | null) => void;\n className?: string;\n}\n\n/**\n * The painting surface: a document-sized canvas the compositor draws into (only changed tiles are\n * uploaded), shown through the view's zoom, pan, rotation and mirroring as a CSS transform (the\n * pixels never resample). Pointer input goes through `PaintGesture`: coalesced samples, a predicted\n * tail drawn as a thin preview, palm rejection, middle-button pan, wheel zoom and Shift+wheel\n * rotation. Guides and floating reference images are drawn on top.\n */\nexport const PaintCanvas: React.FC<PaintCanvasProps> = ({ controller, tool = 'brush', showGuides = true, fitOnMount = true, onError, className }) => {\n const state = usePaintEditorState(controller);\n const viewport = useRef<HTMLDivElement>(null);\n const canvas = useRef<HTMLCanvasElement>(null);\n const [size, setSize] = useState({ width: 800, height: 600 });\n const measured = useRef(false);\n const [predicted, setPredicted] = useState<Array<{ x: number; y: number }>>([]);\n const presenter = useMemo(() => new PaintCanvasPresenter(controller), [controller]);\n const gesture = useMemo(\n () =>\n new PaintGesture(controller, () => {\n const r = viewport.current?.getBoundingClientRect();\n return { left: r?.left ?? 0, top: r?.top ?? 0, width: r?.width || size.width, height: r?.height || size.height };\n }),\n // The box reads the element when called; `size` is only the jsdom fallback.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [controller]\n );\n gesture.tool = tool;\n const { canvas: doc } = state.document;\n\n useEffect(() => {\n const el = viewport.current;\n if (!el || typeof ResizeObserver === 'undefined') return;\n const ro = new ResizeObserver(() => {\n if (!el.clientWidth || !el.clientHeight) return;\n measured.current = true;\n setSize({ width: el.clientWidth, height: el.clientHeight });\n });\n ro.observe(el);\n return () => ro.disconnect();\n }, []);\n\n // Fit once per canvas size, after the viewport has been measured (or at once where it cannot be).\n const fitted = useRef<string | null>(null);\n useEffect(() => {\n const key = `${doc.width}x${doc.height}`;\n if (!fitOnMount || fitted.current === key) return;\n if (typeof ResizeObserver !== 'undefined' && !measured.current) return;\n fitted.current = key;\n controller.setView({ zoom: fitZoom(doc, size), pan: { x: 0, y: 0 } });\n }, [controller, doc, size, fitOnMount]);\n\n // Upload changed tiles whenever the state changes.\n useEffect(() => {\n const ctx = canvas.current?.getContext('2d');\n if (ctx && typeof ctx.createImageData === 'function') presenter.render(ctx as never);\n else controller.takeDirty();\n }, [state, presenter, controller]);\n\n // Wheel needs a non-passive listener to prevent page scroll (see GOTCHAS).\n useEffect(() => {\n const el = viewport.current;\n if (!el) return;\n const onWheel = (e: WheelEvent) => {\n e.preventDefault();\n gesture.wheel(e);\n };\n el.addEventListener('wheel', onWheel, { passive: false });\n return () => el.removeEventListener('wheel', onWheel);\n }, [gesture]);\n\n const report = () => onError?.(gesture.error);\n const transform = viewCssTransform(state.view, doc, size);\n const lines = showGuides ? guideOverlay(controller) : [];\n\n return (\n <div\n ref={viewport}\n tabIndex={0}\n role=\"application\"\n aria-label=\"Paint canvas\"\n data-testid=\"paint-canvas\"\n className={`relative overflow-hidden bg-slate-950 outline-none touch-none select-none ${className ?? ''}`}\n style={{ cursor: tool === 'pan' ? 'grab' : tool === 'eyedropper' ? 'copy' : 'crosshair' }}\n onPointerDown={(e) => {\n viewport.current?.focus();\n if (gesture.down(e.nativeEvent)) (e.target as Element).setPointerCapture?.(e.pointerId);\n report();\n }}\n onPointerMove={(e) => {\n gesture.move(e.nativeEvent);\n if (gesture.predicted.length || predicted.length) setPredicted(gesture.predicted.map((p) => ({ x: p.x, y: p.y })));\n }}\n onPointerUp={(e) => {\n gesture.up(e.nativeEvent);\n setPredicted([]);\n }}\n onPointerCancel={() => {\n gesture.cancel();\n setPredicted([]);\n }}\n onKeyDown={(e) => {\n if (handlePaintShortcut(controller, gesture, e)) e.preventDefault();\n }}\n >\n <canvas\n ref={canvas}\n width={doc.width}\n height={doc.height}\n className=\"absolute left-0 top-0 shadow-2xl\"\n style={{ transform, transformOrigin: '0 0', imageRendering: state.view.zoom > 2 ? 'pixelated' : 'auto' }}\n />\n <svg className=\"absolute left-0 top-0 pointer-events-none overflow-visible\" width={doc.width} height={doc.height} style={{ transform, transformOrigin: '0 0' }} aria-hidden=\"true\">\n {lines.map((l, i) => (\n <line\n key={i}\n x1={l.from.x}\n y1={l.from.y}\n x2={l.to.x}\n y2={l.to.y}\n stroke={l.kind === 'symmetry' ? '#22d3ee' : '#f472b6'}\n strokeOpacity={l.kind === 'symmetry' ? 0.8 : 0.35}\n strokeWidth={1 / state.view.zoom}\n strokeDasharray={l.kind === 'symmetry' ? `${6 / state.view.zoom} ${4 / state.view.zoom}` : undefined}\n />\n ))}\n {predicted.length > 0 && (\n <polyline points={predicted.map((p) => `${p.x},${p.y}`).join(' ')} fill=\"none\" stroke={state.color} strokeOpacity={0.5} strokeWidth={Math.max(1, state.brush.tip.size / 2)} strokeLinecap=\"round\" />\n )}\n </svg>\n {state.guides.references\n .filter((r) => r.visible)\n .map((r) => (\n <ReferencePanel key={r.id} controller={controller} id={r.id} />\n ))}\n <div className=\"absolute bottom-1 right-2 text-[10px] text-slate-500 pointer-events-none\" data-testid=\"paint-view-status\">\n {Math.round(state.view.zoom * 100)}% · {Math.round(state.view.rotation)}°{state.view.mirror ? ' · mirrored' : ''}\n </div>\n </div>\n );\n};\n\n/** A floating reference image: drag its title bar to move it, click the image to pick a colour. */\nconst ReferencePanel: React.FC<{ controller: PaintEditorController; id: string }> = ({ controller, id }) => {\n const state = usePaintEditorState(controller);\n const ref = state.guides.references.find((r) => r.id === id);\n const drag = useRef<{ x: number; y: number; ox: number; oy: number } | null>(null);\n if (!ref) return null;\n const h = (ref.height / ref.width) * ref.displayWidth;\n return (\n <div\n className=\"absolute rounded border border-slate-700 bg-slate-900/95 shadow-xl\"\n style={{ left: ref.x, top: ref.y, width: ref.displayWidth }}\n data-testid=\"paint-reference\"\n onPointerDown={(e) => e.stopPropagation()}\n >\n <div\n className=\"flex items-center justify-between px-1.5 py-0.5 text-[10px] text-slate-300 cursor-move\"\n onPointerDown={(e) => {\n drag.current = { x: e.clientX, y: e.clientY, ox: ref.x, oy: ref.y };\n (e.target as Element).setPointerCapture?.(e.pointerId);\n }}\n onPointerMove={(e) => {\n const d = drag.current;\n if (d) controller.updateReferenceImage(id, { x: d.ox + e.clientX - d.x, y: d.oy + e.clientY - d.y });\n }}\n onPointerUp={() => (drag.current = null)}\n >\n <span className=\"truncate\">{ref.name}</span>\n <button type=\"button\" aria-label={`Hide ${ref.name}`} className=\"px-1 text-slate-400 hover:text-white\" onClick={() => controller.updateReferenceImage(id, { visible: false })}>\n ×\n </button>\n </div>\n <img\n src={ref.src}\n alt={ref.name}\n draggable={false}\n width={ref.displayWidth}\n height={h}\n className=\"block cursor-copy\"\n onClick={(e) => {\n const rect = (e.target as HTMLElement).getBoundingClientRect();\n const k = ref.width / (rect.width || ref.displayWidth);\n controller.setColor(controller.pickReferenceColor(id, Math.min(ref.width - 1, (e.clientX - rect.left) * k), Math.min(ref.height - 1, (e.clientY - rect.top) * k)));\n }}\n />\n </div>\n );\n};\n","import React, { useRef } from 'react';\nimport { PAINT_TOOLS, SYMMETRY_MODES, decodeImageBlob, downloadBytes, type PaintEditorController, type PaintTool, type SymmetryMode } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, button, chip, useAttempt } from './shared';\n\nexport interface PaintToolbarProps {\n controller: PaintEditorController;\n tool: PaintTool;\n onToolChange: (tool: PaintTool) => void;\n /** Base name of saved and exported files (default `painting`). */\n fileName?: string;\n className?: string;\n}\n\n/**\n * Tools (brush, eyedropper, pan, rotate view), undo / redo, view rotation, mirroring and reset,\n * the symmetry and perspective guides, the tracing image and reference images, the drawing hand,\n * and file actions: save / open JSON, export PNG, JPEG and PSD.\n */\nexport const PaintToolbar: React.FC<PaintToolbarProps> = ({ controller, tool, onToolChange, fileName = 'painting', className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const openRef = useRef<HTMLInputElement>(null);\n const tracingRef = useRef<HTMLInputElement>(null);\n const refRef = useRef<HTMLInputElement>(null);\n const { symmetry, perspective, tracing } = state.guides;\n const { canvas } = state.document;\n\n const exportImage = (format: 'image/png' | 'image/jpeg') =>\n attempt(async () => downloadBytes(await controller.exportImage({ format }), `${fileName}.${format === 'image/png' ? 'png' : 'jpg'}`, format));\n\n return (\n <div className={`flex flex-wrap items-center gap-1.5 text-xs text-slate-200 ${className ?? ''}`} role=\"toolbar\" aria-label=\"Paint toolbar\" data-testid=\"paint-toolbar\">\n {PAINT_TOOLS.map((t) => (\n <button key={t.id} type=\"button\" aria-pressed={tool === t.id} title={`${t.label} (${t.key.toUpperCase()})`} className={chip(tool === t.id)} onClick={() => onToolChange(t.id)}>\n {t.label}\n </button>\n ))}\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} disabled={!state.canUndo} title={state.undoLabel ? `Undo ${state.undoLabel}` : 'Undo'} onClick={() => controller.undo()}>\n Undo\n </button>\n <button type=\"button\" className={button} disabled={!state.canRedo} title={state.redoLabel ? `Redo ${state.redoLabel}` : 'Redo'} onClick={() => controller.redo()}>\n Redo\n </button>\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} aria-label=\"Rotate view left\" onClick={() => controller.setView({ rotation: state.view.rotation - 15 })}>\n ⟲\n </button>\n <button type=\"button\" className={button} aria-label=\"Rotate view right\" onClick={() => controller.setView({ rotation: state.view.rotation + 15 })}>\n ⟳\n </button>\n <button type=\"button\" className={chip(state.view.mirror)} aria-pressed={state.view.mirror} onClick={() => controller.setView({ mirror: !state.view.mirror })}>\n Mirror view\n </button>\n <button type=\"button\" className={button} onClick={() => controller.resetView()}>\n Reset view\n </button>\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <label className=\"flex items-center gap-1\">\n Symmetry\n <select\n aria-label=\"Symmetry\"\n value={symmetry.mode}\n onChange={(e) => controller.setSymmetry({ mode: e.target.value as SymmetryMode, center: symmetry.mode === 'off' ? { x: canvas.width / 2, y: canvas.height / 2 } : symmetry.center })}\n className=\"rounded bg-slate-800 px-1 py-0.5\"\n >\n {SYMMETRY_MODES.map((m) => (\n <option key={m} value={m}>\n {m}\n </option>\n ))}\n </select>\n </label>\n {symmetry.mode === 'kaleidoscope' && (\n <input\n type=\"number\"\n aria-label=\"Kaleidoscope segments\"\n min={2}\n max={32}\n value={symmetry.segments}\n onChange={(e) => controller.setSymmetry({ segments: Number(e.target.value) })}\n className=\"w-12 rounded bg-slate-800 px-1 py-0.5\"\n />\n )}\n <button\n type=\"button\"\n className={chip(perspective.enabled)}\n aria-pressed={perspective.enabled}\n onClick={() =>\n attempt(() =>\n controller.setPerspective(\n perspective.enabled ? { enabled: false } : { enabled: true, points: perspective.points.length ? perspective.points : [{ x: canvas.width / 2, y: canvas.height * 0.4 }] }\n )\n )\n }\n >\n Perspective\n </button>\n {perspective.enabled && (\n <select\n aria-label=\"Vanishing points\"\n value={perspective.points.length}\n onChange={(e) => {\n const n = Number(e.target.value);\n const y = canvas.height * 0.4;\n const pts = n === 1 ? [{ x: canvas.width / 2, y }] : n === 2 ? [{ x: -canvas.width * 0.5, y }, { x: canvas.width * 1.5, y }] : [{ x: -canvas.width * 0.5, y }, { x: canvas.width * 1.5, y }, { x: canvas.width / 2, y: canvas.height * 3 }];\n attempt(() => controller.setPerspective({ points: pts }));\n }}\n className=\"rounded bg-slate-800 px-1 py-0.5\"\n >\n <option value={1}>1-point</option>\n <option value={2}>2-point</option>\n <option value={3}>3-point</option>\n </select>\n )}\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} onClick={() => tracingRef.current?.click()}>\n Tracing image…\n </button>\n {tracing && (\n <>\n <input\n type=\"range\"\n aria-label=\"Tracing opacity\"\n min={0}\n max={1}\n step={0.05}\n value={tracing.opacity}\n onChange={(e) => controller.updateTracing({ opacity: Number(e.target.value) })}\n className=\"w-16 accent-indigo-500\"\n />\n <button type=\"button\" className={chip(tracing.sampleColors)} aria-pressed={tracing.sampleColors} onClick={() => controller.updateTracing({ sampleColors: !tracing.sampleColors })}>\n Trace colours\n </button>\n <button type=\"button\" className={chip(tracing.visible)} aria-pressed={tracing.visible} onClick={() => controller.updateTracing({ visible: !tracing.visible })}>\n Show tracing\n </button>\n <button type=\"button\" className={button} onClick={() => controller.clearTracingImage()}>\n Remove tracing\n </button>\n </>\n )}\n <button type=\"button\" className={button} onClick={() => refRef.current?.click()}>\n Reference…\n </button>\n <button type=\"button\" className={button} title=\"Which hand holds the pen (palm rejection)\" onClick={() => controller.setHand(state.hand === 'right' ? 'left' : 'right')}>\n {state.hand === 'right' ? 'Right-handed' : 'Left-handed'}\n </button>\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} onClick={() => attempt(() => downloadBytes(JSON.stringify(controller.toJSON()), `${fileName}.paint.json`, 'application/json'))}>\n Save\n </button>\n <button type=\"button\" className={button} onClick={() => openRef.current?.click()}>\n Open…\n </button>\n <button type=\"button\" className={button} onClick={() => exportImage('image/png')}>\n PNG\n </button>\n <button type=\"button\" className={button} onClick={() => exportImage('image/jpeg')}>\n JPEG\n </button>\n <button type=\"button\" className={button} onClick={() => attempt(() => downloadBytes(controller.exportPsd().bytes, `${fileName}.psd`, 'image/vnd.adobe.photoshop'))}>\n PSD\n </button>\n <input\n ref={openRef}\n type=\"file\"\n accept=\".json,application/json\"\n aria-label=\"Open painting\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.loadJSON(JSON.parse(await f.text())));\n e.target.value = '';\n }}\n />\n <input\n ref={tracingRef}\n type=\"file\"\n accept=\"image/*\"\n aria-label=\"Load tracing image\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.setTracingImage({ pixels: await decodeImageBlob(f) }));\n e.target.value = '';\n }}\n />\n <input\n ref={refRef}\n type=\"file\"\n accept=\"image/*\"\n aria-label=\"Add reference image\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.addReferenceImage({ pixels: await decodeImageBlob(f), name: f.name }));\n e.target.value = '';\n }}\n />\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useEffect, useRef, useState } from 'react';\nimport type { SliderControl } from '@pixerate/editor/paint-editor';\n\nexport const chip = (on: boolean) => `px-2 py-1 rounded text-[11px] ${on ? 'bg-indigo-600 text-white' : 'bg-slate-800 text-slate-300 hover:text-white'}`;\nexport const button = 'px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-200 hover:bg-slate-700 disabled:opacity-40';\nexport const panel = 'flex flex-col gap-2 text-xs text-slate-200';\n\n/** Draws RGBA pixels into a canvas (nothing without a 2D context, as in jsdom). */\nexport const PixelCanvas: React.FC<{ pixels: { width: number; height: number; data: Uint8ClampedArray } | null; label: string; className?: string; style?: React.CSSProperties }> = ({ pixels, label, className, style }) => {\n const ref = useRef<HTMLCanvasElement>(null);\n useEffect(() => {\n const canvas = ref.current;\n const ctx = canvas?.getContext('2d');\n if (!canvas || !ctx || !pixels || typeof ctx.createImageData !== 'function') return;\n canvas.width = pixels.width;\n canvas.height = pixels.height;\n const img = ctx.createImageData(pixels.width, pixels.height);\n img.data.set(pixels.data);\n ctx.putImageData(img, 0, 0);\n }, [pixels]);\n return <canvas ref={ref} role=\"img\" aria-label={label} className={className} style={style} width={pixels?.width} height={pixels?.height} />;\n};\n\nconst fmt = (c: SliderControl, v: number) => (c.step >= 1 ? String(Math.round(v)) : v.toFixed(2));\n\n/**\n * A labelled range input. `onChange` runs while dragging; `onCommit` (if given) runs once on\n * release (the native `change` event), for settings that are undo steps.\n */\nexport const PaintSlider: React.FC<{ control: SliderControl; value: number; onChange?: (v: number) => void; onCommit?: (v: number) => void }> = ({ control, value, onChange, onCommit }) => {\n const [draft, setDraft] = useState<number | null>(null);\n const ref = useRef<HTMLInputElement>(null);\n const commit = useRef(onCommit);\n commit.current = onCommit;\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const done = () => {\n commit.current?.(Number(el.value));\n setDraft(null);\n };\n el.addEventListener('change', done);\n return () => el.removeEventListener('change', done);\n }, []);\n const shown = draft ?? value;\n return (\n <label className=\"flex flex-col gap-0.5\" data-path={control.path}>\n <span className=\"flex justify-between text-slate-400\">\n <span>{control.label}</span>\n <span className=\"font-mono\">{fmt(control, shown)}</span>\n </span>\n <input\n ref={ref}\n type=\"range\"\n aria-label={control.label}\n min={control.min}\n max={control.max}\n step={control.step}\n value={shown}\n onChange={(e) => {\n const v = Number(e.target.value);\n if (onCommit) setDraft(v);\n onChange?.(v);\n }}\n className=\"w-full accent-indigo-500\"\n />\n </label>\n );\n};\n\n/** Runs `fn`, turning a thrown error into a message. */\nexport function useAttempt(): [string | null, (fn: () => unknown) => void, (msg: string | null) => void] {\n const [error, setError] = useState<string | null>(null);\n const attempt = (fn: () => unknown) => {\n try {\n setError(null);\n const r = fn();\n if (r && typeof (r as Promise<unknown>).catch === 'function') (r as Promise<unknown>).catch((e) => setError(e instanceof Error ? e.message : String(e)));\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n }\n };\n return [error, attempt, setError];\n}\n\nexport const ErrorLine: React.FC<{ error: string | null }> = ({ error }) =>\n error ? (\n <p role=\"alert\" className=\"text-[11px] text-rose-400\">\n {error}\n </p>\n ) : null;\n\n/** A colour input that commits once when the picker closes (the native `change` event). */\nexport const CommitColorInput: React.FC<{ value: string; label: string; onCommit: (v: string) => void; className?: string }> = ({ value, label, onCommit, className }) => {\n const ref = useRef<HTMLInputElement>(null);\n const commit = useRef(onCommit);\n commit.current = onCommit;\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const done = () => commit.current(el.value);\n el.addEventListener('change', done);\n return () => el.removeEventListener('change', done);\n }, []);\n return <input ref={ref} type=\"color\" aria-label={label} defaultValue={value} key={value} className={className} />;\n};\n","import React, { useMemo, useRef, useState } from 'react';\nimport { BRUSH_ROTATIONS, BRUSH_SLIDERS, downloadBytes, patchPath, readPath, type BrushRotation, type PaintEditorController } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, PaintSlider, PixelCanvas, button, panel, useAttempt } from './shared';\n\nexport interface BrushPanelProps {\n controller: PaintEditorController;\n /** Thumbnail size in px (default 112 × 32). */\n thumbnailWidth?: number;\n thumbnailHeight?: number;\n className?: string;\n}\n\n/**\n * The brush library (thumbnails rendered from a test stroke on the current paper, grouped by\n * category) and the active brush's settings: size, opacity, flow, hardness, spacing, roundness,\n * angle, paper grain, position and pressure smoothing, dynamics and rotation mode. Save the edited\n * brush, import and export libraries as JSON.\n */\nexport const BrushPanel: React.FC<BrushPanelProps> = ({ controller, thumbnailWidth = 112, thumbnailHeight = 32, className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const [saveName, setSaveName] = useState('');\n const fileRef = useRef<HTMLInputElement>(null);\n const { brush, brushes } = state;\n const paper = state.document.paper;\n const thumbs = useMemo(\n () => new Map(brushes.map((b) => [b.id, controller.brushThumbnail(b.id, { width: thumbnailWidth, height: thumbnailHeight, color: '#26324a' })])),\n // Thumbnails follow the library and the paper.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [controller, brushes, paper, thumbnailWidth, thumbnailHeight]\n );\n const slug = (name: string) => name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 60) || 'brush';\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"brush-panel\">\n <div className=\"grid grid-cols-2 gap-1\" role=\"listbox\" aria-label=\"Brushes\">\n {brushes.map((b) => (\n <button\n key={b.id}\n type=\"button\"\n role=\"option\"\n aria-selected={brush.id === b.id}\n title={`${b.name} (${b.category})`}\n className={`flex flex-col items-start gap-0.5 rounded p-1 text-left ${brush.id === b.id ? 'bg-indigo-600/30 ring-1 ring-indigo-500' : 'bg-slate-900 hover:bg-slate-800'}`}\n onClick={() => controller.setBrush({ id: b.id })}\n >\n <PixelCanvas pixels={thumbs.get(b.id) ?? null} label={`${b.name} thumbnail`} className=\"rounded\" style={{ width: '100%', aspectRatio: `${thumbnailWidth} / ${thumbnailHeight}` }} />\n <span className=\"truncate text-[10px] text-slate-300\">{b.name}</span>\n </button>\n ))}\n </div>\n <div className=\"flex flex-col gap-1.5\">\n {BRUSH_SLIDERS.map((c) => (\n <PaintSlider key={c.path} control={c} value={readPath(brush, c.path)} onChange={(v) => controller.setBrush(patchPath(brush as never, c.path, v) as never)} />\n ))}\n <label className=\"flex items-center justify-between gap-2\">\n <span className=\"text-slate-400\">Rotation</span>\n <select aria-label=\"Brush rotation\" value={brush.rotation} onChange={(e) => controller.setBrush({ rotation: e.target.value as BrushRotation })} className=\"rounded bg-slate-800 px-1 py-0.5\">\n {BRUSH_ROTATIONS.map((r) => (\n <option key={r} value={r}>\n {r === 'stroke' ? 'Follow stroke' : r === 'barrel' ? 'Pen barrel' : 'Fixed'}\n </option>\n ))}\n </select>\n </label>\n <label className=\"flex items-center gap-2\">\n <input type=\"checkbox\" checked={brush.tip.pressureSize} onChange={(e) => controller.setBrush({ tip: { pressureSize: e.target.checked } })} /> Pressure → size\n </label>\n <label className=\"flex items-center gap-2\">\n <input type=\"checkbox\" checked={brush.tip.pressureOpacity} onChange={(e) => controller.setBrush({ tip: { pressureOpacity: e.target.checked } })} /> Pressure → opacity\n </label>\n </div>\n <div className=\"flex flex-wrap items-center gap-1\">\n <input value={saveName} placeholder=\"Brush name\" aria-label=\"Brush name\" onChange={(e) => setSaveName(e.target.value)} className=\"w-28 rounded bg-slate-800 px-1.5 py-0.5\" />\n <button type=\"button\" className={button} disabled={!saveName.trim()} onClick={() => attempt(() => (controller.saveBrush({ id: slug(saveName), name: saveName.trim() }), setSaveName('')))}>\n Save brush\n </button>\n <button type=\"button\" className={button} onClick={() => attempt(() => downloadBytes(JSON.stringify(controller.exportBrushes(), null, 2), 'brushes.json', 'application/json'))}>\n Export\n </button>\n <button type=\"button\" className={button} onClick={() => fileRef.current?.click()}>\n Import…\n </button>\n <input\n ref={fileRef}\n type=\"file\"\n accept=\".json,application/json\"\n aria-label=\"Import brushes\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.importBrushes(JSON.parse(await f.text())));\n e.target.value = '';\n }}\n />\n </div>\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useMemo } from 'react';\nimport { PAPER_FAMILIES, PAPER_LIBRARY, PAPER_SLIDERS, patchPath, readPath, renderPaper, type PaintEditorController } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { CommitColorInput, ErrorLine, PaintSlider, PixelCanvas, panel, useAttempt } from './shared';\n\nexport interface PaperPanelProps {\n controller: PaintEditorController;\n className?: string;\n}\n\nconst SWATCH = { x: 0, y: 0, width: 64, height: 40 };\n\n/**\n * The paper library by family (each a generated grain preview) and the current paper's colour,\n * grain depth, scale, shading and contrast, plus the wet-media properties stored for later.\n * Each change is one undo step (sliders commit on release).\n */\nexport const PaperPanel: React.FC<PaperPanelProps> = ({ controller, className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const paper = state.document.paper;\n const previews = useMemo(() => new Map(PAPER_LIBRARY.map((p) => [p.preset, { ...SWATCH, data: renderPaper({ ...p, shading: Math.max(0.8, p.shading) }, SWATCH) }])), []);\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"paper-panel\">\n {PAPER_FAMILIES.map((family) => (\n <div key={family}>\n <div className=\"mb-0.5 text-[10px] uppercase tracking-wide text-slate-500\">{family}</div>\n <div className=\"flex flex-wrap gap-1\" role=\"listbox\" aria-label={`${family} papers`}>\n {PAPER_LIBRARY.filter((p) => p.family === family).map((p) => (\n <button\n key={p.preset}\n type=\"button\"\n role=\"option\"\n aria-selected={paper.preset === p.preset}\n title={p.name}\n className={`rounded p-0.5 ${paper.preset === p.preset ? 'ring-2 ring-indigo-500' : 'ring-1 ring-slate-700 hover:ring-slate-500'}`}\n onClick={() => attempt(() => controller.setPaper({ preset: p.preset }))}\n >\n <PixelCanvas pixels={previews.get(p.preset) ?? null} label={p.name} style={{ width: 48, height: 30 }} />\n </button>\n ))}\n </div>\n </div>\n ))}\n <div className=\"text-slate-300\">{paper.name}</div>\n <label className=\"flex items-center justify-between\">\n <span className=\"text-slate-400\">Colour</span>\n <CommitColorInput label=\"Paper colour\" value={paper.color} onCommit={(v) => attempt(() => controller.setPaper({ color: v }))} className=\"h-6 w-10 rounded bg-transparent\" />\n </label>\n {PAPER_SLIDERS.map((c) => (\n <PaintSlider key={c.path} control={c} value={readPath(paper, c.path)} onCommit={(v) => attempt(() => controller.setPaper(patchPath(paper as never, c.path, v) as never))} />\n ))}\n <label className=\"flex items-center gap-2\">\n <input type=\"checkbox\" checked={paper.tiling === 'mirror'} onChange={(e) => attempt(() => controller.setPaper({ tiling: e.target.checked ? 'mirror' : 'repeat' }))} /> Mirror tiling\n </label>\n <button type=\"button\" className=\"self-start px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-200 hover:bg-slate-700\" onClick={() => attempt(() => controller.setPaper({ seed: paper.seed + 1 }))}>\n New sheet\n </button>\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useMemo, useRef, useState } from 'react';\nimport {\n HARMONY_KINDS,\n MIXING_PAD_HEIGHT,\n MIXING_PAD_WIDTH,\n hsvToRgb,\n hueToWheel,\n parseHexColor,\n renderColorWheel,\n rgbToHexColor,\n rgbToHsv,\n wheelPick,\n wheelPoint,\n type ColorWheel,\n type HarmonyKind,\n type PaintEditorController,\n} from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, PixelCanvas, button, chip, panel, useAttempt } from './shared';\n\nexport interface ColorPanelProps {\n controller: PaintEditorController;\n /** Wheel diameter in px (default 168). */\n wheelSize?: number;\n /** Show the mixing pad (default true). */\n mixingPad?: boolean;\n className?: string;\n}\n\ntype PadTool = 'paint' | 'knife' | 'pick';\n\n/**\n * Colour: a hue wheel (painter's RYB or RGB) with the chosen harmony marked on it, saturation and\n * value, the paint and second colours, harmony chips, swatches, and a mixing pad to paint on,\n * smear with a palette knife (pigment mixing) and pick from.\n */\nexport const ColorPanel: React.FC<ColorPanelProps> = ({ controller, wheelSize = 168, mixingPad = true, className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const [wheel, setWheel] = useState<ColorWheel>('ryb');\n const [kind, setKind] = useState<HarmonyKind>('complementary');\n const [padTool, setPadTool] = useState<PadTool>('paint');\n const padPoints = useRef<Array<{ x: number; y: number; pressure?: number }> | null>(null);\n const ring = useMemo(() => renderColorWheel(wheelSize, wheel), [wheelSize, wheel]);\n const color = state.color;\n const harmony = useMemo(() => controller.harmony(kind, { color, wheel }), [controller, kind, color, wheel]);\n const [r, g, b] = parseHexColor(color);\n const hsv = rgbToHsv(r, g, b);\n const pad = useMemo(() => ({ width: MIXING_PAD_WIDTH, height: MIXING_PAD_HEIGHT, data: controller.mixingPad.pixels() }), [controller, state.mixingPadVersion]);\n const R = wheelSize / 2;\n const mid = R * 0.82;\n const setHsv = (s: number, v: number) => controller.setColor(rgbToHexColor(...hsvToRgb(hsv.h, s, v)));\n\n const padPoint = (e: React.PointerEvent) => {\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n const kx = MIXING_PAD_WIDTH / (rect.width || MIXING_PAD_WIDTH);\n const ky = MIXING_PAD_HEIGHT / (rect.height || MIXING_PAD_HEIGHT);\n const x = Math.min(MIXING_PAD_WIDTH, Math.max(0, (e.clientX - rect.left) * kx));\n const y = Math.min(MIXING_PAD_HEIGHT, Math.max(0, (e.clientY - rect.top) * ky));\n return e.pointerType === 'pen' && e.pressure > 0 ? { x, y, pressure: e.pressure } : { x, y };\n };\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"color-panel\">\n <div className=\"relative self-center\" style={{ width: wheelSize, height: wheelSize }}>\n <div\n role=\"slider\"\n aria-label=\"Hue wheel\"\n aria-valuemin={0}\n aria-valuemax={360}\n aria-valuenow={Math.round(hueToWheel(hsv.h, wheel))}\n tabIndex={0}\n className=\"absolute inset-0 cursor-crosshair\"\n onPointerDown={(e) => {\n const rect = e.currentTarget.getBoundingClientRect();\n controller.setColor(wheelPick(e.clientX - rect.left - R, e.clientY - rect.top - R, wheel, color));\n }}\n >\n <PixelCanvas pixels={ring} label=\"Colour wheel\" style={{ width: wheelSize, height: wheelSize }} />\n </div>\n <svg className=\"pointer-events-none absolute inset-0\" width={wheelSize} height={wheelSize} aria-hidden=\"true\">\n {harmony.map((h, i) => {\n const p = wheelPoint(h.angle, mid);\n return <circle key={i} cx={R + p.x} cy={R + p.y} r={i === 0 ? 7 : 5} fill={h.color} stroke=\"#fff\" strokeWidth={i === 0 ? 2 : 1} />;\n })}\n </svg>\n <div className=\"absolute rounded-full border border-slate-700\" style={{ left: R - R * 0.45, top: R - R * 0.45, width: R * 0.9, height: R * 0.9, background: color }} />\n </div>\n <div className=\"flex items-center gap-2\">\n <input type=\"color\" aria-label=\"Paint colour\" value={color} onChange={(e) => controller.setColor(e.target.value)} className=\"h-7 w-9 rounded bg-transparent\" />\n <input type=\"color\" aria-label=\"Second colour\" value={state.secondaryColor} onChange={(e) => controller.setSecondaryColor(e.target.value)} className=\"h-5 w-7 rounded bg-transparent\" />\n <button type=\"button\" className={button} title=\"Swap colours (X)\" onClick={() => controller.swapColors()}>\n Swap\n </button>\n <input\n aria-label=\"Hex colour\"\n defaultValue={color}\n key={color}\n onBlur={(e) => attempt(() => controller.setColor(e.target.value.startsWith('#') ? e.target.value : `#${e.target.value}`))}\n className=\"w-20 rounded bg-slate-800 px-1.5 py-0.5 font-mono\"\n />\n </div>\n <label className=\"flex items-center gap-2\">\n <span className=\"w-16 text-slate-400\">Saturation</span>\n <input type=\"range\" aria-label=\"Saturation\" min={0} max={1} step={0.01} value={hsv.s} onChange={(e) => setHsv(Number(e.target.value), hsv.v)} className=\"flex-1 accent-indigo-500\" />\n </label>\n <label className=\"flex items-center gap-2\">\n <span className=\"w-16 text-slate-400\">Value</span>\n <input type=\"range\" aria-label=\"Value\" min={0} max={1} step={0.01} value={hsv.v} onChange={(e) => setHsv(hsv.s, Number(e.target.value))} className=\"flex-1 accent-indigo-500\" />\n </label>\n <div className=\"flex items-center gap-1\">\n <select aria-label=\"Harmony\" value={kind} onChange={(e) => setKind(e.target.value as HarmonyKind)} className=\"rounded bg-slate-800 px-1 py-0.5\">\n {HARMONY_KINDS.map((k) => (\n <option key={k} value={k}>\n {k}\n </option>\n ))}\n </select>\n <button type=\"button\" className={chip(wheel === 'ryb')} aria-pressed={wheel === 'ryb'} onClick={() => setWheel('ryb')}>\n RYB\n </button>\n <button type=\"button\" className={chip(wheel === 'rgb')} aria-pressed={wheel === 'rgb'} onClick={() => setWheel('rgb')}>\n RGB\n </button>\n </div>\n <div className=\"flex flex-wrap gap-1\" aria-label=\"Harmony colours\">\n {harmony.map((h, i) => (\n <button key={i} type=\"button\" aria-label={`Use ${h.color}`} title={h.color} className=\"h-6 w-6 rounded ring-1 ring-slate-700\" style={{ background: h.color }} onClick={() => controller.setColor(h.color)} />\n ))}\n <button type=\"button\" className={button} onClick={() => harmony.forEach((h) => controller.addSwatch(h.color))}>\n + swatches\n </button>\n </div>\n <div className=\"flex flex-wrap gap-1\" role=\"listbox\" aria-label=\"Swatches\">\n {state.swatches.map((s, i) => (\n <button\n key={i}\n type=\"button\"\n role=\"option\"\n aria-selected={s.color === color}\n aria-label={s.name ?? s.color}\n title={`${s.name ?? s.color} (right-click to remove)`}\n className=\"h-5 w-5 rounded ring-1 ring-slate-700\"\n style={{ background: s.color }}\n onClick={() => controller.setColor(s.color)}\n onContextMenu={(e) => {\n e.preventDefault();\n controller.removeSwatch(i);\n }}\n />\n ))}\n <button type=\"button\" className={button} aria-label=\"Add swatch\" onClick={() => controller.addSwatch(color)}>\n +\n </button>\n </div>\n {mixingPad && (\n <div className=\"flex flex-col gap-1\" data-testid=\"mixing-pad\">\n <div className=\"flex items-center gap-1\">\n <span className=\"text-slate-400\">Mixing pad</span>\n {(['paint', 'knife', 'pick'] as const).map((t) => (\n <button key={t} type=\"button\" aria-pressed={padTool === t} className={chip(padTool === t)} onClick={() => setPadTool(t)}>\n {t === 'paint' ? 'Paint' : t === 'knife' ? 'Knife' : 'Pick'}\n </button>\n ))}\n <button type=\"button\" className={button} onClick={() => controller.clearMixingPad()}>\n Clear\n </button>\n </div>\n <div\n role=\"application\"\n aria-label=\"Mixing pad\"\n className=\"touch-none cursor-crosshair\"\n onPointerDown={(e) => {\n const p = padPoint(e);\n if (padTool === 'pick') {\n attempt(() => controller.mixingPadPick(p.x, p.y, { setColor: true }));\n return;\n }\n padPoints.current = [p];\n (e.target as Element).setPointerCapture?.(e.pointerId);\n }}\n onPointerMove={(e) => padPoints.current?.push(padPoint(e))}\n onPointerUp={() => {\n const pts = padPoints.current;\n padPoints.current = null;\n if (pts?.length) attempt(() => controller.mixingPadStroke(pts, { tool: padTool === 'knife' ? 'knife' : 'paint' }));\n }}\n >\n <PixelCanvas pixels={pad} label=\"Mixing pad pixels\" className=\"w-full rounded\" style={{ aspectRatio: `${MIXING_PAD_WIDTH} / ${MIXING_PAD_HEIGHT}` }} />\n </div>\n </div>\n )}\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useState } from 'react';\nimport { BLEND_MODES, type BlendMode, type PaintEditorController, type PaintLayerInfo } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, button, chip, panel, useAttempt } from './shared';\n\nexport interface PaintLayersPanelProps {\n controller: PaintEditorController;\n className?: string;\n}\n\n/** Siblings of a layer, bottom first, and its index among them. */\nfunction siblingIndex(layers: PaintLayerInfo[], l: PaintLayerInfo): { index: number; count: number } {\n const sibs = layers.filter((x) => x.parentId === l.parentId).reverse();\n return { index: sibs.findIndex((x) => x.id === l.id), count: sibs.length };\n}\n\n/**\n * The layer stack, top first: visibility, names (double-click to rename), the active layer's\n * opacity, blend mode and locks, and new layer / group, duplicate, move up / down, merge down and\n * delete. Every change is one undo step.\n */\nexport const PaintLayersPanel: React.FC<PaintLayersPanelProps> = ({ controller, className }) => {\n usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const [renaming, setRenaming] = useState<string | null>(null);\n const layers = controller.listLayers();\n const active = layers.find((l) => l.active) ?? null;\n const move = (delta: number) => {\n if (!active) return;\n const { index, count } = siblingIndex(layers, active);\n const to = Math.min(count - 1, Math.max(0, index + delta));\n if (to !== index) attempt(() => controller.moveLayer(active.id, to));\n };\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"paint-layers-panel\">\n <div className=\"flex flex-wrap gap-1\">\n <button type=\"button\" className={button} onClick={() => attempt(() => controller.addLayer())}>\n New layer\n </button>\n <button type=\"button\" className={button} onClick={() => attempt(() => controller.addLayer({ type: 'group' }))}>\n New group\n </button>\n <button type=\"button\" className={button} disabled={!active} onClick={() => active && attempt(() => controller.duplicateLayer(active.id))}>\n Duplicate\n </button>\n <button type=\"button\" className={button} disabled={!active} aria-label=\"Move layer up\" onClick={() => move(1)}>\n ↑\n </button>\n <button type=\"button\" className={button} disabled={!active} aria-label=\"Move layer down\" onClick={() => move(-1)}>\n ↓\n </button>\n <button type=\"button\" className={button} disabled={!active} onClick={() => active && attempt(() => controller.mergeDown(active.id))}>\n Merge down\n </button>\n <button type=\"button\" className={button} disabled={!active || layers.length < 2} onClick={() => active && attempt(() => controller.removeLayer(active.id))}>\n Delete\n </button>\n </div>\n <ul role=\"tree\" aria-label=\"Layers\" className=\"flex flex-col gap-0.5\">\n {layers.map((l) => (\n <li\n key={l.id}\n role=\"treeitem\"\n aria-selected={l.active}\n className={`flex items-center gap-1.5 rounded px-1.5 py-1 cursor-pointer ${l.active ? 'bg-indigo-600/30 ring-1 ring-indigo-500' : 'hover:bg-slate-800'}`}\n style={{ paddingLeft: 6 + l.depth * 12 }}\n onClick={() => controller.setActiveLayer(l.id)}\n >\n <button\n type=\"button\"\n aria-label={l.visible ? `Hide ${l.name}` : `Show ${l.name}`}\n className={`w-5 text-[11px] ${l.visible ? 'text-slate-200' : 'text-slate-600'}`}\n onClick={(e) => {\n e.stopPropagation();\n attempt(() => controller.updateLayer(l.id, { visible: !l.visible }));\n }}\n >\n {l.visible ? '●' : '○'}\n </button>\n {renaming === l.id ? (\n <input\n autoFocus\n aria-label=\"Layer name\"\n defaultValue={l.name}\n className=\"flex-1 rounded bg-slate-800 px-1\"\n onClick={(e) => e.stopPropagation()}\n onBlur={(e) => {\n setRenaming(null);\n if (e.target.value.trim() && e.target.value !== l.name) attempt(() => controller.updateLayer(l.id, { name: e.target.value }));\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter') (e.target as HTMLInputElement).blur();\n if (e.key === 'Escape') setRenaming(null);\n }}\n />\n ) : (\n <span className=\"flex-1 truncate\" onDoubleClick={() => setRenaming(l.id)}>\n {l.type === 'group' ? '▸ ' : ''}\n {l.name}\n </span>\n )}\n {l.locks.pixels || l.locks.all ? <span title=\"Locked\">🔒</span> : null}\n </li>\n ))}\n </ul>\n {active && (\n <div className=\"flex flex-col gap-1.5\">\n <label className=\"flex items-center gap-2\">\n <span className=\"w-14 text-slate-400\">Opacity</span>\n <input\n type=\"range\"\n aria-label=\"Layer opacity\"\n min={0}\n max={1}\n step={0.01}\n value={active.opacity}\n onChange={(e) => attempt(() => controller.updateLayer(active.id, { opacity: Number(e.target.value) }))}\n className=\"flex-1 accent-indigo-500\"\n />\n </label>\n <label className=\"flex items-center gap-2\">\n <span className=\"w-14 text-slate-400\">Blend</span>\n <select aria-label=\"Layer blend\" value={active.blend} onChange={(e) => attempt(() => controller.updateLayer(active.id, { blend: e.target.value as BlendMode }))} className=\"flex-1 rounded bg-slate-800 px-1 py-0.5\">\n {active.type === 'group' && <option value=\"pass-through\">Pass through</option>}\n {BLEND_MODES.map((m) => (\n <option key={m.id} value={m.id}>\n {m.label}\n </option>\n ))}\n </select>\n </label>\n <div className=\"flex gap-1\">\n {(['pixels', 'transparency'] as const).map((k) => (\n <button key={k} type=\"button\" aria-pressed={Boolean(active.locks[k])} className={chip(Boolean(active.locks[k]))} onClick={() => attempt(() => controller.updateLayer(active.id, { locks: { [k]: !active.locks[k] } }))}>\n {k === 'pixels' ? 'Lock pixels' : 'Lock transparency'}\n </button>\n ))}\n <button type=\"button\" aria-pressed={active.clipped} className={chip(active.clipped)} onClick={() => attempt(() => controller.updateLayer(active.id, { clipped: !active.clipped }))}>\n Clip\n </button>\n </div>\n </div>\n )}\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useState } from 'react';\nimport type { PaintEditorController, PaintTool } from '@pixerate/editor/paint-editor';\nimport { BrushPanel } from './BrushPanel';\nimport { ColorPanel } from './ColorPanel';\nimport { PaintCanvas } from './PaintCanvas';\nimport { PaintLayersPanel } from './PaintLayersPanel';\nimport { PaintToolbar } from './PaintToolbar';\nimport { PaperPanel } from './PaperPanel';\nimport { chip } from './shared';\n\nexport interface PaintEditorProps {\n controller: PaintEditorController;\n /** Base name of saved and exported files (default `painting`). */\n fileName?: string;\n /** Height of the editor (default 720 px). */\n height?: number | string;\n className?: string;\n}\n\ntype SideTab = 'color' | 'paper' | 'layers';\n\n/**\n * The paint editor: toolbar, brush library on the left, the canvas, and colour (wheel,\n * harmonies, swatches, mixing pad), paper and layers on the right.\n */\nexport const PaintEditor: React.FC<PaintEditorProps> = ({ controller, fileName, height = 720, className }) => {\n const [tool, setTool] = useState<PaintTool>('brush');\n const [tab, setTab] = useState<SideTab>('color');\n const [error, setError] = useState<string | null>(null);\n return (\n <div className={`flex flex-col gap-2 rounded-xl border border-slate-800 bg-slate-900 p-2 ${className ?? ''}`} style={{ height }} data-testid=\"paint-editor\">\n <PaintToolbar controller={controller} tool={tool} onToolChange={setTool} fileName={fileName} />\n <div className=\"flex min-h-0 flex-1 gap-2\">\n <BrushPanel controller={controller} className=\"w-60 shrink-0 overflow-y-auto pr-1\" />\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <PaintCanvas controller={controller} tool={tool} onError={setError} className=\"flex-1 rounded-lg\" />\n {error && (\n <p role=\"alert\" className=\"mt-1 text-[11px] text-rose-400\">\n {error}\n </p>\n )}\n </div>\n <div className=\"flex w-64 shrink-0 flex-col gap-2 overflow-y-auto pr-1\">\n <div className=\"flex gap-1\" role=\"tablist\" aria-label=\"Paint panels\">\n {(['color', 'paper', 'layers'] as const).map((t) => (\n <button key={t} type=\"button\" role=\"tab\" aria-selected={tab === t} className={chip(tab === t)} onClick={() => setTab(t)}>\n {t === 'color' ? 'Colour' : t === 'paper' ? 'Paper' : 'Layers'}\n </button>\n ))}\n </div>\n {tab === 'color' && <ColorPanel controller={controller} />}\n {tab === 'paper' && <PaperPanel controller={controller} />}\n {tab === 'layers' && <PaintLayersPanel controller={controller} />}\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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","names":["useMemo","useState","useState","useMemo","useRef","useEffect","useRef","useState","jsx","jsxs","jsx","jsxs","useRef","useMemo","useRef","useState","downloadBytes","jsx","jsxs","useState","useRef","useMemo","downloadBytes","useMemo","patchPath","readPath","jsx","jsxs","useMemo","readPath","patchPath","useMemo","useRef","useState","jsx","jsxs","useState","useRef","useMemo","useState","jsx","jsxs","useState","useState","jsx","jsxs","useState"]}
|
|
1
|
+
{"version":3,"sources":["../../src/paint-editor/usePaintEditor.ts","../../src/paint-editor/PaintCanvas.tsx","../../src/paint-editor/PaintToolbar.tsx","../../src/paint-editor/shared.tsx","../../src/paint-editor/BrushPanel.tsx","../../src/paint-editor/PaperPanel.tsx","../../src/paint-editor/ColorPanel.tsx","../../src/paint-editor/PaintLayersPanel.tsx","../../src/paint-editor/PaintEditor.tsx"],"sourcesContent":["import { useMemo, useState, useSyncExternalStore } from 'react';\nimport { PaintEditorController, type PaintEditorOptions, type PaintEditorState } from '@pixerate/editor/paint-editor';\n\nexport interface UsePaintEditorReturn {\n controller: PaintEditorController;\n /** The controller's snapshot (a new object after every change). */\n state: PaintEditorState;\n}\n\n/**\n * Creates a `PaintEditorController` once (from `options`, read on the first render) or uses the\n * one given, and re-renders on every change.\n */\nexport function usePaintEditor(options: PaintEditorOptions | PaintEditorController = {}): UsePaintEditorReturn {\n const [controller] = useState(() => (options instanceof PaintEditorController ? options : new PaintEditorController(options)));\n const state = usePaintEditorState(controller);\n return useMemo(() => ({ controller, state }), [controller, state]);\n}\n\n/** Subscribes to a controller's state. */\nexport function usePaintEditorState(controller: PaintEditorController): PaintEditorState {\n return useSyncExternalStore(\n (notify) => controller.subscribe(notify),\n () => controller.getState(),\n () => controller.getState()\n );\n}\n","import React, { useEffect, useMemo, useRef, useState } from 'react';\nimport {\n PaintCanvasPresenter,\n PaintGesture,\n fitZoom,\n guideOverlay,\n handlePaintShortcut,\n viewCssTransform,\n type PaintEditorController,\n type PaintTool,\n} from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\n\nexport interface PaintCanvasProps {\n controller: PaintEditorController;\n /** The active tool (default brush). */\n tool?: PaintTool;\n /** Draw the symmetry axes and perspective lines (default true). */\n showGuides?: boolean;\n /** Fit the canvas in the viewport on mount (default true). */\n fitOnMount?: boolean;\n /** Called with a refusal (hidden or locked layer). */\n onError?: (message: string | null) => void;\n className?: string;\n}\n\n/**\n * The painting surface: a document-sized canvas the compositor draws into (only changed tiles are\n * uploaded), shown through the view's zoom, pan, rotation and mirroring as a CSS transform (the\n * pixels never resample). Pointer input goes through `PaintGesture`: coalesced samples, a predicted\n * tail drawn as a thin preview, palm rejection, middle-button pan, wheel zoom and Shift+wheel\n * rotation. Guides and floating reference images are drawn on top.\n */\nexport const PaintCanvas: React.FC<PaintCanvasProps> = ({ controller, tool = 'brush', showGuides = true, fitOnMount = true, onError, className }) => {\n const state = usePaintEditorState(controller);\n const viewport = useRef<HTMLDivElement>(null);\n const canvas = useRef<HTMLCanvasElement>(null);\n const [size, setSize] = useState({ width: 800, height: 600 });\n const measured = useRef(false);\n const [predicted, setPredicted] = useState<Array<{ x: number; y: number }>>([]);\n const presenter = useMemo(() => new PaintCanvasPresenter(controller), [controller]);\n const gesture = useMemo(\n () =>\n new PaintGesture(controller, () => {\n const r = viewport.current?.getBoundingClientRect();\n return { left: r?.left ?? 0, top: r?.top ?? 0, width: r?.width || size.width, height: r?.height || size.height };\n }),\n // The box reads the element when called; `size` is only the jsdom fallback.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [controller]\n );\n gesture.tool = tool;\n const { canvas: doc } = state.document;\n\n useEffect(() => {\n const el = viewport.current;\n if (!el || typeof ResizeObserver === 'undefined') return;\n const ro = new ResizeObserver(() => {\n if (!el.clientWidth || !el.clientHeight) return;\n measured.current = true;\n setSize({ width: el.clientWidth, height: el.clientHeight });\n });\n ro.observe(el);\n return () => ro.disconnect();\n }, []);\n\n // Fit once per canvas size, after the viewport has been measured (or at once where it cannot be).\n const fitted = useRef<string | null>(null);\n useEffect(() => {\n const key = `${doc.width}x${doc.height}`;\n if (!fitOnMount || fitted.current === key) return;\n if (typeof ResizeObserver !== 'undefined' && !measured.current) return;\n fitted.current = key;\n controller.setView({ zoom: fitZoom(doc, size), pan: { x: 0, y: 0 } });\n }, [controller, doc, size, fitOnMount]);\n\n // Upload changed tiles whenever the state changes.\n useEffect(() => {\n const ctx = canvas.current?.getContext('2d');\n if (ctx && typeof ctx.createImageData === 'function') presenter.render(ctx as never);\n else controller.takeDirty();\n }, [state, presenter, controller]);\n\n // Wheel needs a non-passive listener to prevent page scroll (see GOTCHAS).\n useEffect(() => {\n const el = viewport.current;\n if (!el) return;\n const onWheel = (e: WheelEvent) => {\n e.preventDefault();\n gesture.wheel(e);\n };\n el.addEventListener('wheel', onWheel, { passive: false });\n return () => el.removeEventListener('wheel', onWheel);\n }, [gesture]);\n\n const report = () => onError?.(gesture.error);\n const transform = viewCssTransform(state.view, doc, size);\n const lines = showGuides ? guideOverlay(controller) : [];\n\n return (\n <div\n ref={viewport}\n tabIndex={0}\n role=\"application\"\n aria-label=\"Paint canvas\"\n data-testid=\"paint-canvas\"\n className={`relative overflow-hidden bg-slate-950 outline-none touch-none select-none ${className ?? ''}`}\n style={{ cursor: tool === 'pan' ? 'grab' : tool === 'eyedropper' ? 'copy' : 'crosshair' }}\n onPointerDown={(e) => {\n viewport.current?.focus();\n if (gesture.down(e.nativeEvent)) (e.target as Element).setPointerCapture?.(e.pointerId);\n report();\n }}\n onPointerMove={(e) => {\n gesture.move(e.nativeEvent);\n if (gesture.predicted.length || predicted.length) setPredicted(gesture.predicted.map((p) => ({ x: p.x, y: p.y })));\n }}\n onPointerUp={(e) => {\n gesture.up(e.nativeEvent);\n setPredicted([]);\n }}\n onPointerCancel={() => {\n gesture.cancel();\n setPredicted([]);\n }}\n onKeyDown={(e) => {\n if (handlePaintShortcut(controller, gesture, e)) e.preventDefault();\n }}\n >\n <canvas\n ref={canvas}\n width={doc.width}\n height={doc.height}\n className=\"absolute left-0 top-0 shadow-2xl\"\n style={{ transform, transformOrigin: '0 0', imageRendering: state.view.zoom > 2 ? 'pixelated' : 'auto' }}\n />\n <svg className=\"absolute left-0 top-0 pointer-events-none overflow-visible\" width={doc.width} height={doc.height} style={{ transform, transformOrigin: '0 0' }} aria-hidden=\"true\">\n {lines.map((l, i) => (\n <line\n key={i}\n x1={l.from.x}\n y1={l.from.y}\n x2={l.to.x}\n y2={l.to.y}\n stroke={l.kind === 'symmetry' ? '#22d3ee' : '#f472b6'}\n strokeOpacity={l.kind === 'symmetry' ? 0.8 : 0.35}\n strokeWidth={1 / state.view.zoom}\n strokeDasharray={l.kind === 'symmetry' ? `${6 / state.view.zoom} ${4 / state.view.zoom}` : undefined}\n />\n ))}\n {predicted.length > 0 && (\n <polyline points={predicted.map((p) => `${p.x},${p.y}`).join(' ')} fill=\"none\" stroke={state.color} strokeOpacity={0.5} strokeWidth={Math.max(1, state.brush.tip.size / 2)} strokeLinecap=\"round\" />\n )}\n </svg>\n {state.guides.references\n .filter((r) => r.visible)\n .map((r) => (\n <ReferencePanel key={r.id} controller={controller} id={r.id} />\n ))}\n <div className=\"absolute bottom-1 right-2 text-[10px] text-slate-500 pointer-events-none\" data-testid=\"paint-view-status\">\n {Math.round(state.view.zoom * 100)}% · {Math.round(state.view.rotation)}°{state.view.mirror ? ' · mirrored' : ''}\n </div>\n </div>\n );\n};\n\n/** A floating reference image: drag its title bar to move it, click the image to pick a colour. */\nconst ReferencePanel: React.FC<{ controller: PaintEditorController; id: string }> = ({ controller, id }) => {\n const state = usePaintEditorState(controller);\n const ref = state.guides.references.find((r) => r.id === id);\n const drag = useRef<{ x: number; y: number; ox: number; oy: number } | null>(null);\n if (!ref) return null;\n const h = (ref.height / ref.width) * ref.displayWidth;\n return (\n <div\n className=\"absolute rounded border border-slate-700 bg-slate-900/95 shadow-xl\"\n style={{ left: ref.x, top: ref.y, width: ref.displayWidth }}\n data-testid=\"paint-reference\"\n onPointerDown={(e) => e.stopPropagation()}\n >\n <div\n className=\"flex items-center justify-between px-1.5 py-0.5 text-[10px] text-slate-300 cursor-move\"\n onPointerDown={(e) => {\n drag.current = { x: e.clientX, y: e.clientY, ox: ref.x, oy: ref.y };\n (e.target as Element).setPointerCapture?.(e.pointerId);\n }}\n onPointerMove={(e) => {\n const d = drag.current;\n if (d) controller.updateReferenceImage(id, { x: d.ox + e.clientX - d.x, y: d.oy + e.clientY - d.y });\n }}\n onPointerUp={() => (drag.current = null)}\n >\n <span className=\"truncate\">{ref.name}</span>\n <button type=\"button\" aria-label={`Hide ${ref.name}`} className=\"px-1 text-slate-400 hover:text-white\" onClick={() => controller.updateReferenceImage(id, { visible: false })}>\n ×\n </button>\n </div>\n <img\n src={ref.src}\n alt={ref.name}\n draggable={false}\n width={ref.displayWidth}\n height={h}\n className=\"block cursor-copy\"\n onClick={(e) => {\n const rect = (e.target as HTMLElement).getBoundingClientRect();\n const k = ref.width / (rect.width || ref.displayWidth);\n controller.setColor(controller.pickReferenceColor(id, Math.min(ref.width - 1, (e.clientX - rect.left) * k), Math.min(ref.height - 1, (e.clientY - rect.top) * k)));\n }}\n />\n </div>\n );\n};\n","import React, { useRef } from 'react';\nimport { PAINT_TOOLS, SYMMETRY_MODES, decodeImageBlob, downloadBytes, type PaintEditorController, type PaintTool, type SymmetryMode } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, button, chip, useAttempt } from './shared';\n\nexport interface PaintToolbarProps {\n controller: PaintEditorController;\n tool: PaintTool;\n onToolChange: (tool: PaintTool) => void;\n /** Base name of saved and exported files (default `painting`). */\n fileName?: string;\n className?: string;\n}\n\n/**\n * Tools (brush, eyedropper, pan, rotate view), undo / redo, view rotation, mirroring and reset,\n * the symmetry and perspective guides, the tracing image and reference images, the drawing hand,\n * and file actions: save / open JSON, export PNG, JPEG and PSD.\n */\nexport const PaintToolbar: React.FC<PaintToolbarProps> = ({ controller, tool, onToolChange, fileName = 'painting', className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const openRef = useRef<HTMLInputElement>(null);\n const tracingRef = useRef<HTMLInputElement>(null);\n const refRef = useRef<HTMLInputElement>(null);\n const { symmetry, perspective, tracing } = state.guides;\n const { canvas } = state.document;\n\n const exportImage = (format: 'image/png' | 'image/jpeg') =>\n attempt(async () => downloadBytes(await controller.exportImage({ format }), `${fileName}.${format === 'image/png' ? 'png' : 'jpg'}`, format));\n\n return (\n <div className={`flex flex-wrap items-center gap-1.5 text-xs text-slate-200 ${className ?? ''}`} role=\"toolbar\" aria-label=\"Paint toolbar\" data-testid=\"paint-toolbar\">\n {PAINT_TOOLS.map((t) => (\n <button key={t.id} type=\"button\" aria-pressed={tool === t.id} title={`${t.label} (${t.key.toUpperCase()})`} className={chip(tool === t.id)} onClick={() => onToolChange(t.id)}>\n {t.label}\n </button>\n ))}\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} disabled={!state.canUndo} title={state.undoLabel ? `Undo ${state.undoLabel}` : 'Undo'} onClick={() => controller.undo()}>\n Undo\n </button>\n <button type=\"button\" className={button} disabled={!state.canRedo} title={state.redoLabel ? `Redo ${state.redoLabel}` : 'Redo'} onClick={() => controller.redo()}>\n Redo\n </button>\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} aria-label=\"Rotate view left\" onClick={() => controller.setView({ rotation: state.view.rotation - 15 })}>\n ⟲\n </button>\n <button type=\"button\" className={button} aria-label=\"Rotate view right\" onClick={() => controller.setView({ rotation: state.view.rotation + 15 })}>\n ⟳\n </button>\n <button type=\"button\" className={chip(state.view.mirror)} aria-pressed={state.view.mirror} onClick={() => controller.setView({ mirror: !state.view.mirror })}>\n Mirror view\n </button>\n <button type=\"button\" className={button} onClick={() => controller.resetView()}>\n Reset view\n </button>\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <label className=\"flex items-center gap-1\">\n Symmetry\n <select\n aria-label=\"Symmetry\"\n value={symmetry.mode}\n onChange={(e) => controller.setSymmetry({ mode: e.target.value as SymmetryMode, center: symmetry.mode === 'off' ? { x: canvas.width / 2, y: canvas.height / 2 } : symmetry.center })}\n className=\"rounded bg-slate-800 px-1 py-0.5\"\n >\n {SYMMETRY_MODES.map((m) => (\n <option key={m} value={m}>\n {m}\n </option>\n ))}\n </select>\n </label>\n {symmetry.mode === 'kaleidoscope' && (\n <input\n type=\"number\"\n aria-label=\"Kaleidoscope segments\"\n min={2}\n max={32}\n value={symmetry.segments}\n onChange={(e) => controller.setSymmetry({ segments: Number(e.target.value) })}\n className=\"w-12 rounded bg-slate-800 px-1 py-0.5\"\n />\n )}\n <button\n type=\"button\"\n className={chip(perspective.enabled)}\n aria-pressed={perspective.enabled}\n onClick={() =>\n attempt(() =>\n controller.setPerspective(\n perspective.enabled ? { enabled: false } : { enabled: true, points: perspective.points.length ? perspective.points : [{ x: canvas.width / 2, y: canvas.height * 0.4 }] }\n )\n )\n }\n >\n Perspective\n </button>\n {perspective.enabled && (\n <select\n aria-label=\"Vanishing points\"\n value={perspective.points.length}\n onChange={(e) => {\n const n = Number(e.target.value);\n const y = canvas.height * 0.4;\n const pts = n === 1 ? [{ x: canvas.width / 2, y }] : n === 2 ? [{ x: -canvas.width * 0.5, y }, { x: canvas.width * 1.5, y }] : [{ x: -canvas.width * 0.5, y }, { x: canvas.width * 1.5, y }, { x: canvas.width / 2, y: canvas.height * 3 }];\n attempt(() => controller.setPerspective({ points: pts }));\n }}\n className=\"rounded bg-slate-800 px-1 py-0.5\"\n >\n <option value={1}>1-point</option>\n <option value={2}>2-point</option>\n <option value={3}>3-point</option>\n </select>\n )}\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} onClick={() => tracingRef.current?.click()}>\n Tracing image…\n </button>\n {tracing && (\n <>\n <input\n type=\"range\"\n aria-label=\"Tracing opacity\"\n min={0}\n max={1}\n step={0.05}\n value={tracing.opacity}\n onChange={(e) => controller.updateTracing({ opacity: Number(e.target.value) })}\n className=\"w-16 accent-indigo-500\"\n />\n <button type=\"button\" className={chip(tracing.sampleColors)} aria-pressed={tracing.sampleColors} onClick={() => controller.updateTracing({ sampleColors: !tracing.sampleColors })}>\n Trace colours\n </button>\n <button type=\"button\" className={chip(tracing.visible)} aria-pressed={tracing.visible} onClick={() => controller.updateTracing({ visible: !tracing.visible })}>\n Show tracing\n </button>\n <button type=\"button\" className={button} onClick={() => controller.clearTracingImage()}>\n Remove tracing\n </button>\n </>\n )}\n <button type=\"button\" className={button} onClick={() => refRef.current?.click()}>\n Reference…\n </button>\n <button type=\"button\" className={button} title=\"Which hand holds the pen (palm rejection)\" onClick={() => controller.setHand(state.hand === 'right' ? 'left' : 'right')}>\n {state.hand === 'right' ? 'Right-handed' : 'Left-handed'}\n </button>\n <span className=\"mx-1 h-4 w-px bg-slate-700\" />\n <button type=\"button\" className={button} onClick={() => attempt(() => downloadBytes(JSON.stringify(controller.toJSON()), `${fileName}.paint.json`, 'application/json'))}>\n Save\n </button>\n <button type=\"button\" className={button} onClick={() => openRef.current?.click()}>\n Open…\n </button>\n <button type=\"button\" className={button} onClick={() => exportImage('image/png')}>\n PNG\n </button>\n <button type=\"button\" className={button} onClick={() => exportImage('image/jpeg')}>\n JPEG\n </button>\n <button type=\"button\" className={button} onClick={() => attempt(() => downloadBytes(controller.exportPsd().bytes, `${fileName}.psd`, 'image/vnd.adobe.photoshop'))}>\n PSD\n </button>\n <input\n ref={openRef}\n type=\"file\"\n accept=\".json,application/json\"\n aria-label=\"Open painting\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.loadJSON(JSON.parse(await f.text())));\n e.target.value = '';\n }}\n />\n <input\n ref={tracingRef}\n type=\"file\"\n accept=\"image/*\"\n aria-label=\"Load tracing image\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.setTracingImage({ pixels: await decodeImageBlob(f) }));\n e.target.value = '';\n }}\n />\n <input\n ref={refRef}\n type=\"file\"\n accept=\"image/*\"\n aria-label=\"Add reference image\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.addReferenceImage({ pixels: await decodeImageBlob(f), name: f.name }));\n e.target.value = '';\n }}\n />\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useEffect, useRef, useState } from 'react';\nimport type { SliderControl } from '@pixerate/editor/paint-editor';\n\nexport const chip = (on: boolean) => `px-2 py-1 rounded text-[11px] ${on ? 'bg-indigo-600 text-white' : 'bg-slate-800 text-slate-300 hover:text-white'}`;\nexport const button = 'px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-200 hover:bg-slate-700 disabled:opacity-40';\nexport const panel = 'flex flex-col gap-2 text-xs text-slate-200';\n\n/** Draws RGBA pixels into a canvas (nothing without a 2D context, as in jsdom). */\nexport const PixelCanvas: React.FC<{ pixels: { width: number; height: number; data: Uint8ClampedArray } | null; label: string; className?: string; style?: React.CSSProperties }> = ({ pixels, label, className, style }) => {\n const ref = useRef<HTMLCanvasElement>(null);\n useEffect(() => {\n const canvas = ref.current;\n const ctx = canvas?.getContext('2d');\n if (!canvas || !ctx || !pixels || typeof ctx.createImageData !== 'function') return;\n canvas.width = pixels.width;\n canvas.height = pixels.height;\n const img = ctx.createImageData(pixels.width, pixels.height);\n img.data.set(pixels.data);\n ctx.putImageData(img, 0, 0);\n }, [pixels]);\n return <canvas ref={ref} role=\"img\" aria-label={label} className={className} style={style} width={pixels?.width} height={pixels?.height} />;\n};\n\nconst fmt = (c: SliderControl, v: number) => (c.step >= 1 ? String(Math.round(v)) : v.toFixed(2));\n\n/**\n * A labelled range input. `onChange` runs while dragging; `onCommit` (if given) runs once on\n * release (the native `change` event), for settings that are undo steps.\n */\nexport const PaintSlider: React.FC<{ control: SliderControl; value: number; onChange?: (v: number) => void; onCommit?: (v: number) => void }> = ({ control, value, onChange, onCommit }) => {\n const [draft, setDraft] = useState<number | null>(null);\n const ref = useRef<HTMLInputElement>(null);\n const commit = useRef(onCommit);\n commit.current = onCommit;\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const done = () => {\n commit.current?.(Number(el.value));\n setDraft(null);\n };\n el.addEventListener('change', done);\n return () => el.removeEventListener('change', done);\n }, []);\n const shown = draft ?? value;\n return (\n <label className=\"flex flex-col gap-0.5\" data-path={control.path}>\n <span className=\"flex justify-between text-slate-400\">\n <span>{control.label}</span>\n <span className=\"font-mono\">{fmt(control, shown)}</span>\n </span>\n <input\n ref={ref}\n type=\"range\"\n aria-label={control.label}\n min={control.min}\n max={control.max}\n step={control.step}\n value={shown}\n onChange={(e) => {\n const v = Number(e.target.value);\n if (onCommit) setDraft(v);\n onChange?.(v);\n }}\n className=\"w-full accent-indigo-500\"\n />\n </label>\n );\n};\n\n/** Runs `fn`, turning a thrown error into a message. */\nexport function useAttempt(): [string | null, (fn: () => unknown) => void, (msg: string | null) => void] {\n const [error, setError] = useState<string | null>(null);\n const attempt = (fn: () => unknown) => {\n try {\n setError(null);\n const r = fn();\n if (r && typeof (r as Promise<unknown>).catch === 'function') (r as Promise<unknown>).catch((e) => setError(e instanceof Error ? e.message : String(e)));\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n }\n };\n return [error, attempt, setError];\n}\n\nexport const ErrorLine: React.FC<{ error: string | null }> = ({ error }) =>\n error ? (\n <p role=\"alert\" className=\"text-[11px] text-rose-400\">\n {error}\n </p>\n ) : null;\n\n/** A colour input that commits once when the picker closes (the native `change` event). */\nexport const CommitColorInput: React.FC<{ value: string; label: string; onCommit: (v: string) => void; className?: string }> = ({ value, label, onCommit, className }) => {\n const ref = useRef<HTMLInputElement>(null);\n const commit = useRef(onCommit);\n commit.current = onCommit;\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const done = () => commit.current(el.value);\n el.addEventListener('change', done);\n return () => el.removeEventListener('change', done);\n }, []);\n return <input ref={ref} type=\"color\" aria-label={label} defaultValue={value} key={value} className={className} />;\n};\n","import React, { useMemo, useRef, useState } from 'react';\nimport { BRUSH_ROTATIONS, BRUSH_SLIDERS, downloadBytes, patchPath, readPath, type BrushRotation, type PaintEditorController } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, PaintSlider, PixelCanvas, button, panel, useAttempt } from './shared';\n\nexport interface BrushPanelProps {\n controller: PaintEditorController;\n /** Thumbnail size in px (default 112 × 32). */\n thumbnailWidth?: number;\n thumbnailHeight?: number;\n className?: string;\n}\n\n/**\n * The brush library (thumbnails rendered from a test stroke on the current paper, grouped by\n * category) and the active brush's settings: size, opacity, flow, hardness, spacing, roundness,\n * angle, paper grain, position and pressure smoothing, dynamics and rotation mode. Save the edited\n * brush, import and export libraries as JSON.\n */\nexport const BrushPanel: React.FC<BrushPanelProps> = ({ controller, thumbnailWidth = 112, thumbnailHeight = 32, className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const [saveName, setSaveName] = useState('');\n const fileRef = useRef<HTMLInputElement>(null);\n const { brush, brushes } = state;\n const paper = state.document.paper;\n const thumbs = useMemo(\n () => new Map(brushes.map((b) => [b.id, controller.brushThumbnail(b.id, { width: thumbnailWidth, height: thumbnailHeight, color: '#26324a' })])),\n // Thumbnails follow the library and the paper.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [controller, brushes, paper, thumbnailWidth, thumbnailHeight]\n );\n const slug = (name: string) => name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 60) || 'brush';\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"brush-panel\">\n <div className=\"grid grid-cols-2 gap-1\" role=\"listbox\" aria-label=\"Brushes\">\n {brushes.map((b) => (\n <button\n key={b.id}\n type=\"button\"\n role=\"option\"\n aria-selected={brush.id === b.id}\n title={`${b.name} (${b.category})`}\n className={`flex flex-col items-start gap-0.5 rounded p-1 text-left ${brush.id === b.id ? 'bg-indigo-600/30 ring-1 ring-indigo-500' : 'bg-slate-900 hover:bg-slate-800'}`}\n onClick={() => controller.setBrush({ id: b.id })}\n >\n <PixelCanvas pixels={thumbs.get(b.id) ?? null} label={`${b.name} thumbnail`} className=\"rounded\" style={{ width: '100%', aspectRatio: `${thumbnailWidth} / ${thumbnailHeight}` }} />\n <span className=\"truncate text-[10px] text-slate-300\">{b.name}</span>\n </button>\n ))}\n </div>\n <div className=\"flex flex-col gap-1.5\">\n {BRUSH_SLIDERS.map((c) => (\n <PaintSlider key={c.path} control={c} value={readPath(brush, c.path)} onChange={(v) => controller.setBrush(patchPath(brush as never, c.path, v) as never)} />\n ))}\n <label className=\"flex items-center justify-between gap-2\">\n <span className=\"text-slate-400\">Rotation</span>\n <select aria-label=\"Brush rotation\" value={brush.rotation} onChange={(e) => controller.setBrush({ rotation: e.target.value as BrushRotation })} className=\"rounded bg-slate-800 px-1 py-0.5\">\n {BRUSH_ROTATIONS.map((r) => (\n <option key={r} value={r}>\n {r === 'stroke' ? 'Follow stroke' : r === 'barrel' ? 'Pen barrel' : 'Fixed'}\n </option>\n ))}\n </select>\n </label>\n <label className=\"flex items-center gap-2\">\n <input type=\"checkbox\" checked={brush.tip.pressureSize} onChange={(e) => controller.setBrush({ tip: { pressureSize: e.target.checked } })} /> Pressure → size\n </label>\n <label className=\"flex items-center gap-2\">\n <input type=\"checkbox\" checked={brush.tip.pressureOpacity} onChange={(e) => controller.setBrush({ tip: { pressureOpacity: e.target.checked } })} /> Pressure → opacity\n </label>\n </div>\n <div className=\"flex flex-wrap items-center gap-1\">\n <input value={saveName} placeholder=\"Brush name\" aria-label=\"Brush name\" onChange={(e) => setSaveName(e.target.value)} className=\"w-28 rounded bg-slate-800 px-1.5 py-0.5\" />\n <button type=\"button\" className={button} disabled={!saveName.trim()} onClick={() => attempt(() => (controller.saveBrush({ id: slug(saveName), name: saveName.trim() }), setSaveName('')))}>\n Save brush\n </button>\n <button type=\"button\" className={button} onClick={() => attempt(() => downloadBytes(JSON.stringify(controller.exportBrushes(), null, 2), 'brushes.json', 'application/json'))}>\n Export\n </button>\n <button type=\"button\" className={button} onClick={() => fileRef.current?.click()}>\n Import…\n </button>\n <input\n ref={fileRef}\n type=\"file\"\n accept=\".json,application/json\"\n aria-label=\"Import brushes\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) attempt(async () => controller.importBrushes(JSON.parse(await f.text())));\n e.target.value = '';\n }}\n />\n </div>\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useMemo } from 'react';\nimport { PAPER_FAMILIES, PAPER_LIBRARY, PAPER_SLIDERS, patchPath, readPath, renderPaper, type PaintEditorController } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { CommitColorInput, ErrorLine, PaintSlider, PixelCanvas, panel, useAttempt } from './shared';\n\nexport interface PaperPanelProps {\n controller: PaintEditorController;\n className?: string;\n}\n\nconst SWATCH = { x: 0, y: 0, width: 64, height: 40 };\n\n/**\n * The paper library by family (each a generated grain preview) and the current paper's colour,\n * grain depth, scale, shading and contrast, plus the wet-media properties stored for later.\n * Each change is one undo step (sliders commit on release).\n */\nexport const PaperPanel: React.FC<PaperPanelProps> = ({ controller, className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const paper = state.document.paper;\n const previews = useMemo(() => new Map(PAPER_LIBRARY.map((p) => [p.preset, { ...SWATCH, data: renderPaper({ ...p, shading: Math.max(0.8, p.shading) }, SWATCH) }])), []);\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"paper-panel\">\n {PAPER_FAMILIES.map((family) => (\n <div key={family}>\n <div className=\"mb-0.5 text-[10px] uppercase tracking-wide text-slate-500\">{family}</div>\n <div className=\"flex flex-wrap gap-1\" role=\"listbox\" aria-label={`${family} papers`}>\n {PAPER_LIBRARY.filter((p) => p.family === family).map((p) => (\n <button\n key={p.preset}\n type=\"button\"\n role=\"option\"\n aria-selected={paper.preset === p.preset}\n title={p.name}\n className={`rounded p-0.5 ${paper.preset === p.preset ? 'ring-2 ring-indigo-500' : 'ring-1 ring-slate-700 hover:ring-slate-500'}`}\n onClick={() => attempt(() => controller.setPaper({ preset: p.preset }))}\n >\n <PixelCanvas pixels={previews.get(p.preset) ?? null} label={p.name} style={{ width: 48, height: 30 }} />\n </button>\n ))}\n </div>\n </div>\n ))}\n <div className=\"text-slate-300\">{paper.name}</div>\n <label className=\"flex items-center justify-between\">\n <span className=\"text-slate-400\">Colour</span>\n <CommitColorInput label=\"Paper colour\" value={paper.color} onCommit={(v) => attempt(() => controller.setPaper({ color: v }))} className=\"h-6 w-10 rounded bg-transparent\" />\n </label>\n {PAPER_SLIDERS.map((c) => (\n <PaintSlider key={c.path} control={c} value={readPath(paper, c.path)} onCommit={(v) => attempt(() => controller.setPaper(patchPath(paper as never, c.path, v) as never))} />\n ))}\n <label className=\"flex items-center gap-2\">\n <input type=\"checkbox\" checked={paper.tiling === 'mirror'} onChange={(e) => attempt(() => controller.setPaper({ tiling: e.target.checked ? 'mirror' : 'repeat' }))} /> Mirror tiling\n </label>\n <button type=\"button\" className=\"self-start px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-200 hover:bg-slate-700\" onClick={() => attempt(() => controller.setPaper({ seed: paper.seed + 1 }))}>\n New sheet\n </button>\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useMemo, useRef, useState } from 'react';\nimport {\n HARMONY_KINDS,\n MIXING_PAD_HEIGHT,\n MIXING_PAD_WIDTH,\n hsvToRgb,\n hueToWheel,\n parseHexColor,\n renderColorWheel,\n rgbToHexColor,\n rgbToHsv,\n wheelPick,\n wheelPoint,\n type ColorWheel,\n type HarmonyKind,\n type PaintEditorController,\n} from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, PixelCanvas, button, chip, panel, useAttempt } from './shared';\n\nexport interface ColorPanelProps {\n controller: PaintEditorController;\n /** Wheel diameter in px (default 168). */\n wheelSize?: number;\n /** Show the mixing pad (default true). */\n mixingPad?: boolean;\n className?: string;\n}\n\ntype PadTool = 'paint' | 'knife' | 'pick';\n\n/**\n * Colour: a hue wheel (painter's RYB or RGB) with the chosen harmony marked on it, saturation and\n * value, the paint and second colours, harmony chips, swatches, and a mixing pad to paint on,\n * smear with a palette knife (pigment mixing) and pick from.\n */\nexport const ColorPanel: React.FC<ColorPanelProps> = ({ controller, wheelSize = 168, mixingPad = true, className }) => {\n const state = usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const [wheel, setWheel] = useState<ColorWheel>('ryb');\n const [kind, setKind] = useState<HarmonyKind>('complementary');\n const [padTool, setPadTool] = useState<PadTool>('paint');\n const padPoints = useRef<Array<{ x: number; y: number; pressure?: number }> | null>(null);\n const ring = useMemo(() => renderColorWheel(wheelSize, wheel), [wheelSize, wheel]);\n const color = state.color;\n const harmony = useMemo(() => controller.harmony(kind, { color, wheel }), [controller, kind, color, wheel]);\n const [r, g, b] = parseHexColor(color);\n const hsv = rgbToHsv(r, g, b);\n const pad = useMemo(() => ({ width: MIXING_PAD_WIDTH, height: MIXING_PAD_HEIGHT, data: controller.mixingPad.pixels() }), [controller, state.mixingPadVersion]);\n const R = wheelSize / 2;\n const mid = R * 0.82;\n const setHsv = (s: number, v: number) => controller.setColor(rgbToHexColor(...hsvToRgb(hsv.h, s, v)));\n\n const padPoint = (e: React.PointerEvent) => {\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n const kx = MIXING_PAD_WIDTH / (rect.width || MIXING_PAD_WIDTH);\n const ky = MIXING_PAD_HEIGHT / (rect.height || MIXING_PAD_HEIGHT);\n const x = Math.min(MIXING_PAD_WIDTH, Math.max(0, (e.clientX - rect.left) * kx));\n const y = Math.min(MIXING_PAD_HEIGHT, Math.max(0, (e.clientY - rect.top) * ky));\n return e.pointerType === 'pen' && e.pressure > 0 ? { x, y, pressure: e.pressure } : { x, y };\n };\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"color-panel\">\n <div className=\"relative self-center\" style={{ width: wheelSize, height: wheelSize }}>\n <div\n role=\"slider\"\n aria-label=\"Hue wheel\"\n aria-valuemin={0}\n aria-valuemax={360}\n aria-valuenow={Math.round(hueToWheel(hsv.h, wheel))}\n tabIndex={0}\n className=\"absolute inset-0 cursor-crosshair\"\n onPointerDown={(e) => {\n const rect = e.currentTarget.getBoundingClientRect();\n controller.setColor(wheelPick(e.clientX - rect.left - R, e.clientY - rect.top - R, wheel, color));\n }}\n >\n <PixelCanvas pixels={ring} label=\"Colour wheel\" style={{ width: wheelSize, height: wheelSize }} />\n </div>\n <svg className=\"pointer-events-none absolute inset-0\" width={wheelSize} height={wheelSize} aria-hidden=\"true\">\n {harmony.map((h, i) => {\n const p = wheelPoint(h.angle, mid);\n return <circle key={i} cx={R + p.x} cy={R + p.y} r={i === 0 ? 7 : 5} fill={h.color} stroke=\"#fff\" strokeWidth={i === 0 ? 2 : 1} />;\n })}\n </svg>\n <div className=\"absolute rounded-full border border-slate-700\" style={{ left: R - R * 0.45, top: R - R * 0.45, width: R * 0.9, height: R * 0.9, background: color }} />\n </div>\n <div className=\"flex items-center gap-2\">\n <input type=\"color\" aria-label=\"Paint colour\" value={color} onChange={(e) => controller.setColor(e.target.value)} className=\"h-7 w-9 rounded bg-transparent\" />\n <input type=\"color\" aria-label=\"Second colour\" value={state.secondaryColor} onChange={(e) => controller.setSecondaryColor(e.target.value)} className=\"h-5 w-7 rounded bg-transparent\" />\n <button type=\"button\" className={button} title=\"Swap colours (X)\" onClick={() => controller.swapColors()}>\n Swap\n </button>\n <input\n aria-label=\"Hex colour\"\n defaultValue={color}\n key={color}\n onBlur={(e) => attempt(() => controller.setColor(e.target.value.startsWith('#') ? e.target.value : `#${e.target.value}`))}\n className=\"w-20 rounded bg-slate-800 px-1.5 py-0.5 font-mono\"\n />\n </div>\n <label className=\"flex items-center gap-2\">\n <span className=\"w-16 text-slate-400\">Saturation</span>\n <input type=\"range\" aria-label=\"Saturation\" min={0} max={1} step={0.01} value={hsv.s} onChange={(e) => setHsv(Number(e.target.value), hsv.v)} className=\"flex-1 accent-indigo-500\" />\n </label>\n <label className=\"flex items-center gap-2\">\n <span className=\"w-16 text-slate-400\">Value</span>\n <input type=\"range\" aria-label=\"Value\" min={0} max={1} step={0.01} value={hsv.v} onChange={(e) => setHsv(hsv.s, Number(e.target.value))} className=\"flex-1 accent-indigo-500\" />\n </label>\n <div className=\"flex items-center gap-1\">\n <select aria-label=\"Harmony\" value={kind} onChange={(e) => setKind(e.target.value as HarmonyKind)} className=\"rounded bg-slate-800 px-1 py-0.5\">\n {HARMONY_KINDS.map((k) => (\n <option key={k} value={k}>\n {k}\n </option>\n ))}\n </select>\n <button type=\"button\" className={chip(wheel === 'ryb')} aria-pressed={wheel === 'ryb'} onClick={() => setWheel('ryb')}>\n RYB\n </button>\n <button type=\"button\" className={chip(wheel === 'rgb')} aria-pressed={wheel === 'rgb'} onClick={() => setWheel('rgb')}>\n RGB\n </button>\n </div>\n <div className=\"flex flex-wrap gap-1\" aria-label=\"Harmony colours\">\n {harmony.map((h, i) => (\n <button key={i} type=\"button\" aria-label={`Use ${h.color}`} title={h.color} className=\"h-6 w-6 rounded ring-1 ring-slate-700\" style={{ background: h.color }} onClick={() => controller.setColor(h.color)} />\n ))}\n <button type=\"button\" className={button} onClick={() => harmony.forEach((h) => controller.addSwatch(h.color))}>\n + swatches\n </button>\n </div>\n <div className=\"flex flex-wrap gap-1\" role=\"listbox\" aria-label=\"Swatches\">\n {state.swatches.map((s, i) => (\n <button\n key={i}\n type=\"button\"\n role=\"option\"\n aria-selected={s.color === color}\n aria-label={s.name ?? s.color}\n title={`${s.name ?? s.color} (right-click to remove)`}\n className=\"h-5 w-5 rounded ring-1 ring-slate-700\"\n style={{ background: s.color }}\n onClick={() => controller.setColor(s.color)}\n onContextMenu={(e) => {\n e.preventDefault();\n controller.removeSwatch(i);\n }}\n />\n ))}\n <button type=\"button\" className={button} aria-label=\"Add swatch\" onClick={() => controller.addSwatch(color)}>\n +\n </button>\n </div>\n {mixingPad && (\n <div className=\"flex flex-col gap-1\" data-testid=\"mixing-pad\">\n <div className=\"flex items-center gap-1\">\n <span className=\"text-slate-400\">Mixing pad</span>\n {(['paint', 'knife', 'pick'] as const).map((t) => (\n <button key={t} type=\"button\" aria-pressed={padTool === t} className={chip(padTool === t)} onClick={() => setPadTool(t)}>\n {t === 'paint' ? 'Paint' : t === 'knife' ? 'Knife' : 'Pick'}\n </button>\n ))}\n <button type=\"button\" className={button} onClick={() => controller.clearMixingPad()}>\n Clear\n </button>\n </div>\n <div\n role=\"application\"\n aria-label=\"Mixing pad\"\n className=\"touch-none cursor-crosshair\"\n onPointerDown={(e) => {\n const p = padPoint(e);\n if (padTool === 'pick') {\n attempt(() => controller.mixingPadPick(p.x, p.y, { setColor: true }));\n return;\n }\n padPoints.current = [p];\n (e.target as Element).setPointerCapture?.(e.pointerId);\n }}\n onPointerMove={(e) => padPoints.current?.push(padPoint(e))}\n onPointerUp={() => {\n const pts = padPoints.current;\n padPoints.current = null;\n if (pts?.length) attempt(() => controller.mixingPadStroke(pts, { tool: padTool === 'knife' ? 'knife' : 'paint' }));\n }}\n >\n <PixelCanvas pixels={pad} label=\"Mixing pad pixels\" className=\"w-full rounded\" style={{ aspectRatio: `${MIXING_PAD_WIDTH} / ${MIXING_PAD_HEIGHT}` }} />\n </div>\n </div>\n )}\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useState } from 'react';\nimport { BLEND_MENU_GROUPS, type BlendMode, type PaintEditorController, type PaintLayerInfo } from '@pixerate/editor/paint-editor';\nimport { usePaintEditorState } from './usePaintEditor';\nimport { ErrorLine, button, chip, panel, useAttempt } from './shared';\n\nexport interface PaintLayersPanelProps {\n controller: PaintEditorController;\n className?: string;\n}\n\n/** Siblings of a layer, bottom first, and its index among them. */\nfunction siblingIndex(layers: PaintLayerInfo[], l: PaintLayerInfo): { index: number; count: number } {\n const sibs = layers.filter((x) => x.parentId === l.parentId).reverse();\n return { index: sibs.findIndex((x) => x.id === l.id), count: sibs.length };\n}\n\n/**\n * The layer stack, top first: visibility, names (double-click to rename), the active layer's\n * opacity, blend mode and locks, and new layer / group, duplicate, move up / down, merge down and\n * delete. Every change is one undo step.\n */\nexport const PaintLayersPanel: React.FC<PaintLayersPanelProps> = ({ controller, className }) => {\n usePaintEditorState(controller);\n const [error, attempt] = useAttempt();\n const [renaming, setRenaming] = useState<string | null>(null);\n const layers = controller.listLayers();\n const active = layers.find((l) => l.active) ?? null;\n const move = (delta: number) => {\n if (!active) return;\n const { index, count } = siblingIndex(layers, active);\n const to = Math.min(count - 1, Math.max(0, index + delta));\n if (to !== index) attempt(() => controller.moveLayer(active.id, to));\n };\n\n return (\n <div className={`${panel} ${className ?? ''}`} data-testid=\"paint-layers-panel\">\n <div className=\"flex flex-wrap gap-1\">\n <button type=\"button\" className={button} onClick={() => attempt(() => controller.addLayer())}>\n New layer\n </button>\n <button type=\"button\" className={button} onClick={() => attempt(() => controller.addLayer({ type: 'group' }))}>\n New group\n </button>\n <button type=\"button\" className={button} disabled={!active} onClick={() => active && attempt(() => controller.duplicateLayer(active.id))}>\n Duplicate\n </button>\n <button type=\"button\" className={button} disabled={!active} aria-label=\"Move layer up\" onClick={() => move(1)}>\n ↑\n </button>\n <button type=\"button\" className={button} disabled={!active} aria-label=\"Move layer down\" onClick={() => move(-1)}>\n ↓\n </button>\n <button type=\"button\" className={button} disabled={!active} onClick={() => active && attempt(() => controller.mergeDown(active.id))}>\n Merge down\n </button>\n <button type=\"button\" className={button} disabled={!active || layers.length < 2} onClick={() => active && attempt(() => controller.removeLayer(active.id))}>\n Delete\n </button>\n </div>\n <ul role=\"tree\" aria-label=\"Layers\" className=\"flex flex-col gap-0.5\">\n {layers.map((l) => (\n <li\n key={l.id}\n role=\"treeitem\"\n aria-selected={l.active}\n className={`flex items-center gap-1.5 rounded px-1.5 py-1 cursor-pointer ${l.active ? 'bg-indigo-600/30 ring-1 ring-indigo-500' : 'hover:bg-slate-800'}`}\n style={{ paddingLeft: 6 + l.depth * 12 }}\n onClick={() => controller.setActiveLayer(l.id)}\n >\n <button\n type=\"button\"\n aria-label={l.visible ? `Hide ${l.name}` : `Show ${l.name}`}\n className={`w-5 text-[11px] ${l.visible ? 'text-slate-200' : 'text-slate-600'}`}\n onClick={(e) => {\n e.stopPropagation();\n attempt(() => controller.updateLayer(l.id, { visible: !l.visible }));\n }}\n >\n {l.visible ? '●' : '○'}\n </button>\n {renaming === l.id ? (\n <input\n autoFocus\n aria-label=\"Layer name\"\n defaultValue={l.name}\n className=\"flex-1 rounded bg-slate-800 px-1\"\n onClick={(e) => e.stopPropagation()}\n onBlur={(e) => {\n setRenaming(null);\n if (e.target.value.trim() && e.target.value !== l.name) attempt(() => controller.updateLayer(l.id, { name: e.target.value }));\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter') (e.target as HTMLInputElement).blur();\n if (e.key === 'Escape') setRenaming(null);\n }}\n />\n ) : (\n <span className=\"flex-1 truncate\" onDoubleClick={() => setRenaming(l.id)}>\n {l.type === 'group' ? '▸ ' : ''}\n {l.name}\n </span>\n )}\n {l.locks.pixels || l.locks.all ? <span title=\"Locked\">🔒</span> : null}\n </li>\n ))}\n </ul>\n {active && (\n <div className=\"flex flex-col gap-1.5\">\n <label className=\"flex items-center gap-2\">\n <span className=\"w-14 text-slate-400\">Opacity</span>\n <input\n type=\"range\"\n aria-label=\"Layer opacity\"\n min={0}\n max={1}\n step={0.01}\n value={active.opacity}\n onChange={(e) => attempt(() => controller.updateLayer(active.id, { opacity: Number(e.target.value) }))}\n className=\"flex-1 accent-indigo-500\"\n />\n </label>\n <label className=\"flex items-center gap-2\">\n <span className=\"w-14 text-slate-400\">Blend</span>\n <select aria-label=\"Layer blend\" value={active.blend} onChange={(e) => attempt(() => controller.updateLayer(active.id, { blend: e.target.value as BlendMode }))} className=\"flex-1 rounded bg-slate-800 px-1 py-0.5\">\n {active.type === 'group' && <option value=\"pass-through\">Pass through</option>}\n {BLEND_MENU_GROUPS.map((g) => (\n <optgroup key={g.label} label={g.label}>\n {g.modes.map((m) => (\n <option key={m.id} value={m.id} title={m.description}>\n {m.label}\n </option>\n ))}\n </optgroup>\n ))}\n </select>\n </label>\n <div className=\"flex gap-1\">\n {(['pixels', 'transparency'] as const).map((k) => (\n <button key={k} type=\"button\" aria-pressed={Boolean(active.locks[k])} className={chip(Boolean(active.locks[k]))} onClick={() => attempt(() => controller.updateLayer(active.id, { locks: { [k]: !active.locks[k] } }))}>\n {k === 'pixels' ? 'Lock pixels' : 'Lock transparency'}\n </button>\n ))}\n <button type=\"button\" aria-pressed={active.clipped} className={chip(active.clipped)} onClick={() => attempt(() => controller.updateLayer(active.id, { clipped: !active.clipped }))}>\n Clip\n </button>\n </div>\n </div>\n )}\n <ErrorLine error={error} />\n </div>\n );\n};\n","import React, { useState } from 'react';\nimport type { PaintEditorController, PaintTool } from '@pixerate/editor/paint-editor';\nimport { BrushPanel } from './BrushPanel';\nimport { ColorPanel } from './ColorPanel';\nimport { PaintCanvas } from './PaintCanvas';\nimport { PaintLayersPanel } from './PaintLayersPanel';\nimport { PaintToolbar } from './PaintToolbar';\nimport { PaperPanel } from './PaperPanel';\nimport { chip } from './shared';\n\nexport interface PaintEditorProps {\n controller: PaintEditorController;\n /** Base name of saved and exported files (default `painting`). */\n fileName?: string;\n /** Height of the editor (default 720 px). */\n height?: number | string;\n className?: string;\n}\n\ntype SideTab = 'color' | 'paper' | 'layers';\n\n/**\n * The paint editor: toolbar, brush library on the left, the canvas, and colour (wheel,\n * harmonies, swatches, mixing pad), paper and layers on the right.\n */\nexport const PaintEditor: React.FC<PaintEditorProps> = ({ controller, fileName, height = 720, className }) => {\n const [tool, setTool] = useState<PaintTool>('brush');\n const [tab, setTab] = useState<SideTab>('color');\n const [error, setError] = useState<string | null>(null);\n return (\n <div className={`flex flex-col gap-2 rounded-xl border border-slate-800 bg-slate-900 p-2 ${className ?? ''}`} style={{ height }} data-testid=\"paint-editor\">\n <PaintToolbar controller={controller} tool={tool} onToolChange={setTool} fileName={fileName} />\n <div className=\"flex min-h-0 flex-1 gap-2\">\n <BrushPanel controller={controller} className=\"w-60 shrink-0 overflow-y-auto pr-1\" />\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <PaintCanvas controller={controller} tool={tool} onError={setError} className=\"flex-1 rounded-lg\" />\n {error && (\n <p role=\"alert\" className=\"mt-1 text-[11px] text-rose-400\">\n {error}\n </p>\n )}\n </div>\n <div className=\"flex w-64 shrink-0 flex-col gap-2 overflow-y-auto pr-1\">\n <div className=\"flex gap-1\" role=\"tablist\" aria-label=\"Paint panels\">\n {(['color', 'paper', 'layers'] as const).map((t) => (\n <button key={t} type=\"button\" role=\"tab\" aria-selected={tab === t} className={chip(tab === t)} onClick={() => setTab(t)}>\n {t === 'color' ? 'Colour' : t === 'paper' ? 'Paper' : 'Layers'}\n </button>\n ))}\n </div>\n {tab === 'color' && <ColorPanel controller={controller} />}\n {tab === 'paper' && <PaperPanel controller={controller} />}\n {tab === 'layers' && <PaintLayersPanel controller={controller} />}\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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","names":["useMemo","useState","useState","useMemo","useRef","useEffect","useRef","useState","jsx","jsxs","jsx","jsxs","useRef","useMemo","useRef","useState","downloadBytes","jsx","jsxs","useState","useRef","useMemo","downloadBytes","useMemo","patchPath","readPath","jsx","jsxs","useMemo","readPath","patchPath","useMemo","useRef","useState","jsx","jsxs","useState","useRef","useMemo","useState","jsx","jsxs","useState","useState","jsx","jsxs","useState"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixerate/editor-react",
|
|
3
|
-
"version": "0.68.
|
|
3
|
+
"version": "0.68.1",
|
|
4
4
|
"description": "React bindings and prompt/rich-text components for @pixerate/editor",
|
|
5
5
|
"author": "Pixerate",
|
|
6
6
|
"license": "MIT",
|
|
@@ -139,7 +139,7 @@
|
|
|
139
139
|
},
|
|
140
140
|
"peerDependencies": {
|
|
141
141
|
"@dagrejs/dagre": "^1.1.8",
|
|
142
|
-
"@pixerate/editor": ">=0.
|
|
142
|
+
"@pixerate/editor": ">=0.107.0 <1.0.0-0",
|
|
143
143
|
"@tiptap/core": "^2.11.5",
|
|
144
144
|
"@tiptap/pm": "^2.11.5",
|
|
145
145
|
"@tiptap/react": "^2.11.5",
|
|
@@ -166,7 +166,7 @@
|
|
|
166
166
|
"tsup": "^8.4.0",
|
|
167
167
|
"typescript": "^5.7.3",
|
|
168
168
|
"vitest": "^5.0.5",
|
|
169
|
-
"@pixerate/editor": "0.
|
|
169
|
+
"@pixerate/editor": "0.107.0"
|
|
170
170
|
},
|
|
171
171
|
"scripts": {
|
|
172
172
|
"build": "tsup",
|