kritzel-stencil 0.4.8 → 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 (91) hide show
  1. package/dist/cjs/index.cjs.js +9 -1
  2. package/dist/cjs/kritzel-active-users_47.cjs.entry.js +1386 -1250
  3. package/dist/cjs/loader.cjs.js +1 -1
  4. package/dist/cjs/{schema.constants-gDeS7USU.js → schema.constants-ByNZ_qAj.js} +61 -0
  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 +197 -67
  15. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +136 -169
  16. package/dist/collection/components/ui/kritzel-export/kritzel-export.js +1 -1
  17. package/dist/collection/components/ui/kritzel-loading-overlay/kritzel-loading-overlay.js +1 -1
  18. package/dist/collection/components/ui/kritzel-login-dialog/kritzel-login-dialog.js +1 -1
  19. package/dist/collection/components/ui/kritzel-more-menu/kritzel-more-menu.js +90 -4
  20. package/dist/collection/components/ui/kritzel-settings/kritzel-settings.js +1 -1
  21. package/dist/collection/components/ui/kritzel-share-dialog/kritzel-share-dialog.js +2 -2
  22. package/dist/collection/components/ui/kritzel-utility-panel/kritzel-utility-panel.js +1 -1
  23. package/dist/collection/components/ui/kritzel-zoom-panel/kritzel-zoom-panel.js +1 -1
  24. package/dist/collection/constants/version.js +1 -1
  25. package/dist/collection/helpers/object.helper.js +11 -0
  26. package/dist/collection/index.js +1 -0
  27. package/dist/collection/interfaces/object-export.interface.js +1 -0
  28. package/dist/collection/interfaces/sync-config.interface.js +21 -1
  29. package/dist/components/index.js +10 -3
  30. package/dist/components/kritzel-awareness-cursors.js +1 -1
  31. package/dist/components/kritzel-controls.js +1 -1
  32. package/dist/components/kritzel-editor.js +175 -78
  33. package/dist/components/kritzel-engine.js +1 -1
  34. package/dist/components/kritzel-export.js +1 -1
  35. package/dist/components/kritzel-loading-overlay.js +1 -1
  36. package/dist/components/kritzel-login-dialog.js +1 -1
  37. package/dist/components/kritzel-menu-item.js +1 -1
  38. package/dist/components/kritzel-menu.js +1 -1
  39. package/dist/components/kritzel-more-menu.js +1 -1
  40. package/dist/components/kritzel-portal.js +1 -1
  41. package/dist/components/kritzel-settings.js +1 -1
  42. package/dist/components/kritzel-share-dialog.js +1 -1
  43. package/dist/components/kritzel-split-button.js +1 -1
  44. package/dist/components/kritzel-utility-panel.js +1 -1
  45. package/dist/components/kritzel-workspace-manager.js +1 -1
  46. package/dist/components/kritzel-zoom-panel.js +1 -1
  47. package/dist/components/{p-DwY5pghH.js → p-6rQICkGr.js} +1 -1
  48. package/dist/components/{p-BknTMcbz.js → p-8ScektIm.js} +1 -1
  49. package/dist/components/{p-DkY7pIg5.js → p-BRGufCki.js} +95 -6
  50. package/dist/components/{p-BKOsmXB5.js → p-BqWiEmYI.js} +1 -1
  51. package/dist/components/{p-BLOPBDUF.js → p-C2CeSrTm.js} +1 -1
  52. package/dist/components/{p-DDbO5q-e.js → p-CXJZxJvp.js} +4 -4
  53. package/dist/components/{p-7Rt7ml3v.js → p-Cj0NElII.js} +1 -1
  54. package/dist/components/{p-BVEGQLBD.js → p-CoY7emAj.js} +1 -1
  55. package/dist/components/{p-DgA865Tp.js → p-D7H8oxZb.js} +2 -2
  56. package/dist/components/{p-Dd-pMvlr.js → p-DPONTran.js} +11 -0
  57. package/dist/components/{p-BMRln59F.js → p-DW7WW4EN.js} +2 -2
  58. package/dist/components/{p-D8TOEhPY.js → p-DuVkk58V.js} +2 -2
  59. package/dist/components/{p-OLfoATNk.js → p-U9FjWrp-.js} +1 -1
  60. package/dist/components/{p-D8bHNNEm.js → p-ZPPtEla5.js} +1227 -1218
  61. package/dist/components/{p-COjsYPir.js → p-dVfh-Sy9.js} +1 -1
  62. package/dist/components/{p-0H4HOJjy.js → p-lQ7nfhOy.js} +10 -1
  63. package/dist/esm/index.js +9 -2
  64. package/dist/esm/kritzel-active-users_47.entry.js +1386 -1250
  65. package/dist/esm/loader.js +1 -1
  66. package/dist/esm/{schema.constants-Rpm1NA9u.js → schema.constants-1t45c2_U.js} +61 -1
  67. package/dist/esm/stencil.js +1 -1
  68. package/dist/stencil/index.esm.js +9 -2
  69. package/dist/stencil/{p-Rpm1NA9u.js → p-1t45c2_U.js} +61 -1
  70. package/dist/stencil/{p-8c1b7b08.entry.js → p-f5f088ea.entry.js} +1386 -1250
  71. package/dist/stencil/stencil.esm.js +1 -1
  72. package/dist/types/classes/objects/image.class.d.ts +3 -0
  73. package/dist/types/classes/objects/path.class.d.ts +3 -0
  74. package/dist/types/classes/objects/shape.class.d.ts +3 -0
  75. package/dist/types/classes/providers/sync/broadcast-sync-provider.class.d.ts +1 -0
  76. package/dist/types/classes/providers/sync/hocuspocus-sync-provider.class.d.ts +1 -0
  77. package/dist/types/classes/providers/sync/in-memory-sync-provider.class.d.ts +1 -0
  78. package/dist/types/classes/providers/sync/indexeddb-sync-provider.class.d.ts +1 -0
  79. package/dist/types/classes/providers/sync/websocket-sync-provider.class.d.ts +1 -0
  80. package/dist/types/components/core/kritzel-editor/kritzel-editor.d.ts +15 -3
  81. package/dist/types/components/core/kritzel-engine/kritzel-engine.d.ts +16 -34
  82. package/dist/types/components/ui/kritzel-more-menu/kritzel-more-menu.d.ts +10 -1
  83. package/dist/types/components.d.ts +27 -26
  84. package/dist/types/constants/version.d.ts +1 -1
  85. package/dist/types/helpers/object.helper.d.ts +4 -0
  86. package/dist/types/index.d.ts +1 -0
  87. package/dist/types/interfaces/menu-item.interface.d.ts +1 -1
  88. package/dist/types/interfaces/object-export.interface.d.ts +20 -0
  89. package/dist/types/interfaces/sync-config.interface.d.ts +5 -0
  90. package/dist/types/interfaces/sync-provider.interface.d.ts +5 -0
  91. 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;
