kritzel-stencil 0.0.162 → 0.0.163
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/{default-line-tool.config-D1Ns0NmM.js → default-line-tool.config-DJMYrkSu.js} +340 -9
- package/dist/cjs/default-line-tool.config-DJMYrkSu.js.map +1 -0
- package/dist/cjs/index.cjs.js +1 -1
- package/dist/cjs/kritzel-color_22.cjs.entry.js +761 -28
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/stencil.cjs.js +1 -1
- package/dist/collection/classes/core/core.class.js +19 -3
- package/dist/collection/classes/core/core.class.js.map +1 -1
- package/dist/collection/classes/core/reviver.class.js +16 -0
- package/dist/collection/classes/core/reviver.class.js.map +1 -1
- package/dist/collection/classes/core/store.class.js +5 -0
- package/dist/collection/classes/core/store.class.js.map +1 -1
- package/dist/collection/classes/core/viewport.class.js +8 -0
- package/dist/collection/classes/core/viewport.class.js.map +1 -1
- package/dist/collection/classes/managers/anchor.manager.js +181 -3
- package/dist/collection/classes/managers/anchor.manager.js.map +1 -1
- package/dist/collection/classes/objects/path.class.js +85 -0
- package/dist/collection/classes/objects/path.class.js.map +1 -1
- package/dist/collection/classes/objects/shape.class.js +372 -0
- package/dist/collection/classes/objects/shape.class.js.map +1 -0
- package/dist/collection/classes/registries/icon-registry.class.js +4 -0
- package/dist/collection/classes/registries/icon-registry.class.js.map +1 -1
- package/dist/collection/classes/tools/brush-tool.class.js +2 -2
- package/dist/collection/classes/tools/brush-tool.class.js.map +1 -1
- package/dist/collection/classes/tools/line-tool.class.js +2 -2
- package/dist/collection/classes/tools/line-tool.class.js.map +1 -1
- package/dist/collection/classes/tools/shape-tool.class.js +204 -0
- package/dist/collection/classes/tools/shape-tool.class.js.map +1 -0
- package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +17 -6
- package/dist/collection/components/core/kritzel-editor/kritzel-editor.js.map +1 -1
- package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +44 -8
- package/dist/collection/components/core/kritzel-engine/kritzel-engine.js.map +1 -1
- package/dist/collection/components/ui/kritzel-controls/kritzel-controls.css +143 -5
- package/dist/collection/components/ui/kritzel-controls/kritzel-controls.js +76 -12
- package/dist/collection/components/ui/kritzel-controls/kritzel-controls.js.map +1 -1
- package/dist/collection/configs/default-engine-config.js +1 -1
- package/dist/collection/configs/default-engine-config.js.map +1 -1
- package/dist/collection/configs/default-shape-tool.config.js +26 -0
- package/dist/collection/configs/default-shape-tool.config.js.map +1 -0
- package/dist/collection/enums/shape-type.enum.js +7 -0
- package/dist/collection/enums/shape-type.enum.js.map +1 -0
- package/dist/collection/helpers/geometry.helper.js +55 -0
- package/dist/collection/helpers/geometry.helper.js.map +1 -1
- package/dist/collection/interfaces/toolbar-control.interface.js.map +1 -1
- package/dist/components/index.js +3 -3
- package/dist/components/kritzel-brush-style.js +1 -1
- package/dist/components/kritzel-context-menu.js +1 -1
- package/dist/components/kritzel-control-brush-config.js +1 -1
- package/dist/components/kritzel-control-text-config.js +1 -1
- package/dist/components/kritzel-controls.js +1 -1
- package/dist/components/kritzel-editor.js +49 -16
- package/dist/components/kritzel-editor.js.map +1 -1
- package/dist/components/kritzel-engine.js +1 -1
- package/dist/components/kritzel-icon.js +1 -1
- package/dist/components/kritzel-menu-item.js +1 -1
- package/dist/components/kritzel-menu.js +1 -1
- package/dist/components/kritzel-split-button.js +1 -1
- package/dist/components/kritzel-utility-panel.js +1 -1
- package/dist/components/kritzel-workspace-manager.js +1 -1
- package/dist/components/{p-Cqr0Bah5.js → p-5OECjGHq.js} +3 -3
- package/dist/components/{p-Cqr0Bah5.js.map → p-5OECjGHq.js.map} +1 -1
- package/dist/components/{p-CvLFRlQU.js → p-BSBMBjhq.js} +3 -3
- package/dist/components/{p-CvLFRlQU.js.map → p-BSBMBjhq.js.map} +1 -1
- package/dist/components/{p-7_lwv0zQ.js → p-BuS7MM1j.js} +4 -4
- package/dist/components/{p-7_lwv0zQ.js.map → p-BuS7MM1j.js.map} +1 -1
- package/dist/components/{p-CuhOrcET.js → p-CnRfQsIC.js} +838 -22
- package/dist/components/p-CnRfQsIC.js.map +1 -0
- package/dist/components/{p-BixlbUD7.js → p-Cv4BGNPb.js} +6 -2
- package/dist/components/p-Cv4BGNPb.js.map +1 -0
- package/dist/components/{p-dMCB4tJA.js → p-D1YAsWrL.js} +3 -3
- package/dist/components/{p-dMCB4tJA.js.map → p-D1YAsWrL.js.map} +1 -1
- package/dist/components/{p-CDteBYm9.js → p-D8L0t-Ro.js} +3 -3
- package/dist/components/{p-CDteBYm9.js.map → p-D8L0t-Ro.js.map} +1 -1
- package/dist/components/{p-DZ7kxJUx.js → p-DguzZn_x.js} +3 -3
- package/dist/components/{p-DZ7kxJUx.js.map → p-DguzZn_x.js.map} +1 -1
- package/dist/components/{p-sokRZ7Vn.js → p-Dz2XHHqa.js} +145 -5
- package/dist/components/p-Dz2XHHqa.js.map +1 -0
- package/dist/components/{p-CkD1PQQX.js → p-I3iPEDpx.js} +5 -5
- package/dist/components/{p-CkD1PQQX.js.map → p-I3iPEDpx.js.map} +1 -1
- package/dist/components/{p-DKwJJuFb.js → p-tp96UZ0l.js} +83 -19
- package/dist/components/p-tp96UZ0l.js.map +1 -0
- package/dist/esm/{default-line-tool.config-C35m-d1Y.js → default-line-tool.config-C35P3XfD.js} +332 -10
- package/dist/esm/default-line-tool.config-C35P3XfD.js.map +1 -0
- package/dist/esm/index.js +2 -2
- package/dist/esm/kritzel-color_22.entry.js +761 -28
- package/dist/esm/loader.js +1 -1
- package/dist/esm/stencil.js +1 -1
- package/dist/stencil/index.esm.js +1 -1
- package/dist/stencil/p-9d43b708.entry.js +10 -0
- package/dist/stencil/p-9d43b708.entry.js.map +1 -0
- package/dist/stencil/p-C35P3XfD.js +2 -0
- package/dist/stencil/p-C35P3XfD.js.map +1 -0
- package/dist/stencil/stencil.esm.js +1 -1
- package/dist/types/classes/core/core.class.d.ts +1 -0
- package/dist/types/classes/core/store.class.d.ts +2 -0
- package/dist/types/classes/core/viewport.class.d.ts +6 -0
- package/dist/types/classes/managers/anchor.manager.d.ts +20 -0
- package/dist/types/classes/objects/path.class.d.ts +7 -0
- package/dist/types/classes/objects/shape.class.d.ts +116 -0
- package/dist/types/classes/tools/shape-tool.class.d.ts +37 -0
- package/dist/types/components/core/kritzel-engine/kritzel-engine.d.ts +2 -2
- package/dist/types/components/ui/kritzel-controls/kritzel-controls.d.ts +16 -1
- package/dist/types/components.d.ts +5 -5
- package/dist/types/configs/default-shape-tool.config.d.ts +2 -0
- package/dist/types/enums/shape-type.enum.d.ts +5 -0
- package/dist/types/helpers/geometry.helper.d.ts +21 -0
- package/dist/types/interfaces/toolbar-control.interface.d.ts +21 -3
- package/package.json +1 -1
- package/dist/cjs/default-line-tool.config-D1Ns0NmM.js.map +0 -1
- package/dist/components/p-BixlbUD7.js.map +0 -1
- package/dist/components/p-CuhOrcET.js.map +0 -1
- package/dist/components/p-DKwJJuFb.js.map +0 -1
- package/dist/components/p-sokRZ7Vn.js.map +0 -1
- package/dist/esm/default-line-tool.config-C35m-d1Y.js.map +0 -1
- package/dist/stencil/p-C35m-d1Y.js +0 -2
- package/dist/stencil/p-C35m-d1Y.js.map +0 -1
- package/dist/stencil/p-d142ef46.entry.js +0 -10
- package/dist/stencil/p-d142ef46.entry.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as registerInstance, h, H as Host, c as createEvent, g as getElement } from './index-SGde3HXB.js';
|
|
2
|
-
import { Y as KritzelDevicesHelper, I as KritzelBrushTool, N as KritzelTextTool, Z as KritzelMouseButton, Q as KritzelSelectionTool, V as DEFAULT_BRUSH_CONFIG, X as DEFAULT_LINE_TOOL_CONFIG, J as KritzelLineTool, L as KritzelEraserTool, W as DEFAULT_TEXT_CONFIG, M as KritzelImageTool, T as KritzelWorkspace,
|
|
2
|
+
import { Y as KritzelDevicesHelper, I as KritzelBrushTool, N as KritzelTextTool, Z as KritzelMouseButton, _ as KritzelBaseObject, $ as Schema, a0 as schema, a1 as addListNodes, a2 as EditorView, a3 as EditorState, a4 as keymap, a5 as TextSelection, a6 as KritzelKeyboardHelper, a7 as KritzelToolRegistry, a8 as KritzelGeometryHelper, a9 as baseKeymap, aa as KritzelBaseTool, ab as KritzelEventHelper, Q as KritzelSelectionTool, V as DEFAULT_BRUSH_CONFIG, X as DEFAULT_LINE_TOOL_CONFIG, J as KritzelLineTool, L as KritzelEraserTool, W as DEFAULT_TEXT_CONFIG, M as KritzelImageTool, T as KritzelWorkspace, ac as KritzelIconRegistry, ad as KritzelBaseHandler, ae as KritzelSelectionBox, af as KritzelSelectionGroup, F as KritzelImage, K as KritzelText, G as KritzelLine, E as KritzelPath, ag as Doc, ah as DEFAULT_SYNC_CONFIG, ai as UndoManager, P as KritzelCursorHelper, S as KritzelAppStateMap, U as KritzelAnchorManager, aj as ObjectHelper, ak as KritzelClassHelper } from './default-line-tool.config-C35P3XfD.js';
|
|
3
3
|
|
|
4
4
|
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
5
5
|
|
|
@@ -247,7 +247,7 @@ const KritzelControlTextConfig = class {
|
|
|
247
247
|
};
|
|
248
248
|
KritzelControlTextConfig.style = kritzelControlTextConfigCss;
|
|
249
249
|
|
|
250
|
-
const kritzelControlsCss = ":host{display:flex;flex-direction:column;user-select:none}:host(.mobile){--kritzel-controls-control-hover-background-color:transparent;--kritzel-controls-control-active-background-color:transparent}.kritzel-controls{display:flex;flex-direction:row;align-items:center;justify-content:flex-start;gap:var(--kritzel-controls-gap, 8px);height:100%;padding:var(--kritzel-controls-padding, 8px);background-color:var(--kritzel-controls-background-color, #ffffff);border-radius:var(--kritzel-controls-border-radius, 16px);box-shadow:var(--kritzel-controls-box-shadow, 0 0 3px rgba(0, 0, 0, 0.08));border:var(--kritzel-controls-border, 1px solid #ebebeb);z-index:10000;position:relative}.kritzel-control{display:flex;justify-content:center;align-items:center;color:var(--kritzel-controls-control-color, #000000);border-radius:var(--kritzel-controls-control-border-radius, 12px);padding:var(--kritzel-controls-control-padding, 8px);border:none;background:none;cursor:var(--kritzel-pointer-cursor, pointer);-webkit-tap-highlight-color:transparent;font-weight:bold}.kritzel-control:focus,.kritzel-control:hover{background-color:var(--kritzel-controls-control-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.kritzel-control:active{background-color:var(--kritzel-controls-control-active-background-color, hsl(0, 0%, 0%, 8.6%))}.kritzel-control.selected,.kritzel-control.selected:hover,.kritzel-control.selected:active{background-color:var(--kritzel-controls-control-selected-background-color, #007AFF) !important;color:var(--kritzel-controls-control-selected-color, #ffffff) !important}.kritzel-control.selected:focus{background-color:var(--kritzel-controls-control-selected-background-color, #007bffe3) !important}.kritzel-
|
|
250
|
+
const kritzelControlsCss = ":host{display:flex;flex-direction:column;user-select:none}:host(.mobile){--kritzel-controls-control-hover-background-color:transparent;--kritzel-controls-control-active-background-color:transparent}.kritzel-controls{display:flex;flex-direction:row;align-items:center;justify-content:flex-start;gap:var(--kritzel-controls-gap, 8px);height:100%;padding:var(--kritzel-controls-padding, 8px);background-color:var(--kritzel-controls-background-color, #ffffff);border-radius:var(--kritzel-controls-border-radius, 16px);box-shadow:var(--kritzel-controls-box-shadow, 0 0 3px rgba(0, 0, 0, 0.08));border:var(--kritzel-controls-border, 1px solid #ebebeb);z-index:10000;position:relative}.kritzel-control{display:flex;justify-content:center;align-items:center;color:var(--kritzel-controls-control-color, #000000);border-radius:var(--kritzel-controls-control-border-radius, 12px);padding:var(--kritzel-controls-control-padding, 8px);border:none;background:none;cursor:var(--kritzel-pointer-cursor, pointer);-webkit-tap-highlight-color:transparent;font-weight:bold}.kritzel-control:focus,.kritzel-control:hover{background-color:var(--kritzel-controls-control-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.kritzel-control:active{background-color:var(--kritzel-controls-control-active-background-color, hsl(0, 0%, 0%, 8.6%))}.kritzel-control.selected,.kritzel-control.selected:hover,.kritzel-control.selected:active{background-color:var(--kritzel-controls-control-selected-background-color, #007AFF) !important;color:var(--kritzel-controls-control-selected-color, #ffffff) !important}.kritzel-control.selected:focus{background-color:var(--kritzel-controls-control-selected-background-color, #007bffe3) !important}.kritzel-control-split{position:relative;display:flex;align-items:center;border-radius:var(--kritzel-controls-control-border-radius, 12px);color:var(--kritzel-controls-control-color, #000000)}.kritzel-control-split .kritzel-control-main{display:flex;justify-content:center;align-items:center;padding:var(--kritzel-controls-control-padding, 8px);border:none;background:none;cursor:var(--kritzel-pointer-cursor, pointer);-webkit-tap-highlight-color:transparent;border-radius:var(--kritzel-controls-control-border-radius, 12px);color:inherit}.kritzel-control-split.selected .kritzel-control-main{border-radius:var(--kritzel-controls-control-border-radius, 12px) 0 0 var(--kritzel-controls-control-border-radius, 12px)}.kritzel-control-split .kritzel-control-dropdown{display:flex;justify-content:center;align-items:center;align-self:stretch;border:none;background:none;cursor:var(--kritzel-pointer-cursor, pointer);-webkit-tap-highlight-color:transparent;border-radius:0 var(--kritzel-controls-control-border-radius, 12px) var(--kritzel-controls-control-border-radius, 12px) 0;color:inherit;width:0;padding:0;opacity:0;overflow:hidden;pointer-events:none;transition:width 0.15s ease-out, padding 0.15s ease-out, opacity 0.15s ease-out}.kritzel-control-split .kritzel-control-dropdown.visible{width:auto;padding:0 6px;opacity:1;pointer-events:auto}.kritzel-control-split .kritzel-control-main:focus,.kritzel-control-split .kritzel-control-main:hover,.kritzel-control-split .kritzel-control-dropdown:focus,.kritzel-control-split .kritzel-control-dropdown:hover{background-color:var(--kritzel-controls-control-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.kritzel-control-split .kritzel-control-main:active,.kritzel-control-split .kritzel-control-dropdown:active{background-color:var(--kritzel-controls-control-active-background-color, hsl(0, 0%, 0%, 8.6%))}.kritzel-control-split.selected{background-color:var(--kritzel-controls-control-selected-background-color, #007AFF) !important;color:var(--kritzel-controls-control-selected-color, #ffffff) !important}.kritzel-control-split.selected .kritzel-control-main:hover,.kritzel-control-split.selected .kritzel-control-dropdown:hover{background-color:rgba(255, 255, 255, 0.15)}.kritzel-submenu{position:absolute;bottom:calc(100% + 8px);left:50%;transform:translateX(-50%);display:flex;flex-direction:column;background:var(--kritzel-controls-background-color, #ffffff);border-radius:12px;padding:6px;box-shadow:0 4px 12px rgba(0, 0, 0, 0.15);border:1px solid #ebebeb;z-index:10001;min-width:140px}.kritzel-submenu-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border:none;background:none;cursor:var(--kritzel-pointer-cursor, pointer);border-radius:8px;color:var(--kritzel-controls-control-color, #000000);font-size:14px;text-align:left;white-space:nowrap;-webkit-tap-highlight-color:transparent}.kritzel-submenu-item:hover{background-color:var(--kritzel-controls-control-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.kritzel-submenu-item.active{background-color:var(--kritzel-controls-control-selected-background-color, #007AFF);color:var(--kritzel-controls-control-selected-color, #ffffff)}.kritzel-submenu-item.active:hover{background-color:var(--kritzel-controls-control-selected-background-color, #007AFF)}.kritzel-config-container{position:relative;display:flex;justify-content:center;align-items:center;height:40px;box-sizing:border-box;-webkit-tap-highlight-color:transparent;width:0;opacity:0;overflow:hidden;pointer-events:none;margin-left:calc(-1 * var(--kritzel-controls-gap, 8px));transition:width 0.2s ease-out, opacity 0.2s ease-out, margin-left 0.2s ease-out}.kritzel-config-container.visible{width:40px;opacity:1;pointer-events:auto;margin-left:0}.kritzel-config{display:flex;justify-content:center;align-items:center;cursor:var(--kritzel-pointer-cursor, pointer);border-radius:50%}.color-container{display:flex;justify-content:center;align-items:center;width:32px;height:32px;border-radius:50%;cursor:var(--kritzel-pointer-cursor, pointer);border:2px solid transparent;box-sizing:border-box;background-color:var(--kritzel-color-palette-hover-background-color, #ebebeb)}.font-container{display:flex;justify-content:center;align-items:center;width:32px;height:32px;border-radius:50%;cursor:var(--kritzel-pointer-cursor, pointer);border:2px solid transparent;box-sizing:border-box;background-color:var(--kritzel-color-palette-hover-background-color, #ebebeb)}.no-config{height:24px;width:24px;border-radius:50%;border:1px dashed gray}kritzel-tooltip{position:fixed;bottom:56px;left:50%;transform:translateX(-50%);z-index:10001}";
|
|
251
251
|
|
|
252
252
|
const KritzelControls = class {
|
|
253
253
|
constructor(hostRef) {
|
|
@@ -263,17 +263,24 @@ const KritzelControls = class {
|
|
|
263
263
|
firstConfig = null;
|
|
264
264
|
isTooltipVisible = false;
|
|
265
265
|
isTouchDevice = KritzelDevicesHelper.isTouchDevice();
|
|
266
|
+
selectedSubOptions = new Map();
|
|
267
|
+
openSubMenuControl = null;
|
|
266
268
|
handleDocumentClick(event) {
|
|
267
269
|
const element = event.target;
|
|
268
270
|
if (!this.kritzelEngine || element.closest('.kritzel-tooltip')) {
|
|
269
271
|
return;
|
|
270
272
|
}
|
|
271
273
|
this.isTooltipVisible = false;
|
|
274
|
+
// Close submenu when clicking outside
|
|
275
|
+
if (!element.closest('.kritzel-control-split') && !element.closest('.kritzel-submenu')) {
|
|
276
|
+
this.openSubMenuControl = null;
|
|
277
|
+
}
|
|
272
278
|
}
|
|
273
279
|
handleKeyDown(event) {
|
|
274
280
|
if (event.key === 'Escape') {
|
|
275
281
|
event.preventDefault();
|
|
276
282
|
this.closeTooltip();
|
|
283
|
+
this.openSubMenuControl = null;
|
|
277
284
|
this.kritzelEngine?.enable();
|
|
278
285
|
}
|
|
279
286
|
}
|
|
@@ -349,36 +356,91 @@ const KritzelControls = class {
|
|
|
349
356
|
this.isTooltipVisible = false;
|
|
350
357
|
this.kritzelEngine?.enable();
|
|
351
358
|
}
|
|
359
|
+
/**
|
|
360
|
+
* Get the currently selected sub-option for a control.
|
|
361
|
+
* Returns the first sub-option as default if none is selected.
|
|
362
|
+
*/
|
|
363
|
+
getSelectedSubOption(control) {
|
|
364
|
+
if (!control.subOptions?.length)
|
|
365
|
+
return undefined;
|
|
366
|
+
return this.selectedSubOptions.get(control.name) || control.subOptions[0];
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Toggle the submenu for a split-button control
|
|
370
|
+
*/
|
|
371
|
+
toggleSubMenu(event, control) {
|
|
372
|
+
event.stopPropagation();
|
|
373
|
+
if (this.openSubMenuControl?.name === control.name) {
|
|
374
|
+
this.openSubMenuControl = null;
|
|
375
|
+
}
|
|
376
|
+
else {
|
|
377
|
+
this.openSubMenuControl = control;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Select a sub-option and update the tool property
|
|
382
|
+
*/
|
|
383
|
+
async selectSubOption(control, option) {
|
|
384
|
+
// Update the selected sub-options map (create new Map for reactivity)
|
|
385
|
+
const newMap = new Map(this.selectedSubOptions);
|
|
386
|
+
newMap.set(control.name, option);
|
|
387
|
+
this.selectedSubOptions = newMap;
|
|
388
|
+
// Update the tool property if the tool is instantiated
|
|
389
|
+
if (control.tool && typeof control.tool !== 'function') {
|
|
390
|
+
control.tool[option.toolProperty] = option.value;
|
|
391
|
+
}
|
|
392
|
+
// Close the submenu
|
|
393
|
+
this.openSubMenuControl = null;
|
|
394
|
+
// Activate this control
|
|
395
|
+
await this.handleControlClick(control);
|
|
396
|
+
}
|
|
352
397
|
render() {
|
|
353
|
-
const
|
|
354
|
-
|
|
398
|
+
const hasConfigUI = this.activeControl?.tool instanceof KritzelBrushTool ||
|
|
399
|
+
this.activeControl?.tool instanceof KritzelTextTool;
|
|
400
|
+
return (h(Host, { key: '34a8a81224f1714a30a0d6e03fb81ed031fe36a0', class: {
|
|
355
401
|
mobile: this.isTouchDevice,
|
|
356
|
-
} }, this.isUtilityPanelVisible && (h("kritzel-utility-panel", { key: '
|
|
402
|
+
} }, this.isUtilityPanelVisible && (h("kritzel-utility-panel", { key: '8ddfe7b4872d59b08b0561dbd61c67b9c245dcc9', style: {
|
|
357
403
|
position: 'absolute',
|
|
358
404
|
bottom: '56px',
|
|
359
405
|
left: '12px',
|
|
360
|
-
}, undoState: this.undoState, onUndo: () => this.kritzelEngine?.undo(), onRedo: () => this.kritzelEngine?.redo(), onDelete: () => this.kritzelEngine?.delete() })), h("div", { key: '
|
|
406
|
+
}, undoState: this.undoState, onUndo: () => this.kritzelEngine?.undo(), onRedo: () => this.kritzelEngine?.redo(), onDelete: () => this.kritzelEngine?.delete() })), h("div", { key: '370229830b9a6c0ae5704d9fb0ce35d130fcf049', class: "kritzel-controls" }, this.controls.map(control => {
|
|
361
407
|
if (control.type === 'tool') {
|
|
408
|
+
// Check if this control has sub-options (split-button)
|
|
409
|
+
if (control.subOptions?.length) {
|
|
410
|
+
const selectedSubOption = this.getSelectedSubOption(control);
|
|
411
|
+
const isActive = this.activeControl?.name === control.name;
|
|
412
|
+
const isSubMenuOpen = this.openSubMenuControl?.name === control.name;
|
|
413
|
+
return (h("div", { class: {
|
|
414
|
+
'kritzel-control-split': true,
|
|
415
|
+
'selected': isActive,
|
|
416
|
+
}, key: control.name }, h("button", { class: "kritzel-control-main", onClick: () => this.handleControlClick(control), title: selectedSubOption?.label }, h("kritzel-icon", { name: selectedSubOption?.icon || control.icon })), h("button", { class: {
|
|
417
|
+
'kritzel-control-dropdown': true,
|
|
418
|
+
'visible': isActive,
|
|
419
|
+
}, onClick: (e) => this.toggleSubMenu(e, control), "aria-label": "Select shape type", "aria-expanded": isSubMenuOpen ? 'true' : 'false', tabIndex: isActive ? 0 : -1 }, h("kritzel-icon", { name: "chevron-down", size: 12 })), isSubMenuOpen && (h("div", { class: "kritzel-submenu" }, control.subOptions.map(option => (h("button", { class: {
|
|
420
|
+
'kritzel-submenu-item': true,
|
|
421
|
+
'active': option.id === selectedSubOption?.id,
|
|
422
|
+
}, key: option.id, onClick: () => this.selectSubOption(control, option) }, h("kritzel-icon", { name: option.icon, size: 20 }), h("span", null, option.label))))))));
|
|
423
|
+
}
|
|
424
|
+
// Regular tool control (no sub-options)
|
|
362
425
|
return (h("button", { class: {
|
|
363
426
|
'kritzel-control': true,
|
|
364
427
|
'selected': this.activeControl?.name === control?.name,
|
|
365
428
|
}, key: control.name, onClick: _event => this.handleControlClick?.(control) }, h("kritzel-icon", { name: control.icon })));
|
|
366
429
|
}
|
|
367
|
-
if (control.type === 'divider') {
|
|
368
|
-
return h("div", { class: "kritzel-divider", key: control.name });
|
|
369
|
-
}
|
|
370
430
|
if (control.type === 'config' && control.name === this.firstConfig?.name && this.activeControl) {
|
|
371
|
-
return (h("div", { class:
|
|
431
|
+
return (h("div", { class: {
|
|
432
|
+
'kritzel-config-container': true,
|
|
433
|
+
'visible': hasConfigUI,
|
|
434
|
+
}, key: control.name }, h("kritzel-tooltip", { ref: el => (this.tooltipRef = el), isVisible: this.isTooltipVisible, anchorElement: this.host.shadowRoot?.querySelector('.kritzel-config-container'), onTooltipClosed: () => this.handleTooltipClosed() }, h("div", { style: { width: '294px', height: '100%' } }, this.activeControl.name === 'brush' && (h("kritzel-control-brush-config", { tool: this.activeToolAsBrushTool, onToolChange: event => this.handleToolChange?.(event) })), this.activeControl.name === 'text' && (h("kritzel-control-text-config", { tool: this.activeToolAsTextTool, onToolChange: event => this.handleToolChange?.(event) })))), h("div", { tabIndex: hasConfigUI ? 0 : -1, class: "kritzel-config", onClick: event => this.handleConfigClick?.(event), onKeyDown: event => {
|
|
372
435
|
if (event.key === 'Enter') {
|
|
373
436
|
this.handleConfigClick?.(event);
|
|
374
437
|
}
|
|
375
438
|
}, style: {
|
|
376
|
-
cursor:
|
|
377
|
-
pointerEvents: hasNoConfig ? 'none' : 'auto',
|
|
439
|
+
cursor: 'pointer',
|
|
378
440
|
} }, this.activeControl.tool instanceof KritzelBrushTool && (h("div", { class: "color-container" }, h("kritzel-color", { value: this.activeToolAsBrushTool?.color, size: this.activeToolAsBrushTool?.size, style: {
|
|
379
441
|
borderRadius: '50%',
|
|
380
442
|
border: 'none',
|
|
381
|
-
} }))), this.activeControl.tool instanceof KritzelTextTool && (h("div", { class: "font-container" }, h("kritzel-font", { fontFamily: this.activeToolAsTextTool?.fontFamily, size: this.activeToolAsTextTool?.fontSize, color: this.activeToolAsTextTool?.fontColor })))
|
|
443
|
+
} }))), this.activeControl.tool instanceof KritzelTextTool && (h("div", { class: "font-container" }, h("kritzel-font", { fontFamily: this.activeToolAsTextTool?.fontFamily, size: this.activeToolAsTextTool?.fontSize, color: this.activeToolAsTextTool?.fontColor }))))));
|
|
382
444
|
}
|
|
383
445
|
}))));
|
|
384
446
|
}
|
|
@@ -573,6 +635,596 @@ const KritzelDropdown = class {
|
|
|
573
635
|
};
|
|
574
636
|
KritzelDropdown.style = kritzelDropdownCss;
|
|
575
637
|
|
|
638
|
+
var ShapeType;
|
|
639
|
+
(function (ShapeType) {
|
|
640
|
+
ShapeType["Rectangle"] = "rectangle";
|
|
641
|
+
ShapeType["Ellipse"] = "ellipse";
|
|
642
|
+
ShapeType["Triangle"] = "triangle";
|
|
643
|
+
})(ShapeType || (ShapeType = {}));
|
|
644
|
+
|
|
645
|
+
class KritzelShape extends KritzelBaseObject {
|
|
646
|
+
__class__ = 'KritzelShape';
|
|
647
|
+
shapeType = ShapeType.Rectangle;
|
|
648
|
+
fillColor = 'transparent';
|
|
649
|
+
strokeColor = '#000000';
|
|
650
|
+
strokeWidth = 4;
|
|
651
|
+
fontFamily = 'Arial';
|
|
652
|
+
fontSize = 16;
|
|
653
|
+
fontColor = '#000000';
|
|
654
|
+
/** Screen-space x coordinate of the shape's top-left corner (like Path.x) */
|
|
655
|
+
x = 0;
|
|
656
|
+
/** Screen-space y coordinate of the shape's top-left corner (like Path.y) */
|
|
657
|
+
y = 0;
|
|
658
|
+
scale = 1;
|
|
659
|
+
scaleFactor = 1;
|
|
660
|
+
isDebugInfoVisible = true;
|
|
661
|
+
isEditable = true;
|
|
662
|
+
isEditing = false;
|
|
663
|
+
editor = null;
|
|
664
|
+
content = null;
|
|
665
|
+
_schema = new Schema({
|
|
666
|
+
nodes: addListNodes(schema.spec.nodes, 'paragraph block*', 'block'),
|
|
667
|
+
marks: schema.spec.marks,
|
|
668
|
+
});
|
|
669
|
+
uneditedObject = null;
|
|
670
|
+
/**
|
|
671
|
+
* Returns the viewBox for the shape's SVG, using screen-space coordinates.
|
|
672
|
+
* This follows the same pattern as KritzelPath.viewBox.
|
|
673
|
+
*/
|
|
674
|
+
get viewBox() {
|
|
675
|
+
return `${this.x} ${this.y} ${this.width} ${this.height}`;
|
|
676
|
+
}
|
|
677
|
+
constructor(config) {
|
|
678
|
+
super();
|
|
679
|
+
if (config) {
|
|
680
|
+
this.x = config.x ?? 0;
|
|
681
|
+
this.y = config.y ?? 0;
|
|
682
|
+
this.translateX = config.translateX ?? 0;
|
|
683
|
+
this.translateY = config.translateY ?? 0;
|
|
684
|
+
this.width = config.width ?? 100;
|
|
685
|
+
this.height = config.height ?? 100;
|
|
686
|
+
this.shapeType = config.shapeType ?? ShapeType.Rectangle;
|
|
687
|
+
this.fillColor = config.fillColor ?? 'transparent';
|
|
688
|
+
this.strokeColor = config.strokeColor ?? '#000000';
|
|
689
|
+
this.strokeWidth = config.strokeWidth ?? 4;
|
|
690
|
+
this.fontSize = config.fontSize ?? 16;
|
|
691
|
+
this.fontFamily = config.fontFamily ?? 'Arial';
|
|
692
|
+
this.fontColor = config.fontColor ?? '#000000';
|
|
693
|
+
this.scale = config.scale ?? 1;
|
|
694
|
+
this.scaleFactor = config.scaleX ?? 1;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* Creates a new KritzelShape with screen-space coordinates.
|
|
699
|
+
* Following the same pattern as KritzelPath.create():
|
|
700
|
+
* - x, y are screen-space coordinates of the shape's top-left corner
|
|
701
|
+
* - translateX, translateY should be set to -viewportTranslateX, -viewportTranslateY
|
|
702
|
+
* - width, height are in screen-space
|
|
703
|
+
* - scale is the viewport scale at creation time
|
|
704
|
+
*/
|
|
705
|
+
static create(core, config) {
|
|
706
|
+
const object = new KritzelShape();
|
|
707
|
+
object._core = core;
|
|
708
|
+
object.id = object.generateId();
|
|
709
|
+
object.workspaceId = core.store.state.activeWorkspace.id;
|
|
710
|
+
object.x = config?.x ?? 0;
|
|
711
|
+
object.y = config?.y ?? 0;
|
|
712
|
+
object.translateX = config?.translateX ?? 0;
|
|
713
|
+
object.translateY = config?.translateY ?? 0;
|
|
714
|
+
object.width = config?.width ?? 100;
|
|
715
|
+
object.height = config?.height ?? 100;
|
|
716
|
+
object.shapeType = config?.shapeType ?? ShapeType.Rectangle;
|
|
717
|
+
object.fillColor = config?.fillColor ?? 'transparent';
|
|
718
|
+
object.strokeColor = config?.strokeColor ?? '#000000';
|
|
719
|
+
object.strokeWidth = config?.strokeWidth ?? 4;
|
|
720
|
+
object.fontSize = config?.fontSize ?? 16;
|
|
721
|
+
object.fontFamily = config?.fontFamily ?? 'Arial';
|
|
722
|
+
object.fontColor = config?.fontColor ?? '#000000';
|
|
723
|
+
object.backgroundColor = 'transparent';
|
|
724
|
+
object.scaleFactor = 1;
|
|
725
|
+
object.scale = core.store.state.scale;
|
|
726
|
+
object.zIndex = core.store.currentZIndex;
|
|
727
|
+
object.editor = object.createEditor();
|
|
728
|
+
// Compute world-space translateX/Y from screen-space coordinates
|
|
729
|
+
// This follows the same pattern as KritzelPath.updateDimensions()
|
|
730
|
+
object.updateDimensions();
|
|
731
|
+
return object;
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* Updates the translateX/Y to world coordinates based on screen-space x, y.
|
|
735
|
+
* This follows the same pattern as KritzelPath.updateDimensions().
|
|
736
|
+
*
|
|
737
|
+
* The formula: translateX = (x + initialTranslateX) / scale
|
|
738
|
+
* where initialTranslateX was -viewportTranslateX
|
|
739
|
+
*
|
|
740
|
+
* This converts screen-space position to world coordinates.
|
|
741
|
+
*/
|
|
742
|
+
updateDimensions() {
|
|
743
|
+
this.translateX = (this.x + this.translateX) / this.scale;
|
|
744
|
+
this.translateY = (this.y + this.translateY) / this.scale;
|
|
745
|
+
}
|
|
746
|
+
mount(element) {
|
|
747
|
+
if (element === null || this.isInViewport() === false) {
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
if (this.isMounted && this.elementRef === element && this.editor.dom.parentElement === element) {
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
this.elementRef = element;
|
|
754
|
+
this.isMounted = true;
|
|
755
|
+
}
|
|
756
|
+
mountTextEditor(element) {
|
|
757
|
+
if (element === null) {
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
if (this.editor.dom.parentElement === element) {
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
element.style.fontFamily = this.fontFamily;
|
|
764
|
+
element.style.fontSize = `${this.fontSize}pt`;
|
|
765
|
+
element.style.color = this.fontColor;
|
|
766
|
+
element.style.whiteSpace = 'pre-wrap';
|
|
767
|
+
element.style.wordWrap = 'break-word';
|
|
768
|
+
element.innerHTML = '';
|
|
769
|
+
element.appendChild(this.editor.dom);
|
|
770
|
+
}
|
|
771
|
+
createEditor() {
|
|
772
|
+
const doc = this._schema.node('doc', null, [this._schema.node('paragraph')]);
|
|
773
|
+
return new EditorView(null, {
|
|
774
|
+
state: EditorState.create({
|
|
775
|
+
doc: doc,
|
|
776
|
+
plugins: [keymap(baseKeymap)],
|
|
777
|
+
}),
|
|
778
|
+
editable: () => false,
|
|
779
|
+
dispatchTransaction: transaction => {
|
|
780
|
+
const newState = this.editor.state.apply(transaction);
|
|
781
|
+
this.editor.updateState(newState);
|
|
782
|
+
if (transaction.docChanged) {
|
|
783
|
+
this.content = newState.doc.toJSON();
|
|
784
|
+
if (!transaction.getMeta('fromRemote')) {
|
|
785
|
+
this._core.store.state.objects.update(this, { temporary: true });
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
},
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
setContent(content) {
|
|
792
|
+
this.content = content;
|
|
793
|
+
if (this.editor && content) {
|
|
794
|
+
const newDoc = this.editor.state.schema.nodeFromJSON(content);
|
|
795
|
+
const tr = this.editor.state.tr.replaceWith(0, this.editor.state.doc.content.size, newDoc.content);
|
|
796
|
+
tr.setMeta('fromRemote', true);
|
|
797
|
+
this.editor.dispatch(tr);
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
resize(x, y, width, height) {
|
|
801
|
+
if (width <= 1 || height <= 1) {
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
this.width = width;
|
|
805
|
+
this.height = height;
|
|
806
|
+
this.translateX = x;
|
|
807
|
+
this.translateY = y;
|
|
808
|
+
this._core.store.state.objects.update(this);
|
|
809
|
+
}
|
|
810
|
+
focus(coords) {
|
|
811
|
+
if (this.editor) {
|
|
812
|
+
const doc = this.editor.state.doc;
|
|
813
|
+
if (coords?.x && coords?.y) {
|
|
814
|
+
const pos = this.editor.posAtCoords({ left: coords.x, top: coords.y });
|
|
815
|
+
if (pos) {
|
|
816
|
+
this.editor.dispatch(this.editor.state.tr.setSelection(TextSelection.create(doc, pos.pos)));
|
|
817
|
+
this.editor.focus();
|
|
818
|
+
if (KritzelDevicesHelper.isIOS()) {
|
|
819
|
+
this.scrollIntoViewOnIOS();
|
|
820
|
+
}
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
const end = Math.max(1, doc.content.size - 1);
|
|
825
|
+
this.editor.dispatch(this.editor.state.tr.setSelection(TextSelection.create(doc, end)));
|
|
826
|
+
this.editor.focus();
|
|
827
|
+
if (KritzelDevicesHelper.isIOS()) {
|
|
828
|
+
this.scrollIntoViewOnIOS();
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
scrollIntoViewOnIOS() {
|
|
833
|
+
setTimeout(() => {
|
|
834
|
+
if (this.editor && this.editor.dom) {
|
|
835
|
+
this.editor.dom.scrollIntoView({
|
|
836
|
+
behavior: 'smooth',
|
|
837
|
+
block: 'center',
|
|
838
|
+
inline: 'nearest',
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
}, 300);
|
|
842
|
+
}
|
|
843
|
+
edit(event) {
|
|
844
|
+
KritzelKeyboardHelper.disableInteractiveWidget();
|
|
845
|
+
this.uneditedObject = this.clone();
|
|
846
|
+
this._core.store.setState('activeTool', KritzelToolRegistry.getTool('shape'));
|
|
847
|
+
this.editor.setProps({ editable: () => true });
|
|
848
|
+
this.isEditing = true;
|
|
849
|
+
this._core.rerender();
|
|
850
|
+
this.focus({ x: event?.clientX, y: event?.clientY });
|
|
851
|
+
KritzelKeyboardHelper.enableInteractiveWidget();
|
|
852
|
+
}
|
|
853
|
+
save() {
|
|
854
|
+
this.content = this.editor.state.doc.toJSON();
|
|
855
|
+
this.editor.setProps({ editable: () => false });
|
|
856
|
+
this.editor.dom.blur();
|
|
857
|
+
this.isEditing = false;
|
|
858
|
+
this._core.store.state.objects.consolidateTemporaryItems();
|
|
859
|
+
this._core.store.state.objects.update(this);
|
|
860
|
+
this._core.engine.emitObjectsChange();
|
|
861
|
+
}
|
|
862
|
+
handlePointerDown(event) {
|
|
863
|
+
if (!this.isEditing) {
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
event.stopPropagation();
|
|
867
|
+
}
|
|
868
|
+
handlePointerMove(event) {
|
|
869
|
+
if (!this.isEditing) {
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
872
|
+
event.stopPropagation();
|
|
873
|
+
}
|
|
874
|
+
handlePointerUp(event) {
|
|
875
|
+
if (!this.isEditing) {
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
event.stopPropagation();
|
|
879
|
+
}
|
|
880
|
+
copy() {
|
|
881
|
+
const copiedObject = super.copy();
|
|
882
|
+
copiedObject.editor = copiedObject.createEditor();
|
|
883
|
+
if (this.content) {
|
|
884
|
+
copiedObject.setContent(this.content);
|
|
885
|
+
}
|
|
886
|
+
return copiedObject;
|
|
887
|
+
}
|
|
888
|
+
serialize() {
|
|
889
|
+
const { _core, _elementRef, _schema, element, totalWidth, totalHeight, editor, uneditedObject, ...remainingProps } = this;
|
|
890
|
+
const clonedProps = structuredClone(remainingProps);
|
|
891
|
+
if (element && typeof element === 'object' && 'nodeType' in element && element.nodeType === 1) {
|
|
892
|
+
clonedProps.element = element.cloneNode(true);
|
|
893
|
+
}
|
|
894
|
+
return clonedProps;
|
|
895
|
+
}
|
|
896
|
+
deserialize(object) {
|
|
897
|
+
super.deserialize(object);
|
|
898
|
+
if (object.content) {
|
|
899
|
+
this.setContent(object.content);
|
|
900
|
+
}
|
|
901
|
+
return this;
|
|
902
|
+
}
|
|
903
|
+
/**
|
|
904
|
+
* Returns the clipping polygon for arrow intersection.
|
|
905
|
+
* For ellipse: returns a many-sided polygon approximation
|
|
906
|
+
* For triangle: returns the 3 corners
|
|
907
|
+
* For rectangle: returns null (uses default rotatedPolygon)
|
|
908
|
+
*
|
|
909
|
+
* Includes padding for half the stroke width so arrow heads don't overlap the stroke.
|
|
910
|
+
*/
|
|
911
|
+
getClipPolygon() {
|
|
912
|
+
// Calculate world-space center and dimensions
|
|
913
|
+
const worldWidth = this.totalWidth / this.scale;
|
|
914
|
+
const worldHeight = this.totalHeight / this.scale;
|
|
915
|
+
const centerX = this.translateX + worldWidth / 2;
|
|
916
|
+
const centerY = this.translateY + worldHeight / 2;
|
|
917
|
+
// Add padding for stroke width so arrows don't overlap the stroke
|
|
918
|
+
const strokePadding = (this.strokeWidth / this.scale) / 2;
|
|
919
|
+
switch (this.shapeType) {
|
|
920
|
+
case ShapeType.Ellipse:
|
|
921
|
+
// Return a 32-segment polygon approximation of the ellipse
|
|
922
|
+
// Add stroke padding to radii
|
|
923
|
+
return KritzelGeometryHelper.getEllipsePolygonApproximation(centerX, centerY, worldWidth / 2 + strokePadding, worldHeight / 2 + strokePadding, 32, this.rotation);
|
|
924
|
+
case ShapeType.Triangle:
|
|
925
|
+
// Return the 3 corners of the triangle in world coordinates
|
|
926
|
+
// Triangle: top-center, bottom-right, bottom-left
|
|
927
|
+
// Expand each vertex outward from center by strokePadding
|
|
928
|
+
const expandVertex = (vx, vy) => {
|
|
929
|
+
const dx = vx - centerX;
|
|
930
|
+
const dy = vy - centerY;
|
|
931
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
932
|
+
if (dist === 0)
|
|
933
|
+
return { x: vx, y: vy };
|
|
934
|
+
const scale = (dist + strokePadding) / dist;
|
|
935
|
+
return {
|
|
936
|
+
x: centerX + dx * scale,
|
|
937
|
+
y: centerY + dy * scale
|
|
938
|
+
};
|
|
939
|
+
};
|
|
940
|
+
const topX = this.translateX + worldWidth / 2;
|
|
941
|
+
const topY = this.translateY;
|
|
942
|
+
const bottomLeftX = this.translateX;
|
|
943
|
+
const bottomLeftY = this.translateY + worldHeight;
|
|
944
|
+
const bottomRightX = this.translateX + worldWidth;
|
|
945
|
+
const bottomRightY = this.translateY + worldHeight;
|
|
946
|
+
const expandedTop = expandVertex(topX, topY);
|
|
947
|
+
const expandedBottomRight = expandVertex(bottomRightX, bottomRightY);
|
|
948
|
+
const expandedBottomLeft = expandVertex(bottomLeftX, bottomLeftY);
|
|
949
|
+
// Apply rotation around center if rotated
|
|
950
|
+
if (this.rotation !== 0) {
|
|
951
|
+
const cos = Math.cos(this.rotation);
|
|
952
|
+
const sin = Math.sin(this.rotation);
|
|
953
|
+
const rotate = (p) => {
|
|
954
|
+
const dx = p.x - centerX;
|
|
955
|
+
const dy = p.y - centerY;
|
|
956
|
+
return {
|
|
957
|
+
x: centerX + dx * cos - dy * sin,
|
|
958
|
+
y: centerY + dx * sin + dy * cos
|
|
959
|
+
};
|
|
960
|
+
};
|
|
961
|
+
return [
|
|
962
|
+
rotate(expandedTop),
|
|
963
|
+
rotate(expandedBottomRight),
|
|
964
|
+
rotate(expandedBottomLeft)
|
|
965
|
+
];
|
|
966
|
+
}
|
|
967
|
+
return [expandedTop, expandedBottomRight, expandedBottomLeft];
|
|
968
|
+
case ShapeType.Rectangle:
|
|
969
|
+
default:
|
|
970
|
+
// For rectangles, return null to use the default rotatedPolygon
|
|
971
|
+
return null;
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
/**
|
|
975
|
+
* Returns the SVG path for rendering the shape.
|
|
976
|
+
* The path uses screen-space coordinates relative to (x, y).
|
|
977
|
+
*/
|
|
978
|
+
getSvgPath() {
|
|
979
|
+
const w = this.width;
|
|
980
|
+
const h = this.height;
|
|
981
|
+
switch (this.shapeType) {
|
|
982
|
+
case ShapeType.Rectangle:
|
|
983
|
+
return `M ${this.x} ${this.y} L ${this.x + w} ${this.y} L ${this.x + w} ${this.y + h} L ${this.x} ${this.y + h} Z`;
|
|
984
|
+
case ShapeType.Ellipse:
|
|
985
|
+
const cx = this.x + w / 2;
|
|
986
|
+
const cy = this.y + h / 2;
|
|
987
|
+
const rx = w / 2;
|
|
988
|
+
const ry = h / 2;
|
|
989
|
+
return `M ${cx - rx} ${cy} A ${rx} ${ry} 0 1 0 ${cx + rx} ${cy} A ${rx} ${ry} 0 1 0 ${cx - rx} ${cy}`;
|
|
990
|
+
case ShapeType.Triangle:
|
|
991
|
+
const topX = this.x + w / 2;
|
|
992
|
+
const topY = this.y;
|
|
993
|
+
const bottomLeftX = this.x;
|
|
994
|
+
const bottomLeftY = this.y + h;
|
|
995
|
+
const bottomRightX = this.x + w;
|
|
996
|
+
const bottomRightY = this.y + h;
|
|
997
|
+
return `M ${topX} ${topY} L ${bottomRightX} ${bottomRightY} L ${bottomLeftX} ${bottomLeftY} Z`;
|
|
998
|
+
default:
|
|
999
|
+
return `M ${this.x} ${this.y} L ${this.x + w} ${this.y} L ${this.x + w} ${this.y + h} L ${this.x} ${this.y + h} Z`;
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
class KritzelShapeTool extends KritzelBaseTool {
|
|
1005
|
+
shapeType = ShapeType.Rectangle;
|
|
1006
|
+
fillColor = 'transparent';
|
|
1007
|
+
strokeColor = '#000000';
|
|
1008
|
+
strokeWidth = 4;
|
|
1009
|
+
fontFamily = 'Arial';
|
|
1010
|
+
fontSize = 16;
|
|
1011
|
+
fontColor = '#000000';
|
|
1012
|
+
palette = [
|
|
1013
|
+
'#000000',
|
|
1014
|
+
'#FFFFFF',
|
|
1015
|
+
'#FF0000',
|
|
1016
|
+
'#00FF00',
|
|
1017
|
+
'#0000FF',
|
|
1018
|
+
'#FFFF00',
|
|
1019
|
+
'#FF00FF',
|
|
1020
|
+
'#00FFFF',
|
|
1021
|
+
'#808080',
|
|
1022
|
+
'#C0C0C0',
|
|
1023
|
+
'#800000',
|
|
1024
|
+
'#008000',
|
|
1025
|
+
'#000080',
|
|
1026
|
+
'#808000',
|
|
1027
|
+
'#800080',
|
|
1028
|
+
];
|
|
1029
|
+
startX = 0;
|
|
1030
|
+
startY = 0;
|
|
1031
|
+
isDrawing = false;
|
|
1032
|
+
currentShape = null;
|
|
1033
|
+
constructor(core) {
|
|
1034
|
+
super(core);
|
|
1035
|
+
}
|
|
1036
|
+
handlePointerDown(event) {
|
|
1037
|
+
if (event.cancelable) {
|
|
1038
|
+
event.preventDefault();
|
|
1039
|
+
}
|
|
1040
|
+
if (event.pointerType === 'mouse') {
|
|
1041
|
+
const path = event.composedPath().slice(1);
|
|
1042
|
+
const objectElement = path.find(element => element.classList && element.classList.contains('object'));
|
|
1043
|
+
const object = this._core.findObjectById(objectElement?.id);
|
|
1044
|
+
const activeShape = this._core.store.activeShape;
|
|
1045
|
+
if (activeShape === null && object instanceof KritzelShape) {
|
|
1046
|
+
object.edit(event);
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1049
|
+
if (activeShape !== null && object instanceof KritzelShape) {
|
|
1050
|
+
activeShape.save();
|
|
1051
|
+
object.edit(event);
|
|
1052
|
+
return;
|
|
1053
|
+
}
|
|
1054
|
+
if (activeShape !== null && object instanceof KritzelShape === false) {
|
|
1055
|
+
this._core.resetActiveShape();
|
|
1056
|
+
this._core.store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
1059
|
+
if (KritzelEventHelper.isLeftClick(event) === false) {
|
|
1060
|
+
return;
|
|
1061
|
+
}
|
|
1062
|
+
this.startDrawing(event.clientX, event.clientY);
|
|
1063
|
+
}
|
|
1064
|
+
if (event.pointerType === 'touch') {
|
|
1065
|
+
const activePointers = Array.from(this._core.store.state.pointers.values());
|
|
1066
|
+
const path = event.composedPath().slice(1);
|
|
1067
|
+
const objectElement = path.find(element => element.classList && element.classList.contains('object'));
|
|
1068
|
+
const object = this._core.findObjectById(objectElement?.id);
|
|
1069
|
+
const activeShape = this._core.store.activeShape;
|
|
1070
|
+
if (activeShape === null && object instanceof KritzelShape) {
|
|
1071
|
+
object.edit(event);
|
|
1072
|
+
return;
|
|
1073
|
+
}
|
|
1074
|
+
if (activeShape !== null && object instanceof KritzelShape) {
|
|
1075
|
+
activeShape.save();
|
|
1076
|
+
object.edit(event);
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
if (activeShape !== null && object instanceof KritzelShape === false) {
|
|
1080
|
+
this._core.resetActiveShape();
|
|
1081
|
+
this._core.store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1084
|
+
if (activePointers.length > 1) {
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
const clientX = Math.round(activePointers[0].clientX);
|
|
1088
|
+
const clientY = Math.round(activePointers[0].clientY);
|
|
1089
|
+
this.startDrawing(clientX, clientY);
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
handlePointerMove(event) {
|
|
1093
|
+
if (event.cancelable) {
|
|
1094
|
+
event.preventDefault();
|
|
1095
|
+
}
|
|
1096
|
+
if (!this.isDrawing || !this.currentShape) {
|
|
1097
|
+
return;
|
|
1098
|
+
}
|
|
1099
|
+
if (event.pointerType === 'mouse') {
|
|
1100
|
+
this.updateShapeSize(event.clientX, event.clientY);
|
|
1101
|
+
}
|
|
1102
|
+
if (event.pointerType === 'touch') {
|
|
1103
|
+
const activePointers = Array.from(this._core.store.state.pointers.values());
|
|
1104
|
+
if (activePointers.length === 1) {
|
|
1105
|
+
const clientX = Math.round(activePointers[0].clientX);
|
|
1106
|
+
const clientY = Math.round(activePointers[0].clientY);
|
|
1107
|
+
this.updateShapeSize(clientX, clientY);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
handlePointerUp(event) {
|
|
1112
|
+
if (event.cancelable) {
|
|
1113
|
+
event.preventDefault();
|
|
1114
|
+
}
|
|
1115
|
+
if (!this.isDrawing || !this.currentShape) {
|
|
1116
|
+
return;
|
|
1117
|
+
}
|
|
1118
|
+
this.finishDrawing();
|
|
1119
|
+
}
|
|
1120
|
+
/**
|
|
1121
|
+
* Start drawing a shape. Following the same pattern as LineTool/BrushTool:
|
|
1122
|
+
* - Store screen coordinates for startX, startY
|
|
1123
|
+
* - Set translateX/Y to -viewportTranslateX/Y (viewport offset)
|
|
1124
|
+
* - Set x, y to the actual screen position
|
|
1125
|
+
* - Let updateDimensions() convert to world coordinates
|
|
1126
|
+
*/
|
|
1127
|
+
startDrawing(clientX, clientY) {
|
|
1128
|
+
// Store screen coordinates (relative to host element)
|
|
1129
|
+
this.startX = clientX - this._core.store.offsetX;
|
|
1130
|
+
this.startY = clientY - this._core.store.offsetY;
|
|
1131
|
+
this.isDrawing = true;
|
|
1132
|
+
// Create shape using screen coordinates, following Path/Line pattern
|
|
1133
|
+
this.currentShape = KritzelShape.create(this._core, {
|
|
1134
|
+
x: this.startX,
|
|
1135
|
+
y: this.startY,
|
|
1136
|
+
translateX: -this._core.store.state.translateX,
|
|
1137
|
+
translateY: -this._core.store.state.translateY,
|
|
1138
|
+
width: 1,
|
|
1139
|
+
height: 1,
|
|
1140
|
+
shapeType: this.shapeType,
|
|
1141
|
+
fillColor: this.fillColor,
|
|
1142
|
+
strokeColor: this.strokeColor,
|
|
1143
|
+
strokeWidth: this.strokeWidth,
|
|
1144
|
+
fontSize: this.fontSize,
|
|
1145
|
+
fontFamily: this.fontFamily,
|
|
1146
|
+
fontColor: this.fontColor,
|
|
1147
|
+
});
|
|
1148
|
+
this._core.store.state.objects.insert(this.currentShape);
|
|
1149
|
+
this._core.rerender();
|
|
1150
|
+
}
|
|
1151
|
+
/**
|
|
1152
|
+
* Update shape size during drawing. Following the same pattern as LineTool:
|
|
1153
|
+
* - Use screen coordinates directly
|
|
1154
|
+
* - The shape's x, y, width, height are all in screen space
|
|
1155
|
+
* - updateDimensions() handles conversion to world coordinates
|
|
1156
|
+
*/
|
|
1157
|
+
updateShapeSize(clientX, clientY) {
|
|
1158
|
+
if (!this.currentShape) {
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1161
|
+
const currentX = clientX - this._core.store.offsetX;
|
|
1162
|
+
const currentY = clientY - this._core.store.offsetY;
|
|
1163
|
+
// Calculate bounding box in screen coordinates
|
|
1164
|
+
const minX = Math.min(this.startX, currentX);
|
|
1165
|
+
const minY = Math.min(this.startY, currentY);
|
|
1166
|
+
const width = Math.abs(currentX - this.startX);
|
|
1167
|
+
const height = Math.abs(currentY - this.startY);
|
|
1168
|
+
// Update shape with screen coordinates
|
|
1169
|
+
this.currentShape.x = minX;
|
|
1170
|
+
this.currentShape.y = minY;
|
|
1171
|
+
this.currentShape.width = Math.max(1, width);
|
|
1172
|
+
this.currentShape.height = Math.max(1, height);
|
|
1173
|
+
// Recalculate world-space translateX/Y
|
|
1174
|
+
// Reset translateX/Y to initial value before updateDimensions
|
|
1175
|
+
this.currentShape.translateX = -this._core.store.state.translateX;
|
|
1176
|
+
this.currentShape.translateY = -this._core.store.state.translateY;
|
|
1177
|
+
this.currentShape.updateDimensions();
|
|
1178
|
+
this._core.store.state.objects.update(this.currentShape);
|
|
1179
|
+
}
|
|
1180
|
+
finishDrawing() {
|
|
1181
|
+
if (!this.currentShape) {
|
|
1182
|
+
return;
|
|
1183
|
+
}
|
|
1184
|
+
// Remove shape if it's too small (likely an accidental click)
|
|
1185
|
+
// Compare in screen space
|
|
1186
|
+
if (this.currentShape.width < 10 && this.currentShape.height < 10) {
|
|
1187
|
+
const shapeId = this.currentShape.id;
|
|
1188
|
+
this._core.store.state.objects.remove(o => o.id === shapeId);
|
|
1189
|
+
}
|
|
1190
|
+
else {
|
|
1191
|
+
this.currentShape.zIndex = this._core.store.currentZIndex;
|
|
1192
|
+
this._core.store.state.objects.update(this.currentShape);
|
|
1193
|
+
this._core.engine.emitObjectsChange();
|
|
1194
|
+
this._core.selectObjects([this.currentShape]);
|
|
1195
|
+
this._core.store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
|
|
1196
|
+
}
|
|
1197
|
+
this.isDrawing = false;
|
|
1198
|
+
this.currentShape = null;
|
|
1199
|
+
this._core.rerender();
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
const DEFAULT_SHAPE_CONFIG = {
|
|
1204
|
+
shapeType: ShapeType.Rectangle,
|
|
1205
|
+
fillColor: 'transparent',
|
|
1206
|
+
strokeColor: '#000000',
|
|
1207
|
+
strokeWidth: 4,
|
|
1208
|
+
fontColor: '#000000',
|
|
1209
|
+
fontSize: 16,
|
|
1210
|
+
fontFamily: 'Arial',
|
|
1211
|
+
palette: [
|
|
1212
|
+
'#000000',
|
|
1213
|
+
'#ff5252',
|
|
1214
|
+
'#ffbc00',
|
|
1215
|
+
'#00c853',
|
|
1216
|
+
'#0000FF',
|
|
1217
|
+
'#d500f9',
|
|
1218
|
+
'#fafafa',
|
|
1219
|
+
'#a52714',
|
|
1220
|
+
'#ee8100',
|
|
1221
|
+
'#558b2f',
|
|
1222
|
+
'#01579b',
|
|
1223
|
+
'#8e24aa',
|
|
1224
|
+
'#90a4ae',
|
|
1225
|
+
],
|
|
1226
|
+
};
|
|
1227
|
+
|
|
576
1228
|
const ABSOLUTE_SCALE_MAX = 1000;
|
|
577
1229
|
const ABSOLUTE_SCALE_MIN = 0.0001;
|
|
578
1230
|
|
|
@@ -623,16 +1275,24 @@ const KritzelEditor = class {
|
|
|
623
1275
|
icon: 'type',
|
|
624
1276
|
config: DEFAULT_TEXT_CONFIG,
|
|
625
1277
|
},
|
|
1278
|
+
{
|
|
1279
|
+
name: 'shape',
|
|
1280
|
+
type: 'tool',
|
|
1281
|
+
tool: KritzelShapeTool,
|
|
1282
|
+
icon: 'shape-rectangle',
|
|
1283
|
+
config: DEFAULT_SHAPE_CONFIG,
|
|
1284
|
+
subOptions: [
|
|
1285
|
+
{ id: 'rectangle', icon: 'shape-rectangle', label: 'Rectangle', value: ShapeType.Rectangle, toolProperty: 'shapeType' },
|
|
1286
|
+
{ id: 'ellipse', icon: 'shape-ellipse', label: 'Ellipse', value: ShapeType.Ellipse, toolProperty: 'shapeType' },
|
|
1287
|
+
{ id: 'triangle', icon: 'shape-triangle', label: 'Triangle', value: ShapeType.Triangle, toolProperty: 'shapeType' },
|
|
1288
|
+
],
|
|
1289
|
+
},
|
|
626
1290
|
{
|
|
627
1291
|
name: 'image',
|
|
628
1292
|
type: 'tool',
|
|
629
1293
|
tool: KritzelImageTool,
|
|
630
1294
|
icon: 'image',
|
|
631
1295
|
},
|
|
632
|
-
{
|
|
633
|
-
name: 'divider',
|
|
634
|
-
type: 'divider',
|
|
635
|
-
},
|
|
636
1296
|
{
|
|
637
1297
|
name: 'config',
|
|
638
1298
|
type: 'config',
|
|
@@ -809,7 +1469,7 @@ const KritzelEditor = class {
|
|
|
809
1469
|
}
|
|
810
1470
|
}
|
|
811
1471
|
render() {
|
|
812
|
-
return (h(Host, { key: '
|
|
1472
|
+
return (h(Host, { key: 'a39268fb2722bc9e1627a46a3430a574322dfdfb' }, h("kritzel-workspace-manager", { key: 'b0c08f2cab64347c0ee14a87ed0ab769a2e95733', workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), h("kritzel-engine", { key: 'c0efb9b0cdfdf3a9ba945e71e37c60ebfc45e981', ref: el => (this.engineRef = el), workspace: this.activeWorkspace, syncConfig: this.syncConfig, scaleMax: this.scaleMax, scaleMin: this.scaleMin, globalContextMenuItems: this.globalContextMenuItems, objectContextMenuItems: this.objectContextMenuItems, onIsEngineReady: event => this.onEngineReady(event), onWorkspacesChange: event => this.handleWorkspacesChange(event), onObjectsChange: event => this.handleObjectsChange(event), onUndoStateChange: event => this.handleUndoStateChange(event) }), h("kritzel-controls", { key: '5a275fb94e2f55a1f79d6d5b5f518305cd739f24', class: { 'keyboard-open': this.isVirtualKeyboardOpen }, style: { display: this.isControlsVisible ? 'flex' : 'none' }, ref: el => (this.controlsRef = el), controls: this.controls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState, onIsControlsReady: () => (this.isControlsReady = true) })));
|
|
813
1473
|
}
|
|
814
1474
|
static get watchers() { return {
|
|
815
1475
|
"isEngineReady": ["onIsEngineReady"],
|
|
@@ -18054,6 +18714,14 @@ class KritzelViewport {
|
|
|
18054
18714
|
this._core.rerender();
|
|
18055
18715
|
}, 100);
|
|
18056
18716
|
}
|
|
18717
|
+
/**
|
|
18718
|
+
* Cancels any pending debounced viewport updates.
|
|
18719
|
+
* Should be called before switching workspaces to prevent the old workspace's
|
|
18720
|
+
* viewport state from being saved to the new workspace.
|
|
18721
|
+
*/
|
|
18722
|
+
cancelPendingUpdates() {
|
|
18723
|
+
this._debounceUpdate.cancel();
|
|
18724
|
+
}
|
|
18057
18725
|
handleResize() {
|
|
18058
18726
|
this._core.store.state.viewportWidth = this._core.store.state.host.clientWidth;
|
|
18059
18727
|
this._core.store.state.viewportHeight = this._core.store.state.host.clientHeight;
|
|
@@ -18366,7 +19034,7 @@ const DEFAULT_ENGINE_CONFIG = {
|
|
|
18366
19034
|
contextMenuY: 0,
|
|
18367
19035
|
skipContextMenu: false,
|
|
18368
19036
|
debugInfo: {
|
|
18369
|
-
showObjectInfo:
|
|
19037
|
+
showObjectInfo: true,
|
|
18370
19038
|
showViewportInfo: false
|
|
18371
19039
|
},
|
|
18372
19040
|
host: null,
|
|
@@ -18475,6 +19143,17 @@ class KritzelReviver {
|
|
|
18475
19143
|
case 'KritzelText':
|
|
18476
19144
|
revivedObj = KritzelText.create(this._core, obj.fontSize, obj.fontFamily).deserialize(obj);
|
|
18477
19145
|
break;
|
|
19146
|
+
case 'KritzelShape':
|
|
19147
|
+
revivedObj = KritzelShape.create(this._core, {
|
|
19148
|
+
shapeType: obj.shapeType,
|
|
19149
|
+
fillColor: obj.fillColor,
|
|
19150
|
+
strokeColor: obj.strokeColor,
|
|
19151
|
+
strokeWidth: obj.strokeWidth,
|
|
19152
|
+
fontSize: obj.fontSize,
|
|
19153
|
+
fontFamily: obj.fontFamily,
|
|
19154
|
+
fontColor: obj.fontColor,
|
|
19155
|
+
}).deserialize(obj);
|
|
19156
|
+
break;
|
|
18478
19157
|
case 'KritzelImage':
|
|
18479
19158
|
revivedObj = KritzelImage.create(this._core).deserialize(obj);
|
|
18480
19159
|
break;
|
|
@@ -18505,6 +19184,9 @@ class KritzelReviver {
|
|
|
18505
19184
|
case 'KritzelLineTool':
|
|
18506
19185
|
revivedObj = new KritzelLineTool(this._core);
|
|
18507
19186
|
break;
|
|
19187
|
+
case 'KritzelShapeTool':
|
|
19188
|
+
revivedObj = new KritzelShapeTool(this._core);
|
|
19189
|
+
break;
|
|
18508
19190
|
default:
|
|
18509
19191
|
revivedObj = obj;
|
|
18510
19192
|
}
|
|
@@ -18980,6 +19662,10 @@ class KritzelStore {
|
|
|
18980
19662
|
const activeTexts = this._state.objects.filter(o => o instanceof KritzelText && o.isEditing);
|
|
18981
19663
|
return activeTexts.length > 0 ? activeTexts[0] : null;
|
|
18982
19664
|
}
|
|
19665
|
+
get activeShape() {
|
|
19666
|
+
const activeShapes = this._state.objects.filter(o => o instanceof KritzelShape && o.isEditing);
|
|
19667
|
+
return activeShapes.length > 0 ? activeShapes[0] : null;
|
|
19668
|
+
}
|
|
18983
19669
|
get currentPath() {
|
|
18984
19670
|
const drawingPaths = this._state.objects.filter(o => o instanceof KritzelPath && o.isCompleted === false);
|
|
18985
19671
|
return drawingPaths.length > 0 ? drawingPaths[0] : null;
|
|
@@ -19228,6 +19914,11 @@ class KritzelCore {
|
|
|
19228
19914
|
if (this._store.state.objects && this._store.state.objects.isReady) {
|
|
19229
19915
|
this._store.state.objects.destroy();
|
|
19230
19916
|
}
|
|
19917
|
+
// Create new ObjectMap with its own Y.Doc for this workspace
|
|
19918
|
+
const objectsMap = new KritzelObjectMap();
|
|
19919
|
+
// Assign immediately so the UI shows an empty state while loading,
|
|
19920
|
+
// instead of showing the old workspace's objects with the new workspace's viewport
|
|
19921
|
+
this._store.state.objects = objectsMap;
|
|
19231
19922
|
// Set active workspace
|
|
19232
19923
|
this._store.state.activeWorkspace = activeWorkspace;
|
|
19233
19924
|
this._store.state.workspaces = this.loadWorkspacesFromAppState();
|
|
@@ -19236,10 +19927,7 @@ class KritzelCore {
|
|
|
19236
19927
|
this._store.state.translateX = viewport.translateX ?? 0;
|
|
19237
19928
|
this._store.state.translateY = viewport.translateY ?? 0;
|
|
19238
19929
|
this._store.state.scale = viewport.scale ?? 1;
|
|
19239
|
-
// Create new ObjectMap with its own Y.Doc for this workspace
|
|
19240
|
-
const objectsMap = new KritzelObjectMap();
|
|
19241
19930
|
await objectsMap.initialize(this, activeWorkspace.id, this._syncConfig);
|
|
19242
|
-
this._store.state.objects = objectsMap;
|
|
19243
19931
|
// Rebuild anchor index after loading objects
|
|
19244
19932
|
this._anchorManager.rebuildIndex();
|
|
19245
19933
|
this.engine.emitObjectsChange();
|
|
@@ -19616,6 +20304,12 @@ class KritzelCore {
|
|
|
19616
20304
|
}
|
|
19617
20305
|
}
|
|
19618
20306
|
}
|
|
20307
|
+
resetActiveShape() {
|
|
20308
|
+
const activeShape = this._store.activeShape;
|
|
20309
|
+
if (activeShape) {
|
|
20310
|
+
activeShape.save();
|
|
20311
|
+
}
|
|
20312
|
+
}
|
|
19619
20313
|
getObjectFromPointerEvent(event, selector = '.object') {
|
|
19620
20314
|
const shadowRoot = this._store.state.host?.shadowRoot;
|
|
19621
20315
|
if (!shadowRoot)
|
|
@@ -19688,6 +20382,14 @@ class KritzelCore {
|
|
|
19688
20382
|
return { x: worldX, y: worldY };
|
|
19689
20383
|
}
|
|
19690
20384
|
beforeWorkspaceChange() {
|
|
20385
|
+
// Cancel any pending debounced viewport updates to prevent them from
|
|
20386
|
+
// saving the old workspace's viewport to the new workspace
|
|
20387
|
+
this._kritzelEngine.viewport?.cancelPendingUpdates();
|
|
20388
|
+
// Immediately save the current workspace's viewport before switching
|
|
20389
|
+
const currentWorkspace = this._store.state.activeWorkspace;
|
|
20390
|
+
if (currentWorkspace) {
|
|
20391
|
+
this.updateWorkspaceViewport(this._store.state.translateX, this._store.state.translateY, this._store.state.scale);
|
|
20392
|
+
}
|
|
19691
20393
|
this.resetActiveText();
|
|
19692
20394
|
this.clearSelection();
|
|
19693
20395
|
this._store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
|
|
@@ -20113,9 +20815,9 @@ const KritzelEngine = class {
|
|
|
20113
20815
|
height: this.core.store.state.viewportHeight / this.core.store.state.scale,
|
|
20114
20816
|
depth: 100,
|
|
20115
20817
|
};
|
|
20116
|
-
const visibleObjects = this.core.store.state.objects.query(viewportBounds);
|
|
20818
|
+
const visibleObjects = this.core.store.state.objects.query(viewportBounds).sort((a, b) => a.zIndex - b.zIndex);
|
|
20117
20819
|
this.core.cursorManager.applyCursor();
|
|
20118
|
-
return (h(Host, { key: '
|
|
20820
|
+
return (h(Host, { key: '209ccf8414c635c9e04ca4807c95a29c629071ec' }, this.core.store.state.debugInfo.showViewportInfo && (h("div", { key: 'df6a03d1341887960bb91cbaa0a5dca6880a9293', class: "debug-panel" }, h("div", { key: '65157757ec6549ad2af311085a9618ab661f5ac0' }, "ActiveWorkspaceId: ", this.core.store.state?.activeWorkspace?.id), h("div", { key: '20137b6c651a9aa8df15bce66d5bfe870a7af139' }, "ActiveWorkspaceName: ", this.core.store.state?.activeWorkspace?.name), h("div", { key: '49dd30286641236ae428c731bb181cb06269852e' }, "TranslateX: ", this.core.store.state?.translateX), h("div", { key: 'd8ee431a10335e99aec40a596817765d7ee3f67b' }, "TranslateY: ", this.core.store.state?.translateY), h("div", { key: '34b1f31146080780433d6c1718d13bbfe397cb9b' }, "ViewportWidth: ", this.core.store.state?.viewportWidth), h("div", { key: '4c279a106101cf808c91a2be4987569b21ae52b3' }, "ViewportHeight: ", this.core.store.state?.viewportHeight), h("div", { key: '6ebd7ad3c803ef45d58a74180c52e8be8af8bca3' }, "PointerCount: ", this.core.store.state.pointers.size), h("div", { key: '345970c8b2b54f3a0d8fe1d9bb1b7b33023db386' }, "Scale: ", this.core.store.state?.scale), h("div", { key: 'fc265ae0e71cf22311cab3006dfc29b9d24397d2' }, "ActiveTool: ", this.core.store.state?.activeTool?.name), h("div", { key: '9f921032a58b55e60f82d11a76f269051357d3e1' }, "HasViewportChanged: ", this.core.store.state?.hasViewportChanged ? 'true' : 'false'), h("div", { key: '6d197e06cc362a9ecb8bfe00d272aecfec2b49e1' }, "IsEnabled: ", this.core.store.state?.isEnabled ? 'true' : 'false'), h("div", { key: '5313589ba2a509c95a5730dcf29c4003d9884cbf' }, "IsScaling: ", this.core.store.state?.isScaling ? 'true' : 'false'), h("div", { key: '8af9f9d6e33a2897c20962048bbf2a058f9d4a45' }, "IsPanning: ", this.core.store.state?.isPanning ? 'true' : 'false'), h("div", { key: '81aec0050d3e2122643b61fd725e71b25d97bc27' }, "IsSelecting: ", this.isSelecting ? 'true' : 'false'), h("div", { key: 'c9956f05c01b74ee1666d9395a2715c3463fe401' }, "IsSelectionActive: ", this.isSelectionActive ? 'true' : 'false'), h("div", { key: 'ae0a01c8f8aafc08326b136720c6a75b6aec6299' }, "IsResizeHandleSelected: ", this.core.store.state.isResizeHandleSelected ? 'true' : 'false'), h("div", { key: '7816d40d73248a55120440e6d721325e1894178e' }, "IsRotationHandleSelected: ", this.core.store.state.isRotationHandleSelected ? 'true' : 'false'), h("div", { key: 'c22383bacca0ada584f2e8a8577523c905d74ae2' }, "IsRotationHandleHovered: ", this.core.store.state.isRotationHandleHovered ? 'true' : 'false'), h("div", { key: '8185a7318c6cdfde558cc372b79582d58b706f9e' }, "IsDrawing: ", this.core.store.state.isDrawing ? 'true' : 'false'), h("div", { key: '2d56b05377693ef032ab2316fa753ecedf264b9c' }, "IsWriting: ", this.core.store.state.isWriting ? 'true' : 'false'), h("div", { key: '2e2bf9fd321ef04dc0ac6dc21539eb0117c9fb23' }, "IsPointerDown: ", this.core.store.isPointerDown ? 'true' : 'false'), h("div", { key: '3118ab970d5d37e01405c42308fc051d675d4bfa' }, "PointerX: ", this.core.store.state?.pointerX), h("div", { key: 'd8a31065843f89552f2d9c03dcbca960a716fa6c' }, "PointerY: ", this.core.store.state?.pointerY), h("div", { key: 'cb8d28b6ea63cbb6572f761011fccb847b748227' }, "SelectedObjects: ", this.core.store.selectionGroup?.objects.length || 0), h("div", { key: 'd112a7e833c265085246817423557bfdc5b30b74' }, "ViewportCenter: (", viewportCenterX.toFixed(2), ", ", viewportCenterY.toFixed(2), ")"))), h("div", { key: 'df4f302192a8fc9644b7f883618b0a0f8a600dc8', id: "origin", class: "origin", style: {
|
|
20119
20821
|
transform: `matrix(${this.core.store.state?.scale}, 0, 0, ${this.core.store.state?.scale}, ${this.core.store.state?.translateX}, ${this.core.store.state?.translateY})`,
|
|
20120
20822
|
} }, visibleObjects?.map(object => {
|
|
20121
20823
|
return (h("div", { key: object.id, style: {
|
|
@@ -20161,7 +20863,32 @@ const KritzelEngine = class {
|
|
|
20161
20863
|
backgroundColor: object.backgroundColor,
|
|
20162
20864
|
overflow: 'visible',
|
|
20163
20865
|
textRendering: this.core.store.state.isScaling || this.core.store.state.isPanning ? 'optimizeSpeed' : 'auto',
|
|
20164
|
-
} })), KritzelClassHelper.isInstanceOf(object, '
|
|
20866
|
+
} })), KritzelClassHelper.isInstanceOf(object, 'KritzelShape') && (h("div", { ref: el => object.mount(el), onPointerDown: e => object.handlePointerDown(e), onPointerMove: e => object.handlePointerMove(e), onPointerUp: e => object.handlePointerUp(e), style: {
|
|
20867
|
+
width: '100%',
|
|
20868
|
+
height: '100%',
|
|
20869
|
+
position: 'relative',
|
|
20870
|
+
overflow: 'visible',
|
|
20871
|
+
} }, h("svg", { xmlns: "http://www.w3.org/2000/svg", style: {
|
|
20872
|
+
position: 'absolute',
|
|
20873
|
+
top: '0',
|
|
20874
|
+
left: '0',
|
|
20875
|
+
width: '100%',
|
|
20876
|
+
height: '100%',
|
|
20877
|
+
overflow: 'visible',
|
|
20878
|
+
pointerEvents: 'none',
|
|
20879
|
+
}, viewBox: object.viewBox, preserveAspectRatio: "none" }, h("path", { d: object.getSvgPath(), fill: object.fillColor, stroke: object.strokeColor, "stroke-width": object.strokeWidth })), h("div", { ref: el => object.mountTextEditor(el), style: {
|
|
20880
|
+
position: 'absolute',
|
|
20881
|
+
top: '0',
|
|
20882
|
+
left: '0',
|
|
20883
|
+
width: '100%',
|
|
20884
|
+
height: '100%',
|
|
20885
|
+
display: 'flex',
|
|
20886
|
+
alignItems: 'center',
|
|
20887
|
+
justifyContent: 'center',
|
|
20888
|
+
textAlign: 'center',
|
|
20889
|
+
overflow: 'hidden',
|
|
20890
|
+
pointerEvents: object.isEditing ? 'auto' : 'none',
|
|
20891
|
+
} }))), KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement') && (h("div", { ref: el => object.mount(el), style: {
|
|
20165
20892
|
width: '100%',
|
|
20166
20893
|
height: '100%',
|
|
20167
20894
|
pointerEvents: 'auto',
|
|
@@ -20177,7 +20904,13 @@ const KritzelEngine = class {
|
|
|
20177
20904
|
borderWidth: KritzelDevicesHelper.isFirefox() ? object.borderWidth + 'px' : '0',
|
|
20178
20905
|
borderStyle: KritzelDevicesHelper.isFirefox() ? 'solid' : 'none',
|
|
20179
20906
|
borderColor: KritzelDevicesHelper.isFirefox() ? object.borderColor : 'transparent',
|
|
20180
|
-
} }))), this.core.store.state.debugInfo.showObjectInfo && object.isDebugInfoVisible && (h("
|
|
20907
|
+
} })))), this.core.store.state.debugInfo.showObjectInfo && object.isDebugInfoVisible && (h("div", { style: {
|
|
20908
|
+
pointerEvents: 'none',
|
|
20909
|
+
position: 'absolute',
|
|
20910
|
+
left: `${object.totalWidth}px`,
|
|
20911
|
+
top: '0',
|
|
20912
|
+
zIndex: (object.zIndex + 2).toString(),
|
|
20913
|
+
} }, h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "Id: ", object.id), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "width: ", object.width), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "height: ", object.height), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateX: ", object.translateX), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateY: ", object.translateY), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "rotationDegrees: ", object.rotationDegrees), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "zIndex: ", object.zIndex))), h("svg", { xmlns: "http://www.w3.org/2000/svg", style: {
|
|
20181
20914
|
zIndex: (object.zIndex + 1).toString(),
|
|
20182
20915
|
height: object?.totalHeight.toString(),
|
|
20183
20916
|
width: object?.totalWidth.toString(),
|
|
@@ -20333,7 +21066,7 @@ const KritzelEngine = class {
|
|
|
20333
21066
|
stroke: 'var(--kritzel-snap-indicator-stroke, #3b82f6)',
|
|
20334
21067
|
strokeWidth: data.indicatorStrokeWidth,
|
|
20335
21068
|
} }))));
|
|
20336
|
-
})()), this.core.store.state.isContextMenuVisible && (h("kritzel-context-menu", { key: '
|
|
21069
|
+
})()), this.core.store.state.isContextMenuVisible && (h("kritzel-context-menu", { key: '81b44614c23f4016a1daa914ef8ea73eda0869eb', class: "context-menu", ref: el => (this.contextMenuElement = el), items: this.core.store.state.contextMenuItems, objects: this.core.store.selectionGroup?.objects || [], style: {
|
|
20337
21070
|
position: 'fixed',
|
|
20338
21071
|
left: `${this.core.store.state.contextMenuX}px`,
|
|
20339
21072
|
top: `${this.core.store.state.contextMenuY}px`,
|
|
@@ -20344,7 +21077,7 @@ const KritzelEngine = class {
|
|
|
20344
21077
|
y: (-this.core.store.state.translateY + this.core.store.state.contextMenuY) / this.core.store.state.scale,
|
|
20345
21078
|
}, this.core.store.selectionGroup?.objects);
|
|
20346
21079
|
this.hideContextMenu();
|
|
20347
|
-
}, onClose: () => this.hideContextMenu() })), this.core.store.state?.activeTool instanceof KritzelEraserTool && !this.core.store.state.isScaling && h("kritzel-cursor-trail", { key: '
|
|
21080
|
+
}, onClose: () => this.hideContextMenu() })), this.core.store.state?.activeTool instanceof KritzelEraserTool && !this.core.store.state.isScaling && h("kritzel-cursor-trail", { key: 'f748cd15c916d9fcb5fbf445167c69c1cc8aea63', core: this.core })));
|
|
20348
21081
|
}
|
|
20349
21082
|
static get watchers() { return {
|
|
20350
21083
|
"workspace": ["onWorkspaceChange"],
|