kritzel-stencil 0.1.1 → 0.1.3

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.
Files changed (171) hide show
  1. package/dist/cjs/{default-line-tool.config-SdMGkNhv.js → default-line-tool.config-MA02HCrH.js} +635 -118
  2. package/dist/cjs/{index-BeKMS-Zt.js → index-Bj0n7fQQ.js} +84 -7
  3. package/dist/cjs/index.cjs.js +1 -1
  4. package/dist/cjs/kritzel-brush-style.cjs.entry.js +1 -1
  5. package/dist/cjs/{kritzel-color_22.cjs.entry.js → kritzel-color_24.cjs.entry.js} +832 -771
  6. package/dist/cjs/loader.cjs.js +2 -2
  7. package/dist/cjs/stencil.cjs.js +3 -3
  8. package/dist/collection/classes/core/core.class.js +2 -0
  9. package/dist/collection/classes/objects/line.class.js +1 -0
  10. package/dist/collection/classes/objects/path.class.js +1 -0
  11. package/dist/collection/classes/objects/shape.class.js +1 -0
  12. package/dist/collection/classes/objects/text.class.js +4 -3
  13. package/dist/collection/classes/providers/indexeddb-sync-provider.class.js +0 -1
  14. package/dist/collection/classes/tools/brush-tool.class.js +5 -0
  15. package/dist/collection/classes/tools/line-tool.class.js +31 -1
  16. package/dist/collection/classes/tools/selection-tool.class.js +193 -0
  17. package/dist/collection/classes/tools/shape-tool.class.js +2 -0
  18. package/dist/collection/classes/tools/text-tool.class.js +3 -0
  19. package/dist/collection/collection-manifest.json +5 -3
  20. package/dist/collection/components/core/kritzel-cursor-trail/kritzel-cursor-trail.js +3 -2
  21. package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +37 -19
  22. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +108 -36
  23. package/dist/collection/components/shared/kritzel-color/kritzel-color.js +2 -2
  24. package/dist/collection/components/shared/kritzel-color-palette/kritzel-color-palette.css +1 -1
  25. package/dist/collection/components/shared/kritzel-color-palette/kritzel-color-palette.js +24 -2
  26. package/dist/collection/components/shared/kritzel-font/kritzel-font.js +1 -1
  27. package/dist/collection/components/shared/kritzel-font-family/kritzel-font-family.css +1 -1
  28. package/dist/collection/components/shared/kritzel-font-size/kritzel-font-size.css +1 -1
  29. package/dist/collection/components/shared/kritzel-font-size/kritzel-font-size.js +1 -1
  30. package/dist/collection/components/shared/kritzel-line-endings/kritzel-line-endings.css +60 -0
  31. package/dist/collection/components/shared/kritzel-line-endings/kritzel-line-endings.js +187 -0
  32. package/dist/collection/components/shared/kritzel-menu/kritzel-menu.js +15 -8
  33. package/dist/collection/components/shared/kritzel-menu-item/kritzel-menu-item.js +16 -9
  34. package/dist/collection/components/shared/kritzel-opacity-slider/kritzel-opacity-slider.css +85 -0
  35. package/dist/collection/components/shared/kritzel-opacity-slider/kritzel-opacity-slider.js +163 -0
  36. package/dist/collection/components/shared/kritzel-portal/kritzel-portal.js +1 -1
  37. package/dist/collection/components/shared/kritzel-shape-fill/kritzel-shape-fill.css +47 -0
  38. package/dist/collection/components/shared/kritzel-shape-fill/kritzel-shape-fill.js +93 -0
  39. package/dist/collection/components/shared/kritzel-split-button/kritzel-split-button.js +13 -7
  40. package/dist/collection/components/shared/kritzel-stroke-size/kritzel-stroke-size.css +11 -2
  41. package/dist/collection/components/shared/kritzel-stroke-size/kritzel-stroke-size.js +2 -2
  42. package/dist/collection/components/shared/kritzel-tooltip/kritzel-tooltip.css +1 -1
  43. package/dist/collection/components/shared/kritzel-tooltip/kritzel-tooltip.js +6 -4
  44. package/dist/collection/components/ui/kritzel-context-menu/kritzel-context-menu.js +6 -3
  45. package/dist/collection/components/ui/kritzel-controls/kritzel-controls.css +4 -4
  46. package/dist/collection/components/ui/kritzel-controls/kritzel-controls.js +95 -14
  47. package/dist/collection/components/ui/kritzel-tool-config/kritzel-tool-config.css +38 -0
  48. package/dist/collection/components/ui/kritzel-tool-config/kritzel-tool-config.js +321 -0
  49. package/dist/collection/components/ui/kritzel-utility-panel/kritzel-utility-panel.js +3 -2
  50. package/dist/collection/components/ui/kritzel-workspace-manager/kritzel-workspace-manager.js +6 -3
  51. package/dist/collection/configs/default-brush-tool.config.js +2 -52
  52. package/dist/collection/configs/default-line-tool.config.js +2 -26
  53. package/dist/collection/configs/default-shape-tool.config.js +2 -15
  54. package/dist/collection/configs/default-text-tool.config.js +2 -26
  55. package/dist/collection/constants/color-palette.constants.js +30 -0
  56. package/dist/collection/helpers/color.helper.js +31 -0
  57. package/dist/collection/helpers/tool-config.helper.js +65 -0
  58. package/dist/collection/interfaces/tool-config.interface.js +1 -0
  59. package/dist/components/index.d.ts +8 -4
  60. package/dist/components/index.js +1 -1
  61. package/dist/components/kritzel-brush-style.js +1 -1
  62. package/dist/components/kritzel-color-palette.js +1 -1
  63. package/dist/components/kritzel-color.js +1 -1
  64. package/dist/components/kritzel-context-menu.js +1 -1
  65. package/dist/components/kritzel-controls.js +1 -1
  66. package/dist/components/kritzel-cursor-trail.js +1 -1
  67. package/dist/components/kritzel-dropdown.js +1 -1
  68. package/dist/components/kritzel-editor.js +1 -1
  69. package/dist/components/kritzel-engine.js +1 -1
  70. package/dist/components/kritzel-font-family.js +1 -1
  71. package/dist/components/kritzel-font-size.js +1 -1
  72. package/dist/components/kritzel-font.js +1 -1
  73. package/dist/components/kritzel-icon.js +1 -1
  74. package/dist/components/kritzel-line-endings.d.ts +11 -0
  75. package/dist/components/kritzel-line-endings.js +1 -0
  76. package/dist/components/kritzel-menu-item.js +1 -1
  77. package/dist/components/kritzel-menu.js +1 -1
  78. package/dist/components/kritzel-opacity-slider.d.ts +11 -0
  79. package/dist/components/kritzel-opacity-slider.js +1 -0
  80. package/dist/components/kritzel-portal.js +1 -1
  81. package/dist/components/kritzel-shape-fill.d.ts +11 -0
  82. package/dist/components/kritzel-shape-fill.js +1 -0
  83. package/dist/components/kritzel-split-button.js +1 -1
  84. package/dist/components/kritzel-stroke-size.js +1 -1
  85. package/dist/components/kritzel-tool-config.d.ts +11 -0
  86. package/dist/components/kritzel-tool-config.js +1 -0
  87. package/dist/components/kritzel-tooltip.js +1 -1
  88. package/dist/components/kritzel-utility-panel.js +1 -1
  89. package/dist/components/kritzel-workspace-manager.js +1 -1
  90. package/dist/components/p-83YX0-FS.js +1 -0
  91. package/dist/components/p-9XZbc_qK.js +1 -0
  92. package/dist/components/p-BVIY50lR.js +1 -0
  93. package/dist/components/{p-D1tfzpy8.js → p-BlUr7oVq.js} +1 -1
  94. package/dist/components/{p-Bj_Og27M.js → p-BxS4Pdpz.js} +1 -1
  95. package/dist/components/{p-g0N9j_uT.js → p-CCj8nmQH.js} +1 -1
  96. package/dist/components/{p-1z-ds26_.js → p-CLOnpu42.js} +1 -1
  97. package/dist/components/p-CNneo_RD.js +1 -0
  98. package/dist/components/p-CkpOndCn.js +1 -0
  99. package/dist/components/{p-IAqZFssU.js → p-Cnpk2hfo.js} +1 -1
  100. package/dist/components/{p-Cy77SpWt.js → p-Ctv4NAxk.js} +1 -1
  101. package/dist/components/p-CzjSdJio.js +1 -0
  102. package/dist/components/{p-XGgKC_Fe.js → p-DKgqzi2Y.js} +1 -1
  103. package/dist/components/{p-C4krHoUl.js → p-DLijNISu.js} +1 -1
  104. package/dist/components/p-DMJI6opm.js +1 -0
  105. package/dist/components/p-DOF5fWDU.js +1 -0
  106. package/dist/components/{p-4FEa4ADy.js → p-DV_h5Jo2.js} +1 -1
  107. package/dist/components/{p-DTezr6w9.js → p-DgCGSL2Q.js} +1 -1
  108. package/dist/components/p-DwJUC6cw.js +9 -0
  109. package/dist/components/p-FOxrXeq4.js +1 -0
  110. package/dist/components/p-S5GeUsJP.js +1 -0
  111. package/dist/components/{p-CXzfYQ_u.js → p-e1r5dgeP.js} +1 -1
  112. package/dist/components/p-pKbfOI5a.js +1 -0
  113. package/dist/components/{p-D5ZsALCP.js → p-wRXL928z.js} +1 -1
  114. package/dist/esm/{default-line-tool.config-Cw8mdDpt.js → default-line-tool.config-DLpNl6R9.js} +634 -110
  115. package/dist/esm/{index-BqhmuUH2.js → index-OLdaFN6W.js} +84 -7
  116. package/dist/esm/index.js +2 -2
  117. package/dist/esm/kritzel-brush-style.entry.js +1 -1
  118. package/dist/esm/{kritzel-color_22.entry.js → kritzel-color_24.entry.js} +821 -762
  119. package/dist/esm/loader.js +3 -3
  120. package/dist/esm/stencil.js +4 -4
  121. package/dist/stencil/index.esm.js +1 -1
  122. package/dist/stencil/p-361ebc7e.entry.js +9 -0
  123. package/dist/stencil/{p-09295079.entry.js → p-802bc7cf.entry.js} +1 -1
  124. package/dist/stencil/p-DLpNl6R9.js +1 -0
  125. package/dist/stencil/p-OLdaFN6W.js +2 -0
  126. package/dist/stencil/stencil.esm.js +1 -1
  127. package/dist/types/classes/objects/shape.class.d.ts +1 -0
  128. package/dist/types/classes/tools/brush-tool.class.d.ts +1 -0
  129. package/dist/types/classes/tools/line-tool.class.d.ts +2 -1
  130. package/dist/types/classes/tools/selection-tool.class.d.ts +22 -0
  131. package/dist/types/classes/tools/shape-tool.class.d.ts +1 -0
  132. package/dist/types/classes/tools/text-tool.class.d.ts +1 -0
  133. package/dist/types/components/core/kritzel-engine/kritzel-engine.d.ts +2 -0
  134. package/dist/types/components/shared/kritzel-color-palette/kritzel-color-palette.d.ts +1 -0
  135. package/dist/types/components/shared/kritzel-line-endings/kritzel-line-endings.d.ts +23 -0
  136. package/dist/types/components/shared/kritzel-opacity-slider/kritzel-opacity-slider.d.ts +17 -0
  137. package/dist/types/components/shared/kritzel-shape-fill/kritzel-shape-fill.d.ts +10 -0
  138. package/dist/types/components/ui/kritzel-controls/kritzel-controls.d.ts +9 -0
  139. package/dist/types/components/ui/kritzel-tool-config/kritzel-tool-config.d.ts +25 -0
  140. package/dist/types/components.d.ts +235 -82
  141. package/dist/types/constants/color-palette.constants.d.ts +5 -0
  142. package/dist/types/helpers/color.helper.d.ts +9 -0
  143. package/dist/types/helpers/tool-config.helper.d.ts +4 -0
  144. package/dist/types/interfaces/line-options.interface.d.ts +1 -0
  145. package/dist/types/interfaces/path-options.interface.d.ts +1 -0
  146. package/dist/types/interfaces/tool-config.interface.d.ts +26 -0
  147. package/dist/types/stencil-public-runtime.d.ts +29 -0
  148. package/package.json +5 -3
  149. package/dist/collection/components/ui/kritzel-control-brush-config/kritzel-control-brush-config.css +0 -19
  150. package/dist/collection/components/ui/kritzel-control-brush-config/kritzel-control-brush-config.js +0 -134
  151. package/dist/collection/components/ui/kritzel-control-text-config/kritzel-control-text-config.css +0 -19
  152. package/dist/collection/components/ui/kritzel-control-text-config/kritzel-control-text-config.js +0 -114
  153. package/dist/components/kritzel-control-brush-config.d.ts +0 -11
  154. package/dist/components/kritzel-control-brush-config.js +0 -1
  155. package/dist/components/kritzel-control-text-config.d.ts +0 -11
  156. package/dist/components/kritzel-control-text-config.js +0 -1
  157. package/dist/components/p-BXaWhpO2.js +0 -1
  158. package/dist/components/p-BtuXeItZ.js +0 -1
  159. package/dist/components/p-C-d2IH4v.js +0 -1
  160. package/dist/components/p-C3UriJh7.js +0 -1
  161. package/dist/components/p-CF5L2Gdl.js +0 -1
  162. package/dist/components/p-CeKT_dTd.js +0 -1
  163. package/dist/components/p-Cp15toXH.js +0 -1
  164. package/dist/components/p-D4n7UbGY.js +0 -1
  165. package/dist/components/p-Du1vxHy8.js +0 -1
  166. package/dist/components/p-exWKDgI8.js +0 -9
  167. package/dist/stencil/p-BqhmuUH2.js +0 -2
  168. package/dist/stencil/p-Cw8mdDpt.js +0 -1
  169. package/dist/stencil/p-d21a009f.entry.js +0 -9
  170. package/dist/types/components/ui/kritzel-control-brush-config/kritzel-control-brush-config.d.ts +0 -15
  171. 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-BqhmuUH2.js';
