stickyflow 0.4.0 → 0.6.0

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 (65) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +51 -5
  3. package/dist/binding/index.cjs +34 -0
  4. package/dist/binding/index.cjs.map +1 -0
  5. package/dist/binding/index.d.cts +11 -0
  6. package/dist/binding/index.d.ts +11 -0
  7. package/dist/binding/index.js +5 -0
  8. package/dist/binding/index.js.map +1 -0
  9. package/dist/{chunk-BYMIYXP5.js → chunk-4G2R7PEL.js} +513 -61
  10. package/dist/chunk-4G2R7PEL.js.map +1 -0
  11. package/dist/{chunk-HFOGKSNU.cjs → chunk-4LENHH6C.cjs} +15 -15
  12. package/dist/{chunk-HFOGKSNU.cjs.map → chunk-4LENHH6C.cjs.map} +1 -1
  13. package/dist/{chunk-65IVT4GK.js → chunk-FVHVOJS2.js} +1333 -650
  14. package/dist/chunk-FVHVOJS2.js.map +1 -0
  15. package/dist/chunk-JIJMZMGY.cjs +1189 -0
  16. package/dist/chunk-JIJMZMGY.cjs.map +1 -0
  17. package/dist/{chunk-UXDWH2JC.cjs → chunk-KTNCDNDB.cjs} +1165 -1118
  18. package/dist/chunk-KTNCDNDB.cjs.map +1 -0
  19. package/dist/chunk-MFNUJA26.js +1182 -0
  20. package/dist/chunk-MFNUJA26.js.map +1 -0
  21. package/dist/{chunk-XEN5QIIJ.js → chunk-ULQZ6CZW.js} +3 -3
  22. package/dist/{chunk-XEN5QIIJ.js.map → chunk-ULQZ6CZW.js.map} +1 -1
  23. package/dist/{chunk-DDCTNLLD.cjs → chunk-WQRT5PVT.cjs} +1837 -1155
  24. package/dist/chunk-WQRT5PVT.cjs.map +1 -0
  25. package/dist/{chunk-CSXQD3ON.js → chunk-WRDVNMFS.js} +1128 -1081
  26. package/dist/chunk-WRDVNMFS.js.map +1 -0
  27. package/dist/{chunk-CXL254BT.cjs → chunk-XJ4W6TW4.cjs} +528 -60
  28. package/dist/chunk-XJ4W6TW4.cjs.map +1 -0
  29. package/dist/index.cjs +73 -1013
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +67 -14
  32. package/dist/index.d.ts +67 -14
  33. package/dist/index.js +6 -993
  34. package/dist/index.js.map +1 -1
  35. package/dist/interaction/index.cjs +246 -236
  36. package/dist/interaction/index.cjs.map +1 -1
  37. package/dist/interaction/index.d.cts +3 -2
  38. package/dist/interaction/index.d.ts +3 -2
  39. package/dist/interaction/index.js +18 -8
  40. package/dist/interaction/index.js.map +1 -1
  41. package/dist/{render-C5X74hds.d.cts → render-Db0eSz_s.d.cts} +216 -118
  42. package/dist/{render-C5X74hds.d.ts → render-Db0eSz_s.d.ts} +216 -118
  43. package/dist/runtime-BhivvBeL.d.cts +10 -0
  44. package/dist/runtime-n2yG-_j-.d.ts +10 -0
  45. package/dist/{runtimeTypes-yTSAvtCn.d.cts → runtimeTypes-CrkMHvVi.d.cts} +10 -5
  46. package/dist/{runtimeTypes-D8hPZ62T.d.ts → runtimeTypes-DnI7mRF5.d.ts} +10 -5
  47. package/dist/stickyflow-diagram.global.js +35 -35
  48. package/dist/stickyflow-diagram.global.js.map +1 -1
  49. package/dist/{types-CdgGdtoD.d.ts → types-BHfUKT4s.d.cts} +3 -2
  50. package/dist/{types-BDKDf4zr.d.cts → types-D4cH4f1a.d.ts} +3 -2
  51. package/dist/viewer/index.cjs +9 -9
  52. package/dist/viewer/index.d.cts +4 -4
  53. package/dist/viewer/index.d.ts +4 -4
  54. package/dist/viewer/index.js +4 -4
  55. package/dist/web-component/index.cjs +6 -6
  56. package/dist/web-component/index.d.cts +2 -2
  57. package/dist/web-component/index.d.ts +2 -2
  58. package/dist/web-component/index.js +4 -4
  59. package/package.json +6 -1
  60. package/dist/chunk-65IVT4GK.js.map +0 -1
  61. package/dist/chunk-BYMIYXP5.js.map +0 -1
  62. package/dist/chunk-CSXQD3ON.js.map +0 -1
  63. package/dist/chunk-CXL254BT.cjs.map +0 -1
  64. package/dist/chunk-DDCTNLLD.cjs.map +0 -1
  65. package/dist/chunk-UXDWH2JC.cjs.map +0 -1
@@ -80,6 +80,115 @@ function isometricFaces(object) {
80
80
  };
81
81
  }
82
82
 