@@ -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": {
@@ -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
  }
@@ -205,7 +205,7 @@ export class KritzelSettings {
205
205
  return (h("div", { class: "settings-categories-wrapper" }, h("div", { class: { 'settings-tab-panel': true, 'is-active': this.selectedCategoryId === 'general' } }, h("div", { class: "settings-content" }, h("h3", null, this.t('settings.general.title', 'General Settings')), h("div", { class: "settings-group" }, h("div", { class: "settings-item" }, h("label", { class: "settings-label" }, this.t('settings.general.theme.label', 'Theme')), h("p", { class: "settings-description" }, this.t('settings.general.theme.description', 'Select a registered color theme for the editor interface.')), h("kritzel-dropdown", { options: this.availableThemes.map(t => ({ value: t, label: t })), value: this.theme, onValueChanged: this.handleThemeChange })), this.availableLocales.length > 0 && (h("div", { class: "settings-item" }, h("label", { class: "settings-label" }, this.t('settings.general.language.label', 'Language')), h("p", { class: "settings-description" }, this.t('settings.general.language.description', 'Select the display language for the editor interface.')), h("kritzel-dropdown", { options: this.availableLocales.map(l => ({ value: l.code, label: l.label })), value: this.locale, onValueChanged: this.handleLocaleChange }))), h("div", { class: "settings-item" }, h("label", { class: "settings-label" }, this.t('settings.general.lockDrawingScale.label', 'Lock Drawing Scale')), h("p", { class: "settings-description" }, this.t('settings.general.lockDrawingScale.description', 'When enabled, drawn objects maintain a fixed visual size regardless of the current zoom level.')), h("kritzel-slide-toggle", { checked: this.lockDrawingScale, label: this.t('settings.general.lockDrawingScale.label', 'Lock Drawing Scale'), onCheckedChange: this.handleLockDrawingScaleChange }))))), h("div", { class: { 'settings-tab-panel': true, 'is-active': this.selectedCategoryId === 'viewport' } }, h("div", { class: "settings-content" }, h("h3", null, this.t('settings.viewport.title', 'Viewport Settings')), h("div", { class: "settings-group" }, h("div", { class: "settings-item" }, h("label", { class: "settings-label" }, this.t('settings.viewport.minZoom.label', 'Minimum Zoom Level')), h("p", { class: "settings-description" }, this.t('settings.viewport.minZoom.description', 'Sets the minimum zoom level. Lower values allow zooming out further to see more of the canvas.')), h("kritzel-numeric-input", { value: this.scaleMin, min: 0.0001, max: 1, step: 0.0001, onValueChange: this.handleScaleMinChange })), h("div", { class: "settings-item" }, h("label", { class: "settings-label" }, this.t('settings.viewport.maxZoom.label', 'Maximum Zoom Level')), h("p", { class: "settings-description" }, this.t('settings.viewport.maxZoom.description', 'Sets the maximum zoom level. Higher values allow zooming in closer for detailed work.')), h("kritzel-numeric-input", { value: this.scaleMax, min: 1, max: 1000, step: 1, onValueChange: this.handleScaleMaxChange })), h("div", { class: "settings-item" }, h("label", { class: "settings-label" }, this.t('settings.viewport.boundaryLeft.label', 'Viewport Boundary Left')), h("p", { class: "settings-description" }, this.t('settings.viewport.boundaryLeft.description', 'Left boundary in world coordinates. Set to limit how far left the viewport can pan.')), h("kritzel-numeric-input", { value: this.viewportBoundaryLeft, step: 100, placeholder: this.t('settings.viewport.boundaryPlaceholder', 'Infinite'), onValueChange: this.handleViewportBoundaryLeftChange })), h("div", { class: "settings-item" }, h("label", { class: "settings-label" }, this.t('settings.viewport.boundaryRight.label', 'Viewport Boundary Right')), h("p", { class: "settings-description" }, this.t('settings.viewport.boundaryRight.description', 'Right boundary in world coordinates. Set to limit how far right the viewport can pan.')), h("kritzel-numeric-input", { value: this.viewportBoundaryRight, step: 100, placeholder: this.t('settings.viewport.boundaryPlaceholder', 'Infinite'), onValueChange: this.handleViewportBoundaryRightChange })), h("div", { class: "settings-item" }, h("label", { class: "settings-label" }, this.t('settings.viewport.boundaryTop.label', 'Viewport Boundary Top')), h("p", { class: "settings-description" }, this.t('settings.viewport.boundaryTop.description', 'Top boundary in world coordinates. Set to limit how far up the viewport can pan.')), h("kritzel-numeric-input", { value: this.viewportBoundaryTop, step: 100, placeholder: this.t('settings.viewport.boundaryPlaceholder', 'Infinite'), onValueChange: this.handleViewportBoundaryTopChange })), h("div", { class: "settings-item" }, h("label", { class: "settings-label" }, this.t('settings.viewport.boundaryBottom.label', 'Viewport Boundary Bottom')), h("p", { class: "settings-description" }, this.t('settings.viewport.boundaryBottom.description', 'Bottom boundary in world coordinates. Set to limit how far down the viewport can pan.')), h("kritzel-numeric-input", { value: this.viewportBoundaryBottom, step: 100, placeholder: this.t('settings.viewport.boundaryPlaceholder', 'Infinite'), onValueChange: this.handleViewportBoundaryBottomChange }))))), h("div", { class: { 'settings-tab-panel': true, 'is-active': this.selectedCategoryId === 'shortcuts' } }, h("div", { class: "settings-content" }, h("h3", null, this.t('settings.shortcuts.title', 'Keyboard Shortcuts')), h("div", { class: "shortcuts-list" }, Array.from(this.groupShortcutsByCategory()).map(([category, shortcuts]) => (h("div", { class: "shortcuts-category", key: category }, h("h4", { class: "shortcuts-category-title" }, category), h("div", { class: "shortcuts-group" }, shortcuts.map(shortcut => (h("div", { class: "shortcut-item", key: shortcut.key + shortcut.label }, h("span", { class: "shortcut-label" }, shortcut.label), h("kbd", { class: "shortcut-key" }, this.formatKeyCombo(shortcut)))))))))))), h("div", { class: { 'settings-tab-panel': true, 'is-active': this.selectedCategoryId === 'developer' } }, h("div", { class: "settings-content" }, h("h3", null, this.t('settings.developer.title', 'Developer Options')), h("div", { class: "settings-group" }, h("div", { class: "settings-item" }, h("label", { class: "settings-label" }, this.t('settings.developer.showViewportInfo.label', 'Show Viewport Info')), h("p", { class: "settings-description" }, this.t('settings.developer.showViewportInfo.description', 'Display viewport debug information such as position, zoom level, and boundaries.')), h("kritzel-slide-toggle", { checked: this.debugInfo.showViewportInfo, label: this.t('settings.developer.showViewportInfo.label', 'Show Viewport Info'), onCheckedChange: this.handleDebugInfoChange('showViewportInfo') })), h("div", { class: "settings-item" }, h("label", { class: "settings-label" }, this.t('settings.developer.showObjectInfo.label', 'Show Object Info')), h("p", { class: "settings-description" }, this.t('settings.developer.showObjectInfo.description', 'Display debug information about objects on the canvas.')), h("kritzel-slide-toggle", { checked: this.debugInfo.showObjectInfo, label: this.t('settings.developer.showObjectInfo.label', 'Show Object Info'), onCheckedChange: this.handleDebugInfoChange('showObjectInfo') })), h("div", { class: "settings-item" }, h("label", { class: "settings-label" }, this.t('settings.developer.showSyncProviderInfo.label', 'Show Sync Provider Info')), h("p", { class: "settings-description" }, this.t('settings.developer.showSyncProviderInfo.description', 'Display debug information about the sync provider connection status.')), h("kritzel-slide-toggle", { checked: this.debugInfo.showSyncProviderInfo, label: this.t('settings.developer.showSyncProviderInfo.label', 'Show Sync Provider Info'), onCheckedChange: this.handleDebugInfoChange('showSyncProviderInfo') })), h("div", { class: "settings-item" }, h("label", { class: "settings-label" }, this.t('settings.developer.showMigrationInfo.label', 'Show Migration Info')), h("p", { class: "settings-description" }, this.t('settings.developer.showMigrationInfo.description', 'Display debug information about data migrations.')), h("kritzel-slide-toggle", { checked: this.debugInfo.showMigrationInfo, label: this.t('settings.developer.showMigrationInfo.label', 'Show Migration Info'), onCheckedChange: this.handleDebugInfoChange('showMigrationInfo') }))))), h("div", { class: { 'settings-tab-panel': true, 'is-active': this.selectedCategoryId === 'about' } }, h("div", { class: "settings-content" }, h("h3", null, this.t('settings.about.title', 'About')), h("p", null, this.t('settings.about.description', 'Kritzel - A drawing application')), h("p", { class: "version-info" }, "Version ", KRITZEL_VERSION), h("p", { class: "version-info" }, "App-State Schema v", CURRENT_APP_STATE_SCHEMA_VERSION), h("p", { class: "version-info" }, "Workspace Schema v", CURRENT_WORKSPACE_SCHEMA_VERSION)))));
206
206
  }
