kritzel-stencil 0.4.8 → 0.4.10

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 (166) hide show
  1. package/dist/cjs/index.cjs.js +9 -1
  2. package/dist/cjs/kritzel-active-users_47.cjs.entry.js +1427 -1289
  3. package/dist/cjs/loader.cjs.js +1 -1
  4. package/dist/cjs/{schema.constants-gDeS7USU.js → schema.constants-C6PknABJ.js} +81 -6
  5. package/dist/cjs/stencil.cjs.js +1 -1
  6. package/dist/collection/classes/objects/image.class.js +9 -0
  7. package/dist/collection/classes/objects/path.class.js +9 -0
  8. package/dist/collection/classes/objects/shape.class.js +9 -0
  9. package/dist/collection/classes/providers/sync/broadcast-sync-provider.class.js +1 -0
  10. package/dist/collection/classes/providers/sync/hocuspocus-sync-provider.class.js +2 -0
  11. package/dist/collection/classes/providers/sync/in-memory-sync-provider.class.js +1 -0
  12. package/dist/collection/classes/providers/sync/indexeddb-sync-provider.class.js +1 -0
  13. package/dist/collection/classes/providers/sync/websocket-sync-provider.class.js +2 -0
  14. package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +201 -67
  15. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +137 -170
  16. package/dist/collection/components/core/kritzel-watermark/kritzel-watermark.js +1 -1
  17. package/dist/collection/components/shared/kritzel-avatar/kritzel-avatar.js +3 -3
  18. package/dist/collection/components/shared/kritzel-button/kritzel-button.js +2 -2
  19. package/dist/collection/components/shared/kritzel-color/kritzel-color.js +2 -2
  20. package/dist/collection/components/shared/kritzel-color-palette/kritzel-color-palette.js +1 -1
  21. package/dist/collection/components/shared/kritzel-font/kritzel-font.js +1 -1
  22. package/dist/collection/components/shared/kritzel-font-size/kritzel-font-size.js +1 -1
  23. package/dist/collection/components/shared/kritzel-input/kritzel-input.js +1 -1
  24. package/dist/collection/components/shared/kritzel-master-detail/kritzel-master-detail.js +3 -3
  25. package/dist/collection/components/shared/kritzel-menu/kritzel-menu.js +1 -1
  26. package/dist/collection/components/shared/kritzel-menu-item/kritzel-menu-item.js +2 -2
  27. package/dist/collection/components/shared/kritzel-numeric-input/kritzel-numeric-input.js +1 -1
  28. package/dist/collection/components/shared/kritzel-opacity-slider/kritzel-opacity-slider.js +1 -1
  29. package/dist/collection/components/shared/kritzel-portal/kritzel-portal.js +1 -1
  30. package/dist/collection/components/shared/kritzel-slide-toggle/kritzel-slide-toggle.js +1 -1
  31. package/dist/collection/components/shared/kritzel-split-button/kritzel-split-button.js +1 -1
  32. package/dist/collection/components/shared/kritzel-stroke-size/kritzel-stroke-size.js +1 -1
  33. package/dist/collection/components/shared/kritzel-sync-indicator/kritzel-sync-indicator.css +5 -5
  34. package/dist/collection/components/shared/kritzel-sync-indicator/kritzel-sync-indicator.js +1 -1
  35. package/dist/collection/components/shared/kritzel-tooltip/kritzel-tooltip.js +2 -2
  36. package/dist/collection/components/ui/kritzel-back-to-content/kritzel-back-to-content.js +1 -1
  37. package/dist/collection/components/ui/kritzel-controls/kritzel-controls.js +7 -7
  38. package/dist/collection/components/ui/kritzel-current-user/kritzel-current-user.js +2 -2
  39. package/dist/collection/components/ui/kritzel-current-user-dialog/kritzel-current-user-dialog.js +2 -2
  40. package/dist/collection/components/ui/kritzel-export/kritzel-export.js +2 -2
  41. package/dist/collection/components/ui/kritzel-loading-overlay/kritzel-loading-overlay.css +6 -6
  42. package/dist/collection/components/ui/kritzel-loading-overlay/kritzel-loading-overlay.js +1 -1
  43. package/dist/collection/components/ui/kritzel-login-dialog/kritzel-login-dialog.js +1 -1
  44. package/dist/collection/components/ui/kritzel-more-menu/kritzel-more-menu.js +91 -5
  45. package/dist/collection/components/ui/kritzel-settings/kritzel-settings.js +2 -2
  46. package/dist/collection/components/ui/kritzel-share-dialog/kritzel-share-dialog.js +3 -3
  47. package/dist/collection/components/ui/kritzel-tool-config/kritzel-tool-config.js +1 -1
  48. package/dist/collection/components/ui/kritzel-utility-panel/kritzel-utility-panel.js +2 -2
  49. package/dist/collection/components/ui/kritzel-workspace-manager/kritzel-workspace-manager.js +1 -1
  50. package/dist/collection/components/ui/kritzel-zoom-panel/kritzel-zoom-panel.js +2 -2
  51. package/dist/collection/constants/version.js +1 -1
  52. package/dist/collection/helpers/object.helper.js +11 -0
  53. package/dist/collection/index.js +1 -0
  54. package/dist/collection/interfaces/object-export.interface.js +1 -0
  55. package/dist/collection/interfaces/sync-config.interface.js +21 -1
  56. package/dist/collection/locales/de-locale.js +2 -2
  57. package/dist/collection/locales/en-locale.js +2 -2
  58. package/dist/collection/locales/fr-locale.js +2 -2
  59. package/dist/collection/themes/dark-theme.js +7 -0
  60. package/dist/collection/themes/light-theme.js +7 -0
  61. package/dist/components/index.js +11 -4
  62. package/dist/components/kritzel-active-users.js +1 -1
  63. package/dist/components/kritzel-avatar.js +1 -1
  64. package/dist/components/kritzel-awareness-cursors.js +1 -1
  65. package/dist/components/kritzel-back-to-content.js +1 -1
  66. package/dist/components/kritzel-button.js +1 -1
  67. package/dist/components/kritzel-color-palette.js +1 -1
  68. package/dist/components/kritzel-color.js +1 -1
  69. package/dist/components/kritzel-controls.js +1 -1
  70. package/dist/components/kritzel-current-user-dialog.js +1 -1
  71. package/dist/components/kritzel-current-user.js +1 -1
  72. package/dist/components/kritzel-editor.js +200 -99
  73. package/dist/components/kritzel-engine.js +1 -1
  74. package/dist/components/kritzel-export.js +1 -1
  75. package/dist/components/kritzel-font-size.js +1 -1
  76. package/dist/components/kritzel-font.js +1 -1
  77. package/dist/components/kritzel-input.js +1 -1
  78. package/dist/components/kritzel-loading-overlay.js +1 -1
  79. package/dist/components/kritzel-login-dialog.js +1 -1
  80. package/dist/components/kritzel-master-detail.js +1 -1
  81. package/dist/components/kritzel-menu-item.js +1 -1
  82. package/dist/components/kritzel-menu.js +1 -1
  83. package/dist/components/kritzel-more-menu.js +1 -1
  84. package/dist/components/kritzel-numeric-input.js +1 -1
  85. package/dist/components/kritzel-opacity-slider.js +1 -1
  86. package/dist/components/kritzel-portal.js +1 -1
  87. package/dist/components/kritzel-settings.js +1 -1
  88. package/dist/components/kritzel-share-dialog.js +1 -1
  89. package/dist/components/kritzel-slide-toggle.js +1 -1
  90. package/dist/components/kritzel-split-button.js +1 -1
  91. package/dist/components/kritzel-stroke-size.js +1 -1
  92. package/dist/components/kritzel-sync-indicator.js +1 -1
  93. package/dist/components/kritzel-tool-config.js +1 -1
  94. package/dist/components/kritzel-tooltip.js +1 -1
  95. package/dist/components/kritzel-utility-panel.js +1 -1
  96. package/dist/components/kritzel-watermark.js +1 -1
  97. package/dist/components/kritzel-workspace-manager.js +1 -1
  98. package/dist/components/kritzel-zoom-panel.js +1 -1
  99. package/dist/components/{p-8xkoVMfO.js → p-2WiGyky4.js} +2 -2
  100. package/dist/components/{p-D8TOEhPY.js → p-30g2W_Gx.js} +3 -3
  101. package/dist/components/{p-DXcjIb_a.js → p-4SPnZZkH.js} +3 -3
  102. package/dist/components/{p-CURiiQfq.js → p-7I4Uzjrw.js} +14 -0
  103. package/dist/components/{p-9m1cAVwG.js → p-B-585egz.js} +3 -3
  104. package/dist/components/{p-COjsYPir.js → p-BP6Fo3rt.js} +2 -2
  105. package/dist/components/{p-BLOPBDUF.js → p-BPsKYMH6.js} +2 -2
  106. package/dist/components/{p-DkY7pIg5.js → p-BX1aRLEi.js} +95 -6
  107. package/dist/components/{p-BMRln59F.js → p-B_lZQo3s.js} +3 -3
  108. package/dist/components/{p-oGAPPwAL.js → p-BoN700-O.js} +2 -2
  109. package/dist/components/{p-BzJEwFtn.js → p-BozrueXV.js} +1 -1
  110. package/dist/components/{p-DwY5pghH.js → p-Bvv1pGFD.js} +1 -1
  111. package/dist/components/{p-D8bHNNEm.js → p-C6e7eOEb.js} +1238 -1241
  112. package/dist/components/{p-CM1duewg.js → p-CAoN_STZ.js} +2 -2
  113. package/dist/components/{p-CVhcOiEA.js → p-CM65T33m.js} +3 -3
  114. package/dist/components/{p-BknTMcbz.js → p-COylwYw1.js} +16 -16
  115. package/dist/components/{p-BYO6pz8T.js → p-CZ99VWQc.js} +1 -1
  116. package/dist/components/{p-DrQRChp3.js → p-CaBbajU2.js} +2 -2
  117. package/dist/components/{p-BzrxIesp.js → p-CrHvaLRV.js} +1 -1
  118. package/dist/components/{p-BKOsmXB5.js → p-D-UkGru5.js} +4 -4
  119. package/dist/components/{p-BVEGQLBD.js → p-DB58Oa5V.js} +2 -2
  120. package/dist/components/{p-yD_3Z3K1.js → p-DBqoPgev.js} +1 -1
  121. package/dist/components/{p-DIMNEOTW.js → p-DKGg-76-.js} +1 -1
  122. package/dist/components/{p-Dd-pMvlr.js → p-DPONTran.js} +11 -0
  123. package/dist/components/{p-DgnK50xO.js → p-DVXTPI71.js} +1 -1
  124. package/dist/components/{p-DgA865Tp.js → p-DdabFzSa.js} +5 -5
  125. package/dist/components/{p-CMZ09rB1.js → p-Dt7-I2Xz.js} +3 -3
  126. package/dist/components/{p-CwuGA058.js → p-DtnMdWWB.js} +1 -1
  127. package/dist/components/{p-7Rt7ml3v.js → p-Dv4pZx8G.js} +1 -1
  128. package/dist/components/{p-BO9BvTtK.js → p-DwMqCX2P.js} +2 -2
  129. package/dist/components/{p-Cr2z2UBL.js → p-Dy3uucl_.js} +7 -7
  130. package/dist/components/{p-Ckm1Aq0V.js → p-GKmqCI8r.js} +2 -2
  131. package/dist/components/{p-DSOc0eIT.js → p-PjPPCHVL.js} +1 -1
  132. package/dist/components/{p-OLfoATNk.js → p-ShJrZeyt.js} +1 -1
  133. package/dist/components/{p-0H4HOJjy.js → p-bAacqNHq.js} +11 -2
  134. package/dist/components/{p-BU-FZuj0.js → p-vqEUQ-4Q.js} +3 -3
  135. package/dist/components/{p-DDbO5q-e.js → p-x3z0Cz1B.js} +4 -4
  136. package/dist/esm/index.js +9 -2
  137. package/dist/esm/kritzel-active-users_47.entry.js +1427 -1289
  138. package/dist/esm/loader.js +1 -1
  139. package/dist/esm/{schema.constants-Rpm1NA9u.js → schema.constants-C-oQbvCY.js} +81 -7
  140. package/dist/esm/stencil.js +1 -1
  141. package/dist/stencil/index.esm.js +9 -2
  142. package/dist/stencil/{p-Rpm1NA9u.js → p-C-oQbvCY.js} +81 -7
  143. package/dist/stencil/{p-8c1b7b08.entry.js → p-be87f9d3.entry.js} +1427 -1289
  144. package/dist/stencil/stencil.esm.js +1 -1
  145. package/dist/types/classes/objects/image.class.d.ts +3 -0
  146. package/dist/types/classes/objects/path.class.d.ts +3 -0
  147. package/dist/types/classes/objects/shape.class.d.ts +3 -0
  148. package/dist/types/classes/providers/sync/broadcast-sync-provider.class.d.ts +1 -0
  149. package/dist/types/classes/providers/sync/hocuspocus-sync-provider.class.d.ts +1 -0
  150. package/dist/types/classes/providers/sync/in-memory-sync-provider.class.d.ts +1 -0
  151. package/dist/types/classes/providers/sync/indexeddb-sync-provider.class.d.ts +1 -0
  152. package/dist/types/classes/providers/sync/websocket-sync-provider.class.d.ts +1 -0
  153. package/dist/types/components/core/kritzel-editor/kritzel-editor.d.ts +17 -3
  154. package/dist/types/components/core/kritzel-engine/kritzel-engine.d.ts +16 -34
  155. package/dist/types/components/ui/kritzel-more-menu/kritzel-more-menu.d.ts +10 -1
  156. package/dist/types/components.d.ts +27 -26
  157. package/dist/types/constants/version.d.ts +1 -1
  158. package/dist/types/helpers/object.helper.d.ts +4 -0
  159. package/dist/types/index.d.ts +1 -0
  160. package/dist/types/interfaces/localization.interface.d.ts +1 -1
  161. package/dist/types/interfaces/menu-item.interface.d.ts +1 -1
  162. package/dist/types/interfaces/object-export.interface.d.ts +20 -0
  163. package/dist/types/interfaces/sync-config.interface.d.ts +5 -0
  164. package/dist/types/interfaces/sync-provider.interface.d.ts +5 -0
  165. package/dist/types/interfaces/theme.interface.d.ts +11 -5
  166. 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,7 @@ 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", style: {
