dynim-core 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -282
- package/dist/builder/builder-client.d.ts +1 -5
- package/dist/builder/builder-client.d.ts.map +1 -1
- package/dist/builder/builder-client.js +2 -22
- package/dist/builder/builder.d.ts +0 -4
- package/dist/builder/builder.d.ts.map +1 -1
- package/dist/builder/builder.js +64 -207
- package/dist/builder/editor-overlays.d.ts +1 -10
- package/dist/builder/editor-overlays.d.ts.map +1 -1
- package/dist/builder/editor-overlays.js +1 -103
- package/dist/builder/editor-state.d.ts +2 -21
- package/dist/builder/editor-state.d.ts.map +1 -1
- package/dist/builder/editor-state.js +2 -34
- package/dist/builder/element-utils.d.ts +0 -11
- package/dist/builder/element-utils.d.ts.map +1 -1
- package/dist/builder/element-utils.js +0 -58
- package/dist/builder/freeze-overlay.d.ts +1 -1
- package/dist/builder/freeze-overlay.d.ts.map +1 -1
- package/dist/builder/freeze-overlay.js +1 -2
- package/dist/builder/index.d.ts +5 -9
- package/dist/builder/index.d.ts.map +1 -1
- package/dist/builder/index.js +3 -7
- package/dist/builder/{drag-engine.d.ts → interaction-engine.d.ts} +6 -20
- package/dist/builder/interaction-engine.d.ts.map +1 -0
- package/dist/builder/interaction-engine.js +101 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/README.md +10 -0
- package/src/styles/builder.css +1 -189
- package/src/styles/editor.css +2 -61
- package/dist/builder/diff-state.d.ts +0 -24
- package/dist/builder/diff-state.d.ts.map +0 -1
- package/dist/builder/diff-state.js +0 -134
- package/dist/builder/drag-engine.d.ts.map +0 -1
- package/dist/builder/drag-engine.js +0 -686
- package/dist/builder/history-state.d.ts +0 -41
- package/dist/builder/history-state.d.ts.map +0 -1
- package/dist/builder/history-state.js +0 -76
package/dist/builder/builder.js
CHANGED
|
@@ -5,30 +5,26 @@
|
|
|
5
5
|
import { createState } from './state';
|
|
6
6
|
import { createWidget } from './widget';
|
|
7
7
|
import { createEditorState } from './editor-state';
|
|
8
|
-
import { createHistoryState } from './history-state';
|
|
9
|
-
import { createDiffState } from './diff-state';
|
|
10
8
|
import { createTreeState } from './tree-state';
|
|
11
9
|
import { createFreezeOverlay } from './freeze-overlay';
|
|
12
10
|
import { createOverlays } from './editor-overlays';
|
|
13
|
-
import {
|
|
11
|
+
import { createInteractionEngine } from './interaction-engine';
|
|
14
12
|
import { scanDOM } from './dom-scanner';
|
|
15
13
|
import { createAIPromptPopover } from './ai-prompt-popover';
|
|
16
14
|
import { createCodeClient } from './code-client';
|
|
17
15
|
import { createBuilderClient } from './builder-client';
|
|
18
16
|
import { buildElementIdentifier, getRelevantStyles } from './element-utils';
|
|
19
17
|
export function createBuilder(config = {}) {
|
|
20
|
-
const { logo = 'Builder',
|
|
18
|
+
const { logo = 'Builder', onExit, onEnter, chatConfig = {}, contentRoot = document.body, pageId = window.location.pathname, apiBase = 'http://localhost:8080', sessionToken, refreshToken, getSession, codeClient: externalCodeClient } = config;
|
|
21
19
|
let isActive = false;
|
|
22
20
|
let chatWidget = null;
|
|
23
21
|
let state = null;
|
|
24
22
|
let client = null;
|
|
25
23
|
let editorState = null;
|
|
26
|
-
let historyState = null;
|
|
27
|
-
let diffState = null;
|
|
28
24
|
let treeState = null;
|
|
29
25
|
let freezeOverlay = null;
|
|
30
26
|
let overlays = null;
|
|
31
|
-
let
|
|
27
|
+
let interactionEngine = null;
|
|
32
28
|
let aiPromptPopover = null;
|
|
33
29
|
const root = document.createElement('div');
|
|
34
30
|
root.className = 'builder';
|
|
@@ -42,20 +38,15 @@ export function createBuilder(config = {}) {
|
|
|
42
38
|
</div>
|
|
43
39
|
<div class="builder-bar__divider"></div>
|
|
44
40
|
<div class="builder-bar__actions">
|
|
45
|
-
<button class="builder-bar__btn builder-bar__btn--
|
|
46
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor">
|
|
47
|
-
<path d="M12.5 8c-2.65 0-5.05.99-6.9 2.6L2 7v9h9l-3.62-3.62c1.39-1.16 3.16-1.88 5.12-1.88 3.54 0 6.55 2.31 7.6 5.5l2.37-.78C21.08 11.03 17.15 8 12.5 8z"/>
|
|
48
|
-
</svg>
|
|
49
|
-
</button>
|
|
50
|
-
<button class="builder-bar__btn builder-bar__btn--preview" title="Preview">
|
|
41
|
+
<button class="builder-bar__btn builder-bar__btn--preview">
|
|
51
42
|
<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor">
|
|
52
43
|
<path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"/>
|
|
53
44
|
</svg>
|
|
54
45
|
Preview
|
|
55
46
|
</button>
|
|
56
|
-
<button class="builder-bar__btn builder-bar__btn--save"
|
|
47
|
+
<button class="builder-bar__btn builder-bar__btn--save">
|
|
57
48
|
<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor">
|
|
58
|
-
<path d="
|
|
49
|
+
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/>
|
|
59
50
|
</svg>
|
|
60
51
|
Save
|
|
61
52
|
</button>
|
|
@@ -67,23 +58,7 @@ export function createBuilder(config = {}) {
|
|
|
67
58
|
</button>
|
|
68
59
|
</div>
|
|
69
60
|
</div>
|
|
70
|
-
|
|
71
|
-
<div class="builder-modal" style="display: none;">
|
|
72
|
-
<div class="builder-modal__backdrop"></div>
|
|
73
|
-
<div class="builder-modal__dialog">
|
|
74
|
-
<div class="builder-modal__title">Unsaved Changes</div>
|
|
75
|
-
<div class="builder-modal__message">You have unsaved changes. What would you like to do?</div>
|
|
76
|
-
<div class="builder-modal__actions">
|
|
77
|
-
<button class="builder-modal__btn builder-modal__btn--cancel">Cancel</button>
|
|
78
|
-
<button class="builder-modal__btn builder-modal__btn--discard">Discard Changes</button>
|
|
79
|
-
<button class="builder-modal__btn builder-modal__btn--save">Save & Exit</button>
|
|
80
|
-
</div>
|
|
81
|
-
</div>
|
|
82
|
-
</div>
|
|
83
61
|
`;
|
|
84
|
-
const saveBtn = root.querySelector('.builder-bar__btn--save');
|
|
85
|
-
const undoBtn = root.querySelector('.builder-bar__btn--undo');
|
|
86
|
-
const modal = root.querySelector('.builder-modal');
|
|
87
62
|
let builderClient = null;
|
|
88
63
|
// Track unsubscribe function for external client
|
|
89
64
|
let unsubscribeFromClient = null;
|
|
@@ -162,35 +137,11 @@ export function createBuilder(config = {}) {
|
|
|
162
137
|
}
|
|
163
138
|
});
|
|
164
139
|
}
|
|
165
|
-
function updateButtonStates() {
|
|
166
|
-
if (!historyState)
|
|
167
|
-
return;
|
|
168
|
-
// Show/hide undo button contextually
|
|
169
|
-
const canUndo = historyState.canUndo();
|
|
170
|
-
undoBtn.style.display = canUndo ? 'flex' : 'none';
|
|
171
|
-
const hasActualChanges = diffState ? diffState.getDiff().length > 0 : false;
|
|
172
|
-
saveBtn.disabled = !hasActualChanges;
|
|
173
|
-
if (hasActualChanges) {
|
|
174
|
-
saveBtn.style.background = '#3b82f6';
|
|
175
|
-
saveBtn.style.color = '#ffffff';
|
|
176
|
-
saveBtn.style.opacity = '1';
|
|
177
|
-
saveBtn.style.cursor = 'pointer';
|
|
178
|
-
saveBtn.style.pointerEvents = 'auto';
|
|
179
|
-
}
|
|
180
|
-
else {
|
|
181
|
-
saveBtn.style.background = 'rgba(100, 116, 139, 0.5)';
|
|
182
|
-
saveBtn.style.color = 'rgba(255, 255, 255, 0.4)';
|
|
183
|
-
saveBtn.style.opacity = '1';
|
|
184
|
-
saveBtn.style.cursor = 'not-allowed';
|
|
185
|
-
saveBtn.style.pointerEvents = 'none';
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
140
|
function performScan() {
|
|
189
141
|
const tree = scanDOM(contentRoot);
|
|
190
142
|
if (tree) {
|
|
191
143
|
treeState?.setTree(tree);
|
|
192
144
|
}
|
|
193
|
-
updateButtonStates();
|
|
194
145
|
}
|
|
195
146
|
function enter() {
|
|
196
147
|
if (isActive)
|
|
@@ -199,36 +150,28 @@ export function createBuilder(config = {}) {
|
|
|
199
150
|
root.classList.add('builder--active');
|
|
200
151
|
document.body.classList.add('builder-mode-active');
|
|
201
152
|
editorState = createEditorState();
|
|
202
|
-
historyState = createHistoryState();
|
|
203
|
-
diffState = createDiffState();
|
|
204
153
|
treeState = createTreeState();
|
|
205
|
-
diffState.snapshotInitialState(contentRoot);
|
|
206
|
-
historyState.subscribe(updateButtonStates);
|
|
207
154
|
overlays = createOverlays();
|
|
208
155
|
overlays.mount();
|
|
209
|
-
|
|
156
|
+
interactionEngine = createInteractionEngine({
|
|
210
157
|
contentRoot,
|
|
211
158
|
editorState,
|
|
212
|
-
historyState,
|
|
213
|
-
diffState,
|
|
214
|
-
treeState,
|
|
215
159
|
overlays,
|
|
216
160
|
freezeOverlay: null,
|
|
217
|
-
onRescan: performScan
|
|
218
161
|
});
|
|
219
162
|
freezeOverlay = createFreezeOverlay({
|
|
220
163
|
contentRoot,
|
|
221
|
-
onMouseDown: (e, el) =>
|
|
222
|
-
onMouseMove: (e, el) =>
|
|
223
|
-
onMouseUp: (e, el) =>
|
|
224
|
-
onMouseLeave: (e) =>
|
|
225
|
-
onClick: (e, el) =>
|
|
226
|
-
onDoubleClick: (e, el) =>
|
|
227
|
-
onWheel: (e) =>
|
|
164
|
+
onMouseDown: (e, el) => interactionEngine?.handleMouseDown(e, el),
|
|
165
|
+
onMouseMove: (e, el) => interactionEngine?.handleMouseMove(e, el),
|
|
166
|
+
onMouseUp: (e, el) => interactionEngine?.handleMouseUp(e, el),
|
|
167
|
+
onMouseLeave: (e) => interactionEngine?.handleMouseLeave(e),
|
|
168
|
+
onClick: (e, el) => interactionEngine?.handleClick(e, el),
|
|
169
|
+
onDoubleClick: (e, el) => interactionEngine?.handleDoubleClick(e, el),
|
|
170
|
+
onWheel: (e) => interactionEngine?.handleWheel(e)
|
|
228
171
|
});
|
|
229
172
|
freezeOverlay.mount();
|
|
230
|
-
|
|
231
|
-
|
|
173
|
+
interactionEngine.setFreezeOverlay(freezeOverlay);
|
|
174
|
+
interactionEngine.attach();
|
|
232
175
|
aiPromptPopover = createAIPromptPopover({
|
|
233
176
|
onSubmit: (prompt) => {
|
|
234
177
|
const selectedEl = editorState?.getState().selectedElement;
|
|
@@ -272,35 +215,23 @@ export function createBuilder(config = {}) {
|
|
|
272
215
|
}
|
|
273
216
|
});
|
|
274
217
|
aiPromptPopover.mount();
|
|
275
|
-
let chatWasOpenBeforeDrag = false;
|
|
276
218
|
let chatWasOpenBeforeSelection = false;
|
|
277
219
|
editorState.subscribe((newState, prevState) => {
|
|
278
220
|
if (chatWidget) {
|
|
279
|
-
const dragStarted = newState.isDragging && !prevState?.isDragging;
|
|
280
|
-
const dragEnded = !newState.isDragging && prevState?.isDragging;
|
|
281
|
-
if (dragStarted) {
|
|
282
|
-
chatWasOpenBeforeDrag = chatWidget.isOpen();
|
|
283
|
-
if (chatWasOpenBeforeDrag) {
|
|
284
|
-
chatWidget.close();
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
else if (dragEnded && chatWasOpenBeforeDrag) {
|
|
288
|
-
chatWidget.open();
|
|
289
|
-
}
|
|
290
221
|
const selectionStarted = newState.selectedElement && !prevState?.selectedElement;
|
|
291
222
|
const selectionEnded = !newState.selectedElement && prevState?.selectedElement;
|
|
292
|
-
if (selectionStarted
|
|
223
|
+
if (selectionStarted) {
|
|
293
224
|
chatWasOpenBeforeSelection = chatWidget.isOpen();
|
|
294
225
|
if (chatWasOpenBeforeSelection) {
|
|
295
226
|
chatWidget.close();
|
|
296
227
|
}
|
|
297
228
|
}
|
|
298
|
-
else if (selectionEnded && chatWasOpenBeforeSelection
|
|
229
|
+
else if (selectionEnded && chatWasOpenBeforeSelection) {
|
|
299
230
|
chatWidget.open();
|
|
300
231
|
chatWasOpenBeforeSelection = false;
|
|
301
232
|
}
|
|
302
233
|
}
|
|
303
|
-
if (newState.selectedElement && newState.selectionRect
|
|
234
|
+
if (newState.selectedElement && newState.selectionRect) {
|
|
304
235
|
aiPromptPopover?.show(newState.selectionRect);
|
|
305
236
|
}
|
|
306
237
|
else {
|
|
@@ -312,10 +243,10 @@ export function createBuilder(config = {}) {
|
|
|
312
243
|
state = createState();
|
|
313
244
|
state.addMessage({
|
|
314
245
|
role: 'assistant',
|
|
315
|
-
text: 'Hi! I\'m here to help you build. Select an element by clicking on it
|
|
246
|
+
text: 'Hi! I\'m here to help you build. Select an element by clicking on it to make changes.'
|
|
316
247
|
});
|
|
317
248
|
initCodeClient(state);
|
|
318
|
-
initBuilderClient();
|
|
249
|
+
initBuilderClient();
|
|
319
250
|
// Pre-warm the cache for faster chat responses (projectId comes from JWT)
|
|
320
251
|
if (client) {
|
|
321
252
|
client.warmCache();
|
|
@@ -351,22 +282,18 @@ export function createBuilder(config = {}) {
|
|
|
351
282
|
onEnter?.();
|
|
352
283
|
}
|
|
353
284
|
function cleanup() {
|
|
354
|
-
modal.style.display = 'none';
|
|
355
285
|
root.classList.remove('builder--active');
|
|
356
286
|
document.body.classList.remove('builder-mode-active');
|
|
357
|
-
|
|
287
|
+
interactionEngine?.detach();
|
|
358
288
|
aiPromptPopover?.unmount();
|
|
359
289
|
overlays?.unmount();
|
|
360
290
|
freezeOverlay?.unmount();
|
|
361
|
-
|
|
291
|
+
interactionEngine = null;
|
|
362
292
|
aiPromptPopover = null;
|
|
363
293
|
overlays = null;
|
|
364
294
|
freezeOverlay = null;
|
|
365
295
|
editorState = null;
|
|
366
|
-
historyState = null;
|
|
367
|
-
diffState = null;
|
|
368
296
|
treeState = null;
|
|
369
|
-
undoBtn.style.display = 'none';
|
|
370
297
|
if (chatWidget) {
|
|
371
298
|
chatWidget.close();
|
|
372
299
|
chatWidget.root.style.display = 'none';
|
|
@@ -377,7 +304,7 @@ export function createBuilder(config = {}) {
|
|
|
377
304
|
if (!isActive)
|
|
378
305
|
return;
|
|
379
306
|
isActive = false;
|
|
380
|
-
// Notify server of exit
|
|
307
|
+
// Notify server of exit
|
|
381
308
|
if (builderClient) {
|
|
382
309
|
try {
|
|
383
310
|
await builderClient.exit(pageId, true);
|
|
@@ -387,115 +314,69 @@ export function createBuilder(config = {}) {
|
|
|
387
314
|
console.error('[Builder] Exit notification failed:', error);
|
|
388
315
|
}
|
|
389
316
|
}
|
|
390
|
-
while (historyState?.canUndo()) {
|
|
391
|
-
dragEngine?.executeUndo();
|
|
392
|
-
}
|
|
393
317
|
cleanup();
|
|
394
318
|
}
|
|
395
|
-
async function
|
|
396
|
-
|
|
397
|
-
|
|
319
|
+
async function handlePreview() {
|
|
320
|
+
if (!builderClient) {
|
|
321
|
+
console.error('[Builder] Builder client not initialized');
|
|
398
322
|
return;
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
const result = await builderClient.saveDiffs(pageId, diffs);
|
|
407
|
-
console.log('[Builder] Save result:', result);
|
|
408
|
-
}
|
|
409
|
-
catch (error) {
|
|
410
|
-
console.error('[Builder] Save failed:', error);
|
|
323
|
+
}
|
|
324
|
+
try {
|
|
325
|
+
console.log('[Builder] Requesting preview...');
|
|
326
|
+
const result = await builderClient.preview(pageId);
|
|
327
|
+
console.log('[Builder] Preview result:', result);
|
|
328
|
+
if (result.previewUrl) {
|
|
329
|
+
window.open(result.previewUrl, '_blank');
|
|
411
330
|
}
|
|
412
331
|
}
|
|
413
|
-
|
|
414
|
-
console.
|
|
332
|
+
catch (error) {
|
|
333
|
+
console.error('[Builder] Preview failed:', error);
|
|
415
334
|
}
|
|
416
|
-
onSave?.(diffs);
|
|
417
|
-
cleanup();
|
|
418
335
|
}
|
|
419
|
-
async function
|
|
420
|
-
if (!
|
|
336
|
+
async function handleSave() {
|
|
337
|
+
if (!client) {
|
|
338
|
+
console.error('[Builder] Code client not initialized');
|
|
421
339
|
return;
|
|
422
|
-
const diffs = diffState?.getDiff() || [];
|
|
423
|
-
console.log('[Builder] Preview called, diffs:', diffs.length);
|
|
424
|
-
if (builderClient) {
|
|
425
|
-
try {
|
|
426
|
-
const result = await builderClient.preview(pageId, diffs);
|
|
427
|
-
console.log('[Builder] Preview result:', result);
|
|
428
|
-
// TODO: Handle preview result (e.g., open preview URL, toggle preview mode)
|
|
429
|
-
if (result.previewUrl) {
|
|
430
|
-
window.open(result.previewUrl, '_blank');
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
catch (error) {
|
|
434
|
-
console.error('[Builder] Preview failed:', error);
|
|
435
|
-
}
|
|
436
340
|
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
341
|
+
try {
|
|
342
|
+
console.log('[Builder] Saving code edits...');
|
|
343
|
+
await client.saveCode();
|
|
344
|
+
console.log('[Builder] Save complete');
|
|
345
|
+
// Visual feedback - briefly show saved state
|
|
346
|
+
const saveBtn = root.querySelector('.builder-bar__btn--save');
|
|
347
|
+
if (saveBtn) {
|
|
348
|
+
saveBtn.classList.add('builder-bar__btn--saved');
|
|
349
|
+
saveBtn.textContent = 'Saved!';
|
|
350
|
+
setTimeout(() => {
|
|
351
|
+
saveBtn.classList.remove('builder-bar__btn--saved');
|
|
352
|
+
saveBtn.innerHTML = `
|
|
353
|
+
<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor">
|
|
354
|
+
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/>
|
|
355
|
+
</svg>
|
|
356
|
+
Save
|
|
357
|
+
`;
|
|
358
|
+
}, 2000);
|
|
359
|
+
}
|
|
452
360
|
}
|
|
453
|
-
|
|
454
|
-
|
|
361
|
+
catch (error) {
|
|
362
|
+
console.error('[Builder] Save failed:', error);
|
|
455
363
|
}
|
|
456
364
|
}
|
|
457
365
|
root.addEventListener('click', (e) => {
|
|
458
366
|
const target = e.target;
|
|
459
367
|
if (target.closest('.builder-bar__btn--exit')) {
|
|
460
368
|
e.stopPropagation();
|
|
461
|
-
handleExitClick();
|
|
462
|
-
return;
|
|
463
|
-
}
|
|
464
|
-
if (target.closest('.builder-bar__btn--save')) {
|
|
465
|
-
e.stopPropagation();
|
|
466
|
-
save();
|
|
467
|
-
return;
|
|
468
|
-
}
|
|
469
|
-
if (target.closest('.builder-bar__btn--preview')) {
|
|
470
|
-
e.stopPropagation();
|
|
471
|
-
preview();
|
|
472
|
-
return;
|
|
473
|
-
}
|
|
474
|
-
if (target.closest('.builder-bar__btn--undo')) {
|
|
475
|
-
e.stopPropagation();
|
|
476
|
-
dragEngine?.executeUndo();
|
|
477
|
-
return;
|
|
478
|
-
}
|
|
479
|
-
if (target.closest('.builder-modal__btn--cancel')) {
|
|
480
|
-
e.stopPropagation();
|
|
481
|
-
hideModal();
|
|
482
|
-
return;
|
|
483
|
-
}
|
|
484
|
-
if (target.closest('.builder-modal__btn--discard')) {
|
|
485
|
-
e.stopPropagation();
|
|
486
|
-
hideModal();
|
|
487
369
|
exit();
|
|
488
370
|
return;
|
|
489
371
|
}
|
|
490
|
-
if (target.closest('.builder-
|
|
372
|
+
if (target.closest('.builder-bar__btn--preview')) {
|
|
491
373
|
e.stopPropagation();
|
|
492
|
-
|
|
493
|
-
save();
|
|
374
|
+
handlePreview();
|
|
494
375
|
return;
|
|
495
376
|
}
|
|
496
|
-
if (target.closest('.builder-
|
|
377
|
+
if (target.closest('.builder-bar__btn--save')) {
|
|
497
378
|
e.stopPropagation();
|
|
498
|
-
|
|
379
|
+
handleSave();
|
|
499
380
|
return;
|
|
500
381
|
}
|
|
501
382
|
});
|
|
@@ -504,38 +385,14 @@ export function createBuilder(config = {}) {
|
|
|
504
385
|
if (target.closest('.builder-bar__btn--exit')) {
|
|
505
386
|
e.preventDefault();
|
|
506
387
|
e.stopPropagation();
|
|
507
|
-
handleExitClick();
|
|
508
|
-
}
|
|
509
|
-
else if (target.closest('.builder-bar__btn--save') && !saveBtn.disabled) {
|
|
510
|
-
e.preventDefault();
|
|
511
|
-
e.stopPropagation();
|
|
512
|
-
save();
|
|
513
|
-
}
|
|
514
|
-
else if (target.closest('.builder-modal__btn--discard')) {
|
|
515
|
-
e.preventDefault();
|
|
516
|
-
e.stopPropagation();
|
|
517
|
-
hideModal();
|
|
518
388
|
exit();
|
|
519
389
|
}
|
|
520
|
-
else if (target.closest('.builder-modal__btn--save')) {
|
|
521
|
-
e.preventDefault();
|
|
522
|
-
e.stopPropagation();
|
|
523
|
-
hideModal();
|
|
524
|
-
save();
|
|
525
|
-
}
|
|
526
|
-
else if (target.closest('.builder-modal__btn--cancel')) {
|
|
527
|
-
e.preventDefault();
|
|
528
|
-
e.stopPropagation();
|
|
529
|
-
hideModal();
|
|
530
|
-
}
|
|
531
390
|
}, true);
|
|
532
391
|
document.body.appendChild(root);
|
|
533
392
|
return {
|
|
534
393
|
enter,
|
|
535
394
|
exit,
|
|
536
|
-
save,
|
|
537
395
|
isActive: () => isActive,
|
|
538
|
-
getChanges: () => diffState?.getDiff() || [],
|
|
539
396
|
getEditorState: () => editorState?.getState(),
|
|
540
397
|
getTreeState: () => treeState?.getState(),
|
|
541
398
|
destroy: () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Visual overlays for the editor
|
|
3
|
-
* Hover highlight, selection box,
|
|
3
|
+
* Hover highlight, selection box, and tooltip
|
|
4
4
|
* Uses CSS classes with !important to prevent Dark Reader interference
|
|
5
5
|
*/
|
|
6
6
|
export interface OverlaysConfig {
|
|
@@ -14,15 +14,6 @@ export interface Overlays {
|
|
|
14
14
|
hideHover: () => void;
|
|
15
15
|
showSelection: (rect: DOMRect | null) => void;
|
|
16
16
|
hideSelection: () => void;
|
|
17
|
-
showDragGhost: (sourceRect: DOMRect | null, cursorPos: {
|
|
18
|
-
x: number;
|
|
19
|
-
y: number;
|
|
20
|
-
} | null, grabOffsetX?: number | null, grabOffsetY?: number | null) => void;
|
|
21
|
-
hideDragGhost: () => void;
|
|
22
|
-
showDropIndicator: (targetRect: DOMRect | null, position: string | null, parentRect?: DOMRect | null) => void;
|
|
23
|
-
hideDropIndicator: () => void;
|
|
24
|
-
showNoDropIndicator: (rect: DOMRect | null) => void;
|
|
25
|
-
hideNoDropIndicator: () => void;
|
|
26
17
|
showTooltip: (text: string | null, rect: DOMRect | null) => void;
|
|
27
18
|
hideTooltip: () => void;
|
|
28
19
|
hideAll: () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor-overlays.d.ts","sourceRoot":"","sources":["../../src/builder/editor-overlays.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,cAAc,CAAC;IAC1B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC;IAC1C,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,aAAa,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC;IAC9C,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,
|
|
1
|
+
{"version":3,"file":"editor-overlays.d.ts","sourceRoot":"","sources":["../../src/builder/editor-overlays.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,cAAc,CAAC;IAC1B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC;IAC1C,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,aAAa,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC;IAC9C,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC;IACjE,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AASD,wBAAgB,cAAc,CAAC,MAAM,GAAE,cAAmB,GAAG,QAAQ,CAuGpE"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Visual overlays for the editor
|
|
3
|
-
* Hover highlight, selection box,
|
|
3
|
+
* Hover highlight, selection box, and tooltip
|
|
4
4
|
* Uses CSS classes with !important to prevent Dark Reader interference
|
|
5
5
|
*/
|
|
6
6
|
function createOverlayElement(className) {
|
|
@@ -21,20 +21,10 @@ export function createOverlays(config = {}) {
|
|
|
21
21
|
`;
|
|
22
22
|
const hoverOverlay = createOverlayElement('editor-hover-overlay');
|
|
23
23
|
const selectionOverlay = createOverlayElement('editor-selection-overlay');
|
|
24
|
-
const dragGhost = createOverlayElement('editor-drag-ghost');
|
|
25
|
-
const dropLine = createOverlayElement('editor-drop-line');
|
|
26
|
-
const dropTarget = createOverlayElement('editor-drop-target');
|
|
27
|
-
const parentHighlight = createOverlayElement('editor-parent-highlight');
|
|
28
24
|
const tooltip = createOverlayElement('editor-tooltip');
|
|
29
|
-
const noDropIndicator = createOverlayElement('editor-no-drop-indicator');
|
|
30
25
|
container.appendChild(hoverOverlay);
|
|
31
26
|
container.appendChild(selectionOverlay);
|
|
32
|
-
container.appendChild(dragGhost);
|
|
33
|
-
container.appendChild(dropTarget);
|
|
34
|
-
container.appendChild(parentHighlight);
|
|
35
|
-
container.appendChild(dropLine);
|
|
36
27
|
container.appendChild(tooltip);
|
|
37
|
-
container.appendChild(noDropIndicator);
|
|
38
28
|
function mount() {
|
|
39
29
|
document.body.appendChild(container);
|
|
40
30
|
}
|
|
@@ -73,89 +63,6 @@ export function createOverlays(config = {}) {
|
|
|
73
63
|
selectionOverlay.classList.remove('active');
|
|
74
64
|
selectionOverlay.style.display = 'none';
|
|
75
65
|
}
|
|
76
|
-
function showDragGhost(sourceRect, cursorPos, grabOffsetX = null, grabOffsetY = null) {
|
|
77
|
-
if (!sourceRect || !cursorPos) {
|
|
78
|
-
hideDragGhost();
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
const ghostX = grabOffsetX !== null ? cursorPos.x - grabOffsetX : cursorPos.x - sourceRect.width / 2;
|
|
82
|
-
const ghostY = grabOffsetY !== null ? cursorPos.y - grabOffsetY : cursorPos.y - sourceRect.height / 2;
|
|
83
|
-
dragGhost.style.left = `${ghostX}px`;
|
|
84
|
-
dragGhost.style.top = `${ghostY}px`;
|
|
85
|
-
dragGhost.style.width = `${sourceRect.width}px`;
|
|
86
|
-
dragGhost.style.height = `${sourceRect.height}px`;
|
|
87
|
-
dragGhost.style.display = 'block';
|
|
88
|
-
dragGhost.classList.add('active');
|
|
89
|
-
}
|
|
90
|
-
function hideDragGhost() {
|
|
91
|
-
dragGhost.classList.remove('active');
|
|
92
|
-
dragGhost.style.display = 'none';
|
|
93
|
-
}
|
|
94
|
-
function showDropIndicator(targetRect, position, _parentRect) {
|
|
95
|
-
if (!targetRect || !position) {
|
|
96
|
-
hideDropIndicator();
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
dropTarget.style.left = `${targetRect.x}px`;
|
|
100
|
-
dropTarget.style.top = `${targetRect.y}px`;
|
|
101
|
-
dropTarget.style.width = `${targetRect.width}px`;
|
|
102
|
-
dropTarget.style.height = `${targetRect.height}px`;
|
|
103
|
-
dropTarget.style.display = 'block';
|
|
104
|
-
dropTarget.classList.add('active');
|
|
105
|
-
parentHighlight.classList.remove('active');
|
|
106
|
-
parentHighlight.style.display = 'none';
|
|
107
|
-
const lineThickness = 4;
|
|
108
|
-
if (position === 'top') {
|
|
109
|
-
dropLine.style.left = `${targetRect.x}px`;
|
|
110
|
-
dropLine.style.top = `${targetRect.y - lineThickness / 2}px`;
|
|
111
|
-
dropLine.style.width = `${targetRect.width}px`;
|
|
112
|
-
dropLine.style.height = `${lineThickness}px`;
|
|
113
|
-
}
|
|
114
|
-
else if (position === 'bottom') {
|
|
115
|
-
dropLine.style.left = `${targetRect.x}px`;
|
|
116
|
-
dropLine.style.top = `${targetRect.y + targetRect.height - lineThickness / 2}px`;
|
|
117
|
-
dropLine.style.width = `${targetRect.width}px`;
|
|
118
|
-
dropLine.style.height = `${lineThickness}px`;
|
|
119
|
-
}
|
|
120
|
-
else if (position === 'left') {
|
|
121
|
-
dropLine.style.left = `${targetRect.x - lineThickness / 2}px`;
|
|
122
|
-
dropLine.style.top = `${targetRect.y}px`;
|
|
123
|
-
dropLine.style.width = `${lineThickness}px`;
|
|
124
|
-
dropLine.style.height = `${targetRect.height}px`;
|
|
125
|
-
}
|
|
126
|
-
else if (position === 'right') {
|
|
127
|
-
dropLine.style.left = `${targetRect.x + targetRect.width - lineThickness / 2}px`;
|
|
128
|
-
dropLine.style.top = `${targetRect.y}px`;
|
|
129
|
-
dropLine.style.width = `${lineThickness}px`;
|
|
130
|
-
dropLine.style.height = `${targetRect.height}px`;
|
|
131
|
-
}
|
|
132
|
-
dropLine.style.display = 'block';
|
|
133
|
-
dropLine.classList.add('active');
|
|
134
|
-
}
|
|
135
|
-
function hideDropIndicator() {
|
|
136
|
-
dropTarget.classList.remove('active');
|
|
137
|
-
dropTarget.style.display = 'none';
|
|
138
|
-
dropLine.classList.remove('active');
|
|
139
|
-
dropLine.style.display = 'none';
|
|
140
|
-
parentHighlight.classList.remove('active');
|
|
141
|
-
parentHighlight.style.display = 'none';
|
|
142
|
-
}
|
|
143
|
-
function showNoDropIndicator(rect) {
|
|
144
|
-
if (!rect) {
|
|
145
|
-
hideNoDropIndicator();
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
noDropIndicator.style.left = `${rect.x}px`;
|
|
149
|
-
noDropIndicator.style.top = `${rect.y}px`;
|
|
150
|
-
noDropIndicator.style.width = `${rect.width}px`;
|
|
151
|
-
noDropIndicator.style.height = `${rect.height}px`;
|
|
152
|
-
noDropIndicator.style.display = 'block';
|
|
153
|
-
noDropIndicator.classList.add('active');
|
|
154
|
-
}
|
|
155
|
-
function hideNoDropIndicator() {
|
|
156
|
-
noDropIndicator.classList.remove('active');
|
|
157
|
-
noDropIndicator.style.display = 'none';
|
|
158
|
-
}
|
|
159
66
|
function showTooltip(text, rect) {
|
|
160
67
|
if (!text || !rect) {
|
|
161
68
|
hideTooltip();
|
|
@@ -176,9 +83,6 @@ export function createOverlays(config = {}) {
|
|
|
176
83
|
function hideAll() {
|
|
177
84
|
hideHover();
|
|
178
85
|
hideSelection();
|
|
179
|
-
hideDragGhost();
|
|
180
|
-
hideDropIndicator();
|
|
181
|
-
hideNoDropIndicator();
|
|
182
86
|
hideTooltip();
|
|
183
87
|
}
|
|
184
88
|
return {
|
|
@@ -189,12 +93,6 @@ export function createOverlays(config = {}) {
|
|
|
189
93
|
hideHover,
|
|
190
94
|
showSelection,
|
|
191
95
|
hideSelection,
|
|
192
|
-
showDragGhost,
|
|
193
|
-
hideDragGhost,
|
|
194
|
-
showDropIndicator,
|
|
195
|
-
hideDropIndicator,
|
|
196
|
-
showNoDropIndicator,
|
|
197
|
-
hideNoDropIndicator,
|
|
198
96
|
showTooltip,
|
|
199
97
|
hideTooltip,
|
|
200
98
|
hideAll
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Editor state management - Selection
|
|
3
|
-
* Uses event emitters for framework-agnostic reactivity
|
|
2
|
+
* Editor state management - Selection and hover state
|
|
3
|
+
* Uses event emitters for framework-agnostic reactivity
|
|
4
4
|
*/
|
|
5
|
-
export interface DropIndicator {
|
|
6
|
-
rect: DOMRect;
|
|
7
|
-
position: string;
|
|
8
|
-
parentRect?: DOMRect | null;
|
|
9
|
-
}
|
|
10
5
|
export interface EditorStateData {
|
|
11
6
|
selectedIds: string[];
|
|
12
7
|
primarySelectedId: string | null;
|
|
@@ -17,14 +12,6 @@ export interface EditorStateData {
|
|
|
17
12
|
hoveredElement: HTMLElement | null;
|
|
18
13
|
drillDepth: number;
|
|
19
14
|
isMultiSelectActive: boolean;
|
|
20
|
-
isDragging: boolean;
|
|
21
|
-
dragSourceElement: HTMLElement | null;
|
|
22
|
-
dragSourceRect: DOMRect | null;
|
|
23
|
-
dragGhostPos: {
|
|
24
|
-
x: number;
|
|
25
|
-
y: number;
|
|
26
|
-
} | null;
|
|
27
|
-
dropIndicator: DropIndicator | null;
|
|
28
15
|
}
|
|
29
16
|
export type EditorStateListener = (state: EditorStateData, prevState?: EditorStateData) => void;
|
|
30
17
|
export interface EditorState {
|
|
@@ -39,12 +26,6 @@ export interface EditorState {
|
|
|
39
26
|
clearHover: () => void;
|
|
40
27
|
incrementDrillDepth: () => void;
|
|
41
28
|
resetDrillDepth: () => void;
|
|
42
|
-
startDrag: (element: HTMLElement, rect: DOMRect) => void;
|
|
43
|
-
updateDrag: (ghostPos: {
|
|
44
|
-
x: number;
|
|
45
|
-
y: number;
|
|
46
|
-
} | null, dropIndicator: DropIndicator | null) => void;
|
|
47
|
-
endDrag: () => void;
|
|
48
29
|
}
|
|
49
30
|
export declare function createEditorState(initialState?: Partial<EditorStateData>): EditorState;
|
|
50
31
|
//# sourceMappingURL=editor-state.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor-state.d.ts","sourceRoot":"","sources":["../../src/builder/editor-state.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"editor-state.d.ts","sourceRoot":"","sources":["../../src/builder/editor-state.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,aAAa,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,WAAW,GAAG,IAAI,CAAC;IACpC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,cAAc,EAAE,WAAW,GAAG,IAAI,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,MAAM,mBAAmB,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,SAAS,CAAC,EAAE,eAAe,KAAK,IAAI,CAAC;AAEhG,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,eAAe,CAAC;IAChC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC;IACtD,SAAS,EAAE,CAAC,QAAQ,EAAE,mBAAmB,KAAK,MAAM,IAAI,CAAC;IACzD,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACxC,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,YAAY,EAAE,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC;IAC1E,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC;IACzF,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAChC,eAAe,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED,wBAAgB,iBAAiB,CAAC,YAAY,GAAE,OAAO,CAAC,eAAe,CAAM,GAAG,WAAW,CA4G1F"}
|