2
- import { Z as KritzelDevicesHelper, J as KritzelBrushTool, P as KritzelTextTool, _ as KritzelMouseButton, $ as KritzelBaseObject, a0 as Schema, a1 as schema, a2 as addListNodes, a3 as EditorView, a4 as EditorState, a5 as keymap, a6 as TextSelection, a7 as KritzelKeyboardHelper, a8 as KritzelToolRegistry, a9 as KritzelGeometryHelper, aa as baseKeymap, ab as KritzelBaseTool, ac as KritzelEventHelper, R as KritzelSelectionTool, W as DEFAULT_BRUSH_CONFIG, Y as DEFAULT_LINE_TOOL_CONFIG, L as KritzelLineTool, M as KritzelEraserTool, X as DEFAULT_TEXT_CONFIG, N as KritzelImageTool, U as KritzelWorkspace, ad as KritzelIconRegistry, ae as KritzelBaseHandler, af as KritzelSelectionBox, ag as KritzelSelectionGroup, I as KritzelGroup, F as KritzelImage, K as KritzelText, G as KritzelLine, E as KritzelPath, ah as Doc, ai as DEFAULT_SYNC_CONFIG, aj as UndoManager, Q as KritzelCursorHelper, T as KritzelAppStateMap, V as KritzelAnchorManager, ak as ObjectHelper, al as KritzelClassHelper } from './default-line-tool.config-Cw8mdDpt.js';
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: 'edf5d94f476d72d0be74886b362fd37db789c517' }, h("div", { key: 'd8af2373616b9bc6f4ddea0822d737f073563bf9', class: "checkerboard-bg", style: {
40
+ return (h(Host, { key: '16e284aa1e572b81f4413d33c0d046ee57c5980f' }, h("div", { key: '718a391eb984720fdc5cd80f9a4db161e504bb9c', 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: '6b587f7926884e7c38fe36eaef41b0c8cd213c6d', class: {
46
+ } }, h("div", { key: 'bcf5ebc3dda30fcda5f1c61fa55aeef2bf1d799c', 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
- const kritzelColorPaletteCss = () => `:host{display:flex;align-items:flex-start;gap:8px;padding:8px;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)}`;
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: '83e3aa70f68e1bab337a031c2d00ac152f924fe1' }, h("div", { key: '86a6198500ea5bef3ed399fc8f7ec0275899eb79', class: {
128
+ return (h(Host, { key: 'fbb9b59f227cdc0e97e8dfaf73255fb987c58292' }, h("div", { key: '447971664569dd28972587fc44b67575762ef959', 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,99 +237,271 @@ const KritzelContextMenu = class {
204
237
  };
205
238
  KritzelContextMenu.style = kritzelContextMenuCss();
206
239
 
207
- const kritzelControlBrushConfigCss = () => `:host{display:flex;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)}`;
208
-
209
- const KritzelControlBrushConfig = class {
210
- constructor(hostRef) {
211
- registerInstance(this, hostRef);
212
- this.toolChange = createEvent(this, "toolChange");
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);
213
272
  }
214
- tool;
215
- handleToolChange(newTool) {
216
- this.palette = newTool.palettes[newTool.type];
273
+ handlePointerDown(event) {
274
+ if (event.cancelable) {
275
+ event.preventDefault();
276
+ }
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);
300
+ }
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;
310
+ }
311
+ if (activeShape !== null && object instanceof KritzelShape) {
312
+ activeShape.save();
313
+ object.edit(event);
314
+ return;
315
+ }
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;
323
+ }
324
+ const clientX = Math.round(activePointers[0].clientX);
325
+ const clientY = Math.round(activePointers[0].clientY);
326
+ this.startDrawing(clientX, clientY);
327
+ }
217
328
  }
218
- isExpanded = false;
219
- toolChange;
220
- palette = [];
221
- componentWillLoad() {
222
- this.palette = this.tool.palettes[this.tool.type];
329
+ handlePointerMove(event) {
330
+ if (event.cancelable) {
331
+ event.preventDefault();
332
+ }
333
+ if (!this.isDrawing || !this.currentShape) {
334
+ return;
335
+ }
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
+ }
346
+ }
223
347
  }
224
- handleToggleExpand() {
225
- this.isExpanded = !this.isExpanded;
348
+ handlePointerUp(event) {
349
+ if (event.cancelable) {
350
+ event.preventDefault();
351
+ }
352
+ if (!this.isDrawing || !this.currentShape) {
353
+ return;
354
+ }
355
+ this.finishDrawing();
226
356
  }
227
- handleTypeChange(event) {
228
- this.palette = this.tool.palettes[event.detail];
229
- this.tool.type = event.detail;
230
- this.tool.color = this.palette[0];
231
- this.toolChange.emit(this.tool);
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();
232
388
  }
233
- handleColorChange(event) {
234
- this.tool.color = event.detail;
235
- this.toolChange.emit(this.tool);
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);
236
417
  }
237
- handleSizeChange(event) {
238
- this.tool.size = event.detail;
239
- this.toolChange.emit(this.tool);
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();
240
438
  }
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) })));
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;
250
499
  }
251
- static get watchers() { return {
252
- "tool": [{
253
- "handleToolChange": 0
254
- }]
255
- }; }
256
- };
257
- KritzelControlBrushConfig.style = kritzelControlBrushConfigCss();
500
+ }
258
501
 
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)}`;
502
+ const kritzelControlsCss = () => `:host{display:flex;flex-direction:column;user-select:none;max-width:calc(100vw - 16px)}: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:32px;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:-32px;width:32px;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}`;
260
503
 
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;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}`;
298
-
299
- const KritzelControls = class {
504
+ const KritzelControls = class {
300
505
  constructor(hostRef) {
301
506
  registerInstance(this, hostRef);
302
507
  this.isControlsReady = createEvent(this, "isControlsReady");
@@ -314,9 +519,21 @@ const KritzelControls = class {
314
519
  openSubMenuControl = null;
315
520
  canScrollLeft = false;
316
521
  canScrollRight = false;
522
+ displayValues = null;
317
523
  handleDocumentClick(event) {
318
- const element = event.target;
319
- if (!this.kritzelEngine || element.closest('.kritzel-tooltip')) {
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) {
320
537
  return;
321
538
  }
322
539
  this.isTooltipVisible = false;
@@ -331,6 +548,14 @@ const KritzelControls = class {
331
548
  }
332
549
  async handleActiveToolChange(event) {
333
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
+ }
334
559
  }
335
560
  async closeTooltip() {
336
561
  this.isTooltipVisible = false;
@@ -344,6 +569,47 @@ const KritzelControls = class {
344
569
  get activeToolAsBrushTool() {
345
570
  return this.activeControl?.tool;
346
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
+ }
347
613
  async componentWillLoad() {
348
614
  await this.initializeEngine();
349
615
  await this.initializeTools();
@@ -378,6 +644,7 @@ const KritzelControls = class {
378
644
  if (c.type === 'tool' && c.isDefault && c.tool) {
379
645
  await this.kritzelEngine.changeActiveTool(c.tool);
380
646
  this.activeControl = c;
647
+ this.updateDisplayValues(c.tool);
381
648
  }
382
649
  if (c.type === 'config') {
383
650
  if (this.firstConfig === null) {
@@ -392,6 +659,7 @@ const KritzelControls = class {
392
659
  async handleControlClick(control) {
393
660
  this.activeControl = control;
394
661
  if (this.activeControl.type === 'tool') {
662
+ this.updateDisplayValues(this.activeControl.tool);
395
663
  await this.kritzelEngine.changeActiveTool(this.activeControl.tool);
396
664
  }
397
665
  }
@@ -456,17 +724,20 @@ const KritzelControls = class {
456
724
  }
457
725
  render() {
458
726
  const hasConfigUI = this.activeControl?.tool instanceof KritzelBrushTool ||
459
- this.activeControl?.tool instanceof KritzelTextTool;
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());
460
731
  // Separate tool controls from config control
461
732
  const toolControls = this.controls.filter(c => c.type === 'tool');
462
733
  const configControl = this.controls.find(c => c.type === 'config' && c.name === this.firstConfig?.name);
463
- return (h(Host, { key: '78858516fdd1ccec007c9c8ddfc846d7907df664', class: {
734
+ return (h(Host, { key: 'db2a043a2a32d10d7f27c01123da63115781941c', class: {
464
735
  mobile: this.isTouchDevice,
465
- } }, this.isUtilityPanelVisible && (h("kritzel-utility-panel", { key: 'f24a6dc28e86a543a6e9d6ed2d3a5ca552eb7c48', style: {
736
+ } }, this.isUtilityPanelVisible && (h("kritzel-utility-panel", { key: '09104351c9f178b8d0dbc0636cf9cc230b2bca53', style: {
466
737
  position: 'absolute',
467
738
  bottom: '56px',
468
739
  left: '12px',
469
- }, undoState: this.undoState, onUndo: () => this.kritzelEngine?.undo(), onRedo: () => this.kritzelEngine?.redo(), onDelete: () => this.kritzelEngine?.delete() })), h("div", { key: '50dfa80ac8f76a2a00f3fa171a3d6d8503fb0857', class: "kritzel-controls" }, h("div", { key: '75230491b29899e3e08ecf7cf0adae274bd34728', class: { 'scroll-indicator-left': true, 'visible': this.canScrollLeft } }), h("div", { key: 'be5939db03ffe6bb72c38c1c753963f120bf9c58', class: "kritzel-tools-scroll", ref: el => {
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 => {
470
741
  this.toolsScrollRef = el;
471
742
  // Update indicators when ref is set
472
743
  if (el)
@@ -496,19 +767,19 @@ const KritzelControls = class {
496
767
  'kritzel-control': true,
497
768
  'selected': this.activeControl?.name === control?.name,
498
769
  }, key: control.name, onClick: _event => this.handleControlClick?.(control) }, h("kritzel-icon", { name: control.icon })));
499
- })), h("div", { key: '27aa7dd0f1a93a435eebc78c8abe6bc4c8b578f0', class: { 'scroll-indicator-right': true, 'visible': this.canScrollRight } }), configControl && this.activeControl && (h("div", { class: {
770
+ })), h("div", { key: '5f76128a603b02f7e92241453b2bc4045b517438', class: { 'scroll-indicator-right': true, 'visible': this.canScrollRight && !(configControl && this.activeControl && hasConfigUI) } }), configControl && this.activeControl && (h("div", { class: {
500
771
  'kritzel-config-container': true,
501
772
  'visible': hasConfigUI,
502
- }, key: configControl.name }, h("div", { key: '68c28268a98d4cc3bf949acbdea50ed2ec83c0db', class: "config-gradient-left" }), h("kritzel-tooltip", { key: '76af8159e08e78b32ab6798ef408e9246e77afbf', ref: el => (this.tooltipRef = el), isVisible: this.isTooltipVisible, anchorElement: this.host.shadowRoot?.querySelector('.kritzel-config-container'), onTooltipClosed: () => this.handleTooltipClosed() }, h("div", { key: '32cce44dd99f5bdbc730a66997af6930e8da4110', style: { width: '294px', height: '100%' } }, this.activeControl.name === 'brush' && (h("kritzel-control-brush-config", { key: 'da8ce6b563e276cd1566f31e96146e58b3cfa21f', tool: this.activeToolAsBrushTool, onToolChange: event => this.handleToolChange?.(event) })), this.activeControl.name === 'text' && (h("kritzel-control-text-config", { key: 'f7f9d55e52feba674521d5f8a20d4e7f62b14347', tool: this.activeToolAsTextTool, onToolChange: event => this.handleToolChange?.(event) })))), h("div", { key: '59082cc78fabaf11468c41c5333ebc21f9e491c1', tabIndex: hasConfigUI ? 0 : -1, class: "kritzel-config", onClick: event => this.handleConfigClick?.(event), onKeyDown: event => {
773
+ }, key: configControl.name }, h("div", { key: 'dc3903a6631e85c95ed62e23aec93feae2c46c55', class: "config-gradient-left" }), h("kritzel-tooltip", { key: '360a0a16a6aab116d3cd641b9988a63fad8a2e32', ref: el => (this.tooltipRef = el), isVisible: this.isTooltipVisible, anchorElement: this.host.shadowRoot?.querySelector('.kritzel-config-container'), onTooltipClosed: () => this.handleTooltipClosed() }, h("kritzel-tool-config", { key: '9c77db55899b52706ceb0f2c49bf3341c28b663a', tool: this.activeControl.tool, onToolChange: event => this.handleToolChange?.(event), onDisplayValuesChange: this.handleDisplayValuesChange, style: { width: '100%', height: '100%' } })), h("div", { key: 'e9b3a9ae86d9117d194d67cab55771f7322947b0', tabIndex: hasConfigUI ? 0 : -1, class: "kritzel-config", onClick: event => this.handleConfigClick?.(event), onKeyDown: event => {
503
774
  if (event.key === 'Enter') {
504
775
  this.handleConfigClick?.(event);
505
776
  }
506
777
  }, style: {
507
778
  cursor: 'pointer',
508
- } }, this.activeControl.tool instanceof KritzelBrushTool && (h("div", { key: 'd77c688e9f92293e8a7e63ad63483552479a96ef', class: "color-container" }, h("kritzel-color", { key: '42272e42b004f8de4711032f47c5ac2b2724953f', value: this.activeToolAsBrushTool?.color, size: this.activeToolAsBrushTool?.size, style: {
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: {
509
780
  borderRadius: '50%',
510
781
  border: 'none',
511
- } }))), this.activeControl.tool instanceof KritzelTextTool && (h("div", { key: '6f9d8bc06a57717c3a683f20610395f7ea4df48e', class: "font-container" }, h("kritzel-font", { key: '6079881df1283fd176b223506deb9ac5ee9c81e3', fontFamily: this.activeToolAsTextTool?.fontFamily, size: this.activeToolAsTextTool?.fontSize, color: this.activeToolAsTextTool?.fontColor })))))))));
782
+ } })))))))));
512
783
  }
513
784
  static get assetsDirs() { return ["../assets"]; }
514
785
  };
@@ -582,7 +853,7 @@ const KritzelCursorTrail = class {
582
853
  }
583
854
  }
584
855
  render() {
585
- return (h(Host, { key: '556238ffd7eeda2d400039333a37853ebfcca1b6' }, this.cursorTrailPoints.length > 1 && (h("svg", { key: 'a3f451cc9f142f018d0025eb7a68c1bdff5fc0d9', class: "cursor-trail-svg", xmlns: "http://www.w3.org/2000/svg", style: {
856
+ return (h(Host, { key: '5bb40688111e544ec102739c3d606ef34273fbab' }, this.cursorTrailPoints.length > 1 && (h("svg", { key: '91782bcfaae5d97d534a3e44535e85ed28f960b5', class: "cursor-trail-svg", xmlns: "http://www.w3.org/2000/svg", style: {
586
857
  position: 'absolute',
587
858
  left: '0',
588
859
  top: '0',
@@ -787,636 +1058,71 @@ const KritzelDropdown = class {
787
1058
  handleOptionMouseEnter = (index) => {
788
1059
  this.focusedIndex = index;
789
1060
  };
790
- evaluateSuffixContent = () => {
791
- if (this.suffixSlotElement) {
792
- const newHasContent = this.suffixSlotElement.assignedNodes({ flatten: true }).length > 0;
793
- if (this.hasSuffixContent !== newHasContent) {
794
- this.hasSuffixContent = newHasContent;
795
- }
796
- }
797
- else if (this.hasSuffixContent !== false) {
798
- this.hasSuffixContent = false;
799
- }
800
- };
801
- evaluatePrefixContent = () => {
802
- if (this.prefixSlotElement) {
803
- const newHasContent = this.prefixSlotElement.assignedNodes({ flatten: true }).length > 0;
804
- if (this.hasPrefixContent !== newHasContent) {
805
- this.hasPrefixContent = newHasContent;
806
- }
807
- }
808
- else if (this.hasPrefixContent !== false) {
809
- this.hasPrefixContent = false;
810
- }
811
- };
812
- getSelectedLabel() {
813
- const selectedOption = this.options.find(opt => opt.value === this.internalValue);
814
- return selectedOption?.label ?? '';
815
- }
816
- getSelectedStyle() {
817
- const selectedOption = this.options.find(opt => opt.value === this.internalValue);
818
- return selectedOption?.style;
819
- }
820
- render() {
821
- const triggerClasses = {
822
- 'dropdown-trigger': true,
823
- 'has-suffix-border': this.hasSuffixContent,
824
- 'has-prefix-border': this.hasPrefixContent,
825
- 'is-open': this.isOpen,
826
- 'open-up': this.openDirection === 'up',
827
- };
828
- const menuClasses = {
829
- 'dropdown-menu': true,
830
- 'is-open': this.isOpen,
831
- 'open-up': this.openDirection === 'up',
832
- 'open-down': this.openDirection === 'down',
833
- };
834
- 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) => {
835
- const isSelected = option.value === this.internalValue;
836
- const isFocused = index === this.focusedIndex;
837
- const optionClasses = {
838
- 'dropdown-option': true,
839
- 'is-selected': isSelected,
840
- 'is-focused': isFocused,
841
- };
842
- 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" }))))));
843
- })))));
844
- }
845
- static get watchers() { return {
846
- "options": [{
847
- "optionsChanged": 0
848
- }],
849
- "value": [{
850
- "externalValueChanged": 0
851
- }]
852
- }; }
853
- };
854
- KritzelDropdown.style = kritzelDropdownCss();
855
-
856
- var ShapeType;
857
- (function (ShapeType) {
858
- ShapeType["Rectangle"] = "rectangle";
859
- ShapeType["Ellipse"] = "ellipse";
860
- ShapeType["Triangle"] = "triangle";
861
- })(ShapeType || (ShapeType = {}));
862
-
863
- class KritzelShape extends KritzelBaseObject {
864
- __class__ = 'KritzelShape';
865
- shapeType = ShapeType.Rectangle;
866
- fillColor = 'transparent';
867
- strokeColor = '#000000';
868
- strokeWidth = 4;
869
- fontFamily = 'Arial';
870
- fontSize = 16;
871
- fontColor = '#000000';
872
- /** Screen-space x coordinate of the shape's top-left corner (like Path.x) */
873
- x = 0;
874
- /** Screen-space y coordinate of the shape's top-left corner (like Path.y) */
875
- y = 0;
876
- scale = 1;
877
- scaleFactor = 1;
878
- isDebugInfoVisible = true;
879
- isEditable = true;
880
- isEditing = false;
881
- editor = null;
882
- content = null;
883
- _schema = new Schema({
884
- nodes: addListNodes(schema.spec.nodes, 'paragraph block*', 'block'),
885
- marks: schema.spec.marks,
886
- });
887
- uneditedObject = null;
888
- /**
889
- * Returns the viewBox for the shape's SVG, using screen-space coordinates.
890
- * This follows the same pattern as KritzelPath.viewBox.
891
- */
892
- get viewBox() {
893
- return `${this.x} ${this.y} ${this.width} ${this.height}`;
894
- }
895
- constructor(config) {
896
- super();
897
- if (config) {
898
- this.x = config.x ?? 0;
899
- this.y = config.y ?? 0;
900
- this.translateX = config.translateX ?? 0;
901
- this.translateY = config.translateY ?? 0;
902
- this.width = config.width ?? 100;
903
- this.height = config.height ?? 100;
904
- this.shapeType = config.shapeType ?? ShapeType.Rectangle;
905
- this.fillColor = config.fillColor ?? 'transparent';
906
- this.strokeColor = config.strokeColor ?? '#000000';
907
- this.strokeWidth = config.strokeWidth ?? 4;
908
- this.fontSize = config.fontSize ?? 16;
909
- this.fontFamily = config.fontFamily ?? 'Arial';
910
- this.fontColor = config.fontColor ?? '#000000';
911
- this.scale = config.scale ?? 1;
912
- this.scaleFactor = config.scaleX ?? 1;
913
- }
914
- }
915
- /**
916
- * Creates a new KritzelShape with screen-space coordinates.
917
- * Following the same pattern as KritzelPath.create():
918
- * - x, y are screen-space coordinates of the shape's top-left corner
919
- * - translateX, translateY should be set to -viewportTranslateX, -viewportTranslateY
920
- * - width, height are in screen-space
921
- * - scale is the viewport scale at creation time
922
- */
923
- static create(core, config) {
924
- const object = new KritzelShape();
925
- object._core = core;
926
- object.id = object.generateId();
927
- object.workspaceId = core.store.state.activeWorkspace.id;
928
- object.x = config?.x ?? 0;
929
- object.y = config?.y ?? 0;
930
- object.translateX = config?.translateX ?? 0;
931
- object.translateY = config?.translateY ?? 0;
932
- object.width = config?.width ?? 100;
933
- object.height = config?.height ?? 100;
934
- object.shapeType = config?.shapeType ?? ShapeType.Rectangle;
935
- object.fillColor = config?.fillColor ?? 'transparent';
936
- object.strokeColor = config?.strokeColor ?? '#000000';
937
- object.strokeWidth = config?.strokeWidth ?? 4;
938
- object.fontSize = config?.fontSize ?? 16;
939
- object.fontFamily = config?.fontFamily ?? 'Arial';
940
- object.fontColor = config?.fontColor ?? '#000000';
941
- object.backgroundColor = 'transparent';
942
- object.scaleFactor = 1;
943
- object.scale = core.store.state.scale;
944
- object.zIndex = core.store.currentZIndex;
945
- object.editor = object.createEditor();
946
- // Compute world-space translateX/Y from screen-space coordinates
947
- // This follows the same pattern as KritzelPath.updateDimensions()
948
- object.updateDimensions();
949
- return object;
950
- }
951
- /**
952
- * Updates the translateX/Y to world coordinates based on screen-space x, y.
953
- * This follows the same pattern as KritzelPath.updateDimensions().
954
- *
955
- * The formula: translateX = (x + initialTranslateX) / scale
956
- * where initialTranslateX was -viewportTranslateX
957
- *
958
- * This converts screen-space position to world coordinates.
959
- */
960
- updateDimensions() {
961
- this.translateX = (this.x + this.translateX) / this.scale;
962
- this.translateY = (this.y + this.translateY) / this.scale;
963
- }
964
- mount(element) {
965
- if (element === null || this.isInViewport() === false) {
966
- return;
967
- }
968
- if (this.isMounted && this.elementRef === element && this.editor.dom.parentElement === element) {
969
- return;
970
- }
971
- this.elementRef = element;
972
- this.isMounted = true;
973
- }
974
- mountTextEditor(element) {
975
- if (element === null) {
976
- return;
977
- }
978
- if (this.editor.dom.parentElement === element) {
979
- return;
980
- }
981
- element.style.fontFamily = this.fontFamily;
982
- element.style.fontSize = `${this.fontSize}pt`;
983
- element.style.color = this.fontColor;
984
- element.style.whiteSpace = 'pre-wrap';
985
- element.style.wordWrap = 'break-word';
986
- element.innerHTML = '';
987
- element.appendChild(this.editor.dom);
988
- }
989
- createEditor() {
990
- const doc = this._schema.node('doc', null, [this._schema.node('paragraph')]);
991
- return new EditorView(null, {
992
- state: EditorState.create({
993
- doc: doc,
994
- plugins: [keymap(baseKeymap)],
995
- }),
996
- editable: () => false,
997
- dispatchTransaction: transaction => {
998
- const newState = this.editor.state.apply(transaction);
999
- this.editor.updateState(newState);
1000
- if (transaction.docChanged) {
1001
- this.content = newState.doc.toJSON();
1002
- if (!transaction.getMeta('fromRemote')) {
1003
- this._core.store.state.objects.update(this, { temporary: true });
1004
- }
1005
- }
1006
- },
1007
- });
1008
- }
1009
- setContent(content) {
1010
- this.content = content;
1011
- if (this.editor && content) {
1012
- const newDoc = this.editor.state.schema.nodeFromJSON(content);
1013
- const tr = this.editor.state.tr.replaceWith(0, this.editor.state.doc.content.size, newDoc.content);
1014
- tr.setMeta('fromRemote', true);
1015
- this.editor.dispatch(tr);
1016
- }
1017
- }
1018
- resize(x, y, width, height) {
1019
- if (width <= 1 || height <= 1) {
1020
- return;
1021
- }
1022
- this.width = width;
1023
- this.height = height;
1024
- this.translateX = x;
1025
- this.translateY = y;
1026
- this._core.store.state.objects.update(this);
1027
- }
1028
- focus(coords) {
1029
- if (this.editor) {
1030
- const doc = this.editor.state.doc;
1031
- if (coords?.x && coords?.y) {
1032
- const pos = this.editor.posAtCoords({ left: coords.x, top: coords.y });
1033
- if (pos) {
1034
- this.editor.dispatch(this.editor.state.tr.setSelection(TextSelection.create(doc, pos.pos)));
1035
- this.editor.focus();
1036
- if (KritzelDevicesHelper.isIOS()) {
1037
- this.scrollIntoViewOnIOS();
1038
- }
1039
- return;
1040
- }
1041
- }
1042
- const end = Math.max(1, doc.content.size - 1);
1043
- this.editor.dispatch(this.editor.state.tr.setSelection(TextSelection.create(doc, end)));
1044
- this.editor.focus();
1045
- if (KritzelDevicesHelper.isIOS()) {
1046
- this.scrollIntoViewOnIOS();
1047
- }
1048
- }
1049
- }
1050
- scrollIntoViewOnIOS() {
1051
- setTimeout(() => {
1052
- if (this.editor && this.editor.dom) {
1053
- this.editor.dom.scrollIntoView({
1054
- behavior: 'smooth',
1055
- block: 'center',
1056
- inline: 'nearest',
1057
- });
1058
- }
1059
- }, 300);
1060
- }
1061
- edit(event) {
1062
- KritzelKeyboardHelper.disableInteractiveWidget();
1063
- this.uneditedObject = this.clone();
1064
- this._core.store.setState('activeTool', KritzelToolRegistry.getTool('shape'));
1065
- this.editor.setProps({ editable: () => true });
1066
- this.isEditing = true;
1067
- this._core.rerender();
1068
- this.focus({ x: event?.clientX, y: event?.clientY });
1069
- KritzelKeyboardHelper.enableInteractiveWidget();
1070
- }
1071
- save() {
1072
- this.content = this.editor.state.doc.toJSON();
1073
- this.editor.setProps({ editable: () => false });
1074
- this.editor.dom.blur();
1075
- this.isEditing = false;
1076
- this._core.store.state.objects.consolidateTemporaryItems();
1077
- this._core.store.state.objects.update(this);
1078
- this._core.engine.emitObjectsChange();
1079
- }
1080
- handlePointerDown(event) {
1081
- if (!this.isEditing) {
1082
- return;
1083
- }
1084
- event.stopPropagation();
1085
- }
1086
- handlePointerMove(event) {
1087
- if (!this.isEditing) {
1088
- return;
1089
- }
1090
- event.stopPropagation();
1091
- }
1092
- handlePointerUp(event) {
1093
- if (!this.isEditing) {
1094
- return;
1095
- }
1096
- event.stopPropagation();
1097
- }
1098
- copy() {
1099
- const copiedObject = super.copy();
1100
- copiedObject.editor = copiedObject.createEditor();
1101
- if (this.content) {
1102
- copiedObject.setContent(this.content);
1103
- }
1104
- return copiedObject;
1105
- }
1106
- serialize() {
1107
- const { _core, _elementRef, _schema, element, totalWidth, totalHeight, editor, uneditedObject, ...remainingProps } = this;
1108
- const clonedProps = structuredClone(remainingProps);
1109
- if (element && typeof element === 'object' && 'nodeType' in element && element.nodeType === 1) {
1110
- clonedProps.element = element.cloneNode(true);
1111
- }
1112
- return clonedProps;
1113
- }
1114
- deserialize(object) {
1115
- super.deserialize(object);
1116
- if (object.content) {
1117
- this.setContent(object.content);
1118
- }
1119
- return this;
1120
- }
1121
- /**
1122
- * Returns the clipping polygon for arrow intersection.
1123
- * For ellipse: returns a many-sided polygon approximation
1124
- * For triangle: returns the 3 corners
1125
- * For rectangle: returns null (uses default rotatedPolygon)
1126
- *
1127
- * Includes padding for half the stroke width so arrow heads don't overlap the stroke.
1128
- */
1129
- getClipPolygon() {
1130
- // Calculate world-space center and dimensions
1131
- const worldWidth = this.totalWidth / this.scale;
1132
- const worldHeight = this.totalHeight / this.scale;
1133
- const centerX = this.translateX + worldWidth / 2;
1134
- const centerY = this.translateY + worldHeight / 2;
1135
- // Add padding for stroke width so arrows don't overlap the stroke
1136
- const strokePadding = (this.strokeWidth / this.scale) / 2;
1137
- switch (this.shapeType) {
1138
- case ShapeType.Ellipse:
1139
- // Return a 32-segment polygon approximation of the ellipse
1140
- // Add stroke padding to radii
1141
- return KritzelGeometryHelper.getEllipsePolygonApproximation(centerX, centerY, worldWidth / 2 + strokePadding, worldHeight / 2 + strokePadding, 32, this.rotation);
1142
- case ShapeType.Triangle:
1143
- // Return the 3 corners of the triangle in world coordinates
1144
- // Triangle: top-center, bottom-right, bottom-left
1145
- // Expand each vertex outward from center by strokePadding
1146
- const expandVertex = (vx, vy) => {
1147
- const dx = vx - centerX;
1148
- const dy = vy - centerY;
1149
- const dist = Math.sqrt(dx * dx + dy * dy);
1150
- if (dist === 0)
1151
- return { x: vx, y: vy };
1152
- const scale = (dist + strokePadding) / dist;
1153
- return {
1154
- x: centerX + dx * scale,
1155
- y: centerY + dy * scale
1156
- };
1157
- };
1158
- const topX = this.translateX + worldWidth / 2;
1159
- const topY = this.translateY;
1160
- const bottomLeftX = this.translateX;
1161
- const bottomLeftY = this.translateY + worldHeight;
1162
- const bottomRightX = this.translateX + worldWidth;
1163
- const bottomRightY = this.translateY + worldHeight;
1164
- const expandedTop = expandVertex(topX, topY);
1165
- const expandedBottomRight = expandVertex(bottomRightX, bottomRightY);
1166
- const expandedBottomLeft = expandVertex(bottomLeftX, bottomLeftY);
1167
- // Apply rotation around center if rotated
1168
- if (this.rotation !== 0) {
1169
- const cos = Math.cos(this.rotation);
1170
- const sin = Math.sin(this.rotation);
1171
- const rotate = (p) => {
1172
- const dx = p.x - centerX;
1173
- const dy = p.y - centerY;
1174
- return {
1175
- x: centerX + dx * cos - dy * sin,
1176
- y: centerY + dx * sin + dy * cos
1177
- };
1178
- };
1179
- return [
1180
- rotate(expandedTop),
1181
- rotate(expandedBottomRight),
1182
- rotate(expandedBottomLeft)
1183
- ];
1184
- }
1185
- return [expandedTop, expandedBottomRight, expandedBottomLeft];
1186
- case ShapeType.Rectangle:
1187
- default:
1188
- // For rectangles, return null to use the default rotatedPolygon
1189
- return null;
1190
- }
1191
- }
1192
- /**
1193
- * Returns the SVG path for rendering the shape.
1194
- * The path uses screen-space coordinates relative to (x, y).
1195
- */
1196
- getSvgPath() {
1197
- const w = this.width;
1198
- const h = this.height;
1199
- switch (this.shapeType) {
1200
- case ShapeType.Rectangle:
1201
- 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`;
1202
- case ShapeType.Ellipse:
1203
- const cx = this.x + w / 2;
1204
- const cy = this.y + h / 2;
1205
- const rx = w / 2;
1206
- const ry = h / 2;
1207
- return `M ${cx - rx} ${cy} A ${rx} ${ry} 0 1 0 ${cx + rx} ${cy} A ${rx} ${ry} 0 1 0 ${cx - rx} ${cy}`;
1208
- case ShapeType.Triangle:
1209
- const topX = this.x + w / 2;
1210
- const topY = this.y;
1211
- const bottomLeftX = this.x;
1212
- const bottomLeftY = this.y + h;
1213
- const bottomRightX = this.x + w;
1214
- const bottomRightY = this.y + h;
1215
- return `M ${topX} ${topY} L ${bottomRightX} ${bottomRightY} L ${bottomLeftX} ${bottomLeftY} Z`;
1216
- default:
1217
- 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`;
1218
- }
1219
- }
1220
- }
1221
-
1222
- class KritzelShapeTool extends KritzelBaseTool {
1223
- shapeType = ShapeType.Rectangle;
1224
- fillColor = 'transparent';
1225
- strokeColor = '#000000';
1226
- strokeWidth = 4;
1227
- fontFamily = 'Arial';
1228
- fontSize = 16;
1229
- fontColor = '#000000';
1230
- palette = [
1231
- '#000000',
1232
- '#FFFFFF',
1233
- '#FF0000',
1234
- '#00FF00',
1235
- '#0000FF',
1236
- '#FFFF00',
1237
- '#FF00FF',
1238
- '#00FFFF',
1239
- '#808080',
1240
- '#C0C0C0',
1241
- '#800000',
1242
- '#008000',
1243
- '#000080',
1244
- '#808000',
1245
- '#800080',
1246
- ];
1247
- startX = 0;
1248
- startY = 0;
1249
- isDrawing = false;
1250
- currentShape = null;
1251
- constructor(core) {
1252
- super(core);
1253
- }
1254
- handlePointerDown(event) {
1255
- if (event.cancelable) {
1256
- event.preventDefault();
1257
- }
1258
- if (event.pointerType === 'mouse') {
1259
- const path = event.composedPath().slice(1);
1260
- const objectElement = path.find(element => element.classList && element.classList.contains('object'));
1261
- const object = this._core.findObjectById(objectElement?.id);
1262
- const activeShape = this._core.store.activeShape;
1263
- if (activeShape === null && object instanceof KritzelShape) {
1264
- object.edit(event);
1265
- return;
1266
- }
1267
- if (activeShape !== null && object instanceof KritzelShape) {
1268
- activeShape.save();
1269
- object.edit(event);
1270
- return;
1271
- }
1272
- if (activeShape !== null && object instanceof KritzelShape === false) {
1273
- this._core.resetActiveShape();
1274
- this._core.store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
1275
- return;
1276
- }
1277
- if (KritzelEventHelper.isLeftClick(event) === false) {
1278
- return;
1279
- }
1280
- this.startDrawing(event.clientX, event.clientY);
1281
- }
1282
- if (event.pointerType === 'touch') {
1283
- const activePointers = Array.from(this._core.store.state.pointers.values());
1284
- const path = event.composedPath().slice(1);
1285
- const objectElement = path.find(element => element.classList && element.classList.contains('object'));
1286
- const object = this._core.findObjectById(objectElement?.id);
1287
- const activeShape = this._core.store.activeShape;
1288
- if (activeShape === null && object instanceof KritzelShape) {
1289
- object.edit(event);
1290
- return;
1291
- }
1292
- if (activeShape !== null && object instanceof KritzelShape) {
1293
- activeShape.save();
1294
- object.edit(event);
1295
- return;
1296
- }
1297
- if (activeShape !== null && object instanceof KritzelShape === false) {
1298
- this._core.resetActiveShape();
1299
- this._core.store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
1300
- return;
1301
- }
1302
- if (activePointers.length > 1) {
1303
- return;
1304
- }
1305
- const clientX = Math.round(activePointers[0].clientX);
1306
- const clientY = Math.round(activePointers[0].clientY);
1307
- this.startDrawing(clientX, clientY);
1308
- }
1309
- }
1310
- handlePointerMove(event) {
1311
- if (event.cancelable) {
1312
- event.preventDefault();
1313
- }
1314
- if (!this.isDrawing || !this.currentShape) {
1315
- return;
1316
- }
1317
- if (event.pointerType === 'mouse') {
1318
- this.updateShapeSize(event.clientX, event.clientY);
1319
- }
1320
- if (event.pointerType === 'touch') {
1321
- const activePointers = Array.from(this._core.store.state.pointers.values());
1322
- if (activePointers.length === 1) {
1323
- const clientX = Math.round(activePointers[0].clientX);
1324
- const clientY = Math.round(activePointers[0].clientY);
1325
- this.updateShapeSize(clientX, clientY);
1061
+ evaluateSuffixContent = () => {
1062
+ if (this.suffixSlotElement) {
1063
+ const newHasContent = this.suffixSlotElement.assignedNodes({ flatten: true }).length > 0;
1064
+ if (this.hasSuffixContent !== newHasContent) {
1065
+ this.hasSuffixContent = newHasContent;
1326
1066
  }
1327
1067
  }
1328
- }
1329
- handlePointerUp(event) {
1330
- if (event.cancelable) {
1331
- event.preventDefault();
1068
+ else if (this.hasSuffixContent !== false) {
1069
+ this.hasSuffixContent = false;
1332
1070
  }
1333
- if (!this.isDrawing || !this.currentShape) {
1334
- return;
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
+ }
1335
1078
  }
1336
- this.finishDrawing();
1337
- }
1338
- /**
1339
- * Start drawing a shape. Following the same pattern as LineTool/BrushTool:
1340
- * - Store screen coordinates for startX, startY
1341
- * - Set translateX/Y to -viewportTranslateX/Y (viewport offset)
1342
- * - Set x, y to the actual screen position
1343
- * - Let updateDimensions() convert to world coordinates
1344
- */
1345
- startDrawing(clientX, clientY) {
1346
- // Store screen coordinates (relative to host element)
1347
- this.startX = clientX - this._core.store.offsetX;
1348
- this.startY = clientY - this._core.store.offsetY;
1349
- this.isDrawing = true;
1350
- // Create shape using screen coordinates, following Path/Line pattern
1351
- this.currentShape = KritzelShape.create(this._core, {
1352
- x: this.startX,
1353
- y: this.startY,
1354
- translateX: -this._core.store.state.translateX,
1355
- translateY: -this._core.store.state.translateY,
1356
- width: 1,
1357
- height: 1,
1358
- shapeType: this.shapeType,
1359
- fillColor: this.fillColor,
1360
- strokeColor: this.strokeColor,
1361
- strokeWidth: this.strokeWidth,
1362
- fontSize: this.fontSize,
1363
- fontFamily: this.fontFamily,
1364
- fontColor: this.fontColor,
1365
- });
1366
- this._core.store.state.objects.insert(this.currentShape);
1367
- this._core.rerender();
1368
- }
1369
- /**
1370
- * Update shape size during drawing. Following the same pattern as LineTool:
1371
- * - Use screen coordinates directly
1372
- * - The shape's x, y, width, height are all in screen space
1373
- * - updateDimensions() handles conversion to world coordinates
1374
- */
1375
- updateShapeSize(clientX, clientY) {
1376
- if (!this.currentShape) {
1377
- return;
1079
+ else if (this.hasPrefixContent !== false) {
1080
+ this.hasPrefixContent = false;
1378
1081
  }
1379
- const currentX = clientX - this._core.store.offsetX;
1380
- const currentY = clientY - this._core.store.offsetY;
1381
- // Calculate bounding box in screen coordinates
1382
- const minX = Math.min(this.startX, currentX);
1383
- const minY = Math.min(this.startY, currentY);
1384
- const width = Math.abs(currentX - this.startX);
1385
- const height = Math.abs(currentY - this.startY);
1386
- // Update shape with screen coordinates
1387
- this.currentShape.x = minX;
1388
- this.currentShape.y = minY;
1389
- this.currentShape.width = Math.max(1, width);
1390
- this.currentShape.height = Math.max(1, height);
1391
- // Recalculate world-space translateX/Y
1392
- // Reset translateX/Y to initial value before updateDimensions
1393
- this.currentShape.translateX = -this._core.store.state.translateX;
1394
- this.currentShape.translateY = -this._core.store.state.translateY;
1395
- this.currentShape.updateDimensions();
1396
- 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 ?? '';
1397
1086
  }
1398
- finishDrawing() {
1399
- if (!this.currentShape) {
1400
- return;
1401
- }
1402
- // Remove shape if it's too small (likely an accidental click)
1403
- // Compare in screen space
1404
- if (this.currentShape.width < 10 && this.currentShape.height < 10) {
1405
- const shapeId = this.currentShape.id;
1406
- this._core.store.state.objects.remove(o => o.id === shapeId);
1407
- }
1408
- else {
1409
- this.currentShape.zIndex = this._core.store.currentZIndex;
1410
- this._core.store.state.objects.update(this.currentShape);
1411
- this._core.engine.emitObjectsChange();
1412
- this._core.selectObjects([this.currentShape]);
1413
- this._core.store.setState('activeTool', KritzelToolRegistry.getTool('selection'));
1414
- }
1415
- this.isDrawing = false;
1416
- this.currentShape = null;
1417
- this._core.rerender();
1087
+ getSelectedStyle() {
1088
+ const selectedOption = this.options.find(opt => opt.value === this.internalValue);
1089
+ return selectedOption?.style;
1418
1090
  }
1419
- }
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();
1420
1126
 
1421
1127
  const DEFAULT_SHAPE_CONFIG = {
1422
1128
  shapeType: ShapeType.Rectangle,
@@ -1426,21 +1132,7 @@ const DEFAULT_SHAPE_CONFIG = {
1426
1132
  fontColor: '#000000',
1427
1133
  fontSize: 16,
1428
1134
  fontFamily: 'Arial',
1429
- palette: [
1430
- '#000000',
1431
- '#ff5252',
1432
- '#ffbc00',
1433
- '#00c853',
1434
- '#0000FF',
1435
- '#d500f9',
1436
- '#fafafa',
1437
- '#a52714',
1438
- '#ee8100',
1439
- '#558b2f',
1440
- '#01579b',
1441
- '#8e24aa',
1442
- '#90a4ae',
1443
- ],
1135
+ palette: [...DEFAULT_COLOR_PALETTE],
1444
1136
  };
1445
1137
 
1446
1138
  const ABSOLUTE_SCALE_MAX = 1000;
@@ -1702,7 +1394,7 @@ const KritzelEditor = class {
1702
1394
  }
1703
1395
  }
1704
1396
  render() {
1705
- return (h(Host, { key: 'dd67bea86f807f0ccd5905183e73713a015d6bee' }, h("kritzel-workspace-manager", { key: '557edc7e3a131d338be6df91698ba6923e7bc50e', workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), h("kritzel-engine", { key: '98969d0f2bb5a9a365885fb4765e0c04c1394caa', 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: '6092f393562af07643622c07d432f6100497aaf0', 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) })));
1397
+ return (h(Host, { key: '08dae992458f6440295e59a12934c76ad4f9931e' }, h("kritzel-workspace-manager", { key: '43a980a7aadbc3fef9f375c99f1577f771612835', workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), h("kritzel-engine", { key: '471133030308d915fb9fa1e8e818662e56d483db', 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: '7e7c7111e0629309c4bda9d94b95623dbe835f0f', 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) })));
1706
1398
  }
1707
1399
  static get watchers() { return {
1708
1400
  "isEngineReady": [{
@@ -20276,11 +19968,13 @@ class KritzelCore {
20276
19968
  this.removeSelectionGroup();
20277
19969
  this.removeSelectionBox();
20278
19970
  this._store.state.objects.insert(selectionGroup);
19971
+ this._kritzelEngine.triggerSelectionChange();
20279
19972
  }
20280
19973
  removeSelectionGroup() {
20281
19974
  const selectionGroup = this._store.selectionGroup;
20282
19975
  if (selectionGroup) {
20283
19976
  this._store.state.objects.remove(object => object.id === selectionGroup.id);
19977
+ this._kritzelEngine.triggerSelectionChange();
20284
19978
  }
20285
19979
  }
20286
19980
  removeSelectionBox() {
@@ -20822,11 +20516,15 @@ const KritzelEngine = class {
20822
20516
  }
20823
20517
  isEngineReady;
20824
20518
  activeToolChange;
20519
+ objectsSelectionChange;
20825
20520
  workspacesChange;
20826
20521
  longpress;
20827
20522
  objectsChange;
20828
20523
  undoStateChange;
20829
20524
  forceUpdate = 0;
20525
+ async triggerSelectionChange() {
20526
+ this.objectsSelectionChange.emit();
20527
+ }
20830
20528
  throttledWheel = lodashExports.throttle((ev) => {
20831
20529
  this.viewport.handleWheel(ev);
20832
20530
  this.core.store.state?.activeTool?.handleWheel(ev);
@@ -20942,6 +20640,9 @@ const KritzelEngine = class {
20942
20640
  return Promise.resolve(registeredTool);
20943
20641
  }
20944
20642
  async changeActiveTool(tool) {
20643
+ if (this.core.store.state.activeTool === tool) {
20644
+ return;
20645
+ }
20945
20646
  this.core.store.state.activeTool?.onDeactivate();
20946
20647
  this.core.store.setState('activeTool', tool);
20947
20648
  this.core.deselectAllObjects();
@@ -21084,6 +20785,7 @@ const KritzelEngine = class {
21084
20785
  registerInstance(this, hostRef);
21085
20786
  this.isEngineReady = createEvent(this, "isEngineReady");
21086
20787
  this.activeToolChange = createEvent(this, "activeToolChange");
20788
+ this.objectsSelectionChange = createEvent(this, "objectsSelectionChange");
21087
20789
  this.workspacesChange = createEvent(this, "workspacesChange");
21088
20790
  this.longpress = createEvent(this, "longpress");
21089
20791
  this.objectsChange = createEvent(this, "objectsChange");
@@ -21164,7 +20866,7 @@ const KritzelEngine = class {
21164
20866
  };
21165
20867
  const visibleObjects = this.core.store.state.objects.query(viewportBounds).sort((a, b) => a.zIndex - b.zIndex);
21166
20868
  this.core.cursorManager.applyCursor();
21167
- return (h(Host, { key: 'cf63f71e5ab763750f0857595a6b2d56e99b29fd' }, this.core.store.state.debugInfo.showViewportInfo && (h("div", { key: 'cf6d5221edb666692bbed086d1fa5bb57f591442', class: "debug-panel" }, h("div", { key: 'd1e94a59352063d08412c13bee8632b468229431' }, "ActiveWorkspaceId: ", this.core.store.state?.activeWorkspace?.id), h("div", { key: '0eeff49b2c3bd703ef3b0fa574a323822ecef8a3' }, "ActiveWorkspaceName: ", this.core.store.state?.activeWorkspace?.name), h("div", { key: '884aaab5f8c10a21541139cbc1c824a80233c7bb' }, "TranslateX: ", this.core.store.state?.translateX), h("div", { key: '6633c2b83830bc5091825b9c51af2aa82fbc935e' }, "TranslateY: ", this.core.store.state?.translateY), h("div", { key: '905bf21fed43acbada2e5d18dd9eb33979d368a4' }, "ViewportWidth: ", this.core.store.state?.viewportWidth), h("div", { key: 'd2abcda891791cee5386fe065de9b781c2db2e0a' }, "ViewportHeight: ", this.core.store.state?.viewportHeight), h("div", { key: '9f64a19ac4510a2eae4d605dfdbb9a855b001b19' }, "PointerCount: ", this.core.store.state.pointers.size), h("div", { key: '25634969756ec8505e2b169c4f8f77fa5260932a' }, "Scale: ", this.core.store.state?.scale), h("div", { key: '2aea36a0521a5e59154836da290e7c615e4dc36d' }, "ActiveTool: ", this.core.store.state?.activeTool?.name), h("div", { key: '599bafe7e87b23df191849ad23f56eea0009272f' }, "HasViewportChanged: ", this.core.store.state?.hasViewportChanged ? 'true' : 'false'), h("div", { key: 'd5e466d0b64b0f64a808dc8f08dba21530579a49' }, "IsEnabled: ", this.core.store.state?.isEnabled ? 'true' : 'false'), h("div", { key: '6143b384caa285cd850111b3d6d3fe95f3a468db' }, "IsScaling: ", this.core.store.state?.isScaling ? 'true' : 'false'), h("div", { key: '5695722e2e07e024fe1b5db1be22c890fa16b7d9' }, "IsPanning: ", this.core.store.state?.isPanning ? 'true' : 'false'), h("div", { key: '93c2d1a6669b397637d6918055fc14c96493cc65' }, "IsSelecting: ", this.isSelecting ? 'true' : 'false'), h("div", { key: '2245f5894f7460d9d31ee33125260334920c6847' }, "IsSelectionActive: ", this.isSelectionActive ? 'true' : 'false'), h("div", { key: '57fd33a984b7975198d87285658ec4de2824aa34' }, "IsResizeHandleSelected: ", this.core.store.state.isResizeHandleSelected ? 'true' : 'false'), h("div", { key: '257cc4badaa694f04c839ca68ee79d1b695a006b' }, "IsRotationHandleSelected: ", this.core.store.state.isRotationHandleSelected ? 'true' : 'false'), h("div", { key: 'c00f461af4e4b1523e7e5feccfb0abfc6d45f5b7' }, "IsRotationHandleHovered: ", this.core.store.state.isRotationHandleHovered ? 'true' : 'false'), h("div", { key: '3f1bd888dfa360153b930fc5e498ccb348879d81' }, "IsDrawing: ", this.core.store.state.isDrawing ? 'true' : 'false'), h("div", { key: '4b33ce03143d6f96e359bc0a21697a3788fa6d3e' }, "IsWriting: ", this.core.store.state.isWriting ? 'true' : 'false'), h("div", { key: 'd603a0a226357378889c87d1bda5dd194388a81c' }, "IsPointerDown: ", this.core.store.isPointerDown ? 'true' : 'false'), h("div", { key: 'e0cb4c098e14c44c7c4d96a35f75a609a5d83144' }, "PointerX: ", this.core.store.state?.pointerX), h("div", { key: 'd663eff93d7884aa36da56a46e06cb65f0b14c54' }, "PointerY: ", this.core.store.state?.pointerY), h("div", { key: 'fe44809fc10454d605bad012300e8a46a8f180c9' }, "SelectedObjects: ", this.core.store.selectionGroup?.objects.length || 0), h("div", { key: 'd69d570660f6ec9d37d842f24f61e534d4f349e1' }, "ViewportCenter: (", viewportCenterX.toFixed(2), ", ", viewportCenterY.toFixed(2), ")"))), h("div", { key: 'aa6674f91511007c52f7faba849dd82f206e20ed', id: "origin", class: "origin", style: {
20869
+ 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: {
21168
20870
  transform: `matrix(${this.core.store.state?.scale}, 0, 0, ${this.core.store.state?.scale}, ${this.core.store.state?.translateX}, ${this.core.store.state?.translateY})`,
21169
20871
  } }, visibleObjects?.map(object => {
21170
20872
  return (h("div", { key: object.id, style: {
@@ -21413,7 +21115,7 @@ const KritzelEngine = class {
21413
21115
  stroke: 'var(--kritzel-snap-indicator-stroke, #007bff)',
21414
21116
  strokeWidth: data.indicatorStrokeWidth,
21415
21117
  } }))));
21416
- })()), this.core.store.state.isContextMenuVisible && (h("kritzel-context-menu", { key: '95f98d34b26eca7124f973002c2689e9a90f6748', class: "context-menu", ref: el => (this.contextMenuElement = el), items: this.core.store.state.contextMenuItems, objects: this.core.store.selectionGroup?.objects || [], style: {
21118
+ })()), 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: {
21417
21119
  position: 'fixed',
21418
21120
  left: `${this.core.store.state.contextMenuX}px`,
21419
21121
  top: `${this.core.store.state.contextMenuY}px`,
@@ -21424,7 +21126,7 @@ const KritzelEngine = class {
21424
21126
  y: (-this.core.store.state.translateY + this.core.store.state.contextMenuY) / this.core.store.state.scale,
21425
21127
  }, this.core.store.selectionGroup?.objects);
21426
21128
  this.hideContextMenu();
21427
- }, onClose: () => this.hideContextMenu() })), this.core.store.state?.activeTool instanceof KritzelEraserTool && !this.core.store.state.isScaling && h("kritzel-cursor-trail", { key: '412f67f0a484b7f5e37a4e9fa25d9124c389f62b', core: this.core })));
21129
+ }, onClose: () => this.hideContextMenu() })), this.core.store.state?.activeTool instanceof KritzelEraserTool && !this.core.store.state.isScaling && h("kritzel-cursor-trail", { key: 'b86989f2a710324e420994f74bd8c4990cc52060', core: this.core })));
21428
21130
  }
21429
21131
  static get watchers() { return {
21430
21132
  "workspace": [{
@@ -21453,7 +21155,7 @@ const KritzelFont = class {
21453
21155
  size = 24;
21454
21156
  color = '#000000';
21455
21157
  render() {
21456
- return (h(Host, { key: '62d0314df8f62ef2cf21c17f548261b34611750f' }, h("div", { key: '269347c138aab38cb1f018e58db78cab8e087f13', class: "font-preview", style: {
21158
+ return (h(Host, { key: '96cdcbefb7747932e4dc174a1a4a952863a0da99' }, h("div", { key: '228479a564056c0a06db85bbdb07978fe17802a6', class: "font-preview", style: {
21457
21159
  fontFamily: this.fontFamily,
21458
21160
  fontSize: `${this.size}px`,
21459
21161
  color: this.color
@@ -21462,7 +21164,7 @@ const KritzelFont = class {
21462
21164
  };
21463
21165
  KritzelFont.style = kritzelFontCss();
21464
21166
 
21465
- const kritzelFontFamilyCss = () => `:host{display:flex;align-items:flex-start;gap:8px;padding:8px;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}`;
21167
+ 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}`;
21466
21168
 
21467
21169
  const KritzelFontFamily = class {
21468
21170
  constructor(hostRef) {
@@ -21505,7 +21207,7 @@ const KritzelFontFamily = class {
21505
21207
  };
21506
21208
  KritzelFontFamily.style = kritzelFontFamilyCss();
21507
21209
 
21508
- const kritzelFontSizeCss = () => `:host{display:flex;align-items:flex-start;gap:8px;padding:8px;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)}`;
21210
+ 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)}`;
21509
21211
 
21510
21212
  const KritzelFontSize = class {
21511
21213
  constructor(hostRef) {
@@ -21527,7 +21229,7 @@ const KritzelFontSize = class {
21527
21229
  }
21528
21230
  }
21529
21231
  render() {
21530
- return (h(Host, { key: 'b0ee1ab0eb5e1871f7726d4393aea59f63264ec5' }, this.sizes.map(size => (h("div", { tabIndex: 0, class: {
21232
+ return (h(Host, { key: 'd4c62d22c92b540f372120681da797acded5b6cb' }, this.sizes.map(size => (h("div", { tabIndex: 0, class: {
21531
21233
  'size-container': true,
21532
21234
  'selected': this.selectedSize === size,
21533
21235
  }, onClick: () => this.handleSizeClick(size), onKeyDown: event => this.handleKeyDown(event, size) }, h("kritzel-font", { fontFamily: this.fontFamily, size: size }))))));
@@ -21559,6 +21261,91 @@ const KritzelIcon = class {
21559
21261
  };
21560
21262
  KritzelIcon.style = kritzelIconCss();
21561
21263
 
21264
+ 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%}`;
21265
+
21266
+ const KritzelLineEndings = class {
21267
+ constructor(hostRef) {
21268
+ registerInstance(this, hostRef);
21269
+ this.valueChange = createEvent(this, "valueChange");
21270
+ }
21271
+ /** Available ending styles */
21272
+ styles = ['none', 'triangle'];
21273
+ /** Current line arrow configuration */
21274
+ value;
21275
+ /** Stroke color used for rendering the preview */
21276
+ strokeColor = '#000000';
21277
+ valueChange;
21278
+ getStartEnding() {
21279
+ if (!this.value?.start?.enabled)
21280
+ return 'none';
21281
+ return this.value.start.style ?? 'triangle';
21282
+ }
21283
+ getEndEnding() {
21284
+ if (!this.value?.end?.enabled)
21285
+ return 'none';
21286
+ return this.value.end.style ?? 'triangle';
21287
+ }
21288
+ handleStartChange(type) {
21289
+ const newValue = {
21290
+ ...this.value,
21291
+ start: type === 'none'
21292
+ ? { enabled: false }
21293
+ : { enabled: true, style: type },
21294
+ };
21295
+ this.value = newValue;
21296
+ this.valueChange.emit(newValue);
21297
+ }
21298
+ handleEndChange(type) {
21299
+ const newValue = {
21300
+ ...this.value,
21301
+ end: type === 'none'
21302
+ ? { enabled: false }
21303
+ : { enabled: true, style: type },
21304
+ };
21305
+ this.value = newValue;
21306
+ this.valueChange.emit(newValue);
21307
+ }
21308
+ getEndingPath(type) {
21309
+ switch (type) {
21310
+ case 'triangle':
21311
+ return 'M 0 0 L 10 5 L 0 10 Z';
21312
+ case 'open':
21313
+ return 'M 0 0 L 10 5 L 0 10';
21314
+ case 'diamond':
21315
+ return 'M 0 5 L 5 0 L 10 5 L 5 10 Z';
21316
+ case 'circle':
21317
+ return 'M 10 5 A 5 5 0 1 1 0 5 A 5 5 0 1 1 10 5 Z';
21318
+ default:
21319
+ return '';
21320
+ }
21321
+ }
21322
+ renderEndingIcon(type, isStart) {
21323
+ const color = '#000000';
21324
+ if (type === 'none') {
21325
+ 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" })));
21326
+ }
21327
+ const path = this.getEndingPath(type);
21328
+ const isOpenStyle = type === 'open';
21329
+ return (h("svg", { viewBox: "0 0 24 12", class: "ending-icon" }, isStart ? (
21330
+ // Start arrow points left
21331
+ 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)" })))) : (
21332
+ // End arrow points right
21333
+ 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" }))))));
21334
+ }
21335
+ render() {
21336
+ const startEnding = this.getStartEnding();
21337
+ const endEnding = this.getEndEnding();
21338
+ return (h(Host, { key: '424f7faa167fdf487bcf094f72b34488ba477c99' }, h("div", { key: '3c667e2fdba171599ce747b3489258bdbbf8ec8e', class: "endings-section" }, h("div", { key: '1502ec8094550c73cd6e7d21ab0110d1dc5fd035', class: "endings-row" }, this.styles.map(type => (h("button", { class: {
21339
+ 'ending-option': true,
21340
+ 'selected': startEnding === type,
21341
+ }, onClick: () => this.handleStartChange(type), title: type === 'none' ? 'No start arrow' : `${type} start arrow` }, this.renderEndingIcon(type, true)))))), h("div", { key: 'c62e785eb0c60fa00603796193fb77ecb2f3a8dd', class: "endings-section" }, h("div", { key: 'bb256da3a6a1a473a93aa70c12aa12a2ff34f8a3', class: "endings-row" }, this.styles.map(type => (h("button", { class: {
21342
+ 'ending-option': true,
21343
+ 'selected': endEnding === type,
21344
+ }, onClick: () => this.handleEndChange(type), title: type === 'none' ? 'No end arrow' : `${type} end arrow` }, this.renderEndingIcon(type, false))))))));
21345
+ }
21346
+ };
21347
+ KritzelLineEndings.style = kritzelLineEndingsCss();
21348
+
21562
21349
  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}`;
21563
21350
 
21564
21351
  const KritzelMenu = class {
@@ -21622,7 +21409,7 @@ const KritzelMenu = class {
21622
21409
  this.itemCloseChildMenu.emit(event.detail);
21623
21410
  };
21624
21411
  render() {
21625
- return (h(Host, { key: '3901d38f620a544be329e1a20b17b188a81295dc', tabIndex: 0, onClick: e => e.stopPropagation() }, this.openChildMenuItem && h("div", { key: '8804023760f43fa34c3ac3f1829439f6136112b9', 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 })))));
21412
+ 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 })))));
21626
21413
  }
21627
21414
  };
21628
21415
  KritzelMenu.style = kritzelMenuCss();
@@ -21723,12 +21510,12 @@ const KritzelMenuItem = class {
21723
21510
  ];
21724
21511
  }
21725
21512
  render() {
21726
- return (h(Host, { key: '3a8119288e14c4de188663910a58e0ba67b47614', tabIndex: this.item.isDisabled ? -1 : 0, class: {
21513
+ return (h(Host, { key: '59a53dc472dd624f78dd773eb20a8722720ed465', tabIndex: this.item.isDisabled ? -1 : 0, class: {
21727
21514
  'selected': this.item.isSelected,
21728
21515
  'editing': this.item.isEditing,
21729
21516
  'disabled': this.item.isDisabled,
21730
21517
  'child-open': this.item.isChildMenuOpen,
21731
- }, onClick: this.handleItemSelect }, h("div", { key: 'b5dadbff0a915fb032f4a22207683667363eba1d', class: "menu-item-overlay" }), this.item.isEditing ? this.renderEditMode() : this.renderViewMode()));
21518
+ }, onClick: this.handleItemSelect }, h("div", { key: '22665fedfa83e2483d97480a9c9e45da9d296319', class: "menu-item-overlay" }), this.item.isEditing ? this.renderEditMode() : this.renderViewMode()));
21732
21519
  }
21733
21520
  static get watchers() { return {
21734
21521
  "item": [{
@@ -21738,6 +21525,42 @@ const KritzelMenuItem = class {
21738
21525
  };
21739
21526
  KritzelMenuItem.style = kritzelMenuItemCss();
21740
21527
 
21528
+ 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))}`;
21529
+
21530
+ const KritzelOpacitySlider = class {
21531
+ constructor(hostRef) {
21532
+ registerInstance(this, hostRef);
21533
+ this.valueChange = createEvent(this, "valueChange");
21534
+ }
21535
+ /** Current opacity value (0 to 1) */
21536
+ value = 1;
21537
+ /** Minimum opacity value */
21538
+ min = 0;
21539
+ /** Maximum opacity value */
21540
+ max = 1;
21541
+ /** Step increment */
21542
+ step = 0.01;
21543
+ /** Color to display in the preview (optional) */
21544
+ previewColor = '#000000';
21545
+ valueChange;
21546
+ handleInput(event) {
21547
+ const input = event.target;
21548
+ const newValue = parseFloat(input.value);
21549
+ this.value = newValue;
21550
+ this.valueChange.emit(newValue);
21551
+ }
21552
+ getPercentage() {
21553
+ return Math.round(this.value * 100);
21554
+ }
21555
+ render() {
21556
+ const percentage = this.getPercentage();
21557
+ 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: {
21558
+ '--slider-progress': `${percentage}%`,
21559
+ } })))));
21560
+ }
21561
+ };
21562
+ KritzelOpacitySlider.style = kritzelOpacitySliderCss();
21563
+
21741
21564
  class KritzelHTMLHelper {
21742
21565
  static getNumericValueFromStyle(element, property) {
21743
21566
  const value = window.getComputedStyle(element).getPropertyValue(property);
@@ -21994,7 +21817,7 @@ const KritzelPortal = class {
21994
21817
  this.portal.style.left = `${left}px`;
21995
21818
  }
21996
21819
  render() {
21997
- return (h(Host, { key: '9706a815c6f49853983a0fdb68b097d62e65e90b', style: { display: this.anchor ? 'block' : 'none' } }, h("slot", { key: '1bd76deeb440cd25e3895dc8824f5200461e4ae0' })));
21820
+ return (h(Host, { key: 'c70a1f7c4b2801346fc7a711b44e951337f42f77', style: { display: this.anchor ? 'block' : 'none' } }, h("slot", { key: '654bd6dd3ec83d77984a500d505ed1f3c04a0c26' })));
21998
21821
  }
21999
21822
  static get watchers() { return {
22000
21823
  "anchor": [{
@@ -22003,6 +21826,40 @@ const KritzelPortal = class {
22003
21826
  }; }
22004
21827
  };
22005
21828
 
21829
+ 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%}`;
21830
+
21831
+ const KritzelShapeFill = class {
21832
+ constructor(hostRef) {
21833
+ registerInstance(this, hostRef);
21834
+ this.valueChange = createEvent(this, "valueChange");
21835
+ }
21836
+ /** Current fill type */
21837
+ value = 'transparent';
21838
+ valueChange;
21839
+ handleFillChange(type) {
21840
+ this.value = type;
21841
+ this.valueChange.emit(type);
21842
+ }
21843
+ renderFillIcon(type) {
21844
+ const strokeColor = '#000000';
21845
+ if (type === 'transparent') {
21846
+ 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" })));
21847
+ }
21848
+ // Filled
21849
+ 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" })));
21850
+ }
21851
+ render() {
21852
+ return (h(Host, { key: '0d0c051f7b8b8a7c586246bc9d74ed3c3885eb90' }, h("div", { key: 'c2411c4d070fcffff06f372c1e750415486f6a40', class: "fill-row" }, h("button", { key: 'b53097dce91b2f42a7511c4db923730fa089cb7f', class: {
21853
+ 'fill-option': true,
21854
+ 'selected': this.value === 'transparent',
21855
+ }, onClick: () => this.handleFillChange('transparent'), title: "Transparent background" }, this.renderFillIcon('transparent')), h("button", { key: '570424d81fc01a1a09e4efa5ff3918fc9a2c5451', class: {
21856
+ 'fill-option': true,
21857
+ 'selected': this.value === 'filled',
21858
+ }, onClick: () => this.handleFillChange('filled'), title: "Filled background" }, this.renderFillIcon('filled')))));
21859
+ }
21860
+ };
21861
+ KritzelShapeFill.style = kritzelShapeFillCss();
21862
+
22006
21863
  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}`;
22007
21864
 
22008
21865
  const KritzelSplitButton = class {
@@ -22096,12 +21953,12 @@ const KritzelSplitButton = class {
22096
21953
  this.menuScrollTop = event.target.scrollTop;
22097
21954
  };
22098
21955
  render() {
22099
- return (h(Host, { key: 'a5587085e47c4e33148f9d0817731bfa3aa804b6', class: { mobile: this.isTouchDevice } }, h("button", { key: 'd3815785bb0919e2385bc7b9b0812466ed2b45a3', class: "split-main-button", tabIndex: 0, onClick: this.handleButtonClick, disabled: this.mainButtonDisabled }, this.buttonIcon && h("kritzel-icon", { key: 'b3225e1966bd21e8d37590cb39c0922e46afdaa9', name: this.buttonIcon })), h("div", { key: '526a88ef833cae7d2c7749f2a4bd96bcd2210a56', class: "split-divider" }), h("button", { key: '2c3ee46806bc64edc1f89a97c5e76ec493822065', ref: el => (this.splitMenuButtonRef = el), class: "split-menu-button", tabIndex: 0, onClick: this.toggleMenu, disabled: this.menuButtonDisabled }, h("kritzel-icon", { key: 'c6204d8b14d8cefe9d6eff33af95b2a7ea9a6b7c', name: this.dropdownIcon })), h("kritzel-portal", { key: '07a5e9793484f79d9b4b1f9ae09503f762cb2580', anchor: this.anchorElement, offsetY: 4, onClose: this.closeMenu }, h("kritzel-menu", { key: '0cf7601fd43b846a69152f0fc6ab950ac108ebff', 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 }))));
21956
+ 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 }))));
22100
21957
  }
22101
21958
  };
22102
21959
  KritzelSplitButton.style = kritzelSplitButtonCss();
22103
21960
 
22104
- const kritzelStrokeSizeCss = () => `:host{display:flex;align-items:flex-start;gap:8px;padding:8px;box-sizing:border-box}.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)}`;
21961
+ 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)}`;
22105
21962
 
22106
21963
  const KritzelStrokeSize = class {
22107
21964
  constructor(hostRef) {
@@ -22116,15 +21973,215 @@ const KritzelStrokeSize = class {
22116
21973
  this.sizeChange.emit(size);
22117
21974
  }
22118
21975
  render() {
22119
- return (h(Host, { key: 'd204d14384367ca8847ad30cab9801788c8d8fac' }, this.sizes.map(size => (h("div", { tabIndex: 0, class: {
21976
+ return (h(Host, { key: '891f899a41844bba03305e3dd7cbf428d4471ff9' }, h("div", { key: '773a756d54d0632c9ea6b3aebb743abad2274244', class: "size-grid" }, this.sizes.map(size => (h("div", { tabIndex: 0, class: {
22120
21977
  'size-container': true,
22121
21978
  'selected': this.selectedSize === size,
22122
- }, onClick: () => this.handleSizeClick(size) }, h("kritzel-color", { value: '#000000', size: size }))))));
21979
+ }, onClick: () => this.handleSizeClick(size) }, h("kritzel-color", { value: '#000000', size: size })))))));
22123
21980
  }
22124
21981
  };
22125
21982
  KritzelStrokeSize.style = kritzelStrokeSizeCss();
22126
21983
 
22127
- 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, 8px);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))}`;
21984
+ 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%}`;
21985
+
21986
+ const KritzelToolConfig = class {
21987
+ constructor(hostRef) {
21988
+ registerInstance(this, hostRef);
21989
+ this.toolChange = createEvent(this, "toolChange");
21990
+ this.displayValuesChange = createEvent(this, "displayValuesChange");
21991
+ }
21992
+ tool;
21993
+ handleToolChange(newTool, oldTool) {
21994
+ const newConfig = KritzelToolConfigHelper.getToolConfig(newTool);
21995
+ // Maintain settings when switching between shape tools
21996
+ if (oldTool && newTool && newConfig?.type === 'shape') {
21997
+ const oldConfig = KritzelToolConfigHelper.getToolConfig(oldTool);
21998
+ if (oldConfig?.type === 'shape') {
21999
+ // Copy properties that should persist
22000
+ const propsToCopy = [
22001
+ newConfig.colorProperty, // strokeColor
22002
+ newConfig.sizeProperty, // strokeWidth
22003
+ newConfig.opacityProperty, // opacity
22004
+ 'fillColor' // shape specific
22005
+ ];
22006
+ propsToCopy.forEach(prop => {
22007
+ if (prop && oldTool[prop] !== undefined) {
22008
+ newTool[prop] = oldTool[prop];
22009
+ }
22010
+ });
22011
+ }
22012
+ }
22013
+ this.config = newConfig;
22014
+ if (this.config) {
22015
+ this.updatePalette();
22016
+ this.currentOpacity = newTool[this.config.opacityProperty] ?? 1;
22017
+ // Emit the values since they might have been updated from the old tool
22018
+ this.emitDisplayValues();
22019
+ }
22020
+ }
22021
+ isExpanded = false;
22022
+ toolChange;
22023
+ displayValuesChange;
22024
+ config;
22025
+ palette = [];
22026
+ currentOpacity = 1;
22027
+ updateTrigger = 0;
22028
+ handleSelectionChange() {
22029
+ if (this.tool instanceof KritzelSelectionTool) {
22030
+ this.config = KritzelToolConfigHelper.getToolConfig(this.tool);
22031
+ if (this.config) {
22032
+ this.updatePalette();
22033
+ this.currentOpacity = this.tool[this.config.opacityProperty] ?? 1;
22034
+ this.emitDisplayValues();
22035
+ }
22036
+ }
22037
+ }
22038
+ componentWillLoad() {
22039
+ this.config = KritzelToolConfigHelper.getToolConfig(this.tool);
22040
+ if (this.config) {
22041
+ this.updatePalette();
22042
+ this.currentOpacity = this.tool[this.config.opacityProperty] ?? 1;
22043
+ this.emitDisplayValues();
22044
+ }
22045
+ }
22046
+ emitDisplayValues() {
22047
+ if (!this.config)
22048
+ return;
22049
+ const color = this.tool[this.config.colorProperty];
22050
+ const opacity = this.currentOpacity;
22051
+ const size = this.tool[this.config.sizeProperty];
22052
+ const displayValues = {
22053
+ color: KritzelColorHelper.applyOpacity(color, opacity),
22054
+ size,
22055
+ };
22056
+ if (this.tool instanceof KritzelTextTool) {
22057
+ displayValues.fontFamily = this.tool.fontFamily;
22058
+ }
22059
+ this.displayValuesChange.emit(displayValues);
22060
+ }
22061
+ updatePalette() {
22062
+ if (!this.config)
22063
+ return;
22064
+ if (this.config.paletteSource === 'palettes') {
22065
+ // Brush tool has palettes[type]
22066
+ const brushTool = this.tool;
22067
+ this.palette = brushTool.palettes[brushTool.type] || [];
22068
+ }
22069
+ else if (this.config.paletteSource === 'palette') {
22070
+ // Line, Shape, Text tools have palette
22071
+ this.palette = this.tool.palette || [];
22072
+ }
22073
+ }
22074
+ handleToggleExpand = () => {
22075
+ this.isExpanded = !this.isExpanded;
22076
+ };
22077
+ handleColorChange = (event) => {
22078
+ this.tool[this.config.colorProperty] = event.detail;
22079
+ // Special handling for shape fill: when color (stroke) changes, update fill color if it's currently filled
22080
+ if (this.config.type === 'shape' || this.config.type === 'selection') {
22081
+ const tool = this.tool;
22082
+ if (tool.fillColor !== 'transparent') {
22083
+ tool.fillColor = event.detail;
22084
+ }
22085
+ }
22086
+ this.emitDisplayValues();
22087
+ this.toolChange.emit(this.tool);
22088
+ this.updateTrigger++;
22089
+ };
22090
+ handleSizeChange = (event) => {
22091
+ this.tool[this.config.sizeProperty] = event.detail;
22092
+ this.emitDisplayValues();
22093
+ this.toolChange.emit(this.tool);
22094
+ this.updateTrigger++;
22095
+ };
22096
+ handleOpacityChange = (event) => {
22097
+ this.tool[this.config.opacityProperty] = event.detail;
22098
+ this.currentOpacity = event.detail;
22099
+ this.emitDisplayValues();
22100
+ this.toolChange.emit(this.tool);
22101
+ };
22102
+ handlePropertyChange = (propertyName, value) => {
22103
+ // Special handling for shape fill
22104
+ if ((this.config.type === 'shape' || this.config.type === 'selection') && propertyName === 'fillColor') {
22105
+ const newFillColor = value === 'filled' ? this.tool[this.config.colorProperty] : 'transparent';
22106
+ this.tool.fillColor = newFillColor;
22107
+ // When switching to fill mode, also update stroke color to match
22108
+ if (value === 'filled') {
22109
+ this.tool[this.config.colorProperty] = newFillColor;
22110
+ }
22111
+ }
22112
+ // Special handling for brush type change
22113
+ else if (this.config.type === 'brush' && propertyName === 'type') {
22114
+ const brushTool = this.tool;
22115
+ brushTool.type = value;
22116
+ this.palette = brushTool.palettes[value];
22117
+ brushTool.color = this.palette[0];
22118
+ this.emitDisplayValues();
22119
+ }
22120
+ else {
22121
+ this.tool[propertyName] = value;
22122
+ // Emit display values for font family changes
22123
+ if (propertyName === 'fontFamily') {
22124
+ this.emitDisplayValues();
22125
+ }
22126
+ }
22127
+ this.toolChange.emit(this.tool);
22128
+ this.updateTrigger++;
22129
+ };
22130
+ getShapeFillValue() {
22131
+ const fillColor = this.tool.fillColor;
22132
+ return fillColor === 'transparent' ? 'transparent' : 'filled';
22133
+ }
22134
+ renderControl(control) {
22135
+ const value = this.tool[control.propertyName];
22136
+ switch (control.type) {
22137
+ case 'stroke-size':
22138
+ return (h("kritzel-stroke-size", { key: control.type, selectedSize: value, onSizeChange: this.handleSizeChange }));
22139
+ case 'font-size':
22140
+ return (h("kritzel-font-size", { key: control.type, selectedSize: value, fontFamily: this.tool.fontFamily, onSizeChange: this.handleSizeChange }));
22141
+ case 'line-endings':
22142
+ return (h("kritzel-line-endings", { key: control.type, value: value, strokeColor: this.tool[this.config.colorProperty], onValueChange: (event) => this.handlePropertyChange(control.propertyName, event.detail) }));
22143
+ case 'shape-fill':
22144
+ return (h("kritzel-shape-fill", { key: control.type, value: this.getShapeFillValue(), onValueChange: (event) => this.handlePropertyChange(control.propertyName, event.detail) }));
22145
+ case 'font-family':
22146
+ return (h("kritzel-font-family", { key: control.type, selectedFontFamily: value, onFontFamilyChange: (event) => this.handlePropertyChange(control.propertyName, event.detail) }));
22147
+ default:
22148
+ return null;
22149
+ }
22150
+ }
22151
+ render() {
22152
+ if (!this.config)
22153
+ return null;
22154
+ const shouldShowExpandButton = this.palette.length > 6 || this.config.type === 'text';
22155
+ // Separate size control from other controls
22156
+ const sizeControl = this.config.controls.find(c => c.type === 'stroke-size' || c.type === 'font-size');
22157
+ const otherControls = this.config.controls.filter(c => c.type !== 'stroke-size' && c.type !== 'font-size');
22158
+ return (h(Host, null, h("div", { style: {
22159
+ display: 'flex',
22160
+ flexDirection: 'row',
22161
+ gap: '8px',
22162
+ width: '100%',
22163
+ } }, h("div", { style: {
22164
+ display: 'flex',
22165
+ flexDirection: 'column',
22166
+ gap: '12px',
22167
+ flex: '1',
22168
+ } }, 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) => [
22169
+ h("div", { class: "divider" }),
22170
+ this.renderControl(control),
22171
+ ])), shouldShowExpandButton && (h("div", { style: {
22172
+ display: 'flex',
22173
+ alignItems: 'flex-start',
22174
+ } }, h("button", { class: "expand-toggle", onClick: this.handleToggleExpand, title: this.isExpanded ? 'Collapse' : 'Expand' }, h("kritzel-icon", { name: this.isExpanded ? 'chevron-up' : 'chevron-down' })))))));
22175
+ }
22176
+ static get watchers() { return {
22177
+ "tool": [{
22178
+ "handleToolChange": 0
22179
+ }]
22180
+ }; }
22181
+ };
22182
+ KritzelToolConfig.style = kritzelToolConfigCss();
22183
+
22184
+ 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))}`;
22128
22185
 
22129
22186
  const KritzelTooltip = class {
22130
22187
  constructor(hostRef) {
@@ -22141,8 +22198,10 @@ const KritzelTooltip = class {
22141
22198
  handleOutsideClick(event) {
22142
22199
  if (!this.isVisible)
22143
22200
  return;
22144
- const target = event.target;
22145
- if (!this.host.contains(target)) {
22201
+ // Check if click is inside the tooltip host or any of its shadow DOM content
22202
+ const path = event.composedPath();
22203
+ const isInsideTooltip = path.some(el => el === this.host);
22204
+ if (!isInsideTooltip) {
22146
22205
  this.tooltipClosed.emit();
22147
22206
  }
22148
22207
  }
@@ -22192,14 +22251,14 @@ const KritzelTooltip = class {
22192
22251
  }
22193
22252
  }
22194
22253
  render() {
22195
- return (h(Host, { key: 'c257f254b8ba6b95f251eac3136f5be282d23e30', style: {
22254
+ return (h(Host, { key: '104ad4a160e4f47454955696e5f0e7a28873c3f5', style: {
22196
22255
  position: 'fixed',
22197
22256
  zIndex: '9999',
22198
22257
  transition: 'opacity 0.3s ease-in-out, transform 0.3s ease-in-out',
22199
22258
  visibility: this.isVisible ? 'visible' : 'hidden',
22200
22259
  left: `${this.positionX}px`,
22201
22260
  bottom: `${this.positionY}px`,
22202
- } }, h("div", { key: '14f31dc995236a2309e2371ecef278a0e6374139', class: "tooltip-content", onClick: event => event.stopPropagation() }, h("slot", { key: '6dace4d6ed82878333f8771cf4670d53cea36873' }))));
22261
+ } }, h("div", { key: '283eec8d84ea29caefdb1f0c4f129c57d30bc133', class: "tooltip-content", onClick: event => event.stopPropagation(), onPointerDown: event => event.stopPropagation(), onMouseDown: event => event.stopPropagation() }, h("slot", { key: '1c6e2d9bcb69f8deec08b6c10384b4c7593babd3' }))));
22203
22262
  }
22204
22263
  };
22205
22264
  KritzelTooltip.style = kritzelTooltipCss();
@@ -22230,7 +22289,7 @@ const KritzelUtilityPanel = class {
22230
22289
  this.redo.emit();
22231
22290
  }
22232
22291
  render() {
22233
- return (h(Host, { key: 'e8a12bdde840301c5bd9448e2c6be1c3cd558c38' }, h("button", { key: '9ffc5db3ac9d31e6e66822ebcbd60bd60c413062', class: "utility-button", disabled: !this.undoState?.canUndo, onClick: event => this.handleUndo(event) }, h("kritzel-icon", { key: 'caec852e6f83132e46b3ef87c376f62a03554f6b', name: "undo" })), h("button", { key: '6b5eaebd6f1dcfa5fbb96719b8456647132c1415', class: "utility-button", disabled: !this.undoState?.canRedo, onClick: event => this.handleRedo(event) }, h("kritzel-icon", { key: 'bbb07b34186f3a2f1a586a629f0cca738ca924bf', name: "redo" })), h("div", { key: '5a80149b3231e23b1e16fd7f52c4b4b2a5108e75', class: "utility-separator" }), h("button", { key: 'b7d826a7e6667a3a8e28c11507bfc760dc9526e0', class: "utility-button" }, h("kritzel-icon", { key: 'c47c4acead03cee13c64045b817aa166f397ce90', name: "delete", onClick: () => this.delete.emit() }))));
22292
+ 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() }))));
22234
22293
  }
22235
22294
  };
22236
22295
  KritzelUtilityPanel.style = kritzelUtilityPanelCss();
@@ -22375,4 +22434,4 @@ const KritzelWorkspaceManager = class {
22375
22434
  };
22376
22435
  KritzelWorkspaceManager.style = kritzelWorkspaceManagerCss();
22377
22436
 
22378
- export { KritzelColor as kritzel_color, KritzelColorPalette as kritzel_color_palette, KritzelContextMenu as kritzel_context_menu, KritzelControlBrushConfig as kritzel_control_brush_config, KritzelControlTextConfig as kritzel_control_text_config, 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, KritzelMenu as kritzel_menu, KritzelMenuItem as kritzel_menu_item, KritzelPortal as kritzel_portal, KritzelSplitButton as kritzel_split_button, KritzelStrokeSize as kritzel_stroke_size, KritzelTooltip as kritzel_tooltip, KritzelUtilityPanel as kritzel_utility_panel, KritzelWorkspaceManager as kritzel_workspace_manager };
22437
+ 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 };