83
+ // src/model/isometricObject/footprint.ts
84
+ function signedArea(points) {
85
+ let sum = 0;
86
+ for (let i = 0; i < points.length; i += 1) {
87
+ const [x1, y1] = points[i];
88
+ const [x2, y2] = points[(i + 1) % points.length];
89
+ sum += x1 * y2 - x2 * y1;
90
+ }
91
+ return sum / 2;
92
+ }
93
+ function cleanFootprint(points) {
94
+ const clean = (points ?? []).filter(
95
+ (point) => Array.isArray(point) && Number.isFinite(point[0]) && Number.isFinite(point[1])
96
+ );
97
+ const unique = clean.filter((point, index) => {
98
+ const next = clean[(index + 1) % clean.length];
99
+ return point[0] !== next[0] || point[1] !== next[1];
100
+ });
101
+ return unique.length >= 3 ? unique : [];
102
+ }
103
+ var ARC_STEP = Math.PI / 12;
104
+ function roundFootprint(points, radius, width, depth) {
105
+ if (!(radius > 0) || width <= 0 || depth <= 0) {
106
+ return [...points];
107
+ }
108
+ const world = points.map(([u, v]) => ({ x: u * width, y: v * depth }));
109
+ const rounded = [];
110
+ for (let i = 0; i < world.length; i += 1) {
111
+ const here = world[i];
112
+ const before = world[(i - 1 + world.length) % world.length];
113
+ const after = world[(i + 1) % world.length];
114
+ const a = { x: before.x - here.x, y: before.y - here.y };
115
+ const b = { x: after.x - here.x, y: after.y - here.y };
116
+ const lengthA = Math.hypot(a.x, a.y);
117
+ const lengthB = Math.hypot(b.x, b.y);
118
+ const cos = (a.x * b.x + a.y * b.y) / (lengthA * lengthB);
119
+ const angle = Math.acos(Math.max(-1, Math.min(1, cos)));
120
+ if (!Number.isFinite(angle) || angle < 1e-3 || Math.PI - angle < 1e-3) {
121
+ rounded.push(points[i]);
122
+ continue;
123
+ }
124
+ const reach = Math.min(radius / Math.tan(angle / 2), Math.min(lengthA, lengthB) / 2);
125
+ const effective = reach * Math.tan(angle / 2);
126
+ const unitA = { x: a.x / lengthA, y: a.y / lengthA };
127
+ const unitB = { x: b.x / lengthB, y: b.y / lengthB };
128
+ const from = { x: here.x + unitA.x * reach, y: here.y + unitA.y * reach };
129
+ const to = { x: here.x + unitB.x * reach, y: here.y + unitB.y * reach };
130
+ const bisector = { x: unitA.x + unitB.x, y: unitA.y + unitB.y };
131
+ const bisectorLength = Math.hypot(bisector.x, bisector.y);
132
+ const centerDistance = effective / Math.sin(angle / 2);
133
+ const center = {
134
+ x: here.x + bisector.x / bisectorLength * centerDistance,
135
+ y: here.y + bisector.y / bisectorLength * centerDistance
136
+ };
137
+ const start = Math.atan2(from.y - center.y, from.x - center.x);
138
+ let sweep = Math.atan2(to.y - center.y, to.x - center.x) - start;
139
+ sweep -= 2 * Math.PI * Math.round(sweep / (2 * Math.PI));
140
+ const steps = Math.max(2, Math.ceil(Math.abs(sweep) / ARC_STEP));
141
+ for (let step = 0; step <= steps; step += 1) {
142
+ const t = start + sweep * step / steps;
143
+ rounded.push([(center.x + effective * Math.cos(t)) / width, (center.y + effective * Math.sin(t)) / depth]);
144
+ }
145
+ }
146
+ return rounded;
147
+ }
148
+ function extrudeFootprint(frame, footprint, cornerRadius = 0) {
149
+ const width = Math.max(0, frame.width);
150
+ const depth = Math.max(0, frame.depth);
151
+ const height = Math.max(0, frame.height);
152
+ const points = roundFootprint(cleanFootprint(footprint), cornerRadius, width, depth);
153
+ const apexX = frame.x + depth * AXIS_COS;
154
+ const project = ([u, v], z) => ({
155
+ x: apexX + (u * width - v * depth) * AXIS_COS,
156
+ y: frame.y + (u * width + v * depth) * AXIS_SIN + z
157
+ });
158
+ const top = points.map((point) => project(point, 0));
159
+ const turn = signedArea(points) >= 0 ? 1 : -1;
160
+ const edges = points.map((from, i) => {
161
+ const to = points[(i + 1) % points.length];
162
+ const edgeU = (to[0] - from[0]) * width;
163
+ const edgeV = (to[1] - from[1]) * depth;
164
+ const length = Math.hypot(edgeU, edgeV);
165
+ const normalU = length === 0 ? 0 : edgeV / length * turn;
166
+ const normalV = length === 0 ? 0 : -edgeU / length * turn;
167
+ return { from, to, length, normalU, normalV, visible: length > 0 && normalU + normalV > 1e-9 };
168
+ });
169
+ const sameWay = (a, b) => {
170
+ return a.visible && b.visible && a.normalU * b.normalU + a.normalV * b.normalV > Math.cos(0.5);
171
+ };
172
+ const sides = [];
173
+ edges.forEach((edge, i) => {
174
+ if (!edge.visible) {
175
+ return;
176
+ }
177
+ const before = edges[(i - 1 + edges.length) % edges.length];
178
+ const after = edges[(i + 1) % edges.length];
179
+ const { from, to } = edge;
180
+ sides.push({
181
+ points: [project(from, 0), project(to, 0), project(to, height), project(from, height)],
182
+ light: 0.72 + 0.28 * Math.max(0, Math.min(1, edge.normalV / (Math.abs(edge.normalU) + Math.abs(edge.normalV)))),
183
+ depth: (from[0] + to[0]) / 2 + (from[1] + to[1]) / 2,
184
+ smoothStart: sameWay(before, edge),
185
+ smoothEnd: sameWay(edge, after)
186
+ });
187
+ });
188
+ sides.sort((a, b) => a.depth - b.depth);
189
+ return { top, sides };
190
+ }
191
+
83
192
  // src/model/isometricObject/shading.ts
