kritzel-stencil 0.4.7 → 0.4.8

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 (47) hide show
  1. package/dist/cjs/index.cjs.js +1 -1
  2. package/dist/cjs/kritzel-active-users_47.cjs.entry.js +31 -14
  3. package/dist/cjs/{schema.constants-C8hqt--r.js → schema.constants-gDeS7USU.js} +75 -7
  4. package/dist/collection/classes/handlers/line-handle.handler.js +1 -1
  5. package/dist/collection/classes/managers/license.manager.js +56 -0
  6. package/dist/collection/classes/objects/line.class.js +1 -1
  7. package/dist/collection/classes/objects/shape.class.js +3 -3
  8. package/dist/collection/classes/objects/text.class.js +1 -1
  9. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +10 -3
  10. package/dist/collection/constants/license.constants.js +1 -1
  11. package/dist/collection/constants/version.js +1 -1
  12. package/dist/collection/helpers/svg-export.helper.js +19 -9
  13. package/dist/collection/helpers/theme.helper.js +8 -0
  14. package/dist/collection/themes/dark-theme.js +2 -0
  15. package/dist/collection/themes/light-theme.js +2 -0
  16. package/dist/components/index.js +3 -3
  17. package/dist/components/kritzel-awareness-cursors.js +1 -1
  18. package/dist/components/kritzel-color-palette.js +1 -1
  19. package/dist/components/kritzel-color.js +1 -1
  20. package/dist/components/kritzel-controls.js +1 -1
  21. package/dist/components/kritzel-editor.js +9 -9
  22. package/dist/components/kritzel-engine.js +1 -1
  23. package/dist/components/kritzel-settings.js +1 -1
  24. package/dist/components/kritzel-stroke-size.js +1 -1
  25. package/dist/components/kritzel-tool-config.js +1 -1
  26. package/dist/components/{p-Ka7OWbnk.js → p-0H4HOJjy.js} +2 -2
  27. package/dist/components/{p-1nG2hxfJ.js → p-9m1cAVwG.js} +2 -2
  28. package/dist/components/{p-DkH3hoLz.js → p-BknTMcbz.js} +5 -5
  29. package/dist/components/{p-zd7zXld8.js → p-CMZ09rB1.js} +1 -1
  30. package/dist/components/{p-BmyTdQGy.js → p-CURiiQfq.js} +12 -0
  31. package/dist/components/{p-Bm_BWQa4.js → p-Ckm1Aq0V.js} +1 -1
  32. package/dist/components/{p-BZxOukfY.js → p-Cr2z2UBL.js} +4 -4
  33. package/dist/components/{p-C2yi85nc.js → p-D8bHNNEm.js} +93 -20
  34. package/dist/components/{p-D0oplzU-.js → p-DgA865Tp.js} +1 -1
  35. package/dist/esm/index.js +2 -2
  36. package/dist/esm/kritzel-active-users_47.entry.js +31 -14
  37. package/dist/esm/{schema.constants-uC7_X6yr.js → schema.constants-Rpm1NA9u.js} +75 -7
  38. package/dist/stencil/index.esm.js +2 -2
  39. package/dist/stencil/{p-472f2e90.entry.js → p-8c1b7b08.entry.js} +31 -14
  40. package/dist/stencil/{p-uC7_X6yr.js → p-Rpm1NA9u.js} +75 -7
  41. package/dist/stencil/stencil.esm.js +1 -1
  42. package/dist/types/classes/managers/license.manager.d.ts +6 -0
  43. package/dist/types/constants/license.constants.d.ts +1 -1
  44. package/dist/types/constants/version.d.ts +1 -1
  45. package/dist/types/helpers/theme.helper.d.ts +1 -0
  46. package/dist/types/interfaces/theme.interface.d.ts +2 -0
  47. package/package.json +1 -1
@@ -14557,7 +14557,9 @@ const lightTheme = {
14557
14557
  },
14558
14558
  snap: {
14559
14559
  indicatorFill: 'rgba(59, 130, 246, 0.3)',
14560
+ indicatorFillInactive: 'rgba(59, 130, 246, 0.18)',
14560
14561
  indicatorStroke: '#007bff',
14562
+ indicatorStrokeInactive: 'rgba(59, 130, 246, 0.5)',
14561
14563
  lineStroke: 'rgba(0, 0, 0, 0.2)',
14562
14564
  },
