kritzel-stencil 0.4.7 → 0.4.9

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 (113) hide show
  1. package/dist/cjs/index.cjs.js +9 -1
  2. package/dist/cjs/kritzel-active-users_47.cjs.entry.js +1396 -1243
  3. package/dist/cjs/loader.cjs.js +1 -1
  4. package/dist/cjs/{schema.constants-C8hqt--r.js → schema.constants-ByNZ_qAj.js} +136 -7
  5. package/dist/cjs/stencil.cjs.js +1 -1
  6. package/dist/collection/classes/handlers/line-handle.handler.js +1 -1
  7. package/dist/collection/classes/managers/license.manager.js +56 -0
  8. package/dist/collection/classes/objects/image.class.js +9 -0
  9. package/dist/collection/classes/objects/line.class.js +1 -1
  10. package/dist/collection/classes/objects/path.class.js +9 -0
  11. package/dist/collection/classes/objects/shape.class.js +12 -3
  12. package/dist/collection/classes/objects/text.class.js +1 -1
  13. package/dist/collection/classes/providers/sync/broadcast-sync-provider.class.js +1 -0
  14. package/dist/collection/classes/providers/sync/hocuspocus-sync-provider.class.js +2 -0
  15. package/dist/collection/classes/providers/sync/in-memory-sync-provider.class.js +1 -0
  16. package/dist/collection/classes/providers/sync/indexeddb-sync-provider.class.js +1 -0
  17. package/dist/collection/classes/providers/sync/websocket-sync-provider.class.js +2 -0
  18. package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +197 -67
  19. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +146 -172
  20. package/dist/collection/components/ui/kritzel-export/kritzel-export.js +1 -1
  21. package/dist/collection/components/ui/kritzel-loading-overlay/kritzel-loading-overlay.js +1 -1
  22. package/dist/collection/components/ui/kritzel-login-dialog/kritzel-login-dialog.js +1 -1
  23. package/dist/collection/components/ui/kritzel-more-menu/kritzel-more-menu.js +90 -4
  24. package/dist/collection/components/ui/kritzel-settings/kritzel-settings.js +1 -1
  25. package/dist/collection/components/ui/kritzel-share-dialog/kritzel-share-dialog.js +2 -2
  26. package/dist/collection/components/ui/kritzel-utility-panel/kritzel-utility-panel.js +1 -1
  27. package/dist/collection/components/ui/kritzel-zoom-panel/kritzel-zoom-panel.js +1 -1
  28. package/dist/collection/constants/license.constants.js +1 -1
  29. package/dist/collection/constants/version.js +1 -1
  30. package/dist/collection/helpers/object.helper.js +11 -0
  31. package/dist/collection/helpers/svg-export.helper.js +19 -9
  32. package/dist/collection/helpers/theme.helper.js +8 -0
  33. package/dist/collection/index.js +1 -0
  34. package/dist/collection/interfaces/object-export.interface.js +1 -0
  35. package/dist/collection/interfaces/sync-config.interface.js +21 -1
  36. package/dist/collection/themes/dark-theme.js +2 -0
  37. package/dist/collection/themes/light-theme.js +2 -0
  38. package/dist/components/index.js +11 -4
  39. package/dist/components/kritzel-awareness-cursors.js +1 -1
  40. package/dist/components/kritzel-color-palette.js +1 -1
  41. package/dist/components/kritzel-color.js +1 -1
  42. package/dist/components/kritzel-controls.js +1 -1
  43. package/dist/components/kritzel-editor.js +180 -83
  44. package/dist/components/kritzel-engine.js +1 -1
  45. package/dist/components/kritzel-export.js +1 -1
  46. package/dist/components/kritzel-loading-overlay.js +1 -1
  47. package/dist/components/kritzel-login-dialog.js +1 -1
  48. package/dist/components/kritzel-menu-item.js +1 -1
  49. package/dist/components/kritzel-menu.js +1 -1
  50. package/dist/components/kritzel-more-menu.js +1 -1
  51. package/dist/components/kritzel-portal.js +1 -1
  52. package/dist/components/kritzel-settings.js +1 -1
  53. package/dist/components/kritzel-share-dialog.js +1 -1
  54. package/dist/components/kritzel-split-button.js +1 -1
  55. package/dist/components/kritzel-stroke-size.js +1 -1
  56. package/dist/components/kritzel-tool-config.js +1 -1
  57. package/dist/components/kritzel-utility-panel.js +1 -1
  58. package/dist/components/kritzel-workspace-manager.js +1 -1
  59. package/dist/components/kritzel-zoom-panel.js +1 -1
  60. package/dist/components/{p-DwY5pghH.js → p-6rQICkGr.js} +1 -1
  61. package/dist/components/{p-DkH3hoLz.js → p-8ScektIm.js} +6 -6
  62. package/dist/components/{p-1nG2hxfJ.js → p-9m1cAVwG.js} +2 -2
  63. package/dist/components/{p-DkY7pIg5.js → p-BRGufCki.js} +95 -6
  64. package/dist/components/{p-BKOsmXB5.js → p-BqWiEmYI.js} +1 -1
  65. package/dist/components/{p-BLOPBDUF.js → p-C2CeSrTm.js} +1 -1
  66. package/dist/components/{p-zd7zXld8.js → p-CMZ09rB1.js} +1 -1
  67. package/dist/components/{p-BmyTdQGy.js → p-CURiiQfq.js} +12 -0
  68. package/dist/components/{p-DDbO5q-e.js → p-CXJZxJvp.js} +4 -4
  69. package/dist/components/{p-7Rt7ml3v.js → p-Cj0NElII.js} +1 -1
  70. package/dist/components/{p-Bm_BWQa4.js → p-Ckm1Aq0V.js} +1 -1
  71. package/dist/components/{p-BVEGQLBD.js → p-CoY7emAj.js} +1 -1
  72. package/dist/components/{p-BZxOukfY.js → p-Cr2z2UBL.js} +4 -4
  73. package/dist/components/{p-D0oplzU-.js → p-D7H8oxZb.js} +2 -2
  74. package/dist/components/{p-Dd-pMvlr.js → p-DPONTran.js} +11 -0
  75. package/dist/components/{p-BMRln59F.js → p-DW7WW4EN.js} +2 -2
  76. package/dist/components/{p-D8TOEhPY.js → p-DuVkk58V.js} +2 -2
  77. package/dist/components/{p-OLfoATNk.js → p-U9FjWrp-.js} +1 -1
  78. package/dist/components/{p-C2yi85nc.js → p-ZPPtEla5.js} +1213 -1131
  79. package/dist/components/{p-COjsYPir.js → p-dVfh-Sy9.js} +1 -1
  80. package/dist/components/{p-Ka7OWbnk.js → p-lQ7nfhOy.js} +12 -3
  81. package/dist/esm/index.js +9 -2
  82. package/dist/esm/kritzel-active-users_47.entry.js +1396 -1243
  83. package/dist/esm/loader.js +1 -1
  84. package/dist/esm/{schema.constants-uC7_X6yr.js → schema.constants-1t45c2_U.js} +136 -8
  85. package/dist/esm/stencil.js +1 -1
  86. package/dist/stencil/index.esm.js +9 -2
  87. package/dist/stencil/{p-uC7_X6yr.js → p-1t45c2_U.js} +136 -8
  88. package/dist/stencil/{p-472f2e90.entry.js → p-f5f088ea.entry.js} +1396 -1243
  89. package/dist/stencil/stencil.esm.js +1 -1
  90. package/dist/types/classes/managers/license.manager.d.ts +6 -0
  91. package/dist/types/classes/objects/image.class.d.ts +3 -0
  92. package/dist/types/classes/objects/path.class.d.ts +3 -0
  93. package/dist/types/classes/objects/shape.class.d.ts +3 -0
  94. package/dist/types/classes/providers/sync/broadcast-sync-provider.class.d.ts +1 -0
  95. package/dist/types/classes/providers/sync/hocuspocus-sync-provider.class.d.ts +1 -0
  96. package/dist/types/classes/providers/sync/in-memory-sync-provider.class.d.ts +1 -0
  97. package/dist/types/classes/providers/sync/indexeddb-sync-provider.class.d.ts +1 -0
  98. package/dist/types/classes/providers/sync/websocket-sync-provider.class.d.ts +1 -0
  99. package/dist/types/components/core/kritzel-editor/kritzel-editor.d.ts +15 -3
  100. package/dist/types/components/core/kritzel-engine/kritzel-engine.d.ts +16 -34
  101. package/dist/types/components/ui/kritzel-more-menu/kritzel-more-menu.d.ts +10 -1
  102. package/dist/types/components.d.ts +27 -26
  103. package/dist/types/constants/license.constants.d.ts +1 -1
  104. package/dist/types/constants/version.d.ts +1 -1
  105. package/dist/types/helpers/object.helper.d.ts +4 -0
  106. package/dist/types/helpers/theme.helper.d.ts +1 -0
  107. package/dist/types/index.d.ts +1 -0
  108. package/dist/types/interfaces/menu-item.interface.d.ts +1 -1
  109. package/dist/types/interfaces/object-export.interface.d.ts +20 -0
  110. package/dist/types/interfaces/sync-config.interface.d.ts +5 -0
  111. package/dist/types/interfaces/sync-provider.interface.d.ts +5 -0
  112. package/dist/types/interfaces/theme.interface.d.ts +2 -0
  113. package/package.json +1 -1
