kritzel-stencil 0.3.22 → 0.3.24
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/cjs/index.cjs.js +3 -1
- package/dist/cjs/kritzel-active-users_45.cjs.entry.js +507 -288
- package/dist/cjs/{schema.constants-IBG5VW_J.js → schema.constants-D8JoUfNc.js} +744 -49
- package/dist/collection/classes/core/core.class.js +83 -5
- package/dist/collection/classes/core/store.class.js +9 -0
- package/dist/collection/classes/handlers/key.handler.js +1 -1
- package/dist/collection/classes/handlers/selection.handler.js +28 -11
- package/dist/collection/classes/objects/base-object.class.js +20 -8
- package/dist/collection/classes/objects/custom-element.class.js +330 -8
- package/dist/collection/classes/objects/image.class.js +0 -1
- package/dist/collection/classes/objects/selection-group.class.js +29 -0
- package/dist/collection/classes/providers/assets/asset-resolver.class.js +24 -14
- package/dist/collection/classes/providers/assets/indexeddb-asset-provider.class.js +0 -8
- package/dist/collection/classes/registries/custom-element-renderer.registry.js +52 -0
- package/dist/collection/classes/structures/app-state-map.structure.js +17 -3
- package/dist/collection/classes/structures/object-map.structure.js +17 -3
- package/dist/collection/classes/tools/selection-tool.class.js +34 -6
- package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +9 -8
- package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +211 -78
- package/dist/collection/components/ui/kritzel-settings/kritzel-settings.js +2 -1
- package/dist/collection/configs/default-engine-config.js +3 -2
- package/dist/collection/constants/version.js +1 -1
- package/dist/collection/helpers/html.helper.js +52 -0
- package/dist/collection/helpers/object.helper.js +3 -0
- package/dist/collection/helpers/svg-export.helper.js +35 -0
- package/dist/collection/helpers/wheel.helper.js +113 -0
- package/dist/collection/index.js +3 -0
- package/dist/collection/interfaces/custom-element-renderer.interface.js +1 -0
- package/dist/components/index.js +1 -1
- package/dist/components/kritzel-awareness-cursors.js +1 -1
- package/dist/components/kritzel-controls.js +1 -1
- package/dist/components/kritzel-current-user-dialog.js +1 -1
- package/dist/components/kritzel-current-user.js +1 -1
- package/dist/components/kritzel-dialog.js +1 -1
- package/dist/components/kritzel-editor.js +1 -1
- package/dist/components/kritzel-engine.js +1 -1
- package/dist/components/kritzel-export.js +1 -1
- package/dist/components/kritzel-login-dialog.js +1 -1
- package/dist/components/kritzel-menu-item.js +1 -1
- package/dist/components/kritzel-menu.js +1 -1
- package/dist/components/kritzel-more-menu.js +1 -1
- package/dist/components/kritzel-portal.js +1 -1
- package/dist/components/kritzel-settings.js +1 -1
- package/dist/components/kritzel-share-dialog.js +1 -1
- package/dist/components/kritzel-split-button.js +1 -1
- package/dist/components/kritzel-tool-config.js +1 -1
- package/dist/components/kritzel-tooltip.js +1 -1
- package/dist/components/kritzel-workspace-manager.js +1 -1
- package/dist/components/{p-BwuemYET.js → p-B4WfPDj0.js} +1 -1
- package/dist/components/{p-BO1CnEOT.js → p-B5XGjTLd.js} +1 -1
- package/dist/components/p-BNu3Akp5.js +1 -0
- package/dist/components/{p-D28ZylHn.js → p-BixEMVtW.js} +1 -1
- package/dist/components/{p-Ndib1Jb3.js → p-BntMEYss.js} +1 -1
- package/dist/components/p-Bz_zj6dQ.js +1 -0
- package/dist/components/{p-BhODnvMO.js → p-CZQz_mul.js} +1 -1
- package/dist/components/{p-COj8EVzL.js → p-Ckpa5tHF.js} +1 -1
- package/dist/components/{p-BPoDE87Q.js → p-DNDt6O6A.js} +1 -1
- package/dist/components/{p-DRsD38Nl.js → p-DPlEzPKO.js} +1 -1
- package/dist/components/{p-C-RiEw9X.js → p-DSd5xTAH.js} +1 -1
- package/dist/components/{p-CHrSFOSI.js → p-DX2nriaq.js} +1 -1
- package/dist/components/{p-BAN5dnHX.js → p-Dd-pMvlr.js} +1 -1
- package/dist/components/{p-CbMLbDou.js → p-Dw-t1qQc.js} +1 -1
- package/dist/components/{p-C5TZjIE1.js → p-M9m9-OEY.js} +1 -1
- package/dist/components/p-WUdQqYnu.js +1 -0
- package/dist/components/{p-YFR180v-.js → p-XDNjFYRB.js} +1 -1
- package/dist/components/{p-CJEIUs0x.js → p-X_pyPCe8.js} +1 -1
- package/dist/components/{p-CpR9lc-o.js → p-meY80XnF.js} +1 -1
- package/dist/components/p-on11Z8cZ.js +9 -0
- package/dist/components/{p-6Ca7Eolf.js → p-y5T0_Wvi.js} +1 -1
- package/dist/esm/index.js +2 -2
- package/dist/esm/kritzel-active-users_45.entry.js +500 -281
- package/dist/esm/{schema.constants-D35cwCYd.js → schema.constants-B3IqnD8l.js} +742 -49
- package/dist/stencil/index.esm.js +1 -1
- package/dist/stencil/p-63bc234f.entry.js +9 -0
- package/dist/stencil/p-B3IqnD8l.js +1 -0
- package/dist/stencil/stencil.esm.js +1 -1
- package/dist/types/classes/core/core.class.d.ts +15 -0
- package/dist/types/classes/core/store.class.d.ts +6 -0
- package/dist/types/classes/objects/base-object.class.d.ts +3 -2
- package/dist/types/classes/objects/custom-element.class.d.ts +87 -21
- package/dist/types/classes/objects/image.class.d.ts +0 -1
- package/dist/types/classes/objects/selection-group.class.d.ts +7 -0
- package/dist/types/classes/providers/assets/asset-resolver.class.d.ts +3 -0
- package/dist/types/classes/providers/assets/indexeddb-asset-provider.class.d.ts +0 -1
- package/dist/types/classes/registries/custom-element-renderer.registry.d.ts +32 -0
- package/dist/types/components/core/kritzel-engine/kritzel-engine.d.ts +7 -1
- package/dist/types/components.d.ts +2 -2
- package/dist/types/constants/version.d.ts +1 -1
- package/dist/types/helpers/html.helper.d.ts +2 -0
- package/dist/types/helpers/object.helper.d.ts +1 -0
- package/dist/types/helpers/svg-export.helper.d.ts +9 -0
- package/dist/types/helpers/wheel.helper.d.ts +9 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/interfaces/asset-storage-config.interface.d.ts +0 -4
- package/dist/types/interfaces/custom-element-renderer.interface.d.ts +40 -0
- package/dist/types/interfaces/debug-info.interface.d.ts +1 -0
- package/dist/types/interfaces/object.interface.d.ts +0 -1
- package/package.json +1 -1
- package/dist/components/p-BML28BJR.js +0 -1
- package/dist/components/p-CVV-HzFR.js +0 -1
- package/dist/components/p-DWhWFDcC.js +0 -9
- package/dist/components/p-Dd_EODkk.js +0 -1
- package/dist/stencil/p-D35cwCYd.js +0 -1
- package/dist/stencil/p-fcbf7965.entry.js +0 -9
|
@@ -186,6 +186,7 @@ export class KritzelCore {
|
|
|
186
186
|
this._clipboardManager = new KritzelClipboardManager(this);
|
|
187
187
|
this._toolRegistry = new KritzelToolRegistry(this);
|
|
188
188
|
this._assetResolver = new KritzelAssetResolver();
|
|
189
|
+
this._assetResolver.setShowInfo(this._store.state.debugInfo?.showAssetResolverInfo ?? false);
|
|
189
190
|
}
|
|
190
191
|
/**
|
|
191
192
|
* Gets the asset resolver responsible for storing and resolving
|
|
@@ -557,6 +558,10 @@ export class KritzelCore {
|
|
|
557
558
|
this.removeObject(child);
|
|
558
559
|
});
|
|
559
560
|
}
|
|
561
|
+
// Unmount custom elements before removal
|
|
562
|
+
if (KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
|
|
563
|
+
object.unmount();
|
|
564
|
+
}
|
|
560
565
|
// Handle anchor cleanup
|
|
561
566
|
if (KritzelClassHelper.isInstanceOf(object, 'KritzelLine')) {
|
|
562
567
|
// If removing a line, clean up its anchor index entries
|
|
@@ -597,21 +602,84 @@ export class KritzelCore {
|
|
|
597
602
|
* @param selectionGroup - The selection group to add
|
|
598
603
|
*/
|
|
599
604
|
addSelectionGroup(selectionGroup) {
|
|
600
|
-
this.
|
|
605
|
+
this.removeLocalSelectionGroups();
|
|
601
606
|
this.removeSelectionBox();
|
|
607
|
+
for (const object of selectionGroup.objects ?? []) {
|
|
608
|
+
if (KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
|
|
609
|
+
const customElementObject = object;
|
|
610
|
+
if (typeof customElementObject.setIsInteractive === 'function') {
|
|
611
|
+
customElementObject.setIsInteractive(true);
|
|
612
|
+
}
|
|
613
|
+
else {
|
|
614
|
+
customElementObject.isInteractive = true;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
602
618
|
this._store.objects.insert(selectionGroup);
|
|
603
619
|
this._store.setSelectionGroup(selectionGroup);
|
|
604
620
|
this._kritzelEngine.triggerSelectionChange();
|
|
605
621
|
}
|
|
622
|
+
/**
|
|
623
|
+
* Returns whether the provided selection group belongs to the local user context.
|
|
624
|
+
* Local groups are either explicitly owned by the current user or have no user ID.
|
|
625
|
+
*/
|
|
626
|
+
isLocalSelectionGroup(selectionGroup) {
|
|
627
|
+
const localUserId = this._user?.id;
|
|
628
|
+
return localUserId == null || selectionGroup.userId === localUserId || selectionGroup.userId == null;
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* Applies deselection teardown side effects to a selection group before removal.
|
|
632
|
+
*/
|
|
633
|
+
teardownSelectionGroup(selectionGroup) {
|
|
634
|
+
selectionGroup.deselectAllChildren?.();
|
|
635
|
+
for (const object of selectionGroup.objects ?? []) {
|
|
636
|
+
if (KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement')) {
|
|
637
|
+
const customElementObject = object;
|
|
638
|
+
if (typeof customElementObject.setIsInteractive === 'function') {
|
|
639
|
+
customElementObject.setIsInteractive(false);
|
|
640
|
+
}
|
|
641
|
+
else {
|
|
642
|
+
customElementObject.isInteractive = false;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* Removes all local selection groups from the store, including orphaned groups
|
|
649
|
+
* that are no longer referenced by store.selectionGroup.
|
|
650
|
+
* @returns True when at least one local selection group was removed
|
|
651
|
+
*/
|
|
652
|
+
removeLocalSelectionGroups() {
|
|
653
|
+
const allSelectionGroupsInStore = this._store.objects
|
|
654
|
+
.allObjects()
|
|
655
|
+
.filter((object) => {
|
|
656
|
+
return object instanceof KritzelSelectionGroup || KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup');
|
|
657
|
+
});
|
|
658
|
+
const allLocalSelectionGroups = allSelectionGroupsInStore.filter(selectionGroup => this.isLocalSelectionGroup(selectionGroup));
|
|
659
|
+
const currentSelectionGroup = this._store.selectionGroup;
|
|
660
|
+
if (currentSelectionGroup &&
|
|
661
|
+
this.isLocalSelectionGroup(currentSelectionGroup) &&
|
|
662
|
+
!allLocalSelectionGroups.some(group => group.id === currentSelectionGroup.id)) {
|
|
663
|
+
allLocalSelectionGroups.push(currentSelectionGroup);
|
|
664
|
+
}
|
|
665
|
+
if (allLocalSelectionGroups.length === 0) {
|
|
666
|
+
return false;
|
|
667
|
+
}
|
|
668
|
+
for (const selectionGroup of allLocalSelectionGroups) {
|
|
669
|
+
this.teardownSelectionGroup(selectionGroup);
|
|
670
|
+
}
|
|
671
|
+
const localSelectionGroupIds = new Set(allLocalSelectionGroups.map(group => group.id));
|
|
672
|
+
this._store.objects.remove(object => localSelectionGroupIds.has(object.id));
|
|
673
|
+
this._store.setSelectionGroup(null);
|
|
674
|
+
return true;
|
|
675
|
+
}
|
|
606
676
|
/**
|
|
607
677
|
* Removes the current selection group from the canvas.
|
|
608
678
|
* Clears the cached reference and triggers the selection change event.
|
|
609
679
|
*/
|
|
610
680
|
removeSelectionGroup() {
|
|
611
|
-
const
|
|
612
|
-
if (
|
|
613
|
-
this._store.objects.remove(object => object.id === selectionGroup.id);
|
|
614
|
-
this._store.setSelectionGroup(null);
|
|
681
|
+
const removedAnySelectionGroup = this.removeLocalSelectionGroups();
|
|
682
|
+
if (removedAnySelectionGroup) {
|
|
615
683
|
this._kritzelEngine.triggerSelectionChange();
|
|
616
684
|
}
|
|
617
685
|
}
|
|
@@ -915,6 +983,11 @@ export class KritzelCore {
|
|
|
915
983
|
(o instanceof KritzelSelectionGroup && (localUserId == null || o.userId === localUserId || o.userId == null)));
|
|
916
984
|
this._store.setSelectionBox(null);
|
|
917
985
|
this._store.setSelectionGroup(null);
|
|
986
|
+
for (const object of this._store.allNonSelectionObjects) {
|
|
987
|
+
if (object.isSelected) {
|
|
988
|
+
object.isSelected = false;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
918
991
|
this._store.state.isSelecting = false;
|
|
919
992
|
this._store.state.isResizeHandleSelected = false;
|
|
920
993
|
this._store.state.isRotationHandleSelected = false;
|
|
@@ -1077,6 +1150,11 @@ export class KritzelCore {
|
|
|
1077
1150
|
// During selection phase (no group yet), hide UI for KritzelLine objects
|
|
1078
1151
|
return !(object instanceof KritzelLine);
|
|
1079
1152
|
}
|
|
1153
|
+
// Once a local selection group exists, only the selection-group object
|
|
1154
|
+
// should render group UI (children remain selected but don't render handles).
|
|
1155
|
+
if (!(object instanceof KritzelSelectionGroup) || object.id !== selectionGroup.id) {
|
|
1156
|
+
return false;
|
|
1157
|
+
}
|
|
1080
1158
|
// Show UI if selection contains more than one object
|
|
1081
1159
|
if (selectionGroup.objects.length > 1) {
|
|
1082
1160
|
return true;
|
|
@@ -4,6 +4,7 @@ import { KritzelText } from "../objects/text.class";
|
|
|
4
4
|
import { KritzelShape } from "../objects/shape.class";
|
|
5
5
|
import { KritzelPath } from "../objects/path.class";
|
|
6
6
|
import { KritzelLine } from "../objects/line.class";
|
|
7
|
+
import { KritzelClassHelper } from "../../helpers/class.helper";
|
|
7
8
|
import { KritzelObjectMap } from "../structures/object-map.structure";
|
|
8
9
|
/**
|
|
9
10
|
* Central state management store for the Kritzel engine.
|
|
@@ -222,6 +223,14 @@ export class KritzelStore {
|
|
|
222
223
|
const activeShapes = this.objects.filter(o => o instanceof KritzelShape && o.isEditing);
|
|
223
224
|
return activeShapes.length > 0 ? activeShapes[0] : null;
|
|
224
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* Gets the currently selected custom element whose focused descendant is an input-like element.
|
|
228
|
+
* @returns The interactive custom element with focused input-like content, or null if none matches
|
|
229
|
+
*/
|
|
230
|
+
get activeInteractiveCustomElement() {
|
|
231
|
+
const interactiveCustomElement = this.selectedObjects.find(object => KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement') && object.hasFocusedInputElement());
|
|
232
|
+
return interactiveCustomElement ?? null;
|
|
233
|
+
}
|
|
225
234
|
/**
|
|
226
235
|
* Gets the path currently being drawn (not yet completed).
|
|
227
236
|
* @returns The incomplete path object, or null if no path is being drawn
|
|
@@ -129,7 +129,7 @@ export class KritzelKeyHandler extends KritzelBaseHandler {
|
|
|
129
129
|
// of running global canvas shortcuts. Escape is the one exception — it
|
|
130
130
|
// still runs through the shortcut system so it can collapse the text
|
|
131
131
|
// selection (handled inside the shortcut's action).
|
|
132
|
-
if ((this._core.store.activeText || this._core.store.activeShape) && event.key !== 'Escape') {
|
|
132
|
+
if ((this._core.store.activeText || this._core.store.activeShape || this._core.store.activeInteractiveCustomElement) && event.key !== 'Escape') {
|
|
133
133
|
return;
|
|
134
134
|
}
|
|
135
135
|
const shortcut = this.shortcuts.find(s => s.key === event.key && !!s.ctrl === event.ctrlKey && !!s.shift === event.shiftKey && (!s.condition || s.condition(this._core)));
|
|
@@ -178,10 +178,9 @@ export class KritzelSelectionHandler extends KritzelBaseHandler {
|
|
|
178
178
|
selectionBox.translateX = this.startX;
|
|
179
179
|
selectionBox.translateY = this.startY;
|
|
180
180
|
this._core.store.state.isSelecting = true;
|
|
181
|
-
this._core.
|
|
182
|
-
this._core.store.setSelectionBox(null);
|
|
181
|
+
this._core.removeSelectionBox();
|
|
183
182
|
if (!isAdditive) {
|
|
184
|
-
this._core.
|
|
183
|
+
this._core.removeSelectionGroup();
|
|
185
184
|
}
|
|
186
185
|
this._core.store.objects.insert(selectionBox);
|
|
187
186
|
this._core.store.setSelectionBox(selectionBox);
|
|
@@ -210,10 +209,9 @@ export class KritzelSelectionHandler extends KritzelBaseHandler {
|
|
|
210
209
|
selectionBox.translateX = this.startX;
|
|
211
210
|
selectionBox.translateY = this.startY;
|
|
212
211
|
this._core.store.state.isSelecting = true;
|
|
213
|
-
this._core.
|
|
214
|
-
this._core.store.setSelectionBox(null);
|
|
212
|
+
this._core.removeSelectionBox();
|
|
215
213
|
if (!isAdditive) {
|
|
216
|
-
this._core.
|
|
214
|
+
this._core.removeSelectionGroup();
|
|
217
215
|
}
|
|
218
216
|
this._core.store.objects.insert(selectionBox);
|
|
219
217
|
this._core.store.setSelectionBox(selectionBox);
|
|
@@ -383,8 +381,11 @@ export class KritzelSelectionHandler extends KritzelBaseHandler {
|
|
|
383
381
|
*/
|
|
384
382
|
clearSelectionPreview() {
|
|
385
383
|
// Only clear previously tracked selected objects - O(k) instead of O(n)
|
|
384
|
+
const selectedGroupIds = new Set(this._core.store.selectionGroup?.objectIds ?? []);
|
|
386
385
|
for (const obj of this._previouslySelectedObjects) {
|
|
387
|
-
obj.
|
|
386
|
+
if (!selectedGroupIds.has(obj.id)) {
|
|
387
|
+
obj.isSelected = false;
|
|
388
|
+
}
|
|
388
389
|
}
|
|
389
390
|
this._previouslySelectedObjects.clear();
|
|
390
391
|
}
|
|
@@ -403,7 +404,11 @@ export class KritzelSelectionHandler extends KritzelBaseHandler {
|
|
|
403
404
|
// Resolve child objects to their parent groups
|
|
404
405
|
const parentGroup = KritzelGroup.findParentGroup(this._core, object.id);
|
|
405
406
|
const objectToSelect = parentGroup || object;
|
|
406
|
-
|
|
407
|
+
// When the click resolves to a parent group, clear the child's own flag so
|
|
408
|
+
// it does not linger as selected and re-select the group on the next interaction.
|
|
409
|
+
if (parentGroup) {
|
|
410
|
+
object.isSelected = false;
|
|
411
|
+
}
|
|
407
412
|
const existingGroup = this._core.store.selectionGroup;
|
|
408
413
|
if (shiftKey && existingGroup) {
|
|
409
414
|
existingGroup.addOrRemove(objectToSelect);
|
|
@@ -448,9 +453,16 @@ export class KritzelSelectionHandler extends KritzelBaseHandler {
|
|
|
448
453
|
const resolvedObjects = new Map();
|
|
449
454
|
for (const obj of selectedObjects) {
|
|
450
455
|
const parentGroup = childToParentMap.get(obj.id);
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
456
|
+
if (parentGroup) {
|
|
457
|
+
// The child was selected (e.g. via marquee preview) but selection is
|
|
458
|
+
// represented by its parent group. Clear the child's flag so it does
|
|
459
|
+
// not linger as selected and re-select the group on the next interaction.
|
|
460
|
+
obj.isSelected = false;
|
|
461
|
+
resolvedObjects.set(parentGroup.id, parentGroup);
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
resolvedObjects.set(obj.id, obj);
|
|
465
|
+
}
|
|
454
466
|
}
|
|
455
467
|
const unrolledObjects = Array.from(resolvedObjects.values());
|
|
456
468
|
const filteredObjects = this.filterDescendantsOfSelectedGroups(unrolledObjects);
|
|
@@ -458,12 +470,16 @@ export class KritzelSelectionHandler extends KritzelBaseHandler {
|
|
|
458
470
|
if (shiftKey && existingGroup) {
|
|
459
471
|
existingGroup.addObjects(filteredObjects);
|
|
460
472
|
this.removeDescendantsOfSelectedGroups(existingGroup);
|
|
473
|
+
this._previouslySelectedObjects.clear();
|
|
461
474
|
this._core.rerender();
|
|
462
475
|
}
|
|
463
476
|
else {
|
|
464
477
|
// Create selection group and set all IDs at once (no per-item refresh)
|
|
465
478
|
const selectionGroup = KritzelSelectionGroup.create(this._core);
|
|
466
479
|
selectionGroup.objectIds = filteredObjects.map(o => o.id);
|
|
480
|
+
filteredObjects.forEach(obj => {
|
|
481
|
+
obj.isSelected = true;
|
|
482
|
+
});
|
|
467
483
|
// Only refresh dimensions and capture snapshots ONCE at the end - O(n) instead of O(n²)
|
|
468
484
|
if (selectionGroup.length === 1) {
|
|
469
485
|
selectionGroup.rotation = selectionGroup.objects[0].rotation;
|
|
@@ -472,6 +488,7 @@ export class KritzelSelectionHandler extends KritzelBaseHandler {
|
|
|
472
488
|
selectionGroup.refreshObjectDimensions();
|
|
473
489
|
selectionGroup.isSelected = true;
|
|
474
490
|
this._core.addSelectionGroup(selectionGroup);
|
|
491
|
+
this._previouslySelectedObjects.clear();
|
|
475
492
|
this._core.rerender();
|
|
476
493
|
}
|
|
477
494
|
}
|
|
@@ -36,7 +36,8 @@ export class KritzelBaseObject {
|
|
|
36
36
|
isMounted = false;
|
|
37
37
|
isEditable = false;
|
|
38
38
|
isInteractive = false;
|
|
39
|
-
|
|
39
|
+
isResizable = true;
|
|
40
|
+
isRotatable = true;
|
|
40
41
|
/**
|
|
41
42
|
* Gets the total width of the object including padding.
|
|
42
43
|
* @returns The width plus double the padding value
|
|
@@ -344,21 +345,24 @@ export class KritzelBaseObject {
|
|
|
344
345
|
Object.assign(copiedObject, this);
|
|
345
346
|
copiedObject.id = this.generateId();
|
|
346
347
|
copiedObject.isMounted = false;
|
|
348
|
+
copiedObject.isSelected = false;
|
|
349
|
+
copiedObject.isHovered = false;
|
|
350
|
+
copiedObject.isInteractive = false;
|
|
351
|
+
copiedObject.resizing = false;
|
|
352
|
+
copiedObject.markedForRemoval = false;
|
|
353
|
+
copiedObject.isVisible = true;
|
|
347
354
|
return copiedObject;
|
|
348
355
|
}
|
|
349
356
|
/**
|
|
350
357
|
* Serializes the object to a plain JavaScript object for persistence.
|
|
351
358
|
* Excludes internal references (_core, _elementRef) and computed properties.
|
|
352
|
-
*
|
|
359
|
+
* Subclasses should override to handle domain-specific serialization (e.g., HTML elements).
|
|
353
360
|
* @returns A serializable object containing all persistent properties
|
|
354
361
|
*/
|
|
355
362
|
serialize() {
|
|
356
|
-
const { _core, _elementRef, element, totalWidth, totalHeight, ...remainingProps } = this;
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
clonedProps.element = element.cloneNode(true);
|
|
360
|
-
}
|
|
361
|
-
return clonedProps;
|
|
363
|
+
const { _core, _elementRef, element, totalWidth, totalHeight, isSelected, isHovered, isMounted, isInteractive, resizing, markedForRemoval, isVisible, ...remainingProps } = this;
|
|
364
|
+
// No longer clone raw elements—let subclasses handle serializable payloads
|
|
365
|
+
return structuredClone(remainingProps);
|
|
362
366
|
}
|
|
363
367
|
/**
|
|
364
368
|
* Restores the object's state from a serialized plain object.
|
|
@@ -369,6 +373,14 @@ export class KritzelBaseObject {
|
|
|
369
373
|
*/
|
|
370
374
|
deserialize(object) {
|
|
371
375
|
Object.assign(this, object);
|
|
376
|
+
// Selection/interactivity state is transient UI state and must not survive revival.
|
|
377
|
+
this.isSelected = false;
|
|
378
|
+
this.isHovered = false;
|
|
379
|
+
this.isMounted = false;
|
|
380
|
+
this.isInteractive = false;
|
|
381
|
+
this.resizing = false;
|
|
382
|
+
this.markedForRemoval = false;
|
|
383
|
+
this.isVisible = true;
|
|
372
384
|
return this;
|
|
373
385
|
}
|
|
374
386
|
/**
|