84
193
  function clamp255(value) {
85
194
  return Math.max(0, Math.min(255, Math.round(value)));
@@ -103,6 +212,9 @@ function multiply(hex, factor) {
103
212
  const [r, g, b] = rgb;
104
213
  return rgbToHex(r * factor, g * factor, b * factor);
105
214
  }
215
+ function shadeFill(fill, factor) {
216
+ return multiply(fill, factor);
217
+ }
106
218
  function deriveFaceFills(fill) {
107
219
  return {
108
220
  topFill: fill,
@@ -111,6 +223,277 @@ function deriveFaceFills(fill) {
111
223
  };
112
224
  }
113
225
 
226
+ // src/model/path/curve.ts
227
+ var SAMPLES_PER_SEGMENT = 8;
228
+ function pointTension(curve, point) {
229
+ return Math.max(0, point.tension ?? curve.tension);
230
+ }
231
+ function isStraight(curve) {
232
+ return curve.points.length < 3 || curve.points.every((point) => pointTension(curve, point) <= 0);
233
+ }
234
+ function pointAt(curve, index) {
235
+ const { points } = curve;
236
+ if (curve.closed) {
237
+ return points[(index + points.length) % points.length];
238
+ }
239
+ return points[Math.max(0, Math.min(points.length - 1, index))];
240
+ }
241
+ function pathSegments(curve) {
242
+ const count = curve.closed ? curve.points.length : curve.points.length - 1;
243
+ return Array.from({ length: Math.max(0, count) }, (_, index) => {
244
+ const previous = pointAt(curve, index - 1);
245
+ const from = pointAt(curve, index);
246
+ const to = pointAt(curve, index + 1);
247
+ const next = pointAt(curve, index + 2);
248
+ const fromFactor = pointTension(curve, from) / 6;
249
+ const toFactor = pointTension(curve, to) / 6;
250
+ if (fromFactor === 0 && toFactor === 0) {
251
+ return { from, to, controls: null };
252
+ }
253
+ const first = { x: from.x + (to.x - previous.x) * fromFactor, y: from.y + (to.y - previous.y) * fromFactor };
254
+ const second = { x: to.x - (next.x - from.x) * toFactor, y: to.y - (next.y - from.y) * toFactor };
255
+ return { from, to, controls: [first, second] };
256
+ });
257
+ }
258
+ function bezierAt(segment, t) {
259
+ const { from, to, controls } = segment;
260
+ const u = 1 - t;
261
+ const weights = [u * u * u, 3 * u * u * t, 3 * u * t * t, t * t * t];
262
+ const anchors = [from, controls[0], controls[1], to];
263
+ return {
264
+ x: anchors.reduce((sum, anchor, i) => sum + anchor.x * weights[i], 0),
265
+ y: anchors.reduce((sum, anchor, i) => sum + anchor.y * weights[i], 0)
266
+ };
267
+ }
268
+ function flattenPath(curve, samples = SAMPLES_PER_SEGMENT) {
269
+ if (isStraight(curve)) {
270
+ return curve.points.map((point) => ({ x: point.x, y: point.y }));
271
+ }
272
+ const flat = [];
273
+ const segments = pathSegments(curve);
274
+ segments.forEach((segment) => {
275
+ flat.push({ x: segment.from.x, y: segment.from.y });
276
+ if (segment.controls) {
277
+ const curved = { ...segment, controls: segment.controls };
278
+ for (let step = 1; step < samples; step++) {
279
+ flat.push(bezierAt(curved, step / samples));
280
+ }
281
+ }
282
+ });
283
+ const last = segments[segments.length - 1];
284
+ if (!curve.closed && last) {
285
+ flat.push({ x: last.to.x, y: last.to.y });
286
+ }
287
+ return flat;
288
+ }
289
+
290
+ // src/model/path/symbol.ts
291
+ function pathBounds(points) {
292
+ const xs = points.map((point) => point.x);
293
+ const ys = points.map((point) => point.y);
294
+ const x = Math.min(...xs);
295
+ const y = Math.min(...ys);
296
+ return { x, y, width: Math.max(...xs) - x, height: Math.max(...ys) - y };
297
+ }
298
+ var round = (value) => Math.round(value * 1e4) / 1e4;
299
+ function pathToSymbol(points) {
300
+ if (points.length === 0) {
301
+ return { points: [], width: 0, height: 0 };
302
+ }
303
+ const frame = pathBounds(points);
304
+ const unit = (value, size) => size === 0 ? 0 : round(value / size);
305
+ return {
306
+ width: frame.width,
307
+ height: frame.height,
308
+ points: points.map((point) => {
309
+ const x = unit(point.x - frame.x, frame.width);
310
+ const y = unit(point.y - frame.y, frame.height);
311
+ return point.tension === void 0 ? [x, y] : [x, y, point.tension];
312
+ })
313
+ };
314
+ }
315
+ function symbolToPath(points, frame) {
316
+ return points.map((point) => {
317
+ const placed = { x: frame.x + point[0] * frame.width, y: frame.y + point[1] * frame.height };
318
+ return point[2] === void 0 ? placed : { ...placed, tension: point[2] };
319
+ });
320
+ }
321
+
322
+ // src/model/component/supportedTypes.ts
323
+ var BUILT_IN_COMPONENT_TYPES = ["rollingNumber", "tickScale", "ruler"];
324
+ function isBuiltInComponentType(value) {
325
+ return value !== void 0 && BUILT_IN_COMPONENT_TYPES.includes(value);
326
+ }
327
+
328
+ // src/model/component/guards.ts
329
+ function isGenericComponent(component) {
330
+ return !isBuiltInComponentType(component.type);
331
+ }
332
+
333
+ // src/model/component/builtIns.ts
334
+ var BUILT_IN_DESCRIPTORS = [
335
+ {
336
+ type: "rollingNumber",
337
+ group: "readout",
338
+ value: { type: "number", writable: false, default: 0 },
339
+ properties: {},
340
+ interaction: "none",
341
+ pointerScale: false,
342
+ size: { width: 160, height: 90 }
343
+ },
344
+ {
345
+ type: "tickScale",
346
+ group: "readout",
347
+ value: { type: "number", writable: false, default: 0 },
348
+ properties: {},
349
+ interaction: "none",
350
+ pointerScale: true,
351
+ size: { width: 200, height: 200 }
352
+ },
353
+ {
354
+ type: "ruler",
355
+ group: "input",
356
+ value: { type: "number", writable: false, default: 0 },
357
+ properties: {},
358
+ interaction: "scale",
359
+ pointerScale: true,
360
+ size: { width: 120, height: 360 }
361
+ },
362
+ {
363
+ type: "switch",
364
+ group: "input",
365
+ value: { type: "boolean", writable: true, default: false },
366
+ properties: {
367
+ accent: { type: "color", default: "#5a6bff" },
368
+ track: { type: "color", default: "#cbd5e1" },
369
+ thumb: { type: "color", default: "#ffffff" }
370
+ },
371
+ interaction: "toggle",
372
+ pointerScale: false,
373
+ size: { width: 52, height: 30, minWidth: 36, minHeight: 20, aspect: 52 / 30 },
374
+ role: "switch"
375
+ },
376
+ {
377
+ type: "checkbox",
378
+ group: "input",
379
+ value: { type: "boolean", writable: true, default: false },
380
+ properties: {
381
+ accent: { type: "color", default: "#5a6bff" },
382
+ stroke: { type: "color", default: "#94a3b8" },
383
+ check: { type: "color", default: "#ffffff" },
384
+ textColor: { type: "color", default: "#0f172a" },
385
+ fontSize: { type: "number", default: 14, min: 6, max: 200 }
386
+ },
387
+ interaction: "toggle",
388
+ pointerScale: false,
389
+ size: { width: 160, height: 24, minWidth: 18, minHeight: 18 },
390
+ role: "checkbox"
391
+ },
392
+ {
393
+ type: "toggleButton",
394
+ group: "input",
395
+ value: { type: "boolean", writable: true, default: false },
396
+ properties: {
397
+ accent: { type: "color", default: "#5a6bff" },
398
+ stroke: { type: "color", default: "#94a3b8" },
399
+ textColor: { type: "color", default: "#0f172a" },
400
+ onTextColor: { type: "color", default: "#ffffff" },
401
+ fontSize: { type: "number", default: 14, min: 6, max: 200 }
402
+ },
403
+ interaction: "toggle",
404
+ pointerScale: false,
405
+ size: { width: 120, height: 40, minWidth: 40, minHeight: 24 },
406
+ role: "button"
407
+ },
408
+ {
409
+ type: "button",
410
+ group: "action",
411
+ properties: {
412
+ accent: { type: "color", default: "#5a6bff" },
413
+ textColor: { type: "color", default: "#ffffff" },
414
+ radius: { type: "number", default: 8, min: 0, max: 200 },
415
+ fontSize: { type: "number", default: 14, min: 6, max: 200 }
416
+ },
417
+ interaction: "press",
418
+ pointerScale: false,
419
+ size: { width: 120, height: 40, minWidth: 40, minHeight: 24 },
420
+ role: "button"
421
+ }
422
+ ];
423
+
424
+ // src/model/component/registry.ts
425
+ var version = 0;
426
+ var descriptors = new Map(
427
+ BUILT_IN_DESCRIPTORS.map((descriptor) => [descriptor.type, descriptor])
428
+ );
429
+ var TYPE_NAME = /^[A-Za-z][A-Za-z0-9]*$/;
430
+ function registerComponentDescriptor(descriptor) {
431
+ if (!TYPE_NAME.test(descriptor.type)) {
432
+ throw new Error(`'${descriptor.type}' is not a valid component type name.`);
433
+ }
434
+ if (descriptors.has(descriptor.type)) {
435
+ throw new Error(`A component of type '${descriptor.type}' is already defined.`);
436
+ }
437
+ descriptors.set(descriptor.type, descriptor);
438
+ version += 1;
439
+ return () => {
440
+ if (descriptors.get(descriptor.type) === descriptor) {
441
+ descriptors.delete(descriptor.type);
442
+ version += 1;
443
+ }
444
+ };
445
+ }
446
+ function componentRegistryVersion() {
447
+ return version;
448
+ }
449
+ function getComponentDescriptor(type) {
450
+ return type === void 0 ? void 0 : descriptors.get(type);
451
+ }
452
+ function componentTypes() {
453
+ return [...descriptors.keys()];
454
+ }
455
+ function isComponentType(value) {
456
+ return getComponentDescriptor(value) !== void 0;
457
+ }
458
+
459
+ // src/model/component/format.ts
460
+ function formatRollingNumber(value, digits) {
461
+ const text = String(value);
462
+ if (digits === void 0) {
463
+ return text;
464
+ }
465
+ if (!Number.isInteger(digits) || digits < 1) {
466
+ return text;
467
+ }
468
+ return text.padStart(digits, "0");
469
+ }
470
+
471
+ // src/model/component/theme.ts
472
+ var DEFAULT_ROLLING_NUMBER_STYLE = {
473
+ color: "#000000",
474
+ surface: "rgba(255, 255, 255, 0.28)",
475
+ divider: "rgba(0, 0, 0, 0.2)",
476
+ labelColor: "rgba(0, 0, 0, 0.62)",
477
+ fontFamily: "'Roboto Mono', 'SFMono-Regular', Consolas, monospace",
478
+ variant: "flip",
479
+ motion: "roll",
480
+ fontWeight: "300",
481
+ fontSize: 0
482
+ };
483
+ function resolveRollingNumberStyle(style) {
484
+ return {
485
+ color: style.color ?? DEFAULT_ROLLING_NUMBER_STYLE.color,
486
+ surface: style.surface ?? DEFAULT_ROLLING_NUMBER_STYLE.surface,
487
+ divider: style.divider ?? DEFAULT_ROLLING_NUMBER_STYLE.divider,
488
+ labelColor: style.labelColor ?? DEFAULT_ROLLING_NUMBER_STYLE.labelColor,
489
+ fontFamily: style.fontFamily ?? DEFAULT_ROLLING_NUMBER_STYLE.fontFamily,
490
+ variant: style.variant ?? DEFAULT_ROLLING_NUMBER_STYLE.variant,
491
+ motion: style.motion ?? DEFAULT_ROLLING_NUMBER_STYLE.motion,
492
+ fontWeight: style.fontWeight ?? DEFAULT_ROLLING_NUMBER_STYLE.fontWeight,
493
+ fontSize: style.fontSize ?? DEFAULT_ROLLING_NUMBER_STYLE.fontSize
494
+ };
495
+ }
496
+
114
497
  // src/sflLanguage/lexing/cursor.ts
115
498
  var SourceCursor = class {
116
499
  constructor(input) {
@@ -510,9 +893,11 @@ var NAMED_BLOCK_KINDS = [
510
893
  "Path",
511
894
  "Chart",
512
895
  "Widget",
896
+ "Component",
513
897
  "Shape",
514
898
  "Text",
515
899
  "Isometric",
900
+ "Dimension",
516
901
  "Link",
517
902
  "Connection",
518
903
  "Layout",
@@ -528,6 +913,7 @@ var NAMED_BLOCK_KINDS = [
528
913
  ];
529
914
  var SIDES = ["top", "bottom", "left", "right"];
530
915
  var isSide = (s) => SIDES.includes(s);
916
+ var isComponentBlockKind = (kind) => kind === "Component" || kind === "Widget";
531
917
  var isNamedBlockKind = (s) => NAMED_BLOCK_KINDS.includes(s);
532
918
 
533
919
  // src/sflLanguage/parsing/values.ts
@@ -967,14 +1353,14 @@ var DocumentParser = class {
967
1353
  if (header.value !== "sfl") {
968
1354
  throw new SflParseError(`document must start with 'sfl', got '${header.value}'`, header.line, header.col);
969
1355
  }
970
- const version = this.cursor.expect("number", "version number");
1356
+ const version2 = this.cursor.expect("number", "version number");
971
1357
  this.cursor.skipNewlines();
972
1358
  const blocks = [];
973
1359
  while (!this.cursor.at("eof")) {
974
1360
  blocks.push(this.blocks.parseBlock());
975
1361
  this.cursor.skipNewlines();
976
1362
  }
977
- return { version: version.value, blocks };
1363
+ return { version: version2.value, blocks };
978
1364
  }
979
1365
  };
980
1366
 
@@ -1285,6 +1671,11 @@ function isChartObject(canvasObject) {
1285
1671
  return canvasObject.objectType === "chart" && canvasObject.chart !== void 0;
1286
1672
  }
1287
1673
 
1674
+ // src/sflSemantic/canvasObjects/artifacts/dimension/types.ts
1675
+ function isDimensionObject(canvasObject) {
1676
+ return canvasObject.objectType === "dimension" && canvasObject.dimension !== void 0;
1677
+ }
1678
+
1288
1679
  // src/sflSemantic/canvasObjects/artifacts/isometric/types.ts
1289
1680
  function isIsometricObject(canvasObject) {
1290
1681
  return canvasObject.objectType === "isometric" && canvasObject.isometric !== void 0;
@@ -1421,7 +1812,9 @@ var CANVAS_OBJECT_BLOCK_KINDS = [
1421
1812
  "Path",
1422
1813
  "Chart",
1423
1814
  "Widget",
1424
- "Isometric"
1815
+ "Component",
1816
+ "Isometric",
1817
+ "Dimension"
1425
1818
  ];
1426
1819
  var canvasObjectBlockKinds = new Set(CANVAS_OBJECT_BLOCK_KINDS);
1427
1820
  function isCanvasObjectBlockKind(kind) {
@@ -1827,21 +2220,77 @@ function resolveChartObject(base, block2, properties, symbolDefinitions, mergedP
1827
2220
  };
1828
2221
  }
1829
2222
 
2223
+ // src/sflSemantic/canvasObjects/artifacts/dimension/reader.ts
2224
+ function readPoint(value, origin) {
2225
+ const [x, y] = tupleValues(value) ?? [];
2226
+ return { x: origin.x + (x ?? 0), y: origin.y + (y ?? 0) };
2227
+ }
2228
+ function readDimension(properties, origin) {
2229
+ return {
2230
+ start: readPoint(properties.get("start"), origin),
2231
+ end: readPoint(properties.get("end"), origin),
2232
+ offset: asNumber(properties.get("offset")) ?? 0,
2233
+ unit: asString(properties.get("unit"))
2234
+ };
2235
+ }
2236
+
2237
+ // src/sflSemantic/canvasObjects/artifacts/dimension/resolver.ts
2238
+ function resolveDimensionObject(base, properties, origin) {
2239
+ return {
2240
+ ...base,
2241
+ objectType: "dimension",
2242
+ dimension: readDimension(properties, origin)
2243
+ };
2244
+ }
2245
+
1830
2246
  // src/sflSemantic/canvasObjects/artifacts/isometric/reader.ts
1831
- function readIsometric(properties, depth) {
2247
+ function readFootprintPoint(value) {
2248
+ if (value.type !== "list" || value.values.length < 2) {
2249
+ return [];
2250
+ }
2251
+ const x = asNumber(value.values[0]);
2252
+ const y = asNumber(value.values[1]);
2253
+ const tension = value.values[2] === void 0 ? void 0 : asNumber(value.values[2]);
2254
+ if (x === void 0 || y === void 0) {
2255
+ return [];
2256
+ }
2257
+ return [tension === void 0 ? { x, y } : { x, y, tension }];
2258
+ }
2259
+ function asPolygon(points, tension) {
2260
+ const flat = flattenPath({ points, tension, closed: true });
2261
+ return flat.length >= 3 ? flat.map((point) => [point.x, point.y]) : void 0;
2262
+ }
2263
+ function readFootprint(value, symbolDefs) {
2264
+ if (value?.type === "list") {
2265
+ return asPolygon(value.values.flatMap(readFootprintPoint), 0);
2266
+ }
2267
+ const name = asString(value);
2268
+ const definition = name ? symbolDefs.get(name) : void 0;
2269
+ if (!definition) {
2270
+ return void 0;
2271
+ }
2272
+ const points = definition.points.map(([x, y], index) => {
2273
+ const tension = definition.pointTensions?.[index];
2274
+ return tension === void 0 ? { x, y } : { x, y, tension };
2275
+ });
2276
+ return asPolygon(points, definition.tension ?? 0);
2277
+ }
2278
+ function readIsometric(properties, depth, symbolDefs) {
1832
2279
  return {
1833
2280
  depth,
1834
- icon: asString(properties.get("icon"))
2281
+ icon: asString(properties.get("icon")),
2282
+ footprint: readFootprint(properties.get("symbol"), symbolDefs),
2283
+ form: asString(properties.get("shape")) === "sphere" ? "sphere" : "box"
1835
2284
  };
1836
2285
  }
1837
2286
 
1838
2287
  // src/sflSemantic/canvasObjects/artifacts/isometric/resolver.ts
1839
- function resolveIsometricObject(base, block2, properties, layoutProperty) {
2288
+ function resolveIsometricObject(base, block2, properties, layoutProperty, symbolDefinitions) {
1840
2289
  const size = tupleValues(layoutProperty(block2, "size"));
1841
2290
  return {
1842
2291
  ...base,
1843
2292
  objectType: "isometric",
1844
- isometric: readIsometric(properties, size?.[2] ?? 24)
2293
+ isometric: readIsometric(properties, size?.[2] ?? 24, symbolDefinitions)
1845
2294
  };
1846
2295
  }
1847
2296
 
@@ -1854,7 +2303,12 @@ function readPath(p, origin) {
1854
2303
  }
1855
2304
  const x = asNumber(value.values[0]);
1856
2305
  const y = asNumber(value.values[1]);
1857
- return x !== void 0 && y !== void 0 ? [{ x: origin.x + x, y: origin.y + y }] : [];
2306
+ const tension = value.values[2] === void 0 ? void 0 : asNumber(value.values[2]);
2307
+ if (x === void 0 || y === void 0) {
2308
+ return [];
2309
+ }
2310
+ const point = { x: origin.x + x, y: origin.y + y };
2311
+ return [tension === void 0 ? point : { ...point, tension }];
1858
2312
  }) : [];
1859
2313
  return {
1860
2314
  points,
@@ -1912,7 +2366,7 @@ function declaredCanvasObjectKind(block2, properties) {
1912
2366
  if (block2.kind === "Chart") {
1913
2367
  return "chart";
1914
2368
  }
1915
- if (block2.kind === "Widget") {
2369
+ if (isComponentBlockKind(block2.kind)) {
1916
2370
  return asString(properties.get("type")) ?? "widget";
1917
2371
  }
1918
2372
  if (block2.kind === "Text") {
@@ -1921,6 +2375,9 @@ function declaredCanvasObjectKind(block2, properties) {
1921
2375
  if (block2.kind === "Isometric") {
1922
2376
  return "isometric";
1923
2377
  }
2378
+ if (block2.kind === "Dimension") {
2379
+ return "dimension";
2380
+ }
1924
2381
  return asString(properties.get("kind")) ?? "";
1925
2382
  }
1926
2383
  function canvasObjectTypeForKind(kind) {
@@ -1936,12 +2393,15 @@ function canvasObjectTypeForKind(kind) {
1936
2393
  if (kind === "chart") {
1937
2394
  return "chart";
1938
2395
  }
1939
- if (kind === "rollingNumber" || kind === "tickScale" || kind === "ruler") {
1940
- return "widget";
2396
+ if (isBuiltInComponentType(kind)) {
2397
+ return "component";
1941
2398
  }
1942
2399
  if (kind === "isometric") {
1943
2400
  return "isometric";
1944
2401
  }
2402
+ if (kind === "dimension") {
2403
+ return "dimension";
2404
+ }
1945
2405
  return "shape";
1946
2406
  }
1947
2407
  function classifyCanvasObject(block2, properties, symbolDefinitions) {
@@ -1949,7 +2409,7 @@ function classifyCanvasObject(block2, properties, symbolDefinitions) {
1949
2409
  const shapeReference = asString(properties.get("shape"));
1950
2410
  const symbol = shapeReference ? symbolDefinitions.get(shapeReference) : void 0;
1951
2411
  return {
1952
- objectType: block2.kind === "Widget" ? "widget" : canvasObjectTypeForKind(kind),
2412
+ objectType: isComponentBlockKind(block2.kind) ? "component" : canvasObjectTypeForKind(kind),
1953
2413
  kind,
1954
2414
  shapeType: symbol ? "symbol" : shapeReference,
1955
2415
  symbol
@@ -2004,18 +2464,20 @@ function resolveCanvasObject(block2, origin, context, frameId, positionOverride)
2004
2464
  case "chart":
2005
2465
  return resolveChartObject(base, block2, properties, symbolDefs, mergedProps);
2006
2466
  case "isometric":
2007
- return resolveIsometricObject(base, block2, properties, layoutProp);
2467
+ return resolveIsometricObject(base, block2, properties, layoutProp, symbolDefs);
2008
2468
  case "path":
2009
2469
  return resolvePathObject(base, properties, origin);
2470
+ case "dimension":
2471
+ return resolveDimensionObject(base, properties, origin);
2010
2472
  case "swimlane":
2011
2473
  return resolveSwimlaneObject(base, properties);
2012
2474
  case "frame":
2013
2475
  return { ...base, objectType: "frame" };
2014
- case "widget":
2476
+ case "component":
2015
2477
  return {
2016
2478
  ...base,
2017
- objectType: "widget",
2018
- widget: {
2479
+ objectType: "component",
2480
+ component: {
2019
2481
  type: asString(properties.get("type")) ?? "rollingNumber",
2020
2482
  value: asString(properties.get("value")) ?? "0",
2021
2483
  digits: asNumber(properties.get("digits")),
@@ -2162,17 +2624,24 @@ function readShaderDefinition(block2) {
2162
2624
  // src/sflSemantic/definitions/symbols.ts
2163
2625
  function readSymbolPoints(block2) {
2164
2626
  const value = directProperties(block2).get("points");
2627
+ const points = [];
2628
+ const tensions = [];
2165
2629
  if (value?.type !== "list") {
2166
- return [];
2630
+ return { points, tensions };
2167
2631
  }
2168
- return value.values.flatMap((item) => {
2632
+ for (const item of value.values) {
2169
2633
  if (item.type !== "list" || item.values.length < 2) {
2170
- return [];
2634
+ continue;
2171
2635
  }
2172
2636
  const x = asNumber(item.values[0]);
2173
2637
  const y = asNumber(item.values[1]);
2174
- return x === void 0 || y === void 0 ? [] : [[x, y]];
2175
- });
2638
+ if (x === void 0 || y === void 0) {
2639
+ continue;
2640
+ }
2641
+ points.push([x, y]);
2642
+ tensions.push(item.values[2] === void 0 ? void 0 : asNumber(item.values[2]));
2643
+ }
2644
+ return { points, tensions };
2176
2645
  }
2177
2646
  function readSymbolPorts(block2) {
2178
2647
  const ports = childBlocks(block2).filter((child) => child.kind === "Port").flatMap((port) => {
@@ -2185,13 +2654,14 @@ function readSymbolPorts(block2) {
2185
2654
  return ports.length > 0 ? ports : void 0;
2186
2655
  }
2187
2656
  function readSymbolDefinition(block2) {
2188
- const points = readSymbolPoints(block2);
2657
+ const { points, tensions } = readSymbolPoints(block2);
2189
2658
  if (points.length < 2) {
2190
2659
  return void 0;
2191
2660
  }
2192
2661
  return {
2193
2662
  name: block2.name,
2194
2663
  points,
2664
+ pointTensions: tensions.some((tension) => tension !== void 0) ? tensions : void 0,
2195
2665
  tension: asNumber(directProperties(block2).get("tension")),
2196
2666
  ports: readSymbolPorts(block2)
2197
2667
  };
@@ -2448,18 +2918,18 @@ function collectUnsupportedGridShapes(doc) {
2448
2918
  return diagnostics;
2449
2919
  }
2450
2920
 
2451
- // src/sflSemantic/diagnostics/widgets.ts
2452
- function collectUnsupportedWidgetTypes(sflDocument) {
2921
+ // src/sflSemantic/diagnostics/components.ts
2922
+ function collectUnsupportedComponentTypes(sflDocument) {
2453
2923
  const diagnostics = [];
2454
2924
  const visit = (block2) => {
2455
- if (block2.kind === "Widget") {
2925
+ if (isComponentBlockKind(block2.kind)) {
2456
2926
  const type = asString(directProperties(block2).get("type")) ?? "rollingNumber";
2457
- if (type !== "rollingNumber" && type !== "tickScale" && type !== "ruler") {
2927
+ if (!isComponentType(type)) {
2458
2928
  diagnostics.push({
2459
2929
  severity: "warning",
2460
- code: "unsupported-widget-type",
2930
+ code: "unsupported-component-type",
2461
2931
  ownerId: block2.name,
2462
- message: `Unsupported widget type '${type}'. Supported: rollingNumber, tickScale, ruler.`
2932
+ message: `Unsupported component type '${type}'. Supported: ${componentTypes().join(", ")}.`
2463
2933
  });
2464
2934
  }
2465
2935
  }
@@ -2483,7 +2953,7 @@ function createCanvasResolution(doc) {
2483
2953
  ...collectUnsupportedChartTypes(doc),
2484
2954
  ...collectUnsupportedGridShapes(doc),
2485
2955
  ...collectEmptySeries(doc),
2486
- ...collectUnsupportedWidgetTypes(doc)
2956
+ ...collectUnsupportedComponentTypes(doc)
2487
2957
  ],
2488
2958
  canvasObjectResolutionContext: createCanvasObjectPropertyReaders(definitions)
2489
2959
  };
@@ -2732,43 +3202,25 @@ function freeformPathData(geometry) {
2732
3202
  if (geometry.points.length === 0) {
2733
3203
  return "";
2734
3204
  }
2735
- if (geometry.points.length < 3 || geometry.tension <= 0) {
3205
+ if (isStraight(geometry)) {
2736
3206
  return linearPathData(geometry);
2737
3207
  }
2738
- return smoothPathData(geometry);
2739
- }
2740
- function linearPathData(geometry) {
2741
- const [first, ...remaining] = geometry.points;
2742
- const segments = remaining.map((point) => `L ${point.x} ${point.y}`).join(" ");
2743
- return `M ${first.x} ${first.y} ${segments}${geometry.closed ? " Z" : ""}`;
2744
- }
2745
- function smoothPathData(geometry) {
2746
3208
  const first = geometry.points[0];
2747
- const segmentCount = geometry.closed ? geometry.points.length : geometry.points.length - 1;
2748
3209
  const commands = [`M ${first.x} ${first.y}`];
2749
- for (let index = 0; index < segmentCount; index++) {
2750
- commands.push(curveSegmentCommand(geometry, index));
3210
+ for (const { to, controls } of pathSegments(geometry)) {
3211
+ commands.push(
3212
+ controls ? `C ${controls[0].x} ${controls[0].y} ${controls[1].x} ${controls[1].y} ${to.x} ${to.y}` : `L ${to.x} ${to.y}`
3213
+ );
2751
3214
  }
2752
3215
  if (geometry.closed) {
2753
3216
  commands.push("Z");
2754
3217
  }
2755
3218
  return commands.join(" ");
2756
3219
  }
2757
- function curveSegmentCommand(geometry, index) {
2758
- const previous = freeformPointAt(geometry, index - 1);
2759
- const start = freeformPointAt(geometry, index);
2760
- const end = freeformPointAt(geometry, index + 1);
2761
- const next = freeformPointAt(geometry, index + 2);
2762
- const factor = geometry.tension / 6;
2763
- const firstControl = { x: start.x + (end.x - previous.x) * factor, y: start.y + (end.y - previous.y) * factor };
2764
- const secondControl = { x: end.x - (next.x - start.x) * factor, y: end.y - (next.y - start.y) * factor };
2765
- return `C ${firstControl.x} ${firstControl.y} ${secondControl.x} ${secondControl.y} ${end.x} ${end.y}`;
2766
- }
2767
- function freeformPointAt(geometry, index) {
2768
- if (geometry.closed) {
2769
- return geometry.points[(index + geometry.points.length) % geometry.points.length];
2770
- }
2771
- return geometry.points[Math.max(0, Math.min(geometry.points.length - 1, index))];
3220
+ function linearPathData(geometry) {
3221
+ const [first, ...remaining] = geometry.points;
3222
+ const segments = remaining.map((point) => `L ${point.x} ${point.y}`).join(" ");
3223
+ return `M ${first.x} ${first.y} ${segments}${geometry.closed ? " Z" : ""}`;
2772
3224
  }
2773
3225
 
2774
3226
  // src/renderScene/charts/primitives/radarShape.ts
@@ -3267,8 +3719,8 @@ function createRoundedCorner(previous, corner, next, maximumRadius) {
3267
3719
  const outgoing = { x: next.x - corner.x, y: next.y - corner.y };
3268
3720
  const incomingIsAxisAligned = incoming.x === 0 || incoming.y === 0;
3269
3721
  const outgoingIsAxisAligned = outgoing.x === 0 || outgoing.y === 0;
3270
- const isStraight = incoming.x === 0 && outgoing.x === 0 || incoming.y === 0 && outgoing.y === 0;
3271
- if (!incomingIsAxisAligned || !outgoingIsAxisAligned || isStraight) {
3722
+ const isStraight2 = incoming.x === 0 && outgoing.x === 0 || incoming.y === 0 && outgoing.y === 0;
3723
+ if (!incomingIsAxisAligned || !outgoingIsAxisAligned || isStraight2) {
3272
3724
  return null;
3273
3725
  }
3274
3726
  const radius = Math.min(maximumRadius, axisLength(incoming) * 0.4, axisLength(outgoing) * 0.4);
@@ -4690,6 +5142,6 @@ function localShapePath(type, x, y, width, height) {
4690
5142
  }
4691
5143
  }
4692
5144
 
4693
- export { AXIS_COS, AXIS_SIN, BAR_LABEL, CATEGORY_LABEL_ROW, CHART_COLORS, CHART_TITLE_PROP, CHART_TYPES, CORNER_RADIUS_ATTR, DEFAULT_FONT, DEFAULT_HEATMAP_ZONES, DEFAULT_HEX_RADIUS, DEFAULT_ZONE_FILL, DOM_CONTRACT_VERSION, EMPTY_BOUNDS, ISOMETRIC_LABEL_OFFSET_ATTR, ISOMETRIC_SIZE_ATTR, LABEL_WIDTH, LEADER_INSET, PATH_CLOSED_ATTR, PATH_POINTS_ATTR, PATH_POINT_INDEX_ATTR, PATH_TENSION_ATTR, SQUARE_CORNER_ATTR, SYMBOL_BOUNDS_ATTR, SYMBOL_POINTS_ATTR, SYMBOL_TENSION_ATTR, VISIBLE_ISOMETRIC_FACES, angleForAxisValue, axisBands, axisLabelProp, barCategoryCount, barLabelSize, barPath, barShapePath, bottomRoundedRectPath, boxBounds, calculateLinkRoute, canonicalizeSource, categoryProp, chartText, chartTicks, clipSegmentToRect, colorWithAlpha, computeBoxplotStats, contrastTextColor, cornersRoundedRectPath, createPieGeometry, createPieSlicePath, createVerticalErrorWhiskerNode, deriveFaceFills, edgePointToward, elementCenter, ellipsizeToWidth, errorBarRange, estimateTextWidth, finite, formatBarLabel, formatFieldValue, freeformPathData, gapInsetAngle, getLineMidpoint, heuristicRichMeasure, horizontalRows, interpolateHexColorStops, isChartObject, isHorizontalBar, isIsometricObject, isLightColor, isPathObject, isSwimlaneObject, isometricBounds, isometricFaceCenter, isometricFaces, isometricTopFaceCenter, labelGapDash, leftRoundedRectPath, linePathData, localShapePath, mapChartValue, maxApexCornerRadius, maxPieCornerRadius, paint, parseSource, personLabelArea, pieApexRadius, pieArcPoint, pieUsesInnerArc, pillCornerRadius, pillPath, pointAtNormalizedPort, pointAtPort, radarCategoryCount, radarPointAt, radarRadius, radarRadiusForValue, radarSeriesPath, radarValueAtPoint, radarVertexPoint, relativeOffsetOnRectangleSide, renderPieLabels, representativeColor, resolveChartShadow, resolvePieRadii, rightRoundedRectPath, rotatedBounds, roundedBarPath, roundedOrthogonalPathData, roundedPolygonPath, rowTop, ruleAtProp, ruleTextProp, sameHueContrastColor, sameHueTint, segmentedBarPath, seriesColorProp, seriesLabelOffsetXProp, seriesLabelOffsetYProp, seriesLabelProp, seriesValueColorProp, seriesValueProp, sflToCanvasState, stackRank, stackSequence, stackedSegment, tag, tokenizeSource, topRoundedRectPath, wrapText, zoneColorAtValue };
4694
- //# sourceMappingURL=chunk-BYMIYXP5.js.map
4695
- //# sourceMappingURL=chunk-BYMIYXP5.js.map
5145
+ export { AXIS_COS, AXIS_SIN, BAR_LABEL, CATEGORY_LABEL_ROW, CHART_COLORS, CHART_TITLE_PROP, CHART_TYPES, CORNER_RADIUS_ATTR, DEFAULT_FONT, DEFAULT_HEATMAP_ZONES, DEFAULT_HEX_RADIUS, DEFAULT_ROLLING_NUMBER_STYLE, DEFAULT_ZONE_FILL, DOM_CONTRACT_VERSION, EMPTY_BOUNDS, ISOMETRIC_LABEL_OFFSET_ATTR, ISOMETRIC_SIZE_ATTR, LABEL_WIDTH, LEADER_INSET, PATH_CLOSED_ATTR, PATH_POINTS_ATTR, PATH_POINT_INDEX_ATTR, PATH_TENSION_ATTR, SQUARE_CORNER_ATTR, SYMBOL_BOUNDS_ATTR, SYMBOL_POINTS_ATTR, SYMBOL_TENSION_ATTR, VISIBLE_ISOMETRIC_FACES, angleForAxisValue, axisBands, axisLabelProp, barCategoryCount, barLabelSize, barPath, barShapePath, bottomRoundedRectPath, boxBounds, calculateLinkRoute, canonicalizeSource, categoryProp, chartText, chartTicks, cleanFootprint, clipSegmentToRect, colorWithAlpha, componentRegistryVersion, computeBoxplotStats, contrastTextColor, cornersRoundedRectPath, createPieGeometry, createPieSlicePath, createVerticalErrorWhiskerNode, deriveFaceFills, edgePointToward, elementCenter, ellipsizeToWidth, errorBarRange, estimateTextWidth, extrudeFootprint, finite, flattenPath, formatBarLabel, formatFieldValue, formatRollingNumber, freeformPathData, gapInsetAngle, getComponentDescriptor, getLineMidpoint, heuristicRichMeasure, horizontalRows, interpolateHexColorStops, isBuiltInComponentType, isChartObject, isDimensionObject, isGenericComponent, isHorizontalBar, isIsometricObject, isLightColor, isPathObject, isSwimlaneObject, isometricBounds, isometricFaceCenter, isometricFaces, isometricTopFaceCenter, labelGapDash, leftRoundedRectPath, linePathData, localShapePath, mapChartValue, maxApexCornerRadius, maxPieCornerRadius, paint, parseSource, pathBounds, pathToSymbol, personLabelArea, pieApexRadius, pieArcPoint, pieUsesInnerArc, pillCornerRadius, pillPath, pointAtNormalizedPort, pointAtPort, radarCategoryCount, radarPointAt, radarRadius, radarRadiusForValue, radarSeriesPath, radarValueAtPoint, radarVertexPoint, registerComponentDescriptor, relativeOffsetOnRectangleSide, renderPieLabels, representativeColor, resolveChartShadow, resolvePieRadii, resolveRollingNumberStyle, rightRoundedRectPath, rotatedBounds, roundedBarPath, roundedOrthogonalPathData, roundedPolygonPath, rowTop, ruleAtProp, ruleTextProp, sameHueContrastColor, sameHueTint, segmentedBarPath, seriesColorProp, seriesLabelOffsetXProp, seriesLabelOffsetYProp, seriesLabelProp, seriesValueColorProp, seriesValueProp, sflToCanvasState, shadeFill, stackRank, stackSequence, stackedSegment, symbolToPath, tag, tokenizeSource, topRoundedRectPath, wrapText, zoneColorAtValue };
5146
+ //# sourceMappingURL=chunk-4G2R7PEL.js.map
5147
+ //# sourceMappingURL=chunk-4G2R7PEL.js.map