@templatical/core 0.7.2 → 0.7.3
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/dist/index.js +43 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -5,6 +5,11 @@ import {
|
|
|
5
5
|
reactive,
|
|
6
6
|
readonly
|
|
7
7
|
} from "@vue/reactivity";
|
|
8
|
+
function getColumnCount(layout) {
|
|
9
|
+
if (layout === "1") return 1;
|
|
10
|
+
if (layout === "3") return 3;
|
|
11
|
+
return 2;
|
|
12
|
+
}
|
|
8
13
|
function useEditor(options) {
|
|
9
14
|
const state = reactive({
|
|
10
15
|
content: options.content ?? createDefaultTemplateContent(
|
|
@@ -41,6 +46,16 @@ function useEditor(options) {
|
|
|
41
46
|
}
|
|
42
47
|
return null;
|
|
43
48
|
}
|
|
49
|
+
function collectBlockIds(block, ids) {
|
|
50
|
+
ids.add(block.id);
|
|
51
|
+
if (block.type === "section") {
|
|
52
|
+
for (const column of block.children) {
|
|
53
|
+
for (const child of column) {
|
|
54
|
+
collectBlockIds(child, ids);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
44
59
|
function findBlockParent(blocks, id, parent = { blocks }) {
|
|
45
60
|
for (let i = 0; i < blocks.length; i++) {
|
|
46
61
|
const block = blocks[i];
|
|
@@ -120,6 +135,9 @@ function useEditor(options) {
|
|
|
120
135
|
}
|
|
121
136
|
const section = findBlockById(state.content.blocks, targetSectionId);
|
|
122
137
|
if (section && section.type === "section") {
|
|
138
|
+
if (columnIndex < 0 || columnIndex >= getColumnCount(section.columns)) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
123
141
|
section.children[columnIndex] = section.children[columnIndex] || [];
|
|
124
142
|
const targetArray = section.children[columnIndex];
|
|
125
143
|
if (index !== void 0 && index < targetArray.length) {
|
|
@@ -145,9 +163,13 @@ function useEditor(options) {
|
|
|
145
163
|
if (parent) {
|
|
146
164
|
const index = parent.blocks.findIndex((b) => b.id === blockId);
|
|
147
165
|
if (index !== -1) {
|
|
148
|
-
parent.blocks.splice(index, 1);
|
|
149
|
-
if (state.selectedBlockId
|
|
150
|
-
|
|
166
|
+
const [removed] = parent.blocks.splice(index, 1);
|
|
167
|
+
if (state.selectedBlockId) {
|
|
168
|
+
const removedIds = /* @__PURE__ */ new Set();
|
|
169
|
+
collectBlockIds(removed, removedIds);
|
|
170
|
+
if (removedIds.has(state.selectedBlockId)) {
|
|
171
|
+
state.selectedBlockId = null;
|
|
172
|
+
}
|
|
151
173
|
}
|
|
152
174
|
state.isDirty = true;
|
|
153
175
|
}
|
|
@@ -168,6 +190,9 @@ function useEditor(options) {
|
|
|
168
190
|
if (targetSectionId) {
|
|
169
191
|
const section = findBlockById(state.content.blocks, targetSectionId);
|
|
170
192
|
if (!section || section.type !== "section") return;
|
|
193
|
+
if (columnIndex < 0 || columnIndex >= getColumnCount(section.columns)) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
171
196
|
section.children[columnIndex] = section.children[columnIndex] || [];
|
|
172
197
|
targetArray = section.children[columnIndex];
|
|
173
198
|
} else {
|
|
@@ -330,6 +355,19 @@ function useHistory(options) {
|
|
|
330
355
|
|
|
331
356
|
// src/block-actions.ts
|
|
332
357
|
import { createBlock, generateId } from "@templatical/types";
|
|
358
|
+
function regenerateNestedIds(block) {
|
|
359
|
+
if (block.type === "table") {
|
|
360
|
+
block.rows = block.rows.map((row) => ({
|
|
361
|
+
...row,
|
|
362
|
+
id: generateId(),
|
|
363
|
+
cells: row.cells.map((cell) => ({ ...cell, id: generateId() }))
|
|
364
|
+
}));
|
|
365
|
+
} else if (block.type === "social") {
|
|
366
|
+
block.icons = block.icons.map((icon) => ({ ...icon, id: generateId() }));
|
|
367
|
+
} else if (block.type === "menu") {
|
|
368
|
+
block.items = block.items.map((item) => ({ ...item, id: generateId() }));
|
|
369
|
+
}
|
|
370
|
+
}
|
|
333
371
|
function useBlockActions(options) {
|
|
334
372
|
const { addBlock, removeBlock, updateBlock, selectBlock, findBlockLocation } = options;
|
|
335
373
|
function createAndAddBlock(type, targetSectionId, columnIndex) {
|
|
@@ -341,11 +379,13 @@ function useBlockActions(options) {
|
|
|
341
379
|
function duplicateBlock(block, targetSectionId, columnIndex) {
|
|
342
380
|
const cloned = JSON.parse(JSON.stringify(block));
|
|
343
381
|
cloned.id = generateId();
|
|
382
|
+
regenerateNestedIds(cloned);
|
|
344
383
|
if (cloned.type === "section") {
|
|
345
384
|
cloned.children = cloned.children.map(
|
|
346
385
|
(column) => column.map((child) => {
|
|
347
386
|
const clonedChild = JSON.parse(JSON.stringify(child));
|
|
348
387
|
clonedChild.id = generateId();
|
|
388
|
+
regenerateNestedIds(clonedChild);
|
|
349
389
|
return clonedChild;
|
|
350
390
|
})
|
|
351
391
|
);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/editor.ts","../src/history.ts","../src/block-actions.ts","../src/auto-save.ts","../src/condition-preview.ts","../src/data-source-fetch.ts","../src/history-interceptor.ts"],"sourcesContent":["import type {\n Block,\n TemplateContent,\n TemplateDefaults,\n TemplateSettings,\n UiTheme,\n ViewportSize,\n} from \"@templatical/types\";\nimport { createDefaultTemplateContent } from \"@templatical/types\";\nimport {\n computed,\n reactive,\n readonly,\n type DeepReadonly,\n type Ref,\n} from \"@vue/reactivity\";\n\nexport interface EditorState {\n content: TemplateContent;\n selectedBlockId: string | null;\n viewport: ViewportSize;\n darkMode: boolean;\n previewMode: boolean;\n isDirty: boolean;\n uiTheme: UiTheme;\n}\n\nexport interface UseEditorOptions {\n content: TemplateContent;\n defaultFontFamily?: string;\n templateDefaults?: TemplateDefaults;\n lockedBlocks?: Ref<Map<string, unknown>>;\n}\n\nexport interface UseEditorReturn {\n state: DeepReadonly<EditorState>;\n content: Ref<TemplateContent>;\n selectedBlock: Ref<Block | null>;\n setContent: (content: TemplateContent, markDirty?: boolean) => void;\n selectBlock: (blockId: string | null) => void;\n setViewport: (viewport: ViewportSize) => void;\n setDarkMode: (darkMode: boolean) => void;\n setPreviewMode: (previewMode: boolean) => void;\n setUiTheme: (theme: UiTheme) => void;\n updateBlock: (blockId: string, updates: Partial<Block>) => void;\n updateSettings: (updates: Partial<TemplateSettings>) => void;\n addBlock: (\n block: Block,\n targetSectionId?: string,\n columnIndex?: number,\n index?: number,\n ) => void;\n removeBlock: (blockId: string) => void;\n moveBlock: (\n blockId: string,\n newIndex: number,\n targetSectionId?: string,\n columnIndex?: number,\n ) => void;\n isBlockLocked: (blockId: string) => boolean;\n markDirty: () => void;\n findBlockLocation: (blockId: string) => {\n targetSectionId?: string;\n columnIndex?: number;\n index: number;\n } | null;\n}\n\nexport function useEditor(options: UseEditorOptions): UseEditorReturn {\n const state = reactive<EditorState>({\n content:\n options.content ??\n createDefaultTemplateContent(\n options.defaultFontFamily,\n options.templateDefaults,\n ),\n selectedBlockId: null,\n viewport: \"desktop\",\n darkMode: false,\n previewMode: false,\n isDirty: false,\n uiTheme: \"auto\",\n });\n\n const content = computed({\n get: () => state.content,\n set: (value: TemplateContent) => {\n state.content = value;\n state.isDirty = true;\n },\n });\n\n const selectedBlock = computed(() => {\n if (!state.selectedBlockId) return null;\n return findBlockById(state.content.blocks, state.selectedBlockId);\n });\n\n function findBlockById(blocks: Block[], id: string): Block | null {\n for (const block of blocks) {\n if (block.id === id) return block;\n if (block.type === \"section\") {\n for (const column of block.children) {\n const found = findBlockById(column, id);\n if (found) return found;\n }\n }\n }\n return null;\n }\n\n function findBlockParent(\n blocks: Block[],\n id: string,\n parent: {\n blocks: Block[];\n sectionId?: string;\n columnIndex?: number;\n } = { blocks },\n ): { blocks: Block[]; sectionId?: string; columnIndex?: number } | null {\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i];\n if (block.id === id) return parent;\n if (block.type === \"section\") {\n for (let colIdx = 0; colIdx < block.children.length; colIdx++) {\n const result = findBlockParent(block.children[colIdx], id, {\n blocks: block.children[colIdx],\n sectionId: block.id,\n columnIndex: colIdx,\n });\n if (result) return result;\n }\n }\n }\n return null;\n }\n\n function isBlockLocked(blockId: string): boolean {\n return options.lockedBlocks?.value.has(blockId) ?? false;\n }\n\n function findBlockLocation(blockId: string): {\n targetSectionId?: string;\n columnIndex?: number;\n index: number;\n } | null {\n const parent = findBlockParent(state.content.blocks, blockId);\n if (!parent) return null;\n const index = parent.blocks.findIndex((b) => b.id === blockId);\n if (index === -1) return null;\n return {\n targetSectionId: parent.sectionId,\n columnIndex: parent.columnIndex,\n index,\n };\n }\n\n // TODO(collab): the lock checks in addBlock/moveBlock/removeBlock/updateBlock\n // are shallow — they only consider the directly-targeted block id. A section\n // can still be removed, moved, or have its `children` array rewritten while a\n // peer is editing one of its descendants, which silently disrupts that peer's\n // edit. Add a `hasLockedDescendant(blockId)` helper and gate section-level\n // operations on it (and on the parent of each affected child) so cascades\n // through the tree are also blocked.\n\n function setContent(newContent: TemplateContent, markDirty = true): void {\n state.content = newContent;\n if (markDirty) {\n state.isDirty = true;\n }\n }\n\n function selectBlock(blockId: string | null): void {\n if (blockId && isBlockLocked(blockId)) {\n return;\n }\n state.selectedBlockId = blockId;\n }\n\n function setViewport(viewport: ViewportSize): void {\n state.viewport = viewport;\n }\n\n function setDarkMode(darkMode: boolean): void {\n state.darkMode = darkMode;\n }\n\n function setUiTheme(theme: UiTheme): void {\n state.uiTheme = theme;\n }\n\n function setPreviewMode(previewMode: boolean): void {\n state.previewMode = previewMode;\n if (previewMode) {\n state.selectedBlockId = null;\n }\n }\n\n function updateBlock(blockId: string, updates: Partial<Block>): void {\n if (isBlockLocked(blockId)) {\n return;\n }\n const block = findBlockById(state.content.blocks, blockId);\n if (block) {\n Object.assign(block, updates);\n state.isDirty = true;\n }\n }\n\n function updateSettings(updates: Partial<TemplateSettings>): void {\n state.content.settings = { ...state.content.settings, ...updates };\n state.isDirty = true;\n }\n\n function addBlock(\n block: Block,\n targetSectionId?: string,\n columnIndex = 0,\n index?: number,\n ): void {\n if (targetSectionId) {\n if (isBlockLocked(targetSectionId)) {\n return;\n }\n const section = findBlockById(state.content.blocks, targetSectionId);\n if (section && section.type === \"section\") {\n section.children[columnIndex] = section.children[columnIndex] || [];\n const targetArray = section.children[columnIndex];\n if (index !== undefined && index < targetArray.length) {\n targetArray.splice(index, 0, block);\n } else {\n targetArray.push(block);\n }\n }\n } else {\n if (index !== undefined && index < state.content.blocks.length) {\n state.content.blocks.splice(index, 0, block);\n } else {\n state.content.blocks.push(block);\n }\n }\n state.isDirty = true;\n }\n\n function removeBlock(blockId: string): void {\n if (isBlockLocked(blockId)) {\n return;\n }\n const parent = findBlockParent(state.content.blocks, blockId);\n if (parent) {\n const index = parent.blocks.findIndex((b) => b.id === blockId);\n if (index !== -1) {\n parent.blocks.splice(index, 1);\n if (state.selectedBlockId === blockId) {\n state.selectedBlockId = null;\n }\n state.isDirty = true;\n }\n }\n }\n\n function moveBlock(\n blockId: string,\n newIndex: number,\n targetSectionId?: string,\n columnIndex = 0,\n ): void {\n if (isBlockLocked(blockId)) {\n return;\n }\n if (targetSectionId && isBlockLocked(targetSectionId)) {\n return;\n }\n\n const parent = findBlockParent(state.content.blocks, blockId);\n if (!parent) return;\n\n const oldIndex = parent.blocks.findIndex((b) => b.id === blockId);\n if (oldIndex === -1) return;\n\n // Resolve target before mutating the source — otherwise an invalid\n // targetSectionId leaves the block spliced-out and unrecoverable.\n let targetArray: Block[];\n if (targetSectionId) {\n const section = findBlockById(state.content.blocks, targetSectionId);\n if (!section || section.type !== \"section\") return;\n section.children[columnIndex] = section.children[columnIndex] || [];\n targetArray = section.children[columnIndex];\n } else {\n targetArray = state.content.blocks;\n }\n\n const [block] = parent.blocks.splice(oldIndex, 1);\n targetArray.splice(newIndex, 0, block);\n\n state.isDirty = true;\n }\n\n function markDirty(): void {\n state.isDirty = true;\n }\n\n return {\n state: readonly(state),\n content,\n selectedBlock,\n isBlockLocked,\n setContent,\n selectBlock,\n setViewport,\n setDarkMode,\n setUiTheme,\n setPreviewMode,\n updateBlock,\n updateSettings,\n addBlock,\n removeBlock,\n moveBlock,\n markDirty,\n findBlockLocation,\n };\n}\n","import type { TemplateContent } from \"@templatical/types\";\nimport { computed, ref, type ComputedRef, type Ref } from \"@vue/reactivity\";\n\nexport interface UseHistoryOptions {\n content: Ref<TemplateContent>;\n setContent: (content: TemplateContent, markDirty?: boolean) => void;\n isRemoteOperation?: () => boolean;\n maxSize?: number;\n}\n\nexport interface UseHistoryReturn {\n canUndo: ComputedRef<boolean>;\n canRedo: ComputedRef<boolean>;\n isNavigating: Ref<boolean>;\n undo: () => void;\n redo: () => void;\n record: () => void;\n recordDebounced: (blockId: string) => void;\n clear: () => void;\n destroy: () => void;\n}\n\ninterface DebouncedSnapshot {\n blockId: string;\n timeoutId: ReturnType<typeof setTimeout>;\n}\n\nconst MAX_STACK_SIZE = 50;\nconst DEBOUNCE_MS = 300;\nconst NAVIGATE_IDLE_MS = 1500;\n\nexport function useHistory(options: UseHistoryOptions): UseHistoryReturn {\n const {\n content,\n setContent,\n isRemoteOperation,\n maxSize = MAX_STACK_SIZE,\n } = options;\n\n const undoStack = ref<TemplateContent[]>([]);\n const redoStack = ref<TemplateContent[]>([]);\n const isNavigating = ref(false);\n let navigatingTimeoutId: ReturnType<typeof setTimeout> | null = null;\n let pendingDebounce: DebouncedSnapshot | null = null;\n\n const canUndo = computed(() => undoStack.value.length > 0);\n const canRedo = computed(() => redoStack.value.length > 0);\n\n function cloneContent(): TemplateContent {\n // Cycle-safe deep clone. A naked JSON.stringify throws\n // `Converting circular structure to JSON` if anything in the tree\n // is self-referencing — e.g. a DOM element with a Sortable expando\n // back-ref ever sneaks into block data via a drag handler. We'd\n // rather drop the back-ref from the snapshot than freeze the undo\n // stack (the visible symptom: any subsequent mutation that calls\n // `record()` throws, breaking clone/move/etc.).\n const seen = new WeakSet<object>();\n return JSON.parse(\n JSON.stringify(content.value, (_key, value) => {\n if (typeof value === \"object\" && value !== null) {\n if (seen.has(value)) return undefined;\n seen.add(value);\n }\n return value;\n }),\n ) as TemplateContent;\n }\n\n function pushToUndoStack(snapshot: TemplateContent): void {\n undoStack.value.push(snapshot);\n if (undoStack.value.length > maxSize) {\n undoStack.value.splice(0, undoStack.value.length - maxSize);\n }\n }\n\n function flushPendingDebounce(): void {\n if (pendingDebounce) {\n clearTimeout(pendingDebounce.timeoutId);\n pendingDebounce = null;\n }\n }\n\n function record(): void {\n if (isRemoteOperation?.()) {\n return;\n }\n\n flushPendingDebounce();\n pushToUndoStack(cloneContent());\n redoStack.value = [];\n }\n\n function recordDebounced(blockId: string): void {\n if (isRemoteOperation?.()) {\n return;\n }\n\n if (pendingDebounce && pendingDebounce.blockId === blockId) {\n clearTimeout(pendingDebounce.timeoutId);\n pendingDebounce.timeoutId = setTimeout(() => {\n pendingDebounce = null;\n }, DEBOUNCE_MS);\n return;\n }\n\n flushPendingDebounce();\n\n pushToUndoStack(cloneContent());\n redoStack.value = [];\n\n pendingDebounce = {\n blockId,\n timeoutId: setTimeout(() => {\n pendingDebounce = null;\n }, DEBOUNCE_MS),\n };\n }\n\n function setNavigating(): void {\n isNavigating.value = true;\n if (navigatingTimeoutId) {\n clearTimeout(navigatingTimeoutId);\n }\n navigatingTimeoutId = setTimeout(() => {\n isNavigating.value = false;\n navigatingTimeoutId = null;\n }, NAVIGATE_IDLE_MS);\n }\n\n function undo(): void {\n if (undoStack.value.length === 0) {\n return;\n }\n\n flushPendingDebounce();\n\n const snapshot = undoStack.value.pop()!;\n redoStack.value.push(cloneContent());\n setContent(snapshot, true);\n setNavigating();\n }\n\n function redo(): void {\n if (redoStack.value.length === 0) {\n return;\n }\n\n flushPendingDebounce();\n\n const snapshot = redoStack.value.pop()!;\n undoStack.value.push(cloneContent());\n setContent(snapshot, true);\n setNavigating();\n }\n\n function clear(): void {\n undoStack.value = [];\n redoStack.value = [];\n flushPendingDebounce();\n }\n\n function destroy(): void {\n clear();\n if (navigatingTimeoutId) {\n clearTimeout(navigatingTimeoutId);\n navigatingTimeoutId = null;\n }\n }\n\n return {\n canUndo,\n canRedo,\n isNavigating,\n undo,\n redo,\n record,\n recordDebounced,\n clear,\n destroy,\n };\n}\n","import type { Block, BlockDefaults, BlockType } from \"@templatical/types\";\nimport { createBlock, generateId } from \"@templatical/types\";\n\nexport interface UseBlockActionsOptions {\n addBlock: (\n block: Block,\n targetSectionId?: string,\n columnIndex?: number,\n index?: number,\n ) => void;\n removeBlock: (blockId: string) => void;\n updateBlock: (blockId: string, updates: Partial<Block>) => void;\n selectBlock: (blockId: string | null) => void;\n /** Locate a block in the tree — used by `duplicateBlock` to insert the\n * clone right after the source instead of appending to the end. */\n findBlockLocation?: (blockId: string) => {\n targetSectionId?: string;\n columnIndex?: number;\n index: number;\n } | null;\n blockDefaults?: BlockDefaults;\n}\n\nexport interface UseBlockActionsReturn {\n createAndAddBlock: (\n type: BlockType,\n targetSectionId?: string,\n columnIndex?: number,\n ) => Block;\n duplicateBlock: (\n block: Block,\n targetSectionId?: string,\n columnIndex?: number,\n ) => Block;\n deleteBlock: (blockId: string) => void;\n updateBlockProperty: <K extends keyof Block>(\n blockId: string,\n key: K,\n value: Block[K],\n ) => void;\n}\n\nexport function useBlockActions(\n options: UseBlockActionsOptions,\n): UseBlockActionsReturn {\n const { addBlock, removeBlock, updateBlock, selectBlock, findBlockLocation } =\n options;\n\n function createAndAddBlock(\n type: BlockType,\n targetSectionId?: string,\n columnIndex?: number,\n ): Block {\n const block = createBlock(type, options.blockDefaults);\n addBlock(block, targetSectionId, columnIndex);\n selectBlock(block.id);\n return block;\n }\n\n function duplicateBlock(\n block: Block,\n targetSectionId?: string,\n columnIndex?: number,\n ): Block {\n const cloned = JSON.parse(JSON.stringify(block)) as Block;\n cloned.id = generateId();\n\n if (cloned.type === \"section\") {\n cloned.children = cloned.children.map((column) =>\n column.map((child) => {\n const clonedChild = JSON.parse(JSON.stringify(child)) as Block;\n clonedChild.id = generateId();\n return clonedChild;\n }),\n );\n }\n\n // Insert directly after the source block. Explicit target args win;\n // otherwise, resolve the source's location and bump index by 1. Falls\n // back to appending at the end if location is unknown.\n if (targetSectionId !== undefined || columnIndex !== undefined) {\n addBlock(cloned, targetSectionId, columnIndex);\n } else {\n const sourceLocation = findBlockLocation?.(block.id) ?? null;\n if (sourceLocation) {\n addBlock(\n cloned,\n sourceLocation.targetSectionId,\n sourceLocation.columnIndex,\n sourceLocation.index + 1,\n );\n } else {\n addBlock(cloned, targetSectionId, columnIndex);\n }\n }\n selectBlock(cloned.id);\n return cloned;\n }\n\n function deleteBlock(blockId: string): void {\n removeBlock(blockId);\n }\n\n function updateBlockProperty<K extends keyof Block>(\n blockId: string,\n key: K,\n value: Block[K],\n ): void {\n updateBlock(blockId, { [key]: value } as Partial<Block>);\n }\n\n return {\n createAndAddBlock,\n duplicateBlock,\n deleteBlock,\n updateBlockProperty,\n };\n}\n","import type { TemplateContent } from \"@templatical/types\";\nimport { watch, type Ref } from \"@vue/reactivity\";\n\nexport interface UseAutoSaveOptions {\n content: Ref<TemplateContent>;\n isDirty: () => boolean;\n onChange: (content: TemplateContent) => void;\n debounce?: number;\n enabled?: boolean | (() => boolean);\n}\n\nexport interface UseAutoSaveReturn {\n flush: () => void;\n cancel: () => void;\n pause: () => void;\n resume: () => void;\n destroy: () => void;\n}\n\nexport function useAutoSave(options: UseAutoSaveOptions): UseAutoSaveReturn {\n const {\n content,\n isDirty,\n onChange,\n debounce = 1000,\n enabled = true,\n } = options;\n\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n let paused = false;\n\n function isEnabled(): boolean {\n return typeof enabled === \"function\" ? enabled() : enabled;\n }\n\n function pause(): void {\n paused = true;\n cancel();\n }\n\n function resume(): void {\n paused = false;\n }\n\n function cancel(): void {\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n }\n\n function flush(): void {\n cancel();\n if (isDirty()) {\n onChange(JSON.parse(JSON.stringify(content.value)));\n }\n }\n\n function scheduleOnChange(): void {\n if (!isEnabled() || paused) return;\n\n cancel();\n timeoutId = setTimeout(() => {\n timeoutId = null;\n if (isEnabled() && !paused && isDirty()) {\n onChange(JSON.parse(JSON.stringify(content.value)));\n }\n }, debounce);\n }\n\n const stopWatch = watch(\n content,\n () => {\n if (isEnabled() && !paused && isDirty()) {\n scheduleOnChange();\n }\n },\n { deep: true },\n );\n\n function destroy(): void {\n stopWatch();\n cancel();\n }\n\n return {\n flush,\n cancel,\n pause,\n resume,\n destroy,\n };\n}\n","import type { UseEditorReturn } from \"./editor\";\nimport { computed, reactive, type ComputedRef } from \"@vue/reactivity\";\n\nexport interface UseConditionPreviewReturn {\n isHidden: (blockId: string) => boolean;\n toggleBlock: (blockId: string) => void;\n reset: () => void;\n hasHiddenBlocks: ComputedRef<boolean>;\n}\n\nexport function useConditionPreview(\n editor: UseEditorReturn,\n): UseConditionPreviewReturn {\n const hiddenBlockIds = reactive(new Set<string>());\n\n const hasHiddenBlocks = computed(() => hiddenBlockIds.size > 0);\n\n function isHidden(blockId: string): boolean {\n return hiddenBlockIds.has(blockId);\n }\n\n function toggleBlock(blockId: string): void {\n if (hiddenBlockIds.has(blockId)) {\n hiddenBlockIds.delete(blockId);\n } else {\n hiddenBlockIds.add(blockId);\n\n if (editor.state.selectedBlockId === blockId) {\n editor.selectBlock(null);\n }\n }\n }\n\n function reset(): void {\n hiddenBlockIds.clear();\n }\n\n return {\n isHidden,\n toggleBlock,\n reset,\n hasHiddenBlocks,\n };\n}\n","import type { CustomBlock, CustomBlockDefinition } from \"@templatical/types\";\nimport type { ComputedRef, Ref } from \"@vue/reactivity\";\nimport { computed, ref } from \"@vue/reactivity\";\n\nexport function useDataSourceFetch(options: {\n definition: ComputedRef<CustomBlockDefinition | undefined>;\n block: ComputedRef<CustomBlock>;\n onUpdate: (fieldValues: Record<string, unknown>, fetched: boolean) => void;\n}): {\n isFetching: Ref<boolean>;\n fetchError: Ref<boolean>;\n fetch: () => Promise<void>;\n hasDataSource: ComputedRef<boolean>;\n needsFetch: ComputedRef<boolean>;\n} {\n const isFetching = ref(false);\n const fetchError = ref(false);\n\n const hasDataSource = computed(() => !!options.definition.value?.dataSource);\n\n const needsFetch = computed(\n () => hasDataSource.value && !options.block.value.dataSourceFetched,\n );\n\n async function fetch(): Promise<void> {\n const def = options.definition.value;\n if (!def?.dataSource) {\n return;\n }\n\n isFetching.value = true;\n fetchError.value = false;\n\n try {\n const result = await def.dataSource.onFetch({\n fieldValues: { ...options.block.value.fieldValues },\n blockId: options.block.value.id,\n });\n\n if (result == null) {\n return;\n }\n\n const merged = { ...options.block.value.fieldValues };\n for (const key of Object.keys(merged)) {\n if (key in result) {\n merged[key] = result[key];\n }\n }\n\n options.onUpdate(merged, true);\n } catch (error) {\n console.warn(\"[Templatical] Data source fetch error:\", error);\n fetchError.value = true;\n } finally {\n isFetching.value = false;\n }\n }\n\n return {\n isFetching,\n fetchError,\n fetch,\n hasDataSource,\n needsFetch,\n };\n}\n","import type { UseEditorReturn } from \"./editor\";\nimport type { UseHistoryReturn } from \"./history\";\n\n/**\n * Wraps editor mutation methods to record history snapshots before each\n * operation. Mutates the editor object in place.\n *\n * Must be applied **after** any collaboration broadcast wrapping so the\n * call chain is: history.record() → broadcast → original mutation.\n */\nexport function useHistoryInterceptor(\n editor: UseEditorReturn,\n history: UseHistoryReturn,\n): void {\n const originalAddBlock = editor.addBlock;\n const originalRemoveBlock = editor.removeBlock;\n const originalMoveBlock = editor.moveBlock;\n const originalUpdateBlock = editor.updateBlock;\n const originalUpdateSettings = editor.updateSettings;\n\n // Skip recording when the underlying op is a no-op (e.g., a peer-locked\n // block or section), otherwise the undo stack fills with snapshots that\n // are identical to current state and undo silently does nothing.\n editor.addBlock = (block, targetSectionId?, columnIndex?, index?) => {\n if (targetSectionId && editor.isBlockLocked(targetSectionId)) {\n return;\n }\n history.record();\n originalAddBlock(block, targetSectionId, columnIndex, index);\n };\n\n editor.removeBlock = (blockId) => {\n if (editor.isBlockLocked(blockId)) {\n return;\n }\n history.record();\n originalRemoveBlock(blockId);\n };\n\n editor.moveBlock = (blockId, newIndex, targetSectionId?, columnIndex?) => {\n if (editor.isBlockLocked(blockId)) {\n return;\n }\n if (targetSectionId && editor.isBlockLocked(targetSectionId)) {\n return;\n }\n history.record();\n originalMoveBlock(blockId, newIndex, targetSectionId, columnIndex);\n };\n\n editor.updateBlock = (blockId, updates) => {\n if (editor.isBlockLocked(blockId)) {\n return;\n }\n history.recordDebounced(blockId);\n originalUpdateBlock(blockId, updates);\n };\n\n editor.updateSettings = (updates) => {\n history.record();\n originalUpdateSettings(updates);\n };\n}\n"],"mappings":";AAQA,SAAS,oCAAoC;AAC7C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AAqDA,SAAS,UAAU,SAA4C;AACpE,QAAM,QAAQ,SAAsB;AAAA,IAClC,SACE,QAAQ,WACR;AAAA,MACE,QAAQ;AAAA,MACR,QAAQ;AAAA,IACV;AAAA,IACF,iBAAiB;AAAA,IACjB,UAAU;AAAA,IACV,UAAU;AAAA,IACV,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,EACX,CAAC;AAED,QAAM,UAAU,SAAS;AAAA,IACvB,KAAK,MAAM,MAAM;AAAA,IACjB,KAAK,CAAC,UAA2B;AAC/B,YAAM,UAAU;AAChB,YAAM,UAAU;AAAA,IAClB;AAAA,EACF,CAAC;AAED,QAAM,gBAAgB,SAAS,MAAM;AACnC,QAAI,CAAC,MAAM,gBAAiB,QAAO;AACnC,WAAO,cAAc,MAAM,QAAQ,QAAQ,MAAM,eAAe;AAAA,EAClE,CAAC;AAED,WAAS,cAAc,QAAiB,IAA0B;AAChE,eAAW,SAAS,QAAQ;AAC1B,UAAI,MAAM,OAAO,GAAI,QAAO;AAC5B,UAAI,MAAM,SAAS,WAAW;AAC5B,mBAAW,UAAU,MAAM,UAAU;AACnC,gBAAM,QAAQ,cAAc,QAAQ,EAAE;AACtC,cAAI,MAAO,QAAO;AAAA,QACpB;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,WAAS,gBACP,QACA,IACA,SAII,EAAE,OAAO,GACyD;AACtE,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,YAAM,QAAQ,OAAO,CAAC;AACtB,UAAI,MAAM,OAAO,GAAI,QAAO;AAC5B,UAAI,MAAM,SAAS,WAAW;AAC5B,iBAAS,SAAS,GAAG,SAAS,MAAM,SAAS,QAAQ,UAAU;AAC7D,gBAAM,SAAS,gBAAgB,MAAM,SAAS,MAAM,GAAG,IAAI;AAAA,YACzD,QAAQ,MAAM,SAAS,MAAM;AAAA,YAC7B,WAAW,MAAM;AAAA,YACjB,aAAa;AAAA,UACf,CAAC;AACD,cAAI,OAAQ,QAAO;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,WAAS,cAAc,SAA0B;AAC/C,WAAO,QAAQ,cAAc,MAAM,IAAI,OAAO,KAAK;AAAA,EACrD;AAEA,WAAS,kBAAkB,SAIlB;AACP,UAAM,SAAS,gBAAgB,MAAM,QAAQ,QAAQ,OAAO;AAC5D,QAAI,CAAC,OAAQ,QAAO;AACpB,UAAM,QAAQ,OAAO,OAAO,UAAU,CAAC,MAAM,EAAE,OAAO,OAAO;AAC7D,QAAI,UAAU,GAAI,QAAO;AACzB,WAAO;AAAA,MACL,iBAAiB,OAAO;AAAA,MACxB,aAAa,OAAO;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AAUA,WAAS,WAAW,YAA6BA,aAAY,MAAY;AACvE,UAAM,UAAU;AAChB,QAAIA,YAAW;AACb,YAAM,UAAU;AAAA,IAClB;AAAA,EACF;AAEA,WAAS,YAAY,SAA8B;AACjD,QAAI,WAAW,cAAc,OAAO,GAAG;AACrC;AAAA,IACF;AACA,UAAM,kBAAkB;AAAA,EAC1B;AAEA,WAAS,YAAY,UAA8B;AACjD,UAAM,WAAW;AAAA,EACnB;AAEA,WAAS,YAAY,UAAyB;AAC5C,UAAM,WAAW;AAAA,EACnB;AAEA,WAAS,WAAW,OAAsB;AACxC,UAAM,UAAU;AAAA,EAClB;AAEA,WAAS,eAAe,aAA4B;AAClD,UAAM,cAAc;AACpB,QAAI,aAAa;AACf,YAAM,kBAAkB;AAAA,IAC1B;AAAA,EACF;AAEA,WAAS,YAAY,SAAiB,SAA+B;AACnE,QAAI,cAAc,OAAO,GAAG;AAC1B;AAAA,IACF;AACA,UAAM,QAAQ,cAAc,MAAM,QAAQ,QAAQ,OAAO;AACzD,QAAI,OAAO;AACT,aAAO,OAAO,OAAO,OAAO;AAC5B,YAAM,UAAU;AAAA,IAClB;AAAA,EACF;AAEA,WAAS,eAAe,SAA0C;AAChE,UAAM,QAAQ,WAAW,EAAE,GAAG,MAAM,QAAQ,UAAU,GAAG,QAAQ;AACjE,UAAM,UAAU;AAAA,EAClB;AAEA,WAAS,SACP,OACA,iBACA,cAAc,GACd,OACM;AACN,QAAI,iBAAiB;AACnB,UAAI,cAAc,eAAe,GAAG;AAClC;AAAA,MACF;AACA,YAAM,UAAU,cAAc,MAAM,QAAQ,QAAQ,eAAe;AACnE,UAAI,WAAW,QAAQ,SAAS,WAAW;AACzC,gBAAQ,SAAS,WAAW,IAAI,QAAQ,SAAS,WAAW,KAAK,CAAC;AAClE,cAAM,cAAc,QAAQ,SAAS,WAAW;AAChD,YAAI,UAAU,UAAa,QAAQ,YAAY,QAAQ;AACrD,sBAAY,OAAO,OAAO,GAAG,KAAK;AAAA,QACpC,OAAO;AACL,sBAAY,KAAK,KAAK;AAAA,QACxB;AAAA,MACF;AAAA,IACF,OAAO;AACL,UAAI,UAAU,UAAa,QAAQ,MAAM,QAAQ,OAAO,QAAQ;AAC9D,cAAM,QAAQ,OAAO,OAAO,OAAO,GAAG,KAAK;AAAA,MAC7C,OAAO;AACL,cAAM,QAAQ,OAAO,KAAK,KAAK;AAAA,MACjC;AAAA,IACF;AACA,UAAM,UAAU;AAAA,EAClB;AAEA,WAAS,YAAY,SAAuB;AAC1C,QAAI,cAAc,OAAO,GAAG;AAC1B;AAAA,IACF;AACA,UAAM,SAAS,gBAAgB,MAAM,QAAQ,QAAQ,OAAO;AAC5D,QAAI,QAAQ;AACV,YAAM,QAAQ,OAAO,OAAO,UAAU,CAAC,MAAM,EAAE,OAAO,OAAO;AAC7D,UAAI,UAAU,IAAI;AAChB,eAAO,OAAO,OAAO,OAAO,CAAC;AAC7B,YAAI,MAAM,oBAAoB,SAAS;AACrC,gBAAM,kBAAkB;AAAA,QAC1B;AACA,cAAM,UAAU;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAEA,WAAS,UACP,SACA,UACA,iBACA,cAAc,GACR;AACN,QAAI,cAAc,OAAO,GAAG;AAC1B;AAAA,IACF;AACA,QAAI,mBAAmB,cAAc,eAAe,GAAG;AACrD;AAAA,IACF;AAEA,UAAM,SAAS,gBAAgB,MAAM,QAAQ,QAAQ,OAAO;AAC5D,QAAI,CAAC,OAAQ;AAEb,UAAM,WAAW,OAAO,OAAO,UAAU,CAAC,MAAM,EAAE,OAAO,OAAO;AAChE,QAAI,aAAa,GAAI;AAIrB,QAAI;AACJ,QAAI,iBAAiB;AACnB,YAAM,UAAU,cAAc,MAAM,QAAQ,QAAQ,eAAe;AACnE,UAAI,CAAC,WAAW,QAAQ,SAAS,UAAW;AAC5C,cAAQ,SAAS,WAAW,IAAI,QAAQ,SAAS,WAAW,KAAK,CAAC;AAClE,oBAAc,QAAQ,SAAS,WAAW;AAAA,IAC5C,OAAO;AACL,oBAAc,MAAM,QAAQ;AAAA,IAC9B;AAEA,UAAM,CAAC,KAAK,IAAI,OAAO,OAAO,OAAO,UAAU,CAAC;AAChD,gBAAY,OAAO,UAAU,GAAG,KAAK;AAErC,UAAM,UAAU;AAAA,EAClB;AAEA,WAAS,YAAkB;AACzB,UAAM,UAAU;AAAA,EAClB;AAEA,SAAO;AAAA,IACL,OAAO,SAAS,KAAK;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AC/TA,SAAS,YAAAC,WAAU,WAAuC;AA0B1D,IAAM,iBAAiB;AACvB,IAAM,cAAc;AACpB,IAAM,mBAAmB;AAElB,SAAS,WAAW,SAA8C;AACvE,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU;AAAA,EACZ,IAAI;AAEJ,QAAM,YAAY,IAAuB,CAAC,CAAC;AAC3C,QAAM,YAAY,IAAuB,CAAC,CAAC;AAC3C,QAAM,eAAe,IAAI,KAAK;AAC9B,MAAI,sBAA4D;AAChE,MAAI,kBAA4C;AAEhD,QAAM,UAAUA,UAAS,MAAM,UAAU,MAAM,SAAS,CAAC;AACzD,QAAM,UAAUA,UAAS,MAAM,UAAU,MAAM,SAAS,CAAC;AAEzD,WAAS,eAAgC;AAQvC,UAAM,OAAO,oBAAI,QAAgB;AACjC,WAAO,KAAK;AAAA,MACV,KAAK,UAAU,QAAQ,OAAO,CAAC,MAAM,UAAU;AAC7C,YAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,cAAI,KAAK,IAAI,KAAK,EAAG,QAAO;AAC5B,eAAK,IAAI,KAAK;AAAA,QAChB;AACA,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AAEA,WAAS,gBAAgB,UAAiC;AACxD,cAAU,MAAM,KAAK,QAAQ;AAC7B,QAAI,UAAU,MAAM,SAAS,SAAS;AACpC,gBAAU,MAAM,OAAO,GAAG,UAAU,MAAM,SAAS,OAAO;AAAA,IAC5D;AAAA,EACF;AAEA,WAAS,uBAA6B;AACpC,QAAI,iBAAiB;AACnB,mBAAa,gBAAgB,SAAS;AACtC,wBAAkB;AAAA,IACpB;AAAA,EACF;AAEA,WAAS,SAAe;AACtB,QAAI,oBAAoB,GAAG;AACzB;AAAA,IACF;AAEA,yBAAqB;AACrB,oBAAgB,aAAa,CAAC;AAC9B,cAAU,QAAQ,CAAC;AAAA,EACrB;AAEA,WAAS,gBAAgB,SAAuB;AAC9C,QAAI,oBAAoB,GAAG;AACzB;AAAA,IACF;AAEA,QAAI,mBAAmB,gBAAgB,YAAY,SAAS;AAC1D,mBAAa,gBAAgB,SAAS;AACtC,sBAAgB,YAAY,WAAW,MAAM;AAC3C,0BAAkB;AAAA,MACpB,GAAG,WAAW;AACd;AAAA,IACF;AAEA,yBAAqB;AAErB,oBAAgB,aAAa,CAAC;AAC9B,cAAU,QAAQ,CAAC;AAEnB,sBAAkB;AAAA,MAChB;AAAA,MACA,WAAW,WAAW,MAAM;AAC1B,0BAAkB;AAAA,MACpB,GAAG,WAAW;AAAA,IAChB;AAAA,EACF;AAEA,WAAS,gBAAsB;AAC7B,iBAAa,QAAQ;AACrB,QAAI,qBAAqB;AACvB,mBAAa,mBAAmB;AAAA,IAClC;AACA,0BAAsB,WAAW,MAAM;AACrC,mBAAa,QAAQ;AACrB,4BAAsB;AAAA,IACxB,GAAG,gBAAgB;AAAA,EACrB;AAEA,WAAS,OAAa;AACpB,QAAI,UAAU,MAAM,WAAW,GAAG;AAChC;AAAA,IACF;AAEA,yBAAqB;AAErB,UAAM,WAAW,UAAU,MAAM,IAAI;AACrC,cAAU,MAAM,KAAK,aAAa,CAAC;AACnC,eAAW,UAAU,IAAI;AACzB,kBAAc;AAAA,EAChB;AAEA,WAAS,OAAa;AACpB,QAAI,UAAU,MAAM,WAAW,GAAG;AAChC;AAAA,IACF;AAEA,yBAAqB;AAErB,UAAM,WAAW,UAAU,MAAM,IAAI;AACrC,cAAU,MAAM,KAAK,aAAa,CAAC;AACnC,eAAW,UAAU,IAAI;AACzB,kBAAc;AAAA,EAChB;AAEA,WAAS,QAAc;AACrB,cAAU,QAAQ,CAAC;AACnB,cAAU,QAAQ,CAAC;AACnB,yBAAqB;AAAA,EACvB;AAEA,WAAS,UAAgB;AACvB,UAAM;AACN,QAAI,qBAAqB;AACvB,mBAAa,mBAAmB;AAChC,4BAAsB;AAAA,IACxB;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACnLA,SAAS,aAAa,kBAAkB;AAyCjC,SAAS,gBACd,SACuB;AACvB,QAAM,EAAE,UAAU,aAAa,aAAa,aAAa,kBAAkB,IACzE;AAEF,WAAS,kBACP,MACA,iBACA,aACO;AACP,UAAM,QAAQ,YAAY,MAAM,QAAQ,aAAa;AACrD,aAAS,OAAO,iBAAiB,WAAW;AAC5C,gBAAY,MAAM,EAAE;AACpB,WAAO;AAAA,EACT;AAEA,WAAS,eACP,OACA,iBACA,aACO;AACP,UAAM,SAAS,KAAK,MAAM,KAAK,UAAU,KAAK,CAAC;AAC/C,WAAO,KAAK,WAAW;AAEvB,QAAI,OAAO,SAAS,WAAW;AAC7B,aAAO,WAAW,OAAO,SAAS;AAAA,QAAI,CAAC,WACrC,OAAO,IAAI,CAAC,UAAU;AACpB,gBAAM,cAAc,KAAK,MAAM,KAAK,UAAU,KAAK,CAAC;AACpD,sBAAY,KAAK,WAAW;AAC5B,iBAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,IACF;AAKA,QAAI,oBAAoB,UAAa,gBAAgB,QAAW;AAC9D,eAAS,QAAQ,iBAAiB,WAAW;AAAA,IAC/C,OAAO;AACL,YAAM,iBAAiB,oBAAoB,MAAM,EAAE,KAAK;AACxD,UAAI,gBAAgB;AAClB;AAAA,UACE;AAAA,UACA,eAAe;AAAA,UACf,eAAe;AAAA,UACf,eAAe,QAAQ;AAAA,QACzB;AAAA,MACF,OAAO;AACL,iBAAS,QAAQ,iBAAiB,WAAW;AAAA,MAC/C;AAAA,IACF;AACA,gBAAY,OAAO,EAAE;AACrB,WAAO;AAAA,EACT;AAEA,WAAS,YAAY,SAAuB;AAC1C,gBAAY,OAAO;AAAA,EACrB;AAEA,WAAS,oBACP,SACA,KACA,OACM;AACN,gBAAY,SAAS,EAAE,CAAC,GAAG,GAAG,MAAM,CAAmB;AAAA,EACzD;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACpHA,SAAS,aAAuB;AAkBzB,SAAS,YAAY,SAAgD;AAC1E,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,UAAU;AAAA,EACZ,IAAI;AAEJ,MAAI,YAAkD;AACtD,MAAI,SAAS;AAEb,WAAS,YAAqB;AAC5B,WAAO,OAAO,YAAY,aAAa,QAAQ,IAAI;AAAA,EACrD;AAEA,WAAS,QAAc;AACrB,aAAS;AACT,WAAO;AAAA,EACT;AAEA,WAAS,SAAe;AACtB,aAAS;AAAA,EACX;AAEA,WAAS,SAAe;AACtB,QAAI,WAAW;AACb,mBAAa,SAAS;AACtB,kBAAY;AAAA,IACd;AAAA,EACF;AAEA,WAAS,QAAc;AACrB,WAAO;AACP,QAAI,QAAQ,GAAG;AACb,eAAS,KAAK,MAAM,KAAK,UAAU,QAAQ,KAAK,CAAC,CAAC;AAAA,IACpD;AAAA,EACF;AAEA,WAAS,mBAAyB;AAChC,QAAI,CAAC,UAAU,KAAK,OAAQ;AAE5B,WAAO;AACP,gBAAY,WAAW,MAAM;AAC3B,kBAAY;AACZ,UAAI,UAAU,KAAK,CAAC,UAAU,QAAQ,GAAG;AACvC,iBAAS,KAAK,MAAM,KAAK,UAAU,QAAQ,KAAK,CAAC,CAAC;AAAA,MACpD;AAAA,IACF,GAAG,QAAQ;AAAA,EACb;AAEA,QAAM,YAAY;AAAA,IAChB;AAAA,IACA,MAAM;AACJ,UAAI,UAAU,KAAK,CAAC,UAAU,QAAQ,GAAG;AACvC,yBAAiB;AAAA,MACnB;AAAA,IACF;AAAA,IACA,EAAE,MAAM,KAAK;AAAA,EACf;AAEA,WAAS,UAAgB;AACvB,cAAU;AACV,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AC3FA,SAAS,YAAAC,WAAU,YAAAC,iBAAkC;AAS9C,SAAS,oBACd,QAC2B;AAC3B,QAAM,iBAAiBA,UAAS,oBAAI,IAAY,CAAC;AAEjD,QAAM,kBAAkBD,UAAS,MAAM,eAAe,OAAO,CAAC;AAE9D,WAAS,SAAS,SAA0B;AAC1C,WAAO,eAAe,IAAI,OAAO;AAAA,EACnC;AAEA,WAAS,YAAY,SAAuB;AAC1C,QAAI,eAAe,IAAI,OAAO,GAAG;AAC/B,qBAAe,OAAO,OAAO;AAAA,IAC/B,OAAO;AACL,qBAAe,IAAI,OAAO;AAE1B,UAAI,OAAO,MAAM,oBAAoB,SAAS;AAC5C,eAAO,YAAY,IAAI;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAEA,WAAS,QAAc;AACrB,mBAAe,MAAM;AAAA,EACvB;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACzCA,SAAS,YAAAE,WAAU,OAAAC,YAAW;AAEvB,SAAS,mBAAmB,SAUjC;AACA,QAAM,aAAaA,KAAI,KAAK;AAC5B,QAAM,aAAaA,KAAI,KAAK;AAE5B,QAAM,gBAAgBD,UAAS,MAAM,CAAC,CAAC,QAAQ,WAAW,OAAO,UAAU;AAE3E,QAAM,aAAaA;AAAA,IACjB,MAAM,cAAc,SAAS,CAAC,QAAQ,MAAM,MAAM;AAAA,EACpD;AAEA,iBAAe,QAAuB;AACpC,UAAM,MAAM,QAAQ,WAAW;AAC/B,QAAI,CAAC,KAAK,YAAY;AACpB;AAAA,IACF;AAEA,eAAW,QAAQ;AACnB,eAAW,QAAQ;AAEnB,QAAI;AACF,YAAM,SAAS,MAAM,IAAI,WAAW,QAAQ;AAAA,QAC1C,aAAa,EAAE,GAAG,QAAQ,MAAM,MAAM,YAAY;AAAA,QAClD,SAAS,QAAQ,MAAM,MAAM;AAAA,MAC/B,CAAC;AAED,UAAI,UAAU,MAAM;AAClB;AAAA,MACF;AAEA,YAAM,SAAS,EAAE,GAAG,QAAQ,MAAM,MAAM,YAAY;AACpD,iBAAW,OAAO,OAAO,KAAK,MAAM,GAAG;AACrC,YAAI,OAAO,QAAQ;AACjB,iBAAO,GAAG,IAAI,OAAO,GAAG;AAAA,QAC1B;AAAA,MACF;AAEA,cAAQ,SAAS,QAAQ,IAAI;AAAA,IAC/B,SAAS,OAAO;AACd,cAAQ,KAAK,0CAA0C,KAAK;AAC5D,iBAAW,QAAQ;AAAA,IACrB,UAAE;AACA,iBAAW,QAAQ;AAAA,IACrB;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACxDO,SAAS,sBACd,QACA,SACM;AACN,QAAM,mBAAmB,OAAO;AAChC,QAAM,sBAAsB,OAAO;AACnC,QAAM,oBAAoB,OAAO;AACjC,QAAM,sBAAsB,OAAO;AACnC,QAAM,yBAAyB,OAAO;AAKtC,SAAO,WAAW,CAAC,OAAO,iBAAkB,aAAc,UAAW;AACnE,QAAI,mBAAmB,OAAO,cAAc,eAAe,GAAG;AAC5D;AAAA,IACF;AACA,YAAQ,OAAO;AACf,qBAAiB,OAAO,iBAAiB,aAAa,KAAK;AAAA,EAC7D;AAEA,SAAO,cAAc,CAAC,YAAY;AAChC,QAAI,OAAO,cAAc,OAAO,GAAG;AACjC;AAAA,IACF;AACA,YAAQ,OAAO;AACf,wBAAoB,OAAO;AAAA,EAC7B;AAEA,SAAO,YAAY,CAAC,SAAS,UAAU,iBAAkB,gBAAiB;AACxE,QAAI,OAAO,cAAc,OAAO,GAAG;AACjC;AAAA,IACF;AACA,QAAI,mBAAmB,OAAO,cAAc,eAAe,GAAG;AAC5D;AAAA,IACF;AACA,YAAQ,OAAO;AACf,sBAAkB,SAAS,UAAU,iBAAiB,WAAW;AAAA,EACnE;AAEA,SAAO,cAAc,CAAC,SAAS,YAAY;AACzC,QAAI,OAAO,cAAc,OAAO,GAAG;AACjC;AAAA,IACF;AACA,YAAQ,gBAAgB,OAAO;AAC/B,wBAAoB,SAAS,OAAO;AAAA,EACtC;AAEA,SAAO,iBAAiB,CAAC,YAAY;AACnC,YAAQ,OAAO;AACf,2BAAuB,OAAO;AAAA,EAChC;AACF;","names":["markDirty","computed","computed","reactive","computed","ref"]}
|
|
1
|
+
{"version":3,"sources":["../src/editor.ts","../src/history.ts","../src/block-actions.ts","../src/auto-save.ts","../src/condition-preview.ts","../src/data-source-fetch.ts","../src/history-interceptor.ts"],"sourcesContent":["import type {\n Block,\n ColumnLayout,\n TemplateContent,\n TemplateDefaults,\n TemplateSettings,\n UiTheme,\n ViewportSize,\n} from \"@templatical/types\";\nimport { createDefaultTemplateContent } from \"@templatical/types\";\n\nfunction getColumnCount(layout: ColumnLayout): number {\n if (layout === \"1\") return 1;\n if (layout === \"3\") return 3;\n return 2;\n}\nimport {\n computed,\n reactive,\n readonly,\n type DeepReadonly,\n type Ref,\n} from \"@vue/reactivity\";\n\nexport interface EditorState {\n content: TemplateContent;\n selectedBlockId: string | null;\n viewport: ViewportSize;\n darkMode: boolean;\n previewMode: boolean;\n isDirty: boolean;\n uiTheme: UiTheme;\n}\n\nexport interface UseEditorOptions {\n content: TemplateContent;\n defaultFontFamily?: string;\n templateDefaults?: TemplateDefaults;\n lockedBlocks?: Ref<Map<string, unknown>>;\n}\n\nexport interface UseEditorReturn {\n state: DeepReadonly<EditorState>;\n content: Ref<TemplateContent>;\n selectedBlock: Ref<Block | null>;\n setContent: (content: TemplateContent, markDirty?: boolean) => void;\n selectBlock: (blockId: string | null) => void;\n setViewport: (viewport: ViewportSize) => void;\n setDarkMode: (darkMode: boolean) => void;\n setPreviewMode: (previewMode: boolean) => void;\n setUiTheme: (theme: UiTheme) => void;\n updateBlock: (blockId: string, updates: Partial<Block>) => void;\n updateSettings: (updates: Partial<TemplateSettings>) => void;\n addBlock: (\n block: Block,\n targetSectionId?: string,\n columnIndex?: number,\n index?: number,\n ) => void;\n removeBlock: (blockId: string) => void;\n moveBlock: (\n blockId: string,\n newIndex: number,\n targetSectionId?: string,\n columnIndex?: number,\n ) => void;\n isBlockLocked: (blockId: string) => boolean;\n markDirty: () => void;\n findBlockLocation: (blockId: string) => {\n targetSectionId?: string;\n columnIndex?: number;\n index: number;\n } | null;\n}\n\nexport function useEditor(options: UseEditorOptions): UseEditorReturn {\n const state = reactive<EditorState>({\n content:\n options.content ??\n createDefaultTemplateContent(\n options.defaultFontFamily,\n options.templateDefaults,\n ),\n selectedBlockId: null,\n viewport: \"desktop\",\n darkMode: false,\n previewMode: false,\n isDirty: false,\n uiTheme: \"auto\",\n });\n\n const content = computed({\n get: () => state.content,\n set: (value: TemplateContent) => {\n state.content = value;\n state.isDirty = true;\n },\n });\n\n const selectedBlock = computed(() => {\n if (!state.selectedBlockId) return null;\n return findBlockById(state.content.blocks, state.selectedBlockId);\n });\n\n function findBlockById(blocks: Block[], id: string): Block | null {\n for (const block of blocks) {\n if (block.id === id) return block;\n if (block.type === \"section\") {\n for (const column of block.children) {\n const found = findBlockById(column, id);\n if (found) return found;\n }\n }\n }\n return null;\n }\n\n function collectBlockIds(block: Block, ids: Set<string>): void {\n ids.add(block.id);\n if (block.type === \"section\") {\n for (const column of block.children) {\n for (const child of column) {\n collectBlockIds(child, ids);\n }\n }\n }\n }\n\n function findBlockParent(\n blocks: Block[],\n id: string,\n parent: {\n blocks: Block[];\n sectionId?: string;\n columnIndex?: number;\n } = { blocks },\n ): { blocks: Block[]; sectionId?: string; columnIndex?: number } | null {\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i];\n if (block.id === id) return parent;\n if (block.type === \"section\") {\n for (let colIdx = 0; colIdx < block.children.length; colIdx++) {\n const result = findBlockParent(block.children[colIdx], id, {\n blocks: block.children[colIdx],\n sectionId: block.id,\n columnIndex: colIdx,\n });\n if (result) return result;\n }\n }\n }\n return null;\n }\n\n function isBlockLocked(blockId: string): boolean {\n return options.lockedBlocks?.value.has(blockId) ?? false;\n }\n\n function findBlockLocation(blockId: string): {\n targetSectionId?: string;\n columnIndex?: number;\n index: number;\n } | null {\n const parent = findBlockParent(state.content.blocks, blockId);\n if (!parent) return null;\n const index = parent.blocks.findIndex((b) => b.id === blockId);\n if (index === -1) return null;\n return {\n targetSectionId: parent.sectionId,\n columnIndex: parent.columnIndex,\n index,\n };\n }\n\n // TODO(collab): the lock checks in addBlock/moveBlock/removeBlock/updateBlock\n // are shallow — they only consider the directly-targeted block id. A section\n // can still be removed, moved, or have its `children` array rewritten while a\n // peer is editing one of its descendants, which silently disrupts that peer's\n // edit. Add a `hasLockedDescendant(blockId)` helper and gate section-level\n // operations on it (and on the parent of each affected child) so cascades\n // through the tree are also blocked.\n\n function setContent(newContent: TemplateContent, markDirty = true): void {\n state.content = newContent;\n if (markDirty) {\n state.isDirty = true;\n }\n }\n\n function selectBlock(blockId: string | null): void {\n if (blockId && isBlockLocked(blockId)) {\n return;\n }\n state.selectedBlockId = blockId;\n }\n\n function setViewport(viewport: ViewportSize): void {\n state.viewport = viewport;\n }\n\n function setDarkMode(darkMode: boolean): void {\n state.darkMode = darkMode;\n }\n\n function setUiTheme(theme: UiTheme): void {\n state.uiTheme = theme;\n }\n\n function setPreviewMode(previewMode: boolean): void {\n state.previewMode = previewMode;\n if (previewMode) {\n state.selectedBlockId = null;\n }\n }\n\n function updateBlock(blockId: string, updates: Partial<Block>): void {\n if (isBlockLocked(blockId)) {\n return;\n }\n const block = findBlockById(state.content.blocks, blockId);\n if (block) {\n Object.assign(block, updates);\n state.isDirty = true;\n }\n }\n\n function updateSettings(updates: Partial<TemplateSettings>): void {\n state.content.settings = { ...state.content.settings, ...updates };\n state.isDirty = true;\n }\n\n function addBlock(\n block: Block,\n targetSectionId?: string,\n columnIndex = 0,\n index?: number,\n ): void {\n if (targetSectionId) {\n if (isBlockLocked(targetSectionId)) {\n return;\n }\n const section = findBlockById(state.content.blocks, targetSectionId);\n if (section && section.type === \"section\") {\n if (columnIndex < 0 || columnIndex >= getColumnCount(section.columns)) {\n return;\n }\n section.children[columnIndex] = section.children[columnIndex] || [];\n const targetArray = section.children[columnIndex];\n if (index !== undefined && index < targetArray.length) {\n targetArray.splice(index, 0, block);\n } else {\n targetArray.push(block);\n }\n }\n } else {\n if (index !== undefined && index < state.content.blocks.length) {\n state.content.blocks.splice(index, 0, block);\n } else {\n state.content.blocks.push(block);\n }\n }\n state.isDirty = true;\n }\n\n function removeBlock(blockId: string): void {\n if (isBlockLocked(blockId)) {\n return;\n }\n const parent = findBlockParent(state.content.blocks, blockId);\n if (parent) {\n const index = parent.blocks.findIndex((b) => b.id === blockId);\n if (index !== -1) {\n const [removed] = parent.blocks.splice(index, 1);\n if (state.selectedBlockId) {\n const removedIds = new Set<string>();\n collectBlockIds(removed, removedIds);\n if (removedIds.has(state.selectedBlockId)) {\n state.selectedBlockId = null;\n }\n }\n state.isDirty = true;\n }\n }\n }\n\n function moveBlock(\n blockId: string,\n newIndex: number,\n targetSectionId?: string,\n columnIndex = 0,\n ): void {\n if (isBlockLocked(blockId)) {\n return;\n }\n if (targetSectionId && isBlockLocked(targetSectionId)) {\n return;\n }\n\n const parent = findBlockParent(state.content.blocks, blockId);\n if (!parent) return;\n\n const oldIndex = parent.blocks.findIndex((b) => b.id === blockId);\n if (oldIndex === -1) return;\n\n // Resolve target before mutating the source — otherwise an invalid\n // targetSectionId leaves the block spliced-out and unrecoverable.\n let targetArray: Block[];\n if (targetSectionId) {\n const section = findBlockById(state.content.blocks, targetSectionId);\n if (!section || section.type !== \"section\") return;\n if (columnIndex < 0 || columnIndex >= getColumnCount(section.columns)) {\n return;\n }\n section.children[columnIndex] = section.children[columnIndex] || [];\n targetArray = section.children[columnIndex];\n } else {\n targetArray = state.content.blocks;\n }\n\n const [block] = parent.blocks.splice(oldIndex, 1);\n targetArray.splice(newIndex, 0, block);\n\n state.isDirty = true;\n }\n\n function markDirty(): void {\n state.isDirty = true;\n }\n\n return {\n state: readonly(state),\n content,\n selectedBlock,\n isBlockLocked,\n setContent,\n selectBlock,\n setViewport,\n setDarkMode,\n setUiTheme,\n setPreviewMode,\n updateBlock,\n updateSettings,\n addBlock,\n removeBlock,\n moveBlock,\n markDirty,\n findBlockLocation,\n };\n}\n","import type { TemplateContent } from \"@templatical/types\";\nimport { computed, ref, type ComputedRef, type Ref } from \"@vue/reactivity\";\n\nexport interface UseHistoryOptions {\n content: Ref<TemplateContent>;\n setContent: (content: TemplateContent, markDirty?: boolean) => void;\n isRemoteOperation?: () => boolean;\n maxSize?: number;\n}\n\nexport interface UseHistoryReturn {\n canUndo: ComputedRef<boolean>;\n canRedo: ComputedRef<boolean>;\n isNavigating: Ref<boolean>;\n undo: () => void;\n redo: () => void;\n record: () => void;\n recordDebounced: (blockId: string) => void;\n clear: () => void;\n destroy: () => void;\n}\n\ninterface DebouncedSnapshot {\n blockId: string;\n timeoutId: ReturnType<typeof setTimeout>;\n}\n\nconst MAX_STACK_SIZE = 50;\nconst DEBOUNCE_MS = 300;\nconst NAVIGATE_IDLE_MS = 1500;\n\nexport function useHistory(options: UseHistoryOptions): UseHistoryReturn {\n const {\n content,\n setContent,\n isRemoteOperation,\n maxSize = MAX_STACK_SIZE,\n } = options;\n\n const undoStack = ref<TemplateContent[]>([]);\n const redoStack = ref<TemplateContent[]>([]);\n const isNavigating = ref(false);\n let navigatingTimeoutId: ReturnType<typeof setTimeout> | null = null;\n let pendingDebounce: DebouncedSnapshot | null = null;\n\n const canUndo = computed(() => undoStack.value.length > 0);\n const canRedo = computed(() => redoStack.value.length > 0);\n\n function cloneContent(): TemplateContent {\n // Cycle-safe deep clone. A naked JSON.stringify throws\n // `Converting circular structure to JSON` if anything in the tree\n // is self-referencing — e.g. a DOM element with a Sortable expando\n // back-ref ever sneaks into block data via a drag handler. We'd\n // rather drop the back-ref from the snapshot than freeze the undo\n // stack (the visible symptom: any subsequent mutation that calls\n // `record()` throws, breaking clone/move/etc.).\n const seen = new WeakSet<object>();\n return JSON.parse(\n JSON.stringify(content.value, (_key, value) => {\n if (typeof value === \"object\" && value !== null) {\n if (seen.has(value)) return undefined;\n seen.add(value);\n }\n return value;\n }),\n ) as TemplateContent;\n }\n\n function pushToUndoStack(snapshot: TemplateContent): void {\n undoStack.value.push(snapshot);\n if (undoStack.value.length > maxSize) {\n undoStack.value.splice(0, undoStack.value.length - maxSize);\n }\n }\n\n function flushPendingDebounce(): void {\n if (pendingDebounce) {\n clearTimeout(pendingDebounce.timeoutId);\n pendingDebounce = null;\n }\n }\n\n function record(): void {\n if (isRemoteOperation?.()) {\n return;\n }\n\n flushPendingDebounce();\n pushToUndoStack(cloneContent());\n redoStack.value = [];\n }\n\n function recordDebounced(blockId: string): void {\n if (isRemoteOperation?.()) {\n return;\n }\n\n if (pendingDebounce && pendingDebounce.blockId === blockId) {\n clearTimeout(pendingDebounce.timeoutId);\n pendingDebounce.timeoutId = setTimeout(() => {\n pendingDebounce = null;\n }, DEBOUNCE_MS);\n return;\n }\n\n flushPendingDebounce();\n\n pushToUndoStack(cloneContent());\n redoStack.value = [];\n\n pendingDebounce = {\n blockId,\n timeoutId: setTimeout(() => {\n pendingDebounce = null;\n }, DEBOUNCE_MS),\n };\n }\n\n function setNavigating(): void {\n isNavigating.value = true;\n if (navigatingTimeoutId) {\n clearTimeout(navigatingTimeoutId);\n }\n navigatingTimeoutId = setTimeout(() => {\n isNavigating.value = false;\n navigatingTimeoutId = null;\n }, NAVIGATE_IDLE_MS);\n }\n\n function undo(): void {\n if (undoStack.value.length === 0) {\n return;\n }\n\n flushPendingDebounce();\n\n const snapshot = undoStack.value.pop()!;\n redoStack.value.push(cloneContent());\n setContent(snapshot, true);\n setNavigating();\n }\n\n function redo(): void {\n if (redoStack.value.length === 0) {\n return;\n }\n\n flushPendingDebounce();\n\n const snapshot = redoStack.value.pop()!;\n undoStack.value.push(cloneContent());\n setContent(snapshot, true);\n setNavigating();\n }\n\n function clear(): void {\n undoStack.value = [];\n redoStack.value = [];\n flushPendingDebounce();\n }\n\n function destroy(): void {\n clear();\n if (navigatingTimeoutId) {\n clearTimeout(navigatingTimeoutId);\n navigatingTimeoutId = null;\n }\n }\n\n return {\n canUndo,\n canRedo,\n isNavigating,\n undo,\n redo,\n record,\n recordDebounced,\n clear,\n destroy,\n };\n}\n","import type { Block, BlockDefaults, BlockType } from \"@templatical/types\";\nimport { createBlock, generateId } from \"@templatical/types\";\n\nfunction regenerateNestedIds(block: Block): void {\n if (block.type === \"table\") {\n block.rows = block.rows.map((row) => ({\n ...row,\n id: generateId(),\n cells: row.cells.map((cell) => ({ ...cell, id: generateId() })),\n }));\n } else if (block.type === \"social\") {\n block.icons = block.icons.map((icon) => ({ ...icon, id: generateId() }));\n } else if (block.type === \"menu\") {\n block.items = block.items.map((item) => ({ ...item, id: generateId() }));\n }\n}\n\nexport interface UseBlockActionsOptions {\n addBlock: (\n block: Block,\n targetSectionId?: string,\n columnIndex?: number,\n index?: number,\n ) => void;\n removeBlock: (blockId: string) => void;\n updateBlock: (blockId: string, updates: Partial<Block>) => void;\n selectBlock: (blockId: string | null) => void;\n /** Locate a block in the tree — used by `duplicateBlock` to insert the\n * clone right after the source instead of appending to the end. */\n findBlockLocation?: (blockId: string) => {\n targetSectionId?: string;\n columnIndex?: number;\n index: number;\n } | null;\n blockDefaults?: BlockDefaults;\n}\n\nexport interface UseBlockActionsReturn {\n createAndAddBlock: (\n type: BlockType,\n targetSectionId?: string,\n columnIndex?: number,\n ) => Block;\n duplicateBlock: (\n block: Block,\n targetSectionId?: string,\n columnIndex?: number,\n ) => Block;\n deleteBlock: (blockId: string) => void;\n updateBlockProperty: <K extends keyof Block>(\n blockId: string,\n key: K,\n value: Block[K],\n ) => void;\n}\n\nexport function useBlockActions(\n options: UseBlockActionsOptions,\n): UseBlockActionsReturn {\n const { addBlock, removeBlock, updateBlock, selectBlock, findBlockLocation } =\n options;\n\n function createAndAddBlock(\n type: BlockType,\n targetSectionId?: string,\n columnIndex?: number,\n ): Block {\n const block = createBlock(type, options.blockDefaults);\n addBlock(block, targetSectionId, columnIndex);\n selectBlock(block.id);\n return block;\n }\n\n function duplicateBlock(\n block: Block,\n targetSectionId?: string,\n columnIndex?: number,\n ): Block {\n const cloned = JSON.parse(JSON.stringify(block)) as Block;\n cloned.id = generateId();\n regenerateNestedIds(cloned);\n\n if (cloned.type === \"section\") {\n cloned.children = cloned.children.map((column) =>\n column.map((child) => {\n const clonedChild = JSON.parse(JSON.stringify(child)) as Block;\n clonedChild.id = generateId();\n regenerateNestedIds(clonedChild);\n return clonedChild;\n }),\n );\n }\n\n // Insert directly after the source block. Explicit target args win;\n // otherwise, resolve the source's location and bump index by 1. Falls\n // back to appending at the end if location is unknown.\n if (targetSectionId !== undefined || columnIndex !== undefined) {\n addBlock(cloned, targetSectionId, columnIndex);\n } else {\n const sourceLocation = findBlockLocation?.(block.id) ?? null;\n if (sourceLocation) {\n addBlock(\n cloned,\n sourceLocation.targetSectionId,\n sourceLocation.columnIndex,\n sourceLocation.index + 1,\n );\n } else {\n addBlock(cloned, targetSectionId, columnIndex);\n }\n }\n selectBlock(cloned.id);\n return cloned;\n }\n\n function deleteBlock(blockId: string): void {\n removeBlock(blockId);\n }\n\n function updateBlockProperty<K extends keyof Block>(\n blockId: string,\n key: K,\n value: Block[K],\n ): void {\n updateBlock(blockId, { [key]: value } as Partial<Block>);\n }\n\n return {\n createAndAddBlock,\n duplicateBlock,\n deleteBlock,\n updateBlockProperty,\n };\n}\n","import type { TemplateContent } from \"@templatical/types\";\nimport { watch, type Ref } from \"@vue/reactivity\";\n\nexport interface UseAutoSaveOptions {\n content: Ref<TemplateContent>;\n isDirty: () => boolean;\n onChange: (content: TemplateContent) => void;\n debounce?: number;\n enabled?: boolean | (() => boolean);\n}\n\nexport interface UseAutoSaveReturn {\n flush: () => void;\n cancel: () => void;\n pause: () => void;\n resume: () => void;\n destroy: () => void;\n}\n\nexport function useAutoSave(options: UseAutoSaveOptions): UseAutoSaveReturn {\n const {\n content,\n isDirty,\n onChange,\n debounce = 1000,\n enabled = true,\n } = options;\n\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n let paused = false;\n\n function isEnabled(): boolean {\n return typeof enabled === \"function\" ? enabled() : enabled;\n }\n\n function pause(): void {\n paused = true;\n cancel();\n }\n\n function resume(): void {\n paused = false;\n }\n\n function cancel(): void {\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n }\n\n function flush(): void {\n cancel();\n if (isDirty()) {\n onChange(JSON.parse(JSON.stringify(content.value)));\n }\n }\n\n function scheduleOnChange(): void {\n if (!isEnabled() || paused) return;\n\n cancel();\n timeoutId = setTimeout(() => {\n timeoutId = null;\n if (isEnabled() && !paused && isDirty()) {\n onChange(JSON.parse(JSON.stringify(content.value)));\n }\n }, debounce);\n }\n\n const stopWatch = watch(\n content,\n () => {\n if (isEnabled() && !paused && isDirty()) {\n scheduleOnChange();\n }\n },\n { deep: true },\n );\n\n function destroy(): void {\n stopWatch();\n cancel();\n }\n\n return {\n flush,\n cancel,\n pause,\n resume,\n destroy,\n };\n}\n","import type { UseEditorReturn } from \"./editor\";\nimport { computed, reactive, type ComputedRef } from \"@vue/reactivity\";\n\nexport interface UseConditionPreviewReturn {\n isHidden: (blockId: string) => boolean;\n toggleBlock: (blockId: string) => void;\n reset: () => void;\n hasHiddenBlocks: ComputedRef<boolean>;\n}\n\nexport function useConditionPreview(\n editor: UseEditorReturn,\n): UseConditionPreviewReturn {\n const hiddenBlockIds = reactive(new Set<string>());\n\n const hasHiddenBlocks = computed(() => hiddenBlockIds.size > 0);\n\n function isHidden(blockId: string): boolean {\n return hiddenBlockIds.has(blockId);\n }\n\n function toggleBlock(blockId: string): void {\n if (hiddenBlockIds.has(blockId)) {\n hiddenBlockIds.delete(blockId);\n } else {\n hiddenBlockIds.add(blockId);\n\n if (editor.state.selectedBlockId === blockId) {\n editor.selectBlock(null);\n }\n }\n }\n\n function reset(): void {\n hiddenBlockIds.clear();\n }\n\n return {\n isHidden,\n toggleBlock,\n reset,\n hasHiddenBlocks,\n };\n}\n","import type { CustomBlock, CustomBlockDefinition } from \"@templatical/types\";\nimport type { ComputedRef, Ref } from \"@vue/reactivity\";\nimport { computed, ref } from \"@vue/reactivity\";\n\nexport function useDataSourceFetch(options: {\n definition: ComputedRef<CustomBlockDefinition | undefined>;\n block: ComputedRef<CustomBlock>;\n onUpdate: (fieldValues: Record<string, unknown>, fetched: boolean) => void;\n}): {\n isFetching: Ref<boolean>;\n fetchError: Ref<boolean>;\n fetch: () => Promise<void>;\n hasDataSource: ComputedRef<boolean>;\n needsFetch: ComputedRef<boolean>;\n} {\n const isFetching = ref(false);\n const fetchError = ref(false);\n\n const hasDataSource = computed(() => !!options.definition.value?.dataSource);\n\n const needsFetch = computed(\n () => hasDataSource.value && !options.block.value.dataSourceFetched,\n );\n\n async function fetch(): Promise<void> {\n const def = options.definition.value;\n if (!def?.dataSource) {\n return;\n }\n\n isFetching.value = true;\n fetchError.value = false;\n\n try {\n const result = await def.dataSource.onFetch({\n fieldValues: { ...options.block.value.fieldValues },\n blockId: options.block.value.id,\n });\n\n if (result == null) {\n return;\n }\n\n const merged = { ...options.block.value.fieldValues };\n for (const key of Object.keys(merged)) {\n if (key in result) {\n merged[key] = result[key];\n }\n }\n\n options.onUpdate(merged, true);\n } catch (error) {\n console.warn(\"[Templatical] Data source fetch error:\", error);\n fetchError.value = true;\n } finally {\n isFetching.value = false;\n }\n }\n\n return {\n isFetching,\n fetchError,\n fetch,\n hasDataSource,\n needsFetch,\n };\n}\n","import type { UseEditorReturn } from \"./editor\";\nimport type { UseHistoryReturn } from \"./history\";\n\n/**\n * Wraps editor mutation methods to record history snapshots before each\n * operation. Mutates the editor object in place.\n *\n * Must be applied **after** any collaboration broadcast wrapping so the\n * call chain is: history.record() → broadcast → original mutation.\n */\nexport function useHistoryInterceptor(\n editor: UseEditorReturn,\n history: UseHistoryReturn,\n): void {\n const originalAddBlock = editor.addBlock;\n const originalRemoveBlock = editor.removeBlock;\n const originalMoveBlock = editor.moveBlock;\n const originalUpdateBlock = editor.updateBlock;\n const originalUpdateSettings = editor.updateSettings;\n\n // Skip recording when the underlying op is a no-op (e.g., a peer-locked\n // block or section), otherwise the undo stack fills with snapshots that\n // are identical to current state and undo silently does nothing.\n editor.addBlock = (block, targetSectionId?, columnIndex?, index?) => {\n if (targetSectionId && editor.isBlockLocked(targetSectionId)) {\n return;\n }\n history.record();\n originalAddBlock(block, targetSectionId, columnIndex, index);\n };\n\n editor.removeBlock = (blockId) => {\n if (editor.isBlockLocked(blockId)) {\n return;\n }\n history.record();\n originalRemoveBlock(blockId);\n };\n\n editor.moveBlock = (blockId, newIndex, targetSectionId?, columnIndex?) => {\n if (editor.isBlockLocked(blockId)) {\n return;\n }\n if (targetSectionId && editor.isBlockLocked(targetSectionId)) {\n return;\n }\n history.record();\n originalMoveBlock(blockId, newIndex, targetSectionId, columnIndex);\n };\n\n editor.updateBlock = (blockId, updates) => {\n if (editor.isBlockLocked(blockId)) {\n return;\n }\n history.recordDebounced(blockId);\n originalUpdateBlock(blockId, updates);\n };\n\n editor.updateSettings = (updates) => {\n history.record();\n originalUpdateSettings(updates);\n };\n}\n"],"mappings":"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","names":["markDirty","computed","computed","reactive","computed","ref"]}
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@templatical/core",
|
|
3
3
|
"description": "Framework-agnostic editor logic for Templatical email editor",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.3",
|
|
5
5
|
"bugs": "https://github.com/templatical/sdk/issues",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@vue/reactivity": "^3.5.33",
|
|
8
|
-
"@templatical/types": "0.7.
|
|
8
|
+
"@templatical/types": "0.7.3"
|
|
9
9
|
},
|
|
10
10
|
"devDependencies": {
|
|
11
11
|
"pusher-js": "^8.5.0",
|