14563
14565
  fontSize: {
@@ -14894,7 +14896,9 @@ const darkTheme = {
14894
14896
  },
14895
14897
  snap: {
14896
14898
  indicatorFill: 'rgba(10, 132, 255, 0.35)',
14899
+ indicatorFillInactive: 'rgba(10, 132, 255, 0.2)',
14897
14900
  indicatorStroke: '#0A84FF',
14901
+ indicatorStrokeInactive: 'rgba(255, 255, 255, 0.45)',
14898
14902
  lineStroke: 'rgba(255, 255, 255, 0.35)',
14899
14903
  },
14900
14904
  fontSize: {
@@ -15094,6 +15098,7 @@ const darkTheme = {
15094
15098
  };
15095
15099
 
15096
15100
  class ThemeHelper {
15101
+ static appliedVariableNames = new WeakMap();
15097
15102
  /**
15098
15103
  * Converts a camelCase string to kebab-case.
15099
15104
  * @example ThemeHelper.camelToKebab('controlHoverBackgroundColor') → 'control-hover-background-color'
@@ -15159,7 +15164,14 @@ class ThemeHelper {
15159
15164
  */
15160
15165
  static applyThemeToElement(element, theme) {
15161
15166
  const variables = ThemeHelper.flattenThemeToVariables(theme);
15167
+ const previousVariableNames = ThemeHelper.appliedVariableNames.get(element);
15168
+ for (const name of previousVariableNames ?? []) {
15169
+ if (!variables.has(name)) {
15170
+ element.style.removeProperty(name);
15171
+ }
15172
+ }
15162
15173
  ThemeHelper.applyVariablesToElement(element, variables);
15174
+ ThemeHelper.appliedVariableNames.set(element, new Set(variables.keys()));
15163
15175
  }
15164
15176
  }
15165
15177
 
@@ -15780,7 +15792,7 @@ class KritzelText extends KritzelBaseObject {
15780
15792
  }
15781
15793
  element.style.fontFamily = KritzelFontRegistry.resolveCssFontFamily(this.fontFamily);
15782
15794
  element.style.fontSize = `${this.fontSize}pt`;
15783
- element.style.color = KritzelColorHelper.resolveThemeColor(this.fontColor);
15795
+ element.style.color = KritzelColorHelper.resolveThemeColor(this.fontColor, this._core?.themeManager?.currentTheme);
15784
15796
  if (this.isMounted && this.elementRef === element && this.editor.dom.parentElement === element) {
15785
15797
  if (!this._core.store.state.isScaling && !this._core.store.state.isPanning) {
15786
15798
  requestAnimationFrame(() => this.adjustSizeOnInput());
@@ -18687,7 +18699,7 @@ class KritzelLine extends KritzelBaseObject {
18687
18699
  getArrowFill(end) {
18688
18700
  const config = end === 'start' ? this.arrows?.start : this.arrows?.end;
18689
18701
  const color = config?.fill ?? this.stroke;
18690
- return KritzelColorHelper.resolveThemeColor(color);
18702
+ return KritzelColorHelper.resolveThemeColor(color, this._core?.themeManager?.currentTheme);
18691
18703
  }
18692
18704
  /**
18693
18705
  * Generates SVG path data for an arrow head based on the given style.
@@ -19490,7 +19502,7 @@ class KritzelShape extends KritzelBaseObject {
19490
19502
  }
19491
19503
  element.style.fontFamily = this.fontFamily;
19492
19504
  element.style.fontSize = `${this.fontSize}pt`;
19493
- element.style.color = KritzelColorHelper.resolveThemeColor(this.fontColor);
19505
+ element.style.color = KritzelColorHelper.resolveThemeColor(this.fontColor, this._core?.themeManager?.currentTheme);
19494
19506
  element.style.whiteSpace = 'pre-wrap';
19495
19507
  element.style.wordWrap = 'break-word';
19496
19508
  if (this.editor.dom.parentElement === element) {
@@ -19806,13 +19818,13 @@ class KritzelShape extends KritzelBaseObject {
19806
19818
  this.fontColor = KritzelColorHelper.determineTextColor(this.fillColor);
19807
19819
  // Update the editor's text color immediately
19808
19820
  if (this.editor?.dom?.parentElement) {
19809
- this.editor.dom.parentElement.style.color = KritzelColorHelper.resolveThemeColor(this.fontColor);
19821
+ this.editor.dom.parentElement.style.color = KritzelColorHelper.resolveThemeColor(this.fontColor, this._core?.themeManager?.currentTheme);
19810
19822
  }
19811
19823
  }
19812
19824
  else if (changedProperties.includes('fontColor')) {
19813
19825
  // Also update editor when fontColor changes directly
19814
19826
  if (this.editor?.dom?.parentElement) {
19815
- this.editor.dom.parentElement.style.color = KritzelColorHelper.resolveThemeColor(this.fontColor);
19827
+ this.editor.dom.parentElement.style.color = KritzelColorHelper.resolveThemeColor(this.fontColor, this._core?.themeManager?.currentTheme);
19816
19828
  }
19817
19829
  }
19818
19830
  }
@@ -24676,7 +24688,7 @@ class KritzelLineHandleHandler extends KritzelBaseHandler {
24676
24688
  t: clipInfo?.t,
24677
24689
  edgeX: clipInfo?.edgeX,
24678
24690
  edgeY: clipInfo?.edgeY,
24679
- lineStroke: KritzelColorHelper.resolveThemeColor(line.stroke),
24691
+ lineStroke: KritzelColorHelper.resolveThemeColor(line.stroke, this._core.themeManager.currentTheme),
24680
24692
  lineStrokeWidth: line.strokeWidth / line.scale,
24681
24693
  arrowOffset: endpoint === 'start'
24682
24694
  ? (line.hasStartArrow ? line.getArrowSize('start') / line.scale : undefined)
@@ -30255,7 +30267,7 @@ const KRITZEL_LICENSE_TOKEN_PREFIX = 'KRTZL1.';
30255
30267
  * printed public key here. Replacing this value invalidates every license
30256
30268
  * signed with the previous key.
30257
30269
  */
30258
- const KRITZEL_LICENSE_PUBLIC_KEY = 'I-pYJlxDEjT94rwSaqhXW5Sv__fMKS-JKKnV3pg0PaM';
30270
+ const KRITZEL_LICENSE_PUBLIC_KEY = '2IwZDin-qV3kOt8SEQCqdaJsGT9S7tAGapUYJVnVGQo';
30259
30271
 
30260
30272
  /** Minimum delay (ms) between periodic license re-validations. */
30261
30273
  const MIN_REVALIDATION_DELAY_MS = 30_000;
@@ -30488,8 +30500,64 @@ class KritzelLicenseManager {
30488
30500
  if (typeof claims.exp === 'number' && claims.exp * 1000 <= Date.now()) {
30489
30501
  return { status: 'rejected' }; // Cleanly expired.
30490
30502
  }
30503
+ const allowedDomains = this.normalizeAllowedDomains(claims.allowedDomains);
30504
+ if (allowedDomains === null || allowedDomains.length === 0) {
30505
+ return { status: 'rejected' };
30506
+ }
30507
+ const currentHostname = this.getCurrentHostname();
30508
+ if (!currentHostname || !allowedDomains.includes(currentHostname)) {
30509
+ return { status: 'rejected' };
30510
+ }
30491
30511
  return { status: 'pass', payloadSegment, signatureSegment, claims };
30492
30512
  }
30513
+ /** Returns the normalized current hostname, or null when unavailable/invalid. */
30514
+ getCurrentHostname() {
30515
+ const hostname = globalThis.location?.hostname;
30516
+ if (typeof hostname !== 'string') {
30517
+ return null;
30518
+ }
30519
+ return this.normalizeDomain(hostname);
30520
+ }
30521
+ /** Normalizes and validates the allowed domains claim. */
30522
+ normalizeAllowedDomains(domains) {
30523
+ if (!Array.isArray(domains)) {
30524
+ return null;
30525
+ }
30526
+ const normalized = new Set();
30527
+ for (const entry of domains) {
30528
+ if (typeof entry !== 'string') {
30529
+ return null;
30530
+ }
30531
+ const domain = this.normalizeDomain(entry);
30532
+ if (!domain) {
30533
+ return null;
30534
+ }
30535
+ normalized.add(domain);
30536
+ }
30537
+ return Array.from(normalized);
30538
+ }
30539
+ /** Normalizes a domain and rejects malformed hostnames. */
30540
+ normalizeDomain(value) {
30541
+ const trimmed = value.trim().toLowerCase();
30542
+ if (trimmed.length === 0) {
30543
+ return null;
30544
+ }
30545
+ const withoutTrailingDot = trimmed.endsWith('.') ? trimmed.slice(0, -1) : trimmed;
30546
+ if (withoutTrailingDot.length === 0) {
30547
+ return null;
30548
+ }
30549
+ try {
30550
+ const parsed = new URL(`https://${withoutTrailingDot}`);
30551
+ const normalizedHostname = parsed.hostname.toLowerCase();
30552
+ if (normalizedHostname !== withoutTrailingDot) {
30553
+ return null;
30554
+ }
30555
+ return normalizedHostname;
30556
+ }
30557
+ catch {
30558
+ return null;
30559
+ }
30560
+ }
30493
30561
  /**
30494
30562
  * Verifies the Ed25519 signature of the token against the embedded public
30495
30563
  * key. Resolves true/false for a definitive valid/invalid signature.
@@ -1,5 +1,5 @@
1
- import { H as HocuspocusProvider, a as HocuspocusProviderWebsocket } from './p-uC7_X6yr.js';
2
- export { O as APP_STATE_MIGRATIONS, A as AssetNotFoundError, Q as CURRENT_APP_STATE_SCHEMA_VERSION, R as CURRENT_WORKSPACE_SCHEMA_VERSION, C as DEFAULT_ASSET_STORAGE_CONFIG, D as DEFAULT_BRUSH_CONFIG, B as DEFAULT_LINE_TOOL_CONFIG, z as DEFAULT_TEXT_CONFIG, J as DE_LOCALE, G as EN_LOCALE, L as FR_LOCALE, I as IndexedDBAssetProvider, M as KritzelAlignment, t as KritzelAnchorManager, r as KritzelAssetResolver, K as KritzelBaseObject, i as KritzelBaseTool, j as KritzelBrushTool, p as KritzelCursorHelper, h as KritzelCustomElement, x as KritzelCustomElementRendererRegistry, l as KritzelEraserTool, y as KritzelFontRegistry, f as KritzelGroup, d as KritzelImage, m as KritzelImageTool, w as KritzelLicenseManager, e as KritzelLine, k as KritzelLineTool, v as KritzelLocalizationManager, c as KritzelPath, q as KritzelSelectionTool, g as KritzelShape, o as KritzelShapeTool, b as KritzelText, n as KritzelTextTool, u as KritzelThemeManager, s as KritzelWorkspace, S as ShapeType, W as WORKSPACE_EXPORT_VERSION, P as WORKSPACE_MIGRATIONS, F as darkTheme, E as lightTheme, N as runMigrations } from './p-uC7_X6yr.js';
1
+ import { H as HocuspocusProvider, a as HocuspocusProviderWebsocket } from './p-Rpm1NA9u.js';
2
+ export { O as APP_STATE_MIGRATIONS, A as AssetNotFoundError, Q as CURRENT_APP_STATE_SCHEMA_VERSION, R as CURRENT_WORKSPACE_SCHEMA_VERSION, C as DEFAULT_ASSET_STORAGE_CONFIG, D as DEFAULT_BRUSH_CONFIG, B as DEFAULT_LINE_TOOL_CONFIG, z as DEFAULT_TEXT_CONFIG, J as DE_LOCALE, G as EN_LOCALE, L as FR_LOCALE, I as IndexedDBAssetProvider, M as KritzelAlignment, t as KritzelAnchorManager, r as KritzelAssetResolver, K as KritzelBaseObject, i as KritzelBaseTool, j as KritzelBrushTool, p as KritzelCursorHelper, h as KritzelCustomElement, x as KritzelCustomElementRendererRegistry, l as KritzelEraserTool, y as KritzelFontRegistry, f as KritzelGroup, d as KritzelImage, m as KritzelImageTool, w as KritzelLicenseManager, e as KritzelLine, k as KritzelLineTool, v as KritzelLocalizationManager, c as KritzelPath, q as KritzelSelectionTool, g as KritzelShape, o as KritzelShapeTool, b as KritzelText, n as KritzelTextTool, u as KritzelThemeManager, s as KritzelWorkspace, S as ShapeType, W as WORKSPACE_EXPORT_VERSION, P as WORKSPACE_MIGRATIONS, F as darkTheme, E as lightTheme, N as runMigrations } from './p-Rpm1NA9u.js';
3
3
  import * as Y from 'yjs';
4
4
  import { IndexeddbPersistence } from 'y-indexeddb';
5
5
  import { WebsocketProvider } from 'y-websocket';
@@ -1,5 +1,5 @@
1
1
  import { r as registerInstance, h, H as Host, c as createEvent, g as getElement } from './p-Dhio9uis.js';
2
- import { c as KritzelPath, e as KritzelLine, T as KritzelColorHelper, U as KritzelDevicesHelper, V as KritzelMouseButton, X as KritzelHTMLHelper, Y as DEFAULT_STROKE_SIZES, Z as DEFAULT_COLOR_PALETTE, S as ShapeType, q as KritzelSelectionTool, D as DEFAULT_BRUSH_CONFIG, j as KritzelBrushTool, l as KritzelEraserTool, B as DEFAULT_LINE_TOOL_CONFIG, k as KritzelLineTool, o as KritzelShapeTool, z as DEFAULT_TEXT_CONFIG, n as KritzelTextTool, m as KritzelImageTool, M as KritzelAlignment, C as DEFAULT_ASSET_STORAGE_CONFIG, _ as ObjectHelper, $ as resolveTextToolAvailableFonts, a0 as ThemeHelper, F as darkTheme, E as lightTheme, a1 as KritzelSelectionGroup, a2 as KritzelSelectionBox, a3 as KritzelIconRegistry, y as KritzelFontRegistry, a4 as KritzelKeyboardHelper, a5 as KritzelBaseHandler, s as KritzelWorkspace, f as KritzelGroup, h as KritzelCustomElement, d as KritzelImage, g as KritzelShape, b as KritzelText, N as runMigrations, R as CURRENT_WORKSPACE_SCHEMA_VERSION, P as WORKSPACE_MIGRATIONS, a6 as KritzelClassHelper, Q as CURRENT_APP_STATE_SCHEMA_VERSION, O as APP_STATE_MIGRATIONS, p as KritzelCursorHelper, a7 as KritzelImageFileHelper, a8 as imageCompression, t as KritzelAnchorManager, u as KritzelThemeManager, v as KritzelLocalizationManager, w as KritzelLicenseManager, r as KritzelAssetResolver, a9 as KritzelEventHelper, W as WORKSPACE_EXPORT_VERSION, i as KritzelBaseTool } from './p-uC7_X6yr.js';
2
+ import { c as KritzelPath, e as KritzelLine, T as KritzelColorHelper, U as KritzelDevicesHelper, V as KritzelMouseButton, X as KritzelHTMLHelper, Y as DEFAULT_STROKE_SIZES, Z as DEFAULT_COLOR_PALETTE, S as ShapeType, q as KritzelSelectionTool, D as DEFAULT_BRUSH_CONFIG, j as KritzelBrushTool, l as KritzelEraserTool, B as DEFAULT_LINE_TOOL_CONFIG, k as KritzelLineTool, o as KritzelShapeTool, z as DEFAULT_TEXT_CONFIG, n as KritzelTextTool, m as KritzelImageTool, M as KritzelAlignment, C as DEFAULT_ASSET_STORAGE_CONFIG, _ as ObjectHelper, $ as resolveTextToolAvailableFonts, a0 as ThemeHelper, F as darkTheme, E as lightTheme, a1 as KritzelSelectionGroup, a2 as KritzelSelectionBox, a3 as KritzelIconRegistry, y as KritzelFontRegistry, a4 as KritzelKeyboardHelper, a5 as KritzelBaseHandler, s as KritzelWorkspace, f as KritzelGroup, h as KritzelCustomElement, d as KritzelImage, g as KritzelShape, b as KritzelText, N as runMigrations, R as CURRENT_WORKSPACE_SCHEMA_VERSION, P as WORKSPACE_MIGRATIONS, a6 as KritzelClassHelper, Q as CURRENT_APP_STATE_SCHEMA_VERSION, O as APP_STATE_MIGRATIONS, p as KritzelCursorHelper, a7 as KritzelImageFileHelper, a8 as imageCompression, t as KritzelAnchorManager, u as KritzelThemeManager, v as KritzelLocalizationManager, w as KritzelLicenseManager, r as KritzelAssetResolver, a9 as KritzelEventHelper, W as WORKSPACE_EXPORT_VERSION, i as KritzelBaseTool } from './p-Rpm1NA9u.js';
3
3
  import * as Y from 'yjs';
4
4
  import 'y-indexeddb';
5
5
  import 'y-websocket';
@@ -26262,14 +26262,20 @@ class KritzelSvgExportHelper {
26262
26262
  const scale = this.getObjectScale(text);
26263
26263
  // Convert ProseMirror content to HTML
26264
26264
  const htmlContent = this.prosemirrorToHtml(text.content, text, theme);
26265
- // Calculate dimensions accounting for scale
26265
+ // Calculate dimensions in SVG world units (world units = CSS px in a 1:1 SVG).
26266
26266
  const width = text.totalWidth / scale;
26267
26267
  const height = text.totalHeight / scale;
26268
+ // Convert the font size from pt to SVG world units (px equivalent).
26269
+ // text.fontSize is stored in CSS pt; 1 pt = 4/3 px at 96 dpi.
26270
+ // We also bake in scaleFactor (user resize) and divide by the object scale so
26271
+ // that the rendered font aligns with the world-unit dimensions above.
26272
+ // The CSS transform: scale(scaleFactor) is removed from the div because the
26273
+ // adjusted font-size already accounts for it – keeping both would double-scale
26274
+ // the content and overflow the foreignObject.
26275
+ const svgFontSizePx = (text.fontSize * (4 / 3) * (text.scaleFactor || 1) / scale).toFixed(4);
26268
26276
  return `<g transform="${transform}"${opacity}>
26269
- <foreignObject x="0" y="0" width="${width}" height="${height}">
26270
- <div xmlns="http://www.w3.org/1999/xhtml" style="font-family: ${text.fontFamily}; font-size: ${text.fontSize}pt; color: ${fontColor}; background-color: ${bgColor || 'transparent'}; transform: scale(${text.scaleFactor}); transform-origin: top left; white-space: pre-wrap; word-wrap: break-word;">
26271
- ${htmlContent}
26272
- </div>
26277
+ <foreignObject x="0" y="0" width="${width}" height="${height}" overflow="visible">
26278
+ <div xmlns="http://www.w3.org/1999/xhtml" style="font-family: ${text.fontFamily}; font-size: ${svgFontSizePx}px; color: ${fontColor}; background-color: ${bgColor || 'transparent'}; white-space: pre-wrap; word-wrap: break-word; width: 100%; margin: 0; padding: 0; box-sizing: border-box;">${htmlContent.trim()}</div>
26273
26279
  </foreignObject>
26274
26280
  </g>`;
26275
26281
  }
@@ -26288,9 +26294,13 @@ class KritzelSvgExportHelper {
26288
26294
  const height = text.totalHeight / scale;
26289
26295
  const lines = this.prosemirrorToPlainTextLines(text.content);
26290
26296
  const resolvedLines = lines.length > 0 ? lines : [''];
26291
- const resolvedFontSize = Math.max(1, text.fontSize * (text.scaleFactor || 1));
26292
- const lineHeight = resolvedFontSize * 1.2;
26293
- const startY = resolvedFontSize;
26297
+ // Convert the font size from pt to SVG world units (px equivalent).
26298
+ // text.fontSize is stored in CSS pt; 1 pt = 4/3 px at 96 dpi.
26299
+ // We also bake in scaleFactor (user resize) and divide by the object scale so
26300
+ // that the rendered lines align with the world-unit bounding box dimensions above.
26301
+ const resolvedFontSizePx = Math.max(1, text.fontSize * (4 / 3) * (text.scaleFactor || 1) / scale);
26302
+ const lineHeight = resolvedFontSizePx * 1.2;
26303
+ const startY = resolvedFontSizePx;
26294
26304
  const bgRect = bgColor && bgColor !== 'transparent'
26295
26305
  ? `<rect x="0" y="0" width="${width}" height="${height}" fill="${bgColor}"/>`
26296
26306
  : '';
@@ -26302,7 +26312,7 @@ class KritzelSvgExportHelper {
26302
26312
  .join('');
26303
26313
  return `<g transform="${transform}"${opacity}>
26304
26314
  ${bgRect}
26305
- <text font-family="${this.escapeHtml(text.fontFamily)}" font-size="${resolvedFontSize}" fill="${fontColor}">${tspans}</text>
26315
+ <text font-family="${this.escapeHtml(text.fontFamily)}" font-size="${resolvedFontSizePx}" fill="${fontColor}">${tspans}</text>
26306
26316
  </g>`;
26307
26317
  }
26308
26318
  /**
@@ -29961,7 +29971,9 @@ const KritzelEngine = class {
29961
29971
  this.emitObjectsInViewportChange();
29962
29972
  }
29963
29973
  }
29964
- return (h(Host, null, h("kritzel-loading-overlay", { visible: this.core.store.state.isLoading, text: this.core.localizationManager.translate('engine.loading') }), h("kritzel-sync-indicator", { visible: this.isSyncing, text: "Syncing..." }), this.core.store.state.debugInfo.showViewportInfo && (h("div", { class: "debug-panel" }, h("div", null, "ActiveWorkspaceId: ", this.core.store.state?.activeWorkspace?.id), h("div", null, "ActiveWorkspaceName: ", this.core.store.state?.activeWorkspace?.name), h("div", null, "TranslateX: ", this.core.store.state?.translateX), h("div", null, "TranslateY: ", this.core.store.state?.translateY), h("div", null, "ViewportWidth: ", this.core.store.state?.viewportWidth), h("div", null, "ViewportHeight: ", this.core.store.state?.viewportHeight), h("div", null, "PointerCount: ", this.core.store.state.pointers.size), h("div", null, "Scale: ", this.core.store.state?.scale), h("div", null, "ActiveTool: ", this.core.store.state?.activeTool?.name), h("div", null, "HasViewportChanged: ", this.core.store.state?.hasViewportChanged ? 'true' : 'false'), h("div", null, "IsEnabled: ", this.core.store.state?.isEnabled ? 'true' : 'false'), h("div", null, "IsScaling: ", this.core.store.state?.isScaling ? 'true' : 'false'), h("div", null, "IsPanning: ", this.core.store.state?.isPanning ? 'true' : 'false'), h("div", null, "IsSelecting: ", this.isSelecting ? 'true' : 'false'), h("div", null, "IsSelectionActive: ", this.isSelectionActive ? 'true' : 'false'), h("div", null, "IsResizeHandleSelected: ", this.core.store.state.isResizeHandleSelected ? 'true' : 'false'), h("div", null, "IsRotationHandleSelected: ", this.core.store.state.isRotationHandleSelected ? 'true' : 'false'), h("div", null, "IsRotationHandleHovered: ", this.core.store.state.isRotationHandleHovered ? 'true' : 'false'), h("div", null, "IsDrawing: ", this.core.store.state.isDrawing ? 'true' : 'false'), h("div", null, "IsWriting: ", this.core.store.state.isWriting ? 'true' : 'false'), h("div", null, "IsPointerDown: ", this.core.store.isPointerDown ? 'true' : 'false'), h("div", null, "PointerX: ", this.core.store.state?.pointerX), h("div", null, "PointerY: ", this.core.store.state?.pointerY), h("div", null, "TotalObjects: ", this.core.store.totalObjectCount), h("div", null, "ObjectsInViewport: ", this.core.store.objectsInViewport.length), h("div", null, "SelectedObjects: ", this.core.store.selectionGroup?.objects.length || 0), h("div", null, "ViewportCenter: (", viewportCenterX.toFixed(2), ", ", viewportCenterY.toFixed(2), ")"))), h("div", { id: "origin", class: "origin", style: {
29974
+ return (h(Host, null, h("kritzel-loading-overlay", { visible: this.core.store.state.isLoading, text: this.core.localizationManager.translate('engine.loading') }), h("kritzel-sync-indicator", { visible: this.isSyncing, text: "Syncing..." }), this.core.store.state.debugInfo.showViewportInfo && (h("div", { class: "debug-panel", style: {
29975
+ color: 'var(--kritzel-global-text-primary)',
29976
+ } }, h("div", null, "ActiveWorkspaceId: ", this.core.store.state?.activeWorkspace?.id), h("div", null, "ActiveWorkspaceName: ", this.core.store.state?.activeWorkspace?.name), h("div", null, "TranslateX: ", this.core.store.state?.translateX), h("div", null, "TranslateY: ", this.core.store.state?.translateY), h("div", null, "ViewportWidth: ", this.core.store.state?.viewportWidth), h("div", null, "ViewportHeight: ", this.core.store.state?.viewportHeight), h("div", null, "PointerCount: ", this.core.store.state.pointers.size), h("div", null, "Scale: ", this.core.store.state?.scale), h("div", null, "ActiveTool: ", this.core.store.state?.activeTool?.name), h("div", null, "HasViewportChanged: ", this.core.store.state?.hasViewportChanged ? 'true' : 'false'), h("div", null, "IsEnabled: ", this.core.store.state?.isEnabled ? 'true' : 'false'), h("div", null, "IsScaling: ", this.core.store.state?.isScaling ? 'true' : 'false'), h("div", null, "IsPanning: ", this.core.store.state?.isPanning ? 'true' : 'false'), h("div", null, "IsSelecting: ", this.isSelecting ? 'true' : 'false'), h("div", null, "IsSelectionActive: ", this.isSelectionActive ? 'true' : 'false'), h("div", null, "IsResizeHandleSelected: ", this.core.store.state.isResizeHandleSelected ? 'true' : 'false'), h("div", null, "IsRotationHandleSelected: ", this.core.store.state.isRotationHandleSelected ? 'true' : 'false'), h("div", null, "IsRotationHandleHovered: ", this.core.store.state.isRotationHandleHovered ? 'true' : 'false'), h("div", null, "IsDrawing: ", this.core.store.state.isDrawing ? 'true' : 'false'), h("div", null, "IsWriting: ", this.core.store.state.isWriting ? 'true' : 'false'), h("div", null, "IsPointerDown: ", this.core.store.isPointerDown ? 'true' : 'false'), h("div", null, "PointerX: ", this.core.store.state?.pointerX), h("div", null, "PointerY: ", this.core.store.state?.pointerY), h("div", null, "TotalObjects: ", this.core.store.totalObjectCount), h("div", null, "ObjectsInViewport: ", this.core.store.objectsInViewport.length), h("div", null, "SelectedObjects: ", this.core.store.selectionGroup?.objects.length || 0), h("div", null, "ViewportCenter: (", viewportCenterX.toFixed(2), ", ", viewportCenterY.toFixed(2), ")"))), h("div", { id: "origin", class: "origin", style: {
29965
29977
  transform: `matrix(${this.core.store.state?.scale}, 0, 0, ${this.core.store.state?.scale}, ${this.core.store.state?.translateX}, ${this.core.store.state?.translateY})`,
29966
29978
  opacity: this._sceneBootstrapOpacity.toString(),
29967
29979
  transition: this._sceneBootstrapTransitionEnabled ? 'opacity 220ms ease-out' : 'none',
@@ -30144,6 +30156,7 @@ const KritzelEngine = class {
30144
30156
  left: `${object.totalWidth}px`,
30145
30157
  top: '0',
30146
30158
  zIndex: (object.zIndex + 2).toString(),
30159
+ color: 'var(--kritzel-global-text-primary)',
30147
30160
  } }, h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "Id: ", object.id), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "userId: ", object.userId), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "width: ", object.width), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "height: ", object.height), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateX: ", object.translateX), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateY: ", object.translateY), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "scale: ", object.scale), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "rotationDegrees: ", object.rotationDegrees), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "zIndex: ", object.zIndex), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "isSelected: ", object.isSelected ? 'true' : 'false'), KritzelClassHelper.isInstanceOf(object, 'KritzelCustomElement') && (h("div", null, h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "isInteractive: ", object.isInteractive ? 'true' : 'false'))), KritzelClassHelper.isInstanceOf(object, 'KritzelImage') && (h("div", null, h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "assetId: ", object.assetId), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "mimeType: ", object.mimeType))))), (this.core.displaySelectionGroupUI(object) || this.core.displaySelectionLineUI(object)) &&
30148
30161
  (() => {
30149
30162
  const isSelectionGroup = KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup');
@@ -30344,8 +30357,12 @@ const KritzelEngine = class {
30344
30357
  strokeDasharray: data.dashArray,
30345
30358
  strokeLinecap: 'round',
30346
30359
  } }))), h("circle", { cx: data.centerX, cy: data.centerY, r: data.indicatorRadius, style: {
30347
- fill: isActiveSnap ? 'var(--kritzel-snap-indicator-fill, rgba(59, 130, 246, 0.3))' : 'rgba(59, 130, 246, 0.18)',
30348
- stroke: isActiveSnap ? 'var(--kritzel-snap-indicator-stroke, #007bff)' : 'rgba(59, 130, 246, 0.5)',
30360
+ fill: isActiveSnap
30361
+ ? 'var(--kritzel-snap-indicator-fill, rgba(59, 130, 246, 0.3))'
30362
+ : 'var(--kritzel-snap-indicator-fill-inactive, var(--kritzel-snap-indicator-fill, rgba(59, 130, 246, 0.18)))',
30363
+ stroke: isActiveSnap
30364
+ ? 'var(--kritzel-snap-indicator-stroke, #007bff)'
30365
+ : 'var(--kritzel-snap-indicator-stroke-inactive, var(--kritzel-snap-indicator-stroke, rgba(59, 130, 246, 0.5)))',
30349
30366
  strokeWidth: data.indicatorStrokeWidth,
30350
30367
  } }))));
30351
30368
  })(), (() => {
@@ -31818,7 +31835,7 @@ const KritzelPortal = class {
31818
31835
  * This file is auto-generated by the version bump scripts.
31819
31836
  * Do not modify manually.
31820
31837
  */
31821
- const KRITZEL_VERSION = '0.4.7';
31838
+ const KRITZEL_VERSION = '0.4.8';
31822
31839
 
31823
31840
  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-tab-panel{display:none}.settings-tab-panel.is-active{display:block}.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)}`;
31824
31841
 
@@ -14557,7 +14557,9 @@ const lightTheme = {
14557
14557
  },
14558
14558
  snap: {
14559
14559
  indicatorFill: 'rgba(59, 130, 246, 0.3)',
14560
+ indicatorFillInactive: 'rgba(59, 130, 246, 0.18)',
14560
14561
  indicatorStroke: '#007bff',
14562
+ indicatorStrokeInactive: 'rgba(59, 130, 246, 0.5)',
14561
14563
  lineStroke: 'rgba(0, 0, 0, 0.2)',
14562
14564
  },
14563
14565
  fontSize: {
@@ -14894,7 +14896,9 @@ const darkTheme = {
14894
14896
  },
14895
14897
  snap: {
14896
14898
  indicatorFill: 'rgba(10, 132, 255, 0.35)',
14899
+ indicatorFillInactive: 'rgba(10, 132, 255, 0.2)',
14897
14900
  indicatorStroke: '#0A84FF',
14901
+ indicatorStrokeInactive: 'rgba(255, 255, 255, 0.45)',
14898
14902
  lineStroke: 'rgba(255, 255, 255, 0.35)',
14899
14903
  },
14900
14904
  fontSize: {
@@ -15094,6 +15098,7 @@ const darkTheme = {
15094
15098
  };
15095
15099
 
15096
15100
  class ThemeHelper {
15101
+ static appliedVariableNames = new WeakMap();
15097
15102
  /**
15098
15103
  * Converts a camelCase string to kebab-case.
15099
15104
  * @example ThemeHelper.camelToKebab('controlHoverBackgroundColor') → 'control-hover-background-color'
@@ -15159,7 +15164,14 @@ class ThemeHelper {
15159
15164
  */
15160
15165
  static applyThemeToElement(element, theme) {
15161
15166
  const variables = ThemeHelper.flattenThemeToVariables(theme);
15167
+ const previousVariableNames = ThemeHelper.appliedVariableNames.get(element);
15168
+ for (const name of previousVariableNames ?? []) {
15169
+ if (!variables.has(name)) {
15170
+ element.style.removeProperty(name);
15171
+ }
15172
+ }
15162
15173
  ThemeHelper.applyVariablesToElement(element, variables);
15174
+ ThemeHelper.appliedVariableNames.set(element, new Set(variables.keys()));
15163
15175
  }
15164
15176
  }
15165
15177
 
@@ -15780,7 +15792,7 @@ class KritzelText extends KritzelBaseObject {
15780
15792
  }
15781
15793
  element.style.fontFamily = KritzelFontRegistry.resolveCssFontFamily(this.fontFamily);
15782
15794
  element.style.fontSize = `${this.fontSize}pt`;
15783
- element.style.color = KritzelColorHelper.resolveThemeColor(this.fontColor);
15795
+ element.style.color = KritzelColorHelper.resolveThemeColor(this.fontColor, this._core?.themeManager?.currentTheme);
15784
15796
  if (this.isMounted && this.elementRef === element && this.editor.dom.parentElement === element) {
15785
15797
  if (!this._core.store.state.isScaling && !this._core.store.state.isPanning) {
15786
15798
  requestAnimationFrame(() => this.adjustSizeOnInput());
@@ -18687,7 +18699,7 @@ class KritzelLine extends KritzelBaseObject {
18687
18699
  getArrowFill(end) {
18688
18700
  const config = end === 'start' ? this.arrows?.start : this.arrows?.end;
18689
18701
  const color = config?.fill ?? this.stroke;
18690
- return KritzelColorHelper.resolveThemeColor(color);
18702
+ return KritzelColorHelper.resolveThemeColor(color, this._core?.themeManager?.currentTheme);
18691
18703
  }
18692
18704
  /**
18693
18705
  * Generates SVG path data for an arrow head based on the given style.
@@ -19490,7 +19502,7 @@ class KritzelShape extends KritzelBaseObject {
19490
19502
  }
19491
19503
  element.style.fontFamily = this.fontFamily;
19492
19504
  element.style.fontSize = `${this.fontSize}pt`;
19493
- element.style.color = KritzelColorHelper.resolveThemeColor(this.fontColor);
19505
+ element.style.color = KritzelColorHelper.resolveThemeColor(this.fontColor, this._core?.themeManager?.currentTheme);
19494
19506
  element.style.whiteSpace = 'pre-wrap';
19495
19507
  element.style.wordWrap = 'break-word';
19496
19508
  if (this.editor.dom.parentElement === element) {
@@ -19806,13 +19818,13 @@ class KritzelShape extends KritzelBaseObject {
19806
19818
  this.fontColor = KritzelColorHelper.determineTextColor(this.fillColor);
19807
19819
  // Update the editor's text color immediately
19808
19820
  if (this.editor?.dom?.parentElement) {
19809
- this.editor.dom.parentElement.style.color = KritzelColorHelper.resolveThemeColor(this.fontColor);
19821
+ this.editor.dom.parentElement.style.color = KritzelColorHelper.resolveThemeColor(this.fontColor, this._core?.themeManager?.currentTheme);
19810
19822
  }
19811
19823
  }
19812
19824
  else if (changedProperties.includes('fontColor')) {
19813
19825
  // Also update editor when fontColor changes directly
19814
19826
  if (this.editor?.dom?.parentElement) {
19815
- this.editor.dom.parentElement.style.color = KritzelColorHelper.resolveThemeColor(this.fontColor);
19827
+ this.editor.dom.parentElement.style.color = KritzelColorHelper.resolveThemeColor(this.fontColor, this._core?.themeManager?.currentTheme);
19816
19828
  }
19817
19829
  }
19818
19830
  }
@@ -24676,7 +24688,7 @@ class KritzelLineHandleHandler extends KritzelBaseHandler {
24676
24688
  t: clipInfo?.t,
24677
24689
  edgeX: clipInfo?.edgeX,
24678
24690
  edgeY: clipInfo?.edgeY,
24679
- lineStroke: KritzelColorHelper.resolveThemeColor(line.stroke),
24691
+ lineStroke: KritzelColorHelper.resolveThemeColor(line.stroke, this._core.themeManager.currentTheme),
24680
24692
  lineStrokeWidth: line.strokeWidth / line.scale,
24681
24693
  arrowOffset: endpoint === 'start'
24682
24694
  ? (line.hasStartArrow ? line.getArrowSize('start') / line.scale : undefined)
@@ -30255,7 +30267,7 @@ const KRITZEL_LICENSE_TOKEN_PREFIX = 'KRTZL1.';
30255
30267
  * printed public key here. Replacing this value invalidates every license
30256
30268
  * signed with the previous key.
30257
30269
  */
30258
- const KRITZEL_LICENSE_PUBLIC_KEY = 'I-pYJlxDEjT94rwSaqhXW5Sv__fMKS-JKKnV3pg0PaM';
30270
+ const KRITZEL_LICENSE_PUBLIC_KEY = '2IwZDin-qV3kOt8SEQCqdaJsGT9S7tAGapUYJVnVGQo';
30259
30271
 
30260
30272
  /** Minimum delay (ms) between periodic license re-validations. */
30261
30273
  const MIN_REVALIDATION_DELAY_MS = 30_000;
@@ -30488,8 +30500,64 @@ class KritzelLicenseManager {
30488
30500
  if (typeof claims.exp === 'number' && claims.exp * 1000 <= Date.now()) {
30489
30501
  return { status: 'rejected' }; // Cleanly expired.
30490
30502
  }
30503
+ const allowedDomains = this.normalizeAllowedDomains(claims.allowedDomains);
30504
+ if (allowedDomains === null || allowedDomains.length === 0) {
30505
+ return { status: 'rejected' };
30506
+ }
30507
+ const currentHostname = this.getCurrentHostname();
30508
+ if (!currentHostname || !allowedDomains.includes(currentHostname)) {
30509
+ return { status: 'rejected' };
30510
+ }
30491
30511
  return { status: 'pass', payloadSegment, signatureSegment, claims };
30492
30512
  }
30513
+ /** Returns the normalized current hostname, or null when unavailable/invalid. */
30514
+ getCurrentHostname() {
30515
+ const hostname = globalThis.location?.hostname;
30516
+ if (typeof hostname !== 'string') {
30517
+ return null;
30518
+ }
30519
+ return this.normalizeDomain(hostname);
30520
+ }
30521
+ /** Normalizes and validates the allowed domains claim. */
30522
+ normalizeAllowedDomains(domains) {
30523
+ if (!Array.isArray(domains)) {
30524
+ return null;
30525
+ }
30526
+ const normalized = new Set();
30527
+ for (const entry of domains) {
30528
+ if (typeof entry !== 'string') {
30529
+ return null;
30530
+ }
30531
+ const domain = this.normalizeDomain(entry);
30532
+ if (!domain) {
30533
+ return null;
30534
+ }
30535
+ normalized.add(domain);
30536
+ }
30537
+ return Array.from(normalized);
30538
+ }
30539
+ /** Normalizes a domain and rejects malformed hostnames. */
30540
+ normalizeDomain(value) {
30541
+ const trimmed = value.trim().toLowerCase();
30542
+ if (trimmed.length === 0) {
30543
+ return null;
30544
+ }
30545
+ const withoutTrailingDot = trimmed.endsWith('.') ? trimmed.slice(0, -1) : trimmed;
30546
+ if (withoutTrailingDot.length === 0) {
30547
+ return null;
30548
+ }
30549
+ try {
30550
+ const parsed = new URL(`https://${withoutTrailingDot}`);
30551
+ const normalizedHostname = parsed.hostname.toLowerCase();
30552
+ if (normalizedHostname !== withoutTrailingDot) {
30553
+ return null;
30554
+ }
30555
+ return normalizedHostname;
30556
+ }
30557
+ catch {
30558
+ return null;
30559
+ }
30560
+ }
30493
30561
  /**
30494
30562
  * Verifies the Ed25519 signature of the token against the embedded public
30495
30563
  * key. Resolves true/false for a definitive valid/invalid signature.
@@ -17,5 +17,5 @@ var patchBrowser = () => {
17
17
 
18
18
  patchBrowser().then(async (options) => {
19
19
  await globalScripts();
20
- return bootstrapLazy(JSON.parse("[[\"p-472f2e90\",[[512,\"kritzel-editor\",{\"scaleMax\":[1026,\"scale-max\"],\"scaleMin\":[1026,\"scale-min\"],\"lockDrawingScale\":[1028,\"lock-drawing-scale\"],\"viewportBoundaryLeft\":[1026,\"viewport-boundary-left\"],\"viewportBoundaryRight\":[1026,\"viewport-boundary-right\"],\"viewportBoundaryTop\":[1026,\"viewport-boundary-top\"],\"viewportBoundaryBottom\":[1026,\"viewport-boundary-bottom\"],\"debugInfo\":[1040],\"user\":[16],\"activeUsers\":[16],\"controls\":[16],\"globalContextMenuItems\":[16],\"objectContextMenuItems\":[16],\"themes\":[16],\"theme\":[1025],\"licenseKey\":[1,\"license-key\"],\"locale\":[1025],\"locales\":[16],\"fallbackLocale\":[1,\"fallback-locale\"],\"customSvgIcons\":[16],\"customFonts\":[16],\"isPanningEnabled\":[1028,\"is-panning-enabled\"],\"isZoomingEnabled\":[1028,\"is-zooming-enabled\"],\"isControlsVisible\":[4,\"is-controls-visible\"],\"isUtilityPanelVisible\":[4,\"is-utility-panel-visible\"],\"isWorkspaceManagerVisible\":[4,\"is-workspace-manager-visible\"],\"isMoreMenuVisible\":[4,\"is-more-menu-visible\"],\"isZoomPanelVisible\":[4,\"is-zoom-panel-visible\"],\"isObjectDistanceFadingActive\":[4,\"is-object-distance-fading-active\"],\"syncConfig\":[16],\"assetStorageConfig\":[16],\"cursorTarget\":[16],\"loginConfig\":[16],\"isLoading\":[4,\"is-loading\"],\"editorId\":[1,\"editor-id\"],\"activeWorkspaceId\":[1,\"active-workspace-id\"],\"isEngineReady\":[32],\"isControlsReady\":[32],\"isWorkspaceManagerReady\":[32],\"workspaces\":[32],\"activeWorkspace\":[32],\"isVirtualKeyboardOpen\":[32],\"undoState\":[32],\"isBackToContentButtonVisible\":[32],\"resolvedTerms\":[32],\"availableLocaleOptions\":[32],\"currentZoomPercent\":[32],\"shortcuts\":[32],\"currentIsPublic\":[32],\"isEditorVisible\":[32],\"activeNotification\":[32],\"isNotificationDismissing\":[32],\"contextMenuState\":[32],\"normalizedControls\":[32],\"getObjectById\":[64],\"addObject\":[64],\"addObjects\":[64],\"updateObject\":[64],\"removeObject\":[64],\"removeObjects\":[64],\"getSelectedObjects\":[64],\"selectObjects\":[64],\"selectAllObjectsInViewport\":[64],\"clearSelection\":[64],\"centerObjectInViewport\":[64],\"panToObject\":[64],\"backToContent\":[64],\"centerAllObjects\":[64],\"centerObjects\":[64],\"setViewport\":[64],\"panTo\":[64],\"zoomTo\":[64],\"zoomIn\":[64],\"zoomOut\":[64],\"getViewport\":[64],\"screenToWorld\":[64],\"worldToScreen\":[64],\"createWorkspace\":[64],\"updateWorkspace\":[64],\"deleteWorkspace\":[64],\"getWorkspaces\":[64],\"getActiveWorkspace\":[64],\"loadSharedWorkspace\":[64],\"reinitSync\":[64],\"registerTool\":[64],\"changeActiveTool\":[64],\"changeActiveToolByName\":[64],\"disable\":[64],\"enable\":[64],\"copy\":[64],\"cut\":[64],\"paste\":[64],\"delete\":[64],\"bringForward\":[64],\"sendBackward\":[64],\"bringToFront\":[64],\"sendToBack\":[64],\"alignObjects\":[64],\"group\":[64],\"ungroup\":[64],\"undo\":[64],\"redo\":[64],\"getScreenshot\":[64],\"exportViewportAsPng\":[64],\"exportViewportAsSvg\":[64],\"exportSelectedObjectsAsPng\":[64],\"exportSelectedObjectsAsSvg\":[64],\"downloadAsJson\":[64],\"importFromFile\":[64],\"loadObjectsFromJson\":[64],\"getObjectsTotalCount\":[64],\"getAllObjects\":[64],\"findObjects\":[64],\"getObjectsInViewport\":[64],\"hideContextMenu\":[64],\"openContextMenu\":[64],\"triggerSelectionChange\":[64],\"beginSceneBootstrap\":[64],\"endSceneBootstrap\":[64],\"getDisplayableShortcuts\":[64],\"triggerNotification\":[64],\"openLoginDialog\":[64],\"setLoginLoading\":[64],\"setLocale\":[64],\"getLocale\":[64],\"getAvailableLocales\":[64],\"registerLocales\":[64],\"registerFonts\":[64],\"t\":[64]},[[0,\"dblclick\",\"onTouchStart\"]],{\"isEngineReady\":[{\"onIsEngineReady\":0}],\"isControlsReady\":[{\"onIsControlsReady\":0}],\"workspaces\":[{\"onWorkspacesChange\":0}],\"activeWorkspace\":[{\"onActiveWorkspaceChange\":0}],\"customFonts\":[{\"onCustomFontsChange\":0}],\"controls\":[{\"onControlsChange\":0}],\"activeWorkspaceId\":[{\"onActiveWorkspaceIdChange\":0}],\"theme\":[{\"onCurrentThemeChange\":0}],\"themes\":[{\"onThemesChange\":0}],\"locale\":[{\"onLocaleChange\":0}]}],[513,\"kritzel-controls\",{\"visible\":[4],\"controls\":[16],\"activeControl\":[1040],\"isUtilityPanelVisible\":[4,\"is-utility-panel-visible\"],\"undoState\":[16],\"theme\":[1],\"terms\":[16],\"firstConfig\":[32],\"isTouchDevice\":[32],\"selectedSubOptions\":[32],\"canScrollLeft\":[32],\"canScrollRight\":[32],\"needsScrolling\":[32],\"displayValues\":[32],\"internalControls\":[32],\"closeTooltip\":[64]},[[8,\"keydown\",\"handleKeyDown\"]],{\"controls\":[{\"onControlsChange\":0}],\"theme\":[{\"onThemeChange\":0}]}],[513,\"kritzel-engine\",{\"workspace\":[16],\"editorId\":[1,\"editor-id\"],\"activeWorkspaceId\":[1,\"active-workspace-id\"],\"syncConfig\":[16],\"assetStorageConfig\":[16],\"user\":[16],\"globalContextMenuItems\":[16],\"objectContextMenuItems\":[16],\"scaleMax\":[1026,\"scale-max\"],\"scaleMin\":[1026,\"scale-min\"],\"cursorTarget\":[16],\"lockDrawingScale\":[4,\"lock-drawing-scale\"],\"isObjectDistanceFadingActive\":[4,\"is-object-distance-fading-active\"],\"theme\":[1],\"licenseKey\":[1,\"license-key\"],\"themes\":[16],\"locale\":[1],\"locales\":[16],\"fallbackLocale\":[1,\"fallback-locale\"],\"viewportBoundaryLeft\":[2,\"viewport-boundary-left\"],\"viewportBoundaryRight\":[2,\"viewport-boundary-right\"],\"viewportBoundaryTop\":[2,\"viewport-boundary-top\"],\"viewportBoundaryBottom\":[2,\"viewport-boundary-bottom\"],\"debugInfo\":[16],\"isPanningEnabled\":[4,\"is-panning-enabled\"],\"isZoomingEnabled\":[4,\"is-zooming-enabled\"],\"isLoading\":[4,\"is-loading\"],\"forceUpdate\":[32],\"isSyncing\":[32],\"triggerSelectionChange\":[64],\"beginSceneBootstrap\":[64],\"endSceneBootstrap\":[64],\"registerTool\":[64],\"changeActiveTool\":[64],\"changeActiveToolByName\":[64],\"disable\":[64],\"enable\":[64],\"delete\":[64],\"copy\":[64],\"cut\":[64],\"paste\":[64],\"bringForward\":[64],\"sendBackward\":[64],\"bringToFront\":[64],\"sendToBack\":[64],\"alignObjects\":[64],\"group\":[64],\"ungroup\":[64],\"undo\":[64],\"redo\":[64],\"hideContextMenu\":[64],\"openContextMenu\":[64],\"getObjectById\":[64],\"getAllObjects\":[64],\"findObjects\":[64],\"getObjectsTotalCount\":[64],\"addObject\":[64],\"addObjects\":[64],\"updateObject\":[64],\"removeObject\":[64],\"removeObjects\":[64],\"getSelectedObjects\":[64],\"getDisplayableShortcuts\":[64],\"selectObjects\":[64],\"selectAllObjectsInViewport\":[64],\"clearSelection\":[64],\"centerObjectInViewport\":[64],\"panToObject\":[64],\"backToContent\":[64],\"centerAllObjects\":[64],\"centerObjects\":[64],\"setViewport\":[64],\"panTo\":[64],\"zoomTo\":[64],\"zoomIn\":[64],\"zoomOut\":[64],\"getViewport\":[64],\"screenToWorld\":[64],\"worldToScreen\":[64],\"getObjectsInViewport\":[64],\"getScreenshot\":[64],\"exportViewportAsPng\":[64],\"exportViewportAsSvg\":[64],\"getSelectedObjectsAsSvgString\":[64],\"exportSelectedObjectsAsSvg\":[64],\"getSelectedObjectsAsPngDataUrl\":[64],\"exportSelectedObjectsAsPng\":[64],\"exportAsJson\":[64],\"importFromJson\":[64],\"loadObjectsFromJson\":[64],\"downloadAsJson\":[64],\"importFromFile\":[64],\"createWorkspace\":[64],\"updateWorkspace\":[64],\"deleteWorkspace\":[64],\"getWorkspaces\":[64],\"getActiveWorkspace\":[64],\"getIsPublic\":[64],\"loadSharedWorkspace\":[64],\"reinitSync\":[64],\"saveSettings\":[64],\"loadSettings\":[64],\"registerLocales\":[64],\"setLocale\":[64],\"getLocale\":[64],\"getAvailableLocales\":[64],\"getAvailableLocaleOptions\":[64],\"t\":[64],\"getResolvedTerms\":[64]},[[1,\"wheel\",\"handleWheel\"],[0,\"pointerdown\",\"handlePointerDown\"],[0,\"pointermove\",\"handlePointerMove\"],[0,\"pointerup\",\"handlePointerUp\"],[0,\"pointercancel\",\"handlePointerCancel\"],[1,\"pointerleave\",\"handlePointerLeave\"],[1,\"longpress\",\"handleLongPress\"],[0,\"contextmenu\",\"handleContextMenu\"],[9,\"resize\",\"handleResize\"],[8,\"keydown\",\"handleKeyDown\"],[8,\"keyup\",\"handleKeyUp\"],[8,\"copy\",\"handleCopy\"],[8,\"cut\",\"handleCut\"],[8,\"paste\",\"handlePaste\"],[4,\"dblclick\",\"preventDoubleTapZoomOnTouchDevices\"]],{\"workspace\":[{\"onWorkspaceChange\":0}],\"activeWorkspaceId\":[{\"onActiveWorkspaceIdChange\":0}],\"syncConfig\":[{\"onSyncConfigChange\":0}],\"assetStorageConfig\":[{\"onAssetStorageConfigChange\":0}],\"user\":[{\"onUserChange\":0}],\"globalContextMenuItems\":[{\"onGlobalContextMenuItemsChange\":0}],\"objectContextMenuItems\":[{\"onObjectContextMenuItemsChange\":0}],\"scaleMax\":[{\"validateScaleMax\":0}],\"scaleMin\":[{\"validateScaleMin\":0}],\"cursorTarget\":[{\"onCursorTargetChange\":0}],\"lockDrawingScale\":[{\"onLockDrawingScaleChange\":0}],\"isObjectDistanceFadingActive\":[{\"onIsObjectDistanceFadingActiveChange\":0}],\"theme\":[{\"onThemeChange\":0}],\"licenseKey\":[{\"onLicenseKeyChange\":0}],\"themes\":[{\"onThemesChange\":0}],\"locale\":[{\"onLocaleChange\":0}],\"locales\":[{\"onLocalesChange\":0}],\"fallbackLocale\":[{\"onFallbackLocaleChange\":0}],\"viewportBoundaryLeft\":[{\"onViewportBoundaryLeftChange\":0}],\"viewportBoundaryRight\":[{\"onViewportBoundaryRightChange\":0}],\"viewportBoundaryTop\":[{\"onViewportBoundaryTopChange\":0}],\"viewportBoundaryBottom\":[{\"onViewportBoundaryBottomChange\":0}],\"debugInfo\":[{\"onDebugInfoChange\":0}],\"isLoading\":[{\"onIsLoadingChange\":0}]}],[513,\"kritzel-settings\",{\"availableThemes\":[16],\"availableLocales\":[16],\"shortcuts\":[16],\"terms\":[16],\"settings\":[16],\"isDialogOpen\":[32],\"selectedCategoryId\":[32],\"scaleMin\":[32],\"scaleMax\":[32],\"lockDrawingScale\":[32],\"theme\":[32],\"locale\":[32],\"viewportBoundaryLeft\":[32],\"viewportBoundaryRight\":[32],\"viewportBoundaryTop\":[32],\"viewportBoundaryBottom\":[32],\"debugInfo\":[32],\"open\":[64]},null,{\"settings\":[{\"onSettingsPropChange\":0}]}],[513,\"kritzel-export\",{\"workspaceName\":[1,\"workspace-name\"],\"terms\":[16],\"isDialogOpen\":[32],\"previewUrl\":[32],\"isLoading\":[32],\"activeTab\":[32],\"exportFilename\":[32],\"viewportExportFormat\":[32],\"open\":[64]}],[513,\"kritzel-workspace-manager\",{\"visible\":[4],\"activeWorkspace\":[1040],\"workspaces\":[16],\"terms\":[16],\"childMenuAnchor\":[32],\"openChildMenuItem\":[32],\"newWorkspace\":[32],\"editingItemId\":[32]},[[8,\"wheel\",\"handleWheel\"]]],[513,\"kritzel-more-menu\",{\"visible\":[4],\"items\":[16],\"icon\":[1],\"iconSize\":[2,\"icon-size\"],\"offsetY\":[2,\"offset-y\"],\"terms\":[16],\"menuAnchor\":[32],\"isTouchDevice\":[32]}],[513,\"kritzel-current-user-dialog\",{\"user\":[16],\"terms\":[16],\"isDialogOpen\":[32],\"open\":[64],\"close\":[64]}],[513,\"kritzel-share-dialog\",{\"isPublic\":[4,\"is-public\"],\"workspaceId\":[1,\"workspace-id\"],\"terms\":[16],\"isDialogOpen\":[32],\"internalIsPublic\":[32],\"copySuccess\":[32],\"qrCodeDataUrl\":[32],\"open\":[64],\"close\":[64]},null,{\"isPublic\":[{\"onIsPublicChange\":0}],\"workspaceId\":[{\"onWorkspaceIdChange\":0}]}],[513,\"kritzel-login-dialog\",{\"providers\":[16],\"dialogTitle\":[1,\"dialog-title\"],\"subtitle\":[1],\"isDialogOpen\":[32],\"loadingProvider\":[32],\"open\":[64],\"close\":[64],\"setLoading\":[64]}],[513,\"kritzel-active-users\",{\"users\":[16],\"avatarSize\":[2,\"avatar-size\"],\"maxVisible\":[2,\"max-visible\"],\"overlap\":[2]}],[513,\"kritzel-back-to-content\",{\"visible\":[4],\"text\":[1]}],[513,\"kritzel-context-menu\",{\"items\":[16],\"objects\":[16],\"processedItems\":[32],\"openSubmenuPath\":[32],\"submenuPositions\":[32]},[[9,\"pointerdown\",\"handleOutsideClick\"]],{\"items\":[{\"onItemsChanged\":0}]}],[513,\"kritzel-current-user\",{\"user\":[16],\"avatarSize\":[2,\"avatar-size\"],\"terms\":[16]}],[513,\"kritzel-notification-card\",{\"notification\":[16],\"showTimestamp\":[4,\"show-timestamp\"],\"locale\":[1]}],[513,\"kritzel-zoom-panel\",{\"visible\":[4],\"disabled\":[4],\"zoomPercent\":[2,\"zoom-percent\"],\"terms\":[16]}],[513,\"kritzel-tool-config\",{\"tool\":[1040],\"isExpanded\":[1028,\"is-expanded\"],\"theme\":[1],\"engine\":[16],\"terms\":[16],\"config\":[32],\"palette\":[32],\"sizes\":[32],\"currentOpacity\":[32],\"updateTrigger\":[32]},null,{\"tool\":[{\"handleToolChange\":0}],\"theme\":[{\"onThemeChange\":0}],\"engine\":[{\"handleEngineChange\":0}]}],[513,\"kritzel-split-button\",{\"buttonIcon\":[1,\"button-icon\"],\"dropdownIcon\":[1,\"dropdown-icon\"],\"items\":[16],\"mainButtonDisabled\":[4,\"main-button-disabled\"],\"menuButtonDisabled\":[4,\"menu-button-disabled\"],\"isMenuOpen\":[32],\"isTouchDevice\":[32],\"anchorElement\":[32],\"menuScrollTop\":[32],\"open\":[64],\"focusMenu\":[64]}],[769,\"kritzel-master-detail\",{\"items\":[16],\"selectedItemId\":[1,\"selected-item-id\"],\"focusedIndex\":[32],\"showMobileDetail\":[32]},null,{\"selectedItemId\":[{\"watchSelectedItemId\":0}]}],[513,\"kritzel-pill-tabs\",{\"tabs\":[16],\"value\":[1025]}],[513,\"kritzel-utility-panel\",{\"undoState\":[16],\"terms\":[16]}],[513,\"kritzel-awareness-cursors\",{\"core\":[16],\"showEdgeIndicators\":[4,\"show-edge-indicators\"],\"edgeIndicatorPadding\":[2,\"edge-indicator-padding\"],\"remoteCursors\":[32],\"objectVersion\":[32]}],[769,\"kritzel-button\",{\"variant\":[1],\"disabled\":[4],\"type\":[1]}],[513,\"kritzel-cursor-trail\",{\"core\":[16],\"cursorTrailPoints\":[32],\"isLeftButtonDown\":[32]},[[9,\"pointerdown\",\"handleMouseDown\"],[9,\"pointermove\",\"handlePointerMove\"],[9,\"pointerup\",\"handlePointerUp\"]]],[513,\"kritzel-input\",{\"value\":[1025],\"label\":[1],\"placeholder\":[1],\"suffix\":[1],\"type\":[1],\"disabled\":[4],\"inputValue\":[32]},null,{\"value\":[{\"onValueChange\":0}]}],[513,\"kritzel-loading-overlay\",{\"visible\":[4],\"text\":[1]}],[513,\"kritzel-numeric-input\",{\"value\":[1026],\"min\":[2],\"max\":[2],\"step\":[2],\"label\":[1],\"placeholder\":[1],\"inputValue\":[32]},null,{\"value\":[{\"onValueChange\":0}]}],[513,\"kritzel-sync-indicator\",{\"visible\":[4],\"text\":[1]}],[769,\"kritzel-tooltip\",{\"isVisible\":[1028,\"is-visible\"],\"anchorElement\":[16],\"triggerElement\":[16],\"offsetY\":[2,\"offset-y\"],\"positionX\":[32],\"positionY\":[32],\"open\":[64],\"close\":[64],\"toggle\":[64],\"focusContent\":[64]},[[4,\"click\",\"handleOutsideClick\"],[6,\"pointerdown\",\"handleOutsidePointerDown\"],[4,\"kritzelTooltipCloseAll\",\"handleCloseAll\"],[9,\"resize\",\"handleWindowResize\"]],{\"triggerElement\":[{\"handleTriggerElementChange\":0}],\"isVisible\":[{\"handleVisibilityChange\":0}]}],[513,\"kritzel-watermark\",{\"core\":[16],\"label\":[1]}],[513,\"kritzel-color-palette\",{\"colors\":[16],\"selectedColor\":[1040],\"isExpanded\":[4,\"is-expanded\"],\"isOpaque\":[4,\"is-opaque\"],\"opacity\":[2],\"theme\":[1]}],[513,\"kritzel-font-family\",{\"fontOptions\":[16],\"selectedFontFamily\":[1025,\"selected-font-family\"]},null,{\"fontOptions\":[{\"handleFontOptionsChange\":0}]}],[513,\"kritzel-font-size\",{\"sizes\":[16],\"selectedSize\":[1026,\"selected-size\"],\"fontFamily\":[1,\"font-family\"]}],[513,\"kritzel-stroke-size\",{\"sizes\":[16],\"selectedSize\":[1026,\"selected-size\"]}],[513,\"kritzel-line-endings\",{\"styles\":[16],\"value\":[1040]}],[513,\"kritzel-opacity-slider\",{\"value\":[1026],\"min\":[2],\"max\":[2],\"step\":[2],\"previewColor\":[1,\"preview-color\"]}],[513,\"kritzel-shape-fill\",{\"value\":[1025]}],[513,\"kritzel-slide-toggle\",{\"checked\":[1028],\"disabled\":[4],\"label\":[1]}],[513,\"kritzel-avatar\",{\"user\":[16],\"name\":[1],\"size\":[2],\"color\":[1],\"imageError\":[32]},null,{\"user\":[{\"userChanged\":0}],\"profileImageUrl\":[{\"profileImageUrlChanged\":0}]}],[513,\"kritzel-font\",{\"fontFamily\":[1,\"font-family\"],\"size\":[2],\"color\":[1]}],[513,\"kritzel-color\",{\"value\":[1],\"theme\":[1],\"size\":[2]}],[513,\"kritzel-menu\",{\"items\":[16],\"parent\":[16],\"selectedIndex\":[32],\"setScrollTop\":[64],\"setFocus\":[64]}],[513,\"kritzel-menu-item\",{\"item\":[16],\"parent\":[16],\"isDirty\":[32]},null,{\"item\":[{\"onItemChange\":0}]}],[769,\"kritzel-dialog\",{\"isOpen\":[516,\"is-open\"],\"dialogTitle\":[1,\"dialog-title\"],\"closable\":[4],\"closeOnBackdrop\":[4,\"close-on-backdrop\"],\"closeOnEscape\":[4,\"close-on-escape\"],\"autoFocus\":[4,\"auto-focus\"],\"trapFocus\":[4,\"trap-focus\"],\"size\":[1],\"fullscreenOnMobile\":[4,\"fullscreen-on-mobile\"],\"contained\":[516],\"isAnimating\":[32],\"mobileLockedHeight\":[32],\"containerRect\":[32],\"containerBorderRadius\":[32],\"open\":[64],\"close\":[64],\"focusFirstElement\":[64]},[[8,\"keydown\",\"handleKeyDown\"],[9,\"resize\",\"handleWindowResize\"],[8,\"orientationchange\",\"handleOrientationChange\"]],{\"isOpen\":[{\"handleIsOpenChange\":0}]}],[769,\"kritzel-portal\",{\"anchor\":[16],\"offsetX\":[2,\"offset-x\"],\"offsetY\":[2,\"offset-y\"],\"autoFocus\":[4,\"auto-focus\"]},[[8,\"kritzel-dismiss-menus\",\"handleDismissMenus\"],[8,\"click\",\"handleOutsideClick\"],[6,\"pointerdown\",\"handleOutsidePointerDown\"],[8,\"keydown\",\"handleKeyDown\"],[11,\"resize\",\"handleResize\"],[11,\"scroll\",\"handleWindowScroll\"]],{\"anchor\":[{\"anchorChanged\":0}]}],[769,\"kritzel-dropdown\",{\"options\":[16],\"value\":[1],\"width\":[1],\"selectStyles\":[16],\"forceOpenDirection\":[1,\"force-open-direction\"],\"internalValue\":[32],\"hasSuffixContent\":[32],\"hasPrefixContent\":[32],\"isOpen\":[32],\"focusedIndex\":[32],\"openDirection\":[32]},[[4,\"click\",\"handleDocumentClick\"],[4,\"keydown\",\"handleDocumentKeydown\"]],{\"options\":[{\"optionsChanged\":0}],\"value\":[{\"externalValueChanged\":0}]}],[513,\"kritzel-icon\",{\"name\":[1],\"label\":[1],\"size\":[2]}]]],[\"p-fb32cd8f\",[[513,\"kritzel-brush-style\",{\"type\":[1],\"brushOptions\":[16]}]]]]"), options);
20
+ return bootstrapLazy(JSON.parse("[[\"p-8c1b7b08\",[[512,\"kritzel-editor\",{\"scaleMax\":[1026,\"scale-max\"],\"scaleMin\":[1026,\"scale-min\"],\"lockDrawingScale\":[1028,\"lock-drawing-scale\"],\"viewportBoundaryLeft\":[1026,\"viewport-boundary-left\"],\"viewportBoundaryRight\":[1026,\"viewport-boundary-right\"],\"viewportBoundaryTop\":[1026,\"viewport-boundary-top\"],\"viewportBoundaryBottom\":[1026,\"viewport-boundary-bottom\"],\"debugInfo\":[1040],\"user\":[16],\"activeUsers\":[16],\"controls\":[16],\"globalContextMenuItems\":[16],\"objectContextMenuItems\":[16],\"themes\":[16],\"theme\":[1025],\"licenseKey\":[1,\"license-key\"],\"locale\":[1025],\"locales\":[16],\"fallbackLocale\":[1,\"fallback-locale\"],\"customSvgIcons\":[16],\"customFonts\":[16],\"isPanningEnabled\":[1028,\"is-panning-enabled\"],\"isZoomingEnabled\":[1028,\"is-zooming-enabled\"],\"isControlsVisible\":[4,\"is-controls-visible\"],\"isUtilityPanelVisible\":[4,\"is-utility-panel-visible\"],\"isWorkspaceManagerVisible\":[4,\"is-workspace-manager-visible\"],\"isMoreMenuVisible\":[4,\"is-more-menu-visible\"],\"isZoomPanelVisible\":[4,\"is-zoom-panel-visible\"],\"isObjectDistanceFadingActive\":[4,\"is-object-distance-fading-active\"],\"syncConfig\":[16],\"assetStorageConfig\":[16],\"cursorTarget\":[16],\"loginConfig\":[16],\"isLoading\":[4,\"is-loading\"],\"editorId\":[1,\"editor-id\"],\"activeWorkspaceId\":[1,\"active-workspace-id\"],\"isEngineReady\":[32],\"isControlsReady\":[32],\"isWorkspaceManagerReady\":[32],\"workspaces\":[32],\"activeWorkspace\":[32],\"isVirtualKeyboardOpen\":[32],\"undoState\":[32],\"isBackToContentButtonVisible\":[32],\"resolvedTerms\":[32],\"availableLocaleOptions\":[32],\"currentZoomPercent\":[32],\"shortcuts\":[32],\"currentIsPublic\":[32],\"isEditorVisible\":[32],\"activeNotification\":[32],\"isNotificationDismissing\":[32],\"contextMenuState\":[32],\"normalizedControls\":[32],\"getObjectById\":[64],\"addObject\":[64],\"addObjects\":[64],\"updateObject\":[64],\"removeObject\":[64],\"removeObjects\":[64],\"getSelectedObjects\":[64],\"selectObjects\":[64],\"selectAllObjectsInViewport\":[64],\"clearSelection\":[64],\"centerObjectInViewport\":[64],\"panToObject\":[64],\"backToContent\":[64],\"centerAllObjects\":[64],\"centerObjects\":[64],\"setViewport\":[64],\"panTo\":[64],\"zoomTo\":[64],\"zoomIn\":[64],\"zoomOut\":[64],\"getViewport\":[64],\"screenToWorld\":[64],\"worldToScreen\":[64],\"createWorkspace\":[64],\"updateWorkspace\":[64],\"deleteWorkspace\":[64],\"getWorkspaces\":[64],\"getActiveWorkspace\":[64],\"loadSharedWorkspace\":[64],\"reinitSync\":[64],\"registerTool\":[64],\"changeActiveTool\":[64],\"changeActiveToolByName\":[64],\"disable\":[64],\"enable\":[64],\"copy\":[64],\"cut\":[64],\"paste\":[64],\"delete\":[64],\"bringForward\":[64],\"sendBackward\":[64],\"bringToFront\":[64],\"sendToBack\":[64],\"alignObjects\":[64],\"group\":[64],\"ungroup\":[64],\"undo\":[64],\"redo\":[64],\"getScreenshot\":[64],\"exportViewportAsPng\":[64],\"exportViewportAsSvg\":[64],\"exportSelectedObjectsAsPng\":[64],\"exportSelectedObjectsAsSvg\":[64],\"downloadAsJson\":[64],\"importFromFile\":[64],\"loadObjectsFromJson\":[64],\"getObjectsTotalCount\":[64],\"getAllObjects\":[64],\"findObjects\":[64],\"getObjectsInViewport\":[64],\"hideContextMenu\":[64],\"openContextMenu\":[64],\"triggerSelectionChange\":[64],\"beginSceneBootstrap\":[64],\"endSceneBootstrap\":[64],\"getDisplayableShortcuts\":[64],\"triggerNotification\":[64],\"openLoginDialog\":[64],\"setLoginLoading\":[64],\"setLocale\":[64],\"getLocale\":[64],\"getAvailableLocales\":[64],\"registerLocales\":[64],\"registerFonts\":[64],\"t\":[64]},[[0,\"dblclick\",\"onTouchStart\"]],{\"isEngineReady\":[{\"onIsEngineReady\":0}],\"isControlsReady\":[{\"onIsControlsReady\":0}],\"workspaces\":[{\"onWorkspacesChange\":0}],\"activeWorkspace\":[{\"onActiveWorkspaceChange\":0}],\"customFonts\":[{\"onCustomFontsChange\":0}],\"controls\":[{\"onControlsChange\":0}],\"activeWorkspaceId\":[{\"onActiveWorkspaceIdChange\":0}],\"theme\":[{\"onCurrentThemeChange\":0}],\"themes\":[{\"onThemesChange\":0}],\"locale\":[{\"onLocaleChange\":0}]}],[513,\"kritzel-controls\",{\"visible\":[4],\"controls\":[16],\"activeControl\":[1040],\"isUtilityPanelVisible\":[4,\"is-utility-panel-visible\"],\"undoState\":[16],\"theme\":[1],\"terms\":[16],\"firstConfig\":[32],\"isTouchDevice\":[32],\"selectedSubOptions\":[32],\"canScrollLeft\":[32],\"canScrollRight\":[32],\"needsScrolling\":[32],\"displayValues\":[32],\"internalControls\":[32],\"closeTooltip\":[64]},[[8,\"keydown\",\"handleKeyDown\"]],{\"controls\":[{\"onControlsChange\":0}],\"theme\":[{\"onThemeChange\":0}]}],[513,\"kritzel-engine\",{\"workspace\":[16],\"editorId\":[1,\"editor-id\"],\"activeWorkspaceId\":[1,\"active-workspace-id\"],\"syncConfig\":[16],\"assetStorageConfig\":[16],\"user\":[16],\"globalContextMenuItems\":[16],\"objectContextMenuItems\":[16],\"scaleMax\":[1026,\"scale-max\"],\"scaleMin\":[1026,\"scale-min\"],\"cursorTarget\":[16],\"lockDrawingScale\":[4,\"lock-drawing-scale\"],\"isObjectDistanceFadingActive\":[4,\"is-object-distance-fading-active\"],\"theme\":[1],\"licenseKey\":[1,\"license-key\"],\"themes\":[16],\"locale\":[1],\"locales\":[16],\"fallbackLocale\":[1,\"fallback-locale\"],\"viewportBoundaryLeft\":[2,\"viewport-boundary-left\"],\"viewportBoundaryRight\":[2,\"viewport-boundary-right\"],\"viewportBoundaryTop\":[2,\"viewport-boundary-top\"],\"viewportBoundaryBottom\":[2,\"viewport-boundary-bottom\"],\"debugInfo\":[16],\"isPanningEnabled\":[4,\"is-panning-enabled\"],\"isZoomingEnabled\":[4,\"is-zooming-enabled\"],\"isLoading\":[4,\"is-loading\"],\"forceUpdate\":[32],\"isSyncing\":[32],\"triggerSelectionChange\":[64],\"beginSceneBootstrap\":[64],\"endSceneBootstrap\":[64],\"registerTool\":[64],\"changeActiveTool\":[64],\"changeActiveToolByName\":[64],\"disable\":[64],\"enable\":[64],\"delete\":[64],\"copy\":[64],\"cut\":[64],\"paste\":[64],\"bringForward\":[64],\"sendBackward\":[64],\"bringToFront\":[64],\"sendToBack\":[64],\"alignObjects\":[64],\"group\":[64],\"ungroup\":[64],\"undo\":[64],\"redo\":[64],\"hideContextMenu\":[64],\"openContextMenu\":[64],\"getObjectById\":[64],\"getAllObjects\":[64],\"findObjects\":[64],\"getObjectsTotalCount\":[64],\"addObject\":[64],\"addObjects\":[64],\"updateObject\":[64],\"removeObject\":[64],\"removeObjects\":[64],\"getSelectedObjects\":[64],\"getDisplayableShortcuts\":[64],\"selectObjects\":[64],\"selectAllObjectsInViewport\":[64],\"clearSelection\":[64],\"centerObjectInViewport\":[64],\"panToObject\":[64],\"backToContent\":[64],\"centerAllObjects\":[64],\"centerObjects\":[64],\"setViewport\":[64],\"panTo\":[64],\"zoomTo\":[64],\"zoomIn\":[64],\"zoomOut\":[64],\"getViewport\":[64],\"screenToWorld\":[64],\"worldToScreen\":[64],\"getObjectsInViewport\":[64],\"getScreenshot\":[64],\"exportViewportAsPng\":[64],\"exportViewportAsSvg\":[64],\"getSelectedObjectsAsSvgString\":[64],\"exportSelectedObjectsAsSvg\":[64],\"getSelectedObjectsAsPngDataUrl\":[64],\"exportSelectedObjectsAsPng\":[64],\"exportAsJson\":[64],\"importFromJson\":[64],\"loadObjectsFromJson\":[64],\"downloadAsJson\":[64],\"importFromFile\":[64],\"createWorkspace\":[64],\"updateWorkspace\":[64],\"deleteWorkspace\":[64],\"getWorkspaces\":[64],\"getActiveWorkspace\":[64],\"getIsPublic\":[64],\"loadSharedWorkspace\":[64],\"reinitSync\":[64],\"saveSettings\":[64],\"loadSettings\":[64],\"registerLocales\":[64],\"setLocale\":[64],\"getLocale\":[64],\"getAvailableLocales\":[64],\"getAvailableLocaleOptions\":[64],\"t\":[64],\"getResolvedTerms\":[64]},[[1,\"wheel\",\"handleWheel\"],[0,\"pointerdown\",\"handlePointerDown\"],[0,\"pointermove\",\"handlePointerMove\"],[0,\"pointerup\",\"handlePointerUp\"],[0,\"pointercancel\",\"handlePointerCancel\"],[1,\"pointerleave\",\"handlePointerLeave\"],[1,\"longpress\",\"handleLongPress\"],[0,\"contextmenu\",\"handleContextMenu\"],[9,\"resize\",\"handleResize\"],[8,\"keydown\",\"handleKeyDown\"],[8,\"keyup\",\"handleKeyUp\"],[8,\"copy\",\"handleCopy\"],[8,\"cut\",\"handleCut\"],[8,\"paste\",\"handlePaste\"],[4,\"dblclick\",\"preventDoubleTapZoomOnTouchDevices\"]],{\"workspace\":[{\"onWorkspaceChange\":0}],\"activeWorkspaceId\":[{\"onActiveWorkspaceIdChange\":0}],\"syncConfig\":[{\"onSyncConfigChange\":0}],\"assetStorageConfig\":[{\"onAssetStorageConfigChange\":0}],\"user\":[{\"onUserChange\":0}],\"globalContextMenuItems\":[{\"onGlobalContextMenuItemsChange\":0}],\"objectContextMenuItems\":[{\"onObjectContextMenuItemsChange\":0}],\"scaleMax\":[{\"validateScaleMax\":0}],\"scaleMin\":[{\"validateScaleMin\":0}],\"cursorTarget\":[{\"onCursorTargetChange\":0}],\"lockDrawingScale\":[{\"onLockDrawingScaleChange\":0}],\"isObjectDistanceFadingActive\":[{\"onIsObjectDistanceFadingActiveChange\":0}],\"theme\":[{\"onThemeChange\":0}],\"licenseKey\":[{\"onLicenseKeyChange\":0}],\"themes\":[{\"onThemesChange\":0}],\"locale\":[{\"onLocaleChange\":0}],\"locales\":[{\"onLocalesChange\":0}],\"fallbackLocale\":[{\"onFallbackLocaleChange\":0}],\"viewportBoundaryLeft\":[{\"onViewportBoundaryLeftChange\":0}],\"viewportBoundaryRight\":[{\"onViewportBoundaryRightChange\":0}],\"viewportBoundaryTop\":[{\"onViewportBoundaryTopChange\":0}],\"viewportBoundaryBottom\":[{\"onViewportBoundaryBottomChange\":0}],\"debugInfo\":[{\"onDebugInfoChange\":0}],\"isLoading\":[{\"onIsLoadingChange\":0}]}],[513,\"kritzel-settings\",{\"availableThemes\":[16],\"availableLocales\":[16],\"shortcuts\":[16],\"terms\":[16],\"settings\":[16],\"isDialogOpen\":[32],\"selectedCategoryId\":[32],\"scaleMin\":[32],\"scaleMax\":[32],\"lockDrawingScale\":[32],\"theme\":[32],\"locale\":[32],\"viewportBoundaryLeft\":[32],\"viewportBoundaryRight\":[32],\"viewportBoundaryTop\":[32],\"viewportBoundaryBottom\":[32],\"debugInfo\":[32],\"open\":[64]},null,{\"settings\":[{\"onSettingsPropChange\":0}]}],[513,\"kritzel-export\",{\"workspaceName\":[1,\"workspace-name\"],\"terms\":[16],\"isDialogOpen\":[32],\"previewUrl\":[32],\"isLoading\":[32],\"activeTab\":[32],\"exportFilename\":[32],\"viewportExportFormat\":[32],\"open\":[64]}],[513,\"kritzel-workspace-manager\",{\"visible\":[4],\"activeWorkspace\":[1040],\"workspaces\":[16],\"terms\":[16],\"childMenuAnchor\":[32],\"openChildMenuItem\":[32],\"newWorkspace\":[32],\"editingItemId\":[32]},[[8,\"wheel\",\"handleWheel\"]]],[513,\"kritzel-more-menu\",{\"visible\":[4],\"items\":[16],\"icon\":[1],\"iconSize\":[2,\"icon-size\"],\"offsetY\":[2,\"offset-y\"],\"terms\":[16],\"menuAnchor\":[32],\"isTouchDevice\":[32]}],[513,\"kritzel-current-user-dialog\",{\"user\":[16],\"terms\":[16],\"isDialogOpen\":[32],\"open\":[64],\"close\":[64]}],[513,\"kritzel-share-dialog\",{\"isPublic\":[4,\"is-public\"],\"workspaceId\":[1,\"workspace-id\"],\"terms\":[16],\"isDialogOpen\":[32],\"internalIsPublic\":[32],\"copySuccess\":[32],\"qrCodeDataUrl\":[32],\"open\":[64],\"close\":[64]},null,{\"isPublic\":[{\"onIsPublicChange\":0}],\"workspaceId\":[{\"onWorkspaceIdChange\":0}]}],[513,\"kritzel-login-dialog\",{\"providers\":[16],\"dialogTitle\":[1,\"dialog-title\"],\"subtitle\":[1],\"isDialogOpen\":[32],\"loadingProvider\":[32],\"open\":[64],\"close\":[64],\"setLoading\":[64]}],[513,\"kritzel-active-users\",{\"users\":[16],\"avatarSize\":[2,\"avatar-size\"],\"maxVisible\":[2,\"max-visible\"],\"overlap\":[2]}],[513,\"kritzel-back-to-content\",{\"visible\":[4],\"text\":[1]}],[513,\"kritzel-context-menu\",{\"items\":[16],\"objects\":[16],\"processedItems\":[32],\"openSubmenuPath\":[32],\"submenuPositions\":[32]},[[9,\"pointerdown\",\"handleOutsideClick\"]],{\"items\":[{\"onItemsChanged\":0}]}],[513,\"kritzel-current-user\",{\"user\":[16],\"avatarSize\":[2,\"avatar-size\"],\"terms\":[16]}],[513,\"kritzel-notification-card\",{\"notification\":[16],\"showTimestamp\":[4,\"show-timestamp\"],\"locale\":[1]}],[513,\"kritzel-zoom-panel\",{\"visible\":[4],\"disabled\":[4],\"zoomPercent\":[2,\"zoom-percent\"],\"terms\":[16]}],[513,\"kritzel-tool-config\",{\"tool\":[1040],\"isExpanded\":[1028,\"is-expanded\"],\"theme\":[1],\"engine\":[16],\"terms\":[16],\"config\":[32],\"palette\":[32],\"sizes\":[32],\"currentOpacity\":[32],\"updateTrigger\":[32]},null,{\"tool\":[{\"handleToolChange\":0}],\"theme\":[{\"onThemeChange\":0}],\"engine\":[{\"handleEngineChange\":0}]}],[513,\"kritzel-split-button\",{\"buttonIcon\":[1,\"button-icon\"],\"dropdownIcon\":[1,\"dropdown-icon\"],\"items\":[16],\"mainButtonDisabled\":[4,\"main-button-disabled\"],\"menuButtonDisabled\":[4,\"menu-button-disabled\"],\"isMenuOpen\":[32],\"isTouchDevice\":[32],\"anchorElement\":[32],\"menuScrollTop\":[32],\"open\":[64],\"focusMenu\":[64]}],[769,\"kritzel-master-detail\",{\"items\":[16],\"selectedItemId\":[1,\"selected-item-id\"],\"focusedIndex\":[32],\"showMobileDetail\":[32]},null,{\"selectedItemId\":[{\"watchSelectedItemId\":0}]}],[513,\"kritzel-pill-tabs\",{\"tabs\":[16],\"value\":[1025]}],[513,\"kritzel-utility-panel\",{\"undoState\":[16],\"terms\":[16]}],[513,\"kritzel-awareness-cursors\",{\"core\":[16],\"showEdgeIndicators\":[4,\"show-edge-indicators\"],\"edgeIndicatorPadding\":[2,\"edge-indicator-padding\"],\"remoteCursors\":[32],\"objectVersion\":[32]}],[769,\"kritzel-button\",{\"variant\":[1],\"disabled\":[4],\"type\":[1]}],[513,\"kritzel-cursor-trail\",{\"core\":[16],\"cursorTrailPoints\":[32],\"isLeftButtonDown\":[32]},[[9,\"pointerdown\",\"handleMouseDown\"],[9,\"pointermove\",\"handlePointerMove\"],[9,\"pointerup\",\"handlePointerUp\"]]],[513,\"kritzel-input\",{\"value\":[1025],\"label\":[1],\"placeholder\":[1],\"suffix\":[1],\"type\":[1],\"disabled\":[4],\"inputValue\":[32]},null,{\"value\":[{\"onValueChange\":0}]}],[513,\"kritzel-loading-overlay\",{\"visible\":[4],\"text\":[1]}],[513,\"kritzel-numeric-input\",{\"value\":[1026],\"min\":[2],\"max\":[2],\"step\":[2],\"label\":[1],\"placeholder\":[1],\"inputValue\":[32]},null,{\"value\":[{\"onValueChange\":0}]}],[513,\"kritzel-sync-indicator\",{\"visible\":[4],\"text\":[1]}],[769,\"kritzel-tooltip\",{\"isVisible\":[1028,\"is-visible\"],\"anchorElement\":[16],\"triggerElement\":[16],\"offsetY\":[2,\"offset-y\"],\"positionX\":[32],\"positionY\":[32],\"open\":[64],\"close\":[64],\"toggle\":[64],\"focusContent\":[64]},[[4,\"click\",\"handleOutsideClick\"],[6,\"pointerdown\",\"handleOutsidePointerDown\"],[4,\"kritzelTooltipCloseAll\",\"handleCloseAll\"],[9,\"resize\",\"handleWindowResize\"]],{\"triggerElement\":[{\"handleTriggerElementChange\":0}],\"isVisible\":[{\"handleVisibilityChange\":0}]}],[513,\"kritzel-watermark\",{\"core\":[16],\"label\":[1]}],[513,\"kritzel-color-palette\",{\"colors\":[16],\"selectedColor\":[1040],\"isExpanded\":[4,\"is-expanded\"],\"isOpaque\":[4,\"is-opaque\"],\"opacity\":[2],\"theme\":[1]}],[513,\"kritzel-font-family\",{\"fontOptions\":[16],\"selectedFontFamily\":[1025,\"selected-font-family\"]},null,{\"fontOptions\":[{\"handleFontOptionsChange\":0}]}],[513,\"kritzel-font-size\",{\"sizes\":[16],\"selectedSize\":[1026,\"selected-size\"],\"fontFamily\":[1,\"font-family\"]}],[513,\"kritzel-stroke-size\",{\"sizes\":[16],\"selectedSize\":[1026,\"selected-size\"]}],[513,\"kritzel-line-endings\",{\"styles\":[16],\"value\":[1040]}],[513,\"kritzel-opacity-slider\",{\"value\":[1026],\"min\":[2],\"max\":[2],\"step\":[2],\"previewColor\":[1,\"preview-color\"]}],[513,\"kritzel-shape-fill\",{\"value\":[1025]}],[513,\"kritzel-slide-toggle\",{\"checked\":[1028],\"disabled\":[4],\"label\":[1]}],[513,\"kritzel-avatar\",{\"user\":[16],\"name\":[1],\"size\":[2],\"color\":[1],\"imageError\":[32]},null,{\"user\":[{\"userChanged\":0}],\"profileImageUrl\":[{\"profileImageUrlChanged\":0}]}],[513,\"kritzel-font\",{\"fontFamily\":[1,\"font-family\"],\"size\":[2],\"color\":[1]}],[513,\"kritzel-color\",{\"value\":[1],\"theme\":[1],\"size\":[2]}],[513,\"kritzel-menu\",{\"items\":[16],\"parent\":[16],\"selectedIndex\":[32],\"setScrollTop\":[64],\"setFocus\":[64]}],[513,\"kritzel-menu-item\",{\"item\":[16],\"parent\":[16],\"isDirty\":[32]},null,{\"item\":[{\"onItemChange\":0}]}],[769,\"kritzel-dialog\",{\"isOpen\":[516,\"is-open\"],\"dialogTitle\":[1,\"dialog-title\"],\"closable\":[4],\"closeOnBackdrop\":[4,\"close-on-backdrop\"],\"closeOnEscape\":[4,\"close-on-escape\"],\"autoFocus\":[4,\"auto-focus\"],\"trapFocus\":[4,\"trap-focus\"],\"size\":[1],\"fullscreenOnMobile\":[4,\"fullscreen-on-mobile\"],\"contained\":[516],\"isAnimating\":[32],\"mobileLockedHeight\":[32],\"containerRect\":[32],\"containerBorderRadius\":[32],\"open\":[64],\"close\":[64],\"focusFirstElement\":[64]},[[8,\"keydown\",\"handleKeyDown\"],[9,\"resize\",\"handleWindowResize\"],[8,\"orientationchange\",\"handleOrientationChange\"]],{\"isOpen\":[{\"handleIsOpenChange\":0}]}],[769,\"kritzel-portal\",{\"anchor\":[16],\"offsetX\":[2,\"offset-x\"],\"offsetY\":[2,\"offset-y\"],\"autoFocus\":[4,\"auto-focus\"]},[[8,\"kritzel-dismiss-menus\",\"handleDismissMenus\"],[8,\"click\",\"handleOutsideClick\"],[6,\"pointerdown\",\"handleOutsidePointerDown\"],[8,\"keydown\",\"handleKeyDown\"],[11,\"resize\",\"handleResize\"],[11,\"scroll\",\"handleWindowScroll\"]],{\"anchor\":[{\"anchorChanged\":0}]}],[769,\"kritzel-dropdown\",{\"options\":[16],\"value\":[1],\"width\":[1],\"selectStyles\":[16],\"forceOpenDirection\":[1,\"force-open-direction\"],\"internalValue\":[32],\"hasSuffixContent\":[32],\"hasPrefixContent\":[32],\"isOpen\":[32],\"focusedIndex\":[32],\"openDirection\":[32]},[[4,\"click\",\"handleDocumentClick\"],[4,\"keydown\",\"handleDocumentKeydown\"]],{\"options\":[{\"optionsChanged\":0}],\"value\":[{\"externalValueChanged\":0}]}],[513,\"kritzel-icon\",{\"name\":[1],\"label\":[1],\"size\":[2]}]]],[\"p-fb32cd8f\",[[513,\"kritzel-brush-style\",{\"type\":[1],\"brushOptions\":[16]}]]]]"), options);
21
21
  });
@@ -120,6 +120,12 @@ export declare class KritzelLicenseManager {
120
120
  * parsed segments and claims for a structurally valid, unexpired token.
121
121
  */
122
122
  private preCheck;
123
+ /** Returns the normalized current hostname, or null when unavailable/invalid. */
124
+ private getCurrentHostname;
125
+ /** Normalizes and validates the allowed domains claim. */
126
+ private normalizeAllowedDomains;
127
+ /** Normalizes a domain and rejects malformed hostnames. */
128
+ private normalizeDomain;
123
129
  /**
124
130
  * Verifies the Ed25519 signature of the token against the embedded public
125
131
  * key. Resolves true/false for a definitive valid/invalid signature.
@@ -22,4 +22,4 @@ export declare const KRITZEL_LICENSE_TOKEN_PREFIX = "KRTZL1.";
22
22
  * printed public key here. Replacing this value invalidates every license
23
23
  * signed with the previous key.
24
24
  */
25
- export declare const KRITZEL_LICENSE_PUBLIC_KEY = "I-pYJlxDEjT94rwSaqhXW5Sv__fMKS-JKKnV3pg0PaM";
25
+ export declare const KRITZEL_LICENSE_PUBLIC_KEY = "2IwZDin-qV3kOt8SEQCqdaJsGT9S7tAGapUYJVnVGQo";
@@ -3,4 +3,4 @@
3
3
  * This file is auto-generated by the version bump scripts.
4
4
  * Do not modify manually.
5
5
  */
6
- export declare const KRITZEL_VERSION = "0.4.7";
6
+ export declare const KRITZEL_VERSION = "0.4.8";
@@ -1,5 +1,6 @@
1
1
  import { KritzelTheme } from '../interfaces/theme.interface';
2
2
  export declare class ThemeHelper {
3
+ private static readonly appliedVariableNames;
3
4
  /**
4
5
  * Converts a camelCase string to kebab-case.
5
6
  * @example ThemeHelper.camelToKebab('controlHoverBackgroundColor') → 'control-hover-background-color'