207
207
  render() {
208
- return (h(Host, { key: '36bca8be04b34a37630d6aa5394595a8b394d180' }, h("kritzel-dialog", { key: '1e257904178fd9afa2bfbe4a758663fb366c8847', isOpen: this.isDialogOpen, dialogTitle: this.t('settings.dialogTitle', 'Settings'), size: "large", contained: true, onDialogClose: this.closeDialog }, h("kritzel-master-detail", { key: 'b7d9ad97d9b126ccf6e800e6c9032749635eb988', items: this.categories, selectedItemId: this.selectedCategoryId, onItemSelect: this.handleCategorySelect }, this.renderCategoryContent()))));
208
+ return (h(Host, { key: 'b8a899abd3dd55bc3493b7d124ac5505e2284036' }, h("kritzel-dialog", { key: '8d47f3548271e24a8a280a30139f04b2e4b4ec2b', isOpen: this.isDialogOpen, dialogTitle: this.t('settings.dialogTitle', 'Settings'), size: "large", contained: true, onDialogClose: this.closeDialog }, h("kritzel-master-detail", { key: 'a5213307761b84b8f5f67cb35409ab1c0c1fa57b', items: this.categories, selectedItemId: this.selectedCategoryId, onItemSelect: this.handleCategorySelect }, this.renderCategoryContent()))));
209
209
  }
