kritzel-stencil 0.3.46 → 0.4.1

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 (81) hide show
  1. package/dist/cjs/index.cjs.js +2 -1
  2. package/dist/cjs/kritzel-active-users_47.cjs.entry.js +249 -68
  3. package/dist/cjs/loader.cjs.js +1 -1
  4. package/dist/cjs/{schema.constants-fuAsi56H.js → schema.constants-IAt9YXDZ.js} +273 -32
  5. package/dist/cjs/stencil.cjs.js +1 -1
  6. package/dist/collection/classes/handlers/context-menu.handler.js +2 -3
  7. package/dist/collection/classes/managers/clipboard.manager.js +9 -3
  8. package/dist/collection/classes/objects/base-object.class.js +0 -1
  9. package/dist/collection/classes/objects/text.class.js +2 -1
  10. package/dist/collection/classes/registries/font-registry.class.js +161 -0
  11. package/dist/collection/classes/structures/object-map.structure.js +9 -0
  12. package/dist/collection/classes/tools/image-tool.class.js +19 -3
  13. package/dist/collection/classes/tools/text-tool.class.js +2 -0
  14. package/dist/collection/components/core/kritzel-awareness-cursors/kritzel-awareness-cursors.js +22 -7
  15. package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +138 -9
  16. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +58 -13
  17. package/dist/collection/components/shared/kritzel-font-family/kritzel-font-family.js +31 -22
  18. package/dist/collection/components/ui/kritzel-controls/kritzel-controls.js +10 -11
  19. package/dist/collection/components/ui/kritzel-tool-config/kritzel-tool-config.js +40 -5
  20. package/dist/collection/configs/default-text-tool.config.js +2 -0
  21. package/dist/collection/constants/text-tool-fonts.constants.js +18 -0
  22. package/dist/collection/constants/version.js +1 -1
  23. package/dist/collection/helpers/image-file.helper.js +6 -0
  24. package/dist/collection/index.js +2 -0
  25. package/dist/collection/interfaces/font.interface.js +1 -0
  26. package/dist/components/index.js +1 -1
  27. package/dist/components/kritzel-awareness-cursors.js +1 -1
  28. package/dist/components/kritzel-controls.js +1 -1
  29. package/dist/components/kritzel-cursor-trail.js +1 -1
  30. package/dist/components/kritzel-editor.js +1 -1
  31. package/dist/components/kritzel-engine.js +1 -1
  32. package/dist/components/kritzel-font-family.js +1 -1
  33. package/dist/components/kritzel-settings.js +1 -1
  34. package/dist/components/kritzel-tool-config.js +1 -1
  35. package/dist/components/p-BH4oJ7yX.js +9 -0
  36. package/dist/components/p-C38P-Vd0.js +1 -0
  37. package/dist/components/p-Cm33td2O.js +1 -0
  38. package/dist/components/{p-Bjy2t3_g.js → p-Co165PAZ.js} +1 -1
  39. package/dist/components/p-DJkKlUyZ.js +1 -0
  40. package/dist/components/p-JYj3Facr.js +1 -0
  41. package/dist/components/p-Ka7OWbnk.js +1 -0
  42. package/dist/components/p-djJSnjAX.js +1 -0
  43. package/dist/esm/index.js +2 -2
  44. package/dist/esm/kritzel-active-users_47.entry.js +249 -68
  45. package/dist/esm/loader.js +1 -1
  46. package/dist/esm/{schema.constants-Cv5-yM39.js → schema.constants-rIkxAcpB.js} +271 -33
  47. package/dist/esm/stencil.js +1 -1
  48. package/dist/stencil/index.esm.js +1 -1
  49. package/dist/stencil/p-966ca4b5.entry.js +9 -0
  50. package/dist/stencil/p-rIkxAcpB.js +1 -0
  51. package/dist/stencil/stencil.esm.js +1 -1
  52. package/dist/types/classes/managers/clipboard.manager.d.ts +1 -0
  53. package/dist/types/classes/objects/base-object.class.d.ts +0 -1
  54. package/dist/types/classes/registries/font-registry.class.d.ts +19 -0
  55. package/dist/types/classes/structures/object-map.structure.d.ts +2 -2
  56. package/dist/types/classes/tools/image-tool.class.d.ts +9 -2
  57. package/dist/types/classes/tools/text-tool.class.d.ts +3 -0
  58. package/dist/types/components/core/kritzel-awareness-cursors/kritzel-awareness-cursors.d.ts +2 -0
  59. package/dist/types/components/core/kritzel-editor/kritzel-editor.d.ts +22 -0
  60. package/dist/types/components/core/kritzel-engine/kritzel-engine.d.ts +10 -0
  61. package/dist/types/components/shared/kritzel-font-family/kritzel-font-family.d.ts +4 -0
  62. package/dist/types/components/ui/kritzel-tool-config/kritzel-tool-config.d.ts +1 -0
  63. package/dist/types/components.d.ts +20 -2
  64. package/dist/types/constants/text-tool-fonts.constants.d.ts +3 -0
  65. package/dist/types/constants/version.d.ts +1 -1
  66. package/dist/types/helpers/image-file.helper.d.ts +3 -0
  67. package/dist/types/index.d.ts +2 -0
  68. package/dist/types/interfaces/font.interface.d.ts +15 -0
  69. package/dist/types/interfaces/toolbar-control.interface.d.ts +2 -0
  70. package/package.json +1 -1
  71. package/dist/components/p-B4b6TDxp.js +0 -1
  72. package/dist/components/p-C2ocjA6D.js +0 -1
  73. package/dist/components/p-CwbZCXKh.js +0 -1
  74. package/dist/components/p-D2q_wTyG.js +0 -1
  75. package/dist/components/p-D8NvNMcU.js +0 -1
  76. package/dist/components/p-D8W6LE-c.js +0 -1
  77. package/dist/components/p-G9G9y5VE.js +0 -9
  78. package/dist/components/p-JhOYwUOj.js +0 -1
  79. package/dist/components/p-UEf2EN23.js +0 -1
  80. package/dist/stencil/p-56ea721b.entry.js +0 -9
  81. package/dist/stencil/p-Cv5-yM39.js +0 -1
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var index = require('./index-Xav9JFHg.js');
4
- var schema_constants = require('./schema.constants-fuAsi56H.js');
4
+ var schema_constants = require('./schema.constants-IAt9YXDZ.js');
5
5
  var Y = require('yjs');
6
6
  require('y-indexeddb');
7
7
  require('y-websocket');