@@ -21,11 +21,11 @@ import { KritzelCore } from "../../../classes/core/core.class";
21
21
  import { KritzelDevicesHelper } from "../../../helpers/devices.helper";
22
22
  import { throttle } from "lodash";
23
23
  import { KritzelColorHelper } from "../../../helpers/color.helper";
24
- import { KritzelSvgExportHelper } from "../../../helpers/svg-export.helper";
25
24
  import { toPng, toSvg } from "html-to-image";
26
25
  import { ObjectHelper } from "../../../helpers/object.helper";
27
26
  import { KritzelWheelHelper } from "../../../helpers/wheel.helper";
28
27
  import { resolveTextToolAvailableFonts } from "../../../constants/text-tool-fonts.constants";
28
+ import { KritzelSvgExportHelper } from "../../../helpers/svg-export.helper";
29
29
  export class KritzelEngine {
30
30
  host;
31
31
  /** The workspace to load and display. Changing this prop switches the active workspace. */
@@ -1217,10 +1217,7 @@ export class KritzelEngine {
1217
1217
  console.error('Failed to export viewport as PNG: screenshot could not be generated');
1218
1218
  return;
1219
1219
  }
1220
- const link = document.createElement('a');
1221
- link.download = filename;
1222
- link.href = dataUrl;
1223
- link.click();
1220
+ this.triggerDataUrlDownload(dataUrl, filename);
1224
1221
  }