210
210
  static get is() { return "kritzel-settings"; }
211
211
  static get encapsulation() { return "shadow"; }
@@ -123,9 +123,9 @@ export class KritzelShareDialog {
123
123
  this.dialogClosed.emit();
124
124
  };
125
125
  render() {
126
- return (h(Host, { key: 'd30a468b9443f76731b207cb5caec1911f378c15' }, h("kritzel-dialog", { key: '4a4ec0a2becba58a49a87fc411a82e26557d8232', dialogTitle: this.terms['share.dialogTitle'] ?? 'Share Workspace', size: "small", isOpen: this.isDialogOpen, onDialogClose: this.closeDialog, contained: true }, h("div", { key: '0b2fec3db6c039752429768fb4bd6a2150a4345e', class: "share-content" }, h("div", { key: 'bd0b85f8418d0c46d14b718024ed62b9f72e4f52', class: "share-section" }, h("div", { key: 'bf62503a593454ffacd30d532fcd79dcbf938659', class: "share-row" }, h("div", { key: 'dfd9e83166b886d00fb5b097d0ccd77169c011bd', class: "share-label-group" }, h("label", { key: '67dba950ded47a08eb006c1628d14038b18171b5', class: "share-label" }, this.terms['share.linkSharing.label'] ?? 'Link sharing'), h("p", { key: '926f8670b35dab1e3e2a6496f44b5d6e0ee46417', class: "share-description" }, this.internalIsPublic
126
+ return (h(Host, { key: '75deaa66e6a6f640506985a8b3a2746892b5da07' }, h("kritzel-dialog", { key: '237413c9302e3756c5f7653e69326fac80d9e181', dialogTitle: this.terms['share.dialogTitle'] ?? 'Share Workspace', size: "small", isOpen: this.isDialogOpen, onDialogClose: this.closeDialog, contained: true }, h("div", { key: '295394b851cc2210fece6f3e297dfbc0c516b0f7', class: "share-content" }, h("div", { key: 'df64d71f9c7a7064d36db6d0a196071f1e8835a9', class: "share-section" }, h("div", { key: '9db4902a5edd917efb5ad6c183f0862b12313635', class: "share-row" }, h("div", { key: '8ead1d363d3430a4e65fa3b5835401b0e20006db', class: "share-label-group" }, h("label", { key: '2f3c28a3909eab86a123ba6cf7386b79894717c5', class: "share-label" }, this.terms['share.linkSharing.label'] ?? 'Link sharing'), h("p", { key: '3167ae1ed6ff52abc531eafdd905f1397807f551', class: "share-description" }, this.internalIsPublic
127
127
  ? (this.terms['share.linkSharing.enabledDescription'] ?? 'Anyone with the link can access this workspace.')
128
- : (this.terms['share.linkSharing.disabledDescription'] ?? 'Link sharing is disabled. Only you can access this workspace.'))), h("kritzel-slide-toggle", { key: 'e42fabecb37fd21cc4907b966e2f50113b945eda', checked: this.internalIsPublic, onCheckedChange: this.handleToggleChange, label: this.terms['share.linkSharing.toggleLabel'] ?? 'Enable link sharing' }))), this.internalIsPublic && (h("div", { key: '40afacc81e0bbcf4c404ae32491e5142a32bca66', class: "share-section" }, h("div", { key: '57b6952670b1cbc789770362b573623035b50cf3', class: "share-url-container" }, h("input", { key: '0ee836655ca26c1e073d5d86014322939527c74b', type: "text", class: "share-url-input", value: this.getShareUrl(), readOnly: true, onClick: (e) => e.target.select() }), h("button", { key: '2d4661c1718bd8390dbe1146e8f9afe035934635', class: { 'copy-button': true, 'copy-success': this.copySuccess }, onClick: this.handleCopyUrl, title: this.copySuccess ? (this.terms['share.copyLink.copied'] ?? 'Copied!') : (this.terms['share.copyLink.title'] ?? 'Copy link') }, h("kritzel-icon", { key: 'b43bde94601c352b6065c89c026807d7efb3bcc3', name: this.copySuccess ? 'check' : 'copy', size: 18 }))), this.qrCodeDataUrl && (h("div", { key: 'f4d657aa918abbb3cf3ed039332d8c67247b83e8', class: "share-qr-container" }, h("img", { key: 'b165a446df3fba87918a19928734d39af1e6bfcf', class: "share-qr-image", src: this.qrCodeDataUrl, alt: "QR code for share link" })))))))));
128
+ : (this.terms['share.linkSharing.disabledDescription'] ?? 'Link sharing is disabled. Only you can access this workspace.'))), h("kritzel-slide-toggle", { key: '3ff608b262e2ff3fa779f7d1e9a4ee3c0b9a16c0', checked: this.internalIsPublic, onCheckedChange: this.handleToggleChange, label: this.terms['share.linkSharing.toggleLabel'] ?? 'Enable link sharing' }))), this.internalIsPublic && (h("div", { key: '355261384b0ed386f3b48c041bcf0039db0534c1', class: "share-section" }, h("div", { key: 'ad3d975c650757d0b6dbd5317c9bac4f98029e0c', class: "share-url-container" }, h("input", { key: '0da2cc9cb30f1da8bcab3aa82c679b8d685641bd', type: "text", class: "share-url-input", value: this.getShareUrl(), readOnly: true, onClick: (e) => e.target.select() }), h("button", { key: 'aee232b7a70b524d52a4b4cf9074c099d29a5300', class: { 'copy-button': true, 'copy-success': this.copySuccess }, onClick: this.handleCopyUrl, title: this.copySuccess ? (this.terms['share.copyLink.copied'] ?? 'Copied!') : (this.terms['share.copyLink.title'] ?? 'Copy link') }, h("kritzel-icon", { key: 'c151baf7b890dbf51c4f4831d60b0ebb1a5d05fa', name: this.copySuccess ? 'check' : 'copy', size: 18 }))), this.qrCodeDataUrl && (h("div", { key: '63b43efe3dc5929054af9e5ee7f64d093864b3b0', class: "share-qr-container" }, h("img", { key: '9d3b0418eb80ff8c7e9106ad86d7cc211d017504', class: "share-qr-image", src: this.qrCodeDataUrl, alt: "QR code for share link" })))))))));
129
129
  }
130
130
  static get is() { return "kritzel-share-dialog"; }
131
131
  static get encapsulation() { return "shadow"; }