@@ -196,23 +196,38 @@ const KritzelAwarenessCursors = class {
196
196
  objectVersion = 0;
197
197
  cleanupIntervalId;
198
198
  objectChangeRafId = null;
199
+ removeAwarenessChangeListener;
200
+ removeObjectsChangeListener;
199
201
  componentDidLoad() {
200
- this.core.store.objects?.onAwarenessChange(states => {
202
+ this.removeAwarenessChangeListener = this.core.store.objects?.onAwarenessChange(states => {
201
203
  this.handleAwarenessChange(states);
202
204
  });
203
- this.core.store.objects?.onObjectsChange(() => {
205
+ this.removeObjectsChangeListener = this.core.store.objects?.onObjectsChange(() => {
204
206
  this.handleRemoteObjectChange();
205
207
  });
206
208
  this.cleanupIntervalId = setInterval(() => {
207
209
  this.cleanupStaleCursors();
208
210
  }, CLEANUP_INTERVAL_MS);
211
+ if (this.cleanupIntervalId && typeof this.cleanupIntervalId.unref === 'function') {
212
+ this.cleanupIntervalId.unref();
213
+ }
209
214
  }
210
215
  disconnectedCallback() {
211
- if (this.cleanupIntervalId) {
212
- clearInterval(this.cleanupIntervalId);
216
+ if (this.removeAwarenessChangeListener) {
217
+ this.removeAwarenessChangeListener();
218
+ this.removeAwarenessChangeListener = undefined;
219
+ }
220
+ if (this.removeObjectsChangeListener) {
221
+ this.removeObjectsChangeListener();
222
+ this.removeObjectsChangeListener = undefined;
213
223
  }
214
- if (this.objectChangeRafId !== null) {
215
- cancelAnimationFrame(this.objectChangeRafId);
224
+ if (this.cleanupIntervalId && typeof globalThis.clearInterval === 'function') {
225
+ globalThis.clearInterval(this.cleanupIntervalId);
226
+ this.cleanupIntervalId = undefined;
227
+ }
228
+ if (this.objectChangeRafId !== null && typeof globalThis.cancelAnimationFrame === 'function') {
229
+ globalThis.cancelAnimationFrame(this.objectChangeRafId);
230
+ this.objectChangeRafId = null;
216
231
  }
217
232
  }
218
233
  handleAwarenessChange(states) {
@@ -370,7 +385,7 @@ const KritzelAwarenessCursors = class {
370
385
  }
371
386
  render() {
372
387
  const cursors = Array.from(this.remoteCursors.values());
373
- return (index.h(index.Host, { key: '5c695e3c5a012767b31bb1b756ef03e2a174f46e' }, cursors.map(remoteCursor => {
388
+ return (index.h(index.Host, { key: '9be6694250bafe011be27301d1c7a53fc7957657' }, cursors.map(remoteCursor => {
374
389
  if (!remoteCursor.cursor)
375
390
  return null;
376
391
  // When a remote user is actively drawing, derive cursor position from
@@ -993,8 +1008,9 @@ const KritzelControls = class {
993
1008
  this.closeTooltip();
994
1009
  }
995
1010
  handleSelectionChange() {
996
- if (this.activeControl?.tool instanceof schema_constants.KritzelSelectionTool) {
997
- this.updateDisplayValues(this.activeControl.tool);
1011
+ const tool = this.activeControl?.tool;
1012
+ if (tool && typeof tool !== 'function' && tool.toolType === 'selection') {
1013
+ this.updateDisplayValues(tool);
998
1014
  }
999
1015
  }
1000
1016
  async onControlsChange() {
@@ -1045,7 +1061,7 @@ const KritzelControls = class {
1045
1061
  color: schema_constants.KritzelColorHelper.applyOpacity(color, opacity, this.theme),
1046
1062
  size,
1047
1063
  };
1048
- if (tool instanceof schema_constants.KritzelTextTool) {
1064
+ if (tool.toolType === 'text') {
1049
1065
  displayValues.fontFamily = tool.fontFamily;
1050
1066
  }
1051
1067
  // Check for equality implementation to prevent unnecessary re-renders
@@ -1186,13 +1202,13 @@ const KritzelControls = class {
1186
1202
  // Separate tool controls from config control
1187
1203
  const toolControls = this.internalControls.filter(c => c.type === 'tool' || c.type === 'separator');
1188
1204
  const configControl = this.internalControls.find(c => c.type === 'config' && c.name === this.firstConfig?.name);
1189
- return (index.h(index.Host, { key: '5a23a0a1baa407097b18b9bc43f41186c0c333b2', style: { display: this.visible ? '' : 'none' }, class: {
1205
+ return (index.h(index.Host, { key: 'a526bd337a6b75933ec4be89c3edded0a9c39e7c', style: { display: this.visible ? '' : 'none' }, class: {
1190
1206
  mobile: this.isTouchDevice,
1191
- } }, this.isUtilityPanelVisible && (index.h("kritzel-utility-panel", { key: '6d3878904bd13266be79cef0e0d1ee55d760b3da', style: {
1207
+ } }, this.isUtilityPanelVisible && (index.h("kritzel-utility-panel", { key: '5314f067c5a22425690e3b6f26c836962ac528a2', style: {
1192
1208
  position: 'absolute',
1193
1209
  bottom: '56px',
1194
1210
  left: '12px',
1195
- }, undoState: this.undoState, terms: this.terms, onUndo: () => this.kritzelEngine?.undo(), onRedo: () => this.kritzelEngine?.redo(), onDelete: () => this.kritzelEngine?.delete() })), index.h("div", { key: '5e066964eba04ad9b0d1abf36f61b93464254f48', class: "kritzel-controls" }, index.h("div", { key: '76e49fd459e0a312837ec0b5e552355395b8814e', class: { 'scroll-indicator-left': true, 'visible': this.canScrollLeft } }), index.h("div", { key: 'd4cffe56418dae5c569a47fe2ffc3f810f221455', class: "kritzel-tools-scroll", ref: el => (this.toolsScrollRef = el), onScroll: this.handleToolsScroll }, toolControls.map(control => {
1211
+ }, undoState: this.undoState, terms: this.terms, onUndo: () => this.kritzelEngine?.undo(), onRedo: () => this.kritzelEngine?.redo(), onDelete: () => this.kritzelEngine?.delete() })), index.h("div", { key: '7cf0cd164d723b5901f54a6671395f63dd8bad29', class: "kritzel-controls" }, index.h("div", { key: 'b7169122686a0a67c37d96751291fc43f4c45e4a', class: { 'scroll-indicator-left': true, 'visible': this.canScrollLeft } }), index.h("div", { key: '6e3c4f30900e4722abdfaf3cfdc68cf1a07b9292', class: "kritzel-tools-scroll", ref: el => (this.toolsScrollRef = el), onScroll: this.handleToolsScroll }, toolControls.map(control => {
1196
1212
  // Check if this control has sub-options (split-button)
1197
1213
  if (control.subOptions?.length) {
1198
1214
  const selectedSubOption = this.getSelectedSubOption(control);
@@ -1222,10 +1238,10 @@ const KritzelControls = class {
1222
1238
  'kritzel-control': true,
1223
1239
  'selected': this.activeControl?.name === control?.name,
1224
1240
  }, key: control.name, "data-testid": `tool-${control.name}`, onClick: _event => this.handleControlClick?.(control), "aria-label": control.name.charAt(0).toUpperCase() + control.name.slice(1) }, index.h("kritzel-icon", { name: control.icon })));
1225
- })), index.h("div", { key: '49806e8e06b8756a097eeec53203a55586214a4a', class: { 'scroll-indicator-right': true, 'visible': this.canScrollRight && !(configControl && this.activeControl && hasConfigUI) } }), configControl && this.activeControl && (index.h("div", { class: {
1241
+ })), index.h("div", { key: 'bc8d79e0512f30fe150c6d2ac7f81206fc47c1a5', class: { 'scroll-indicator-right': true, 'visible': this.canScrollRight && !(configControl && this.activeControl && hasConfigUI) } }), configControl && this.activeControl && (index.h("div", { class: {
1226
1242
  'kritzel-config-container': true,
1227
1243
  'visible': hasConfigUI,
1228
- }, key: configControl.name }, index.h("div", { key: 'da0ec9cf776dee0872bbb7f0369a6a5a56ebb955', class: { 'config-gradient-left': true, 'visible': this.needsScrolling } }), index.h("kritzel-tooltip", { key: 'c848a63392d4ed9a30f467512421fbea3096d876', anchorElement: this.host.shadowRoot?.querySelector('.kritzel-config-container'), triggerElement: this.configTriggerRef }, index.h("kritzel-tool-config", { key: 'c7ed50fbdfbdab1847fb8c5c6e73d0e743b45706', tool: this.activeControl.tool, theme: this.theme, engine: this.kritzelEngine, terms: this.terms, onToolChange: event => this.handleToolChange?.(event), onDisplayValuesChange: this.handleDisplayValuesChange, style: { width: '100%', height: '100%' } })), index.h("div", { key: 'de6c9801d3e9e89674b60b1c4e270b8520014aae', tabIndex: hasConfigUI ? 0 : -1, class: "kritzel-config", "data-testid": "tool-config", ref: el => {
1244
+ }, key: configControl.name }, index.h("div", { key: '671431a9c388080fb917d4e8c596d17e92eaba08', class: { 'config-gradient-left': true, 'visible': this.needsScrolling } }), index.h("kritzel-tooltip", { key: '394e8e2c07b191b3fb93645d68d7eae67761167a', anchorElement: this.host.shadowRoot?.querySelector('.kritzel-config-container'), triggerElement: this.configTriggerRef }, index.h("kritzel-tool-config", { key: 'b8479fba2afdb51fe0ef965e18b1ae45ba8a7da6', tool: this.activeControl.tool, theme: this.theme, engine: this.kritzelEngine, terms: this.terms, onToolChange: event => this.handleToolChange?.(event), onDisplayValuesChange: this.handleDisplayValuesChange, style: { width: '100%', height: '100%' } })), index.h("div", { key: '8fac81d682dbdec6b5247154fd20d553dfe6f1a7', tabIndex: hasConfigUI ? 0 : -1, class: "kritzel-config", "data-testid": "tool-config", ref: el => {
1229
1245
  if (el)
1230
1246
  this.configTriggerRef = el;
1231
1247
  }, onKeyDown: event => {
@@ -1234,7 +1250,7 @@ const KritzelControls = class {
1234
1250
  }
1235
1251
  }, style: {
1236
1252
  cursor: 'pointer',
1237
- } }, this.displayValues && (index.h("div", { key: '140bbf567b0bbd2a2fe878536e93d8646a58b209', class: "color-container" }, index.h("kritzel-color", { key: 'eeb1d94fa41bbc177d39b4158ae3c4c1d692c0ec', value: this.displayValues.color, theme: this.theme, size: 18, style: {
1253
+ } }, this.displayValues && (index.h("div", { key: '6aa1daed9425d069c7d0405a04e65b4c4e88291f', class: "color-container" }, index.h("kritzel-color", { key: '7b54461769bf4aec3e39d1fbe21c015b7d7a85bb', value: this.displayValues.color, theme: this.theme, size: 18, style: {
1238
1254
  borderRadius: '50%',
1239
1255
  border: 'none',
1240
1256
  } })))))))));
@@ -2312,6 +2328,11 @@ const KritzelEditor = class {
2312
2328
  /** The locale used to resolve terms missing from the active locale. */
2313
2329
  fallbackLocale = 'en';
2314
2330
  customSvgIcons = {};
2331
+ /**
2332
+ * Registers fonts for runtime usage (for example custom object rendering).
2333
+ * Text-tool config tooltip options are controlled via controls[].config.availableFonts.
2334
+ */
2335
+ customFonts = {};
2315
2336
  isPanningEnabled = true;
2316
2337
  isZoomingEnabled = true;
2317
2338
  isControlsVisible = true;
@@ -2364,11 +2385,14 @@ const KritzelEditor = class {
2364
2385
  isEditorVisible = false;
2365
2386
  activeNotification;
2366
2387
  isNotificationDismissing = false;
2388
+ normalizedControls = [];
2367
2389
  notificationDismissTimeout;
2368
2390
  notificationDismissAnimationTimeout;
2369
2391
  notificationDisplayDurationMs = 5000;
2370
2392
  notificationDismissAnimationDurationMs = 180;
2371
2393
  isNotificationHovered = false;
2394
+ customFontsLoadVersion = 0;
2395
+ customFontsReady = Promise.resolve();
2372
2396
  onIsEngineReady(newValue) {
2373
2397
  if (newValue && this.isControlsReady) {
2374
2398
  this.checkIsReady();
@@ -2398,6 +2422,12 @@ const KritzelEditor = class {
2398
2422
  onActiveWorkspaceChange() {
2399
2423
  this.updateCurrentIsPublic();
2400
2424
  }
2425
+ onCustomFontsChange(newValue) {
2426
+ void this.registerCustomFonts(newValue);
2427
+ }
2428
+ onControlsChange(newValue) {
2429
+ this.normalizedControls = this.normalizeControls(newValue);
2430
+ }
2401
2431
  onActiveWorkspaceIdChange(newId) {
2402
2432
  // If no ID is provided, do nothing (allows other logic to control activeWorkspace)
2403
2433
  if (!newId) {
@@ -2671,9 +2701,27 @@ const KritzelEditor = class {
2671
2701
  loginDialogRef;
2672
2702
  currentUserDialogRef;
2673
2703
  componentWillLoad() {
2704
+ this.normalizedControls = this.normalizeControls(this.controls);
2674
2705
  this.loadSettingsFromStorage();
2675
2706
  this.applyTheme();
2676
2707
  }
2708
+ isTextToolConfig(config) {
2709
+ return !!config && 'fontFamily' in config && 'size' in config && 'color' in config;
2710
+ }
2711
+ normalizeControls(controls) {
2712
+ return controls.map(control => {
2713
+ if (!this.isTextToolConfig(control.config)) {
2714
+ return control;
2715
+ }
2716
+ return {
2717
+ ...control,
2718
+ config: {
2719
+ ...control.config,
2720
+ availableFonts: schema_constants.resolveTextToolAvailableFonts(control.config.availableFonts),
2721
+ },
2722
+ };
2723
+ });
2724
+ }
2677
2725
  applyTheme() {
2678
2726
  const themeObj = this.resolveThemeObject();
2679
2727
  schema_constants.ThemeHelper.applyThemeToElement(this.host, themeObj);
@@ -2684,6 +2732,7 @@ const KritzelEditor = class {
2684
2732
  }
2685
2733
  componentDidLoad() {
2686
2734
  this.registerCustomSvgIcons();
2735
+ this.registerCustomFonts();
2687
2736
  this.listenForMobileKeyboard();
2688
2737
  this.setOsSpecificCssVariables();
2689
2738
  }
@@ -2696,6 +2745,7 @@ const KritzelEditor = class {
2696
2745
  await customElements.whenDefined('kritzel-workspace-manager');
2697
2746
  await customElements.whenDefined('kritzel-controls');
2698
2747
  await customElements.whenDefined('kritzel-engine');
2748
+ await this.waitForCustomFontsReady();
2699
2749
  if (!this.isEngineReady || !this.isControlsReady || !this.isWorkspaceManagerReady || !this.activeWorkspace) {
2700
2750
  return;
2701
2751
  }
@@ -2959,6 +3009,15 @@ const KritzelEditor = class {
2959
3009
  async registerLocales(locales) {
2960
3010
  await this.engineRef?.registerLocales(locales);
2961
3011
  }
3012
+ /**
3013
+ * Registers custom fonts for the editor runtime.
3014
+ * @param fonts - Mapping from font keys to family names or font definitions.
3015
+ * @remarks This no longer controls the text-tool config tooltip font options.
3016
+ * Configure tooltip fonts via controls[].config.availableFonts.
3017
+ */
3018
+ async registerFonts(fonts) {
3019
+ await this.registerCustomFonts(fonts);
3020
+ }
2962
3021
  /**
2963
3022
  * Resolves a term key to its translated string for the active locale.
2964
3023
  * @param key - The term key to resolve.
@@ -3036,6 +3095,25 @@ const KritzelEditor = class {
3036
3095
  schema_constants.KritzelIconRegistry.register(name, svg);
3037
3096
  }
3038
3097
  }
3098
+ async registerCustomFonts(fonts = this.customFonts) {
3099
+ schema_constants.KritzelFontRegistry.registerFonts(fonts);
3100
+ const currentVersion = ++this.customFontsLoadVersion;
3101
+ const loadPromise = schema_constants.KritzelFontRegistry.waitForFonts(fonts);
3102
+ this.customFontsReady = loadPromise;
3103
+ await loadPromise;
3104
+ if (currentVersion !== this.customFontsLoadVersion) {
3105
+ await this.waitForCustomFontsReady();
3106
+ }
3107
+ }
3108
+ async waitForCustomFontsReady() {
3109
+ while (true) {
3110
+ const version = this.customFontsLoadVersion;
3111
+ await this.customFontsReady;
3112
+ if (version === this.customFontsLoadVersion) {
3113
+ return;
3114
+ }
3115
+ }
3116
+ }
3039
3117
  listenForMobileKeyboard() {
3040
3118
  schema_constants.KritzelKeyboardHelper.onKeyboardVisibleChanged(isOpen => {
3041
3119
  this.isVirtualKeyboardOpen = isOpen;
@@ -3074,36 +3152,36 @@ const KritzelEditor = class {
3074
3152
  const isLoggedIn = this.isLoggedIn;
3075
3153
  const shouldShowCurrentUser = isLoggedIn;
3076
3154
  const shouldShowLoginButton = this.isReady && !!this.loginConfig && !isLoggedIn;
3077
- return (index.h(index.Host, { key: '3128b38a04cd636abc1f2466f1ac1aa3dcea2262' }, index.h("div", { key: 'b1fbb051cb1144fd84f28cfea4ad824f92189dbd', class: "editor-content", style: {
3155
+ return (index.h(index.Host, { key: '00d652c74feac7b4917772146368125da6deeb1c' }, index.h("div", { key: 'f8fb86b45b0cdabb5e3ad52de6d6ef31a71a09e4', class: "editor-content", style: {
3078
3156
  opacity: this.isEditorVisible ? '1' : '0',
3079
3157
  visibility: this.isEditorVisible ? 'visible' : 'hidden',
3080
3158
  transition: 'opacity 0.2s ease-in-out, visibility 0.2s ease-in-out',
3081
- } }, index.h("div", { key: '2b896fa8bd00a7c68b74df7a9846e8c3e0f6efc4', class: "top-left-buttons" }, index.h("kritzel-workspace-manager", { key: '13244251aa8999d78d275eefe5583d592f3506fc', visible: this.isWorkspaceManagerVisible, workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, terms: this.resolvedTerms, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), index.h("kritzel-back-to-content", { key: '7d3015918e4af7ee435aee8da37ddfa206cdfd66', visible: this.isBackToContentButtonVisible, text: this.resolvedTerms['backToContent.label'] ?? 'Back to content', onBackToContent: () => this.backToContent() })), this.activeNotification && (index.h("div", { key: '49f13f23698db9b804d139e0f35696be06569346', class: "top-center-notification-layer", role: "presentation" }, index.h("div", { key: '765aa6995398aca3c7738758bedb7d9a7c2f099a', class: { 'top-center-notification-container': true, 'is-dismissing': this.isNotificationDismissing }, role: "presentation" }, index.h("kritzel-notification-card", { key: 'fe0dfa30aa498a608f9167b01e0a2309dfa67162', notification: this.activeNotification, locale: this.locale, onDismiss: this.dismissNotification, onHoverChange: event => this.handleNotificationHoverChange(event) })))), index.h("kritzel-engine", { key: '5aeb7979faa8779653ff6a2930d288fd601cb0e9', ref: el => {
3159
+ } }, index.h("div", { key: '2378c776d8eecf2614567bed11c6e93fb338e302', class: "top-left-buttons" }, index.h("kritzel-workspace-manager", { key: 'ce41192540169694482d6f8cca60701bc4427438', visible: this.isWorkspaceManagerVisible, workspaces: this.workspaces, activeWorkspace: this.activeWorkspace, terms: this.resolvedTerms, onWorkspaceChange: event => (this.activeWorkspace = event.detail), onIsWorkspaceManagerReady: () => (this.isWorkspaceManagerReady = true) }), index.h("kritzel-back-to-content", { key: 'ec269d3e9f589362d8301370778f0c5e4252eead', visible: this.isBackToContentButtonVisible, text: this.resolvedTerms['backToContent.label'] ?? 'Back to content', onBackToContent: () => this.backToContent() })), this.activeNotification && (index.h("div", { key: '847ed8149d556c934090424ff54b17b6721ccc76', class: "top-center-notification-layer", role: "presentation" }, index.h("div", { key: '61d8b8e91cda100ffa6620db26ba6dfb2232946a', class: { 'top-center-notification-container': true, 'is-dismissing': this.isNotificationDismissing }, role: "presentation" }, index.h("kritzel-notification-card", { key: 'b7e132773225ace38e447756110dd39e4661f5fc', notification: this.activeNotification, locale: this.locale, onDismiss: this.dismissNotification, onHoverChange: event => this.handleNotificationHoverChange(event) })))), index.h("kritzel-engine", { key: '3e4a6d0dbc015ec675fb21a59990c87e9eaa805f', ref: el => {
3082
3160
  if (el) {
3083
3161
  this.engineRef = el;
3084
3162
  }
3085
- }, workspace: this.activeWorkspace, activeWorkspaceId: this.activeWorkspaceId, editorId: this.editorId, syncConfig: this.syncConfig, assetStorageConfig: this.assetStorageConfig, user: this.user, scaleMax: this.scaleMax, lockDrawingScale: this.lockDrawingScale, isObjectDistanceFadingActive: this.isObjectDistanceFadingActive, scaleMin: this.scaleMin, cursorTarget: this.cursorTarget, isLoading: this.isLoading, viewportBoundaryLeft: this.viewportBoundaryLeft, viewportBoundaryRight: this.viewportBoundaryRight, viewportBoundaryTop: this.viewportBoundaryTop, viewportBoundaryBottom: this.viewportBoundaryBottom, isPanningEnabled: this.isPanningEnabled, isZoomingEnabled: this.isZoomingEnabled, theme: this.theme, themes: this.themes, licenseKey: this.licenseKey, locale: this.locale, locales: this.locales, fallbackLocale: this.fallbackLocale, debugInfo: this.debugInfo, globalContextMenuItems: this.globalContextMenuItems, objectContextMenuItems: this.objectContextMenuItems, onIsEngineReady: event => this.onEngineReady(event), onWorkspacesChange: event => this.handleWorkspacesChange(event), onActiveWorkspaceChange: event => this.handleActiveWorkspaceChange(event), onObjectsChange: event => this.handleObjectsChange(event), onObjectsAdded: event => this.handleObjectsAdded(event), onObjectsRemoved: event => this.handleObjectsRemoved(event), onObjectsUpdated: event => this.handleObjectsUpdated(event), onUndoStateChange: event => this.handleUndoStateChange(event), onObjectsInViewportChange: event => this.handleObjectsInViewportChange(event), onViewportChange: event => this.handleViewportChange(event), onAwarenessChange: event => this.handleAwarenessChange(event), onNotificationsChange: event => this.handleNotificationsChange(event) }), index.h("kritzel-controls", { key: 'eda4dc93fe663c8472638190216bea5bf64d7153', visible: this.isControlsVisible, class: { 'keyboard-open': this.isVirtualKeyboardOpen }, ref: el => {
3163
+ }, workspace: this.activeWorkspace, activeWorkspaceId: this.activeWorkspaceId, editorId: this.editorId, syncConfig: this.syncConfig, assetStorageConfig: this.assetStorageConfig, user: this.user, scaleMax: this.scaleMax, lockDrawingScale: this.lockDrawingScale, isObjectDistanceFadingActive: this.isObjectDistanceFadingActive, scaleMin: this.scaleMin, cursorTarget: this.cursorTarget, isLoading: this.isLoading, viewportBoundaryLeft: this.viewportBoundaryLeft, viewportBoundaryRight: this.viewportBoundaryRight, viewportBoundaryTop: this.viewportBoundaryTop, viewportBoundaryBottom: this.viewportBoundaryBottom, isPanningEnabled: this.isPanningEnabled, isZoomingEnabled: this.isZoomingEnabled, theme: this.theme, themes: this.themes, licenseKey: this.licenseKey, locale: this.locale, locales: this.locales, fallbackLocale: this.fallbackLocale, debugInfo: this.debugInfo, globalContextMenuItems: this.globalContextMenuItems, objectContextMenuItems: this.objectContextMenuItems, onIsEngineReady: event => this.onEngineReady(event), onWorkspacesChange: event => this.handleWorkspacesChange(event), onActiveWorkspaceChange: event => this.handleActiveWorkspaceChange(event), onObjectsChange: event => this.handleObjectsChange(event), onObjectsAdded: event => this.handleObjectsAdded(event), onObjectsRemoved: event => this.handleObjectsRemoved(event), onObjectsUpdated: event => this.handleObjectsUpdated(event), onUndoStateChange: event => this.handleUndoStateChange(event), onObjectsInViewportChange: event => this.handleObjectsInViewportChange(event), onViewportChange: event => this.handleViewportChange(event), onAwarenessChange: event => this.handleAwarenessChange(event), onNotificationsChange: event => this.handleNotificationsChange(event) }), index.h("kritzel-controls", { key: 'f84607a0a4d0762c1249400f85b7b8454d672c1e', visible: this.isControlsVisible, class: { 'keyboard-open': this.isVirtualKeyboardOpen }, ref: el => {
3086
3164
  if (el) {
3087
3165
  this.controlsRef = el;
3088
3166
  }
3089
- }, controls: this.controls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState ?? undefined, theme: this.theme, terms: this.resolvedTerms, onIsControlsReady: () => (this.isControlsReady = true) }), index.h("div", { key: 'ffdb548da8aac3498b1b3e9bfdc9a41f8c448675', class: "bottom-left-buttons" }, index.h("kritzel-zoom-panel", { key: 'af6f6a86212195fd3ee13bc33c16574e0a5236a6', visible: this.isZoomPanelVisible, disabled: !this.isZoomingEnabled, zoomPercent: this.currentZoomPercent, terms: this.resolvedTerms, onZoomIn: () => this.zoomIn(), onZoomOut: () => this.zoomOut() })), index.h("div", { key: '0870c0e47838fc99b4041718a431535827e199cf', class: "top-right-buttons" }, index.h("kritzel-settings", { key: 'b95beb43dbe1a9c99454fc4ff74f0630aca7ad83', ref: el => {
3167
+ }, controls: this.normalizedControls, isUtilityPanelVisible: this.isUtilityPanelVisible, undoState: this.undoState ?? undefined, theme: this.theme, terms: this.resolvedTerms, onIsControlsReady: () => (this.isControlsReady = true) }), index.h("div", { key: 'e2691e7c730195e197511cb1e4d0fe707677b5ff', class: "bottom-left-buttons" }, index.h("kritzel-zoom-panel", { key: 'd0ac6624eab49af78d4761c3ad91842834717aad', visible: this.isZoomPanelVisible, disabled: !this.isZoomingEnabled, zoomPercent: this.currentZoomPercent, terms: this.resolvedTerms, onZoomIn: () => this.zoomIn(), onZoomOut: () => this.zoomOut() })), index.h("div", { key: 'ad3d386ab7e8ad9fdfbb12754db005bc85fa28ce', class: "top-right-buttons" }, index.h("kritzel-settings", { key: '566024ac6f3d8f7f20238cc1f83882b39dbf698e', ref: el => {
3090
3168
  if (el) {
3091
3169
  this.settingsRef = el;
3092
3170
  }
3093
- }, shortcuts: this.shortcuts, availableThemes: this.themes && this.themes.length > 0 ? this.themes.map(t => t.name) : ['light', 'dark'], availableLocales: this.availableLocaleOptions, settings: this.currentSettingsConfig, terms: this.resolvedTerms, onSettingsChange: event => this.handleSettingsChange(event) }), index.h("kritzel-export", { key: 'ef6fea2715ff99226fde937185a693efc2a7dd75', ref: el => {
3171
+ }, shortcuts: this.shortcuts, availableThemes: this.themes && this.themes.length > 0 ? this.themes.map(t => t.name) : ['light', 'dark'], availableLocales: this.availableLocaleOptions, settings: this.currentSettingsConfig, terms: this.resolvedTerms, onSettingsChange: event => this.handleSettingsChange(event) }), index.h("kritzel-export", { key: '4a23ea0c6e070d424a90e9fc87de04e11cff7ade', ref: el => {
3094
3172
  if (el) {
3095
3173
  this.exportRef = el;
3096
3174
  }
3097
- }, workspaceName: this.activeWorkspace?.name || 'workspace', terms: this.resolvedTerms, onExportPng: () => this.engineRef.exportViewportAsPng(), onExportSvg: () => this.engineRef.exportViewportAsSvg(), onExportJson: event => this.engineRef.downloadAsJson(event.detail) }), index.h("kritzel-active-users", { key: '872b7fa12d49410d1c370baed3386a34f89d3e2a', users: this.activeUsers }), shouldShowCurrentUser && index.h("kritzel-current-user", { key: 'da19825b4fba6a516803f8330cdfdfac6b6c9db1', user: this.user, terms: this.resolvedTerms, onClick: () => this.currentUserDialogRef?.open() }), shouldShowCurrentUser && (index.h("kritzel-current-user-dialog", { key: '9336ce611286d3ecf9318317ab4bedb8c3f79f05', ref: el => {
3175
+ }, workspaceName: this.activeWorkspace?.name || 'workspace', terms: this.resolvedTerms, onExportPng: () => this.engineRef.exportViewportAsPng(), onExportSvg: () => this.engineRef.exportViewportAsSvg(), onExportJson: event => this.engineRef.downloadAsJson(event.detail) }), index.h("kritzel-active-users", { key: 'feef074b52e552fa2ef7e8258002571aca4c5abd', users: this.activeUsers }), shouldShowCurrentUser && index.h("kritzel-current-user", { key: '844c722545363eaf7eec69037a835eae943afeb9', user: this.user, terms: this.resolvedTerms, onClick: () => this.currentUserDialogRef?.open() }), shouldShowCurrentUser && (index.h("kritzel-current-user-dialog", { key: '8363c1d3230d111cf1ace0ccf805669e592bb533', ref: el => {
3098
3176
  if (el) {
3099
3177
  this.currentUserDialogRef = el;
3100
3178
  this.currentUserDialogRef.addEventListener('logoutRequest', this.handleCurrentUserLogout);
3101
3179
  }
3102
- }, user: this.user, terms: this.resolvedTerms })), shouldShowLoginButton && (index.h("kritzel-button", { key: 'a9e38ad3e13c785f6a4223ebde95f60451c6515f', onButtonClick: () => this.loginDialogRef?.open() }, this.resolvedTerms['login.dialogTitle'] ?? 'Sign in')), index.h("kritzel-more-menu", { key: 'b8f63a63ae4e75a70d0069410170af902f2a362b', items: this.moreMenuItems, visible: this.isMoreMenuVisible, terms: this.resolvedTerms }), index.h("kritzel-share-dialog", { key: '7a923fd51e8d2bd1e2833e0941622efadd55f881', ref: el => {
3180
+ }, user: this.user, terms: this.resolvedTerms })), shouldShowLoginButton && (index.h("kritzel-button", { key: '68ddf8c3aabc7634b4c1d88f3d2d584fa1f1b150', onButtonClick: () => this.loginDialogRef?.open() }, this.resolvedTerms['login.dialogTitle'] ?? 'Sign in')), index.h("kritzel-more-menu", { key: '39b938f5792f7a36bbf21ed88a1a5c7717a785a6', items: this.moreMenuItems, visible: this.isMoreMenuVisible, terms: this.resolvedTerms }), index.h("kritzel-share-dialog", { key: '61ed918499760d874d5d2ec140d3cf59ce94520b', ref: el => {
3103
3181
  if (el) {
3104
3182
  this.shareDialogRef = el;
3105
3183
  }
3106
- }, isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, terms: this.resolvedTerms, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (index.h("kritzel-login-dialog", { key: 'ac54c699a94bb2657a6817c37d6220b75d931cd3', ref: el => {
3184
+ }, isPublic: this.currentIsPublic, workspaceId: this.activeWorkspace?.id, terms: this.resolvedTerms, onToggleIsPublic: this.handleToggleIsPublic }), this.loginConfig && (index.h("kritzel-login-dialog", { key: '5f6528a57884bd1494e45755609e710f69041a4d', ref: el => {
3107
3185
  if (el) {
3108
3186
  this.loginDialogRef = el;
3109
3187
  }
@@ -3122,6 +3200,12 @@ const KritzelEditor = class {
3122
3200
  "activeWorkspace": [{
3123
3201
  "onActiveWorkspaceChange": 0
3124
3202
  }],
3203
+ "customFonts": [{
3204
+ "onCustomFontsChange": 0
3205
+ }],
3206
+ "controls": [{
3207
+ "onControlsChange": 0
3208
+ }],
3125
3209
  "activeWorkspaceId": [{
3126
3210
  "onActiveWorkspaceIdChange": 0
3127
3211
  }],
@@ -21403,7 +21487,7 @@ class KritzelContextMenuHandler extends schema_constants.KritzelBaseHandler {
21403
21487
  * @returns void - This method does not return a value; it updates state and triggers a rerender.
21404
21488
  */
21405
21489
  handleContextMenu(event) {
21406
- if (!(this._core.store.state.activeTool instanceof schema_constants.KritzelSelectionTool)) {
21490
+ if (this._core.store.state.activeTool?.toolType !== 'selection') {
21407
21491
  return;
21408
21492
  }
21409
21493
  if (this._core.store.state.skipContextMenu) {
@@ -21463,7 +21547,7 @@ class KritzelContextMenuHandler extends schema_constants.KritzelBaseHandler {
21463
21547
  */
21464
21548
  open(options) {
21465
21549
  const { x, y, objectId } = options;
21466
- if (this._core.store.state.activeTool instanceof schema_constants.KritzelSelectionTool) {
21550
+ if (this._core.store.state.activeTool?.toolType === 'selection') {
21467
21551
  const selectionTool = this._core.store.state.activeTool;
21468
21552
  selectionTool?.moveHandler?.cancelPendingDrag();
21469
21553
  }
@@ -22278,6 +22362,9 @@ class KritzelObjectMap {
22278
22362
  */
22279
22363
  onAwarenessChange(callback) {
22280
22364
  this._awarenessChangeCallbacks.push(callback);
22365
+ return () => {
22366
+ this._awarenessChangeCallbacks = this._awarenessChangeCallbacks.filter(existingCallback => existingCallback !== callback);
22367
+ };
22281
22368
  }
22282
22369
  /**
22283
22370
  * Registers a callback to be invoked when remote object changes are received.
@@ -22286,6 +22373,9 @@ class KritzelObjectMap {
22286
22373
  */
22287
22374
  onObjectsChange(callback) {
22288
22375
  this._objectsChangeCallbacks.push(callback);
22376
+ return () => {
22377
+ this._objectsChangeCallbacks = this._objectsChangeCallbacks.filter(existingCallback => existingCallback !== callback);
22378
+ };
22289
22379
  }
22290
22380
  /**
22291
22381
  * Returns the Yjs UndoManager instance for managing undo/redo operations.
@@ -22482,6 +22572,9 @@ class KritzelObjectMap {
22482
22572
  callback(states);
22483
22573
  }
22484
22574
  }, delayMs);
22575
+ if (typeof this._awarenessEmitTimeout.unref === 'function') {
22576
+ this._awarenessEmitTimeout.unref();
22577
+ }
22485
22578
  }
22486
22579
  };
22487
22580
  this._awareness.on('change', this._awarenessChangeHandler);
@@ -24472,9 +24565,8 @@ class KritzelClipboardManager {
24472
24565
  const scale = this._core.store.state.scale;
24473
24566
  const offset = 25 / scale;
24474
24567
  const preparePromises = intent.files.map(async (file, index) => {
24475
- // Use the default image compression size of 1200
24476
- const compressed = await schema_constants.imageCompression(file, { maxWidthOrHeight: 1200 });
24477
- return schema_constants.KritzelImage.fromBlob(this._core, compressed, {
24568
+ const preparedFile = await this.prepareImageFile(file);
24569
+ return schema_constants.KritzelImage.fromBlob(this._core, preparedFile, {
24478
24570
  translateX: index * offset,
24479
24571
  translateY: index * offset,
24480
24572
  });
@@ -24486,6 +24578,12 @@ class KritzelClipboardManager {
24486
24578
  return null;
24487
24579
  }
24488
24580
  }
24581
+ async prepareImageFile(file) {
24582
+ if (schema_constants.KritzelImageFileHelper.isGifFile(file)) {
24583
+ return file;
24584
+ }
24585
+ return schema_constants.imageCompression(file, { maxWidthOrHeight: 1200 });
24586
+ }
24489
24587
  async materializePlainText(intent) {
24490
24588
  const textObject = schema_constants.KritzelText.create(this._core);
24491
24589
  const paragraphs = intent.text.split('\n').map(line => {
@@ -27953,7 +28051,7 @@ const KritzelEngine = class {
27953
28051
  }
27954
28052
  return existingTool;
27955
28053
  }
27956
- const registeredTool = this.core.toolRegistry.registerTool(toolName, toolClass);
28054
+ const registeredTool = this.core.toolRegistry.registerTool(toolName, this.resolveToolClass(toolClass));
27957
28055
  if (toolConfig) {
27958
28056
  this.applyToolConfig(registeredTool, toolConfig);
27959
28057
  }
@@ -29134,31 +29232,71 @@ const KritzelEngine = class {
29134
29232
  this.syncingChange.emit(isSyncing);
29135
29233
  }
29136
29234
  applyToolConfig(tool, toolConfig) {
29137
- Object.entries(toolConfig).forEach(([key, value]) => {
29235
+ const normalizedToolConfig = this.normalizeToolConfig(toolConfig);
29236
+ Object.entries(normalizedToolConfig).forEach(([key, value]) => {
29138
29237
  tool[key] = value;
29139
29238
  });
29140
29239
  // Resolve palettes map into the flat palette array the UI reads
29141
- if ('palettes' in toolConfig && 'type' in toolConfig) {
29142
- const brushConfig = toolConfig;
29240
+ if ('palettes' in normalizedToolConfig && 'type' in normalizedToolConfig) {
29241
+ const brushConfig = normalizedToolConfig;
29143
29242
  const resolvedPalette = brushConfig.palettes[brushConfig.type];
29144
29243
  if (resolvedPalette) {
29145
29244
  tool['palette'] = resolvedPalette;
29146
29245
  }
29147
29246
  }
29148
29247
  // Resolve sizes map into the flat sizes array the UI reads (brush tool uses a map keyed by type)
29149
- if ('sizes' in toolConfig && toolConfig.sizes != null && 'type' in toolConfig) {
29150
- const brushConfig = toolConfig;
29248
+ if ('sizes' in normalizedToolConfig && normalizedToolConfig.sizes != null && 'type' in normalizedToolConfig) {
29249
+ const brushConfig = normalizedToolConfig;
29151
29250
  const resolvedSizes = brushConfig.sizes?.[brushConfig.type];
29152
29251
  if (resolvedSizes) {
29153
29252
  tool['sizes'] = resolvedSizes;
29154
29253
  }
29155
29254
  }
29156
29255
  }
29256
+ normalizeToolConfig(toolConfig) {
29257
+ if (!this.isTextToolConfig(toolConfig)) {
29258
+ return toolConfig;
29259
+ }
29260
+ return {
29261
+ ...toolConfig,
29262
+ availableFonts: schema_constants.resolveTextToolAvailableFonts(toolConfig.availableFonts),
29263
+ };
29264
+ }
29265
+ isTextToolConfig(toolConfig) {
29266
+ return 'fontFamily' in toolConfig && 'size' in toolConfig && 'color' in toolConfig;
29267
+ }
29268
+ /** Built-in tool classes of this bundle keyed by their tool type. */
29269
+ static BUILT_IN_TOOL_CLASSES = {
29270
+ selection: schema_constants.KritzelSelectionTool,
29271
+ brush: schema_constants.KritzelBrushTool,
29272
+ eraser: schema_constants.KritzelEraserTool,
29273
+ line: schema_constants.KritzelLineTool,
29274
+ shape: schema_constants.KritzelShapeTool,
29275
+ text: schema_constants.KritzelTextTool,
29276
+ image: schema_constants.KritzelImageTool,
29277
+ };
29278
+ /**
29279
+ * Resolves a tool class to the internal built-in class when a foreign copy is passed.
29280
+ * Classes from another compiled copy of the library (dual-package hazard, e.g. built-ins
29281
+ * re-exported by a framework wrapper) would otherwise break `instanceof` checks.
29282
+ */
29283
+ resolveToolClass(toolClass) {
29284
+ if (toolClass.prototype instanceof schema_constants.KritzelBaseTool) {
29285
+ return toolClass;
29286
+ }
29287
+ try {
29288
+ const probe = new toolClass(this.core);
29289
+ return KritzelEngine.BUILT_IN_TOOL_CLASSES[probe.toolType] ?? toolClass;
29290
+ }
29291
+ catch {
29292
+ return toolClass;
29293
+ }
29294
+ }
29157
29295
  get isSelecting() {
29158
- return this.core.store.state.activeTool instanceof schema_constants.KritzelSelectionTool && this.core.store.state.isSelecting;
29296
+ return this.core.store.state.activeTool?.toolType === 'selection' && this.core.store.state.isSelecting;
29159
29297
  }
29160
29298
  get isSelectionActive() {
29161
- return this.core.store.state.activeTool instanceof schema_constants.KritzelSelectionTool && this.core.store.selectionGroup !== null;
29299
+ return this.core.store.state.activeTool?.toolType === 'selection' && this.core.store.selectionGroup !== null;
29162
29300
  }
29163
29301
  constructor(hostRef) {
29164
29302
  index.registerInstance(this, hostRef);
@@ -29475,7 +29613,7 @@ const KritzelEngine = class {
29475
29613
  this.core.store.onStateChange('activeTool', this._handleActiveToolChange.bind(this));
29476
29614
  }
29477
29615
  _handleActiveToolChange(activeTool) {
29478
- if (!(activeTool instanceof schema_constants.KritzelSelectionTool)) {
29616
+ if (activeTool?.toolType !== 'selection') {
29479
29617
  this.core.clearSelection();
29480
29618
  this.core.store.objects?.remove(o => o instanceof schema_constants.KritzelSelectionBox);
29481
29619
  this.core.store.setSelectionBox(null);
@@ -29484,10 +29622,10 @@ const KritzelEngine = class {
29484
29622
  this.core.store.state.isResizeHandleSelected = false;
29485
29623
  this.core.store.state.isRotationHandleSelected = false;
29486
29624
  }
29487
- if (!(activeTool instanceof schema_constants.KritzelTextTool)) {
29625
+ if (activeTool?.toolType !== 'text') {
29488
29626
  this.core.resetActiveText();
29489
29627
  }
29490
- if (!(activeTool instanceof schema_constants.KritzelShapeTool)) {
29628
+ if (activeTool?.toolType !== 'shape') {
29491
29629
  this.core.resetActiveShape();
29492
29630
  }
29493
29631
  this.core.store.state.skipContextMenu = false;
@@ -29721,7 +29859,7 @@ const KritzelEngine = class {
29721
29859
  borderWidth: object.borderWidth + 'px',
29722
29860
  borderStyle: 'solid',
29723
29861
  padding: object.padding + 'px',
29724
- overflow: 'hidden',
29862
+ overflow: 'visible',
29725
29863
  display: 'block',
29726
29864
  } })), schema_constants.KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup') && !this.core.displaySelectionLineUI(object) && (index.h("div", { ref: el => el && object.mount(el), style: {
29727
29865
  position: 'absolute',
@@ -30071,7 +30209,7 @@ const KritzelEngine = class {
30071
30209
  }, this.core.store.selectionGroup?.objects || []);
30072
30210
  }
30073
30211
  this.hideContextMenu();
30074
- }, onClose: () => this.hideContextMenu() })), this.core.store.objects?.hasAwareness && index.h("kritzel-awareness-cursors", { core: this.core }), this.core.store.state?.activeTool instanceof schema_constants.KritzelEraserTool && !this.core.store.state.isScaling && index.h("kritzel-cursor-trail", { core: this.core }), !this.core.licenseManager.isLicensed && index.h("kritzel-watermark", { core: this.core, label: this.core.localizationManager.translate('watermark.poweredBy') })));
30212
+ }, onClose: () => this.hideContextMenu() })), this.core.store.objects?.hasAwareness && index.h("kritzel-awareness-cursors", { core: this.core }), this.core.store.state?.activeTool?.toolType === 'eraser' && !this.core.store.state.isScaling && index.h("kritzel-cursor-trail", { core: this.core }), !this.core.licenseManager.isLicensed && index.h("kritzel-watermark", { core: this.core, label: this.core.localizationManager.translate('watermark.poweredBy') })));
30075
30213
  }
30076
30214
  static get watchers() { return {
30077
30215
  "workspace": [{
@@ -30259,39 +30397,47 @@ const KritzelFontFamily = class {
30259
30397
  index.registerInstance(this, hostRef);
30260
30398
  this.fontFamilyChange = index.createEvent(this, "fontFamilyChange");
30261
30399
  }
30262
- fontOptions = [
30263
- { value: 'arial', label: 'Arial' },
30264
- { value: 'verdana', label: 'Verdana' },
30265
- { value: 'helvetica', label: 'Helvetica' },
30266
- { value: 'tahoma', label: 'Tahoma' },
30267
- { value: 'trebuchet ms', label: 'Trebuchet MS' },
30268
- { value: 'times new roman', label: 'Times New Roman' },
30269
- { value: 'georgia', label: 'Georgia' },
30270
- { value: 'garamond', label: 'Garamond' },
30271
- { value: 'courier new', label: 'Courier New' },
30272
- { value: 'brush script mt', label: 'Brush Script MT' },
30273
- ];
30400
+ fontOptions = [];
30274
30401
  selectedFontFamily;
30275
30402
  fontFamilyChange;
30403
+ handleFontOptionsChange() {
30404
+ this.ensureValidSelectedFont(this.resolveFontOptions());
30405
+ }
30276
30406
  componentWillLoad() {
30277
- if (this.fontOptions && this.fontOptions.length > 0) {
30278
- const isValidCurrentFont = this.fontOptions.some(opt => opt.value === this.selectedFontFamily);
30279
- if (!this.selectedFontFamily || !isValidCurrentFont) {
30280
- this.selectedFontFamily = this.fontOptions[0].value;
30281
- }
30282
- }
30407
+ this.ensureValidSelectedFont(this.resolveFontOptions());
30283
30408
  }
30284
30409
  handleDropdownValueChange = (event) => {
30285
30410
  this.fontFamilyChange.emit(event.detail);
30286
30411
  };
30412
+ ensureValidSelectedFont(options) {
30413
+ if (options.length === 0) {
30414
+ return;
30415
+ }
30416
+ const normalizedSelected = this.selectedFontFamily?.trim().toLocaleLowerCase();
30417
+ const isValidCurrentFont = options.some(opt => opt.value.trim().toLocaleLowerCase() === normalizedSelected);
30418
+ if (!normalizedSelected || !isValidCurrentFont) {
30419
+ this.selectedFontFamily = options[0].value;
30420
+ }
30421
+ }
30422
+ resolveFontOptions() {
30423
+ return this.fontOptions;
30424
+ }
30287
30425
  render() {
30288
- const dropdownOptions = this.fontOptions.map(option => ({
30426
+ const fontOptions = this.resolveFontOptions();
30427
+ const selectedOption = fontOptions.find(option => option.value === this.selectedFontFamily);
30428
+ const selectedFontFamily = selectedOption?.cssFontFamily ?? this.selectedFontFamily;
30429
+ const dropdownOptions = fontOptions.map(option => ({
30289
30430
  value: option.value,
30290
30431
  label: option.label,
30291
- style: { fontFamily: option.value },
30432
+ style: { fontFamily: option.cssFontFamily ?? option.value },
30292
30433
  }));
30293
- return (index.h(index.Host, { key: '0123dbdff9b7051d2ebc9dcf8d1f9c7c4c161dc4' }, index.h("kritzel-dropdown", { key: '5d4e289161502ecc60cef3d0c6d546a64817a12a', options: dropdownOptions, value: this.selectedFontFamily, onValueChanged: this.handleDropdownValueChange, selectStyles: { fontFamily: this.selectedFontFamily } })));
30434
+ return (index.h(index.Host, { key: '059350f34370f7a291f47a42721ca5d9bb82df49' }, index.h("kritzel-dropdown", { key: 'fbd8cf1ae463c7e9b76d0ac754a41de54397058e', options: dropdownOptions, value: this.selectedFontFamily, onValueChanged: this.handleDropdownValueChange, selectStyles: { fontFamily: selectedFontFamily } })));
30294
30435
  }
30436
+ static get watchers() { return {
30437
+ "fontOptions": [{
30438
+ "handleFontOptionsChange": 0
30439
+ }]
30440
+ }; }
30295
30441
  };
30296
30442
  KritzelFontFamily.style = kritzelFontFamilyCss();
30297
30443
 
@@ -31489,7 +31635,7 @@ const KritzelPortal = class {
31489
31635
  * This file is auto-generated by the version bump scripts.
31490
31636
  * Do not modify manually.
31491
31637
  */
31492
- const KRITZEL_VERSION = '0.3.46';
31638
+ const KRITZEL_VERSION = '0.4.1';
31493
31639
 
31494
31640
  const kritzelSettingsCss = () => `:host{display:contents}kritzel-dialog{--kritzel-dialog-body-padding:0;--kritzel-dialog-width-large:800px;--kritzel-dialog-height-large:500px}.footer-button{padding:8px 16px;border-radius:6px;cursor:pointer;font-size:14px}.cancel-button{border:1px solid #ebebeb;background:#fff;color:inherit}.cancel-button:hover{background:#f5f5f5}.settings-content{padding:0}.settings-content h3{margin:0 0 16px 0;font-size:18px;font-weight:600;color:var(--kritzel-settings-content-heading-color, #333333)}.settings-content p{margin:0;font-size:14px;color:var(--kritzel-settings-content-text-color, #666666);line-height:1.5}.settings-group{display:flex;flex-direction:column;gap:24px}.settings-item{display:flex;flex-direction:column;gap:8px}.settings-row{display:flex;align-items:center;justify-content:space-between;gap:16px}.settings-label{font-size:14px;font-weight:600;color:var(--kritzel-settings-label-color, #333333);margin:0 0 4px 0}.settings-description{font-size:12px;color:var(--kritzel-settings-description-color, #888888);margin:0;line-height:1.4}.shortcuts-list{display:flex;flex-direction:column;gap:24px}.shortcuts-category{display:flex;flex-direction:column;gap:8px}.shortcuts-category-title{font-size:14px;font-weight:600;color:var(--kritzel-settings-label-color, #333333);margin:0 0 4px 0}.shortcuts-group{display:flex;flex-direction:column;gap:4px}.shortcut-item{display:flex;justify-content:space-between;align-items:center;padding:6px 8px;border-radius:4px;background:var(--kritzel-settings-shortcut-item-bg, rgba(0, 0, 0, 0.02))}.shortcut-label{font-size:14px;color:var(--kritzel-settings-content-text-color, #666666)}.shortcut-key{font-family:monospace;font-size:12px;padding:2px 8px;border-radius:4px;background:var(--kritzel-settings-shortcut-key-bg, #f0f0f0);color:var(--kritzel-settings-shortcut-key-color, #333333);border:1px solid var(--kritzel-settings-shortcut-key-border, #ddd)}`;
31495
31641
 
@@ -35204,8 +35350,43 @@ const KritzelToolConfig = class {
35204
35350
  sizes = [];
35205
35351
  currentOpacity = 1;
35206
35352
  updateTrigger = 0;
35353
+ getFontOptionsFromTool() {
35354
+ const configuredFonts = schema_constants.resolveTextToolAvailableFonts(this.tool.availableFonts).map(font => {
35355
+ const registeredFont = typeof font === 'string'
35356
+ ? {
35357
+ family: font,
35358
+ label: font,
35359
+ cssFontFamily: font,
35360
+ }
35361
+ : {
35362
+ family: font.family,
35363
+ label: font.label ?? font.family,
35364
+ cssFontFamily: font.cssFontFamily ?? font.family,
35365
+ };
35366
+ return {
35367
+ value: registeredFont.family,
35368
+ label: registeredFont.label,
35369
+ cssFontFamily: registeredFont.cssFontFamily,
35370
+ };
35371
+ });
35372
+ const mergedFonts = [...configuredFonts];
35373
+ const seenFonts = new Set(mergedFonts.map(font => font.value.trim().toLocaleLowerCase()));
35374
+ for (const font of schema_constants.KritzelFontRegistry.list()) {
35375
+ const normalizedValue = font.family.trim().toLocaleLowerCase();
35376
+ if (seenFonts.has(normalizedValue)) {
35377
+ continue;
35378
+ }
35379
+ seenFonts.add(normalizedValue);
35380
+ mergedFonts.push({
35381
+ value: font.family,
35382
+ label: font.label,
35383
+ cssFontFamily: font.cssFontFamily,
35384
+ });
35385
+ }
35386
+ return mergedFonts;
35387
+ }
35207
35388
  handleSelectionChange() {
35208
- if (this.tool instanceof schema_constants.KritzelSelectionTool) {
35389
+ if (this.tool?.toolType === 'selection') {
35209
35390
  this.config = KritzelToolConfigHelper.getToolConfig(this.tool);
35210
35391
  if (this.config) {
35211
35392
  this.updatePalette();
@@ -35242,7 +35423,7 @@ const KritzelToolConfig = class {
35242
35423
  color: schema_constants.KritzelColorHelper.applyOpacity(color, opacity, this.theme),
35243
35424
  size,
35244
35425
  };
35245
- if (this.tool instanceof schema_constants.KritzelTextTool) {
35426
+ if (this.tool.toolType === 'text') {
35246
35427
  displayValues.fontFamily = this.tool.fontFamily;
35247
35428
  }
35248
35429
  this.displayValuesChange.emit(displayValues);
@@ -35335,7 +35516,7 @@ const KritzelToolConfig = class {
35335
35516
  case 'shape-fill':
35336
35517
  return (index.h("kritzel-shape-fill", { key: control.type, value: this.getShapeFillValue(), onValueChange: (event) => this.handlePropertyChange(control.propertyName, event.detail) }));
35337
35518
  case 'font-family':
35338
- return (index.h("kritzel-font-family", { key: control.type, selectedFontFamily: value, onFontFamilyChange: (event) => this.handlePropertyChange(control.propertyName, event.detail) }));
35519
+ return (index.h("kritzel-font-family", { key: control.type, fontOptions: this.getFontOptionsFromTool(), selectedFontFamily: value, onFontFamilyChange: (event) => this.handlePropertyChange(control.propertyName, event.detail) }));
35339
35520
  default:
35340
35521
  return null;
35341
35522
  }