@pictor-sdk/ui 0.1.0 → 0.2.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.
- package/README.md +12 -1
- package/dist/index.d.mts +34 -2
- package/dist/index.d.ts +34 -2
- package/dist/index.js +82 -38
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +80 -38
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
- package/src/gestures/LayerGestureSurface.tsx +7 -4
- package/src/index.ts +1 -0
- package/src/panels/LayoutPanel.tsx +11 -5
- package/src/panels/layoutMath.ts +86 -32
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/Editor.tsx","../src/hostCallbacks.tsx","../src/gestures/DrawingSurface.tsx","../src/uiState.tsx","../src/gestures/drawController.ts","../src/gestures/CropGestureSurface.tsx","../src/panels/useTargetImageLayer.ts","../src/gestures/interactionState.tsx","../src/gestures/TiltShiftGestureSurface.tsx","../src/gestures/CropGrid.tsx","../src/gestures/LayerGestureSurface.tsx","../src/gestures/layerGestureWorklet.ts","../src/gestures/StoryMediaGestureSurface.tsx","../src/gestures/mediaGestureWorklet.ts","../src/gestures/settleCoordinator.ts","../src/gestures/transformOwnership.ts","../src/gestures/routing.ts","../src/gestures/InteractionGuides.tsx","../src/theme.ts","../src/ToolPanelHost.tsx","../src/panels/AdjustPanel.tsx","../src/components/Slider.tsx","../src/panels/AddPhotoPanel.tsx","../src/panels/addPhotoController.ts","../src/panels/ColorPanel.tsx","../src/panels/CropPanel.tsx","../src/components/StraightenRuler.tsx","../src/panels/cropMath.ts","../src/panels/DrawPanel.tsx","../src/panels/FilterStrip.tsx","../src/panels/LayoutPanel.tsx","../src/panels/layoutMath.ts","../src/panels/LuxPanel.tsx","../src/panels/MediaPanel.tsx","../src/panels/LayersPanel.tsx","../src/panels/PerspectivePanel.tsx","../src/panels/StickerPanel.tsx","../src/panels/TiltShiftPanel.tsx","../src/composer/TextComposer.tsx","../src/composer/keyboardLayout.ts","../src/composer/useTextSession.ts","../src/components/TopBar.tsx","../src/components/ToolRail.tsx","../src/gestures/EditorGestures.tsx","../src/gestures/controller.ts","../src/index.ts","../src/panels/TextPanel.tsx"],"sourcesContent":["import {\n EditorProvider,\n selectionChromeEnabled,\n useEditor,\n type EditorPlugin,\n type EditorProfile,\n type EditorDocument,\n type ExportSpec,\n type InsertableImage,\n type Size,\n} from '@pictor-sdk/core'\nimport { EditorCanvas } from '@pictor-sdk/skia'\nimport React, { useState, type ComponentType, type ReactNode } from 'react'\nimport { View } from 'react-native'\nimport { GestureHandlerRootView } from 'react-native-gesture-handler'\nimport { HostCallbacksProvider } from './hostCallbacks'\nimport { DrawingSurface } from './gestures/DrawingSurface'\nimport { CropGestureSurface } from './gestures/CropGestureSurface'\nimport { TiltShiftGestureSurface } from './gestures/TiltShiftGestureSurface'\nimport { CropGrid } from './gestures/CropGrid'\nimport { InteractionProvider, useInteractionState } from './gestures/interactionState'\nimport { LayerGestureSurface } from './gestures/LayerGestureSurface'\nimport { StoryMediaGestureSurface } from './gestures/StoryMediaGestureSurface'\nimport { resolveGestureSurface } from './gestures/routing'\nimport { InteractionGuides } from './gestures/InteractionGuides'\nimport { UiStateProvider, useUiState } from './uiState'\nimport { type StickerAsset } from './panels/StickerPanel'\nimport { ThemeContext, mergeTheme, useTheme, type PartialTheme } from './theme'\nimport { ToolPanelHost } from './ToolPanelHost'\nimport { TextComposer, TextComposerHost, type TextComposerProps } from './composer/TextComposer'\nimport { TopBar, type TopBarProps } from './components/TopBar'\nimport { ToolRail } from './components/ToolRail'\n\n/**\n * Every region of the default editor is a slot: pass your own component to\n * replace it, or null to remove it. All slots are built exclusively on the\n * public headless hooks — replacing one can never break the others.\n */\nexport interface EditorSlots {\n TopBar: ComponentType<TopBarProps> | null\n CanvasStage: ComponentType<CanvasStageProps> | null\n ToolRail: ComponentType | null\n ToolPanelHost: ComponentType | null\n /**\n * The full-screen text composer, shown while the `text` tool is active.\n *\n * Replace it to ship your own composition UI without replacing the canvas or\n * the editor; it receives everything the default one gets. `null` removes it,\n * leaving text editing to a host-built surface.\n *\n * @experimental\n */\n TextComposer: ComponentType<TextComposerProps> | null\n}\n\n/** What the canvas slot receives. Children draw over the canvas, in its coordinates. */\nexport interface CanvasStageProps {\n children?: ReactNode\n /** Reported when a layer's image source fails to load. */\n onError?: (error: unknown) => void\n}\n\n/**\n * The canvas plus whichever gesture surface the active tool calls for.\n *\n * Exactly one surface is mounted at a time — precedence lives in\n * `resolveGestureSurface`, not in this JSX — so two recognisers can never\n * arbitrate over the same touch.\n */\nexport function CanvasStage({ children, onError }: CanvasStageProps) {\n const { activeTool, profile } = useEditor()\n const { previews } = useInteractionState()\n const surface = resolveGestureSurface(activeTool)\n return (\n <EditorCanvas\n style={{ flex: 1 }}\n onError={onError}\n previewTransforms={previews}\n showSelectionChrome={selectionChromeEnabled(profile)}\n >\n {/* exactly one surface owns the canvas; precedence is resolveGestureSurface */}\n {surface === 'draw' ? (\n <DrawingSurface />\n ) : surface === 'crop' ? (\n <>\n <CropGestureSurface />\n <CropGrid />\n </>\n ) : surface === 'tilt' ? (\n <TiltShiftGestureSurface />\n ) : surface === 'media' ? (\n <StoryMediaGestureSurface />\n ) : (\n <>\n <LayerGestureSurface />\n <InteractionGuides />\n </>\n )}\n {children}\n </EditorCanvas>\n )\n}\n\n/**\n * What `<Editor>` accepts: a profile, its plugins, a document or a source, and\n * any slots or theme you want to replace.\n */\nexport interface EditorProps {\n profile: EditorProfile\n plugins?: EditorPlugin[]\n /** Image source for a fresh document (or pass initialDocument). */\n source?: unknown\n intrinsic?: Size\n initialDocument?: EditorDocument\n onExport?: (bytes: Uint8Array) => void | Promise<void>\n onCancel?: () => void\n onError?: (error: unknown) => void\n exportSpec?: Partial<ExportSpec>\n slots?: Partial<EditorSlots>\n theme?: PartialTheme\n /** Host-supplied sticker catalog for the built-in sticker panel. */\n stickers?: StickerAsset[]\n /**\n * Asked to supply photos when the user presses the add-photo control.\n *\n * The library never touches the gallery: permissions, the picker and any\n * HEIC/HEIF transcoding stay with the host, which is what keeps it free of\n * Expo and of native code. Resolve `null` or `[]` for cancellation, which\n * adds nothing. Omit it and the control renders unavailable rather than\n * throwing.\n *\n * @experimental\n */\n requestImages?: () => Promise<readonly InsertableImage[] | null>\n}\n\n/** Merge slot overrides over the defaults. Pure — unit tested. */\nexport function mergeSlots(overrides?: Partial<EditorSlots>): EditorSlots {\n return {\n TopBar,\n CanvasStage,\n ToolRail,\n ToolPanelHost,\n TextComposer,\n ...overrides,\n }\n}\n\nfunction EditorBody({\n slots,\n onExport,\n onCancel,\n onError,\n exportSpec,\n stickers,\n}: Pick<EditorProps, 'onExport' | 'onCancel' | 'onError' | 'exportSpec' | 'stickers'> & {\n slots: EditorSlots\n}) {\n const { export: exportDoc, activeTool } = useEditor()\n const { layerDragActive } = useInteractionState()\n const [, setStickers] = useUiState<StickerAsset[]>('stickers', [])\n React.useEffect(() => {\n if (stickers) setStickers(stickers)\n }, [stickers, setStickers])\n const theme = useTheme()\n const [busy, setBusy] = useState(false)\n\n const handleNext = onExport\n ? async () => {\n setBusy(true)\n try {\n const bytes = await exportDoc(exportSpec)\n await onExport(bytes)\n } catch (error) {\n onError?.(error)\n } finally {\n setBusy(false)\n }\n }\n : undefined\n\n const {\n TopBar: Top,\n CanvasStage: Stage,\n ToolRail: Rail,\n ToolPanelHost: PanelHost,\n TextComposer: Composer,\n } = slots\n // The composer is full-screen and owns the whole interaction, so the ordinary\n // chrome and the tool panel stand down while it is up rather than competing\n // with it for the keyboard and for taps.\n const composing = activeTool === 'text' && Composer !== null\n // While a layer is being dragged the editing chrome gets out of the way, so\n // the canvas and the delete target are all that is on screen.\n //\n // It is hidden with opacity rather than unmounted on purpose: unmounting\n // would hand the freed space to the canvas, which resizes it mid-gesture and\n // moves the ground under the interaction. Keeping the boxes in the layout\n // holds the canvas metrics still for the whole drag.\n const chrome = !layerDragActive\n const hidden = { opacity: chrome ? 1 : 0 }\n const hits = chrome ? 'auto' : ('none' as const)\n return (\n // GestureDetector requires a GestureHandlerRootView ancestor; providing it\n // here means consumers never have to know (nesting under an app-level one\n // is harmless).\n <GestureHandlerRootView style={{ flex: 1 }}>\n <View style={{ flex: 1, backgroundColor: theme.colors.background }}>\n {Top && !composing ? (\n <View style={hidden} pointerEvents={hits}>\n <Top onCancel={onCancel} onNext={handleNext} busy={busy} />\n </View>\n ) : null}\n {Stage ? <Stage onError={onError} /> : null}\n {PanelHost && !composing ? (\n <View style={hidden} pointerEvents={hits}>\n <PanelHost />\n </View>\n ) : null}\n {Rail && !activeTool ? (\n <View style={hidden} pointerEvents={hits}>\n <Rail />\n </View>\n ) : null}\n {composing && Composer ? <TextComposerHost Composer={Composer} /> : null}\n </View>\n </GestureHandlerRootView>\n )\n}\n\n/**\n * The batteries-included editor. `<Editor profile={POST_PROFILE} … />` gives\n * the full IG-style flow; every part is replaceable via `slots`.\n */\nexport function Editor({\n profile,\n plugins,\n source,\n intrinsic,\n initialDocument,\n onExport,\n onCancel,\n onError,\n exportSpec,\n slots,\n theme,\n stickers,\n requestImages,\n}: EditorProps) {\n return (\n <EditorProvider\n profile={profile}\n plugins={plugins}\n source={source}\n intrinsic={intrinsic}\n initialDocument={initialDocument}\n >\n <ThemeContext.Provider value={mergeTheme(theme)}>\n <UiStateProvider>\n <HostCallbacksProvider value={{ requestImages, onError }}>\n <InteractionProvider>\n <EditorBody\n slots={mergeSlots(slots)}\n onExport={onExport}\n onCancel={onCancel}\n onError={onError}\n exportSpec={exportSpec}\n stickers={stickers}\n />\n </InteractionProvider>\n </HostCallbacksProvider>\n </UiStateProvider>\n </ThemeContext.Provider>\n </EditorProvider>\n )\n}\n","import { type InsertableImage } from '@pictor-sdk/core'\nimport React, { createContext, useContext, useRef } from 'react'\n\n/**\n * Callbacks the host supplies to `<Editor>` that panels deep in the tree need.\n *\n * Held in a **ref** rather than state. A callback prop is usually an inline\n * arrow recreated every render, so storing it in state would notify on every\n * render and re-render forever; consumers read `.current` at call time instead\n * and never re-render because the host re-created its closure.\n *\n * @experimental\n */\nexport interface HostCallbacks {\n /**\n * Asked to supply photos when the user presses the add-photo control.\n *\n * The library never touches the gallery itself: permissions, the picker and\n * any HEIC/HEIF transcoding are the host's, which is what keeps the library\n * free of Expo and of native code. Resolve `null` or `[]` for cancellation.\n */\n requestImages?: () => Promise<readonly InsertableImage[] | null>\n /** Where a failed request is reported. */\n onError?: (error: unknown) => void\n}\n\nconst Context = createContext<{ current: HostCallbacks } | null>(null)\n\n/**\n * Makes the host's callbacks reachable from panels deep in the tree.\n *\n * Mounted by `<Editor>`; a host composing its own editor from slots mounts it\n * itself, or omits it and the controls render unavailable.\n *\n * @experimental\n */\nexport function HostCallbacksProvider({\n value,\n children,\n}: {\n value: HostCallbacks\n children?: React.ReactNode\n}) {\n const ref = useRef<HostCallbacks>(value)\n // Updated during render on purpose: a panel that calls one of these in the\n // same commit must see the latest, and an effect would be a frame late.\n ref.current = value\n return <Context.Provider value={ref}>{children}</Context.Provider>\n}\n\n/**\n * The host's callbacks, as a stable ref.\n *\n * Returns an empty set outside an `<Editor>` rather than throwing — a panel\n * rendered standalone should degrade to \"unavailable\", not crash.\n *\n * @experimental\n */\nexport function useHostCallbacks(): { current: HostCallbacks } {\n const fallback = useRef<HostCallbacks>({})\n return useContext(Context) ?? fallback\n}\n","import { useEditor, useEditorStore } from '@pictor-sdk/core'\nimport { samplePixelColor, useCanvasMetrics, useRenderer } from '@pictor-sdk/skia'\nimport React, { useMemo, useRef } from 'react'\nimport { StyleSheet } from 'react-native'\nimport { Gesture, GestureDetector } from 'react-native-gesture-handler'\nimport Animated from 'react-native-reanimated'\nimport { runOnJS } from 'react-native-worklets'\nimport { useUiState } from '../uiState'\nimport { createDrawController, type BrushConfig } from './drawController'\n\n/** The brush a drawing session starts with. */\nexport const DEFAULT_BRUSH: BrushConfig = { brush: 'pen', color: '#ffffff', width: 0.012 }\n\n/**\n * Freehand drawing capture, active while the draw tool is open. In\n * eyedropper mode a tap samples the rendered pixel color into the brush.\n */\nexport function DrawingSurface() {\n const store = useEditorStore()\n const { document } = useEditor()\n const renderer = useRenderer()\n const metrics = useCanvasMetrics()\n const metricsRef = useRef(metrics)\n metricsRef.current = metrics\n const [brush, setBrush] = useUiState<BrushConfig>('draw.brush', DEFAULT_BRUSH)\n const [eyedropper, setEyedropper] = useUiState('draw.eyedropper', false)\n const brushRef = useRef(brush)\n brushRef.current = brush\n const stateRef = useRef({ eyedropper, document, setBrush, setEyedropper })\n stateRef.current = { eyedropper, document, setBrush, setEyedropper }\n\n const controller = useMemo(\n () => createDrawController(store, () => metricsRef.current, () => brushRef.current),\n [store],\n )\n\n const gesture = useMemo(() => {\n const sample = async (x: number, y: number) => {\n const m = metricsRef.current\n const s = stateRef.current\n if (!m || !s.eyedropper) return\n const color = await samplePixelColor(renderer, s.document, {\n x: x / m.width,\n y: y / m.height,\n })\n if (color) s.setBrush({ ...brushRef.current, color })\n s.setEyedropper(false)\n }\n const beginOrSample = (x: number, y: number) => {\n if (stateRef.current.eyedropper) {\n void sample(x, y)\n } else {\n controller.begin(x, y)\n }\n }\n return Gesture.Pan()\n .minDistance(0)\n .onStart((e) => {\n 'worklet'\n runOnJS(beginOrSample)(e.x, e.y)\n })\n .onUpdate((e) => {\n 'worklet'\n runOnJS(controller.move)(e.x, e.y)\n })\n .onFinalize(() => {\n 'worklet'\n runOnJS(controller.end)()\n })\n }, [controller, renderer])\n\n return (\n <GestureDetector gesture={gesture}>\n <Animated.View style={StyleSheet.absoluteFill} />\n </GestureDetector>\n )\n}\n","import React, { createContext, useCallback, useContext, useRef, useSyncExternalStore } from 'react'\n\n/**\n * A tiny shared key/value store for panel ↔ canvas coordination (brush\n * config, sticker catalogs, eyedropper mode). Ephemeral — never touches the\n * document or history.\n */\nexport interface UiStateStore {\n get<T>(key: string, fallback: T): T\n set(key: string, value: unknown): void\n subscribe(listener: () => void): () => void\n}\n\n/** A scratch store for UI state that is neither document nor history. */\nexport function createUiStateStore(): UiStateStore {\n const values = new Map<string, unknown>()\n const listeners = new Set<() => void>()\n return {\n get: <T,>(key: string, fallback: T) =>\n (values.has(key) ? (values.get(key) as T) : fallback),\n set(key, value) {\n values.set(key, value)\n for (const l of [...listeners]) l()\n },\n subscribe(listener) {\n listeners.add(listener)\n return () => listeners.delete(listener)\n },\n }\n}\n\nconst UiStateContext = createContext<UiStateStore | null>(null)\n\n/**\n * Holds ephemeral panel state — which tab is open, which swatch is selected.\n *\n * Deliberately outside the document: none of it should be serialized, undoable,\n * or survive the editor closing.\n */\nexport function UiStateProvider({ children }: { children?: React.ReactNode }) {\n const ref = useRef<UiStateStore | null>(null)\n if (!ref.current) ref.current = createUiStateStore()\n return <UiStateContext.Provider value={ref.current}>{children}</UiStateContext.Provider>\n}\n\n/** Read and write one key of the ephemeral UI state. Throws outside an `<Editor>`. */\nexport function useUiState<T>(key: string, fallback: T): [T, (value: T) => void] {\n const store = useContext(UiStateContext)\n if (!store) throw new Error('useUiState must be used inside <Editor> (UiStateProvider)')\n const value = useSyncExternalStore(\n store.subscribe,\n () => store.get(key, fallback),\n () => store.get(key, fallback),\n )\n const set = useCallback((v: T) => store.set(key, v), [store, key])\n return [value, set]\n}\n","import { createId, type EditorStore, type Stroke } from '@pictor-sdk/core'\nimport { type GestureMetrics } from './controller'\n\n/** The active brush: kind, colour and width. Width is a fraction of document width. */\nexport interface BrushConfig {\n brush: Stroke['brush']\n color: string\n /** 0..1 of document width */\n width: number\n}\n\n/**\n * Pure drawing controller: converts a pan gesture into a stroke on the\n * top-most draw layer (created on first use), committed as ONE undo step.\n * Live feedback comes from patching the stroke into the document on every\n * move inside the history batch.\n */\nexport function createDrawController(\n store: Pick<EditorStore, 'getState' | 'dispatch'>,\n getMetrics: () => GestureMetrics | null,\n getBrush: () => BrushConfig,\n) {\n let drawing = false\n let layerId: string | null = null\n let points: Stroke['points'] = []\n let baseStrokes: Stroke[] = []\n\n function toDocPoint(xDp: number, yDp: number) {\n const metrics = getMetrics()\n if (!metrics || metrics.width === 0 || metrics.height === 0) return null\n return { x: xDp / metrics.width, y: yDp / metrics.height }\n }\n\n function ensureDrawLayer(): string {\n const doc = store.getState().document\n for (let i = doc.layers.length - 1; i >= 0; i--) {\n const layer = doc.layers[i]!\n if (layer.type === 'draw' && !layer.locked && !layer.hidden) return layer.id\n }\n const id = createId('draw')\n store.dispatch({\n type: 'layer/add',\n layer: {\n id,\n type: 'draw',\n transform: { x: 0.5, y: 0.5, scale: 1, rotation: 0 },\n opacity: 1,\n blendMode: 'normal',\n data: { strokes: [] },\n },\n })\n return id\n }\n\n function currentStroke(): Stroke {\n const brush = getBrush()\n return { points, color: brush.color, width: brush.width, brush: brush.brush }\n }\n\n function patch() {\n if (!layerId) return\n store.dispatch({\n type: 'layer/patchData',\n id: layerId,\n patch: { strokes: [...baseStrokes, currentStroke()] },\n })\n }\n\n return {\n begin(xDp: number, yDp: number) {\n const point = toDocPoint(xDp, yDp)\n if (!point || drawing) return\n drawing = true\n store.dispatch({ type: 'history/beginBatch', label: 'draw' })\n layerId = ensureDrawLayer()\n const layer = store.getState().document.layers.find((l) => l.id === layerId)\n baseStrokes = (layer?.data as { strokes?: Stroke[] } | undefined)?.strokes ?? []\n points = [point]\n patch()\n },\n move(xDp: number, yDp: number) {\n if (!drawing) return\n const point = toDocPoint(xDp, yDp)\n if (!point) return\n const last = points[points.length - 1]\n // drop sub-half-percent movements to keep strokes light\n if (last && Math.hypot(point.x - last.x, point.y - last.y) < 0.003) return\n points = [...points, point]\n patch()\n },\n end() {\n if (!drawing) return\n drawing = false\n store.dispatch({ type: 'history/endBatch' })\n layerId = null\n points = []\n baseStrokes = []\n },\n isDrawing: () => drawing,\n }\n}\n\n/** Accumulates touch points into strokes and commits them to the document. */\nexport type DrawController = ReturnType<typeof createDrawController>\n","import {\n clampCropTransform,\n cropFitScale,\n cropPanBounds,\n focalZoomTransform,\n type ImageLayerData,\n type Transform,\n} from '@pictor-sdk/core'\nimport { useCanvasMetrics } from '@pictor-sdk/skia'\nimport React, { useEffect, useMemo, useRef } from 'react'\nimport { StyleSheet } from 'react-native'\nimport { Gesture, GestureDetector } from 'react-native-gesture-handler'\nimport Animated, { useDerivedValue, useSharedValue, withTiming } from 'react-native-reanimated'\nimport { runOnJS } from 'react-native-worklets'\nimport { useTargetImageLayer } from '../panels/useTargetImageLayer'\nimport { useEditor } from '@pictor-sdk/core'\nimport { useInteractionState } from './interactionState'\n\n/** Overrides for crop gestures, defaulting to the profile's interaction settings. */\nexport interface CropGestureSurfaceProps {\n /** Override profile crop fit for this surface. */\n fit?: 'contain' | 'cover'\n maxScale?: number\n /** Enable free two-finger rotation; disabled by the default Post profile. */\n rotationEnabled?: boolean\n /** Optional host haptic/motion callback. */\n onInteractionChange?: (active: boolean) => void\n}\n\n/**\n * Fixed-viewport photo crop gestures. Pan and focal-point pinch run as shared\n * values on the UI thread; one normalized transform is committed on release.\n */\nexport function CropGestureSurface({ fit, maxScale, rotationEnabled, onInteractionChange }: CropGestureSurfaceProps) {\n const { document, dispatch, profile } = useEditor()\n const layer = useTargetImageLayer()\n const metrics = useCanvasMetrics()\n const interaction = useInteractionState()\n const config = profile.interaction?.crop\n const source = (layer?.data as ImageLayerData | undefined)?.intrinsic\n const resolvedFit = fit ?? config?.fit ?? 'contain'\n const resolvedMax = maxScale ?? config?.maxScale ?? 8\n const resolvedRotation = rotationEnabled ?? config?.rotationEnabled ?? false\n\n const liveX = useSharedValue(layer?.transform.x ?? 0.5)\n const liveY = useSharedValue(layer?.transform.y ?? 0.5)\n const liveScale = useSharedValue(layer?.transform.scale ?? 1)\n // Seed from React state directly; reading shared values during render trips\n // Reanimated strict mode on real devices.\n const baseX = useSharedValue(layer?.transform.x ?? 0.5)\n const baseY = useSharedValue(layer?.transform.y ?? 0.5)\n const baseScale = useSharedValue(layer?.transform.scale ?? 1)\n const liveRotation = useSharedValue(layer?.transform.rotation ?? 0)\n const baseRotation = useSharedValue(layer?.transform.rotation ?? 0)\n const panX = useSharedValue(0)\n const panY = useSharedValue(0)\n const pinchScale = useSharedValue(1)\n const rotateDelta = useSharedValue(0)\n const focalX = useSharedValue(0.5)\n const focalY = useSharedValue(0.5)\n const activeRecognizers = useSharedValue(0)\n const commitTimer = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n const minScale = source\n ? cropFitScale(source, document.size, resolvedFit, layer?.transform.rotation ?? 0)\n : 1\n\n useEffect(() => {\n if (!layer) return\n liveX.value = layer.transform.x\n liveY.value = layer.transform.y\n liveScale.value = layer.transform.scale\n liveRotation.value = layer.transform.rotation\n // Shared-value identities are stable; only committed scalar values resync them.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [layer?.transform.x, layer?.transform.y, layer?.transform.scale, layer?.transform.rotation])\n\n const previewTransform = useDerivedValue(() => {\n const ratio = liveScale.value / Math.max(baseScale.value, 0.000001)\n return [\n { translateX: liveX.value * document.size.width },\n { translateY: liveY.value * document.size.height },\n { rotate: liveRotation.value - baseRotation.value },\n { scale: ratio },\n { translateX: -baseX.value * document.size.width },\n { translateY: -baseY.value * document.size.height },\n ]\n }, [document.size.width, document.size.height])\n\n useEffect(() => {\n if (!layer) return\n interaction.setPreview({ layerId: layer.id, transform: previewTransform })\n return () => interaction.setPreview(null)\n // Register by layer identity; crop-active context changes must not replace it.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [layer?.id, previewTransform, interaction.setPreview])\n\n const setActive = (active: boolean) => {\n interaction.setCropActive(active)\n onInteractionChange?.(active)\n }\n\n const commit = (candidate: Transform) => {\n if (!layer || !source) return\n if (commitTimer.current) clearTimeout(commitTimer.current)\n const settledMinScale = cropFitScale(source, document.size, resolvedFit, candidate.rotation)\n const bounds = cropPanBounds(source, document.size, candidate.scale, settledMinScale, resolvedMax, candidate.rotation)\n const settled = clampCropTransform(candidate, bounds)\n liveX.value = withTiming(settled.x, { duration: 160 })\n liveY.value = withTiming(settled.y, { duration: 160 })\n liveScale.value = withTiming(settled.scale, { duration: 160 })\n liveRotation.value = withTiming(settled.rotation, { duration: 160 })\n commitTimer.current = setTimeout(() => {\n dispatch({\n type: 'layer/transform',\n id: layer.id,\n patch: {\n x: settled.x,\n y: settled.y,\n scale: settled.scale,\n ...(resolvedRotation ? { rotation: settled.rotation } : {}),\n },\n })\n baseX.value = settled.x\n baseY.value = settled.y\n baseScale.value = settled.scale\n baseRotation.value = settled.rotation\n liveX.value = settled.x\n liveY.value = settled.y\n liveScale.value = settled.scale\n liveRotation.value = settled.rotation\n setActive(false)\n }, 165)\n }\n\n const toggleZoom = (xDp: number, yDp: number) => {\n if (!layer || !source || !metrics) return\n baseX.value = layer.transform.x\n baseY.value = layer.transform.y\n baseScale.value = layer.transform.scale\n baseRotation.value = layer.transform.rotation\n liveX.value = layer.transform.x\n liveY.value = layer.transform.y\n liveScale.value = layer.transform.scale\n liveRotation.value = layer.transform.rotation\n setActive(true)\n const atMinimum = Math.abs(layer.transform.scale - minScale) < 0.01\n const targetScale = atMinimum\n ? Math.min(resolvedMax, minScale * (config?.doubleTapScale ?? 2))\n : minScale\n commit(focalZoomTransform(layer.transform, targetScale, {\n x: xDp / metrics.width,\n y: yDp / metrics.height,\n }))\n }\n\n const gesture = useMemo(() => {\n if (!metrics || !source || !layer) return Gesture.Tap()\n const begin = () => {\n 'worklet'\n if (activeRecognizers.value === 0) {\n baseX.value = liveX.value\n baseY.value = liveY.value\n baseScale.value = liveScale.value\n baseRotation.value = liveRotation.value\n panX.value = 0\n panY.value = 0\n pinchScale.value = 1\n rotateDelta.value = 0\n runOnJS(setActive)(true)\n }\n activeRecognizers.value += 1\n }\n const updateLive = () => {\n 'worklet'\n const rotation = baseRotation.value + rotateDelta.value\n const naturalWidth = document.size.width\n const naturalHeight = document.size.width * (source.height / source.width)\n const cos = Math.abs(Math.cos(rotation))\n const sin = Math.abs(Math.sin(rotation))\n const rotatedWidth = naturalWidth * cos + naturalHeight * sin\n const rotatedHeight = naturalWidth * sin + naturalHeight * cos\n const widthScale = document.size.width / rotatedWidth\n const heightScale = document.size.height / rotatedHeight\n const dynamicMin = resolvedFit === 'contain' ? Math.min(widthScale, heightScale) : Math.max(widthScale, heightScale)\n const rawScale = baseScale.value * pinchScale.value\n const resistance = config?.resistance ?? 0.35\n const scale = rawScale < dynamicMin\n ? dynamicMin - (dynamicMin - rawScale) * resistance\n : rawScale > resolvedMax\n ? resolvedMax + (rawScale - resolvedMax) * resistance\n : rawScale\n const ratio = scale / Math.max(baseScale.value, 0.000001)\n const zoomX = focalX.value - (focalX.value - baseX.value) * ratio\n const zoomY = focalY.value - (focalY.value - baseY.value) * ratio\n liveRotation.value = rotation\n const dx = Math.max(0, (rotatedWidth * scale - document.size.width) / (2 * document.size.width))\n const dy = Math.max(0, (rotatedHeight * scale - document.size.height) / (2 * document.size.height))\n liveScale.value = scale\n const rawX = zoomX + panX.value\n const rawY = zoomY + panY.value\n const minX = 0.5 - dx\n const maxX = 0.5 + dx\n const minY = 0.5 - dy\n const maxY = 0.5 + dy\n liveX.value = rawX < minX ? minX - (minX - rawX) * resistance : rawX > maxX ? maxX + (rawX - maxX) * resistance : rawX\n liveY.value = rawY < minY ? minY - (minY - rawY) * resistance : rawY > maxY ? maxY + (rawY - maxY) * resistance : rawY\n }\n const finish = () => {\n 'worklet'\n activeRecognizers.value = Math.max(0, activeRecognizers.value - 1)\n if (activeRecognizers.value === 0) {\n runOnJS(commit)({\n x: liveX.value,\n y: liveY.value,\n scale: liveScale.value,\n rotation: liveRotation.value,\n ...(layer.transform.anchor ? { anchor: layer.transform.anchor } : {}),\n ...(layer.transform.flipX !== undefined ? { flipX: layer.transform.flipX } : {}),\n ...(layer.transform.flipY !== undefined ? { flipY: layer.transform.flipY } : {}),\n })\n }\n }\n const pan = Gesture.Pan()\n .minPointers(1)\n .onStart(begin)\n .onUpdate((event) => {\n 'worklet'\n panX.value = event.translationX / metrics.width\n panY.value = event.translationY / metrics.height\n updateLive()\n })\n .onFinalize(finish)\n const pinch = Gesture.Pinch()\n .onStart(begin)\n .onUpdate((event) => {\n 'worklet'\n pinchScale.value = event.scale\n focalX.value = event.focalX / metrics.width\n focalY.value = event.focalY / metrics.height\n updateLive()\n })\n .onFinalize(finish)\n const rotate = Gesture.Rotation()\n .enabled(resolvedRotation)\n .onStart(begin)\n .onUpdate((event) => {\n 'worklet'\n rotateDelta.value = event.rotation\n updateLive()\n })\n .onFinalize(finish)\n const doubleTap = Gesture.Tap()\n .numberOfTaps(2)\n .onEnd((event) => {\n 'worklet'\n runOnJS(toggleZoom)(event.x, event.y)\n })\n return Gesture.Exclusive(doubleTap, Gesture.Simultaneous(pan, pinch, rotate))\n // Gesture worklets read stable shared values; recreate only for geometry/config changes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [metrics, source, layer, resolvedFit, resolvedMax, resolvedRotation, minScale, document.size.width, document.size.height, config?.resistance, config?.doubleTapScale])\n\n if (!layer) return null\n return (\n <GestureDetector gesture={gesture}>\n <Animated.View style={StyleSheet.absoluteFill} />\n </GestureDetector>\n )\n}\n","import {\n pinnedTargetImageLayer,\n resolveTargetImageLayer,\n useEditor,\n type Layer,\n} from '@pictor-sdk/core'\nimport { useRef } from 'react'\n\n/**\n * The image an open panel edits, **pinned for the whole session**.\n *\n * Resolved once, from the selection at the moment the panel mounts, and then\n * held by id. `ToolPanelHost` mounts a fresh panel per tool activation, so a\n * mount *is* a session, and closing and reopening resolves again.\n *\n * The pinning is the point. Re-resolving each render would let a selection\n * change mid-drag redirect the next slider movement to a different photo — an\n * edit landing silently on the wrong image, which is worse than an edit that\n * does nothing. So when the target is deleted, locked or hidden mid-session\n * this returns `null` and the panel disables its controls; it never quietly\n * falls back to the base.\n *\n * `useBaseImageLayer` is unchanged and still means *the base photo*. Use it\n * where a capability is genuinely base-only — Story media layout, the derived\n * background — rather than by inertia.\n *\n * @experimental\n */\nexport function useTargetImageLayer(): Layer | null {\n const { document, selection } = useEditor()\n const pinned = useRef<string | null>(null)\n\n // Resolved on the first render of this mount and never again. A ref rather\n // than an effect: an effect would leave the first render targeting nothing,\n // and a panel that renders once with no target flashes disabled controls.\n if (pinned.current === null) {\n pinned.current = resolveTargetImageLayer(document, selection)?.id ?? null\n }\n\n return pinnedTargetImageLayer(document, pinned.current) ?? null\n}\n","import { NO_SNAP, type LayerSnapState } from '@pictor-sdk/core'\nimport { type PreviewLayerTransform } from '@pictor-sdk/skia'\nimport React, { createContext, useCallback, useContext, useMemo, useState } from 'react'\n\n/**\n * Transient interaction state shared between the gesture surfaces and the\n * chrome. None of it is part of the document: it never reaches history,\n * serialization or export.\n *\n * Per-frame transforms stay on the UI thread as shared values (`previews`).\n * Only the discrete flags below cross to the JS thread, and only when they\n * actually change — a drag starting, a guide engaging, the delete target being\n * entered — so the render path is untouched while fingers move.\n */\nexport interface InteractionState {\n previews: readonly PreviewLayerTransform[]\n setPreview(preview: PreviewLayerTransform | null): void\n cropActive: boolean\n setCropActive(active: boolean): void\n /** True while a layer is being dragged/scaled/rotated. */\n layerDragActive: boolean\n setLayerDragActive(active: boolean): void\n /** True while the dragged layer is over the delete target. */\n overDeleteTarget: boolean\n setOverDeleteTarget(over: boolean): void\n /** Which alignment guides are currently engaged. */\n snap: LayerSnapState\n setSnap(snap: LayerSnapState): void\n}\n\nconst Context = createContext<InteractionState | null>(null)\n\n/**\n * Shares the in-flight interaction between the gesture surfaces and the canvas.\n *\n * How a live preview transform reaches the renderer without going through the\n * document — which would mean dispatching every frame.\n */\nexport function InteractionProvider({ children }: { children?: React.ReactNode }) {\n const [preview, setPreviewValue] = useState<PreviewLayerTransform | null>(null)\n const [cropActive, setCropActive] = useState(false)\n const [layerDragActive, setLayerDragActive] = useState(false)\n const [overDeleteTarget, setOverDeleteTarget] = useState(false)\n const [snap, setSnapValue] = useState<LayerSnapState>(NO_SNAP)\n\n const setPreview = useCallback((value: PreviewLayerTransform | null) => setPreviewValue(value), [])\n // identity-stable so worklets can call it through runOnJS without re-creating\n const setSnap = useCallback((value: LayerSnapState) => {\n setSnapValue((current) =>\n current.centerX === value.centerX &&\n current.centerY === value.centerY &&\n current.rotation === value.rotation\n ? current\n : value,\n )\n }, [])\n\n const value = useMemo(\n () => ({\n previews: preview ? [preview] : [],\n setPreview,\n cropActive,\n setCropActive,\n layerDragActive,\n setLayerDragActive,\n overDeleteTarget,\n setOverDeleteTarget,\n snap,\n setSnap,\n }),\n [preview, setPreview, cropActive, layerDragActive, overDeleteTarget, snap, setSnap],\n )\n return <Context.Provider value={value}>{children}</Context.Provider>\n}\n\n/** The current interaction. Throws outside an `<Editor>`, where there is none. */\nexport function useInteractionState(): InteractionState {\n const value = useContext(Context)\n if (!value) throw new Error('interaction components must be used inside <Editor>')\n return value\n}\n","import {\n moveTiltCenter,\n needsTiltShift,\n rotateTiltBand,\n scaleTiltRadius,\n tiltShiftPatch,\n useEditor,\n type ImageLayerData,\n type TiltShift,\n} from '@pictor-sdk/core'\nimport { useCanvasMetrics } from '@pictor-sdk/skia'\nimport React, { useMemo, useRef } from 'react'\nimport { StyleSheet } from 'react-native'\nimport { Gesture, GestureDetector } from 'react-native-gesture-handler'\nimport Animated, { useAnimatedStyle, useSharedValue } from 'react-native-reanimated'\nimport { runOnJS } from 'react-native-worklets'\nimport { useTargetImageLayer } from '../panels/useTargetImageLayer'\n\n/**\n * Placing the focus region: drag to move it, pinch to size it, twist to turn a\n * band.\n *\n * **Why the blur does not follow the finger.** The focus geometry lives in the\n * document and the shader reads it from there, so updating it per frame would\n * mean dispatching per frame — exactly the React-state-per-frame rule this\n * codebase forbids. Instead the gesture drives a **transient indicator**\n * computed entirely on the UI thread, and commits one normalized value on\n * release inside the tool's batch. That is also what the research pass measured\n * on the reference implementation: no focus ring is drawn persistently, and the\n * indicator appears only during interaction.\n *\n * Composition follows the media surface's rules: `Simultaneous(pan, pinch,\n * rotate)`, never `Exclusive` against a tap — an `Exclusive` gate makes every\n * drag wait for a tap to fail first, which is what made the story surface feel\n * laggy. The origin is captured once when the first recogniser activates, so a\n * second finger landing mid-gesture cannot re-base the interaction on a value\n * it is itself changing.\n */\nexport function TiltShiftGestureSurface() {\n const { dispatch } = useEditor()\n const layer = useTargetImageLayer()\n const metrics = useCanvasMetrics()\n const tilt = (layer?.data as ImageLayerData | undefined)?.tiltShift\n const active = needsTiltShift(tilt)\n\n // The value the whole interaction is measured from. A ref, not state: it is\n // read by the commit on the JS thread and never rendered.\n const origin = useRef<TiltShift | null>(null)\n const live = useRef<TiltShift | null>(null)\n live.current = active ? tilt! : null\n\n const width = metrics?.width ?? 0\n const height = metrics?.height ?? 0\n\n // Origin geometry in canvas dp, mirrored so the indicator needs no JS.\n const oX = useSharedValue(0)\n const oY = useSharedValue(0)\n const oR = useSharedValue(0)\n const oRot = useSharedValue(0)\n const oLinear = useSharedValue(0)\n const visible = useSharedValue(0)\n // Live totals from each recogniser. Every one reports its own running total\n // against the origin, so they combine without accumulating.\n const dx = useSharedValue(0)\n const dy = useSharedValue(0)\n const pinch = useSharedValue(1)\n const twist = useSharedValue(0)\n const activeCount = useSharedValue(0)\n\n const capture = useMemo(\n () => () => {\n const from = live.current\n if (!from || origin.current) return\n origin.current = from\n oX.value = from.x * width\n oY.value = from.y * height\n oR.value = from.radius * width\n oRot.value = from.rotation\n oLinear.value = from.mode === 'linear' ? 1 : 0\n },\n [width, height, oX, oY, oR, oRot, oLinear],\n )\n\n const commit = useMemo(\n () => (tx: number, ty: number, scale: number, rotation: number) => {\n const from = origin.current\n origin.current = null\n if (!from || !layer || width <= 0 || height <= 0) return\n // Each transform applied once, from the captured origin.\n let next = moveTiltCenter(from, tx / width, ty / height)\n next = scaleTiltRadius({ ...next, radius: from.radius, feather: from.feather }, scale)\n next = rotateTiltBand({ ...next, rotation: from.rotation }, rotation)\n dispatch({\n type: 'layer/patchData',\n id: layer.id,\n patch: tiltShiftPatch(next) as unknown as Record<string, unknown>,\n })\n },\n [dispatch, layer, width, height],\n )\n\n const gesture = useMemo(() => {\n const begin = () => {\n 'worklet'\n activeCount.value += 1\n visible.value = 1\n runOnJS(capture)()\n }\n /** Commit once, when the last recogniser lets go. */\n const end = () => {\n 'worklet'\n activeCount.value = Math.max(0, activeCount.value - 1)\n if (activeCount.value > 0) return\n visible.value = 0\n runOnJS(commit)(dx.value, dy.value, pinch.value, twist.value)\n dx.value = 0\n dy.value = 0\n pinch.value = 1\n twist.value = 0\n }\n\n const pan = Gesture.Pan()\n .enabled(active)\n .onStart(begin)\n .onUpdate((e) => {\n 'worklet'\n dx.value = e.translationX\n dy.value = e.translationY\n })\n .onFinalize(end)\n\n const pinchGesture = Gesture.Pinch()\n .enabled(active)\n .onStart(begin)\n .onUpdate((e) => {\n 'worklet'\n pinch.value = e.scale\n })\n .onFinalize(end)\n\n const rotation = Gesture.Rotation()\n .enabled(active)\n .onStart(begin)\n .onUpdate((e) => {\n 'worklet'\n twist.value = e.rotation\n })\n .onFinalize(end)\n\n return Gesture.Simultaneous(pan, pinchGesture, rotation)\n }, [active, capture, commit, activeCount, visible, dx, dy, pinch, twist])\n\n // The indicator, entirely on the UI thread — no dispatch, no re-render, and\n // no JS hop per frame.\n const ringStyle = useAnimatedStyle(() => {\n const r = Math.max(1, oR.value * pinch.value)\n const cx = oX.value + dx.value\n const cy = oY.value + dy.value\n const band = oLinear.value > 0.5\n return {\n opacity: visible.value,\n left: band ? -width : cx - r,\n top: cy - r,\n width: band ? width * 3 : r * 2,\n height: r * 2,\n borderRadius: band ? 0 : r,\n transform: [{ rotate: `${oRot.value + twist.value}rad` }],\n }\n })\n\n if (!active) return null\n return (\n <GestureDetector gesture={gesture}>\n <Animated.View style={StyleSheet.absoluteFill}>\n {/* Drawn here, in React Native, never inside renderDocument — so no\n editing chrome can reach an export. */}\n <Animated.View pointerEvents=\"none\" style={[styles.ring, ringStyle]} />\n </Animated.View>\n </GestureDetector>\n )\n}\n\nconst styles = StyleSheet.create({\n ring: {\n position: 'absolute',\n borderWidth: 1.5,\n borderColor: 'rgba(255,255,255,0.9)',\n },\n})\n","import React from 'react'\nimport { StyleSheet, View } from 'react-native'\nimport { useInteractionState } from './interactionState'\n\n/** Rule-of-thirds overlay shown only while crop interaction is active. */\nexport function CropGrid({ always = false }: { always?: boolean }) {\n const { cropActive } = useInteractionState()\n if (!always && !cropActive) return null\n return (\n <View pointerEvents=\"none\" style={StyleSheet.absoluteFill}>\n {[1 / 3, 2 / 3].map((fraction) => (\n <React.Fragment key={fraction}>\n <View style={[styles.vertical, { left: `${fraction * 100}%` }]} />\n <View style={[styles.horizontal, { top: `${fraction * 100}%` }]} />\n </React.Fragment>\n ))}\n </View>\n )\n}\n\nconst styles = StyleSheet.create({\n vertical: { position: 'absolute', top: 0, bottom: 0, width: 1, backgroundColor: '#ffffff88' },\n horizontal: { position: 'absolute', left: 0, right: 0, height: 1, backgroundColor: '#ffffff88' },\n})\n","import {\n deleteTargetFromProfile,\n hitTestDocument,\n isDirectManipulationLayer,\n isSameTransform,\n layerNaturalSize,\n layerGestureConfigFromProfile,\n NO_SNAP,\n useEditor,\n useEditorStore,\n type DeleteTarget,\n type LayerSnapState,\n type Transform,\n} from '@pictor-sdk/core'\nimport { preferMeasuredSize, useCanvasMetrics, useRenderer } from '@pictor-sdk/skia'\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { StyleSheet } from 'react-native'\nimport { Gesture, GestureDetector } from 'react-native-gesture-handler'\nimport Animated, { useDerivedValue, useSharedValue } from 'react-native-reanimated'\nimport { runOnJS } from 'react-native-worklets'\nimport {\n composeLayerGestureUI,\n isOverDeleteTargetUI,\n hitTestLayerCandidatesUI,\n layerPreviewDeltaUI,\n} from './layerGestureWorklet'\nimport { useInteractionState } from './interactionState'\nimport { type GestureSnapEvent } from './controller'\n\n/** Overrides for overlay-layer gestures, defaulting to the profile's settings. */\nexport interface LayerGestureSurfaceProps {\n /** Fired once per snap engagement — hook up haptics here if you want them. */\n onSnap?: (event: GestureSnapEvent) => void\n}\n\n/**\n * Direct manipulation of overlay layers: grab the top-most layer under the\n * finger and pan, focal-pinch and rotate it on the UI thread.\n *\n * Three things make this feel right, and each is covered by tests:\n *\n * - **Focal composition.** Scale and rotation happen about the gesture\n * centroid, so the document point under the fingers stays under them.\n * - **Pointer-count re-basing.** Gesture Handler restarts its cumulative\n * translation/scale/rotation when a finger lands or lifts. Every recognizer\n * value is read relative to an origin captured at the last re-base, and the\n * frame re-bases from the live transform whenever the pointer count changes\n * — so two fingers going to one does not jump.\n * - **One history entry.** The document is written exactly once, when the\n * gesture settles, and not at all if nothing actually moved.\n */\nexport function LayerGestureSurface({ onSnap }: LayerGestureSurfaceProps) {\n const { document, dispatch, profile } = useEditor()\n const store = useEditorStore()\n const metrics = useCanvasMetrics()\n // Destructure the setters: the context value's identity changes on every\n // interaction state change (including ones this component causes), so\n // depending on the object would tear down effects mid-gesture. The setters\n // themselves are stable.\n const { setPreview, setLayerDragActive, setOverDeleteTarget, setSnap } = useInteractionState()\n\n const renderer = useRenderer()\n\n const config = useMemo(\n () => layerGestureConfigFromProfile(profile.interaction?.layers),\n [profile],\n )\n const deleteTarget = useMemo(\n () => deleteTargetFromProfile(profile.interaction?.layers),\n [profile],\n )\n const aspect = document.size.height / document.size.width\n // Rebuild hit geometry when the renderer publishes a new text measurement,\n // so a layer's touch box tracks the box it actually draws.\n const [measureVersion, setMeasureVersion] = useState(0)\n useEffect(\n () => renderer.textMeasures.subscribe(() => setMeasureVersion((v) => v + 1)),\n [renderer],\n )\n\n const hitCandidates = useMemo(\n () =>\n document.layers\n .map((layer, index) => ({ layer, index }))\n .filter(\n ({ layer, index }) =>\n !layer.hidden &&\n !layer.locked &&\n isDirectManipulationLayer(layer, index, profile.interaction?.layers),\n )\n .reverse()\n .map(({ layer }) => {\n // The renderer's measurement when it has one, core's estimate\n // otherwise — core cannot lay out text, so its estimate is a\n // character-count approximation that does not match the drawn box.\n const natural = preferMeasuredSize(\n renderer.textMeasures.get(layer.id),\n layerNaturalSize(layer, store.registry, document),\n )\n const anchor = layer.transform.anchor ?? { x: 0.5, y: 0.5 }\n return {\n id: layer.id,\n x: layer.transform.x,\n y: layer.transform.y,\n scale: layer.transform.scale,\n rotation: layer.transform.rotation,\n width: natural.width,\n height: natural.height,\n anchorX: anchor.x,\n anchorY: anchor.y,\n flipX: layer.transform.flipX ?? false,\n flipY: layer.transform.flipY ?? false,\n }\n }),\n // `measureVersion` is deliberate: the measurements live outside React, so\n // this is how a new one re-derives the hit geometry.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [document, profile, store.registry, renderer, measureVersion],\n )\n\n // ── live transform (UI thread) ──\n const liveX = useSharedValue(0.5)\n const liveY = useSharedValue(0.5)\n const liveScale = useSharedValue(1)\n const liveRotation = useSharedValue(0)\n // Immutable for the lifetime of a gesture. The renderer preview is always a\n // delta from the still-committed document transform, never from a frame base.\n const committedX = useSharedValue(0.5)\n const committedY = useSharedValue(0.5)\n const committedScale = useSharedValue(1)\n const committedRotation = useSharedValue(0)\n // ── frame base, re-captured on every pointer-count change ──\n const baseX = useSharedValue(0.5)\n const baseY = useSharedValue(0.5)\n const baseScale = useSharedValue(1)\n const baseRotation = useSharedValue(0)\n // ── recognizer origins, subtracted so each frame starts from zero ──\n const originPanX = useSharedValue(0)\n const originPanY = useSharedValue(0)\n const originPinch = useSharedValue(1)\n const originRotate = useSharedValue(0)\n const rawPanX = useSharedValue(0)\n const rawPanY = useSharedValue(0)\n const rawPinch = useSharedValue(1)\n const rawRotate = useSharedValue(0)\n const focalX = useSharedValue(0.5)\n const focalY = useSharedValue(0.5)\n const pointers = useSharedValue(0)\n const active = useSharedValue(false)\n const snapCX = useSharedValue(false)\n const snapCY = useSharedValue(false)\n const snapR = useSharedValue(false)\n const overDelete = useSharedValue(false)\n\n // ── preview transform: a delta from the committed transform, UI-thread only ──\n const previewTransform = useDerivedValue(() => {\n return layerPreviewDeltaUI(\n {\n x: committedX.value,\n y: committedY.value,\n scale: committedScale.value,\n rotation: committedRotation.value,\n },\n { x: liveX.value, y: liveY.value, scale: liveScale.value, rotation: liveRotation.value },\n document.size.width,\n document.size.height,\n )\n }, [document.size.width, document.size.height])\n\n /**\n * Fresh render state for the JS callbacks below.\n *\n * The callbacks themselves must be identity-stable, because a worklet has to\n * capture them *directly*: Reanimated serialises captured objects, so a\n * function reached through `someRef.current` arrives on the UI thread as a\n * plain value and calling it throws \"Object is not a function\". Stable\n * callbacks + a mutable snapshot gives both fresh data and a gesture object\n * that never needs rebuilding.\n */\n const latest = useRef({ document, metrics, store, dispatch, onSnap, profile })\n latest.current = { document, metrics, store, dispatch, onSnap, profile }\n\n const grabbedId = useRef<string | null>(null)\n const grabbedFrom = useRef<Transform | null>(null)\n const snapState = useRef<LayerSnapState>(NO_SNAP)\n\n const onGrabLayer = useCallback((id: string) => {\n const { document: doc, store: s } = latest.current\n const hit = doc.layers.find((layer) => layer.id === id)\n if (!hit) return\n const t = hit.transform\n grabbedId.current = hit.id\n grabbedFrom.current = { ...t }\n s.select([hit.id])\n setPreview({ layerId: hit.id, transform: previewTransform })\n setLayerDragActive(true)\n }, [setPreview, setLayerDragActive, previewTransform])\n\n const onSelectAt = useCallback((xDp: number, yDp: number) => {\n const { document: doc, metrics: m, store: s } = latest.current\n if (!m) return\n const layerInteraction = latest.current.profile.interaction?.layers\n const hit = hitTestDocument(\n doc,\n { x: xDp / m.width, y: yDp / m.height },\n s.registry,\n (layer, index) => isDirectManipulationLayer(layer, index, layerInteraction),\n )\n s.select(hit && !hit.locked ? [hit.id] : [])\n }, [])\n\n const onSnapChanged = useCallback(\n (centerX: boolean, centerY: boolean, rotation: boolean) => {\n const previous = snapState.current\n const next = { centerX, centerY, rotation }\n snapState.current = next\n const notify = latest.current.onSnap\n if (centerX && !previous.centerX) notify?.({ kind: 'centerX' })\n if (centerY && !previous.centerY) notify?.({ kind: 'centerY' })\n if (rotation && !previous.rotation) notify?.({ kind: 'rotation' })\n setSnap(next)\n },\n [setSnap],\n )\n\n const onHoverChanged = useCallback(\n (over: boolean) => setOverDeleteTarget(over),\n [setOverDeleteTarget],\n )\n\n const onGestureFinished = useCallback(\n (t: Transform, deleted: boolean) => {\n const { dispatch: d, store: s } = latest.current\n const id = grabbedId.current\n const from = grabbedFrom.current\n grabbedId.current = null\n grabbedFrom.current = null\n snapState.current = NO_SNAP\n setLayerDragActive(false)\n setOverDeleteTarget(false)\n setSnap(NO_SNAP)\n setPreview(null)\n if (!id) return\n if (deleted) {\n d({ type: 'layer/remove', id })\n s.select([])\n return\n }\n // a tap, or a drag that ended where it started, must not create an undo entry\n if (from && isSameTransform(from, t)) return\n d({ type: 'layer/transform', id, patch: t })\n },\n [setLayerDragActive, setOverDeleteTarget, setSnap, setPreview],\n )\n\n useEffect(() => () => setPreview(null), [setPreview])\n\n const gesture = useMemo(() => {\n const metricsWidth = metrics?.width ?? 0\n const metricsHeight = metrics?.height ?? 0\n const target: DeleteTarget | null = deleteTarget\n const candidates = hitCandidates\n\n /** Re-capture the frame base and zero every recognizer origin. */\n const rebase = () => {\n 'worklet'\n baseX.value = liveX.value\n baseY.value = liveY.value\n baseScale.value = liveScale.value\n baseRotation.value = liveRotation.value\n originPanX.value = rawPanX.value\n originPanY.value = rawPanY.value\n originPinch.value = rawPinch.value\n originRotate.value = rawRotate.value\n }\n\n const recompute = (settle: boolean) => {\n 'worklet'\n if (!active.value || metricsWidth === 0 || metricsHeight === 0) return\n const out = composeLayerGestureUI(\n {\n x: baseX.value,\n y: baseY.value,\n scale: baseScale.value,\n rotation: baseRotation.value,\n },\n {\n panX: (rawPanX.value - originPanX.value) / metricsWidth,\n panY: (rawPanY.value - originPanY.value) / metricsHeight,\n pinch: rawPinch.value / Math.max(originPinch.value, 1e-9),\n rotate: rawRotate.value - originRotate.value,\n focalX: focalX.value,\n focalY: focalY.value,\n },\n aspect,\n config,\n { centerX: snapCX.value, centerY: snapCY.value, rotation: snapR.value },\n settle,\n )\n liveX.value = out.x\n liveY.value = out.y\n liveScale.value = out.scale\n liveRotation.value = out.rotation\n\n if (\n out.snapCenterX !== snapCX.value ||\n out.snapCenterY !== snapCY.value ||\n out.snapRotation !== snapR.value\n ) {\n snapCX.value = out.snapCenterX\n snapCY.value = out.snapCenterY\n snapR.value = out.snapRotation\n runOnJS(onSnapChanged)(out.snapCenterX, out.snapCenterY, out.snapRotation)\n }\n\n if (target) {\n const over = isOverDeleteTargetUI(out.x, out.y, target, aspect)\n if (over !== overDelete.value) {\n overDelete.value = over\n runOnJS(onHoverChanged)(over)\n }\n }\n }\n\n /** Track pointer count and re-base the frame whenever it changes. */\n const syncPointers = (count: number) => {\n 'worklet'\n if (active.value && count !== pointers.value) {\n pointers.value = count\n rebase()\n }\n }\n\n const endIfIdle = () => {\n 'worklet'\n if (!active.value) {\n // an inert gesture (nothing was grabbed) still has to clear UI state\n runOnJS(onGestureFinished)({ x: 0, y: 0, scale: 1, rotation: 0 }, false)\n return\n }\n recompute(true)\n active.value = false\n pointers.value = 0\n const deleted = overDelete.value\n overDelete.value = false\n snapCX.value = false\n snapCY.value = false\n snapR.value = false\n runOnJS(onGestureFinished)(\n {\n x: liveX.value,\n y: liveY.value,\n scale: liveScale.value,\n rotation: liveRotation.value,\n },\n deleted,\n )\n }\n\n const pan = Gesture.Pan()\n .minPointers(1)\n .maxPointers(2)\n .onBegin((e) => {\n 'worklet'\n if (active.value) return\n rawPanX.value = 0\n rawPanY.value = 0\n rawPinch.value = 1\n rawRotate.value = 0\n originPanX.value = 0\n originPanY.value = 0\n originPinch.value = 1\n originRotate.value = 0\n pointers.value = e.numberOfPointers\n const hit = hitTestLayerCandidatesUI(\n e.x / Math.max(metricsWidth, 1e-9),\n e.y / Math.max(metricsHeight, 1e-9),\n candidates,\n document.size.width,\n document.size.height,\n )\n if (!hit) {\n active.value = false\n return\n }\n liveX.value = hit.x\n liveY.value = hit.y\n liveScale.value = hit.scale\n liveRotation.value = hit.rotation\n committedX.value = hit.x\n committedY.value = hit.y\n committedScale.value = hit.scale\n committedRotation.value = hit.rotation\n baseX.value = hit.x\n baseY.value = hit.y\n baseScale.value = hit.scale\n baseRotation.value = hit.rotation\n focalX.value = hit.x\n focalY.value = hit.y\n active.value = true\n runOnJS(onGrabLayer)(hit.id)\n })\n .onUpdate((e) => {\n 'worklet'\n rawPanX.value = e.translationX\n rawPanY.value = e.translationY\n syncPointers(e.numberOfPointers)\n recompute(false)\n })\n .onFinalize(() => {\n 'worklet'\n endIfIdle()\n })\n\n const pinch = Gesture.Pinch().onUpdate((e) => {\n 'worklet'\n rawPinch.value = e.scale\n focalX.value = e.focalX / metricsWidth\n focalY.value = e.focalY / metricsHeight\n syncPointers(e.numberOfPointers)\n recompute(false)\n })\n\n const rotate = Gesture.Rotation()\n .enabled(config.rotationEnabled)\n .onUpdate((e) => {\n 'worklet'\n rawRotate.value = e.rotation\n focalX.value = e.anchorX / metricsWidth\n focalY.value = e.anchorY / metricsHeight\n syncPointers(e.numberOfPointers)\n recompute(false)\n })\n\n const tap = Gesture.Tap().onEnd((e) => {\n 'worklet'\n runOnJS(onSelectAt)(e.x, e.y)\n })\n\n return Gesture.Simultaneous(Gesture.Race(pan, tap), pinch, rotate)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n metrics,\n config,\n deleteTarget,\n aspect,\n onGrabLayer,\n onSelectAt,\n onSnapChanged,\n onHoverChanged,\n onGestureFinished,\n hitCandidates,\n document.size.width,\n document.size.height,\n ])\n\n return (\n <GestureDetector gesture={gesture}>\n <Animated.View style={StyleSheet.absoluteFill} />\n </GestureDetector>\n )\n}\n","import { type ResolvedLayerGestureConfig } from '@pictor-sdk/core'\n\n/**\n * UI-thread twin of `composeLayerGesture` from @pictor-sdk/core.\n *\n * DECISION: the gesture math exists twice on purpose. @pictor-sdk/core must stay\n * free of Reanimated (invariant 5) and must run in plain Node, so it cannot\n * carry a `'worklet'` directive; but the preview has to recompute the\n * transform on the UI thread every frame, which requires a worklet. Rather\n * than rely on the consumer's Babel config workletizing another package's\n * source, the worklet lives here — and `worklet-parity.test.ts` asserts the\n * two implementations agree across a grid of inputs, so they cannot drift.\n *\n * Keep this function free of imports and closures over anything but plain\n * numbers and frozen config objects.\n */\nexport interface WorkletTransform {\n x: number\n y: number\n scale: number\n rotation: number\n snapCenterX: boolean\n snapCenterY: boolean\n snapRotation: boolean\n}\n\nexport interface WorkletBase {\n x: number\n y: number\n scale: number\n rotation: number\n}\n\nexport interface WorkletInput {\n panX: number\n panY: number\n pinch: number\n rotate: number\n focalX: number\n focalY: number\n}\n\nexport interface WorkletPrevSnap {\n centerX: boolean\n centerY: boolean\n rotation: boolean\n}\n\nexport function composeLayerGestureUI(\n base: WorkletBase,\n input: WorkletInput,\n aspect: number,\n config: ResolvedLayerGestureConfig,\n previous: WorkletPrevSnap,\n settle: boolean,\n): WorkletTransform {\n 'worklet'\n const requested = base.scale * input.pinch\n let scale: number\n if (settle) {\n scale = Math.min(config.maxScale, Math.max(config.minScale, requested))\n } else if (requested < config.minScale) {\n scale = config.minScale - (config.minScale - requested) * config.scaleResistance\n } else if (requested > config.maxScale) {\n scale = config.maxScale + (requested - config.maxScale) * config.scaleResistance\n } else {\n scale = requested\n }\n\n const ratio = scale / Math.max(base.scale, 1e-9)\n const rotationDelta = config.rotationEnabled ? input.rotate : 0\n\n const dx = base.x - input.focalX\n const dy = (base.y - input.focalY) * aspect\n const cos = Math.cos(rotationDelta)\n const sin = Math.sin(rotationDelta)\n const rx = (dx * cos - dy * sin) * ratio\n const ry = (dx * sin + dy * cos) * ratio\n\n let x = input.focalX + rx + input.panX\n let y = input.focalY + ry / aspect + input.panY\n let rotation = base.rotation + rotationDelta\n\n let snapCenterX = false\n let snapCenterY = false\n let snapRotation = false\n\n if (config.centerSnap !== false) {\n const engage = config.centerSnap\n const release = Math.max(engage, config.centerSnapRelease)\n const tx = previous.centerX ? release : engage\n if (Math.abs(x - 0.5) <= tx + 1e-9) {\n x = 0.5\n snapCenterX = true\n }\n const ty = previous.centerY ? release : engage\n if (Math.abs(y - 0.5) <= ty + 1e-9) {\n y = 0.5\n snapCenterY = true\n }\n }\n\n if (config.rotationSnap !== false && config.rotationEnabled) {\n const engage = config.rotationSnap\n const release = Math.max(engage, config.rotationSnapRelease)\n const step = Math.PI / 2\n const nearest = Math.round(rotation / step) * step\n const tr = previous.rotation ? release : engage\n if (Math.abs(rotation - nearest) <= tr + 1e-9) {\n rotation = nearest\n snapRotation = true\n }\n }\n\n return { x, y, scale, rotation, snapCenterX, snapCenterY, snapRotation }\n}\n\n/**\n * UI-thread twin of `isOverDeleteTarget`.\n *\n * Same reason as above: a worklet may only call other worklets, and\n * @pictor-sdk/core cannot carry the directive. Held to core by the parity test.\n */\nexport function isOverDeleteTargetUI(\n x: number,\n y: number,\n target: { x: number; y: number; radius: number },\n aspect: number,\n): boolean {\n 'worklet'\n const dx = x - target.x\n const dy = (y - target.y) * aspect\n return Math.sqrt(dx * dx + dy * dy) <= target.radius\n}\n\n/**\n * Renderer delta from the immutable committed transform to the live transform.\n * Pointer-frame rebasing must never change these reference values.\n */\nexport function layerPreviewDeltaUI(\n committed: { x: number; y: number; scale: number; rotation: number },\n live: { x: number; y: number; scale: number; rotation: number },\n width: number,\n height: number,\n) {\n 'worklet'\n return [\n { translateX: live.x * width },\n { translateY: live.y * height },\n { rotate: live.rotation - committed.rotation },\n { scale: live.scale / Math.max(committed.scale, 1e-9) },\n { translateX: -committed.x * width },\n { translateY: -committed.y * height },\n ]\n}\n\nexport interface LayerHitCandidateUI {\n id: string\n x: number\n y: number\n scale: number\n rotation: number\n width: number\n height: number\n anchorX: number\n anchorY: number\n flipX: boolean\n flipY: boolean\n}\n\n/** Top-most bounding-box hit test used to activate built-in overlays instantly. */\nexport function hitTestLayerCandidatesUI(\n x: number,\n y: number,\n candidates: readonly LayerHitCandidateUI[],\n documentWidth: number,\n documentHeight: number,\n): LayerHitCandidateUI | null {\n 'worklet'\n for (let i = 0; i < candidates.length; i++) {\n const candidate = candidates[i]!\n let dx = x * documentWidth - candidate.x * documentWidth\n let dy = y * documentHeight - candidate.y * documentHeight\n const cos = Math.cos(-candidate.rotation)\n const sin = Math.sin(-candidate.rotation)\n const rx = dx * cos - dy * sin\n const ry = dx * sin + dy * cos\n dx = candidate.flipX ? -rx : rx\n dy = candidate.flipY ? -ry : ry\n const width = candidate.scale * candidate.width * documentWidth\n const height = candidate.scale * candidate.height * documentWidth\n if (width <= 0 || height <= 0) continue\n const localX = dx / width + candidate.anchorX\n const localY = dy / height + candidate.anchorY\n if (localX >= 0 && localX <= 1 && localY >= 0 && localY <= 1) return candidate\n }\n return null\n}\n","import {\n doubleTapMediaTransform,\n isBaseImageLayer,\n isSameTransform,\n mediaConfigFromProfile,\n useEditor,\n type ImageLayerData,\n type Layer,\n type Transform,\n} from '@pictor-sdk/core'\nimport { preferResolvedSize, useCanvasMetrics, useResolvedImageSize } from '@pictor-sdk/skia'\nimport React, { useCallback, useEffect, useMemo, useRef } from 'react'\nimport { StyleSheet } from 'react-native'\nimport { Gesture, GestureDetector } from 'react-native-gesture-handler'\nimport Animated, {\n cancelAnimation,\n useDerivedValue,\n useSharedValue,\n withTiming,\n} from 'react-native-reanimated'\nimport { runOnJS } from 'react-native-worklets'\nimport {\n composeMediaGestureUI,\n onRecognizerBegin,\n onRecognizerEnd,\n} from './mediaGestureWorklet'\nimport { createSettleCoordinator, type SettleCoordinator } from './settleCoordinator'\nimport {\n beginOwnership,\n commitOwnership,\n documentChanged,\n IDLE_OWNERSHIP,\n type OwnershipState,\n} from './transformOwnership'\nimport { useInteractionState } from './interactionState'\n\n/** Overrides for base-media gestures, defaulting to the profile's settings. */\nexport interface StoryMediaGestureSurfaceProps {\n /** Fired when a media gesture starts and ends — for host haptics/chrome. */\n onInteractionChange?: (active: boolean) => void\n}\n\n/** Find the document's base media — the bottom-most layer, if it is an image. */\nexport function useBaseMediaLayer(): Layer | undefined {\n const { document } = useEditor()\n const base = document.layers[0]\n return base && isBaseImageLayer(document.layers, base.id) ? base : undefined\n}\n\n/**\n * Direct manipulation of the Story base photo: one-finger reposition, focal\n * pinch and rotation, held inside rotation-aware pan bounds with rubber-band\n * resistance and a bounded settle.\n *\n * Mounted only while the `media` tool is active, so it cannot compete with\n * overlay or drawing gestures. The transform is written to the document once\n * per settled gesture; because the tool session already opened a history batch\n * (see `ToolPanelHost`), a whole session of adjustments collapses into one undo\n * entry, and a session that changed nothing records none.\n */\nexport function StoryMediaGestureSurface({\n onInteractionChange,\n}: StoryMediaGestureSurfaceProps) {\n const { document, dispatch, profile } = useEditor()\n const metrics = useCanvasMetrics()\n const { setPreview } = useInteractionState()\n const layer = useBaseMediaLayer()\n\n const config = useMemo(\n () => mediaConfigFromProfile(profile.interaction?.media),\n [profile],\n )\n // The renderer sizes the layer from the DECODED image, so geometry must use\n // the same number. A declared intrinsic of 0x0 is normal for a remote URL.\n const declared = (layer?.data as ImageLayerData | undefined)?.intrinsic\n const resolved = useResolvedImageSize((layer?.data as ImageLayerData | undefined)?.source)\n const intrinsic = useMemo(\n () => preferResolvedSize(resolved, declared),\n [resolved, declared],\n )\n const canvas = document.size\n\n // ── live transform (UI thread) ──\n const liveX = useSharedValue(0.5)\n const liveY = useSharedValue(0.5)\n const liveScale = useSharedValue(1)\n const liveRotation = useSharedValue(0)\n // ── frame base, re-captured on every pointer-count change ──\n const baseX = useSharedValue(0.5)\n const baseY = useSharedValue(0.5)\n const baseScale = useSharedValue(1)\n const baseRotation = useSharedValue(0)\n // ── recognizer origins, subtracted so each frame starts from zero ──\n const originPanX = useSharedValue(0)\n const originPanY = useSharedValue(0)\n const originPinch = useSharedValue(1)\n const originRotate = useSharedValue(0)\n const rawPanX = useSharedValue(0)\n const rawPanY = useSharedValue(0)\n const rawPinch = useSharedValue(1)\n const rawRotate = useSharedValue(0)\n const focalX = useSharedValue(0.5)\n const focalY = useSharedValue(0.5)\n const active = useSharedValue(false)\n /** How many of pan/pinch/rotation are still live. */\n const recognizers = useSharedValue(0)\n /**\n * Whether each recognizer actually activated.\n *\n * `onBegin` fires on touch-down for every recognizer, including the taps of a\n * double-tap that `Gesture.Exclusive` will go on to win. Ownership has to key\n * off activation instead, or a plain tap opens and closes a whole interaction\n * -- registering a preview, settling and committing -- underneath the\n * double-tap animation it is racing.\n */\n const startedPan = useSharedValue(false)\n const startedPinch = useSharedValue(false)\n const startedRotate = useSharedValue(false)\n /**\n * Drives the settle's timing, and nothing else.\n *\n * The commit has to happen when the settle *finishes*, which means some\n * animation has to report completion. Using one of the four transform\n * animations for that is a trap: a gesture clamped in position but not scale\n * ends with `liveScale` already at its target, and `withTiming` from a value\n * to itself completes in a single frame. That committed 6ms into a 180ms\n * settle and cut the x/y animations off before they had moved. This value\n * always travels 0 -> 1, so it always takes the full duration.\n */\n const settleProgress = useSharedValue(0)\n\n const committed = layer?.transform\n\n /**\n * Ownership of the transform, as a plain ref.\n *\n * Deliberately not a shared value: this is read during render on the JS\n * thread, and a shared value written on the UI thread reaches the JS side\n * only asynchronously, so the guard could read stale and skip the reseed.\n * Every writer here runs on the JS thread.\n */\n const ownership = useRef<OwnershipState>(IDLE_OWNERSHIP)\n\n // Re-seed from the document whenever the committed transform changes from\n // outside the gesture (undo, Cancel, a fresh photo) and whenever a gesture\n // commits — the preview is a delta from these, so they must track the\n // document exactly.\n useEffect(() => {\n const next = documentChanged(ownership.current, committed)\n ownership.current = next.state\n if (!next.reseed || !committed) return\n liveX.value = committed.x\n liveY.value = committed.y\n liveScale.value = committed.scale\n liveRotation.value = committed.rotation\n // shared values are stable refs; only committed scalars resync them\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [committed?.x, committed?.y, committed?.scale, committed?.rotation])\n\n /**\n * The transform the canvas already drew the layer at, captured when the\n * interaction begins.\n *\n * The preview is a *delta* from it, so the two must never disagree. Deriving\n * it from the document each render sounds safer but is worse: the preview is\n * registered from an effect, so on the render that commits, the canvas holds\n * the new document transform and still the previous preview — one frame of\n * the delta applied to the wrong baseline. Capturing it at grab sidesteps the\n * question entirely, because the document cannot change during an\n * interaction, and the preview is cleared in the same call that dispatches.\n */\n const baseCommittedX = useSharedValue(0.5)\n const baseCommittedY = useSharedValue(0.5)\n const baseCommittedScale = useSharedValue(1)\n const baseCommittedRotation = useSharedValue(0)\n\n const previewTransform = useDerivedValue(() => {\n const ratio = liveScale.value / Math.max(baseCommittedScale.value, 1e-9)\n return [\n { translateX: liveX.value * canvas.width },\n { translateY: liveY.value * canvas.height },\n { rotate: liveRotation.value - baseCommittedRotation.value },\n { scale: ratio },\n { translateX: -baseCommittedX.value * canvas.width },\n { translateY: -baseCommittedY.value * canvas.height },\n ]\n }, [canvas.width, canvas.height])\n\n useEffect(() => () => setPreview(null), [setPreview])\n\n const latest = useRef({ layer, dispatch, onInteractionChange, previewTransform })\n latest.current = { layer, dispatch, onInteractionChange, previewTransform }\n const settleCoordinatorRef = useRef<SettleCoordinator<Transform> | null>(null)\n\n /** Hand the transform to the gesture: stop any settle, start previewing. */\n const beginInteraction = useCallback(() => {\n // A touch that lands during a settle takes ownership of the transform, so\n // the settle in flight must never commit its stale target. This runs in the\n // same `runOnJS` hop `begin()` already makes, and the interrupted\n // animation's own completion callback is queued ahead of it, so there is no\n // window in which the old settle can still write.\n settleCoordinatorRef.current?.cancel()\n ownership.current = beginOwnership()\n const current = latest.current.layer\n if (current) {\n // snapshot the baseline the canvas is drawing at, then start previewing\n baseCommittedX.value = current.transform.x\n baseCommittedY.value = current.transform.y\n baseCommittedScale.value = current.transform.scale\n baseCommittedRotation.value = current.transform.rotation\n setPreview({ layerId: current.id, transform: latest.current.previewTransform })\n }\n latest.current.onInteractionChange?.(true)\n // shared values are stable refs\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [setPreview])\n\n /**\n * Write the settled transform. One document write per gesture — and none at\n * all when the gesture settled exactly where it started, so a tap or a\n * there-and-back drag leaves the session clean.\n */\n const commitNow = useCallback((next: Transform) => {\n const current = latest.current.layer\n // Cleared in the same call that dispatches, so React batches them into one\n // render: the delta goes away exactly as the document takes the transform.\n setPreview(null)\n latest.current.onInteractionChange?.(false)\n // A no-op commit means no document update is coming, so ownership ends\n // here. Otherwise it lasts until the document reports `next` back — until\n // then `live` already holds it, and reseeding would flash the old value.\n const dispatched = current !== undefined && !isSameTransform(current.transform, next)\n ownership.current = commitOwnership(next, dispatched, current?.transform)\n if (!dispatched || !current) return\n latest.current.dispatch({\n type: 'layer/transform',\n id: current.id,\n patch: { x: next.x, y: next.y, scale: next.scale, rotation: next.rotation },\n })\n }, [setPreview])\n\n const settleCoordinator = useMemo(\n () => createSettleCoordinator<Transform>((target) => commitNow(target)),\n // commitNow reads through `latest`, so it is stable\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [],\n )\n // `beginInteraction` is created before the coordinator exists, so it reaches it here.\n settleCoordinatorRef.current = settleCoordinator\n\n /**\n * Animate to `target`, then write it. The write happens in the animation's\n * completion callback — writing first would change `committed` and cancel the\n * very animation heading there.\n */\n const settleTo = useCallback(\n (target: Transform, duration: number) => {\n settleCoordinator.settle(target, (done) => {\n liveX.value = withTiming(target.x, { duration })\n liveY.value = withTiming(target.y, { duration })\n liveRotation.value = withTiming(target.rotation, { duration })\n liveScale.value = withTiming(target.scale, { duration })\n // the timekeeper: never degenerate, so it always runs the full duration\n settleProgress.value = 0\n settleProgress.value = withTiming(1, { duration }, (finished) => {\n 'worklet'\n runOnJS(done)(finished === true)\n })\n })\n },\n // shared values are stable refs, so they are deliberately not dependencies\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [settleCoordinator],\n )\n\n // Abandon a settle in flight if the tool closes or the surface unmounts, so\n // no stale transform is written after the session has gone.\n useEffect(\n () => () => {\n settleCoordinator.cancel()\n ownership.current = IDLE_OWNERSHIP\n cancelAnimation(liveX)\n cancelAnimation(liveY)\n cancelAnimation(liveScale)\n cancelAnimation(liveRotation)\n cancelAnimation(settleProgress)\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [settleCoordinator],\n )\n\n const runDoubleTap = useCallback(\n (xDp: number, yDp: number) => {\n const current = latest.current.layer\n if (!current || !metrics) return\n const target = doubleTapMediaTransform(current.transform, canvas, intrinsic, config, {\n x: xDp / metrics.width,\n y: yDp / metrics.height,\n })\n // the animation drives the live values, so it needs the preview too\n beginInteraction()\n settleTo(target, config.settleMs)\n },\n [metrics, canvas, intrinsic, config, settleTo, beginInteraction],\n )\n\n const gesture = useMemo(() => {\n const width = metrics?.width ?? 0\n const height = metrics?.height ?? 0\n const settleMs = config.settleMs\n\n const recompute = () => {\n 'worklet'\n if (!active.value || width === 0 || height === 0) return\n const out = composeMediaGestureUI(\n {\n x: baseX.value,\n y: baseY.value,\n scale: baseScale.value,\n rotation: baseRotation.value,\n },\n {\n panX: (rawPanX.value - originPanX.value) / width,\n panY: (rawPanY.value - originPanY.value) / height,\n pinch: rawPinch.value / Math.max(originPinch.value, 1e-9),\n rotate: rawRotate.value - originRotate.value,\n focalX: focalX.value,\n focalY: focalY.value,\n },\n canvas,\n intrinsic,\n config,\n false,\n )\n liveX.value = out.x\n liveY.value = out.y\n liveScale.value = out.scale\n liveRotation.value = out.rotation\n }\n\n const begin = () => {\n 'worklet'\n const started = onRecognizerBegin(recognizers.value)\n recognizers.value = started.count\n // A recognizer joining an interaction already in flight seeds its own\n // raw/origin pair in its onStart and needs nothing else: each one's\n // contribution is measured from its own activation, so they compose\n // without re-anchoring the frame.\n if (!started.isFirst) return\n // Take the transform away from any settle in flight. The animations are\n // stopped first so `live*` holds what is actually on screen, and that is\n // what the new gesture bases itself on — grabbing a photo mid-settle\n // continues from where the finger sees it, with no jump.\n cancelAnimation(liveX)\n cancelAnimation(liveY)\n cancelAnimation(liveScale)\n cancelAnimation(liveRotation)\n cancelAnimation(settleProgress)\n active.value = true\n // each recognizer seeds its own raw/origin pair in its onStart; anything\n // that has not activated contributes a neutral value\n rawPanX.value = 0\n rawPanY.value = 0\n rawPinch.value = 1\n rawRotate.value = 0\n originPanX.value = 0\n originPanY.value = 0\n originPinch.value = 1\n originRotate.value = 0\n baseX.value = liveX.value\n baseY.value = liveY.value\n baseScale.value = liveScale.value\n baseRotation.value = liveRotation.value\n focalX.value = liveX.value\n focalY.value = liveY.value\n runOnJS(beginInteraction)()\n }\n\n const finish = () => {\n 'worklet'\n const ended = onRecognizerEnd(recognizers.value)\n recognizers.value = ended.count\n // Pinch and rotation finalise as soon as a finger lifts while the pan\n // recognizer keeps running with the remaining one. Ending here would cut\n // the interaction short, so wait for the last recognizer.\n if (!ended.isLast || !active.value) return\n active.value = false\n // settle: hard-clamp back inside the bounds, then animate there\n const settled = composeMediaGestureUI(\n {\n x: baseX.value,\n y: baseY.value,\n scale: baseScale.value,\n rotation: baseRotation.value,\n },\n {\n panX: (rawPanX.value - originPanX.value) / width,\n panY: (rawPanY.value - originPanY.value) / height,\n pinch: rawPinch.value / Math.max(originPinch.value, 1e-9),\n rotate: rawRotate.value - originRotate.value,\n focalX: focalX.value,\n focalY: focalY.value,\n },\n canvas,\n intrinsic,\n config,\n true,\n )\n runOnJS(settleTo)(settled, settleMs)\n }\n\n const pan = Gesture.Pan()\n .minPointers(1)\n .maxPointers(2)\n // A recognizer only activates once the finger has travelled past the\n // touch slop, and by then its cumulative value already includes that\n // travel. Taking the origin at activation is what keeps the photo still\n // under the finger; taking it at touch-down makes it leap by the slop.\n .onStart((e) => {\n 'worklet'\n startedPan.value = true\n begin()\n rawPanX.value = e.translationX\n rawPanY.value = e.translationY\n originPanX.value = e.translationX\n originPanY.value = e.translationY\n })\n .onUpdate((e) => {\n 'worklet'\n rawPanX.value = e.translationX\n rawPanY.value = e.translationY\n recompute()\n })\n .onFinalize(() => {\n 'worklet'\n if (!startedPan.value) return\n startedPan.value = false\n finish()\n })\n\n const pinch = Gesture.Pinch()\n .onStart((e) => {\n 'worklet'\n startedPinch.value = true\n begin()\n rawPinch.value = e.scale\n originPinch.value = e.scale\n focalX.value = e.focalX / width\n focalY.value = e.focalY / height\n })\n .onUpdate((e) => {\n 'worklet'\n rawPinch.value = e.scale\n focalX.value = e.focalX / width\n focalY.value = e.focalY / height\n recompute()\n })\n .onFinalize(() => {\n 'worklet'\n if (!startedPinch.value) return\n startedPinch.value = false\n finish()\n })\n\n const rotate = Gesture.Rotation()\n .enabled(config.rotationEnabled)\n .onStart((e) => {\n 'worklet'\n startedRotate.value = true\n begin()\n rawRotate.value = e.rotation\n originRotate.value = e.rotation\n })\n .onUpdate((e) => {\n 'worklet'\n // Only the pinch owns the focal point. Gesture Handler's rotation\n // anchor and pinch focal are computed separately and disagree by a\n // pixel or two, so letting both write it made the focal — and with it\n // the whole composed transform — oscillate every frame.\n rawRotate.value = e.rotation\n recompute()\n })\n .onFinalize(() => {\n 'worklet'\n if (!startedRotate.value) return\n startedRotate.value = false\n finish()\n })\n\n const doubleTap = Gesture.Tap()\n .numberOfTaps(2)\n .onEnd((e) => {\n 'worklet'\n runOnJS(runDoubleTap)(e.x, e.y)\n })\n\n // `Exclusive(doubleTap, ...)` would make the pan wait for the double-tap to\n // *fail* before it may activate — and a two-tap gesture only fails once the\n // finger has moved past its delta threshold or its timing windows expire,\n // up to half a second. That gated the start of every drag, which is felt as\n // lag however fast the rest of the pipeline is.\n //\n // Racing them instead lets the pan activate the moment it passes touch\n // slop, while a stationary double-tap still wins because a tap never moves\n // far enough to activate the pan. This is the composition the overlay\n // surface uses, which is the one that feels immediate.\n return Gesture.Simultaneous(Gesture.Race(pan, doubleTap), pinch, rotate)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [metrics, canvas, intrinsic, config, settleTo, beginInteraction, runDoubleTap])\n\n if (!layer) return null\n return (\n <GestureDetector gesture={gesture}>\n <Animated.View style={StyleSheet.absoluteFill} />\n </GestureDetector>\n )\n}\n","import { type ResolvedMediaConfig } from '@pictor-sdk/core'\n\n/**\n * UI-thread twin of `composeMediaGesture` from @pictor-sdk/core.\n *\n * DECISION: the same deliberate duplication as `layerGestureWorklet`. Core must\n * stay free of Reanimated and must run in plain Node, so it cannot carry a\n * `'worklet'` directive; but the preview recomputes the transform every frame\n * on the UI thread, which requires one. `media-worklet-parity.test.ts` holds\n * the two implementations together across a grid of inputs, so they cannot\n * drift.\n *\n * Keep this file free of imports beyond types, and of closures over anything\n * but plain numbers and frozen config objects.\n */\nexport interface MediaWorkletTransform {\n x: number\n y: number\n scale: number\n rotation: number\n}\n\nexport interface MediaWorkletInput {\n panX: number\n panY: number\n pinch: number\n rotate: number\n focalX: number\n focalY: number\n}\n\nexport interface MediaWorkletSize {\n width: number\n height: number\n}\n\n/** Mirror of core's `mediaFitScale`. */\nexport function mediaFitScaleUI(\n intrinsic: MediaWorkletSize,\n canvas: MediaWorkletSize,\n fit: 'width' | 'cover' | 'contain',\n rotation: number,\n): number {\n 'worklet'\n if (intrinsic.width <= 0 || intrinsic.height <= 0) return 1\n if (fit === 'width') return 1\n const w = canvas.width\n const h = canvas.width * (intrinsic.height / intrinsic.width)\n const cos = Math.abs(Math.cos(rotation))\n const sin = Math.abs(Math.sin(rotation))\n const byWidth = canvas.width / (w * cos + h * sin)\n const byHeight = canvas.height / (w * sin + h * cos)\n return fit === 'cover' ? Math.max(byWidth, byHeight) : Math.min(byWidth, byHeight)\n}\n\n/** Mirror of core's `mediaPanBounds`. */\nexport function mediaPanBoundsUI(\n _intrinsic: MediaWorkletSize,\n _canvas: MediaWorkletSize,\n _scale: number,\n _rotation: number,\n): { minX: number; maxX: number; minY: number; maxY: number } {\n 'worklet'\n // Mirror of core's `mediaPanBounds`: the media is freely positionable, held\n // only so its anchor stays on the canvas and it can always be dragged back.\n return { minX: 0, maxX: 1, minY: 0, maxY: 1 }\n}\n\n/** Mirror of core's `composeMediaGesture`. */\nexport function composeMediaGestureUI(\n base: MediaWorkletTransform,\n input: MediaWorkletInput,\n canvas: MediaWorkletSize,\n intrinsic: MediaWorkletSize,\n config: ResolvedMediaConfig,\n settle: boolean,\n): MediaWorkletTransform {\n 'worklet'\n const rotationDelta = config.rotationEnabled ? input.rotate : 0\n const rotation = base.rotation + rotationDelta\n\n const fit = mediaFitScaleUI(intrinsic, canvas, config.fit, rotation)\n const minScale = fit * config.minScaleFactor\n const maxScale = Math.max(minScale, config.maxScale)\n\n const requested = base.scale * input.pinch\n let scale: number\n if (settle) {\n scale = Math.min(maxScale, Math.max(minScale, requested))\n } else if (requested < minScale) {\n scale = minScale - (minScale - requested) * config.resistance\n } else if (requested > maxScale) {\n scale = maxScale + (requested - maxScale) * config.resistance\n } else {\n scale = requested\n }\n\n const aspect = canvas.height / canvas.width\n const ratio = scale / Math.max(base.scale, 1e-9)\n const dx = base.x - input.focalX\n const dy = (base.y - input.focalY) * aspect\n const cos = Math.cos(rotationDelta)\n const sin = Math.sin(rotationDelta)\n const rx = (dx * cos - dy * sin) * ratio\n const ry = (dx * sin + dy * cos) * ratio\n\n const rawX = input.focalX + rx + input.panX\n const rawY = input.focalY + ry / aspect + input.panY\n\n const bounds = mediaPanBoundsUI(intrinsic, canvas, scale, rotation)\n let x: number\n let y: number\n if (settle) {\n x = Math.min(bounds.maxX, Math.max(bounds.minX, rawX))\n y = Math.min(bounds.maxY, Math.max(bounds.minY, rawY))\n } else {\n x =\n rawX < bounds.minX\n ? bounds.minX - (bounds.minX - rawX) * config.resistance\n : rawX > bounds.maxX\n ? bounds.maxX + (rawX - bounds.maxX) * config.resistance\n : rawX\n y =\n rawY < bounds.minY\n ? bounds.minY - (bounds.minY - rawY) * config.resistance\n : rawY > bounds.maxY\n ? bounds.maxY + (rawY - bounds.maxY) * config.resistance\n : rawY\n }\n\n return { x, y, scale, rotation }\n}\n\n// ─────────────────────────────────────────────────────────────\n// Recognizer lifecycle\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Pan, pinch and rotation run simultaneously, and each finalises on its own.\n * Lifting one finger of a two-finger gesture finalises pinch and rotation while\n * the pan recognizer keeps running with the remaining finger — so an\n * interaction must only be considered over once *every* recognizer has\n * finalised. Counting them is what makes two-fingers-to-one continuous instead\n * of ending the gesture early.\n *\n * Pure and worklet-safe so the surface and its tests share one definition.\n */\nexport function onRecognizerBegin(count: number): { count: number; isFirst: boolean } {\n 'worklet'\n const next = Math.max(0, count) + 1\n return { count: next, isFirst: next === 1 }\n}\n\n/** Returns `isLast` only when this was the final live recognizer. */\nexport function onRecognizerEnd(count: number): { count: number; isLast: boolean } {\n 'worklet'\n const next = Math.max(0, count - 1)\n return { count: next, isLast: next === 0 && count > 0 }\n}\n","/**\n * Coordinates the settle animation and the single document write that follows\n * it.\n *\n * Committing *while* the animation runs is the trap: the commit changes the\n * document, which re-seeds the live shared values from the committed\n * transform, which cancels the animation that was still running. So the commit\n * has to happen when the animation reports completion, not when it is started.\n *\n * Kept pure — the animator and the commit are injected — so the ordering rules\n * below are unit-testable without Reanimated:\n *\n * - a settle commits exactly once, when its animation finishes;\n * - an animation that is interrupted commits nothing;\n * - a newer settle supersedes an older one, so a late completion from the\n * superseded animation cannot commit stale values;\n * - `cancel()` (tool dismissed, unmount) prevents any pending commit.\n */\nexport interface SettleAnimation {\n /** Run the animation; call `done(true)` on completion, `done(false)` if interrupted. */\n (done: (finished: boolean) => void): void\n}\n\nexport interface SettleCoordinator<T> {\n /** Animate toward `target`, committing it when the animation completes. */\n settle(target: T, animate: SettleAnimation): void\n /** Abandon any settle in flight without committing. */\n cancel(): void\n /** True while an animation is running and its commit is still pending. */\n isSettling(): boolean\n}\n\nexport function createSettleCoordinator<T>(commit: (target: T) => void): SettleCoordinator<T> {\n // Monotonic token: only the newest settle may commit. Cancelling bumps it too,\n // so a completion callback that arrives afterwards is ignored.\n let generation = 0\n let settling = false\n\n return {\n settle(target, animate) {\n generation += 1\n const mine = generation\n settling = true\n animate((finished) => {\n if (mine !== generation) return // superseded, cancelled, or already resolved\n generation += 1 // one completion per settle, whatever the animator does\n settling = false\n if (finished) commit(target)\n })\n },\n\n cancel() {\n generation += 1\n settling = false\n },\n\n isSettling() {\n return settling\n },\n }\n}\n","import { isSameTransform, type Transform } from '@pictor-sdk/core'\n\n/**\n * Who owns a layer's live transform: the gesture surface, or the document.\n *\n * The surface drives `live*` shared values while a gesture or its settle runs,\n * and the canvas draws them as a delta from the transform the document holds.\n * The handover back to the document is the delicate part, and getting it wrong\n * is visible as a single-frame flash:\n *\n * - release ownership when `dispatch` is *called* and the resync can fire while\n * the document still holds the old transform, snapping `live` back to it for\n * one frame;\n * - never release it and an undo or a Cancel cannot reseed `live` at all.\n *\n * So ownership ends when the document actually reports the transform that was\n * committed — not before. Until then `live` is already correct and must be left\n * alone. Pure and synchronous, so the ordering is unit-testable.\n */\nexport interface OwnershipState {\n /** True while the surface, not the document, decides the transform. */\n owning: boolean\n /** A transform dispatched but not yet observed on the document. */\n pending: Transform | null\n /**\n * What the document held when `pending` was dispatched.\n *\n * Needed to tell \"our commit has not landed yet\" from \"something else\n * changed the document\": both merely differ from `pending`, and only the\n * second should reseed.\n */\n previous: Transform | null\n}\n\nexport const IDLE_OWNERSHIP: OwnershipState = { owning: false, pending: null, previous: null }\n\n/** A gesture or animation takes the transform. */\nexport function beginOwnership(): OwnershipState {\n return { owning: true, pending: null, previous: null }\n}\n\n/**\n * The surface committed `target`.\n *\n * `dispatched` is false when the commit was a no-op — the transform never\n * changed, so no document update is coming and ownership ends immediately.\n */\nexport function commitOwnership(\n target: Transform,\n dispatched: boolean,\n previous?: Transform,\n): OwnershipState {\n return dispatched\n ? { owning: true, pending: target, previous: previous ?? null }\n : IDLE_OWNERSHIP\n}\n\nexport interface DocumentChange {\n state: OwnershipState\n /** Whether `live*` should be reseeded from the document. */\n reseed: boolean\n}\n\n/**\n * The document's transform for this layer changed, or the effect re-ran.\n *\n * Reseeding is for changes the surface did not make — undo, Cancel, a new\n * photo. A change the surface itself dispatched needs no reseed: `live` is\n * already sitting on exactly that value, and rewriting it is what introduces\n * the flash.\n */\nexport function documentChanged(\n state: OwnershipState,\n committed: Transform | undefined,\n): DocumentChange {\n if (!committed) return { state, reseed: false }\n if (state.pending) {\n // our commit landed: `live` is already on it, so hand back without touching\n if (isSameTransform(state.pending, committed)) return { state: IDLE_OWNERSHIP, reseed: false }\n // the document still holds what it did when we dispatched — the update has\n // simply not rendered yet. Reseeding here is the one-frame flash.\n if (state.previous && isSameTransform(state.previous, committed)) {\n return { state, reseed: false }\n }\n // anything else means something outside changed the document first; that\n // wins, and our pending commit is stale\n return { state: IDLE_OWNERSHIP, reseed: true }\n }\n if (state.owning) return { state, reseed: false }\n return { state, reseed: true }\n}\n","/**\n * Which gesture surface owns the canvas.\n *\n * Precedence is decided by the active tool and nothing else, so it is a pure\n * function that can be tested without mounting anything — and so the rule is\n * stated in one place rather than implied by JSX nesting.\n */\nexport type GestureSurfaceKind = 'media' | 'draw' | 'crop' | 'tilt' | 'text' | 'overlay'\n\n/**\n * Resolve the surface for the active tool.\n *\n * - `text` — the full-screen composer owns the screen, so **no** canvas surface\n * is mounted at all. Not mounting is the strongest form of \"disabled\": there\n * is no recogniser to arbitrate with, so a tap meant for the caret cannot\n * start a canvas gesture, and a drag begins immediately once composing ends.\n * - `media` — the base photo tool owns the surface, so the photo moves and\n * overlays are inert.\n * - `draw` — drawing owns the surface, so strokes are never interpreted as\n * layer drags.\n * - `crop` — the Post crop surface.\n * - `tilt` — placing the selective-focus region, which needs the whole canvas;\n * overlay hit-testing would steal the drag to whatever sits under the finger.\n * - anything else (including no active tool) — overlay hit-testing, which\n * excludes the base photo, so dragging text or a sticker cannot move it.\n */\nexport function resolveGestureSurface(activeTool: string | null | undefined): GestureSurfaceKind {\n switch (activeTool) {\n case 'text':\n return 'text'\n case 'media':\n return 'media'\n case 'draw':\n return 'draw'\n case 'crop':\n return 'crop'\n case 'tilt':\n return 'tilt'\n default:\n return 'overlay'\n }\n}\n","import { deleteTargetFromProfile, useEditor } from '@pictor-sdk/core'\nimport { useCanvasMetrics } from '@pictor-sdk/skia'\nimport React from 'react'\nimport { StyleSheet, Text, View } from 'react-native'\nimport { useTheme } from '../theme'\nimport { useInteractionState } from './interactionState'\n\n/** The centre and rotation guides shown while a layer snaps. */\nexport interface InteractionGuidesProps {\n /** Label shown above the delete target. */\n deleteLabel?: string\n}\n\n/**\n * Alignment guides and the drag-to-delete target.\n *\n * DECISION: these are plain React Native views layered over `<EditorCanvas>`,\n * not Skia nodes inside `renderDocument`. Transient interaction chrome then\n * has no way of reaching an export — stronger than an `isExport` check — and\n * the single render path (invariant 1) stays untouched.\n *\n * Render as a child of `<EditorCanvas>`, which sizes its children to the\n * fitted document box, so percentage offsets here are document-relative.\n */\nexport function InteractionGuides({ deleteLabel = 'Drag to delete' }: InteractionGuidesProps) {\n const { profile } = useEditor()\n const metrics = useCanvasMetrics()\n const theme = useTheme()\n const { snap, layerDragActive, overDeleteTarget } = useInteractionState()\n const target = deleteTargetFromProfile(profile.interaction?.layers)\n\n if (!metrics) return null\n\n // radius is in document-WIDTH units, so it maps through the canvas width\n const radius = target ? target.radius * metrics.width : 0\n const size = radius * 2\n const active = overDeleteTarget\n\n return (\n <View pointerEvents=\"none\" style={StyleSheet.absoluteFill}>\n {snap.centerX ? (\n <View\n style={{\n position: 'absolute',\n left: metrics.width / 2 - 1,\n top: 0,\n width: 2,\n height: metrics.height,\n backgroundColor: theme.colors.accent,\n }}\n />\n ) : null}\n {snap.centerY ? (\n <View\n style={{\n position: 'absolute',\n top: metrics.height / 2 - 1,\n left: 0,\n height: 2,\n width: metrics.width,\n backgroundColor: theme.colors.accent,\n }}\n />\n ) : null}\n\n {snap.rotation ? (\n <View\n style={{\n position: 'absolute',\n top: theme.spacing.md,\n alignSelf: 'center',\n backgroundColor: 'rgba(0,0,0,0.6)',\n borderRadius: theme.radii.lg,\n paddingHorizontal: theme.spacing.md,\n paddingVertical: theme.spacing.xs,\n }}\n >\n <Text\n style={{\n color: theme.colors.text,\n fontSize: theme.font.sizeSm,\n fontWeight: theme.font.weight,\n }}\n >\n Right-angle snap\n </Text>\n </View>\n ) : null}\n\n {target && layerDragActive ? (\n <View\n style={{\n position: 'absolute',\n left: target.x * metrics.width - radius,\n top: target.y * metrics.height - radius,\n width: size,\n height: size,\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <View\n style={{\n width: size,\n height: size,\n borderRadius: radius,\n borderWidth: 2,\n borderColor: theme.colors.text,\n // a scrim keeps the target legible over light photos, which a\n // plain white ring is not\n backgroundColor: active ? theme.colors.danger : 'rgba(0,0,0,0.45)',\n alignItems: 'center',\n justifyContent: 'center',\n transform: [{ scale: active ? 1.15 : 1 }],\n }}\n >\n <Text\n style={{\n color: theme.colors.text,\n fontSize: radius * 0.7,\n fontWeight: theme.font.weight,\n }}\n >\n ×\n </Text>\n </View>\n </View>\n ) : null}\n\n {/* the label sits in the full-canvas box, not the target-sized one, so a\n longer or translated string is never clipped by the target diameter */}\n {target && layerDragActive ? (\n <View\n style={{\n position: 'absolute',\n left: 0,\n right: 0,\n top: target.y * metrics.height - radius - theme.spacing.lg * 2,\n alignItems: 'center',\n }}\n >\n <Text\n style={{\n color: theme.colors.text,\n fontSize: theme.font.sizeSm,\n fontWeight: theme.font.weight,\n backgroundColor: 'rgba(0,0,0,0.45)',\n paddingHorizontal: theme.spacing.sm,\n paddingVertical: theme.spacing.xs,\n borderRadius: theme.radii.sm,\n overflow: 'hidden',\n }}\n numberOfLines={1}\n >\n {deleteLabel}\n </Text>\n </View>\n ) : null}\n </View>\n )\n}\n","import { createContext, useContext } from 'react'\n\n/**\n * Theming is one token object on context — no style props on individual\n * components (ARCHITECTURE.md). Override any subset via <Editor theme={…}>.\n */\nexport interface EditorTheme {\n colors: {\n background: string\n surface: string\n text: string\n textMuted: string\n accent: string\n danger: string\n track: string\n thumb: string\n }\n radii: { sm: number; md: number; lg: number }\n spacing: { xs: number; sm: number; md: number; lg: number }\n font: { size: number; sizeSm: number; weight: '400' | '500' | '600' | '700' }\n}\n\n/** The bundled dark theme. Every value is overridable; see {@link mergeTheme}. */\nexport const defaultTheme: EditorTheme = {\n colors: {\n background: '#000000',\n surface: '#121212',\n text: '#ffffff',\n textMuted: '#9a9a9a',\n accent: '#3897f0',\n danger: '#ed4956',\n track: '#3a3a3a',\n thumb: '#ffffff',\n },\n radii: { sm: 6, md: 10, lg: 16 },\n spacing: { xs: 4, sm: 8, md: 14, lg: 22 },\n font: { size: 15, sizeSm: 12, weight: '600' },\n}\n\n/** A theme override — any subset of any group, the rest falling back to the default. */\nexport type PartialTheme = {\n [K in keyof EditorTheme]?: Partial<EditorTheme[K]>\n}\n\n/** Apply an override onto the default theme, one group at a time. */\nexport function mergeTheme(overrides?: PartialTheme): EditorTheme {\n if (!overrides) return defaultTheme\n return {\n colors: { ...defaultTheme.colors, ...overrides.colors },\n radii: { ...defaultTheme.radii, ...overrides.radii },\n spacing: { ...defaultTheme.spacing, ...overrides.spacing },\n font: { ...defaultTheme.font, ...overrides.font },\n }\n}\n\n/** Carries the resolved theme. `<Editor>` provides it; components read it with {@link useTheme}. */\nexport const ThemeContext = createContext<EditorTheme>(defaultTheme)\n/** The theme in effect. Defaults outside an `<Editor>` rather than throwing. */\nexport function useTheme(): EditorTheme {\n return useContext(ThemeContext)\n}\n","import { useEditor, useTools, type ToolPanelProps } from '@pictor-sdk/core'\nimport React, { useEffect, useRef, type ComponentType } from 'react'\nimport { Pressable, Text, View } from 'react-native'\nimport { useTheme } from './theme'\nimport { AdjustPanel } from './panels/AdjustPanel'\nimport { AddPhotoPanel } from './panels/AddPhotoPanel'\nimport { ColorPanel } from './panels/ColorPanel'\nimport { CropPanel } from './panels/CropPanel'\nimport { DrawPanel } from './panels/DrawPanel'\nimport { FilterStrip } from './panels/FilterStrip'\nimport { LayoutPanel } from './panels/LayoutPanel'\nimport { LuxPanel } from './panels/LuxPanel'\nimport { MediaPanel } from './panels/MediaPanel'\nimport { LayersPanel } from './panels/LayersPanel'\nimport { PerspectivePanel } from './panels/PerspectivePanel'\nimport { StickerPanel } from './panels/StickerPanel'\nimport { TiltShiftPanel } from './panels/TiltShiftPanel'\n\n/**\n * Built-in panels for the built-in tool ids. Pure — unit tested.\n *\n * `text` deliberately has no panel: the text tool is served by the full-screen\n * composer slot, which owns its own controls. Leaving a panel here would open a\n * second history batch alongside the composer's and render a bottom sheet\n * underneath it.\n */\nexport function resolvePanel(\n toolId: string | null,\n pluginPanel: unknown,\n builtins: Record<string, ComponentType> = BUILTIN_PANELS,\n): ComponentType<Partial<ToolPanelProps>> | null {\n if (!toolId) return null\n if (pluginPanel) return pluginPanel as ComponentType<Partial<ToolPanelProps>>\n return (builtins[toolId] as ComponentType<Partial<ToolPanelProps>>) ?? null\n}\n\nexport const BUILTIN_PANELS: Record<string, ComponentType> = {\n media: MediaPanel,\n addPhoto: AddPhotoPanel,\n filter: FilterStrip,\n adjust: AdjustPanel,\n lux: LuxPanel,\n color: ColorPanel,\n tilt: TiltShiftPanel,\n perspective: PerspectivePanel,\n crop: CropPanel,\n draw: DrawPanel,\n sticker: StickerPanel,\n layout: LayoutPanel,\n layers: LayersPanel,\n}\n\n/** Renders the active tool's panel — plugin-provided Panel wins over built-ins. */\nexport function ToolPanelHost() {\n const { activeTool, document, selection, dispatch, setActiveTool } = useEditor()\n const tools = useTools()\n const tool = tools.find((t) => t.id === activeTool)\n const Panel = resolvePanel(activeTool, tool?.Panel)\n const theme = useTheme()\n const finalized = useRef(false)\n\n useEffect(() => {\n if (!activeTool || !Panel) return\n finalized.current = false\n dispatch({ type: 'history/beginBatch', label: activeTool })\n return () => {\n if (!finalized.current) dispatch({ type: 'history/cancelBatch' })\n }\n }, [activeTool, Panel, dispatch])\n\n if (!Panel) return null\n const done = () => {\n finalized.current = true\n dispatch({ type: 'history/endBatch' })\n setActiveTool(null)\n }\n const cancel = () => {\n finalized.current = true\n dispatch({ type: 'history/cancelBatch' })\n setActiveTool(null)\n }\n return (\n <View style={{ backgroundColor: theme.colors.background, borderTopLeftRadius: theme.radii.lg, borderTopRightRadius: theme.radii.lg, overflow: 'hidden' }}>\n <Panel document={document} selection={selection} dispatch={dispatch} close={done} />\n <View style={{ height: 52, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', borderTopWidth: 1, borderTopColor: theme.colors.track, paddingHorizontal: theme.spacing.lg }}>\n <Pressable accessibilityRole=\"button\" accessibilityLabel=\"Cancel edits\" onPress={cancel}>\n <Text style={{ color: theme.colors.text, fontSize: theme.font.size }}>Cancel</Text>\n </Pressable>\n <Text style={{ color: theme.colors.text, fontSize: theme.font.size, fontWeight: theme.font.weight }}>\n {tool?.label ?? activeTool}\n </Text>\n <Pressable accessibilityRole=\"button\" accessibilityLabel=\"Apply edits\" onPress={done}>\n <Text style={{ color: theme.colors.accent, fontSize: theme.font.size, fontWeight: theme.font.weight }}>Done</Text>\n </Pressable>\n </View>\n </View>\n )\n}\n","import {\n adjustmentResetPatch,\n hasAdjustment,\n useEditor,\n useEditorStore,\n type Adjustments,\n type ImageLayerData,\n} from '@pictor-sdk/core'\nimport React, { useState } from 'react'\nimport { Pressable, ScrollView, Text, View } from 'react-native'\nimport { useTheme } from '../theme'\nimport { Slider } from '../components/Slider'\nimport { useTargetImageLayer } from './useTargetImageLayer'\n\nconst LABELS: Record<string, string> = {\n brightness: 'Brightness',\n contrast: 'Contrast',\n saturation: 'Saturation',\n warmth: 'Warmth',\n tint: 'Tint',\n exposure: 'Exposure',\n highlights: 'Highlights',\n shadows: 'Shadows',\n fade: 'Fade',\n structure: 'Structure',\n sharpen: 'Sharpen',\n grain: 'Grain',\n vignette: 'Vignette',\n}\n\n/**\n * The Adjust tab: the 13 tools from profile/registry order, one centred\n * slider with a detent at 0 (a 0 adjustment is a provable render no-op).\n */\nexport function AdjustPanel() {\n const { dispatch } = useEditor()\n const store = useEditorStore()\n const theme = useTheme()\n const layer = useTargetImageLayer()\n const keys = store.registry.adjustments\n const [activeKey, setActiveKey] = useState(keys[0] ?? 'brightness')\n\n if (!layer) return null\n const adjustments: Adjustments = (layer.data as ImageLayerData).color.adjustments ?? {}\n const value = adjustments[activeKey] ?? 0\n const touchedActive = hasAdjustment(adjustments, activeKey)\n\n /**\n * Clear the active adjustment, and only it.\n *\n * No batch of its own: the adjust tool session already opened one, so this\n * belongs to that session's single undo entry — Cancel rolls it back with\n * everything else, and Done commits it as part of the whole.\n */\n const resetActive = () =>\n dispatch({\n type: 'layer/patchData',\n id: layer.id,\n patch: adjustmentResetPatch(activeKey) as Record<string, unknown>,\n })\n\n return (\n <View style={{ backgroundColor: theme.colors.background }}>\n <View style={{ paddingHorizontal: theme.spacing.lg }}>\n {/* Value readout, with an inline reset once the adjustment is set —\n the affordance Instagram uses, and the one the milestone asks for:\n it clears this adjustment only. */}\n <View\n style={{\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'center',\n gap: theme.spacing.sm,\n minHeight: 28,\n }}\n >\n <Text\n style={{\n color: theme.colors.textMuted,\n textAlign: 'center',\n fontSize: theme.font.sizeSm,\n }}\n >\n {LABELS[activeKey] ?? activeKey}{' '}\n {value === 0 ? '' : (value > 0 ? '+' : '') + Math.round(value * 100)}\n </Text>\n {touchedActive ? (\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={`Reset ${LABELS[activeKey] ?? activeKey}`}\n onPress={resetActive}\n hitSlop={8}\n style={{\n paddingHorizontal: theme.spacing.sm,\n paddingVertical: 2,\n borderRadius: theme.radii.sm,\n borderWidth: 1,\n borderColor: theme.colors.track,\n }}\n >\n <Text style={{ color: theme.colors.text, fontSize: theme.font.sizeSm }}>Reset</Text>\n </Pressable>\n ) : null}\n </View>\n <Slider\n value={value}\n min={-1}\n max={1}\n centered\n valueLabel={`${value > 0 ? '+' : ''}${Math.round(value * 100)}`}\n onStart={() => dispatch({ type: 'history/beginBatch', label: activeKey })}\n onChange={(v) =>\n dispatch({\n type: 'layer/patchData',\n id: layer.id,\n patch: { color: { adjustments: { [activeKey]: v } } },\n })\n }\n onEnd={() => dispatch({ type: 'history/endBatch' })}\n />\n </View>\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{ gap: theme.spacing.sm, padding: theme.spacing.md }}\n style={{ flexGrow: 0 }}\n >\n {keys.map((key) => {\n const touched = (adjustments[key] ?? 0) !== 0\n const active = key === activeKey\n return (\n <Pressable\n key={key}\n onPress={() => setActiveKey(key)}\n style={{ alignItems: 'center', gap: 6, width: 76 }}\n >\n <View style={{ width: 48, height: 48, borderRadius: 24, borderWidth: 1, borderColor: active ? theme.colors.accent : theme.colors.textMuted, backgroundColor: active ? theme.colors.surface : 'transparent', alignItems: 'center', justifyContent: 'center' }}>\n <Text style={{ color: active ? theme.colors.accent : theme.colors.text, fontSize: 18 }}>\n {(LABELS[key] ?? key).slice(0, 1)}\n </Text>\n </View>\n <Text\n style={{\n color: active ? theme.colors.accent : touched ? theme.colors.text : theme.colors.textMuted,\n fontSize: theme.font.sizeSm,\n fontWeight: theme.font.weight,\n }}\n >\n {LABELS[key] ?? key}\n {touched ? ' •' : ''}\n </Text>\n </Pressable>\n )\n })}\n </ScrollView>\n </View>\n )\n}\n","import React, { useMemo, useRef, useState } from 'react'\nimport { Text, View, type LayoutChangeEvent } from 'react-native'\nimport { Gesture, GestureDetector } from 'react-native-gesture-handler'\nimport Animated from 'react-native-reanimated'\nimport { runOnJS } from 'react-native-worklets'\nimport { useTheme } from '../theme'\n\n/**\n * A slider's value and range.\n *\n * `centered` is the adjustment shape — `-1..1` resting in the middle with a\n * detent at zero. A quantity with no meaningful negative (Lux, tint strength,\n * blur) uses `min: 0` and `centered: false` instead, which is the control shape\n * measured on the reference editor.\n */\nexport interface SliderProps {\n /** -1..1 when centered, 0..1 otherwise */\n value: number\n min?: number\n max?: number\n /** show a centre detent and snap to 0 within ±0.05 (adjustment sliders) */\n centered?: boolean\n onStart?: () => void\n onChange: (value: number) => void\n onEnd?: () => void\n testID?: string\n /** Floating value label shown above the thumb. */\n valueLabel?: string\n /**\n * Inert and dimmed. For a control whose value has nothing meaningful to\n * write yet — dragging it would record something untrue.\n */\n disabled?: boolean\n}\n\n/** Snap a centered slider value into its detent. Pure — unit tested. */\nexport function applyDetent(value: number, centered: boolean, width = 0.05): number {\n if (centered && Math.abs(value) < width) return 0\n return value\n}\n\n/** Dependency-free horizontal slider with an optional centre detent. */\nexport function Slider({\n value,\n min = -1,\n max = 1,\n centered = true,\n onStart,\n onChange,\n onEnd,\n testID,\n valueLabel,\n disabled = false,\n}: SliderProps) {\n const theme = useTheme()\n const [width, setWidth] = useState(0)\n const widthRef = useRef(0)\n const startValue = useRef(value)\n const valueRef = useRef(value)\n valueRef.current = value\n\n const onLayout = (e: LayoutChangeEvent) => {\n setWidth(e.nativeEvent.layout.width)\n widthRef.current = e.nativeEvent.layout.width\n }\n\n const handlers = useMemo(() => {\n const begin = () => {\n startValue.current = valueRef.current\n onStart?.()\n }\n const update = (tx: number) => {\n const w = widthRef.current\n if (w === 0) return\n const range = max - min\n const raw = startValue.current + (tx / w) * range\n const clamped = Math.min(max, Math.max(min, raw))\n onChange(applyDetent(clamped, centered && min < 0))\n }\n const finish = () => onEnd?.()\n return { begin, update, finish }\n }, [min, max, centered, onChange, onStart, onEnd])\n\n const gesture = useMemo(\n () =>\n Gesture.Pan()\n .enabled(!disabled)\n .onStart(() => {\n 'worklet'\n runOnJS(handlers.begin)()\n })\n .onUpdate((e) => {\n 'worklet'\n runOnJS(handlers.update)(e.translationX)\n })\n .onFinalize(() => {\n 'worklet'\n runOnJS(handlers.finish)()\n }),\n [handlers, disabled],\n )\n\n const t = (value - min) / (max - min)\n const thumbX = width * t\n\n return (\n <GestureDetector gesture={gesture}>\n <Animated.View\n testID={testID}\n onLayout={onLayout}\n style={{\n height: valueLabel ? 58 : 36,\n justifyContent: 'flex-end',\n paddingBottom: 9,\n opacity: disabled ? 0.4 : 1,\n }}\n >\n {valueLabel ? (\n <View\n pointerEvents=\"none\"\n style={{\n position: 'absolute',\n top: 0,\n left: Math.max(0, Math.min(width - 44, thumbX - 22)),\n width: 44,\n alignItems: 'center',\n paddingVertical: 3,\n borderRadius: 10,\n backgroundColor: theme.colors.surface,\n }}\n >\n <Text style={{ color: theme.colors.text, fontSize: theme.font.sizeSm }}>{valueLabel}</Text>\n </View>\n ) : null}\n <View style={{ height: 2, borderRadius: 1, backgroundColor: theme.colors.track }} />\n <View\n style={{\n position: 'absolute',\n bottom: 9,\n left: centered && min < 0 ? Math.min(width / 2, thumbX) : 0,\n width: centered && min < 0 ? Math.abs(thumbX - width / 2) : thumbX,\n height: 2,\n borderRadius: 1,\n backgroundColor: theme.colors.accent,\n }}\n />\n {centered && min < 0 ? (\n <View\n style={{\n position: 'absolute',\n left: width / 2 - 1,\n width: 2,\n height: 10,\n backgroundColor: theme.colors.textMuted,\n }}\n />\n ) : null}\n <View\n style={{\n position: 'absolute',\n bottom: 1,\n left: Math.max(0, Math.min(width - 18, thumbX - 9)),\n width: 18,\n height: 18,\n borderRadius: 9,\n backgroundColor: theme.colors.thumb,\n }}\n />\n </Animated.View>\n </GestureDetector>\n )\n}\n","import { useEditor } from '@pictor-sdk/core'\nimport React, { useEffect, useMemo, useState } from 'react'\nimport { Pressable, Text, View } from 'react-native'\nimport { useHostCallbacks } from '../hostCallbacks'\nimport { useTheme } from '../theme'\nimport { createAddPhotoController } from './addPhotoController'\n\n/**\n * The add-photo control: one press, one picker, one undo entry.\n *\n * Nothing happens on mount. Opening a picker because a panel appeared would\n * take the choice away from the user and make a stray tool tap launch the\n * gallery, so acquisition waits for an explicit press.\n *\n * All the asynchronous behaviour lives in `createAddPhotoController`, which is\n * testable without mounting anything. This is the shell.\n *\n * @experimental\n */\nexport function AddPhotoPanel() {\n const { dispatch, select } = useEditor()\n const host = useHostCallbacks()\n const theme = useTheme()\n const [pending, setPending] = useState(false)\n\n const controller = useMemo(\n () =>\n createAddPhotoController({\n // Read through the ref at call time, so a host re-creating its closure\n // does not rebuild the controller mid-request.\n requestImages: host.current.requestImages\n ? () => host.current.requestImages!()\n : undefined,\n dispatch,\n select,\n onError: (error) => host.current.onError?.(error),\n }),\n [dispatch, select, host],\n )\n\n // Disposal is what makes a late result harmless: the picker can resolve long\n // after the user has closed the tool.\n useEffect(() => () => controller.dispose(), [controller])\n\n // Session-scoped, like the panel's image target: whether a picker exists is\n // decided at mount. A host that wires `requestImages` while this is open sees\n // it on the next open.\n const available = controller.isAvailable()\n\n const press = async () => {\n if (!available || pending) return\n setPending(true)\n try {\n await controller.request()\n } finally {\n setPending(false)\n }\n }\n\n return (\n <View style={{ backgroundColor: theme.colors.background, padding: theme.spacing.lg }}>\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel=\"Add photos\"\n accessibilityState={{ disabled: !available || pending }}\n disabled={!available || pending}\n onPress={press}\n style={{\n paddingVertical: theme.spacing.md,\n borderRadius: theme.radii.sm,\n borderWidth: 1,\n borderColor: available ? theme.colors.accent : theme.colors.track,\n alignItems: 'center',\n opacity: available && !pending ? 1 : 0.45,\n }}\n >\n <Text\n style={{\n color: available ? theme.colors.accent : theme.colors.textMuted,\n fontSize: theme.font.size,\n fontWeight: theme.font.weight,\n }}\n >\n {pending ? 'Choosing…' : 'Add photos'}\n </Text>\n </Pressable>\n <Text\n style={{\n color: theme.colors.textMuted,\n fontSize: theme.font.sizeSm,\n textAlign: 'center',\n marginTop: theme.spacing.sm,\n }}\n >\n {available\n ? 'Pick one or more photos to place on the story'\n : `Unavailable — pass \\`requestImages\\` to <Editor>`}\n </Text>\n </View>\n )\n}\n","import {\n createImageLayers,\n insertImageCommands,\n type Dispatch,\n type InsertableImage,\n type InsertImageOptions,\n type InsertImageTransaction,\n} from '@pictor-sdk/core'\n\n/**\n * Acquiring photos from the host, then inserting them.\n *\n * Deliberately **not** a React component. Acquisition is asynchronous and has\n * to survive a re-render, refuse a second request while one is in flight, and\n * do nothing at all if the panel is gone by the time the host answers — none of\n * which is expressible as render logic, and all of which is worth testing\n * without mounting anything.\n *\n * Acquisition is also kept separate from insertion so a host that wants neither\n * this controller nor the default panel can call `createImageLayers` and\n * `insertImageCommands` directly.\n *\n * @experimental\n */\n\nexport interface AddPhotoControllerOptions {\n /**\n * Supplied by the host. Resolving `null` or `[]` means the user cancelled,\n * which must add nothing — no command, no selection change, no history entry.\n */\n requestImages?: () => Promise<readonly InsertableImage[] | null>\n dispatch: Dispatch\n select: (ids: string[]) => void\n /** Anything the host's picker throws, or a result that is not usable. */\n onError?: (error: unknown) => void\n /** Presentation and transaction options forwarded to the core helpers. */\n insert?: InsertImageOptions & InsertImageTransaction\n}\n\n/**\n * A live add-photo session.\n *\n * @experimental\n */\nexport interface AddPhotoController {\n /** Ask the host for photos and insert whatever comes back. */\n request: () => Promise<void>\n /** True while a request is in flight; a second press is ignored. */\n isPending: () => boolean\n /**\n * Whether the host supplied a way to ask at all.\n *\n * **Session-scoped.** Captured when the controller is created, which for the\n * bundled panel means when it mounts. A host that adds `requestImages` while\n * the panel is open sees it unavailable until the tool is reopened — the\n * mount is the session boundary everywhere else in this panel too, and a\n * control that becomes live mid-session is a stranger surprise than one that\n * waits for the next open.\n */\n isAvailable: () => boolean\n /** Called when the panel unmounts: a late result is then discarded. */\n dispose: () => void\n}\n\n/** An entry the library can actually insert. */\nfunction isInsertable(value: unknown): value is InsertableImage {\n if (typeof value !== 'object' || value === null) return false\n const source = (value as { source?: unknown }).source\n // `source` is deliberately `unknown` in the document model — a URI, a\n // `{ uri }`, a Metro asset id — so the only thing worth asserting is that the\n // host gave us *something* to resolve.\n return source !== undefined && source !== null && source !== ''\n}\n\n/**\n * A dense list of insertable images, or `null` if the result is unusable.\n *\n * Every index is checked with `in` rather than by iterating, because a sparse\n * array **skips its holes**: `new Array(3).every(fn)` is `true`, so a host\n * returning one would pass validation and go on to produce sparse layers and a\n * command list with `undefined` in it — dispatching `history/beginBatch` and\n * then failing part-way, leaving a batch open.\n *\n * Copied into a dense array before anything is constructed, so nothing\n * downstream has to think about holes again.\n */\nfunction toDenseImages(value: unknown): InsertableImage[] | null {\n if (!Array.isArray(value)) return null\n const dense: InsertableImage[] = []\n for (let index = 0; index < value.length; index++) {\n if (!(index in value)) return null\n const entry = value[index]\n if (!isInsertable(entry)) return null\n dense.push(entry)\n }\n return dense\n}\n\n/** A command the reducer could actually accept. */\nfunction isDispatchable(command: unknown): boolean {\n return (\n typeof command === 'object' &&\n command !== null &&\n typeof (command as { type?: unknown }).type === 'string'\n )\n}\n\n/**\n * The host resolved with something that is not a list of insertable images.\n *\n * Reported rather than coerced: guessing at a malformed result would insert\n * layers the host did not mean to add.\n *\n * @experimental\n */\nexport class InvalidImageResultError extends Error {\n constructor() {\n super('requestImages resolved with something that is not a list of images')\n this.name = 'InvalidImageResultError'\n }\n}\n\n/**\n * Wire a host's picker to the core insertion helpers.\n *\n * Acquisition stays separate from insertion, so a host that wants neither this\n * controller nor the default panel can call `createImageLayers` and\n * `insertImageCommands` itself.\n *\n * @experimental\n */\nexport function createAddPhotoController({\n requestImages,\n dispatch,\n select,\n onError,\n insert,\n}: AddPhotoControllerOptions): AddPhotoController {\n let pending = false\n let disposed = false\n\n return {\n isPending: () => pending,\n isAvailable: () => typeof requestImages === 'function',\n dispose: () => {\n disposed = true\n },\n async request() {\n // A second press while the picker is open must not open a second picker,\n // and must not ask the host twice for one intent.\n if (!requestImages || pending || disposed) return\n pending = true\n try {\n const result = await requestImages()\n // Disposal is checked *first*, before the result is even looked at.\n // Once the panel is gone the user has moved on, so nothing that comes\n // back matters — not a success, not a malformed result, and not an\n // error worth interrupting them about.\n if (disposed) return\n // Cancellation. Not an error, and nothing to do.\n if (result === null || result === undefined) return\n\n const images = toDenseImages(result)\n if (!images) {\n onError?.(new InvalidImageResultError())\n return\n }\n if (images.length === 0) return\n\n // Everything is built and checked before the *first* dispatch, so a\n // problem discovered late cannot leave a `beginBatch` open with no\n // matching end.\n const layers = createImageLayers(images, insert)\n const commands = insertImageCommands(layers, insert)\n if (!commands.every(isDispatchable)) {\n onError?.(new InvalidImageResultError())\n return\n }\n\n for (const command of commands) dispatch(command)\n // Only the last — the topmost photo, and the one the user ends up\n // looking at. Selecting all of them would invite a bulk edit that is\n // not designed.\n const last = layers[layers.length - 1]\n if (last) select([last.id])\n } catch (error) {\n // Same rule as a late success: after disposal, silence.\n if (!disposed) onError?.(error)\n } finally {\n // Cleared even after a failure, so reopening — or simply pressing\n // again — can try once more.\n pending = false\n }\n },\n }\n}\n","import {\n isInertTint,\n tintPatch,\n useEditor,\n type ColorTint,\n type ImageLayerData,\n} from '@pictor-sdk/core'\nimport React, { useState } from 'react'\nimport { Pressable, ScrollView, Text, View } from 'react-native'\nimport { Slider } from '../components/Slider'\nimport { useTheme } from '../theme'\nimport { useTargetImageLayer } from './useTargetImageLayer'\n\n/**\n * Split toning: a colour cast on the shadows, another on the highlights.\n *\n * Two ends, each with a palette and a strength. They are edited one at a time\n * because they are genuinely independent — the render masks confine each to its\n * own end of the tonal range — so showing both at once would suggest an\n * interaction that does not exist.\n *\n * The strength slider is one-directional and rests at zero, like Lux: a cast\n * has an amount, not a direction.\n */\n\n/**\n * Our own palette — eight hues spread around the wheel at a muted saturation.\n *\n * Deliberately not anyone else's swatch set. Muted rather than pure because a\n * fully saturated cast at any usable strength reads as a colour error; these\n * still shift the grade decisively at strength 1.\n */\nexport const TINT_SWATCHES: readonly string[] = [\n '#1f8a8a',\n '#2f6fd0',\n '#7a5cd0',\n '#c04a9e',\n '#c8443c',\n '#d99038',\n '#8a9a3f',\n '#3f9a6a',\n]\n\nconst ENDS = [\n { key: 'shadows', label: 'Shadows' },\n { key: 'highlights', label: 'Highlights' },\n] as const\n\n/** Strength given to a colour picked while the end has none yet. */\nconst INITIAL_STRENGTH = 0.5\n\nexport function ColorPanel() {\n const { dispatch } = useEditor()\n const theme = useTheme()\n const layer = useTargetImageLayer()\n const [end, setEnd] = useState<'shadows' | 'highlights'>('shadows')\n\n if (!layer) return null\n const data = layer.data as ImageLayerData\n const tint: ColorTint | undefined = data.color.tinting?.[end]\n const active = isInertTint(tint) ? undefined : tint\n\n const patch = (next: ColorTint | undefined) =>\n dispatch({\n type: 'layer/patchData',\n id: layer.id,\n patch: { color: tintPatch(end, next) } as unknown as Record<string, unknown>,\n })\n\n /** Picking the colour already applied clears this end — tap again to undo it. */\n const pick = (color: string) =>\n patch(\n active?.color === color\n ? undefined\n : { color, strength: active?.strength ?? INITIAL_STRENGTH },\n )\n\n return (\n <View style={{ backgroundColor: theme.colors.background, paddingBottom: theme.spacing.md }}>\n <View\n style={{\n flexDirection: 'row',\n justifyContent: 'center',\n gap: theme.spacing.md,\n paddingTop: theme.spacing.sm,\n }}\n >\n {ENDS.map(({ key, label }) => {\n const selected = key === end\n const set = !isInertTint(data.color.tinting?.[key])\n return (\n <Pressable\n key={key}\n accessibilityRole=\"button\"\n accessibilityLabel={`Tint ${label.toLowerCase()}`}\n onPress={() => setEnd(key)}\n style={{\n paddingHorizontal: theme.spacing.md,\n paddingVertical: 6,\n borderRadius: theme.radii.sm,\n borderWidth: 1,\n borderColor: selected ? theme.colors.accent : 'transparent',\n }}\n >\n <Text\n style={{\n color: selected ? theme.colors.accent : theme.colors.textMuted,\n fontSize: theme.font.sizeSm,\n fontWeight: theme.font.weight,\n }}\n >\n {label}\n {set ? ' •' : ''}\n </Text>\n </Pressable>\n )\n })}\n </View>\n\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{ gap: theme.spacing.sm, paddingHorizontal: theme.spacing.lg, paddingVertical: theme.spacing.md }}\n style={{ flexGrow: 0 }}\n >\n {TINT_SWATCHES.map((color) => (\n <Pressable\n key={color}\n accessibilityRole=\"button\"\n accessibilityLabel={`Tint ${end} ${color}`}\n onPress={() => pick(color)}\n style={{\n width: 40,\n height: 40,\n borderRadius: 20,\n backgroundColor: color,\n borderWidth: active?.color === color ? 3 : 1,\n borderColor: active?.color === color ? theme.colors.text : theme.colors.track,\n }}\n />\n ))}\n </ScrollView>\n\n <View style={{ paddingHorizontal: theme.spacing.lg }}>\n <View\n style={{\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'center',\n gap: theme.spacing.sm,\n minHeight: 28,\n }}\n >\n <Text style={{ color: theme.colors.textMuted, fontSize: theme.font.sizeSm }}>\n {active ? `Strength ${Math.round(active.strength * 100)}` : 'Pick a colour'}\n </Text>\n {active ? (\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={`Reset ${end} tint`}\n onPress={() => patch(undefined)}\n hitSlop={8}\n style={{\n paddingHorizontal: theme.spacing.sm,\n paddingVertical: 2,\n borderRadius: theme.radii.sm,\n borderWidth: 1,\n borderColor: theme.colors.track,\n }}\n >\n <Text style={{ color: theme.colors.text, fontSize: theme.font.sizeSm }}>Reset</Text>\n </Pressable>\n ) : null}\n </View>\n <Slider\n value={active?.strength ?? 0}\n min={0}\n max={1}\n centered={false}\n testID=\"tint-strength\"\n disabled={!active}\n valueLabel={`${Math.round((active?.strength ?? 0) * 100)}`}\n onStart={() => dispatch({ type: 'history/beginBatch', label: `tint-${end}` })}\n onChange={(strength) => {\n if (!active) return\n patch({ color: active.color, strength })\n }}\n onEnd={() => dispatch({ type: 'history/endBatch' })}\n />\n </View>\n </View>\n )\n}\n","import {\n cropFitScale,\n flipPatch,\n isFlipped,\n useEditor,\n useEditorStore,\n type FlipAxis,\n type ImageLayerData,\n} from '@pictor-sdk/core'\nimport React from 'react'\nimport { Pressable, ScrollView, Text, View } from 'react-native'\nimport { useTheme } from '../theme'\nimport { StraightenRuler } from '../components/StraightenRuler'\nimport { useTargetImageLayer } from './useTargetImageLayer'\nimport {\n canvasSizeForAspect,\n} from './cropMath'\n\nfunction aspectLabel(aspect: number | 'free'): string {\n if (aspect === 'free') return 'Free'\n const known: Array<[number, string]> = [\n [4 / 5, '4:5'],\n [1, '1:1'],\n [16 / 9, '16:9'],\n [9 / 16, '9:16'],\n [3 / 4, '3:4'],\n [4 / 3, '4:3'],\n ]\n for (const [value, label] of known) {\n if (Math.abs(aspect - value) < 1e-6) return label\n }\n return aspect.toFixed(2)\n}\n\n/** Crop tool: aspect presets from the profile, 90° rotate, straighten dial. */\nexport function CropPanel() {\n const { document, dispatch, profile } = useEditor()\n useEditorStore() // subscribe\n const theme = useTheme()\n const layer = useTargetImageLayer()\n if (!layer) return null\n const data = layer.data as ImageLayerData\n const straighten = data.straighten ?? 0\n\n const applyAspect = (aspect: number | 'free') => {\n const nextSize = canvasSizeForAspect(document.size, aspect)\n dispatch({ type: 'history/beginBatch', label: 'aspect' })\n dispatch({ type: 'doc/patch', patch: { size: nextSize } })\n dispatch({ type: 'layer/patchData', id: layer.id, patch: { crop: undefined } })\n dispatch({\n type: 'layer/transform',\n id: layer.id,\n patch: {\n x: 0.5,\n y: 0.5,\n scale: cropFitScale(data.intrinsic, nextSize, profile.interaction?.crop?.fit ?? 'contain'),\n },\n })\n dispatch({ type: 'history/endBatch' })\n }\n\n const rotate90 = () => {\n const current = layer.transform.rotation\n const rotation = current + Math.PI / 2\n dispatch({\n type: 'layer/transform',\n id: layer.id,\n patch: {\n rotation,\n x: 0.5,\n y: 0.5,\n scale: cropFitScale(data.intrinsic, document.size, profile.interaction?.crop?.fit ?? 'contain', rotation),\n },\n })\n }\n\n /**\n * Mirror the photo on one axis.\n *\n * No batch of its own: the crop tool session already opened one, so a flip\n * joins that session's single undo entry and Cancel rolls it back with the\n * rest. Only the flip flag changes — the crop window, straighten, position\n * and scale are all left alone, and hit-testing follows because it reads the\n * same flag the renderer does.\n */\n const flip = (axis: FlipAxis) =>\n dispatch({\n type: 'layer/transform',\n id: layer.id,\n patch: flipPatch(layer.transform, axis),\n })\n\n return (\n <View style={{ backgroundColor: theme.colors.background }}>\n <View style={{ paddingHorizontal: theme.spacing.lg }}>\n <StraightenRuler\n value={(straighten * 180) / Math.PI}\n min={-45}\n max={45}\n onStart={() => dispatch({ type: 'history/beginBatch', label: 'straighten' })}\n onChange={(v) =>\n dispatch({\n type: 'layer/patchData',\n id: layer.id,\n patch: { straighten: (v * Math.PI) / 180 },\n })\n }\n onEnd={() => dispatch({ type: 'history/endBatch' })}\n />\n </View>\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{ gap: theme.spacing.sm, padding: theme.spacing.md }}\n style={{ flexGrow: 0 }}\n >\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel=\"Rotate 90 degrees\"\n onPress={rotate90}\n style={{\n paddingHorizontal: theme.spacing.md,\n paddingVertical: theme.spacing.sm,\n borderRadius: theme.radii.md,\n backgroundColor: theme.colors.surface,\n }}\n >\n <Text style={{ color: theme.colors.text, fontSize: theme.font.sizeSm, fontWeight: theme.font.weight }}>\n ⟳ 90°\n </Text>\n </Pressable>\n {(['horizontal', 'vertical'] as const).map((axis) => {\n const on = isFlipped(layer.transform, axis)\n return (\n <Pressable\n key={axis}\n accessibilityRole=\"button\"\n accessibilityLabel={`Flip ${axis}`}\n accessibilityState={{ selected: on }}\n onPress={() => flip(axis)}\n style={{\n paddingHorizontal: theme.spacing.md,\n paddingVertical: theme.spacing.sm,\n borderRadius: theme.radii.md,\n backgroundColor: theme.colors.surface,\n borderWidth: 1,\n borderColor: on ? theme.colors.accent : 'transparent',\n }}\n >\n <Text\n style={{\n color: on ? theme.colors.accent : theme.colors.text,\n fontSize: theme.font.sizeSm,\n fontWeight: theme.font.weight,\n }}\n >\n {axis === 'horizontal' ? '⇋' : '⇅'}\n </Text>\n </Pressable>\n )\n })}\n {profile.aspects.map((aspect, i) => (\n <Pressable\n key={i}\n onPress={() => applyAspect(aspect)}\n style={{\n width: 58,\n height: 48,\n borderRadius: theme.radii.md,\n borderWidth: 1,\n borderColor: theme.colors.textMuted,\n backgroundColor: 'transparent',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <Text style={{ color: theme.colors.text, fontSize: theme.font.sizeSm, fontWeight: theme.font.weight }}>\n {aspectLabel(aspect)}\n </Text>\n </Pressable>\n ))}\n </ScrollView>\n </View>\n )\n}\n","import React, { useMemo, useRef } from 'react'\nimport { Text, View } from 'react-native'\nimport { Gesture, GestureDetector } from 'react-native-gesture-handler'\nimport Animated from 'react-native-reanimated'\nimport { runOnJS } from 'react-native-worklets'\nimport { useTheme } from '../theme'\n\n/** The straighten dial: a value in -1..1 and the callbacks bracketing a drag. */\nexport interface StraightenRulerProps {\n value: number\n min?: number\n max?: number\n onStart?: () => void\n onChange(value: number): void\n onEnd?: () => void\n}\n\nconst PX_PER_DEGREE = 60\n\n/** Fine, zero-snapping ruler for angle correction. Values are degrees. */\nexport function StraightenRuler({ value, min = -45, max = 45, onStart, onChange, onEnd }: StraightenRulerProps) {\n const theme = useTheme()\n const start = useRef(value)\n const current = useRef(value)\n current.current = value\n const handlers = useMemo(() => ({\n begin: () => { start.current = current.current; onStart?.() },\n update: (translationX: number) => {\n const raw = Math.min(max, Math.max(min, start.current - translationX / PX_PER_DEGREE))\n onChange(Math.abs(raw) < 0.15 ? 0 : raw)\n },\n finish: () => onEnd?.(),\n }), [min, max, onStart, onChange, onEnd])\n const gesture = useMemo(() => Gesture.Pan()\n .onStart(() => { 'worklet'; runOnJS(handlers.begin)() })\n .onUpdate((event) => { 'worklet'; runOnJS(handlers.update)(event.translationX) })\n .onFinalize(() => { 'worklet'; runOnJS(handlers.finish)() }), [handlers])\n\n const rounded = Math.round(value * 10) / 10\n return (\n <GestureDetector gesture={gesture}>\n <Animated.View style={{ height: 76, overflow: 'hidden', justifyContent: 'flex-end' }}>\n <View style={{ position: 'absolute', top: 0, alignSelf: 'center', paddingHorizontal: 10, paddingVertical: 4, borderRadius: 12, backgroundColor: theme.colors.surface }}>\n <Text style={{ color: theme.colors.text, fontSize: theme.font.sizeSm }}>{rounded.toFixed(1)}°</Text>\n </View>\n <View style={{ height: 34, flexDirection: 'row', justifyContent: 'center', alignItems: 'flex-end', gap: 8 }}>\n {Array.from({ length: 31 }, (_, index) => {\n const offset = index - 15\n const major = offset % 5 === 0\n return <View key={offset} style={{ width: 1, height: major ? 22 : 11, backgroundColor: offset === 0 ? theme.colors.accent : theme.colors.textMuted }} />\n })}\n </View>\n <View style={{ position: 'absolute', bottom: 0, left: '50%', width: 2, height: 30, backgroundColor: theme.colors.accent }} />\n </Animated.View>\n </GestureDetector>\n )\n}\n","import { type Rect, type Size } from '@pictor-sdk/core'\n\n/**\n * Pure crop math for the Crop tool (unit-tested in Node).\n *\n * Aspect selection: the document canvas takes the chosen aspect (constant\n * width) and the image layer gets a maximal centred crop matching it.\n */\nexport function canvasSizeForAspect(current: Size, aspect: number | 'free'): Size {\n if (aspect === 'free') return current\n return { width: current.width, height: Math.round(current.width / aspect) }\n}\n\n/** Maximal centred crop (normalized within the source) with the given aspect. */\nexport function centeredCropForAspect(intrinsic: Size, aspect: number): Rect {\n const sourceAspect = intrinsic.width / intrinsic.height\n if (sourceAspect > aspect) {\n // source is wider → crop the sides\n const width = aspect / sourceAspect\n return { x: (1 - width) / 2, y: 0, width, height: 1 }\n }\n // source is taller → crop top/bottom\n const height = sourceAspect / aspect\n return { x: 0, y: (1 - height) / 2, width: 1, height }\n}\n\n/** The straighten dial's range: ±45°, in radians. */\nexport const STRAIGHTEN_LIMIT = (45 * Math.PI) / 180\n\n/** Straighten dial value (-1..1) ↔ radians (±45°). */\nexport function straightenToRadians(value: number): number {\n return Math.max(-1, Math.min(1, value)) * STRAIGHTEN_LIMIT\n}\n/** Radians to dial value (-1..1), clamped to the limit. */\nexport function radiansToStraighten(rad: number): number {\n return Math.max(-1, Math.min(1, rad / STRAIGHTEN_LIMIT))\n}\n","import { type Stroke } from '@pictor-sdk/core'\nimport React from 'react'\nimport { Pressable, ScrollView, Text, View } from 'react-native'\nimport { DEFAULT_BRUSH } from '../gestures/DrawingSurface'\nimport { type BrushConfig } from '../gestures/drawController'\nimport { useTheme } from '../theme'\nimport { useUiState } from '../uiState'\nimport { Slider } from '../components/Slider'\n\nconst BRUSHES: Array<{ id: Stroke['brush']; label: string }> = [\n { id: 'pen', label: 'Pen' },\n { id: 'marker', label: 'Marker' },\n { id: 'neon', label: 'Neon' },\n { id: 'highlighter', label: 'Highlight' },\n { id: 'eraser', label: 'Eraser' },\n]\n\nconst SWATCHES = [\n '#ffffff', '#000000', '#ed4956', '#ffb43b', '#ffe25c',\n '#78de85', '#4dc4ff', '#3897f0', '#a15fed', '#d977b1',\n]\n\n/** Draw tab: brush picker, color swatches + eyedropper, width slider. */\nexport function DrawPanel() {\n const theme = useTheme()\n const [brush, setBrush] = useUiState<BrushConfig>('draw.brush', DEFAULT_BRUSH)\n const [eyedropper, setEyedropper] = useUiState('draw.eyedropper', false)\n\n return (\n <View style={{ backgroundColor: theme.colors.background }}>\n <View style={{ paddingHorizontal: theme.spacing.lg }}>\n <Slider\n value={brush.width}\n min={0.002}\n max={0.06}\n centered={false}\n onChange={(width) => setBrush({ ...brush, width })}\n />\n </View>\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{ gap: theme.spacing.sm, paddingHorizontal: theme.spacing.md, alignItems: 'center' }}\n style={{ flexGrow: 0 }}\n >\n <Pressable\n onPress={() => setEyedropper(!eyedropper)}\n style={{\n width: 28,\n height: 28,\n borderRadius: 14,\n borderWidth: 2,\n borderColor: eyedropper ? theme.colors.accent : theme.colors.textMuted,\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <Text style={{ color: theme.colors.text, fontSize: 13 }}>💧</Text>\n </Pressable>\n {SWATCHES.map((color) => (\n <Pressable\n key={color}\n onPress={() => setBrush({ ...brush, color })}\n style={{\n width: 26,\n height: 26,\n borderRadius: 13,\n backgroundColor: color,\n borderWidth: brush.color === color ? 3 : 1,\n borderColor: brush.color === color ? theme.colors.accent : theme.colors.track,\n }}\n />\n ))}\n </ScrollView>\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{ gap: theme.spacing.sm, padding: theme.spacing.md }}\n style={{ flexGrow: 0 }}\n >\n {BRUSHES.map((b) => (\n <Pressable\n key={b.id}\n onPress={() => setBrush({ ...brush, brush: b.id })}\n style={{\n paddingHorizontal: theme.spacing.md,\n paddingVertical: theme.spacing.sm,\n borderRadius: theme.radii.md,\n backgroundColor: brush.brush === b.id ? theme.colors.surface : 'transparent',\n }}\n >\n <Text\n style={{\n color: brush.brush === b.id ? theme.colors.accent : theme.colors.text,\n fontSize: theme.font.sizeSm,\n fontWeight: theme.font.weight,\n }}\n >\n {b.label}\n </Text>\n </Pressable>\n ))}\n </ScrollView>\n </View>\n )\n}\n","import { baseImageLayer, useEditor, useLuts, type ImageLayerData, type LutRef } from '@pictor-sdk/core'\nimport { useRenderer } from '@pictor-sdk/skia'\nimport { Canvas, Image as SkiaImage, type SkImage } from '@shopify/react-native-skia'\nimport React, { useEffect, useState } from 'react'\nimport { Pressable, ScrollView, Text, View } from 'react-native'\nimport { useTheme } from '../theme'\nimport { Slider } from '../components/Slider'\nimport { useTargetImageLayer } from './useTargetImageLayer'\n\nconst THUMB = 84\n\n/**\n * The base photo — the bottom-most image layer.\n *\n * Unchanged, and deliberately still available: some capabilities are genuinely\n * about *the base photo* rather than about whichever photo is selected — Story\n * media placement and the derived background are computed from it. Panels that\n * edit \"the current image\" use {@link useTargetImageLayer} instead.\n */\nexport function useBaseImageLayer() {\n const { document } = useEditor()\n return baseImageLayer(document)\n}\n\nfunction Thumb({ lut, label, active }: { lut: LutRef | undefined; label: string; active: boolean }) {\n const { document } = useEditor()\n const renderer = useRenderer()\n const theme = useTheme()\n const [image, setImage] = useState<SkImage | null>(null)\n const lutId = lut?.id\n const lutIntensity = lut?.intensity\n\n // cached by (source, crop, lut) inside the renderer — free after first render\n useEffect(() => {\n let alive = true\n const requestedLut = lutId === undefined ? undefined : { id: lutId, intensity: lutIntensity ?? 1 }\n renderer\n .renderThumbnailImage(document, requestedLut, THUMB)\n .then((img) => alive && setImage(img))\n .catch(() => {})\n return () => {\n alive = false\n }\n }, [renderer, document, lutId, lutIntensity])\n\n return (\n <View style={{ alignItems: 'center', gap: 4 }}>\n <Text\n style={{\n color: active ? theme.colors.accent : theme.colors.textMuted,\n fontSize: theme.font.sizeSm,\n }}\n >\n {label}\n </Text>\n <View\n style={{\n width: THUMB,\n height: THUMB,\n borderRadius: theme.radii.sm,\n overflow: 'hidden',\n borderWidth: active ? 2 : 0,\n borderColor: theme.colors.accent,\n backgroundColor: theme.colors.surface,\n }}\n >\n {image ? (\n <Canvas style={{ width: THUMB, height: THUMB }}>\n <SkiaImage image={image} x={0} y={0} width={THUMB} height={THUMB} fit=\"cover\" />\n </Canvas>\n ) : null}\n </View>\n </View>\n )\n}\n\n/**\n * The LUT filter strip: live thumbnails, tap to apply, second tap on the\n * active filter reveals the intensity slider.\n */\nexport function FilterStrip() {\n const { dispatch } = useEditor()\n const luts = useLuts()\n const theme = useTheme()\n const layer = useTargetImageLayer()\n const [intensityFor, setIntensityFor] = useState<string | null>(null)\n\n if (!layer) return null\n const color = (layer.data as ImageLayerData).color\n const activeLut = color.lut\n\n const applyLut = (lutId: string | null) => {\n if (lutId === null) {\n dispatch({ type: 'layer/patchData', id: layer.id, patch: { color: { lut: undefined } } })\n setIntensityFor(null)\n return\n }\n if (activeLut?.id === lutId) {\n // second tap → intensity slider\n setIntensityFor((cur) => (cur === lutId ? null : lutId))\n return\n }\n dispatch({\n type: 'layer/patchData',\n id: layer.id,\n patch: { color: { lut: { id: lutId, intensity: 1 } } },\n })\n }\n\n return (\n <View style={{ backgroundColor: theme.colors.background }}>\n {intensityFor && activeLut?.id === intensityFor ? (\n <View style={{ paddingHorizontal: theme.spacing.lg }}>\n <Slider\n value={activeLut.intensity}\n min={0}\n max={1}\n centered={false}\n valueLabel={`${Math.round(activeLut.intensity * 100)}`}\n onStart={() => dispatch({ type: 'history/beginBatch', label: 'intensity' })}\n onChange={(intensity) =>\n dispatch({\n type: 'layer/patchData',\n id: layer.id,\n patch: { color: { lut: { id: intensityFor, intensity } } },\n })\n }\n onEnd={() => dispatch({ type: 'history/endBatch' })}\n />\n </View>\n ) : null}\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{ gap: theme.spacing.sm, padding: theme.spacing.md }}\n style={{ flexGrow: 0 }}\n >\n <Pressable onPress={() => applyLut(null)}>\n <Thumb lut={undefined} label=\"Original\" active={!activeLut} />\n </Pressable>\n {luts.map((lut) => (\n <Pressable key={lut.id} onPress={() => applyLut(lut.id)}>\n <Thumb\n lut={{ id: lut.id, intensity: 1 }}\n label={lut.label}\n active={activeLut?.id === lut.id}\n />\n </Pressable>\n ))}\n </ScrollView>\n </View>\n )\n}\n","import { useEditor } from '@pictor-sdk/core'\nimport React from 'react'\nimport { Pressable, ScrollView, Text } from 'react-native'\nimport { useTheme } from '../theme'\nimport { cellToTransformPatch, layoutCells, type LayoutPreset } from './layoutMath'\n\nconst PRESETS: Array<{ id: LayoutPreset; label: string }> = [\n { id: '1', label: 'Single' },\n { id: '2v', label: '2 rows' },\n { id: '2h', label: '2 cols' },\n { id: '3v', label: '3 rows' },\n { id: '4grid', label: 'Grid' },\n]\n\n/** Layout grids: snap the image layers into the chosen arrangement. */\nexport function LayoutPanel() {\n const { document, dispatch } = useEditor()\n const theme = useTheme()\n\n const apply = (preset: LayoutPreset) => {\n const cells = layoutCells(preset, document.size)\n const images = document.layers.filter((l) => l.type === 'image')\n dispatch({ type: 'history/beginBatch', label: 'layout' })\n images.slice(0, cells.length).forEach((layer, i) => {\n dispatch({ type: 'layer/transform', id: layer.id, patch: cellToTransformPatch(cells[i]!) })\n })\n dispatch({ type: 'history/endBatch' })\n }\n\n return (\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{ gap: theme.spacing.sm, padding: theme.spacing.md }}\n style={{ flexGrow: 0, backgroundColor: theme.colors.background }}\n >\n {PRESETS.map((preset) => (\n <Pressable\n key={preset.id}\n onPress={() => apply(preset.id)}\n style={{\n paddingHorizontal: theme.spacing.md,\n paddingVertical: theme.spacing.sm,\n borderRadius: theme.radii.md,\n backgroundColor: theme.colors.surface,\n }}\n >\n <Text style={{ color: theme.colors.text, fontSize: theme.font.sizeSm, fontWeight: theme.font.weight }}>\n {preset.label}\n </Text>\n </Pressable>\n ))}\n </ScrollView>\n )\n}\n","import { type Size, type Transform } from '@pictor-sdk/core'\n\n/** The bundled multi-photo arrangements, by cell count and split direction. */\nexport type LayoutPreset = '1' | '2v' | '2h' | '3v' | '4grid'\n\n/** One slot in a layout: where its photo sits, in normalized document units. */\nexport interface LayoutCell {\n /** centre + scale in normalized document units */\n x: number\n y: number\n /** width of the cell as a fraction of document width */\n scale: number\n}\n\n/**\n * Story layout grids: cell centres and scales for placing the first N image\n * layers. Pure — unit tested. Cells are defined as document fractions so any\n * canvas size works.\n */\nexport function layoutCells(preset: LayoutPreset, _doc: Size): LayoutCell[] {\n switch (preset) {\n case '1':\n return [{ x: 0.5, y: 0.5, scale: 1 }]\n case '2v': // two rows\n return [\n { x: 0.5, y: 0.25, scale: 1 },\n { x: 0.5, y: 0.75, scale: 1 },\n ]\n case '2h': // two columns\n return [\n { x: 0.25, y: 0.5, scale: 0.5 },\n { x: 0.75, y: 0.5, scale: 0.5 },\n ]\n case '3v':\n return [\n { x: 0.5, y: 1 / 6, scale: 1 },\n { x: 0.5, y: 0.5, scale: 1 },\n { x: 0.5, y: 5 / 6, scale: 1 },\n ]\n case '4grid':\n return [\n { x: 0.25, y: 0.25, scale: 0.5 },\n { x: 0.75, y: 0.25, scale: 0.5 },\n { x: 0.25, y: 0.75, scale: 0.5 },\n { x: 0.75, y: 0.75, scale: 0.5 },\n ]\n default: {\n const _exhaustive: never = preset\n void _exhaustive\n return [{ x: 0.5, y: 0.5, scale: 1 }]\n }\n }\n}\n\n/** The transform patch that moves a layer into a cell, leaving its other fields alone. */\nexport function cellToTransformPatch(cell: LayoutCell): Partial<Transform> {\n return { x: cell.x, y: cell.y, scale: cell.scale, rotation: 0 }\n}\n","import {\n luxControlState,\n luxIntensityPatch,\n useEditor,\n type ImageLayerData,\n type LuxState,\n} from '@pictor-sdk/core'\nimport { useLuxAnalysis } from '@pictor-sdk/skia'\nimport React from 'react'\nimport { Pressable, Text, View } from 'react-native'\nimport { Slider } from '../components/Slider'\nimport { useTheme } from '../theme'\nimport { useTargetImageLayer } from './useTargetImageLayer'\n\n/**\n * Lux: one intensity slider over an analysis of the photograph.\n *\n * Two things distinguish it from the 13 adjustments, both taken from\n * measurement (`docs/research/photo-editor-ux.md`):\n *\n * * the slider is **one-directional and rests at zero**, not centred — Lux is\n * an amount of correction, and there is no meaningful negative;\n * * the correction itself is **image-dependent**. The same slider position\n * lifts a flat photograph's highlights and pulls a well-exposed one's down.\n *\n * The analysis is written into the document the moment the user engages the\n * slider, and everything afterwards — preview, undo, save, export — reads it\n * from there. Recomputing at render time would let a different decode, a\n * resized preview or a future analyzer quietly restyle an existing document.\n */\nexport function LuxPanel() {\n const { dispatch } = useEditor()\n const theme = useTheme()\n const layer = useTargetImageLayer()\n const data = layer?.data as ImageLayerData | undefined\n const proposal = useLuxAnalysis(data?.source)\n\n if (!layer || !data) return null\n const stored: LuxState | undefined = data.color.lux\n const intensity = stored?.intensity ?? 0\n // Once stored, the document's analysis wins — that is the whole point. Until\n // one exists, the control is inert rather than falling back to a neutral\n // proposal: a neutral analysis stored during a slow decode would render as\n // nothing *and* suppress the real proposal permanently.\n const state = luxControlState(stored, proposal)\n\n const setIntensity = (value: number) => {\n const lux = luxIntensityPatch(state, value)\n if (!lux) return\n dispatch({ type: 'layer/patchData', id: layer.id, patch: { color: { lux } } })\n }\n\n /**\n * Clear Lux entirely — `undefined` deletes the key, so the document returns\n * to the shape it had before Lux was ever touched and the render path skips\n * the contribution instead of adding zeroes.\n *\n * Inside the tool session's batch, like every other reset: Cancel rolls it\n * back with the rest and Done commits it as one entry.\n */\n const reset = () =>\n dispatch({\n type: 'layer/patchData',\n id: layer.id,\n patch: { color: { lux: undefined } } as unknown as Record<string, unknown>,\n })\n\n return (\n <View style={{ backgroundColor: theme.colors.background, paddingBottom: theme.spacing.md }}>\n <View style={{ paddingHorizontal: theme.spacing.lg }}>\n <View\n style={{\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'center',\n gap: theme.spacing.sm,\n minHeight: 28,\n }}\n >\n <Text\n style={{\n color: theme.colors.textMuted,\n textAlign: 'center',\n fontSize: theme.font.sizeSm,\n }}\n >\n {state.pending ? 'Analyzing…' : `Lux ${intensity === 0 ? '' : Math.round(intensity * 100)}`}\n </Text>\n {intensity > 0 ? (\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel=\"Reset Lux\"\n onPress={reset}\n hitSlop={8}\n style={{\n paddingHorizontal: theme.spacing.sm,\n paddingVertical: 2,\n borderRadius: theme.radii.sm,\n borderWidth: 1,\n borderColor: theme.colors.track,\n }}\n >\n <Text style={{ color: theme.colors.text, fontSize: theme.font.sizeSm }}>Reset</Text>\n </Pressable>\n ) : null}\n </View>\n <Slider\n value={intensity}\n min={0}\n max={1}\n centered={false}\n disabled={!state.interactive}\n testID=\"lux-slider\"\n valueLabel={`${Math.round(intensity * 100)}`}\n onStart={() => dispatch({ type: 'history/beginBatch', label: 'lux' })}\n onChange={setIntensity}\n onEnd={() => dispatch({ type: 'history/endBatch' })}\n />\n </View>\n </View>\n )\n}\n","import {\n initialMediaTransform,\n mediaConfigFromProfile,\n useEditor,\n type ImageLayerData,\n} from '@pictor-sdk/core'\nimport { preferResolvedSize, useResolvedImageSize } from '@pictor-sdk/skia'\nimport React from 'react'\nimport { Pressable, Text, View } from 'react-native'\nimport { useBaseMediaLayer } from '../gestures/StoryMediaGestureSurface'\nimport { useTheme } from '../theme'\n\n/**\n * The base-photo tool panel.\n *\n * It is deliberately thin: the gestures live on the canvas surface, and the\n * Cancel/Done transaction comes from `ToolPanelHost`, which opens a history\n * batch for any tool with a panel. The panel only offers the affordances that\n * are not gestures — a reset to the initial fit — and explains the interaction.\n */\nexport function MediaPanel() {\n const { document, dispatch, profile } = useEditor()\n const layer = useBaseMediaLayer()\n const theme = useTheme()\n // same size the renderer and the gesture surface use, so Reset agrees with them\n const data = layer?.data as ImageLayerData | undefined\n const resolved = useResolvedImageSize(data?.source)\n\n if (!layer) {\n return (\n <View style={{ padding: theme.spacing.lg }}>\n <Text style={{ color: theme.colors.textMuted, fontSize: theme.font.sizeSm }}>\n This document has no base photo.\n </Text>\n </View>\n )\n }\n\n const reset = () => {\n const config = mediaConfigFromProfile(profile.interaction?.media)\n dispatch({\n type: 'layer/transform',\n id: layer.id,\n patch: initialMediaTransform(\n preferResolvedSize(resolved, data?.intrinsic),\n document.size,\n config,\n ),\n })\n }\n\n return (\n <View style={{ padding: theme.spacing.lg, gap: theme.spacing.md }}>\n <Text style={{ color: theme.colors.textMuted, fontSize: theme.font.sizeSm }}>\n Drag to reposition · pinch to zoom · twist to rotate · double-tap to zoom\n </Text>\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel=\"Reset photo placement\"\n onPress={reset}\n style={{\n alignSelf: 'flex-start',\n paddingHorizontal: theme.spacing.md,\n paddingVertical: theme.spacing.sm,\n borderRadius: theme.radii.md,\n backgroundColor: theme.colors.surface,\n }}\n >\n <Text style={{ color: theme.colors.text, fontSize: theme.font.size }}>Reset</Text>\n </Pressable>\n </View>\n )\n}\n","import {\n isDirectManipulationLayer,\n useEditor,\n type EditorDocument,\n type ProfileLayerInteraction,\n} from '@pictor-sdk/core'\nimport React from 'react'\nimport { Pressable, ScrollView, Text, View } from 'react-native'\nimport { useTheme } from '../theme'\n\n/**\n * Z-order UI: top-most first, tap to select, reorder and delete.\n * (Drag-to-delete on canvas maps to the same layer/remove command.)\n */\nexport function LayersPanel() {\n const { document, selection, select, dispatch, profile } = useEditor()\n const theme = useTheme()\n const layers = layersForPanel(document, profile.interaction?.layers)\n const minimumIndex = minimumLayerIndexForPanel(document, profile.interaction?.layers)\n\n return (\n <ScrollView style={{ maxHeight: 220, backgroundColor: theme.colors.background }}>\n {layers.map(({ layer, index }) => {\n const selected = selection.includes(layer.id)\n return (\n <View\n key={layer.id}\n style={{\n flexDirection: 'row',\n alignItems: 'center',\n paddingHorizontal: theme.spacing.md,\n paddingVertical: theme.spacing.xs,\n backgroundColor: selected ? theme.colors.surface : 'transparent',\n }}\n >\n <Pressable style={{ flex: 1 }} onPress={() => select([layer.id])}>\n <Text style={{ color: selected ? theme.colors.accent : theme.colors.text, fontSize: theme.font.sizeSm }}>\n {layer.name ?? `${layer.type} · ${layer.id.slice(0, 6)}`}\n </Text>\n </Pressable>\n <Pressable\n disabled={index === document.layers.length - 1}\n onPress={() => dispatch({ type: 'layer/reorder', id: layer.id, to: index + 1 })}\n style={{ padding: theme.spacing.xs }}\n >\n <Text style={{ color: theme.colors.textMuted }}>▲</Text>\n </Pressable>\n <Pressable\n disabled={index === minimumIndex}\n onPress={() => dispatch({ type: 'layer/reorder', id: layer.id, to: index - 1 })}\n style={{ padding: theme.spacing.xs }}\n >\n <Text style={{ color: theme.colors.textMuted }}>▼</Text>\n </Pressable>\n <Pressable\n onPress={() => dispatch({ type: 'layer/remove', id: layer.id })}\n style={{ padding: theme.spacing.xs }}\n >\n <Text style={{ color: theme.colors.danger }}>✕</Text>\n </Pressable>\n </View>\n )\n })}\n </ScrollView>\n )\n}\n\n/** Lowest z-index to which the panel may move an overlay. */\nexport function minimumLayerIndexForPanel(\n document: EditorDocument,\n interaction?: ProfileLayerInteraction,\n): number {\n return interaction?.excludeBaseImage && document.layers[0]?.type === 'image' ? 1 : 0\n}\n\n/** Overlay layers shown by the built-in manager, top-most first. */\nexport function layersForPanel(\n document: EditorDocument,\n interaction?: ProfileLayerInteraction,\n): Array<{ layer: EditorDocument['layers'][number]; index: number }> {\n return document.layers\n .map((layer, index) => ({ layer, index }))\n .filter(({ layer, index }) => isDirectManipulationLayer(layer, index, interaction))\n .reverse()\n}\n","import {\n needsPerspective,\n perspectivePatch,\n useEditor,\n MAX_PERSPECTIVE_DEGREES,\n type ImageLayerData,\n type Perspective,\n} from '@pictor-sdk/core'\nimport React, { useState } from 'react'\nimport { Pressable, Text, View } from 'react-native'\nimport { Slider } from '../components/Slider'\nimport { useTheme } from '../theme'\nimport { useTargetImageLayer } from './useTargetImageLayer'\n\n/**\n * Geometry: vertical keystone, straighten, horizontal keystone.\n *\n * One control shared by all three, because they are one family — the research\n * pass found the reference driving exactly these three from a single dial, and\n * that observation is what justified a single unified cover calculation rather\n * than multiplying separate zooms.\n *\n * Values read in **degrees**, as measured, and each mode carries an inline\n * reset that clears only itself.\n */\n\n/** Straighten shares the perspective range here, so one slider serves all three. */\nconst MAX_STRAIGHTEN_DEGREES = MAX_PERSPECTIVE_DEGREES\n\nconst MODES = [\n { key: 'vertical', label: 'Vertical' },\n { key: 'straighten', label: 'Straighten' },\n { key: 'horizontal', label: 'Horizontal' },\n] as const\n\ntype ModeKey = (typeof MODES)[number]['key']\n\nconst toRadians = (degrees: number) => (degrees * Math.PI) / 180\nconst toDegrees = (radians: number) => (radians * 180) / Math.PI\n\nexport function PerspectivePanel() {\n const { dispatch } = useEditor()\n const theme = useTheme()\n const layer = useTargetImageLayer()\n const [mode, setMode] = useState<ModeKey>('vertical')\n\n if (!layer) return null\n const data = layer.data as ImageLayerData\n const perspective: Perspective = data.perspective ?? { vertical: 0, horizontal: 0 }\n const straightenDegrees = toDegrees(data.straighten ?? 0)\n\n /** Every mode expressed as degrees, so one slider can drive all three. */\n const degreesOf = (key: ModeKey): number =>\n key === 'straighten'\n ? straightenDegrees\n : perspective[key] * MAX_PERSPECTIVE_DEGREES\n\n const setDegrees = (key: ModeKey, degrees: number) => {\n if (key === 'straighten') {\n return dispatch({\n type: 'layer/patchData',\n id: layer.id,\n patch: { straighten: degrees === 0 ? undefined : toRadians(degrees) } as unknown as Record<\n string,\n unknown\n >,\n })\n }\n const next: Perspective = { ...perspective, [key]: degrees / MAX_PERSPECTIVE_DEGREES }\n dispatch({\n type: 'layer/patchData',\n id: layer.id,\n // `perspectivePatch` deletes the key when both axes reach zero, so\n // straightening a correction back out leaves nothing serialized.\n patch: perspectivePatch(needsPerspective(next) ? next : undefined) as unknown as Record<\n string,\n unknown\n >,\n })\n }\n\n const value = degreesOf(mode)\n const max = mode === 'straighten' ? MAX_STRAIGHTEN_DEGREES : MAX_PERSPECTIVE_DEGREES\n\n return (\n <View style={{ backgroundColor: theme.colors.background, paddingBottom: theme.spacing.md }}>\n <View\n style={{\n flexDirection: 'row',\n justifyContent: 'center',\n gap: theme.spacing.sm,\n paddingVertical: theme.spacing.sm,\n }}\n >\n {MODES.map(({ key, label }) => {\n const selected = key === mode\n const degrees = degreesOf(key)\n const set = Math.abs(degrees) > 0.05\n return (\n <Pressable\n key={key}\n accessibilityRole=\"button\"\n accessibilityLabel={`${label} correction`}\n onPress={() => setMode(key)}\n style={{\n flexDirection: 'row',\n alignItems: 'center',\n gap: 6,\n paddingHorizontal: theme.spacing.sm,\n paddingVertical: 6,\n borderRadius: theme.radii.sm,\n borderWidth: 1,\n borderColor: selected ? theme.colors.accent : theme.colors.track,\n }}\n >\n <Text\n style={{\n color: selected ? theme.colors.accent : theme.colors.textMuted,\n fontSize: theme.font.sizeSm,\n fontWeight: theme.font.weight,\n }}\n >\n {/* A pill showing the value with its unit once set — the\n affordance the research pass measured. */}\n {set ? `${label} ${degrees.toFixed(1)}°` : label}\n </Text>\n {set ? (\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={`Reset ${label.toLowerCase()}`}\n onPress={() => setDegrees(key, 0)}\n hitSlop={8}\n >\n <Text style={{ color: theme.colors.text, fontSize: theme.font.sizeSm }}>✕</Text>\n </Pressable>\n ) : null}\n </Pressable>\n )\n })}\n </View>\n\n <View style={{ paddingHorizontal: theme.spacing.lg }}>\n <Slider\n value={value}\n min={-max}\n max={max}\n centered\n testID={`perspective-${mode}`}\n valueLabel={`${value > 0 ? '+' : ''}${value.toFixed(1)}°`}\n onStart={() => dispatch({ type: 'history/beginBatch', label: `perspective-${mode}` })}\n onChange={(v) => setDegrees(mode, v)}\n onEnd={() => dispatch({ type: 'history/endBatch' })}\n />\n </View>\n </View>\n )\n}\n","import { createId, useEditor, type Size } from '@pictor-sdk/core'\nimport React from 'react'\nimport { Image, Pressable, ScrollView, Text, View } from 'react-native'\nimport { useTheme } from '../theme'\nimport { useUiState } from '../uiState'\n\n/**\n * One sticker offered by the panel.\n *\n * Supplied by the host: the library ships no sticker artwork, so what appears\n * here is entirely the app's own.\n */\nexport interface StickerAsset {\n id: string\n /** image source (require() result, {uri}, or URL string) */\n source: unknown\n intrinsic?: Size\n label?: string\n}\n\n/**\n * Sticker tab. Sticker catalogs are host-supplied — pass them via\n * <Editor stickers={…}> (or replace this panel through a plugin tool Panel).\n * DECISION: no sticker assets ship with the library (same reasoning as LUTs).\n */\nexport function StickerPanel() {\n const { dispatch, select } = useEditor()\n const theme = useTheme()\n const [stickers] = useUiState<StickerAsset[]>('stickers', [])\n\n const add = (sticker: StickerAsset) => {\n const id = createId('sticker')\n dispatch({\n type: 'layer/add',\n layer: {\n id,\n type: 'sticker',\n transform: { x: 0.5, y: 0.5, scale: 1, rotation: 0 },\n opacity: 1,\n blendMode: 'normal',\n data: {\n source: sticker.source,\n intrinsic: sticker.intrinsic ?? { width: 0, height: 0 },\n },\n },\n })\n select([id])\n }\n\n if (stickers.length === 0) {\n return (\n <View style={{ backgroundColor: theme.colors.background, padding: theme.spacing.md }}>\n <Text style={{ color: theme.colors.textMuted, textAlign: 'center', fontSize: theme.font.sizeSm }}>\n No stickers registered — pass `stickers` to {'<Editor>'}.\n </Text>\n </View>\n )\n }\n\n return (\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{ gap: theme.spacing.sm, padding: theme.spacing.md }}\n style={{ flexGrow: 0, backgroundColor: theme.colors.background }}\n >\n {stickers.map((sticker) => (\n <Pressable key={sticker.id} onPress={() => add(sticker)}>\n <Image\n source={sticker.source as never}\n style={{ width: 64, height: 64, borderRadius: theme.radii.sm, backgroundColor: theme.colors.surface }}\n resizeMode=\"contain\"\n />\n </Pressable>\n ))}\n </ScrollView>\n )\n}\n","import {\n createTiltShift,\n needsTiltShift,\n tiltShiftPatch,\n useEditor,\n MAX_TILT_BLUR,\n MAX_TILT_FEATHER,\n MAX_TILT_RADIUS,\n type ImageLayerData,\n type TiltShift,\n} from '@pictor-sdk/core'\nimport React from 'react'\nimport { Pressable, Text, View } from 'react-native'\nimport { Slider } from '../components/Slider'\nimport { useTheme } from '../theme'\nimport { useTargetImageLayer } from './useTargetImageLayer'\n\n/**\n * Selective focus: Off · Radial · Linear, then the shape of the region.\n *\n * The mode row is explicit rather than implied by a non-zero blur, because the\n * research pass measured it that way and because \"off\" needs to be reachable\n * without dragging a slider back to exactly zero.\n *\n * Position and size are set by dragging on the canvas, not here — see\n * `TiltShiftGestureSurface`. The sliders cover what a gesture cannot express.\n */\n\nconst MODES = [\n { key: 'off', label: 'Off' },\n { key: 'radial', label: 'Radial' },\n { key: 'linear', label: 'Linear' },\n] as const\n\nexport function TiltShiftPanel() {\n const { dispatch } = useEditor()\n const theme = useTheme()\n const layer = useTargetImageLayer()\n\n if (!layer) return null\n const data = layer.data as ImageLayerData\n const tilt = needsTiltShift(data.tiltShift) ? data.tiltShift! : undefined\n const mode = tilt?.mode ?? 'off'\n\n const patch = (next: TiltShift | undefined) =>\n dispatch({\n type: 'layer/patchData',\n id: layer.id,\n patch: tiltShiftPatch(next) as unknown as Record<string, unknown>,\n })\n\n /**\n * Switching mode keeps the region where the user put it.\n *\n * Only the shape changes; re-centring on every mode tap would throw away\n * positioning work for no reason.\n */\n const setMode = (key: (typeof MODES)[number]['key']) => {\n if (key === 'off') return patch(undefined)\n patch(tilt ? { ...tilt, mode: key } : createTiltShift(key))\n }\n\n const set = (over: Partial<TiltShift>) => tilt && patch({ ...tilt, ...over })\n\n const sliders: Array<{ key: keyof TiltShift; label: string; max: number }> = [\n { key: 'blur', label: 'Blur', max: MAX_TILT_BLUR },\n { key: 'radius', label: 'Size', max: MAX_TILT_RADIUS },\n { key: 'feather', label: 'Feather', max: MAX_TILT_FEATHER },\n ]\n\n return (\n <View style={{ backgroundColor: theme.colors.background, paddingBottom: theme.spacing.md }}>\n <View\n style={{\n flexDirection: 'row',\n justifyContent: 'center',\n gap: theme.spacing.md,\n paddingVertical: theme.spacing.sm,\n }}\n >\n {MODES.map(({ key, label }) => {\n const selected = key === mode\n return (\n <Pressable\n key={key}\n accessibilityRole=\"button\"\n accessibilityLabel={`Tilt shift ${label.toLowerCase()}`}\n onPress={() => setMode(key)}\n style={{\n paddingHorizontal: theme.spacing.md,\n paddingVertical: 6,\n borderRadius: theme.radii.sm,\n borderWidth: 1,\n borderColor: selected ? theme.colors.accent : theme.colors.track,\n }}\n >\n <Text\n style={{\n color: selected ? theme.colors.accent : theme.colors.textMuted,\n fontSize: theme.font.sizeSm,\n fontWeight: theme.font.weight,\n }}\n >\n {label}\n </Text>\n </Pressable>\n )\n })}\n </View>\n\n <View style={{ paddingHorizontal: theme.spacing.lg }}>\n <Text\n style={{\n color: theme.colors.textMuted,\n textAlign: 'center',\n fontSize: theme.font.sizeSm,\n minHeight: 20,\n }}\n >\n {tilt ? 'Drag on the photo to place the focus' : 'Off'}\n </Text>\n {sliders.map(({ key, label, max }) => {\n const value = (tilt?.[key] as number | undefined) ?? 0\n return (\n <View key={key}>\n <Text style={{ color: theme.colors.textMuted, fontSize: theme.font.sizeSm }}>\n {label} {tilt ? Math.round((value / max) * 100) : ''}\n </Text>\n <Slider\n value={value}\n min={0}\n max={max}\n centered={false}\n testID={`tilt-${key}`}\n disabled={!tilt}\n onStart={() => dispatch({ type: 'history/beginBatch', label: `tilt-${key}` })}\n onChange={(v) => set({ [key]: v } as Partial<TiltShift>)}\n onEnd={() => dispatch({ type: 'history/endBatch' })}\n />\n </View>\n )\n })}\n </View>\n </View>\n )\n}\n","import {\n MAX_TEXT_SIZE,\n MIN_TEXT_SIZE,\n fontChoices,\n useEditor,\n useEditorStore,\n type TextLayerData,\n} from '@pictor-sdk/core'\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport {\n BackHandler,\n Keyboard,\n Platform,\n Pressable,\n ScrollView,\n Text,\n TextInput,\n View,\n type TextInputSelectionChangeEventData,\n type NativeSyntheticEvent,\n} from 'react-native'\nimport { Slider } from '../components/Slider'\nimport { useTheme } from '../theme'\nimport {\n composerInsets,\n fitCanvasRect,\n HIDDEN_KEYBOARD,\n type ComposerInsets,\n} from './keyboardLayout'\nimport { useTextSession, type TextSessionController } from './useTextSession'\n\nconst SWATCHES = ['#ffffff', '#000000', '#ed4956', '#ffe25c', '#78de85', '#4dc4ff', '#a15fed']\nconst ALIGNS = ['left', 'center', 'right'] as const\nconst ALIGN_GLYPH = { left: '⇤', center: '☰', right: '⇥' } as const\nconst FILL_MODES = [undefined, 'solid', 'perLine'] as const\n/** Normalized stroke widths: off, hairline, bold. All fractions of doc width. */\nconst STROKE_WIDTHS = [undefined, 0.002, 0.005] as const\n/** Normalized shadow presets: off, soft, hard. */\nconst SHADOWS = [\n undefined,\n { color: '#000000', blur: 0.012, dx: 0.002, dy: 0.004 },\n { color: '#000000', blur: 0.002, dx: 0.006, dy: 0.008 },\n] as const\n\n/**\n * Props a text composer receives.\n *\n * The default composer is built on exactly this, so a replacement has\n * everything the built-in one had — no privileged access to reach for.\n *\n * @experimental\n */\nexport interface TextComposerProps {\n /** The live session: layer, value, style commands, Done and Cancel. */\n session: TextSessionController\n /** Where the controls should sit, given the keyboard. */\n insets: ComposerInsets\n /** Finish and keep the text. */\n onDone(): void\n /** Abandon, restoring the document. */\n onCancel(): void\n}\n\n/**\n * The full-screen Story text composer.\n *\n * An absolute overlay above the canvas. The canvas keeps rendering the layer\n * being typed — there is no second text renderer and no editing chrome inside\n * `renderDocument` — so what is on screen while composing is what exports.\n *\n * The `TextInput` itself is invisible and stretched over the canvas: it owns\n * the caret, the platform selection handles and the IME, while the *visible*\n * text is the real Skia layer underneath. That is what keeps preview and export\n * identical without giving up native text editing.\n *\n * @experimental\n */\nexport function TextComposer({ session, insets, onDone, onCancel }: TextComposerProps) {\n const theme = useTheme()\n const store = useEditorStore()\n const { document } = useEditor()\n // Measured rather than taken from `useCanvasMetrics`: that context belongs to\n // EditorCanvas's children, and the composer is its sibling.\n const [container, setContainer] = useState({ width: 0, height: 0 })\n const input = useRef<TextInput>(null)\n const [selectionRange, setSelectionRange] = useState<{ start: number; end: number } | undefined>(\n undefined,\n )\n\n const data = session.data\n const span = session.span\n\n /**\n * Lay the input out over the text it is editing.\n *\n * The visible glyphs are the Skia layer; this input is transparent and only\n * carries the caret, the selection handles and the IME. For the caret to land\n * where the user sees their text, the input's own layout has to match the\n * layer's: same font size in dp, same alignment, and a box centred on the\n * layer's normalized y. It will never be glyph-exact — Skia and the platform\n * measure differently — but it tracks closely enough to edit by.\n */\n const layout = useMemo(() => {\n const canvas = fitCanvasRect(container, document.size)\n const fontSize = (span?.fontSize ?? 0.08) * canvas.width\n const centreY = canvas.top + (session.layer?.transform.y ?? 0.42) * canvas.height\n const height = canvas.height\n return {\n fontSize: Math.max(1, fontSize),\n lineHeight: Math.max(1, fontSize * (span?.lineHeight ?? 1.2)),\n left: canvas.left,\n width: Math.max(1, canvas.width),\n top: Math.max(0, centreY - height / 2),\n height: Math.max(1, height),\n }\n }, [container, document.size, span?.fontSize, span?.lineHeight, session.layer?.transform.y])\n const fonts = useMemo(() => fontChoices(store.registry.fonts), [store.registry.fonts])\n\n // Focus once the overlay is up. A frame's delay lets the mount settle so the\n // keyboard animates in rather than appearing half-drawn.\n useEffect(() => {\n const handle = setTimeout(() => input.current?.focus(), 50)\n return () => clearTimeout(handle)\n }, [])\n\n const onSelectionChange = useCallback(\n (event: NativeSyntheticEvent<TextInputSelectionChangeEventData>) => {\n setSelectionRange(event.nativeEvent.selection)\n },\n [],\n )\n\n /**\n * Apply a style without disturbing the caret.\n *\n * Style controls are outside the input, so tapping one would ordinarily blur\n * it and collapse the selection. Re-focusing and restoring the range keeps\n * the user where they were — the difference between styling a selection and\n * losing it.\n */\n const keepFocus = useCallback(\n (apply: () => void) => {\n apply()\n if (!input.current?.isFocused()) input.current?.focus()\n if (selectionRange) {\n const range = selectionRange\n requestAnimationFrame(() => input.current?.setNativeProps({ selection: range }))\n }\n },\n [selectionRange],\n )\n\n const cycleAlign = () => {\n if (!data) return\n const next = ALIGNS[(ALIGNS.indexOf(data.align) + 1) % ALIGNS.length]!\n keepFocus(() => session.styleText({ align: next }))\n }\n\n const cycleFill = () => {\n if (!data || !span) return\n const index = FILL_MODES.indexOf(data.fill?.mode as (typeof FILL_MODES)[number])\n const next = FILL_MODES[(index + 1) % FILL_MODES.length]\n keepFocus(() =>\n session.styleText({\n fill: next\n ? {\n color: span.color === '#000000' ? '#ffffff' : '#000000',\n radius: 0.012,\n padding: 0.012,\n mode: next,\n }\n : undefined,\n }),\n )\n }\n\n /**\n * Cycle the outline. Widths are normalized fractions of document width, like\n * every other length in the document, so they scale with the export.\n */\n const cycleStroke = () => {\n if (!data || !span) return\n const current = data.stroke?.width\n const index = STROKE_WIDTHS.findIndex((w) => w === current)\n const next = STROKE_WIDTHS[(index + 1) % STROKE_WIDTHS.length]\n keepFocus(() =>\n session.styleText({\n stroke: next\n ? { color: span.color === '#000000' ? '#ffffff' : '#000000', width: next }\n : undefined,\n }),\n )\n }\n\n /** Cycle the drop shadow: off, soft, hard. */\n const cycleShadow = () => {\n if (!data) return\n const current = data.shadow\n const index = current\n ? SHADOWS.findIndex((s) => s && current && s.blur === current.blur && s.dx === current.dx)\n : 0\n const next = SHADOWS[(index + 1) % SHADOWS.length]\n keepFocus(() => session.styleText({ shadow: next ? { ...next } : undefined }))\n }\n\n // Hardware back dismisses the keyboard first, and only closes the session on\n // a second press — so a stray back does not discard what was typed.\n useEffect(() => {\n const subscription = BackHandler.addEventListener('hardwareBackPress', () => {\n if (Keyboard.isVisible?.() ?? insets.keyboardVisible) {\n Keyboard.dismiss()\n return true\n }\n onCancel()\n return true\n })\n return () => subscription.remove()\n }, [onCancel, insets.keyboardVisible])\n\n const controlRow = {\n flexDirection: 'row' as const,\n alignItems: 'center' as const,\n gap: theme.spacing.sm,\n paddingHorizontal: theme.spacing.md,\n }\n\n return (\n <View\n style={{ position: 'absolute', left: 0, right: 0, top: 0, bottom: 0 }}\n onLayout={(event) => {\n const { width, height } = event.nativeEvent.layout\n setContainer((current) =>\n current.width === width && current.height === height ? current : { width, height },\n )\n }}\n >\n {/* Subdues the canvas so the text being typed reads clearly. Preview-only\n React Native UI — never part of renderDocument, so it cannot export. */}\n <View\n pointerEvents=\"none\"\n style={{ position: 'absolute', left: 0, right: 0, top: 0, bottom: 0, backgroundColor: '#00000055' }}\n />\n\n {/* The invisible editing surface. The visible glyphs are the Skia layer\n underneath; this owns the caret, selection handles and IME. */}\n <TextInput\n ref={input}\n value={session.value}\n onChangeText={session.setValue}\n onSelectionChange={onSelectionChange}\n multiline\n // Enter inserts a newline. Without this, a submit blurs the input and\n // the session ends on the first line break the user types.\n submitBehavior=\"newline\"\n // Android draws IME composing text itself, ignoring the transparent\n // colour below, which ghosts the input's glyphs beside the Skia ones.\n // Correction, spell-check and autofill are off to keep the composing\n // region as small as possible.\n //\n // DECISION: `keyboardType=\"visible-password\"` suppresses composing\n // entirely and removes the ghost completely — but it also strips the\n // emoji key and language switching from the keyboard, which this\n // milestone needs for emoji and Bengali. A faint composing underline on\n // the word being typed is the better trade.\n autoCorrect={false}\n spellCheck={false}\n autoComplete=\"off\"\n importantForAutofill=\"no\"\n accessibilityLabel=\"Story text\"\n placeholder=\"\"\n style={{\n position: 'absolute',\n left: layout.left,\n width: layout.width,\n top: layout.top,\n height: layout.height,\n // Fully transparent glyphs. The Skia layer is what the user reads;\n // drawing the same text twice would double it on screen. Written as\n // rgba rather than the 'transparent' keyword because the keyword is\n // not reliably honoured for TextInput colour on Android.\n color: 'rgba(0,0,0,0)',\n fontSize: layout.fontSize,\n lineHeight: layout.lineHeight,\n textAlign: data?.align ?? 'center',\n ...(Platform.OS === 'ios' ? {} : { textAlignVertical: 'center' as const }),\n padding: 0,\n }}\n // The caret and the selection highlight must stay visible even though\n // the glyphs are not.\n selectionColor={theme.colors.accent}\n cursorColor={theme.colors.accent}\n />\n\n {/* Top bar: Cancel / Done, above the keyboard-independent area. */}\n <View\n style={{\n position: 'absolute',\n left: 0,\n right: 0,\n top: 0,\n height: 56,\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n paddingHorizontal: theme.spacing.lg,\n }}\n >\n <Pressable accessibilityRole=\"button\" accessibilityLabel=\"Cancel text\" onPress={onCancel}>\n <Text style={{ color: theme.colors.text, fontSize: theme.font.size }}>Cancel</Text>\n </Pressable>\n <Pressable accessibilityRole=\"button\" accessibilityLabel=\"Done editing text\" onPress={onDone}>\n <Text\n style={{\n color: theme.colors.accent,\n fontSize: theme.font.size,\n fontWeight: theme.font.weight,\n }}\n >\n Done\n </Text>\n </Pressable>\n </View>\n\n {/* Controls ride the keyboard. The canvas never moves. */}\n <View\n style={{\n position: 'absolute',\n left: 0,\n right: 0,\n bottom: insets.bottom,\n paddingVertical: theme.spacing.sm,\n gap: theme.spacing.sm,\n backgroundColor: '#00000066',\n }}\n >\n <View style={controlRow}>\n <Text\n style={{ color: theme.colors.textMuted, fontSize: theme.font.sizeSm, width: 34 }}\n accessibilityLabel=\"Text size\"\n >\n Aa\n </Text>\n <View style={{ flex: 1 }}>\n <Slider\n value={span?.fontSize ?? MIN_TEXT_SIZE}\n min={MIN_TEXT_SIZE}\n max={MAX_TEXT_SIZE}\n centered={false}\n onChange={(size) => session.setSize(size)}\n />\n </View>\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={`Alignment ${data?.align ?? 'center'}`}\n onPress={cycleAlign}\n style={{ padding: theme.spacing.sm }}\n >\n <Text style={{ color: theme.colors.text, fontWeight: theme.font.weight }}>\n {ALIGN_GLYPH[data?.align ?? 'center']}\n </Text>\n </Pressable>\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel=\"Text background\"\n accessibilityState={{ selected: Boolean(data?.fill) }}\n onPress={cycleFill}\n style={{ padding: theme.spacing.sm }}\n >\n <Text\n style={{\n color: data?.fill ? theme.colors.accent : theme.colors.text,\n fontWeight: theme.font.weight,\n }}\n >\n {data?.fill?.mode === 'perLine' ? 'A⃞⃞' : 'A⃞'}\n </Text>\n </Pressable>\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel=\"Text outline\"\n accessibilityState={{ selected: Boolean(data?.stroke) }}\n onPress={cycleStroke}\n style={{ padding: theme.spacing.sm }}\n >\n <Text\n style={{\n color: data?.stroke ? theme.colors.accent : theme.colors.text,\n fontWeight: theme.font.weight,\n }}\n >\n Ⓐ\n </Text>\n </Pressable>\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel=\"Text shadow\"\n accessibilityState={{ selected: Boolean(data?.shadow) }}\n onPress={cycleShadow}\n style={{ padding: theme.spacing.sm }}\n >\n <Text\n style={{\n color: data?.shadow ? theme.colors.accent : theme.colors.text,\n fontWeight: theme.font.weight,\n }}\n >\n A˙\n </Text>\n </Pressable>\n </View>\n\n <ScrollView\n horizontal\n keyboardShouldPersistTaps=\"always\"\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{ gap: theme.spacing.sm, paddingHorizontal: theme.spacing.md, alignItems: 'center' }}\n style={{ flexGrow: 0 }}\n >\n {fonts.map((font) => (\n <Pressable\n key={font.family}\n accessibilityRole=\"button\"\n accessibilityLabel={`Font ${font.label}`}\n accessibilityState={{ selected: span?.fontFamily === font.family }}\n onPress={() => keepFocus(() => session.styleSpan({ fontFamily: font.family }))}\n style={{\n paddingHorizontal: theme.spacing.md,\n paddingVertical: theme.spacing.xs,\n borderRadius: theme.radii.md,\n backgroundColor:\n span?.fontFamily === font.family ? theme.colors.surface : 'transparent',\n borderWidth: 1,\n borderColor:\n span?.fontFamily === font.family ? theme.colors.accent : theme.colors.track,\n }}\n >\n <Text style={{ color: theme.colors.text, fontSize: theme.font.sizeSm }}>\n {font.label}\n </Text>\n </Pressable>\n ))}\n </ScrollView>\n\n <ScrollView\n horizontal\n keyboardShouldPersistTaps=\"always\"\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{ gap: theme.spacing.sm, paddingHorizontal: theme.spacing.md, alignItems: 'center' }}\n style={{ flexGrow: 0 }}\n >\n {SWATCHES.map((color) => (\n <Pressable\n key={color}\n accessibilityRole=\"button\"\n accessibilityLabel={`Text colour ${color}`}\n accessibilityState={{ selected: span?.color === color }}\n onPress={() => keepFocus(() => session.styleSpan({ color }))}\n style={{\n width: 28,\n height: 28,\n borderRadius: 14,\n backgroundColor: color,\n borderWidth: span?.color === color ? 3 : 1,\n borderColor: span?.color === color ? theme.colors.accent : theme.colors.track,\n }}\n />\n ))}\n </ScrollView>\n </View>\n </View>\n )\n}\n\n/**\n * Mounts a text session and the composer for it, and keeps the keyboard inset\n * up to date. This is what `<Editor>` renders while the text tool is active.\n *\n * @experimental\n */\nexport function TextComposerHost({\n Composer = TextComposer,\n}: {\n /** Replace the default composer without replacing the canvas or editor. */\n Composer?: React.ComponentType<TextComposerProps>\n}) {\n const { setActiveTool } = useEditor()\n const session = useTextSession()\n const [frame, setFrame] = useState(HIDDEN_KEYBOARD)\n\n // A monotonic token so a keyboard event that arrives after this session has\n // closed cannot resize a later one.\n const token = useRef(0)\n useEffect(() => {\n token.current += 1\n const mine = token.current\n const show = Keyboard.addListener(\n Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow',\n (event) => {\n if (mine !== token.current) return\n setFrame({ height: event.endCoordinates?.height ?? 0, duration: event.duration })\n },\n )\n const hide = Keyboard.addListener(\n Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide',\n (event) => {\n if (mine !== token.current) return\n setFrame({ height: 0, duration: event?.duration })\n },\n )\n return () => {\n token.current += 1\n show.remove()\n hide.remove()\n }\n }, [])\n\n const insets = useMemo(() => composerInsets(frame), [frame])\n\n const finish = useCallback(\n (commit: boolean) => {\n if (commit) session.commit()\n else session.cancel()\n Keyboard.dismiss()\n setActiveTool(null)\n },\n [session, setActiveTool],\n )\n\n return (\n <Composer\n session={session}\n insets={insets}\n onDone={() => finish(true)}\n onCancel={() => finish(false)}\n />\n )\n}\n\n/** Narrow re-export so the composer's data type is reachable without deep imports. */\nexport type { TextLayerData }\n","/**\n * Keyboard layout maths for the text composer.\n *\n * Split from the component so it can be tested without mounting a keyboard,\n * and kept free of any React Native import so it runs in plain Node.\n *\n * The rule this encodes: **the canvas never moves.** Milestone 2 established\n * that changing canvas metrics mid-interaction moves the ground under the\n * gesture; the same is true of a caret. So the keyboard's height becomes an\n * inset for the composer's *controls*, and nothing else in the editor reacts to\n * it.\n *\n * @experimental\n */\n\nexport interface KeyboardFrame {\n /** Height of the keyboard in dp; 0 when hidden or when a hardware keyboard is attached. */\n height: number\n /** Milliseconds the platform will take to move it. Android often reports 0. */\n duration?: number\n}\n\nexport interface ComposerInsets {\n /** Distance from the bottom of the screen to place the control bar. */\n bottom: number\n /** True while the keyboard occupies screen space. */\n keyboardVisible: boolean\n /** Animation duration to match the platform's own, clamped to something sane. */\n duration: number\n}\n\nexport const HIDDEN_KEYBOARD: KeyboardFrame = { height: 0 }\n\n/** Longest keyboard animation we will follow; beyond this the UI feels stuck. */\nconst MAX_DURATION = 400\n/** Android frequently reports 0; a short move still reads better than a jump. */\nconst FALLBACK_DURATION = 180\n\n/**\n * Where the composer's controls sit, given the keyboard and the safe area.\n *\n * When the keyboard is up it already covers the home indicator, so the bottom\n * safe-area inset must *not* be added on top of it — doing so leaves a visible\n * gap between the controls and the keyboard on iOS.\n */\nexport function composerInsets(\n frame: KeyboardFrame,\n safeAreaBottom = 0,\n): ComposerInsets {\n const height = Number.isFinite(frame.height) ? Math.max(0, frame.height) : 0\n const visible = height > 0\n const raw = frame.duration\n const duration =\n raw === undefined || !Number.isFinite(raw) || raw <= 0\n ? FALLBACK_DURATION\n : Math.min(MAX_DURATION, raw)\n return {\n bottom: visible ? height : Math.max(0, safeAreaBottom),\n keyboardVisible: visible,\n duration,\n }\n}\n\n/**\n * Whether a keyboard event belongs to the session that is listening.\n *\n * Keyboard events arrive asynchronously and can land after a session has\n * closed — or, worse, after the *next* one has opened. Sessions carry a\n * monotonic token so a late event from an earlier session is ignored rather\n * than resizing the wrong composer.\n */\nexport function isCurrentSession(eventToken: number, currentToken: number): boolean {\n return eventToken === currentToken\n}\n\n/**\n * Space available for the text itself, between the top chrome and the controls.\n *\n * Returns 0 rather than a negative number when the keyboard leaves no room —\n * a caller sizing a view with this must not be handed a negative height.\n */\nexport function composerContentHeight(\n screenHeight: number,\n insets: ComposerInsets,\n topChrome: number,\n controlsHeight: number,\n): number {\n return Math.max(0, screenHeight - topChrome - controlsHeight - insets.bottom)\n}\n\nexport interface Box {\n width: number\n height: number\n}\n\nexport interface CanvasRect {\n /** Size of the fitted canvas inside the container. */\n width: number\n height: number\n /** Offset of the canvas inside the container, which centres it. */\n left: number\n top: number\n}\n\n/**\n * Where the canvas sits inside a container, fitted to the document's aspect.\n *\n * The composer needs this to lay its input over the text it is editing, and it\n * cannot ask the canvas: `useCanvasMetrics` is provided by `EditorCanvas` to\n * its own children, and the composer is a sibling of the canvas, not a child.\n * Reading it there returns `null` — which, when used as a width, silently\n * produced a zero-width input that swallowed every keystroke.\n *\n * So the fit is recomputed here from the same rule `EditorCanvas` uses:\n * contain, then centre.\n */\nexport function fitCanvasRect(container: Box, document: Box): CanvasRect {\n if (container.width <= 0 || container.height <= 0 || document.width <= 0 || document.height <= 0) {\n return { width: 0, height: 0, left: 0, top: 0 }\n }\n const scale = Math.min(container.width / document.width, container.height / document.height)\n const width = document.width * scale\n const height = document.height * scale\n return {\n width,\n height,\n left: (container.width - width) / 2,\n top: (container.height - height) / 2,\n }\n}\n","import {\n clampTextSize,\n collapseTextSpans,\n createTextDraft,\n needsSpanCollapse,\n isBlankText,\n patchTextSpan,\n resolveTextSession,\n textSpanOf,\n textValueOf,\n useEditor,\n type Layer,\n type TextLayerData,\n type TextSpan,\n} from '@pictor-sdk/core'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\n/**\n * The state and commands behind a text-editing session.\n *\n * This is the whole contract a composer needs, so the default composer and any\n * replacement are built on exactly the same surface — which is what makes the\n * default one genuinely replaceable rather than merely swappable-in-principle.\n *\n * The session owns its history batch. The text tool has no bottom-sheet panel —\n * the composer *is* its UI — so `ToolPanelHost` never opens one for it, and the\n * session must, or every keystroke would be its own undo entry. Opening it here\n * also fixes the ordering: the batch is open before the draft is created,\n * which it would not be if a parent opened it in its own mount effect (effects\n * run child-first).\n *\n * @experimental\n */\nexport interface TextSessionController {\n /** The layer being edited — a fresh draft, or the one that was selected. */\n layer: Layer | undefined\n /** Whether this session created the layer, which decides blank-Done. */\n kind: 'draft' | 'existing'\n /** Current text. Mirrors the document; drives the input's value. */\n value: string\n /** Replace the text. */\n setValue(next: string): void\n /** The span the composer styles as a whole. */\n span: TextSpan | undefined\n /** Full layer data, for alignment/fill/stroke/shadow controls. */\n data: TextLayerData | undefined\n /** Patch the styled span — font, size, colour, weight, spacing. */\n styleSpan(patch: Partial<TextSpan>): void\n /** Patch layer-level text data — alignment, fill, stroke, shadow, maxWidth. */\n styleText(patch: Partial<TextLayerData>): void\n /** Set a normalized font size, held inside the supported range. */\n setSize(size: number): void\n /**\n * Finish. A draft that ended blank is discarded and records nothing.\n *\n * Returns the committed layer id, or `null` when nothing was kept.\n */\n commit(): string | null\n /** Abandon. Restores the document to exactly its state when the tool opened. */\n cancel(): void\n}\n\n/** Hooks into the composing session — chiefly what to do when it ends. */\nexport interface UseTextSessionOptions {\n /**\n * Edit this layer instead of resolving from the selection. Lets a custom UI\n * request editing for a specific layer — the re-entry API.\n */\n layerId?: string\n /** Called once the session has committed or been discarded. */\n onFinished?: (layerId: string | null) => void\n}\n\n/**\n * Open a text-editing session for the current selection (or `layerId`).\n *\n * Creates its draft on mount so the canvas shows the layer immediately and the\n * caret has something to sit on.\n */\nexport function useTextSession(options: UseTextSessionOptions = {}): TextSessionController {\n const { document, dispatch, profile, selection, select } = useEditor()\n const { layerId: requestedId, onFinished } = options\n\n // Resolved once: what the session is editing must not change under the user\n // because the selection moved.\n const [session] = useState(() =>\n resolveTextSession(document.layers, requestedId ? [requestedId] : selection),\n )\n const [draftId, setDraftId] = useState<string | null>(null)\n const finished = useRef(false)\n /**\n * The selection as it was before the session opened.\n *\n * Rolling the *document* back is not enough: a draft replaces the selection\n * with its own id, so a rollback that clears the selection leaves the editor\n * in a state the user never chose. Captured once, restored on every rollback\n * path — Cancel, blank-draft Done, and unmount.\n */\n const priorSelection = useRef<string[]>([])\n const capturedPrior = useRef(false)\n if (!capturedPrior.current) {\n capturedPrior.current = true\n priorSelection.current = [...selection]\n }\n\n const latest = useRef({ document, dispatch, select, selection, profile })\n latest.current = { document, dispatch, select, selection, profile }\n\n // Open the transaction, then create the draft inside it. Both exactly once:\n // a second draft would be a second layer, and a second batch would leak depth.\n useEffect(() => {\n latest.current.dispatch({ type: 'history/beginBatch', label: 'text' })\n if (session.kind === 'draft') {\n const draft = createTextDraft(latest.current.profile)\n setDraftId(draft.id)\n latest.current.dispatch({ type: 'layer/add', layer: draft })\n latest.current.select([draft.id])\n } else if (session.layerId) {\n // Whole-layer editing cannot address more than one span, so a multi-span\n // layer is collapsed up front — inside the batch, so Cancel reverses it\n // exactly. See `collapseTextSpans` for why.\n const layer = latest.current.document.layers.find((l) => l.id === session.layerId)\n const layerData = layer?.data as TextLayerData | undefined\n if (layerData && needsSpanCollapse(layerData)) {\n latest.current.dispatch({\n type: 'layer/patchData',\n id: session.layerId,\n patch: { spans: collapseTextSpans(layerData).spans },\n })\n }\n }\n return () => {\n // Unmounting without Done or Cancel — a tool switch, a navigation, an\n // unmount mid-typing — must not leave the batch open or the edit applied.\n if (finished.current) return\n finished.current = true\n latest.current.dispatch({ type: 'history/cancelBatch' })\n latest.current.select(priorSelection.current)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n const layerId = session.kind === 'existing' ? session.layerId! : draftId\n const layer = layerId ? document.layers.find((l) => l.id === layerId) : undefined\n const data = layer ? (layer.data as TextLayerData) : undefined\n const span = data ? textSpanOf(data) : undefined\n const value = data ? textValueOf(data) : ''\n\n // Read through refs so the commands keep a stable identity: a composer that\n // re-created its callbacks each keystroke would remount its controls.\n const idRef = useRef<string | null>(null)\n idRef.current = layerId ?? null\n const dataRef = useRef<TextLayerData | undefined>(undefined)\n dataRef.current = data\n\n const patchData = useCallback((patch: Partial<TextLayerData>) => {\n const id = idRef.current\n if (!id) return\n latest.current.dispatch({ type: 'layer/patchData', id, patch: patch as Record<string, unknown> })\n }, [])\n\n const setValue = useCallback(\n (next: string) => {\n const current = dataRef.current\n if (!current) return\n patchData({ spans: patchTextSpan(current, { text: next }).spans })\n },\n [patchData],\n )\n\n const styleSpan = useCallback(\n (patch: Partial<TextSpan>) => {\n const current = dataRef.current\n if (!current) return\n patchData({ spans: patchTextSpan(current, patch).spans })\n },\n [patchData],\n )\n\n const setSize = useCallback(\n (size: number) => styleSpan({ fontSize: clampTextSize(size) }),\n [styleSpan],\n )\n\n const commit = useCallback((): string | null => {\n if (finished.current) return null\n finished.current = true\n const id = idRef.current\n const blank = isBlankText(dataRef.current ? textValueOf(dataRef.current) : '')\n // A blank draft is discarded by cancelling, not by removing and committing:\n // `endBatch` compares opening and closing documents by identity, so\n // add-then-remove still pushes an undo entry that appears to do nothing.\n if (session.kind === 'draft' && blank) {\n latest.current.dispatch({ type: 'history/cancelBatch' })\n latest.current.select(priorSelection.current)\n onFinished?.(null)\n return null\n }\n latest.current.dispatch({ type: 'history/endBatch' })\n onFinished?.(id ?? null)\n return id ?? null\n }, [session.kind, onFinished])\n\n const cancel = useCallback(() => {\n if (finished.current) return\n finished.current = true\n latest.current.dispatch({ type: 'history/cancelBatch' })\n // Restore the whole editor state, not just the document: the session may\n // have moved the selection to its draft.\n latest.current.select(priorSelection.current)\n onFinished?.(null)\n }, [onFinished])\n\n return useMemo(\n () => ({\n layer,\n kind: session.kind,\n value,\n setValue,\n span,\n data,\n styleSpan,\n styleText: patchData,\n setSize,\n commit,\n cancel,\n }),\n [layer, session.kind, value, setValue, span, data, styleSpan, patchData, setSize, commit, cancel],\n )\n}\n","import { useEditor } from '@pictor-sdk/core'\nimport React from 'react'\nimport { ActivityIndicator, Pressable, Text, View } from 'react-native'\nimport { useTheme } from '../theme'\n\n/** What the top bar slot receives: the transaction actions and undo state. */\nexport interface TopBarProps {\n onCancel?: () => void\n onNext?: () => void\n /** true while an export is running (Next shows a spinner). */\n busy?: boolean\n}\n\n/** The default top bar: cancel, undo/redo, and the action that ends the session. */\nexport function TopBar({ onCancel, onNext, busy = false }: TopBarProps) {\n const { canUndo, canRedo, dispatch } = useEditor()\n const theme = useTheme()\n const button = (label: string, enabled: boolean, onPress?: () => void, color?: string) => (\n <Pressable disabled={!enabled} onPress={onPress} style={{ padding: theme.spacing.sm }}>\n <Text\n style={{\n color: enabled ? (color ?? theme.colors.text) : theme.colors.textMuted,\n fontSize: theme.font.size,\n fontWeight: theme.font.weight,\n }}\n >\n {label}\n </Text>\n </Pressable>\n )\n return (\n <View\n style={{\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n paddingHorizontal: theme.spacing.sm,\n backgroundColor: theme.colors.background,\n }}\n >\n {button('Cancel', !!onCancel, onCancel)}\n <View style={{ flexDirection: 'row' }}>\n {button('↺', canUndo, () => dispatch({ type: 'history/undo' }))}\n {button('↻', canRedo, () => dispatch({ type: 'history/redo' }))}\n </View>\n {busy ? (\n <ActivityIndicator color={theme.colors.accent} style={{ padding: theme.spacing.sm }} />\n ) : (\n button('Next', !!onNext, onNext, theme.colors.accent)\n )}\n </View>\n )\n}\n","import { useEditor, useTools } from '@pictor-sdk/core'\nimport React from 'react'\nimport { Pressable, ScrollView, Text, View } from 'react-native'\nimport { useTheme } from '../theme'\n\n/** The toolbar IS profile.tools — rendered from the registry, never hardcoded. */\nexport function ToolRail() {\n const { activeTool, setActiveTool, document, selection, dispatch } = useEditor()\n const tools = useTools()\n const theme = useTheme()\n return (\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{\n gap: theme.spacing.md,\n paddingHorizontal: theme.spacing.md,\n paddingVertical: theme.spacing.md,\n }}\n style={{ flexGrow: 0, backgroundColor: theme.colors.background }}\n >\n {tools.map((tool) => {\n const enabled = tool.isEnabled ? tool.isEnabled({ document, selection }) : true\n const active = activeTool === tool.id\n return (\n <Pressable\n key={tool.id}\n disabled={!enabled}\n onPress={() => {\n if (tool.onActivate) {\n tool.onActivate({ document, dispatch })\n } else {\n setActiveTool(active ? null : tool.id)\n }\n }}\n style={{ width: 72, alignItems: 'center', gap: 6, opacity: enabled ? 1 : 0.4 }}\n >\n <View style={{ width: 46, height: 46, borderRadius: 23, borderWidth: 1, borderColor: active ? theme.colors.accent : theme.colors.textMuted, backgroundColor: active ? theme.colors.surface : 'transparent', alignItems: 'center', justifyContent: 'center' }}>\n <Text style={{ color: active ? theme.colors.accent : theme.colors.text, fontSize: 18 }}>\n {tool.label.slice(0, 1)}\n </Text>\n </View>\n <Text\n style={{\n color: active ? theme.colors.accent : theme.colors.text,\n fontSize: theme.font.sizeSm,\n fontWeight: theme.font.weight,\n }}\n numberOfLines={1}\n >\n {tool.label}\n </Text>\n </Pressable>\n )\n })}\n </ScrollView>\n )\n}\n","import { useEditorStore } from '@pictor-sdk/core'\nimport { useCanvasMetrics } from '@pictor-sdk/skia'\nimport React, { useMemo, useRef } from 'react'\nimport { StyleSheet } from 'react-native'\nimport { Gesture, GestureDetector } from 'react-native-gesture-handler'\nimport Animated from 'react-native-reanimated'\nimport { runOnJS } from 'react-native-worklets'\nimport {\n createGestureController,\n type GestureSnapEvent,\n} from './controller'\n\n/** Overrides forwarded to whichever gesture surface the active tool mounts. */\nexport interface EditorGesturesProps {\n /** Optional haptic hook — fired once per snap engagement. */\n onSnap?: (event: GestureSnapEvent) => void\n}\n\n/**\n * Invisible gesture surface for <EditorCanvas children={…}/>: tap to select,\n * pan/pinch/rotate the selected layer. Recognizers run simultaneously on the\n * UI thread; commits are batched into a single undo step (see controller).\n */\nexport function EditorGestures({ onSnap }: EditorGesturesProps) {\n const store = useEditorStore()\n const metrics = useCanvasMetrics()\n const metricsRef = useRef(metrics)\n metricsRef.current = metrics\n const onSnapRef = useRef(onSnap)\n onSnapRef.current = onSnap\n\n const controller = useMemo(\n () =>\n createGestureController(store, () => metricsRef.current, {\n onSnap: (e) => onSnapRef.current?.(e),\n }),\n // metricsRef/onSnap are read through refs — store identity is the only dep\n [store],\n )\n\n const gesture = useMemo(() => {\n const tap = Gesture.Tap().onEnd((e) => {\n 'worklet'\n runOnJS(controller.tap)(e.x, e.y)\n })\n const pan = Gesture.Pan()\n .minPointers(1)\n .onStart(() => {\n 'worklet'\n runOnJS(controller.begin)()\n })\n .onUpdate((e) => {\n 'worklet'\n runOnJS(controller.setPan)(e.translationX, e.translationY)\n })\n .onFinalize(() => {\n 'worklet'\n runOnJS(controller.end)()\n })\n const pinch = Gesture.Pinch()\n .onStart(() => {\n 'worklet'\n runOnJS(controller.begin)()\n })\n .onUpdate((e) => {\n 'worklet'\n runOnJS(controller.setPinch)(e.scale)\n })\n .onFinalize(() => {\n 'worklet'\n runOnJS(controller.end)()\n })\n const rotate = Gesture.Rotation()\n .onStart(() => {\n 'worklet'\n runOnJS(controller.begin)()\n })\n .onUpdate((e) => {\n 'worklet'\n runOnJS(controller.setRotate)(e.rotation)\n })\n .onFinalize(() => {\n 'worklet'\n runOnJS(controller.end)()\n })\n return Gesture.Race(\n Gesture.Simultaneous(pan, pinch, rotate),\n tap,\n )\n }, [controller])\n\n return (\n <GestureDetector gesture={gesture}>\n <Animated.View style={StyleSheet.absoluteFill} />\n </GestureDetector>\n )\n}\n","import {\n hitTestDocument,\n snapCenter,\n snapRotation,\n type EditorStore,\n type Transform,\n} from '@pictor-sdk/core'\n\n/** The fitted canvas's size in dp, for turning touches into document units. */\nexport interface GestureMetrics {\n /** canvas size in dp (the fitted preview) */\n width: number\n height: number\n}\n\n/** Emitted the moment a gesture snaps — the hook for haptics. */\nexport interface GestureSnapEvent {\n kind: 'rotation' | 'centerX' | 'centerY'\n}\n\n/**\n * Host callbacks a gesture controller may fire.\n *\n * Callbacks rather than behaviour: haptics would mean a native dependency, so\n * the library reports the moment and the host decides what it means.\n */\nexport interface GestureControllerOptions {\n /** e.g. trigger haptics — optional callback, no haptics dependency here. */\n onSnap?: (event: GestureSnapEvent) => void\n}\n\n/**\n * Pure gesture → command translation, shared by the RN gesture wiring and\n * unit tests. Pan/pinch/rotate report cumulative deltas; the controller\n * recomputes the transform from the base captured at gesture start and\n * commits through a history batch so the whole gesture is ONE undo step.\n *\n * DECISION: shared values give 60fps feedback on the UI thread; document\n * commits hop to JS per frame (cheap — one reducer pass at preview scale)\n * inside the batch. True UI-thread document mutation would need a worklet\n * store and is out of scope for v0.1.\n */\nexport function createGestureController(\n store: Pick<EditorStore, 'getState' | 'dispatch' | 'select' | 'registry'>,\n getMetrics: () => GestureMetrics | null,\n options: GestureControllerOptions = {},\n) {\n let active = 0\n let base: Transform | null = null\n let layerId: string | null = null\n let pan = { x: 0, y: 0 }\n let pinch = 1\n let rotate = 0\n const snapState = { rotation: false, centerX: false, centerY: false }\n\n function targetLayerId(): string | null {\n return store.getState().selection[0] ?? null\n }\n\n function begin() {\n if (active === 0) {\n layerId = targetLayerId()\n if (!layerId) return\n const layer = store.getState().document.layers.find((l) => l.id === layerId)\n if (!layer || layer.locked) {\n layerId = null\n return\n }\n base = { ...layer.transform }\n pan = { x: 0, y: 0 }\n pinch = 1\n rotate = 0\n snapState.rotation = snapState.centerX = snapState.centerY = false\n store.dispatch({ type: 'history/beginBatch', label: 'gesture' })\n }\n active++\n }\n\n function fireSnap(kind: GestureSnapEvent['kind'], snapped: boolean) {\n if (snapped && !snapState[kind]) options.onSnap?.({ kind })\n snapState[kind] = snapped\n }\n\n function commit() {\n if (!base || !layerId) return\n const metrics = getMetrics()\n if (!metrics || metrics.width === 0 || metrics.height === 0) return\n\n const rawX = base.x + pan.x / metrics.width\n const rawY = base.y + pan.y / metrics.height\n const rawRotation = base.rotation + rotate\n\n const sx = snapCenter(rawX)\n const sy = snapCenter(rawY)\n const sr = snapRotation(rawRotation)\n fireSnap('centerX', sx.snapped)\n fireSnap('centerY', sy.snapped)\n fireSnap('rotation', sr.snapped)\n\n store.dispatch({\n type: 'layer/transform',\n id: layerId,\n patch: {\n x: sx.value,\n y: sy.value,\n rotation: sr.value,\n scale: Math.max(0.01, base.scale * pinch),\n },\n })\n }\n\n function end() {\n if (active === 0) return\n active--\n if (active === 0) {\n if (layerId) store.dispatch({ type: 'history/endBatch' })\n base = null\n layerId = null\n }\n }\n\n return {\n /** Pan/pinch/rotate lifecycles — call begin/end once per recognizer. */\n begin,\n end,\n setPan(xDp: number, yDp: number) {\n pan = { x: xDp, y: yDp }\n commit()\n },\n setPinch(scale: number) {\n pinch = scale\n commit()\n },\n setRotate(rad: number) {\n rotate = rad\n commit()\n },\n /** Tap in canvas dp → hit-test → select (empty tap clears selection). */\n tap(xDp: number, yDp: number) {\n const metrics = getMetrics()\n if (!metrics) return\n const point = { x: xDp / metrics.width, y: yDp / metrics.height }\n const hit = hitTestDocument(store.getState().document, point, store.registry)\n store.select(hit ? [hit.id] : [])\n },\n /** true while a gesture is in flight (used to mute other UI). */\n isActive: () => active > 0,\n }\n}\n\n/** Turns raw gesture input into layer transforms, with snapping. */\nexport type GestureController = ReturnType<typeof createGestureController>\n","export { Editor, CanvasStage, mergeSlots, type CanvasStageProps, type EditorProps, type EditorSlots } from './Editor'\nexport { TopBar, type TopBarProps } from './components/TopBar'\nexport { ToolRail } from './components/ToolRail'\nexport { ToolPanelHost, resolvePanel } from './ToolPanelHost'\nexport { FilterStrip, useBaseImageLayer } from './panels/FilterStrip'\nexport { useTargetImageLayer } from './panels/useTargetImageLayer'\nexport { AddPhotoPanel } from './panels/AddPhotoPanel'\nexport {\n createAddPhotoController,\n InvalidImageResultError,\n type AddPhotoController,\n type AddPhotoControllerOptions,\n} from './panels/addPhotoController'\nexport { HostCallbacksProvider, useHostCallbacks, type HostCallbacks } from './hostCallbacks'\nexport { AdjustPanel } from './panels/AdjustPanel'\nexport { CropPanel } from './panels/CropPanel'\nexport {\n canvasSizeForAspect,\n centeredCropForAspect,\n radiansToStraighten,\n straightenToRadians,\n STRAIGHTEN_LIMIT,\n} from './panels/cropMath'\nexport { Slider, type SliderProps } from './components/Slider'\nexport { StraightenRuler, type StraightenRulerProps } from './components/StraightenRuler'\nexport { defaultTheme, mergeTheme, useTheme, ThemeContext, type EditorTheme, type PartialTheme } from './theme'\nexport { EditorGestures, type EditorGesturesProps } from './gestures/EditorGestures'\nexport { LayerGestureSurface, type LayerGestureSurfaceProps } from './gestures/LayerGestureSurface'\nexport { InteractionGuides, type InteractionGuidesProps } from './gestures/InteractionGuides'\nexport {\n StoryMediaGestureSurface,\n useBaseMediaLayer,\n type StoryMediaGestureSurfaceProps,\n} from './gestures/StoryMediaGestureSurface'\nexport { resolveGestureSurface, type GestureSurfaceKind } from './gestures/routing'\nexport { MediaPanel } from './panels/MediaPanel'\n// The worklet twins, the slider's detent maths, the built-in panel registry and\n// the composer's keyboard arithmetic stay internal. Unlike the panels and\n// surfaces above — which exist to be picked apart, so their broad surface is\n// deliberate — these describe how one component is wired, and a consumer\n// replacing that component replaces the wiring too. Their tests import by path.\nexport { CropGestureSurface, type CropGestureSurfaceProps } from './gestures/CropGestureSurface'\nexport { CropGrid } from './gestures/CropGrid'\nexport { InteractionProvider, useInteractionState } from './gestures/interactionState'\nexport {\n createGestureController,\n type GestureController,\n type GestureControllerOptions,\n type GestureMetrics,\n type GestureSnapEvent,\n} from './gestures/controller'\n// Convenience re-exports so consumers of the default UI need one import\nexport { POST_PROFILE, STORY_PROFILE } from '@pictor-sdk/core'\nexport {\n TextComposer,\n TextComposerHost,\n type TextComposerProps,\n} from './composer/TextComposer'\nexport {\n useTextSession,\n type TextSessionController,\n type UseTextSessionOptions,\n} from './composer/useTextSession'\nexport { TextPanel } from './panels/TextPanel'\nexport { DrawPanel } from './panels/DrawPanel'\nexport { StickerPanel, type StickerAsset } from './panels/StickerPanel'\nexport { LayersPanel } from './panels/LayersPanel'\nexport { LayoutPanel } from './panels/LayoutPanel'\nexport { layoutCells, cellToTransformPatch, type LayoutCell, type LayoutPreset } from './panels/layoutMath'\nexport { DrawingSurface, DEFAULT_BRUSH } from './gestures/DrawingSurface'\nexport { createDrawController, type BrushConfig, type DrawController } from './gestures/drawController'\nexport { UiStateProvider, useUiState, createUiStateStore, type UiStateStore } from './uiState'\n","import {\n createId,\n useEditor,\n useEditorStore,\n type TextLayerData,\n type TextSpan,\n} from '@pictor-sdk/core'\nimport React from 'react'\nimport { Pressable, ScrollView, Text, TextInput, View } from 'react-native'\nimport { useTheme } from '../theme'\nimport { Slider } from '../components/Slider'\n\nconst SWATCHES = ['#ffffff', '#000000', '#ed4956', '#ffe25c', '#78de85', '#4dc4ff', '#a15fed']\nconst ALIGNS = ['left', 'center', 'right'] as const\nconst FILL_MODES = [undefined, 'solid', 'perLine'] as const\n\n/**\n * Text tab: add a text layer, then edit the selected one — content, font,\n * size, color, alignment, and the fill treatment (solid / per-line\n * @experimental). Editing happens in the panel for v0.2; DECISION:\n * on-canvas edit-in-place needs a native text-input overlay pass, deferred.\n */\nexport function TextPanel() {\n const { document, selection, dispatch, select } = useEditor()\n const store = useEditorStore()\n const theme = useTheme()\n\n const selected = document.layers.find(\n (l) => l.type === 'text' && selection.includes(l.id),\n )\n const data = selected ? (selected.data as TextLayerData) : null\n const span: TextSpan | null = data?.spans[0] ?? null\n\n const addText = () => {\n const id = createId('text')\n dispatch({\n type: 'layer/add',\n layer: {\n id,\n type: 'text',\n transform: { x: 0.5, y: 0.4, scale: 1, rotation: 0 },\n opacity: 1,\n blendMode: 'normal',\n data: {\n spans: [{ text: 'Tap to edit', fontFamily: 'System', fontSize: 0.07, color: '#ffffff' }],\n align: 'center',\n maxWidth: 0.9,\n } satisfies TextLayerData,\n },\n })\n select([id])\n }\n\n const patchSpan = (patch: Partial<TextSpan>) => {\n if (!selected || !span) return\n dispatch({\n type: 'layer/patchData',\n id: selected.id,\n patch: { spans: [{ ...span, ...patch }, ...(data!.spans.slice(1) ?? [])] },\n })\n }\n\n const fonts = ['System', ...store.registry.fonts.map((f) => f.family)]\n\n if (!selected || !span || !data) {\n return (\n <View style={{ backgroundColor: theme.colors.background, padding: theme.spacing.md, alignItems: 'center' }}>\n <Pressable\n onPress={addText}\n style={{\n paddingHorizontal: theme.spacing.lg,\n paddingVertical: theme.spacing.sm,\n borderRadius: theme.radii.md,\n backgroundColor: theme.colors.surface,\n }}\n >\n <Text style={{ color: theme.colors.accent, fontSize: theme.font.size, fontWeight: theme.font.weight }}>\n + Add text\n </Text>\n </Pressable>\n </View>\n )\n }\n\n const cycleAlign = () => {\n const next = ALIGNS[(ALIGNS.indexOf(data.align) + 1) % ALIGNS.length]!\n dispatch({ type: 'layer/patchData', id: selected.id, patch: { align: next } })\n }\n\n const cycleFill = () => {\n const current = data.fill?.mode\n const index = FILL_MODES.indexOf(current as (typeof FILL_MODES)[number])\n const next = FILL_MODES[(index + 1) % FILL_MODES.length]\n dispatch({\n type: 'layer/patchData',\n id: selected.id,\n patch: {\n fill: next\n ? { color: span.color === '#000000' ? '#ffffff' : '#000000', radius: 0.012, padding: 0.012, mode: next }\n : undefined,\n },\n })\n }\n\n return (\n <View style={{ backgroundColor: theme.colors.background }}>\n <View style={{ paddingHorizontal: theme.spacing.md }}>\n <TextInput\n value={span.text}\n onChangeText={(text) => patchSpan({ text })}\n multiline\n placeholder=\"Your text\"\n placeholderTextColor={theme.colors.textMuted}\n style={{\n color: theme.colors.text,\n backgroundColor: theme.colors.surface,\n borderRadius: theme.radii.sm,\n padding: theme.spacing.sm,\n fontSize: theme.font.size,\n }}\n />\n <Slider\n value={span.fontSize}\n min={0.02}\n max={0.2}\n centered={false}\n onStart={() => dispatch({ type: 'history/beginBatch', label: 'font size' })}\n onChange={(fontSize) => patchSpan({ fontSize })}\n onEnd={() => dispatch({ type: 'history/endBatch' })}\n />\n </View>\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{ gap: theme.spacing.sm, paddingHorizontal: theme.spacing.md, alignItems: 'center', paddingBottom: theme.spacing.sm }}\n style={{ flexGrow: 0 }}\n >\n <Pressable onPress={cycleAlign} style={{ padding: theme.spacing.sm }}>\n <Text style={{ color: theme.colors.text, fontWeight: theme.font.weight }}>\n {data.align === 'left' ? '⇤' : data.align === 'center' ? '☰' : '⇥'}\n </Text>\n </Pressable>\n <Pressable onPress={cycleFill} style={{ padding: theme.spacing.sm }}>\n <Text style={{ color: data.fill ? theme.colors.accent : theme.colors.text, fontWeight: theme.font.weight }}>\n {data.fill?.mode === 'perLine' ? 'A⃞⃞' : 'A⃞'}\n </Text>\n </Pressable>\n {fonts.map((family) => (\n <Pressable key={family} onPress={() => patchSpan({ fontFamily: family })} style={{ padding: theme.spacing.sm }}>\n <Text\n style={{\n color: span.fontFamily === family ? theme.colors.accent : theme.colors.textMuted,\n fontSize: theme.font.sizeSm,\n }}\n >\n {family}\n </Text>\n </Pressable>\n ))}\n {SWATCHES.map((color) => (\n <Pressable\n key={color}\n onPress={() => patchSpan({ color })}\n style={{\n width: 24,\n height: 24,\n borderRadius: 12,\n backgroundColor: color,\n borderWidth: span.color === color ? 3 : 1,\n borderColor: span.color === color ? theme.colors.accent : theme.colors.track,\n }}\n />\n ))}\n </ScrollView>\n </View>\n )\n}\n"],"mappings":"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","names":["useEditor","React","useState","View","useRef","createContext","useContext","useRef","jsx","jsx","useRef","useCanvasMetrics","useMemo","useRef","StyleSheet","Gesture","GestureDetector","Animated","runOnJS","useEditor","useRef","useEditor","createContext","useCallback","useContext","useMemo","jsx","Context","value","jsx","useEditor","useCanvasMetrics","useRef","useMemo","Gesture","runOnJS","GestureDetector","Animated","StyleSheet","useEditor","useCanvasMetrics","useMemo","useRef","StyleSheet","Gesture","GestureDetector","Animated","useSharedValue","runOnJS","jsx","useEditor","useCanvasMetrics","useRef","useSharedValue","useMemo","runOnJS","Gesture","GestureDetector","Animated","StyleSheet","React","StyleSheet","jsx","StyleSheet","React","styles","NO_SNAP","useEditor","useEditorStore","useCanvasMetrics","useRenderer","useCallback","useEffect","useMemo","useRef","useState","StyleSheet","Gesture","GestureDetector","Animated","useDerivedValue","useSharedValue","runOnJS","snapRotation","jsx","useEditor","useEditorStore","useCanvasMetrics","useRenderer","useMemo","useState","useEffect","useSharedValue","useDerivedValue","useRef","NO_SNAP","useCallback","runOnJS","Gesture","GestureDetector","Animated","StyleSheet","isSameTransform","useEditor","useCanvasMetrics","useCallback","useEffect","useMemo","useRef","StyleSheet","Gesture","GestureDetector","Animated","useDerivedValue","useSharedValue","withTiming","runOnJS","isSameTransform","jsx","useEditor","useCanvasMetrics","useMemo","useSharedValue","useRef","useEffect","useDerivedValue","useCallback","isSameTransform","withTiming","runOnJS","Gesture","GestureDetector","Animated","StyleSheet","deleteTargetFromProfile","useEditor","useCanvasMetrics","StyleSheet","View","createContext","useContext","jsx","jsxs","useEditor","useCanvasMetrics","deleteTargetFromProfile","View","StyleSheet","useEditor","useEffect","useRef","Pressable","Text","View","useEditor","useEditorStore","useState","Text","View","useMemo","useRef","useState","Text","View","Gesture","GestureDetector","Animated","runOnJS","jsx","jsxs","useState","useRef","useMemo","Gesture","runOnJS","GestureDetector","Animated","View","Text","jsx","jsxs","useEditor","useEditorStore","useState","View","Text","useEditor","useEffect","useMemo","useState","Pressable","Text","View","jsx","jsxs","useEditor","useState","useMemo","useEffect","View","Pressable","Text","useEditor","useState","Pressable","ScrollView","Text","View","jsx","jsxs","useEditor","useState","View","Pressable","Text","ScrollView","cropFitScale","useEditor","useEditorStore","Pressable","ScrollView","Text","View","useMemo","useRef","Text","View","Gesture","GestureDetector","Animated","runOnJS","jsx","jsxs","useRef","useMemo","Gesture","runOnJS","GestureDetector","Animated","View","Text","jsx","jsxs","useEditor","useEditorStore","cropFitScale","View","ScrollView","Pressable","Text","Pressable","ScrollView","Text","View","jsx","jsxs","View","ScrollView","Pressable","Text","useEditor","useRenderer","useEffect","useState","Pressable","ScrollView","Text","View","jsx","jsxs","useEditor","useRenderer","useState","useEffect","View","Text","ScrollView","Pressable","useEditor","Pressable","ScrollView","Text","jsx","useEditor","ScrollView","Pressable","Text","useEditor","Pressable","Text","View","jsx","jsxs","useEditor","View","Text","Pressable","mediaConfigFromProfile","useEditor","preferResolvedSize","useResolvedImageSize","Pressable","Text","View","jsx","jsxs","useEditor","useResolvedImageSize","View","Text","mediaConfigFromProfile","preferResolvedSize","Pressable","isDirectManipulationLayer","useEditor","Pressable","ScrollView","Text","View","jsx","jsxs","useEditor","ScrollView","View","Pressable","Text","isDirectManipulationLayer","useEditor","useState","Pressable","Text","View","jsx","jsxs","useEditor","useState","View","Pressable","Text","createId","useEditor","Pressable","ScrollView","Text","View","jsx","jsxs","useEditor","createId","View","Text","ScrollView","Pressable","needsTiltShift","tiltShiftPatch","useEditor","Pressable","Text","View","jsx","jsxs","MODES","useEditor","needsTiltShift","tiltShiftPatch","View","Pressable","Text","jsx","jsxs","useEditor","useRef","useEffect","View","Pressable","Text","useEditor","useEditorStore","useCallback","useEffect","useMemo","useRef","useState","Pressable","ScrollView","Text","View","useEditor","useCallback","useEffect","useMemo","useRef","useState","layer","jsx","jsxs","SWATCHES","useEditorStore","useEditor","useState","useRef","useMemo","useEffect","useCallback","View","Pressable","Text","ScrollView","useEditor","Pressable","Text","View","jsx","jsxs","useEditor","Pressable","Text","View","useEditor","useTools","Pressable","ScrollView","Text","View","jsx","jsxs","useEditor","useTools","ScrollView","Pressable","View","Text","jsx","jsxs","useEditor","React","useState","View","useEditorStore","useCanvasMetrics","useMemo","useRef","StyleSheet","Gesture","GestureDetector","Animated","runOnJS","hitTestDocument","jsx","useEditorStore","useCanvasMetrics","useRef","useMemo","Gesture","runOnJS","GestureDetector","Animated","StyleSheet","createId","useEditor","useEditorStore","Pressable","ScrollView","Text","TextInput","View","jsx","jsxs","SWATCHES","ALIGNS","FILL_MODES","useEditor","useEditorStore","createId","View","Pressable","Text","TextInput","ScrollView"]}
|
|
1
|
+
{"version":3,"sources":["../src/Editor.tsx","../src/hostCallbacks.tsx","../src/gestures/DrawingSurface.tsx","../src/uiState.tsx","../src/gestures/drawController.ts","../src/gestures/CropGestureSurface.tsx","../src/panels/useTargetImageLayer.ts","../src/gestures/interactionState.tsx","../src/gestures/TiltShiftGestureSurface.tsx","../src/gestures/CropGrid.tsx","../src/gestures/LayerGestureSurface.tsx","../src/gestures/layerGestureWorklet.ts","../src/gestures/StoryMediaGestureSurface.tsx","../src/gestures/mediaGestureWorklet.ts","../src/gestures/settleCoordinator.ts","../src/gestures/transformOwnership.ts","../src/gestures/routing.ts","../src/gestures/InteractionGuides.tsx","../src/theme.ts","../src/ToolPanelHost.tsx","../src/panels/AdjustPanel.tsx","../src/components/Slider.tsx","../src/panels/AddPhotoPanel.tsx","../src/panels/addPhotoController.ts","../src/panels/ColorPanel.tsx","../src/panels/CropPanel.tsx","../src/components/StraightenRuler.tsx","../src/panels/cropMath.ts","../src/panels/DrawPanel.tsx","../src/panels/FilterStrip.tsx","../src/panels/LayoutPanel.tsx","../src/panels/layoutMath.ts","../src/panels/LuxPanel.tsx","../src/panels/MediaPanel.tsx","../src/panels/LayersPanel.tsx","../src/panels/PerspectivePanel.tsx","../src/panels/StickerPanel.tsx","../src/panels/TiltShiftPanel.tsx","../src/composer/TextComposer.tsx","../src/composer/keyboardLayout.ts","../src/composer/useTextSession.ts","../src/components/TopBar.tsx","../src/components/ToolRail.tsx","../src/gestures/EditorGestures.tsx","../src/gestures/controller.ts","../src/index.ts","../src/panels/TextPanel.tsx"],"sourcesContent":["import {\n EditorProvider,\n selectionChromeEnabled,\n useEditor,\n type EditorPlugin,\n type EditorProfile,\n type EditorDocument,\n type ExportSpec,\n type InsertableImage,\n type Size,\n} from '@pictor-sdk/core'\nimport { EditorCanvas } from '@pictor-sdk/skia'\nimport React, { useState, type ComponentType, type ReactNode } from 'react'\nimport { View } from 'react-native'\nimport { GestureHandlerRootView } from 'react-native-gesture-handler'\nimport { HostCallbacksProvider } from './hostCallbacks'\nimport { DrawingSurface } from './gestures/DrawingSurface'\nimport { CropGestureSurface } from './gestures/CropGestureSurface'\nimport { TiltShiftGestureSurface } from './gestures/TiltShiftGestureSurface'\nimport { CropGrid } from './gestures/CropGrid'\nimport { InteractionProvider, useInteractionState } from './gestures/interactionState'\nimport { LayerGestureSurface } from './gestures/LayerGestureSurface'\nimport { StoryMediaGestureSurface } from './gestures/StoryMediaGestureSurface'\nimport { resolveGestureSurface } from './gestures/routing'\nimport { InteractionGuides } from './gestures/InteractionGuides'\nimport { UiStateProvider, useUiState } from './uiState'\nimport { type StickerAsset } from './panels/StickerPanel'\nimport { ThemeContext, mergeTheme, useTheme, type PartialTheme } from './theme'\nimport { ToolPanelHost } from './ToolPanelHost'\nimport { TextComposer, TextComposerHost, type TextComposerProps } from './composer/TextComposer'\nimport { TopBar, type TopBarProps } from './components/TopBar'\nimport { ToolRail } from './components/ToolRail'\n\n/**\n * Every region of the default editor is a slot: pass your own component to\n * replace it, or null to remove it. All slots are built exclusively on the\n * public headless hooks — replacing one can never break the others.\n */\nexport interface EditorSlots {\n TopBar: ComponentType<TopBarProps> | null\n CanvasStage: ComponentType<CanvasStageProps> | null\n ToolRail: ComponentType | null\n ToolPanelHost: ComponentType | null\n /**\n * The full-screen text composer, shown while the `text` tool is active.\n *\n * Replace it to ship your own composition UI without replacing the canvas or\n * the editor; it receives everything the default one gets. `null` removes it,\n * leaving text editing to a host-built surface.\n *\n * @experimental\n */\n TextComposer: ComponentType<TextComposerProps> | null\n}\n\n/** What the canvas slot receives. Children draw over the canvas, in its coordinates. */\nexport interface CanvasStageProps {\n children?: ReactNode\n /** Reported when a layer's image source fails to load. */\n onError?: (error: unknown) => void\n}\n\n/**\n * The canvas plus whichever gesture surface the active tool calls for.\n *\n * Exactly one surface is mounted at a time — precedence lives in\n * `resolveGestureSurface`, not in this JSX — so two recognisers can never\n * arbitrate over the same touch.\n */\nexport function CanvasStage({ children, onError }: CanvasStageProps) {\n const { activeTool, profile } = useEditor()\n const { previews } = useInteractionState()\n const surface = resolveGestureSurface(activeTool)\n return (\n <EditorCanvas\n style={{ flex: 1 }}\n onError={onError}\n previewTransforms={previews}\n showSelectionChrome={selectionChromeEnabled(profile)}\n >\n {/* exactly one surface owns the canvas; precedence is resolveGestureSurface */}\n {surface === 'draw' ? (\n <DrawingSurface />\n ) : surface === 'crop' ? (\n <>\n <CropGestureSurface />\n <CropGrid />\n </>\n ) : surface === 'tilt' ? (\n <TiltShiftGestureSurface />\n ) : surface === 'media' ? (\n <StoryMediaGestureSurface />\n ) : (\n <>\n <LayerGestureSurface />\n <InteractionGuides />\n </>\n )}\n {children}\n </EditorCanvas>\n )\n}\n\n/**\n * What `<Editor>` accepts: a profile, its plugins, a document or a source, and\n * any slots or theme you want to replace.\n */\nexport interface EditorProps {\n profile: EditorProfile\n plugins?: EditorPlugin[]\n /** Image source for a fresh document (or pass initialDocument). */\n source?: unknown\n intrinsic?: Size\n initialDocument?: EditorDocument\n onExport?: (bytes: Uint8Array) => void | Promise<void>\n onCancel?: () => void\n onError?: (error: unknown) => void\n exportSpec?: Partial<ExportSpec>\n slots?: Partial<EditorSlots>\n theme?: PartialTheme\n /** Host-supplied sticker catalog for the built-in sticker panel. */\n stickers?: StickerAsset[]\n /**\n * Asked to supply photos when the user presses the add-photo control.\n *\n * The library never touches the gallery: permissions, the picker and any\n * HEIC/HEIF transcoding stay with the host, which is what keeps it free of\n * Expo and of native code. Resolve `null` or `[]` for cancellation, which\n * adds nothing. Omit it and the control renders unavailable rather than\n * throwing.\n *\n * @experimental\n */\n requestImages?: () => Promise<readonly InsertableImage[] | null>\n}\n\n/** Merge slot overrides over the defaults. Pure — unit tested. */\nexport function mergeSlots(overrides?: Partial<EditorSlots>): EditorSlots {\n return {\n TopBar,\n CanvasStage,\n ToolRail,\n ToolPanelHost,\n TextComposer,\n ...overrides,\n }\n}\n\nfunction EditorBody({\n slots,\n onExport,\n onCancel,\n onError,\n exportSpec,\n stickers,\n}: Pick<EditorProps, 'onExport' | 'onCancel' | 'onError' | 'exportSpec' | 'stickers'> & {\n slots: EditorSlots\n}) {\n const { export: exportDoc, activeTool } = useEditor()\n const { layerDragActive } = useInteractionState()\n const [, setStickers] = useUiState<StickerAsset[]>('stickers', [])\n React.useEffect(() => {\n if (stickers) setStickers(stickers)\n }, [stickers, setStickers])\n const theme = useTheme()\n const [busy, setBusy] = useState(false)\n\n const handleNext = onExport\n ? async () => {\n setBusy(true)\n try {\n const bytes = await exportDoc(exportSpec)\n await onExport(bytes)\n } catch (error) {\n onError?.(error)\n } finally {\n setBusy(false)\n }\n }\n : undefined\n\n const {\n TopBar: Top,\n CanvasStage: Stage,\n ToolRail: Rail,\n ToolPanelHost: PanelHost,\n TextComposer: Composer,\n } = slots\n // The composer is full-screen and owns the whole interaction, so the ordinary\n // chrome and the tool panel stand down while it is up rather than competing\n // with it for the keyboard and for taps.\n const composing = activeTool === 'text' && Composer !== null\n // While a layer is being dragged the editing chrome gets out of the way, so\n // the canvas and the delete target are all that is on screen.\n //\n // It is hidden with opacity rather than unmounted on purpose: unmounting\n // would hand the freed space to the canvas, which resizes it mid-gesture and\n // moves the ground under the interaction. Keeping the boxes in the layout\n // holds the canvas metrics still for the whole drag.\n const chrome = !layerDragActive\n const hidden = { opacity: chrome ? 1 : 0 }\n const hits = chrome ? 'auto' : ('none' as const)\n return (\n // GestureDetector requires a GestureHandlerRootView ancestor; providing it\n // here means consumers never have to know (nesting under an app-level one\n // is harmless).\n <GestureHandlerRootView style={{ flex: 1 }}>\n <View style={{ flex: 1, backgroundColor: theme.colors.background }}>\n {Top && !composing ? (\n <View style={hidden} pointerEvents={hits}>\n <Top onCancel={onCancel} onNext={handleNext} busy={busy} />\n </View>\n ) : null}\n {Stage ? <Stage onError={onError} /> : null}\n {PanelHost && !composing ? (\n <View style={hidden} pointerEvents={hits}>\n <PanelHost />\n </View>\n ) : null}\n {Rail && !activeTool ? (\n <View style={hidden} pointerEvents={hits}>\n <Rail />\n </View>\n ) : null}\n {composing && Composer ? <TextComposerHost Composer={Composer} /> : null}\n </View>\n </GestureHandlerRootView>\n )\n}\n\n/**\n * The batteries-included editor. `<Editor profile={POST_PROFILE} … />` gives\n * the full IG-style flow; every part is replaceable via `slots`.\n */\nexport function Editor({\n profile,\n plugins,\n source,\n intrinsic,\n initialDocument,\n onExport,\n onCancel,\n onError,\n exportSpec,\n slots,\n theme,\n stickers,\n requestImages,\n}: EditorProps) {\n return (\n <EditorProvider\n profile={profile}\n plugins={plugins}\n source={source}\n intrinsic={intrinsic}\n initialDocument={initialDocument}\n >\n <ThemeContext.Provider value={mergeTheme(theme)}>\n <UiStateProvider>\n <HostCallbacksProvider value={{ requestImages, onError }}>\n <InteractionProvider>\n <EditorBody\n slots={mergeSlots(slots)}\n onExport={onExport}\n onCancel={onCancel}\n onError={onError}\n exportSpec={exportSpec}\n stickers={stickers}\n />\n </InteractionProvider>\n </HostCallbacksProvider>\n </UiStateProvider>\n </ThemeContext.Provider>\n </EditorProvider>\n )\n}\n","import { type InsertableImage } from '@pictor-sdk/core'\nimport React, { createContext, useContext, useRef } from 'react'\n\n/**\n * Callbacks the host supplies to `<Editor>` that panels deep in the tree need.\n *\n * Held in a **ref** rather than state. A callback prop is usually an inline\n * arrow recreated every render, so storing it in state would notify on every\n * render and re-render forever; consumers read `.current` at call time instead\n * and never re-render because the host re-created its closure.\n *\n * @experimental\n */\nexport interface HostCallbacks {\n /**\n * Asked to supply photos when the user presses the add-photo control.\n *\n * The library never touches the gallery itself: permissions, the picker and\n * any HEIC/HEIF transcoding are the host's, which is what keeps the library\n * free of Expo and of native code. Resolve `null` or `[]` for cancellation.\n */\n requestImages?: () => Promise<readonly InsertableImage[] | null>\n /** Where a failed request is reported. */\n onError?: (error: unknown) => void\n}\n\nconst Context = createContext<{ current: HostCallbacks } | null>(null)\n\n/**\n * Makes the host's callbacks reachable from panels deep in the tree.\n *\n * Mounted by `<Editor>`; a host composing its own editor from slots mounts it\n * itself, or omits it and the controls render unavailable.\n *\n * @experimental\n */\nexport function HostCallbacksProvider({\n value,\n children,\n}: {\n value: HostCallbacks\n children?: React.ReactNode\n}) {\n const ref = useRef<HostCallbacks>(value)\n // Updated during render on purpose: a panel that calls one of these in the\n // same commit must see the latest, and an effect would be a frame late.\n ref.current = value\n return <Context.Provider value={ref}>{children}</Context.Provider>\n}\n\n/**\n * The host's callbacks, as a stable ref.\n *\n * Returns an empty set outside an `<Editor>` rather than throwing — a panel\n * rendered standalone should degrade to \"unavailable\", not crash.\n *\n * @experimental\n */\nexport function useHostCallbacks(): { current: HostCallbacks } {\n const fallback = useRef<HostCallbacks>({})\n return useContext(Context) ?? fallback\n}\n","import { useEditor, useEditorStore } from '@pictor-sdk/core'\nimport { samplePixelColor, useCanvasMetrics, useRenderer } from '@pictor-sdk/skia'\nimport React, { useMemo, useRef } from 'react'\nimport { StyleSheet } from 'react-native'\nimport { Gesture, GestureDetector } from 'react-native-gesture-handler'\nimport Animated from 'react-native-reanimated'\nimport { runOnJS } from 'react-native-worklets'\nimport { useUiState } from '../uiState'\nimport { createDrawController, type BrushConfig } from './drawController'\n\n/** The brush a drawing session starts with. */\nexport const DEFAULT_BRUSH: BrushConfig = { brush: 'pen', color: '#ffffff', width: 0.012 }\n\n/**\n * Freehand drawing capture, active while the draw tool is open. In\n * eyedropper mode a tap samples the rendered pixel color into the brush.\n */\nexport function DrawingSurface() {\n const store = useEditorStore()\n const { document } = useEditor()\n const renderer = useRenderer()\n const metrics = useCanvasMetrics()\n const metricsRef = useRef(metrics)\n metricsRef.current = metrics\n const [brush, setBrush] = useUiState<BrushConfig>('draw.brush', DEFAULT_BRUSH)\n const [eyedropper, setEyedropper] = useUiState('draw.eyedropper', false)\n const brushRef = useRef(brush)\n brushRef.current = brush\n const stateRef = useRef({ eyedropper, document, setBrush, setEyedropper })\n stateRef.current = { eyedropper, document, setBrush, setEyedropper }\n\n const controller = useMemo(\n () => createDrawController(store, () => metricsRef.current, () => brushRef.current),\n [store],\n )\n\n const gesture = useMemo(() => {\n const sample = async (x: number, y: number) => {\n const m = metricsRef.current\n const s = stateRef.current\n if (!m || !s.eyedropper) return\n const color = await samplePixelColor(renderer, s.document, {\n x: x / m.width,\n y: y / m.height,\n })\n if (color) s.setBrush({ ...brushRef.current, color })\n s.setEyedropper(false)\n }\n const beginOrSample = (x: number, y: number) => {\n if (stateRef.current.eyedropper) {\n void sample(x, y)\n } else {\n controller.begin(x, y)\n }\n }\n return Gesture.Pan()\n .minDistance(0)\n .onStart((e) => {\n 'worklet'\n runOnJS(beginOrSample)(e.x, e.y)\n })\n .onUpdate((e) => {\n 'worklet'\n runOnJS(controller.move)(e.x, e.y)\n })\n .onFinalize(() => {\n 'worklet'\n runOnJS(controller.end)()\n })\n }, [controller, renderer])\n\n return (\n <GestureDetector gesture={gesture}>\n <Animated.View style={StyleSheet.absoluteFill} />\n </GestureDetector>\n )\n}\n","import React, { createContext, useCallback, useContext, useRef, useSyncExternalStore } from 'react'\n\n/**\n * A tiny shared key/value store for panel ↔ canvas coordination (brush\n * config, sticker catalogs, eyedropper mode). Ephemeral — never touches the\n * document or history.\n */\nexport interface UiStateStore {\n get<T>(key: string, fallback: T): T\n set(key: string, value: unknown): void\n subscribe(listener: () => void): () => void\n}\n\n/** A scratch store for UI state that is neither document nor history. */\nexport function createUiStateStore(): UiStateStore {\n const values = new Map<string, unknown>()\n const listeners = new Set<() => void>()\n return {\n get: <T,>(key: string, fallback: T) =>\n (values.has(key) ? (values.get(key) as T) : fallback),\n set(key, value) {\n values.set(key, value)\n for (const l of [...listeners]) l()\n },\n subscribe(listener) {\n listeners.add(listener)\n return () => listeners.delete(listener)\n },\n }\n}\n\nconst UiStateContext = createContext<UiStateStore | null>(null)\n\n/**\n * Holds ephemeral panel state — which tab is open, which swatch is selected.\n *\n * Deliberately outside the document: none of it should be serialized, undoable,\n * or survive the editor closing.\n */\nexport function UiStateProvider({ children }: { children?: React.ReactNode }) {\n const ref = useRef<UiStateStore | null>(null)\n if (!ref.current) ref.current = createUiStateStore()\n return <UiStateContext.Provider value={ref.current}>{children}</UiStateContext.Provider>\n}\n\n/** Read and write one key of the ephemeral UI state. Throws outside an `<Editor>`. */\nexport function useUiState<T>(key: string, fallback: T): [T, (value: T) => void] {\n const store = useContext(UiStateContext)\n if (!store) throw new Error('useUiState must be used inside <Editor> (UiStateProvider)')\n const value = useSyncExternalStore(\n store.subscribe,\n () => store.get(key, fallback),\n () => store.get(key, fallback),\n )\n const set = useCallback((v: T) => store.set(key, v), [store, key])\n return [value, set]\n}\n","import { createId, type EditorStore, type Stroke } from '@pictor-sdk/core'\nimport { type GestureMetrics } from './controller'\n\n/** The active brush: kind, colour and width. Width is a fraction of document width. */\nexport interface BrushConfig {\n brush: Stroke['brush']\n color: string\n /** 0..1 of document width */\n width: number\n}\n\n/**\n * Pure drawing controller: converts a pan gesture into a stroke on the\n * top-most draw layer (created on first use), committed as ONE undo step.\n * Live feedback comes from patching the stroke into the document on every\n * move inside the history batch.\n */\nexport function createDrawController(\n store: Pick<EditorStore, 'getState' | 'dispatch'>,\n getMetrics: () => GestureMetrics | null,\n getBrush: () => BrushConfig,\n) {\n let drawing = false\n let layerId: string | null = null\n let points: Stroke['points'] = []\n let baseStrokes: Stroke[] = []\n\n function toDocPoint(xDp: number, yDp: number) {\n const metrics = getMetrics()\n if (!metrics || metrics.width === 0 || metrics.height === 0) return null\n return { x: xDp / metrics.width, y: yDp / metrics.height }\n }\n\n function ensureDrawLayer(): string {\n const doc = store.getState().document\n for (let i = doc.layers.length - 1; i >= 0; i--) {\n const layer = doc.layers[i]!\n if (layer.type === 'draw' && !layer.locked && !layer.hidden) return layer.id\n }\n const id = createId('draw')\n store.dispatch({\n type: 'layer/add',\n layer: {\n id,\n type: 'draw',\n transform: { x: 0.5, y: 0.5, scale: 1, rotation: 0 },\n opacity: 1,\n blendMode: 'normal',\n data: { strokes: [] },\n },\n })\n return id\n }\n\n function currentStroke(): Stroke {\n const brush = getBrush()\n return { points, color: brush.color, width: brush.width, brush: brush.brush }\n }\n\n function patch() {\n if (!layerId) return\n store.dispatch({\n type: 'layer/patchData',\n id: layerId,\n patch: { strokes: [...baseStrokes, currentStroke()] },\n })\n }\n\n return {\n begin(xDp: number, yDp: number) {\n const point = toDocPoint(xDp, yDp)\n if (!point || drawing) return\n drawing = true\n store.dispatch({ type: 'history/beginBatch', label: 'draw' })\n layerId = ensureDrawLayer()\n const layer = store.getState().document.layers.find((l) => l.id === layerId)\n baseStrokes = (layer?.data as { strokes?: Stroke[] } | undefined)?.strokes ?? []\n points = [point]\n patch()\n },\n move(xDp: number, yDp: number) {\n if (!drawing) return\n const point = toDocPoint(xDp, yDp)\n if (!point) return\n const last = points[points.length - 1]\n // drop sub-half-percent movements to keep strokes light\n if (last && Math.hypot(point.x - last.x, point.y - last.y) < 0.003) return\n points = [...points, point]\n patch()\n },\n end() {\n if (!drawing) return\n drawing = false\n store.dispatch({ type: 'history/endBatch' })\n layerId = null\n points = []\n baseStrokes = []\n },\n isDrawing: () => drawing,\n }\n}\n\n/** Accumulates touch points into strokes and commits them to the document. */\nexport type DrawController = ReturnType<typeof createDrawController>\n","import {\n clampCropTransform,\n cropFitScale,\n cropPanBounds,\n focalZoomTransform,\n type ImageLayerData,\n type Transform,\n} from '@pictor-sdk/core'\nimport { useCanvasMetrics } from '@pictor-sdk/skia'\nimport React, { useEffect, useMemo, useRef } from 'react'\nimport { StyleSheet } from 'react-native'\nimport { Gesture, GestureDetector } from 'react-native-gesture-handler'\nimport Animated, { useDerivedValue, useSharedValue, withTiming } from 'react-native-reanimated'\nimport { runOnJS } from 'react-native-worklets'\nimport { useTargetImageLayer } from '../panels/useTargetImageLayer'\nimport { useEditor } from '@pictor-sdk/core'\nimport { useInteractionState } from './interactionState'\n\n/** Overrides for crop gestures, defaulting to the profile's interaction settings. */\nexport interface CropGestureSurfaceProps {\n /** Override profile crop fit for this surface. */\n fit?: 'contain' | 'cover'\n maxScale?: number\n /** Enable free two-finger rotation; disabled by the default Post profile. */\n rotationEnabled?: boolean\n /** Optional host haptic/motion callback. */\n onInteractionChange?: (active: boolean) => void\n}\n\n/**\n * Fixed-viewport photo crop gestures. Pan and focal-point pinch run as shared\n * values on the UI thread; one normalized transform is committed on release.\n */\nexport function CropGestureSurface({ fit, maxScale, rotationEnabled, onInteractionChange }: CropGestureSurfaceProps) {\n const { document, dispatch, profile } = useEditor()\n const layer = useTargetImageLayer()\n const metrics = useCanvasMetrics()\n const interaction = useInteractionState()\n const config = profile.interaction?.crop\n const source = (layer?.data as ImageLayerData | undefined)?.intrinsic\n const resolvedFit = fit ?? config?.fit ?? 'contain'\n const resolvedMax = maxScale ?? config?.maxScale ?? 8\n const resolvedRotation = rotationEnabled ?? config?.rotationEnabled ?? false\n\n const liveX = useSharedValue(layer?.transform.x ?? 0.5)\n const liveY = useSharedValue(layer?.transform.y ?? 0.5)\n const liveScale = useSharedValue(layer?.transform.scale ?? 1)\n // Seed from React state directly; reading shared values during render trips\n // Reanimated strict mode on real devices.\n const baseX = useSharedValue(layer?.transform.x ?? 0.5)\n const baseY = useSharedValue(layer?.transform.y ?? 0.5)\n const baseScale = useSharedValue(layer?.transform.scale ?? 1)\n const liveRotation = useSharedValue(layer?.transform.rotation ?? 0)\n const baseRotation = useSharedValue(layer?.transform.rotation ?? 0)\n const panX = useSharedValue(0)\n const panY = useSharedValue(0)\n const pinchScale = useSharedValue(1)\n const rotateDelta = useSharedValue(0)\n const focalX = useSharedValue(0.5)\n const focalY = useSharedValue(0.5)\n const activeRecognizers = useSharedValue(0)\n const commitTimer = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n const minScale = source\n ? cropFitScale(source, document.size, resolvedFit, layer?.transform.rotation ?? 0)\n : 1\n\n useEffect(() => {\n if (!layer) return\n liveX.value = layer.transform.x\n liveY.value = layer.transform.y\n liveScale.value = layer.transform.scale\n liveRotation.value = layer.transform.rotation\n // Shared-value identities are stable; only committed scalar values resync them.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [layer?.transform.x, layer?.transform.y, layer?.transform.scale, layer?.transform.rotation])\n\n const previewTransform = useDerivedValue(() => {\n const ratio = liveScale.value / Math.max(baseScale.value, 0.000001)\n return [\n { translateX: liveX.value * document.size.width },\n { translateY: liveY.value * document.size.height },\n { rotate: liveRotation.value - baseRotation.value },\n { scale: ratio },\n { translateX: -baseX.value * document.size.width },\n { translateY: -baseY.value * document.size.height },\n ]\n }, [document.size.width, document.size.height])\n\n useEffect(() => {\n if (!layer) return\n interaction.setPreview({ layerId: layer.id, transform: previewTransform })\n return () => interaction.setPreview(null)\n // Register by layer identity; crop-active context changes must not replace it.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [layer?.id, previewTransform, interaction.setPreview])\n\n const setActive = (active: boolean) => {\n interaction.setCropActive(active)\n onInteractionChange?.(active)\n }\n\n const commit = (candidate: Transform) => {\n if (!layer || !source) return\n if (commitTimer.current) clearTimeout(commitTimer.current)\n const settledMinScale = cropFitScale(source, document.size, resolvedFit, candidate.rotation)\n const bounds = cropPanBounds(source, document.size, candidate.scale, settledMinScale, resolvedMax, candidate.rotation)\n const settled = clampCropTransform(candidate, bounds)\n liveX.value = withTiming(settled.x, { duration: 160 })\n liveY.value = withTiming(settled.y, { duration: 160 })\n liveScale.value = withTiming(settled.scale, { duration: 160 })\n liveRotation.value = withTiming(settled.rotation, { duration: 160 })\n commitTimer.current = setTimeout(() => {\n dispatch({\n type: 'layer/transform',\n id: layer.id,\n patch: {\n x: settled.x,\n y: settled.y,\n scale: settled.scale,\n ...(resolvedRotation ? { rotation: settled.rotation } : {}),\n },\n })\n baseX.value = settled.x\n baseY.value = settled.y\n baseScale.value = settled.scale\n baseRotation.value = settled.rotation\n liveX.value = settled.x\n liveY.value = settled.y\n liveScale.value = settled.scale\n liveRotation.value = settled.rotation\n setActive(false)\n }, 165)\n }\n\n const toggleZoom = (xDp: number, yDp: number) => {\n if (!layer || !source || !metrics) return\n baseX.value = layer.transform.x\n baseY.value = layer.transform.y\n baseScale.value = layer.transform.scale\n baseRotation.value = layer.transform.rotation\n liveX.value = layer.transform.x\n liveY.value = layer.transform.y\n liveScale.value = layer.transform.scale\n liveRotation.value = layer.transform.rotation\n setActive(true)\n const atMinimum = Math.abs(layer.transform.scale - minScale) < 0.01\n const targetScale = atMinimum\n ? Math.min(resolvedMax, minScale * (config?.doubleTapScale ?? 2))\n : minScale\n commit(focalZoomTransform(layer.transform, targetScale, {\n x: xDp / metrics.width,\n y: yDp / metrics.height,\n }))\n }\n\n const gesture = useMemo(() => {\n if (!metrics || !source || !layer) return Gesture.Tap()\n const begin = () => {\n 'worklet'\n if (activeRecognizers.value === 0) {\n baseX.value = liveX.value\n baseY.value = liveY.value\n baseScale.value = liveScale.value\n baseRotation.value = liveRotation.value\n panX.value = 0\n panY.value = 0\n pinchScale.value = 1\n rotateDelta.value = 0\n runOnJS(setActive)(true)\n }\n activeRecognizers.value += 1\n }\n const updateLive = () => {\n 'worklet'\n const rotation = baseRotation.value + rotateDelta.value\n const naturalWidth = document.size.width\n const naturalHeight = document.size.width * (source.height / source.width)\n const cos = Math.abs(Math.cos(rotation))\n const sin = Math.abs(Math.sin(rotation))\n const rotatedWidth = naturalWidth * cos + naturalHeight * sin\n const rotatedHeight = naturalWidth * sin + naturalHeight * cos\n const widthScale = document.size.width / rotatedWidth\n const heightScale = document.size.height / rotatedHeight\n const dynamicMin = resolvedFit === 'contain' ? Math.min(widthScale, heightScale) : Math.max(widthScale, heightScale)\n const rawScale = baseScale.value * pinchScale.value\n const resistance = config?.resistance ?? 0.35\n const scale = rawScale < dynamicMin\n ? dynamicMin - (dynamicMin - rawScale) * resistance\n : rawScale > resolvedMax\n ? resolvedMax + (rawScale - resolvedMax) * resistance\n : rawScale\n const ratio = scale / Math.max(baseScale.value, 0.000001)\n const zoomX = focalX.value - (focalX.value - baseX.value) * ratio\n const zoomY = focalY.value - (focalY.value - baseY.value) * ratio\n liveRotation.value = rotation\n const dx = Math.max(0, (rotatedWidth * scale - document.size.width) / (2 * document.size.width))\n const dy = Math.max(0, (rotatedHeight * scale - document.size.height) / (2 * document.size.height))\n liveScale.value = scale\n const rawX = zoomX + panX.value\n const rawY = zoomY + panY.value\n const minX = 0.5 - dx\n const maxX = 0.5 + dx\n const minY = 0.5 - dy\n const maxY = 0.5 + dy\n liveX.value = rawX < minX ? minX - (minX - rawX) * resistance : rawX > maxX ? maxX + (rawX - maxX) * resistance : rawX\n liveY.value = rawY < minY ? minY - (minY - rawY) * resistance : rawY > maxY ? maxY + (rawY - maxY) * resistance : rawY\n }\n const finish = () => {\n 'worklet'\n activeRecognizers.value = Math.max(0, activeRecognizers.value - 1)\n if (activeRecognizers.value === 0) {\n runOnJS(commit)({\n x: liveX.value,\n y: liveY.value,\n scale: liveScale.value,\n rotation: liveRotation.value,\n ...(layer.transform.anchor ? { anchor: layer.transform.anchor } : {}),\n ...(layer.transform.flipX !== undefined ? { flipX: layer.transform.flipX } : {}),\n ...(layer.transform.flipY !== undefined ? { flipY: layer.transform.flipY } : {}),\n })\n }\n }\n const pan = Gesture.Pan()\n .minPointers(1)\n .onStart(begin)\n .onUpdate((event) => {\n 'worklet'\n panX.value = event.translationX / metrics.width\n panY.value = event.translationY / metrics.height\n updateLive()\n })\n .onFinalize(finish)\n const pinch = Gesture.Pinch()\n .onStart(begin)\n .onUpdate((event) => {\n 'worklet'\n pinchScale.value = event.scale\n focalX.value = event.focalX / metrics.width\n focalY.value = event.focalY / metrics.height\n updateLive()\n })\n .onFinalize(finish)\n const rotate = Gesture.Rotation()\n .enabled(resolvedRotation)\n .onStart(begin)\n .onUpdate((event) => {\n 'worklet'\n rotateDelta.value = event.rotation\n updateLive()\n })\n .onFinalize(finish)\n const doubleTap = Gesture.Tap()\n .numberOfTaps(2)\n .onEnd((event) => {\n 'worklet'\n runOnJS(toggleZoom)(event.x, event.y)\n })\n return Gesture.Exclusive(doubleTap, Gesture.Simultaneous(pan, pinch, rotate))\n // Gesture worklets read stable shared values; recreate only for geometry/config changes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [metrics, source, layer, resolvedFit, resolvedMax, resolvedRotation, minScale, document.size.width, document.size.height, config?.resistance, config?.doubleTapScale])\n\n if (!layer) return null\n return (\n <GestureDetector gesture={gesture}>\n <Animated.View style={StyleSheet.absoluteFill} />\n </GestureDetector>\n )\n}\n","import {\n pinnedTargetImageLayer,\n resolveTargetImageLayer,\n useEditor,\n type Layer,\n} from '@pictor-sdk/core'\nimport { useRef } from 'react'\n\n/**\n * The image an open panel edits, **pinned for the whole session**.\n *\n * Resolved once, from the selection at the moment the panel mounts, and then\n * held by id. `ToolPanelHost` mounts a fresh panel per tool activation, so a\n * mount *is* a session, and closing and reopening resolves again.\n *\n * The pinning is the point. Re-resolving each render would let a selection\n * change mid-drag redirect the next slider movement to a different photo — an\n * edit landing silently on the wrong image, which is worse than an edit that\n * does nothing. So when the target is deleted, locked or hidden mid-session\n * this returns `null` and the panel disables its controls; it never quietly\n * falls back to the base.\n *\n * `useBaseImageLayer` is unchanged and still means *the base photo*. Use it\n * where a capability is genuinely base-only — Story media layout, the derived\n * background — rather than by inertia.\n *\n * @experimental\n */\nexport function useTargetImageLayer(): Layer | null {\n const { document, selection } = useEditor()\n const pinned = useRef<string | null>(null)\n\n // Resolved on the first render of this mount and never again. A ref rather\n // than an effect: an effect would leave the first render targeting nothing,\n // and a panel that renders once with no target flashes disabled controls.\n if (pinned.current === null) {\n pinned.current = resolveTargetImageLayer(document, selection)?.id ?? null\n }\n\n return pinnedTargetImageLayer(document, pinned.current) ?? null\n}\n","import { NO_SNAP, type LayerSnapState } from '@pictor-sdk/core'\nimport { type PreviewLayerTransform } from '@pictor-sdk/skia'\nimport React, { createContext, useCallback, useContext, useMemo, useState } from 'react'\n\n/**\n * Transient interaction state shared between the gesture surfaces and the\n * chrome. None of it is part of the document: it never reaches history,\n * serialization or export.\n *\n * Per-frame transforms stay on the UI thread as shared values (`previews`).\n * Only the discrete flags below cross to the JS thread, and only when they\n * actually change — a drag starting, a guide engaging, the delete target being\n * entered — so the render path is untouched while fingers move.\n */\nexport interface InteractionState {\n previews: readonly PreviewLayerTransform[]\n setPreview(preview: PreviewLayerTransform | null): void\n cropActive: boolean\n setCropActive(active: boolean): void\n /** True while a layer is being dragged/scaled/rotated. */\n layerDragActive: boolean\n setLayerDragActive(active: boolean): void\n /** True while the dragged layer is over the delete target. */\n overDeleteTarget: boolean\n setOverDeleteTarget(over: boolean): void\n /** Which alignment guides are currently engaged. */\n snap: LayerSnapState\n setSnap(snap: LayerSnapState): void\n}\n\nconst Context = createContext<InteractionState | null>(null)\n\n/**\n * Shares the in-flight interaction between the gesture surfaces and the canvas.\n *\n * How a live preview transform reaches the renderer without going through the\n * document — which would mean dispatching every frame.\n */\nexport function InteractionProvider({ children }: { children?: React.ReactNode }) {\n const [preview, setPreviewValue] = useState<PreviewLayerTransform | null>(null)\n const [cropActive, setCropActive] = useState(false)\n const [layerDragActive, setLayerDragActive] = useState(false)\n const [overDeleteTarget, setOverDeleteTarget] = useState(false)\n const [snap, setSnapValue] = useState<LayerSnapState>(NO_SNAP)\n\n const setPreview = useCallback((value: PreviewLayerTransform | null) => setPreviewValue(value), [])\n // identity-stable so worklets can call it through runOnJS without re-creating\n const setSnap = useCallback((value: LayerSnapState) => {\n setSnapValue((current) =>\n current.centerX === value.centerX &&\n current.centerY === value.centerY &&\n current.rotation === value.rotation\n ? current\n : value,\n )\n }, [])\n\n const value = useMemo(\n () => ({\n previews: preview ? [preview] : [],\n setPreview,\n cropActive,\n setCropActive,\n layerDragActive,\n setLayerDragActive,\n overDeleteTarget,\n setOverDeleteTarget,\n snap,\n setSnap,\n }),\n [preview, setPreview, cropActive, layerDragActive, overDeleteTarget, snap, setSnap],\n )\n return <Context.Provider value={value}>{children}</Context.Provider>\n}\n\n/** The current interaction. Throws outside an `<Editor>`, where there is none. */\nexport function useInteractionState(): InteractionState {\n const value = useContext(Context)\n if (!value) throw new Error('interaction components must be used inside <Editor>')\n return value\n}\n","import {\n moveTiltCenter,\n needsTiltShift,\n rotateTiltBand,\n scaleTiltRadius,\n tiltShiftPatch,\n useEditor,\n type ImageLayerData,\n type TiltShift,\n} from '@pictor-sdk/core'\nimport { useCanvasMetrics } from '@pictor-sdk/skia'\nimport React, { useMemo, useRef } from 'react'\nimport { StyleSheet } from 'react-native'\nimport { Gesture, GestureDetector } from 'react-native-gesture-handler'\nimport Animated, { useAnimatedStyle, useSharedValue } from 'react-native-reanimated'\nimport { runOnJS } from 'react-native-worklets'\nimport { useTargetImageLayer } from '../panels/useTargetImageLayer'\n\n/**\n * Placing the focus region: drag to move it, pinch to size it, twist to turn a\n * band.\n *\n * **Why the blur does not follow the finger.** The focus geometry lives in the\n * document and the shader reads it from there, so updating it per frame would\n * mean dispatching per frame — exactly the React-state-per-frame rule this\n * codebase forbids. Instead the gesture drives a **transient indicator**\n * computed entirely on the UI thread, and commits one normalized value on\n * release inside the tool's batch. That is also what the research pass measured\n * on the reference implementation: no focus ring is drawn persistently, and the\n * indicator appears only during interaction.\n *\n * Composition follows the media surface's rules: `Simultaneous(pan, pinch,\n * rotate)`, never `Exclusive` against a tap — an `Exclusive` gate makes every\n * drag wait for a tap to fail first, which is what made the story surface feel\n * laggy. The origin is captured once when the first recogniser activates, so a\n * second finger landing mid-gesture cannot re-base the interaction on a value\n * it is itself changing.\n */\nexport function TiltShiftGestureSurface() {\n const { dispatch } = useEditor()\n const layer = useTargetImageLayer()\n const metrics = useCanvasMetrics()\n const tilt = (layer?.data as ImageLayerData | undefined)?.tiltShift\n const active = needsTiltShift(tilt)\n\n // The value the whole interaction is measured from. A ref, not state: it is\n // read by the commit on the JS thread and never rendered.\n const origin = useRef<TiltShift | null>(null)\n const live = useRef<TiltShift | null>(null)\n live.current = active ? tilt! : null\n\n const width = metrics?.width ?? 0\n const height = metrics?.height ?? 0\n\n // Origin geometry in canvas dp, mirrored so the indicator needs no JS.\n const oX = useSharedValue(0)\n const oY = useSharedValue(0)\n const oR = useSharedValue(0)\n const oRot = useSharedValue(0)\n const oLinear = useSharedValue(0)\n const visible = useSharedValue(0)\n // Live totals from each recogniser. Every one reports its own running total\n // against the origin, so they combine without accumulating.\n const dx = useSharedValue(0)\n const dy = useSharedValue(0)\n const pinch = useSharedValue(1)\n const twist = useSharedValue(0)\n const activeCount = useSharedValue(0)\n\n const capture = useMemo(\n () => () => {\n const from = live.current\n if (!from || origin.current) return\n origin.current = from\n oX.value = from.x * width\n oY.value = from.y * height\n oR.value = from.radius * width\n oRot.value = from.rotation\n oLinear.value = from.mode === 'linear' ? 1 : 0\n },\n [width, height, oX, oY, oR, oRot, oLinear],\n )\n\n const commit = useMemo(\n () => (tx: number, ty: number, scale: number, rotation: number) => {\n const from = origin.current\n origin.current = null\n if (!from || !layer || width <= 0 || height <= 0) return\n // Each transform applied once, from the captured origin.\n let next = moveTiltCenter(from, tx / width, ty / height)\n next = scaleTiltRadius({ ...next, radius: from.radius, feather: from.feather }, scale)\n next = rotateTiltBand({ ...next, rotation: from.rotation }, rotation)\n dispatch({\n type: 'layer/patchData',\n id: layer.id,\n patch: tiltShiftPatch(next) as unknown as Record<string, unknown>,\n })\n },\n [dispatch, layer, width, height],\n )\n\n const gesture = useMemo(() => {\n const begin = () => {\n 'worklet'\n activeCount.value += 1\n visible.value = 1\n runOnJS(capture)()\n }\n /** Commit once, when the last recogniser lets go. */\n const end = () => {\n 'worklet'\n activeCount.value = Math.max(0, activeCount.value - 1)\n if (activeCount.value > 0) return\n visible.value = 0\n runOnJS(commit)(dx.value, dy.value, pinch.value, twist.value)\n dx.value = 0\n dy.value = 0\n pinch.value = 1\n twist.value = 0\n }\n\n const pan = Gesture.Pan()\n .enabled(active)\n .onStart(begin)\n .onUpdate((e) => {\n 'worklet'\n dx.value = e.translationX\n dy.value = e.translationY\n })\n .onFinalize(end)\n\n const pinchGesture = Gesture.Pinch()\n .enabled(active)\n .onStart(begin)\n .onUpdate((e) => {\n 'worklet'\n pinch.value = e.scale\n })\n .onFinalize(end)\n\n const rotation = Gesture.Rotation()\n .enabled(active)\n .onStart(begin)\n .onUpdate((e) => {\n 'worklet'\n twist.value = e.rotation\n })\n .onFinalize(end)\n\n return Gesture.Simultaneous(pan, pinchGesture, rotation)\n }, [active, capture, commit, activeCount, visible, dx, dy, pinch, twist])\n\n // The indicator, entirely on the UI thread — no dispatch, no re-render, and\n // no JS hop per frame.\n const ringStyle = useAnimatedStyle(() => {\n const r = Math.max(1, oR.value * pinch.value)\n const cx = oX.value + dx.value\n const cy = oY.value + dy.value\n const band = oLinear.value > 0.5\n return {\n opacity: visible.value,\n left: band ? -width : cx - r,\n top: cy - r,\n width: band ? width * 3 : r * 2,\n height: r * 2,\n borderRadius: band ? 0 : r,\n transform: [{ rotate: `${oRot.value + twist.value}rad` }],\n }\n })\n\n if (!active) return null\n return (\n <GestureDetector gesture={gesture}>\n <Animated.View style={StyleSheet.absoluteFill}>\n {/* Drawn here, in React Native, never inside renderDocument — so no\n editing chrome can reach an export. */}\n <Animated.View pointerEvents=\"none\" style={[styles.ring, ringStyle]} />\n </Animated.View>\n </GestureDetector>\n )\n}\n\nconst styles = StyleSheet.create({\n ring: {\n position: 'absolute',\n borderWidth: 1.5,\n borderColor: 'rgba(255,255,255,0.9)',\n },\n})\n","import React from 'react'\nimport { StyleSheet, View } from 'react-native'\nimport { useInteractionState } from './interactionState'\n\n/** Rule-of-thirds overlay shown only while crop interaction is active. */\nexport function CropGrid({ always = false }: { always?: boolean }) {\n const { cropActive } = useInteractionState()\n if (!always && !cropActive) return null\n return (\n <View pointerEvents=\"none\" style={StyleSheet.absoluteFill}>\n {[1 / 3, 2 / 3].map((fraction) => (\n <React.Fragment key={fraction}>\n <View style={[styles.vertical, { left: `${fraction * 100}%` }]} />\n <View style={[styles.horizontal, { top: `${fraction * 100}%` }]} />\n </React.Fragment>\n ))}\n </View>\n )\n}\n\nconst styles = StyleSheet.create({\n vertical: { position: 'absolute', top: 0, bottom: 0, width: 1, backgroundColor: '#ffffff88' },\n horizontal: { position: 'absolute', left: 0, right: 0, height: 1, backgroundColor: '#ffffff88' },\n})\n","import {\n deleteTargetFromProfile,\n hitTestDocument,\n isDirectManipulationLayer,\n isSameTransform,\n layerNaturalSize,\n layerGestureConfigFromProfile,\n NO_SNAP,\n useEditor,\n useEditorStore,\n type DeleteTarget,\n type LayerSnapState,\n type Transform,\n} from '@pictor-sdk/core'\nimport { preferMeasuredSize, useCanvasMetrics, useRenderer } from '@pictor-sdk/skia'\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { StyleSheet } from 'react-native'\nimport { Gesture, GestureDetector } from 'react-native-gesture-handler'\nimport Animated, { useDerivedValue, useSharedValue } from 'react-native-reanimated'\nimport { runOnJS } from 'react-native-worklets'\nimport {\n composeLayerGestureUI,\n isOverDeleteTargetUI,\n hitTestLayerCandidatesUI,\n layerPreviewDeltaUI,\n} from './layerGestureWorklet'\nimport { useInteractionState } from './interactionState'\nimport { type GestureSnapEvent } from './controller'\n\n/** Overrides for overlay-layer gestures, defaulting to the profile's settings. */\nexport interface LayerGestureSurfaceProps {\n /** Fired once per snap engagement — hook up haptics here if you want them. */\n onSnap?: (event: GestureSnapEvent) => void\n}\n\n/**\n * Direct manipulation of overlay layers: grab the top-most layer under the\n * finger and pan, focal-pinch and rotate it on the UI thread.\n *\n * Three things make this feel right, and each is covered by tests:\n *\n * - **Focal composition.** Scale and rotation happen about the gesture\n * centroid, so the document point under the fingers stays under them.\n * - **Pointer-count re-basing.** Gesture Handler restarts its cumulative\n * translation/scale/rotation when a finger lands or lifts. Every recognizer\n * value is read relative to an origin captured at the last re-base, and the\n * frame re-bases from the live transform whenever the pointer count changes\n * — so two fingers going to one does not jump.\n * - **One history entry.** The document is written exactly once, when the\n * gesture settles, and not at all if nothing actually moved.\n */\nexport function LayerGestureSurface({ onSnap }: LayerGestureSurfaceProps) {\n const { document, dispatch, profile } = useEditor()\n const store = useEditorStore()\n const metrics = useCanvasMetrics()\n // Destructure the setters: the context value's identity changes on every\n // interaction state change (including ones this component causes), so\n // depending on the object would tear down effects mid-gesture. The setters\n // themselves are stable.\n const { setPreview, setLayerDragActive, setOverDeleteTarget, setSnap } = useInteractionState()\n\n const renderer = useRenderer()\n\n const config = useMemo(\n () => layerGestureConfigFromProfile(profile.interaction?.layers),\n [profile],\n )\n const deleteTarget = useMemo(\n () => deleteTargetFromProfile(profile.interaction?.layers),\n [profile],\n )\n const aspect = document.size.height / document.size.width\n // Rebuild hit geometry when the renderer publishes a new text measurement,\n // so a layer's touch box tracks the box it actually draws.\n const [measureVersion, setMeasureVersion] = useState(0)\n useEffect(() => {\n const refresh = () => setMeasureVersion((v) => v + 1)\n const unsubscribe = renderer.textMeasures.subscribe(refresh)\n // The first scene may have committed before this passive effect subscribed.\n refresh()\n return unsubscribe\n }, [renderer])\n\n const hitCandidates = useMemo(\n () =>\n document.layers\n .map((layer, index) => ({ layer, index }))\n .filter(\n ({ layer, index }) =>\n !layer.hidden &&\n !layer.locked &&\n isDirectManipulationLayer(layer, index, profile.interaction?.layers),\n )\n .reverse()\n .map(({ layer }) => {\n // The renderer's measurement when it has one, core's estimate\n // otherwise — core cannot lay out text, so its estimate is a\n // character-count approximation that does not match the drawn box.\n const natural = preferMeasuredSize(\n renderer.textMeasures.get(layer.id),\n layerNaturalSize(layer, store.registry, document),\n )\n const anchor = layer.transform.anchor ?? { x: 0.5, y: 0.5 }\n return {\n id: layer.id,\n x: layer.transform.x,\n y: layer.transform.y,\n scale: layer.transform.scale,\n rotation: layer.transform.rotation,\n width: natural.width,\n height: natural.height,\n anchorX: anchor.x,\n anchorY: anchor.y,\n flipX: layer.transform.flipX ?? false,\n flipY: layer.transform.flipY ?? false,\n }\n }),\n // `measureVersion` is deliberate: the measurements live outside React, so\n // this is how a new one re-derives the hit geometry.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [document, profile, store.registry, renderer, measureVersion],\n )\n\n // ── live transform (UI thread) ──\n const liveX = useSharedValue(0.5)\n const liveY = useSharedValue(0.5)\n const liveScale = useSharedValue(1)\n const liveRotation = useSharedValue(0)\n // Immutable for the lifetime of a gesture. The renderer preview is always a\n // delta from the still-committed document transform, never from a frame base.\n const committedX = useSharedValue(0.5)\n const committedY = useSharedValue(0.5)\n const committedScale = useSharedValue(1)\n const committedRotation = useSharedValue(0)\n // ── frame base, re-captured on every pointer-count change ──\n const baseX = useSharedValue(0.5)\n const baseY = useSharedValue(0.5)\n const baseScale = useSharedValue(1)\n const baseRotation = useSharedValue(0)\n // ── recognizer origins, subtracted so each frame starts from zero ──\n const originPanX = useSharedValue(0)\n const originPanY = useSharedValue(0)\n const originPinch = useSharedValue(1)\n const originRotate = useSharedValue(0)\n const rawPanX = useSharedValue(0)\n const rawPanY = useSharedValue(0)\n const rawPinch = useSharedValue(1)\n const rawRotate = useSharedValue(0)\n const focalX = useSharedValue(0.5)\n const focalY = useSharedValue(0.5)\n const pointers = useSharedValue(0)\n const active = useSharedValue(false)\n const snapCX = useSharedValue(false)\n const snapCY = useSharedValue(false)\n const snapR = useSharedValue(false)\n const overDelete = useSharedValue(false)\n\n // ── preview transform: a delta from the committed transform, UI-thread only ──\n const previewTransform = useDerivedValue(() => {\n return layerPreviewDeltaUI(\n {\n x: committedX.value,\n y: committedY.value,\n scale: committedScale.value,\n rotation: committedRotation.value,\n },\n { x: liveX.value, y: liveY.value, scale: liveScale.value, rotation: liveRotation.value },\n document.size.width,\n document.size.height,\n )\n }, [document.size.width, document.size.height])\n\n /**\n * Fresh render state for the JS callbacks below.\n *\n * The callbacks themselves must be identity-stable, because a worklet has to\n * capture them *directly*: Reanimated serialises captured objects, so a\n * function reached through `someRef.current` arrives on the UI thread as a\n * plain value and calling it throws \"Object is not a function\". Stable\n * callbacks + a mutable snapshot gives both fresh data and a gesture object\n * that never needs rebuilding.\n */\n const latest = useRef({ document, metrics, store, dispatch, onSnap, profile })\n latest.current = { document, metrics, store, dispatch, onSnap, profile }\n\n const grabbedId = useRef<string | null>(null)\n const grabbedFrom = useRef<Transform | null>(null)\n const snapState = useRef<LayerSnapState>(NO_SNAP)\n\n const onGrabLayer = useCallback((id: string) => {\n const { document: doc, store: s } = latest.current\n const hit = doc.layers.find((layer) => layer.id === id)\n if (!hit) return\n const t = hit.transform\n grabbedId.current = hit.id\n grabbedFrom.current = { ...t }\n s.select([hit.id])\n setPreview({ layerId: hit.id, transform: previewTransform })\n setLayerDragActive(true)\n }, [setPreview, setLayerDragActive, previewTransform])\n\n const onSelectAt = useCallback((xDp: number, yDp: number) => {\n const { document: doc, metrics: m, store: s } = latest.current\n if (!m) return\n const layerInteraction = latest.current.profile.interaction?.layers\n const hit = hitTestDocument(\n doc,\n { x: xDp / m.width, y: yDp / m.height },\n s.registry,\n (layer, index) => isDirectManipulationLayer(layer, index, layerInteraction),\n )\n s.select(hit && !hit.locked ? [hit.id] : [])\n }, [])\n\n const onSnapChanged = useCallback(\n (centerX: boolean, centerY: boolean, rotation: boolean) => {\n const previous = snapState.current\n const next = { centerX, centerY, rotation }\n snapState.current = next\n const notify = latest.current.onSnap\n if (centerX && !previous.centerX) notify?.({ kind: 'centerX' })\n if (centerY && !previous.centerY) notify?.({ kind: 'centerY' })\n if (rotation && !previous.rotation) notify?.({ kind: 'rotation' })\n setSnap(next)\n },\n [setSnap],\n )\n\n const onHoverChanged = useCallback(\n (over: boolean) => setOverDeleteTarget(over),\n [setOverDeleteTarget],\n )\n\n const onGestureFinished = useCallback(\n (t: Transform, deleted: boolean) => {\n const { dispatch: d, store: s } = latest.current\n const id = grabbedId.current\n const from = grabbedFrom.current\n grabbedId.current = null\n grabbedFrom.current = null\n snapState.current = NO_SNAP\n setLayerDragActive(false)\n setOverDeleteTarget(false)\n setSnap(NO_SNAP)\n setPreview(null)\n if (!id) return\n if (deleted) {\n d({ type: 'layer/remove', id })\n s.select([])\n return\n }\n // a tap, or a drag that ended where it started, must not create an undo entry\n if (from && isSameTransform(from, t)) return\n d({ type: 'layer/transform', id, patch: t })\n },\n [setLayerDragActive, setOverDeleteTarget, setSnap, setPreview],\n )\n\n useEffect(() => () => setPreview(null), [setPreview])\n\n const gesture = useMemo(() => {\n const metricsWidth = metrics?.width ?? 0\n const metricsHeight = metrics?.height ?? 0\n const target: DeleteTarget | null = deleteTarget\n const candidates = hitCandidates\n\n /** Re-capture the frame base and zero every recognizer origin. */\n const rebase = () => {\n 'worklet'\n baseX.value = liveX.value\n baseY.value = liveY.value\n baseScale.value = liveScale.value\n baseRotation.value = liveRotation.value\n originPanX.value = rawPanX.value\n originPanY.value = rawPanY.value\n originPinch.value = rawPinch.value\n originRotate.value = rawRotate.value\n }\n\n const recompute = (settle: boolean) => {\n 'worklet'\n if (!active.value || metricsWidth === 0 || metricsHeight === 0) return\n const out = composeLayerGestureUI(\n {\n x: baseX.value,\n y: baseY.value,\n scale: baseScale.value,\n rotation: baseRotation.value,\n },\n {\n panX: (rawPanX.value - originPanX.value) / metricsWidth,\n panY: (rawPanY.value - originPanY.value) / metricsHeight,\n pinch: rawPinch.value / Math.max(originPinch.value, 1e-9),\n rotate: rawRotate.value - originRotate.value,\n focalX: focalX.value,\n focalY: focalY.value,\n },\n aspect,\n config,\n { centerX: snapCX.value, centerY: snapCY.value, rotation: snapR.value },\n settle,\n )\n liveX.value = out.x\n liveY.value = out.y\n liveScale.value = out.scale\n liveRotation.value = out.rotation\n\n if (\n out.snapCenterX !== snapCX.value ||\n out.snapCenterY !== snapCY.value ||\n out.snapRotation !== snapR.value\n ) {\n snapCX.value = out.snapCenterX\n snapCY.value = out.snapCenterY\n snapR.value = out.snapRotation\n runOnJS(onSnapChanged)(out.snapCenterX, out.snapCenterY, out.snapRotation)\n }\n\n if (target) {\n const over = isOverDeleteTargetUI(out.x, out.y, target, aspect)\n if (over !== overDelete.value) {\n overDelete.value = over\n runOnJS(onHoverChanged)(over)\n }\n }\n }\n\n /** Track pointer count and re-base the frame whenever it changes. */\n const syncPointers = (count: number) => {\n 'worklet'\n if (active.value && count !== pointers.value) {\n pointers.value = count\n rebase()\n }\n }\n\n const endIfIdle = () => {\n 'worklet'\n if (!active.value) {\n // an inert gesture (nothing was grabbed) still has to clear UI state\n runOnJS(onGestureFinished)({ x: 0, y: 0, scale: 1, rotation: 0 }, false)\n return\n }\n recompute(true)\n active.value = false\n pointers.value = 0\n const deleted = overDelete.value\n overDelete.value = false\n snapCX.value = false\n snapCY.value = false\n snapR.value = false\n runOnJS(onGestureFinished)(\n {\n x: liveX.value,\n y: liveY.value,\n scale: liveScale.value,\n rotation: liveRotation.value,\n },\n deleted,\n )\n }\n\n const pan = Gesture.Pan()\n .minPointers(1)\n .maxPointers(2)\n .onBegin((e) => {\n 'worklet'\n if (active.value) return\n rawPanX.value = 0\n rawPanY.value = 0\n rawPinch.value = 1\n rawRotate.value = 0\n originPanX.value = 0\n originPanY.value = 0\n originPinch.value = 1\n originRotate.value = 0\n pointers.value = e.numberOfPointers\n const hit = hitTestLayerCandidatesUI(\n e.x / Math.max(metricsWidth, 1e-9),\n e.y / Math.max(metricsHeight, 1e-9),\n candidates,\n document.size.width,\n document.size.height,\n )\n if (!hit) {\n active.value = false\n return\n }\n liveX.value = hit.x\n liveY.value = hit.y\n liveScale.value = hit.scale\n liveRotation.value = hit.rotation\n committedX.value = hit.x\n committedY.value = hit.y\n committedScale.value = hit.scale\n committedRotation.value = hit.rotation\n baseX.value = hit.x\n baseY.value = hit.y\n baseScale.value = hit.scale\n baseRotation.value = hit.rotation\n focalX.value = hit.x\n focalY.value = hit.y\n active.value = true\n runOnJS(onGrabLayer)(hit.id)\n })\n .onUpdate((e) => {\n 'worklet'\n rawPanX.value = e.translationX\n rawPanY.value = e.translationY\n syncPointers(e.numberOfPointers)\n recompute(false)\n })\n .onFinalize(() => {\n 'worklet'\n endIfIdle()\n })\n\n const pinch = Gesture.Pinch().onUpdate((e) => {\n 'worklet'\n rawPinch.value = e.scale\n focalX.value = e.focalX / metricsWidth\n focalY.value = e.focalY / metricsHeight\n syncPointers(e.numberOfPointers)\n recompute(false)\n })\n\n const rotate = Gesture.Rotation()\n .enabled(config.rotationEnabled)\n .onUpdate((e) => {\n 'worklet'\n rawRotate.value = e.rotation\n focalX.value = e.anchorX / metricsWidth\n focalY.value = e.anchorY / metricsHeight\n syncPointers(e.numberOfPointers)\n recompute(false)\n })\n\n const tap = Gesture.Tap().onEnd((e) => {\n 'worklet'\n runOnJS(onSelectAt)(e.x, e.y)\n })\n\n return Gesture.Simultaneous(Gesture.Race(pan, tap), pinch, rotate)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n metrics,\n config,\n deleteTarget,\n aspect,\n onGrabLayer,\n onSelectAt,\n onSnapChanged,\n onHoverChanged,\n onGestureFinished,\n hitCandidates,\n document.size.width,\n document.size.height,\n ])\n\n return (\n <GestureDetector gesture={gesture}>\n <Animated.View style={StyleSheet.absoluteFill} />\n </GestureDetector>\n )\n}\n","import { type ResolvedLayerGestureConfig } from '@pictor-sdk/core'\n\n/**\n * UI-thread twin of `composeLayerGesture` from @pictor-sdk/core.\n *\n * DECISION: the gesture math exists twice on purpose. @pictor-sdk/core must stay\n * free of Reanimated (invariant 5) and must run in plain Node, so it cannot\n * carry a `'worklet'` directive; but the preview has to recompute the\n * transform on the UI thread every frame, which requires a worklet. Rather\n * than rely on the consumer's Babel config workletizing another package's\n * source, the worklet lives here — and `worklet-parity.test.ts` asserts the\n * two implementations agree across a grid of inputs, so they cannot drift.\n *\n * Keep this function free of imports and closures over anything but plain\n * numbers and frozen config objects.\n */\nexport interface WorkletTransform {\n x: number\n y: number\n scale: number\n rotation: number\n snapCenterX: boolean\n snapCenterY: boolean\n snapRotation: boolean\n}\n\nexport interface WorkletBase {\n x: number\n y: number\n scale: number\n rotation: number\n}\n\nexport interface WorkletInput {\n panX: number\n panY: number\n pinch: number\n rotate: number\n focalX: number\n focalY: number\n}\n\nexport interface WorkletPrevSnap {\n centerX: boolean\n centerY: boolean\n rotation: boolean\n}\n\nexport function composeLayerGestureUI(\n base: WorkletBase,\n input: WorkletInput,\n aspect: number,\n config: ResolvedLayerGestureConfig,\n previous: WorkletPrevSnap,\n settle: boolean,\n): WorkletTransform {\n 'worklet'\n const requested = base.scale * input.pinch\n let scale: number\n if (settle) {\n scale = Math.min(config.maxScale, Math.max(config.minScale, requested))\n } else if (requested < config.minScale) {\n scale = config.minScale - (config.minScale - requested) * config.scaleResistance\n } else if (requested > config.maxScale) {\n scale = config.maxScale + (requested - config.maxScale) * config.scaleResistance\n } else {\n scale = requested\n }\n\n const ratio = scale / Math.max(base.scale, 1e-9)\n const rotationDelta = config.rotationEnabled ? input.rotate : 0\n\n const dx = base.x - input.focalX\n const dy = (base.y - input.focalY) * aspect\n const cos = Math.cos(rotationDelta)\n const sin = Math.sin(rotationDelta)\n const rx = (dx * cos - dy * sin) * ratio\n const ry = (dx * sin + dy * cos) * ratio\n\n let x = input.focalX + rx + input.panX\n let y = input.focalY + ry / aspect + input.panY\n let rotation = base.rotation + rotationDelta\n\n let snapCenterX = false\n let snapCenterY = false\n let snapRotation = false\n\n if (config.centerSnap !== false) {\n const engage = config.centerSnap\n const release = Math.max(engage, config.centerSnapRelease)\n const tx = previous.centerX ? release : engage\n if (Math.abs(x - 0.5) <= tx + 1e-9) {\n x = 0.5\n snapCenterX = true\n }\n const ty = previous.centerY ? release : engage\n if (Math.abs(y - 0.5) <= ty + 1e-9) {\n y = 0.5\n snapCenterY = true\n }\n }\n\n if (config.rotationSnap !== false && config.rotationEnabled) {\n const engage = config.rotationSnap\n const release = Math.max(engage, config.rotationSnapRelease)\n const step = Math.PI / 2\n const nearest = Math.round(rotation / step) * step\n const tr = previous.rotation ? release : engage\n if (Math.abs(rotation - nearest) <= tr + 1e-9) {\n rotation = nearest\n snapRotation = true\n }\n }\n\n return { x, y, scale, rotation, snapCenterX, snapCenterY, snapRotation }\n}\n\n/**\n * UI-thread twin of `isOverDeleteTarget`.\n *\n * Same reason as above: a worklet may only call other worklets, and\n * @pictor-sdk/core cannot carry the directive. Held to core by the parity test.\n */\nexport function isOverDeleteTargetUI(\n x: number,\n y: number,\n target: { x: number; y: number; radius: number },\n aspect: number,\n): boolean {\n 'worklet'\n const dx = x - target.x\n const dy = (y - target.y) * aspect\n return Math.sqrt(dx * dx + dy * dy) <= target.radius\n}\n\n/**\n * Renderer delta from the immutable committed transform to the live transform.\n * Pointer-frame rebasing must never change these reference values.\n */\nexport function layerPreviewDeltaUI(\n committed: { x: number; y: number; scale: number; rotation: number },\n live: { x: number; y: number; scale: number; rotation: number },\n width: number,\n height: number,\n) {\n 'worklet'\n return [\n { translateX: live.x * width },\n { translateY: live.y * height },\n { rotate: live.rotation - committed.rotation },\n { scale: live.scale / Math.max(committed.scale, 1e-9) },\n { translateX: -committed.x * width },\n { translateY: -committed.y * height },\n ]\n}\n\nexport interface LayerHitCandidateUI {\n id: string\n x: number\n y: number\n scale: number\n rotation: number\n width: number\n height: number\n anchorX: number\n anchorY: number\n flipX: boolean\n flipY: boolean\n}\n\n/** Top-most bounding-box hit test used to activate built-in overlays instantly. */\nexport function hitTestLayerCandidatesUI(\n x: number,\n y: number,\n candidates: readonly LayerHitCandidateUI[],\n documentWidth: number,\n documentHeight: number,\n): LayerHitCandidateUI | null {\n 'worklet'\n for (let i = 0; i < candidates.length; i++) {\n const candidate = candidates[i]!\n let dx = x * documentWidth - candidate.x * documentWidth\n let dy = y * documentHeight - candidate.y * documentHeight\n const cos = Math.cos(-candidate.rotation)\n const sin = Math.sin(-candidate.rotation)\n const rx = dx * cos - dy * sin\n const ry = dx * sin + dy * cos\n dx = candidate.flipX ? -rx : rx\n dy = candidate.flipY ? -ry : ry\n const width = candidate.scale * candidate.width * documentWidth\n const height = candidate.scale * candidate.height * documentWidth\n if (width <= 0 || height <= 0) continue\n const localX = dx / width + candidate.anchorX\n const localY = dy / height + candidate.anchorY\n if (localX >= 0 && localX <= 1 && localY >= 0 && localY <= 1) return candidate\n }\n return null\n}\n","import {\n doubleTapMediaTransform,\n isBaseImageLayer,\n isSameTransform,\n mediaConfigFromProfile,\n useEditor,\n type ImageLayerData,\n type Layer,\n type Transform,\n} from '@pictor-sdk/core'\nimport { preferResolvedSize, useCanvasMetrics, useResolvedImageSize } from '@pictor-sdk/skia'\nimport React, { useCallback, useEffect, useMemo, useRef } from 'react'\nimport { StyleSheet } from 'react-native'\nimport { Gesture, GestureDetector } from 'react-native-gesture-handler'\nimport Animated, {\n cancelAnimation,\n useDerivedValue,\n useSharedValue,\n withTiming,\n} from 'react-native-reanimated'\nimport { runOnJS } from 'react-native-worklets'\nimport {\n composeMediaGestureUI,\n onRecognizerBegin,\n onRecognizerEnd,\n} from './mediaGestureWorklet'\nimport { createSettleCoordinator, type SettleCoordinator } from './settleCoordinator'\nimport {\n beginOwnership,\n commitOwnership,\n documentChanged,\n IDLE_OWNERSHIP,\n type OwnershipState,\n} from './transformOwnership'\nimport { useInteractionState } from './interactionState'\n\n/** Overrides for base-media gestures, defaulting to the profile's settings. */\nexport interface StoryMediaGestureSurfaceProps {\n /** Fired when a media gesture starts and ends — for host haptics/chrome. */\n onInteractionChange?: (active: boolean) => void\n}\n\n/** Find the document's base media — the bottom-most layer, if it is an image. */\nexport function useBaseMediaLayer(): Layer | undefined {\n const { document } = useEditor()\n const base = document.layers[0]\n return base && isBaseImageLayer(document.layers, base.id) ? base : undefined\n}\n\n/**\n * Direct manipulation of the Story base photo: one-finger reposition, focal\n * pinch and rotation, held inside rotation-aware pan bounds with rubber-band\n * resistance and a bounded settle.\n *\n * Mounted only while the `media` tool is active, so it cannot compete with\n * overlay or drawing gestures. The transform is written to the document once\n * per settled gesture; because the tool session already opened a history batch\n * (see `ToolPanelHost`), a whole session of adjustments collapses into one undo\n * entry, and a session that changed nothing records none.\n */\nexport function StoryMediaGestureSurface({\n onInteractionChange,\n}: StoryMediaGestureSurfaceProps) {\n const { document, dispatch, profile } = useEditor()\n const metrics = useCanvasMetrics()\n const { setPreview } = useInteractionState()\n const layer = useBaseMediaLayer()\n\n const config = useMemo(\n () => mediaConfigFromProfile(profile.interaction?.media),\n [profile],\n )\n // The renderer sizes the layer from the DECODED image, so geometry must use\n // the same number. A declared intrinsic of 0x0 is normal for a remote URL.\n const declared = (layer?.data as ImageLayerData | undefined)?.intrinsic\n const resolved = useResolvedImageSize((layer?.data as ImageLayerData | undefined)?.source)\n const intrinsic = useMemo(\n () => preferResolvedSize(resolved, declared),\n [resolved, declared],\n )\n const canvas = document.size\n\n // ── live transform (UI thread) ──\n const liveX = useSharedValue(0.5)\n const liveY = useSharedValue(0.5)\n const liveScale = useSharedValue(1)\n const liveRotation = useSharedValue(0)\n // ── frame base, re-captured on every pointer-count change ──\n const baseX = useSharedValue(0.5)\n const baseY = useSharedValue(0.5)\n const baseScale = useSharedValue(1)\n const baseRotation = useSharedValue(0)\n // ── recognizer origins, subtracted so each frame starts from zero ──\n const originPanX = useSharedValue(0)\n const originPanY = useSharedValue(0)\n const originPinch = useSharedValue(1)\n const originRotate = useSharedValue(0)\n const rawPanX = useSharedValue(0)\n const rawPanY = useSharedValue(0)\n const rawPinch = useSharedValue(1)\n const rawRotate = useSharedValue(0)\n const focalX = useSharedValue(0.5)\n const focalY = useSharedValue(0.5)\n const active = useSharedValue(false)\n /** How many of pan/pinch/rotation are still live. */\n const recognizers = useSharedValue(0)\n /**\n * Whether each recognizer actually activated.\n *\n * `onBegin` fires on touch-down for every recognizer, including the taps of a\n * double-tap that `Gesture.Exclusive` will go on to win. Ownership has to key\n * off activation instead, or a plain tap opens and closes a whole interaction\n * -- registering a preview, settling and committing -- underneath the\n * double-tap animation it is racing.\n */\n const startedPan = useSharedValue(false)\n const startedPinch = useSharedValue(false)\n const startedRotate = useSharedValue(false)\n /**\n * Drives the settle's timing, and nothing else.\n *\n * The commit has to happen when the settle *finishes*, which means some\n * animation has to report completion. Using one of the four transform\n * animations for that is a trap: a gesture clamped in position but not scale\n * ends with `liveScale` already at its target, and `withTiming` from a value\n * to itself completes in a single frame. That committed 6ms into a 180ms\n * settle and cut the x/y animations off before they had moved. This value\n * always travels 0 -> 1, so it always takes the full duration.\n */\n const settleProgress = useSharedValue(0)\n\n const committed = layer?.transform\n\n /**\n * Ownership of the transform, as a plain ref.\n *\n * Deliberately not a shared value: this is read during render on the JS\n * thread, and a shared value written on the UI thread reaches the JS side\n * only asynchronously, so the guard could read stale and skip the reseed.\n * Every writer here runs on the JS thread.\n */\n const ownership = useRef<OwnershipState>(IDLE_OWNERSHIP)\n\n // Re-seed from the document whenever the committed transform changes from\n // outside the gesture (undo, Cancel, a fresh photo) and whenever a gesture\n // commits — the preview is a delta from these, so they must track the\n // document exactly.\n useEffect(() => {\n const next = documentChanged(ownership.current, committed)\n ownership.current = next.state\n if (!next.reseed || !committed) return\n liveX.value = committed.x\n liveY.value = committed.y\n liveScale.value = committed.scale\n liveRotation.value = committed.rotation\n // shared values are stable refs; only committed scalars resync them\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [committed?.x, committed?.y, committed?.scale, committed?.rotation])\n\n /**\n * The transform the canvas already drew the layer at, captured when the\n * interaction begins.\n *\n * The preview is a *delta* from it, so the two must never disagree. Deriving\n * it from the document each render sounds safer but is worse: the preview is\n * registered from an effect, so on the render that commits, the canvas holds\n * the new document transform and still the previous preview — one frame of\n * the delta applied to the wrong baseline. Capturing it at grab sidesteps the\n * question entirely, because the document cannot change during an\n * interaction, and the preview is cleared in the same call that dispatches.\n */\n const baseCommittedX = useSharedValue(0.5)\n const baseCommittedY = useSharedValue(0.5)\n const baseCommittedScale = useSharedValue(1)\n const baseCommittedRotation = useSharedValue(0)\n\n const previewTransform = useDerivedValue(() => {\n const ratio = liveScale.value / Math.max(baseCommittedScale.value, 1e-9)\n return [\n { translateX: liveX.value * canvas.width },\n { translateY: liveY.value * canvas.height },\n { rotate: liveRotation.value - baseCommittedRotation.value },\n { scale: ratio },\n { translateX: -baseCommittedX.value * canvas.width },\n { translateY: -baseCommittedY.value * canvas.height },\n ]\n }, [canvas.width, canvas.height])\n\n useEffect(() => () => setPreview(null), [setPreview])\n\n const latest = useRef({ layer, dispatch, onInteractionChange, previewTransform })\n latest.current = { layer, dispatch, onInteractionChange, previewTransform }\n const settleCoordinatorRef = useRef<SettleCoordinator<Transform> | null>(null)\n\n /** Hand the transform to the gesture: stop any settle, start previewing. */\n const beginInteraction = useCallback(() => {\n // A touch that lands during a settle takes ownership of the transform, so\n // the settle in flight must never commit its stale target. This runs in the\n // same `runOnJS` hop `begin()` already makes, and the interrupted\n // animation's own completion callback is queued ahead of it, so there is no\n // window in which the old settle can still write.\n settleCoordinatorRef.current?.cancel()\n ownership.current = beginOwnership()\n const current = latest.current.layer\n if (current) {\n // snapshot the baseline the canvas is drawing at, then start previewing\n baseCommittedX.value = current.transform.x\n baseCommittedY.value = current.transform.y\n baseCommittedScale.value = current.transform.scale\n baseCommittedRotation.value = current.transform.rotation\n setPreview({ layerId: current.id, transform: latest.current.previewTransform })\n }\n latest.current.onInteractionChange?.(true)\n // shared values are stable refs\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [setPreview])\n\n /**\n * Write the settled transform. One document write per gesture — and none at\n * all when the gesture settled exactly where it started, so a tap or a\n * there-and-back drag leaves the session clean.\n */\n const commitNow = useCallback((next: Transform) => {\n const current = latest.current.layer\n // Cleared in the same call that dispatches, so React batches them into one\n // render: the delta goes away exactly as the document takes the transform.\n setPreview(null)\n latest.current.onInteractionChange?.(false)\n // A no-op commit means no document update is coming, so ownership ends\n // here. Otherwise it lasts until the document reports `next` back — until\n // then `live` already holds it, and reseeding would flash the old value.\n const dispatched = current !== undefined && !isSameTransform(current.transform, next)\n ownership.current = commitOwnership(next, dispatched, current?.transform)\n if (!dispatched || !current) return\n latest.current.dispatch({\n type: 'layer/transform',\n id: current.id,\n patch: { x: next.x, y: next.y, scale: next.scale, rotation: next.rotation },\n })\n }, [setPreview])\n\n const settleCoordinator = useMemo(\n () => createSettleCoordinator<Transform>((target) => commitNow(target)),\n // commitNow reads through `latest`, so it is stable\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [],\n )\n // `beginInteraction` is created before the coordinator exists, so it reaches it here.\n settleCoordinatorRef.current = settleCoordinator\n\n /**\n * Animate to `target`, then write it. The write happens in the animation's\n * completion callback — writing first would change `committed` and cancel the\n * very animation heading there.\n */\n const settleTo = useCallback(\n (target: Transform, duration: number) => {\n settleCoordinator.settle(target, (done) => {\n liveX.value = withTiming(target.x, { duration })\n liveY.value = withTiming(target.y, { duration })\n liveRotation.value = withTiming(target.rotation, { duration })\n liveScale.value = withTiming(target.scale, { duration })\n // the timekeeper: never degenerate, so it always runs the full duration\n settleProgress.value = 0\n settleProgress.value = withTiming(1, { duration }, (finished) => {\n 'worklet'\n runOnJS(done)(finished === true)\n })\n })\n },\n // shared values are stable refs, so they are deliberately not dependencies\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [settleCoordinator],\n )\n\n // Abandon a settle in flight if the tool closes or the surface unmounts, so\n // no stale transform is written after the session has gone.\n useEffect(\n () => () => {\n settleCoordinator.cancel()\n ownership.current = IDLE_OWNERSHIP\n cancelAnimation(liveX)\n cancelAnimation(liveY)\n cancelAnimation(liveScale)\n cancelAnimation(liveRotation)\n cancelAnimation(settleProgress)\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [settleCoordinator],\n )\n\n const runDoubleTap = useCallback(\n (xDp: number, yDp: number) => {\n const current = latest.current.layer\n if (!current || !metrics) return\n const target = doubleTapMediaTransform(current.transform, canvas, intrinsic, config, {\n x: xDp / metrics.width,\n y: yDp / metrics.height,\n })\n // the animation drives the live values, so it needs the preview too\n beginInteraction()\n settleTo(target, config.settleMs)\n },\n [metrics, canvas, intrinsic, config, settleTo, beginInteraction],\n )\n\n const gesture = useMemo(() => {\n const width = metrics?.width ?? 0\n const height = metrics?.height ?? 0\n const settleMs = config.settleMs\n\n const recompute = () => {\n 'worklet'\n if (!active.value || width === 0 || height === 0) return\n const out = composeMediaGestureUI(\n {\n x: baseX.value,\n y: baseY.value,\n scale: baseScale.value,\n rotation: baseRotation.value,\n },\n {\n panX: (rawPanX.value - originPanX.value) / width,\n panY: (rawPanY.value - originPanY.value) / height,\n pinch: rawPinch.value / Math.max(originPinch.value, 1e-9),\n rotate: rawRotate.value - originRotate.value,\n focalX: focalX.value,\n focalY: focalY.value,\n },\n canvas,\n intrinsic,\n config,\n false,\n )\n liveX.value = out.x\n liveY.value = out.y\n liveScale.value = out.scale\n liveRotation.value = out.rotation\n }\n\n const begin = () => {\n 'worklet'\n const started = onRecognizerBegin(recognizers.value)\n recognizers.value = started.count\n // A recognizer joining an interaction already in flight seeds its own\n // raw/origin pair in its onStart and needs nothing else: each one's\n // contribution is measured from its own activation, so they compose\n // without re-anchoring the frame.\n if (!started.isFirst) return\n // Take the transform away from any settle in flight. The animations are\n // stopped first so `live*` holds what is actually on screen, and that is\n // what the new gesture bases itself on — grabbing a photo mid-settle\n // continues from where the finger sees it, with no jump.\n cancelAnimation(liveX)\n cancelAnimation(liveY)\n cancelAnimation(liveScale)\n cancelAnimation(liveRotation)\n cancelAnimation(settleProgress)\n active.value = true\n // each recognizer seeds its own raw/origin pair in its onStart; anything\n // that has not activated contributes a neutral value\n rawPanX.value = 0\n rawPanY.value = 0\n rawPinch.value = 1\n rawRotate.value = 0\n originPanX.value = 0\n originPanY.value = 0\n originPinch.value = 1\n originRotate.value = 0\n baseX.value = liveX.value\n baseY.value = liveY.value\n baseScale.value = liveScale.value\n baseRotation.value = liveRotation.value\n focalX.value = liveX.value\n focalY.value = liveY.value\n runOnJS(beginInteraction)()\n }\n\n const finish = () => {\n 'worklet'\n const ended = onRecognizerEnd(recognizers.value)\n recognizers.value = ended.count\n // Pinch and rotation finalise as soon as a finger lifts while the pan\n // recognizer keeps running with the remaining one. Ending here would cut\n // the interaction short, so wait for the last recognizer.\n if (!ended.isLast || !active.value) return\n active.value = false\n // settle: hard-clamp back inside the bounds, then animate there\n const settled = composeMediaGestureUI(\n {\n x: baseX.value,\n y: baseY.value,\n scale: baseScale.value,\n rotation: baseRotation.value,\n },\n {\n panX: (rawPanX.value - originPanX.value) / width,\n panY: (rawPanY.value - originPanY.value) / height,\n pinch: rawPinch.value / Math.max(originPinch.value, 1e-9),\n rotate: rawRotate.value - originRotate.value,\n focalX: focalX.value,\n focalY: focalY.value,\n },\n canvas,\n intrinsic,\n config,\n true,\n )\n runOnJS(settleTo)(settled, settleMs)\n }\n\n const pan = Gesture.Pan()\n .minPointers(1)\n .maxPointers(2)\n // A recognizer only activates once the finger has travelled past the\n // touch slop, and by then its cumulative value already includes that\n // travel. Taking the origin at activation is what keeps the photo still\n // under the finger; taking it at touch-down makes it leap by the slop.\n .onStart((e) => {\n 'worklet'\n startedPan.value = true\n begin()\n rawPanX.value = e.translationX\n rawPanY.value = e.translationY\n originPanX.value = e.translationX\n originPanY.value = e.translationY\n })\n .onUpdate((e) => {\n 'worklet'\n rawPanX.value = e.translationX\n rawPanY.value = e.translationY\n recompute()\n })\n .onFinalize(() => {\n 'worklet'\n if (!startedPan.value) return\n startedPan.value = false\n finish()\n })\n\n const pinch = Gesture.Pinch()\n .onStart((e) => {\n 'worklet'\n startedPinch.value = true\n begin()\n rawPinch.value = e.scale\n originPinch.value = e.scale\n focalX.value = e.focalX / width\n focalY.value = e.focalY / height\n })\n .onUpdate((e) => {\n 'worklet'\n rawPinch.value = e.scale\n focalX.value = e.focalX / width\n focalY.value = e.focalY / height\n recompute()\n })\n .onFinalize(() => {\n 'worklet'\n if (!startedPinch.value) return\n startedPinch.value = false\n finish()\n })\n\n const rotate = Gesture.Rotation()\n .enabled(config.rotationEnabled)\n .onStart((e) => {\n 'worklet'\n startedRotate.value = true\n begin()\n rawRotate.value = e.rotation\n originRotate.value = e.rotation\n })\n .onUpdate((e) => {\n 'worklet'\n // Only the pinch owns the focal point. Gesture Handler's rotation\n // anchor and pinch focal are computed separately and disagree by a\n // pixel or two, so letting both write it made the focal — and with it\n // the whole composed transform — oscillate every frame.\n rawRotate.value = e.rotation\n recompute()\n })\n .onFinalize(() => {\n 'worklet'\n if (!startedRotate.value) return\n startedRotate.value = false\n finish()\n })\n\n const doubleTap = Gesture.Tap()\n .numberOfTaps(2)\n .onEnd((e) => {\n 'worklet'\n runOnJS(runDoubleTap)(e.x, e.y)\n })\n\n // `Exclusive(doubleTap, ...)` would make the pan wait for the double-tap to\n // *fail* before it may activate — and a two-tap gesture only fails once the\n // finger has moved past its delta threshold or its timing windows expire,\n // up to half a second. That gated the start of every drag, which is felt as\n // lag however fast the rest of the pipeline is.\n //\n // Racing them instead lets the pan activate the moment it passes touch\n // slop, while a stationary double-tap still wins because a tap never moves\n // far enough to activate the pan. This is the composition the overlay\n // surface uses, which is the one that feels immediate.\n return Gesture.Simultaneous(Gesture.Race(pan, doubleTap), pinch, rotate)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [metrics, canvas, intrinsic, config, settleTo, beginInteraction, runDoubleTap])\n\n if (!layer) return null\n return (\n <GestureDetector gesture={gesture}>\n <Animated.View style={StyleSheet.absoluteFill} />\n </GestureDetector>\n )\n}\n","import { type ResolvedMediaConfig } from '@pictor-sdk/core'\n\n/**\n * UI-thread twin of `composeMediaGesture` from @pictor-sdk/core.\n *\n * DECISION: the same deliberate duplication as `layerGestureWorklet`. Core must\n * stay free of Reanimated and must run in plain Node, so it cannot carry a\n * `'worklet'` directive; but the preview recomputes the transform every frame\n * on the UI thread, which requires one. `media-worklet-parity.test.ts` holds\n * the two implementations together across a grid of inputs, so they cannot\n * drift.\n *\n * Keep this file free of imports beyond types, and of closures over anything\n * but plain numbers and frozen config objects.\n */\nexport interface MediaWorkletTransform {\n x: number\n y: number\n scale: number\n rotation: number\n}\n\nexport interface MediaWorkletInput {\n panX: number\n panY: number\n pinch: number\n rotate: number\n focalX: number\n focalY: number\n}\n\nexport interface MediaWorkletSize {\n width: number\n height: number\n}\n\n/** Mirror of core's `mediaFitScale`. */\nexport function mediaFitScaleUI(\n intrinsic: MediaWorkletSize,\n canvas: MediaWorkletSize,\n fit: 'width' | 'cover' | 'contain',\n rotation: number,\n): number {\n 'worklet'\n if (intrinsic.width <= 0 || intrinsic.height <= 0) return 1\n if (fit === 'width') return 1\n const w = canvas.width\n const h = canvas.width * (intrinsic.height / intrinsic.width)\n const cos = Math.abs(Math.cos(rotation))\n const sin = Math.abs(Math.sin(rotation))\n const byWidth = canvas.width / (w * cos + h * sin)\n const byHeight = canvas.height / (w * sin + h * cos)\n return fit === 'cover' ? Math.max(byWidth, byHeight) : Math.min(byWidth, byHeight)\n}\n\n/** Mirror of core's `mediaPanBounds`. */\nexport function mediaPanBoundsUI(\n _intrinsic: MediaWorkletSize,\n _canvas: MediaWorkletSize,\n _scale: number,\n _rotation: number,\n): { minX: number; maxX: number; minY: number; maxY: number } {\n 'worklet'\n // Mirror of core's `mediaPanBounds`: the media is freely positionable, held\n // only so its anchor stays on the canvas and it can always be dragged back.\n return { minX: 0, maxX: 1, minY: 0, maxY: 1 }\n}\n\n/** Mirror of core's `composeMediaGesture`. */\nexport function composeMediaGestureUI(\n base: MediaWorkletTransform,\n input: MediaWorkletInput,\n canvas: MediaWorkletSize,\n intrinsic: MediaWorkletSize,\n config: ResolvedMediaConfig,\n settle: boolean,\n): MediaWorkletTransform {\n 'worklet'\n const rotationDelta = config.rotationEnabled ? input.rotate : 0\n const rotation = base.rotation + rotationDelta\n\n const fit = mediaFitScaleUI(intrinsic, canvas, config.fit, rotation)\n const minScale = fit * config.minScaleFactor\n const maxScale = Math.max(minScale, config.maxScale)\n\n const requested = base.scale * input.pinch\n let scale: number\n if (settle) {\n scale = Math.min(maxScale, Math.max(minScale, requested))\n } else if (requested < minScale) {\n scale = minScale - (minScale - requested) * config.resistance\n } else if (requested > maxScale) {\n scale = maxScale + (requested - maxScale) * config.resistance\n } else {\n scale = requested\n }\n\n const aspect = canvas.height / canvas.width\n const ratio = scale / Math.max(base.scale, 1e-9)\n const dx = base.x - input.focalX\n const dy = (base.y - input.focalY) * aspect\n const cos = Math.cos(rotationDelta)\n const sin = Math.sin(rotationDelta)\n const rx = (dx * cos - dy * sin) * ratio\n const ry = (dx * sin + dy * cos) * ratio\n\n const rawX = input.focalX + rx + input.panX\n const rawY = input.focalY + ry / aspect + input.panY\n\n const bounds = mediaPanBoundsUI(intrinsic, canvas, scale, rotation)\n let x: number\n let y: number\n if (settle) {\n x = Math.min(bounds.maxX, Math.max(bounds.minX, rawX))\n y = Math.min(bounds.maxY, Math.max(bounds.minY, rawY))\n } else {\n x =\n rawX < bounds.minX\n ? bounds.minX - (bounds.minX - rawX) * config.resistance\n : rawX > bounds.maxX\n ? bounds.maxX + (rawX - bounds.maxX) * config.resistance\n : rawX\n y =\n rawY < bounds.minY\n ? bounds.minY - (bounds.minY - rawY) * config.resistance\n : rawY > bounds.maxY\n ? bounds.maxY + (rawY - bounds.maxY) * config.resistance\n : rawY\n }\n\n return { x, y, scale, rotation }\n}\n\n// ─────────────────────────────────────────────────────────────\n// Recognizer lifecycle\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Pan, pinch and rotation run simultaneously, and each finalises on its own.\n * Lifting one finger of a two-finger gesture finalises pinch and rotation while\n * the pan recognizer keeps running with the remaining finger — so an\n * interaction must only be considered over once *every* recognizer has\n * finalised. Counting them is what makes two-fingers-to-one continuous instead\n * of ending the gesture early.\n *\n * Pure and worklet-safe so the surface and its tests share one definition.\n */\nexport function onRecognizerBegin(count: number): { count: number; isFirst: boolean } {\n 'worklet'\n const next = Math.max(0, count) + 1\n return { count: next, isFirst: next === 1 }\n}\n\n/** Returns `isLast` only when this was the final live recognizer. */\nexport function onRecognizerEnd(count: number): { count: number; isLast: boolean } {\n 'worklet'\n const next = Math.max(0, count - 1)\n return { count: next, isLast: next === 0 && count > 0 }\n}\n","/**\n * Coordinates the settle animation and the single document write that follows\n * it.\n *\n * Committing *while* the animation runs is the trap: the commit changes the\n * document, which re-seeds the live shared values from the committed\n * transform, which cancels the animation that was still running. So the commit\n * has to happen when the animation reports completion, not when it is started.\n *\n * Kept pure — the animator and the commit are injected — so the ordering rules\n * below are unit-testable without Reanimated:\n *\n * - a settle commits exactly once, when its animation finishes;\n * - an animation that is interrupted commits nothing;\n * - a newer settle supersedes an older one, so a late completion from the\n * superseded animation cannot commit stale values;\n * - `cancel()` (tool dismissed, unmount) prevents any pending commit.\n */\nexport interface SettleAnimation {\n /** Run the animation; call `done(true)` on completion, `done(false)` if interrupted. */\n (done: (finished: boolean) => void): void\n}\n\nexport interface SettleCoordinator<T> {\n /** Animate toward `target`, committing it when the animation completes. */\n settle(target: T, animate: SettleAnimation): void\n /** Abandon any settle in flight without committing. */\n cancel(): void\n /** True while an animation is running and its commit is still pending. */\n isSettling(): boolean\n}\n\nexport function createSettleCoordinator<T>(commit: (target: T) => void): SettleCoordinator<T> {\n // Monotonic token: only the newest settle may commit. Cancelling bumps it too,\n // so a completion callback that arrives afterwards is ignored.\n let generation = 0\n let settling = false\n\n return {\n settle(target, animate) {\n generation += 1\n const mine = generation\n settling = true\n animate((finished) => {\n if (mine !== generation) return // superseded, cancelled, or already resolved\n generation += 1 // one completion per settle, whatever the animator does\n settling = false\n if (finished) commit(target)\n })\n },\n\n cancel() {\n generation += 1\n settling = false\n },\n\n isSettling() {\n return settling\n },\n }\n}\n","import { isSameTransform, type Transform } from '@pictor-sdk/core'\n\n/**\n * Who owns a layer's live transform: the gesture surface, or the document.\n *\n * The surface drives `live*` shared values while a gesture or its settle runs,\n * and the canvas draws them as a delta from the transform the document holds.\n * The handover back to the document is the delicate part, and getting it wrong\n * is visible as a single-frame flash:\n *\n * - release ownership when `dispatch` is *called* and the resync can fire while\n * the document still holds the old transform, snapping `live` back to it for\n * one frame;\n * - never release it and an undo or a Cancel cannot reseed `live` at all.\n *\n * So ownership ends when the document actually reports the transform that was\n * committed — not before. Until then `live` is already correct and must be left\n * alone. Pure and synchronous, so the ordering is unit-testable.\n */\nexport interface OwnershipState {\n /** True while the surface, not the document, decides the transform. */\n owning: boolean\n /** A transform dispatched but not yet observed on the document. */\n pending: Transform | null\n /**\n * What the document held when `pending` was dispatched.\n *\n * Needed to tell \"our commit has not landed yet\" from \"something else\n * changed the document\": both merely differ from `pending`, and only the\n * second should reseed.\n */\n previous: Transform | null\n}\n\nexport const IDLE_OWNERSHIP: OwnershipState = { owning: false, pending: null, previous: null }\n\n/** A gesture or animation takes the transform. */\nexport function beginOwnership(): OwnershipState {\n return { owning: true, pending: null, previous: null }\n}\n\n/**\n * The surface committed `target`.\n *\n * `dispatched` is false when the commit was a no-op — the transform never\n * changed, so no document update is coming and ownership ends immediately.\n */\nexport function commitOwnership(\n target: Transform,\n dispatched: boolean,\n previous?: Transform,\n): OwnershipState {\n return dispatched\n ? { owning: true, pending: target, previous: previous ?? null }\n : IDLE_OWNERSHIP\n}\n\nexport interface DocumentChange {\n state: OwnershipState\n /** Whether `live*` should be reseeded from the document. */\n reseed: boolean\n}\n\n/**\n * The document's transform for this layer changed, or the effect re-ran.\n *\n * Reseeding is for changes the surface did not make — undo, Cancel, a new\n * photo. A change the surface itself dispatched needs no reseed: `live` is\n * already sitting on exactly that value, and rewriting it is what introduces\n * the flash.\n */\nexport function documentChanged(\n state: OwnershipState,\n committed: Transform | undefined,\n): DocumentChange {\n if (!committed) return { state, reseed: false }\n if (state.pending) {\n // our commit landed: `live` is already on it, so hand back without touching\n if (isSameTransform(state.pending, committed)) return { state: IDLE_OWNERSHIP, reseed: false }\n // the document still holds what it did when we dispatched — the update has\n // simply not rendered yet. Reseeding here is the one-frame flash.\n if (state.previous && isSameTransform(state.previous, committed)) {\n return { state, reseed: false }\n }\n // anything else means something outside changed the document first; that\n // wins, and our pending commit is stale\n return { state: IDLE_OWNERSHIP, reseed: true }\n }\n if (state.owning) return { state, reseed: false }\n return { state, reseed: true }\n}\n","/**\n * Which gesture surface owns the canvas.\n *\n * Precedence is decided by the active tool and nothing else, so it is a pure\n * function that can be tested without mounting anything — and so the rule is\n * stated in one place rather than implied by JSX nesting.\n */\nexport type GestureSurfaceKind = 'media' | 'draw' | 'crop' | 'tilt' | 'text' | 'overlay'\n\n/**\n * Resolve the surface for the active tool.\n *\n * - `text` — the full-screen composer owns the screen, so **no** canvas surface\n * is mounted at all. Not mounting is the strongest form of \"disabled\": there\n * is no recogniser to arbitrate with, so a tap meant for the caret cannot\n * start a canvas gesture, and a drag begins immediately once composing ends.\n * - `media` — the base photo tool owns the surface, so the photo moves and\n * overlays are inert.\n * - `draw` — drawing owns the surface, so strokes are never interpreted as\n * layer drags.\n * - `crop` — the Post crop surface.\n * - `tilt` — placing the selective-focus region, which needs the whole canvas;\n * overlay hit-testing would steal the drag to whatever sits under the finger.\n * - anything else (including no active tool) — overlay hit-testing, which\n * excludes the base photo, so dragging text or a sticker cannot move it.\n */\nexport function resolveGestureSurface(activeTool: string | null | undefined): GestureSurfaceKind {\n switch (activeTool) {\n case 'text':\n return 'text'\n case 'media':\n return 'media'\n case 'draw':\n return 'draw'\n case 'crop':\n return 'crop'\n case 'tilt':\n return 'tilt'\n default:\n return 'overlay'\n }\n}\n","import { deleteTargetFromProfile, useEditor } from '@pictor-sdk/core'\nimport { useCanvasMetrics } from '@pictor-sdk/skia'\nimport React from 'react'\nimport { StyleSheet, Text, View } from 'react-native'\nimport { useTheme } from '../theme'\nimport { useInteractionState } from './interactionState'\n\n/** The centre and rotation guides shown while a layer snaps. */\nexport interface InteractionGuidesProps {\n /** Label shown above the delete target. */\n deleteLabel?: string\n}\n\n/**\n * Alignment guides and the drag-to-delete target.\n *\n * DECISION: these are plain React Native views layered over `<EditorCanvas>`,\n * not Skia nodes inside `renderDocument`. Transient interaction chrome then\n * has no way of reaching an export — stronger than an `isExport` check — and\n * the single render path (invariant 1) stays untouched.\n *\n * Render as a child of `<EditorCanvas>`, which sizes its children to the\n * fitted document box, so percentage offsets here are document-relative.\n */\nexport function InteractionGuides({ deleteLabel = 'Drag to delete' }: InteractionGuidesProps) {\n const { profile } = useEditor()\n const metrics = useCanvasMetrics()\n const theme = useTheme()\n const { snap, layerDragActive, overDeleteTarget } = useInteractionState()\n const target = deleteTargetFromProfile(profile.interaction?.layers)\n\n if (!metrics) return null\n\n // radius is in document-WIDTH units, so it maps through the canvas width\n const radius = target ? target.radius * metrics.width : 0\n const size = radius * 2\n const active = overDeleteTarget\n\n return (\n <View pointerEvents=\"none\" style={StyleSheet.absoluteFill}>\n {snap.centerX ? (\n <View\n style={{\n position: 'absolute',\n left: metrics.width / 2 - 1,\n top: 0,\n width: 2,\n height: metrics.height,\n backgroundColor: theme.colors.accent,\n }}\n />\n ) : null}\n {snap.centerY ? (\n <View\n style={{\n position: 'absolute',\n top: metrics.height / 2 - 1,\n left: 0,\n height: 2,\n width: metrics.width,\n backgroundColor: theme.colors.accent,\n }}\n />\n ) : null}\n\n {snap.rotation ? (\n <View\n style={{\n position: 'absolute',\n top: theme.spacing.md,\n alignSelf: 'center',\n backgroundColor: 'rgba(0,0,0,0.6)',\n borderRadius: theme.radii.lg,\n paddingHorizontal: theme.spacing.md,\n paddingVertical: theme.spacing.xs,\n }}\n >\n <Text\n style={{\n color: theme.colors.text,\n fontSize: theme.font.sizeSm,\n fontWeight: theme.font.weight,\n }}\n >\n Right-angle snap\n </Text>\n </View>\n ) : null}\n\n {target && layerDragActive ? (\n <View\n style={{\n position: 'absolute',\n left: target.x * metrics.width - radius,\n top: target.y * metrics.height - radius,\n width: size,\n height: size,\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <View\n style={{\n width: size,\n height: size,\n borderRadius: radius,\n borderWidth: 2,\n borderColor: theme.colors.text,\n // a scrim keeps the target legible over light photos, which a\n // plain white ring is not\n backgroundColor: active ? theme.colors.danger : 'rgba(0,0,0,0.45)',\n alignItems: 'center',\n justifyContent: 'center',\n transform: [{ scale: active ? 1.15 : 1 }],\n }}\n >\n <Text\n style={{\n color: theme.colors.text,\n fontSize: radius * 0.7,\n fontWeight: theme.font.weight,\n }}\n >\n ×\n </Text>\n </View>\n </View>\n ) : null}\n\n {/* the label sits in the full-canvas box, not the target-sized one, so a\n longer or translated string is never clipped by the target diameter */}\n {target && layerDragActive ? (\n <View\n style={{\n position: 'absolute',\n left: 0,\n right: 0,\n top: target.y * metrics.height - radius - theme.spacing.lg * 2,\n alignItems: 'center',\n }}\n >\n <Text\n style={{\n color: theme.colors.text,\n fontSize: theme.font.sizeSm,\n fontWeight: theme.font.weight,\n backgroundColor: 'rgba(0,0,0,0.45)',\n paddingHorizontal: theme.spacing.sm,\n paddingVertical: theme.spacing.xs,\n borderRadius: theme.radii.sm,\n overflow: 'hidden',\n }}\n numberOfLines={1}\n >\n {deleteLabel}\n </Text>\n </View>\n ) : null}\n </View>\n )\n}\n","import { createContext, useContext } from 'react'\n\n/**\n * Theming is one token object on context — no style props on individual\n * components (ARCHITECTURE.md). Override any subset via <Editor theme={…}>.\n */\nexport interface EditorTheme {\n colors: {\n background: string\n surface: string\n text: string\n textMuted: string\n accent: string\n danger: string\n track: string\n thumb: string\n }\n radii: { sm: number; md: number; lg: number }\n spacing: { xs: number; sm: number; md: number; lg: number }\n font: { size: number; sizeSm: number; weight: '400' | '500' | '600' | '700' }\n}\n\n/** The bundled dark theme. Every value is overridable; see {@link mergeTheme}. */\nexport const defaultTheme: EditorTheme = {\n colors: {\n background: '#000000',\n surface: '#121212',\n text: '#ffffff',\n textMuted: '#9a9a9a',\n accent: '#3897f0',\n danger: '#ed4956',\n track: '#3a3a3a',\n thumb: '#ffffff',\n },\n radii: { sm: 6, md: 10, lg: 16 },\n spacing: { xs: 4, sm: 8, md: 14, lg: 22 },\n font: { size: 15, sizeSm: 12, weight: '600' },\n}\n\n/** A theme override — any subset of any group, the rest falling back to the default. */\nexport type PartialTheme = {\n [K in keyof EditorTheme]?: Partial<EditorTheme[K]>\n}\n\n/** Apply an override onto the default theme, one group at a time. */\nexport function mergeTheme(overrides?: PartialTheme): EditorTheme {\n if (!overrides) return defaultTheme\n return {\n colors: { ...defaultTheme.colors, ...overrides.colors },\n radii: { ...defaultTheme.radii, ...overrides.radii },\n spacing: { ...defaultTheme.spacing, ...overrides.spacing },\n font: { ...defaultTheme.font, ...overrides.font },\n }\n}\n\n/** Carries the resolved theme. `<Editor>` provides it; components read it with {@link useTheme}. */\nexport const ThemeContext = createContext<EditorTheme>(defaultTheme)\n/** The theme in effect. Defaults outside an `<Editor>` rather than throwing. */\nexport function useTheme(): EditorTheme {\n return useContext(ThemeContext)\n}\n","import { useEditor, useTools, type ToolPanelProps } from '@pictor-sdk/core'\nimport React, { useEffect, useRef, type ComponentType } from 'react'\nimport { Pressable, Text, View } from 'react-native'\nimport { useTheme } from './theme'\nimport { AdjustPanel } from './panels/AdjustPanel'\nimport { AddPhotoPanel } from './panels/AddPhotoPanel'\nimport { ColorPanel } from './panels/ColorPanel'\nimport { CropPanel } from './panels/CropPanel'\nimport { DrawPanel } from './panels/DrawPanel'\nimport { FilterStrip } from './panels/FilterStrip'\nimport { LayoutPanel } from './panels/LayoutPanel'\nimport { LuxPanel } from './panels/LuxPanel'\nimport { MediaPanel } from './panels/MediaPanel'\nimport { LayersPanel } from './panels/LayersPanel'\nimport { PerspectivePanel } from './panels/PerspectivePanel'\nimport { StickerPanel } from './panels/StickerPanel'\nimport { TiltShiftPanel } from './panels/TiltShiftPanel'\n\n/**\n * Built-in panels for the built-in tool ids. Pure — unit tested.\n *\n * `text` deliberately has no panel: the text tool is served by the full-screen\n * composer slot, which owns its own controls. Leaving a panel here would open a\n * second history batch alongside the composer's and render a bottom sheet\n * underneath it.\n */\nexport function resolvePanel(\n toolId: string | null,\n pluginPanel: unknown,\n builtins: Record<string, ComponentType> = BUILTIN_PANELS,\n): ComponentType<Partial<ToolPanelProps>> | null {\n if (!toolId) return null\n if (pluginPanel) return pluginPanel as ComponentType<Partial<ToolPanelProps>>\n return (builtins[toolId] as ComponentType<Partial<ToolPanelProps>>) ?? null\n}\n\nexport const BUILTIN_PANELS: Record<string, ComponentType> = {\n media: MediaPanel,\n addPhoto: AddPhotoPanel,\n filter: FilterStrip,\n adjust: AdjustPanel,\n lux: LuxPanel,\n color: ColorPanel,\n tilt: TiltShiftPanel,\n perspective: PerspectivePanel,\n crop: CropPanel,\n draw: DrawPanel,\n sticker: StickerPanel,\n layout: LayoutPanel,\n layers: LayersPanel,\n}\n\n/** Renders the active tool's panel — plugin-provided Panel wins over built-ins. */\nexport function ToolPanelHost() {\n const { activeTool, document, selection, dispatch, setActiveTool } = useEditor()\n const tools = useTools()\n const tool = tools.find((t) => t.id === activeTool)\n const Panel = resolvePanel(activeTool, tool?.Panel)\n const theme = useTheme()\n const finalized = useRef(false)\n\n useEffect(() => {\n if (!activeTool || !Panel) return\n finalized.current = false\n dispatch({ type: 'history/beginBatch', label: activeTool })\n return () => {\n if (!finalized.current) dispatch({ type: 'history/cancelBatch' })\n }\n }, [activeTool, Panel, dispatch])\n\n if (!Panel) return null\n const done = () => {\n finalized.current = true\n dispatch({ type: 'history/endBatch' })\n setActiveTool(null)\n }\n const cancel = () => {\n finalized.current = true\n dispatch({ type: 'history/cancelBatch' })\n setActiveTool(null)\n }\n return (\n <View style={{ backgroundColor: theme.colors.background, borderTopLeftRadius: theme.radii.lg, borderTopRightRadius: theme.radii.lg, overflow: 'hidden' }}>\n <Panel document={document} selection={selection} dispatch={dispatch} close={done} />\n <View style={{ height: 52, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', borderTopWidth: 1, borderTopColor: theme.colors.track, paddingHorizontal: theme.spacing.lg }}>\n <Pressable accessibilityRole=\"button\" accessibilityLabel=\"Cancel edits\" onPress={cancel}>\n <Text style={{ color: theme.colors.text, fontSize: theme.font.size }}>Cancel</Text>\n </Pressable>\n <Text style={{ color: theme.colors.text, fontSize: theme.font.size, fontWeight: theme.font.weight }}>\n {tool?.label ?? activeTool}\n </Text>\n <Pressable accessibilityRole=\"button\" accessibilityLabel=\"Apply edits\" onPress={done}>\n <Text style={{ color: theme.colors.accent, fontSize: theme.font.size, fontWeight: theme.font.weight }}>Done</Text>\n </Pressable>\n </View>\n </View>\n )\n}\n","import {\n adjustmentResetPatch,\n hasAdjustment,\n useEditor,\n useEditorStore,\n type Adjustments,\n type ImageLayerData,\n} from '@pictor-sdk/core'\nimport React, { useState } from 'react'\nimport { Pressable, ScrollView, Text, View } from 'react-native'\nimport { useTheme } from '../theme'\nimport { Slider } from '../components/Slider'\nimport { useTargetImageLayer } from './useTargetImageLayer'\n\nconst LABELS: Record<string, string> = {\n brightness: 'Brightness',\n contrast: 'Contrast',\n saturation: 'Saturation',\n warmth: 'Warmth',\n tint: 'Tint',\n exposure: 'Exposure',\n highlights: 'Highlights',\n shadows: 'Shadows',\n fade: 'Fade',\n structure: 'Structure',\n sharpen: 'Sharpen',\n grain: 'Grain',\n vignette: 'Vignette',\n}\n\n/**\n * The Adjust tab: the 13 tools from profile/registry order, one centred\n * slider with a detent at 0 (a 0 adjustment is a provable render no-op).\n */\nexport function AdjustPanel() {\n const { dispatch } = useEditor()\n const store = useEditorStore()\n const theme = useTheme()\n const layer = useTargetImageLayer()\n const keys = store.registry.adjustments\n const [activeKey, setActiveKey] = useState(keys[0] ?? 'brightness')\n\n if (!layer) return null\n const adjustments: Adjustments = (layer.data as ImageLayerData).color.adjustments ?? {}\n const value = adjustments[activeKey] ?? 0\n const touchedActive = hasAdjustment(adjustments, activeKey)\n\n /**\n * Clear the active adjustment, and only it.\n *\n * No batch of its own: the adjust tool session already opened one, so this\n * belongs to that session's single undo entry — Cancel rolls it back with\n * everything else, and Done commits it as part of the whole.\n */\n const resetActive = () =>\n dispatch({\n type: 'layer/patchData',\n id: layer.id,\n patch: adjustmentResetPatch(activeKey) as Record<string, unknown>,\n })\n\n return (\n <View style={{ backgroundColor: theme.colors.background }}>\n <View style={{ paddingHorizontal: theme.spacing.lg }}>\n {/* Value readout, with an inline reset once the adjustment is set —\n the affordance Instagram uses, and the one the milestone asks for:\n it clears this adjustment only. */}\n <View\n style={{\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'center',\n gap: theme.spacing.sm,\n minHeight: 28,\n }}\n >\n <Text\n style={{\n color: theme.colors.textMuted,\n textAlign: 'center',\n fontSize: theme.font.sizeSm,\n }}\n >\n {LABELS[activeKey] ?? activeKey}{' '}\n {value === 0 ? '' : (value > 0 ? '+' : '') + Math.round(value * 100)}\n </Text>\n {touchedActive ? (\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={`Reset ${LABELS[activeKey] ?? activeKey}`}\n onPress={resetActive}\n hitSlop={8}\n style={{\n paddingHorizontal: theme.spacing.sm,\n paddingVertical: 2,\n borderRadius: theme.radii.sm,\n borderWidth: 1,\n borderColor: theme.colors.track,\n }}\n >\n <Text style={{ color: theme.colors.text, fontSize: theme.font.sizeSm }}>Reset</Text>\n </Pressable>\n ) : null}\n </View>\n <Slider\n value={value}\n min={-1}\n max={1}\n centered\n valueLabel={`${value > 0 ? '+' : ''}${Math.round(value * 100)}`}\n onStart={() => dispatch({ type: 'history/beginBatch', label: activeKey })}\n onChange={(v) =>\n dispatch({\n type: 'layer/patchData',\n id: layer.id,\n patch: { color: { adjustments: { [activeKey]: v } } },\n })\n }\n onEnd={() => dispatch({ type: 'history/endBatch' })}\n />\n </View>\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{ gap: theme.spacing.sm, padding: theme.spacing.md }}\n style={{ flexGrow: 0 }}\n >\n {keys.map((key) => {\n const touched = (adjustments[key] ?? 0) !== 0\n const active = key === activeKey\n return (\n <Pressable\n key={key}\n onPress={() => setActiveKey(key)}\n style={{ alignItems: 'center', gap: 6, width: 76 }}\n >\n <View style={{ width: 48, height: 48, borderRadius: 24, borderWidth: 1, borderColor: active ? theme.colors.accent : theme.colors.textMuted, backgroundColor: active ? theme.colors.surface : 'transparent', alignItems: 'center', justifyContent: 'center' }}>\n <Text style={{ color: active ? theme.colors.accent : theme.colors.text, fontSize: 18 }}>\n {(LABELS[key] ?? key).slice(0, 1)}\n </Text>\n </View>\n <Text\n style={{\n color: active ? theme.colors.accent : touched ? theme.colors.text : theme.colors.textMuted,\n fontSize: theme.font.sizeSm,\n fontWeight: theme.font.weight,\n }}\n >\n {LABELS[key] ?? key}\n {touched ? ' •' : ''}\n </Text>\n </Pressable>\n )\n })}\n </ScrollView>\n </View>\n )\n}\n","import React, { useMemo, useRef, useState } from 'react'\nimport { Text, View, type LayoutChangeEvent } from 'react-native'\nimport { Gesture, GestureDetector } from 'react-native-gesture-handler'\nimport Animated from 'react-native-reanimated'\nimport { runOnJS } from 'react-native-worklets'\nimport { useTheme } from '../theme'\n\n/**\n * A slider's value and range.\n *\n * `centered` is the adjustment shape — `-1..1` resting in the middle with a\n * detent at zero. A quantity with no meaningful negative (Lux, tint strength,\n * blur) uses `min: 0` and `centered: false` instead, which is the control shape\n * measured on the reference editor.\n */\nexport interface SliderProps {\n /** -1..1 when centered, 0..1 otherwise */\n value: number\n min?: number\n max?: number\n /** show a centre detent and snap to 0 within ±0.05 (adjustment sliders) */\n centered?: boolean\n onStart?: () => void\n onChange: (value: number) => void\n onEnd?: () => void\n testID?: string\n /** Floating value label shown above the thumb. */\n valueLabel?: string\n /**\n * Inert and dimmed. For a control whose value has nothing meaningful to\n * write yet — dragging it would record something untrue.\n */\n disabled?: boolean\n}\n\n/** Snap a centered slider value into its detent. Pure — unit tested. */\nexport function applyDetent(value: number, centered: boolean, width = 0.05): number {\n if (centered && Math.abs(value) < width) return 0\n return value\n}\n\n/** Dependency-free horizontal slider with an optional centre detent. */\nexport function Slider({\n value,\n min = -1,\n max = 1,\n centered = true,\n onStart,\n onChange,\n onEnd,\n testID,\n valueLabel,\n disabled = false,\n}: SliderProps) {\n const theme = useTheme()\n const [width, setWidth] = useState(0)\n const widthRef = useRef(0)\n const startValue = useRef(value)\n const valueRef = useRef(value)\n valueRef.current = value\n\n const onLayout = (e: LayoutChangeEvent) => {\n setWidth(e.nativeEvent.layout.width)\n widthRef.current = e.nativeEvent.layout.width\n }\n\n const handlers = useMemo(() => {\n const begin = () => {\n startValue.current = valueRef.current\n onStart?.()\n }\n const update = (tx: number) => {\n const w = widthRef.current\n if (w === 0) return\n const range = max - min\n const raw = startValue.current + (tx / w) * range\n const clamped = Math.min(max, Math.max(min, raw))\n onChange(applyDetent(clamped, centered && min < 0))\n }\n const finish = () => onEnd?.()\n return { begin, update, finish }\n }, [min, max, centered, onChange, onStart, onEnd])\n\n const gesture = useMemo(\n () =>\n Gesture.Pan()\n .enabled(!disabled)\n .onStart(() => {\n 'worklet'\n runOnJS(handlers.begin)()\n })\n .onUpdate((e) => {\n 'worklet'\n runOnJS(handlers.update)(e.translationX)\n })\n .onFinalize(() => {\n 'worklet'\n runOnJS(handlers.finish)()\n }),\n [handlers, disabled],\n )\n\n const t = (value - min) / (max - min)\n const thumbX = width * t\n\n return (\n <GestureDetector gesture={gesture}>\n <Animated.View\n testID={testID}\n onLayout={onLayout}\n style={{\n height: valueLabel ? 58 : 36,\n justifyContent: 'flex-end',\n paddingBottom: 9,\n opacity: disabled ? 0.4 : 1,\n }}\n >\n {valueLabel ? (\n <View\n pointerEvents=\"none\"\n style={{\n position: 'absolute',\n top: 0,\n left: Math.max(0, Math.min(width - 44, thumbX - 22)),\n width: 44,\n alignItems: 'center',\n paddingVertical: 3,\n borderRadius: 10,\n backgroundColor: theme.colors.surface,\n }}\n >\n <Text style={{ color: theme.colors.text, fontSize: theme.font.sizeSm }}>{valueLabel}</Text>\n </View>\n ) : null}\n <View style={{ height: 2, borderRadius: 1, backgroundColor: theme.colors.track }} />\n <View\n style={{\n position: 'absolute',\n bottom: 9,\n left: centered && min < 0 ? Math.min(width / 2, thumbX) : 0,\n width: centered && min < 0 ? Math.abs(thumbX - width / 2) : thumbX,\n height: 2,\n borderRadius: 1,\n backgroundColor: theme.colors.accent,\n }}\n />\n {centered && min < 0 ? (\n <View\n style={{\n position: 'absolute',\n left: width / 2 - 1,\n width: 2,\n height: 10,\n backgroundColor: theme.colors.textMuted,\n }}\n />\n ) : null}\n <View\n style={{\n position: 'absolute',\n bottom: 1,\n left: Math.max(0, Math.min(width - 18, thumbX - 9)),\n width: 18,\n height: 18,\n borderRadius: 9,\n backgroundColor: theme.colors.thumb,\n }}\n />\n </Animated.View>\n </GestureDetector>\n )\n}\n","import { useEditor } from '@pictor-sdk/core'\nimport React, { useEffect, useMemo, useState } from 'react'\nimport { Pressable, Text, View } from 'react-native'\nimport { useHostCallbacks } from '../hostCallbacks'\nimport { useTheme } from '../theme'\nimport { createAddPhotoController } from './addPhotoController'\n\n/**\n * The add-photo control: one press, one picker, one undo entry.\n *\n * Nothing happens on mount. Opening a picker because a panel appeared would\n * take the choice away from the user and make a stray tool tap launch the\n * gallery, so acquisition waits for an explicit press.\n *\n * All the asynchronous behaviour lives in `createAddPhotoController`, which is\n * testable without mounting anything. This is the shell.\n *\n * @experimental\n */\nexport function AddPhotoPanel() {\n const { dispatch, select } = useEditor()\n const host = useHostCallbacks()\n const theme = useTheme()\n const [pending, setPending] = useState(false)\n\n const controller = useMemo(\n () =>\n createAddPhotoController({\n // Read through the ref at call time, so a host re-creating its closure\n // does not rebuild the controller mid-request.\n requestImages: host.current.requestImages\n ? () => host.current.requestImages!()\n : undefined,\n dispatch,\n select,\n onError: (error) => host.current.onError?.(error),\n }),\n [dispatch, select, host],\n )\n\n // Disposal is what makes a late result harmless: the picker can resolve long\n // after the user has closed the tool.\n useEffect(() => () => controller.dispose(), [controller])\n\n // Session-scoped, like the panel's image target: whether a picker exists is\n // decided at mount. A host that wires `requestImages` while this is open sees\n // it on the next open.\n const available = controller.isAvailable()\n\n const press = async () => {\n if (!available || pending) return\n setPending(true)\n try {\n await controller.request()\n } finally {\n setPending(false)\n }\n }\n\n return (\n <View style={{ backgroundColor: theme.colors.background, padding: theme.spacing.lg }}>\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel=\"Add photos\"\n accessibilityState={{ disabled: !available || pending }}\n disabled={!available || pending}\n onPress={press}\n style={{\n paddingVertical: theme.spacing.md,\n borderRadius: theme.radii.sm,\n borderWidth: 1,\n borderColor: available ? theme.colors.accent : theme.colors.track,\n alignItems: 'center',\n opacity: available && !pending ? 1 : 0.45,\n }}\n >\n <Text\n style={{\n color: available ? theme.colors.accent : theme.colors.textMuted,\n fontSize: theme.font.size,\n fontWeight: theme.font.weight,\n }}\n >\n {pending ? 'Choosing…' : 'Add photos'}\n </Text>\n </Pressable>\n <Text\n style={{\n color: theme.colors.textMuted,\n fontSize: theme.font.sizeSm,\n textAlign: 'center',\n marginTop: theme.spacing.sm,\n }}\n >\n {available\n ? 'Pick one or more photos to place on the story'\n : `Unavailable — pass \\`requestImages\\` to <Editor>`}\n </Text>\n </View>\n )\n}\n","import {\n createImageLayers,\n insertImageCommands,\n type Dispatch,\n type InsertableImage,\n type InsertImageOptions,\n type InsertImageTransaction,\n} from '@pictor-sdk/core'\n\n/**\n * Acquiring photos from the host, then inserting them.\n *\n * Deliberately **not** a React component. Acquisition is asynchronous and has\n * to survive a re-render, refuse a second request while one is in flight, and\n * do nothing at all if the panel is gone by the time the host answers — none of\n * which is expressible as render logic, and all of which is worth testing\n * without mounting anything.\n *\n * Acquisition is also kept separate from insertion so a host that wants neither\n * this controller nor the default panel can call `createImageLayers` and\n * `insertImageCommands` directly.\n *\n * @experimental\n */\n\nexport interface AddPhotoControllerOptions {\n /**\n * Supplied by the host. Resolving `null` or `[]` means the user cancelled,\n * which must add nothing — no command, no selection change, no history entry.\n */\n requestImages?: () => Promise<readonly InsertableImage[] | null>\n dispatch: Dispatch\n select: (ids: string[]) => void\n /** Anything the host's picker throws, or a result that is not usable. */\n onError?: (error: unknown) => void\n /** Presentation and transaction options forwarded to the core helpers. */\n insert?: InsertImageOptions & InsertImageTransaction\n}\n\n/**\n * A live add-photo session.\n *\n * @experimental\n */\nexport interface AddPhotoController {\n /** Ask the host for photos and insert whatever comes back. */\n request: () => Promise<void>\n /** True while a request is in flight; a second press is ignored. */\n isPending: () => boolean\n /**\n * Whether the host supplied a way to ask at all.\n *\n * **Session-scoped.** Captured when the controller is created, which for the\n * bundled panel means when it mounts. A host that adds `requestImages` while\n * the panel is open sees it unavailable until the tool is reopened — the\n * mount is the session boundary everywhere else in this panel too, and a\n * control that becomes live mid-session is a stranger surprise than one that\n * waits for the next open.\n */\n isAvailable: () => boolean\n /** Called when the panel unmounts: a late result is then discarded. */\n dispose: () => void\n}\n\n/** An entry the library can actually insert. */\nfunction isInsertable(value: unknown): value is InsertableImage {\n if (typeof value !== 'object' || value === null) return false\n const source = (value as { source?: unknown }).source\n // `source` is deliberately `unknown` in the document model — a URI, a\n // `{ uri }`, a Metro asset id — so the only thing worth asserting is that the\n // host gave us *something* to resolve.\n return source !== undefined && source !== null && source !== ''\n}\n\n/**\n * A dense list of insertable images, or `null` if the result is unusable.\n *\n * Every index is checked with `in` rather than by iterating, because a sparse\n * array **skips its holes**: `new Array(3).every(fn)` is `true`, so a host\n * returning one would pass validation and go on to produce sparse layers and a\n * command list with `undefined` in it — dispatching `history/beginBatch` and\n * then failing part-way, leaving a batch open.\n *\n * Copied into a dense array before anything is constructed, so nothing\n * downstream has to think about holes again.\n */\nfunction toDenseImages(value: unknown): InsertableImage[] | null {\n if (!Array.isArray(value)) return null\n const dense: InsertableImage[] = []\n for (let index = 0; index < value.length; index++) {\n if (!(index in value)) return null\n const entry = value[index]\n if (!isInsertable(entry)) return null\n dense.push(entry)\n }\n return dense\n}\n\n/** A command the reducer could actually accept. */\nfunction isDispatchable(command: unknown): boolean {\n return (\n typeof command === 'object' &&\n command !== null &&\n typeof (command as { type?: unknown }).type === 'string'\n )\n}\n\n/**\n * The host resolved with something that is not a list of insertable images.\n *\n * Reported rather than coerced: guessing at a malformed result would insert\n * layers the host did not mean to add.\n *\n * @experimental\n */\nexport class InvalidImageResultError extends Error {\n constructor() {\n super('requestImages resolved with something that is not a list of images')\n this.name = 'InvalidImageResultError'\n }\n}\n\n/**\n * Wire a host's picker to the core insertion helpers.\n *\n * Acquisition stays separate from insertion, so a host that wants neither this\n * controller nor the default panel can call `createImageLayers` and\n * `insertImageCommands` itself.\n *\n * @experimental\n */\nexport function createAddPhotoController({\n requestImages,\n dispatch,\n select,\n onError,\n insert,\n}: AddPhotoControllerOptions): AddPhotoController {\n let pending = false\n let disposed = false\n\n return {\n isPending: () => pending,\n isAvailable: () => typeof requestImages === 'function',\n dispose: () => {\n disposed = true\n },\n async request() {\n // A second press while the picker is open must not open a second picker,\n // and must not ask the host twice for one intent.\n if (!requestImages || pending || disposed) return\n pending = true\n try {\n const result = await requestImages()\n // Disposal is checked *first*, before the result is even looked at.\n // Once the panel is gone the user has moved on, so nothing that comes\n // back matters — not a success, not a malformed result, and not an\n // error worth interrupting them about.\n if (disposed) return\n // Cancellation. Not an error, and nothing to do.\n if (result === null || result === undefined) return\n\n const images = toDenseImages(result)\n if (!images) {\n onError?.(new InvalidImageResultError())\n return\n }\n if (images.length === 0) return\n\n // Everything is built and checked before the *first* dispatch, so a\n // problem discovered late cannot leave a `beginBatch` open with no\n // matching end.\n const layers = createImageLayers(images, insert)\n const commands = insertImageCommands(layers, insert)\n if (!commands.every(isDispatchable)) {\n onError?.(new InvalidImageResultError())\n return\n }\n\n for (const command of commands) dispatch(command)\n // Only the last — the topmost photo, and the one the user ends up\n // looking at. Selecting all of them would invite a bulk edit that is\n // not designed.\n const last = layers[layers.length - 1]\n if (last) select([last.id])\n } catch (error) {\n // Same rule as a late success: after disposal, silence.\n if (!disposed) onError?.(error)\n } finally {\n // Cleared even after a failure, so reopening — or simply pressing\n // again — can try once more.\n pending = false\n }\n },\n }\n}\n","import {\n isInertTint,\n tintPatch,\n useEditor,\n type ColorTint,\n type ImageLayerData,\n} from '@pictor-sdk/core'\nimport React, { useState } from 'react'\nimport { Pressable, ScrollView, Text, View } from 'react-native'\nimport { Slider } from '../components/Slider'\nimport { useTheme } from '../theme'\nimport { useTargetImageLayer } from './useTargetImageLayer'\n\n/**\n * Split toning: a colour cast on the shadows, another on the highlights.\n *\n * Two ends, each with a palette and a strength. They are edited one at a time\n * because they are genuinely independent — the render masks confine each to its\n * own end of the tonal range — so showing both at once would suggest an\n * interaction that does not exist.\n *\n * The strength slider is one-directional and rests at zero, like Lux: a cast\n * has an amount, not a direction.\n */\n\n/**\n * Our own palette — eight hues spread around the wheel at a muted saturation.\n *\n * Deliberately not anyone else's swatch set. Muted rather than pure because a\n * fully saturated cast at any usable strength reads as a colour error; these\n * still shift the grade decisively at strength 1.\n */\nexport const TINT_SWATCHES: readonly string[] = [\n '#1f8a8a',\n '#2f6fd0',\n '#7a5cd0',\n '#c04a9e',\n '#c8443c',\n '#d99038',\n '#8a9a3f',\n '#3f9a6a',\n]\n\nconst ENDS = [\n { key: 'shadows', label: 'Shadows' },\n { key: 'highlights', label: 'Highlights' },\n] as const\n\n/** Strength given to a colour picked while the end has none yet. */\nconst INITIAL_STRENGTH = 0.5\n\nexport function ColorPanel() {\n const { dispatch } = useEditor()\n const theme = useTheme()\n const layer = useTargetImageLayer()\n const [end, setEnd] = useState<'shadows' | 'highlights'>('shadows')\n\n if (!layer) return null\n const data = layer.data as ImageLayerData\n const tint: ColorTint | undefined = data.color.tinting?.[end]\n const active = isInertTint(tint) ? undefined : tint\n\n const patch = (next: ColorTint | undefined) =>\n dispatch({\n type: 'layer/patchData',\n id: layer.id,\n patch: { color: tintPatch(end, next) } as unknown as Record<string, unknown>,\n })\n\n /** Picking the colour already applied clears this end — tap again to undo it. */\n const pick = (color: string) =>\n patch(\n active?.color === color\n ? undefined\n : { color, strength: active?.strength ?? INITIAL_STRENGTH },\n )\n\n return (\n <View style={{ backgroundColor: theme.colors.background, paddingBottom: theme.spacing.md }}>\n <View\n style={{\n flexDirection: 'row',\n justifyContent: 'center',\n gap: theme.spacing.md,\n paddingTop: theme.spacing.sm,\n }}\n >\n {ENDS.map(({ key, label }) => {\n const selected = key === end\n const set = !isInertTint(data.color.tinting?.[key])\n return (\n <Pressable\n key={key}\n accessibilityRole=\"button\"\n accessibilityLabel={`Tint ${label.toLowerCase()}`}\n onPress={() => setEnd(key)}\n style={{\n paddingHorizontal: theme.spacing.md,\n paddingVertical: 6,\n borderRadius: theme.radii.sm,\n borderWidth: 1,\n borderColor: selected ? theme.colors.accent : 'transparent',\n }}\n >\n <Text\n style={{\n color: selected ? theme.colors.accent : theme.colors.textMuted,\n fontSize: theme.font.sizeSm,\n fontWeight: theme.font.weight,\n }}\n >\n {label}\n {set ? ' •' : ''}\n </Text>\n </Pressable>\n )\n })}\n </View>\n\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{ gap: theme.spacing.sm, paddingHorizontal: theme.spacing.lg, paddingVertical: theme.spacing.md }}\n style={{ flexGrow: 0 }}\n >\n {TINT_SWATCHES.map((color) => (\n <Pressable\n key={color}\n accessibilityRole=\"button\"\n accessibilityLabel={`Tint ${end} ${color}`}\n onPress={() => pick(color)}\n style={{\n width: 40,\n height: 40,\n borderRadius: 20,\n backgroundColor: color,\n borderWidth: active?.color === color ? 3 : 1,\n borderColor: active?.color === color ? theme.colors.text : theme.colors.track,\n }}\n />\n ))}\n </ScrollView>\n\n <View style={{ paddingHorizontal: theme.spacing.lg }}>\n <View\n style={{\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'center',\n gap: theme.spacing.sm,\n minHeight: 28,\n }}\n >\n <Text style={{ color: theme.colors.textMuted, fontSize: theme.font.sizeSm }}>\n {active ? `Strength ${Math.round(active.strength * 100)}` : 'Pick a colour'}\n </Text>\n {active ? (\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={`Reset ${end} tint`}\n onPress={() => patch(undefined)}\n hitSlop={8}\n style={{\n paddingHorizontal: theme.spacing.sm,\n paddingVertical: 2,\n borderRadius: theme.radii.sm,\n borderWidth: 1,\n borderColor: theme.colors.track,\n }}\n >\n <Text style={{ color: theme.colors.text, fontSize: theme.font.sizeSm }}>Reset</Text>\n </Pressable>\n ) : null}\n </View>\n <Slider\n value={active?.strength ?? 0}\n min={0}\n max={1}\n centered={false}\n testID=\"tint-strength\"\n disabled={!active}\n valueLabel={`${Math.round((active?.strength ?? 0) * 100)}`}\n onStart={() => dispatch({ type: 'history/beginBatch', label: `tint-${end}` })}\n onChange={(strength) => {\n if (!active) return\n patch({ color: active.color, strength })\n }}\n onEnd={() => dispatch({ type: 'history/endBatch' })}\n />\n </View>\n </View>\n )\n}\n","import {\n cropFitScale,\n flipPatch,\n isFlipped,\n useEditor,\n useEditorStore,\n type FlipAxis,\n type ImageLayerData,\n} from '@pictor-sdk/core'\nimport React from 'react'\nimport { Pressable, ScrollView, Text, View } from 'react-native'\nimport { useTheme } from '../theme'\nimport { StraightenRuler } from '../components/StraightenRuler'\nimport { useTargetImageLayer } from './useTargetImageLayer'\nimport {\n canvasSizeForAspect,\n} from './cropMath'\n\nfunction aspectLabel(aspect: number | 'free'): string {\n if (aspect === 'free') return 'Free'\n const known: Array<[number, string]> = [\n [4 / 5, '4:5'],\n [1, '1:1'],\n [16 / 9, '16:9'],\n [9 / 16, '9:16'],\n [3 / 4, '3:4'],\n [4 / 3, '4:3'],\n ]\n for (const [value, label] of known) {\n if (Math.abs(aspect - value) < 1e-6) return label\n }\n return aspect.toFixed(2)\n}\n\n/** Crop tool: aspect presets from the profile, 90° rotate, straighten dial. */\nexport function CropPanel() {\n const { document, dispatch, profile } = useEditor()\n useEditorStore() // subscribe\n const theme = useTheme()\n const layer = useTargetImageLayer()\n if (!layer) return null\n const data = layer.data as ImageLayerData\n const straighten = data.straighten ?? 0\n\n const applyAspect = (aspect: number | 'free') => {\n const nextSize = canvasSizeForAspect(document.size, aspect)\n dispatch({ type: 'history/beginBatch', label: 'aspect' })\n dispatch({ type: 'doc/patch', patch: { size: nextSize } })\n dispatch({ type: 'layer/patchData', id: layer.id, patch: { crop: undefined } })\n dispatch({\n type: 'layer/transform',\n id: layer.id,\n patch: {\n x: 0.5,\n y: 0.5,\n scale: cropFitScale(data.intrinsic, nextSize, profile.interaction?.crop?.fit ?? 'contain'),\n },\n })\n dispatch({ type: 'history/endBatch' })\n }\n\n const rotate90 = () => {\n const current = layer.transform.rotation\n const rotation = current + Math.PI / 2\n dispatch({\n type: 'layer/transform',\n id: layer.id,\n patch: {\n rotation,\n x: 0.5,\n y: 0.5,\n scale: cropFitScale(data.intrinsic, document.size, profile.interaction?.crop?.fit ?? 'contain', rotation),\n },\n })\n }\n\n /**\n * Mirror the photo on one axis.\n *\n * No batch of its own: the crop tool session already opened one, so a flip\n * joins that session's single undo entry and Cancel rolls it back with the\n * rest. Only the flip flag changes — the crop window, straighten, position\n * and scale are all left alone, and hit-testing follows because it reads the\n * same flag the renderer does.\n */\n const flip = (axis: FlipAxis) =>\n dispatch({\n type: 'layer/transform',\n id: layer.id,\n patch: flipPatch(layer.transform, axis),\n })\n\n return (\n <View style={{ backgroundColor: theme.colors.background }}>\n <View style={{ paddingHorizontal: theme.spacing.lg }}>\n <StraightenRuler\n value={(straighten * 180) / Math.PI}\n min={-45}\n max={45}\n onStart={() => dispatch({ type: 'history/beginBatch', label: 'straighten' })}\n onChange={(v) =>\n dispatch({\n type: 'layer/patchData',\n id: layer.id,\n patch: { straighten: (v * Math.PI) / 180 },\n })\n }\n onEnd={() => dispatch({ type: 'history/endBatch' })}\n />\n </View>\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{ gap: theme.spacing.sm, padding: theme.spacing.md }}\n style={{ flexGrow: 0 }}\n >\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel=\"Rotate 90 degrees\"\n onPress={rotate90}\n style={{\n paddingHorizontal: theme.spacing.md,\n paddingVertical: theme.spacing.sm,\n borderRadius: theme.radii.md,\n backgroundColor: theme.colors.surface,\n }}\n >\n <Text style={{ color: theme.colors.text, fontSize: theme.font.sizeSm, fontWeight: theme.font.weight }}>\n ⟳ 90°\n </Text>\n </Pressable>\n {(['horizontal', 'vertical'] as const).map((axis) => {\n const on = isFlipped(layer.transform, axis)\n return (\n <Pressable\n key={axis}\n accessibilityRole=\"button\"\n accessibilityLabel={`Flip ${axis}`}\n accessibilityState={{ selected: on }}\n onPress={() => flip(axis)}\n style={{\n paddingHorizontal: theme.spacing.md,\n paddingVertical: theme.spacing.sm,\n borderRadius: theme.radii.md,\n backgroundColor: theme.colors.surface,\n borderWidth: 1,\n borderColor: on ? theme.colors.accent : 'transparent',\n }}\n >\n <Text\n style={{\n color: on ? theme.colors.accent : theme.colors.text,\n fontSize: theme.font.sizeSm,\n fontWeight: theme.font.weight,\n }}\n >\n {axis === 'horizontal' ? '⇋' : '⇅'}\n </Text>\n </Pressable>\n )\n })}\n {profile.aspects.map((aspect, i) => (\n <Pressable\n key={i}\n onPress={() => applyAspect(aspect)}\n style={{\n width: 58,\n height: 48,\n borderRadius: theme.radii.md,\n borderWidth: 1,\n borderColor: theme.colors.textMuted,\n backgroundColor: 'transparent',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <Text style={{ color: theme.colors.text, fontSize: theme.font.sizeSm, fontWeight: theme.font.weight }}>\n {aspectLabel(aspect)}\n </Text>\n </Pressable>\n ))}\n </ScrollView>\n </View>\n )\n}\n","import React, { useMemo, useRef } from 'react'\nimport { Text, View } from 'react-native'\nimport { Gesture, GestureDetector } from 'react-native-gesture-handler'\nimport Animated from 'react-native-reanimated'\nimport { runOnJS } from 'react-native-worklets'\nimport { useTheme } from '../theme'\n\n/** The straighten dial: a value in -1..1 and the callbacks bracketing a drag. */\nexport interface StraightenRulerProps {\n value: number\n min?: number\n max?: number\n onStart?: () => void\n onChange(value: number): void\n onEnd?: () => void\n}\n\nconst PX_PER_DEGREE = 60\n\n/** Fine, zero-snapping ruler for angle correction. Values are degrees. */\nexport function StraightenRuler({ value, min = -45, max = 45, onStart, onChange, onEnd }: StraightenRulerProps) {\n const theme = useTheme()\n const start = useRef(value)\n const current = useRef(value)\n current.current = value\n const handlers = useMemo(() => ({\n begin: () => { start.current = current.current; onStart?.() },\n update: (translationX: number) => {\n const raw = Math.min(max, Math.max(min, start.current - translationX / PX_PER_DEGREE))\n onChange(Math.abs(raw) < 0.15 ? 0 : raw)\n },\n finish: () => onEnd?.(),\n }), [min, max, onStart, onChange, onEnd])\n const gesture = useMemo(() => Gesture.Pan()\n .onStart(() => { 'worklet'; runOnJS(handlers.begin)() })\n .onUpdate((event) => { 'worklet'; runOnJS(handlers.update)(event.translationX) })\n .onFinalize(() => { 'worklet'; runOnJS(handlers.finish)() }), [handlers])\n\n const rounded = Math.round(value * 10) / 10\n return (\n <GestureDetector gesture={gesture}>\n <Animated.View style={{ height: 76, overflow: 'hidden', justifyContent: 'flex-end' }}>\n <View style={{ position: 'absolute', top: 0, alignSelf: 'center', paddingHorizontal: 10, paddingVertical: 4, borderRadius: 12, backgroundColor: theme.colors.surface }}>\n <Text style={{ color: theme.colors.text, fontSize: theme.font.sizeSm }}>{rounded.toFixed(1)}°</Text>\n </View>\n <View style={{ height: 34, flexDirection: 'row', justifyContent: 'center', alignItems: 'flex-end', gap: 8 }}>\n {Array.from({ length: 31 }, (_, index) => {\n const offset = index - 15\n const major = offset % 5 === 0\n return <View key={offset} style={{ width: 1, height: major ? 22 : 11, backgroundColor: offset === 0 ? theme.colors.accent : theme.colors.textMuted }} />\n })}\n </View>\n <View style={{ position: 'absolute', bottom: 0, left: '50%', width: 2, height: 30, backgroundColor: theme.colors.accent }} />\n </Animated.View>\n </GestureDetector>\n )\n}\n","import { type Rect, type Size } from '@pictor-sdk/core'\n\n/**\n * Pure crop math for the Crop tool (unit-tested in Node).\n *\n * Aspect selection: the document canvas takes the chosen aspect (constant\n * width) and the image layer gets a maximal centred crop matching it.\n */\nexport function canvasSizeForAspect(current: Size, aspect: number | 'free'): Size {\n if (aspect === 'free') return current\n return { width: current.width, height: Math.round(current.width / aspect) }\n}\n\n/** Maximal centred crop (normalized within the source) with the given aspect. */\nexport function centeredCropForAspect(intrinsic: Size, aspect: number): Rect {\n const sourceAspect = intrinsic.width / intrinsic.height\n if (sourceAspect > aspect) {\n // source is wider → crop the sides\n const width = aspect / sourceAspect\n return { x: (1 - width) / 2, y: 0, width, height: 1 }\n }\n // source is taller → crop top/bottom\n const height = sourceAspect / aspect\n return { x: 0, y: (1 - height) / 2, width: 1, height }\n}\n\n/** The straighten dial's range: ±45°, in radians. */\nexport const STRAIGHTEN_LIMIT = (45 * Math.PI) / 180\n\n/** Straighten dial value (-1..1) ↔ radians (±45°). */\nexport function straightenToRadians(value: number): number {\n return Math.max(-1, Math.min(1, value)) * STRAIGHTEN_LIMIT\n}\n/** Radians to dial value (-1..1), clamped to the limit. */\nexport function radiansToStraighten(rad: number): number {\n return Math.max(-1, Math.min(1, rad / STRAIGHTEN_LIMIT))\n}\n","import { type Stroke } from '@pictor-sdk/core'\nimport React from 'react'\nimport { Pressable, ScrollView, Text, View } from 'react-native'\nimport { DEFAULT_BRUSH } from '../gestures/DrawingSurface'\nimport { type BrushConfig } from '../gestures/drawController'\nimport { useTheme } from '../theme'\nimport { useUiState } from '../uiState'\nimport { Slider } from '../components/Slider'\n\nconst BRUSHES: Array<{ id: Stroke['brush']; label: string }> = [\n { id: 'pen', label: 'Pen' },\n { id: 'marker', label: 'Marker' },\n { id: 'neon', label: 'Neon' },\n { id: 'highlighter', label: 'Highlight' },\n { id: 'eraser', label: 'Eraser' },\n]\n\nconst SWATCHES = [\n '#ffffff', '#000000', '#ed4956', '#ffb43b', '#ffe25c',\n '#78de85', '#4dc4ff', '#3897f0', '#a15fed', '#d977b1',\n]\n\n/** Draw tab: brush picker, color swatches + eyedropper, width slider. */\nexport function DrawPanel() {\n const theme = useTheme()\n const [brush, setBrush] = useUiState<BrushConfig>('draw.brush', DEFAULT_BRUSH)\n const [eyedropper, setEyedropper] = useUiState('draw.eyedropper', false)\n\n return (\n <View style={{ backgroundColor: theme.colors.background }}>\n <View style={{ paddingHorizontal: theme.spacing.lg }}>\n <Slider\n value={brush.width}\n min={0.002}\n max={0.06}\n centered={false}\n onChange={(width) => setBrush({ ...brush, width })}\n />\n </View>\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{ gap: theme.spacing.sm, paddingHorizontal: theme.spacing.md, alignItems: 'center' }}\n style={{ flexGrow: 0 }}\n >\n <Pressable\n onPress={() => setEyedropper(!eyedropper)}\n style={{\n width: 28,\n height: 28,\n borderRadius: 14,\n borderWidth: 2,\n borderColor: eyedropper ? theme.colors.accent : theme.colors.textMuted,\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <Text style={{ color: theme.colors.text, fontSize: 13 }}>💧</Text>\n </Pressable>\n {SWATCHES.map((color) => (\n <Pressable\n key={color}\n onPress={() => setBrush({ ...brush, color })}\n style={{\n width: 26,\n height: 26,\n borderRadius: 13,\n backgroundColor: color,\n borderWidth: brush.color === color ? 3 : 1,\n borderColor: brush.color === color ? theme.colors.accent : theme.colors.track,\n }}\n />\n ))}\n </ScrollView>\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{ gap: theme.spacing.sm, padding: theme.spacing.md }}\n style={{ flexGrow: 0 }}\n >\n {BRUSHES.map((b) => (\n <Pressable\n key={b.id}\n onPress={() => setBrush({ ...brush, brush: b.id })}\n style={{\n paddingHorizontal: theme.spacing.md,\n paddingVertical: theme.spacing.sm,\n borderRadius: theme.radii.md,\n backgroundColor: brush.brush === b.id ? theme.colors.surface : 'transparent',\n }}\n >\n <Text\n style={{\n color: brush.brush === b.id ? theme.colors.accent : theme.colors.text,\n fontSize: theme.font.sizeSm,\n fontWeight: theme.font.weight,\n }}\n >\n {b.label}\n </Text>\n </Pressable>\n ))}\n </ScrollView>\n </View>\n )\n}\n","import { baseImageLayer, useEditor, useLuts, type ImageLayerData, type LutRef } from '@pictor-sdk/core'\nimport { useRenderer } from '@pictor-sdk/skia'\nimport { Canvas, Image as SkiaImage, type SkImage } from '@shopify/react-native-skia'\nimport React, { useEffect, useState } from 'react'\nimport { Pressable, ScrollView, Text, View } from 'react-native'\nimport { useTheme } from '../theme'\nimport { Slider } from '../components/Slider'\nimport { useTargetImageLayer } from './useTargetImageLayer'\n\nconst THUMB = 84\n\n/**\n * The base photo — the bottom-most image layer.\n *\n * Unchanged, and deliberately still available: some capabilities are genuinely\n * about *the base photo* rather than about whichever photo is selected — Story\n * media placement and the derived background are computed from it. Panels that\n * edit \"the current image\" use {@link useTargetImageLayer} instead.\n */\nexport function useBaseImageLayer() {\n const { document } = useEditor()\n return baseImageLayer(document)\n}\n\nfunction Thumb({ lut, label, active }: { lut: LutRef | undefined; label: string; active: boolean }) {\n const { document } = useEditor()\n const renderer = useRenderer()\n const theme = useTheme()\n const [image, setImage] = useState<SkImage | null>(null)\n const lutId = lut?.id\n const lutIntensity = lut?.intensity\n\n // cached by (source, crop, lut) inside the renderer — free after first render\n useEffect(() => {\n let alive = true\n const requestedLut = lutId === undefined ? undefined : { id: lutId, intensity: lutIntensity ?? 1 }\n renderer\n .renderThumbnailImage(document, requestedLut, THUMB)\n .then((img) => alive && setImage(img))\n .catch(() => {})\n return () => {\n alive = false\n }\n }, [renderer, document, lutId, lutIntensity])\n\n return (\n <View style={{ alignItems: 'center', gap: 4 }}>\n <Text\n style={{\n color: active ? theme.colors.accent : theme.colors.textMuted,\n fontSize: theme.font.sizeSm,\n }}\n >\n {label}\n </Text>\n <View\n style={{\n width: THUMB,\n height: THUMB,\n borderRadius: theme.radii.sm,\n overflow: 'hidden',\n borderWidth: active ? 2 : 0,\n borderColor: theme.colors.accent,\n backgroundColor: theme.colors.surface,\n }}\n >\n {image ? (\n <Canvas style={{ width: THUMB, height: THUMB }}>\n <SkiaImage image={image} x={0} y={0} width={THUMB} height={THUMB} fit=\"cover\" />\n </Canvas>\n ) : null}\n </View>\n </View>\n )\n}\n\n/**\n * The LUT filter strip: live thumbnails, tap to apply, second tap on the\n * active filter reveals the intensity slider.\n */\nexport function FilterStrip() {\n const { dispatch } = useEditor()\n const luts = useLuts()\n const theme = useTheme()\n const layer = useTargetImageLayer()\n const [intensityFor, setIntensityFor] = useState<string | null>(null)\n\n if (!layer) return null\n const color = (layer.data as ImageLayerData).color\n const activeLut = color.lut\n\n const applyLut = (lutId: string | null) => {\n if (lutId === null) {\n dispatch({ type: 'layer/patchData', id: layer.id, patch: { color: { lut: undefined } } })\n setIntensityFor(null)\n return\n }\n if (activeLut?.id === lutId) {\n // second tap → intensity slider\n setIntensityFor((cur) => (cur === lutId ? null : lutId))\n return\n }\n dispatch({\n type: 'layer/patchData',\n id: layer.id,\n patch: { color: { lut: { id: lutId, intensity: 1 } } },\n })\n }\n\n return (\n <View style={{ backgroundColor: theme.colors.background }}>\n {intensityFor && activeLut?.id === intensityFor ? (\n <View style={{ paddingHorizontal: theme.spacing.lg }}>\n <Slider\n value={activeLut.intensity}\n min={0}\n max={1}\n centered={false}\n valueLabel={`${Math.round(activeLut.intensity * 100)}`}\n onStart={() => dispatch({ type: 'history/beginBatch', label: 'intensity' })}\n onChange={(intensity) =>\n dispatch({\n type: 'layer/patchData',\n id: layer.id,\n patch: { color: { lut: { id: intensityFor, intensity } } },\n })\n }\n onEnd={() => dispatch({ type: 'history/endBatch' })}\n />\n </View>\n ) : null}\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{ gap: theme.spacing.sm, padding: theme.spacing.md }}\n style={{ flexGrow: 0 }}\n >\n <Pressable onPress={() => applyLut(null)}>\n <Thumb lut={undefined} label=\"Original\" active={!activeLut} />\n </Pressable>\n {luts.map((lut) => (\n <Pressable key={lut.id} onPress={() => applyLut(lut.id)}>\n <Thumb\n lut={{ id: lut.id, intensity: 1 }}\n label={lut.label}\n active={activeLut?.id === lut.id}\n />\n </Pressable>\n ))}\n </ScrollView>\n </View>\n )\n}\n","import { useEditor, type ImageLayerData } from '@pictor-sdk/core'\nimport React from 'react'\nimport { Pressable, ScrollView, Text } from 'react-native'\nimport { useTheme } from '../theme'\nimport { fitImageToLayoutCell, layoutCellBounds, type LayoutPreset } from './layoutMath'\n\nconst PRESETS: Array<{ id: LayoutPreset; label: string }> = [\n { id: '1', label: 'Single' },\n { id: '2v', label: '2 rows' },\n { id: '2h', label: '2 cols' },\n { id: '3v', label: '3 rows' },\n { id: '4grid', label: 'Grid' },\n { id: '6grid', label: '6 grid' },\n]\n\n/** Layout grids: snap the image layers into the chosen arrangement. */\nexport function LayoutPanel() {\n const { document, dispatch } = useEditor()\n const theme = useTheme()\n\n const apply = (preset: LayoutPreset) => {\n const cells = layoutCellBounds(preset)\n const images = document.layers.filter((l) => l.type === 'image')\n // Calculate before opening history: invalid intrinsic data cannot leave a batch open.\n const fits = images.slice(0, cells.length).map((layer, i) => ({\n layer, fit: fitImageToLayoutCell(cells[i]!, document.size, (layer.data as ImageLayerData).intrinsic),\n }))\n dispatch({ type: 'history/beginBatch', label: 'layout' })\n fits.forEach(({ layer, fit }) => {\n dispatch({ type: 'layer/transform', id: layer.id, patch: fit.transform })\n dispatch({ type: 'layer/patchData', id: layer.id, patch: { crop: fit.crop, pixelSnap: fit.pixelSnap } })\n })\n dispatch({ type: 'history/endBatch' })\n }\n\n return (\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{ gap: theme.spacing.sm, padding: theme.spacing.md }}\n style={{ flexGrow: 0, backgroundColor: theme.colors.background }}\n >\n {PRESETS.map((preset) => (\n <Pressable\n key={preset.id}\n onPress={() => apply(preset.id)}\n style={{\n paddingHorizontal: theme.spacing.md,\n paddingVertical: theme.spacing.sm,\n borderRadius: theme.radii.md,\n backgroundColor: theme.colors.surface,\n }}\n >\n <Text style={{ color: theme.colors.text, fontSize: theme.font.sizeSm, fontWeight: theme.font.weight }}>\n {preset.label}\n </Text>\n </Pressable>\n ))}\n </ScrollView>\n )\n}\n","import { type Rect, type Size, type Transform } from '@pictor-sdk/core'\nimport { centeredCropForAspect } from './cropMath'\n\n/** The bundled multi-photo arrangements, by cell count and split direction. */\nexport type LayoutPreset = '1' | '2v' | '2h' | '3v' | '4grid' | '6grid'\n\n/** One slot in a layout: where its photo sits, in normalized document units. */\nexport interface LayoutCell {\n /** centre + scale in normalized document units */\n x: number\n y: number\n /** width of the cell as a fraction of document width */\n scale: number\n}\n\n/**\n * Story layout grids: cell centres and scales for placing the first N image\n * layers. Pure — unit tested. Cells are defined as document fractions so any\n * canvas size works.\n */\nexport function layoutCells(preset: LayoutPreset, _doc: Size): LayoutCell[] {\n return layoutCellBounds(preset).map((cell) => ({\n x: (cell.x / cell.width + 0.5) * cell.width,\n y: (cell.y / cell.height + 0.5) * cell.height,\n scale: cell.width,\n }))\n}\n\n/**\n * Axis-aligned cell rectangles, row-major, normalized to document width/height.\n * x/y are TOP-LEFT coordinates, unlike the centres in legacy LayoutCell.\n * Returns fresh rectangles; no document aspect ratio is assumed.\n */\nexport function layoutCellBounds(preset: LayoutPreset): Rect[] {\n const dimensions: Record<LayoutPreset, readonly [number, number]> = {\n '1': [1, 1], '2v': [1, 2], '2h': [2, 1], '3v': [1, 3],\n '4grid': [2, 2], '6grid': [2, 3],\n }\n const grid = dimensions[preset]\n if (!grid) throw new RangeError('Unknown layout preset')\n const [columns, rows] = grid\n return Array.from({ length: columns * rows }, (_, index) => ({\n x: (index % columns) / columns, y: Math.floor(index / columns) / rows,\n width: 1 / columns, height: 1 / rows,\n }))\n}\n\n/** Source-window controls; pan is a source-space crop centre, not a layer translation. */\nexport interface LayoutCropOptions {\n /** Magnification relative to crop-to-fill. Clamped to [1, 32]; default 1. */\n zoom?: number\n /** Desired source-normalized crop centre; clamped so the crop stays in the source. */\n center?: { x: number; y: number }\n}\n\n/** Crop and complete transform to apply together in one history batch. */\nexport interface LayoutImageFit {\n crop: Rect\n transform: Transform\n /** Apply to ImageLayerData together with crop for seam-free cell edges. */\n pixelSnap: true\n}\n\n/**\n * Fill a fixed cell without bleed. Zoom/pan alter only the source crop, never\n * the cell bounds. intrinsic must describe the decoded, orientation-corrected\n * source. Recompute after source replacement or document resize.\n * Throws RangeError for non-finite controls, invalid sizes or out-of-document cells.\n * Apply transform with layer/transform and crop + pixelSnap with layer/patchData in one batch.\n * General layer gestures must not subsequently move/rotate/scale a fixed cell.\n */\nexport function fitImageToLayoutCell(\n cell: Rect, documentSize: Size, intrinsic: Size, options: LayoutCropOptions = {},\n): LayoutImageFit {\n for (const size of [documentSize, intrinsic]) {\n if (![size.width, size.height].every((v) => Number.isFinite(v) && v > 0)) {\n throw new RangeError('Layout sizes must be finite and positive')\n }\n }\n if (![cell.x, cell.y, cell.width, cell.height].every(Number.isFinite) ||\n cell.x < 0 || cell.y < 0 || cell.width <= 0 || cell.height <= 0 ||\n cell.x + cell.width > 1 + 1e-12 || cell.y + cell.height > 1 + 1e-12) {\n throw new RangeError('Layout cell must lie inside the document')\n }\n const zoom = options.zoom ?? 1\n const center = options.center ?? { x: 0.5, y: 0.5 }\n if (![zoom, center.x, center.y].every(Number.isFinite)) {\n throw new RangeError('Layout controls must be finite')\n }\n const base = centeredCropForAspect(intrinsic,\n (cell.width * documentSize.width) / (cell.height * documentSize.height))\n const factor = Math.max(1, Math.min(32, zoom))\n const width = base.width / factor\n const height = base.height / factor\n return {\n pixelSnap: true,\n crop: {\n x: Math.max(0, Math.min(1 - width, center.x - width / 2)),\n y: Math.max(0, Math.min(1 - height, center.y - height / 2)), width, height,\n },\n transform: {\n x: cell.x + cell.width / 2, y: cell.y + cell.height / 2,\n scale: cell.width, rotation: 0, anchor: { x: 0.5, y: 0.5 },\n flipX: false, flipY: false,\n },\n }\n}\n\n/** The transform patch that moves a layer into a cell, leaving its other fields alone. */\nexport function cellToTransformPatch(cell: LayoutCell): Partial<Transform> {\n return { x: cell.x, y: cell.y, scale: cell.scale, rotation: 0 }\n}\n","import {\n luxControlState,\n luxIntensityPatch,\n useEditor,\n type ImageLayerData,\n type LuxState,\n} from '@pictor-sdk/core'\nimport { useLuxAnalysis } from '@pictor-sdk/skia'\nimport React from 'react'\nimport { Pressable, Text, View } from 'react-native'\nimport { Slider } from '../components/Slider'\nimport { useTheme } from '../theme'\nimport { useTargetImageLayer } from './useTargetImageLayer'\n\n/**\n * Lux: one intensity slider over an analysis of the photograph.\n *\n * Two things distinguish it from the 13 adjustments, both taken from\n * measurement (`docs/research/photo-editor-ux.md`):\n *\n * * the slider is **one-directional and rests at zero**, not centred — Lux is\n * an amount of correction, and there is no meaningful negative;\n * * the correction itself is **image-dependent**. The same slider position\n * lifts a flat photograph's highlights and pulls a well-exposed one's down.\n *\n * The analysis is written into the document the moment the user engages the\n * slider, and everything afterwards — preview, undo, save, export — reads it\n * from there. Recomputing at render time would let a different decode, a\n * resized preview or a future analyzer quietly restyle an existing document.\n */\nexport function LuxPanel() {\n const { dispatch } = useEditor()\n const theme = useTheme()\n const layer = useTargetImageLayer()\n const data = layer?.data as ImageLayerData | undefined\n const proposal = useLuxAnalysis(data?.source)\n\n if (!layer || !data) return null\n const stored: LuxState | undefined = data.color.lux\n const intensity = stored?.intensity ?? 0\n // Once stored, the document's analysis wins — that is the whole point. Until\n // one exists, the control is inert rather than falling back to a neutral\n // proposal: a neutral analysis stored during a slow decode would render as\n // nothing *and* suppress the real proposal permanently.\n const state = luxControlState(stored, proposal)\n\n const setIntensity = (value: number) => {\n const lux = luxIntensityPatch(state, value)\n if (!lux) return\n dispatch({ type: 'layer/patchData', id: layer.id, patch: { color: { lux } } })\n }\n\n /**\n * Clear Lux entirely — `undefined` deletes the key, so the document returns\n * to the shape it had before Lux was ever touched and the render path skips\n * the contribution instead of adding zeroes.\n *\n * Inside the tool session's batch, like every other reset: Cancel rolls it\n * back with the rest and Done commits it as one entry.\n */\n const reset = () =>\n dispatch({\n type: 'layer/patchData',\n id: layer.id,\n patch: { color: { lux: undefined } } as unknown as Record<string, unknown>,\n })\n\n return (\n <View style={{ backgroundColor: theme.colors.background, paddingBottom: theme.spacing.md }}>\n <View style={{ paddingHorizontal: theme.spacing.lg }}>\n <View\n style={{\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'center',\n gap: theme.spacing.sm,\n minHeight: 28,\n }}\n >\n <Text\n style={{\n color: theme.colors.textMuted,\n textAlign: 'center',\n fontSize: theme.font.sizeSm,\n }}\n >\n {state.pending ? 'Analyzing…' : `Lux ${intensity === 0 ? '' : Math.round(intensity * 100)}`}\n </Text>\n {intensity > 0 ? (\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel=\"Reset Lux\"\n onPress={reset}\n hitSlop={8}\n style={{\n paddingHorizontal: theme.spacing.sm,\n paddingVertical: 2,\n borderRadius: theme.radii.sm,\n borderWidth: 1,\n borderColor: theme.colors.track,\n }}\n >\n <Text style={{ color: theme.colors.text, fontSize: theme.font.sizeSm }}>Reset</Text>\n </Pressable>\n ) : null}\n </View>\n <Slider\n value={intensity}\n min={0}\n max={1}\n centered={false}\n disabled={!state.interactive}\n testID=\"lux-slider\"\n valueLabel={`${Math.round(intensity * 100)}`}\n onStart={() => dispatch({ type: 'history/beginBatch', label: 'lux' })}\n onChange={setIntensity}\n onEnd={() => dispatch({ type: 'history/endBatch' })}\n />\n </View>\n </View>\n )\n}\n","import {\n initialMediaTransform,\n mediaConfigFromProfile,\n useEditor,\n type ImageLayerData,\n} from '@pictor-sdk/core'\nimport { preferResolvedSize, useResolvedImageSize } from '@pictor-sdk/skia'\nimport React from 'react'\nimport { Pressable, Text, View } from 'react-native'\nimport { useBaseMediaLayer } from '../gestures/StoryMediaGestureSurface'\nimport { useTheme } from '../theme'\n\n/**\n * The base-photo tool panel.\n *\n * It is deliberately thin: the gestures live on the canvas surface, and the\n * Cancel/Done transaction comes from `ToolPanelHost`, which opens a history\n * batch for any tool with a panel. The panel only offers the affordances that\n * are not gestures — a reset to the initial fit — and explains the interaction.\n */\nexport function MediaPanel() {\n const { document, dispatch, profile } = useEditor()\n const layer = useBaseMediaLayer()\n const theme = useTheme()\n // same size the renderer and the gesture surface use, so Reset agrees with them\n const data = layer?.data as ImageLayerData | undefined\n const resolved = useResolvedImageSize(data?.source)\n\n if (!layer) {\n return (\n <View style={{ padding: theme.spacing.lg }}>\n <Text style={{ color: theme.colors.textMuted, fontSize: theme.font.sizeSm }}>\n This document has no base photo.\n </Text>\n </View>\n )\n }\n\n const reset = () => {\n const config = mediaConfigFromProfile(profile.interaction?.media)\n dispatch({\n type: 'layer/transform',\n id: layer.id,\n patch: initialMediaTransform(\n preferResolvedSize(resolved, data?.intrinsic),\n document.size,\n config,\n ),\n })\n }\n\n return (\n <View style={{ padding: theme.spacing.lg, gap: theme.spacing.md }}>\n <Text style={{ color: theme.colors.textMuted, fontSize: theme.font.sizeSm }}>\n Drag to reposition · pinch to zoom · twist to rotate · double-tap to zoom\n </Text>\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel=\"Reset photo placement\"\n onPress={reset}\n style={{\n alignSelf: 'flex-start',\n paddingHorizontal: theme.spacing.md,\n paddingVertical: theme.spacing.sm,\n borderRadius: theme.radii.md,\n backgroundColor: theme.colors.surface,\n }}\n >\n <Text style={{ color: theme.colors.text, fontSize: theme.font.size }}>Reset</Text>\n </Pressable>\n </View>\n )\n}\n","import {\n isDirectManipulationLayer,\n useEditor,\n type EditorDocument,\n type ProfileLayerInteraction,\n} from '@pictor-sdk/core'\nimport React from 'react'\nimport { Pressable, ScrollView, Text, View } from 'react-native'\nimport { useTheme } from '../theme'\n\n/**\n * Z-order UI: top-most first, tap to select, reorder and delete.\n * (Drag-to-delete on canvas maps to the same layer/remove command.)\n */\nexport function LayersPanel() {\n const { document, selection, select, dispatch, profile } = useEditor()\n const theme = useTheme()\n const layers = layersForPanel(document, profile.interaction?.layers)\n const minimumIndex = minimumLayerIndexForPanel(document, profile.interaction?.layers)\n\n return (\n <ScrollView style={{ maxHeight: 220, backgroundColor: theme.colors.background }}>\n {layers.map(({ layer, index }) => {\n const selected = selection.includes(layer.id)\n return (\n <View\n key={layer.id}\n style={{\n flexDirection: 'row',\n alignItems: 'center',\n paddingHorizontal: theme.spacing.md,\n paddingVertical: theme.spacing.xs,\n backgroundColor: selected ? theme.colors.surface : 'transparent',\n }}\n >\n <Pressable style={{ flex: 1 }} onPress={() => select([layer.id])}>\n <Text style={{ color: selected ? theme.colors.accent : theme.colors.text, fontSize: theme.font.sizeSm }}>\n {layer.name ?? `${layer.type} · ${layer.id.slice(0, 6)}`}\n </Text>\n </Pressable>\n <Pressable\n disabled={index === document.layers.length - 1}\n onPress={() => dispatch({ type: 'layer/reorder', id: layer.id, to: index + 1 })}\n style={{ padding: theme.spacing.xs }}\n >\n <Text style={{ color: theme.colors.textMuted }}>▲</Text>\n </Pressable>\n <Pressable\n disabled={index === minimumIndex}\n onPress={() => dispatch({ type: 'layer/reorder', id: layer.id, to: index - 1 })}\n style={{ padding: theme.spacing.xs }}\n >\n <Text style={{ color: theme.colors.textMuted }}>▼</Text>\n </Pressable>\n <Pressable\n onPress={() => dispatch({ type: 'layer/remove', id: layer.id })}\n style={{ padding: theme.spacing.xs }}\n >\n <Text style={{ color: theme.colors.danger }}>✕</Text>\n </Pressable>\n </View>\n )\n })}\n </ScrollView>\n )\n}\n\n/** Lowest z-index to which the panel may move an overlay. */\nexport function minimumLayerIndexForPanel(\n document: EditorDocument,\n interaction?: ProfileLayerInteraction,\n): number {\n return interaction?.excludeBaseImage && document.layers[0]?.type === 'image' ? 1 : 0\n}\n\n/** Overlay layers shown by the built-in manager, top-most first. */\nexport function layersForPanel(\n document: EditorDocument,\n interaction?: ProfileLayerInteraction,\n): Array<{ layer: EditorDocument['layers'][number]; index: number }> {\n return document.layers\n .map((layer, index) => ({ layer, index }))\n .filter(({ layer, index }) => isDirectManipulationLayer(layer, index, interaction))\n .reverse()\n}\n","import {\n needsPerspective,\n perspectivePatch,\n useEditor,\n MAX_PERSPECTIVE_DEGREES,\n type ImageLayerData,\n type Perspective,\n} from '@pictor-sdk/core'\nimport React, { useState } from 'react'\nimport { Pressable, Text, View } from 'react-native'\nimport { Slider } from '../components/Slider'\nimport { useTheme } from '../theme'\nimport { useTargetImageLayer } from './useTargetImageLayer'\n\n/**\n * Geometry: vertical keystone, straighten, horizontal keystone.\n *\n * One control shared by all three, because they are one family — the research\n * pass found the reference driving exactly these three from a single dial, and\n * that observation is what justified a single unified cover calculation rather\n * than multiplying separate zooms.\n *\n * Values read in **degrees**, as measured, and each mode carries an inline\n * reset that clears only itself.\n */\n\n/** Straighten shares the perspective range here, so one slider serves all three. */\nconst MAX_STRAIGHTEN_DEGREES = MAX_PERSPECTIVE_DEGREES\n\nconst MODES = [\n { key: 'vertical', label: 'Vertical' },\n { key: 'straighten', label: 'Straighten' },\n { key: 'horizontal', label: 'Horizontal' },\n] as const\n\ntype ModeKey = (typeof MODES)[number]['key']\n\nconst toRadians = (degrees: number) => (degrees * Math.PI) / 180\nconst toDegrees = (radians: number) => (radians * 180) / Math.PI\n\nexport function PerspectivePanel() {\n const { dispatch } = useEditor()\n const theme = useTheme()\n const layer = useTargetImageLayer()\n const [mode, setMode] = useState<ModeKey>('vertical')\n\n if (!layer) return null\n const data = layer.data as ImageLayerData\n const perspective: Perspective = data.perspective ?? { vertical: 0, horizontal: 0 }\n const straightenDegrees = toDegrees(data.straighten ?? 0)\n\n /** Every mode expressed as degrees, so one slider can drive all three. */\n const degreesOf = (key: ModeKey): number =>\n key === 'straighten'\n ? straightenDegrees\n : perspective[key] * MAX_PERSPECTIVE_DEGREES\n\n const setDegrees = (key: ModeKey, degrees: number) => {\n if (key === 'straighten') {\n return dispatch({\n type: 'layer/patchData',\n id: layer.id,\n patch: { straighten: degrees === 0 ? undefined : toRadians(degrees) } as unknown as Record<\n string,\n unknown\n >,\n })\n }\n const next: Perspective = { ...perspective, [key]: degrees / MAX_PERSPECTIVE_DEGREES }\n dispatch({\n type: 'layer/patchData',\n id: layer.id,\n // `perspectivePatch` deletes the key when both axes reach zero, so\n // straightening a correction back out leaves nothing serialized.\n patch: perspectivePatch(needsPerspective(next) ? next : undefined) as unknown as Record<\n string,\n unknown\n >,\n })\n }\n\n const value = degreesOf(mode)\n const max = mode === 'straighten' ? MAX_STRAIGHTEN_DEGREES : MAX_PERSPECTIVE_DEGREES\n\n return (\n <View style={{ backgroundColor: theme.colors.background, paddingBottom: theme.spacing.md }}>\n <View\n style={{\n flexDirection: 'row',\n justifyContent: 'center',\n gap: theme.spacing.sm,\n paddingVertical: theme.spacing.sm,\n }}\n >\n {MODES.map(({ key, label }) => {\n const selected = key === mode\n const degrees = degreesOf(key)\n const set = Math.abs(degrees) > 0.05\n return (\n <Pressable\n key={key}\n accessibilityRole=\"button\"\n accessibilityLabel={`${label} correction`}\n onPress={() => setMode(key)}\n style={{\n flexDirection: 'row',\n alignItems: 'center',\n gap: 6,\n paddingHorizontal: theme.spacing.sm,\n paddingVertical: 6,\n borderRadius: theme.radii.sm,\n borderWidth: 1,\n borderColor: selected ? theme.colors.accent : theme.colors.track,\n }}\n >\n <Text\n style={{\n color: selected ? theme.colors.accent : theme.colors.textMuted,\n fontSize: theme.font.sizeSm,\n fontWeight: theme.font.weight,\n }}\n >\n {/* A pill showing the value with its unit once set — the\n affordance the research pass measured. */}\n {set ? `${label} ${degrees.toFixed(1)}°` : label}\n </Text>\n {set ? (\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={`Reset ${label.toLowerCase()}`}\n onPress={() => setDegrees(key, 0)}\n hitSlop={8}\n >\n <Text style={{ color: theme.colors.text, fontSize: theme.font.sizeSm }}>✕</Text>\n </Pressable>\n ) : null}\n </Pressable>\n )\n })}\n </View>\n\n <View style={{ paddingHorizontal: theme.spacing.lg }}>\n <Slider\n value={value}\n min={-max}\n max={max}\n centered\n testID={`perspective-${mode}`}\n valueLabel={`${value > 0 ? '+' : ''}${value.toFixed(1)}°`}\n onStart={() => dispatch({ type: 'history/beginBatch', label: `perspective-${mode}` })}\n onChange={(v) => setDegrees(mode, v)}\n onEnd={() => dispatch({ type: 'history/endBatch' })}\n />\n </View>\n </View>\n )\n}\n","import { createId, useEditor, type Size } from '@pictor-sdk/core'\nimport React from 'react'\nimport { Image, Pressable, ScrollView, Text, View } from 'react-native'\nimport { useTheme } from '../theme'\nimport { useUiState } from '../uiState'\n\n/**\n * One sticker offered by the panel.\n *\n * Supplied by the host: the library ships no sticker artwork, so what appears\n * here is entirely the app's own.\n */\nexport interface StickerAsset {\n id: string\n /** image source (require() result, {uri}, or URL string) */\n source: unknown\n intrinsic?: Size\n label?: string\n}\n\n/**\n * Sticker tab. Sticker catalogs are host-supplied — pass them via\n * <Editor stickers={…}> (or replace this panel through a plugin tool Panel).\n * DECISION: no sticker assets ship with the library (same reasoning as LUTs).\n */\nexport function StickerPanel() {\n const { dispatch, select } = useEditor()\n const theme = useTheme()\n const [stickers] = useUiState<StickerAsset[]>('stickers', [])\n\n const add = (sticker: StickerAsset) => {\n const id = createId('sticker')\n dispatch({\n type: 'layer/add',\n layer: {\n id,\n type: 'sticker',\n transform: { x: 0.5, y: 0.5, scale: 1, rotation: 0 },\n opacity: 1,\n blendMode: 'normal',\n data: {\n source: sticker.source,\n intrinsic: sticker.intrinsic ?? { width: 0, height: 0 },\n },\n },\n })\n select([id])\n }\n\n if (stickers.length === 0) {\n return (\n <View style={{ backgroundColor: theme.colors.background, padding: theme.spacing.md }}>\n <Text style={{ color: theme.colors.textMuted, textAlign: 'center', fontSize: theme.font.sizeSm }}>\n No stickers registered — pass `stickers` to {'<Editor>'}.\n </Text>\n </View>\n )\n }\n\n return (\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{ gap: theme.spacing.sm, padding: theme.spacing.md }}\n style={{ flexGrow: 0, backgroundColor: theme.colors.background }}\n >\n {stickers.map((sticker) => (\n <Pressable key={sticker.id} onPress={() => add(sticker)}>\n <Image\n source={sticker.source as never}\n style={{ width: 64, height: 64, borderRadius: theme.radii.sm, backgroundColor: theme.colors.surface }}\n resizeMode=\"contain\"\n />\n </Pressable>\n ))}\n </ScrollView>\n )\n}\n","import {\n createTiltShift,\n needsTiltShift,\n tiltShiftPatch,\n useEditor,\n MAX_TILT_BLUR,\n MAX_TILT_FEATHER,\n MAX_TILT_RADIUS,\n type ImageLayerData,\n type TiltShift,\n} from '@pictor-sdk/core'\nimport React from 'react'\nimport { Pressable, Text, View } from 'react-native'\nimport { Slider } from '../components/Slider'\nimport { useTheme } from '../theme'\nimport { useTargetImageLayer } from './useTargetImageLayer'\n\n/**\n * Selective focus: Off · Radial · Linear, then the shape of the region.\n *\n * The mode row is explicit rather than implied by a non-zero blur, because the\n * research pass measured it that way and because \"off\" needs to be reachable\n * without dragging a slider back to exactly zero.\n *\n * Position and size are set by dragging on the canvas, not here — see\n * `TiltShiftGestureSurface`. The sliders cover what a gesture cannot express.\n */\n\nconst MODES = [\n { key: 'off', label: 'Off' },\n { key: 'radial', label: 'Radial' },\n { key: 'linear', label: 'Linear' },\n] as const\n\nexport function TiltShiftPanel() {\n const { dispatch } = useEditor()\n const theme = useTheme()\n const layer = useTargetImageLayer()\n\n if (!layer) return null\n const data = layer.data as ImageLayerData\n const tilt = needsTiltShift(data.tiltShift) ? data.tiltShift! : undefined\n const mode = tilt?.mode ?? 'off'\n\n const patch = (next: TiltShift | undefined) =>\n dispatch({\n type: 'layer/patchData',\n id: layer.id,\n patch: tiltShiftPatch(next) as unknown as Record<string, unknown>,\n })\n\n /**\n * Switching mode keeps the region where the user put it.\n *\n * Only the shape changes; re-centring on every mode tap would throw away\n * positioning work for no reason.\n */\n const setMode = (key: (typeof MODES)[number]['key']) => {\n if (key === 'off') return patch(undefined)\n patch(tilt ? { ...tilt, mode: key } : createTiltShift(key))\n }\n\n const set = (over: Partial<TiltShift>) => tilt && patch({ ...tilt, ...over })\n\n const sliders: Array<{ key: keyof TiltShift; label: string; max: number }> = [\n { key: 'blur', label: 'Blur', max: MAX_TILT_BLUR },\n { key: 'radius', label: 'Size', max: MAX_TILT_RADIUS },\n { key: 'feather', label: 'Feather', max: MAX_TILT_FEATHER },\n ]\n\n return (\n <View style={{ backgroundColor: theme.colors.background, paddingBottom: theme.spacing.md }}>\n <View\n style={{\n flexDirection: 'row',\n justifyContent: 'center',\n gap: theme.spacing.md,\n paddingVertical: theme.spacing.sm,\n }}\n >\n {MODES.map(({ key, label }) => {\n const selected = key === mode\n return (\n <Pressable\n key={key}\n accessibilityRole=\"button\"\n accessibilityLabel={`Tilt shift ${label.toLowerCase()}`}\n onPress={() => setMode(key)}\n style={{\n paddingHorizontal: theme.spacing.md,\n paddingVertical: 6,\n borderRadius: theme.radii.sm,\n borderWidth: 1,\n borderColor: selected ? theme.colors.accent : theme.colors.track,\n }}\n >\n <Text\n style={{\n color: selected ? theme.colors.accent : theme.colors.textMuted,\n fontSize: theme.font.sizeSm,\n fontWeight: theme.font.weight,\n }}\n >\n {label}\n </Text>\n </Pressable>\n )\n })}\n </View>\n\n <View style={{ paddingHorizontal: theme.spacing.lg }}>\n <Text\n style={{\n color: theme.colors.textMuted,\n textAlign: 'center',\n fontSize: theme.font.sizeSm,\n minHeight: 20,\n }}\n >\n {tilt ? 'Drag on the photo to place the focus' : 'Off'}\n </Text>\n {sliders.map(({ key, label, max }) => {\n const value = (tilt?.[key] as number | undefined) ?? 0\n return (\n <View key={key}>\n <Text style={{ color: theme.colors.textMuted, fontSize: theme.font.sizeSm }}>\n {label} {tilt ? Math.round((value / max) * 100) : ''}\n </Text>\n <Slider\n value={value}\n min={0}\n max={max}\n centered={false}\n testID={`tilt-${key}`}\n disabled={!tilt}\n onStart={() => dispatch({ type: 'history/beginBatch', label: `tilt-${key}` })}\n onChange={(v) => set({ [key]: v } as Partial<TiltShift>)}\n onEnd={() => dispatch({ type: 'history/endBatch' })}\n />\n </View>\n )\n })}\n </View>\n </View>\n )\n}\n","import {\n MAX_TEXT_SIZE,\n MIN_TEXT_SIZE,\n fontChoices,\n useEditor,\n useEditorStore,\n type TextLayerData,\n} from '@pictor-sdk/core'\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport {\n BackHandler,\n Keyboard,\n Platform,\n Pressable,\n ScrollView,\n Text,\n TextInput,\n View,\n type TextInputSelectionChangeEventData,\n type NativeSyntheticEvent,\n} from 'react-native'\nimport { Slider } from '../components/Slider'\nimport { useTheme } from '../theme'\nimport {\n composerInsets,\n fitCanvasRect,\n HIDDEN_KEYBOARD,\n type ComposerInsets,\n} from './keyboardLayout'\nimport { useTextSession, type TextSessionController } from './useTextSession'\n\nconst SWATCHES = ['#ffffff', '#000000', '#ed4956', '#ffe25c', '#78de85', '#4dc4ff', '#a15fed']\nconst ALIGNS = ['left', 'center', 'right'] as const\nconst ALIGN_GLYPH = { left: '⇤', center: '☰', right: '⇥' } as const\nconst FILL_MODES = [undefined, 'solid', 'perLine'] as const\n/** Normalized stroke widths: off, hairline, bold. All fractions of doc width. */\nconst STROKE_WIDTHS = [undefined, 0.002, 0.005] as const\n/** Normalized shadow presets: off, soft, hard. */\nconst SHADOWS = [\n undefined,\n { color: '#000000', blur: 0.012, dx: 0.002, dy: 0.004 },\n { color: '#000000', blur: 0.002, dx: 0.006, dy: 0.008 },\n] as const\n\n/**\n * Props a text composer receives.\n *\n * The default composer is built on exactly this, so a replacement has\n * everything the built-in one had — no privileged access to reach for.\n *\n * @experimental\n */\nexport interface TextComposerProps {\n /** The live session: layer, value, style commands, Done and Cancel. */\n session: TextSessionController\n /** Where the controls should sit, given the keyboard. */\n insets: ComposerInsets\n /** Finish and keep the text. */\n onDone(): void\n /** Abandon, restoring the document. */\n onCancel(): void\n}\n\n/**\n * The full-screen Story text composer.\n *\n * An absolute overlay above the canvas. The canvas keeps rendering the layer\n * being typed — there is no second text renderer and no editing chrome inside\n * `renderDocument` — so what is on screen while composing is what exports.\n *\n * The `TextInput` itself is invisible and stretched over the canvas: it owns\n * the caret, the platform selection handles and the IME, while the *visible*\n * text is the real Skia layer underneath. That is what keeps preview and export\n * identical without giving up native text editing.\n *\n * @experimental\n */\nexport function TextComposer({ session, insets, onDone, onCancel }: TextComposerProps) {\n const theme = useTheme()\n const store = useEditorStore()\n const { document } = useEditor()\n // Measured rather than taken from `useCanvasMetrics`: that context belongs to\n // EditorCanvas's children, and the composer is its sibling.\n const [container, setContainer] = useState({ width: 0, height: 0 })\n const input = useRef<TextInput>(null)\n const [selectionRange, setSelectionRange] = useState<{ start: number; end: number } | undefined>(\n undefined,\n )\n\n const data = session.data\n const span = session.span\n\n /**\n * Lay the input out over the text it is editing.\n *\n * The visible glyphs are the Skia layer; this input is transparent and only\n * carries the caret, the selection handles and the IME. For the caret to land\n * where the user sees their text, the input's own layout has to match the\n * layer's: same font size in dp, same alignment, and a box centred on the\n * layer's normalized y. It will never be glyph-exact — Skia and the platform\n * measure differently — but it tracks closely enough to edit by.\n */\n const layout = useMemo(() => {\n const canvas = fitCanvasRect(container, document.size)\n const fontSize = (span?.fontSize ?? 0.08) * canvas.width\n const centreY = canvas.top + (session.layer?.transform.y ?? 0.42) * canvas.height\n const height = canvas.height\n return {\n fontSize: Math.max(1, fontSize),\n lineHeight: Math.max(1, fontSize * (span?.lineHeight ?? 1.2)),\n left: canvas.left,\n width: Math.max(1, canvas.width),\n top: Math.max(0, centreY - height / 2),\n height: Math.max(1, height),\n }\n }, [container, document.size, span?.fontSize, span?.lineHeight, session.layer?.transform.y])\n const fonts = useMemo(() => fontChoices(store.registry.fonts), [store.registry.fonts])\n\n // Focus once the overlay is up. A frame's delay lets the mount settle so the\n // keyboard animates in rather than appearing half-drawn.\n useEffect(() => {\n const handle = setTimeout(() => input.current?.focus(), 50)\n return () => clearTimeout(handle)\n }, [])\n\n const onSelectionChange = useCallback(\n (event: NativeSyntheticEvent<TextInputSelectionChangeEventData>) => {\n setSelectionRange(event.nativeEvent.selection)\n },\n [],\n )\n\n /**\n * Apply a style without disturbing the caret.\n *\n * Style controls are outside the input, so tapping one would ordinarily blur\n * it and collapse the selection. Re-focusing and restoring the range keeps\n * the user where they were — the difference between styling a selection and\n * losing it.\n */\n const keepFocus = useCallback(\n (apply: () => void) => {\n apply()\n if (!input.current?.isFocused()) input.current?.focus()\n if (selectionRange) {\n const range = selectionRange\n requestAnimationFrame(() => input.current?.setNativeProps({ selection: range }))\n }\n },\n [selectionRange],\n )\n\n const cycleAlign = () => {\n if (!data) return\n const next = ALIGNS[(ALIGNS.indexOf(data.align) + 1) % ALIGNS.length]!\n keepFocus(() => session.styleText({ align: next }))\n }\n\n const cycleFill = () => {\n if (!data || !span) return\n const index = FILL_MODES.indexOf(data.fill?.mode as (typeof FILL_MODES)[number])\n const next = FILL_MODES[(index + 1) % FILL_MODES.length]\n keepFocus(() =>\n session.styleText({\n fill: next\n ? {\n color: span.color === '#000000' ? '#ffffff' : '#000000',\n radius: 0.012,\n padding: 0.012,\n mode: next,\n }\n : undefined,\n }),\n )\n }\n\n /**\n * Cycle the outline. Widths are normalized fractions of document width, like\n * every other length in the document, so they scale with the export.\n */\n const cycleStroke = () => {\n if (!data || !span) return\n const current = data.stroke?.width\n const index = STROKE_WIDTHS.findIndex((w) => w === current)\n const next = STROKE_WIDTHS[(index + 1) % STROKE_WIDTHS.length]\n keepFocus(() =>\n session.styleText({\n stroke: next\n ? { color: span.color === '#000000' ? '#ffffff' : '#000000', width: next }\n : undefined,\n }),\n )\n }\n\n /** Cycle the drop shadow: off, soft, hard. */\n const cycleShadow = () => {\n if (!data) return\n const current = data.shadow\n const index = current\n ? SHADOWS.findIndex((s) => s && current && s.blur === current.blur && s.dx === current.dx)\n : 0\n const next = SHADOWS[(index + 1) % SHADOWS.length]\n keepFocus(() => session.styleText({ shadow: next ? { ...next } : undefined }))\n }\n\n // Hardware back dismisses the keyboard first, and only closes the session on\n // a second press — so a stray back does not discard what was typed.\n useEffect(() => {\n const subscription = BackHandler.addEventListener('hardwareBackPress', () => {\n if (Keyboard.isVisible?.() ?? insets.keyboardVisible) {\n Keyboard.dismiss()\n return true\n }\n onCancel()\n return true\n })\n return () => subscription.remove()\n }, [onCancel, insets.keyboardVisible])\n\n const controlRow = {\n flexDirection: 'row' as const,\n alignItems: 'center' as const,\n gap: theme.spacing.sm,\n paddingHorizontal: theme.spacing.md,\n }\n\n return (\n <View\n style={{ position: 'absolute', left: 0, right: 0, top: 0, bottom: 0 }}\n onLayout={(event) => {\n const { width, height } = event.nativeEvent.layout\n setContainer((current) =>\n current.width === width && current.height === height ? current : { width, height },\n )\n }}\n >\n {/* Subdues the canvas so the text being typed reads clearly. Preview-only\n React Native UI — never part of renderDocument, so it cannot export. */}\n <View\n pointerEvents=\"none\"\n style={{ position: 'absolute', left: 0, right: 0, top: 0, bottom: 0, backgroundColor: '#00000055' }}\n />\n\n {/* The invisible editing surface. The visible glyphs are the Skia layer\n underneath; this owns the caret, selection handles and IME. */}\n <TextInput\n ref={input}\n value={session.value}\n onChangeText={session.setValue}\n onSelectionChange={onSelectionChange}\n multiline\n // Enter inserts a newline. Without this, a submit blurs the input and\n // the session ends on the first line break the user types.\n submitBehavior=\"newline\"\n // Android draws IME composing text itself, ignoring the transparent\n // colour below, which ghosts the input's glyphs beside the Skia ones.\n // Correction, spell-check and autofill are off to keep the composing\n // region as small as possible.\n //\n // DECISION: `keyboardType=\"visible-password\"` suppresses composing\n // entirely and removes the ghost completely — but it also strips the\n // emoji key and language switching from the keyboard, which this\n // milestone needs for emoji and Bengali. A faint composing underline on\n // the word being typed is the better trade.\n autoCorrect={false}\n spellCheck={false}\n autoComplete=\"off\"\n importantForAutofill=\"no\"\n accessibilityLabel=\"Story text\"\n placeholder=\"\"\n style={{\n position: 'absolute',\n left: layout.left,\n width: layout.width,\n top: layout.top,\n height: layout.height,\n // Fully transparent glyphs. The Skia layer is what the user reads;\n // drawing the same text twice would double it on screen. Written as\n // rgba rather than the 'transparent' keyword because the keyword is\n // not reliably honoured for TextInput colour on Android.\n color: 'rgba(0,0,0,0)',\n fontSize: layout.fontSize,\n lineHeight: layout.lineHeight,\n textAlign: data?.align ?? 'center',\n ...(Platform.OS === 'ios' ? {} : { textAlignVertical: 'center' as const }),\n padding: 0,\n }}\n // The caret and the selection highlight must stay visible even though\n // the glyphs are not.\n selectionColor={theme.colors.accent}\n cursorColor={theme.colors.accent}\n />\n\n {/* Top bar: Cancel / Done, above the keyboard-independent area. */}\n <View\n style={{\n position: 'absolute',\n left: 0,\n right: 0,\n top: 0,\n height: 56,\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n paddingHorizontal: theme.spacing.lg,\n }}\n >\n <Pressable accessibilityRole=\"button\" accessibilityLabel=\"Cancel text\" onPress={onCancel}>\n <Text style={{ color: theme.colors.text, fontSize: theme.font.size }}>Cancel</Text>\n </Pressable>\n <Pressable accessibilityRole=\"button\" accessibilityLabel=\"Done editing text\" onPress={onDone}>\n <Text\n style={{\n color: theme.colors.accent,\n fontSize: theme.font.size,\n fontWeight: theme.font.weight,\n }}\n >\n Done\n </Text>\n </Pressable>\n </View>\n\n {/* Controls ride the keyboard. The canvas never moves. */}\n <View\n style={{\n position: 'absolute',\n left: 0,\n right: 0,\n bottom: insets.bottom,\n paddingVertical: theme.spacing.sm,\n gap: theme.spacing.sm,\n backgroundColor: '#00000066',\n }}\n >\n <View style={controlRow}>\n <Text\n style={{ color: theme.colors.textMuted, fontSize: theme.font.sizeSm, width: 34 }}\n accessibilityLabel=\"Text size\"\n >\n Aa\n </Text>\n <View style={{ flex: 1 }}>\n <Slider\n value={span?.fontSize ?? MIN_TEXT_SIZE}\n min={MIN_TEXT_SIZE}\n max={MAX_TEXT_SIZE}\n centered={false}\n onChange={(size) => session.setSize(size)}\n />\n </View>\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={`Alignment ${data?.align ?? 'center'}`}\n onPress={cycleAlign}\n style={{ padding: theme.spacing.sm }}\n >\n <Text style={{ color: theme.colors.text, fontWeight: theme.font.weight }}>\n {ALIGN_GLYPH[data?.align ?? 'center']}\n </Text>\n </Pressable>\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel=\"Text background\"\n accessibilityState={{ selected: Boolean(data?.fill) }}\n onPress={cycleFill}\n style={{ padding: theme.spacing.sm }}\n >\n <Text\n style={{\n color: data?.fill ? theme.colors.accent : theme.colors.text,\n fontWeight: theme.font.weight,\n }}\n >\n {data?.fill?.mode === 'perLine' ? 'A⃞⃞' : 'A⃞'}\n </Text>\n </Pressable>\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel=\"Text outline\"\n accessibilityState={{ selected: Boolean(data?.stroke) }}\n onPress={cycleStroke}\n style={{ padding: theme.spacing.sm }}\n >\n <Text\n style={{\n color: data?.stroke ? theme.colors.accent : theme.colors.text,\n fontWeight: theme.font.weight,\n }}\n >\n Ⓐ\n </Text>\n </Pressable>\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel=\"Text shadow\"\n accessibilityState={{ selected: Boolean(data?.shadow) }}\n onPress={cycleShadow}\n style={{ padding: theme.spacing.sm }}\n >\n <Text\n style={{\n color: data?.shadow ? theme.colors.accent : theme.colors.text,\n fontWeight: theme.font.weight,\n }}\n >\n A˙\n </Text>\n </Pressable>\n </View>\n\n <ScrollView\n horizontal\n keyboardShouldPersistTaps=\"always\"\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{ gap: theme.spacing.sm, paddingHorizontal: theme.spacing.md, alignItems: 'center' }}\n style={{ flexGrow: 0 }}\n >\n {fonts.map((font) => (\n <Pressable\n key={font.family}\n accessibilityRole=\"button\"\n accessibilityLabel={`Font ${font.label}`}\n accessibilityState={{ selected: span?.fontFamily === font.family }}\n onPress={() => keepFocus(() => session.styleSpan({ fontFamily: font.family }))}\n style={{\n paddingHorizontal: theme.spacing.md,\n paddingVertical: theme.spacing.xs,\n borderRadius: theme.radii.md,\n backgroundColor:\n span?.fontFamily === font.family ? theme.colors.surface : 'transparent',\n borderWidth: 1,\n borderColor:\n span?.fontFamily === font.family ? theme.colors.accent : theme.colors.track,\n }}\n >\n <Text style={{ color: theme.colors.text, fontSize: theme.font.sizeSm }}>\n {font.label}\n </Text>\n </Pressable>\n ))}\n </ScrollView>\n\n <ScrollView\n horizontal\n keyboardShouldPersistTaps=\"always\"\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{ gap: theme.spacing.sm, paddingHorizontal: theme.spacing.md, alignItems: 'center' }}\n style={{ flexGrow: 0 }}\n >\n {SWATCHES.map((color) => (\n <Pressable\n key={color}\n accessibilityRole=\"button\"\n accessibilityLabel={`Text colour ${color}`}\n accessibilityState={{ selected: span?.color === color }}\n onPress={() => keepFocus(() => session.styleSpan({ color }))}\n style={{\n width: 28,\n height: 28,\n borderRadius: 14,\n backgroundColor: color,\n borderWidth: span?.color === color ? 3 : 1,\n borderColor: span?.color === color ? theme.colors.accent : theme.colors.track,\n }}\n />\n ))}\n </ScrollView>\n </View>\n </View>\n )\n}\n\n/**\n * Mounts a text session and the composer for it, and keeps the keyboard inset\n * up to date. This is what `<Editor>` renders while the text tool is active.\n *\n * @experimental\n */\nexport function TextComposerHost({\n Composer = TextComposer,\n}: {\n /** Replace the default composer without replacing the canvas or editor. */\n Composer?: React.ComponentType<TextComposerProps>\n}) {\n const { setActiveTool } = useEditor()\n const session = useTextSession()\n const [frame, setFrame] = useState(HIDDEN_KEYBOARD)\n\n // A monotonic token so a keyboard event that arrives after this session has\n // closed cannot resize a later one.\n const token = useRef(0)\n useEffect(() => {\n token.current += 1\n const mine = token.current\n const show = Keyboard.addListener(\n Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow',\n (event) => {\n if (mine !== token.current) return\n setFrame({ height: event.endCoordinates?.height ?? 0, duration: event.duration })\n },\n )\n const hide = Keyboard.addListener(\n Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide',\n (event) => {\n if (mine !== token.current) return\n setFrame({ height: 0, duration: event?.duration })\n },\n )\n return () => {\n token.current += 1\n show.remove()\n hide.remove()\n }\n }, [])\n\n const insets = useMemo(() => composerInsets(frame), [frame])\n\n const finish = useCallback(\n (commit: boolean) => {\n if (commit) session.commit()\n else session.cancel()\n Keyboard.dismiss()\n setActiveTool(null)\n },\n [session, setActiveTool],\n )\n\n return (\n <Composer\n session={session}\n insets={insets}\n onDone={() => finish(true)}\n onCancel={() => finish(false)}\n />\n )\n}\n\n/** Narrow re-export so the composer's data type is reachable without deep imports. */\nexport type { TextLayerData }\n","/**\n * Keyboard layout maths for the text composer.\n *\n * Split from the component so it can be tested without mounting a keyboard,\n * and kept free of any React Native import so it runs in plain Node.\n *\n * The rule this encodes: **the canvas never moves.** Milestone 2 established\n * that changing canvas metrics mid-interaction moves the ground under the\n * gesture; the same is true of a caret. So the keyboard's height becomes an\n * inset for the composer's *controls*, and nothing else in the editor reacts to\n * it.\n *\n * @experimental\n */\n\nexport interface KeyboardFrame {\n /** Height of the keyboard in dp; 0 when hidden or when a hardware keyboard is attached. */\n height: number\n /** Milliseconds the platform will take to move it. Android often reports 0. */\n duration?: number\n}\n\nexport interface ComposerInsets {\n /** Distance from the bottom of the screen to place the control bar. */\n bottom: number\n /** True while the keyboard occupies screen space. */\n keyboardVisible: boolean\n /** Animation duration to match the platform's own, clamped to something sane. */\n duration: number\n}\n\nexport const HIDDEN_KEYBOARD: KeyboardFrame = { height: 0 }\n\n/** Longest keyboard animation we will follow; beyond this the UI feels stuck. */\nconst MAX_DURATION = 400\n/** Android frequently reports 0; a short move still reads better than a jump. */\nconst FALLBACK_DURATION = 180\n\n/**\n * Where the composer's controls sit, given the keyboard and the safe area.\n *\n * When the keyboard is up it already covers the home indicator, so the bottom\n * safe-area inset must *not* be added on top of it — doing so leaves a visible\n * gap between the controls and the keyboard on iOS.\n */\nexport function composerInsets(\n frame: KeyboardFrame,\n safeAreaBottom = 0,\n): ComposerInsets {\n const height = Number.isFinite(frame.height) ? Math.max(0, frame.height) : 0\n const visible = height > 0\n const raw = frame.duration\n const duration =\n raw === undefined || !Number.isFinite(raw) || raw <= 0\n ? FALLBACK_DURATION\n : Math.min(MAX_DURATION, raw)\n return {\n bottom: visible ? height : Math.max(0, safeAreaBottom),\n keyboardVisible: visible,\n duration,\n }\n}\n\n/**\n * Whether a keyboard event belongs to the session that is listening.\n *\n * Keyboard events arrive asynchronously and can land after a session has\n * closed — or, worse, after the *next* one has opened. Sessions carry a\n * monotonic token so a late event from an earlier session is ignored rather\n * than resizing the wrong composer.\n */\nexport function isCurrentSession(eventToken: number, currentToken: number): boolean {\n return eventToken === currentToken\n}\n\n/**\n * Space available for the text itself, between the top chrome and the controls.\n *\n * Returns 0 rather than a negative number when the keyboard leaves no room —\n * a caller sizing a view with this must not be handed a negative height.\n */\nexport function composerContentHeight(\n screenHeight: number,\n insets: ComposerInsets,\n topChrome: number,\n controlsHeight: number,\n): number {\n return Math.max(0, screenHeight - topChrome - controlsHeight - insets.bottom)\n}\n\nexport interface Box {\n width: number\n height: number\n}\n\nexport interface CanvasRect {\n /** Size of the fitted canvas inside the container. */\n width: number\n height: number\n /** Offset of the canvas inside the container, which centres it. */\n left: number\n top: number\n}\n\n/**\n * Where the canvas sits inside a container, fitted to the document's aspect.\n *\n * The composer needs this to lay its input over the text it is editing, and it\n * cannot ask the canvas: `useCanvasMetrics` is provided by `EditorCanvas` to\n * its own children, and the composer is a sibling of the canvas, not a child.\n * Reading it there returns `null` — which, when used as a width, silently\n * produced a zero-width input that swallowed every keystroke.\n *\n * So the fit is recomputed here from the same rule `EditorCanvas` uses:\n * contain, then centre.\n */\nexport function fitCanvasRect(container: Box, document: Box): CanvasRect {\n if (container.width <= 0 || container.height <= 0 || document.width <= 0 || document.height <= 0) {\n return { width: 0, height: 0, left: 0, top: 0 }\n }\n const scale = Math.min(container.width / document.width, container.height / document.height)\n const width = document.width * scale\n const height = document.height * scale\n return {\n width,\n height,\n left: (container.width - width) / 2,\n top: (container.height - height) / 2,\n }\n}\n","import {\n clampTextSize,\n collapseTextSpans,\n createTextDraft,\n needsSpanCollapse,\n isBlankText,\n patchTextSpan,\n resolveTextSession,\n textSpanOf,\n textValueOf,\n useEditor,\n type Layer,\n type TextLayerData,\n type TextSpan,\n} from '@pictor-sdk/core'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\n/**\n * The state and commands behind a text-editing session.\n *\n * This is the whole contract a composer needs, so the default composer and any\n * replacement are built on exactly the same surface — which is what makes the\n * default one genuinely replaceable rather than merely swappable-in-principle.\n *\n * The session owns its history batch. The text tool has no bottom-sheet panel —\n * the composer *is* its UI — so `ToolPanelHost` never opens one for it, and the\n * session must, or every keystroke would be its own undo entry. Opening it here\n * also fixes the ordering: the batch is open before the draft is created,\n * which it would not be if a parent opened it in its own mount effect (effects\n * run child-first).\n *\n * @experimental\n */\nexport interface TextSessionController {\n /** The layer being edited — a fresh draft, or the one that was selected. */\n layer: Layer | undefined\n /** Whether this session created the layer, which decides blank-Done. */\n kind: 'draft' | 'existing'\n /** Current text. Mirrors the document; drives the input's value. */\n value: string\n /** Replace the text. */\n setValue(next: string): void\n /** The span the composer styles as a whole. */\n span: TextSpan | undefined\n /** Full layer data, for alignment/fill/stroke/shadow controls. */\n data: TextLayerData | undefined\n /** Patch the styled span — font, size, colour, weight, spacing. */\n styleSpan(patch: Partial<TextSpan>): void\n /** Patch layer-level text data — alignment, fill, stroke, shadow, maxWidth. */\n styleText(patch: Partial<TextLayerData>): void\n /** Set a normalized font size, held inside the supported range. */\n setSize(size: number): void\n /**\n * Finish. A draft that ended blank is discarded and records nothing.\n *\n * Returns the committed layer id, or `null` when nothing was kept.\n */\n commit(): string | null\n /** Abandon. Restores the document to exactly its state when the tool opened. */\n cancel(): void\n}\n\n/** Hooks into the composing session — chiefly what to do when it ends. */\nexport interface UseTextSessionOptions {\n /**\n * Edit this layer instead of resolving from the selection. Lets a custom UI\n * request editing for a specific layer — the re-entry API.\n */\n layerId?: string\n /** Called once the session has committed or been discarded. */\n onFinished?: (layerId: string | null) => void\n}\n\n/**\n * Open a text-editing session for the current selection (or `layerId`).\n *\n * Creates its draft on mount so the canvas shows the layer immediately and the\n * caret has something to sit on.\n */\nexport function useTextSession(options: UseTextSessionOptions = {}): TextSessionController {\n const { document, dispatch, profile, selection, select } = useEditor()\n const { layerId: requestedId, onFinished } = options\n\n // Resolved once: what the session is editing must not change under the user\n // because the selection moved.\n const [session] = useState(() =>\n resolveTextSession(document.layers, requestedId ? [requestedId] : selection),\n )\n const [draftId, setDraftId] = useState<string | null>(null)\n const finished = useRef(false)\n /**\n * The selection as it was before the session opened.\n *\n * Rolling the *document* back is not enough: a draft replaces the selection\n * with its own id, so a rollback that clears the selection leaves the editor\n * in a state the user never chose. Captured once, restored on every rollback\n * path — Cancel, blank-draft Done, and unmount.\n */\n const priorSelection = useRef<string[]>([])\n const capturedPrior = useRef(false)\n if (!capturedPrior.current) {\n capturedPrior.current = true\n priorSelection.current = [...selection]\n }\n\n const latest = useRef({ document, dispatch, select, selection, profile })\n latest.current = { document, dispatch, select, selection, profile }\n\n // Open the transaction, then create the draft inside it. Both exactly once:\n // a second draft would be a second layer, and a second batch would leak depth.\n useEffect(() => {\n latest.current.dispatch({ type: 'history/beginBatch', label: 'text' })\n if (session.kind === 'draft') {\n const draft = createTextDraft(latest.current.profile)\n setDraftId(draft.id)\n latest.current.dispatch({ type: 'layer/add', layer: draft })\n latest.current.select([draft.id])\n } else if (session.layerId) {\n // Whole-layer editing cannot address more than one span, so a multi-span\n // layer is collapsed up front — inside the batch, so Cancel reverses it\n // exactly. See `collapseTextSpans` for why.\n const layer = latest.current.document.layers.find((l) => l.id === session.layerId)\n const layerData = layer?.data as TextLayerData | undefined\n if (layerData && needsSpanCollapse(layerData)) {\n latest.current.dispatch({\n type: 'layer/patchData',\n id: session.layerId,\n patch: { spans: collapseTextSpans(layerData).spans },\n })\n }\n }\n return () => {\n // Unmounting without Done or Cancel — a tool switch, a navigation, an\n // unmount mid-typing — must not leave the batch open or the edit applied.\n if (finished.current) return\n finished.current = true\n latest.current.dispatch({ type: 'history/cancelBatch' })\n latest.current.select(priorSelection.current)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n const layerId = session.kind === 'existing' ? session.layerId! : draftId\n const layer = layerId ? document.layers.find((l) => l.id === layerId) : undefined\n const data = layer ? (layer.data as TextLayerData) : undefined\n const span = data ? textSpanOf(data) : undefined\n const value = data ? textValueOf(data) : ''\n\n // Read through refs so the commands keep a stable identity: a composer that\n // re-created its callbacks each keystroke would remount its controls.\n const idRef = useRef<string | null>(null)\n idRef.current = layerId ?? null\n const dataRef = useRef<TextLayerData | undefined>(undefined)\n dataRef.current = data\n\n const patchData = useCallback((patch: Partial<TextLayerData>) => {\n const id = idRef.current\n if (!id) return\n latest.current.dispatch({ type: 'layer/patchData', id, patch: patch as Record<string, unknown> })\n }, [])\n\n const setValue = useCallback(\n (next: string) => {\n const current = dataRef.current\n if (!current) return\n patchData({ spans: patchTextSpan(current, { text: next }).spans })\n },\n [patchData],\n )\n\n const styleSpan = useCallback(\n (patch: Partial<TextSpan>) => {\n const current = dataRef.current\n if (!current) return\n patchData({ spans: patchTextSpan(current, patch).spans })\n },\n [patchData],\n )\n\n const setSize = useCallback(\n (size: number) => styleSpan({ fontSize: clampTextSize(size) }),\n [styleSpan],\n )\n\n const commit = useCallback((): string | null => {\n if (finished.current) return null\n finished.current = true\n const id = idRef.current\n const blank = isBlankText(dataRef.current ? textValueOf(dataRef.current) : '')\n // A blank draft is discarded by cancelling, not by removing and committing:\n // `endBatch` compares opening and closing documents by identity, so\n // add-then-remove still pushes an undo entry that appears to do nothing.\n if (session.kind === 'draft' && blank) {\n latest.current.dispatch({ type: 'history/cancelBatch' })\n latest.current.select(priorSelection.current)\n onFinished?.(null)\n return null\n }\n latest.current.dispatch({ type: 'history/endBatch' })\n onFinished?.(id ?? null)\n return id ?? null\n }, [session.kind, onFinished])\n\n const cancel = useCallback(() => {\n if (finished.current) return\n finished.current = true\n latest.current.dispatch({ type: 'history/cancelBatch' })\n // Restore the whole editor state, not just the document: the session may\n // have moved the selection to its draft.\n latest.current.select(priorSelection.current)\n onFinished?.(null)\n }, [onFinished])\n\n return useMemo(\n () => ({\n layer,\n kind: session.kind,\n value,\n setValue,\n span,\n data,\n styleSpan,\n styleText: patchData,\n setSize,\n commit,\n cancel,\n }),\n [layer, session.kind, value, setValue, span, data, styleSpan, patchData, setSize, commit, cancel],\n )\n}\n","import { useEditor } from '@pictor-sdk/core'\nimport React from 'react'\nimport { ActivityIndicator, Pressable, Text, View } from 'react-native'\nimport { useTheme } from '../theme'\n\n/** What the top bar slot receives: the transaction actions and undo state. */\nexport interface TopBarProps {\n onCancel?: () => void\n onNext?: () => void\n /** true while an export is running (Next shows a spinner). */\n busy?: boolean\n}\n\n/** The default top bar: cancel, undo/redo, and the action that ends the session. */\nexport function TopBar({ onCancel, onNext, busy = false }: TopBarProps) {\n const { canUndo, canRedo, dispatch } = useEditor()\n const theme = useTheme()\n const button = (label: string, enabled: boolean, onPress?: () => void, color?: string) => (\n <Pressable disabled={!enabled} onPress={onPress} style={{ padding: theme.spacing.sm }}>\n <Text\n style={{\n color: enabled ? (color ?? theme.colors.text) : theme.colors.textMuted,\n fontSize: theme.font.size,\n fontWeight: theme.font.weight,\n }}\n >\n {label}\n </Text>\n </Pressable>\n )\n return (\n <View\n style={{\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n paddingHorizontal: theme.spacing.sm,\n backgroundColor: theme.colors.background,\n }}\n >\n {button('Cancel', !!onCancel, onCancel)}\n <View style={{ flexDirection: 'row' }}>\n {button('↺', canUndo, () => dispatch({ type: 'history/undo' }))}\n {button('↻', canRedo, () => dispatch({ type: 'history/redo' }))}\n </View>\n {busy ? (\n <ActivityIndicator color={theme.colors.accent} style={{ padding: theme.spacing.sm }} />\n ) : (\n button('Next', !!onNext, onNext, theme.colors.accent)\n )}\n </View>\n )\n}\n","import { useEditor, useTools } from '@pictor-sdk/core'\nimport React from 'react'\nimport { Pressable, ScrollView, Text, View } from 'react-native'\nimport { useTheme } from '../theme'\n\n/** The toolbar IS profile.tools — rendered from the registry, never hardcoded. */\nexport function ToolRail() {\n const { activeTool, setActiveTool, document, selection, dispatch } = useEditor()\n const tools = useTools()\n const theme = useTheme()\n return (\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{\n gap: theme.spacing.md,\n paddingHorizontal: theme.spacing.md,\n paddingVertical: theme.spacing.md,\n }}\n style={{ flexGrow: 0, backgroundColor: theme.colors.background }}\n >\n {tools.map((tool) => {\n const enabled = tool.isEnabled ? tool.isEnabled({ document, selection }) : true\n const active = activeTool === tool.id\n return (\n <Pressable\n key={tool.id}\n disabled={!enabled}\n onPress={() => {\n if (tool.onActivate) {\n tool.onActivate({ document, dispatch })\n } else {\n setActiveTool(active ? null : tool.id)\n }\n }}\n style={{ width: 72, alignItems: 'center', gap: 6, opacity: enabled ? 1 : 0.4 }}\n >\n <View style={{ width: 46, height: 46, borderRadius: 23, borderWidth: 1, borderColor: active ? theme.colors.accent : theme.colors.textMuted, backgroundColor: active ? theme.colors.surface : 'transparent', alignItems: 'center', justifyContent: 'center' }}>\n <Text style={{ color: active ? theme.colors.accent : theme.colors.text, fontSize: 18 }}>\n {tool.label.slice(0, 1)}\n </Text>\n </View>\n <Text\n style={{\n color: active ? theme.colors.accent : theme.colors.text,\n fontSize: theme.font.sizeSm,\n fontWeight: theme.font.weight,\n }}\n numberOfLines={1}\n >\n {tool.label}\n </Text>\n </Pressable>\n )\n })}\n </ScrollView>\n )\n}\n","import { useEditorStore } from '@pictor-sdk/core'\nimport { useCanvasMetrics } from '@pictor-sdk/skia'\nimport React, { useMemo, useRef } from 'react'\nimport { StyleSheet } from 'react-native'\nimport { Gesture, GestureDetector } from 'react-native-gesture-handler'\nimport Animated from 'react-native-reanimated'\nimport { runOnJS } from 'react-native-worklets'\nimport {\n createGestureController,\n type GestureSnapEvent,\n} from './controller'\n\n/** Overrides forwarded to whichever gesture surface the active tool mounts. */\nexport interface EditorGesturesProps {\n /** Optional haptic hook — fired once per snap engagement. */\n onSnap?: (event: GestureSnapEvent) => void\n}\n\n/**\n * Invisible gesture surface for <EditorCanvas children={…}/>: tap to select,\n * pan/pinch/rotate the selected layer. Recognizers run simultaneously on the\n * UI thread; commits are batched into a single undo step (see controller).\n */\nexport function EditorGestures({ onSnap }: EditorGesturesProps) {\n const store = useEditorStore()\n const metrics = useCanvasMetrics()\n const metricsRef = useRef(metrics)\n metricsRef.current = metrics\n const onSnapRef = useRef(onSnap)\n onSnapRef.current = onSnap\n\n const controller = useMemo(\n () =>\n createGestureController(store, () => metricsRef.current, {\n onSnap: (e) => onSnapRef.current?.(e),\n }),\n // metricsRef/onSnap are read through refs — store identity is the only dep\n [store],\n )\n\n const gesture = useMemo(() => {\n const tap = Gesture.Tap().onEnd((e) => {\n 'worklet'\n runOnJS(controller.tap)(e.x, e.y)\n })\n const pan = Gesture.Pan()\n .minPointers(1)\n .onStart(() => {\n 'worklet'\n runOnJS(controller.begin)()\n })\n .onUpdate((e) => {\n 'worklet'\n runOnJS(controller.setPan)(e.translationX, e.translationY)\n })\n .onFinalize(() => {\n 'worklet'\n runOnJS(controller.end)()\n })\n const pinch = Gesture.Pinch()\n .onStart(() => {\n 'worklet'\n runOnJS(controller.begin)()\n })\n .onUpdate((e) => {\n 'worklet'\n runOnJS(controller.setPinch)(e.scale)\n })\n .onFinalize(() => {\n 'worklet'\n runOnJS(controller.end)()\n })\n const rotate = Gesture.Rotation()\n .onStart(() => {\n 'worklet'\n runOnJS(controller.begin)()\n })\n .onUpdate((e) => {\n 'worklet'\n runOnJS(controller.setRotate)(e.rotation)\n })\n .onFinalize(() => {\n 'worklet'\n runOnJS(controller.end)()\n })\n return Gesture.Race(\n Gesture.Simultaneous(pan, pinch, rotate),\n tap,\n )\n }, [controller])\n\n return (\n <GestureDetector gesture={gesture}>\n <Animated.View style={StyleSheet.absoluteFill} />\n </GestureDetector>\n )\n}\n","import {\n hitTestDocument,\n snapCenter,\n snapRotation,\n type EditorStore,\n type Transform,\n} from '@pictor-sdk/core'\n\n/** The fitted canvas's size in dp, for turning touches into document units. */\nexport interface GestureMetrics {\n /** canvas size in dp (the fitted preview) */\n width: number\n height: number\n}\n\n/** Emitted the moment a gesture snaps — the hook for haptics. */\nexport interface GestureSnapEvent {\n kind: 'rotation' | 'centerX' | 'centerY'\n}\n\n/**\n * Host callbacks a gesture controller may fire.\n *\n * Callbacks rather than behaviour: haptics would mean a native dependency, so\n * the library reports the moment and the host decides what it means.\n */\nexport interface GestureControllerOptions {\n /** e.g. trigger haptics — optional callback, no haptics dependency here. */\n onSnap?: (event: GestureSnapEvent) => void\n}\n\n/**\n * Pure gesture → command translation, shared by the RN gesture wiring and\n * unit tests. Pan/pinch/rotate report cumulative deltas; the controller\n * recomputes the transform from the base captured at gesture start and\n * commits through a history batch so the whole gesture is ONE undo step.\n *\n * DECISION: shared values give 60fps feedback on the UI thread; document\n * commits hop to JS per frame (cheap — one reducer pass at preview scale)\n * inside the batch. True UI-thread document mutation would need a worklet\n * store and is out of scope for v0.1.\n */\nexport function createGestureController(\n store: Pick<EditorStore, 'getState' | 'dispatch' | 'select' | 'registry'>,\n getMetrics: () => GestureMetrics | null,\n options: GestureControllerOptions = {},\n) {\n let active = 0\n let base: Transform | null = null\n let layerId: string | null = null\n let pan = { x: 0, y: 0 }\n let pinch = 1\n let rotate = 0\n const snapState = { rotation: false, centerX: false, centerY: false }\n\n function targetLayerId(): string | null {\n return store.getState().selection[0] ?? null\n }\n\n function begin() {\n if (active === 0) {\n layerId = targetLayerId()\n if (!layerId) return\n const layer = store.getState().document.layers.find((l) => l.id === layerId)\n if (!layer || layer.locked) {\n layerId = null\n return\n }\n base = { ...layer.transform }\n pan = { x: 0, y: 0 }\n pinch = 1\n rotate = 0\n snapState.rotation = snapState.centerX = snapState.centerY = false\n store.dispatch({ type: 'history/beginBatch', label: 'gesture' })\n }\n active++\n }\n\n function fireSnap(kind: GestureSnapEvent['kind'], snapped: boolean) {\n if (snapped && !snapState[kind]) options.onSnap?.({ kind })\n snapState[kind] = snapped\n }\n\n function commit() {\n if (!base || !layerId) return\n const metrics = getMetrics()\n if (!metrics || metrics.width === 0 || metrics.height === 0) return\n\n const rawX = base.x + pan.x / metrics.width\n const rawY = base.y + pan.y / metrics.height\n const rawRotation = base.rotation + rotate\n\n const sx = snapCenter(rawX)\n const sy = snapCenter(rawY)\n const sr = snapRotation(rawRotation)\n fireSnap('centerX', sx.snapped)\n fireSnap('centerY', sy.snapped)\n fireSnap('rotation', sr.snapped)\n\n store.dispatch({\n type: 'layer/transform',\n id: layerId,\n patch: {\n x: sx.value,\n y: sy.value,\n rotation: sr.value,\n scale: Math.max(0.01, base.scale * pinch),\n },\n })\n }\n\n function end() {\n if (active === 0) return\n active--\n if (active === 0) {\n if (layerId) store.dispatch({ type: 'history/endBatch' })\n base = null\n layerId = null\n }\n }\n\n return {\n /** Pan/pinch/rotate lifecycles — call begin/end once per recognizer. */\n begin,\n end,\n setPan(xDp: number, yDp: number) {\n pan = { x: xDp, y: yDp }\n commit()\n },\n setPinch(scale: number) {\n pinch = scale\n commit()\n },\n setRotate(rad: number) {\n rotate = rad\n commit()\n },\n /** Tap in canvas dp → hit-test → select (empty tap clears selection). */\n tap(xDp: number, yDp: number) {\n const metrics = getMetrics()\n if (!metrics) return\n const point = { x: xDp / metrics.width, y: yDp / metrics.height }\n const hit = hitTestDocument(store.getState().document, point, store.registry)\n store.select(hit ? [hit.id] : [])\n },\n /** true while a gesture is in flight (used to mute other UI). */\n isActive: () => active > 0,\n }\n}\n\n/** Turns raw gesture input into layer transforms, with snapping. */\nexport type GestureController = ReturnType<typeof createGestureController>\n","export { Editor, CanvasStage, mergeSlots, type CanvasStageProps, type EditorProps, type EditorSlots } from './Editor'\nexport { TopBar, type TopBarProps } from './components/TopBar'\nexport { ToolRail } from './components/ToolRail'\nexport { ToolPanelHost, resolvePanel } from './ToolPanelHost'\nexport { FilterStrip, useBaseImageLayer } from './panels/FilterStrip'\nexport { useTargetImageLayer } from './panels/useTargetImageLayer'\nexport { AddPhotoPanel } from './panels/AddPhotoPanel'\nexport {\n createAddPhotoController,\n InvalidImageResultError,\n type AddPhotoController,\n type AddPhotoControllerOptions,\n} from './panels/addPhotoController'\nexport { HostCallbacksProvider, useHostCallbacks, type HostCallbacks } from './hostCallbacks'\nexport { AdjustPanel } from './panels/AdjustPanel'\nexport { CropPanel } from './panels/CropPanel'\nexport {\n canvasSizeForAspect,\n centeredCropForAspect,\n radiansToStraighten,\n straightenToRadians,\n STRAIGHTEN_LIMIT,\n} from './panels/cropMath'\nexport { Slider, type SliderProps } from './components/Slider'\nexport { StraightenRuler, type StraightenRulerProps } from './components/StraightenRuler'\nexport { defaultTheme, mergeTheme, useTheme, ThemeContext, type EditorTheme, type PartialTheme } from './theme'\nexport { EditorGestures, type EditorGesturesProps } from './gestures/EditorGestures'\nexport { LayerGestureSurface, type LayerGestureSurfaceProps } from './gestures/LayerGestureSurface'\nexport { InteractionGuides, type InteractionGuidesProps } from './gestures/InteractionGuides'\nexport {\n StoryMediaGestureSurface,\n useBaseMediaLayer,\n type StoryMediaGestureSurfaceProps,\n} from './gestures/StoryMediaGestureSurface'\nexport { resolveGestureSurface, type GestureSurfaceKind } from './gestures/routing'\nexport { MediaPanel } from './panels/MediaPanel'\n// The worklet twins, the slider's detent maths, the built-in panel registry and\n// the composer's keyboard arithmetic stay internal. Unlike the panels and\n// surfaces above — which exist to be picked apart, so their broad surface is\n// deliberate — these describe how one component is wired, and a consumer\n// replacing that component replaces the wiring too. Their tests import by path.\nexport { CropGestureSurface, type CropGestureSurfaceProps } from './gestures/CropGestureSurface'\nexport { CropGrid } from './gestures/CropGrid'\nexport { InteractionProvider, useInteractionState } from './gestures/interactionState'\nexport {\n createGestureController,\n type GestureController,\n type GestureControllerOptions,\n type GestureMetrics,\n type GestureSnapEvent,\n} from './gestures/controller'\n// Convenience re-exports so consumers of the default UI need one import\nexport { POST_PROFILE, STORY_PROFILE } from '@pictor-sdk/core'\nexport {\n TextComposer,\n TextComposerHost,\n type TextComposerProps,\n} from './composer/TextComposer'\nexport {\n useTextSession,\n type TextSessionController,\n type UseTextSessionOptions,\n} from './composer/useTextSession'\nexport { TextPanel } from './panels/TextPanel'\nexport { DrawPanel } from './panels/DrawPanel'\nexport { StickerPanel, type StickerAsset } from './panels/StickerPanel'\nexport { LayersPanel } from './panels/LayersPanel'\nexport { LayoutPanel } from './panels/LayoutPanel'\nexport { layoutCells, cellToTransformPatch, type LayoutCell, type LayoutPreset } from './panels/layoutMath'\nexport { layoutCellBounds, fitImageToLayoutCell, type LayoutCropOptions, type LayoutImageFit } from './panels/layoutMath'\nexport { DrawingSurface, DEFAULT_BRUSH } from './gestures/DrawingSurface'\nexport { createDrawController, type BrushConfig, type DrawController } from './gestures/drawController'\nexport { UiStateProvider, useUiState, createUiStateStore, type UiStateStore } from './uiState'\n","import {\n createId,\n useEditor,\n useEditorStore,\n type TextLayerData,\n type TextSpan,\n} from '@pictor-sdk/core'\nimport React from 'react'\nimport { Pressable, ScrollView, Text, TextInput, View } from 'react-native'\nimport { useTheme } from '../theme'\nimport { Slider } from '../components/Slider'\n\nconst SWATCHES = ['#ffffff', '#000000', '#ed4956', '#ffe25c', '#78de85', '#4dc4ff', '#a15fed']\nconst ALIGNS = ['left', 'center', 'right'] as const\nconst FILL_MODES = [undefined, 'solid', 'perLine'] as const\n\n/**\n * Text tab: add a text layer, then edit the selected one — content, font,\n * size, color, alignment, and the fill treatment (solid / per-line\n * @experimental). Editing happens in the panel for v0.2; DECISION:\n * on-canvas edit-in-place needs a native text-input overlay pass, deferred.\n */\nexport function TextPanel() {\n const { document, selection, dispatch, select } = useEditor()\n const store = useEditorStore()\n const theme = useTheme()\n\n const selected = document.layers.find(\n (l) => l.type === 'text' && selection.includes(l.id),\n )\n const data = selected ? (selected.data as TextLayerData) : null\n const span: TextSpan | null = data?.spans[0] ?? null\n\n const addText = () => {\n const id = createId('text')\n dispatch({\n type: 'layer/add',\n layer: {\n id,\n type: 'text',\n transform: { x: 0.5, y: 0.4, scale: 1, rotation: 0 },\n opacity: 1,\n blendMode: 'normal',\n data: {\n spans: [{ text: 'Tap to edit', fontFamily: 'System', fontSize: 0.07, color: '#ffffff' }],\n align: 'center',\n maxWidth: 0.9,\n } satisfies TextLayerData,\n },\n })\n select([id])\n }\n\n const patchSpan = (patch: Partial<TextSpan>) => {\n if (!selected || !span) return\n dispatch({\n type: 'layer/patchData',\n id: selected.id,\n patch: { spans: [{ ...span, ...patch }, ...(data!.spans.slice(1) ?? [])] },\n })\n }\n\n const fonts = ['System', ...store.registry.fonts.map((f) => f.family)]\n\n if (!selected || !span || !data) {\n return (\n <View style={{ backgroundColor: theme.colors.background, padding: theme.spacing.md, alignItems: 'center' }}>\n <Pressable\n onPress={addText}\n style={{\n paddingHorizontal: theme.spacing.lg,\n paddingVertical: theme.spacing.sm,\n borderRadius: theme.radii.md,\n backgroundColor: theme.colors.surface,\n }}\n >\n <Text style={{ color: theme.colors.accent, fontSize: theme.font.size, fontWeight: theme.font.weight }}>\n + Add text\n </Text>\n </Pressable>\n </View>\n )\n }\n\n const cycleAlign = () => {\n const next = ALIGNS[(ALIGNS.indexOf(data.align) + 1) % ALIGNS.length]!\n dispatch({ type: 'layer/patchData', id: selected.id, patch: { align: next } })\n }\n\n const cycleFill = () => {\n const current = data.fill?.mode\n const index = FILL_MODES.indexOf(current as (typeof FILL_MODES)[number])\n const next = FILL_MODES[(index + 1) % FILL_MODES.length]\n dispatch({\n type: 'layer/patchData',\n id: selected.id,\n patch: {\n fill: next\n ? { color: span.color === '#000000' ? '#ffffff' : '#000000', radius: 0.012, padding: 0.012, mode: next }\n : undefined,\n },\n })\n }\n\n return (\n <View style={{ backgroundColor: theme.colors.background }}>\n <View style={{ paddingHorizontal: theme.spacing.md }}>\n <TextInput\n value={span.text}\n onChangeText={(text) => patchSpan({ text })}\n multiline\n placeholder=\"Your text\"\n placeholderTextColor={theme.colors.textMuted}\n style={{\n color: theme.colors.text,\n backgroundColor: theme.colors.surface,\n borderRadius: theme.radii.sm,\n padding: theme.spacing.sm,\n fontSize: theme.font.size,\n }}\n />\n <Slider\n value={span.fontSize}\n min={0.02}\n max={0.2}\n centered={false}\n onStart={() => dispatch({ type: 'history/beginBatch', label: 'font size' })}\n onChange={(fontSize) => patchSpan({ fontSize })}\n onEnd={() => dispatch({ type: 'history/endBatch' })}\n />\n </View>\n <ScrollView\n horizontal\n showsHorizontalScrollIndicator={false}\n contentContainerStyle={{ gap: theme.spacing.sm, paddingHorizontal: theme.spacing.md, alignItems: 'center', paddingBottom: theme.spacing.sm }}\n style={{ flexGrow: 0 }}\n >\n <Pressable onPress={cycleAlign} style={{ padding: theme.spacing.sm }}>\n <Text style={{ color: theme.colors.text, fontWeight: theme.font.weight }}>\n {data.align === 'left' ? '⇤' : data.align === 'center' ? '☰' : '⇥'}\n </Text>\n </Pressable>\n <Pressable onPress={cycleFill} style={{ padding: theme.spacing.sm }}>\n <Text style={{ color: data.fill ? theme.colors.accent : theme.colors.text, fontWeight: theme.font.weight }}>\n {data.fill?.mode === 'perLine' ? 'A⃞⃞' : 'A⃞'}\n </Text>\n </Pressable>\n {fonts.map((family) => (\n <Pressable key={family} onPress={() => patchSpan({ fontFamily: family })} style={{ padding: theme.spacing.sm }}>\n <Text\n style={{\n color: span.fontFamily === family ? theme.colors.accent : theme.colors.textMuted,\n fontSize: theme.font.sizeSm,\n }}\n >\n {family}\n </Text>\n </Pressable>\n ))}\n {SWATCHES.map((color) => (\n <Pressable\n key={color}\n onPress={() => patchSpan({ color })}\n style={{\n width: 24,\n height: 24,\n borderRadius: 12,\n backgroundColor: color,\n borderWidth: span.color === color ? 3 : 1,\n borderColor: span.color === color ? theme.colors.accent : theme.colors.track,\n }}\n />\n ))}\n </ScrollView>\n </View>\n )\n}\n"],"mappings":"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","names":["useEditor","React","useState","View","useRef","createContext","useContext","useRef","jsx","jsx","useRef","useCanvasMetrics","useMemo","useRef","StyleSheet","Gesture","GestureDetector","Animated","runOnJS","useEditor","useRef","useEditor","createContext","useCallback","useContext","useMemo","jsx","Context","value","jsx","useEditor","useCanvasMetrics","useRef","useMemo","Gesture","runOnJS","GestureDetector","Animated","StyleSheet","useEditor","useCanvasMetrics","useMemo","useRef","StyleSheet","Gesture","GestureDetector","Animated","useSharedValue","runOnJS","jsx","useEditor","useCanvasMetrics","useRef","useSharedValue","useMemo","runOnJS","Gesture","GestureDetector","Animated","StyleSheet","React","StyleSheet","jsx","StyleSheet","React","styles","NO_SNAP","useEditor","useEditorStore","useCanvasMetrics","useRenderer","useCallback","useEffect","useMemo","useRef","useState","StyleSheet","Gesture","GestureDetector","Animated","useDerivedValue","useSharedValue","runOnJS","snapRotation","jsx","useEditor","useEditorStore","useCanvasMetrics","useRenderer","useMemo","useState","useEffect","useSharedValue","useDerivedValue","useRef","NO_SNAP","useCallback","runOnJS","Gesture","GestureDetector","Animated","StyleSheet","isSameTransform","useEditor","useCanvasMetrics","useCallback","useEffect","useMemo","useRef","StyleSheet","Gesture","GestureDetector","Animated","useDerivedValue","useSharedValue","withTiming","runOnJS","isSameTransform","jsx","useEditor","useCanvasMetrics","useMemo","useSharedValue","useRef","useEffect","useDerivedValue","useCallback","isSameTransform","withTiming","runOnJS","Gesture","GestureDetector","Animated","StyleSheet","deleteTargetFromProfile","useEditor","useCanvasMetrics","StyleSheet","View","createContext","useContext","jsx","jsxs","useEditor","useCanvasMetrics","deleteTargetFromProfile","View","StyleSheet","useEditor","useEffect","useRef","Pressable","Text","View","useEditor","useEditorStore","useState","Text","View","useMemo","useRef","useState","Text","View","Gesture","GestureDetector","Animated","runOnJS","jsx","jsxs","useState","useRef","useMemo","Gesture","runOnJS","GestureDetector","Animated","View","Text","jsx","jsxs","useEditor","useEditorStore","useState","View","Text","useEditor","useEffect","useMemo","useState","Pressable","Text","View","jsx","jsxs","useEditor","useState","useMemo","useEffect","View","Pressable","Text","useEditor","useState","Pressable","ScrollView","Text","View","jsx","jsxs","useEditor","useState","View","Pressable","Text","ScrollView","cropFitScale","useEditor","useEditorStore","Pressable","ScrollView","Text","View","useMemo","useRef","Text","View","Gesture","GestureDetector","Animated","runOnJS","jsx","jsxs","useRef","useMemo","Gesture","runOnJS","GestureDetector","Animated","View","Text","jsx","jsxs","useEditor","useEditorStore","cropFitScale","View","ScrollView","Pressable","Text","Pressable","ScrollView","Text","View","jsx","jsxs","View","ScrollView","Pressable","Text","useEditor","useRenderer","useEffect","useState","Pressable","ScrollView","Text","View","jsx","jsxs","useEditor","useRenderer","useState","useEffect","View","Text","ScrollView","Pressable","useEditor","Pressable","ScrollView","Text","jsx","useEditor","ScrollView","Pressable","Text","useEditor","Pressable","Text","View","jsx","jsxs","useEditor","View","Text","Pressable","mediaConfigFromProfile","useEditor","preferResolvedSize","useResolvedImageSize","Pressable","Text","View","jsx","jsxs","useEditor","useResolvedImageSize","View","Text","mediaConfigFromProfile","preferResolvedSize","Pressable","isDirectManipulationLayer","useEditor","Pressable","ScrollView","Text","View","jsx","jsxs","useEditor","ScrollView","View","Pressable","Text","isDirectManipulationLayer","useEditor","useState","Pressable","Text","View","jsx","jsxs","useEditor","useState","View","Pressable","Text","createId","useEditor","Pressable","ScrollView","Text","View","jsx","jsxs","useEditor","createId","View","Text","ScrollView","Pressable","needsTiltShift","tiltShiftPatch","useEditor","Pressable","Text","View","jsx","jsxs","MODES","useEditor","needsTiltShift","tiltShiftPatch","View","Pressable","Text","jsx","jsxs","useEditor","useRef","useEffect","View","Pressable","Text","useEditor","useEditorStore","useCallback","useEffect","useMemo","useRef","useState","Pressable","ScrollView","Text","View","useEditor","useCallback","useEffect","useMemo","useRef","useState","layer","jsx","jsxs","SWATCHES","useEditorStore","useEditor","useState","useRef","useMemo","useEffect","useCallback","View","Pressable","Text","ScrollView","useEditor","Pressable","Text","View","jsx","jsxs","useEditor","Pressable","Text","View","useEditor","useTools","Pressable","ScrollView","Text","View","jsx","jsxs","useEditor","useTools","ScrollView","Pressable","View","Text","jsx","jsxs","useEditor","React","useState","View","useEditorStore","useCanvasMetrics","useMemo","useRef","StyleSheet","Gesture","GestureDetector","Animated","runOnJS","hitTestDocument","jsx","useEditorStore","useCanvasMetrics","useRef","useMemo","Gesture","runOnJS","GestureDetector","Animated","StyleSheet","createId","useEditor","useEditorStore","Pressable","ScrollView","Text","TextInput","View","jsx","jsxs","SWATCHES","ALIGNS","FILL_MODES","useEditor","useEditorStore","createId","View","Pressable","Text","TextInput","ScrollView"]}
|