1225
1222
  catch (error) {
1226
1223
  console.error('Failed to export viewport as PNG:', error);
@@ -1242,129 +1239,57 @@ export class KritzelEngine {
1242
1239
  console.error('Failed to export viewport as SVG: screenshot could not be generated');
1243
1240
  return;
1244
1241
  }
1245
- const link = document.createElement('a');
1246
- link.download = filename;
1247
- link.href = dataUrl;
1248
- link.click();
1242
+ this.triggerDataUrlDownload(dataUrl, filename);
1249
1243
  }
1250
1244
  catch (error) {
1251
1245
  console.error('Failed to export viewport as SVG:', error);
1252
1246
  }
1253
1247
  }
1254
1248
  /**
1255
- * Generates an SVG string from the currently selected objects.
1256
- * Creates clean, standards-compliant SVG markup by directly serializing object properties.
1257
- * @param options - Optional export settings (theme, padding, raster-safe mode for canvas export).
1258
- * @returns SVG markup string, or null if no objects are selected.
1249
+ * Returns export formats supported by the currently selected object.
1250
+ * Only returns formats when exactly one object is selected.
1259
1251
  */
1260
- async getSelectedObjectsAsSvgString(options) {
1261
- const selectedObjects = await this.getSelectedObjects();
1262
- if (!selectedObjects || selectedObjects.length === 0) {
1263
- return null;
1252
+ async getSelectedObjectSupportedExportFormats() {
1253
+ const selected = this.getSingleSelectedExportableObject();
1254
+ if (!selected) {
1255
+ return [];
1264
1256
  }
1265
- const theme = options?.theme ?? this.core.themeManager.getStoredTheme();
1266
- // Inline image bytes as data URLs so they survive both standalone SVG
1267
- // files and rasterization to PNG (a `blob:` href is not loaded when an
1268
- // SVG is drawn into a canvas, which otherwise yields a broken image).
1269
- const imageDataUrls = await KritzelSvgExportHelper.resolveImageDataUrls(selectedObjects, this.core.assetResolver);
1270
- return KritzelSvgExportHelper.generateSvg(selectedObjects, {
1271
- theme,
1272
- padding: options?.padding ?? 0,
1273
- includeXmlDeclaration: true,
1274
- rasterSafeForCanvas: options?.rasterSafeForCanvas ?? false,
1275
- imageDataUrls,
1276
- });
1257
+ return selected.getSupportedExportFormats();
1277
1258
  }
1278
1259
  /**
1279
- * Exports the currently selected objects as an SVG file and triggers a browser download.
1280
- * Creates clean, standards-compliant SVG markup suitable for import into vector editors.
1281
- * @param options - Optional export settings (theme, padding).
1260
+ * Checks whether the currently selected object supports a specific export format.
1261
+ * Returns false when none or multiple objects are selected.
1282
1262
  */
1283
- async exportSelectedObjectsAsSvg(options) {
1284
- try {
1285
- const svgString = await this.getSelectedObjectsAsSvgString(options);
1286
- if (!svgString) {
1287
- console.warn('No objects selected for SVG export');
1288
- return;
1289
- }
1290
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
1291
- const filename = `selection-${timestamp}.svg`;
1292
- const blob = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' });
1293
- const url = URL.createObjectURL(blob);
1294
- const link = document.createElement('a');
1295
- link.download = filename;
1296
- link.href = url;
1297
- link.click();
1298
- URL.revokeObjectURL(url);
1299
- }
1300
- catch (error) {
1301
- console.error('Failed to export selected objects as SVG:', error);
1263
+ async canExportSelectedObjectAs(format) {
1264
+ const selected = this.getSingleSelectedExportableObject();
1265
+ if (!selected) {
1266
+ return false;
1302
1267
  }
1268
+ return selected.getSupportedExportFormats().includes(format);
1303
1269
  }
1304
1270
  /**
1305
- * Generates a PNG data URL from the currently selected objects.
1306
- * Converts the SVG representation to a rasterized PNG image.
1307
- * @param options - Optional export settings (theme, padding, scale for resolution).
1308
- * @returns PNG data URL string, or null if no objects are selected.
1271
+ * Exports the currently selected object in the requested format and triggers a file download.
1272
+ * Only supports single selection.
1309
1273
  */
1310
- async getSelectedObjectsAsPngDataUrl(options) {
1311
- const svgString = await this.getSelectedObjectsAsSvgString({
1312
- theme: options?.theme,
1313
- padding: options?.padding,
1314
- // Avoid foreignObject-based text serialization, which taints the
1315
- // canvas in SVG->PNG conversion paths.
1316
- rasterSafeForCanvas: true,
1317
- });
1318
- if (!svgString) {
1319
- return null;
1274
+ async exportSelectedObject(format) {
1275
+ const selected = this.getSingleSelectedExportableObject();
1276
+ if (!selected) {
1277
+ return;
1320
1278
  }
1321
- const scale = options?.scale ?? 2; // Default 2x for better quality
1322
- return new Promise((resolve, reject) => {
1323
- const img = new Image();
1324
- const svgBlob = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' });
1325
- const url = URL.createObjectURL(svgBlob);
1326
- img.onload = () => {
1327
- const canvas = document.createElement('canvas');
1328
- canvas.width = img.width * scale;
1329
- canvas.height = img.height * scale;
1330
- const ctx = canvas.getContext('2d');
1331
- if (!ctx) {
1332
- URL.revokeObjectURL(url);
1333
- reject(new Error('Failed to get canvas context'));
1334
- return;
1335
- }
1336
- ctx.scale(scale, scale);
1337
- ctx.drawImage(img, 0, 0);
1338
- URL.revokeObjectURL(url);
1339
- resolve(canvas.toDataURL('image/png'));
1340
- };
1341
- img.onerror = () => {
1342
- URL.revokeObjectURL(url);
1343
- reject(new Error('Failed to load SVG for PNG conversion'));
1344
- };
1345
- img.src = url;
1346
- });
1347
- }
1348
- /**
1349
- * Exports the currently selected objects as a PNG file and triggers a browser download.
1350
- * @param options - Optional export settings (theme, padding, scale for resolution).
1351
- */
1352
- async exportSelectedObjectsAsPng(options) {
1353
1279
  try {
1354
- const dataUrl = await this.getSelectedObjectsAsPngDataUrl(options);
1280
+ const dataUrl = await selected.exportAs(format, this.getObjectExportContext());
1355
1281
  if (!dataUrl) {
1356
- console.warn('No objects selected for PNG export');
1282
+ console.error(`Failed to export selected object as ${format}: export returned no data URL`);
1357
1283
  return;
1358
1284
  }
1285
+ const activeWorkspaceName = this.core.store.state?.activeWorkspace?.name || 'workspace';
1286
+ const objectName = selected.__class__.replace(/^Kritzel/, '').toLowerCase() || 'object';
1359
1287
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
1360
- const filename = `selection-${timestamp}.png`;
1361
- const link = document.createElement('a');
1362
- link.download = filename;
1363
- link.href = dataUrl;
1364
- link.click();
1288
+ const filename = `${activeWorkspaceName}-${objectName}-${timestamp}.${format}`;
1289
+ this.triggerDataUrlDownload(dataUrl, filename);
1365
1290
  }
1366
1291
  catch (error) {
1367
- console.error('Failed to export selected objects as PNG:', error);
1292
+ console.error(`Failed to export selected object as ${format}:`, error);
1368
1293
  }
1369
1294
  }
1370
1295
  /**
@@ -1559,6 +1484,73 @@ export class KritzelEngine {
1559
1484
  const response = await fetch(dataUrl);
1560
1485
  return response.blob();
1561
1486
  }
1487
+ triggerDataUrlDownload(dataUrl, filename) {
1488
+ const link = document.createElement('a');
1489
+ link.download = filename;
1490
+ link.href = dataUrl;
1491
+ link.click();
1492
+ }
1493
+ getSingleSelectedExportableObject() {
1494
+ const selectedObjects = this.core.store.selectionGroup?.objects ?? [];
1495
+ if (selectedObjects.length !== 1) {
1496
+ return null;
1497
+ }
1498
+ const [selected] = selectedObjects;
1499
+ if (!ObjectHelper.isKritzelExportable(selected)) {
1500
+ return null;
1501
+ }
1502
+ return selected;
1503
+ }
1504
+ getObjectExportContext() {
1505
+ return {
1506
+ getObjectAsSvgDataUrl: async (object, options) => {
1507
+ const svg = await this.getObjectAsSvgMarkup(object, options?.rasterSafeForCanvas ?? false);
1508
+ return svg ? this.svgMarkupToDataUrl(svg) : null;
1509
+ },
1510
+ getObjectAsPngDataUrl: async (object) => {
1511
+ const svg = await this.getObjectAsSvgMarkup(object, true);
1512
+ return svg ? this.svgMarkupToPngDataUrl(svg) : null;
1513
+ },
1514
+ };
1515
+ }
1516
+ async getObjectAsSvgMarkup(object, rasterSafeForCanvas) {
1517
+ const imageDataUrls = await KritzelSvgExportHelper.resolveImageDataUrls([object], this.core.assetResolver);
1518
+ const svg = KritzelSvgExportHelper.generateSvg([object], {
1519
+ theme: this.theme,
1520
+ rasterSafeForCanvas,
1521
+ imageDataUrls,
1522
+ });
1523
+ return svg || null;
1524
+ }
1525
+ svgMarkupToDataUrl(svgMarkup) {
1526
+ return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgMarkup)}`;
1527
+ }
1528
+ async svgMarkupToPngDataUrl(svgMarkup) {
1529
+ const svgBlob = new Blob([svgMarkup], { type: 'image/svg+xml;charset=utf-8' });
1530
+ const svgBlobUrl = URL.createObjectURL(svgBlob);
1531
+ try {
1532
+ const img = await new Promise((resolve, reject) => {
1533
+ const element = new Image();
1534
+ element.onload = () => resolve(element);
1535
+ element.onerror = err => reject(err);
1536
+ element.src = svgBlobUrl;
1537
+ });
1538
+ const width = Math.max(1, Math.ceil(img.naturalWidth || img.width));
1539
+ const height = Math.max(1, Math.ceil(img.naturalHeight || img.height));
1540
+ const canvas = document.createElement('canvas');
1541
+ canvas.width = width;
1542
+ canvas.height = height;
1543
+ const context = canvas.getContext('2d');
1544
+ if (!context) {
1545
+ throw new Error('Could not create 2D canvas context for PNG export');
1546
+ }
1547
+ context.drawImage(img, 0, 0, width, height);
1548
+ return canvas.toDataURL('image/png');
1549
+ }
1550
+ finally {
1551
+ URL.revokeObjectURL(svgBlobUrl);
1552
+ }
1553
+ }
1562
1554
  getImportedWorkspaceName(rawName) {
1563
1555
  if (typeof rawName === 'string' && rawName.trim().length > 0) {
1564
1556
  return rawName;
@@ -2416,7 +2408,9 @@ export class KritzelEngine {
2416
2408
  this.emitObjectsInViewportChange();
2417
2409
  }
2418
2410
  }
2419
- 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: {
2411
+ 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: {
2412
+ color: 'var(--kritzel-global-text-primary)',
2413
+ } }, 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: {
2420
2414
  transform: `matrix(${this.core.store.state?.scale}, 0, 0, ${this.core.store.state?.scale}, ${this.core.store.state?.translateX}, ${this.core.store.state?.translateY})`,
2421
2415
  opacity: this._sceneBootstrapOpacity.toString(),
2422
2416
  transition: this._sceneBootstrapTransitionEnabled ? 'opacity 220ms ease-out' : 'none',
@@ -2599,6 +2593,7 @@ export class KritzelEngine {
2599
2593
  left: `${object.totalWidth}px`,
2600
2594
  top: '0',
2601
2595
  zIndex: (object.zIndex + 2).toString(),
2596
+ color: 'var(--kritzel-global-text-primary)',
2602
2597
  } }, 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)) &&
2603
2598
  (() => {
2604
2599
  const isSelectionGroup = KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup');
@@ -2799,8 +2794,12 @@ export class KritzelEngine {
2799
2794
  strokeDasharray: data.dashArray,
2800
2795
  strokeLinecap: 'round',
2801
2796
  } }))), h("circle", { cx: data.centerX, cy: data.centerY, r: data.indicatorRadius, style: {
2802
- fill: isActiveSnap ? 'var(--kritzel-snap-indicator-fill, rgba(59, 130, 246, 0.3))' : 'rgba(59, 130, 246, 0.18)',
2803
- stroke: isActiveSnap ? 'var(--kritzel-snap-indicator-stroke, #007bff)' : 'rgba(59, 130, 246, 0.5)',
2797
+ fill: isActiveSnap
2798
+ ? 'var(--kritzel-snap-indicator-fill, rgba(59, 130, 246, 0.3))'
2799
+ : 'var(--kritzel-snap-indicator-fill-inactive, var(--kritzel-snap-indicator-fill, rgba(59, 130, 246, 0.18)))',
2800
+ stroke: isActiveSnap
2801
+ ? 'var(--kritzel-snap-indicator-stroke, #007bff)'
2802
+ : 'var(--kritzel-snap-indicator-stroke-inactive, var(--kritzel-snap-indicator-stroke, rgba(59, 130, 246, 0.5)))',
2804
2803
  strokeWidth: data.indicatorStrokeWidth,
2805
2804
  } }))));
2806
2805
  })(), (() => {
@@ -5446,106 +5445,81 @@ export class KritzelEngine {
5446
5445
  }]
5447
5446
  }
5448
5447
  },
5449
- "getSelectedObjectsAsSvgString": {
5448
+ "getSelectedObjectSupportedExportFormats": {
5450
5449
  "complexType": {
5451
- "signature": "(options?: { theme?: \"light\" | \"dark\"; padding?: number; rasterSafeForCanvas?: boolean; }) => Promise<string | null>",
5452
- "parameters": [{
5453
- "name": "options",
5454
- "type": "{ theme?: \"light\" | \"dark\"; padding?: number; rasterSafeForCanvas?: boolean; }",
5455
- "docs": "- Optional export settings (theme, padding, raster-safe mode for canvas export)."
5456
- }],
5457
- "references": {
5458
- "Promise": {
5459
- "location": "global",
5460
- "id": "global::Promise"
5461
- }
5462
- },
5463
- "return": "Promise<string>"
5464
- },
5465
- "docs": {
5466
- "text": "Generates an SVG string from the currently selected objects.\nCreates clean, standards-compliant SVG markup by directly serializing object properties.",
5467
- "tags": [{
5468
- "name": "param",
5469
- "text": "options - Optional export settings (theme, padding, raster-safe mode for canvas export)."
5470
- }, {
5471
- "name": "returns",
5472
- "text": "SVG markup string, or null if no objects are selected."
5473
- }]
5474
- }
5475
- },
5476
- "exportSelectedObjectsAsSvg": {
5477
- "complexType": {
5478
- "signature": "(options?: { theme?: \"light\" | \"dark\"; padding?: number; }) => Promise<void>",
5479
- "parameters": [{
5480
- "name": "options",
5481
- "type": "{ theme?: \"light\" | \"dark\"; padding?: number; }",
5482
- "docs": "- Optional export settings (theme, padding)."
5483
- }],
5450
+ "signature": "() => Promise<KritzelObjectExportFormat[]>",
5451
+ "parameters": [],
5484
5452
  "references": {
5485
5453
  "Promise": {
5486
5454
  "location": "global",
5487
5455
  "id": "global::Promise"
5456
+ },
5457
+ "KritzelObjectExportFormat": {
5458
+ "location": "import",
5459
+ "path": "../../../interfaces/object-export.interface",
5460
+ "id": "src/interfaces/object-export.interface.ts::KritzelObjectExportFormat",
5461
+ "referenceLocation": "KritzelObjectExportFormat"
5488
5462
  }
5489
5463
  },
5490
- "return": "Promise<void>"
5464
+ "return": "Promise<KritzelObjectExportFormat[]>"
5491
5465
  },
5492
5466
  "docs": {
5493
- "text": "Exports the currently selected objects as an SVG file and triggers a browser download.\nCreates clean, standards-compliant SVG markup suitable for import into vector editors.",
5494
- "tags": [{
5495
- "name": "param",
5496
- "text": "options - Optional export settings (theme, padding)."
5497
- }]
5467
+ "text": "Returns export formats supported by the currently selected object.\nOnly returns formats when exactly one object is selected.",
5468
+ "tags": []
5498
5469
  }
5499
5470
  },
5500
- "getSelectedObjectsAsPngDataUrl": {
5471
+ "canExportSelectedObjectAs": {
5501
5472
  "complexType": {
5502
- "signature": "(options?: { theme?: \"light\" | \"dark\"; padding?: number; scale?: number; }) => Promise<string | null>",
5473
+ "signature": "(format: KritzelObjectExportFormat) => Promise<boolean>",
5503
5474
  "parameters": [{
5504
- "name": "options",
5505
- "type": "{ theme?: \"light\" | \"dark\"; padding?: number; scale?: number; }",
5506
- "docs": "- Optional export settings (theme, padding, scale for resolution)."
5475
+ "name": "format",
5476
+ "type": "\"svg\" | \"png\"",
5477
+ "docs": ""
5507
5478
  }],
5508
5479
  "references": {
5509
5480
  "Promise": {
5510
5481
  "location": "global",
5511
5482
  "id": "global::Promise"
5483
+ },
5484
+ "KritzelObjectExportFormat": {
5485
+ "location": "import",
5486
+ "path": "../../../interfaces/object-export.interface",
5487
+ "id": "src/interfaces/object-export.interface.ts::KritzelObjectExportFormat",
5488
+ "referenceLocation": "KritzelObjectExportFormat"
5512
5489
  }
5513
5490
  },
5514
- "return": "Promise<string>"
5491
+ "return": "Promise<boolean>"
5515
5492
  },
5516
5493
  "docs": {
5517
- "text": "Generates a PNG data URL from the currently selected objects.\nConverts the SVG representation to a rasterized PNG image.",
5518
- "tags": [{
5519
- "name": "param",
5520
- "text": "options - Optional export settings (theme, padding, scale for resolution)."
5521
- }, {
5522
- "name": "returns",
5523
- "text": "PNG data URL string, or null if no objects are selected."
5524
- }]
5494
+ "text": "Checks whether the currently selected object supports a specific export format.\nReturns false when none or multiple objects are selected.",
5495
+ "tags": []
5525
5496
  }
5526
5497
  },
5527
- "exportSelectedObjectsAsPng": {
5498
+ "exportSelectedObject": {
5528
5499
  "complexType": {
5529
- "signature": "(options?: { theme?: \"light\" | \"dark\"; padding?: number; scale?: number; }) => Promise<void>",
5500
+ "signature": "(format: KritzelObjectExportFormat) => Promise<void>",
5530
5501
  "parameters": [{
5531
- "name": "options",
5532
- "type": "{ theme?: \"light\" | \"dark\"; padding?: number; scale?: number; }",
5533
- "docs": "- Optional export settings (theme, padding, scale for resolution)."
5502
+ "name": "format",
5503
+ "type": "\"svg\" | \"png\"",
5504
+ "docs": ""
5534
5505
  }],
5535
5506
  "references": {
5536
5507
  "Promise": {
5537
5508
  "location": "global",
5538
5509
  "id": "global::Promise"
5510
+ },
5511
+ "KritzelObjectExportFormat": {
5512
+ "location": "import",
5513
+ "path": "../../../interfaces/object-export.interface",
5514
+ "id": "src/interfaces/object-export.interface.ts::KritzelObjectExportFormat",
5515
+ "referenceLocation": "KritzelObjectExportFormat"
5539
5516
  }
5540
5517
  },
5541
5518
  "return": "Promise<void>"
5542
5519
  },
5543
5520
  "docs": {
5544
- "text": "Exports the currently selected objects as a PNG file and triggers a browser download.",
5545
- "tags": [{
5546
- "name": "param",
5547
- "text": "options - Optional export settings (theme, padding, scale for resolution)."
5548
- }]
5521
+ "text": "Exports the currently selected object in the requested format and triggers a file download.\nOnly supports single selection.",
5522
+ "tags": []
5549
5523
  }
5550
5524
  },
5551
5525
  "exportAsJson": {
@@ -69,7 +69,7 @@ export class KritzelExport {
69
69
  return (h("div", { class: "export-tab-content" }, h("kritzel-input", { label: this.terms['export.filename.label'] ?? 'Filename', value: this.exportFilename, placeholder: this.terms['export.filename.placeholder'] ?? 'Enter filename', suffix: ".json", onValueChange: this.handleFilenameChange })));
70
70
  }
71
71
  render() {
72
- return (h(Host, { key: '0bc45e80716be4a7b19ae12a6464a641b5bd4550' }, h("kritzel-dialog", { key: 'f336f8b1e4ae10954d48ca67da88504faf06b295', isOpen: this.isDialogOpen, dialogTitle: this.terms['export.dialogTitle'] ?? 'Export', closable: true, contained: true, onDialogClose: this.closeDialog }, h("div", { key: 'e2d1209652bb54fb7f623e50bc4bbbb703083b76', class: "export-content" }, h("kritzel-pill-tabs", { key: 'dd78430b78d1e8c4ac0a76e8a6a5d48bebf5e889', tabs: this.tabs, value: this.activeTab, onValueChange: this.handleTabChange }), this.activeTab === 'viewport' && this.renderViewportExport(), this.activeTab === 'workspace' && this.renderWorkspaceExport(), h("button", { key: 'e06564889d991afc7a4ac43bb1e5504e98c94c52', class: "export-primary-button", onClick: this.handleExport }, this.terms['export.exportButton'] ?? 'Export')))));
72
+ return (h(Host, { key: '0bc45e80716be4a7b19ae12a6464a641b5bd4550' }, h("kritzel-dialog", { key: 'f336f8b1e4ae10954d48ca67da88504faf06b295', isOpen: this.isDialogOpen, dialogTitle: this.terms['export.dialogTitle'] ?? 'Export', closable: true, contained: true, onDialogClose: this.closeDialog }, h("div", { key: 'e2d1209652bb54fb7f623e50bc4bbbb703083b76', class: "export-content" }, h("kritzel-pill-tabs", { key: 'dd78430b78d1e8c4ac0a76e8a6a5d48bebf5e889', tabs: this.tabs, value: this.activeTab, onValueChange: this.handleTabChange }), this.activeTab === 'viewport' && this.renderViewportExport(), this.activeTab === 'workspace' && this.renderWorkspaceExport()), h("div", { key: 'd04221d9f98a066d538f98f8c9409c558fdfa29f', slot: "footer" }, h("button", { key: '5cbb062756f29a897088d6647c6b8eae9f5781e2', class: "export-primary-button", onClick: this.handleExport }, this.terms['export.exportButton'] ?? 'Export')))));
73
73
  }
74
74
  static get is() { return "kritzel-export"; }
75
75
  static get encapsulation() { return "shadow"; }
@@ -9,7 +9,7 @@ export class KritzelLoadingOverlay {
9
9
  */
10
10
  text = 'Loading...';
11
11
  render() {
12
- return (h(Host, { key: '331e4c9eb30e6f7b98023c23218b3caf5093c34b' }, h("div", { key: 'f994fec0db325a2bd687e5acc68263752e7a6acd', class: { 'loading-overlay': true, visible: this.visible }, "aria-hidden": this.visible ? 'false' : 'true' }, h("span", { key: 'b6087dc1e59845ab95946e654c7bb8e568b42dda', class: "loading-spinner" }), this.text)));
12
+ return (h(Host, { key: 'ce2edf698db335518979f597ad32fa259c3055b9' }, h("div", { key: '7cf019929b72d18fdd1cea55157dc5b5fc2ea151', class: { 'loading-overlay': true, visible: this.visible }, "aria-hidden": this.visible ? 'false' : 'true' }, h("span", { key: '86b7cb040bcfb1abb2161a38f9cff153d5aa6c18', class: "loading-spinner" }), this.text)));
13
13
  }
14
14
  static get is() { return "kritzel-loading-overlay"; }
15
15
  static get encapsulation() { return "shadow"; }
@@ -44,7 +44,7 @@ export class KritzelLoginDialog {
44
44
  this.dialogClosed.emit();
45
45
  };
46
46
  render() {
47
- return (h(Host, { key: 'bcd7f30bbfeb07bbca732c5f1034bcabbd5e4f80' }, h("kritzel-dialog", { key: '61b5c5054d43433894747f37c571e68ecf08fc4c', dialogTitle: this.dialogTitle, isOpen: this.isDialogOpen, onDialogClose: this.closeDialog, size: "small", contained: true }, h("div", { key: '3ddcb858b6148e8be4bd121b2bd8ca38c66e0505', class: "login-content" }, this.subtitle && (h("p", { key: '6f10f890af9f6025a3aa2d69f8f4d916821fd653', class: "login-subtitle" }, this.subtitle)), h("div", { key: '0d043ac1ac751dc3d0a561bc16e52a2cfaffc578', class: "login-providers" }, this.providers.map(provider => (h("button", { key: provider.name, class: {
47
+ return (h(Host, { key: '561b4e76017e71d99f05cd33ed9f6e3769bb9aec' }, h("kritzel-dialog", { key: '74b904f67496debebf7a1854e3e3dd193f14a445', dialogTitle: this.dialogTitle, isOpen: this.isDialogOpen, onDialogClose: this.closeDialog, size: "small", contained: true }, h("div", { key: 'dcc2a024349fcdfcad7c7c6d5b7754e5ae990ae3', class: "login-content" }, this.subtitle && (h("p", { key: 'fdc927c84294a2ac92aec90001c3da373cc5f082', class: "login-subtitle" }, this.subtitle)), h("div", { key: 'a6e74ff9b3211df195b05edd2be0ce69d1b128df', class: "login-providers" }, this.providers.map(provider => (h("button", { key: provider.name, class: {
48
48
  'provider-button': true,
49
49
  'is-loading': this.loadingProvider === provider.name,
50
50
  'is-disabled': this.loadingProvider !== null && this.loadingProvider !== provider.name,
@@ -32,6 +32,14 @@ export class KritzelMoreMenu {
32
32
  itemSelect;
33
33
  menuAnchor = null;
34
34
  isTouchDevice = KritzelDevicesHelper.isTouchDevice();
35
+ visibleItems = [];
36
+ visibilityResolveVersion = 0;
37
+ onItemsChange() {
38
+ void this.resolveVisibleItems();
39
+ }
40
+ componentWillLoad() {
41
+ void this.resolveVisibleItems();
42
+ }
35
43
  toggleMenu = (event) => {
36
44
  event.stopPropagation();
37
45
  if (this.menuAnchor) {
@@ -40,13 +48,84 @@ export class KritzelMoreMenu {
40
48
  else {
41
49
  window.dispatchEvent(new CustomEvent('kritzel-dismiss-menus'));
42
50
  this.menuAnchor = this.host;
51
+ this.visibleItems = this.filterVisibleItemsSync(this.items ?? []);
52
+ void this.resolveVisibleItems();
43
53
  }
44
54
  };
45
55
  closeMenu = () => {
46
56
  this.menuAnchor = null;
47
57
  };
48
- get visibleItems() {
49
- return this.items.filter(item => item.isVisible !== false);
58
+ async evaluateVisibility(visibility) {
59
+ if (typeof visibility === 'function') {
60
+ try {
61
+ return (await visibility()) !== false;
62
+ }
63
+ catch {
64
+ return false;
65
+ }
66
+ }
67
+ return visibility !== false;
68
+ }
69
+ evaluateVisibilitySync(visibility) {
70
+ if (typeof visibility === 'function') {
71
+ try {
72
+ const result = visibility();
73
+ return result instanceof Promise ? null : result !== false;
74
+ }
75
+ catch {
76
+ return false;
77
+ }
78
+ }
79
+ return visibility !== false;
80
+ }
81
+ filterVisibleItemsSync(items) {
82
+ return items.reduce((visibleItems, item) => {
83
+ const isVisible = this.evaluateVisibilitySync(item.isVisible);
84
+ if (isVisible === null || !isVisible) {
85
+ return visibleItems;
86
+ }
87
+ if (!item.children?.length) {
88
+ visibleItems.push(item);
89
+ return visibleItems;
90
+ }
91
+ visibleItems.push({
92
+ ...item,
93
+ children: this.filterVisibleItemsSync(item.children),
94
+ });
95
+ return visibleItems;
96
+ }, []);
97
+ }
98
+ async filterVisibleItems(items) {
99
+ const resolved = await Promise.all(items.map(async (item) => {
100
+ const isVisible = await this.evaluateVisibility(item.isVisible);
101
+ if (!isVisible) {
102
+ return null;
103
+ }
104
+ if (!item.children?.length) {
105
+ return item;
106
+ }
107
+ return {
108
+ ...item,
109
+ children: await this.filterVisibleItems(item.children),
110
+ };
111
+ }));
112
+ return resolved.filter((item) => !!item);
113
+ }
114
+ async resolveVisibleItems() {
115
+ const version = ++this.visibilityResolveVersion;
116
+ const items = this.items ?? [];
117
+ const resolvedItems = await this.filterVisibleItems(items);
118
+ if (version !== this.visibilityResolveVersion) {
119
+ return;
120
+ }
121
+ this.visibleItems = resolvedItems;
122
+ }
123
+ resolveMenuLabels(items) {
124
+ return items.map(item => ({
125
+ ...item,
126
+ label: this.terms[item.label] ?? item.label,
127
+ children: item.children ? this.resolveMenuLabels(item.children) : undefined,
128
+ }));
50
129
  }
51
130
  handleMenuItemSelect = (event) => {
52
131
  const { item, parent } = event.detail;
@@ -57,7 +136,7 @@ export class KritzelMoreMenu {
57
136
  this.closeMenu();
58
137
  };
59
138
  render() {
60
- return (h(Host, { key: '96451062021ac2ebcb44b65384a7e9be67f1563b', class: { mobile: this.isTouchDevice }, style: { display: this.visible ? '' : 'none' } }, h("div", { key: 'e776398742284ea6984925d4a5a99e732674d640', class: { 'more-menu-wrapper': true, visible: this.visible } }, h("button", { key: '4371b2e5cbf7d35fac09a06ee2e54cd49072929b', class: "more-menu-button", "data-testid": "more-menu-button", onClick: this.toggleMenu, "aria-label": this.terms['moreMenu.ariaLabel'] ?? 'More options' }, h("kritzel-icon", { key: '076513ce393222b6f604036ec646a8309bc3a3ac', name: this.icon, size: this.iconSize })), h("kritzel-portal", { key: 'fde8071b3199735cc7827a2d6f2eaf79d0e1b997', anchor: this.menuAnchor, offsetY: this.offsetY, onClose: this.closeMenu }, h("kritzel-menu", { key: '2d49ad8a228c4b55a34c388b794bfdf500fec3c8', items: this.visibleItems, onItemSelect: this.handleMenuItemSelect })))));
139
+ return (h(Host, { key: 'dbfe312eccd24901ffc68179ef93ba0a94a765c5', class: { mobile: this.isTouchDevice }, style: { display: this.visible ? '' : 'none' } }, h("div", { key: '33bd535bb58ae32a32d44133a109fdd3667b4947', class: { 'more-menu-wrapper': true, visible: this.visible } }, h("button", { key: '23dbae51d73b92b181721bdef4a44049ec6484c5', class: "more-menu-button", "data-testid": "more-menu-button", onClick: this.toggleMenu, "aria-label": this.terms['moreMenu.ariaLabel'] ?? 'More options' }, h("kritzel-icon", { key: 'bda7c092b57af366b5d6b882cbab991cd9bb77ba', name: this.icon, size: this.iconSize })), h("kritzel-portal", { key: '2959ac3e6e0a5598c735ce7a01619bda8753039f', anchor: this.menuAnchor, offsetY: this.offsetY, onClose: this.closeMenu }, h("kritzel-menu", { key: 'a5481a1bc02dc059dc0ad188b93b9eaf9b56e98f', items: this.resolveMenuLabels(this.visibleItems), onItemSelect: this.handleMenuItemSelect })))));
61
140
  }
62
141
  static get is() { return "kritzel-more-menu"; }
63
142
  static get encapsulation() { return "shadow"; }
@@ -216,7 +295,8 @@ export class KritzelMoreMenu {
216
295
  static get states() {
217
296
  return {
218
297
  "menuAnchor": {},
219
- "isTouchDevice": {}
298
+ "isTouchDevice": {},
299
+ "visibleItems": {}
220
300
  };
221
301
  }
222
302
  static get events() {
@@ -245,4 +325,10 @@ export class KritzelMoreMenu {
245
325
  }];
246
326
  }
247
327
  static get elementRef() { return "host"; }
328
+ static get watchers() {
329
+ return [{
330
+ "propName": "items",
331
+ "methodName": "onItemsChange"
332
+ }];
333
+ }
248
334
  }