kritzel-stencil 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/{default-line-tool.config-7eJND6Jb.js → default-line-tool.config-MA02HCrH.js} +703 -133
- package/dist/cjs/{index-BeKMS-Zt.js → index-Bj0n7fQQ.js} +84 -7
- package/dist/cjs/index.cjs.js +1 -1
- package/dist/cjs/kritzel-brush-style.cjs.entry.js +1 -1
- package/dist/cjs/{kritzel-color_22.cjs.entry.js → kritzel-color_24.cjs.entry.js} +1018 -897
- package/dist/cjs/loader.cjs.js +2 -2
- package/dist/cjs/stencil.cjs.js +3 -3
- package/dist/collection/classes/core/core.class.js +2 -0
- package/dist/collection/classes/core/viewport.class.js +43 -3
- package/dist/collection/classes/handlers/move.handler.js +6 -0
- package/dist/collection/classes/objects/line.class.js +63 -15
- package/dist/collection/classes/objects/path.class.js +1 -0
- package/dist/collection/classes/objects/shape.class.js +1 -0
- package/dist/collection/classes/objects/text.class.js +4 -3
- package/dist/collection/classes/providers/indexeddb-sync-provider.class.js +0 -1
- package/dist/collection/classes/tools/brush-tool.class.js +5 -0
- package/dist/collection/classes/tools/line-tool.class.js +31 -1
- package/dist/collection/classes/tools/selection-tool.class.js +193 -0
- package/dist/collection/classes/tools/shape-tool.class.js +2 -0
- package/dist/collection/classes/tools/text-tool.class.js +3 -0
- package/dist/collection/collection-manifest.json +5 -3
- package/dist/collection/components/core/kritzel-cursor-trail/kritzel-cursor-trail.js +3 -2
- package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +37 -19
- package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +108 -36
- package/dist/collection/components/shared/kritzel-color/kritzel-color.js +2 -2
- package/dist/collection/components/shared/kritzel-color-palette/kritzel-color-palette.css +1 -1
- package/dist/collection/components/shared/kritzel-color-palette/kritzel-color-palette.js +24 -2
- package/dist/collection/components/shared/kritzel-font/kritzel-font.js +1 -1
- package/dist/collection/components/shared/kritzel-font-family/kritzel-font-family.css +1 -1
- package/dist/collection/components/shared/kritzel-font-size/kritzel-font-size.css +1 -1
- package/dist/collection/components/shared/kritzel-font-size/kritzel-font-size.js +1 -1
- package/dist/collection/components/shared/kritzel-line-endings/kritzel-line-endings.css +60 -0
- package/dist/collection/components/shared/kritzel-line-endings/kritzel-line-endings.js +187 -0
- package/dist/collection/components/shared/kritzel-menu/kritzel-menu.js +15 -8
- package/dist/collection/components/shared/kritzel-menu-item/kritzel-menu-item.js +16 -9
- package/dist/collection/components/shared/kritzel-opacity-slider/kritzel-opacity-slider.css +85 -0
- package/dist/collection/components/shared/kritzel-opacity-slider/kritzel-opacity-slider.js +163 -0
- package/dist/collection/components/shared/kritzel-portal/kritzel-portal.js +1 -1
- package/dist/collection/components/shared/kritzel-shape-fill/kritzel-shape-fill.css +47 -0
- package/dist/collection/components/shared/kritzel-shape-fill/kritzel-shape-fill.js +93 -0
- package/dist/collection/components/shared/kritzel-split-button/kritzel-split-button.js +13 -7
- package/dist/collection/components/shared/kritzel-stroke-size/kritzel-stroke-size.css +11 -2
- package/dist/collection/components/shared/kritzel-stroke-size/kritzel-stroke-size.js +2 -2
- package/dist/collection/components/shared/kritzel-tooltip/kritzel-tooltip.css +1 -1
- package/dist/collection/components/shared/kritzel-tooltip/kritzel-tooltip.js +6 -4
- package/dist/collection/components/ui/kritzel-context-menu/kritzel-context-menu.js +6 -3
- package/dist/collection/components/ui/kritzel-controls/kritzel-controls.css +66 -0
- package/dist/collection/components/ui/kritzel-controls/kritzel-controls.js +153 -50
- package/dist/collection/components/ui/kritzel-tool-config/kritzel-tool-config.css +38 -0
- package/dist/collection/components/ui/kritzel-tool-config/kritzel-tool-config.js +321 -0
- package/dist/collection/components/ui/kritzel-utility-panel/kritzel-utility-panel.js +3 -2
- package/dist/collection/components/ui/kritzel-workspace-manager/kritzel-workspace-manager.js +6 -3
- package/dist/collection/configs/default-brush-tool.config.js +2 -52
- package/dist/collection/configs/default-line-tool.config.js +2 -26
- package/dist/collection/configs/default-shape-tool.config.js +2 -15
- package/dist/collection/configs/default-text-tool.config.js +2 -26
- package/dist/collection/constants/color-palette.constants.js +30 -0
- package/dist/collection/helpers/color.helper.js +31 -0
- package/dist/collection/helpers/tool-config.helper.js +65 -0
- package/dist/collection/interfaces/tool-config.interface.js +1 -0
- package/dist/components/index.d.ts +8 -4
- package/dist/components/index.js +1 -1
- package/dist/components/kritzel-brush-style.js +1 -1
- package/dist/components/kritzel-color-palette.js +1 -1
- package/dist/components/kritzel-color.js +1 -1
- package/dist/components/kritzel-context-menu.js +1 -1
- package/dist/components/kritzel-controls.js +1 -1
- package/dist/components/kritzel-cursor-trail.js +1 -1
- package/dist/components/kritzel-dropdown.js +1 -1
- package/dist/components/kritzel-editor.js +1 -1
- package/dist/components/kritzel-engine.js +1 -1
- package/dist/components/kritzel-font-family.js +1 -1
- package/dist/components/kritzel-font-size.js +1 -1
- package/dist/components/kritzel-font.js +1 -1
- package/dist/components/kritzel-icon.js +1 -1
- package/dist/components/kritzel-line-endings.d.ts +11 -0
- package/dist/components/kritzel-line-endings.js +1 -0
- package/dist/components/kritzel-menu-item.js +1 -1
- package/dist/components/kritzel-menu.js +1 -1
- package/dist/components/kritzel-opacity-slider.d.ts +11 -0
- package/dist/components/kritzel-opacity-slider.js +1 -0
- package/dist/components/kritzel-portal.js +1 -1
- package/dist/components/kritzel-shape-fill.d.ts +11 -0
- package/dist/components/kritzel-shape-fill.js +1 -0
- package/dist/components/kritzel-split-button.js +1 -1
- package/dist/components/kritzel-stroke-size.js +1 -1
- package/dist/components/kritzel-tool-config.d.ts +11 -0
- package/dist/components/kritzel-tool-config.js +1 -0
- package/dist/components/kritzel-tooltip.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-83YX0-FS.js +1 -0
- package/dist/components/p-8iEiCuEN.js +1 -0
- package/dist/components/p-9XZbc_qK.js +1 -0
- package/dist/components/p-B3P64-gH.js +9 -0
- package/dist/components/p-B8QjTqOY.js +1 -0
- package/dist/components/p-BF6MdW17.js +1 -0
- package/dist/components/p-BVIY50lR.js +1 -0
- package/dist/components/p-BbqT9o1F.js +1 -0
- package/dist/components/{p-CXzfYQ_u.js → p-BnidlyU0.js} +1 -1
- package/dist/components/{p-Bj_Og27M.js → p-BxS4Pdpz.js} +1 -1
- package/dist/components/{p-g0N9j_uT.js → p-CCj8nmQH.js} +1 -1
- package/dist/components/{p-1z-ds26_.js → p-CLOnpu42.js} +1 -1
- package/dist/components/{p-D1tfzpy8.js → p-CSGeDE4f.js} +1 -1
- package/dist/components/p-CbuHMNa9.js +1 -0
- package/dist/components/p-ClMFs3KI.js +1 -0
- package/dist/components/{p-IAqZFssU.js → p-Cnpk2hfo.js} +1 -1
- package/dist/components/{p-Cy77SpWt.js → p-Ctv4NAxk.js} +1 -1
- package/dist/components/p-CyHZWbkS.js +1 -0
- package/dist/components/{p-C4krHoUl.js → p-D8GeJNUv.js} +1 -1
- package/dist/components/{p-DB5s1NY4.js → p-DKgqzi2Y.js} +1 -1
- package/dist/components/p-DOF5fWDU.js +1 -0
- package/dist/components/{p-4FEa4ADy.js → p-DV_h5Jo2.js} +1 -1
- package/dist/components/{p-DTezr6w9.js → p-DgCGSL2Q.js} +1 -1
- package/dist/components/{p-D5ZsALCP.js → p-wRXL928z.js} +1 -1
- package/dist/esm/{default-line-tool.config-CD5sTKH-.js → default-line-tool.config-DLpNl6R9.js} +702 -125
- package/dist/esm/{index-BqhmuUH2.js → index-OLdaFN6W.js} +84 -7
- package/dist/esm/index.js +2 -2
- package/dist/esm/kritzel-brush-style.entry.js +1 -1
- package/dist/esm/{kritzel-color_22.entry.js → kritzel-color_24.entry.js} +1009 -890
- package/dist/esm/loader.js +3 -3
- package/dist/esm/stencil.js +4 -4
- package/dist/stencil/index.esm.js +1 -1
- package/dist/stencil/{p-09295079.entry.js → p-802bc7cf.entry.js} +1 -1
- package/dist/stencil/p-DLpNl6R9.js +1 -0
- package/dist/stencil/p-OLdaFN6W.js +2 -0
- package/dist/stencil/p-caf30edb.entry.js +9 -0
- package/dist/stencil/stencil.esm.js +1 -1
- package/dist/types/classes/core/viewport.class.d.ts +6 -0
- package/dist/types/classes/managers/anchor.manager.d.ts +1 -1
- package/dist/types/classes/objects/line.class.d.ts +2 -0
- package/dist/types/classes/objects/shape.class.d.ts +1 -0
- package/dist/types/classes/tools/brush-tool.class.d.ts +1 -0
- package/dist/types/classes/tools/line-tool.class.d.ts +2 -1
- package/dist/types/classes/tools/selection-tool.class.d.ts +22 -0
- package/dist/types/classes/tools/shape-tool.class.d.ts +1 -0
- package/dist/types/classes/tools/text-tool.class.d.ts +1 -0
- package/dist/types/components/core/kritzel-engine/kritzel-engine.d.ts +2 -0
- package/dist/types/components/shared/kritzel-color-palette/kritzel-color-palette.d.ts +1 -0
- package/dist/types/components/shared/kritzel-line-endings/kritzel-line-endings.d.ts +23 -0
- package/dist/types/components/shared/kritzel-opacity-slider/kritzel-opacity-slider.d.ts +17 -0
- package/dist/types/components/shared/kritzel-shape-fill/kritzel-shape-fill.d.ts +10 -0
- package/dist/types/components/ui/kritzel-controls/kritzel-controls.d.ts +15 -0
- package/dist/types/components/ui/kritzel-tool-config/kritzel-tool-config.d.ts +25 -0
- package/dist/types/components.d.ts +235 -82
- package/dist/types/constants/color-palette.constants.d.ts +5 -0
- package/dist/types/helpers/color.helper.d.ts +9 -0
- package/dist/types/helpers/tool-config.helper.d.ts +4 -0
- package/dist/types/interfaces/line-options.interface.d.ts +1 -0
- package/dist/types/interfaces/path-options.interface.d.ts +1 -0
- package/dist/types/interfaces/tool-config.interface.d.ts +26 -0
- package/dist/types/stencil-public-runtime.d.ts +29 -0
- package/package.json +5 -3
- package/dist/collection/components/ui/kritzel-control-brush-config/kritzel-control-brush-config.css +0 -19
- package/dist/collection/components/ui/kritzel-control-brush-config/kritzel-control-brush-config.js +0 -134
- package/dist/collection/components/ui/kritzel-control-text-config/kritzel-control-text-config.css +0 -19
- package/dist/collection/components/ui/kritzel-control-text-config/kritzel-control-text-config.js +0 -114
- package/dist/components/kritzel-control-brush-config.d.ts +0 -11
- package/dist/components/kritzel-control-brush-config.js +0 -1
- package/dist/components/kritzel-control-text-config.d.ts +0 -11
- package/dist/components/kritzel-control-text-config.js +0 -1
- package/dist/components/p-B7Fdo5QJ.js +0 -1
- package/dist/components/p-BXaWhpO2.js +0 -1
- package/dist/components/p-BtuXeItZ.js +0 -1
- package/dist/components/p-C-d2IH4v.js +0 -1
- package/dist/components/p-C3UriJh7.js +0 -1
- package/dist/components/p-CF5L2Gdl.js +0 -1
- package/dist/components/p-CeKT_dTd.js +0 -1
- package/dist/components/p-Cp15toXH.js +0 -1
- package/dist/components/p-D3LRBk2t.js +0 -9
- package/dist/components/p-Du1vxHy8.js +0 -1
- package/dist/stencil/p-381c0e9c.entry.js +0 -9
- package/dist/stencil/p-BqhmuUH2.js +0 -2
- package/dist/stencil/p-CD5sTKH-.js +0 -1
- package/dist/types/components/ui/kritzel-control-brush-config/kritzel-control-brush-config.d.ts +0 -15
- package/dist/types/components/ui/kritzel-control-text-config/kritzel-control-text-config.d.ts +0 -12
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { r as registerInstance, h, H as Host, c as createEvent, g as getElement } from './index-
|
|
2
|
-
import { Z as
|
|
1
|
+
import { r as registerInstance, h, H as Host, c as createEvent, g as getElement } from './index-OLdaFN6W.js';
|
|
2
|
+
import { Z as KritzelBaseTool, _ as ShapeType, $ as KritzelShape, a0 as KritzelToolRegistry, a1 as KritzelEventHelper, R as KritzelSelectionTool, J as KritzelBrushTool, L as KritzelLineTool, P as KritzelTextTool, a2 as KritzelDevicesHelper, a3 as KritzelMouseButton, a4 as DEFAULT_COLOR_PALETTE, W as DEFAULT_BRUSH_CONFIG, Y as DEFAULT_LINE_TOOL_CONFIG, M as KritzelEraserTool, X as DEFAULT_TEXT_CONFIG, N as KritzelImageTool, U as KritzelWorkspace, a5 as KritzelIconRegistry, a6 as KritzelKeyboardHelper, a7 as KritzelBaseHandler, a8 as KritzelSelectionBox, a9 as KritzelSelectionGroup, aa as KritzelBaseObject, I as KritzelGroup, F as KritzelImage, K as KritzelText, G as KritzelLine, E as KritzelPath, ab as Doc, ac as DEFAULT_SYNC_CONFIG, ad as UndoManager, Q as KritzelCursorHelper, T as KritzelAppStateMap, V as KritzelAnchorManager, ae as ObjectHelper, af as KritzelClassHelper } from './default-line-tool.config-DLpNl6R9.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
|
|
|
@@ -37,13 +37,13 @@ const KritzelColor = class {
|
|
|
37
37
|
}
|
|
38
38
|
render() {
|
|
39
39
|
const isColorVeryLight = this.isLightColor(this.value);
|
|
40
|
-
return (h(Host, { key: '
|
|
40
|
+
return (h(Host, { key: '5d9fa3dd0fa30dd8e6589459efafd63a71c317bb' }, h("div", { key: 'fe35227ea4636234de62b7eec42f11a58ca788bb', class: "checkerboard-bg", style: {
|
|
41
41
|
width: `${this.size}px`,
|
|
42
42
|
height: `${this.size}px`,
|
|
43
43
|
borderRadius: '50%',
|
|
44
44
|
display: 'inline-block',
|
|
45
45
|
position: 'relative',
|
|
46
|
-
} }, h("div", { key: '
|
|
46
|
+
} }, h("div", { key: '37f99d30a6f238e9e1f9976d2419364d2f83bbd8', class: {
|
|
47
47
|
'color-circle': true,
|
|
48
48
|
'white': isColorVeryLight,
|
|
49
49
|
}, style: {
|
|
@@ -60,7 +60,39 @@ const KritzelColor = class {
|
|
|
60
60
|
};
|
|
61
61
|
KritzelColor.style = kritzelColorCss();
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
class KritzelColorHelper {
|
|
64
|
+
/**
|
|
65
|
+
* Applies opacity to a hex color and returns an rgba string.
|
|
66
|
+
* @param hexColor - The hex color string (e.g., '#ff0000' or '#f00')
|
|
67
|
+
* @param opacity - The opacity value between 0 and 1
|
|
68
|
+
* @returns The color as an rgba string, or the original hex if opacity is 1
|
|
69
|
+
*/
|
|
70
|
+
static applyOpacity(hexColor, opacity) {
|
|
71
|
+
if (opacity >= 1)
|
|
72
|
+
return hexColor;
|
|
73
|
+
const sanitizedHex = hexColor.startsWith('#') ? hexColor.slice(1) : hexColor;
|
|
74
|
+
let r, g, b;
|
|
75
|
+
if (sanitizedHex.length === 3) {
|
|
76
|
+
r = parseInt(sanitizedHex[0] + sanitizedHex[0], 16);
|
|
77
|
+
g = parseInt(sanitizedHex[1] + sanitizedHex[1], 16);
|
|
78
|
+
b = parseInt(sanitizedHex[2] + sanitizedHex[2], 16);
|
|
79
|
+
}
|
|
80
|
+
else if (sanitizedHex.length === 6) {
|
|
81
|
+
r = parseInt(sanitizedHex.substring(0, 2), 16);
|
|
82
|
+
g = parseInt(sanitizedHex.substring(2, 4), 16);
|
|
83
|
+
b = parseInt(sanitizedHex.substring(4, 6), 16);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
return hexColor;
|
|
87
|
+
}
|
|
88
|
+
if (isNaN(r) || isNaN(g) || isNaN(b)) {
|
|
89
|
+
return hexColor;
|
|
90
|
+
}
|
|
91
|
+
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const kritzelColorPaletteCss = () => `:host{display:flex;align-items:flex-start;gap:8px;padding:0;width:100%;box-sizing:border-box}.color-grid{width:100%;display:grid;grid-template-columns:repeat(6, 32px);gap:8px;justify-items:center;overflow:hidden;height:40px;transition:height 0.1s ease-in-out}.color-grid.expanded{height:500px}.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}.color-container:hover{background-color:var(--kritzel-color-palette-hover-background-color, #ebebeb)}.color-container.selected{border-color:var(--kritzel-selection-border-color, #007AFF);background-color:var(--kritzel-color-palette-selected-background-color)}`;
|
|
64
96
|
|
|
65
97
|
const KritzelColorPalette = class {
|
|
66
98
|
constructor(hostRef) {
|
|
@@ -71,6 +103,7 @@ const KritzelColorPalette = class {
|
|
|
71
103
|
selectedColor = null;
|
|
72
104
|
isExpanded = false;
|
|
73
105
|
isOpaque = false;
|
|
106
|
+
opacity = 1;
|
|
74
107
|
colorChange;
|
|
75
108
|
handleColorClick(color) {
|
|
76
109
|
this.selectedColor = color;
|
|
@@ -92,7 +125,7 @@ const KritzelColorPalette = class {
|
|
|
92
125
|
render() {
|
|
93
126
|
const displayedColors = this.isExpanded ? this.colors : this.colors.slice(0, 6);
|
|
94
127
|
const expandedHeight = this.isExpanded ? this.calculateHeight() : '32px';
|
|
95
|
-
return (h(Host, { key: '
|
|
128
|
+
return (h(Host, { key: '5d7861ab8510af002d4f0f4171a38bf4624d70cb' }, h("div", { key: 'd8b65ecf9aa36e0a158170e12aec27d112f5e0de', class: {
|
|
96
129
|
'color-grid': true,
|
|
97
130
|
'expanded': this.isExpanded,
|
|
98
131
|
}, style: {
|
|
@@ -100,7 +133,7 @@ const KritzelColorPalette = class {
|
|
|
100
133
|
} }, displayedColors.map(color => (h("div", { tabIndex: 0, class: {
|
|
101
134
|
'color-container': true,
|
|
102
135
|
'selected': this.selectedColor === color,
|
|
103
|
-
}, onClick: () => this.handleColorClick(color), onKeyDown: event => this.handleKeyDown(event, color) }, h("kritzel-color", { value: color })))))));
|
|
136
|
+
}, onClick: () => this.handleColorClick(color), onKeyDown: event => this.handleKeyDown(event, color) }, h("kritzel-color", { value: KritzelColorHelper.applyOpacity(color, this.opacity) })))))));
|
|
104
137
|
}
|
|
105
138
|
};
|
|
106
139
|
KritzelColorPalette.style = kritzelColorPaletteCss();
|
|
@@ -204,198 +237,450 @@ const KritzelContextMenu = class {
|
|
|
204
237
|
};
|
|
205
238
|
KritzelContextMenu.style = kritzelContextMenuCss();
|
|
206
239
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
this.toolChange.emit(this.tool);
|
|
240
|
-
}
|
|
241
|
-
render() {
|
|
242
|
-
return (h(Host, { key: 'ce2ac77db22f52239a45b62f690d54009f2c6954' }, h("div", { key: '5f6c50853e876c3612bb5c270bccc468c2c9a726', style: {
|
|
243
|
-
display: 'flex',
|
|
244
|
-
flexDirection: 'row',
|
|
245
|
-
alignItems: this.isExpanded ? 'flex-start' : 'center',
|
|
246
|
-
justifyContent: 'flex-start',
|
|
247
|
-
width: '100%',
|
|
248
|
-
gap: '8px',
|
|
249
|
-
} }, h("kritzel-color-palette", { key: 'bfa24bb8683027c37f200ad65e4e6787d7224c56', colors: this.palette, selectedColor: this.tool.color, isExpanded: this.isExpanded, isOpaque: true, onColorChange: color => this.handleColorChange(color) }), h("button", { key: '8e2c55c6d16ca3911c5f068c354bdce5a4f7e844', class: "expand-toggle", onClick: () => this.handleToggleExpand(), title: this.isExpanded ? 'Collapse' : 'Expand', style: this.palette.length > 6 ? { visibillity: 'visible' } : { visibility: 'hidden' } }, h("kritzel-icon", { key: '33610ada109fe5d1d9cb2da4c70a60d672e3d6cb', name: this.isExpanded ? 'chevron-up' : 'chevron-down' }))), h("kritzel-stroke-size", { key: '9b095dd9436e46dd88a3485ceb2dafa5d06d1bc4', selectedSize: this.tool.size, onSizeChange: event => this.handleSizeChange(event) })));
|
|
250
|
-
}
|
|
251
|
-
static get watchers() { return {
|
|
252
|
-
"tool": [{
|
|
253
|
-
"handleToolChange": 0
|
|
254
|
-
}]
|
|
255
|
-
}; }
|
|
256
|
-
};
|
|
257
|
-
KritzelControlBrushConfig.style = kritzelControlBrushConfigCss();
|
|
258
|
-
|
|
259
|
-
const kritzelControlTextConfigCss = () => `:host{display:block;flex-direction:column;width:100%}.expand-toggle{background:none;border:none;cursor:var(--kritzel-pointer-cursor, pointer);font-size:14px;line-height:1;padding:8px;color:var(--kritzel-color-palette-expand-toggle-color, #666666)}.expand-toggle:hover{color:var(--kritzel-color-palette-expand-toggle-hover-color, #333333)}`;
|
|
260
|
-
|
|
261
|
-
const KritzelControlTextConfig = class {
|
|
262
|
-
constructor(hostRef) {
|
|
263
|
-
registerInstance(this, hostRef);
|
|
264
|
-
this.toolChange = createEvent(this, "toolChange");
|
|
265
|
-
}
|
|
266
|
-
tool;
|
|
267
|
-
isExpanded = false;
|
|
268
|
-
toolChange;
|
|
269
|
-
handleToggleExpand() {
|
|
270
|
-
this.isExpanded = !this.isExpanded;
|
|
271
|
-
}
|
|
272
|
-
handleFamilyChange(event) {
|
|
273
|
-
this.tool.fontFamily = event.detail;
|
|
274
|
-
this.toolChange.emit(this.tool);
|
|
275
|
-
}
|
|
276
|
-
handleColorChange(event) {
|
|
277
|
-
this.tool.fontColor = event.detail;
|
|
278
|
-
this.toolChange.emit(this.tool);
|
|
279
|
-
}
|
|
280
|
-
handleSizeChange(event) {
|
|
281
|
-
this.tool.fontSize = event.detail;
|
|
282
|
-
this.toolChange.emit(this.tool);
|
|
283
|
-
}
|
|
284
|
-
render() {
|
|
285
|
-
return (h(Host, { key: '4a0027969b183fef77c374eb114d9d30104e5ad7' }, h("div", { key: '9f49eb3a95080447b938fdfeb256fafbe5ff9ddc', style: {
|
|
286
|
-
display: 'flex',
|
|
287
|
-
flexDirection: 'row',
|
|
288
|
-
alignItems: 'center',
|
|
289
|
-
justifyContent: 'flex-start',
|
|
290
|
-
width: '100%',
|
|
291
|
-
gap: '8px',
|
|
292
|
-
} }, h("kritzel-font-family", { key: '4e75cda048f8b8c04e6cb5568e7cdcde91e28112', selectedFontFamily: this.tool.fontFamily, onFontFamilyChange: event => this.handleFamilyChange(event) }), h("button", { key: '05c6ce98bd700e9e9d2e676cbcf191b943a2980e', class: "expand-toggle", onClick: () => this.handleToggleExpand(), title: this.isExpanded ? 'Collapse' : 'Expand', tabindex: "0" }, h("kritzel-icon", { key: 'ce30d48dd5ce5eefeee7702dff81ca8f96e0872d', name: this.isExpanded ? 'chevron-up' : 'chevron-down' }))), h("kritzel-color-palette", { key: 'a3d313bf01dafc15c8cf39a129d8c0c35741a3ca', colors: this.tool.palette, selectedColor: this.tool.fontColor, isExpanded: this.isExpanded, onColorChange: event => this.handleColorChange(event) }), h("kritzel-font-size", { key: '954db891b80fb244083de24dc87255b1239ff913', selectedSize: this.tool.fontSize, fontFamily: this.tool.fontFamily, onSizeChange: event => this.handleSizeChange(event) })));
|
|
293
|
-
}
|
|
294
|
-
};
|
|
295
|
-
KritzelControlTextConfig.style = kritzelControlTextConfigCss();
|
|
296
|
-
|
|
297
|
-
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-content{display:flex;flex-direction:column;gap:var(--kritzel-submenu-gap, 4px);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{z-index:10001}`;
|
|
298
|
-
|
|
299
|
-
const KritzelControls = class {
|
|
300
|
-
constructor(hostRef) {
|
|
301
|
-
registerInstance(this, hostRef);
|
|
302
|
-
this.isControlsReady = createEvent(this, "isControlsReady");
|
|
303
|
-
}
|
|
304
|
-
get host() { return getElement(this); }
|
|
305
|
-
controls = [];
|
|
306
|
-
activeControl = null;
|
|
307
|
-
isUtilityPanelVisible = true;
|
|
308
|
-
undoState = null;
|
|
309
|
-
isControlsReady;
|
|
310
|
-
firstConfig = null;
|
|
311
|
-
isTooltipVisible = false;
|
|
312
|
-
isTouchDevice = KritzelDevicesHelper.isTouchDevice();
|
|
313
|
-
selectedSubOptions = new Map();
|
|
314
|
-
openSubMenuControl = null;
|
|
315
|
-
handleDocumentClick(event) {
|
|
316
|
-
const element = event.target;
|
|
317
|
-
if (!this.kritzelEngine || element.closest('.kritzel-tooltip')) {
|
|
318
|
-
return;
|
|
319
|
-
}
|
|
320
|
-
this.isTooltipVisible = false;
|
|
240
|
+
class KritzelShapeTool extends KritzelBaseTool {
|
|
241
|
+
shapeType = ShapeType.Rectangle;
|
|
242
|
+
fillColor = 'transparent';
|
|
243
|
+
strokeColor = '#000000';
|
|
244
|
+
strokeWidth = 4;
|
|
245
|
+
opacity = 1;
|
|
246
|
+
fontFamily = 'Arial';
|
|
247
|
+
fontSize = 16;
|
|
248
|
+
fontColor = '#000000';
|
|
249
|
+
palette = [
|
|
250
|
+
'#000000',
|
|
251
|
+
'#FFFFFF',
|
|
252
|
+
'#FF0000',
|
|
253
|
+
'#00FF00',
|
|
254
|
+
'#0000FF',
|
|
255
|
+
'#FFFF00',
|
|
256
|
+
'#FF00FF',
|
|
257
|
+
'#00FFFF',
|
|
258
|
+
'#808080',
|
|
259
|
+
'#C0C0C0',
|
|
260
|
+
'#800000',
|
|
261
|
+
'#008000',
|
|
262
|
+
'#000080',
|
|
263
|
+
'#808000',
|
|
264
|
+
'#800080',
|
|
265
|
+
];
|
|
266
|
+
startX = 0;
|
|
267
|
+
startY = 0;
|
|
268
|
+
isDrawing = false;
|
|
269
|
+
currentShape = null;
|
|
270
|
+
constructor(core) {
|
|
271
|
+
super(core);
|
|
321
272
|
}
|
|
322
|
-
|
|
323
|
-
if (event.
|
|
273
|
+
handlePointerDown(event) {
|
|
274
|
+
if (event.cancelable) {
|
|
324
275
|
event.preventDefault();
|
|
325
|
-
this.closeTooltip();
|
|
326
|
-
this.openSubMenuControl = null;
|
|
327
|
-
this.kritzelEngine?.enable();
|
|
328
276
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
if (!this.kritzelEngine) {
|
|
353
|
-
throw new Error('kritzel-engine not found in parent element.');
|
|
277
|
+
if (event.pointerType === 'mouse') {
|
|
278
|
+
const path = event.composedPath().slice(1);
|
|
279
|
+
const objectElement = path.find(element => element.classList && element.classList.contains('object'));
|
|
280
|
+
const object = this._core.findObjectById(objectElement?.id);
|
|
281
|
+
const activeShape = this._core.store.activeShape;
|
|
282
|
+
if (activeShape === null && object instanceof KritzelShape) {
|
|
283
|
+
object.edit(event);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
if (activeShape !== null && object instanceof KritzelShape) {
|
|
287
|
+
activeShape.save();
|
|
288
|
+
object.edit(event);
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
if (activeShape !== null && object instanceof KritzelShape === false) {
|
|
292
|
+
this._core.resetActiveShape();
|
|
293
|
+
this._core.store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
if (KritzelEventHelper.isLeftClick(event) === false) {
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
this.startDrawing(event.clientX, event.clientY);
|
|
354
300
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
301
|
+
if (event.pointerType === 'touch') {
|
|
302
|
+
const activePointers = Array.from(this._core.store.state.pointers.values());
|
|
303
|
+
const path = event.composedPath().slice(1);
|
|
304
|
+
const objectElement = path.find(element => element.classList && element.classList.contains('object'));
|
|
305
|
+
const object = this._core.findObjectById(objectElement?.id);
|
|
306
|
+
const activeShape = this._core.store.activeShape;
|
|
307
|
+
if (activeShape === null && object instanceof KritzelShape) {
|
|
308
|
+
object.edit(event);
|
|
309
|
+
return;
|
|
360
310
|
}
|
|
361
|
-
if (
|
|
362
|
-
|
|
363
|
-
|
|
311
|
+
if (activeShape !== null && object instanceof KritzelShape) {
|
|
312
|
+
activeShape.save();
|
|
313
|
+
object.edit(event);
|
|
314
|
+
return;
|
|
364
315
|
}
|
|
365
|
-
if (
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
316
|
+
if (activeShape !== null && object instanceof KritzelShape === false) {
|
|
317
|
+
this._core.resetActiveShape();
|
|
318
|
+
this._core.store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
if (activePointers.length > 1) {
|
|
322
|
+
return;
|
|
372
323
|
}
|
|
324
|
+
const clientX = Math.round(activePointers[0].clientX);
|
|
325
|
+
const clientY = Math.round(activePointers[0].clientY);
|
|
326
|
+
this.startDrawing(clientX, clientY);
|
|
373
327
|
}
|
|
374
328
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
await this.kritzelEngine.changeActiveTool(this.activeControl.tool);
|
|
329
|
+
handlePointerMove(event) {
|
|
330
|
+
if (event.cancelable) {
|
|
331
|
+
event.preventDefault();
|
|
379
332
|
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
event.stopPropagation();
|
|
383
|
-
this.isTooltipVisible = !this.isTooltipVisible;
|
|
384
|
-
if (this.isTooltipVisible) {
|
|
385
|
-
this.kritzelEngine?.disable();
|
|
333
|
+
if (!this.isDrawing || !this.currentShape) {
|
|
334
|
+
return;
|
|
386
335
|
}
|
|
387
|
-
|
|
388
|
-
this.
|
|
336
|
+
if (event.pointerType === 'mouse') {
|
|
337
|
+
this.updateShapeSize(event.clientX, event.clientY);
|
|
338
|
+
}
|
|
339
|
+
if (event.pointerType === 'touch') {
|
|
340
|
+
const activePointers = Array.from(this._core.store.state.pointers.values());
|
|
341
|
+
if (activePointers.length === 1) {
|
|
342
|
+
const clientX = Math.round(activePointers[0].clientX);
|
|
343
|
+
const clientY = Math.round(activePointers[0].clientY);
|
|
344
|
+
this.updateShapeSize(clientX, clientY);
|
|
345
|
+
}
|
|
389
346
|
}
|
|
390
|
-
setTimeout(() => {
|
|
391
|
-
this.tooltipRef?.focusContent();
|
|
392
|
-
}, 100);
|
|
393
|
-
}
|
|
394
|
-
async handleToolChange(event) {
|
|
395
|
-
this.activeControl = { ...this.activeControl, tool: event.detail };
|
|
396
|
-
await this.kritzelEngine.changeActiveTool(this.activeControl.tool);
|
|
397
347
|
}
|
|
398
|
-
|
|
348
|
+
handlePointerUp(event) {
|
|
349
|
+
if (event.cancelable) {
|
|
350
|
+
event.preventDefault();
|
|
351
|
+
}
|
|
352
|
+
if (!this.isDrawing || !this.currentShape) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
this.finishDrawing();
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Start drawing a shape. Following the same pattern as LineTool/BrushTool:
|
|
359
|
+
* - Store screen coordinates for startX, startY
|
|
360
|
+
* - Set translateX/Y to -viewportTranslateX/Y (viewport offset)
|
|
361
|
+
* - Set x, y to the actual screen position
|
|
362
|
+
* - Let updateDimensions() convert to world coordinates
|
|
363
|
+
*/
|
|
364
|
+
startDrawing(clientX, clientY) {
|
|
365
|
+
// Store screen coordinates (relative to host element)
|
|
366
|
+
this.startX = clientX - this._core.store.offsetX;
|
|
367
|
+
this.startY = clientY - this._core.store.offsetY;
|
|
368
|
+
this.isDrawing = true;
|
|
369
|
+
// Create shape using screen coordinates, following Path/Line pattern
|
|
370
|
+
this.currentShape = KritzelShape.create(this._core, {
|
|
371
|
+
x: this.startX,
|
|
372
|
+
y: this.startY,
|
|
373
|
+
translateX: -this._core.store.state.translateX,
|
|
374
|
+
translateY: -this._core.store.state.translateY,
|
|
375
|
+
width: 1,
|
|
376
|
+
height: 1,
|
|
377
|
+
shapeType: this.shapeType,
|
|
378
|
+
fillColor: this.fillColor,
|
|
379
|
+
strokeColor: this.strokeColor,
|
|
380
|
+
strokeWidth: this.strokeWidth,
|
|
381
|
+
opacity: this.opacity,
|
|
382
|
+
fontSize: this.fontSize,
|
|
383
|
+
fontFamily: this.fontFamily,
|
|
384
|
+
fontColor: this.fontColor,
|
|
385
|
+
});
|
|
386
|
+
this._core.store.state.objects.insert(this.currentShape);
|
|
387
|
+
this._core.rerender();
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Update shape size during drawing. Following the same pattern as LineTool:
|
|
391
|
+
* - Use screen coordinates directly
|
|
392
|
+
* - The shape's x, y, width, height are all in screen space
|
|
393
|
+
* - updateDimensions() handles conversion to world coordinates
|
|
394
|
+
*/
|
|
395
|
+
updateShapeSize(clientX, clientY) {
|
|
396
|
+
if (!this.currentShape) {
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
const currentX = clientX - this._core.store.offsetX;
|
|
400
|
+
const currentY = clientY - this._core.store.offsetY;
|
|
401
|
+
// Calculate bounding box in screen coordinates
|
|
402
|
+
const minX = Math.min(this.startX, currentX);
|
|
403
|
+
const minY = Math.min(this.startY, currentY);
|
|
404
|
+
const width = Math.abs(currentX - this.startX);
|
|
405
|
+
const height = Math.abs(currentY - this.startY);
|
|
406
|
+
// Update shape with screen coordinates
|
|
407
|
+
this.currentShape.x = minX;
|
|
408
|
+
this.currentShape.y = minY;
|
|
409
|
+
this.currentShape.width = Math.max(1, width);
|
|
410
|
+
this.currentShape.height = Math.max(1, height);
|
|
411
|
+
// Recalculate world-space translateX/Y
|
|
412
|
+
// Reset translateX/Y to initial value before updateDimensions
|
|
413
|
+
this.currentShape.translateX = -this._core.store.state.translateX;
|
|
414
|
+
this.currentShape.translateY = -this._core.store.state.translateY;
|
|
415
|
+
this.currentShape.updateDimensions();
|
|
416
|
+
this._core.store.state.objects.update(this.currentShape);
|
|
417
|
+
}
|
|
418
|
+
finishDrawing() {
|
|
419
|
+
if (!this.currentShape) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
// Remove shape if it's too small (likely an accidental click)
|
|
423
|
+
// Compare in screen space
|
|
424
|
+
if (this.currentShape.width < 10 && this.currentShape.height < 10) {
|
|
425
|
+
const shapeId = this.currentShape.id;
|
|
426
|
+
this._core.store.state.objects.remove(o => o.id === shapeId);
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
this.currentShape.zIndex = this._core.store.currentZIndex;
|
|
430
|
+
this._core.store.state.objects.update(this.currentShape);
|
|
431
|
+
this._core.engine.emitObjectsChange();
|
|
432
|
+
this._core.selectObjects([this.currentShape]);
|
|
433
|
+
this._core.store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
|
|
434
|
+
}
|
|
435
|
+
this.isDrawing = false;
|
|
436
|
+
this.currentShape = null;
|
|
437
|
+
this._core.rerender();
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
class KritzelToolConfigHelper {
|
|
442
|
+
static getToolConfig(tool) {
|
|
443
|
+
if (tool instanceof KritzelSelectionTool) {
|
|
444
|
+
return tool.getToolConfig();
|
|
445
|
+
}
|
|
446
|
+
if (tool instanceof KritzelBrushTool) {
|
|
447
|
+
return {
|
|
448
|
+
type: 'brush',
|
|
449
|
+
colorProperty: 'color',
|
|
450
|
+
sizeProperty: 'size',
|
|
451
|
+
opacityProperty: 'opacity',
|
|
452
|
+
paletteSource: 'palettes',
|
|
453
|
+
controls: [
|
|
454
|
+
{ type: 'stroke-size', propertyName: 'size' },
|
|
455
|
+
],
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
if (tool instanceof KritzelLineTool) {
|
|
459
|
+
return {
|
|
460
|
+
type: 'line',
|
|
461
|
+
colorProperty: 'color',
|
|
462
|
+
sizeProperty: 'size',
|
|
463
|
+
opacityProperty: 'opacity',
|
|
464
|
+
paletteSource: 'palette',
|
|
465
|
+
controls: [
|
|
466
|
+
{ type: 'stroke-size', propertyName: 'size' },
|
|
467
|
+
{ type: 'line-endings', propertyName: 'arrows', additionalProps: {} },
|
|
468
|
+
],
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
if (tool instanceof KritzelShapeTool) {
|
|
472
|
+
return {
|
|
473
|
+
type: 'shape',
|
|
474
|
+
colorProperty: 'strokeColor',
|
|
475
|
+
sizeProperty: 'strokeWidth',
|
|
476
|
+
opacityProperty: 'opacity',
|
|
477
|
+
paletteSource: 'palette',
|
|
478
|
+
controls: [
|
|
479
|
+
{ type: 'stroke-size', propertyName: 'strokeWidth' },
|
|
480
|
+
{ type: 'shape-fill', propertyName: 'fillColor', additionalProps: {} },
|
|
481
|
+
],
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
if (tool instanceof KritzelTextTool) {
|
|
485
|
+
return {
|
|
486
|
+
type: 'text',
|
|
487
|
+
colorProperty: 'fontColor',
|
|
488
|
+
sizeProperty: 'fontSize',
|
|
489
|
+
opacityProperty: 'opacity',
|
|
490
|
+
paletteSource: 'palette',
|
|
491
|
+
controls: [
|
|
492
|
+
{ type: 'font-size', propertyName: 'fontSize', additionalProps: {} },
|
|
493
|
+
{ type: 'font-family', propertyName: 'fontFamily' },
|
|
494
|
+
],
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
// Tool is not configurable (e.g., selection, eraser, image)
|
|
498
|
+
return null;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
const kritzelControlsCss = () => `:host{display:flex;flex-direction:column;user-select:none;max-width:calc(100vw - 28px)}: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;max-width:100%;overflow:hidden}.kritzel-tools-scroll{display:flex;flex-direction:row;align-items:center;gap:var(--kritzel-controls-gap, 8px);overflow-x:auto;overflow-y:hidden;flex:1 1 auto;min-width:0;scrollbar-width:none;-ms-overflow-style:none}.kritzel-tools-scroll::-webkit-scrollbar{display:none}.scroll-indicator-left,.scroll-indicator-right{position:absolute;top:0;bottom:0;width:24px;pointer-events:none;opacity:0;transition:opacity 0.2s ease-out;z-index:1}.scroll-indicator-left{left:0;background:linear-gradient(to right, var(--kritzel-controls-background-color, #ffffff), transparent);border-radius:var(--kritzel-controls-border-radius, 16px) 0 0 var(--kritzel-controls-border-radius, 16px)}.scroll-indicator-right{right:0;background:linear-gradient(to left, var(--kritzel-controls-background-color, #ffffff), transparent);border-radius:0 var(--kritzel-controls-border-radius, 16px) var(--kritzel-controls-border-radius, 16px) 0}.scroll-indicator-left.visible,.scroll-indicator-right.visible{opacity:1}.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-content{display:flex;flex-direction:column;gap:var(--kritzel-submenu-gap, 4px);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;flex-shrink:0;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;overflow:visible}.config-gradient-left{position:absolute;top:0;bottom:0;left:-16px;width:16px;background:linear-gradient(to right, transparent, var(--kritzel-controls-background-color, #ffffff));pointer-events:none;z-index:1}.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{z-index:10001}`;
|
|
503
|
+
|
|
504
|
+
const KritzelControls = class {
|
|
505
|
+
constructor(hostRef) {
|
|
506
|
+
registerInstance(this, hostRef);
|
|
507
|
+
this.isControlsReady = createEvent(this, "isControlsReady");
|
|
508
|
+
}
|
|
509
|
+
get host() { return getElement(this); }
|
|
510
|
+
controls = [];
|
|
511
|
+
activeControl = null;
|
|
512
|
+
isUtilityPanelVisible = true;
|
|
513
|
+
undoState = null;
|
|
514
|
+
isControlsReady;
|
|
515
|
+
firstConfig = null;
|
|
516
|
+
isTooltipVisible = false;
|
|
517
|
+
isTouchDevice = KritzelDevicesHelper.isTouchDevice();
|
|
518
|
+
selectedSubOptions = new Map();
|
|
519
|
+
openSubMenuControl = null;
|
|
520
|
+
canScrollLeft = false;
|
|
521
|
+
canScrollRight = false;
|
|
522
|
+
displayValues = null;
|
|
523
|
+
handleDocumentClick(event) {
|
|
524
|
+
if (!this.kritzelEngine) {
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
// Use composedPath to check if click is inside tooltip (works across shadow DOM boundaries)
|
|
528
|
+
const path = event.composedPath();
|
|
529
|
+
const isInsideTooltip = path.some(el => {
|
|
530
|
+
const element = el;
|
|
531
|
+
if (element.tagName) {
|
|
532
|
+
return element.tagName.toLowerCase() === 'kritzel-tooltip' || element.classList?.contains('kritzel-tooltip');
|
|
533
|
+
}
|
|
534
|
+
return false;
|
|
535
|
+
});
|
|
536
|
+
if (isInsideTooltip) {
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
this.isTooltipVisible = false;
|
|
540
|
+
}
|
|
541
|
+
handleKeyDown(event) {
|
|
542
|
+
if (event.key === 'Escape') {
|
|
543
|
+
event.preventDefault();
|
|
544
|
+
this.closeTooltip();
|
|
545
|
+
this.openSubMenuControl = null;
|
|
546
|
+
this.kritzelEngine?.enable();
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
async handleActiveToolChange(event) {
|
|
550
|
+
this.activeControl = this.controls.find(control => control.tool === event.detail) || null;
|
|
551
|
+
if (this.activeControl?.tool) {
|
|
552
|
+
this.updateDisplayValues(this.activeControl.tool);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
handleSelectionChange() {
|
|
556
|
+
if (this.activeControl?.tool instanceof KritzelSelectionTool) {
|
|
557
|
+
this.updateDisplayValues(this.activeControl.tool);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
async closeTooltip() {
|
|
561
|
+
this.isTooltipVisible = false;
|
|
562
|
+
}
|
|
563
|
+
kritzelEngine = null;
|
|
564
|
+
tooltipRef = null;
|
|
565
|
+
toolsScrollRef = null;
|
|
566
|
+
get activeToolAsTextTool() {
|
|
567
|
+
return this.activeControl?.tool;
|
|
568
|
+
}
|
|
569
|
+
get activeToolAsBrushTool() {
|
|
570
|
+
return this.activeControl?.tool;
|
|
571
|
+
}
|
|
572
|
+
get activeToolAsLineTool() {
|
|
573
|
+
return this.activeControl?.tool;
|
|
574
|
+
}
|
|
575
|
+
get activeToolAsShapeTool() {
|
|
576
|
+
return this.activeControl?.tool;
|
|
577
|
+
}
|
|
578
|
+
handleDisplayValuesChange = (event) => {
|
|
579
|
+
const newVal = event.detail;
|
|
580
|
+
if (this.displayValues &&
|
|
581
|
+
this.displayValues.color === newVal.color &&
|
|
582
|
+
this.displayValues.size === newVal.size &&
|
|
583
|
+
this.displayValues.fontFamily === newVal.fontFamily) {
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
this.displayValues = newVal;
|
|
587
|
+
};
|
|
588
|
+
updateDisplayValues(tool) {
|
|
589
|
+
const config = KritzelToolConfigHelper.getToolConfig(tool);
|
|
590
|
+
if (!config) {
|
|
591
|
+
this.displayValues = null;
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
const color = tool[config.colorProperty];
|
|
595
|
+
const opacity = tool[config.opacityProperty] ?? 1;
|
|
596
|
+
const size = tool[config.sizeProperty];
|
|
597
|
+
const displayValues = {
|
|
598
|
+
color: KritzelColorHelper.applyOpacity(color, opacity),
|
|
599
|
+
size,
|
|
600
|
+
};
|
|
601
|
+
if (tool instanceof KritzelTextTool) {
|
|
602
|
+
displayValues.fontFamily = tool.fontFamily;
|
|
603
|
+
}
|
|
604
|
+
// Check for equality implementation to prevent unnecessary re-renders
|
|
605
|
+
if (this.displayValues &&
|
|
606
|
+
this.displayValues.color === displayValues.color &&
|
|
607
|
+
this.displayValues.size === displayValues.size &&
|
|
608
|
+
this.displayValues.fontFamily === displayValues.fontFamily) {
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
this.displayValues = displayValues;
|
|
612
|
+
}
|
|
613
|
+
async componentWillLoad() {
|
|
614
|
+
await this.initializeEngine();
|
|
615
|
+
await this.initializeTools();
|
|
616
|
+
this.isControlsReady.emit();
|
|
617
|
+
}
|
|
618
|
+
componentDidLoad() {
|
|
619
|
+
this.updateScrollIndicators();
|
|
620
|
+
}
|
|
621
|
+
updateScrollIndicators() {
|
|
622
|
+
if (!this.toolsScrollRef)
|
|
623
|
+
return;
|
|
624
|
+
const { scrollLeft, scrollWidth, clientWidth } = this.toolsScrollRef;
|
|
625
|
+
const threshold = 2; // Small threshold to account for rounding
|
|
626
|
+
this.canScrollLeft = scrollLeft > threshold;
|
|
627
|
+
this.canScrollRight = scrollLeft + clientWidth < scrollWidth - threshold;
|
|
628
|
+
}
|
|
629
|
+
handleToolsScroll = () => {
|
|
630
|
+
this.updateScrollIndicators();
|
|
631
|
+
};
|
|
632
|
+
async initializeEngine() {
|
|
633
|
+
await customElements.whenDefined('kritzel-engine');
|
|
634
|
+
this.kritzelEngine = this.host.parentElement.querySelector('kritzel-engine');
|
|
635
|
+
if (!this.kritzelEngine) {
|
|
636
|
+
throw new Error('kritzel-engine not found in parent element.');
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
async initializeTools() {
|
|
640
|
+
for (const c of this.controls) {
|
|
641
|
+
if (c.type === 'tool' && c.tool) {
|
|
642
|
+
c.tool = await this.kritzelEngine.registerTool(c.name, c.tool, c.config);
|
|
643
|
+
}
|
|
644
|
+
if (c.type === 'tool' && c.isDefault && c.tool) {
|
|
645
|
+
await this.kritzelEngine.changeActiveTool(c.tool);
|
|
646
|
+
this.activeControl = c;
|
|
647
|
+
this.updateDisplayValues(c.tool);
|
|
648
|
+
}
|
|
649
|
+
if (c.type === 'config') {
|
|
650
|
+
if (this.firstConfig === null) {
|
|
651
|
+
this.firstConfig = c;
|
|
652
|
+
}
|
|
653
|
+
else {
|
|
654
|
+
console.warn('Only one config control is allowed. The first one will be used.');
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
async handleControlClick(control) {
|
|
660
|
+
this.activeControl = control;
|
|
661
|
+
if (this.activeControl.type === 'tool') {
|
|
662
|
+
this.updateDisplayValues(this.activeControl.tool);
|
|
663
|
+
await this.kritzelEngine.changeActiveTool(this.activeControl.tool);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
handleConfigClick(event) {
|
|
667
|
+
event.stopPropagation();
|
|
668
|
+
this.isTooltipVisible = !this.isTooltipVisible;
|
|
669
|
+
if (this.isTooltipVisible) {
|
|
670
|
+
this.kritzelEngine?.disable();
|
|
671
|
+
}
|
|
672
|
+
else {
|
|
673
|
+
this.kritzelEngine?.enable();
|
|
674
|
+
}
|
|
675
|
+
setTimeout(() => {
|
|
676
|
+
this.tooltipRef?.focusContent();
|
|
677
|
+
}, 100);
|
|
678
|
+
}
|
|
679
|
+
async handleToolChange(event) {
|
|
680
|
+
this.activeControl = { ...this.activeControl, tool: event.detail };
|
|
681
|
+
await this.kritzelEngine.changeActiveTool(this.activeControl.tool);
|
|
682
|
+
}
|
|
683
|
+
handleTooltipClosed() {
|
|
399
684
|
this.isTooltipVisible = false;
|
|
400
685
|
this.kritzelEngine?.enable();
|
|
401
686
|
}
|
|
@@ -439,56 +724,62 @@ const KritzelControls = class {
|
|
|
439
724
|
}
|
|
440
725
|
render() {
|
|
441
726
|
const hasConfigUI = this.activeControl?.tool instanceof KritzelBrushTool ||
|
|
442
|
-
this.activeControl?.tool instanceof KritzelTextTool
|
|
443
|
-
|
|
727
|
+
this.activeControl?.tool instanceof KritzelTextTool ||
|
|
728
|
+
this.activeControl?.tool instanceof KritzelLineTool ||
|
|
729
|
+
this.activeControl?.tool instanceof KritzelShapeTool ||
|
|
730
|
+
(this.activeControl?.tool instanceof KritzelSelectionTool && this.activeControl.tool.hasSelection());
|
|
731
|
+
// Separate tool controls from config control
|
|
732
|
+
const toolControls = this.controls.filter(c => c.type === 'tool');
|
|
733
|
+
const configControl = this.controls.find(c => c.type === 'config' && c.name === this.firstConfig?.name);
|
|
734
|
+
return (h(Host, { key: 'db2a043a2a32d10d7f27c01123da63115781941c', class: {
|
|
444
735
|
mobile: this.isTouchDevice,
|
|
445
|
-
} }, this.isUtilityPanelVisible && (h("kritzel-utility-panel", { key: '
|
|
736
|
+
} }, this.isUtilityPanelVisible && (h("kritzel-utility-panel", { key: '09104351c9f178b8d0dbc0636cf9cc230b2bca53', style: {
|
|
446
737
|
position: 'absolute',
|
|
447
738
|
bottom: '56px',
|
|
448
739
|
left: '12px',
|
|
449
|
-
}, undoState: this.undoState, onUndo: () => this.kritzelEngine?.undo(), onRedo: () => this.kritzelEngine?.redo(), onDelete: () => this.kritzelEngine?.delete() })), h("div", { key: '
|
|
450
|
-
|
|
451
|
-
//
|
|
452
|
-
if (
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
if (el)
|
|
461
|
-
control._anchorRef = el;
|
|
462
|
-
} }, h("button", { class: "kritzel-control-main", onClick: () => this.handleControlClick(control), title: selectedSubOption?.label }, h("kritzel-icon", { name: selectedSubOption?.icon || control.icon })), h("button", { class: {
|
|
463
|
-
'kritzel-control-dropdown': true,
|
|
464
|
-
'visible': isActive,
|
|
465
|
-
}, 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 })), h("kritzel-tooltip", { isVisible: isSubMenuOpen, anchorElement: control._anchorRef, onTooltipClosed: () => { this.openSubMenuControl = null; } }, h("div", { class: "kritzel-submenu-content" }, control.subOptions.map(option => (h("button", { class: {
|
|
466
|
-
'kritzel-submenu-item': true,
|
|
467
|
-
'active': option.id === selectedSubOption?.id,
|
|
468
|
-
}, key: option.id, onClick: () => this.selectSubOption(control, option) }, h("kritzel-icon", { name: option.icon, size: 20 }), h("span", null, option.label))))))));
|
|
469
|
-
}
|
|
470
|
-
// Regular tool control (no sub-options)
|
|
471
|
-
return (h("button", { class: {
|
|
472
|
-
'kritzel-control': true,
|
|
473
|
-
'selected': this.activeControl?.name === control?.name,
|
|
474
|
-
}, key: control.name, onClick: _event => this.handleControlClick?.(control) }, h("kritzel-icon", { name: control.icon })));
|
|
475
|
-
}
|
|
476
|
-
if (control.type === 'config' && control.name === this.firstConfig?.name && this.activeControl) {
|
|
740
|
+
}, undoState: this.undoState, onUndo: () => this.kritzelEngine?.undo(), onRedo: () => this.kritzelEngine?.redo(), onDelete: () => this.kritzelEngine?.delete() })), h("div", { key: '22f95249dddcf05a75425f96ab5381fe8a4824d4', class: "kritzel-controls" }, h("div", { key: 'fcca99e2a56f401b28205b8806497c46b7f9a94b', class: { 'scroll-indicator-left': true, 'visible': this.canScrollLeft } }), h("div", { key: '145802334aa83b0190a70dd2a3aca4389cb8b88c', class: "kritzel-tools-scroll", ref: el => {
|
|
741
|
+
this.toolsScrollRef = el;
|
|
742
|
+
// Update indicators when ref is set
|
|
743
|
+
if (el)
|
|
744
|
+
this.updateScrollIndicators();
|
|
745
|
+
}, onScroll: this.handleToolsScroll }, toolControls.map(control => {
|
|
746
|
+
// Check if this control has sub-options (split-button)
|
|
747
|
+
if (control.subOptions?.length) {
|
|
748
|
+
const selectedSubOption = this.getSelectedSubOption(control);
|
|
749
|
+
const isActive = this.activeControl?.name === control.name;
|
|
750
|
+
const isSubMenuOpen = this.openSubMenuControl?.name === control.name;
|
|
477
751
|
return (h("div", { class: {
|
|
478
|
-
'kritzel-
|
|
479
|
-
'
|
|
480
|
-
}, key: control.name
|
|
481
|
-
if (
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
}
|
|
752
|
+
'kritzel-control-split': true,
|
|
753
|
+
'selected': isActive,
|
|
754
|
+
}, key: control.name, ref: el => {
|
|
755
|
+
if (el)
|
|
756
|
+
control._anchorRef = el;
|
|
757
|
+
} }, h("button", { class: "kritzel-control-main", onClick: () => this.handleControlClick(control), title: selectedSubOption?.label }, h("kritzel-icon", { name: selectedSubOption?.icon || control.icon })), h("button", { class: {
|
|
758
|
+
'kritzel-control-dropdown': true,
|
|
759
|
+
'visible': isActive,
|
|
760
|
+
}, 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 })), h("kritzel-tooltip", { isVisible: isSubMenuOpen, anchorElement: control._anchorRef, onTooltipClosed: () => { this.openSubMenuControl = null; } }, h("div", { class: "kritzel-submenu-content" }, control.subOptions.map(option => (h("button", { class: {
|
|
761
|
+
'kritzel-submenu-item': true,
|
|
762
|
+
'active': option.id === selectedSubOption?.id,
|
|
763
|
+
}, key: option.id, onClick: () => this.selectSubOption(control, option) }, h("kritzel-icon", { name: option.icon, size: 20 }), h("span", null, option.label))))))));
|
|
490
764
|
}
|
|
491
|
-
|
|
765
|
+
// Regular tool control (no sub-options)
|
|
766
|
+
return (h("button", { class: {
|
|
767
|
+
'kritzel-control': true,
|
|
768
|
+
'selected': this.activeControl?.name === control?.name,
|
|
769
|
+
}, key: control.name, onClick: _event => this.handleControlClick?.(control) }, h("kritzel-icon", { name: control.icon })));
|
|
770
|
+
})), h("div", { key: '43e7811998855f57097b743998363fd6866bfb29', class: { 'scroll-indicator-right': true, 'visible': this.canScrollRight } }), configControl && this.activeControl && (h("div", { class: {
|
|
771
|
+
'kritzel-config-container': true,
|
|
772
|
+
'visible': hasConfigUI,
|
|
773
|
+
}, key: configControl.name }, h("div", { key: 'c1ff98f16c41d45666915b96931f23e0cf12ed6f', class: "config-gradient-left" }), h("kritzel-tooltip", { key: 'eac68125daa371d751b65ac561e33848cad3bd69', ref: el => (this.tooltipRef = el), isVisible: this.isTooltipVisible, anchorElement: this.host.shadowRoot?.querySelector('.kritzel-config-container'), onTooltipClosed: () => this.handleTooltipClosed() }, h("kritzel-tool-config", { key: '83ed025386d9d1b3ec8b52e99930645c4c35b20a', tool: this.activeControl.tool, onToolChange: event => this.handleToolChange?.(event), onDisplayValuesChange: this.handleDisplayValuesChange, style: { width: '100%', height: '100%' } })), h("div", { key: 'cf18abb832c10826685fb41794a42b8b6a6a7486', tabIndex: hasConfigUI ? 0 : -1, class: "kritzel-config", onClick: event => this.handleConfigClick?.(event), onKeyDown: event => {
|
|
774
|
+
if (event.key === 'Enter') {
|
|
775
|
+
this.handleConfigClick?.(event);
|
|
776
|
+
}
|
|
777
|
+
}, style: {
|
|
778
|
+
cursor: 'pointer',
|
|
779
|
+
} }, this.activeControl.tool instanceof KritzelTextTool && this.displayValues ? (h("div", { class: "font-container" }, h("kritzel-font", { fontFamily: this.displayValues.fontFamily, size: this.displayValues.size, color: this.displayValues.color }))) : this.displayValues && (h("div", { class: "color-container" }, h("kritzel-color", { value: this.displayValues.color, size: this.displayValues.size, style: {
|
|
780
|
+
borderRadius: '50%',
|
|
781
|
+
border: 'none',
|
|
782
|
+
} })))))))));
|
|
492
783
|
}
|
|
493
784
|
static get assetsDirs() { return ["../assets"]; }
|
|
494
785
|
};
|
|
@@ -562,7 +853,7 @@ const KritzelCursorTrail = class {
|
|
|
562
853
|
}
|
|
563
854
|
}
|
|
564
855
|
render() {
|
|
565
|
-
return (h(Host, { key: '
|
|
856
|
+
return (h(Host, { key: '65563f09091c0014046b65d424b4cecf89d4a407' }, this.cursorTrailPoints.length > 1 && (h("svg", { key: '9634426566a9cd69cbc63f419726af16826e45f9', class: "cursor-trail-svg", xmlns: "http://www.w3.org/2000/svg", style: {
|
|
566
857
|
position: 'absolute',
|
|
567
858
|
left: '0',
|
|
568
859
|
top: '0',
|
|
@@ -774,629 +1065,64 @@ const KritzelDropdown = class {
|
|
|
774
1065
|
this.hasSuffixContent = newHasContent;
|
|
775
1066
|
}
|
|
776
1067
|
}
|
|
777
|
-
else if (this.hasSuffixContent !== false) {
|
|
778
|
-
this.hasSuffixContent = false;
|
|
779
|
-
}
|
|
780
|
-
};
|
|
781
|
-
evaluatePrefixContent = () => {
|
|
782
|
-
if (this.prefixSlotElement) {
|
|
783
|
-
const newHasContent = this.prefixSlotElement.assignedNodes({ flatten: true }).length > 0;
|
|
784
|
-
if (this.hasPrefixContent !== newHasContent) {
|
|
785
|
-
this.hasPrefixContent = newHasContent;
|
|
786
|
-
}
|
|
787
|
-
}
|
|
788
|
-
else if (this.hasPrefixContent !== false) {
|
|
789
|
-
this.hasPrefixContent = false;
|
|
790
|
-
}
|
|
791
|
-
};
|
|
792
|
-
getSelectedLabel() {
|
|
793
|
-
const selectedOption = this.options.find(opt => opt.value === this.internalValue);
|
|
794
|
-
return selectedOption?.label ?? '';
|
|
795
|
-
}
|
|
796
|
-
getSelectedStyle() {
|
|
797
|
-
const selectedOption = this.options.find(opt => opt.value === this.internalValue);
|
|
798
|
-
return selectedOption?.style;
|
|
799
|
-
}
|
|
800
|
-
render() {
|
|
801
|
-
const triggerClasses = {
|
|
802
|
-
'dropdown-trigger': true,
|
|
803
|
-
'has-suffix-border': this.hasSuffixContent,
|
|
804
|
-
'has-prefix-border': this.hasPrefixContent,
|
|
805
|
-
'is-open': this.isOpen,
|
|
806
|
-
'open-up': this.openDirection === 'up',
|
|
807
|
-
};
|
|
808
|
-
const menuClasses = {
|
|
809
|
-
'dropdown-menu': true,
|
|
810
|
-
'is-open': this.isOpen,
|
|
811
|
-
'open-up': this.openDirection === 'up',
|
|
812
|
-
'open-down': this.openDirection === 'down',
|
|
813
|
-
};
|
|
814
|
-
return (h(Host, { key: '29d076eb2ef76527c0930ab82ace0d05c896ab6c' }, h("div", { key: '1afac5cc0b7f408849670b8cb62fe0bd0f3b27f1', class: "dropdown-wrapper", ref: el => (this.wrapperElement = el) }, h("slot", { key: '3cfcf787c3b3eedbd6bf30c7506a0a4912429672', name: "prefix", ref: el => (this.prefixSlotElement = el), onSlotchange: this.evaluatePrefixContent }), h("div", { key: 'b88120ed3e44871220e6ba61e8bef457651a2086', class: "dropdown-container", style: { width: this.width } }, h("button", { key: '79082189066f3d0b4f5797420ec222847792fe52', type: "button", class: triggerClasses, style: { ...this.selectStyles, ...this.getSelectedStyle() }, onClick: this.toggleMenu, onKeyDown: this.handleTriggerKeyDown, "aria-haspopup": "listbox", "aria-expanded": this.isOpen ? 'true' : 'false', ref: el => (this.triggerElement = el) }, h("span", { key: 'a490bb6689ec1820144fe82f6833bee82e6ead0e', class: "dropdown-trigger-label" }, this.getSelectedLabel()), h("span", { key: '8bd7768f6fdd3c507bbca54d7d135adabe04901f', class: "dropdown-trigger-arrow", "aria-hidden": "true" }, h("svg", { key: 'e1b854d2c93e3067181108f8d782e1393ddb615c', xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("polyline", { key: '3622cbf8964f4e50aa55be5209240dfd252f1d84', points: "6 9 12 15 18 9" }))))), h("slot", { key: 'b91317736904cbeee0f87058b822bd77c6b163ca', name: "suffix", ref: el => (this.suffixSlotElement = el), onSlotchange: this.evaluateSuffixContent }), h("ul", { key: '0ca8690345974e9b7ad184f4c7ab7cf5367b183c', class: menuClasses, role: "listbox", tabindex: "-1", onKeyDown: this.handleMenuKeyDown, ref: el => (this.menuElement = el) }, this.options.map((option, index) => {
|
|
815
|
-
const isSelected = option.value === this.internalValue;
|
|
816
|
-
const isFocused = index === this.focusedIndex;
|
|
817
|
-
const optionClasses = {
|
|
818
|
-
'dropdown-option': true,
|
|
819
|
-
'is-selected': isSelected,
|
|
820
|
-
'is-focused': isFocused,
|
|
821
|
-
};
|
|
822
|
-
return (h("li", { class: optionClasses, role: "option", "aria-selected": isSelected ? 'true' : 'false', style: option.style, onClick: () => this.selectOption(option), onMouseEnter: () => this.handleOptionMouseEnter(index) }, option.label, isSelected && (h("span", { class: "dropdown-option-check", "aria-hidden": "true" }, h("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("polyline", { points: "20 6 9 17 4 12" }))))));
|
|
823
|
-
})))));
|
|
824
|
-
}
|
|
825
|
-
static get watchers() { return {
|
|
826
|
-
"options": [{
|
|
827
|
-
"optionsChanged": 0
|
|
828
|
-
}],
|
|
829
|
-
"value": [{
|
|
830
|
-
"externalValueChanged": 0
|
|
831
|
-
}]
|
|
832
|
-
}; }
|
|
833
|
-
};
|
|
834
|
-
KritzelDropdown.style = kritzelDropdownCss();
|
|
835
|
-
|
|
836
|
-
var ShapeType;
|
|
837
|
-
(function (ShapeType) {
|
|
838
|
-
ShapeType["Rectangle"] = "rectangle";
|
|
839
|
-
ShapeType["Ellipse"] = "ellipse";
|
|
840
|
-
ShapeType["Triangle"] = "triangle";
|
|
841
|
-
})(ShapeType || (ShapeType = {}));
|
|
842
|
-
|
|
843
|
-
class KritzelShape extends KritzelBaseObject {
|
|
844
|
-
__class__ = 'KritzelShape';
|
|
845
|
-
shapeType = ShapeType.Rectangle;
|
|
846
|
-
fillColor = 'transparent';
|
|
847
|
-
strokeColor = '#000000';
|
|
848
|
-
strokeWidth = 4;
|
|
849
|
-
fontFamily = 'Arial';
|
|
850
|
-
fontSize = 16;
|
|
851
|
-
fontColor = '#000000';
|
|
852
|
-
/** Screen-space x coordinate of the shape's top-left corner (like Path.x) */
|
|
853
|
-
x = 0;
|
|
854
|
-
/** Screen-space y coordinate of the shape's top-left corner (like Path.y) */
|
|
855
|
-
y = 0;
|
|
856
|
-
scale = 1;
|
|
857
|
-
scaleFactor = 1;
|
|
858
|
-
isDebugInfoVisible = true;
|
|
859
|
-
isEditable = true;
|
|
860
|
-
isEditing = false;
|
|
861
|
-
editor = null;
|
|
862
|
-
content = null;
|
|
863
|
-
_schema = new Schema({
|
|
864
|
-
nodes: addListNodes(schema.spec.nodes, 'paragraph block*', 'block'),
|
|
865
|
-
marks: schema.spec.marks,
|
|
866
|
-
});
|
|
867
|
-
uneditedObject = null;
|
|
868
|
-
/**
|
|
869
|
-
* Returns the viewBox for the shape's SVG, using screen-space coordinates.
|
|
870
|
-
* This follows the same pattern as KritzelPath.viewBox.
|
|
871
|
-
*/
|
|
872
|
-
get viewBox() {
|
|
873
|
-
return `${this.x} ${this.y} ${this.width} ${this.height}`;
|
|
874
|
-
}
|
|
875
|
-
constructor(config) {
|
|
876
|
-
super();
|
|
877
|
-
if (config) {
|
|
878
|
-
this.x = config.x ?? 0;
|
|
879
|
-
this.y = config.y ?? 0;
|
|
880
|
-
this.translateX = config.translateX ?? 0;
|
|
881
|
-
this.translateY = config.translateY ?? 0;
|
|
882
|
-
this.width = config.width ?? 100;
|
|
883
|
-
this.height = config.height ?? 100;
|
|
884
|
-
this.shapeType = config.shapeType ?? ShapeType.Rectangle;
|
|
885
|
-
this.fillColor = config.fillColor ?? 'transparent';
|
|
886
|
-
this.strokeColor = config.strokeColor ?? '#000000';
|
|
887
|
-
this.strokeWidth = config.strokeWidth ?? 4;
|
|
888
|
-
this.fontSize = config.fontSize ?? 16;
|
|
889
|
-
this.fontFamily = config.fontFamily ?? 'Arial';
|
|
890
|
-
this.fontColor = config.fontColor ?? '#000000';
|
|
891
|
-
this.scale = config.scale ?? 1;
|
|
892
|
-
this.scaleFactor = config.scaleX ?? 1;
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
/**
|
|
896
|
-
* Creates a new KritzelShape with screen-space coordinates.
|
|
897
|
-
* Following the same pattern as KritzelPath.create():
|
|
898
|
-
* - x, y are screen-space coordinates of the shape's top-left corner
|
|
899
|
-
* - translateX, translateY should be set to -viewportTranslateX, -viewportTranslateY
|
|
900
|
-
* - width, height are in screen-space
|
|
901
|
-
* - scale is the viewport scale at creation time
|
|
902
|
-
*/
|
|
903
|
-
static create(core, config) {
|
|
904
|
-
const object = new KritzelShape();
|
|
905
|
-
object._core = core;
|
|
906
|
-
object.id = object.generateId();
|
|
907
|
-
object.workspaceId = core.store.state.activeWorkspace.id;
|
|
908
|
-
object.x = config?.x ?? 0;
|
|
909
|
-
object.y = config?.y ?? 0;
|
|
910
|
-
object.translateX = config?.translateX ?? 0;
|
|
911
|
-
object.translateY = config?.translateY ?? 0;
|
|
912
|
-
object.width = config?.width ?? 100;
|
|
913
|
-
object.height = config?.height ?? 100;
|
|
914
|
-
object.shapeType = config?.shapeType ?? ShapeType.Rectangle;
|
|
915
|
-
object.fillColor = config?.fillColor ?? 'transparent';
|
|
916
|
-
object.strokeColor = config?.strokeColor ?? '#000000';
|
|
917
|
-
object.strokeWidth = config?.strokeWidth ?? 4;
|
|
918
|
-
object.fontSize = config?.fontSize ?? 16;
|
|
919
|
-
object.fontFamily = config?.fontFamily ?? 'Arial';
|
|
920
|
-
object.fontColor = config?.fontColor ?? '#000000';
|
|
921
|
-
object.backgroundColor = 'transparent';
|
|
922
|
-
object.scaleFactor = 1;
|
|
923
|
-
object.scale = core.store.state.scale;
|
|
924
|
-
object.zIndex = core.store.currentZIndex;
|
|
925
|
-
object.editor = object.createEditor();
|
|
926
|
-
// Compute world-space translateX/Y from screen-space coordinates
|
|
927
|
-
// This follows the same pattern as KritzelPath.updateDimensions()
|
|
928
|
-
object.updateDimensions();
|
|
929
|
-
return object;
|
|
930
|
-
}
|
|
931
|
-
/**
|
|
932
|
-
* Updates the translateX/Y to world coordinates based on screen-space x, y.
|
|
933
|
-
* This follows the same pattern as KritzelPath.updateDimensions().
|
|
934
|
-
*
|
|
935
|
-
* The formula: translateX = (x + initialTranslateX) / scale
|
|
936
|
-
* where initialTranslateX was -viewportTranslateX
|
|
937
|
-
*
|
|
938
|
-
* This converts screen-space position to world coordinates.
|
|
939
|
-
*/
|
|
940
|
-
updateDimensions() {
|
|
941
|
-
this.translateX = (this.x + this.translateX) / this.scale;
|
|
942
|
-
this.translateY = (this.y + this.translateY) / this.scale;
|
|
943
|
-
}
|
|
944
|
-
mount(element) {
|
|
945
|
-
if (element === null || this.isInViewport() === false) {
|
|
946
|
-
return;
|
|
947
|
-
}
|
|
948
|
-
if (this.isMounted && this.elementRef === element && this.editor.dom.parentElement === element) {
|
|
949
|
-
return;
|
|
950
|
-
}
|
|
951
|
-
this.elementRef = element;
|
|
952
|
-
this.isMounted = true;
|
|
953
|
-
}
|
|
954
|
-
mountTextEditor(element) {
|
|
955
|
-
if (element === null) {
|
|
956
|
-
return;
|
|
957
|
-
}
|
|
958
|
-
if (this.editor.dom.parentElement === element) {
|
|
959
|
-
return;
|
|
960
|
-
}
|
|
961
|
-
element.style.fontFamily = this.fontFamily;
|
|
962
|
-
element.style.fontSize = `${this.fontSize}pt`;
|
|
963
|
-
element.style.color = this.fontColor;
|
|
964
|
-
element.style.whiteSpace = 'pre-wrap';
|
|
965
|
-
element.style.wordWrap = 'break-word';
|
|
966
|
-
element.innerHTML = '';
|
|
967
|
-
element.appendChild(this.editor.dom);
|
|
968
|
-
}
|
|
969
|
-
createEditor() {
|
|
970
|
-
const doc = this._schema.node('doc', null, [this._schema.node('paragraph')]);
|
|
971
|
-
return new EditorView(null, {
|
|
972
|
-
state: EditorState.create({
|
|
973
|
-
doc: doc,
|
|
974
|
-
plugins: [keymap(baseKeymap)],
|
|
975
|
-
}),
|
|
976
|
-
editable: () => false,
|
|
977
|
-
dispatchTransaction: transaction => {
|
|
978
|
-
const newState = this.editor.state.apply(transaction);
|
|
979
|
-
this.editor.updateState(newState);
|
|
980
|
-
if (transaction.docChanged) {
|
|
981
|
-
this.content = newState.doc.toJSON();
|
|
982
|
-
if (!transaction.getMeta('fromRemote')) {
|
|
983
|
-
this._core.store.state.objects.update(this, { temporary: true });
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
},
|
|
987
|
-
});
|
|
988
|
-
}
|
|
989
|
-
setContent(content) {
|
|
990
|
-
this.content = content;
|
|
991
|
-
if (this.editor && content) {
|
|
992
|
-
const newDoc = this.editor.state.schema.nodeFromJSON(content);
|
|
993
|
-
const tr = this.editor.state.tr.replaceWith(0, this.editor.state.doc.content.size, newDoc.content);
|
|
994
|
-
tr.setMeta('fromRemote', true);
|
|
995
|
-
this.editor.dispatch(tr);
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
resize(x, y, width, height) {
|
|
999
|
-
if (width <= 1 || height <= 1) {
|
|
1000
|
-
return;
|
|
1001
|
-
}
|
|
1002
|
-
this.width = width;
|
|
1003
|
-
this.height = height;
|
|
1004
|
-
this.translateX = x;
|
|
1005
|
-
this.translateY = y;
|
|
1006
|
-
this._core.store.state.objects.update(this);
|
|
1007
|
-
}
|
|
1008
|
-
focus(coords) {
|
|
1009
|
-
if (this.editor) {
|
|
1010
|
-
const doc = this.editor.state.doc;
|
|
1011
|
-
if (coords?.x && coords?.y) {
|
|
1012
|
-
const pos = this.editor.posAtCoords({ left: coords.x, top: coords.y });
|
|
1013
|
-
if (pos) {
|
|
1014
|
-
this.editor.dispatch(this.editor.state.tr.setSelection(TextSelection.create(doc, pos.pos)));
|
|
1015
|
-
this.editor.focus();
|
|
1016
|
-
if (KritzelDevicesHelper.isIOS()) {
|
|
1017
|
-
this.scrollIntoViewOnIOS();
|
|
1018
|
-
}
|
|
1019
|
-
return;
|
|
1020
|
-
}
|
|
1021
|
-
}
|
|
1022
|
-
const end = Math.max(1, doc.content.size - 1);
|
|
1023
|
-
this.editor.dispatch(this.editor.state.tr.setSelection(TextSelection.create(doc, end)));
|
|
1024
|
-
this.editor.focus();
|
|
1025
|
-
if (KritzelDevicesHelper.isIOS()) {
|
|
1026
|
-
this.scrollIntoViewOnIOS();
|
|
1027
|
-
}
|
|
1028
|
-
}
|
|
1029
|
-
}
|
|
1030
|
-
scrollIntoViewOnIOS() {
|
|
1031
|
-
setTimeout(() => {
|
|
1032
|
-
if (this.editor && this.editor.dom) {
|
|
1033
|
-
this.editor.dom.scrollIntoView({
|
|
1034
|
-
behavior: 'smooth',
|
|
1035
|
-
block: 'center',
|
|
1036
|
-
inline: 'nearest',
|
|
1037
|
-
});
|
|
1038
|
-
}
|
|
1039
|
-
}, 300);
|
|
1040
|
-
}
|
|
1041
|
-
edit(event) {
|
|
1042
|
-
KritzelKeyboardHelper.disableInteractiveWidget();
|
|
1043
|
-
this.uneditedObject = this.clone();
|
|
1044
|
-
this._core.store.setState('activeTool', KritzelToolRegistry.getTool('shape'));
|
|
1045
|
-
this.editor.setProps({ editable: () => true });
|
|
1046
|
-
this.isEditing = true;
|
|
1047
|
-
this._core.rerender();
|
|
1048
|
-
this.focus({ x: event?.clientX, y: event?.clientY });
|
|
1049
|
-
KritzelKeyboardHelper.enableInteractiveWidget();
|
|
1050
|
-
}
|
|
1051
|
-
save() {
|
|
1052
|
-
this.content = this.editor.state.doc.toJSON();
|
|
1053
|
-
this.editor.setProps({ editable: () => false });
|
|
1054
|
-
this.editor.dom.blur();
|
|
1055
|
-
this.isEditing = false;
|
|
1056
|
-
this._core.store.state.objects.consolidateTemporaryItems();
|
|
1057
|
-
this._core.store.state.objects.update(this);
|
|
1058
|
-
this._core.engine.emitObjectsChange();
|
|
1059
|
-
}
|
|
1060
|
-
handlePointerDown(event) {
|
|
1061
|
-
if (!this.isEditing) {
|
|
1062
|
-
return;
|
|
1063
|
-
}
|
|
1064
|
-
event.stopPropagation();
|
|
1065
|
-
}
|
|
1066
|
-
handlePointerMove(event) {
|
|
1067
|
-
if (!this.isEditing) {
|
|
1068
|
-
return;
|
|
1069
|
-
}
|
|
1070
|
-
event.stopPropagation();
|
|
1071
|
-
}
|
|
1072
|
-
handlePointerUp(event) {
|
|
1073
|
-
if (!this.isEditing) {
|
|
1074
|
-
return;
|
|
1075
|
-
}
|
|
1076
|
-
event.stopPropagation();
|
|
1077
|
-
}
|
|
1078
|
-
copy() {
|
|
1079
|
-
const copiedObject = super.copy();
|
|
1080
|
-
copiedObject.editor = copiedObject.createEditor();
|
|
1081
|
-
if (this.content) {
|
|
1082
|
-
copiedObject.setContent(this.content);
|
|
1083
|
-
}
|
|
1084
|
-
return copiedObject;
|
|
1085
|
-
}
|
|
1086
|
-
serialize() {
|
|
1087
|
-
const { _core, _elementRef, _schema, element, totalWidth, totalHeight, editor, uneditedObject, ...remainingProps } = this;
|
|
1088
|
-
const clonedProps = structuredClone(remainingProps);
|
|
1089
|
-
if (element && typeof element === 'object' && 'nodeType' in element && element.nodeType === 1) {
|
|
1090
|
-
clonedProps.element = element.cloneNode(true);
|
|
1091
|
-
}
|
|
1092
|
-
return clonedProps;
|
|
1093
|
-
}
|
|
1094
|
-
deserialize(object) {
|
|
1095
|
-
super.deserialize(object);
|
|
1096
|
-
if (object.content) {
|
|
1097
|
-
this.setContent(object.content);
|
|
1098
|
-
}
|
|
1099
|
-
return this;
|
|
1100
|
-
}
|
|
1101
|
-
/**
|
|
1102
|
-
* Returns the clipping polygon for arrow intersection.
|
|
1103
|
-
* For ellipse: returns a many-sided polygon approximation
|
|
1104
|
-
* For triangle: returns the 3 corners
|
|
1105
|
-
* For rectangle: returns null (uses default rotatedPolygon)
|
|
1106
|
-
*
|
|
1107
|
-
* Includes padding for half the stroke width so arrow heads don't overlap the stroke.
|
|
1108
|
-
*/
|
|
1109
|
-
getClipPolygon() {
|
|
1110
|
-
// Calculate world-space center and dimensions
|
|
1111
|
-
const worldWidth = this.totalWidth / this.scale;
|
|
1112
|
-
const worldHeight = this.totalHeight / this.scale;
|
|
1113
|
-
const centerX = this.translateX + worldWidth / 2;
|
|
1114
|
-
const centerY = this.translateY + worldHeight / 2;
|
|
1115
|
-
// Add padding for stroke width so arrows don't overlap the stroke
|
|
1116
|
-
const strokePadding = (this.strokeWidth / this.scale) / 2;
|
|
1117
|
-
switch (this.shapeType) {
|
|
1118
|
-
case ShapeType.Ellipse:
|
|
1119
|
-
// Return a 32-segment polygon approximation of the ellipse
|
|
1120
|
-
// Add stroke padding to radii
|
|
1121
|
-
return KritzelGeometryHelper.getEllipsePolygonApproximation(centerX, centerY, worldWidth / 2 + strokePadding, worldHeight / 2 + strokePadding, 32, this.rotation);
|
|
1122
|
-
case ShapeType.Triangle:
|
|
1123
|
-
// Return the 3 corners of the triangle in world coordinates
|
|
1124
|
-
// Triangle: top-center, bottom-right, bottom-left
|
|
1125
|
-
// Expand each vertex outward from center by strokePadding
|
|
1126
|
-
const expandVertex = (vx, vy) => {
|
|
1127
|
-
const dx = vx - centerX;
|
|
1128
|
-
const dy = vy - centerY;
|
|
1129
|
-
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
1130
|
-
if (dist === 0)
|
|
1131
|
-
return { x: vx, y: vy };
|
|
1132
|
-
const scale = (dist + strokePadding) / dist;
|
|
1133
|
-
return {
|
|
1134
|
-
x: centerX + dx * scale,
|
|
1135
|
-
y: centerY + dy * scale
|
|
1136
|
-
};
|
|
1137
|
-
};
|
|
1138
|
-
const topX = this.translateX + worldWidth / 2;
|
|
1139
|
-
const topY = this.translateY;
|
|
1140
|
-
const bottomLeftX = this.translateX;
|
|
1141
|
-
const bottomLeftY = this.translateY + worldHeight;
|
|
1142
|
-
const bottomRightX = this.translateX + worldWidth;
|
|
1143
|
-
const bottomRightY = this.translateY + worldHeight;
|
|
1144
|
-
const expandedTop = expandVertex(topX, topY);
|
|
1145
|
-
const expandedBottomRight = expandVertex(bottomRightX, bottomRightY);
|
|
1146
|
-
const expandedBottomLeft = expandVertex(bottomLeftX, bottomLeftY);
|
|
1147
|
-
// Apply rotation around center if rotated
|
|
1148
|
-
if (this.rotation !== 0) {
|
|
1149
|
-
const cos = Math.cos(this.rotation);
|
|
1150
|
-
const sin = Math.sin(this.rotation);
|
|
1151
|
-
const rotate = (p) => {
|
|
1152
|
-
const dx = p.x - centerX;
|
|
1153
|
-
const dy = p.y - centerY;
|
|
1154
|
-
return {
|
|
1155
|
-
x: centerX + dx * cos - dy * sin,
|
|
1156
|
-
y: centerY + dx * sin + dy * cos
|
|
1157
|
-
};
|
|
1158
|
-
};
|
|
1159
|
-
return [
|
|
1160
|
-
rotate(expandedTop),
|
|
1161
|
-
rotate(expandedBottomRight),
|
|
1162
|
-
rotate(expandedBottomLeft)
|
|
1163
|
-
];
|
|
1164
|
-
}
|
|
1165
|
-
return [expandedTop, expandedBottomRight, expandedBottomLeft];
|
|
1166
|
-
case ShapeType.Rectangle:
|
|
1167
|
-
default:
|
|
1168
|
-
// For rectangles, return null to use the default rotatedPolygon
|
|
1169
|
-
return null;
|
|
1170
|
-
}
|
|
1171
|
-
}
|
|
1172
|
-
/**
|
|
1173
|
-
* Returns the SVG path for rendering the shape.
|
|
1174
|
-
* The path uses screen-space coordinates relative to (x, y).
|
|
1175
|
-
*/
|
|
1176
|
-
getSvgPath() {
|
|
1177
|
-
const w = this.width;
|
|
1178
|
-
const h = this.height;
|
|
1179
|
-
switch (this.shapeType) {
|
|
1180
|
-
case ShapeType.Rectangle:
|
|
1181
|
-
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`;
|
|
1182
|
-
case ShapeType.Ellipse:
|
|
1183
|
-
const cx = this.x + w / 2;
|
|
1184
|
-
const cy = this.y + h / 2;
|
|
1185
|
-
const rx = w / 2;
|
|
1186
|
-
const ry = h / 2;
|
|
1187
|
-
return `M ${cx - rx} ${cy} A ${rx} ${ry} 0 1 0 ${cx + rx} ${cy} A ${rx} ${ry} 0 1 0 ${cx - rx} ${cy}`;
|
|
1188
|
-
case ShapeType.Triangle:
|
|
1189
|
-
const topX = this.x + w / 2;
|
|
1190
|
-
const topY = this.y;
|
|
1191
|
-
const bottomLeftX = this.x;
|
|
1192
|
-
const bottomLeftY = this.y + h;
|
|
1193
|
-
const bottomRightX = this.x + w;
|
|
1194
|
-
const bottomRightY = this.y + h;
|
|
1195
|
-
return `M ${topX} ${topY} L ${bottomRightX} ${bottomRightY} L ${bottomLeftX} ${bottomLeftY} Z`;
|
|
1196
|
-
default:
|
|
1197
|
-
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`;
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
|
-
class KritzelShapeTool extends KritzelBaseTool {
|
|
1203
|
-
shapeType = ShapeType.Rectangle;
|
|
1204
|
-
fillColor = 'transparent';
|
|
1205
|
-
strokeColor = '#000000';
|
|
1206
|
-
strokeWidth = 4;
|
|
1207
|
-
fontFamily = 'Arial';
|
|
1208
|
-
fontSize = 16;
|
|
1209
|
-
fontColor = '#000000';
|
|
1210
|
-
palette = [
|
|
1211
|
-
'#000000',
|
|
1212
|
-
'#FFFFFF',
|
|
1213
|
-
'#FF0000',
|
|
1214
|
-
'#00FF00',
|
|
1215
|
-
'#0000FF',
|
|
1216
|
-
'#FFFF00',
|
|
1217
|
-
'#FF00FF',
|
|
1218
|
-
'#00FFFF',
|
|
1219
|
-
'#808080',
|
|
1220
|
-
'#C0C0C0',
|
|
1221
|
-
'#800000',
|
|
1222
|
-
'#008000',
|
|
1223
|
-
'#000080',
|
|
1224
|
-
'#808000',
|
|
1225
|
-
'#800080',
|
|
1226
|
-
];
|
|
1227
|
-
startX = 0;
|
|
1228
|
-
startY = 0;
|
|
1229
|
-
isDrawing = false;
|
|
1230
|
-
currentShape = null;
|
|
1231
|
-
constructor(core) {
|
|
1232
|
-
super(core);
|
|
1233
|
-
}
|
|
1234
|
-
handlePointerDown(event) {
|
|
1235
|
-
if (event.cancelable) {
|
|
1236
|
-
event.preventDefault();
|
|
1237
|
-
}
|
|
1238
|
-
if (event.pointerType === 'mouse') {
|
|
1239
|
-
const path = event.composedPath().slice(1);
|
|
1240
|
-
const objectElement = path.find(element => element.classList && element.classList.contains('object'));
|
|
1241
|
-
const object = this._core.findObjectById(objectElement?.id);
|
|
1242
|
-
const activeShape = this._core.store.activeShape;
|
|
1243
|
-
if (activeShape === null && object instanceof KritzelShape) {
|
|
1244
|
-
object.edit(event);
|
|
1245
|
-
return;
|
|
1246
|
-
}
|
|
1247
|
-
if (activeShape !== null && object instanceof KritzelShape) {
|
|
1248
|
-
activeShape.save();
|
|
1249
|
-
object.edit(event);
|
|
1250
|
-
return;
|
|
1251
|
-
}
|
|
1252
|
-
if (activeShape !== null && object instanceof KritzelShape === false) {
|
|
1253
|
-
this._core.resetActiveShape();
|
|
1254
|
-
this._core.store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
|
|
1255
|
-
return;
|
|
1256
|
-
}
|
|
1257
|
-
if (KritzelEventHelper.isLeftClick(event) === false) {
|
|
1258
|
-
return;
|
|
1259
|
-
}
|
|
1260
|
-
this.startDrawing(event.clientX, event.clientY);
|
|
1261
|
-
}
|
|
1262
|
-
if (event.pointerType === 'touch') {
|
|
1263
|
-
const activePointers = Array.from(this._core.store.state.pointers.values());
|
|
1264
|
-
const path = event.composedPath().slice(1);
|
|
1265
|
-
const objectElement = path.find(element => element.classList && element.classList.contains('object'));
|
|
1266
|
-
const object = this._core.findObjectById(objectElement?.id);
|
|
1267
|
-
const activeShape = this._core.store.activeShape;
|
|
1268
|
-
if (activeShape === null && object instanceof KritzelShape) {
|
|
1269
|
-
object.edit(event);
|
|
1270
|
-
return;
|
|
1271
|
-
}
|
|
1272
|
-
if (activeShape !== null && object instanceof KritzelShape) {
|
|
1273
|
-
activeShape.save();
|
|
1274
|
-
object.edit(event);
|
|
1275
|
-
return;
|
|
1276
|
-
}
|
|
1277
|
-
if (activeShape !== null && object instanceof KritzelShape === false) {
|
|
1278
|
-
this._core.resetActiveShape();
|
|
1279
|
-
this._core.store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
|
|
1280
|
-
return;
|
|
1281
|
-
}
|
|
1282
|
-
if (activePointers.length > 1) {
|
|
1283
|
-
return;
|
|
1284
|
-
}
|
|
1285
|
-
const clientX = Math.round(activePointers[0].clientX);
|
|
1286
|
-
const clientY = Math.round(activePointers[0].clientY);
|
|
1287
|
-
this.startDrawing(clientX, clientY);
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
handlePointerMove(event) {
|
|
1291
|
-
if (event.cancelable) {
|
|
1292
|
-
event.preventDefault();
|
|
1293
|
-
}
|
|
1294
|
-
if (!this.isDrawing || !this.currentShape) {
|
|
1295
|
-
return;
|
|
1296
|
-
}
|
|
1297
|
-
if (event.pointerType === 'mouse') {
|
|
1298
|
-
this.updateShapeSize(event.clientX, event.clientY);
|
|
1299
|
-
}
|
|
1300
|
-
if (event.pointerType === 'touch') {
|
|
1301
|
-
const activePointers = Array.from(this._core.store.state.pointers.values());
|
|
1302
|
-
if (activePointers.length === 1) {
|
|
1303
|
-
const clientX = Math.round(activePointers[0].clientX);
|
|
1304
|
-
const clientY = Math.round(activePointers[0].clientY);
|
|
1305
|
-
this.updateShapeSize(clientX, clientY);
|
|
1306
|
-
}
|
|
1307
|
-
}
|
|
1308
|
-
}
|
|
1309
|
-
handlePointerUp(event) {
|
|
1310
|
-
if (event.cancelable) {
|
|
1311
|
-
event.preventDefault();
|
|
1068
|
+
else if (this.hasSuffixContent !== false) {
|
|
1069
|
+
this.hasSuffixContent = false;
|
|
1312
1070
|
}
|
|
1313
|
-
|
|
1314
|
-
|
|
1071
|
+
};
|
|
1072
|
+
evaluatePrefixContent = () => {
|
|
1073
|
+
if (this.prefixSlotElement) {
|
|
1074
|
+
const newHasContent = this.prefixSlotElement.assignedNodes({ flatten: true }).length > 0;
|
|
1075
|
+
if (this.hasPrefixContent !== newHasContent) {
|
|
1076
|
+
this.hasPrefixContent = newHasContent;
|
|
1077
|
+
}
|
|
1315
1078
|
}
|
|
1316
|
-
this.
|
|
1317
|
-
|
|
1318
|
-
/**
|
|
1319
|
-
* Start drawing a shape. Following the same pattern as LineTool/BrushTool:
|
|
1320
|
-
* - Store screen coordinates for startX, startY
|
|
1321
|
-
* - Set translateX/Y to -viewportTranslateX/Y (viewport offset)
|
|
1322
|
-
* - Set x, y to the actual screen position
|
|
1323
|
-
* - Let updateDimensions() convert to world coordinates
|
|
1324
|
-
*/
|
|
1325
|
-
startDrawing(clientX, clientY) {
|
|
1326
|
-
// Store screen coordinates (relative to host element)
|
|
1327
|
-
this.startX = clientX - this._core.store.offsetX;
|
|
1328
|
-
this.startY = clientY - this._core.store.offsetY;
|
|
1329
|
-
this.isDrawing = true;
|
|
1330
|
-
// Create shape using screen coordinates, following Path/Line pattern
|
|
1331
|
-
this.currentShape = KritzelShape.create(this._core, {
|
|
1332
|
-
x: this.startX,
|
|
1333
|
-
y: this.startY,
|
|
1334
|
-
translateX: -this._core.store.state.translateX,
|
|
1335
|
-
translateY: -this._core.store.state.translateY,
|
|
1336
|
-
width: 1,
|
|
1337
|
-
height: 1,
|
|
1338
|
-
shapeType: this.shapeType,
|
|
1339
|
-
fillColor: this.fillColor,
|
|
1340
|
-
strokeColor: this.strokeColor,
|
|
1341
|
-
strokeWidth: this.strokeWidth,
|
|
1342
|
-
fontSize: this.fontSize,
|
|
1343
|
-
fontFamily: this.fontFamily,
|
|
1344
|
-
fontColor: this.fontColor,
|
|
1345
|
-
});
|
|
1346
|
-
this._core.store.state.objects.insert(this.currentShape);
|
|
1347
|
-
this._core.rerender();
|
|
1348
|
-
}
|
|
1349
|
-
/**
|
|
1350
|
-
* Update shape size during drawing. Following the same pattern as LineTool:
|
|
1351
|
-
* - Use screen coordinates directly
|
|
1352
|
-
* - The shape's x, y, width, height are all in screen space
|
|
1353
|
-
* - updateDimensions() handles conversion to world coordinates
|
|
1354
|
-
*/
|
|
1355
|
-
updateShapeSize(clientX, clientY) {
|
|
1356
|
-
if (!this.currentShape) {
|
|
1357
|
-
return;
|
|
1079
|
+
else if (this.hasPrefixContent !== false) {
|
|
1080
|
+
this.hasPrefixContent = false;
|
|
1358
1081
|
}
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
const minY = Math.min(this.startY, currentY);
|
|
1364
|
-
const width = Math.abs(currentX - this.startX);
|
|
1365
|
-
const height = Math.abs(currentY - this.startY);
|
|
1366
|
-
// Update shape with screen coordinates
|
|
1367
|
-
this.currentShape.x = minX;
|
|
1368
|
-
this.currentShape.y = minY;
|
|
1369
|
-
this.currentShape.width = Math.max(1, width);
|
|
1370
|
-
this.currentShape.height = Math.max(1, height);
|
|
1371
|
-
// Recalculate world-space translateX/Y
|
|
1372
|
-
// Reset translateX/Y to initial value before updateDimensions
|
|
1373
|
-
this.currentShape.translateX = -this._core.store.state.translateX;
|
|
1374
|
-
this.currentShape.translateY = -this._core.store.state.translateY;
|
|
1375
|
-
this.currentShape.updateDimensions();
|
|
1376
|
-
this._core.store.state.objects.update(this.currentShape);
|
|
1082
|
+
};
|
|
1083
|
+
getSelectedLabel() {
|
|
1084
|
+
const selectedOption = this.options.find(opt => opt.value === this.internalValue);
|
|
1085
|
+
return selectedOption?.label ?? '';
|
|
1377
1086
|
}
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
}
|
|
1382
|
-
// Remove shape if it's too small (likely an accidental click)
|
|
1383
|
-
// Compare in screen space
|
|
1384
|
-
if (this.currentShape.width < 10 && this.currentShape.height < 10) {
|
|
1385
|
-
const shapeId = this.currentShape.id;
|
|
1386
|
-
this._core.store.state.objects.remove(o => o.id === shapeId);
|
|
1387
|
-
}
|
|
1388
|
-
else {
|
|
1389
|
-
this.currentShape.zIndex = this._core.store.currentZIndex;
|
|
1390
|
-
this._core.store.state.objects.update(this.currentShape);
|
|
1391
|
-
this._core.engine.emitObjectsChange();
|
|
1392
|
-
this._core.selectObjects([this.currentShape]);
|
|
1393
|
-
this._core.store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
|
|
1394
|
-
}
|
|
1395
|
-
this.isDrawing = false;
|
|
1396
|
-
this.currentShape = null;
|
|
1397
|
-
this._core.rerender();
|
|
1087
|
+
getSelectedStyle() {
|
|
1088
|
+
const selectedOption = this.options.find(opt => opt.value === this.internalValue);
|
|
1089
|
+
return selectedOption?.style;
|
|
1398
1090
|
}
|
|
1399
|
-
|
|
1091
|
+
render() {
|
|
1092
|
+
const triggerClasses = {
|
|
1093
|
+
'dropdown-trigger': true,
|
|
1094
|
+
'has-suffix-border': this.hasSuffixContent,
|
|
1095
|
+
'has-prefix-border': this.hasPrefixContent,
|
|
1096
|
+
'is-open': this.isOpen,
|
|
1097
|
+
'open-up': this.openDirection === 'up',
|
|
1098
|
+
};
|
|
1099
|
+
const menuClasses = {
|
|
1100
|
+
'dropdown-menu': true,
|
|
1101
|
+
'is-open': this.isOpen,
|
|
1102
|
+
'open-up': this.openDirection === 'up',
|
|
1103
|
+
'open-down': this.openDirection === 'down',
|
|
1104
|
+
};
|
|
1105
|
+
return (h(Host, { key: '29d076eb2ef76527c0930ab82ace0d05c896ab6c' }, h("div", { key: '1afac5cc0b7f408849670b8cb62fe0bd0f3b27f1', class: "dropdown-wrapper", ref: el => (this.wrapperElement = el) }, h("slot", { key: '3cfcf787c3b3eedbd6bf30c7506a0a4912429672', name: "prefix", ref: el => (this.prefixSlotElement = el), onSlotchange: this.evaluatePrefixContent }), h("div", { key: 'b88120ed3e44871220e6ba61e8bef457651a2086', class: "dropdown-container", style: { width: this.width } }, h("button", { key: '79082189066f3d0b4f5797420ec222847792fe52', type: "button", class: triggerClasses, style: { ...this.selectStyles, ...this.getSelectedStyle() }, onClick: this.toggleMenu, onKeyDown: this.handleTriggerKeyDown, "aria-haspopup": "listbox", "aria-expanded": this.isOpen ? 'true' : 'false', ref: el => (this.triggerElement = el) }, h("span", { key: 'a490bb6689ec1820144fe82f6833bee82e6ead0e', class: "dropdown-trigger-label" }, this.getSelectedLabel()), h("span", { key: '8bd7768f6fdd3c507bbca54d7d135adabe04901f', class: "dropdown-trigger-arrow", "aria-hidden": "true" }, h("svg", { key: 'e1b854d2c93e3067181108f8d782e1393ddb615c', xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("polyline", { key: '3622cbf8964f4e50aa55be5209240dfd252f1d84', points: "6 9 12 15 18 9" }))))), h("slot", { key: 'b91317736904cbeee0f87058b822bd77c6b163ca', name: "suffix", ref: el => (this.suffixSlotElement = el), onSlotchange: this.evaluateSuffixContent }), h("ul", { key: '0ca8690345974e9b7ad184f4c7ab7cf5367b183c', class: menuClasses, role: "listbox", tabindex: "-1", onKeyDown: this.handleMenuKeyDown, ref: el => (this.menuElement = el) }, this.options.map((option, index) => {
|
|
1106
|
+
const isSelected = option.value === this.internalValue;
|
|
1107
|
+
const isFocused = index === this.focusedIndex;
|
|
1108
|
+
const optionClasses = {
|
|
1109
|
+
'dropdown-option': true,
|
|
1110
|
+
'is-selected': isSelected,
|
|
1111
|
+
'is-focused': isFocused,
|
|
1112
|
+
};
|
|
1113
|
+
return (h("li", { class: optionClasses, role: "option", "aria-selected": isSelected ? 'true' : 'false', style: option.style, onClick: () => this.selectOption(option), onMouseEnter: () => this.handleOptionMouseEnter(index) }, option.label, isSelected && (h("span", { class: "dropdown-option-check", "aria-hidden": "true" }, h("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("polyline", { points: "20 6 9 17 4 12" }))))));
|
|
1114
|
+
})))));
|
|
1115
|
+
}
|
|
1116
|
+
static get watchers() { return {
|
|
1117
|
+
"options": [{
|
|
1118
|
+
"optionsChanged": 0
|
|
1119
|
+
}],
|
|
1120
|
+
"value": [{
|
|
1121
|
+
"externalValueChanged": 0
|
|
1122
|
+
}]
|
|
1123
|
+
}; }
|
|
1124
|
+
};
|
|
1125
|
+
KritzelDropdown.style = kritzelDropdownCss();
|
|
1400
1126
|
|
|
1401
1127
|
const DEFAULT_SHAPE_CONFIG = {
|
|
1402
1128
|
shapeType: ShapeType.Rectangle,
|
|
@@ -1406,21 +1132,7 @@ const DEFAULT_SHAPE_CONFIG = {
|
|
|
1406
1132
|
fontColor: '#000000',
|
|
1407
1133
|
fontSize: 16,
|
|
1408
1134
|
fontFamily: 'Arial',
|
|
1409
|
-
palette: [
|
|
1410
|
-
'#000000',
|
|
1411
|
-
'#ff5252',
|
|
1412
|
-
'#ffbc00',
|
|
1413
|
-
'#00c853',
|
|
1414
|
-
'#0000FF',
|
|
1415
|
-
'#d500f9',
|
|
1416
|
-
'#fafafa',
|
|
1417
|
-
'#a52714',
|
|
1418
|
-
'#ee8100',
|
|
1419
|
-
'#558b2f',
|
|
1420
|
-
'#01579b',
|
|
1421
|
-
'#8e24aa',
|
|
1422
|
-
'#90a4ae',
|
|
1423
|
-
],
|
|
1135
|
+
palette: [...DEFAULT_COLOR_PALETTE],
|
|
1424
1136
|
};
|
|
1425
1137
|
|
|
1426
1138
|
const ABSOLUTE_SCALE_MAX = 1000;
|
|
@@ -1682,7 +1394,7 @@ const KritzelEditor = class {
|
|
|
1682
1394
|
}
|
|
1683
1395
|
}
|
|
1684
1396
|
render() {
|
|
1685
|
-
return (h(Host, { key: '
|
|
1397
|
+
return (h(Host, { key: '46500c70e4c5321532eddc7f6aa96210c0fe73c8' }, h("kritzel-workspace-manager", { key: '70f780b4d42281c6c37b3fd16acab1541cc84ee1', workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), h("kritzel-engine", { key: 'a4906f8ac2d42126a4e55ad7c16697aca25763fb', 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: '4d08c06fa2c6e4f5c3c75c5e5a60bddb61083b98', 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) })));
|
|
1686
1398
|
}
|
|
1687
1399
|
static get watchers() { return {
|
|
1688
1400
|
"isEngineReady": [{
|
|
@@ -18913,6 +18625,11 @@ class KritzelViewport {
|
|
|
18913
18625
|
_core;
|
|
18914
18626
|
_debounceUpdate;
|
|
18915
18627
|
_debounceEndScaling;
|
|
18628
|
+
_velocityX = 0;
|
|
18629
|
+
_velocityY = 0;
|
|
18630
|
+
_panRafId = null;
|
|
18631
|
+
_friction = 0.92;
|
|
18632
|
+
_minVelocity = 0.5;
|
|
18916
18633
|
initialTouchDistance = 0;
|
|
18917
18634
|
startX = 0;
|
|
18918
18635
|
startY = 0;
|
|
@@ -19096,12 +18813,47 @@ class KritzelViewport {
|
|
|
19096
18813
|
this._debounceEndScaling();
|
|
19097
18814
|
}
|
|
19098
18815
|
handlePan(event) {
|
|
18816
|
+
// Normalize delta for trackpad vs mouse wheel
|
|
18817
|
+
// WheelEvent.deltaMode: 0=pixels, 1=lines, 2=pages
|
|
18818
|
+
let deltaX = event.deltaX;
|
|
18819
|
+
let deltaY = event.deltaY;
|
|
18820
|
+
if (event.deltaMode === 1) {
|
|
18821
|
+
deltaX *= 16;
|
|
18822
|
+
deltaY *= 16;
|
|
18823
|
+
}
|
|
18824
|
+
else if (event.deltaMode === 2) {
|
|
18825
|
+
deltaX *= window.innerWidth;
|
|
18826
|
+
deltaY *= window.innerHeight;
|
|
18827
|
+
}
|
|
19099
18828
|
const panSpeed = 0.8;
|
|
19100
|
-
|
|
19101
|
-
this.
|
|
18829
|
+
// Add to velocity for momentum effect
|
|
18830
|
+
this._velocityX = -deltaX * panSpeed;
|
|
18831
|
+
this._velocityY = -deltaY * panSpeed;
|
|
18832
|
+
// Start animation loop if not already running
|
|
18833
|
+
if (this._panRafId === null) {
|
|
18834
|
+
this._animatePan();
|
|
18835
|
+
}
|
|
18836
|
+
}
|
|
18837
|
+
_animatePan() {
|
|
18838
|
+
// Apply current velocity
|
|
18839
|
+
this._core.store.state.translateX += this._velocityX;
|
|
18840
|
+
this._core.store.state.translateY += this._velocityY;
|
|
19102
18841
|
this._core.store.state.hasViewportChanged = true;
|
|
19103
18842
|
this._core.rerender();
|
|
19104
|
-
|
|
18843
|
+
// Apply friction to slow down
|
|
18844
|
+
this._velocityX *= this._friction;
|
|
18845
|
+
this._velocityY *= this._friction;
|
|
18846
|
+
// Continue animation if velocity is still significant
|
|
18847
|
+
if (Math.abs(this._velocityX) > this._minVelocity || Math.abs(this._velocityY) > this._minVelocity) {
|
|
18848
|
+
this._panRafId = requestAnimationFrame(() => this._animatePan());
|
|
18849
|
+
}
|
|
18850
|
+
else {
|
|
18851
|
+
// Stop animation and finalize
|
|
18852
|
+
this._velocityX = 0;
|
|
18853
|
+
this._velocityY = 0;
|
|
18854
|
+
this._panRafId = null;
|
|
18855
|
+
this._debounceUpdate();
|
|
18856
|
+
}
|
|
19105
18857
|
}
|
|
19106
18858
|
}
|
|
19107
18859
|
|
|
@@ -20256,11 +20008,13 @@ class KritzelCore {
|
|
|
20256
20008
|
this.removeSelectionGroup();
|
|
20257
20009
|
this.removeSelectionBox();
|
|
20258
20010
|
this._store.state.objects.insert(selectionGroup);
|
|
20011
|
+
this._kritzelEngine.triggerSelectionChange();
|
|
20259
20012
|
}
|
|
20260
20013
|
removeSelectionGroup() {
|
|
20261
20014
|
const selectionGroup = this._store.selectionGroup;
|
|
20262
20015
|
if (selectionGroup) {
|
|
20263
20016
|
this._store.state.objects.remove(object => object.id === selectionGroup.id);
|
|
20017
|
+
this._kritzelEngine.triggerSelectionChange();
|
|
20264
20018
|
}
|
|
20265
20019
|
}
|
|
20266
20020
|
removeSelectionBox() {
|
|
@@ -20802,11 +20556,15 @@ const KritzelEngine = class {
|
|
|
20802
20556
|
}
|
|
20803
20557
|
isEngineReady;
|
|
20804
20558
|
activeToolChange;
|
|
20559
|
+
objectsSelectionChange;
|
|
20805
20560
|
workspacesChange;
|
|
20806
20561
|
longpress;
|
|
20807
20562
|
objectsChange;
|
|
20808
20563
|
undoStateChange;
|
|
20809
20564
|
forceUpdate = 0;
|
|
20565
|
+
async triggerSelectionChange() {
|
|
20566
|
+
this.objectsSelectionChange.emit();
|
|
20567
|
+
}
|
|
20810
20568
|
throttledWheel = lodashExports.throttle((ev) => {
|
|
20811
20569
|
this.viewport.handleWheel(ev);
|
|
20812
20570
|
this.core.store.state?.activeTool?.handleWheel(ev);
|
|
@@ -20922,6 +20680,9 @@ const KritzelEngine = class {
|
|
|
20922
20680
|
return Promise.resolve(registeredTool);
|
|
20923
20681
|
}
|
|
20924
20682
|
async changeActiveTool(tool) {
|
|
20683
|
+
if (this.core.store.state.activeTool === tool) {
|
|
20684
|
+
return;
|
|
20685
|
+
}
|
|
20925
20686
|
this.core.store.state.activeTool?.onDeactivate();
|
|
20926
20687
|
this.core.store.setState('activeTool', tool);
|
|
20927
20688
|
this.core.deselectAllObjects();
|
|
@@ -21064,6 +20825,7 @@ const KritzelEngine = class {
|
|
|
21064
20825
|
registerInstance(this, hostRef);
|
|
21065
20826
|
this.isEngineReady = createEvent(this, "isEngineReady");
|
|
21066
20827
|
this.activeToolChange = createEvent(this, "activeToolChange");
|
|
20828
|
+
this.objectsSelectionChange = createEvent(this, "objectsSelectionChange");
|
|
21067
20829
|
this.workspacesChange = createEvent(this, "workspacesChange");
|
|
21068
20830
|
this.longpress = createEvent(this, "longpress");
|
|
21069
20831
|
this.objectsChange = createEvent(this, "objectsChange");
|
|
@@ -21144,7 +20906,7 @@ const KritzelEngine = class {
|
|
|
21144
20906
|
};
|
|
21145
20907
|
const visibleObjects = this.core.store.state.objects.query(viewportBounds).sort((a, b) => a.zIndex - b.zIndex);
|
|
21146
20908
|
this.core.cursorManager.applyCursor();
|
|
21147
|
-
return (h(Host, { key: '
|
|
20909
|
+
return (h(Host, { key: '49fbba9ba7044acb82cb23627bf08435f8683b80' }, this.core.store.state.debugInfo.showViewportInfo && (h("div", { key: '7e18e66bdbae71ec35a6ea14bfdcd735e537a37b', class: "debug-panel" }, h("div", { key: '562ff35d3803b80f3c02c075741f1c4b81ba0739' }, "ActiveWorkspaceId: ", this.core.store.state?.activeWorkspace?.id), h("div", { key: '82d08ac0527017c9f3674e1d551a071b0002477e' }, "ActiveWorkspaceName: ", this.core.store.state?.activeWorkspace?.name), h("div", { key: 'e4e3b8c6f18714dbf141a900768b2fb78ef8ec3a' }, "TranslateX: ", this.core.store.state?.translateX), h("div", { key: '68823a22db98800c7ec7b18770f38f03dd53f826' }, "TranslateY: ", this.core.store.state?.translateY), h("div", { key: '4683676eca0796b927ac8c10fe9ea48770366ee5' }, "ViewportWidth: ", this.core.store.state?.viewportWidth), h("div", { key: 'fcbd728c4483f06cffe1e9d581399a9619b3c172' }, "ViewportHeight: ", this.core.store.state?.viewportHeight), h("div", { key: 'f713005a414bd05b187327b5ffa021c51f227d97' }, "PointerCount: ", this.core.store.state.pointers.size), h("div", { key: 'fdb4892c0b5df0a599d4e457d656ca8e71086033' }, "Scale: ", this.core.store.state?.scale), h("div", { key: '7c1ceb6398ceccb891d5854a731467771d88e688' }, "ActiveTool: ", this.core.store.state?.activeTool?.name), h("div", { key: 'fddfb8b396ab095dd99158b32bf4c9a06745c65f' }, "HasViewportChanged: ", this.core.store.state?.hasViewportChanged ? 'true' : 'false'), h("div", { key: '8b807879e83bada98ff44a9124dddc7e7f8d8516' }, "IsEnabled: ", this.core.store.state?.isEnabled ? 'true' : 'false'), h("div", { key: '93827fa7bf4c27db8b3165a1d2be5d0cde5a65b6' }, "IsScaling: ", this.core.store.state?.isScaling ? 'true' : 'false'), h("div", { key: '923455fb261bc9aa8d6cd22c74894e41dc6a2f93' }, "IsPanning: ", this.core.store.state?.isPanning ? 'true' : 'false'), h("div", { key: '33579a767be0a80bed4a177da9577e6304d4900c' }, "IsSelecting: ", this.isSelecting ? 'true' : 'false'), h("div", { key: '950c340bf725d7c8c92a51c61066c1aa7d09aa41' }, "IsSelectionActive: ", this.isSelectionActive ? 'true' : 'false'), h("div", { key: '2a8ce1e6d68ea030f42521b25615bf60a1a8267e' }, "IsResizeHandleSelected: ", this.core.store.state.isResizeHandleSelected ? 'true' : 'false'), h("div", { key: '9fd5a4b1a842c9aa178dc98dc9a210cf7d947615' }, "IsRotationHandleSelected: ", this.core.store.state.isRotationHandleSelected ? 'true' : 'false'), h("div", { key: '81f9c6f9f5c38b48db1faaa8da08476cd747e906' }, "IsRotationHandleHovered: ", this.core.store.state.isRotationHandleHovered ? 'true' : 'false'), h("div", { key: 'bbea182105ab1f1856d8ffe7ee6dae2c96cefbae' }, "IsDrawing: ", this.core.store.state.isDrawing ? 'true' : 'false'), h("div", { key: '0e57b3b517fc6f4780a6bf8b13a18e7d595e2e91' }, "IsWriting: ", this.core.store.state.isWriting ? 'true' : 'false'), h("div", { key: '5be12fd92b4ccb6890680e725aea0f29fa16eda4' }, "IsPointerDown: ", this.core.store.isPointerDown ? 'true' : 'false'), h("div", { key: '51402f4730b8e482ee534bb83944c50462d895af' }, "PointerX: ", this.core.store.state?.pointerX), h("div", { key: 'dddf5bed76a1755aec71ae7f30eab8dd0c39fdb0' }, "PointerY: ", this.core.store.state?.pointerY), h("div", { key: '367166d068f34090eb895116d8ac1ddd3ab5aaad' }, "SelectedObjects: ", this.core.store.selectionGroup?.objects.length || 0), h("div", { key: 'e88d10e302e4ff3e8cb877a509a883e2cffcc067' }, "ViewportCenter: (", viewportCenterX.toFixed(2), ", ", viewportCenterY.toFixed(2), ")"))), h("div", { key: '12bf294a8640947230611690f71b8c8116e861f4', id: "origin", class: "origin", style: {
|
|
21148
20910
|
transform: `matrix(${this.core.store.state?.scale}, 0, 0, ${this.core.store.state?.scale}, ${this.core.store.state?.translateX}, ${this.core.store.state?.translateY})`,
|
|
21149
20911
|
} }, visibleObjects?.map(object => {
|
|
21150
20912
|
return (h("div", { key: object.id, style: {
|
|
@@ -21393,7 +21155,7 @@ const KritzelEngine = class {
|
|
|
21393
21155
|
stroke: 'var(--kritzel-snap-indicator-stroke, #007bff)',
|
|
21394
21156
|
strokeWidth: data.indicatorStrokeWidth,
|
|
21395
21157
|
} }))));
|
|
21396
|
-
})()), this.core.store.state.isContextMenuVisible && (h("kritzel-context-menu", { key: '
|
|
21158
|
+
})()), this.core.store.state.isContextMenuVisible && (h("kritzel-context-menu", { key: '9d17520994c59b7eca2940d1a05f4f150b790767', class: "context-menu", ref: el => (this.contextMenuElement = el), items: this.core.store.state.contextMenuItems, objects: this.core.store.selectionGroup?.objects || [], style: {
|
|
21397
21159
|
position: 'fixed',
|
|
21398
21160
|
left: `${this.core.store.state.contextMenuX}px`,
|
|
21399
21161
|
top: `${this.core.store.state.contextMenuY}px`,
|
|
@@ -21404,7 +21166,7 @@ const KritzelEngine = class {
|
|
|
21404
21166
|
y: (-this.core.store.state.translateY + this.core.store.state.contextMenuY) / this.core.store.state.scale,
|
|
21405
21167
|
}, this.core.store.selectionGroup?.objects);
|
|
21406
21168
|
this.hideContextMenu();
|
|
21407
|
-
}, onClose: () => this.hideContextMenu() })), this.core.store.state?.activeTool instanceof KritzelEraserTool && !this.core.store.state.isScaling && h("kritzel-cursor-trail", { key: '
|
|
21169
|
+
}, onClose: () => this.hideContextMenu() })), this.core.store.state?.activeTool instanceof KritzelEraserTool && !this.core.store.state.isScaling && h("kritzel-cursor-trail", { key: 'b86989f2a710324e420994f74bd8c4990cc52060', core: this.core })));
|
|
21408
21170
|
}
|
|
21409
21171
|
static get watchers() { return {
|
|
21410
21172
|
"workspace": [{
|
|
@@ -21433,7 +21195,7 @@ const KritzelFont = class {
|
|
|
21433
21195
|
size = 24;
|
|
21434
21196
|
color = '#000000';
|
|
21435
21197
|
render() {
|
|
21436
|
-
return (h(Host, { key: '
|
|
21198
|
+
return (h(Host, { key: '47e1580b093d5c9039a5bc1a7764e345afb7700b' }, h("div", { key: '1d6d36e895ab4e1fd76383b0847f81918e14dbb0', class: "font-preview", style: {
|
|
21437
21199
|
fontFamily: this.fontFamily,
|
|
21438
21200
|
fontSize: `${this.size}px`,
|
|
21439
21201
|
color: this.color
|
|
@@ -21442,7 +21204,7 @@ const KritzelFont = class {
|
|
|
21442
21204
|
};
|
|
21443
21205
|
KritzelFont.style = kritzelFontCss();
|
|
21444
21206
|
|
|
21445
|
-
const kritzelFontFamilyCss = () => `:host{display:flex;align-items:flex-start;gap:8px;padding:
|
|
21207
|
+
const kritzelFontFamilyCss = () => `:host{display:flex;align-items:flex-start;gap:8px;padding:0;box-sizing:border-box;width:100%}.font-style-button{display:flex;justify-content:center;align-items:center;width:42px;height:32px;padding:0;border:none;outline:none;background:none;cursor:var(--kritzel-pointer-cursor, pointer);border-radius:0;color:var(--control-text-color);font-weight:bold;-webkit-tap-highlight-color:transparent}.font-style-button:not(:last-child){border-right:1px solid #333333}.font-style-button:hover{background-color:var(--control-hover-bg)}.font-style-button:active{background-color:var(--control-active-bg)}.font-style-button.selected,.font-style-button.selected:hover,.font-style-button.selected:active{background-color:var(--control-selected-bg);color:var(--control-selected-color)}.font-style-button.italic-text{font-style:italic}`;
|
|
21446
21208
|
|
|
21447
21209
|
const KritzelFontFamily = class {
|
|
21448
21210
|
constructor(hostRef) {
|
|
@@ -21485,7 +21247,7 @@ const KritzelFontFamily = class {
|
|
|
21485
21247
|
};
|
|
21486
21248
|
KritzelFontFamily.style = kritzelFontFamilyCss();
|
|
21487
21249
|
|
|
21488
|
-
const kritzelFontSizeCss = () => `:host{display:flex;align-items:flex-start;gap:8px;padding:
|
|
21250
|
+
const kritzelFontSizeCss = () => `:host{display:flex;align-items:flex-start;gap:8px;padding:0;box-sizing:border-box}.size-container{display:flex;justify-content:center;align-items:center;width:32px;height:32px;border-radius:4px;cursor:var(--kritzel-pointer-cursor, pointer);border:2px solid transparent;box-sizing:border-box;border-radius:50%}.size-container:hover{background-color:var(--kritzel-font-size-hover-background-color, #ebebeb)}.size-container.selected{border-color:var(--kritzel-selection-border-color, #007AFF);background-color:var(--kritzel-font-size-selected-background-color, #e0e0e0)}`;
|
|
21489
21251
|
|
|
21490
21252
|
const KritzelFontSize = class {
|
|
21491
21253
|
constructor(hostRef) {
|
|
@@ -21507,7 +21269,7 @@ const KritzelFontSize = class {
|
|
|
21507
21269
|
}
|
|
21508
21270
|
}
|
|
21509
21271
|
render() {
|
|
21510
|
-
return (h(Host, { key: '
|
|
21272
|
+
return (h(Host, { key: 'ea8461f3b921c6adec6360ffcca69832a30e5808' }, this.sizes.map(size => (h("div", { tabIndex: 0, class: {
|
|
21511
21273
|
'size-container': true,
|
|
21512
21274
|
'selected': this.selectedSize === size,
|
|
21513
21275
|
}, onClick: () => this.handleSizeClick(size), onKeyDown: event => this.handleKeyDown(event, size) }, h("kritzel-font", { fontFamily: this.fontFamily, size: size }))))));
|
|
@@ -21539,6 +21301,91 @@ const KritzelIcon = class {
|
|
|
21539
21301
|
};
|
|
21540
21302
|
KritzelIcon.style = kritzelIconCss();
|
|
21541
21303
|
|
|
21304
|
+
const kritzelLineEndingsCss = () => `:host{display:flex;flex-direction:column;gap:12px;padding:0;box-sizing:border-box}.endings-section{display:flex;flex-direction:column;gap:6px}.section-label{font-size:12px;font-weight:500;color:var(--kritzel-line-endings-label-color, #666666);padding-left:4px}.endings-row{display:flex;align-items:center;gap:4px}.ending-option{display:flex;justify-content:center;align-items:center;width:48px;height:32px;border-radius:6px;cursor:var(--kritzel-pointer-cursor, pointer);border:2px solid transparent;box-sizing:border-box;background:var(--kritzel-line-endings-option-background, #ffffff);padding:4px;transition:background-color 0.15s ease, border-color 0.15s ease}.ending-option:hover{background-color:var(--kritzel-line-endings-hover-background-color, #ebebeb)}.ending-option.selected{border-color:var(--kritzel-selection-border-color, #007AFF);background-color:var(--kritzel-line-endings-selected-background-color, #ebebeb)}.ending-option:focus{outline:none;box-shadow:0 0 0 2px var(--kritzel-focus-ring-color, rgba(0, 122, 255, 0.3))}.ending-icon{width:100%;height:100%}`;
|
|
21305
|
+
|
|
21306
|
+
const KritzelLineEndings = class {
|
|
21307
|
+
constructor(hostRef) {
|
|
21308
|
+
registerInstance(this, hostRef);
|
|
21309
|
+
this.valueChange = createEvent(this, "valueChange");
|
|
21310
|
+
}
|
|
21311
|
+
/** Available ending styles */
|
|
21312
|
+
styles = ['none', 'triangle'];
|
|
21313
|
+
/** Current line arrow configuration */
|
|
21314
|
+
value;
|
|
21315
|
+
/** Stroke color used for rendering the preview */
|
|
21316
|
+
strokeColor = '#000000';
|
|
21317
|
+
valueChange;
|
|
21318
|
+
getStartEnding() {
|
|
21319
|
+
if (!this.value?.start?.enabled)
|
|
21320
|
+
return 'none';
|
|
21321
|
+
return this.value.start.style ?? 'triangle';
|
|
21322
|
+
}
|
|
21323
|
+
getEndEnding() {
|
|
21324
|
+
if (!this.value?.end?.enabled)
|
|
21325
|
+
return 'none';
|
|
21326
|
+
return this.value.end.style ?? 'triangle';
|
|
21327
|
+
}
|
|
21328
|
+
handleStartChange(type) {
|
|
21329
|
+
const newValue = {
|
|
21330
|
+
...this.value,
|
|
21331
|
+
start: type === 'none'
|
|
21332
|
+
? { enabled: false }
|
|
21333
|
+
: { enabled: true, style: type },
|
|
21334
|
+
};
|
|
21335
|
+
this.value = newValue;
|
|
21336
|
+
this.valueChange.emit(newValue);
|
|
21337
|
+
}
|
|
21338
|
+
handleEndChange(type) {
|
|
21339
|
+
const newValue = {
|
|
21340
|
+
...this.value,
|
|
21341
|
+
end: type === 'none'
|
|
21342
|
+
? { enabled: false }
|
|
21343
|
+
: { enabled: true, style: type },
|
|
21344
|
+
};
|
|
21345
|
+
this.value = newValue;
|
|
21346
|
+
this.valueChange.emit(newValue);
|
|
21347
|
+
}
|
|
21348
|
+
getEndingPath(type) {
|
|
21349
|
+
switch (type) {
|
|
21350
|
+
case 'triangle':
|
|
21351
|
+
return 'M 0 0 L 10 5 L 0 10 Z';
|
|
21352
|
+
case 'open':
|
|
21353
|
+
return 'M 0 0 L 10 5 L 0 10';
|
|
21354
|
+
case 'diamond':
|
|
21355
|
+
return 'M 0 5 L 5 0 L 10 5 L 5 10 Z';
|
|
21356
|
+
case 'circle':
|
|
21357
|
+
return 'M 10 5 A 5 5 0 1 1 0 5 A 5 5 0 1 1 10 5 Z';
|
|
21358
|
+
default:
|
|
21359
|
+
return '';
|
|
21360
|
+
}
|
|
21361
|
+
}
|
|
21362
|
+
renderEndingIcon(type, isStart) {
|
|
21363
|
+
const color = '#000000';
|
|
21364
|
+
if (type === 'none') {
|
|
21365
|
+
return (h("svg", { viewBox: "0 0 24 12", class: "ending-icon" }, h("line", { x1: isStart ? 4 : 2, y1: "6", x2: isStart ? 22 : 20, y2: "6", stroke: color, "stroke-width": "2", "stroke-linecap": "round" })));
|
|
21366
|
+
}
|
|
21367
|
+
const path = this.getEndingPath(type);
|
|
21368
|
+
const isOpenStyle = type === 'open';
|
|
21369
|
+
return (h("svg", { viewBox: "0 0 24 12", class: "ending-icon" }, isStart ? (
|
|
21370
|
+
// Start arrow points left
|
|
21371
|
+
h("g", null, h("line", { x1: "12", y1: "6", x2: "22", y2: "6", stroke: color, "stroke-width": "2", "stroke-linecap": "round" }), h("g", { transform: "translate(2, 1) scale(1, 1)" }, h("path", { d: path, fill: isOpenStyle ? 'none' : color, stroke: color, "stroke-width": isOpenStyle ? 2 : 0, "stroke-linecap": "round", "stroke-linejoin": "round", transform: "scale(-1, 1) translate(-10, 0)" })))) : (
|
|
21372
|
+
// End arrow points right
|
|
21373
|
+
h("g", null, h("line", { x1: "2", y1: "6", x2: "12", y2: "6", stroke: color, "stroke-width": "2", "stroke-linecap": "round" }), h("g", { transform: "translate(12, 1)" }, h("path", { d: path, fill: isOpenStyle ? 'none' : color, stroke: color, "stroke-width": isOpenStyle ? 2 : 0, "stroke-linecap": "round", "stroke-linejoin": "round" }))))));
|
|
21374
|
+
}
|
|
21375
|
+
render() {
|
|
21376
|
+
const startEnding = this.getStartEnding();
|
|
21377
|
+
const endEnding = this.getEndEnding();
|
|
21378
|
+
return (h(Host, { key: '395c2c7e54986d9edffe7b1329361d9e0727d086' }, h("div", { key: '9f29cb35182b74d73fe82a89f91be42da3e43d3f', class: "endings-section" }, h("div", { key: '61f3e2bc9e3c2739e241213e68af71dd1091774e', class: "endings-row" }, this.styles.map(type => (h("button", { class: {
|
|
21379
|
+
'ending-option': true,
|
|
21380
|
+
'selected': startEnding === type,
|
|
21381
|
+
}, onClick: () => this.handleStartChange(type), title: type === 'none' ? 'No start arrow' : `${type} start arrow` }, this.renderEndingIcon(type, true)))))), h("div", { key: '1e39f687277ebdd0786f56b9be40101df42495d2', class: "endings-section" }, h("div", { key: 'fbe2ea8393cbf82b7c7aff7d6d8ca16abab1020a', class: "endings-row" }, this.styles.map(type => (h("button", { class: {
|
|
21382
|
+
'ending-option': true,
|
|
21383
|
+
'selected': endEnding === type,
|
|
21384
|
+
}, onClick: () => this.handleEndChange(type), title: type === 'none' ? 'No end arrow' : `${type} end arrow` }, this.renderEndingIcon(type, false))))))));
|
|
21385
|
+
}
|
|
21386
|
+
};
|
|
21387
|
+
KritzelLineEndings.style = kritzelLineEndingsCss();
|
|
21388
|
+
|
|
21542
21389
|
const kritzelMenuCss = () => `:host{position:relative;display:flex;flex-direction:column;background-color:var(--kritzel-menu-background-color, #ffffff);width:var(--kritzel-menu-width, 200px);padding:var(--kritzel-menu-padding, 8px);border-radius:var(--kritzel-menu-border-radius, 12px);box-shadow:var(--kritzel-menu-box-shadow, 0 0 3px rgba(0, 0, 0, 0.08));border:var(--kritzel-menu-border, 1px solid #ebebeb);z-index:2;gap:var(--kritzel-menu-gap, 4px);overflow-y:auto;scrollbar-color:#ebebeb transparent;scrollbar-width:thin;max-height:var(--kritzel-portal-max-height, 300px);box-sizing:border-box}.has-open-child-overlay{position:absolute;top:0;left:0;right:0;bottom:0;z-index:3}`;
|
|
21543
21390
|
|
|
21544
21391
|
const KritzelMenu = class {
|
|
@@ -21602,7 +21449,7 @@ const KritzelMenu = class {
|
|
|
21602
21449
|
this.itemCloseChildMenu.emit(event.detail);
|
|
21603
21450
|
};
|
|
21604
21451
|
render() {
|
|
21605
|
-
return (h(Host, { key: '
|
|
21452
|
+
return (h(Host, { key: '7143a116ad361651851491bce048901d6c0a02a0', tabIndex: 0, onClick: e => e.stopPropagation() }, this.openChildMenuItem && h("div", { key: '8a5524ca7516955e1be34d10b8495c7b40ac05dd', class: "has-open-child-overlay", onClick: this.onOverlayClick }), this.items.map(item => (h("kritzel-menu-item", { key: item.id, item: item, parent: this.parent, style: { pointerEvents: this.editingMenuItem && !item.isEditing ? 'none' : 'auto' }, onItemSelect: this.handleItemSelect, onItemSave: this.handleSave, onItemCancel: this.handleCancel, onItemToggleChildMenu: this.handleToggleChildMenu, onItemCloseChildMenu: this.handleCloseChildMenu })))));
|
|
21606
21453
|
}
|
|
21607
21454
|
};
|
|
21608
21455
|
KritzelMenu.style = kritzelMenuCss();
|
|
@@ -21703,12 +21550,12 @@ const KritzelMenuItem = class {
|
|
|
21703
21550
|
];
|
|
21704
21551
|
}
|
|
21705
21552
|
render() {
|
|
21706
|
-
return (h(Host, { key: '
|
|
21553
|
+
return (h(Host, { key: '59a53dc472dd624f78dd773eb20a8722720ed465', tabIndex: this.item.isDisabled ? -1 : 0, class: {
|
|
21707
21554
|
'selected': this.item.isSelected,
|
|
21708
21555
|
'editing': this.item.isEditing,
|
|
21709
21556
|
'disabled': this.item.isDisabled,
|
|
21710
21557
|
'child-open': this.item.isChildMenuOpen,
|
|
21711
|
-
}, onClick: this.handleItemSelect }, h("div", { key: '
|
|
21558
|
+
}, onClick: this.handleItemSelect }, h("div", { key: '22665fedfa83e2483d97480a9c9e45da9d296319', class: "menu-item-overlay" }), this.item.isEditing ? this.renderEditMode() : this.renderViewMode()));
|
|
21712
21559
|
}
|
|
21713
21560
|
static get watchers() { return {
|
|
21714
21561
|
"item": [{
|
|
@@ -21718,6 +21565,42 @@ const KritzelMenuItem = class {
|
|
|
21718
21565
|
};
|
|
21719
21566
|
KritzelMenuItem.style = kritzelMenuItemCss();
|
|
21720
21567
|
|
|
21568
|
+
const kritzelOpacitySliderCss = () => `:host{display:flex;flex-direction:column;padding:0;box-sizing:border-box}.opacity-container{display:flex;align-items:center;width:232px}.slider-wrapper{flex:1;display:flex;align-items:center}.opacity-slider{-webkit-appearance:none;appearance:none;width:100%;height:6px;border-radius:3px;background:linear-gradient( to right, var(--kritzel-opacity-slider-active-color, #007AFF) 0%, var(--kritzel-opacity-slider-active-color, #007AFF) var(--slider-progress, 100%), var(--kritzel-opacity-slider-track-color, #e0e0e0) var(--slider-progress, 100%), var(--kritzel-opacity-slider-track-color, #e0e0e0) 100% );outline:none;cursor:var(--kritzel-pointer-cursor, pointer)}.opacity-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:16px;height:16px;border-radius:50%;background:var(--kritzel-opacity-slider-thumb-color, #ffffff);border:2px solid var(--kritzel-opacity-slider-thumb-border-color, #007AFF);cursor:var(--kritzel-pointer-cursor, pointer);box-shadow:0 1px 3px rgba(0, 0, 0, 0.2);transition:transform 0.1s ease}.opacity-slider::-webkit-slider-thumb:hover{transform:scale(1.1)}.opacity-slider::-moz-range-thumb{width:16px;height:16px;border-radius:50%;background:var(--kritzel-opacity-slider-thumb-color, #ffffff);border:2px solid var(--kritzel-opacity-slider-thumb-border-color, #007AFF);cursor:var(--kritzel-pointer-cursor, pointer);box-shadow:0 1px 3px rgba(0, 0, 0, 0.2);transition:transform 0.1s ease}.opacity-slider::-moz-range-thumb:hover{transform:scale(1.1)}.opacity-slider::-moz-range-track{height:6px;border-radius:3px;background:transparent}.opacity-slider:focus{outline:none}.opacity-slider:focus::-webkit-slider-thumb{box-shadow:0 0 0 3px var(--kritzel-focus-ring-color, rgba(0, 122, 255, 0.3))}.opacity-slider:focus::-moz-range-thumb{box-shadow:0 0 0 3px var(--kritzel-focus-ring-color, rgba(0, 122, 255, 0.3))}`;
|
|
21569
|
+
|
|
21570
|
+
const KritzelOpacitySlider = class {
|
|
21571
|
+
constructor(hostRef) {
|
|
21572
|
+
registerInstance(this, hostRef);
|
|
21573
|
+
this.valueChange = createEvent(this, "valueChange");
|
|
21574
|
+
}
|
|
21575
|
+
/** Current opacity value (0 to 1) */
|
|
21576
|
+
value = 1;
|
|
21577
|
+
/** Minimum opacity value */
|
|
21578
|
+
min = 0;
|
|
21579
|
+
/** Maximum opacity value */
|
|
21580
|
+
max = 1;
|
|
21581
|
+
/** Step increment */
|
|
21582
|
+
step = 0.01;
|
|
21583
|
+
/** Color to display in the preview (optional) */
|
|
21584
|
+
previewColor = '#000000';
|
|
21585
|
+
valueChange;
|
|
21586
|
+
handleInput(event) {
|
|
21587
|
+
const input = event.target;
|
|
21588
|
+
const newValue = parseFloat(input.value);
|
|
21589
|
+
this.value = newValue;
|
|
21590
|
+
this.valueChange.emit(newValue);
|
|
21591
|
+
}
|
|
21592
|
+
getPercentage() {
|
|
21593
|
+
return Math.round(this.value * 100);
|
|
21594
|
+
}
|
|
21595
|
+
render() {
|
|
21596
|
+
const percentage = this.getPercentage();
|
|
21597
|
+
return (h(Host, { key: 'e1409175b038e78d2659356452c48ccc7d79b8de' }, h("div", { key: '1de138f56f699fc54623ed8d7b8b5c6d3eda3c67', class: "opacity-container" }, h("div", { key: '1dd5d0d36c8d025ba46a0623a20f040990cc749a', class: "slider-wrapper" }, h("input", { key: '7b555aa0a4a9abfdcdadc86bffa5878c9336d1e4', type: "range", class: "opacity-slider", min: this.min, max: this.max, step: this.step, value: this.value, onInput: (e) => this.handleInput(e), style: {
|
|
21598
|
+
'--slider-progress': `${percentage}%`,
|
|
21599
|
+
} })))));
|
|
21600
|
+
}
|
|
21601
|
+
};
|
|
21602
|
+
KritzelOpacitySlider.style = kritzelOpacitySliderCss();
|
|
21603
|
+
|
|
21721
21604
|
class KritzelHTMLHelper {
|
|
21722
21605
|
static getNumericValueFromStyle(element, property) {
|
|
21723
21606
|
const value = window.getComputedStyle(element).getPropertyValue(property);
|
|
@@ -21974,7 +21857,7 @@ const KritzelPortal = class {
|
|
|
21974
21857
|
this.portal.style.left = `${left}px`;
|
|
21975
21858
|
}
|
|
21976
21859
|
render() {
|
|
21977
|
-
return (h(Host, { key: '
|
|
21860
|
+
return (h(Host, { key: 'c70a1f7c4b2801346fc7a711b44e951337f42f77', style: { display: this.anchor ? 'block' : 'none' } }, h("slot", { key: '654bd6dd3ec83d77984a500d505ed1f3c04a0c26' })));
|
|
21978
21861
|
}
|
|
21979
21862
|
static get watchers() { return {
|
|
21980
21863
|
"anchor": [{
|
|
@@ -21983,6 +21866,40 @@ const KritzelPortal = class {
|
|
|
21983
21866
|
}; }
|
|
21984
21867
|
};
|
|
21985
21868
|
|
|
21869
|
+
const kritzelShapeFillCss = () => `:host{display:flex;flex-direction:column;gap:12px;padding:0;box-sizing:border-box}.fill-row{display:flex;align-items:center;gap:4px}.fill-option{display:flex;justify-content:center;align-items:center;width:48px;height:32px;border-radius:6px;cursor:var(--kritzel-pointer-cursor, pointer);border:2px solid transparent;box-sizing:border-box;background:var(--kritzel-shape-fill-option-background, #ffffff);padding:4px;transition:background-color 0.15s ease, border-color 0.15s ease}.fill-option:hover{background-color:var(--kritzel-shape-fill-hover-background-color, #ebebeb)}.fill-option.selected{border-color:var(--kritzel-selection-border-color, #007AFF);background-color:var(--kritzel-shape-fill-selected-background-color, #ebebeb)}.fill-option:focus{outline:none;box-shadow:0 0 0 2px var(--kritzel-focus-ring-color, rgba(0, 122, 255, 0.3))}.fill-icon{width:100%;height:100%}`;
|
|
21870
|
+
|
|
21871
|
+
const KritzelShapeFill = class {
|
|
21872
|
+
constructor(hostRef) {
|
|
21873
|
+
registerInstance(this, hostRef);
|
|
21874
|
+
this.valueChange = createEvent(this, "valueChange");
|
|
21875
|
+
}
|
|
21876
|
+
/** Current fill type */
|
|
21877
|
+
value = 'transparent';
|
|
21878
|
+
valueChange;
|
|
21879
|
+
handleFillChange(type) {
|
|
21880
|
+
this.value = type;
|
|
21881
|
+
this.valueChange.emit(type);
|
|
21882
|
+
}
|
|
21883
|
+
renderFillIcon(type) {
|
|
21884
|
+
const strokeColor = '#000000';
|
|
21885
|
+
if (type === 'transparent') {
|
|
21886
|
+
return (h("svg", { viewBox: "0 0 24 24", class: "fill-icon" }, h("rect", { x: "4", y: "4", width: "16", height: "16", rx: "2", fill: "none", stroke: strokeColor, "stroke-width": "2" })));
|
|
21887
|
+
}
|
|
21888
|
+
// Filled
|
|
21889
|
+
return (h("svg", { viewBox: "0 0 24 24", class: "fill-icon" }, h("rect", { x: "4", y: "4", width: "16", height: "16", rx: "2", fill: strokeColor, stroke: strokeColor, "stroke-width": "2" })));
|
|
21890
|
+
}
|
|
21891
|
+
render() {
|
|
21892
|
+
return (h(Host, { key: '7935296eb495557672cc96ab838ff4996953b220' }, h("div", { key: '69011629ff2dbdd38c7fb03b873fe5411b712de3', class: "fill-row" }, h("button", { key: '8a16a43b1ed8f316bc698a304d76667397a83015', class: {
|
|
21893
|
+
'fill-option': true,
|
|
21894
|
+
'selected': this.value === 'transparent',
|
|
21895
|
+
}, onClick: () => this.handleFillChange('transparent'), title: "Transparent background" }, this.renderFillIcon('transparent')), h("button", { key: 'f51854da5ece9f18242b4b91ac9645e13efc41b3', class: {
|
|
21896
|
+
'fill-option': true,
|
|
21897
|
+
'selected': this.value === 'filled',
|
|
21898
|
+
}, onClick: () => this.handleFillChange('filled'), title: "Filled background" }, this.renderFillIcon('filled')))));
|
|
21899
|
+
}
|
|
21900
|
+
};
|
|
21901
|
+
KritzelShapeFill.style = kritzelShapeFillCss();
|
|
21902
|
+
|
|
21986
21903
|
const kritzelSplitButtonCss = () => `:host{position:relative;display:flex;align-items:center;font-family:sans-serif;z-index:1;padding:var(--kritzel-split-button-padding, 4px);background-color:var(--kritzel-split-button-background-color, #ffffff);border-radius:var(--kritzel-split-button-border-radius, 12px);box-shadow:var(--kritzel-split-button-box-shadow, 0 0 3px rgba(0, 0, 0, 0.08));border:var(--kritzel-split-button-border, 1px solid #ebebeb);gap:var(--kritzel-split-button-gap, 4px)}:host(.mobile){--kritzel-split-button-hover-background-color:transparent}button{border:none;background-color:transparent;padding:0;margin:0;font-family:inherit;font-size:inherit;color:inherit;-webkit-appearance:none;-moz-appearance:none;appearance:none;cursor:var(--kritzel-pointer-cursor, pointer);text-align:center;display:flex;align-items:center;justify-content:center;pointer-events:all;-webkit-tap-highlight-color:transparent}.split-main-button,.split-menu-button{height:auto;display:flex;align-items:center;padding:var(--kritzel-split-button-padding, 8px);background-color:var(--kritzel-split-button-background-color, #ffffff);border-radius:var(--kritzel-split-button-border-radius, 12px);font-size:var(--kritzel-split-button-font-size, 14px)}.split-main-button:hover,.split-menu-button:hover{background-color:var(--kritzel-split-button-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.split-main-button:focus,.split-menu-button:focus{background-color:var(--kritzel-split-button-hover-background-color, hsl(0, 0%, 0%, 4.3%))}.split-main-button{gap:var(--kritzel-split-button-gap, 4px)}.split-menu-button{border-left:none;justify-content:center}.split-divider{width:var(--kritzel-split-button-divider-width, 1px);height:24px;background-color:var(--kritzel-split-button-divider-background-color, hsl(0, 0%, 0%, 4.3%))}:disabled{pointer-events:none;opacity:0.5}`;
|
|
21987
21904
|
|
|
21988
21905
|
const KritzelSplitButton = class {
|
|
@@ -22076,12 +21993,12 @@ const KritzelSplitButton = class {
|
|
|
22076
21993
|
this.menuScrollTop = event.target.scrollTop;
|
|
22077
21994
|
};
|
|
22078
21995
|
render() {
|
|
22079
|
-
return (h(Host, { key: '
|
|
21996
|
+
return (h(Host, { key: 'cdfb795efe513061f464c76650aa226cd7d5ac81', class: { mobile: this.isTouchDevice } }, h("button", { key: '5c38c82b57f35c2e39b0dbba71b3ccfd99ebcc5c', class: "split-main-button", tabIndex: 0, onClick: this.handleButtonClick, disabled: this.mainButtonDisabled }, this.buttonIcon && h("kritzel-icon", { key: '862d96cca7ec5aef55284ac6a65ce16b07a03dda', name: this.buttonIcon })), h("div", { key: '41849e36e756af257d10baf82d2cb0c9cd1e441f', class: "split-divider" }), h("button", { key: '0c54c40c84dcf5cf1b94b024353334e4be0e3404', ref: el => (this.splitMenuButtonRef = el), class: "split-menu-button", tabIndex: 0, onClick: this.toggleMenu, disabled: this.menuButtonDisabled }, h("kritzel-icon", { key: '15b0d07c9afa584105180fb5f0701c15974f11aa', name: this.dropdownIcon })), h("kritzel-portal", { key: '23014ad95c3ee688b9348f480cc33cdb1c970244', anchor: this.anchorElement, offsetY: 4, onClose: this.closeMenu }, h("kritzel-menu", { key: '90f4f29429a80f5700d16b1e99f3dd6315464bbb', ref: el => (this.menuRef = el), items: this.items, onItemSelect: this.handleItemSelect, onItemSave: this.handleItemSave, onItemCancel: this.handleItemCancel, onItemToggleChildMenu: this.handleItemToggleChildMenu, onItemCloseChildMenu: this.handleItemCloseChildMenu, onClose: this.closeMenu, onScroll: this.handleScroll }))));
|
|
22080
21997
|
}
|
|
22081
21998
|
};
|
|
22082
21999
|
KritzelSplitButton.style = kritzelSplitButtonCss();
|
|
22083
22000
|
|
|
22084
|
-
const kritzelStrokeSizeCss = () => `:host{display:flex;align-items:flex-start;gap:
|
|
22001
|
+
const kritzelStrokeSizeCss = () => `:host{display:flex;align-items:flex-start;gap:0;padding:0;width:100%;box-sizing:border-box}.size-grid{width:100%;display:grid;grid-template-columns:repeat(6, 32px);gap:8px;justify-items:center}.size-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}.size-container:hover{background-color:var(--kritzel-stroke-size-hover-background-color, #ebebeb)}.size-container.selected{border-color:var(--kritzel-selection-border-color, #007AFF);background-color:var(--kritzel-stroke-size-selected-background-color, #ebebeb)}`;
|
|
22085
22002
|
|
|
22086
22003
|
const KritzelStrokeSize = class {
|
|
22087
22004
|
constructor(hostRef) {
|
|
@@ -22096,15 +22013,215 @@ const KritzelStrokeSize = class {
|
|
|
22096
22013
|
this.sizeChange.emit(size);
|
|
22097
22014
|
}
|
|
22098
22015
|
render() {
|
|
22099
|
-
return (h(Host, { key: '
|
|
22016
|
+
return (h(Host, { key: '891f899a41844bba03305e3dd7cbf428d4471ff9' }, h("div", { key: '773a756d54d0632c9ea6b3aebb743abad2274244', class: "size-grid" }, this.sizes.map(size => (h("div", { tabIndex: 0, class: {
|
|
22100
22017
|
'size-container': true,
|
|
22101
22018
|
'selected': this.selectedSize === size,
|
|
22102
|
-
}, onClick: () => this.handleSizeClick(size) }, h("kritzel-color", { value: '#000000', size: size }))))));
|
|
22019
|
+
}, onClick: () => this.handleSizeClick(size) }, h("kritzel-color", { value: '#000000', size: size })))))));
|
|
22103
22020
|
}
|
|
22104
22021
|
};
|
|
22105
22022
|
KritzelStrokeSize.style = kritzelStrokeSizeCss();
|
|
22106
22023
|
|
|
22107
|
-
const
|
|
22024
|
+
const kritzelToolConfigCss = () => `.expand-toggle{background:none;border:none;cursor:pointer;padding:0;margin:0;display:flex;align-items:center;justify-content:center;width:32px;height:32px;color:var(--kritzel-icon-color, currentColor);transition:transform 0.2s ease}.expand-toggle:hover{opacity:0.7}.expand-toggle:focus{outline:none}.expand-toggle:focus-visible{outline:2px solid var(--kritzel-focus-color, #007acc);outline-offset:2px}.expand-toggle:active{transform:scale(0.95)}.divider{height:1px;background-color:var(--kritzel-divider-color, #e0e0e0);margin:4px 0;width:100%}`;
|
|
22025
|
+
|
|
22026
|
+
const KritzelToolConfig = class {
|
|
22027
|
+
constructor(hostRef) {
|
|
22028
|
+
registerInstance(this, hostRef);
|
|
22029
|
+
this.toolChange = createEvent(this, "toolChange");
|
|
22030
|
+
this.displayValuesChange = createEvent(this, "displayValuesChange");
|
|
22031
|
+
}
|
|
22032
|
+
tool;
|
|
22033
|
+
handleToolChange(newTool, oldTool) {
|
|
22034
|
+
const newConfig = KritzelToolConfigHelper.getToolConfig(newTool);
|
|
22035
|
+
// Maintain settings when switching between shape tools
|
|
22036
|
+
if (oldTool && newTool && newConfig?.type === 'shape') {
|
|
22037
|
+
const oldConfig = KritzelToolConfigHelper.getToolConfig(oldTool);
|
|
22038
|
+
if (oldConfig?.type === 'shape') {
|
|
22039
|
+
// Copy properties that should persist
|
|
22040
|
+
const propsToCopy = [
|
|
22041
|
+
newConfig.colorProperty, // strokeColor
|
|
22042
|
+
newConfig.sizeProperty, // strokeWidth
|
|
22043
|
+
newConfig.opacityProperty, // opacity
|
|
22044
|
+
'fillColor' // shape specific
|
|
22045
|
+
];
|
|
22046
|
+
propsToCopy.forEach(prop => {
|
|
22047
|
+
if (prop && oldTool[prop] !== undefined) {
|
|
22048
|
+
newTool[prop] = oldTool[prop];
|
|
22049
|
+
}
|
|
22050
|
+
});
|
|
22051
|
+
}
|
|
22052
|
+
}
|
|
22053
|
+
this.config = newConfig;
|
|
22054
|
+
if (this.config) {
|
|
22055
|
+
this.updatePalette();
|
|
22056
|
+
this.currentOpacity = newTool[this.config.opacityProperty] ?? 1;
|
|
22057
|
+
// Emit the values since they might have been updated from the old tool
|
|
22058
|
+
this.emitDisplayValues();
|
|
22059
|
+
}
|
|
22060
|
+
}
|
|
22061
|
+
isExpanded = false;
|
|
22062
|
+
toolChange;
|
|
22063
|
+
displayValuesChange;
|
|
22064
|
+
config;
|
|
22065
|
+
palette = [];
|
|
22066
|
+
currentOpacity = 1;
|
|
22067
|
+
updateTrigger = 0;
|
|
22068
|
+
handleSelectionChange() {
|
|
22069
|
+
if (this.tool instanceof KritzelSelectionTool) {
|
|
22070
|
+
this.config = KritzelToolConfigHelper.getToolConfig(this.tool);
|
|
22071
|
+
if (this.config) {
|
|
22072
|
+
this.updatePalette();
|
|
22073
|
+
this.currentOpacity = this.tool[this.config.opacityProperty] ?? 1;
|
|
22074
|
+
this.emitDisplayValues();
|
|
22075
|
+
}
|
|
22076
|
+
}
|
|
22077
|
+
}
|
|
22078
|
+
componentWillLoad() {
|
|
22079
|
+
this.config = KritzelToolConfigHelper.getToolConfig(this.tool);
|
|
22080
|
+
if (this.config) {
|
|
22081
|
+
this.updatePalette();
|
|
22082
|
+
this.currentOpacity = this.tool[this.config.opacityProperty] ?? 1;
|
|
22083
|
+
this.emitDisplayValues();
|
|
22084
|
+
}
|
|
22085
|
+
}
|
|
22086
|
+
emitDisplayValues() {
|
|
22087
|
+
if (!this.config)
|
|
22088
|
+
return;
|
|
22089
|
+
const color = this.tool[this.config.colorProperty];
|
|
22090
|
+
const opacity = this.currentOpacity;
|
|
22091
|
+
const size = this.tool[this.config.sizeProperty];
|
|
22092
|
+
const displayValues = {
|
|
22093
|
+
color: KritzelColorHelper.applyOpacity(color, opacity),
|
|
22094
|
+
size,
|
|
22095
|
+
};
|
|
22096
|
+
if (this.tool instanceof KritzelTextTool) {
|
|
22097
|
+
displayValues.fontFamily = this.tool.fontFamily;
|
|
22098
|
+
}
|
|
22099
|
+
this.displayValuesChange.emit(displayValues);
|
|
22100
|
+
}
|
|
22101
|
+
updatePalette() {
|
|
22102
|
+
if (!this.config)
|
|
22103
|
+
return;
|
|
22104
|
+
if (this.config.paletteSource === 'palettes') {
|
|
22105
|
+
// Brush tool has palettes[type]
|
|
22106
|
+
const brushTool = this.tool;
|
|
22107
|
+
this.palette = brushTool.palettes[brushTool.type] || [];
|
|
22108
|
+
}
|
|
22109
|
+
else if (this.config.paletteSource === 'palette') {
|
|
22110
|
+
// Line, Shape, Text tools have palette
|
|
22111
|
+
this.palette = this.tool.palette || [];
|
|
22112
|
+
}
|
|
22113
|
+
}
|
|
22114
|
+
handleToggleExpand = () => {
|
|
22115
|
+
this.isExpanded = !this.isExpanded;
|
|
22116
|
+
};
|
|
22117
|
+
handleColorChange = (event) => {
|
|
22118
|
+
this.tool[this.config.colorProperty] = event.detail;
|
|
22119
|
+
// Special handling for shape fill: when color (stroke) changes, update fill color if it's currently filled
|
|
22120
|
+
if (this.config.type === 'shape' || this.config.type === 'selection') {
|
|
22121
|
+
const tool = this.tool;
|
|
22122
|
+
if (tool.fillColor !== 'transparent') {
|
|
22123
|
+
tool.fillColor = event.detail;
|
|
22124
|
+
}
|
|
22125
|
+
}
|
|
22126
|
+
this.emitDisplayValues();
|
|
22127
|
+
this.toolChange.emit(this.tool);
|
|
22128
|
+
this.updateTrigger++;
|
|
22129
|
+
};
|
|
22130
|
+
handleSizeChange = (event) => {
|
|
22131
|
+
this.tool[this.config.sizeProperty] = event.detail;
|
|
22132
|
+
this.emitDisplayValues();
|
|
22133
|
+
this.toolChange.emit(this.tool);
|
|
22134
|
+
this.updateTrigger++;
|
|
22135
|
+
};
|
|
22136
|
+
handleOpacityChange = (event) => {
|
|
22137
|
+
this.tool[this.config.opacityProperty] = event.detail;
|
|
22138
|
+
this.currentOpacity = event.detail;
|
|
22139
|
+
this.emitDisplayValues();
|
|
22140
|
+
this.toolChange.emit(this.tool);
|
|
22141
|
+
};
|
|
22142
|
+
handlePropertyChange = (propertyName, value) => {
|
|
22143
|
+
// Special handling for shape fill
|
|
22144
|
+
if ((this.config.type === 'shape' || this.config.type === 'selection') && propertyName === 'fillColor') {
|
|
22145
|
+
const newFillColor = value === 'filled' ? this.tool[this.config.colorProperty] : 'transparent';
|
|
22146
|
+
this.tool.fillColor = newFillColor;
|
|
22147
|
+
// When switching to fill mode, also update stroke color to match
|
|
22148
|
+
if (value === 'filled') {
|
|
22149
|
+
this.tool[this.config.colorProperty] = newFillColor;
|
|
22150
|
+
}
|
|
22151
|
+
}
|
|
22152
|
+
// Special handling for brush type change
|
|
22153
|
+
else if (this.config.type === 'brush' && propertyName === 'type') {
|
|
22154
|
+
const brushTool = this.tool;
|
|
22155
|
+
brushTool.type = value;
|
|
22156
|
+
this.palette = brushTool.palettes[value];
|
|
22157
|
+
brushTool.color = this.palette[0];
|
|
22158
|
+
this.emitDisplayValues();
|
|
22159
|
+
}
|
|
22160
|
+
else {
|
|
22161
|
+
this.tool[propertyName] = value;
|
|
22162
|
+
// Emit display values for font family changes
|
|
22163
|
+
if (propertyName === 'fontFamily') {
|
|
22164
|
+
this.emitDisplayValues();
|
|
22165
|
+
}
|
|
22166
|
+
}
|
|
22167
|
+
this.toolChange.emit(this.tool);
|
|
22168
|
+
this.updateTrigger++;
|
|
22169
|
+
};
|
|
22170
|
+
getShapeFillValue() {
|
|
22171
|
+
const fillColor = this.tool.fillColor;
|
|
22172
|
+
return fillColor === 'transparent' ? 'transparent' : 'filled';
|
|
22173
|
+
}
|
|
22174
|
+
renderControl(control) {
|
|
22175
|
+
const value = this.tool[control.propertyName];
|
|
22176
|
+
switch (control.type) {
|
|
22177
|
+
case 'stroke-size':
|
|
22178
|
+
return (h("kritzel-stroke-size", { key: control.type, selectedSize: value, onSizeChange: this.handleSizeChange }));
|
|
22179
|
+
case 'font-size':
|
|
22180
|
+
return (h("kritzel-font-size", { key: control.type, selectedSize: value, fontFamily: this.tool.fontFamily, onSizeChange: this.handleSizeChange }));
|
|
22181
|
+
case 'line-endings':
|
|
22182
|
+
return (h("kritzel-line-endings", { key: control.type, value: value, strokeColor: this.tool[this.config.colorProperty], onValueChange: (event) => this.handlePropertyChange(control.propertyName, event.detail) }));
|
|
22183
|
+
case 'shape-fill':
|
|
22184
|
+
return (h("kritzel-shape-fill", { key: control.type, value: this.getShapeFillValue(), onValueChange: (event) => this.handlePropertyChange(control.propertyName, event.detail) }));
|
|
22185
|
+
case 'font-family':
|
|
22186
|
+
return (h("kritzel-font-family", { key: control.type, selectedFontFamily: value, onFontFamilyChange: (event) => this.handlePropertyChange(control.propertyName, event.detail) }));
|
|
22187
|
+
default:
|
|
22188
|
+
return null;
|
|
22189
|
+
}
|
|
22190
|
+
}
|
|
22191
|
+
render() {
|
|
22192
|
+
if (!this.config)
|
|
22193
|
+
return null;
|
|
22194
|
+
const shouldShowExpandButton = this.palette.length > 6 || this.config.type === 'text';
|
|
22195
|
+
// Separate size control from other controls
|
|
22196
|
+
const sizeControl = this.config.controls.find(c => c.type === 'stroke-size' || c.type === 'font-size');
|
|
22197
|
+
const otherControls = this.config.controls.filter(c => c.type !== 'stroke-size' && c.type !== 'font-size');
|
|
22198
|
+
return (h(Host, null, h("div", { style: {
|
|
22199
|
+
display: 'flex',
|
|
22200
|
+
flexDirection: 'row',
|
|
22201
|
+
gap: '8px',
|
|
22202
|
+
width: '100%',
|
|
22203
|
+
} }, h("div", { style: {
|
|
22204
|
+
display: 'flex',
|
|
22205
|
+
flexDirection: 'column',
|
|
22206
|
+
gap: '12px',
|
|
22207
|
+
flex: '1',
|
|
22208
|
+
} }, h("kritzel-color-palette", { colors: this.palette, selectedColor: this.tool[this.config.colorProperty], isExpanded: this.isExpanded, isOpaque: true, opacity: this.currentOpacity, onColorChange: this.handleColorChange }), sizeControl && this.renderControl(sizeControl), h("kritzel-opacity-slider", { value: this.tool[this.config.opacityProperty], previewColor: this.tool[this.config.colorProperty], onValueChange: this.handleOpacityChange }), otherControls.map((control) => [
|
|
22209
|
+
h("div", { class: "divider" }),
|
|
22210
|
+
this.renderControl(control),
|
|
22211
|
+
])), shouldShowExpandButton && (h("div", { style: {
|
|
22212
|
+
display: 'flex',
|
|
22213
|
+
alignItems: 'flex-start',
|
|
22214
|
+
} }, h("button", { class: "expand-toggle", onClick: this.handleToggleExpand, title: this.isExpanded ? 'Collapse' : 'Expand' }, h("kritzel-icon", { name: this.isExpanded ? 'chevron-up' : 'chevron-down' })))))));
|
|
22215
|
+
}
|
|
22216
|
+
static get watchers() { return {
|
|
22217
|
+
"tool": [{
|
|
22218
|
+
"handleToolChange": 0
|
|
22219
|
+
}]
|
|
22220
|
+
}; }
|
|
22221
|
+
};
|
|
22222
|
+
KritzelToolConfig.style = kritzelToolConfigCss();
|
|
22223
|
+
|
|
22224
|
+
const kritzelTooltipCss = () => `:host{width:auto}.tooltip-content{position:relative;padding:8px 12px;border-radius:4px;width:fit-content;background-color:var(--kritzel-controls-tooltip-background-color, #ffffff);color:var(--kritzel-controls-tooltip-color, #000000);padding:var(--kritzel-controls-tooltip-padding, 12px);border-radius:var(--kritzel-controls-tooltip-border-radius, 16px);white-space:nowrap;box-shadow:var(--kritzel-controls-tooltip-box-shadow, 0 1px 6px rgba(0, 0, 0, 0.12))}`;
|
|
22108
22225
|
|
|
22109
22226
|
const KritzelTooltip = class {
|
|
22110
22227
|
constructor(hostRef) {
|
|
@@ -22121,8 +22238,10 @@ const KritzelTooltip = class {
|
|
|
22121
22238
|
handleOutsideClick(event) {
|
|
22122
22239
|
if (!this.isVisible)
|
|
22123
22240
|
return;
|
|
22124
|
-
|
|
22125
|
-
|
|
22241
|
+
// Check if click is inside the tooltip host or any of its shadow DOM content
|
|
22242
|
+
const path = event.composedPath();
|
|
22243
|
+
const isInsideTooltip = path.some(el => el === this.host);
|
|
22244
|
+
if (!isInsideTooltip) {
|
|
22126
22245
|
this.tooltipClosed.emit();
|
|
22127
22246
|
}
|
|
22128
22247
|
}
|
|
@@ -22172,14 +22291,14 @@ const KritzelTooltip = class {
|
|
|
22172
22291
|
}
|
|
22173
22292
|
}
|
|
22174
22293
|
render() {
|
|
22175
|
-
return (h(Host, { key: '
|
|
22294
|
+
return (h(Host, { key: '104ad4a160e4f47454955696e5f0e7a28873c3f5', style: {
|
|
22176
22295
|
position: 'fixed',
|
|
22177
22296
|
zIndex: '9999',
|
|
22178
22297
|
transition: 'opacity 0.3s ease-in-out, transform 0.3s ease-in-out',
|
|
22179
22298
|
visibility: this.isVisible ? 'visible' : 'hidden',
|
|
22180
22299
|
left: `${this.positionX}px`,
|
|
22181
22300
|
bottom: `${this.positionY}px`,
|
|
22182
|
-
} }, h("div", { key: '
|
|
22301
|
+
} }, h("div", { key: '283eec8d84ea29caefdb1f0c4f129c57d30bc133', class: "tooltip-content", onClick: event => event.stopPropagation(), onPointerDown: event => event.stopPropagation(), onMouseDown: event => event.stopPropagation() }, h("slot", { key: '1c6e2d9bcb69f8deec08b6c10384b4c7593babd3' }))));
|
|
22183
22302
|
}
|
|
22184
22303
|
};
|
|
22185
22304
|
KritzelTooltip.style = kritzelTooltipCss();
|
|
@@ -22210,7 +22329,7 @@ const KritzelUtilityPanel = class {
|
|
|
22210
22329
|
this.redo.emit();
|
|
22211
22330
|
}
|
|
22212
22331
|
render() {
|
|
22213
|
-
return (h(Host, { key: '
|
|
22332
|
+
return (h(Host, { key: 'b0994bdfd10e1bfbad18d7df2810575b19a9e67d' }, h("button", { key: '4bcb8106f6977ff1472477b6a689942e7eedd8b7', class: "utility-button", disabled: !this.undoState?.canUndo, onClick: event => this.handleUndo(event) }, h("kritzel-icon", { key: '05c9a0b6a926eeb236cda9bf8c333dd6a0b563cb', name: "undo" })), h("button", { key: '88b008c4c37de9440da414617a0b2e144e47e830', class: "utility-button", disabled: !this.undoState?.canRedo, onClick: event => this.handleRedo(event) }, h("kritzel-icon", { key: 'ec921af2eca35fd1d1aad88d88d5f0a0804e4c44', name: "redo" })), h("div", { key: '94b7eec2edee8a41296726ab79d61bccba1940d8', class: "utility-separator" }), h("button", { key: '50be446ae7510d5133b7767e0dd382b7e1c87c3f', class: "utility-button" }, h("kritzel-icon", { key: 'd11d988dafc42c250b7361f5bba532fa9f81d97e', name: "delete", onClick: () => this.delete.emit() }))));
|
|
22214
22333
|
}
|
|
22215
22334
|
};
|
|
22216
22335
|
KritzelUtilityPanel.style = kritzelUtilityPanelCss();
|
|
@@ -22355,4 +22474,4 @@ const KritzelWorkspaceManager = class {
|
|
|
22355
22474
|
};
|
|
22356
22475
|
KritzelWorkspaceManager.style = kritzelWorkspaceManagerCss();
|
|
22357
22476
|
|
|
22358
|
-
export { KritzelColor as kritzel_color, KritzelColorPalette as kritzel_color_palette, KritzelContextMenu as kritzel_context_menu,
|
|
22477
|
+
export { KritzelColor as kritzel_color, KritzelColorPalette as kritzel_color_palette, KritzelContextMenu as kritzel_context_menu, KritzelControls as kritzel_controls, KritzelCursorTrail as kritzel_cursor_trail, KritzelDropdown as kritzel_dropdown, KritzelEditor as kritzel_editor, KritzelEngine as kritzel_engine, KritzelFont as kritzel_font, KritzelFontFamily as kritzel_font_family, KritzelFontSize as kritzel_font_size, KritzelIcon as kritzel_icon, KritzelLineEndings as kritzel_line_endings, KritzelMenu as kritzel_menu, KritzelMenuItem as kritzel_menu_item, KritzelOpacitySlider as kritzel_opacity_slider, KritzelPortal as kritzel_portal, KritzelShapeFill as kritzel_shape_fill, KritzelSplitButton as kritzel_split_button, KritzelStrokeSize as kritzel_stroke_size, KritzelToolConfig as kritzel_tool_config, KritzelTooltip as kritzel_tooltip, KritzelUtilityPanel as kritzel_utility_panel, KritzelWorkspaceManager as kritzel_workspace_manager };
|