@templatical/core 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,484 @@
1
+ // src/editor.ts
2
+ import { createDefaultTemplateContent } from "@templatical/types";
3
+ import {
4
+ computed,
5
+ reactive,
6
+ readonly
7
+ } from "@vue/reactivity";
8
+ function useEditor(options) {
9
+ const state = reactive({
10
+ content: options.content ?? createDefaultTemplateContent(
11
+ options.defaultFontFamily,
12
+ options.templateDefaults
13
+ ),
14
+ selectedBlockId: null,
15
+ viewport: "desktop",
16
+ darkMode: false,
17
+ previewMode: false,
18
+ isDirty: false
19
+ });
20
+ const content = computed({
21
+ get: () => state.content,
22
+ set: (value) => {
23
+ state.content = value;
24
+ state.isDirty = true;
25
+ }
26
+ });
27
+ const selectedBlock = computed(() => {
28
+ if (!state.selectedBlockId) return null;
29
+ return findBlockById(state.content.blocks, state.selectedBlockId);
30
+ });
31
+ function findBlockById(blocks, id) {
32
+ for (const block of blocks) {
33
+ if (block.id === id) return block;
34
+ if (block.type === "section") {
35
+ for (const column of block.children) {
36
+ const found = findBlockById(column, id);
37
+ if (found) return found;
38
+ }
39
+ }
40
+ }
41
+ return null;
42
+ }
43
+ function findBlockParent(blocks, id, parent = { blocks }) {
44
+ for (let i = 0; i < blocks.length; i++) {
45
+ const block = blocks[i];
46
+ if (block.id === id) return parent;
47
+ if (block.type === "section") {
48
+ for (let colIdx = 0; colIdx < block.children.length; colIdx++) {
49
+ const result = findBlockParent(block.children[colIdx], id, {
50
+ blocks: block.children[colIdx],
51
+ sectionId: block.id,
52
+ columnIndex: colIdx
53
+ });
54
+ if (result) return result;
55
+ }
56
+ }
57
+ }
58
+ return null;
59
+ }
60
+ function isBlockLocked(blockId) {
61
+ return options.lockedBlocks?.value.has(blockId) ?? false;
62
+ }
63
+ function setContent(newContent, markDirty2 = true) {
64
+ state.content = newContent;
65
+ if (markDirty2) {
66
+ state.isDirty = true;
67
+ }
68
+ }
69
+ function selectBlock(blockId) {
70
+ if (blockId && isBlockLocked(blockId)) {
71
+ return;
72
+ }
73
+ state.selectedBlockId = blockId;
74
+ }
75
+ function setViewport(viewport) {
76
+ state.viewport = viewport;
77
+ }
78
+ function setDarkMode(darkMode) {
79
+ state.darkMode = darkMode;
80
+ }
81
+ function setPreviewMode(previewMode) {
82
+ state.previewMode = previewMode;
83
+ if (previewMode) {
84
+ state.selectedBlockId = null;
85
+ }
86
+ }
87
+ function updateBlock(blockId, updates) {
88
+ if (isBlockLocked(blockId)) {
89
+ return;
90
+ }
91
+ const block = findBlockById(state.content.blocks, blockId);
92
+ if (block) {
93
+ Object.assign(block, updates);
94
+ state.isDirty = true;
95
+ }
96
+ }
97
+ function updateSettings(updates) {
98
+ state.content.settings = { ...state.content.settings, ...updates };
99
+ state.isDirty = true;
100
+ }
101
+ function addBlock(block, targetSectionId, columnIndex = 0, index) {
102
+ if (targetSectionId) {
103
+ const section = findBlockById(state.content.blocks, targetSectionId);
104
+ if (section && section.type === "section") {
105
+ section.children[columnIndex] = section.children[columnIndex] || [];
106
+ const targetArray = section.children[columnIndex];
107
+ if (index !== void 0 && index < targetArray.length) {
108
+ targetArray.splice(index, 0, block);
109
+ } else {
110
+ targetArray.push(block);
111
+ }
112
+ }
113
+ } else {
114
+ if (index !== void 0 && index < state.content.blocks.length) {
115
+ state.content.blocks.splice(index, 0, block);
116
+ } else {
117
+ state.content.blocks.push(block);
118
+ }
119
+ }
120
+ state.isDirty = true;
121
+ }
122
+ function removeBlock(blockId) {
123
+ if (isBlockLocked(blockId)) {
124
+ return;
125
+ }
126
+ const parent = findBlockParent(state.content.blocks, blockId);
127
+ if (parent) {
128
+ const index = parent.blocks.findIndex((b) => b.id === blockId);
129
+ if (index !== -1) {
130
+ parent.blocks.splice(index, 1);
131
+ if (state.selectedBlockId === blockId) {
132
+ state.selectedBlockId = null;
133
+ }
134
+ state.isDirty = true;
135
+ }
136
+ }
137
+ }
138
+ function moveBlock(blockId, newIndex, targetSectionId, columnIndex = 0) {
139
+ const parent = findBlockParent(state.content.blocks, blockId);
140
+ if (!parent) return;
141
+ const oldIndex = parent.blocks.findIndex((b) => b.id === blockId);
142
+ if (oldIndex === -1) return;
143
+ const [block] = parent.blocks.splice(oldIndex, 1);
144
+ if (targetSectionId) {
145
+ const section = findBlockById(state.content.blocks, targetSectionId);
146
+ if (section && section.type === "section") {
147
+ section.children[columnIndex] = section.children[columnIndex] || [];
148
+ section.children[columnIndex].splice(newIndex, 0, block);
149
+ }
150
+ } else {
151
+ state.content.blocks.splice(newIndex, 0, block);
152
+ }
153
+ state.isDirty = true;
154
+ }
155
+ function markDirty() {
156
+ state.isDirty = true;
157
+ }
158
+ return {
159
+ state: readonly(state),
160
+ content,
161
+ selectedBlock,
162
+ isBlockLocked,
163
+ setContent,
164
+ selectBlock,
165
+ setViewport,
166
+ setDarkMode,
167
+ setPreviewMode,
168
+ updateBlock,
169
+ updateSettings,
170
+ addBlock,
171
+ removeBlock,
172
+ moveBlock,
173
+ markDirty
174
+ };
175
+ }
176
+
177
+ // src/history.ts
178
+ import { computed as computed2, ref } from "@vue/reactivity";
179
+ var MAX_STACK_SIZE = 50;
180
+ var DEBOUNCE_MS = 300;
181
+ var NAVIGATE_IDLE_MS = 1500;
182
+ function useHistory(options) {
183
+ const {
184
+ content,
185
+ setContent,
186
+ isRemoteOperation,
187
+ maxSize = MAX_STACK_SIZE
188
+ } = options;
189
+ const undoStack = ref([]);
190
+ const redoStack = ref([]);
191
+ const isNavigating = ref(false);
192
+ let navigatingTimeoutId = null;
193
+ let pendingDebounce = null;
194
+ const canUndo = computed2(() => undoStack.value.length > 0);
195
+ const canRedo = computed2(() => redoStack.value.length > 0);
196
+ function cloneContent() {
197
+ return JSON.parse(JSON.stringify(content.value));
198
+ }
199
+ function pushToUndoStack(snapshot) {
200
+ undoStack.value.push(snapshot);
201
+ if (undoStack.value.length > maxSize) {
202
+ undoStack.value.splice(0, undoStack.value.length - maxSize);
203
+ }
204
+ }
205
+ function flushPendingDebounce() {
206
+ if (pendingDebounce) {
207
+ clearTimeout(pendingDebounce.timeoutId);
208
+ pendingDebounce = null;
209
+ }
210
+ }
211
+ function record() {
212
+ if (isRemoteOperation?.()) {
213
+ return;
214
+ }
215
+ flushPendingDebounce();
216
+ pushToUndoStack(cloneContent());
217
+ redoStack.value = [];
218
+ }
219
+ function recordDebounced(blockId) {
220
+ if (isRemoteOperation?.()) {
221
+ return;
222
+ }
223
+ if (pendingDebounce && pendingDebounce.blockId === blockId) {
224
+ clearTimeout(pendingDebounce.timeoutId);
225
+ pendingDebounce.timeoutId = setTimeout(() => {
226
+ pendingDebounce = null;
227
+ }, DEBOUNCE_MS);
228
+ return;
229
+ }
230
+ flushPendingDebounce();
231
+ pushToUndoStack(cloneContent());
232
+ redoStack.value = [];
233
+ pendingDebounce = {
234
+ blockId,
235
+ timeoutId: setTimeout(() => {
236
+ pendingDebounce = null;
237
+ }, DEBOUNCE_MS)
238
+ };
239
+ }
240
+ function setNavigating() {
241
+ isNavigating.value = true;
242
+ if (navigatingTimeoutId) {
243
+ clearTimeout(navigatingTimeoutId);
244
+ }
245
+ navigatingTimeoutId = setTimeout(() => {
246
+ isNavigating.value = false;
247
+ navigatingTimeoutId = null;
248
+ }, NAVIGATE_IDLE_MS);
249
+ }
250
+ function undo() {
251
+ if (undoStack.value.length === 0) {
252
+ return;
253
+ }
254
+ flushPendingDebounce();
255
+ const snapshot = undoStack.value.pop();
256
+ redoStack.value.push(cloneContent());
257
+ setContent(snapshot, true);
258
+ setNavigating();
259
+ }
260
+ function redo() {
261
+ if (redoStack.value.length === 0) {
262
+ return;
263
+ }
264
+ flushPendingDebounce();
265
+ const snapshot = redoStack.value.pop();
266
+ undoStack.value.push(cloneContent());
267
+ setContent(snapshot, true);
268
+ setNavigating();
269
+ }
270
+ function clear() {
271
+ undoStack.value = [];
272
+ redoStack.value = [];
273
+ flushPendingDebounce();
274
+ }
275
+ function destroy() {
276
+ clear();
277
+ if (navigatingTimeoutId) {
278
+ clearTimeout(navigatingTimeoutId);
279
+ navigatingTimeoutId = null;
280
+ }
281
+ }
282
+ return {
283
+ canUndo,
284
+ canRedo,
285
+ isNavigating,
286
+ undo,
287
+ redo,
288
+ record,
289
+ recordDebounced,
290
+ clear,
291
+ destroy
292
+ };
293
+ }
294
+
295
+ // src/block-actions.ts
296
+ import { createBlock, generateId } from "@templatical/types";
297
+ function useBlockActions(options) {
298
+ const { addBlock, removeBlock, updateBlock, selectBlock } = options;
299
+ function createAndAddBlock(type, targetSectionId, columnIndex) {
300
+ const block = createBlock(type, options.blockDefaults);
301
+ addBlock(block, targetSectionId, columnIndex);
302
+ selectBlock(block.id);
303
+ return block;
304
+ }
305
+ function duplicateBlock(block, targetSectionId, columnIndex) {
306
+ const cloned = JSON.parse(JSON.stringify(block));
307
+ cloned.id = generateId();
308
+ if (cloned.type === "section") {
309
+ cloned.children = cloned.children.map(
310
+ (column) => column.map((child) => {
311
+ const clonedChild = JSON.parse(JSON.stringify(child));
312
+ clonedChild.id = generateId();
313
+ return clonedChild;
314
+ })
315
+ );
316
+ }
317
+ addBlock(cloned, targetSectionId, columnIndex);
318
+ selectBlock(cloned.id);
319
+ return cloned;
320
+ }
321
+ function deleteBlock(blockId) {
322
+ removeBlock(blockId);
323
+ }
324
+ function updateBlockProperty(blockId, key, value) {
325
+ updateBlock(blockId, { [key]: value });
326
+ }
327
+ return {
328
+ createAndAddBlock,
329
+ duplicateBlock,
330
+ deleteBlock,
331
+ updateBlockProperty
332
+ };
333
+ }
334
+
335
+ // src/auto-save.ts
336
+ import { watch } from "@vue/reactivity";
337
+ function useAutoSave(options) {
338
+ const {
339
+ content,
340
+ isDirty,
341
+ onChange,
342
+ debounce = 1e3,
343
+ enabled = true
344
+ } = options;
345
+ let timeoutId = null;
346
+ let paused = false;
347
+ function isEnabled() {
348
+ return typeof enabled === "function" ? enabled() : enabled;
349
+ }
350
+ function pause() {
351
+ paused = true;
352
+ cancel();
353
+ }
354
+ function resume() {
355
+ paused = false;
356
+ }
357
+ function cancel() {
358
+ if (timeoutId) {
359
+ clearTimeout(timeoutId);
360
+ timeoutId = null;
361
+ }
362
+ }
363
+ function flush() {
364
+ cancel();
365
+ if (isDirty()) {
366
+ onChange(JSON.parse(JSON.stringify(content.value)));
367
+ }
368
+ }
369
+ function scheduleOnChange() {
370
+ if (!isEnabled() || paused) return;
371
+ cancel();
372
+ timeoutId = setTimeout(() => {
373
+ timeoutId = null;
374
+ if (isDirty()) {
375
+ onChange(JSON.parse(JSON.stringify(content.value)));
376
+ }
377
+ }, debounce);
378
+ }
379
+ const stopWatch = watch(
380
+ content,
381
+ () => {
382
+ if (isEnabled() && !paused && isDirty()) {
383
+ scheduleOnChange();
384
+ }
385
+ },
386
+ { deep: true }
387
+ );
388
+ function destroy() {
389
+ stopWatch();
390
+ cancel();
391
+ }
392
+ return {
393
+ flush,
394
+ cancel,
395
+ pause,
396
+ resume,
397
+ destroy
398
+ };
399
+ }
400
+
401
+ // src/condition-preview.ts
402
+ import { computed as computed3, reactive as reactive2 } from "@vue/reactivity";
403
+ function useConditionPreview(editor) {
404
+ const hiddenBlockIds = reactive2(/* @__PURE__ */ new Set());
405
+ const hasHiddenBlocks = computed3(() => hiddenBlockIds.size > 0);
406
+ function isHidden(blockId) {
407
+ return hiddenBlockIds.has(blockId);
408
+ }
409
+ function toggleBlock(blockId) {
410
+ if (hiddenBlockIds.has(blockId)) {
411
+ hiddenBlockIds.delete(blockId);
412
+ } else {
413
+ hiddenBlockIds.add(blockId);
414
+ if (editor.state.selectedBlockId === blockId) {
415
+ editor.selectBlock(null);
416
+ }
417
+ }
418
+ }
419
+ function reset() {
420
+ hiddenBlockIds.clear();
421
+ }
422
+ return {
423
+ isHidden,
424
+ toggleBlock,
425
+ reset,
426
+ hasHiddenBlocks
427
+ };
428
+ }
429
+
430
+ // src/data-source-fetch.ts
431
+ import { computed as computed4, ref as ref2 } from "@vue/reactivity";
432
+ function useDataSourceFetch(options) {
433
+ const isFetching = ref2(false);
434
+ const fetchError = ref2(false);
435
+ const hasDataSource = computed4(() => !!options.definition.value?.dataSource);
436
+ const needsFetch = computed4(
437
+ () => hasDataSource.value && !options.block.value.dataSourceFetched
438
+ );
439
+ async function fetch() {
440
+ const def = options.definition.value;
441
+ if (!def?.dataSource) {
442
+ return;
443
+ }
444
+ isFetching.value = true;
445
+ fetchError.value = false;
446
+ try {
447
+ const result = await def.dataSource.onFetch({
448
+ fieldValues: { ...options.block.value.fieldValues },
449
+ blockId: options.block.value.id
450
+ });
451
+ if (result === null || result === void 0) {
452
+ return;
453
+ }
454
+ const merged = { ...options.block.value.fieldValues };
455
+ for (const key of Object.keys(merged)) {
456
+ if (key in result) {
457
+ merged[key] = result[key];
458
+ }
459
+ }
460
+ options.onUpdate(merged, true);
461
+ } catch (error) {
462
+ console.warn("[Templatical] Data source fetch error:", error);
463
+ fetchError.value = true;
464
+ } finally {
465
+ isFetching.value = false;
466
+ }
467
+ }
468
+ return {
469
+ isFetching,
470
+ fetchError,
471
+ fetch,
472
+ hasDataSource,
473
+ needsFetch
474
+ };
475
+ }
476
+ export {
477
+ useAutoSave,
478
+ useBlockActions,
479
+ useConditionPreview,
480
+ useDataSourceFetch,
481
+ useEditor,
482
+ useHistory
483
+ };
484
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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"],"sourcesContent":["import type {\n Block,\n TemplateContent,\n TemplateDefaults,\n TemplateSettings,\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}\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 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}\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 });\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 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 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 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 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 const [block] = parent.blocks.splice(oldIndex, 1);\n\n if (targetSectionId) {\n const section = findBlockById(state.content.blocks, targetSectionId);\n if (section && section.type === \"section\") {\n section.children[columnIndex] = section.children[columnIndex] || [];\n section.children[columnIndex].splice(newIndex, 0, block);\n }\n } else {\n state.content.blocks.splice(newIndex, 0, block);\n }\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 setPreviewMode,\n updateBlock,\n updateSettings,\n addBlock,\n removeBlock,\n moveBlock,\n markDirty,\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 return JSON.parse(JSON.stringify(content.value)) 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 ) => void;\n removeBlock: (blockId: string) => void;\n updateBlock: (blockId: string, updates: Partial<Block>) => void;\n selectBlock: (blockId: string | null) => void;\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 } = 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 addBlock(cloned, targetSectionId, columnIndex);\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 (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 || result === undefined) {\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"],"mappings":"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","names":["markDirty","computed","computed","reactive","computed","ref"]}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@templatical/core",
3
+ "version": "0.0.1",
4
+ "publishConfig": { "access": "public" },
5
+ "description": "Framework-agnostic editor logic for Templatical email editor",
6
+ "license": "SEE LICENSE IN LICENSE",
7
+ "type": "module",
8
+ "main": "./dist/index.cjs",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js",
15
+ "require": "./dist/index.cjs"
16
+ },
17
+ "./cloud": {
18
+ "types": "./dist/cloud/index.d.ts",
19
+ "import": "./dist/cloud/index.js",
20
+ "require": "./dist/cloud/index.cjs"
21
+ }
22
+ },
23
+ "files": [
24
+ "dist"
25
+ ],
26
+ "scripts": {
27
+ "build": "tsup",
28
+ "test": "vitest run --config vitest.config.ts",
29
+ "typecheck": "tsc --noEmit"
30
+ },
31
+ "dependencies": {
32
+ "@templatical/types": "workspace:*",
33
+ "@vue/reactivity": "^3.5.31",
34
+ "pusher-js": "^8.0.0"
35
+ },
36
+ "devDependencies": {
37
+ "tsup": "^8.0.0",
38
+ "typescript": "^5.7.0",
39
+ "vitest": "^3.0.0",
40
+ "vue": "^3.5.30"
41
+ }
42
+ }