dynim-core 1.0.4 → 1.0.5
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 +21 -232
- 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 +0 -192
- 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,23 +38,6 @@ 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--undo" title="Undo (Cmd+Z)" style="display: none;">
|
|
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">
|
|
51
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor">
|
|
52
|
-
<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
|
-
</svg>
|
|
54
|
-
Preview
|
|
55
|
-
</button>
|
|
56
|
-
<button class="builder-bar__btn builder-bar__btn--save" title="Save changes" disabled style="background: rgba(100, 116, 139, 0.5); color: rgba(255, 255, 255, 0.4); cursor: not-allowed; pointer-events: none;">
|
|
57
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor">
|
|
58
|
-
<path d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"/>
|
|
59
|
-
</svg>
|
|
60
|
-
Save
|
|
61
|
-
</button>
|
|
62
41
|
<button class="builder-bar__btn builder-bar__btn--exit">
|
|
63
42
|
<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor">
|
|
64
43
|
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
|
|
@@ -67,23 +46,7 @@ export function createBuilder(config = {}) {
|
|
|
67
46
|
</button>
|
|
68
47
|
</div>
|
|
69
48
|
</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
49
|
`;
|
|
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
50
|
let builderClient = null;
|
|
88
51
|
// Track unsubscribe function for external client
|
|
89
52
|
let unsubscribeFromClient = null;
|
|
@@ -162,35 +125,11 @@ export function createBuilder(config = {}) {
|
|
|
162
125
|
}
|
|
163
126
|
});
|
|
164
127
|
}
|
|
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
128
|
function performScan() {
|
|
189
129
|
const tree = scanDOM(contentRoot);
|
|
190
130
|
if (tree) {
|
|
191
131
|
treeState?.setTree(tree);
|
|
192
132
|
}
|
|
193
|
-
updateButtonStates();
|
|
194
133
|
}
|
|
195
134
|
function enter() {
|
|
196
135
|
if (isActive)
|
|
@@ -199,36 +138,28 @@ export function createBuilder(config = {}) {
|
|
|
199
138
|
root.classList.add('builder--active');
|
|
200
139
|
document.body.classList.add('builder-mode-active');
|
|
201
140
|
editorState = createEditorState();
|
|
202
|
-
historyState = createHistoryState();
|
|
203
|
-
diffState = createDiffState();
|
|
204
141
|
treeState = createTreeState();
|
|
205
|
-
diffState.snapshotInitialState(contentRoot);
|
|
206
|
-
historyState.subscribe(updateButtonStates);
|
|
207
142
|
overlays = createOverlays();
|
|
208
143
|
overlays.mount();
|
|
209
|
-
|
|
144
|
+
interactionEngine = createInteractionEngine({
|
|
210
145
|
contentRoot,
|
|
211
146
|
editorState,
|
|
212
|
-
historyState,
|
|
213
|
-
diffState,
|
|
214
|
-
treeState,
|
|
215
147
|
overlays,
|
|
216
148
|
freezeOverlay: null,
|
|
217
|
-
onRescan: performScan
|
|
218
149
|
});
|
|
219
150
|
freezeOverlay = createFreezeOverlay({
|
|
220
151
|
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) =>
|
|
152
|
+
onMouseDown: (e, el) => interactionEngine?.handleMouseDown(e, el),
|
|
153
|
+
onMouseMove: (e, el) => interactionEngine?.handleMouseMove(e, el),
|
|
154
|
+
onMouseUp: (e, el) => interactionEngine?.handleMouseUp(e, el),
|
|
155
|
+
onMouseLeave: (e) => interactionEngine?.handleMouseLeave(e),
|
|
156
|
+
onClick: (e, el) => interactionEngine?.handleClick(e, el),
|
|
157
|
+
onDoubleClick: (e, el) => interactionEngine?.handleDoubleClick(e, el),
|
|
158
|
+
onWheel: (e) => interactionEngine?.handleWheel(e)
|
|
228
159
|
});
|
|
229
160
|
freezeOverlay.mount();
|
|
230
|
-
|
|
231
|
-
|
|
161
|
+
interactionEngine.setFreezeOverlay(freezeOverlay);
|
|
162
|
+
interactionEngine.attach();
|
|
232
163
|
aiPromptPopover = createAIPromptPopover({
|
|
233
164
|
onSubmit: (prompt) => {
|
|
234
165
|
const selectedEl = editorState?.getState().selectedElement;
|
|
@@ -272,35 +203,23 @@ export function createBuilder(config = {}) {
|
|
|
272
203
|
}
|
|
273
204
|
});
|
|
274
205
|
aiPromptPopover.mount();
|
|
275
|
-
let chatWasOpenBeforeDrag = false;
|
|
276
206
|
let chatWasOpenBeforeSelection = false;
|
|
277
207
|
editorState.subscribe((newState, prevState) => {
|
|
278
208
|
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
209
|
const selectionStarted = newState.selectedElement && !prevState?.selectedElement;
|
|
291
210
|
const selectionEnded = !newState.selectedElement && prevState?.selectedElement;
|
|
292
|
-
if (selectionStarted
|
|
211
|
+
if (selectionStarted) {
|
|
293
212
|
chatWasOpenBeforeSelection = chatWidget.isOpen();
|
|
294
213
|
if (chatWasOpenBeforeSelection) {
|
|
295
214
|
chatWidget.close();
|
|
296
215
|
}
|
|
297
216
|
}
|
|
298
|
-
else if (selectionEnded && chatWasOpenBeforeSelection
|
|
217
|
+
else if (selectionEnded && chatWasOpenBeforeSelection) {
|
|
299
218
|
chatWidget.open();
|
|
300
219
|
chatWasOpenBeforeSelection = false;
|
|
301
220
|
}
|
|
302
221
|
}
|
|
303
|
-
if (newState.selectedElement && newState.selectionRect
|
|
222
|
+
if (newState.selectedElement && newState.selectionRect) {
|
|
304
223
|
aiPromptPopover?.show(newState.selectionRect);
|
|
305
224
|
}
|
|
306
225
|
else {
|
|
@@ -312,10 +231,10 @@ export function createBuilder(config = {}) {
|
|
|
312
231
|
state = createState();
|
|
313
232
|
state.addMessage({
|
|
314
233
|
role: 'assistant',
|
|
315
|
-
text: 'Hi! I\'m here to help you build. Select an element by clicking on it
|
|
234
|
+
text: 'Hi! I\'m here to help you build. Select an element by clicking on it to make changes.'
|
|
316
235
|
});
|
|
317
236
|
initCodeClient(state);
|
|
318
|
-
initBuilderClient();
|
|
237
|
+
initBuilderClient();
|
|
319
238
|
// Pre-warm the cache for faster chat responses (projectId comes from JWT)
|
|
320
239
|
if (client) {
|
|
321
240
|
client.warmCache();
|
|
@@ -351,22 +270,18 @@ export function createBuilder(config = {}) {
|
|
|
351
270
|
onEnter?.();
|
|
352
271
|
}
|
|
353
272
|
function cleanup() {
|
|
354
|
-
modal.style.display = 'none';
|
|
355
273
|
root.classList.remove('builder--active');
|
|
356
274
|
document.body.classList.remove('builder-mode-active');
|
|
357
|
-
|
|
275
|
+
interactionEngine?.detach();
|
|
358
276
|
aiPromptPopover?.unmount();
|
|
359
277
|
overlays?.unmount();
|
|
360
278
|
freezeOverlay?.unmount();
|
|
361
|
-
|
|
279
|
+
interactionEngine = null;
|
|
362
280
|
aiPromptPopover = null;
|
|
363
281
|
overlays = null;
|
|
364
282
|
freezeOverlay = null;
|
|
365
283
|
editorState = null;
|
|
366
|
-
historyState = null;
|
|
367
|
-
diffState = null;
|
|
368
284
|
treeState = null;
|
|
369
|
-
undoBtn.style.display = 'none';
|
|
370
285
|
if (chatWidget) {
|
|
371
286
|
chatWidget.close();
|
|
372
287
|
chatWidget.root.style.display = 'none';
|
|
@@ -377,7 +292,7 @@ export function createBuilder(config = {}) {
|
|
|
377
292
|
if (!isActive)
|
|
378
293
|
return;
|
|
379
294
|
isActive = false;
|
|
380
|
-
// Notify server of exit
|
|
295
|
+
// Notify server of exit
|
|
381
296
|
if (builderClient) {
|
|
382
297
|
try {
|
|
383
298
|
await builderClient.exit(pageId, true);
|
|
@@ -387,155 +302,29 @@ export function createBuilder(config = {}) {
|
|
|
387
302
|
console.error('[Builder] Exit notification failed:', error);
|
|
388
303
|
}
|
|
389
304
|
}
|
|
390
|
-
while (historyState?.canUndo()) {
|
|
391
|
-
dragEngine?.executeUndo();
|
|
392
|
-
}
|
|
393
305
|
cleanup();
|
|
394
306
|
}
|
|
395
|
-
async function save() {
|
|
396
|
-
console.log('[Builder] Save called, isActive:', isActive);
|
|
397
|
-
if (!isActive)
|
|
398
|
-
return;
|
|
399
|
-
isActive = false;
|
|
400
|
-
const diffs = diffState?.getDiff() || [];
|
|
401
|
-
console.log('[Builder] Diffs count:', diffs.length);
|
|
402
|
-
console.log('[Builder] builderClient exists:', !!builderClient);
|
|
403
|
-
if (builderClient && diffs.length > 0) {
|
|
404
|
-
try {
|
|
405
|
-
console.log('[Builder] Saving diffs to backend:', { pageId, diffs });
|
|
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);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
else {
|
|
414
|
-
console.log('[Builder] Skipping save - no client or no diffs');
|
|
415
|
-
}
|
|
416
|
-
onSave?.(diffs);
|
|
417
|
-
cleanup();
|
|
418
|
-
}
|
|
419
|
-
async function preview() {
|
|
420
|
-
if (!isActive)
|
|
421
|
-
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
|
-
}
|
|
437
|
-
}
|
|
438
|
-
function showModal() {
|
|
439
|
-
modal.style.display = '';
|
|
440
|
-
}
|
|
441
|
-
function hideModal() {
|
|
442
|
-
modal.style.display = 'none';
|
|
443
|
-
}
|
|
444
|
-
function hasUnsavedChanges() {
|
|
445
|
-
const hasDiffs = diffState ? diffState.getDiff().length > 0 : false;
|
|
446
|
-
const hasHistory = historyState ? historyState.canUndo() : false;
|
|
447
|
-
return hasDiffs || hasHistory;
|
|
448
|
-
}
|
|
449
|
-
function handleExitClick() {
|
|
450
|
-
if (hasUnsavedChanges()) {
|
|
451
|
-
showModal();
|
|
452
|
-
}
|
|
453
|
-
else {
|
|
454
|
-
exit();
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
307
|
root.addEventListener('click', (e) => {
|
|
458
308
|
const target = e.target;
|
|
459
309
|
if (target.closest('.builder-bar__btn--exit')) {
|
|
460
310
|
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
311
|
exit();
|
|
488
312
|
return;
|
|
489
313
|
}
|
|
490
|
-
if (target.closest('.builder-modal__btn--save')) {
|
|
491
|
-
e.stopPropagation();
|
|
492
|
-
hideModal();
|
|
493
|
-
save();
|
|
494
|
-
return;
|
|
495
|
-
}
|
|
496
|
-
if (target.closest('.builder-modal__backdrop')) {
|
|
497
|
-
e.stopPropagation();
|
|
498
|
-
hideModal();
|
|
499
|
-
return;
|
|
500
|
-
}
|
|
501
314
|
});
|
|
502
315
|
document.addEventListener('click', (e) => {
|
|
503
316
|
const target = e.target;
|
|
504
317
|
if (target.closest('.builder-bar__btn--exit')) {
|
|
505
318
|
e.preventDefault();
|
|
506
319
|
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
320
|
exit();
|
|
519
321
|
}
|
|
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
322
|
}, true);
|
|
532
323
|
document.body.appendChild(root);
|
|
533
324
|
return {
|
|
534
325
|
enter,
|
|
535
326
|
exit,
|
|
536
|
-
save,
|
|
537
327
|
isActive: () => isActive,
|
|
538
|
-
getChanges: () => diffState?.getDiff() || [],
|
|
539
328
|
getEditorState: () => editorState?.getState(),
|
|
540
329
|
getTreeState: () => treeState?.getState(),
|
|
541
330
|
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"}
|