@aswin.dev/core 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +56 -0
- package/README.md +64 -0
- package/dist/cloud/index.d.ts +487 -0
- package/dist/cloud/index.js +2853 -0
- package/dist/cloud/index.js.map +1 -0
- package/dist/editor-Cp6y4tLN.d.ts +52 -0
- package/dist/index.d.ts +85 -0
- package/dist/index.js +645 -0
- package/dist/index.js.map +1 -0
- package/package.json +64 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,645 @@
|
|
|
1
|
+
// src/editor.ts
|
|
2
|
+
import {
|
|
3
|
+
createDefaultTemplateContent,
|
|
4
|
+
normalizeTemplateContentPages
|
|
5
|
+
} from "@aswin.dev/types";
|
|
6
|
+
import {
|
|
7
|
+
computed,
|
|
8
|
+
reactive,
|
|
9
|
+
readonly
|
|
10
|
+
} from "@vue/reactivity";
|
|
11
|
+
function useEditor(options) {
|
|
12
|
+
const initialRaw = options.content ?? createDefaultTemplateContent(
|
|
13
|
+
options.defaultFontFamily,
|
|
14
|
+
options.templateDefaults
|
|
15
|
+
);
|
|
16
|
+
const state = reactive({
|
|
17
|
+
content: normalizeTemplateContentPages(initialRaw),
|
|
18
|
+
selectedBlockId: null,
|
|
19
|
+
viewport: "desktop",
|
|
20
|
+
darkMode: false,
|
|
21
|
+
previewMode: false,
|
|
22
|
+
isDirty: false,
|
|
23
|
+
uiTheme: "auto"
|
|
24
|
+
});
|
|
25
|
+
const content = computed({
|
|
26
|
+
get: () => state.content,
|
|
27
|
+
set: (value) => {
|
|
28
|
+
state.content = normalizeTemplateContentPages(value);
|
|
29
|
+
state.isDirty = true;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
const selectedBlock = computed(() => {
|
|
33
|
+
if (!state.selectedBlockId) return null;
|
|
34
|
+
return findBlockById(state.content.blocks, state.selectedBlockId);
|
|
35
|
+
});
|
|
36
|
+
function findBlockById(blocks, id) {
|
|
37
|
+
for (const block of blocks) {
|
|
38
|
+
if (block.id === id) return block;
|
|
39
|
+
if (block.type === "section") {
|
|
40
|
+
for (const column of block.children) {
|
|
41
|
+
const found = findBlockById(column, id);
|
|
42
|
+
if (found) return found;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
function findBlockParent(blocks, id, parent = { blocks }) {
|
|
49
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
50
|
+
const block = blocks[i];
|
|
51
|
+
if (block.id === id) return parent;
|
|
52
|
+
if (block.type === "section") {
|
|
53
|
+
for (let colIdx = 0; colIdx < block.children.length; colIdx++) {
|
|
54
|
+
const result = findBlockParent(block.children[colIdx], id, {
|
|
55
|
+
blocks: block.children[colIdx],
|
|
56
|
+
sectionId: block.id,
|
|
57
|
+
columnIndex: colIdx
|
|
58
|
+
});
|
|
59
|
+
if (result) return result;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
function isBlockLocked(blockId) {
|
|
66
|
+
return options.lockedBlocks?.value.has(blockId) ?? false;
|
|
67
|
+
}
|
|
68
|
+
function setContent(newContent, markDirty2 = true) {
|
|
69
|
+
state.content = normalizeTemplateContentPages(newContent);
|
|
70
|
+
if (markDirty2) {
|
|
71
|
+
state.isDirty = true;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function selectBlock(blockId) {
|
|
75
|
+
if (blockId && isBlockLocked(blockId)) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
state.selectedBlockId = blockId;
|
|
79
|
+
}
|
|
80
|
+
function setViewport(viewport) {
|
|
81
|
+
state.viewport = viewport;
|
|
82
|
+
}
|
|
83
|
+
function setDarkMode(darkMode) {
|
|
84
|
+
state.darkMode = darkMode;
|
|
85
|
+
}
|
|
86
|
+
function setUiTheme(theme) {
|
|
87
|
+
state.uiTheme = theme;
|
|
88
|
+
}
|
|
89
|
+
function setPreviewMode(previewMode) {
|
|
90
|
+
state.previewMode = previewMode;
|
|
91
|
+
if (previewMode) {
|
|
92
|
+
state.selectedBlockId = null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function updateBlock(blockId, updates) {
|
|
96
|
+
if (isBlockLocked(blockId)) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const block = findBlockById(state.content.blocks, blockId);
|
|
100
|
+
if (block) {
|
|
101
|
+
Object.assign(block, updates);
|
|
102
|
+
state.isDirty = true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function updateSettings(updates) {
|
|
106
|
+
state.content.settings = { ...state.content.settings, ...updates };
|
|
107
|
+
state.isDirty = true;
|
|
108
|
+
}
|
|
109
|
+
function addBlock(block, targetSectionId, columnIndex = 0, index) {
|
|
110
|
+
if (targetSectionId) {
|
|
111
|
+
if (isBlockLocked(targetSectionId)) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const section = findBlockById(state.content.blocks, targetSectionId);
|
|
115
|
+
if (section && section.type === "section") {
|
|
116
|
+
section.children[columnIndex] = section.children[columnIndex] || [];
|
|
117
|
+
const targetArray = section.children[columnIndex];
|
|
118
|
+
if (index !== void 0 && index < targetArray.length) {
|
|
119
|
+
targetArray.splice(index, 0, block);
|
|
120
|
+
} else {
|
|
121
|
+
targetArray.push(block);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
if (index !== void 0 && index < state.content.blocks.length) {
|
|
126
|
+
state.content.blocks.splice(index, 0, block);
|
|
127
|
+
} else {
|
|
128
|
+
state.content.blocks.push(block);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
state.isDirty = true;
|
|
132
|
+
}
|
|
133
|
+
function removeBlock(blockId) {
|
|
134
|
+
if (isBlockLocked(blockId)) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const parent = findBlockParent(state.content.blocks, blockId);
|
|
138
|
+
if (parent) {
|
|
139
|
+
const index = parent.blocks.findIndex((b) => b.id === blockId);
|
|
140
|
+
if (index !== -1) {
|
|
141
|
+
parent.blocks.splice(index, 1);
|
|
142
|
+
if (state.selectedBlockId === blockId) {
|
|
143
|
+
state.selectedBlockId = null;
|
|
144
|
+
}
|
|
145
|
+
state.isDirty = true;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function moveBlock(blockId, newIndex, targetSectionId, columnIndex = 0) {
|
|
150
|
+
if (isBlockLocked(blockId)) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (targetSectionId && isBlockLocked(targetSectionId)) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const parent = findBlockParent(state.content.blocks, blockId);
|
|
157
|
+
if (!parent) return;
|
|
158
|
+
const oldIndex = parent.blocks.findIndex((b) => b.id === blockId);
|
|
159
|
+
if (oldIndex === -1) return;
|
|
160
|
+
let targetArray;
|
|
161
|
+
if (targetSectionId) {
|
|
162
|
+
const section = findBlockById(state.content.blocks, targetSectionId);
|
|
163
|
+
if (!section || section.type !== "section") return;
|
|
164
|
+
section.children[columnIndex] = section.children[columnIndex] || [];
|
|
165
|
+
targetArray = section.children[columnIndex];
|
|
166
|
+
} else {
|
|
167
|
+
targetArray = state.content.blocks;
|
|
168
|
+
}
|
|
169
|
+
const [block] = parent.blocks.splice(oldIndex, 1);
|
|
170
|
+
targetArray.splice(newIndex, 0, block);
|
|
171
|
+
state.isDirty = true;
|
|
172
|
+
}
|
|
173
|
+
function markDirty() {
|
|
174
|
+
state.isDirty = true;
|
|
175
|
+
}
|
|
176
|
+
function ensureCanvasPages() {
|
|
177
|
+
if (state.content.canvasPages?.length) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const id = crypto.randomUUID();
|
|
181
|
+
const blocks = state.content.blocks;
|
|
182
|
+
state.content.canvasPages = [{ id, title: "Step 1", blocks }];
|
|
183
|
+
state.content.activeCanvasPageId = id;
|
|
184
|
+
state.content.blocks = blocks;
|
|
185
|
+
state.isDirty = true;
|
|
186
|
+
}
|
|
187
|
+
function switchCanvasPage(pageId) {
|
|
188
|
+
const pages = state.content.canvasPages;
|
|
189
|
+
if (!pages?.length) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const page = pages.find((p) => p.id === pageId);
|
|
193
|
+
if (!page) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
state.selectedBlockId = null;
|
|
197
|
+
state.content.blocks = page.blocks;
|
|
198
|
+
state.content.activeCanvasPageId = pageId;
|
|
199
|
+
state.isDirty = true;
|
|
200
|
+
}
|
|
201
|
+
function addCanvasPage() {
|
|
202
|
+
ensureCanvasPages();
|
|
203
|
+
const pages = state.content.canvasPages;
|
|
204
|
+
const id = crypto.randomUUID();
|
|
205
|
+
const title = `Step ${pages.length + 1}`;
|
|
206
|
+
const newBlocks = [];
|
|
207
|
+
pages.push({ id, title, blocks: newBlocks });
|
|
208
|
+
switchCanvasPage(id);
|
|
209
|
+
}
|
|
210
|
+
function removeCanvasPage(pageId) {
|
|
211
|
+
const pages = state.content.canvasPages;
|
|
212
|
+
if (!pages || pages.length <= 1) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const idx = pages.findIndex((p) => p.id === pageId);
|
|
216
|
+
if (idx === -1) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
pages.splice(idx, 1);
|
|
220
|
+
if (state.content.activeCanvasPageId === pageId) {
|
|
221
|
+
const next = pages[Math.min(idx, pages.length - 1)];
|
|
222
|
+
switchCanvasPage(next.id);
|
|
223
|
+
} else {
|
|
224
|
+
state.content.canvasPages = [...pages];
|
|
225
|
+
state.isDirty = true;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
function renameCanvasPage(pageId, title) {
|
|
229
|
+
const pages = state.content.canvasPages;
|
|
230
|
+
if (!pages) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
const page = pages.find((p) => p.id === pageId);
|
|
234
|
+
if (!page) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
page.title = title.trim() || page.title;
|
|
238
|
+
state.isDirty = true;
|
|
239
|
+
}
|
|
240
|
+
function switchToNextCanvasPage() {
|
|
241
|
+
const pages = state.content.canvasPages;
|
|
242
|
+
if (!pages?.length) {
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
const activeId = state.content.activeCanvasPageId;
|
|
246
|
+
const idx = pages.findIndex((p) => p.id === activeId);
|
|
247
|
+
if (idx === -1 || idx >= pages.length - 1) {
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
switchCanvasPage(pages[idx + 1].id);
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
function switchToPreviousCanvasPage() {
|
|
254
|
+
const pages = state.content.canvasPages;
|
|
255
|
+
if (!pages?.length) {
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
const activeId = state.content.activeCanvasPageId;
|
|
259
|
+
const idx = pages.findIndex((p) => p.id === activeId);
|
|
260
|
+
if (idx <= 0) {
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
switchCanvasPage(pages[idx - 1].id);
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
return {
|
|
267
|
+
state: readonly(state),
|
|
268
|
+
content,
|
|
269
|
+
selectedBlock,
|
|
270
|
+
isBlockLocked,
|
|
271
|
+
setContent,
|
|
272
|
+
selectBlock,
|
|
273
|
+
setViewport,
|
|
274
|
+
setDarkMode,
|
|
275
|
+
setUiTheme,
|
|
276
|
+
setPreviewMode,
|
|
277
|
+
updateBlock,
|
|
278
|
+
updateSettings,
|
|
279
|
+
addBlock,
|
|
280
|
+
removeBlock,
|
|
281
|
+
moveBlock,
|
|
282
|
+
markDirty,
|
|
283
|
+
ensureCanvasPages,
|
|
284
|
+
switchCanvasPage,
|
|
285
|
+
addCanvasPage,
|
|
286
|
+
removeCanvasPage,
|
|
287
|
+
renameCanvasPage,
|
|
288
|
+
switchToNextCanvasPage,
|
|
289
|
+
switchToPreviousCanvasPage
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// src/history.ts
|
|
294
|
+
import { computed as computed2, ref } from "@vue/reactivity";
|
|
295
|
+
var MAX_STACK_SIZE = 50;
|
|
296
|
+
var DEBOUNCE_MS = 300;
|
|
297
|
+
var NAVIGATE_IDLE_MS = 1500;
|
|
298
|
+
function useHistory(options) {
|
|
299
|
+
const {
|
|
300
|
+
content,
|
|
301
|
+
setContent,
|
|
302
|
+
isRemoteOperation,
|
|
303
|
+
maxSize = MAX_STACK_SIZE
|
|
304
|
+
} = options;
|
|
305
|
+
const undoStack = ref([]);
|
|
306
|
+
const redoStack = ref([]);
|
|
307
|
+
const isNavigating = ref(false);
|
|
308
|
+
let navigatingTimeoutId = null;
|
|
309
|
+
let pendingDebounce = null;
|
|
310
|
+
const canUndo = computed2(() => undoStack.value.length > 0);
|
|
311
|
+
const canRedo = computed2(() => redoStack.value.length > 0);
|
|
312
|
+
function cloneContent() {
|
|
313
|
+
return JSON.parse(JSON.stringify(content.value));
|
|
314
|
+
}
|
|
315
|
+
function pushToUndoStack(snapshot) {
|
|
316
|
+
undoStack.value.push(snapshot);
|
|
317
|
+
if (undoStack.value.length > maxSize) {
|
|
318
|
+
undoStack.value.splice(0, undoStack.value.length - maxSize);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function flushPendingDebounce() {
|
|
322
|
+
if (pendingDebounce) {
|
|
323
|
+
clearTimeout(pendingDebounce.timeoutId);
|
|
324
|
+
pendingDebounce = null;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
function record() {
|
|
328
|
+
if (isRemoteOperation?.()) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
flushPendingDebounce();
|
|
332
|
+
pushToUndoStack(cloneContent());
|
|
333
|
+
redoStack.value = [];
|
|
334
|
+
}
|
|
335
|
+
function recordDebounced(blockId) {
|
|
336
|
+
if (isRemoteOperation?.()) {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
if (pendingDebounce && pendingDebounce.blockId === blockId) {
|
|
340
|
+
clearTimeout(pendingDebounce.timeoutId);
|
|
341
|
+
pendingDebounce.timeoutId = setTimeout(() => {
|
|
342
|
+
pendingDebounce = null;
|
|
343
|
+
}, DEBOUNCE_MS);
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
flushPendingDebounce();
|
|
347
|
+
pushToUndoStack(cloneContent());
|
|
348
|
+
redoStack.value = [];
|
|
349
|
+
pendingDebounce = {
|
|
350
|
+
blockId,
|
|
351
|
+
timeoutId: setTimeout(() => {
|
|
352
|
+
pendingDebounce = null;
|
|
353
|
+
}, DEBOUNCE_MS)
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
function setNavigating() {
|
|
357
|
+
isNavigating.value = true;
|
|
358
|
+
if (navigatingTimeoutId) {
|
|
359
|
+
clearTimeout(navigatingTimeoutId);
|
|
360
|
+
}
|
|
361
|
+
navigatingTimeoutId = setTimeout(() => {
|
|
362
|
+
isNavigating.value = false;
|
|
363
|
+
navigatingTimeoutId = null;
|
|
364
|
+
}, NAVIGATE_IDLE_MS);
|
|
365
|
+
}
|
|
366
|
+
function undo() {
|
|
367
|
+
if (undoStack.value.length === 0) {
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
flushPendingDebounce();
|
|
371
|
+
const snapshot = undoStack.value.pop();
|
|
372
|
+
redoStack.value.push(cloneContent());
|
|
373
|
+
setContent(snapshot, true);
|
|
374
|
+
setNavigating();
|
|
375
|
+
}
|
|
376
|
+
function redo() {
|
|
377
|
+
if (redoStack.value.length === 0) {
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
flushPendingDebounce();
|
|
381
|
+
const snapshot = redoStack.value.pop();
|
|
382
|
+
undoStack.value.push(cloneContent());
|
|
383
|
+
setContent(snapshot, true);
|
|
384
|
+
setNavigating();
|
|
385
|
+
}
|
|
386
|
+
function clear() {
|
|
387
|
+
undoStack.value = [];
|
|
388
|
+
redoStack.value = [];
|
|
389
|
+
flushPendingDebounce();
|
|
390
|
+
}
|
|
391
|
+
function destroy() {
|
|
392
|
+
clear();
|
|
393
|
+
if (navigatingTimeoutId) {
|
|
394
|
+
clearTimeout(navigatingTimeoutId);
|
|
395
|
+
navigatingTimeoutId = null;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return {
|
|
399
|
+
canUndo,
|
|
400
|
+
canRedo,
|
|
401
|
+
isNavigating,
|
|
402
|
+
undo,
|
|
403
|
+
redo,
|
|
404
|
+
record,
|
|
405
|
+
recordDebounced,
|
|
406
|
+
clear,
|
|
407
|
+
destroy
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// src/block-actions.ts
|
|
412
|
+
import { createBlock, generateId } from "@aswin.dev/types";
|
|
413
|
+
function useBlockActions(options) {
|
|
414
|
+
const { addBlock, removeBlock, updateBlock, selectBlock } = options;
|
|
415
|
+
function createAndAddBlock(type, targetSectionId, columnIndex) {
|
|
416
|
+
const block = createBlock(type, options.blockDefaults);
|
|
417
|
+
addBlock(block, targetSectionId, columnIndex);
|
|
418
|
+
selectBlock(block.id);
|
|
419
|
+
return block;
|
|
420
|
+
}
|
|
421
|
+
function duplicateBlock(block, targetSectionId, columnIndex) {
|
|
422
|
+
const cloned = JSON.parse(JSON.stringify(block));
|
|
423
|
+
cloned.id = generateId();
|
|
424
|
+
if (cloned.type === "section") {
|
|
425
|
+
cloned.children = cloned.children.map(
|
|
426
|
+
(column) => column.map((child) => {
|
|
427
|
+
const clonedChild = JSON.parse(JSON.stringify(child));
|
|
428
|
+
clonedChild.id = generateId();
|
|
429
|
+
return clonedChild;
|
|
430
|
+
})
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
addBlock(cloned, targetSectionId, columnIndex);
|
|
434
|
+
selectBlock(cloned.id);
|
|
435
|
+
return cloned;
|
|
436
|
+
}
|
|
437
|
+
function deleteBlock(blockId) {
|
|
438
|
+
removeBlock(blockId);
|
|
439
|
+
}
|
|
440
|
+
function updateBlockProperty(blockId, key, value) {
|
|
441
|
+
updateBlock(blockId, { [key]: value });
|
|
442
|
+
}
|
|
443
|
+
return {
|
|
444
|
+
createAndAddBlock,
|
|
445
|
+
duplicateBlock,
|
|
446
|
+
deleteBlock,
|
|
447
|
+
updateBlockProperty
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// src/auto-save.ts
|
|
452
|
+
import { watch } from "@vue/reactivity";
|
|
453
|
+
function useAutoSave(options) {
|
|
454
|
+
const {
|
|
455
|
+
content,
|
|
456
|
+
isDirty,
|
|
457
|
+
onChange,
|
|
458
|
+
debounce = 1e3,
|
|
459
|
+
enabled = true
|
|
460
|
+
} = options;
|
|
461
|
+
let timeoutId = null;
|
|
462
|
+
let paused = false;
|
|
463
|
+
function isEnabled() {
|
|
464
|
+
return typeof enabled === "function" ? enabled() : enabled;
|
|
465
|
+
}
|
|
466
|
+
function pause() {
|
|
467
|
+
paused = true;
|
|
468
|
+
cancel();
|
|
469
|
+
}
|
|
470
|
+
function resume() {
|
|
471
|
+
paused = false;
|
|
472
|
+
}
|
|
473
|
+
function cancel() {
|
|
474
|
+
if (timeoutId) {
|
|
475
|
+
clearTimeout(timeoutId);
|
|
476
|
+
timeoutId = null;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
function flush() {
|
|
480
|
+
cancel();
|
|
481
|
+
if (isDirty()) {
|
|
482
|
+
onChange(JSON.parse(JSON.stringify(content.value)));
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
function scheduleOnChange() {
|
|
486
|
+
if (!isEnabled() || paused) return;
|
|
487
|
+
cancel();
|
|
488
|
+
timeoutId = setTimeout(() => {
|
|
489
|
+
timeoutId = null;
|
|
490
|
+
if (isEnabled() && !paused && isDirty()) {
|
|
491
|
+
onChange(JSON.parse(JSON.stringify(content.value)));
|
|
492
|
+
}
|
|
493
|
+
}, debounce);
|
|
494
|
+
}
|
|
495
|
+
const stopWatch = watch(
|
|
496
|
+
content,
|
|
497
|
+
() => {
|
|
498
|
+
if (isEnabled() && !paused && isDirty()) {
|
|
499
|
+
scheduleOnChange();
|
|
500
|
+
}
|
|
501
|
+
},
|
|
502
|
+
{ deep: true }
|
|
503
|
+
);
|
|
504
|
+
function destroy() {
|
|
505
|
+
stopWatch();
|
|
506
|
+
cancel();
|
|
507
|
+
}
|
|
508
|
+
return {
|
|
509
|
+
flush,
|
|
510
|
+
cancel,
|
|
511
|
+
pause,
|
|
512
|
+
resume,
|
|
513
|
+
destroy
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// src/condition-preview.ts
|
|
518
|
+
import { computed as computed3, reactive as reactive2 } from "@vue/reactivity";
|
|
519
|
+
function useConditionPreview(editor) {
|
|
520
|
+
const hiddenBlockIds = reactive2(/* @__PURE__ */ new Set());
|
|
521
|
+
const hasHiddenBlocks = computed3(() => hiddenBlockIds.size > 0);
|
|
522
|
+
function isHidden(blockId) {
|
|
523
|
+
return hiddenBlockIds.has(blockId);
|
|
524
|
+
}
|
|
525
|
+
function toggleBlock(blockId) {
|
|
526
|
+
if (hiddenBlockIds.has(blockId)) {
|
|
527
|
+
hiddenBlockIds.delete(blockId);
|
|
528
|
+
} else {
|
|
529
|
+
hiddenBlockIds.add(blockId);
|
|
530
|
+
if (editor.state.selectedBlockId === blockId) {
|
|
531
|
+
editor.selectBlock(null);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
function reset() {
|
|
536
|
+
hiddenBlockIds.clear();
|
|
537
|
+
}
|
|
538
|
+
return {
|
|
539
|
+
isHidden,
|
|
540
|
+
toggleBlock,
|
|
541
|
+
reset,
|
|
542
|
+
hasHiddenBlocks
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// src/data-source-fetch.ts
|
|
547
|
+
import { computed as computed4, ref as ref2 } from "@vue/reactivity";
|
|
548
|
+
function useDataSourceFetch(options) {
|
|
549
|
+
const isFetching = ref2(false);
|
|
550
|
+
const fetchError = ref2(false);
|
|
551
|
+
const hasDataSource = computed4(() => !!options.definition.value?.dataSource);
|
|
552
|
+
const needsFetch = computed4(
|
|
553
|
+
() => hasDataSource.value && !options.block.value.dataSourceFetched
|
|
554
|
+
);
|
|
555
|
+
async function fetch() {
|
|
556
|
+
const def = options.definition.value;
|
|
557
|
+
if (!def?.dataSource) {
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
isFetching.value = true;
|
|
561
|
+
fetchError.value = false;
|
|
562
|
+
try {
|
|
563
|
+
const result = await def.dataSource.onFetch({
|
|
564
|
+
fieldValues: { ...options.block.value.fieldValues },
|
|
565
|
+
blockId: options.block.value.id
|
|
566
|
+
});
|
|
567
|
+
if (result == null) {
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
const merged = { ...options.block.value.fieldValues };
|
|
571
|
+
for (const key of Object.keys(merged)) {
|
|
572
|
+
if (key in result) {
|
|
573
|
+
merged[key] = result[key];
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
options.onUpdate(merged, true);
|
|
577
|
+
} catch (error) {
|
|
578
|
+
console.warn("[Templatical] Data source fetch error:", error);
|
|
579
|
+
fetchError.value = true;
|
|
580
|
+
} finally {
|
|
581
|
+
isFetching.value = false;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
return {
|
|
585
|
+
isFetching,
|
|
586
|
+
fetchError,
|
|
587
|
+
fetch,
|
|
588
|
+
hasDataSource,
|
|
589
|
+
needsFetch
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// src/history-interceptor.ts
|
|
594
|
+
function useHistoryInterceptor(editor, history) {
|
|
595
|
+
const originalAddBlock = editor.addBlock;
|
|
596
|
+
const originalRemoveBlock = editor.removeBlock;
|
|
597
|
+
const originalMoveBlock = editor.moveBlock;
|
|
598
|
+
const originalUpdateBlock = editor.updateBlock;
|
|
599
|
+
const originalUpdateSettings = editor.updateSettings;
|
|
600
|
+
editor.addBlock = (block, targetSectionId, columnIndex, index) => {
|
|
601
|
+
if (targetSectionId && editor.isBlockLocked(targetSectionId)) {
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
history.record();
|
|
605
|
+
originalAddBlock(block, targetSectionId, columnIndex, index);
|
|
606
|
+
};
|
|
607
|
+
editor.removeBlock = (blockId) => {
|
|
608
|
+
if (editor.isBlockLocked(blockId)) {
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
history.record();
|
|
612
|
+
originalRemoveBlock(blockId);
|
|
613
|
+
};
|
|
614
|
+
editor.moveBlock = (blockId, newIndex, targetSectionId, columnIndex) => {
|
|
615
|
+
if (editor.isBlockLocked(blockId)) {
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
if (targetSectionId && editor.isBlockLocked(targetSectionId)) {
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
history.record();
|
|
622
|
+
originalMoveBlock(blockId, newIndex, targetSectionId, columnIndex);
|
|
623
|
+
};
|
|
624
|
+
editor.updateBlock = (blockId, updates) => {
|
|
625
|
+
if (editor.isBlockLocked(blockId)) {
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
history.recordDebounced(blockId);
|
|
629
|
+
originalUpdateBlock(blockId, updates);
|
|
630
|
+
};
|
|
631
|
+
editor.updateSettings = (updates) => {
|
|
632
|
+
history.record();
|
|
633
|
+
originalUpdateSettings(updates);
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
export {
|
|
637
|
+
useAutoSave,
|
|
638
|
+
useBlockActions,
|
|
639
|
+
useConditionPreview,
|
|
640
|
+
useDataSourceFetch,
|
|
641
|
+
useEditor,
|
|
642
|
+
useHistory,
|
|
643
|
+
useHistoryInterceptor
|
|
644
|
+
};
|
|
645
|
+
//# sourceMappingURL=index.js.map
|