kritzel-stencil 0.0.161 → 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-text-tool.config-zB3FPuXq.js → default-line-tool.config-DJMYrkSu.js} +6301 -3866
- package/dist/cjs/default-line-tool.config-DJMYrkSu.js.map +1 -0
- package/dist/cjs/index.cjs.js +131 -127
- package/dist/cjs/index.cjs.js.map +1 -1
- package/dist/cjs/kritzel-color_22.cjs.entry.js +1233 -167
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/stencil.cjs.js +1 -1
- package/dist/collection/classes/core/core.class.js +159 -6
- package/dist/collection/classes/core/core.class.js.map +1 -1
- package/dist/collection/classes/core/reviver.class.js +24 -0
- package/dist/collection/classes/core/reviver.class.js.map +1 -1
- package/dist/collection/classes/core/store.class.js +10 -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/handlers/line-handle.handler.js +383 -0
- package/dist/collection/classes/handlers/line-handle.handler.js.map +1 -0
- package/dist/collection/classes/handlers/move.handler.js +2 -2
- package/dist/collection/classes/handlers/move.handler.js.map +1 -1
- package/dist/collection/classes/managers/anchor.manager.js +1052 -0
- package/dist/collection/classes/managers/anchor.manager.js.map +1 -0
- package/dist/collection/classes/managers/cursor.manager.js +117 -0
- package/dist/collection/classes/managers/cursor.manager.js.map +1 -0
- package/dist/collection/classes/objects/base-object.class.js +4 -2
- package/dist/collection/classes/objects/base-object.class.js.map +1 -1
- package/dist/collection/classes/objects/line.class.js +564 -0
- package/dist/collection/classes/objects/line.class.js.map +1 -0
- 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/selection-group.class.js +4 -0
- package/dist/collection/classes/objects/selection-group.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 +5 -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 +172 -0
- package/dist/collection/classes/tools/line-tool.class.js.map +1 -0
- package/dist/collection/classes/tools/selection-tool.class.js +41 -8
- package/dist/collection/classes/tools/selection-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 +26 -6
- package/dist/collection/components/core/kritzel-editor/kritzel-editor.js.map +1 -1
- package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +168 -60
- 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 +5 -1
- package/dist/collection/configs/default-engine-config.js.map +1 -1
- package/dist/collection/configs/default-line-tool.config.js +34 -0
- package/dist/collection/configs/default-line-tool.config.js.map +1 -0
- 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 +97 -0
- package/dist/collection/helpers/geometry.helper.js.map +1 -1
- package/dist/collection/index.js +5 -0
- package/dist/collection/index.js.map +1 -1
- package/dist/collection/interfaces/anchor.interface.js +2 -0
- package/dist/collection/interfaces/anchor.interface.js.map +1 -0
- package/dist/collection/interfaces/arrow-head.interface.js +2 -0
- package/dist/collection/interfaces/arrow-head.interface.js.map +1 -0
- package/dist/collection/interfaces/engine-state.interface.js.map +1 -1
- package/dist/collection/interfaces/line-options.interface.js +2 -0
- package/dist/collection/interfaces/line-options.interface.js.map +1 -0
- package/dist/collection/interfaces/toolbar-control.interface.js.map +1 -1
- package/dist/components/index.js +4 -4
- 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 +91 -17
- 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-DxNbcUzt.js → p-5OECjGHq.js} +3 -3
- package/dist/components/{p-DxNbcUzt.js.map → p-5OECjGHq.js.map} +1 -1
- package/dist/components/{p-i0IlGLv2.js → p-BSBMBjhq.js} +3 -3
- package/dist/components/{p-i0IlGLv2.js.map → p-BSBMBjhq.js.map} +1 -1
- package/dist/components/{p-BdZKPKnx.js → p-BuS7MM1j.js} +4 -4
- package/dist/components/{p-BdZKPKnx.js.map → p-BuS7MM1j.js.map} +1 -1
- package/dist/components/{p-D7BLVRXX.js → p-CnRfQsIC.js} +3716 -554
- package/dist/components/p-CnRfQsIC.js.map +1 -0
- package/dist/components/{p-DbKKCHKd.js → p-Cv4BGNPb.js} +7 -2
- package/dist/components/p-Cv4BGNPb.js.map +1 -0
- package/dist/components/{p-D_ygcWSz.js → p-D1YAsWrL.js} +3 -3
- package/dist/components/{p-D_ygcWSz.js.map → p-D1YAsWrL.js.map} +1 -1
- package/dist/components/{p-Doixm8-N.js → p-D8L0t-Ro.js} +3 -3
- package/dist/components/{p-Doixm8-N.js.map → p-D8L0t-Ro.js.map} +1 -1
- package/dist/components/{p-CC8KFHSe.js → p-DguzZn_x.js} +3 -3
- package/dist/components/{p-CC8KFHSe.js.map → p-DguzZn_x.js.map} +1 -1
- package/dist/components/{p-CBYBurdY.js → p-Dz2XHHqa.js} +191 -7
- package/dist/components/p-Dz2XHHqa.js.map +1 -0
- package/dist/components/{p-58y59Acb.js → p-I3iPEDpx.js} +5 -5
- package/dist/components/{p-58y59Acb.js.map → p-I3iPEDpx.js.map} +1 -1
- package/dist/components/{p-BpXgwgnV.js → p-tp96UZ0l.js} +83 -19
- package/dist/components/p-tp96UZ0l.js.map +1 -0
- package/dist/esm/{default-text-tool.config-BvCgOiKA.js → default-line-tool.config-C35P3XfD.js} +6288 -3867
- 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 +1154 -88
- 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 +19 -0
- package/dist/types/classes/core/store.class.d.ts +4 -0
- package/dist/types/classes/core/viewport.class.d.ts +6 -0
- package/dist/types/classes/handlers/line-handle.handler.d.ts +34 -0
- package/dist/types/classes/managers/anchor.manager.d.ts +180 -0
- package/dist/types/classes/managers/cursor.manager.d.ts +43 -0
- package/dist/types/classes/objects/line.class.d.ts +98 -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/line-tool.class.d.ts +17 -0
- package/dist/types/classes/tools/selection-tool.class.d.ts +4 -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 -4
- 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-line-tool.config.d.ts +2 -0
- 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 +31 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/interfaces/anchor.interface.d.ts +137 -0
- package/dist/types/interfaces/arrow-head.interface.d.ts +26 -0
- package/dist/types/interfaces/engine-state.interface.d.ts +8 -0
- package/dist/types/interfaces/line-options.interface.d.ts +21 -0
- package/dist/types/interfaces/toolbar-control.interface.d.ts +36 -2
- package/package.json +1 -1
- package/dist/cjs/default-text-tool.config-zB3FPuXq.js.map +0 -1
- package/dist/components/p-BpXgwgnV.js.map +0 -1
- package/dist/components/p-CBYBurdY.js.map +0 -1
- package/dist/components/p-D7BLVRXX.js.map +0 -1
- package/dist/components/p-DbKKCHKd.js.map +0 -1
- package/dist/esm/default-text-tool.config-BvCgOiKA.js.map +0 -1
- package/dist/stencil/p-6d9756d9.entry.js +0 -10
- package/dist/stencil/p-6d9756d9.entry.js.map +0 -1
- package/dist/stencil/p-BvCgOiKA.js +0 -2
- package/dist/stencil/p-BvCgOiKA.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 {
|
|
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
|
|
|
@@ -603,6 +1255,13 @@ const KritzelEditor = class {
|
|
|
603
1255
|
icon: 'pen',
|
|
604
1256
|
config: DEFAULT_BRUSH_CONFIG,
|
|
605
1257
|
},
|
|
1258
|
+
{
|
|
1259
|
+
name: 'line',
|
|
1260
|
+
type: 'tool',
|
|
1261
|
+
tool: KritzelLineTool,
|
|
1262
|
+
icon: 'arrow',
|
|
1263
|
+
config: DEFAULT_LINE_TOOL_CONFIG,
|
|
1264
|
+
},
|
|
606
1265
|
{
|
|
607
1266
|
name: 'eraser',
|
|
608
1267
|
type: 'tool',
|
|
@@ -616,16 +1275,24 @@ const KritzelEditor = class {
|
|
|
616
1275
|
icon: 'type',
|
|
617
1276
|
config: DEFAULT_TEXT_CONFIG,
|
|
618
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
|
+
},
|
|
619
1290
|
{
|
|
620
1291
|
name: 'image',
|
|
621
1292
|
type: 'tool',
|
|
622
1293
|
tool: KritzelImageTool,
|
|
623
1294
|
icon: 'image',
|
|
624
1295
|
},
|
|
625
|
-
{
|
|
626
|
-
name: 'divider',
|
|
627
|
-
type: 'divider',
|
|
628
|
-
},
|
|
629
1296
|
{
|
|
630
1297
|
name: 'config',
|
|
631
1298
|
type: 'config',
|
|
@@ -802,7 +1469,7 @@ const KritzelEditor = class {
|
|
|
802
1469
|
}
|
|
803
1470
|
}
|
|
804
1471
|
render() {
|
|
805
|
-
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) })));
|
|
806
1473
|
}
|
|
807
1474
|
static get watchers() { return {
|
|
808
1475
|
"isEngineReady": ["onIsEngineReady"],
|
|
@@ -18047,6 +18714,14 @@ class KritzelViewport {
|
|
|
18047
18714
|
this._core.rerender();
|
|
18048
18715
|
}, 100);
|
|
18049
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
|
+
}
|
|
18050
18725
|
handleResize() {
|
|
18051
18726
|
this._core.store.state.viewportWidth = this._core.store.state.host.clientWidth;
|
|
18052
18727
|
this._core.store.state.viewportHeight = this._core.store.state.host.clientHeight;
|
|
@@ -18325,18 +19000,14 @@ class KritzelContextMenuHandler extends KritzelBaseHandler {
|
|
|
18325
19000
|
}
|
|
18326
19001
|
}
|
|
18327
19002
|
|
|
18328
|
-
class KritzelClassHelper {
|
|
18329
|
-
static isInstanceOf(object, className) {
|
|
18330
|
-
return !!object && object.__class__ === className;
|
|
18331
|
-
}
|
|
18332
|
-
}
|
|
18333
|
-
|
|
18334
19003
|
const DEFAULT_ENGINE_CONFIG = {
|
|
18335
19004
|
activeWorkspace: null,
|
|
18336
19005
|
activeTool: null,
|
|
18337
19006
|
copiedObjects: null,
|
|
18338
19007
|
objects: null,
|
|
19008
|
+
snapCandidate: null,
|
|
18339
19009
|
resizeHandleType: null,
|
|
19010
|
+
lineHandleType: null,
|
|
18340
19011
|
hasViewportChanged: false,
|
|
18341
19012
|
hasObjectsChanged: false,
|
|
18342
19013
|
isReady: false,
|
|
@@ -18350,6 +19021,8 @@ const DEFAULT_ENGINE_CONFIG = {
|
|
|
18350
19021
|
isRotating: false,
|
|
18351
19022
|
isRotationHandleHovered: false,
|
|
18352
19023
|
isRotationHandleSelected: false,
|
|
19024
|
+
isLineHandleSelected: false,
|
|
19025
|
+
isLineHandleDragging: false,
|
|
18353
19026
|
isDragging: false,
|
|
18354
19027
|
isDrawing: false,
|
|
18355
19028
|
isErasing: false,
|
|
@@ -18361,7 +19034,7 @@ const DEFAULT_ENGINE_CONFIG = {
|
|
|
18361
19034
|
contextMenuY: 0,
|
|
18362
19035
|
skipContextMenu: false,
|
|
18363
19036
|
debugInfo: {
|
|
18364
|
-
showObjectInfo:
|
|
19037
|
+
showObjectInfo: true,
|
|
18365
19038
|
showViewportInfo: false
|
|
18366
19039
|
},
|
|
18367
19040
|
host: null,
|
|
@@ -18464,9 +19137,23 @@ class KritzelReviver {
|
|
|
18464
19137
|
case 'KritzelPath':
|
|
18465
19138
|
revivedObj = KritzelPath.create(this._core).deserialize(obj);
|
|
18466
19139
|
break;
|
|
19140
|
+
case 'KritzelLine':
|
|
19141
|
+
revivedObj = KritzelLine.create(this._core).deserialize(obj);
|
|
19142
|
+
break;
|
|
18467
19143
|
case 'KritzelText':
|
|
18468
19144
|
revivedObj = KritzelText.create(this._core, obj.fontSize, obj.fontFamily).deserialize(obj);
|
|
18469
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;
|
|
18470
19157
|
case 'KritzelImage':
|
|
18471
19158
|
revivedObj = KritzelImage.create(this._core).deserialize(obj);
|
|
18472
19159
|
break;
|
|
@@ -18494,6 +19181,12 @@ class KritzelReviver {
|
|
|
18494
19181
|
case 'KritzelTextTool':
|
|
18495
19182
|
revivedObj = new KritzelTextTool(this._core);
|
|
18496
19183
|
break;
|
|
19184
|
+
case 'KritzelLineTool':
|
|
19185
|
+
revivedObj = new KritzelLineTool(this._core);
|
|
19186
|
+
break;
|
|
19187
|
+
case 'KritzelShapeTool':
|
|
19188
|
+
revivedObj = new KritzelShapeTool(this._core);
|
|
19189
|
+
break;
|
|
18497
19190
|
default:
|
|
18498
19191
|
revivedObj = obj;
|
|
18499
19192
|
}
|
|
@@ -18969,10 +19662,18 @@ class KritzelStore {
|
|
|
18969
19662
|
const activeTexts = this._state.objects.filter(o => o instanceof KritzelText && o.isEditing);
|
|
18970
19663
|
return activeTexts.length > 0 ? activeTexts[0] : null;
|
|
18971
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
|
+
}
|
|
18972
19669
|
get currentPath() {
|
|
18973
19670
|
const drawingPaths = this._state.objects.filter(o => o instanceof KritzelPath && o.isCompleted === false);
|
|
18974
19671
|
return drawingPaths.length > 0 ? drawingPaths[0] : null;
|
|
18975
19672
|
}
|
|
19673
|
+
get currentLine() {
|
|
19674
|
+
const drawingLines = this._state.objects.filter(o => o instanceof KritzelLine && o.isCompleted === false);
|
|
19675
|
+
return drawingLines.length > 0 ? drawingLines[0] : null;
|
|
19676
|
+
}
|
|
18976
19677
|
get offsetX() {
|
|
18977
19678
|
return this._state.host.getBoundingClientRect().left;
|
|
18978
19679
|
}
|
|
@@ -19009,11 +19710,129 @@ class KritzelStore {
|
|
|
19009
19710
|
}
|
|
19010
19711
|
}
|
|
19011
19712
|
|
|
19713
|
+
/**
|
|
19714
|
+
* Manages cursor state and updates across the application.
|
|
19715
|
+
* Handles cursor changes based on handle hovers, tool states, and interactions.
|
|
19716
|
+
*/
|
|
19717
|
+
class KritzelCursorManager {
|
|
19718
|
+
_core;
|
|
19719
|
+
_targetElement = null;
|
|
19720
|
+
_shadowRoot = null;
|
|
19721
|
+
constructor(core) {
|
|
19722
|
+
this._core = core;
|
|
19723
|
+
}
|
|
19724
|
+
/**
|
|
19725
|
+
* Sets the target element where cursor styles will be applied.
|
|
19726
|
+
* Also sets the pointer cursor CSS variable for child components.
|
|
19727
|
+
*/
|
|
19728
|
+
setTargetElement(element) {
|
|
19729
|
+
// Reset cursor on old target
|
|
19730
|
+
if (this._targetElement) {
|
|
19731
|
+
this._targetElement.style.cursor = '';
|
|
19732
|
+
this._targetElement.style.removeProperty('--kritzel-pointer-cursor');
|
|
19733
|
+
}
|
|
19734
|
+
this._targetElement = element;
|
|
19735
|
+
// Set the pointer cursor CSS variable for child components to use
|
|
19736
|
+
if (this._targetElement) {
|
|
19737
|
+
this._targetElement.style.setProperty('--kritzel-pointer-cursor', KritzelCursorHelper.getPointerCursor());
|
|
19738
|
+
}
|
|
19739
|
+
}
|
|
19740
|
+
/**
|
|
19741
|
+
* Gets the current cursor target element.
|
|
19742
|
+
*/
|
|
19743
|
+
getTargetElement() {
|
|
19744
|
+
return this._targetElement;
|
|
19745
|
+
}
|
|
19746
|
+
/**
|
|
19747
|
+
* Sets the shadow root for element detection.
|
|
19748
|
+
*/
|
|
19749
|
+
setShadowRoot(shadowRoot) {
|
|
19750
|
+
this._shadowRoot = shadowRoot;
|
|
19751
|
+
}
|
|
19752
|
+
/**
|
|
19753
|
+
* Resets cursor to default state.
|
|
19754
|
+
* Should be called when all pointers are released.
|
|
19755
|
+
*/
|
|
19756
|
+
resetToDefault() {
|
|
19757
|
+
this._core.store.state.cursor = { icon: 'default', iconActive: 'default' };
|
|
19758
|
+
}
|
|
19759
|
+
/**
|
|
19760
|
+
* Detects handle hover states using elementsFromPoint() to work with overlapped elements.
|
|
19761
|
+
* This approach finds all elements at the pointer position instead of relying on pointerenter/pointerleave.
|
|
19762
|
+
*/
|
|
19763
|
+
updateHoverState(ev) {
|
|
19764
|
+
if (this._core.store.isPointerDown)
|
|
19765
|
+
return;
|
|
19766
|
+
if (!this._shadowRoot)
|
|
19767
|
+
return;
|
|
19768
|
+
const elementsAtPoint = this._shadowRoot.elementsFromPoint(ev.clientX, ev.clientY);
|
|
19769
|
+
if (!elementsAtPoint || elementsAtPoint.length === 0)
|
|
19770
|
+
return;
|
|
19771
|
+
// Check for resize handle overlays (selection group)
|
|
19772
|
+
const resizeHandleOverlay = elementsAtPoint.find(el => el.classList.contains('resize-handle-overlay'));
|
|
19773
|
+
if (resizeHandleOverlay) {
|
|
19774
|
+
const selectionGroup = this._core.store.selectionGroup;
|
|
19775
|
+
const rotationDegrees = selectionGroup?.rotationDegrees ?? 0;
|
|
19776
|
+
// Determine rotation offset based on handle position
|
|
19777
|
+
const isTopLeft = resizeHandleOverlay.classList.contains('top-left');
|
|
19778
|
+
const isBottomRight = resizeHandleOverlay.classList.contains('bottom-right');
|
|
19779
|
+
const rotationOffset = (isTopLeft || isBottomRight) ? -45 : 45;
|
|
19780
|
+
this._core.store.state.cursor = { icon: 'move-vertical', rotation: rotationDegrees + rotationOffset };
|
|
19781
|
+
return;
|
|
19782
|
+
}
|
|
19783
|
+
// Check for rotation handle overlay
|
|
19784
|
+
const rotationHandleOverlay = elementsAtPoint.find(el => el.classList.contains('rotation-handle-overlay'));
|
|
19785
|
+
if (rotationHandleOverlay) {
|
|
19786
|
+
this._core.store.state.cursor = { icon: 'hand', iconActive: 'hand-grab' };
|
|
19787
|
+
return;
|
|
19788
|
+
}
|
|
19789
|
+
// Check for line handle overlays (selection line)
|
|
19790
|
+
const lineHandleOverlay = elementsAtPoint.find(el => el.classList.contains('selection-line-handle-overlay'));
|
|
19791
|
+
if (lineHandleOverlay) {
|
|
19792
|
+
this._core.store.state.cursor = { icon: 'hand', iconActive: 'hand-grab' };
|
|
19793
|
+
return;
|
|
19794
|
+
}
|
|
19795
|
+
// Reset cursor if not hovering any handle
|
|
19796
|
+
this._core.store.state.cursor = { icon: 'default', iconActive: 'default' };
|
|
19797
|
+
}
|
|
19798
|
+
/**
|
|
19799
|
+
* Applies the current cursor state to the target element.
|
|
19800
|
+
* Should be called in the render loop.
|
|
19801
|
+
*/
|
|
19802
|
+
applyCursor() {
|
|
19803
|
+
const state = this._core.store.state;
|
|
19804
|
+
const isPointerDown = this._core.store.isPointerDown;
|
|
19805
|
+
const icon = state.cursor?.icon;
|
|
19806
|
+
const iconActive = state.cursor?.iconActive ?? icon;
|
|
19807
|
+
const rotation = state.cursor?.rotation;
|
|
19808
|
+
const cursor = KritzelCursorHelper.getCursor({
|
|
19809
|
+
iconName: isPointerDown ? iconActive : icon,
|
|
19810
|
+
rotation: rotation,
|
|
19811
|
+
});
|
|
19812
|
+
if (this._targetElement) {
|
|
19813
|
+
this._targetElement.style.cursor = cursor;
|
|
19814
|
+
}
|
|
19815
|
+
}
|
|
19816
|
+
/**
|
|
19817
|
+
* Cleans up cursor state when the component is disconnected.
|
|
19818
|
+
*/
|
|
19819
|
+
cleanup() {
|
|
19820
|
+
if (this._targetElement) {
|
|
19821
|
+
this._targetElement.style.cursor = '';
|
|
19822
|
+
this._targetElement.style.removeProperty('--kritzel-pointer-cursor');
|
|
19823
|
+
}
|
|
19824
|
+
this._targetElement = null;
|
|
19825
|
+
this._shadowRoot = null;
|
|
19826
|
+
}
|
|
19827
|
+
}
|
|
19828
|
+
|
|
19012
19829
|
class KritzelCore {
|
|
19013
19830
|
_kritzelEngine;
|
|
19014
19831
|
_store;
|
|
19015
19832
|
_syncConfig;
|
|
19016
19833
|
_appStateMap;
|
|
19834
|
+
_anchorManager;
|
|
19835
|
+
_cursorManager;
|
|
19017
19836
|
get engine() {
|
|
19018
19837
|
return this._kritzelEngine;
|
|
19019
19838
|
}
|
|
@@ -19023,10 +19842,18 @@ class KritzelCore {
|
|
|
19023
19842
|
get appStateMap() {
|
|
19024
19843
|
return this._appStateMap;
|
|
19025
19844
|
}
|
|
19845
|
+
get anchorManager() {
|
|
19846
|
+
return this._anchorManager;
|
|
19847
|
+
}
|
|
19848
|
+
get cursorManager() {
|
|
19849
|
+
return this._cursorManager;
|
|
19850
|
+
}
|
|
19026
19851
|
constructor(kritzelEngine) {
|
|
19027
19852
|
this._kritzelEngine = kritzelEngine;
|
|
19028
19853
|
this._store = new KritzelStore(DEFAULT_ENGINE_CONFIG);
|
|
19029
19854
|
this._appStateMap = new KritzelAppStateMap();
|
|
19855
|
+
this._anchorManager = new KritzelAnchorManager(this);
|
|
19856
|
+
this._cursorManager = new KritzelCursorManager(this);
|
|
19030
19857
|
}
|
|
19031
19858
|
setSyncConfig(config) {
|
|
19032
19859
|
this._syncConfig = config;
|
|
@@ -19087,6 +19914,11 @@ class KritzelCore {
|
|
|
19087
19914
|
if (this._store.state.objects && this._store.state.objects.isReady) {
|
|
19088
19915
|
this._store.state.objects.destroy();
|
|
19089
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;
|
|
19090
19922
|
// Set active workspace
|
|
19091
19923
|
this._store.state.activeWorkspace = activeWorkspace;
|
|
19092
19924
|
this._store.state.workspaces = this.loadWorkspacesFromAppState();
|
|
@@ -19095,10 +19927,9 @@ class KritzelCore {
|
|
|
19095
19927
|
this._store.state.translateX = viewport.translateX ?? 0;
|
|
19096
19928
|
this._store.state.translateY = viewport.translateY ?? 0;
|
|
19097
19929
|
this._store.state.scale = viewport.scale ?? 1;
|
|
19098
|
-
// Create new ObjectMap with its own Y.Doc for this workspace
|
|
19099
|
-
const objectsMap = new KritzelObjectMap();
|
|
19100
19930
|
await objectsMap.initialize(this, activeWorkspace.id, this._syncConfig);
|
|
19101
|
-
|
|
19931
|
+
// Rebuild anchor index after loading objects
|
|
19932
|
+
this._anchorManager.rebuildIndex();
|
|
19102
19933
|
this.engine.emitObjectsChange();
|
|
19103
19934
|
this.rerender();
|
|
19104
19935
|
}
|
|
@@ -19159,6 +19990,15 @@ class KritzelCore {
|
|
|
19159
19990
|
this._store.state.objects.insert(object);
|
|
19160
19991
|
}
|
|
19161
19992
|
removeObject(object) {
|
|
19993
|
+
// Handle anchor cleanup
|
|
19994
|
+
if (object instanceof KritzelLine) {
|
|
19995
|
+
// If removing a line, clean up its anchor index entries
|
|
19996
|
+
this._anchorManager.handleLineDeleted(object.id);
|
|
19997
|
+
}
|
|
19998
|
+
else {
|
|
19999
|
+
// If removing a non-line object, detach any lines anchored to it
|
|
20000
|
+
this._anchorManager.handleObjectDeleted(object.id);
|
|
20001
|
+
}
|
|
19162
20002
|
object.isMounted = false;
|
|
19163
20003
|
this._store.state.objects.remove(o => o.id === object.id);
|
|
19164
20004
|
}
|
|
@@ -19216,8 +20056,18 @@ class KritzelCore {
|
|
|
19216
20056
|
copy() {
|
|
19217
20057
|
const selectionGroup = this._store.selectionGroup;
|
|
19218
20058
|
if (selectionGroup) {
|
|
19219
|
-
// Copy each object and store them in an array
|
|
19220
|
-
|
|
20059
|
+
// Copy each object and store them in an array, also track the ID mapping
|
|
20060
|
+
const idMapping = new Map();
|
|
20061
|
+
const copiedObjects = selectionGroup.objects
|
|
20062
|
+
.sort((a, b) => a.zIndex - b.zIndex)
|
|
20063
|
+
.map(obj => {
|
|
20064
|
+
const copiedObj = obj.copy();
|
|
20065
|
+
// Map: newId -> originalId
|
|
20066
|
+
idMapping.set(copiedObj.id, obj.id);
|
|
20067
|
+
return copiedObj;
|
|
20068
|
+
});
|
|
20069
|
+
this._store.state.copiedObjects = copiedObjects;
|
|
20070
|
+
this._store.state.copiedObjectIdMapping = idMapping;
|
|
19221
20071
|
}
|
|
19222
20072
|
}
|
|
19223
20073
|
paste(x, y) {
|
|
@@ -19226,6 +20076,7 @@ class KritzelCore {
|
|
|
19226
20076
|
return;
|
|
19227
20077
|
}
|
|
19228
20078
|
const activeWorkspace = this._store.state.activeWorkspace;
|
|
20079
|
+
const originalIdMapping = this._store.state.copiedObjectIdMapping;
|
|
19229
20080
|
// Check if we're pasting from a different workspace
|
|
19230
20081
|
const isDifferentWorkspace = copiedObjects.some(obj => obj.workspaceId !== activeWorkspace.id);
|
|
19231
20082
|
// Calculate the bounding box of all copied objects
|
|
@@ -19257,6 +20108,14 @@ class KritzelCore {
|
|
|
19257
20108
|
this.removeSelectionBox();
|
|
19258
20109
|
// Create a new selection group for the pasted objects
|
|
19259
20110
|
const selectionGroup = KritzelSelectionGroup.create(this);
|
|
20111
|
+
// Build a reverse mapping: originalId -> newCopiedObjectId
|
|
20112
|
+
// This is used to remap anchor references from original IDs to the copied object IDs
|
|
20113
|
+
const originalToNewIdMap = new Map();
|
|
20114
|
+
if (originalIdMapping) {
|
|
20115
|
+
originalIdMapping.forEach((originalId, copiedId) => {
|
|
20116
|
+
originalToNewIdMap.set(originalId, copiedId);
|
|
20117
|
+
});
|
|
20118
|
+
}
|
|
19260
20119
|
// First add all copied objects to the objectsMap with updated positions
|
|
19261
20120
|
copiedObjects.forEach((obj, i) => {
|
|
19262
20121
|
// Update workspace if pasting to a different workspace
|
|
@@ -19272,6 +20131,27 @@ class KritzelCore {
|
|
|
19272
20131
|
// Add to selection group
|
|
19273
20132
|
selectionGroup.addOrRemove(obj);
|
|
19274
20133
|
});
|
|
20134
|
+
// Update line anchors to point to the newly pasted objects
|
|
20135
|
+
// Only remap if the anchor target was also part of the copied selection
|
|
20136
|
+
copiedObjects.forEach(obj => {
|
|
20137
|
+
if (obj instanceof KritzelLine) {
|
|
20138
|
+
let updated = false;
|
|
20139
|
+
if (obj.startAnchor && originalToNewIdMap.has(obj.startAnchor.objectId)) {
|
|
20140
|
+
obj.startAnchor = { objectId: originalToNewIdMap.get(obj.startAnchor.objectId) };
|
|
20141
|
+
updated = true;
|
|
20142
|
+
}
|
|
20143
|
+
if (obj.endAnchor && originalToNewIdMap.has(obj.endAnchor.objectId)) {
|
|
20144
|
+
obj.endAnchor = { objectId: originalToNewIdMap.get(obj.endAnchor.objectId) };
|
|
20145
|
+
updated = true;
|
|
20146
|
+
}
|
|
20147
|
+
// If anchors were updated, rebuild the anchor index and persist the change
|
|
20148
|
+
if (updated) {
|
|
20149
|
+
this._store.state.objects.update(obj);
|
|
20150
|
+
}
|
|
20151
|
+
}
|
|
20152
|
+
});
|
|
20153
|
+
// Rebuild anchor index after all anchor updates
|
|
20154
|
+
this._anchorManager.rebuildIndex();
|
|
19275
20155
|
// Mark selection group as selected
|
|
19276
20156
|
selectionGroup.isSelected = true;
|
|
19277
20157
|
// Set rotation for single object
|
|
@@ -19297,7 +20177,17 @@ class KritzelCore {
|
|
|
19297
20177
|
// Update copiedObjects to the newly created objects for potential future pastes
|
|
19298
20178
|
const newSelectionGroup = this._store.selectionGroup;
|
|
19299
20179
|
if (newSelectionGroup) {
|
|
19300
|
-
|
|
20180
|
+
// Create new copies and track the ID mapping for future pastes
|
|
20181
|
+
const newIdMapping = new Map();
|
|
20182
|
+
const newCopiedObjects = newSelectionGroup.objects
|
|
20183
|
+
.sort((a, b) => a.zIndex - b.zIndex)
|
|
20184
|
+
.map(obj => {
|
|
20185
|
+
const copiedObj = obj.copy();
|
|
20186
|
+
newIdMapping.set(copiedObj.id, obj.id);
|
|
20187
|
+
return copiedObj;
|
|
20188
|
+
});
|
|
20189
|
+
this._store.state.copiedObjects = newCopiedObjects;
|
|
20190
|
+
this._store.state.copiedObjectIdMapping = newIdMapping;
|
|
19301
20191
|
}
|
|
19302
20192
|
this._store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
|
|
19303
20193
|
this.engine.emitObjectsChange();
|
|
@@ -19398,6 +20288,9 @@ class KritzelCore {
|
|
|
19398
20288
|
this._store.state.isSelecting = false;
|
|
19399
20289
|
this._store.state.isResizeHandleSelected = false;
|
|
19400
20290
|
this._store.state.isRotationHandleSelected = false;
|
|
20291
|
+
this._store.state.isLineHandleSelected = false;
|
|
20292
|
+
this._store.state.isLineHandleDragging = false;
|
|
20293
|
+
this._store.state.lineHandleType = null;
|
|
19401
20294
|
this.rerender();
|
|
19402
20295
|
}
|
|
19403
20296
|
resetActiveText() {
|
|
@@ -19411,6 +20304,12 @@ class KritzelCore {
|
|
|
19411
20304
|
}
|
|
19412
20305
|
}
|
|
19413
20306
|
}
|
|
20307
|
+
resetActiveShape() {
|
|
20308
|
+
const activeShape = this._store.activeShape;
|
|
20309
|
+
if (activeShape) {
|
|
20310
|
+
activeShape.save();
|
|
20311
|
+
}
|
|
20312
|
+
}
|
|
19414
20313
|
getObjectFromPointerEvent(event, selector = '.object') {
|
|
19415
20314
|
const shadowRoot = this._store.state.host?.shadowRoot;
|
|
19416
20315
|
if (!shadowRoot)
|
|
@@ -19449,6 +20348,26 @@ class KritzelCore {
|
|
|
19449
20348
|
}
|
|
19450
20349
|
return [];
|
|
19451
20350
|
}
|
|
20351
|
+
/**
|
|
20352
|
+
* Get all elements at a pointer position that match a given selector.
|
|
20353
|
+
* Uses elementsFromPoint to find overlapped elements.
|
|
20354
|
+
*/
|
|
20355
|
+
getElementsAtPoint(event, selector) {
|
|
20356
|
+
const shadowRoot = this._store.state.host?.shadowRoot;
|
|
20357
|
+
if (!shadowRoot)
|
|
20358
|
+
return [];
|
|
20359
|
+
const elementsAtPoint = shadowRoot.elementsFromPoint(event.clientX, event.clientY);
|
|
20360
|
+
if (!elementsAtPoint || elementsAtPoint.length === 0)
|
|
20361
|
+
return [];
|
|
20362
|
+
return elementsAtPoint.filter(el => el.matches(selector));
|
|
20363
|
+
}
|
|
20364
|
+
/**
|
|
20365
|
+
* Check if any element at the pointer position matches the given selector.
|
|
20366
|
+
* Useful for detecting hover states on overlapped elements.
|
|
20367
|
+
*/
|
|
20368
|
+
isPointerOverElement(event, selector) {
|
|
20369
|
+
return this.getElementsAtPoint(event, selector).length > 0;
|
|
20370
|
+
}
|
|
19452
20371
|
getCanvasPoint(event) {
|
|
19453
20372
|
if (!this._store.state.host) {
|
|
19454
20373
|
return { x: 0, y: 0 };
|
|
@@ -19463,10 +20382,58 @@ class KritzelCore {
|
|
|
19463
20382
|
return { x: worldX, y: worldY };
|
|
19464
20383
|
}
|
|
19465
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
|
+
}
|
|
19466
20393
|
this.resetActiveText();
|
|
19467
20394
|
this.clearSelection();
|
|
19468
20395
|
this._store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
|
|
19469
20396
|
}
|
|
20397
|
+
displaySelectionGroupUI(object) {
|
|
20398
|
+
if (!object.isSelected) {
|
|
20399
|
+
return false;
|
|
20400
|
+
}
|
|
20401
|
+
const selectionGroup = this._store.selectionGroup;
|
|
20402
|
+
if (!selectionGroup) {
|
|
20403
|
+
// During selection phase (no group yet), hide UI for KritzelLine objects
|
|
20404
|
+
return !(object instanceof KritzelLine);
|
|
20405
|
+
}
|
|
20406
|
+
// Show UI if selection contains more than one object
|
|
20407
|
+
if (selectionGroup.objects.length > 1) {
|
|
20408
|
+
return true;
|
|
20409
|
+
}
|
|
20410
|
+
// Hide UI if selection contains a single KritzelLine
|
|
20411
|
+
if (selectionGroup.objects.length === 1) {
|
|
20412
|
+
const selectedObject = selectionGroup.objects[0];
|
|
20413
|
+
return !(selectedObject instanceof KritzelLine);
|
|
20414
|
+
}
|
|
20415
|
+
return true;
|
|
20416
|
+
}
|
|
20417
|
+
displaySelectionLineUI(object) {
|
|
20418
|
+
// Only show line UI on KritzelLine objects, not on selection groups
|
|
20419
|
+
if (!(object instanceof KritzelLine)) {
|
|
20420
|
+
return false;
|
|
20421
|
+
}
|
|
20422
|
+
// During selection phase (no group yet), show line UI if line is selected
|
|
20423
|
+
const selectionGroup = this._store.selectionGroup;
|
|
20424
|
+
if (!selectionGroup) {
|
|
20425
|
+
return object.isSelected;
|
|
20426
|
+
}
|
|
20427
|
+
if (!selectionGroup.isSelected) {
|
|
20428
|
+
return false;
|
|
20429
|
+
}
|
|
20430
|
+
// Show UI only if selection contains exactly one KritzelLine and it's this object
|
|
20431
|
+
if (selectionGroup.objects.length === 1) {
|
|
20432
|
+
const selectedObject = selectionGroup.objects[0];
|
|
20433
|
+
return selectedObject instanceof KritzelLine && selectedObject.id === object.id;
|
|
20434
|
+
}
|
|
20435
|
+
return false;
|
|
20436
|
+
}
|
|
19470
20437
|
}
|
|
19471
20438
|
|
|
19472
20439
|
const kritzelEngineCss = ":host{display:block;position:relative;height:100%;width:100%;overflow:hidden;background-color:var(--kritzel-engine-background-color, #ffffff)}:host,:host *{touch-action:none;user-select:none}.ProseMirror{outline:none}p,h1,h2,h3,h4,h5,h6,blockquote,pre{margin:0;padding:0}.debug-panel{position:absolute;pointer-events:none;top:0;right:0}.origin{position:relative;top:0;left:0;height:0;width:0;pointer-events:none;-webkit-transform-origin:top left;-moz-transform-origin:top left;transform-origin:top left;overflow:visible}.object{overflow:visible}.PlaygroundEditorTheme__quote{margin:0;margin-left:20px;margin-bottom:10px;font-size:15px;color:rgb(101, 103, 107);border-left-color:rgb(206, 208, 212);border-left-width:4px;border-left-style:solid;padding-left:16px}";
|
|
@@ -19510,12 +20477,7 @@ const KritzelEngine = class {
|
|
|
19510
20477
|
}
|
|
19511
20478
|
cursorTarget;
|
|
19512
20479
|
onCursorTargetChange(newValue) {
|
|
19513
|
-
|
|
19514
|
-
if (this.cursorTargetElement) {
|
|
19515
|
-
this.cursorTargetElement.style.cursor = '';
|
|
19516
|
-
}
|
|
19517
|
-
// Set new target (defaults to document.body)
|
|
19518
|
-
this.cursorTargetElement = newValue || document.body;
|
|
20480
|
+
this.core.cursorManager.setTargetElement(newValue || document.body);
|
|
19519
20481
|
}
|
|
19520
20482
|
isEngineReady;
|
|
19521
20483
|
activeToolChange;
|
|
@@ -19563,6 +20525,8 @@ const KritzelEngine = class {
|
|
|
19563
20525
|
if (this.core.store.state.pointers.size > 1) {
|
|
19564
20526
|
this.throttledPointerMoveMulti(ev);
|
|
19565
20527
|
}
|
|
20528
|
+
// Update cursor for handle hover states using elementsFromPoint
|
|
20529
|
+
this.core.cursorManager.updateHoverState(ev);
|
|
19566
20530
|
this.viewport.handlePointerMove(ev);
|
|
19567
20531
|
this.core.store.state?.activeTool?.handlePointerMove(ev);
|
|
19568
20532
|
}
|
|
@@ -19574,7 +20538,7 @@ const KritzelEngine = class {
|
|
|
19574
20538
|
this.host.releasePointerCapture(ev.pointerId);
|
|
19575
20539
|
// Reset cursor to default when all pointers are released
|
|
19576
20540
|
if (this.core.store.state.pointers.size === 0) {
|
|
19577
|
-
this.core.
|
|
20541
|
+
this.core.cursorManager.resetToDefault();
|
|
19578
20542
|
}
|
|
19579
20543
|
this.viewport.handlePointerUp(ev);
|
|
19580
20544
|
this.core.store.state?.activeTool?.handlePointerUp(ev);
|
|
@@ -19587,7 +20551,7 @@ const KritzelEngine = class {
|
|
|
19587
20551
|
this.core.store.state.pointers.delete(ev.pointerId);
|
|
19588
20552
|
// Reset cursor to default when all pointers are released
|
|
19589
20553
|
if (this.core.store.state.pointers.size === 0) {
|
|
19590
|
-
this.core.
|
|
20554
|
+
this.core.cursorManager.resetToDefault();
|
|
19591
20555
|
}
|
|
19592
20556
|
this.viewport.handlePointerUp(ev);
|
|
19593
20557
|
this.core.store.state?.activeTool?.handlePointerUp(ev);
|
|
@@ -19763,7 +20727,6 @@ const KritzelEngine = class {
|
|
|
19763
20727
|
contextMenuHandler;
|
|
19764
20728
|
keyHandler;
|
|
19765
20729
|
contextMenuElement = null;
|
|
19766
|
-
cursorTargetElement = null;
|
|
19767
20730
|
get isSelecting() {
|
|
19768
20731
|
return this.core.store.state.activeTool instanceof KritzelSelectionTool && this.core.store.state.isSelecting;
|
|
19769
20732
|
}
|
|
@@ -19783,12 +20746,7 @@ const KritzelEngine = class {
|
|
|
19783
20746
|
disconnectedCallback() {
|
|
19784
20747
|
this.throttledWheel.cancel();
|
|
19785
20748
|
this.throttledPointerMoveMulti.cancel();
|
|
19786
|
-
|
|
19787
|
-
if (this.cursorTargetElement) {
|
|
19788
|
-
this.cursorTargetElement.style.cursor = '';
|
|
19789
|
-
this.cursorTargetElement.style.removeProperty('--kritzel-pointer-cursor');
|
|
19790
|
-
this.cursorTargetElement = null;
|
|
19791
|
-
}
|
|
20749
|
+
this.core.cursorManager.cleanup();
|
|
19792
20750
|
}
|
|
19793
20751
|
componentWillLoad() {
|
|
19794
20752
|
this.validateScaleMax(this.scaleMax);
|
|
@@ -19798,10 +20756,9 @@ const KritzelEngine = class {
|
|
|
19798
20756
|
this.contextMenuHandler = new KritzelContextMenuHandler(this.core, this.globalContextMenuItems, this.objectContextMenuItems);
|
|
19799
20757
|
this.keyHandler = new KritzelKeyHandler(this.core);
|
|
19800
20758
|
this.viewport = new KritzelViewport(this.core, this.host);
|
|
19801
|
-
//
|
|
19802
|
-
this.
|
|
19803
|
-
|
|
19804
|
-
this.cursorTargetElement.style.setProperty('--kritzel-pointer-cursor', KritzelCursorHelper.getPointerCursor());
|
|
20759
|
+
// Initialize cursor manager with target element and shadow root
|
|
20760
|
+
this.core.cursorManager.setTargetElement(this.cursorTarget || document.body);
|
|
20761
|
+
this.core.cursorManager.setShadowRoot(this.host.shadowRoot);
|
|
19805
20762
|
// Set sync configuration if provided
|
|
19806
20763
|
if (this.syncConfig) {
|
|
19807
20764
|
this.core.setSyncConfig(this.syncConfig);
|
|
@@ -19843,20 +20800,6 @@ const KritzelEngine = class {
|
|
|
19843
20800
|
KritzelKeyboardHelper.forceHideKeyboard();
|
|
19844
20801
|
this.core.rerender();
|
|
19845
20802
|
}
|
|
19846
|
-
updateCursor() {
|
|
19847
|
-
const state = this.core.store.state;
|
|
19848
|
-
const isPointerDown = this.core.store.isPointerDown;
|
|
19849
|
-
const icon = state.cursor?.icon;
|
|
19850
|
-
const iconActive = state.cursor?.iconActive ?? icon;
|
|
19851
|
-
const rotation = state.cursor?.rotation;
|
|
19852
|
-
const cursor = KritzelCursorHelper.getCursor({
|
|
19853
|
-
iconName: isPointerDown ? iconActive : icon,
|
|
19854
|
-
rotation: rotation,
|
|
19855
|
-
});
|
|
19856
|
-
if (this.cursorTargetElement) {
|
|
19857
|
-
this.cursorTargetElement.style.cursor = cursor;
|
|
19858
|
-
}
|
|
19859
|
-
}
|
|
19860
20803
|
render() {
|
|
19861
20804
|
const computedStyle = window.getComputedStyle(this.host);
|
|
19862
20805
|
const baseHandleSizePx = computedStyle.getPropertyValue('--kritzel-selection-handle-size').trim() || '6px';
|
|
@@ -19872,18 +20815,18 @@ const KritzelEngine = class {
|
|
|
19872
20815
|
height: this.core.store.state.viewportHeight / this.core.store.state.scale,
|
|
19873
20816
|
depth: 100,
|
|
19874
20817
|
};
|
|
19875
|
-
const visibleObjects = this.core.store.state.objects.query(viewportBounds);
|
|
19876
|
-
this.
|
|
19877
|
-
return (h(Host, { key: '
|
|
20818
|
+
const visibleObjects = this.core.store.state.objects.query(viewportBounds).sort((a, b) => a.zIndex - b.zIndex);
|
|
20819
|
+
this.core.cursorManager.applyCursor();
|
|
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: {
|
|
19878
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})`,
|
|
19879
20822
|
} }, visibleObjects?.map(object => {
|
|
19880
20823
|
return (h("div", { key: object.id, style: {
|
|
19881
20824
|
transform: object?.transformationMatrix,
|
|
19882
20825
|
transformOrigin: 'top left',
|
|
19883
|
-
zIndex: object.zIndex.toString(),
|
|
19884
20826
|
position: 'absolute',
|
|
19885
20827
|
pointerEvents: this.core.store.state.isScaling ? 'none' : 'auto',
|
|
19886
20828
|
} }, h("svg", { xmlns: "http://www.w3.org/2000/svg", id: object.id, class: "object", style: {
|
|
20829
|
+
zIndex: object.zIndex.toString(),
|
|
19887
20830
|
height: object?.totalHeight.toString(),
|
|
19888
20831
|
width: object?.totalWidth.toString(),
|
|
19889
20832
|
left: '0',
|
|
@@ -19893,7 +20836,7 @@ const KritzelEngine = class {
|
|
|
19893
20836
|
transformOrigin: `${object.totalWidth / 2}px ${object.totalHeight / 2}px`,
|
|
19894
20837
|
opacity: object.markedForRemoval ? '0.5' : object.opacity.toString(),
|
|
19895
20838
|
pointerEvents: object.markedForRemoval ? 'none' : 'auto',
|
|
19896
|
-
} }, h("foreignObject", { x: "0", y: "0", width: object.totalWidth.toString(), height: object.totalHeight.toString(), style: {
|
|
20839
|
+
} }, KritzelClassHelper.isInstanceOf(object, 'KritzelPath') && (h("svg", { ref: el => object.mount(el), xmlns: "http://www.w3.org/2000/svg", style: { overflow: 'visible' }, viewBox: object?.viewBox }, h("path", { d: object?.d, fill: object.fill, stroke: object?.stroke, "shape-rendering": object.isLowRes() ? 'optimizeSpeed' : 'auto' }))), KritzelClassHelper.isInstanceOf(object, 'KritzelLine') && (h("svg", { ref: el => object.mount(el), xmlns: "http://www.w3.org/2000/svg", style: { overflow: 'visible' }, viewBox: object?.viewBox }, h("defs", null, object.hasStartArrow && (h("marker", { id: object.startMarkerId, markerWidth: object.getArrowSize('start'), markerHeight: object.getArrowSize('start'), refX: 0, refY: object.getArrowSize('start') / 2, orient: "auto-start-reverse", markerUnits: "userSpaceOnUse" }, h("path", { d: object.getArrowPath(object.arrows?.start?.style), fill: object.getArrowFill('start'), transform: `scale(${object.getArrowSize('start') / 10})` }))), object.hasEndArrow && (h("marker", { id: object.endMarkerId, markerWidth: object.getArrowSize('end'), markerHeight: object.getArrowSize('end'), refX: 0, refY: object.getArrowSize('end') / 2, orient: "auto", markerUnits: "userSpaceOnUse" }, h("path", { d: object.getArrowPath(object.arrows?.end?.style), fill: object.getArrowFill('end'), transform: `scale(${object.getArrowSize('end') / 10})` })))), h("path", { d: this.core.anchorManager.computeClippedLinePath(object), fill: "none", stroke: object?.stroke, "stroke-width": object?.strokeWidth, "stroke-linecap": "round", "marker-start": object.hasStartArrow ? `url(#${object.startMarkerId})` : undefined, "marker-end": object.hasEndArrow ? `url(#${object.endMarkerId})` : undefined }))), h("foreignObject", { x: "0", y: "0", width: object.totalWidth.toString(), height: object.totalHeight.toString(), style: {
|
|
19897
20840
|
minHeight: '0',
|
|
19898
20841
|
minWidth: '0',
|
|
19899
20842
|
backgroundColor: object.backgroundColor,
|
|
@@ -19902,18 +20845,14 @@ const KritzelEngine = class {
|
|
|
19902
20845
|
borderStyle: 'solid',
|
|
19903
20846
|
padding: object.padding + 'px',
|
|
19904
20847
|
overflow: 'visible',
|
|
19905
|
-
|
|
19906
|
-
|
|
19907
|
-
width: object?.width.toString(),
|
|
19908
|
-
position: 'absolute',
|
|
19909
|
-
overflow: 'visible',
|
|
19910
|
-
}, viewBox: object?.viewBox }, h("path", { d: object?.d, fill: object.fill, stroke: object?.stroke, "shape-rendering": object.isLowRes() ? 'optimizeSpeed' : 'auto' }))), KritzelClassHelper.isInstanceOf(object, 'KritzelImage') && (h("img", { ref: el => object.mount(el), src: object.src, style: {
|
|
20848
|
+
display: KritzelClassHelper.isInstanceOf(object, 'KritzelLine') || KritzelClassHelper.isInstanceOf(object, 'KritzelPath') ? 'none' : 'block'
|
|
20849
|
+
} }, KritzelClassHelper.isInstanceOf(object, 'KritzelImage') && (h("img", { ref: el => object.mount(el), src: object.src, style: {
|
|
19911
20850
|
width: '100%',
|
|
19912
20851
|
height: '100%',
|
|
19913
20852
|
userSelect: 'none',
|
|
19914
20853
|
pointerEvents: 'none',
|
|
19915
20854
|
imageRendering: this.core.store.state.isScaling || this.core.store.state.isPanning ? 'pixelated' : 'auto',
|
|
19916
|
-
}, draggable: false, onDragStart: e => e.preventDefault() })), KritzelClassHelper.isInstanceOf(object, 'KritzelText') && (h("div", { ref: el => object.mount(el), onPointerDown: e => object.handlePointerDown(e), onPointerMove: e => object.handlePointerMove(e), onPointerUp: e => object.handlePointerUp(e), style: {
|
|
20855
|
+
}, draggable: false, onDragStart: e => e.preventDefault() })), KritzelClassHelper.isInstanceOf(object, 'KritzelText') && (h("div", { id: "text-object", ref: el => object.mount(el), onPointerDown: e => object.handlePointerDown(e), onPointerMove: e => object.handlePointerMove(e), onPointerUp: e => object.handlePointerUp(e), style: {
|
|
19917
20856
|
minWidth: object.initialWidth + 'px',
|
|
19918
20857
|
minHeight: object.initialHeight + 'px',
|
|
19919
20858
|
maxWidth: '500px',
|
|
@@ -19924,13 +20863,38 @@ const KritzelEngine = class {
|
|
|
19924
20863
|
backgroundColor: object.backgroundColor,
|
|
19925
20864
|
overflow: 'visible',
|
|
19926
20865
|
textRendering: this.core.store.state.isScaling || this.core.store.state.isPanning ? 'optimizeSpeed' : 'auto',
|
|
19927
|
-
} })), 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: {
|
|
19928
20892
|
width: '100%',
|
|
19929
20893
|
height: '100%',
|
|
19930
20894
|
pointerEvents: 'auto',
|
|
19931
20895
|
overflow: 'hidden',
|
|
19932
20896
|
display: 'block',
|
|
19933
|
-
} })), KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup') && (h("div", { ref: el => object.mount(el), style: {
|
|
20897
|
+
} })), KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup') && !this.core.displaySelectionLineUI(object) && (h("div", { ref: el => object.mount(el), style: {
|
|
19934
20898
|
width: '100%',
|
|
19935
20899
|
height: '100%',
|
|
19936
20900
|
} })), KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionBox') && (h("div", { ref: el => object.mount(el), style: {
|
|
@@ -19940,7 +20904,14 @@ const KritzelEngine = class {
|
|
|
19940
20904
|
borderWidth: KritzelDevicesHelper.isFirefox() ? object.borderWidth + 'px' : '0',
|
|
19941
20905
|
borderStyle: KritzelDevicesHelper.isFirefox() ? 'solid' : 'none',
|
|
19942
20906
|
borderColor: KritzelDevicesHelper.isFirefox() ? object.borderColor : 'transparent',
|
|
19943
|
-
} }))), 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: {
|
|
20914
|
+
zIndex: (object.zIndex + 1).toString(),
|
|
19944
20915
|
height: object?.totalHeight.toString(),
|
|
19945
20916
|
width: object?.totalWidth.toString(),
|
|
19946
20917
|
left: '0',
|
|
@@ -19950,7 +20921,7 @@ const KritzelEngine = class {
|
|
|
19950
20921
|
transformOrigin: `${object.totalWidth / 2}px ${object.totalHeight / 2}px`,
|
|
19951
20922
|
overflow: 'visible',
|
|
19952
20923
|
pointerEvents: 'none',
|
|
19953
|
-
} }, object
|
|
20924
|
+
} }, this.core.displaySelectionGroupUI(object) && (h("g", { class: "selection-group-ui", style: { pointerEvents: 'none' } }, h("g", { class: "selection-group-borders" }, h("line", { x1: "0", y1: "0", x2: object.totalWidth, y2: "0", style: {
|
|
19954
20925
|
stroke: 'var(--kritzel-selection-border-color, #007AFF)',
|
|
19955
20926
|
strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
|
|
19956
20927
|
strokeLinecap: 'square',
|
|
@@ -19966,31 +20937,31 @@ const KritzelEngine = class {
|
|
|
19966
20937
|
stroke: 'var(--kritzel-selection-border-color, #007AFF)',
|
|
19967
20938
|
strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
|
|
19968
20939
|
strokeLinecap: 'square',
|
|
19969
|
-
} }))
|
|
20940
|
+
} })), !this.isSelecting && (h("g", { class: "selection-group-handles", style: { pointerEvents: 'auto' } }, h("circle", { class: "resize-handle top-left", cx: "0", cy: "0", r: `${(baseHandleSize * object.scale) / this.core.store.state?.scale}`, style: {
|
|
19970
20941
|
fill: 'var(--kritzel-selection-handle-color, #000000)',
|
|
19971
20942
|
paintOrder: 'fill',
|
|
19972
20943
|
} }), h("circle", { class: "resize-handle-overlay top-left", cx: "0", cy: "0", r: `${(baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, style: {
|
|
19973
20944
|
fill: 'transparent',
|
|
19974
20945
|
paintOrder: 'fill',
|
|
19975
|
-
}
|
|
20946
|
+
} }), h("circle", { class: "resize-handle top-right", cx: object.totalWidth, cy: "0", r: `${(baseHandleSize * object.scale) / this.core.store.state?.scale}`, style: {
|
|
19976
20947
|
fill: 'var(--kritzel-selection-handle-color, #000000)',
|
|
19977
20948
|
paintOrder: 'fill',
|
|
19978
20949
|
} }), h("circle", { class: "resize-handle-overlay top-right", cx: object.totalWidth, cy: "0", r: `${(baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, style: {
|
|
19979
20950
|
fill: 'transparent',
|
|
19980
20951
|
paintOrder: 'fill',
|
|
19981
|
-
}
|
|
20952
|
+
} }), h("circle", { class: "resize-handle bottom-left", cx: "0", cy: object.totalHeight, r: `${(baseHandleSize * object.scale) / this.core.store.state?.scale}`, style: {
|
|
19982
20953
|
fill: 'var(--kritzel-selection-handle-color, #000000)',
|
|
19983
20954
|
paintOrder: 'fill',
|
|
19984
20955
|
} }), h("circle", { class: "resize-handle-overlay bottom-left", cx: "0", cy: object.totalHeight, r: `${(baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, style: {
|
|
19985
20956
|
fill: 'transparent',
|
|
19986
20957
|
paintOrder: 'fill',
|
|
19987
|
-
}
|
|
20958
|
+
} }), h("circle", { class: "resize-handle bottom-right", cx: object.totalWidth, cy: object.totalHeight, r: `${(baseHandleSize * object.scale) / this.core.store.state?.scale}`, style: {
|
|
19988
20959
|
fill: 'var(--kritzel-selection-handle-color, #000000)',
|
|
19989
20960
|
paintOrder: 'fill',
|
|
19990
20961
|
} }), h("circle", { class: "resize-handle-overlay bottom-right", cx: object.totalWidth, cy: object.totalHeight, r: `${(baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, style: {
|
|
19991
20962
|
fill: 'transparent',
|
|
19992
20963
|
paintOrder: 'fill',
|
|
19993
|
-
}
|
|
20964
|
+
} }), h("line", { x1: object.totalWidth / 2, y1: "0", x2: object.totalWidth / 2, y2: -((15 * object.scale) / this.core.store.state?.scale), style: {
|
|
19994
20965
|
stroke: 'var(--kritzel-selection-border-color, #007AFF)',
|
|
19995
20966
|
strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
|
|
19996
20967
|
} }), h("circle", { class: "rotation-handle", cx: object.totalWidth / 2, cy: -((15 * object.scale) / this.core.store.state?.scale), r: `${(baseHandleSize * object.scale) / this.core.store.state?.scale}`, style: {
|
|
@@ -19999,8 +20970,103 @@ const KritzelEngine = class {
|
|
|
19999
20970
|
} }), h("circle", { class: "rotation-handle-overlay", cx: object.totalWidth / 2, cy: -((15 * object.scale) / this.core.store.state?.scale), r: `${(baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, style: {
|
|
20000
20971
|
fill: 'transparent',
|
|
20001
20972
|
paintOrder: 'fill',
|
|
20002
|
-
}
|
|
20003
|
-
|
|
20973
|
+
} }))))), this.core.displaySelectionLineUI(object) && KritzelClassHelper.isInstanceOf(object, 'KritzelLine') && (h("g", { class: "selection-line-ui", style: { pointerEvents: 'none' } }, h("g", { class: "selection-line-borders" }, h("path", { class: "selection-line-border", d: this.core.anchorManager.computeClippedLinePath(object, true), style: {
|
|
20974
|
+
stroke: 'var(--kritzel-selection-border-color, #007AFF)',
|
|
20975
|
+
strokeWidth: `calc(var(--kritzel-selection-border-width, 2px) * ${object.scale} / ${this.core.store.state?.scale})`,
|
|
20976
|
+
strokeLinecap: 'round',
|
|
20977
|
+
fill: 'none',
|
|
20978
|
+
} })), !this.isSelecting && (h("g", { class: "selection-line-handles", style: { pointerEvents: 'auto' } }, h("circle", { class: "selection-line-handle start", cx: object.startX - object.x, cy: object.startY - object.y, r: `${(baseHandleSize * object.scale) / this.core.store.state?.scale}`, style: {
|
|
20979
|
+
fill: 'var(--kritzel-selection-handle-color, #000000)',
|
|
20980
|
+
paintOrder: 'fill',
|
|
20981
|
+
} }), h("circle", { class: "selection-line-handle-overlay start", cx: object.startX - object.x, cy: object.startY - object.y, r: `${(baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, style: {
|
|
20982
|
+
fill: 'transparent',
|
|
20983
|
+
paintOrder: 'fill',
|
|
20984
|
+
} }), h("circle", { class: "selection-line-handle center", cx: object.controlX !== undefined ? (object.startX + 2 * object.controlX + object.endX) / 4 - object.x : (object.startX - object.x + object.endX - object.x) / 2, cy: object.controlY !== undefined ? (object.startY + 2 * object.controlY + object.endY) / 4 - object.y : (object.startY - object.y + object.endY - object.y) / 2, r: `${(baseHandleSize * object.scale) / this.core.store.state?.scale}`, style: {
|
|
20985
|
+
fill: 'var(--kritzel-selection-handle-color, #000000)',
|
|
20986
|
+
paintOrder: 'fill',
|
|
20987
|
+
} }), h("circle", { class: "selection-line-handle-overlay center", cx: object.controlX !== undefined ? (object.startX + 2 * object.controlX + object.endX) / 4 - object.x : (object.startX - object.x + object.endX - object.x) / 2, cy: object.controlY !== undefined ? (object.startY + 2 * object.controlY + object.endY) / 4 - object.y : (object.startY - object.y + object.endY - object.y) / 2, r: `${(baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, style: {
|
|
20988
|
+
fill: 'transparent',
|
|
20989
|
+
paintOrder: 'fill',
|
|
20990
|
+
} }), h("circle", { class: "selection-line-handle end", cx: object.endX - object.x, cy: object.endY - object.y, r: `${(baseHandleSize * object.scale) / this.core.store.state?.scale}`, style: {
|
|
20991
|
+
fill: 'var(--kritzel-selection-handle-color, #000000)',
|
|
20992
|
+
paintOrder: 'fill',
|
|
20993
|
+
} }), h("circle", { class: "selection-line-handle-overlay end", cx: object.endX - object.x, cy: object.endY - object.y, r: `${(baseHandleTouchSize * object.scale) / this.core.store.state?.scale}`, style: {
|
|
20994
|
+
fill: 'transparent',
|
|
20995
|
+
paintOrder: 'fill',
|
|
20996
|
+
} }))))))));
|
|
20997
|
+
}), (() => {
|
|
20998
|
+
const data = this.core.anchorManager.getAnchorLinesRenderData();
|
|
20999
|
+
if (!data)
|
|
21000
|
+
return null;
|
|
21001
|
+
return (h("svg", { xmlns: "http://www.w3.org/2000/svg", class: "anchor-lines", style: {
|
|
21002
|
+
position: 'absolute',
|
|
21003
|
+
left: '0',
|
|
21004
|
+
top: '0',
|
|
21005
|
+
width: '1px',
|
|
21006
|
+
height: '1px',
|
|
21007
|
+
pointerEvents: 'none',
|
|
21008
|
+
zIndex: '9998',
|
|
21009
|
+
overflow: 'visible',
|
|
21010
|
+
} }, data.startAnchorViz && (h("g", { class: "anchor-line-start" }, data.startAnchorViz.pathD ? (h("path", { d: data.startAnchorViz.pathD, style: {
|
|
21011
|
+
stroke: 'var(--kritzel-snap-line-stroke, rgba(0, 0, 0, 0.3))',
|
|
21012
|
+
strokeWidth: `${data.lineStrokeWidth}`,
|
|
21013
|
+
strokeDasharray: data.dashArray,
|
|
21014
|
+
strokeLinecap: 'round',
|
|
21015
|
+
fill: 'none',
|
|
21016
|
+
} })) : (h("line", { x1: data.startAnchorViz.edgeX, y1: data.startAnchorViz.edgeY, x2: data.startAnchorViz.centerX, y2: data.startAnchorViz.centerY, style: {
|
|
21017
|
+
stroke: 'var(--kritzel-snap-line-stroke, rgba(0, 0, 0, 0.3))',
|
|
21018
|
+
strokeWidth: `${data.lineStrokeWidth}`,
|
|
21019
|
+
strokeDasharray: data.dashArray,
|
|
21020
|
+
strokeLinecap: 'round',
|
|
21021
|
+
} })), h("circle", { cx: data.startAnchorViz.centerX, cy: data.startAnchorViz.centerY, r: data.indicatorRadius, style: {
|
|
21022
|
+
fill: 'var(--kritzel-snap-indicator-fill, rgba(0, 0, 0))',
|
|
21023
|
+
stroke: 'var(--kritzel-snap-indicator-stroke, #3b82f6)',
|
|
21024
|
+
strokeWidth: data.indicatorStrokeWidth,
|
|
21025
|
+
} }))), data.endAnchorViz && (h("g", { class: "anchor-line-end" }, data.endAnchorViz.pathD ? (h("path", { d: data.endAnchorViz.pathD, style: {
|
|
21026
|
+
stroke: 'var(--kritzel-snap-line-stroke, rgba(0, 0, 0, 0.2))',
|
|
21027
|
+
strokeWidth: `${data.lineStrokeWidth}`,
|
|
21028
|
+
strokeDasharray: data.dashArray,
|
|
21029
|
+
strokeLinecap: 'round',
|
|
21030
|
+
fill: 'none',
|
|
21031
|
+
} })) : (h("line", { x1: data.endAnchorViz.edgeX, y1: data.endAnchorViz.edgeY, x2: data.endAnchorViz.centerX, y2: data.endAnchorViz.centerY, style: {
|
|
21032
|
+
stroke: 'var(--kritzel-snap-line-stroke, rgba(0, 0, 0, 0.2))',
|
|
21033
|
+
strokeWidth: `${data.lineStrokeWidth}`,
|
|
21034
|
+
strokeDasharray: data.dashArray,
|
|
21035
|
+
strokeLinecap: 'round',
|
|
21036
|
+
} })), h("circle", { cx: data.endAnchorViz.centerX, cy: data.endAnchorViz.centerY, r: data.indicatorRadius, style: {
|
|
21037
|
+
fill: 'var(--kritzel-snap-indicator-fill, rgba(59, 130, 246, 0.3))',
|
|
21038
|
+
stroke: 'var(--kritzel-snap-indicator-stroke, #3b82f6)',
|
|
21039
|
+
strokeWidth: data.indicatorStrokeWidth,
|
|
21040
|
+
} })))));
|
|
21041
|
+
})(), (() => {
|
|
21042
|
+
const data = this.core.anchorManager.getSnapIndicatorRenderData();
|
|
21043
|
+
if (!data)
|
|
21044
|
+
return null;
|
|
21045
|
+
return (h("svg", { xmlns: "http://www.w3.org/2000/svg", class: "snap-indicator", style: {
|
|
21046
|
+
position: 'absolute',
|
|
21047
|
+
left: '0',
|
|
21048
|
+
top: '0',
|
|
21049
|
+
width: '1px',
|
|
21050
|
+
height: '1px',
|
|
21051
|
+
pointerEvents: 'none',
|
|
21052
|
+
zIndex: '9999',
|
|
21053
|
+
overflow: 'visible',
|
|
21054
|
+
} }, h("g", null, data.snapLinePath ? (h("path", { d: data.snapLinePath, fill: "none", style: {
|
|
21055
|
+
stroke: 'var(--kritzel-snap-line-stroke, rgba(0, 0, 0, 0.2))',
|
|
21056
|
+
strokeWidth: data.lineStrokeWidth,
|
|
21057
|
+
strokeDasharray: data.dashArray,
|
|
21058
|
+
strokeLinecap: 'round',
|
|
21059
|
+
} })) : (data.edgeX !== undefined && data.edgeY !== undefined && (h("line", { x1: data.edgeX, y1: data.edgeY, x2: data.centerX, y2: data.centerY, style: {
|
|
21060
|
+
stroke: 'var(--kritzel-snap-line-stroke, rgba(0, 0, 0, 0.2))',
|
|
21061
|
+
strokeWidth: data.lineStrokeWidth,
|
|
21062
|
+
strokeDasharray: data.dashArray,
|
|
21063
|
+
strokeLinecap: 'round',
|
|
21064
|
+
} }))), h("circle", { cx: data.centerX, cy: data.centerY, r: data.indicatorRadius, style: {
|
|
21065
|
+
fill: 'var(--kritzel-snap-indicator-fill, rgba(59, 130, 246, 0.3))',
|
|
21066
|
+
stroke: 'var(--kritzel-snap-indicator-stroke, #3b82f6)',
|
|
21067
|
+
strokeWidth: data.indicatorStrokeWidth,
|
|
21068
|
+
} }))));
|
|
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: {
|
|
20004
21070
|
position: 'fixed',
|
|
20005
21071
|
left: `${this.core.store.state.contextMenuX}px`,
|
|
20006
21072
|
top: `${this.core.store.state.contextMenuY}px`,
|
|
@@ -20011,7 +21077,7 @@ const KritzelEngine = class {
|
|
|
20011
21077
|
y: (-this.core.store.state.translateY + this.core.store.state.contextMenuY) / this.core.store.state.scale,
|
|
20012
21078
|
}, this.core.store.selectionGroup?.objects);
|
|
20013
21079
|
this.hideContextMenu();
|
|
20014
|
-
}, 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 })));
|
|
20015
21081
|
}
|
|
20016
21082
|
static get watchers() { return {
|
|
20017
21083
|
"workspace": ["onWorkspaceChange"],
|