2411
+ return (h(Host, null, this.core.store.state.debugInfo.showViewportInfo && (h("div", { class: "debug-panel", style: {
2420
2412
  color: 'var(--kritzel-global-text-primary)',
2421
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: {
2422
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})`,
@@ -5453,106 +5445,81 @@ export class KritzelEngine {
5453
5445
  }]
5454
5446
  }
5455
5447
  },
5456
- "getSelectedObjectsAsSvgString": {
5448
+ "getSelectedObjectSupportedExportFormats": {
5457
5449
  "complexType": {
5458
- "signature": "(options?: { theme?: \"light\" | \"dark\"; padding?: number; rasterSafeForCanvas?: boolean; }) => Promise<string | null>",
5459
- "parameters": [{
5460
- "name": "options",
5461
- "type": "{ theme?: \"light\" | \"dark\"; padding?: number; rasterSafeForCanvas?: boolean; }",
5462
- "docs": "- Optional export settings (theme, padding, raster-safe mode for canvas export)."
5463
- }],
5464
- "references": {
5465
- "Promise": {
5466
- "location": "global",
5467
- "id": "global::Promise"
5468
- }
5469
- },
5470
- "return": "Promise<string>"
5471
- },
5472
- "docs": {
5473
- "text": "Generates an SVG string from the currently selected objects.\nCreates clean, standards-compliant SVG markup by directly serializing object properties.",
5474
- "tags": [{
5475
- "name": "param",
5476
- "text": "options - Optional export settings (theme, padding, raster-safe mode for canvas export)."
5477
- }, {
5478
- "name": "returns",
5479
- "text": "SVG markup string, or null if no objects are selected."
5480
- }]
5481
- }
5482
- },
5483
- "exportSelectedObjectsAsSvg": {
5484
- "complexType": {
5485
- "signature": "(options?: { theme?: \"light\" | \"dark\"; padding?: number; }) => Promise<void>",
5486
- "parameters": [{
5487
- "name": "options",
5488
- "type": "{ theme?: \"light\" | \"dark\"; padding?: number; }",
5489
- "docs": "- Optional export settings (theme, padding)."
5490
- }],
5450
+ "signature": "() => Promise<KritzelObjectExportFormat[]>",
5451
+ "parameters": [],
5491
5452
  "references": {
5492
5453
  "Promise": {
5493
5454
  "location": "global",
5494
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"
5495
5462
  }
5496
5463
  },
5497
- "return": "Promise<void>"
5464
+ "return": "Promise<KritzelObjectExportFormat[]>"
5498
5465
  },
5499
5466
  "docs": {
5500
- "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.",
5501
- "tags": [{
5502
- "name": "param",
5503
- "text": "options - Optional export settings (theme, padding)."
5504
- }]
5467
+ "text": "Returns export formats supported by the currently selected object.\nOnly returns formats when exactly one object is selected.",
5468
+ "tags": []
5505
5469
  }
5506
5470
  },
5507
- "getSelectedObjectsAsPngDataUrl": {
5471
+ "canExportSelectedObjectAs": {
5508
5472
  "complexType": {
5509
- "signature": "(options?: { theme?: \"light\" | \"dark\"; padding?: number; scale?: number; }) => Promise<string | null>",
5473
+ "signature": "(format: KritzelObjectExportFormat) => Promise<boolean>",
5510
5474
  "parameters": [{
5511
- "name": "options",
5512
- "type": "{ theme?: \"light\" | \"dark\"; padding?: number; scale?: number; }",
5513
- "docs": "- Optional export settings (theme, padding, scale for resolution)."
5475
+ "name": "format",
5476
+ "type": "\"svg\" | \"png\"",
5477
+ "docs": ""
5514
5478
  }],
5515
5479
  "references": {
5516
5480
  "Promise": {
5517
5481
  "location": "global",
5518
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"
5519
5489
  }
5520
5490
  },
5521
- "return": "Promise<string>"
5491
+ "return": "Promise<boolean>"
5522
5492
  },
5523
5493
  "docs": {
5524
- "text": "Generates a PNG data URL from the currently selected objects.\nConverts the SVG representation to a rasterized PNG image.",
5525
- "tags": [{
5526
- "name": "param",
5527
- "text": "options - Optional export settings (theme, padding, scale for resolution)."
5528
- }, {
5529
- "name": "returns",
5530
- "text": "PNG data URL string, or null if no objects are selected."
5531
- }]
5494
+ "text": "Checks whether the currently selected object supports a specific export format.\nReturns false when none or multiple objects are selected.",
5495
+ "tags": []
5532
5496
  }
5533
5497
  },
5534
- "exportSelectedObjectsAsPng": {
5498
+ "exportSelectedObject": {
5535
5499
  "complexType": {
5536
- "signature": "(options?: { theme?: \"light\" | \"dark\"; padding?: number; scale?: number; }) => Promise<void>",
5500
+ "signature": "(format: KritzelObjectExportFormat) => Promise<void>",
5537
5501
  "parameters": [{
5538
- "name": "options",
5539
- "type": "{ theme?: \"light\" | \"dark\"; padding?: number; scale?: number; }",
5540
- "docs": "- Optional export settings (theme, padding, scale for resolution)."
5502
+ "name": "format",
5503
+ "type": "\"svg\" | \"png\"",
5504
+ "docs": ""
5541
5505
  }],
5542
5506
  "references": {
5543
5507
  "Promise": {
5544
5508
  "location": "global",
5545
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"
5546
5516
  }
5547
5517
  },
5548
5518
  "return": "Promise<void>"
5549
5519
  },
5550
5520
  "docs": {
5551
- "text": "Exports the currently selected objects as a PNG file and triggers a browser download.",
5552
- "tags": [{
5553
- "name": "param",
5554
- "text": "options - Optional export settings (theme, padding, scale for resolution)."
5555
- }]
5521
+ "text": "Exports the currently selected object in the requested format and triggers a file download.\nOnly supports single selection.",
5522
+ "tags": []
5556
5523
  }
5557
5524
  },
5558
5525
  "exportAsJson": {
@@ -19,7 +19,7 @@ export class KritzelWatermark {
19
19
  label;
20
20
  render() {
21
21
  const label = this.label ?? this.core.localizationManager.translate('watermark.poweredBy');
22
- return (h(Host, { key: '0eccc75e51c7ac199e23d8f3a871593f1fb65a17' }, h("a", { key: '2029f8b56ba8609ca621447eac0df9d30ebfbbbe', class: "watermark-link", href: KRITZEL_WEBSITE_URL, target: "_blank", rel: "noopener noreferrer", part: "watermark", onPointerDown: (ev) => ev.stopPropagation(), onPointerUp: (ev) => ev.stopPropagation() }, label)));
22
+ return (h(Host, { key: 'ae00d98f16912afcb7a90d47a9fc4d55fc7468f0' }, h("a", { key: '8781f94c9efe44b0e7a7a8c20a119160cb9feb8e', class: "watermark-link", href: KRITZEL_WEBSITE_URL, target: "_blank", rel: "noopener noreferrer", part: "watermark", onPointerDown: (ev) => ev.stopPropagation(), onPointerUp: (ev) => ev.stopPropagation() }, label)));
23
23
  }
24
24
  static get is() { return "kritzel-watermark"; }
25
25
  static get encapsulation() { return "shadow"; }
@@ -81,16 +81,16 @@ export class KritzelAvatar {
81
81
  height: `${this.size}px`,
82
82
  fontSize: `${Math.round(this.size * 0.4)}px`,
83
83
  };
84
- return (h(Host, { key: '116725d55e4443e80216b3b3251e957d2009b43e', style: containerStyles, class: {
84
+ return (h(Host, { key: '90ce966bb2a374e68c544906c8c746df6cc01038', style: containerStyles, class: {
85
85
  'has-image': !!showImage,
86
86
  'has-initials': !!showInitials,
87
87
  'has-default': !!showDefaultIcon,
88
- }, role: "img", "aria-label": this.getDisplayName() || 'User avatar' }, showImage && (h("img", { key: 'd70ad4eb484404b18c13e066e8c10b3c86918ee5', src: imageUrl, alt: "", class: "avatar-image", ref: (el) => {
88
+ }, role: "img", "aria-label": this.getDisplayName() || 'User avatar' }, showImage && (h("img", { key: '6799f4ad45c7d40ebaf640f191171ed6a5f14ae9', src: imageUrl, alt: "", class: "avatar-image", ref: (el) => {
89
89
  if (el) {
90
90
  el.referrerPolicy = 'no-referrer';
91
91
  el.crossOrigin = 'anonymous';
92
92
  }
93
- }, onError: this.handleImageError })), showInitials && (h("span", { key: '21a9022cffdb69e0c3626e513cb3c036a9d3a16d', class: "avatar-initials", style: { backgroundColor: this.getBackgroundColor() } }, initials)), showDefaultIcon && (h("span", { key: '43e676af007bf254b1921f3efcbc7fff4e204359', class: "avatar-default" }, h("svg", { key: 'a7378795539a902e28ca644a80f1ca00cc9f818a', viewBox: "0 0 24 24", fill: "currentColor" }, h("path", { key: '31548a495a86f033325c98cfcc0ae398b6bb8281', d: "M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" }))))));
93
+ }, onError: this.handleImageError })), showInitials && (h("span", { key: '98cdcda64b900994b61a03179be9f2af17c489e8', class: "avatar-initials", style: { backgroundColor: this.getBackgroundColor() } }, initials)), showDefaultIcon && (h("span", { key: '64e6a6ee67017c927dce0b51810a5bb02fc0d6d1', class: "avatar-default" }, h("svg", { key: '42f99637a3c23aaf10fa7c99753347ede1d518c0', viewBox: "0 0 24 24", fill: "currentColor" }, h("path", { key: '28b52a68b36e98b0e14891fd225457be65f1bb46', d: "M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" }))))));
94
94
  }
95
95
  static get is() { return "kritzel-avatar"; }
96
96
  static get encapsulation() { return "shadow"; }
@@ -15,11 +15,11 @@ export class KritzelButton {
15
15
  this.buttonClick.emit();
16
16
  };
17
17
  render() {
18
- return (h(Host, { key: 'b9de2a1261ca0cb491f6980db6a596c48fa45b3a' }, h("button", { key: 'a9507ea0f6a1d9fcb19a7df16bea54cc0ead24f9', type: this.type, class: {
18
+ return (h(Host, { key: '51621006f6b085db2b43accf52192f0674d2c50c' }, h("button", { key: '01ab2d96abe5ad34285e59f6fec66f6b21e91849', type: this.type, class: {
19
19
  'kritzel-button': true,
20
20
  [this.variant]: true,
21
21
  'disabled': this.disabled,
22
- }, disabled: this.disabled, onClick: this.handleClick }, h("slot", { key: '8449a26d4f9fe0226c6150a6639c522486b59780' }))));
22
+ }, disabled: this.disabled, onClick: this.handleClick }, h("slot", { key: '4b085139ea85ad9f836059f4cf2dde15b948e0e2' }))));
23
23
  }
24
24
  static get is() { return "kritzel-button"; }
25
25
  static get encapsulation() { return "shadow"; }
@@ -38,13 +38,13 @@ export class KritzelColorComponent {
38
38
  render() {
39
39
  const resolvedColor = this.resolveColor();
40
40
  const isColorVeryLight = this.isLightColor(resolvedColor);
41
- return (h(Host, { key: 'e39c77c55942b9c615e404efabf4939b2cf05a34' }, h("div", { key: 'ac343295592ea80ca7d3da61ca1244dd1aaa50db', class: "checkerboard-bg", style: {
41
+ return (h(Host, { key: 'e797bfa6a2aed82d1913ec2f02f8b25a063564e5' }, h("div", { key: '5b62fcdbb2985b90fe0d7c7b65b507ec1c55e240', class: "checkerboard-bg", style: {
42
42
  width: `${this.size}px`,
43
43
  height: `${this.size}px`,
44
44
  borderRadius: '50%',
45
45
  display: 'inline-block',
46
46
  position: 'relative',
47
- } }, h("div", { key: '4c87934b3febd4c41874cd290d86a9a9a557e3e5', class: {
47
+ } }, h("div", { key: '2d62717ebf81be93219ebda7071c0ba992d7441a', class: {
48
48
  'color-circle': true,
49
49
  'white': isColorVeryLight,
50
50
  }, style: {
@@ -33,7 +33,7 @@ export class KritzelColorPalette {
33
33
  render() {
34
34
  const displayedColors = this.isExpanded ? this.colors : this.colors.slice(0, 6);
35
35
  const expandedHeight = this.isExpanded ? this.calculateHeight() : '32px';
36
- return (h(Host, { key: '16aa405a43b3943473e577c5a6ab86adf4ae1ba9' }, h("div", { key: 'f65bb286889700dc1f0e8d84ff59721071b7b73a', class: {
36
+ return (h(Host, { key: '9a637b3a6946384a889f54dc3a635da7ff014439' }, h("div", { key: '4db8bbc7a234bfed26b60ed306a5f999875e2195', class: {
37
37
  'color-grid': true,
38
38
  'expanded': this.isExpanded,
39
39
  }, style: {
@@ -4,7 +4,7 @@ export class KritzelFont {
4
4
  size = 24;
5
5
  color = '#000000';
6
6
  render() {
7
- return (h(Host, { key: '054371cac30a2433611139a670406b0a1e3b99ff' }, h("div", { key: 'b4f2142b3cb31d067f39952a38b6f665f28f63bf', class: "font-preview", style: {
7
+ return (h(Host, { key: '42f058426e2afcc49c788f2385e23a5ff153e77c' }, h("div", { key: '962dfc48ba84c5f5d2b98eb2464c69c04764ab0f', class: "font-preview", style: {
8
8
  fontFamily: this.fontFamily,
9
9
  fontSize: `${this.size}px`,
10
10
  color: this.color
@@ -17,7 +17,7 @@ export class KritzelFontSize {
17
17
  render() {
18
18
  const color = 'var(--kritzel-global-text-primary)';
19
19
  const sizes = this.sizes ?? [];
20
- return (h(Host, { key: '56eb19367abe312bac3b626cfcae3b1ff6e90d21' }, sizes.map(size => (h("div", { tabIndex: 0, class: {
20
+ return (h(Host, { key: '9d6592f049c25e9dfa2f6f3a270feb2440aa7f35' }, sizes.map(size => (h("div", { tabIndex: 0, class: {
21
21
  'size-container': true,
22
22
  'selected': this.selectedSize === size,
23
23
  }, onClick: () => this.handleSizeClick(size), onKeyDown: event => this.handleKeyDown(event, size) }, h("kritzel-font", { fontFamily: this.fontFamily, size: size, color: color }))))));
@@ -28,7 +28,7 @@ export class KritzelInput {
28
28
  this.valueChange.emit(input.value);
29
29
  };
30
30
  render() {
31
- return (h(Host, { key: '46a0a48902a06ad85edcbaad3679ce3fe9ba850c' }, h("div", { key: 'a6beaf920614aa959d2fbd68b7268afba8637358', class: "input-container" }, this.label && h("label", { key: 'ca6d3fb3c22f1540795dbb0695ddd9b87cc05eee', class: "input-label" }, this.label), h("div", { key: '78d116e82531a9cca996d594792245449bcaf9c8', class: { 'input-wrapper': true, 'has-suffix': !!this.suffix } }, h("input", { key: '0d10d6356dea3a11338172bbe8c3c878eefcc708', type: this.type, class: "text-input", value: this.inputValue, placeholder: this.placeholder, disabled: this.disabled, onInput: this.handleInput }), this.suffix && h("span", { key: '0e6166ba8728efc1035302d7fb048306efbe5a68', class: "input-suffix" }, this.suffix)))));
31
+ return (h(Host, { key: 'a4d86101322da32c87a62ac8bb05edb7015ede2a' }, h("div", { key: 'abc5b007af0f6f9353e0b680636c92813ee1ef49', class: "input-container" }, this.label && h("label", { key: 'f79e02a925aa6bd1b6cd48fc4225e441695ff893', class: "input-label" }, this.label), h("div", { key: 'e2937d2ad1def996e1937a9dd711578a3f9b6494', class: { 'input-wrapper': true, 'has-suffix': !!this.suffix } }, h("input", { key: '8bc45cc6f2603bec30f2299286d03beacd8c07fb', type: this.type, class: "text-input", value: this.inputValue, placeholder: this.placeholder, disabled: this.disabled, onInput: this.handleInput }), this.suffix && h("span", { key: '917fb6fa6c5fe62ab0f1e5c83f09aedd22623353', class: "input-suffix" }, this.suffix)))));
32
32
  }
33
33
  static get is() { return "kritzel-input"; }
34
34
  static get encapsulation() { return "shadow"; }
@@ -90,15 +90,15 @@ export class KritzelMasterDetail {
90
90
  const selectedItem = this.items.find(item => item.id === this.selectedItemId);
91
91
  const panelId = 'master-detail-panel';
92
92
  const selectedTabId = selectedItem ? `tab-${selectedItem.id}` : undefined;
93
- return (h(Host, { key: '0edf50b0b853633b88bf481f97f22aceba9e163e' }, h("div", { key: '21a0a3f81e5a60889ccd152c905cb41f52c3e037', class: {
93
+ return (h(Host, { key: '0166376f16ebb098049cd2ef5539a86086a5570e' }, h("div", { key: 'f5091fe672bc4751c8f66d43baa5c1fc86fca034', class: {
94
94
  'master-detail-container': true,
95
95
  'is-mobile-detail-visible': this.showMobileDetail,
96
- } }, h("nav", { key: '41f88248cc372c8cae4cb50a19edf462a01e43f2', class: "master-menu", role: "tablist", "aria-orientation": "vertical", "aria-label": "Settings categories" }, this.items.map((item, index) => (h("button", { key: item.id, id: `tab-${item.id}`, ref: el => this.setTabRef(el, index), class: {
96
+ } }, h("nav", { key: '66f5c61ea0308ea9ae1339526e86dcf1ee51fc0a', class: "master-menu", role: "tablist", "aria-orientation": "vertical", "aria-label": "Settings categories" }, this.items.map((item, index) => (h("button", { key: item.id, id: `tab-${item.id}`, ref: el => this.setTabRef(el, index), class: {
97
97
  'menu-item': true,
98
98
  'is-selected': item.id === this.selectedItemId,
99
99
  'is-disabled': !!item.disabled,
100
100
  'is-focused': index === this.focusedIndex,
101
- }, role: "tab", "aria-selected": item.id === this.selectedItemId ? 'true' : 'false', "aria-controls": panelId, "aria-disabled": item.disabled ? 'true' : undefined, tabIndex: this.getTabIndex(item, index), disabled: item.disabled, onClick: () => this.handleItemClick(item), onKeyDown: e => this.handleKeyDown(e, item, index), onFocus: () => this.handleFocus(index), onBlur: this.handleBlur }, item.icon && (h("kritzel-icon", { name: item.icon, size: 20, class: "menu-item-icon" })), h("span", { class: "menu-item-label" }, item.label), h("span", { class: "menu-item-chevron", "aria-hidden": "true" }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "1.5", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("path", { d: "m9 18 6-6-6-6" }))))))), h("div", { key: 'f8447facf3dfdbd7772823654847e1b90b03f73e', id: panelId, class: "detail-panel", role: "tabpanel", "aria-labelledby": selectedTabId }, h("button", { key: '3edc9784267613e6b3a706739bbb537161e4c747', class: "mobile-back-button", onClick: this.handleBackClick, "aria-label": "Back to menu" }, h("kritzel-icon", { key: 'ec0b4691735578525e5863842271366e04b13fb7', name: "chevron-left", size: 20, class: "mobile-back-icon" }), "Back"), h("slot", { key: 'c21fbaff78f98859b9756427125b60504d4bb630' })))));
101
+ }, role: "tab", "aria-selected": item.id === this.selectedItemId ? 'true' : 'false', "aria-controls": panelId, "aria-disabled": item.disabled ? 'true' : undefined, tabIndex: this.getTabIndex(item, index), disabled: item.disabled, onClick: () => this.handleItemClick(item), onKeyDown: e => this.handleKeyDown(e, item, index), onFocus: () => this.handleFocus(index), onBlur: this.handleBlur }, item.icon && (h("kritzel-icon", { name: item.icon, size: 20, class: "menu-item-icon" })), h("span", { class: "menu-item-label" }, item.label), h("span", { class: "menu-item-chevron", "aria-hidden": "true" }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "1.5", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("path", { d: "m9 18 6-6-6-6" }))))))), h("div", { key: 'e8f762ad87fdcf401ec717538bf1e979b22a9f15', id: panelId, class: "detail-panel", role: "tabpanel", "aria-labelledby": selectedTabId }, h("button", { key: '958360d57a1fad0953bc3865503e86c1d8aa24e3', class: "mobile-back-button", onClick: this.handleBackClick, "aria-label": "Back to menu" }, h("kritzel-icon", { key: 'c65eb947f80aafec99b367dae7ea72b1a77acdac', name: "chevron-left", size: 20, class: "mobile-back-icon" }), "Back"), h("slot", { key: '44557fddf513fffd86c7a1b28b71a41fef7701f1' })))));
102
102
  }
103
103
  static get is() { return "kritzel-master-detail"; }
104
104
  static get encapsulation() { return "shadow"; }
@@ -51,7 +51,7 @@ export class KritzelMenu {
51
51
  this.itemCloseChildMenu.emit(event.detail);
52
52
  };
53
53
  render() {
54
- return (h(Host, { key: '27a90a3a8549517a2d6e341a5da13496bf714970', tabIndex: 0, onClick: e => e.stopPropagation() }, this.openChildMenuItem && h("div", { key: 'c0c2351fac389f6676b38481eaacee553ca6867a', class: "has-open-child-overlay", onClick: this.onOverlayClick }), this.items.map(item => (h("kritzel-menu-item", { key: item.id, "data-testid": `menu-item-${item.id}`, item: item, parent: this.parent, style: { pointerEvents: this.editingMenuItem && !item.isEditing ? 'none' : 'auto' }, onItemSelect: this.handleItemSelect, onItemSave: this.handleSave, onItemCancel: this.handleCancel, onItemToggleChildMenu: this.handleToggleChildMenu, onItemCloseChildMenu: this.handleCloseChildMenu })))));
54
+ return (h(Host, { key: '804ed34eb5340ecc1611ada01f608f7a0cf2f619', tabIndex: 0, onClick: e => e.stopPropagation() }, this.openChildMenuItem && h("div", { key: '6de5954a05b7f28961fa33cf8d34df3a81aae5f8', class: "has-open-child-overlay", onClick: this.onOverlayClick }), this.items.map(item => (h("kritzel-menu-item", { key: item.id, "data-testid": `menu-item-${item.id}`, item: item, parent: this.parent, style: { pointerEvents: this.editingMenuItem && !item.isEditing ? 'none' : 'auto' }, onItemSelect: this.handleItemSelect, onItemSave: this.handleSave, onItemCancel: this.handleCancel, onItemToggleChildMenu: this.handleToggleChildMenu, onItemCloseChildMenu: this.handleCloseChildMenu })))));
55
55
  }
56
56
  static get is() { return "kritzel-menu"; }
57
57
  static get encapsulation() { return "shadow"; }
@@ -90,12 +90,12 @@ export class KritzelMenuItem {
90
90
  ];
91
91
  }
92
92
  render() {
93
- return (h(Host, { key: '9d6653a630da5a3da38291d89d6d7d59d6994e02', tabIndex: this.item.isDisabled ? -1 : 0, class: {
93
+ return (h(Host, { key: '9b35e5631cfa14aca391636f06598ef6f2f26550', tabIndex: this.item.isDisabled ? -1 : 0, class: {
94
94
  'selected': this.item.isSelected,
95
95
  'editing': this.item.isEditing,
96
96
  'disabled': this.item.isDisabled,
97
97
  'child-open': this.item.isChildMenuOpen,
98
- }, onClick: this.handleItemSelect }, h("div", { key: '48a1678296e672c6c03fb3e1473c42d3a246d481', class: "menu-item-overlay" }), this.item.isEditing ? this.renderEditMode() : this.renderViewMode()));
98
+ }, onClick: this.handleItemSelect }, h("div", { key: '175258699f76fdad5dcf3c7481e7882c6765bf33', class: "menu-item-overlay" }), this.item.isEditing ? this.renderEditMode() : this.renderViewMode()));
99
99
  }
100
100
  static get is() { return "kritzel-menu-item"; }
101
101
  static get encapsulation() { return "shadow"; }
@@ -86,7 +86,7 @@ export class KritzelNumericInput {
86
86
  this.valueChange.emit(newValue);
87
87
  };
88
88
  render() {
89
- return (h(Host, { key: '8901e0b56ccbc344420483a4a56663f7cd74d9e8' }, h("div", { key: '5f3d6b5c56007e11383aa69f60f22031b0e8f332', class: "input-container" }, this.label && h("label", { key: '2cb102a5b6c16d068f4f304fbcc6241f79fc0ce8', class: "input-label" }, this.label), h("div", { key: '96441095acc3d9a8e77b6d2bac2ceda683c9c976', class: "input-wrapper" }, h("input", { key: '523a5485111077e20faded235df6362e5ea9cfd4', type: "number", class: "numeric-input", title: "", min: this.min === Number.MIN_SAFE_INTEGER ? undefined : this.min, max: this.max === Number.MAX_SAFE_INTEGER ? undefined : this.max, step: this.step, value: this.inputValue, placeholder: this.placeholder, onInput: this.handleInput, onBlur: this.handleBlur, onKeyDown: this.handleKeyDown, onInvalid: this.handleInvalid }), h("div", { key: '2071e98125a8d014513e93052bd8c1fee17932a5', class: "spinner-buttons" }, h("button", { key: '12422e5285dfb532dbbb6eb1a36dbcb3de50f2bc', type: "button", class: "spinner-button spinner-up", onClick: this.handleIncrement, tabIndex: -1, "aria-label": "Increase value" }, h("svg", { key: '49ad5625c80fae6706ba4ab91f47bd550481ef74', viewBox: "0 0 10 6", class: "spinner-icon" }, h("path", { key: 'ff7d19b61baeb5ba58bb60f2cc629bcec6eb4411', d: "M1 5L5 1L9 5", stroke: "currentColor", "stroke-width": "1.5", fill: "none", "stroke-linecap": "round", "stroke-linejoin": "round" }))), h("button", { key: 'e4fec28e4fc997e007127f2b30b00cc752433221', type: "button", class: "spinner-button spinner-down", onClick: this.handleDecrement, tabIndex: -1, "aria-label": "Decrease value" }, h("svg", { key: '27bf06cde8de11f4a97090911afd6b8993463112', viewBox: "0 0 10 6", class: "spinner-icon" }, h("path", { key: 'ed7071dd79bfe509ebb319ce43ecb3e982dd4157', d: "M1 1L5 5L9 1", stroke: "currentColor", "stroke-width": "1.5", fill: "none", "stroke-linecap": "round", "stroke-linejoin": "round" }))))))));
89
+ return (h(Host, { key: '68e6fecd79c3c970d1742b1a0bb8667ca2d31729' }, h("div", { key: 'efcf623186d221690bbb956088ec51343de07f3a', class: "input-container" }, this.label && h("label", { key: '300de793f02008ad037da021003b46fc34fc5239', class: "input-label" }, this.label), h("div", { key: '9ff424901fddfcbdac4835e2b2089df2e0966d0f', class: "input-wrapper" }, h("input", { key: 'fc77e6ad1c0b15e3dd3f960b6448ddab1a9beeb1', type: "number", class: "numeric-input", title: "", min: this.min === Number.MIN_SAFE_INTEGER ? undefined : this.min, max: this.max === Number.MAX_SAFE_INTEGER ? undefined : this.max, step: this.step, value: this.inputValue, placeholder: this.placeholder, onInput: this.handleInput, onBlur: this.handleBlur, onKeyDown: this.handleKeyDown, onInvalid: this.handleInvalid }), h("div", { key: 'c286606fa0617cc3acbbe40a27e40b154002e01d', class: "spinner-buttons" }, h("button", { key: 'e3a65a327975918fe604cd196ffb087fc4d3ca47', type: "button", class: "spinner-button spinner-up", onClick: this.handleIncrement, tabIndex: -1, "aria-label": "Increase value" }, h("svg", { key: '62b2ff4ed67ca8b6fc220ff9c63ceca90f75baea', viewBox: "0 0 10 6", class: "spinner-icon" }, h("path", { key: '803d5c30826d40d95f282071f3f88356366a9faf', d: "M1 5L5 1L9 5", stroke: "currentColor", "stroke-width": "1.5", fill: "none", "stroke-linecap": "round", "stroke-linejoin": "round" }))), h("button", { key: '3c54a48e7082f5aaa9ed923357d0cc4a722018b5', type: "button", class: "spinner-button spinner-down", onClick: this.handleDecrement, tabIndex: -1, "aria-label": "Decrease value" }, h("svg", { key: '9f6cb5f34bbb0e70b5773aecec519b7d8b742712', viewBox: "0 0 10 6", class: "spinner-icon" }, h("path", { key: '6539b0d4f4bd26e463fa9152cf58757497355cf6', d: "M1 1L5 5L9 1", stroke: "currentColor", "stroke-width": "1.5", fill: "none", "stroke-linecap": "round", "stroke-linejoin": "round" }))))))));
90
90
  }
91
91
  static get is() { return "kritzel-numeric-input"; }
92
92
  static get encapsulation() { return "shadow"; }
@@ -22,7 +22,7 @@ export class KritzelOpacitySlider {
22
22
  }
23
23
  render() {
24
24
  const percentage = this.getPercentage();
25
- return (h(Host, { key: '2dadd8a7c4d1af748e91a6005433288ab231f2e8' }, h("div", { key: '65ae90d95bffff244d97329754cf0cb8f73331fa', class: "opacity-container" }, h("div", { key: '90e95347f7015882112f0653a25347e715233227', class: "slider-wrapper" }, h("input", { key: '15836bc089c1725062016677d3b95384d1958431', type: "range", class: "opacity-slider", min: this.min, max: this.max, step: this.step, value: this.value, onInput: (e) => this.handleInput(e), style: {
25
+ return (h(Host, { key: '895ae10ad71e846a1bc62b794751332816650727' }, h("div", { key: '22ea167ce0d6eb17c733d789cde10477c48a2a0e', class: "opacity-container" }, h("div", { key: '2be4fbf8c1f8ddb1fde8f9da727ed0947d21646c', class: "slider-wrapper" }, h("input", { key: 'ed3621baf0adc54aa513a0296ede2f413378a06f', type: "range", class: "opacity-slider", min: this.min, max: this.max, step: this.step, value: this.value, onInput: (e) => this.handleInput(e), style: {
26
26
  '--slider-progress': `${percentage}%`,
27
27
  '--kritzel-opacity-slider-thumb-border-color': this.previewColor,
28
28
  } })))));