@adminide-stack/yantra-mobile 12.0.131 → 12.0.132-alpha.0
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/lib/components/CustomDrawer.js +2 -2
- package/lib/components/CustomDrawer.js.map +1 -1
- package/lib/features/apps/AppsCatalog.js +7 -1
- package/lib/features/apps/AppsCatalog.js.map +1 -1
- package/lib/features/apps/nativeSurfaceTwin.js +35 -0
- package/lib/features/apps/nativeSurfaceTwin.js.map +1 -0
- package/lib/features/canvas/CanvasBoardsGrid.js +49 -49
- package/lib/features/canvas/CanvasBoardsGrid.js.map +1 -1
- package/lib/features/canvas/CanvasExperience.js +69 -28
- package/lib/features/canvas/CanvasExperience.js.map +1 -1
- package/lib/features/canvas/audioEditor/AudioWaveform.js +1 -1
- package/lib/features/canvas/designCatalog.js +63 -39
- package/lib/features/canvas/designCatalog.js.map +1 -1
- package/lib/features/canvas/designCategories.js +56 -0
- package/lib/features/canvas/designCategories.js.map +1 -1
- package/lib/features/canvas/generator/DirectorSheet.js +3 -2
- package/lib/features/canvas/generator/DirectorSheet.js.map +1 -1
- package/lib/features/canvas/home/HeroComposer.js +165 -76
- package/lib/features/canvas/home/HeroComposer.js.map +1 -1
- package/lib/features/canvas/home/HeroMonitor.js +75 -46
- package/lib/features/canvas/home/HeroMonitor.js.map +1 -1
- package/lib/features/canvas/home/TemplatesGallery.js +273 -138
- package/lib/features/canvas/home/TemplatesGallery.js.map +1 -1
- package/lib/features/canvas/home/templatesGallerySources.js +221 -0
- package/lib/features/canvas/home/templatesGallerySources.js.map +1 -0
- package/lib/features/canvas/homeWork.js +12 -11
- package/lib/features/canvas/homeWork.js.map +1 -1
- package/lib/features/canvas/lazyEditors.js +51 -0
- package/lib/features/canvas/lazyEditors.js.map +1 -0
- package/lib/features/canvas/rankedCatalogSearch.js +33 -23
- package/lib/features/canvas/rankedCatalogSearch.js.map +1 -1
- package/lib/features/canvas/set/SetViewportWebView.js +1 -1
- package/lib/features/canvas/set/agent/tools.js +1 -1
- package/lib/features/canvas/studioCatalog.js +2 -2
- package/lib/features/canvas/studioCatalog.js.map +1 -1
- package/lib/features/canvas/templateSearch.js +8 -1
- package/lib/features/canvas/templateSearch.js.map +1 -1
- package/lib/features/canvas/videoEditor/BlurBoxOverlay.js +1 -1
- package/lib/features/design/DesignEditorExperience.js +103 -29
- package/lib/features/design/DesignEditorExperience.js.map +1 -1
- package/lib/features/design/DesignExperience.js +4 -3
- package/lib/features/design/DesignExperience.js.map +1 -1
- package/lib/features/design/doc/aiDesign.js +1 -1
- package/lib/features/design/doc/aiDesign.js.map +1 -1
- package/lib/features/design/doc/artifacts.js +40 -13
- package/lib/features/design/doc/artifacts.js.map +1 -1
- package/lib/features/design/doc/chart.js +387 -13
- package/lib/features/design/doc/chart.js.map +1 -1
- package/lib/features/design/doc/copyStyle.js +47 -0
- package/lib/features/design/doc/copyStyle.js.map +1 -0
- package/lib/features/design/doc/docOps.js +22 -4
- package/lib/features/design/doc/docOps.js.map +1 -1
- package/lib/features/design/doc/geometry.js +32 -18
- package/lib/features/design/doc/geometry.js.map +1 -1
- package/lib/features/design/doc/newDoc.js +5 -1
- package/lib/features/design/doc/newDoc.js.map +1 -1
- package/lib/features/design/doc/resize.js +101 -0
- package/lib/features/design/doc/resize.js.map +1 -0
- package/lib/features/design/doc/sizes.js +15 -2
- package/lib/features/design/doc/sizes.js.map +1 -1
- package/lib/features/design/editor/ChartDataPanel.js +49 -9
- package/lib/features/design/editor/ChartDataPanel.js.map +1 -1
- package/lib/features/design/editor/CropOverlay.js +1 -1
- package/lib/features/design/editor/DesignCanvas.js +14 -13
- package/lib/features/design/editor/DesignCanvas.js.map +1 -1
- package/lib/features/design/editor/ExportSheet.js +8 -4
- package/lib/features/design/editor/ExportSheet.js.map +1 -1
- package/lib/features/design/editor/LayerTools.js +37 -5
- package/lib/features/design/editor/LayerTools.js.map +1 -1
- package/lib/features/design/editor/Slideshow.js +30 -5
- package/lib/features/design/editor/Slideshow.js.map +1 -1
- package/lib/features/design/editor/useDesignSave.js +21 -36
- package/lib/features/design/editor/useDesignSave.js.map +1 -1
- package/lib/features/design/export/exportDesign.js +3 -1
- package/lib/features/design/export/exportDesign.js.map +1 -1
- package/lib/features/design/home/DesignHome.js +7 -2
- package/lib/features/design/home/DesignHome.js.map +1 -1
- package/lib/features/design/render/DesignPageView.js +1 -1
- package/lib/features/design/render/DesignPageView.js.map +1 -1
- package/lib/features/design/render/PageCapture.js +11 -10
- package/lib/features/design/render/PageCapture.js.map +1 -1
- package/lib/features/design/render/fontRegistry.js +27 -3
- package/lib/features/design/render/fontRegistry.js.map +1 -1
- package/lib/features/design/render/svgParts.js +27 -74
- package/lib/features/design/render/svgParts.js.map +1 -1
- package/lib/features/devices/brands/qnScale.js +7 -2
- package/lib/features/devices/brands/qnScale.js.map +1 -1
- package/lib/features/devices/brands/uuids.js +2 -1
- package/lib/features/devices/brands/uuids.js.map +1 -1
- package/lib/features/devices/devices.js +2 -1
- package/lib/features/devices/devices.js.map +1 -1
- package/lib/features/docs/DocBlockRow.js +1 -1
- package/lib/features/docs/docArtifacts.js +2 -2
- package/lib/features/docs/docArtifacts.js.map +1 -1
- package/lib/features/health/healthSync.js +3 -1
- package/lib/features/health/healthSync.js.map +1 -1
- package/lib/features/health/nativeHealth.js +8 -0
- package/lib/features/health/nativeHealth.js.map +1 -0
- package/lib/features/links/openInApp.js +11 -1
- package/lib/features/links/openInApp.js.map +1 -1
- package/lib/features/webbuilder/WebBuilderExperience.js +135 -28
- package/lib/features/webbuilder/WebBuilderExperience.js.map +1 -1
- package/lib/features/webbuilder/buildFragments.js +14 -6
- package/lib/features/webbuilder/buildFragments.js.map +1 -1
- package/lib/features/webbuilder/components/PreviewFrame.js +28 -3
- package/lib/features/webbuilder/components/PreviewFrame.js.map +1 -1
- package/lib/features/webbuilder/components/PreviewScreen.js +1 -1
- package/lib/features/webbuilder/components/PreviewScreen.js.map +1 -1
- package/lib/features/webbuilder/components/ProjectChat.js +24 -5
- package/lib/features/webbuilder/components/ProjectChat.js.map +1 -1
- package/lib/features/webbuilder/components/ProjectsScreen.js +18 -2
- package/lib/features/webbuilder/components/ProjectsScreen.js.map +1 -1
- package/lib/features/webbuilder/components/ui.js +20 -6
- package/lib/features/webbuilder/components/ui.js.map +1 -1
- package/lib/features/webbuilder/exportCode.js +52 -0
- package/lib/features/webbuilder/exportCode.js.map +1 -0
- package/lib/features/webbuilder/siteAddress.js +71 -0
- package/lib/features/webbuilder/siteAddress.js.map +1 -0
- package/lib/features/webbuilder/widgetBlocks.js +30 -0
- package/lib/features/webbuilder/widgetBlocks.js.map +1 -0
- package/lib/screens/Chat/index.js +5 -6
- package/lib/screens/Chat/index.js.map +1 -1
- package/lib/screens/ChatHistory/index.js +3 -2
- package/lib/screens/ChatHistory/index.js.map +1 -1
- package/lib/screens/Home/HomeScreen.js +20 -4
- package/lib/screens/Home/HomeScreen.js.map +1 -1
- package/lib/screens/Home/components/WebBuilderCodePrewarm.js +18 -0
- package/lib/screens/Home/components/WebBuilderCodePrewarm.js.map +1 -0
- package/lib/screens/WebBuilderNative/index.js +1 -1
- package/lib/screens/WebBuilderNative/index.js.map +1 -1
- package/lib/screens/WebBuilderNative/keepAlive.js +112 -0
- package/lib/screens/WebBuilderNative/keepAlive.js.map +1 -0
- package/lib/screens/WebBuilderNative/runningBuilds.js +40 -0
- package/lib/screens/WebBuilderNative/runningBuilds.js.map +1 -0
- package/lib/screens/WebBuilderNative/useSandboxKeepAlive.js +57 -0
- package/lib/screens/WebBuilderNative/useSandboxKeepAlive.js.map +1 -0
- package/lib/screens/WebBuilderNative/useWebBuilderGallery.js +73 -14
- package/lib/screens/WebBuilderNative/useWebBuilderGallery.js.map +1 -1
- package/lib/screens/WebBuilderNative/useWebBuilderHost.js +143 -34
- package/lib/screens/WebBuilderNative/useWebBuilderHost.js.map +1 -1
- package/lib/screens/WebBuilderNative/useWebBuilderJobs.js +17 -5
- package/lib/screens/WebBuilderNative/useWebBuilderJobs.js.map +1 -1
- package/lib/screens/WebBuilderNative/versionUndo.js +144 -0
- package/lib/screens/WebBuilderNative/versionUndo.js.map +1 -0
- package/lib/screens/WebBuilderNative/webbuilderSnapshotKey.js +1 -0
- package/lib/screens/WebBuilderNative/webbuilderSnapshotKey.js.map +1 -0
- package/lib/screens/WebBuilderNative/webbuilderTransport.js +90 -6
- package/lib/screens/WebBuilderNative/webbuilderTransport.js.map +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docOps.js","sources":["../../../../src/features/design/doc/docOps.ts"],"sourcesContent":["/**\n * The editor's document state and every edit it makes - native twin of the\n * reducer in canvas-surface `editors/carousel-editor/state.tsx`.\n *\n * One reducer, so undo is one stack: every action that changes the document\n * pushes the previous one, except a burst of the same edit (a drag, typing,\n * a slider) which coalesces into the step that started it - one undo puts a\n * dragged layer back where the drag began, not one frame earlier.\n *\n * Layer factories carry the web's defaults (TEXT_PRESETS, makeShapeLayer,\n * makeChartLayer), so a heading added on the phone matches one added on web.\n *\n * Pure: runs under jest as-is.\n */\nimport { isStrokeShape, type ShapeKind } from './shapes';\nimport {\n DEFAULT_TEXT_COLOR,\n newLayerId,\n newPageId,\n type ChartKind,\n type ChartLayer,\n type DesignDoc,\n type DesignPage,\n type EditorLayer,\n type ImageLayer,\n type PageBackground,\n type ShapeLayer,\n type TextLayer,\n} from './types';\n\n/** Undo keeps this many steps; a long session must not hold every keystroke's document. */\nexport const HISTORY_LIMIT = 60;\n/** Edits with the same key this close together are one undo step. */\nexport const COALESCE_MS = 700;\n\nexport interface EditorState {\n doc: DesignDoc;\n pageId: string;\n layerId: string | null;\n past: DesignDoc[];\n future: DesignDoc[];\n /** The last coalescing edit: its key and when it landed. */\n lastEdit: { key: string; at: number } | null;\n}\n\nexport type LayerOrderMove = 'forward' | 'backward' | 'front' | 'back';\n\nexport type EditorAction =\n | { type: 'select'; pageId?: string; layerId: string | null }\n | {\n type: 'patchLayer';\n pageId: string;\n layerId: string;\n patch: Partial<EditorLayer>;\n coalesce?: string;\n at?: number;\n /** Not an undo step: an upload swapping its hosted URL in for the local pick. */\n silent?: boolean;\n }\n | { type: 'addLayer'; pageId: string; layer: EditorLayer }\n | { type: 'deleteLayer'; pageId: string; layerId: string }\n | { type: 'duplicateLayer'; pageId: string; layerId: string }\n | { type: 'reorderLayer'; pageId: string; layerId: string; move: LayerOrderMove }\n | { type: 'setBackground'; pageId: string; background: PageBackground; coalesce?: string; at?: number }\n | { type: 'addPage'; afterId?: string }\n | { type: 'insertPages'; afterId?: string; pages: DesignPage[] }\n | { type: 'duplicatePage'; pageId: string }\n | { type: 'deletePage'; pageId: string }\n | { type: 'movePage'; pageId: string; dir: -1 | 1 }\n /** A page dragged to a new place in the rail (web PageRail drag). */\n | { type: 'movePageTo'; pageId: string; index: number }\n /** One page's content swapped whole (an AI edit); `silent` for a picture landing after it. */\n | { type: 'replacePage'; page: DesignPage; silent?: boolean }\n | { type: 'patchDoc'; patch: Partial<DesignDoc>; coalesce?: string; at?: number }\n | { type: 'replaceDoc'; doc: DesignDoc }\n | { type: 'undo' }\n | { type: 'redo' };\n\nexport function initEditorState(doc: DesignDoc): EditorState {\n return { doc, pageId: doc.pages[0]?.id ?? '', layerId: null, past: [], future: [], lastEdit: null };\n}\n\nexport function currentPage(state: Pick<EditorState, 'doc' | 'pageId'>): DesignPage | undefined {\n return state.doc.pages.find((p) => p.id === state.pageId) ?? state.doc.pages[0];\n}\n\nexport function selectedLayer(state: Pick<EditorState, 'doc' | 'pageId' | 'layerId'>): EditorLayer | undefined {\n if (!state.layerId) return undefined;\n return currentPage(state)?.layers?.find((l) => l.id === state.layerId);\n}\n\nfunction mapPage(doc: DesignDoc, pageId: string, fn: (page: DesignPage) => DesignPage): DesignDoc {\n return { ...doc, pages: doc.pages.map((p) => (p.id === pageId ? fn(p) : p)) };\n}\n\nfunction mapLayers(doc: DesignDoc, pageId: string, fn: (layers: EditorLayer[]) => EditorLayer[]): DesignDoc {\n return mapPage(doc, pageId, (p) => ({ ...p, layers: fn(p.layers ?? []) }));\n}\n\n/** A layer copy with fresh ids, nested chart arrays cloned so the two never share one. */\nfunction cloneLayer(layer: EditorLayer): EditorLayer {\n const copy = JSON.parse(JSON.stringify(layer)) as EditorLayer;\n return { ...copy, id: newLayerId() };\n}\n\n/**\n * Commit `doc` as the next document. `coalesce` joins it to the step before\n * when that step had the same key and landed within COALESCE_MS.\n */\nfunction commit(\n state: EditorState,\n doc: DesignDoc,\n extra: Partial<EditorState> = {},\n coalesce?: string,\n at: number = Date.now(),\n): EditorState {\n if (doc === state.doc) return { ...state, ...extra };\n const joins =\n coalesce !== undefined &&\n state.lastEdit?.key === coalesce &&\n at - state.lastEdit.at <= COALESCE_MS &&\n state.past.length > 0;\n const past = joins ? state.past : [...state.past, state.doc].slice(-HISTORY_LIMIT);\n return {\n ...state,\n ...extra,\n doc,\n past,\n future: [],\n lastEdit: coalesce !== undefined ? { key: coalesce, at } : null,\n };\n}\n\nexport function editorReducer(state: EditorState, action: EditorAction): EditorState {\n const { doc } = state;\n switch (action.type) {\n case 'select': {\n const pageId = action.pageId ?? state.pageId;\n return { ...state, pageId, layerId: action.layerId, lastEdit: null };\n }\n case 'patchLayer': {\n const next = mapLayers(doc, action.pageId, (layers) =>\n layers.map((l) => (l.id === action.layerId ? ({ ...l, ...action.patch } as EditorLayer) : l)),\n );\n if (action.silent) return { ...state, doc: next };\n return commit(state, next, {}, action.coalesce ?? `layer:${action.layerId}`, action.at);\n }\n case 'addLayer':\n return commit(\n state,\n mapLayers(doc, action.pageId, (layers) => [...layers, action.layer]),\n {\n pageId: action.pageId,\n layerId: action.layer.id,\n },\n );\n case 'deleteLayer': {\n const layer = doc.pages.find((p) => p.id === action.pageId)?.layers?.find((l) => l.id === action.layerId);\n if (!layer || layer.locked) return state;\n const next = mapLayers(doc, action.pageId, (layers) => layers.filter((l) => l.id !== action.layerId));\n return commit(state, next, { layerId: state.layerId === action.layerId ? null : state.layerId });\n }\n case 'duplicateLayer': {\n const layers = doc.pages.find((p) => p.id === action.pageId)?.layers ?? [];\n const index = layers.findIndex((l) => l.id === action.layerId);\n if (index < 0) return state;\n const source = layers[index];\n // Nudged down-right like web's Duplicate, kept on the page.\n const copy = {\n ...cloneLayer(source),\n x: Math.min(1 - source.w, source.x + 0.03),\n y: Math.min(1 - source.h, source.y + 0.03),\n locked: undefined,\n } as EditorLayer;\n const next = mapLayers(doc, action.pageId, (all) => [\n ...all.slice(0, index + 1),\n copy,\n ...all.slice(index + 1),\n ]);\n return commit(state, next, { layerId: copy.id });\n }\n case 'reorderLayer': {\n const layers = doc.pages.find((p) => p.id === action.pageId)?.layers ?? [];\n const index = layers.findIndex((l) => l.id === action.layerId);\n if (index < 0) return state;\n const target =\n action.move === 'front'\n ? layers.length - 1\n : action.move === 'back'\n ? 0\n : action.move === 'forward'\n ? Math.min(layers.length - 1, index + 1)\n : Math.max(0, index - 1);\n if (target === index) return state;\n const reordered = [...layers];\n const [moved] = reordered.splice(index, 1);\n reordered.splice(target, 0, moved);\n return commit(\n state,\n mapLayers(doc, action.pageId, () => reordered),\n );\n }\n case 'setBackground':\n return commit(\n state,\n mapPage(doc, action.pageId, (p) => ({ ...p, background: action.background })),\n {},\n action.coalesce,\n action.at,\n );\n case 'addPage': {\n const page: DesignPage = {\n id: newPageId(),\n name: '',\n prompt: '',\n src: null,\n status: 'ready',\n role: 'content',\n // A blank white sheet, like web's Add page.\n background: { kind: 'color', color: '#ffffff' },\n layers: [],\n };\n return insertPagesInto(state, [page], action.afterId);\n }\n case 'insertPages':\n return action.pages.length ? insertPagesInto(state, action.pages, action.afterId) : state;\n case 'duplicatePage': {\n const index = doc.pages.findIndex((p) => p.id === action.pageId);\n if (index < 0) return state;\n const source = doc.pages[index];\n const page: DesignPage = { ...source, id: newPageId(), layers: source.layers?.map(cloneLayer) };\n const pages = [...doc.pages];\n pages.splice(index + 1, 0, page);\n return commit(state, { ...doc, pages }, { pageId: page.id, layerId: null });\n }\n case 'deletePage': {\n if (doc.pages.length <= 1) return state;\n const index = doc.pages.findIndex((p) => p.id === action.pageId);\n if (index < 0) return state;\n const pages = doc.pages.filter((p) => p.id !== action.pageId);\n const pageId = state.pageId === action.pageId ? pages[Math.min(index, pages.length - 1)].id : state.pageId;\n return commit(state, { ...doc, pages }, { pageId, layerId: null });\n }\n case 'movePage': {\n const index = doc.pages.findIndex((p) => p.id === action.pageId);\n const target = index + action.dir;\n if (index < 0 || target < 0 || target >= doc.pages.length) return state;\n const pages = [...doc.pages];\n [pages[index], pages[target]] = [pages[target], pages[index]];\n return commit(state, { ...doc, pages });\n }\n case 'movePageTo': {\n const from = doc.pages.findIndex((p) => p.id === action.pageId);\n const to = Math.max(0, Math.min(doc.pages.length - 1, Math.round(action.index)));\n if (from < 0 || from === to) return state;\n const pages = [...doc.pages];\n const [moved] = pages.splice(from, 1);\n pages.splice(to, 0, moved);\n return commit(state, { ...doc, pages });\n }\n case 'replacePage': {\n if (!doc.pages.some((p) => p.id === action.page.id)) return state;\n const next = mapPage(doc, action.page.id, () => action.page);\n if (action.silent) return { ...state, doc: next };\n return commit(state, next, { layerId: null });\n }\n case 'patchDoc':\n return commit(state, { ...doc, ...action.patch }, {}, action.coalesce, action.at);\n case 'replaceDoc':\n return commit(state, action.doc, { pageId: action.doc.pages[0]?.id ?? '', layerId: null });\n case 'undo': {\n const prev = state.past[state.past.length - 1];\n if (!prev) return state;\n return {\n ...state,\n doc: prev,\n past: state.past.slice(0, -1),\n future: [state.doc, ...state.future],\n pageId: prev.pages.some((p) => p.id === state.pageId) ? state.pageId : (prev.pages[0]?.id ?? ''),\n layerId: null,\n lastEdit: null,\n };\n }\n case 'redo': {\n const next = state.future[0];\n if (!next) return state;\n return {\n ...state,\n doc: next,\n past: [...state.past, state.doc],\n future: state.future.slice(1),\n pageId: next.pages.some((p) => p.id === state.pageId) ? state.pageId : (next.pages[0]?.id ?? ''),\n layerId: null,\n lastEdit: null,\n };\n }\n default:\n return state;\n }\n}\n\nfunction insertPagesInto(state: EditorState, pages: DesignPage[], afterId?: string): EditorState {\n const { doc } = state;\n const index = afterId ? doc.pages.findIndex((p) => p.id === afterId) : -1;\n const at = index >= 0 ? index + 1 : doc.pages.length;\n const next = [...doc.pages];\n next.splice(at, 0, ...pages);\n return commit(state, { ...doc, pages: next }, { pageId: pages[0].id, layerId: null });\n}\n\n// ── Layer factories (web state.tsx defaults) ─────────────────────────────\n\nexport type TextPreset = 'heading' | 'subheading' | 'body';\n\n/** Preset text layers offered in the Text tool (Canva-style heading/subheading/body). */\nexport const TEXT_PRESETS: Record<\n TextPreset,\n { content: string; fontSizeFrac: number; fontWeight: number; fontToken: 'display' | 'body' }\n> = {\n heading: { content: 'Add a heading', fontSizeFrac: 0.09, fontWeight: 700, fontToken: 'display' },\n subheading: { content: 'Add a subheading', fontSizeFrac: 0.055, fontWeight: 600, fontToken: 'display' },\n body: { content: 'Add a little bit of body text', fontSizeFrac: 0.03, fontWeight: 400, fontToken: 'body' },\n};\n\n/** Web \"Add a text box\": a plain body-size box ready to type into. */\nexport function makeTextBox(): TextLayer {\n return { ...makeTextLayer('body'), content: 'Your text here', fontSizeFrac: 0.04 };\n}\n\n/** An emoji sticker (web Graphics): a big centred glyph, as text so it draws everywhere without a hosted picture. */\nexport function makeStickerLayer(emoji: string, pageW: number, pageH: number): TextLayer {\n const w = 0.28;\n const h = (w * pageW) / pageH;\n return {\n ...makeTextLayer('body'),\n content: emoji,\n x: (1 - w) / 2,\n y: (1 - h) / 2,\n w,\n h,\n fontSizeFrac: w * 0.8,\n align: 'center',\n lineHeight: 1.1,\n };\n}\n\nexport function makeTextLayer(preset: TextPreset): TextLayer {\n const p = TEXT_PRESETS[preset];\n return {\n id: newLayerId(),\n kind: 'text',\n content: p.content,\n x: 0.1,\n y: 0.4,\n w: 0.8,\n h: 0.12,\n fontToken: p.fontToken,\n fontWeight: p.fontWeight,\n fontSizeFrac: p.fontSizeFrac,\n color: DEFAULT_TEXT_COLOR,\n align: 'left',\n lineHeight: 1.2,\n };\n}\n\nexport function makeShapeLayer(shape: ShapeKind, palette?: DesignDoc['palette']): ShapeLayer {\n const isLine = isStrokeShape(shape);\n return {\n id: newLayerId(),\n kind: 'shape',\n shape,\n x: 0.2,\n y: 0.4,\n w: isLine ? 0.5 : 0.3,\n h: isLine ? 0.05 : 0.3,\n fill: palette?.primary ?? '#38bdf8',\n radiusFrac: shape === 'rect' ? 0.08 : 0,\n opacity: 1,\n ...(isLine ? { strokeWidthFrac: 0.008 } : {}),\n };\n}\n\n/** Two series out of the box, so the legend is self-explanatory on first open (web CHART_SAMPLE). */\nconst CHART_SAMPLE = {\n categories: ['Jan', 'Feb', 'Mar'],\n series: [\n { name: 'Desktop', values: [4000, 3200, 2200] },\n { name: 'Mobile', values: [2500, 1700, 1200] },\n ],\n};\n\nexport function makeChartLayer(chart: ChartKind, palette?: DesignDoc['palette']): ChartLayer {\n return {\n id: newLayerId(),\n kind: 'chart',\n chart,\n x: 0.15,\n y: 0.3,\n w: 0.7,\n h: 0.45,\n categories: [...CHART_SAMPLE.categories],\n series: CHART_SAMPLE.series.map((s) => ({ name: s.name, values: [...s.values] })),\n // The legacy single-series mirror a connector without `series` still reads.\n data: CHART_SAMPLE.categories.map((label, i) => ({ label, value: CHART_SAMPLE.series[0].values[i] })),\n colors: [palette?.primary ?? '#38bdf8', palette?.muted ?? '#818cf8', '#f472b6', '#fbbf24'],\n opacity: 1,\n };\n}\n\n/**\n * A placed picture: its own aspect kept, fitting within half the page each way\n * (web `fitImageBox`), centred. Without a measured size it takes a square.\n */\nexport function makeImageLayer(\n src: string,\n pageW: number,\n pageH: number,\n size?: { width: number; height: number } | null,\n): ImageLayer {\n const imgW = size && size.width > 0 ? size.width : 1;\n const imgH = size && size.height > 0 ? size.height : 1;\n const scale = 0.5 * Math.min(pageW / imgW, pageH / imgH);\n const w = (imgW * scale) / pageW;\n const h = (imgH * scale) / pageH;\n return {\n id: newLayerId(),\n kind: 'image',\n prompt: '',\n src,\n imageStatus: 'ready',\n uploaded: true,\n x: (1 - w) / 2,\n y: (1 - h) / 2,\n w,\n h,\n };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"docOps.js","sources":["../../../../src/features/design/doc/docOps.ts"],"sourcesContent":["/**\n * The editor's document state and every edit it makes - native twin of the\n * reducer in canvas-surface `editors/carousel-editor/state.tsx`.\n *\n * One reducer, so undo is one stack: every action that changes the document\n * pushes the previous one, except a burst of the same edit (a drag, typing,\n * a slider) which coalesces into the step that started it - one undo puts a\n * dragged layer back where the drag began, not one frame earlier.\n *\n * Layer factories carry the web's defaults (TEXT_PRESETS, makeShapeLayer,\n * makeChartLayer), so a heading added on the phone matches one added on web.\n *\n * Pure: runs under jest as-is.\n */\nimport { isStrokeShape, type ShapeKind } from './shapes';\nimport {\n DEFAULT_TEXT_COLOR,\n newLayerId,\n newPageId,\n type ChartKind,\n type ChartLayer,\n type DesignDoc,\n type DesignPage,\n type EditorLayer,\n type ImageLayer,\n type PageBackground,\n type ShapeLayer,\n type TextLayer,\n} from './types';\n\n/** Undo keeps this many steps; a long session must not hold every keystroke's document. */\nexport const HISTORY_LIMIT = 60;\n/** Edits with the same key this close together are one undo step. */\nexport const COALESCE_MS = 700;\n\nexport interface EditorState {\n doc: DesignDoc;\n pageId: string;\n layerId: string | null;\n past: DesignDoc[];\n future: DesignDoc[];\n /** The last coalescing edit: its key and when it landed. */\n lastEdit: { key: string; at: number } | null;\n}\n\nexport type LayerOrderMove = 'forward' | 'backward' | 'front' | 'back';\n\nexport type EditorAction =\n | { type: 'select'; pageId?: string; layerId: string | null }\n | {\n type: 'patchLayer';\n pageId: string;\n layerId: string;\n patch: Partial<EditorLayer>;\n coalesce?: string;\n at?: number;\n /** Not an undo step: an upload swapping its hosted URL in for the local pick. */\n silent?: boolean;\n }\n | { type: 'addLayer'; pageId: string; layer: EditorLayer }\n | { type: 'deleteLayer'; pageId: string; layerId: string }\n | { type: 'duplicateLayer'; pageId: string; layerId: string }\n | { type: 'reorderLayer'; pageId: string; layerId: string; move: LayerOrderMove }\n | { type: 'setBackground'; pageId: string; background: PageBackground; coalesce?: string; at?: number }\n | { type: 'addPage'; afterId?: string }\n | { type: 'insertPages'; afterId?: string; pages: DesignPage[] }\n | { type: 'duplicatePage'; pageId: string }\n | { type: 'deletePage'; pageId: string }\n | { type: 'movePage'; pageId: string; dir: -1 | 1 }\n /** A page dragged to a new place in the rail (web PageRail drag). */\n | { type: 'movePageTo'; pageId: string; index: number }\n /** One page's content swapped whole (an AI edit); `silent` for a picture landing after it. */\n | { type: 'replacePage'; page: DesignPage; silent?: boolean }\n | { type: 'patchDoc'; patch: Partial<DesignDoc>; coalesce?: string; at?: number }\n | { type: 'replaceDoc'; doc: DesignDoc }\n | { type: 'undo' }\n | { type: 'redo' };\n\nexport function initEditorState(doc: DesignDoc): EditorState {\n return { doc, pageId: doc.pages[0]?.id ?? '', layerId: null, past: [], future: [], lastEdit: null };\n}\n\nexport function currentPage(state: Pick<EditorState, 'doc' | 'pageId'>): DesignPage | undefined {\n return state.doc.pages.find((p) => p.id === state.pageId) ?? state.doc.pages[0];\n}\n\nexport function selectedLayer(state: Pick<EditorState, 'doc' | 'pageId' | 'layerId'>): EditorLayer | undefined {\n if (!state.layerId) return undefined;\n return currentPage(state)?.layers?.find((l) => l.id === state.layerId);\n}\n\nfunction mapPage(doc: DesignDoc, pageId: string, fn: (page: DesignPage) => DesignPage): DesignDoc {\n return { ...doc, pages: doc.pages.map((p) => (p.id === pageId ? fn(p) : p)) };\n}\n\nfunction mapLayers(doc: DesignDoc, pageId: string, fn: (layers: EditorLayer[]) => EditorLayer[]): DesignDoc {\n return mapPage(doc, pageId, (p) => ({ ...p, layers: fn(p.layers ?? []) }));\n}\n\n/** A layer copy with fresh ids, nested chart arrays cloned so the two never share one. */\n/** The style keys a text run can override (TextRun minus its range). */\nconst RUN_STYLE_KEYS = [\n 'fontFamily',\n 'fontWeight',\n 'fontSizeFrac',\n 'italic',\n 'underline',\n 'strike',\n 'color',\n 'lineHeight',\n 'letterSpacingFrac',\n] as const;\n\n/**\n * A layer patch applied, web-style: a box-wide style clears the same key from\n * the layer's runs (web applyTextLayerPatch), or a colour set on a rich-text\n * layer would stay hidden under its runs - and be saved that way.\n */\nexport function withRunsCleared(layer: EditorLayer, patch: Partial<EditorLayer>): EditorLayer {\n const next = { ...layer, ...patch } as EditorLayer;\n if (layer.kind !== 'text' || !layer.runs?.length || 'runs' in patch) return next;\n const keys = RUN_STYLE_KEYS.filter((k) => k in patch);\n if (!keys.length) return next;\n const runs = layer.runs\n .map((run) => {\n const kept = { ...run };\n for (const k of keys) delete kept[k];\n return kept;\n })\n .filter((run) => RUN_STYLE_KEYS.some((k) => run[k] !== undefined));\n return { ...next, runs: runs.length ? runs : undefined } as EditorLayer;\n}\n\nfunction cloneLayer(layer: EditorLayer): EditorLayer {\n const copy = JSON.parse(JSON.stringify(layer)) as EditorLayer;\n return { ...copy, id: newLayerId() };\n}\n\n/**\n * Commit `doc` as the next document. `coalesce` joins it to the step before\n * when that step had the same key and landed within COALESCE_MS.\n */\nfunction commit(\n state: EditorState,\n doc: DesignDoc,\n extra: Partial<EditorState> = {},\n coalesce?: string,\n at: number = Date.now(),\n): EditorState {\n if (doc === state.doc) return { ...state, ...extra };\n const joins =\n coalesce !== undefined &&\n state.lastEdit?.key === coalesce &&\n at - state.lastEdit.at <= COALESCE_MS &&\n state.past.length > 0;\n const past = joins ? state.past : [...state.past, state.doc].slice(-HISTORY_LIMIT);\n return {\n ...state,\n ...extra,\n doc,\n past,\n future: [],\n lastEdit: coalesce !== undefined ? { key: coalesce, at } : null,\n };\n}\n\nexport function editorReducer(state: EditorState, action: EditorAction): EditorState {\n const { doc } = state;\n switch (action.type) {\n case 'select': {\n const pageId = action.pageId ?? state.pageId;\n return { ...state, pageId, layerId: action.layerId, lastEdit: null };\n }\n case 'patchLayer': {\n const next = mapLayers(doc, action.pageId, (layers) =>\n layers.map((l) => (l.id === action.layerId ? withRunsCleared(l, action.patch) : l)),\n );\n if (action.silent) return { ...state, doc: next };\n return commit(state, next, {}, action.coalesce ?? `layer:${action.layerId}`, action.at);\n }\n case 'addLayer':\n return commit(\n state,\n mapLayers(doc, action.pageId, (layers) => [...layers, action.layer]),\n {\n pageId: action.pageId,\n layerId: action.layer.id,\n },\n );\n case 'deleteLayer': {\n const layer = doc.pages.find((p) => p.id === action.pageId)?.layers?.find((l) => l.id === action.layerId);\n if (!layer || layer.locked) return state;\n const next = mapLayers(doc, action.pageId, (layers) => layers.filter((l) => l.id !== action.layerId));\n return commit(state, next, { layerId: state.layerId === action.layerId ? null : state.layerId });\n }\n case 'duplicateLayer': {\n const layers = doc.pages.find((p) => p.id === action.pageId)?.layers ?? [];\n const index = layers.findIndex((l) => l.id === action.layerId);\n if (index < 0) return state;\n const source = layers[index];\n // Nudged down-right like web's Duplicate, kept on the page.\n const copy = {\n ...cloneLayer(source),\n x: Math.min(1 - source.w, source.x + 0.03),\n y: Math.min(1 - source.h, source.y + 0.03),\n locked: undefined,\n // A copy starts a group of its own (web insertCopies); sharing the id would join the original's.\n ...(source.groupId ? { groupId: `group-${newLayerId()}` } : {}),\n } as EditorLayer;\n const next = mapLayers(doc, action.pageId, (all) => [\n ...all.slice(0, index + 1),\n copy,\n ...all.slice(index + 1),\n ]);\n return commit(state, next, { layerId: copy.id });\n }\n case 'reorderLayer': {\n const layers = doc.pages.find((p) => p.id === action.pageId)?.layers ?? [];\n const index = layers.findIndex((l) => l.id === action.layerId);\n if (index < 0) return state;\n const target =\n action.move === 'front'\n ? layers.length - 1\n : action.move === 'back'\n ? 0\n : action.move === 'forward'\n ? Math.min(layers.length - 1, index + 1)\n : Math.max(0, index - 1);\n if (target === index) return state;\n const reordered = [...layers];\n const [moved] = reordered.splice(index, 1);\n reordered.splice(target, 0, moved);\n return commit(\n state,\n mapLayers(doc, action.pageId, () => reordered),\n );\n }\n case 'setBackground':\n return commit(\n state,\n mapPage(doc, action.pageId, (p) => ({ ...p, background: action.background })),\n {},\n action.coalesce,\n action.at,\n );\n case 'addPage': {\n const page: DesignPage = {\n id: newPageId(),\n name: '',\n prompt: '',\n src: null,\n status: 'ready',\n role: 'content',\n // A blank white sheet, like web's Add page.\n background: { kind: 'color', color: '#ffffff' },\n layers: [],\n };\n return insertPagesInto(state, [page], action.afterId);\n }\n case 'insertPages':\n return action.pages.length ? insertPagesInto(state, action.pages, action.afterId) : state;\n case 'duplicatePage': {\n const index = doc.pages.findIndex((p) => p.id === action.pageId);\n if (index < 0) return state;\n const source = doc.pages[index];\n const page: DesignPage = { ...source, id: newPageId(), layers: source.layers?.map(cloneLayer) };\n const pages = [...doc.pages];\n pages.splice(index + 1, 0, page);\n return commit(state, { ...doc, pages }, { pageId: page.id, layerId: null });\n }\n case 'deletePage': {\n if (doc.pages.length <= 1) return state;\n const index = doc.pages.findIndex((p) => p.id === action.pageId);\n if (index < 0) return state;\n const pages = doc.pages.filter((p) => p.id !== action.pageId);\n const pageId = state.pageId === action.pageId ? pages[Math.min(index, pages.length - 1)].id : state.pageId;\n return commit(state, { ...doc, pages }, { pageId, layerId: null });\n }\n case 'movePage': {\n const index = doc.pages.findIndex((p) => p.id === action.pageId);\n const target = index + action.dir;\n if (index < 0 || target < 0 || target >= doc.pages.length) return state;\n const pages = [...doc.pages];\n [pages[index], pages[target]] = [pages[target], pages[index]];\n return commit(state, { ...doc, pages });\n }\n case 'movePageTo': {\n const from = doc.pages.findIndex((p) => p.id === action.pageId);\n const to = Math.max(0, Math.min(doc.pages.length - 1, Math.round(action.index)));\n if (from < 0 || from === to) return state;\n const pages = [...doc.pages];\n const [moved] = pages.splice(from, 1);\n pages.splice(to, 0, moved);\n return commit(state, { ...doc, pages });\n }\n case 'replacePage': {\n if (!doc.pages.some((p) => p.id === action.page.id)) return state;\n const next = mapPage(doc, action.page.id, () => action.page);\n if (action.silent) return { ...state, doc: next };\n return commit(state, next, { layerId: null });\n }\n case 'patchDoc':\n return commit(state, { ...doc, ...action.patch }, {}, action.coalesce, action.at);\n case 'replaceDoc':\n return commit(state, action.doc, { pageId: action.doc.pages[0]?.id ?? '', layerId: null });\n case 'undo': {\n const prev = state.past[state.past.length - 1];\n if (!prev) return state;\n return {\n ...state,\n doc: prev,\n past: state.past.slice(0, -1),\n future: [state.doc, ...state.future],\n pageId: prev.pages.some((p) => p.id === state.pageId) ? state.pageId : (prev.pages[0]?.id ?? ''),\n layerId: null,\n lastEdit: null,\n };\n }\n case 'redo': {\n const next = state.future[0];\n if (!next) return state;\n return {\n ...state,\n doc: next,\n past: [...state.past, state.doc],\n future: state.future.slice(1),\n pageId: next.pages.some((p) => p.id === state.pageId) ? state.pageId : (next.pages[0]?.id ?? ''),\n layerId: null,\n lastEdit: null,\n };\n }\n default:\n return state;\n }\n}\n\nfunction insertPagesInto(state: EditorState, pages: DesignPage[], afterId?: string): EditorState {\n const { doc } = state;\n const index = afterId ? doc.pages.findIndex((p) => p.id === afterId) : -1;\n const at = index >= 0 ? index + 1 : doc.pages.length;\n const next = [...doc.pages];\n next.splice(at, 0, ...pages);\n return commit(state, { ...doc, pages: next }, { pageId: pages[0].id, layerId: null });\n}\n\n// ── Layer factories (web state.tsx defaults) ─────────────────────────────\n\nexport type TextPreset = 'heading' | 'subheading' | 'body';\n\n/** Preset text layers offered in the Text tool (Canva-style heading/subheading/body). */\nexport const TEXT_PRESETS: Record<\n TextPreset,\n { content: string; fontSizeFrac: number; fontWeight: number; fontToken: 'display' | 'body' }\n> = {\n heading: { content: 'Add a heading', fontSizeFrac: 0.09, fontWeight: 700, fontToken: 'display' },\n subheading: { content: 'Add a subheading', fontSizeFrac: 0.055, fontWeight: 600, fontToken: 'display' },\n body: { content: 'Add a little bit of body text', fontSizeFrac: 0.03, fontWeight: 400, fontToken: 'body' },\n};\n\n/** Web \"Add a text box\": a plain body-size box ready to type into. */\nexport function makeTextBox(): TextLayer {\n return { ...makeTextLayer('body'), content: 'Your text here', fontSizeFrac: 0.04 };\n}\n\n/** An emoji sticker (web Graphics): a big centred glyph, as text so it draws everywhere without a hosted picture. */\nexport function makeStickerLayer(emoji: string, pageW: number, pageH: number): TextLayer {\n const w = 0.28;\n const h = (w * pageW) / pageH;\n return {\n ...makeTextLayer('body'),\n content: emoji,\n x: (1 - w) / 2,\n y: (1 - h) / 2,\n w,\n h,\n fontSizeFrac: w * 0.8,\n align: 'center',\n lineHeight: 1.1,\n };\n}\n\nexport function makeTextLayer(preset: TextPreset): TextLayer {\n const p = TEXT_PRESETS[preset];\n return {\n id: newLayerId(),\n kind: 'text',\n content: p.content,\n x: 0.1,\n y: 0.4,\n w: 0.8,\n h: 0.12,\n fontToken: p.fontToken,\n fontWeight: p.fontWeight,\n fontSizeFrac: p.fontSizeFrac,\n color: DEFAULT_TEXT_COLOR,\n align: 'left',\n lineHeight: 1.2,\n };\n}\n\nexport function makeShapeLayer(shape: ShapeKind, palette?: DesignDoc['palette']): ShapeLayer {\n const isLine = isStrokeShape(shape);\n return {\n id: newLayerId(),\n kind: 'shape',\n shape,\n x: 0.2,\n y: 0.4,\n w: isLine ? 0.5 : 0.3,\n h: isLine ? 0.05 : 0.3,\n fill: palette?.primary ?? '#38bdf8',\n radiusFrac: shape === 'rect' ? 0.08 : 0,\n opacity: 1,\n ...(isLine ? { strokeWidthFrac: 0.008 } : {}),\n };\n}\n\n/** Two series out of the box, so the legend is self-explanatory on first open (web CHART_SAMPLE). */\nconst CHART_SAMPLE = {\n categories: ['Jan', 'Feb', 'Mar'],\n series: [\n { name: 'Desktop', values: [4000, 3200, 2200] },\n { name: 'Mobile', values: [2500, 1700, 1200] },\n ],\n};\n\nexport function makeChartLayer(chart: ChartKind, palette?: DesignDoc['palette']): ChartLayer {\n return {\n id: newLayerId(),\n kind: 'chart',\n chart,\n x: 0.15,\n y: 0.3,\n w: 0.7,\n h: 0.45,\n categories: [...CHART_SAMPLE.categories],\n series: CHART_SAMPLE.series.map((s) => ({ name: s.name, values: [...s.values] })),\n // The legacy single-series mirror a connector without `series` still reads.\n data: CHART_SAMPLE.categories.map((label, i) => ({ label, value: CHART_SAMPLE.series[0].values[i] })),\n colors: [palette?.primary ?? '#38bdf8', palette?.muted ?? '#818cf8', '#f472b6', '#fbbf24'],\n opacity: 1,\n };\n}\n\n/**\n * A placed picture: its own aspect kept, fitting within half the page each way\n * (web `fitImageBox`), centred. Without a measured size it takes a square.\n */\nexport function makeImageLayer(\n src: string,\n pageW: number,\n pageH: number,\n size?: { width: number; height: number } | null,\n): ImageLayer {\n const imgW = size && size.width > 0 ? size.width : 1;\n const imgH = size && size.height > 0 ? size.height : 1;\n const scale = 0.5 * Math.min(pageW / imgW, pageH / imgH);\n const w = (imgW * scale) / pageW;\n const h = (imgH * scale) / pageH;\n return {\n id: newLayerId(),\n kind: 'image',\n prompt: '',\n src,\n imageStatus: 'ready',\n uploaded: true,\n x: (1 - w) / 2,\n y: (1 - h) / 2,\n w,\n h,\n };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -107,27 +107,41 @@ function rotateFromDrag(box, startDeg, from, to, snap = 4) {
|
|
|
107
107
|
if (Math.abs(deg - nearest) <= snap) deg = nearest === -180 ? 180 : nearest;
|
|
108
108
|
return Math.round(deg * 10) / 10;
|
|
109
109
|
}
|
|
110
|
-
function
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
let guideY = false;
|
|
117
|
-
if (Math.abs(x + box.w / 2 - W / 2) <= tol) {
|
|
118
|
-
x = W / 2 - box.w / 2;
|
|
119
|
-
guideX = true;
|
|
110
|
+
function snapLines(others, W, H) {
|
|
111
|
+
const xs = [0, W / 2, W];
|
|
112
|
+
const ys = [0, H / 2, H];
|
|
113
|
+
for (const o of others) {
|
|
114
|
+
xs.push(o.x, o.x + o.w / 2, o.x + o.w);
|
|
115
|
+
ys.push(o.y, o.y + o.h / 2, o.y + o.h);
|
|
120
116
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
117
|
+
return {
|
|
118
|
+
xs,
|
|
119
|
+
ys
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function nearestLine(values, lines, tol) {
|
|
123
|
+
let best = null;
|
|
124
|
+
for (const v of values) {
|
|
125
|
+
for (const line of lines) {
|
|
126
|
+
const delta = line - v;
|
|
127
|
+
if (Math.abs(delta) <= tol && (!best || Math.abs(delta) < Math.abs(best.delta))) best = {
|
|
128
|
+
delta,
|
|
129
|
+
line
|
|
130
|
+
};
|
|
131
|
+
}
|
|
124
132
|
}
|
|
133
|
+
return best;
|
|
134
|
+
}
|
|
135
|
+
function snapMove(box, lines, tol = 6) {
|
|
136
|
+
var _a, _b;
|
|
137
|
+
const sx = nearestLine([box.x, box.x + box.w / 2, box.x + box.w], lines.xs, tol);
|
|
138
|
+
const sy = nearestLine([box.y, box.y + box.h / 2, box.y + box.h], lines.ys, tol);
|
|
125
139
|
return {
|
|
126
140
|
box: __spreadProps(__spreadValues({}, box), {
|
|
127
|
-
x,
|
|
128
|
-
y
|
|
141
|
+
x: box.x + ((_a = sx == null ? void 0 : sx.delta) != null ? _a : 0),
|
|
142
|
+
y: box.y + ((_b = sy == null ? void 0 : sy.delta) != null ? _b : 0)
|
|
129
143
|
}),
|
|
130
|
-
guideX,
|
|
131
|
-
guideY
|
|
144
|
+
guideX: sx ? sx.line : null,
|
|
145
|
+
guideY: sy ? sy.line : null
|
|
132
146
|
};
|
|
133
|
-
}export{handlePoint,hitTest,layerBox,pointInBox,resizeBox,rotateFromDrag,rotateKnobPoint,
|
|
147
|
+
}export{handlePoint,hitTest,layerBox,pointInBox,resizeBox,rotateFromDrag,rotateKnobPoint,snapLines,snapMove};//# sourceMappingURL=geometry.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geometry.js","sources":["../../../../src/features/design/doc/geometry.ts"],"sourcesContent":["/**\n * Touch geometry for the editor: which layer a tap lands on, where a rotated\n * layer's handles are, and how a handle drag resizes or turns it.\n *\n * Everything works in the canvas's own px (page fractions times the drawn\n * page size). A layer turns about its centre, as on web, so a point is tested\n * against the box by turning it back first; a resize keeps the handle's\n * opposite corner (or side) where it was on screen, turned or not.\n *\n * Pure: runs under jest as-is.\n */\nimport type { EditorLayer } from './types';\n\nexport interface Box {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nexport type Handle = 'nw' | 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w';\n\nconst rad = (deg: number) => (deg * Math.PI) / 180;\n\nfunction rotate(x: number, y: number, deg: number): [number, number] {\n const t = rad(deg);\n const c = Math.cos(t);\n const s = Math.sin(t);\n return [x * c - y * s, x * s + y * c];\n}\n\nexport function layerBox(layer: Pick<EditorLayer, 'x' | 'y' | 'w' | 'h'>, W: number, H: number): Box {\n return { x: layer.x * W, y: layer.y * H, w: layer.w * W, h: layer.h * H };\n}\n\n/** Is a point inside a box turned `deg` about its centre? `slop` widens it for a thumb. */\nexport function pointInBox(px: number, py: number, box: Box, deg = 0, slop = 0): boolean {\n const cx = box.x + box.w / 2;\n const cy = box.y + box.h / 2;\n const [lx, ly] = rotate(px - cx, py - cy, -deg);\n return Math.abs(lx) <= box.w / 2 + slop && Math.abs(ly) <= box.h / 2 + slop;\n}\n\n/**\n * The topmost layer under a point, or null. A thin layer (a rule, a line of\n * small text) takes a few px of slop so it can still be tapped.\n */\nexport function hitTest(\n layers: readonly EditorLayer[],\n px: number,\n py: number,\n W: number,\n H: number,\n): EditorLayer | null {\n for (let i = layers.length - 1; i >= 0; i -= 1) {\n const layer = layers[i];\n const box = layerBox(layer, W, H);\n const slop = Math.min(box.w, box.h) < 24 ? 10 : 0;\n if (pointInBox(px, py, box, layer.rotation ?? 0, slop)) return layer;\n }\n return null;\n}\n\nconst SIGN: Record<Handle, [number, number]> = {\n nw: [-1, -1],\n n: [0, -1],\n ne: [1, -1],\n e: [1, 0],\n se: [1, 1],\n s: [0, 1],\n sw: [-1, 1],\n w: [-1, 0],\n};\n\n/** Where a handle sits on screen, the box turned `deg`. */\nexport function handlePoint(box: Box, deg: number, handle: Handle): [number, number] {\n const [sx, sy] = SIGN[handle];\n const [ox, oy] = rotate((sx * box.w) / 2, (sy * box.h) / 2, deg);\n return [box.x + box.w / 2 + ox, box.y + box.h / 2 + oy];\n}\n\n/** The rotate knob: below the box, `gap` px past its bottom edge, turning with it. */\nexport function rotateKnobPoint(box: Box, deg: number, gap: number): [number, number] {\n const [ox, oy] = rotate(0, box.h / 2 + gap, deg);\n return [box.x + box.w / 2 + ox, box.y + box.h / 2 + oy];\n}\n\n/**\n * Drag a handle by (dx, dy) screen px. Corners keep the box's aspect when\n * `keepAspect` (pictures, and text, whose corners scale its words); sides move\n * one edge. The opposite corner or side stays put on screen.\n */\nexport function resizeBox(\n box: Box,\n deg: number,\n handle: Handle,\n dx: number,\n dy: number,\n opts: { keepAspect?: boolean; minSize?: number } = {},\n): Box {\n const min = opts.minSize ?? 8;\n const [sx, sy] = SIGN[handle];\n const [ldx, ldy] = rotate(dx, dy, -deg);\n let w = sx ? Math.max(min, box.w + sx * ldx) : box.w;\n let h = sy ? Math.max(min, box.h + sy * ldy) : box.h;\n if (opts.keepAspect && sx && sy) {\n // The larger pull wins, so a diagonal drag tracks the thumb.\n const scale = Math.max(w / box.w, h / box.h);\n const floor = min / Math.min(box.w, box.h);\n const s = Math.max(scale, floor);\n w = box.w * s;\n h = box.h * s;\n }\n // The anchor: the opposite corner (or side midpoint), fixed on screen.\n const cx = box.x + box.w / 2;\n const cy = box.y + box.h / 2;\n const [ax, ay] = rotate((-sx * box.w) / 2, (-sy * box.h) / 2, deg);\n const anchorX = cx + ax;\n const anchorY = cy + ay;\n const [nx, ny] = rotate((-sx * w) / 2, (-sy * h) / 2, deg);\n const ncx = anchorX - nx;\n const ncy = anchorY - ny;\n return { x: ncx - w / 2, y: ncy - h / 2, w, h };\n}\n\n/** Rotation after dragging the knob from `from` to `to` (screen px), snapped to 45° steps within `snap` degrees. */\nexport function rotateFromDrag(\n box: Box,\n startDeg: number,\n from: [number, number],\n to: [number, number],\n snap = 4,\n): number {\n const cx = box.x + box.w / 2;\n const cy = box.y + box.h / 2;\n const a0 = Math.atan2(from[1] - cy, from[0] - cx);\n const a1 = Math.atan2(to[1] - cy, to[0] - cx);\n let deg = startDeg + ((a1 - a0) * 180) / Math.PI;\n deg = ((((deg + 180) % 360) + 360) % 360) - 180;\n const nearest = Math.round(deg / 45) * 45;\n if (Math.abs(deg - nearest) <= snap) deg = nearest === -180 ? 180 : nearest;\n return Math.round(deg * 10) / 10;\n}\n\n/** Snap a moved box's centre and edges to the page's centre lines within `tol` px; returns the snapped box and the guides hit. */\nexport function snapToPage(box: Box, W: number, H: number, tol = 6): { box: Box; guideX: boolean; guideY: boolean } {\n let { x, y } = box;\n let guideX = false;\n let guideY = false;\n if (Math.abs(x + box.w / 2 - W / 2) <= tol) {\n x = W / 2 - box.w / 2;\n guideX = true;\n }\n if (Math.abs(y + box.h / 2 - H / 2) <= tol) {\n y = H / 2 - box.h / 2;\n guideY = true;\n }\n return { box: { ...box, x, y }, guideX, guideY };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"geometry.js","sources":["../../../../src/features/design/doc/geometry.ts"],"sourcesContent":["/**\n * Touch geometry for the editor: which layer a tap lands on, where a rotated\n * layer's handles are, and how a handle drag resizes or turns it.\n *\n * Everything works in the canvas's own px (page fractions times the drawn\n * page size). A layer turns about its centre, as on web, so a point is tested\n * against the box by turning it back first; a resize keeps the handle's\n * opposite corner (or side) where it was on screen, turned or not.\n *\n * Pure: runs under jest as-is.\n */\nimport type { EditorLayer } from './types';\n\nexport interface Box {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nexport type Handle = 'nw' | 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w';\n\nconst rad = (deg: number) => (deg * Math.PI) / 180;\n\nfunction rotate(x: number, y: number, deg: number): [number, number] {\n const t = rad(deg);\n const c = Math.cos(t);\n const s = Math.sin(t);\n return [x * c - y * s, x * s + y * c];\n}\n\nexport function layerBox(layer: Pick<EditorLayer, 'x' | 'y' | 'w' | 'h'>, W: number, H: number): Box {\n return { x: layer.x * W, y: layer.y * H, w: layer.w * W, h: layer.h * H };\n}\n\n/** Is a point inside a box turned `deg` about its centre? `slop` widens it for a thumb. */\nexport function pointInBox(px: number, py: number, box: Box, deg = 0, slop = 0): boolean {\n const cx = box.x + box.w / 2;\n const cy = box.y + box.h / 2;\n const [lx, ly] = rotate(px - cx, py - cy, -deg);\n return Math.abs(lx) <= box.w / 2 + slop && Math.abs(ly) <= box.h / 2 + slop;\n}\n\n/**\n * The topmost layer under a point, or null. A thin layer (a rule, a line of\n * small text) takes a few px of slop so it can still be tapped.\n */\nexport function hitTest(\n layers: readonly EditorLayer[],\n px: number,\n py: number,\n W: number,\n H: number,\n): EditorLayer | null {\n for (let i = layers.length - 1; i >= 0; i -= 1) {\n const layer = layers[i];\n const box = layerBox(layer, W, H);\n const slop = Math.min(box.w, box.h) < 24 ? 10 : 0;\n if (pointInBox(px, py, box, layer.rotation ?? 0, slop)) return layer;\n }\n return null;\n}\n\nconst SIGN: Record<Handle, [number, number]> = {\n nw: [-1, -1],\n n: [0, -1],\n ne: [1, -1],\n e: [1, 0],\n se: [1, 1],\n s: [0, 1],\n sw: [-1, 1],\n w: [-1, 0],\n};\n\n/** Where a handle sits on screen, the box turned `deg`. */\nexport function handlePoint(box: Box, deg: number, handle: Handle): [number, number] {\n const [sx, sy] = SIGN[handle];\n const [ox, oy] = rotate((sx * box.w) / 2, (sy * box.h) / 2, deg);\n return [box.x + box.w / 2 + ox, box.y + box.h / 2 + oy];\n}\n\n/** The rotate knob: below the box, `gap` px past its bottom edge, turning with it. */\nexport function rotateKnobPoint(box: Box, deg: number, gap: number): [number, number] {\n const [ox, oy] = rotate(0, box.h / 2 + gap, deg);\n return [box.x + box.w / 2 + ox, box.y + box.h / 2 + oy];\n}\n\n/**\n * Drag a handle by (dx, dy) screen px. Corners keep the box's aspect when\n * `keepAspect` (pictures, and text, whose corners scale its words); sides move\n * one edge. The opposite corner or side stays put on screen.\n */\nexport function resizeBox(\n box: Box,\n deg: number,\n handle: Handle,\n dx: number,\n dy: number,\n opts: { keepAspect?: boolean; minSize?: number } = {},\n): Box {\n const min = opts.minSize ?? 8;\n const [sx, sy] = SIGN[handle];\n const [ldx, ldy] = rotate(dx, dy, -deg);\n let w = sx ? Math.max(min, box.w + sx * ldx) : box.w;\n let h = sy ? Math.max(min, box.h + sy * ldy) : box.h;\n if (opts.keepAspect && sx && sy) {\n // The larger pull wins, so a diagonal drag tracks the thumb.\n const scale = Math.max(w / box.w, h / box.h);\n const floor = min / Math.min(box.w, box.h);\n const s = Math.max(scale, floor);\n w = box.w * s;\n h = box.h * s;\n }\n // The anchor: the opposite corner (or side midpoint), fixed on screen.\n const cx = box.x + box.w / 2;\n const cy = box.y + box.h / 2;\n const [ax, ay] = rotate((-sx * box.w) / 2, (-sy * box.h) / 2, deg);\n const anchorX = cx + ax;\n const anchorY = cy + ay;\n const [nx, ny] = rotate((-sx * w) / 2, (-sy * h) / 2, deg);\n const ncx = anchorX - nx;\n const ncy = anchorY - ny;\n return { x: ncx - w / 2, y: ncy - h / 2, w, h };\n}\n\n/** Rotation after dragging the knob from `from` to `to` (screen px), snapped to 45° steps within `snap` degrees. */\nexport function rotateFromDrag(\n box: Box,\n startDeg: number,\n from: [number, number],\n to: [number, number],\n snap = 4,\n): number {\n const cx = box.x + box.w / 2;\n const cy = box.y + box.h / 2;\n const a0 = Math.atan2(from[1] - cy, from[0] - cx);\n const a1 = Math.atan2(to[1] - cy, to[0] - cx);\n let deg = startDeg + ((a1 - a0) * 180) / Math.PI;\n deg = ((((deg + 180) % 360) + 360) % 360) - 180;\n const nearest = Math.round(deg / 45) * 45;\n if (Math.abs(deg - nearest) <= snap) deg = nearest === -180 ? 180 : nearest;\n return Math.round(deg * 10) / 10;\n}\n\n/** Snap a moved box's centre and edges to the page's centre lines within `tol` px; returns the snapped box and the guides hit. */\nexport function snapToPage(box: Box, W: number, H: number, tol = 6): { box: Box; guideX: boolean; guideY: boolean } {\n let { x, y } = box;\n let guideX = false;\n let guideY = false;\n if (Math.abs(x + box.w / 2 - W / 2) <= tol) {\n x = W / 2 - box.w / 2;\n guideX = true;\n }\n if (Math.abs(y + box.h / 2 - H / 2) <= tol) {\n y = H / 2 - box.h / 2;\n guideY = true;\n }\n return { box: { ...box, x, y }, guideX, guideY };\n}\n\n/** The lines a moved box snaps to (web studio `utils/snap.ts` snapLines): page edges and centre, every other layer's edges and centre. */\nexport function snapLines(others: readonly Box[], W: number, H: number): { xs: number[]; ys: number[] } {\n const xs = [0, W / 2, W];\n const ys = [0, H / 2, H];\n for (const o of others) {\n xs.push(o.x, o.x + o.w / 2, o.x + o.w);\n ys.push(o.y, o.y + o.h / 2, o.y + o.h);\n }\n return { xs, ys };\n}\n\nfunction nearestLine(\n values: readonly number[],\n lines: readonly number[],\n tol: number,\n): { delta: number; line: number } | null {\n let best: { delta: number; line: number } | null = null;\n for (const v of values) {\n for (const line of lines) {\n const delta = line - v;\n if (Math.abs(delta) <= tol && (!best || Math.abs(delta) < Math.abs(best.delta))) best = { delta, line };\n }\n }\n return best;\n}\n\n/**\n * A move snapped web's way (snapMove): the box's nearest edge or centre onto the\n * nearest line on each axis; `guideX` / `guideY` are where to draw the guides.\n */\nexport function snapMove(\n box: Box,\n lines: { xs: number[]; ys: number[] },\n tol = 6,\n): { box: Box; guideX: number | null; guideY: number | null } {\n const sx = nearestLine([box.x, box.x + box.w / 2, box.x + box.w], lines.xs, tol);\n const sy = nearestLine([box.y, box.y + box.h / 2, box.y + box.h], lines.ys, tol);\n return {\n box: { ...box, x: box.x + (sx?.delta ?? 0), y: box.y + (sy?.delta ?? 0) },\n guideX: sx ? sx.line : null,\n guideY: sy ? sy.line : null,\n };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -221,7 +221,11 @@ const PRINT = {
|
|
|
221
221
|
"canvas-worksheet": PRINT_PLATFORM.worksheet,
|
|
222
222
|
"canvas-proposal": PRINT_PLATFORM.proposal,
|
|
223
223
|
"canvas-newsletter": PRINT_PLATFORM.newsletter,
|
|
224
|
-
"canvas-menu": PRINT_PLATFORM.menu
|
|
224
|
+
"canvas-menu": PRINT_PLATFORM.menu,
|
|
225
|
+
"canvas-document": PRINT_PLATFORM.document,
|
|
226
|
+
"canvas-report": PRINT_PLATFORM.report,
|
|
227
|
+
"canvas-letter": PRINT_PLATFORM.letter,
|
|
228
|
+
"canvas-resume": PRINT_PLATFORM.resume
|
|
225
229
|
};
|
|
226
230
|
const catalogKind = (template) => SCREEN[template.group] ? "deck" : "flyer";
|
|
227
231
|
const platformOf = (group) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"newDoc.js","sources":["../../../../src/features/design/doc/newDoc.ts"],"sourcesContent":["/**\n * Where a design starts: a blank size, or a catalog template.\n *\n * Native twin of canvas-surface `utils/templates.ts` (`blankDoc`),\n * `utils/catalogDoc.ts` (`catalogToDoc`, `catalogKind`, `catalogGroupOf`) and\n * surface-kit `templateCatalogs/designCatalog.ts` (the full card a template\n * opens from). The canvas home's `DesignCatalogCard` carries only what a\n * cover needs; opening a template reads its row again, pages and all.\n *\n * Pure apart from the injected catalog read: runs under jest as-is.\n */\nimport {\n DESIGN_CATALOG_QUERY,\n designCatalogFilter,\n groupOfTemplate,\n type DesignCatalogGroup,\n} from '../../canvas/designCatalog';\nimport { PRINT_PLATFORM, snapAspect, toPx, type DesignSize } from './sizes';\nimport {\n DEFAULT_FONT_PAIR,\n defaultPageName,\n newLayerId,\n newPageId,\n type DesignBrief,\n type DesignDoc,\n type DesignKind,\n type DesignPage,\n type DesignPalette,\n type EditorLayer,\n type PrintSpec,\n} from './types';\n\nexport const DEFAULT_BLEED_MM = 4;\nexport const DEFAULT_SAFE_AREA_MM = 4;\n\nexport function defaultPrintSpec(trimMm?: { w: number; h: number }): PrintSpec {\n return { bleedMm: DEFAULT_BLEED_MM, safeAreaMm: DEFAULT_SAFE_AREA_MM, ...(trimMm ? { trimMm } : {}) };\n}\n\nconst BLANK_PALETTE: DesignPalette = {\n background: '#ffffff',\n surface: '#f1f5f9',\n primary: '#0f172a',\n text: '#020817',\n muted: '#64748b',\n};\n\n/** Templates have no wizard answers behind them - this stands in until the user edits. */\nfunction templateBrief(topic: string, aspectRatio: string, pageCount: number): DesignBrief {\n return {\n platform: 'Instagram',\n format: aspectRatio,\n pageCount,\n topic,\n audience: 'a general audience',\n tone: 'Professional',\n };\n}\n\n/** A blank white page (what web's `designToPages` makes of a blank design page). */\nfunction blankPage(index: number, name?: string): DesignPage {\n return {\n id: `page-${index + 1}-${Date.now().toString(36)}`,\n name: name ?? defaultPageName('cover', index),\n prompt: '',\n src: null,\n status: 'ready',\n role: 'cover',\n background: { kind: 'color', color: BLANK_PALETTE.background },\n layers: [],\n };\n}\n\n/**\n * Blank pages on a white ground, at any pixel size: one per `pageNames` entry (a business\n * card's Front and Back), else one. A print size (`kind: 'flyer'`) also gets a print spec.\n */\nexport function blankDoc({\n width,\n height,\n platform,\n kind,\n trimMm,\n pageNames,\n}: {\n width: number;\n height: number;\n platform: string;\n kind?: DesignKind;\n trimMm?: { w: number; h: number };\n pageNames?: string[];\n}): DesignDoc {\n const aspectRatio = snapAspect(width, height);\n const names = pageNames?.length ? pageNames : [undefined];\n const pages = names.map((name, i) => {\n // a deck's page starts as its Hook; a printed one has no such word (print PDFs name pages by it)\n const page = blankPage(i, name);\n return name ? page : kind === 'flyer' ? { ...page, name: '' } : page;\n });\n return {\n version: 2,\n brief: { ...templateBrief('Untitled design', aspectRatio, pages.length), platform },\n aspectRatio,\n pageWidth: width,\n pageHeight: height,\n palette: BLANK_PALETTE,\n fontPair: { ...DEFAULT_FONT_PAIR },\n pages,\n ...(kind === 'flyer' ? { print: defaultPrintSpec(trimMm) } : {}),\n };\n}\n\n/** A blank design at one of the create screen's sizes. */\nexport function blankDocForSize(size: DesignSize): DesignDoc {\n return blankDoc({\n width: size.width,\n height: size.height,\n platform: size.platform,\n kind: size.kind,\n trimMm: size.trimMm,\n pageNames: size.pageNames,\n });\n}\n\n/** A blank at a size the person typed (Custom size): a screen design unless it came in a physical unit. */\nexport function blankDocCustom(width: number, height: number, trimMm?: { w: number; h: number }): DesignDoc {\n return blankDoc({ width, height, platform: trimMm ? 'Print' : 'Custom', kind: trimMm ? 'flyer' : 'deck', trimMm });\n}\n\n// ── Catalog templates ────────────────────────────────────────────────────\n\n/** One converted template page: editable layers minus the ids and image bookkeeping the editor assigns. */\nexport interface DesignTemplateLayerPage {\n role?: 'cover' | 'content' | 'cta';\n background?: { kind: 'color'; color: string };\n layers: Array<Record<string, unknown>>;\n}\n\n/** A catalog template with everything it opens with (surface-kit `DesignCatalogCard`). */\nexport interface DesignTemplate {\n id: string;\n group: DesignCatalogGroup;\n title: string;\n summary: string;\n coverUrl: string;\n aspectRatio: string;\n pageWidth: number;\n pageHeight: number;\n /** Converted layer pages, or one full-size page image per page (older rows). */\n pages: Array<string | DesignTemplateLayerPage>;\n previews?: string[];\n fonts?: Array<{ family: string; url: string; weight?: number; italic?: boolean }>;\n /** A print template's finished size in mm. */\n trimMm?: { w: number; h: number };\n prompt: string;\n tags?: string[];\n}\n\nconst str = (v: unknown): string => (typeof v === 'string' ? v.trim() : '');\nconst obj = (v: unknown): Record<string, any> =>\n v && typeof v === 'object' && !Array.isArray(v) ? (v as Record<string, any>) : {};\nconst isHttps = (v: unknown): v is string => typeof v === 'string' && /^https:\\/\\//.test(v);\n\n/** One row -> one template; a row without a cover, a size or pages is not a usable template. */\nexport function designTemplateFromRow(row: Record<string, any>, group: DesignCatalogGroup): DesignTemplate | null {\n let formData: Record<string, any> = obj(row?.formData);\n if (typeof row?.formData === 'string') {\n try {\n formData = obj(JSON.parse(row.formData));\n } catch {\n return null;\n }\n }\n const details = obj(formData.generationDetails);\n const design = obj(formData.design);\n const pages: Array<string | DesignTemplateLayerPage> = Array.isArray(design.pages)\n ? design.pages.filter(\n (p: unknown): p is string | DesignTemplateLayerPage =>\n isHttps(p) ||\n (Boolean(p) && typeof p === 'object' && Array.isArray((p as DesignTemplateLayerPage).layers)),\n )\n : [];\n const previews: string[] = Array.isArray(design.previews) ? design.previews.filter(isHttps) : [];\n const fonts = Array.isArray(design.fonts)\n ? design.fonts.filter((f: any) => typeof f?.family === 'string' && isHttps(f?.url))\n : [];\n const pageWidth = Number(design.pageWidth);\n const pageHeight = Number(design.pageHeight);\n const trim = obj(design.trimMm);\n const trimMm = Number(trim.w) > 0 && Number(trim.h) > 0 ? { w: Number(trim.w), h: Number(trim.h) } : null;\n const id = str(row?.name);\n const coverUrl = isHttps(details.previewUrl) ? str(details.previewUrl) : '';\n if (!id || !coverUrl || pages.length === 0 || !(pageWidth > 0) || !(pageHeight > 0)) return null;\n const title = str(details.title) || id;\n return {\n id,\n group,\n title,\n summary: str(details.summary) || str(row?.description),\n coverUrl,\n aspectRatio: str(design.aspectRatio) || str(obj(formData.generation).aspectRatio),\n pageWidth,\n pageHeight,\n pages,\n ...(previews.length ? { previews } : {}),\n ...(fonts.length ? { fonts } : {}),\n ...(trimMm ? { trimMm } : {}),\n prompt: str(obj(formData.generation).prompt) || title,\n ...(Array.isArray(row?.tags) ? { tags: row.tags.filter((t: unknown) => typeof t === 'string') } : {}),\n };\n}\n\n/** Rows a catalog read returns for a filter. */\nexport type ReadCatalogRows = (filter: ReturnType<typeof designCatalogFilter>) => Promise<Array<Record<string, any>>>;\n\n/** One template by id (`?design=<id>`, a gallery tap), or null when it is not in the catalog. */\nexport async function findDesignTemplate(id: string, readRows: ReadCatalogRows): Promise<DesignTemplate | null> {\n const group = groupOfTemplate(id);\n if (!group) return null;\n // The resolver searches names, so the id finds its row; match it exactly. Any row of the\n // group: a template a listing no longer shows still opens by its id.\n const rows = await readRows(designCatalogFilter(group, { search: id, limit: 10, offset: 0, anyRecord: true }));\n for (const row of rows) {\n if (str(row?.name) !== id) continue;\n const template = designTemplateFromRow(row, group);\n if (template) return template;\n }\n return null;\n}\n\n/** The backend read `findDesignTemplate` uses on a phone: plain fetch, bearer when there is one. */\nexport function backendCatalogRows(graphqlUrl: string, token?: string | null): ReadCatalogRows {\n return async (filter) => {\n const res = await fetch(graphqlUrl, {\n method: 'POST',\n headers: { 'content-type': 'application/json', ...(token ? { authorization: `Bearer ${token}` } : {}) },\n body: JSON.stringify({ query: DESIGN_CATALOG_QUERY, variables: { filter } }),\n });\n if (!res.ok) throw new Error(`Template read failed (${res.status})`);\n const json = (await res.json().catch(() => ({}))) as {\n data?: { formTemplateSubmissions?: { nodes?: Array<Record<string, any>> | null } };\n errors?: Array<{ message?: string }>;\n };\n if (json.errors?.length) throw new Error(json.errors[0]?.message || 'Template read failed');\n const nodes = json.data?.formTemplateSubmissions?.nodes;\n return Array.isArray(nodes) ? nodes : [];\n };\n}\n\nconst PALETTE: DesignPalette = {\n background: '#ffffff',\n surface: '#f1f5f9',\n primary: '#0f172a',\n text: '#020817',\n muted: '#64748b',\n};\n\n/** Screen designs save as decks; the rest are printed (flyers, business cards, brochures, stationery). */\nconst SCREEN: Partial<Record<DesignCatalogGroup, string>> = {\n 'canvas-presentation': 'Presentation',\n 'canvas-carousel': 'Instagram',\n 'canvas-logo': 'Logo',\n 'canvas-banner': 'Banner',\n 'canvas-social-post': 'Social',\n 'canvas-infographic': 'Infographic',\n};\n\n/** Printed formats a flyer's shape can't tell apart name their own platform. */\nconst PRINT: Partial<Record<DesignCatalogGroup, string>> = {\n 'canvas-brochure': PRINT_PLATFORM.brochure,\n 'canvas-branding': PRINT_PLATFORM.branding,\n 'canvas-certificate': PRINT_PLATFORM.certificate,\n 'canvas-worksheet': PRINT_PLATFORM.worksheet,\n 'canvas-proposal': PRINT_PLATFORM.proposal,\n 'canvas-newsletter': PRINT_PLATFORM.newsletter,\n 'canvas-menu': PRINT_PLATFORM.menu,\n};\n\nexport const catalogKind = (template: Pick<DesignTemplate, 'group'>): DesignKind =>\n SCREEN[template.group] ? 'deck' : 'flyer';\n\nconst platformOf = (group: DesignCatalogGroup): string => SCREEN[group] ?? PRINT[group] ?? 'Print';\n\n/** The catalog group whose templates fit a design; null for formats the catalog has none for (custom). */\nexport function catalogGroupOf(doc: Pick<DesignDoc, 'brief' | 'pageWidth' | 'pageHeight'>): DesignCatalogGroup | null {\n const platform = doc.brief?.platform;\n const groups = Object.keys({ ...SCREEN, ...PRINT }) as DesignCatalogGroup[];\n const named = groups.find((g) => platformOf(g) === platform);\n if (named) return named;\n if (platform !== 'Print') return null;\n // Business cards run 1.55-1.8 long side to short; the widest flyer preset (postcard) is 1.5.\n const ratio = Math.max(doc.pageWidth, doc.pageHeight) / Math.min(doc.pageWidth, doc.pageHeight);\n return ratio > 1.52 ? 'canvas-business-card' : 'canvas-flyer';\n}\n\n/** Sides a two-page print template is named by, as its blank opens. */\nconst SIDES: Partial<Record<DesignCatalogGroup, [string, string]>> = {\n 'canvas-business-card': ['Front', 'Back'],\n 'canvas-brochure': ['Outside', 'Inside'],\n};\n\n/** A print template with its finished size opens at that size in print px (150 per inch); layers are fractions. */\nfunction pageSizeOf(template: DesignTemplate): { width: number; height: number; trimMm?: { w: number; h: number } } {\n if (catalogKind(template) === 'flyer' && template.trimMm)\n return {\n width: toPx(template.trimMm.w, 'mm'),\n height: toPx(template.trimMm.h, 'mm'),\n trimMm: template.trimMm,\n };\n return { width: template.pageWidth, height: template.pageHeight };\n}\n\n/** A catalog template as a Design Studio document - web `catalogToDoc`, field for field. */\nexport function catalogToDoc(template: DesignTemplate): DesignDoc {\n const stamp = Date.now().toString(36);\n const last = template.pages.length - 1;\n const size = pageSizeOf(template);\n const sides = template.pages.length === 2 ? SIDES[template.group] : undefined;\n const print = catalogKind(template) === 'flyer';\n const nameOf = (role: DesignPage['role'], i: number) => sides?.[i] ?? (print ? '' : defaultPageName(role, i));\n return {\n version: 2,\n brief: {\n platform: platformOf(template.group),\n format: template.aspectRatio || `${template.pageWidth}x${template.pageHeight}`,\n pageCount: template.pages.length,\n topic: template.title,\n audience: 'a general audience',\n tone: 'Professional',\n templateNotes: template.prompt,\n },\n aspectRatio: template.aspectRatio || `${template.pageWidth}:${template.pageHeight}`,\n pageWidth: size.width,\n pageHeight: size.height,\n ...(size.trimMm ? { print: defaultPrintSpec(size.trimMm) } : {}),\n palette: PALETTE,\n fontPair: { display: 'Inter', body: 'Inter' },\n ...(template.fonts?.length ? { fonts: template.fonts } : {}),\n pages: template.pages.map((page, i): DesignPage => {\n const fallbackRole = i === 0 ? 'cover' : i === last && last > 0 ? 'cta' : 'content';\n const base = { id: `page-${i + 1}-${stamp}`, prompt: '', src: null, status: 'ready' as const };\n // An older row: the page image as the page background.\n if (typeof page === 'string') {\n return {\n ...base,\n name: nameOf(fallbackRole, i),\n role: fallbackRole,\n background: { kind: 'image', src: page, imageStatus: 'ready' },\n layers: [],\n };\n }\n const role = page.role ?? fallbackRole;\n return {\n ...base,\n name: nameOf(role, i),\n role,\n background: page.background ?? { kind: 'color', color: '#ffffff' },\n layers: page.layers.map(\n (layer) =>\n ({\n ...layer,\n id: newLayerId(),\n ...(layer.kind === 'image' ? { imageStatus: 'ready', uploaded: true } : {}),\n }) as unknown as EditorLayer,\n ),\n };\n }),\n };\n}\n\n/**\n * A template's pages added to an open design (the Templates tool on a design that already has\n * work): fresh page and layer ids, the layers re-anchored by fraction, so they fit the page size.\n */\nexport function templatePagesFor(template: DesignTemplate): DesignPage[] {\n return catalogToDoc(template).pages.map((page) => ({ ...page, id: newPageId() }));\n}\n"],"names":["_a"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"newDoc.js","sources":["../../../../src/features/design/doc/newDoc.ts"],"sourcesContent":["/**\n * Where a design starts: a blank size, or a catalog template.\n *\n * Native twin of canvas-surface `utils/templates.ts` (`blankDoc`),\n * `utils/catalogDoc.ts` (`catalogToDoc`, `catalogKind`, `catalogGroupOf`) and\n * surface-kit `templateCatalogs/designCatalog.ts` (the full card a template\n * opens from). The canvas home's `DesignCatalogCard` carries only what a\n * cover needs; opening a template reads its row again, pages and all.\n *\n * Pure apart from the injected catalog read: runs under jest as-is.\n */\nimport {\n DESIGN_CATALOG_QUERY,\n designCatalogFilter,\n groupOfTemplate,\n type DesignCatalogGroup,\n} from '../../canvas/designCatalog';\nimport { PRINT_PLATFORM, snapAspect, toPx, type DesignSize } from './sizes';\nimport {\n DEFAULT_FONT_PAIR,\n defaultPageName,\n newLayerId,\n newPageId,\n type DesignBrief,\n type DesignDoc,\n type DesignKind,\n type DesignPage,\n type DesignPalette,\n type EditorLayer,\n type PrintSpec,\n} from './types';\n\nexport const DEFAULT_BLEED_MM = 4;\nexport const DEFAULT_SAFE_AREA_MM = 4;\n\nexport function defaultPrintSpec(trimMm?: { w: number; h: number }): PrintSpec {\n return { bleedMm: DEFAULT_BLEED_MM, safeAreaMm: DEFAULT_SAFE_AREA_MM, ...(trimMm ? { trimMm } : {}) };\n}\n\nconst BLANK_PALETTE: DesignPalette = {\n background: '#ffffff',\n surface: '#f1f5f9',\n primary: '#0f172a',\n text: '#020817',\n muted: '#64748b',\n};\n\n/** Templates have no wizard answers behind them - this stands in until the user edits. */\nfunction templateBrief(topic: string, aspectRatio: string, pageCount: number): DesignBrief {\n return {\n platform: 'Instagram',\n format: aspectRatio,\n pageCount,\n topic,\n audience: 'a general audience',\n tone: 'Professional',\n };\n}\n\n/** A blank white page (what web's `designToPages` makes of a blank design page). */\nfunction blankPage(index: number, name?: string): DesignPage {\n return {\n id: `page-${index + 1}-${Date.now().toString(36)}`,\n name: name ?? defaultPageName('cover', index),\n prompt: '',\n src: null,\n status: 'ready',\n role: 'cover',\n background: { kind: 'color', color: BLANK_PALETTE.background },\n layers: [],\n };\n}\n\n/**\n * Blank pages on a white ground, at any pixel size: one per `pageNames` entry (a business\n * card's Front and Back), else one. A print size (`kind: 'flyer'`) also gets a print spec.\n */\nexport function blankDoc({\n width,\n height,\n platform,\n kind,\n trimMm,\n pageNames,\n}: {\n width: number;\n height: number;\n platform: string;\n kind?: DesignKind;\n trimMm?: { w: number; h: number };\n pageNames?: string[];\n}): DesignDoc {\n const aspectRatio = snapAspect(width, height);\n const names = pageNames?.length ? pageNames : [undefined];\n const pages = names.map((name, i) => {\n // a deck's page starts as its Hook; a printed one has no such word (print PDFs name pages by it)\n const page = blankPage(i, name);\n return name ? page : kind === 'flyer' ? { ...page, name: '' } : page;\n });\n return {\n version: 2,\n brief: { ...templateBrief('Untitled design', aspectRatio, pages.length), platform },\n aspectRatio,\n pageWidth: width,\n pageHeight: height,\n palette: BLANK_PALETTE,\n fontPair: { ...DEFAULT_FONT_PAIR },\n pages,\n ...(kind === 'flyer' ? { print: defaultPrintSpec(trimMm) } : {}),\n };\n}\n\n/** A blank design at one of the create screen's sizes. */\nexport function blankDocForSize(size: DesignSize): DesignDoc {\n return blankDoc({\n width: size.width,\n height: size.height,\n platform: size.platform,\n kind: size.kind,\n trimMm: size.trimMm,\n pageNames: size.pageNames,\n });\n}\n\n/** A blank at a size the person typed (Custom size): a screen design unless it came in a physical unit. */\nexport function blankDocCustom(width: number, height: number, trimMm?: { w: number; h: number }): DesignDoc {\n return blankDoc({ width, height, platform: trimMm ? 'Print' : 'Custom', kind: trimMm ? 'flyer' : 'deck', trimMm });\n}\n\n// ── Catalog templates ────────────────────────────────────────────────────\n\n/** One converted template page: editable layers minus the ids and image bookkeeping the editor assigns. */\nexport interface DesignTemplateLayerPage {\n role?: 'cover' | 'content' | 'cta';\n background?: { kind: 'color'; color: string };\n layers: Array<Record<string, unknown>>;\n}\n\n/** A catalog template with everything it opens with (surface-kit `DesignCatalogCard`). */\nexport interface DesignTemplate {\n id: string;\n group: DesignCatalogGroup;\n title: string;\n summary: string;\n coverUrl: string;\n aspectRatio: string;\n pageWidth: number;\n pageHeight: number;\n /** Converted layer pages, or one full-size page image per page (older rows). */\n pages: Array<string | DesignTemplateLayerPage>;\n previews?: string[];\n fonts?: Array<{ family: string; url: string; weight?: number; italic?: boolean }>;\n /** A print template's finished size in mm. */\n trimMm?: { w: number; h: number };\n prompt: string;\n tags?: string[];\n}\n\nconst str = (v: unknown): string => (typeof v === 'string' ? v.trim() : '');\nconst obj = (v: unknown): Record<string, any> =>\n v && typeof v === 'object' && !Array.isArray(v) ? (v as Record<string, any>) : {};\nconst isHttps = (v: unknown): v is string => typeof v === 'string' && /^https:\\/\\//.test(v);\n\n/** One row -> one template; a row without a cover, a size or pages is not a usable template. */\nexport function designTemplateFromRow(row: Record<string, any>, group: DesignCatalogGroup): DesignTemplate | null {\n let formData: Record<string, any> = obj(row?.formData);\n if (typeof row?.formData === 'string') {\n try {\n formData = obj(JSON.parse(row.formData));\n } catch {\n return null;\n }\n }\n const details = obj(formData.generationDetails);\n const design = obj(formData.design);\n const pages: Array<string | DesignTemplateLayerPage> = Array.isArray(design.pages)\n ? design.pages.filter(\n (p: unknown): p is string | DesignTemplateLayerPage =>\n isHttps(p) ||\n (Boolean(p) && typeof p === 'object' && Array.isArray((p as DesignTemplateLayerPage).layers)),\n )\n : [];\n const previews: string[] = Array.isArray(design.previews) ? design.previews.filter(isHttps) : [];\n const fonts = Array.isArray(design.fonts)\n ? design.fonts.filter((f: any) => typeof f?.family === 'string' && isHttps(f?.url))\n : [];\n const pageWidth = Number(design.pageWidth);\n const pageHeight = Number(design.pageHeight);\n const trim = obj(design.trimMm);\n const trimMm = Number(trim.w) > 0 && Number(trim.h) > 0 ? { w: Number(trim.w), h: Number(trim.h) } : null;\n const id = str(row?.name);\n const coverUrl = isHttps(details.previewUrl) ? str(details.previewUrl) : '';\n if (!id || !coverUrl || pages.length === 0 || !(pageWidth > 0) || !(pageHeight > 0)) return null;\n const title = str(details.title) || id;\n return {\n id,\n group,\n title,\n summary: str(details.summary) || str(row?.description),\n coverUrl,\n aspectRatio: str(design.aspectRatio) || str(obj(formData.generation).aspectRatio),\n pageWidth,\n pageHeight,\n pages,\n ...(previews.length ? { previews } : {}),\n ...(fonts.length ? { fonts } : {}),\n ...(trimMm ? { trimMm } : {}),\n prompt: str(obj(formData.generation).prompt) || title,\n ...(Array.isArray(row?.tags) ? { tags: row.tags.filter((t: unknown) => typeof t === 'string') } : {}),\n };\n}\n\n/** Rows a catalog read returns for a filter. */\nexport type ReadCatalogRows = (filter: ReturnType<typeof designCatalogFilter>) => Promise<Array<Record<string, any>>>;\n\n/** One template by id (`?design=<id>`, a gallery tap), or null when it is not in the catalog. */\nexport async function findDesignTemplate(id: string, readRows: ReadCatalogRows): Promise<DesignTemplate | null> {\n const group = groupOfTemplate(id);\n if (!group) return null;\n // The resolver searches names, so the id finds its row; match it exactly. Any row of the\n // group: a template a listing no longer shows still opens by its id.\n const rows = await readRows(designCatalogFilter(group, { search: id, limit: 10, offset: 0, anyRecord: true }));\n for (const row of rows) {\n if (str(row?.name) !== id) continue;\n const template = designTemplateFromRow(row, group);\n if (template) return template;\n }\n return null;\n}\n\n/** The backend read `findDesignTemplate` uses on a phone: plain fetch, bearer when there is one. */\nexport function backendCatalogRows(graphqlUrl: string, token?: string | null): ReadCatalogRows {\n return async (filter) => {\n const res = await fetch(graphqlUrl, {\n method: 'POST',\n headers: { 'content-type': 'application/json', ...(token ? { authorization: `Bearer ${token}` } : {}) },\n body: JSON.stringify({ query: DESIGN_CATALOG_QUERY, variables: { filter } }),\n });\n if (!res.ok) throw new Error(`Template read failed (${res.status})`);\n const json = (await res.json().catch(() => ({}))) as {\n data?: { formTemplateSubmissions?: { nodes?: Array<Record<string, any>> | null } };\n errors?: Array<{ message?: string }>;\n };\n if (json.errors?.length) throw new Error(json.errors[0]?.message || 'Template read failed');\n const nodes = json.data?.formTemplateSubmissions?.nodes;\n return Array.isArray(nodes) ? nodes : [];\n };\n}\n\nconst PALETTE: DesignPalette = {\n background: '#ffffff',\n surface: '#f1f5f9',\n primary: '#0f172a',\n text: '#020817',\n muted: '#64748b',\n};\n\n/** Screen designs save as decks; the rest are printed (flyers, business cards, brochures, stationery). */\nconst SCREEN: Partial<Record<DesignCatalogGroup, string>> = {\n 'canvas-presentation': 'Presentation',\n 'canvas-carousel': 'Instagram',\n 'canvas-logo': 'Logo',\n 'canvas-banner': 'Banner',\n 'canvas-social-post': 'Social',\n 'canvas-infographic': 'Infographic',\n};\n\n/** Printed formats a flyer's shape can't tell apart name their own platform. */\nconst PRINT: Partial<Record<DesignCatalogGroup, string>> = {\n 'canvas-brochure': PRINT_PLATFORM.brochure,\n 'canvas-branding': PRINT_PLATFORM.branding,\n 'canvas-certificate': PRINT_PLATFORM.certificate,\n 'canvas-worksheet': PRINT_PLATFORM.worksheet,\n 'canvas-proposal': PRINT_PLATFORM.proposal,\n 'canvas-newsletter': PRINT_PLATFORM.newsletter,\n 'canvas-menu': PRINT_PLATFORM.menu,\n 'canvas-document': PRINT_PLATFORM.document,\n 'canvas-report': PRINT_PLATFORM.report,\n 'canvas-letter': PRINT_PLATFORM.letter,\n 'canvas-resume': PRINT_PLATFORM.resume,\n};\n\nexport const catalogKind = (template: Pick<DesignTemplate, 'group'>): DesignKind =>\n SCREEN[template.group] ? 'deck' : 'flyer';\n\nconst platformOf = (group: DesignCatalogGroup): string => SCREEN[group] ?? PRINT[group] ?? 'Print';\n\n/** The catalog group whose templates fit a design; null for formats the catalog has none for (custom). */\nexport function catalogGroupOf(doc: Pick<DesignDoc, 'brief' | 'pageWidth' | 'pageHeight'>): DesignCatalogGroup | null {\n const platform = doc.brief?.platform;\n const groups = Object.keys({ ...SCREEN, ...PRINT }) as DesignCatalogGroup[];\n const named = groups.find((g) => platformOf(g) === platform);\n if (named) return named;\n if (platform !== 'Print') return null;\n // Business cards run 1.55-1.8 long side to short; the widest flyer preset (postcard) is 1.5.\n const ratio = Math.max(doc.pageWidth, doc.pageHeight) / Math.min(doc.pageWidth, doc.pageHeight);\n return ratio > 1.52 ? 'canvas-business-card' : 'canvas-flyer';\n}\n\n/** Sides a two-page print template is named by, as its blank opens. */\nconst SIDES: Partial<Record<DesignCatalogGroup, [string, string]>> = {\n 'canvas-business-card': ['Front', 'Back'],\n 'canvas-brochure': ['Outside', 'Inside'],\n};\n\n/** A print template with its finished size opens at that size in print px (150 per inch); layers are fractions. */\nfunction pageSizeOf(template: DesignTemplate): { width: number; height: number; trimMm?: { w: number; h: number } } {\n if (catalogKind(template) === 'flyer' && template.trimMm)\n return {\n width: toPx(template.trimMm.w, 'mm'),\n height: toPx(template.trimMm.h, 'mm'),\n trimMm: template.trimMm,\n };\n return { width: template.pageWidth, height: template.pageHeight };\n}\n\n/** A catalog template as a Design Studio document - web `catalogToDoc`, field for field. */\nexport function catalogToDoc(template: DesignTemplate): DesignDoc {\n const stamp = Date.now().toString(36);\n const last = template.pages.length - 1;\n const size = pageSizeOf(template);\n const sides = template.pages.length === 2 ? SIDES[template.group] : undefined;\n const print = catalogKind(template) === 'flyer';\n const nameOf = (role: DesignPage['role'], i: number) => sides?.[i] ?? (print ? '' : defaultPageName(role, i));\n return {\n version: 2,\n brief: {\n platform: platformOf(template.group),\n format: template.aspectRatio || `${template.pageWidth}x${template.pageHeight}`,\n pageCount: template.pages.length,\n topic: template.title,\n audience: 'a general audience',\n tone: 'Professional',\n templateNotes: template.prompt,\n },\n aspectRatio: template.aspectRatio || `${template.pageWidth}:${template.pageHeight}`,\n pageWidth: size.width,\n pageHeight: size.height,\n ...(size.trimMm ? { print: defaultPrintSpec(size.trimMm) } : {}),\n palette: PALETTE,\n fontPair: { display: 'Inter', body: 'Inter' },\n ...(template.fonts?.length ? { fonts: template.fonts } : {}),\n pages: template.pages.map((page, i): DesignPage => {\n const fallbackRole = i === 0 ? 'cover' : i === last && last > 0 ? 'cta' : 'content';\n const base = { id: `page-${i + 1}-${stamp}`, prompt: '', src: null, status: 'ready' as const };\n // An older row: the page image as the page background.\n if (typeof page === 'string') {\n return {\n ...base,\n name: nameOf(fallbackRole, i),\n role: fallbackRole,\n background: { kind: 'image', src: page, imageStatus: 'ready' },\n layers: [],\n };\n }\n const role = page.role ?? fallbackRole;\n return {\n ...base,\n name: nameOf(role, i),\n role,\n background: page.background ?? { kind: 'color', color: '#ffffff' },\n layers: page.layers.map(\n (layer) =>\n ({\n ...layer,\n id: newLayerId(),\n ...(layer.kind === 'image' ? { imageStatus: 'ready', uploaded: true } : {}),\n }) as unknown as EditorLayer,\n ),\n };\n }),\n };\n}\n\n/**\n * A template's pages added to an open design (the Templates tool on a design that already has\n * work): fresh page and layer ids, the layers re-anchored by fraction, so they fit the page size.\n */\nexport function templatePagesFor(template: DesignTemplate): DesignPage[] {\n return catalogToDoc(template).pages.map((page) => ({ ...page, id: newPageId() }));\n}\n"],"names":["_a"],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import {isStrokeShape}from'./shapes.js';import {defaultPrintSpec}from'./newDoc.js';var __defProp = Object.defineProperty;
|
|
2
|
+
var __defProps = Object.defineProperties;
|
|
3
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __spreadValues = (a, b) => {
|
|
9
|
+
for (var prop in b || (b = {}))
|
|
10
|
+
if (__hasOwnProp.call(b, prop))
|
|
11
|
+
__defNormalProp(a, prop, b[prop]);
|
|
12
|
+
if (__getOwnPropSymbols)
|
|
13
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
+
if (__propIsEnum.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
}
|
|
17
|
+
return a;
|
|
18
|
+
};
|
|
19
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
+
var __objRest = (source, exclude) => {
|
|
21
|
+
var target = {};
|
|
22
|
+
for (var prop in source)
|
|
23
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
24
|
+
target[prop] = source[prop];
|
|
25
|
+
if (source != null && __getOwnPropSymbols)
|
|
26
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
27
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
28
|
+
target[prop] = source[prop];
|
|
29
|
+
}
|
|
30
|
+
return target;
|
|
31
|
+
};
|
|
32
|
+
const SPAN = 0.98;
|
|
33
|
+
const CENTRE_TOL = 0.05;
|
|
34
|
+
function axis(start, size, oldPx, newPx, s) {
|
|
35
|
+
const next = size * oldPx * s / newPx;
|
|
36
|
+
const before = start;
|
|
37
|
+
const after = 1 - start - size;
|
|
38
|
+
if (Math.abs(before - after) <= CENTRE_TOL) return [start + size / 2 - next / 2, next];
|
|
39
|
+
if (before < after) return [before * oldPx * s / newPx, next];
|
|
40
|
+
return [1 - after * oldPx * s / newPx - next, next];
|
|
41
|
+
}
|
|
42
|
+
function resizeLayer(layer, oldW, oldH, newW, newH) {
|
|
43
|
+
const s = Math.min(newW / oldW, newH / oldH);
|
|
44
|
+
const band = layer.kind === "shape" && (layer.shape === "rect" || isStrokeShape(layer.shape));
|
|
45
|
+
const [x, w] = band && layer.w >= SPAN ? [layer.x, layer.w] : axis(layer.x, layer.w, oldW, newW, s);
|
|
46
|
+
const [y, h] = band && layer.h >= SPAN ? [layer.y, layer.h] : axis(layer.y, layer.h, oldH, newH, s);
|
|
47
|
+
const k = oldW * s / newW;
|
|
48
|
+
if (layer.kind === "text") {
|
|
49
|
+
return __spreadValues(__spreadProps(__spreadValues({}, layer), {
|
|
50
|
+
x,
|
|
51
|
+
y,
|
|
52
|
+
w,
|
|
53
|
+
h,
|
|
54
|
+
fontSizeFrac: layer.fontSizeFrac * k
|
|
55
|
+
}), layer.letterSpacingFrac ? {
|
|
56
|
+
letterSpacingFrac: layer.letterSpacingFrac * k
|
|
57
|
+
} : {});
|
|
58
|
+
}
|
|
59
|
+
if (layer.kind === "shape" && layer.strokeWidthFrac) {
|
|
60
|
+
return __spreadProps(__spreadValues({}, layer), {
|
|
61
|
+
x,
|
|
62
|
+
y,
|
|
63
|
+
w,
|
|
64
|
+
h,
|
|
65
|
+
strokeWidthFrac: layer.strokeWidthFrac * k
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return __spreadProps(__spreadValues({}, layer), {
|
|
69
|
+
x,
|
|
70
|
+
y,
|
|
71
|
+
w,
|
|
72
|
+
h
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function resizedPrintSpec(print, trimMm) {
|
|
76
|
+
if (trimMm) return {
|
|
77
|
+
print: __spreadProps(__spreadValues({}, print != null ? print : defaultPrintSpec()), {
|
|
78
|
+
trimMm
|
|
79
|
+
})
|
|
80
|
+
};
|
|
81
|
+
if (!print) return {};
|
|
82
|
+
const _a = print, {
|
|
83
|
+
trimMm: _stale
|
|
84
|
+
} = _a, kept = __objRest(_a, [
|
|
85
|
+
"trimMm"
|
|
86
|
+
]);
|
|
87
|
+
return {
|
|
88
|
+
print: kept
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function resizeDocPatch(doc, width, height, aspectRatio, trimMm) {
|
|
92
|
+
return {
|
|
93
|
+
pageWidth: width,
|
|
94
|
+
pageHeight: height,
|
|
95
|
+
aspectRatio,
|
|
96
|
+
print: resizedPrintSpec(doc.print, trimMm).print,
|
|
97
|
+
pages: doc.pages.map((p) => p.layers ? __spreadProps(__spreadValues({}, p), {
|
|
98
|
+
layers: p.layers.map((l) => resizeLayer(l, doc.pageWidth, doc.pageHeight, width, height))
|
|
99
|
+
}) : p)
|
|
100
|
+
};
|
|
101
|
+
}export{resizeDocPatch,resizeLayer,resizedPrintSpec};//# sourceMappingURL=resize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resize.js","sources":["../../../../src/features/design/doc/resize.ts"],"sourcesContent":["/**\n * Resize a design without stretching it - native twin of web studio\n * `utils/resize.ts` (`resizeLayer`) and `state.tsx` `resizedPrintSpec`.\n *\n * Each layer keeps its aspect and re-anchors to its nearer edge (or the centre\n * when it was centred); full-width bands keep spanning. A physical size sets\n * the print trim; a screen size drops only the trim, keeping bleed and safe\n * area. Pure: runs under jest as-is.\n */\nimport { isStrokeShape } from './shapes';\nimport { defaultPrintSpec } from './newDoc';\nimport type { DesignDoc, EditorLayer, PrintSpec } from './types';\n\n/** A rect or line this wide (or tall) is a band and keeps spanning the new page. */\nconst SPAN = 0.98;\n/** Edge gaps this close count as centred. */\nconst CENTRE_TOL = 0.05;\n\n/** Scale size in pixels while preserving the nearer edge's gap or the centre on each axis. */\nfunction axis(start: number, size: number, oldPx: number, newPx: number, s: number): [number, number] {\n const next = (size * oldPx * s) / newPx;\n const before = start;\n const after = 1 - start - size;\n if (Math.abs(before - after) <= CENTRE_TOL) return [start + size / 2 - next / 2, next];\n if (before < after) return [(before * oldPx * s) / newPx, next];\n return [1 - (after * oldPx * s) / newPx - next, next];\n}\n\nexport function resizeLayer<T extends EditorLayer>(\n layer: T,\n oldW: number,\n oldH: number,\n newW: number,\n newH: number,\n): T {\n const s = Math.min(newW / oldW, newH / oldH);\n const band = layer.kind === 'shape' && (layer.shape === 'rect' || isStrokeShape(layer.shape));\n const [x, w] = band && layer.w >= SPAN ? [layer.x, layer.w] : axis(layer.x, layer.w, oldW, newW, s);\n const [y, h] = band && layer.h >= SPAN ? [layer.y, layer.h] : axis(layer.y, layer.h, oldH, newH, s);\n // Sizes stored as page-width fractions keep their px-per-scale.\n const k = (oldW * s) / newW;\n if (layer.kind === 'text') {\n return {\n ...layer,\n x,\n y,\n w,\n h,\n fontSizeFrac: layer.fontSizeFrac * k,\n ...(layer.letterSpacingFrac ? { letterSpacingFrac: layer.letterSpacingFrac * k } : {}),\n };\n }\n if (layer.kind === 'shape' && layer.strokeWidthFrac) {\n return { ...layer, x, y, w, h, strokeWidthFrac: layer.strokeWidthFrac * k };\n }\n return { ...layer, x, y, w, h };\n}\n\n/** `trimMm`: a physical size sets the trim; null (a screen size) drops only the trim. */\nexport function resizedPrintSpec(\n print: PrintSpec | undefined,\n trimMm: PrintSpec['trimMm'] | null,\n): { print?: PrintSpec } {\n if (trimMm) return { print: { ...(print ?? defaultPrintSpec()), trimMm } };\n if (!print) return {};\n const { trimMm: _stale, ...kept } = print;\n return { print: kept as PrintSpec };\n}\n\n/** The doc patch a resize applies: the size, the print spec and every layer re-anchored. */\nexport function resizeDocPatch(\n doc: DesignDoc,\n width: number,\n height: number,\n aspectRatio: string,\n trimMm: PrintSpec['trimMm'] | null,\n): Partial<DesignDoc> {\n return {\n pageWidth: width,\n pageHeight: height,\n aspectRatio,\n print: resizedPrintSpec(doc.print, trimMm).print,\n pages: doc.pages.map((p) =>\n p.layers\n ? { ...p, layers: p.layers.map((l) => resizeLayer(l, doc.pageWidth, doc.pageHeight, width, height)) }\n : p,\n ),\n };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -17,7 +17,7 @@ var __spreadValues = (a, b) => {
|
|
|
17
17
|
return a;
|
|
18
18
|
};
|
|
19
19
|
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
-
const PRINT_CATEGORIES = ["flyer", "business-card", "brochure", "branding", "certificate", "worksheet", "proposal", "newsletter", "menu"];
|
|
20
|
+
const PRINT_CATEGORIES = ["flyer", "business-card", "brochure", "branding", "certificate", "worksheet", "proposal", "newsletter", "menu", "document", "report", "letter", "resume"];
|
|
21
21
|
function isPrintCategory(category) {
|
|
22
22
|
return PRINT_CATEGORIES.includes(category);
|
|
23
23
|
}
|
|
@@ -30,7 +30,11 @@ const PRINT_PLATFORM = {
|
|
|
30
30
|
worksheet: "Worksheet",
|
|
31
31
|
proposal: "Proposal",
|
|
32
32
|
newsletter: "Newsletter",
|
|
33
|
-
menu: "Menu"
|
|
33
|
+
menu: "Menu",
|
|
34
|
+
document: "Document",
|
|
35
|
+
report: "Report",
|
|
36
|
+
letter: "Letter",
|
|
37
|
+
resume: "Resume"
|
|
34
38
|
};
|
|
35
39
|
const PRINT_DPI = 150;
|
|
36
40
|
const MIN_PX = 40;
|
|
@@ -200,6 +204,15 @@ const DESIGN_SIZES = [
|
|
|
200
204
|
print("menu-letter", "Menu (US Letter)", 8.5, 11, "in", "restaurant cafe bar food drinks", "menu"),
|
|
201
205
|
print("menu-a4", "Menu (A4)", 210, 297, "mm", "restaurant cafe bar food drinks", "menu"),
|
|
202
206
|
print("menu-tabloid", "Menu (Tabloid)", 11, 17, "in", "restaurant cafe bar large", "menu"),
|
|
207
|
+
// Canva's documents, reports, letters and resumes are portrait Letter or A4 pages.
|
|
208
|
+
print("document-letter", "Document (US Letter)", 8.5, 11, "in", "agenda form plan handout doc paper", "document"),
|
|
209
|
+
print("document-a4", "Document (A4)", 210, 297, "mm", "agenda form plan handout doc paper", "document"),
|
|
210
|
+
print("report-letter", "Report (US Letter)", 8.5, 11, "in", "annual business project research school", "report"),
|
|
211
|
+
print("report-a4", "Report (A4)", 210, 297, "mm", "annual business project research school", "report"),
|
|
212
|
+
print("letter-us", "Letter (US Letter)", 8.5, 11, "in", "cover business formal thank you", "letter"),
|
|
213
|
+
print("letter-a4", "Letter (A4)", 210, 297, "mm", "cover business formal thank you", "letter"),
|
|
214
|
+
print("resume-letter", "Resume (US Letter)", 8.5, 11, "in", "cv curriculum vitae job career", "resume"),
|
|
215
|
+
print("resume-a4", "Resume (A4)", 210, 297, "mm", "cv curriculum vitae job career", "resume"),
|
|
203
216
|
// Canva's infographic is a tall screen page, 800 x 2000 px.
|
|
204
217
|
{
|
|
205
218
|
id: "infographic",
|