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
@@ -82,6 +82,115 @@ function isometricFaces(object) {
82
82
  };
83
83
  }
84
84
 
85
+ // src/model/isometricObject/footprint.ts
86
+ function signedArea(points) {
87
+ let sum = 0;
88
+ for (let i = 0; i < points.length; i += 1) {
89
+ const [x1, y1] = points[i];
90
+ const [x2, y2] = points[(i + 1) % points.length];
91
+ sum += x1 * y2 - x2 * y1;
92
+ }
93
+ return sum / 2;
94
+ }
95
+ function cleanFootprint(points) {
96
+ const clean = (points ?? []).filter(
97
+ (point) => Array.isArray(point) && Number.isFinite(point[0]) && Number.isFinite(point[1])
98
+ );
99
+ const unique = clean.filter((point, index) => {
100
+ const next = clean[(index + 1) % clean.length];
101
+ return point[0] !== next[0] || point[1] !== next[1];
102
+ });
103
+ return unique.length >= 3 ? unique : [];
104
+ }
105
+ var ARC_STEP = Math.PI / 12;
106
+ function roundFootprint(points, radius, width, depth) {
107
+ if (!(radius > 0) || width <= 0 || depth <= 0) {
108
+ return [...points];
109
+ }
110
+ const world = points.map(([u, v]) => ({ x: u * width, y: v * depth }));
111
+ const rounded = [];
112
+ for (let i = 0; i < world.length; i += 1) {
113
+ const here = world[i];
114
+ const before = world[(i - 1 + world.length) % world.length];
115
+ const after = world[(i + 1) % world.length];
116
+ const a = { x: before.x - here.x, y: before.y - here.y };
117
+ const b = { x: after.x - here.x, y: after.y - here.y };
118
+ const lengthA = Math.hypot(a.x, a.y);
119
+ const lengthB = Math.hypot(b.x, b.y);
120
+ const cos = (a.x * b.x + a.y * b.y) / (lengthA * lengthB);
121
+ const angle = Math.acos(Math.max(-1, Math.min(1, cos)));
122
+ if (!Number.isFinite(angle) || angle < 1e-3 || Math.PI - angle < 1e-3) {
123
+ rounded.push(points[i]);
124
+ continue;
125
+ }
126
+ const reach = Math.min(radius / Math.tan(angle / 2), Math.min(lengthA, lengthB) / 2);
127
+ const effective = reach * Math.tan(angle / 2);
128
+ const unitA = { x: a.x / lengthA, y: a.y / lengthA };
129
+ const unitB = { x: b.x / lengthB, y: b.y / lengthB };
130
+ const from = { x: here.x + unitA.x * reach, y: here.y + unitA.y * reach };
131
+ const to = { x: here.x + unitB.x * reach, y: here.y + unitB.y * reach };
132
+ const bisector = { x: unitA.x + unitB.x, y: unitA.y + unitB.y };
133
+ const bisectorLength = Math.hypot(bisector.x, bisector.y);
134
+ const centerDistance = effective / Math.sin(angle / 2);
135
+ const center = {
136
+ x: here.x + bisector.x / bisectorLength * centerDistance,
137
+ y: here.y + bisector.y / bisectorLength * centerDistance
138
+ };
139
+ const start = Math.atan2(from.y - center.y, from.x - center.x);
140
+ let sweep = Math.atan2(to.y - center.y, to.x - center.x) - start;
141
+ sweep -= 2 * Math.PI * Math.round(sweep / (2 * Math.PI));
142
+ const steps = Math.max(2, Math.ceil(Math.abs(sweep) / ARC_STEP));
143
+ for (let step = 0; step <= steps; step += 1) {
144
+ const t = start + sweep * step / steps;
145
+ rounded.push([(center.x + effective * Math.cos(t)) / width, (center.y + effective * Math.sin(t)) / depth]);
146
+ }
147
+ }
148
+ return rounded;
149
+ }
150
+ function extrudeFootprint(frame, footprint, cornerRadius = 0) {
151
+ const width = Math.max(0, frame.width);
152
+ const depth = Math.max(0, frame.depth);
153
+ const height = Math.max(0, frame.height);
154
+ const points = roundFootprint(cleanFootprint(footprint), cornerRadius, width, depth);
155
+ const apexX = frame.x + depth * AXIS_COS;
156
+ const project = ([u, v], z) => ({
157
+ x: apexX + (u * width - v * depth) * AXIS_COS,
158
+ y: frame.y + (u * width + v * depth) * AXIS_SIN + z
159
+ });
160
+ const top = points.map((point) => project(point, 0));
161
+ const turn = signedArea(points) >= 0 ? 1 : -1;
162
+ const edges = points.map((from, i) => {
163
+ const to = points[(i + 1) % points.length];
164
+ const edgeU = (to[0] - from[0]) * width;
165
+ const edgeV = (to[1] - from[1]) * depth;
166
+ const length = Math.hypot(edgeU, edgeV);
167
+ const normalU = length === 0 ? 0 : edgeV / length * turn;
168
+ const normalV = length === 0 ? 0 : -edgeU / length * turn;
169
+ return { from, to, length, normalU, normalV, visible: length > 0 && normalU + normalV > 1e-9 };
170
+ });
171
+ const sameWay = (a, b) => {
172
+ return a.visible && b.visible && a.normalU * b.normalU + a.normalV * b.normalV > Math.cos(0.5);
173
+ };
174
+ const sides = [];
175
+ edges.forEach((edge, i) => {
176
+ if (!edge.visible) {
177
+ return;
178
+ }
179
+ const before = edges[(i - 1 + edges.length) % edges.length];
180
+ const after = edges[(i + 1) % edges.length];
181
+ const { from, to } = edge;
182
+ sides.push({
183
+ points: [project(from, 0), project(to, 0), project(to, height), project(from, height)],
184
+ light: 0.72 + 0.28 * Math.max(0, Math.min(1, edge.normalV / (Math.abs(edge.normalU) + Math.abs(edge.normalV)))),
185
+ depth: (from[0] + to[0]) / 2 + (from[1] + to[1]) / 2,
186
+ smoothStart: sameWay(before, edge),
187
+ smoothEnd: sameWay(edge, after)
188
+ });
189
+ });
190
+ sides.sort((a, b) => a.depth - b.depth);
191
+ return { top, sides };
192
+ }
193
+
85
194
  // src/model/isometricObject/shading.ts
86
195
  function clamp255(value) {
87
196
  return Math.max(0, Math.min(255, Math.round(value)));
@@ -105,6 +214,9 @@ function multiply(hex, factor) {
105
214
  const [r, g, b] = rgb;
106
215
  return rgbToHex(r * factor, g * factor, b * factor);
107
216
  }
217
+ function shadeFill(fill, factor) {
218
+ return multiply(fill, factor);
219
+ }
108
220
  function deriveFaceFills(fill) {
109
221
  return {
110
222
  topFill: fill,
@@ -113,6 +225,277 @@ function deriveFaceFills(fill) {
113
225
  };
114
226
  }
115
227
 
228
+ // src/model/path/curve.ts
229
+ var SAMPLES_PER_SEGMENT = 8;
230
+ function pointTension(curve, point) {
231
+ return Math.max(0, point.tension ?? curve.tension);
232
+ }
233
+ function isStraight(curve) {
234
+ return curve.points.length < 3 || curve.points.every((point) => pointTension(curve, point) <= 0);
235
+ }
236
+ function pointAt(curve, index) {
237
+ const { points } = curve;
238
+ if (curve.closed) {
239
+ return points[(index + points.length) % points.length];
240
+ }
241
+ return points[Math.max(0, Math.min(points.length - 1, index))];
242
+ }
243
+ function pathSegments(curve) {
244
+ const count = curve.closed ? curve.points.length : curve.points.length - 1;
245
+ return Array.from({ length: Math.max(0, count) }, (_, index) => {
246
+ const previous = pointAt(curve, index - 1);
247
+ const from = pointAt(curve, index);
248
+ const to = pointAt(curve, index + 1);
249
+ const next = pointAt(curve, index + 2);
250
+ const fromFactor = pointTension(curve, from) / 6;
251
+ const toFactor = pointTension(curve, to) / 6;
252
+ if (fromFactor === 0 && toFactor === 0) {
253
+ return { from, to, controls: null };
254
+ }
255
+ const first = { x: from.x + (to.x - previous.x) * fromFactor, y: from.y + (to.y - previous.y) * fromFactor };
256
+ const second = { x: to.x - (next.x - from.x) * toFactor, y: to.y - (next.y - from.y) * toFactor };
257
+ return { from, to, controls: [first, second] };
258
+ });
259
+ }
260
+ function bezierAt(segment, t) {
261
+ const { from, to, controls } = segment;
262
+ const u = 1 - t;
263
+ const weights = [u * u * u, 3 * u * u * t, 3 * u * t * t, t * t * t];
264
+ const anchors = [from, controls[0], controls[1], to];
265
+ return {
266
+ x: anchors.reduce((sum, anchor, i) => sum + anchor.x * weights[i], 0),
267
+ y: anchors.reduce((sum, anchor, i) => sum + anchor.y * weights[i], 0)
268
+ };
269
+ }
270
+ function flattenPath(curve, samples = SAMPLES_PER_SEGMENT) {
271
+ if (isStraight(curve)) {
272
+ return curve.points.map((point) => ({ x: point.x, y: point.y }));
273
+ }
274
+ const flat = [];
275
+ const segments = pathSegments(curve);
276
+ segments.forEach((segment) => {
277
+ flat.push({ x: segment.from.x, y: segment.from.y });
278
+ if (segment.controls) {
279
+ const curved = { ...segment, controls: segment.controls };
280
+ for (let step = 1; step < samples; step++) {
281
+ flat.push(bezierAt(curved, step / samples));
282
+ }
283
+ }
284
+ });
285
+ const last = segments[segments.length - 1];
286
+ if (!curve.closed && last) {
287
+ flat.push({ x: last.to.x, y: last.to.y });
288
+ }
289
+ return flat;
290
+ }
291
+
292
+ // src/model/path/symbol.ts
293
+ function pathBounds(points) {
294
+ const xs = points.map((point) => point.x);
295
+ const ys = points.map((point) => point.y);
296
+ const x = Math.min(...xs);
297
+ const y = Math.min(...ys);
298
+ return { x, y, width: Math.max(...xs) - x, height: Math.max(...ys) - y };
299
+ }
300
+ var round = (value) => Math.round(value * 1e4) / 1e4;
301
+ function pathToSymbol(points) {
302
+ if (points.length === 0) {
303
+ return { points: [], width: 0, height: 0 };
304
+ }
305
+ const frame = pathBounds(points);
306
+ const unit = (value, size) => size === 0 ? 0 : round(value / size);
307
+ return {
308
+ width: frame.width,
309
+ height: frame.height,
310
+ points: points.map((point) => {
311
+ const x = unit(point.x - frame.x, frame.width);
312
+ const y = unit(point.y - frame.y, frame.height);
313
+ return point.tension === void 0 ? [x, y] : [x, y, point.tension];
314
+ })
315
+ };
316
+ }
317
+ function symbolToPath(points, frame) {
318
+ return points.map((point) => {
319
+ const placed = { x: frame.x + point[0] * frame.width, y: frame.y + point[1] * frame.height };
320
+ return point[2] === void 0 ? placed : { ...placed, tension: point[2] };
321
+ });
322
+ }
323
+
324
+ // src/model/component/supportedTypes.ts
325
+ var BUILT_IN_COMPONENT_TYPES = ["rollingNumber", "tickScale", "ruler"];
326
+ function isBuiltInComponentType(value) {
327
+ return value !== void 0 && BUILT_IN_COMPONENT_TYPES.includes(value);
328
+ }
329
+
330
+ // src/model/component/guards.ts
331
+ function isGenericComponent(component) {
332
+ return !isBuiltInComponentType(component.type);
333
+ }
334
+
335
+ // src/model/component/builtIns.ts
336
+ var BUILT_IN_DESCRIPTORS = [
337
+ {
338
+ type: "rollingNumber",
339
+ group: "readout",
340
+ value: { type: "number", writable: false, default: 0 },
341
+ properties: {},
342
+ interaction: "none",
343
+ pointerScale: false,
344
+ size: { width: 160, height: 90 }
345
+ },
346
+ {
347
+ type: "tickScale",
348
+ group: "readout",
349
+ value: { type: "number", writable: false, default: 0 },
350
+ properties: {},
351
+ interaction: "none",
352
+ pointerScale: true,
353
+ size: { width: 200, height: 200 }
354
+ },
355
+ {
356
+ type: "ruler",
357
+ group: "input",
358
+ value: { type: "number", writable: false, default: 0 },
359
+ properties: {},
360
+ interaction: "scale",
361
+ pointerScale: true,
362
+ size: { width: 120, height: 360 }
363
+ },
364
+ {
365
+ type: "switch",
366
+ group: "input",
367
+ value: { type: "boolean", writable: true, default: false },
368
+ properties: {
369
+ accent: { type: "color", default: "#5a6bff" },
370
+ track: { type: "color", default: "#cbd5e1" },
371
+ thumb: { type: "color", default: "#ffffff" }
372
+ },
373
+ interaction: "toggle",
374
+ pointerScale: false,
375
+ size: { width: 52, height: 30, minWidth: 36, minHeight: 20, aspect: 52 / 30 },
376
+ role: "switch"
377
+ },
378
+ {
379
+ type: "checkbox",
380
+ group: "input",
381
+ value: { type: "boolean", writable: true, default: false },
382
+ properties: {
383
+ accent: { type: "color", default: "#5a6bff" },
384
+ stroke: { type: "color", default: "#94a3b8" },
385
+ check: { type: "color", default: "#ffffff" },
386
+ textColor: { type: "color", default: "#0f172a" },
387
+ fontSize: { type: "number", default: 14, min: 6, max: 200 }
388
+ },
389
+ interaction: "toggle",
390
+ pointerScale: false,
391
+ size: { width: 160, height: 24, minWidth: 18, minHeight: 18 },
392
+ role: "checkbox"
393
+ },
394
+ {
395
+ type: "toggleButton",
396
+ group: "input",
397
+ value: { type: "boolean", writable: true, default: false },
398
+ properties: {
399
+ accent: { type: "color", default: "#5a6bff" },
400
+ stroke: { type: "color", default: "#94a3b8" },
401
+ textColor: { type: "color", default: "#0f172a" },
402
+ onTextColor: { type: "color", default: "#ffffff" },
403
+ fontSize: { type: "number", default: 14, min: 6, max: 200 }
404
+ },
405
+ interaction: "toggle",
406
+ pointerScale: false,
407
+ size: { width: 120, height: 40, minWidth: 40, minHeight: 24 },
408
+ role: "button"
409
+ },
410
+ {
411
+ type: "button",
412
+ group: "action",
413
+ properties: {
414
+ accent: { type: "color", default: "#5a6bff" },
415
+ textColor: { type: "color", default: "#ffffff" },
416
+ radius: { type: "number", default: 8, min: 0, max: 200 },
417
+ fontSize: { type: "number", default: 14, min: 6, max: 200 }
418
+ },
419
+ interaction: "press",
420
+ pointerScale: false,
421
+ size: { width: 120, height: 40, minWidth: 40, minHeight: 24 },
422
+ role: "button"
423
+ }
424
+ ];
425
+
426
+ // src/model/component/registry.ts
427
+ var version = 0;
428
+ var descriptors = new Map(
429
+ BUILT_IN_DESCRIPTORS.map((descriptor) => [descriptor.type, descriptor])
430
+ );
431
+ var TYPE_NAME = /^[A-Za-z][A-Za-z0-9]*$/;
432
+ function registerComponentDescriptor(descriptor) {
433
+ if (!TYPE_NAME.test(descriptor.type)) {
434
+ throw new Error(`'${descriptor.type}' is not a valid component type name.`);
435
+ }
436
+ if (descriptors.has(descriptor.type)) {
437
+ throw new Error(`A component of type '${descriptor.type}' is already defined.`);
438
+ }
439
+ descriptors.set(descriptor.type, descriptor);
440
+ version += 1;
441
+ return () => {
442
+ if (descriptors.get(descriptor.type) === descriptor) {
443
+ descriptors.delete(descriptor.type);
444
+ version += 1;
445
+ }
446
+ };
447
+ }
448
+ function componentRegistryVersion() {
449
+ return version;
450
+ }
451
+ function getComponentDescriptor(type) {
452
+ return type === void 0 ? void 0 : descriptors.get(type);
453
+ }
454
+ function componentTypes() {
455
+ return [...descriptors.keys()];
456
+ }
457
+ function isComponentType(value) {
458
+ return getComponentDescriptor(value) !== void 0;
459
+ }
460
+
461
+ // src/model/component/format.ts
462
+ function formatRollingNumber(value, digits) {
463
+ const text = String(value);
464
+ if (digits === void 0) {
465
+ return text;
466
+ }
467
+ if (!Number.isInteger(digits) || digits < 1) {
468
+ return text;
469
+ }
470
+ return text.padStart(digits, "0");
471
+ }
472
+
473
+ // src/model/component/theme.ts
474
+ var DEFAULT_ROLLING_NUMBER_STYLE = {
475
+ color: "#000000",
476
+ surface: "rgba(255, 255, 255, 0.28)",
477
+ divider: "rgba(0, 0, 0, 0.2)",
478
+ labelColor: "rgba(0, 0, 0, 0.62)",
479
+ fontFamily: "'Roboto Mono', 'SFMono-Regular', Consolas, monospace",
480
+ variant: "flip",
481
+ motion: "roll",
482
+ fontWeight: "300",
483
+ fontSize: 0
484
+ };
485
+ function resolveRollingNumberStyle(style) {
486
+ return {
487
+ color: style.color ?? DEFAULT_ROLLING_NUMBER_STYLE.color,
488
+ surface: style.surface ?? DEFAULT_ROLLING_NUMBER_STYLE.surface,
489
+ divider: style.divider ?? DEFAULT_ROLLING_NUMBER_STYLE.divider,
490
+ labelColor: style.labelColor ?? DEFAULT_ROLLING_NUMBER_STYLE.labelColor,
491
+ fontFamily: style.fontFamily ?? DEFAULT_ROLLING_NUMBER_STYLE.fontFamily,
492
+ variant: style.variant ?? DEFAULT_ROLLING_NUMBER_STYLE.variant,
493
+ motion: style.motion ?? DEFAULT_ROLLING_NUMBER_STYLE.motion,
494
+ fontWeight: style.fontWeight ?? DEFAULT_ROLLING_NUMBER_STYLE.fontWeight,
495
+ fontSize: style.fontSize ?? DEFAULT_ROLLING_NUMBER_STYLE.fontSize
496
+ };
497
+ }
498
+
116
499
  // src/sflLanguage/lexing/cursor.ts
117
500
  var SourceCursor = class {
118
501
  constructor(input) {
@@ -512,9 +895,11 @@ var NAMED_BLOCK_KINDS = [
512
895
  "Path",
513
896
  "Chart",
514
897
  "Widget",
898
+ "Component",
515
899
  "Shape",
516
900
  "Text",
517
901
  "Isometric",
902
+ "Dimension",
518
903
  "Link",
519
904
  "Connection",
520
905
  "Layout",
@@ -530,6 +915,7 @@ var NAMED_BLOCK_KINDS = [
530
915
  ];
531
916
  var SIDES = ["top", "bottom", "left", "right"];
532
917
  var isSide = (s) => SIDES.includes(s);
918
+ var isComponentBlockKind = (kind) => kind === "Component" || kind === "Widget";
533
919
  var isNamedBlockKind = (s) => NAMED_BLOCK_KINDS.includes(s);
534
920
 
535
921
  // src/sflLanguage/parsing/values.ts
@@ -969,14 +1355,14 @@ var DocumentParser = class {
969
1355
  if (header.value !== "sfl") {
970
1356
  throw new SflParseError(`document must start with 'sfl', got '${header.value}'`, header.line, header.col);
971
1357
  }
972
- const version = this.cursor.expect("number", "version number");
1358
+ const version2 = this.cursor.expect("number", "version number");
973
1359
  this.cursor.skipNewlines();
974
1360
  const blocks = [];
975
1361
  while (!this.cursor.at("eof")) {
976
1362
  blocks.push(this.blocks.parseBlock());
977
1363
  this.cursor.skipNewlines();
978
1364
  }
979
- return { version: version.value, blocks };
1365
+ return { version: version2.value, blocks };
980
1366
  }
981
1367
  };
982
1368
 
@@ -1287,6 +1673,11 @@ function isChartObject(canvasObject) {
1287
1673
  return canvasObject.objectType === "chart" && canvasObject.chart !== void 0;
1288
1674
  }
1289
1675
 
1676
+ // src/sflSemantic/canvasObjects/artifacts/dimension/types.ts
1677
+ function isDimensionObject(canvasObject) {
1678
+ return canvasObject.objectType === "dimension" && canvasObject.dimension !== void 0;
1679
+ }
1680
+
1290
1681
  // src/sflSemantic/canvasObjects/artifacts/isometric/types.ts
1291
1682
  function isIsometricObject(canvasObject) {
1292
1683
  return canvasObject.objectType === "isometric" && canvasObject.isometric !== void 0;
@@ -1423,7 +1814,9 @@ var CANVAS_OBJECT_BLOCK_KINDS = [
1423
1814
  "Path",
1424
1815
  "Chart",
1425
1816
  "Widget",
1426
- "Isometric"
1817
+ "Component",
1818
+ "Isometric",
1819
+ "Dimension"
1427
1820
  ];
1428
1821
  var canvasObjectBlockKinds = new Set(CANVAS_OBJECT_BLOCK_KINDS);
1429
1822
  function isCanvasObjectBlockKind(kind) {
@@ -1829,21 +2222,77 @@ function resolveChartObject(base, block2, properties, symbolDefinitions, mergedP
1829
2222
  };
1830
2223
  }
1831
2224
 
2225
+ // src/sflSemantic/canvasObjects/artifacts/dimension/reader.ts
2226
+ function readPoint(value, origin) {
2227
+ const [x, y] = tupleValues(value) ?? [];
2228
+ return { x: origin.x + (x ?? 0), y: origin.y + (y ?? 0) };
2229
+ }
2230
+ function readDimension(properties, origin) {
2231
+ return {
2232
+ start: readPoint(properties.get("start"), origin),
2233
+ end: readPoint(properties.get("end"), origin),
2234
+ offset: asNumber(properties.get("offset")) ?? 0,
2235
+ unit: asString(properties.get("unit"))
2236
+ };
2237
+ }
2238
+
2239
+ // src/sflSemantic/canvasObjects/artifacts/dimension/resolver.ts
2240
+ function resolveDimensionObject(base, properties, origin) {
2241
+ return {
2242
+ ...base,
2243
+ objectType: "dimension",
2244
+ dimension: readDimension(properties, origin)
2245
+ };
2246
+ }
2247
+
1832
2248
  // src/sflSemantic/canvasObjects/artifacts/isometric/reader.ts
1833
- function readIsometric(properties, depth) {
2249
+ function readFootprintPoint(value) {
2250
+ if (value.type !== "list" || value.values.length < 2) {
2251
+ return [];
2252
+ }
2253
+ const x = asNumber(value.values[0]);
2254
+ const y = asNumber(value.values[1]);
2255
+ const tension = value.values[2] === void 0 ? void 0 : asNumber(value.values[2]);
2256
+ if (x === void 0 || y === void 0) {
2257
+ return [];
2258
+ }
2259
+ return [tension === void 0 ? { x, y } : { x, y, tension }];
2260
+ }
2261
+ function asPolygon(points, tension) {
2262
+ const flat = flattenPath({ points, tension, closed: true });
2263
+ return flat.length >= 3 ? flat.map((point) => [point.x, point.y]) : void 0;
2264
+ }
2265
+ function readFootprint(value, symbolDefs) {
2266
+ if (value?.type === "list") {
2267
+ return asPolygon(value.values.flatMap(readFootprintPoint), 0);
2268
+ }
2269
+ const name = asString(value);
2270
+ const definition = name ? symbolDefs.get(name) : void 0;
2271
+ if (!definition) {
2272
+ return void 0;
2273
+ }
2274
+ const points = definition.points.map(([x, y], index) => {
2275
+ const tension = definition.pointTensions?.[index];
2276
+ return tension === void 0 ? { x, y } : { x, y, tension };
2277
+ });
2278
+ return asPolygon(points, definition.tension ?? 0);
2279
+ }
2280
+ function readIsometric(properties, depth, symbolDefs) {
1834
2281
  return {
1835
2282
  depth,
1836
- icon: asString(properties.get("icon"))
2283
+ icon: asString(properties.get("icon")),
2284
+ footprint: readFootprint(properties.get("symbol"), symbolDefs),
2285
+ form: asString(properties.get("shape")) === "sphere" ? "sphere" : "box"
1837
2286
  };
1838
2287
  }
1839
2288
 
1840
2289
  // src/sflSemantic/canvasObjects/artifacts/isometric/resolver.ts
1841
- function resolveIsometricObject(base, block2, properties, layoutProperty) {
2290
+ function resolveIsometricObject(base, block2, properties, layoutProperty, symbolDefinitions) {
1842
2291
  const size = tupleValues(layoutProperty(block2, "size"));
1843
2292
  return {
1844
2293
  ...base,
1845
2294
  objectType: "isometric",
1846
- isometric: readIsometric(properties, size?.[2] ?? 24)
2295
+ isometric: readIsometric(properties, size?.[2] ?? 24, symbolDefinitions)
1847
2296
  };
1848
2297
  }
1849
2298
 
@@ -1856,7 +2305,12 @@ function readPath(p, origin) {
1856
2305
  }
1857
2306
  const x = asNumber(value.values[0]);
1858
2307
  const y = asNumber(value.values[1]);
1859
- return x !== void 0 && y !== void 0 ? [{ x: origin.x + x, y: origin.y + y }] : [];
2308
+ const tension = value.values[2] === void 0 ? void 0 : asNumber(value.values[2]);
2309
+ if (x === void 0 || y === void 0) {
2310
+ return [];
2311
+ }
2312
+ const point = { x: origin.x + x, y: origin.y + y };
2313
+ return [tension === void 0 ? point : { ...point, tension }];
1860
2314
  }) : [];
1861
2315
  return {
1862
2316
  points,
@@ -1914,7 +2368,7 @@ function declaredCanvasObjectKind(block2, properties) {
1914
2368
  if (block2.kind === "Chart") {
1915
2369
  return "chart";
1916
2370
  }
1917
- if (block2.kind === "Widget") {
2371
+ if (isComponentBlockKind(block2.kind)) {
1918
2372
  return asString(properties.get("type")) ?? "widget";
1919
2373
  }
1920
2374
  if (block2.kind === "Text") {
@@ -1923,6 +2377,9 @@ function declaredCanvasObjectKind(block2, properties) {
1923
2377
  if (block2.kind === "Isometric") {
1924
2378
  return "isometric";
1925
2379
  }
2380
+ if (block2.kind === "Dimension") {
2381
+ return "dimension";
2382
+ }
1926
2383
  return asString(properties.get("kind")) ?? "";
1927
2384
  }
1928
2385
  function canvasObjectTypeForKind(kind) {
@@ -1938,12 +2395,15 @@ function canvasObjectTypeForKind(kind) {
1938
2395
  if (kind === "chart") {
1939
2396
  return "chart";
1940
2397
  }
1941
- if (kind === "rollingNumber" || kind === "tickScale" || kind === "ruler") {
1942
- return "widget";
2398
+ if (isBuiltInComponentType(kind)) {
2399
+ return "component";
1943
2400
  }
1944
2401
  if (kind === "isometric") {
1945
2402
  return "isometric";
1946
2403
  }
2404
+ if (kind === "dimension") {
2405
+ return "dimension";
2406
+ }
1947
2407
  return "shape";
1948
2408
  }
1949
2409
  function classifyCanvasObject(block2, properties, symbolDefinitions) {
@@ -1951,7 +2411,7 @@ function classifyCanvasObject(block2, properties, symbolDefinitions) {
1951
2411
  const shapeReference = asString(properties.get("shape"));
1952
2412
  const symbol = shapeReference ? symbolDefinitions.get(shapeReference) : void 0;
1953
2413
  return {
1954
- objectType: block2.kind === "Widget" ? "widget" : canvasObjectTypeForKind(kind),
2414
+ objectType: isComponentBlockKind(block2.kind) ? "component" : canvasObjectTypeForKind(kind),
1955
2415
  kind,
1956
2416
  shapeType: symbol ? "symbol" : shapeReference,
1957
2417
  symbol
@@ -2006,18 +2466,20 @@ function resolveCanvasObject(block2, origin, context, frameId, positionOverride)
2006
2466
  case "chart":
2007
2467
  return resolveChartObject(base, block2, properties, symbolDefs, mergedProps);
2008
2468
  case "isometric":
2009
- return resolveIsometricObject(base, block2, properties, layoutProp);
2469
+ return resolveIsometricObject(base, block2, properties, layoutProp, symbolDefs);
2010
2470
  case "path":
2011
2471
  return resolvePathObject(base, properties, origin);
2472
+ case "dimension":
2473
+ return resolveDimensionObject(base, properties, origin);
2012
2474
  case "swimlane":
2013
2475
  return resolveSwimlaneObject(base, properties);
2014
2476
  case "frame":
2015
2477
  return { ...base, objectType: "frame" };
2016
- case "widget":
2478
+ case "component":
2017
2479
  return {
2018
2480
  ...base,
2019
- objectType: "widget",
2020
- widget: {
2481
+ objectType: "component",
2482
+ component: {
2021
2483
  type: asString(properties.get("type")) ?? "rollingNumber",
2022
2484
  value: asString(properties.get("value")) ?? "0",
2023
2485
  digits: asNumber(properties.get("digits")),
@@ -2164,17 +2626,24 @@ function readShaderDefinition(block2) {
2164
2626
  // src/sflSemantic/definitions/symbols.ts
2165
2627
  function readSymbolPoints(block2) {
2166
2628
  const value = directProperties(block2).get("points");
2629
+ const points = [];
2630
+ const tensions = [];
2167
2631
  if (value?.type !== "list") {
2168
- return [];
2632
+ return { points, tensions };
2169
2633
  }
2170
- return value.values.flatMap((item) => {
2634
+ for (const item of value.values) {
2171
2635
  if (item.type !== "list" || item.values.length < 2) {
2172
- return [];
2636
+ continue;
2173
2637
  }
2174
2638
  const x = asNumber(item.values[0]);
2175
2639
  const y = asNumber(item.values[1]);
2176
- return x === void 0 || y === void 0 ? [] : [[x, y]];
2177
- });
2640
+ if (x === void 0 || y === void 0) {
2641
+ continue;
2642
+ }
2643
+ points.push([x, y]);
2644
+ tensions.push(item.values[2] === void 0 ? void 0 : asNumber(item.values[2]));
2645
+ }
2646
+ return { points, tensions };
2178
2647
  }
2179
2648
  function readSymbolPorts(block2) {
2180
2649
  const ports = childBlocks(block2).filter((child) => child.kind === "Port").flatMap((port) => {
@@ -2187,13 +2656,14 @@ function readSymbolPorts(block2) {
2187
2656
  return ports.length > 0 ? ports : void 0;
2188
2657
  }
2189
2658
  function readSymbolDefinition(block2) {
2190
- const points = readSymbolPoints(block2);
2659
+ const { points, tensions } = readSymbolPoints(block2);
2191
2660
  if (points.length < 2) {
2192
2661
  return void 0;
2193
2662
  }
2194
2663
  return {
2195
2664
  name: block2.name,
2196
2665
  points,
2666
+ pointTensions: tensions.some((tension) => tension !== void 0) ? tensions : void 0,
2197
2667
  tension: asNumber(directProperties(block2).get("tension")),
2198
2668
  ports: readSymbolPorts(block2)
2199
2669
  };
@@ -2450,18 +2920,18 @@ function collectUnsupportedGridShapes(doc) {
2450
2920
  return diagnostics;
2451
2921
  }
2452
2922
 
2453
- // src/sflSemantic/diagnostics/widgets.ts
2454
- function collectUnsupportedWidgetTypes(sflDocument) {
2923
+ // src/sflSemantic/diagnostics/components.ts
2924
+ function collectUnsupportedComponentTypes(sflDocument) {
2455
2925
  const diagnostics = [];
2456
2926
  const visit = (block2) => {
2457
- if (block2.kind === "Widget") {
2927
+ if (isComponentBlockKind(block2.kind)) {
2458
2928
  const type = asString(directProperties(block2).get("type")) ?? "rollingNumber";
2459
- if (type !== "rollingNumber" && type !== "tickScale" && type !== "ruler") {
2929
+ if (!isComponentType(type)) {
2460
2930
  diagnostics.push({
2461
2931
  severity: "warning",
2462
- code: "unsupported-widget-type",
2932
+ code: "unsupported-component-type",
2463
2933
  ownerId: block2.name,
2464
- message: `Unsupported widget type '${type}'. Supported: rollingNumber, tickScale, ruler.`
2934
+ message: `Unsupported component type '${type}'. Supported: ${componentTypes().join(", ")}.`
2465
2935
  });
2466
2936
  }
2467
2937
  }
@@ -2485,7 +2955,7 @@ function createCanvasResolution(doc) {
2485
2955
  ...collectUnsupportedChartTypes(doc),
2486
2956
  ...collectUnsupportedGridShapes(doc),
2487
2957
  ...collectEmptySeries(doc),
2488
- ...collectUnsupportedWidgetTypes(doc)
2958
+ ...collectUnsupportedComponentTypes(doc)
2489
2959
  ],
2490
2960
  canvasObjectResolutionContext: createCanvasObjectPropertyReaders(definitions)
2491
2961
  };
@@ -2734,43 +3204,25 @@ function freeformPathData(geometry) {
2734
3204
  if (geometry.points.length === 0) {
2735
3205
  return "";
2736
3206
  }
2737
- if (geometry.points.length < 3 || geometry.tension <= 0) {
3207
+ if (isStraight(geometry)) {
2738
3208
  return linearPathData(geometry);
2739
3209
  }
2740
- return smoothPathData(geometry);
2741
- }
2742
- function linearPathData(geometry) {
2743
- const [first, ...remaining] = geometry.points;
2744
- const segments = remaining.map((point) => `L ${point.x} ${point.y}`).join(" ");
2745
- return `M ${first.x} ${first.y} ${segments}${geometry.closed ? " Z" : ""}`;
2746
- }
2747
- function smoothPathData(geometry) {
2748
3210
  const first = geometry.points[0];
2749
- const segmentCount = geometry.closed ? geometry.points.length : geometry.points.length - 1;
2750
3211
  const commands = [`M ${first.x} ${first.y}`];
2751
- for (let index = 0; index < segmentCount; index++) {
2752
- commands.push(curveSegmentCommand(geometry, index));
3212
+ for (const { to, controls } of pathSegments(geometry)) {
3213
+ commands.push(
3214
+ controls ? `C ${controls[0].x} ${controls[0].y} ${controls[1].x} ${controls[1].y} ${to.x} ${to.y}` : `L ${to.x} ${to.y}`
3215
+ );
2753
3216
  }
2754
3217
  if (geometry.closed) {
2755
3218
  commands.push("Z");
2756
3219
  }
2757
3220
  return commands.join(" ");
2758
3221
  }
2759
- function curveSegmentCommand(geometry, index) {
2760
- const previous = freeformPointAt(geometry, index - 1);
2761
- const start = freeformPointAt(geometry, index);
2762
- const end = freeformPointAt(geometry, index + 1);
2763
- const next = freeformPointAt(geometry, index + 2);
2764
- const factor = geometry.tension / 6;
2765
- const firstControl = { x: start.x + (end.x - previous.x) * factor, y: start.y + (end.y - previous.y) * factor };
2766
- const secondControl = { x: end.x - (next.x - start.x) * factor, y: end.y - (next.y - start.y) * factor };
2767
- return `C ${firstControl.x} ${firstControl.y} ${secondControl.x} ${secondControl.y} ${end.x} ${end.y}`;
2768
- }
2769
- function freeformPointAt(geometry, index) {
2770
- if (geometry.closed) {
2771
- return geometry.points[(index + geometry.points.length) % geometry.points.length];
2772
- }
2773
- return geometry.points[Math.max(0, Math.min(geometry.points.length - 1, index))];
3222
+ function linearPathData(geometry) {
3223
+ const [first, ...remaining] = geometry.points;
3224
+ const segments = remaining.map((point) => `L ${point.x} ${point.y}`).join(" ");
3225
+ return `M ${first.x} ${first.y} ${segments}${geometry.closed ? " Z" : ""}`;
2774
3226
  }
2775
3227
 
2776
3228
  // src/renderScene/charts/primitives/radarShape.ts
@@ -3269,8 +3721,8 @@ function createRoundedCorner(previous, corner, next, maximumRadius) {
3269
3721
  const outgoing = { x: next.x - corner.x, y: next.y - corner.y };
3270
3722
  const incomingIsAxisAligned = incoming.x === 0 || incoming.y === 0;
3271
3723
  const outgoingIsAxisAligned = outgoing.x === 0 || outgoing.y === 0;
3272
- const isStraight = incoming.x === 0 && outgoing.x === 0 || incoming.y === 0 && outgoing.y === 0;
3273
- if (!incomingIsAxisAligned || !outgoingIsAxisAligned || isStraight) {
3724
+ const isStraight2 = incoming.x === 0 && outgoing.x === 0 || incoming.y === 0 && outgoing.y === 0;
3725
+ if (!incomingIsAxisAligned || !outgoingIsAxisAligned || isStraight2) {
3274
3726
  return null;
3275
3727
  }
3276
3728
  const radius = Math.min(maximumRadius, axisLength(incoming) * 0.4, axisLength(outgoing) * 0.4);
@@ -4703,6 +5155,7 @@ exports.CORNER_RADIUS_ATTR = CORNER_RADIUS_ATTR;
4703
5155
  exports.DEFAULT_FONT = DEFAULT_FONT;
4704
5156
  exports.DEFAULT_HEATMAP_ZONES = DEFAULT_HEATMAP_ZONES;
4705
5157
  exports.DEFAULT_HEX_RADIUS = DEFAULT_HEX_RADIUS;
5158
+ exports.DEFAULT_ROLLING_NUMBER_STYLE = DEFAULT_ROLLING_NUMBER_STYLE;
4706
5159
  exports.DEFAULT_ZONE_FILL = DEFAULT_ZONE_FILL;
4707
5160
  exports.DOM_CONTRACT_VERSION = DOM_CONTRACT_VERSION;
4708
5161
  exports.EMPTY_BOUNDS = EMPTY_BOUNDS;
@@ -4733,8 +5186,10 @@ exports.canonicalizeSource = canonicalizeSource;
4733
5186
  exports.categoryProp = categoryProp;
4734
5187
  exports.chartText = chartText;
4735
5188
  exports.chartTicks = chartTicks;
5189
+ exports.cleanFootprint = cleanFootprint;
4736
5190
  exports.clipSegmentToRect = clipSegmentToRect;
4737
5191
  exports.colorWithAlpha = colorWithAlpha;
5192
+ exports.componentRegistryVersion = componentRegistryVersion;
4738
5193
  exports.computeBoxplotStats = computeBoxplotStats;
4739
5194
  exports.contrastTextColor = contrastTextColor;
4740
5195
  exports.cornersRoundedRectPath = cornersRoundedRectPath;
@@ -4747,16 +5202,23 @@ exports.elementCenter = elementCenter;
4747
5202
  exports.ellipsizeToWidth = ellipsizeToWidth;
4748
5203
  exports.errorBarRange = errorBarRange;
4749
5204
  exports.estimateTextWidth = estimateTextWidth;
5205
+ exports.extrudeFootprint = extrudeFootprint;
4750
5206
  exports.finite = finite;
5207
+ exports.flattenPath = flattenPath;
4751
5208
  exports.formatBarLabel = formatBarLabel;
4752
5209
  exports.formatFieldValue = formatFieldValue;
5210
+ exports.formatRollingNumber = formatRollingNumber;
4753
5211
  exports.freeformPathData = freeformPathData;
4754
5212
  exports.gapInsetAngle = gapInsetAngle;
5213
+ exports.getComponentDescriptor = getComponentDescriptor;
4755
5214
  exports.getLineMidpoint = getLineMidpoint;
4756
5215
  exports.heuristicRichMeasure = heuristicRichMeasure;
4757
5216
  exports.horizontalRows = horizontalRows;
4758
5217
  exports.interpolateHexColorStops = interpolateHexColorStops;
5218
+ exports.isBuiltInComponentType = isBuiltInComponentType;
4759
5219
  exports.isChartObject = isChartObject;
5220
+ exports.isDimensionObject = isDimensionObject;
5221
+ exports.isGenericComponent = isGenericComponent;
4760
5222
  exports.isHorizontalBar = isHorizontalBar;
4761
5223
  exports.isIsometricObject = isIsometricObject;
4762
5224
  exports.isLightColor = isLightColor;
@@ -4775,6 +5237,8 @@ exports.maxApexCornerRadius = maxApexCornerRadius;
4775
5237
  exports.maxPieCornerRadius = maxPieCornerRadius;
4776
5238
  exports.paint = paint;
4777
5239
  exports.parseSource = parseSource;
5240
+ exports.pathBounds = pathBounds;
5241
+ exports.pathToSymbol = pathToSymbol;
4778
5242
  exports.personLabelArea = personLabelArea;
4779
5243
  exports.pieApexRadius = pieApexRadius;
4780
5244
  exports.pieArcPoint = pieArcPoint;
@@ -4790,11 +5254,13 @@ exports.radarRadiusForValue = radarRadiusForValue;
4790
5254
  exports.radarSeriesPath = radarSeriesPath;
4791
5255
  exports.radarValueAtPoint = radarValueAtPoint;
4792
5256
  exports.radarVertexPoint = radarVertexPoint;
5257
+ exports.registerComponentDescriptor = registerComponentDescriptor;
4793
5258
  exports.relativeOffsetOnRectangleSide = relativeOffsetOnRectangleSide;
4794
5259
  exports.renderPieLabels = renderPieLabels;
4795
5260
  exports.representativeColor = representativeColor;
4796
5261
  exports.resolveChartShadow = resolveChartShadow;
4797
5262
  exports.resolvePieRadii = resolvePieRadii;
5263
+ exports.resolveRollingNumberStyle = resolveRollingNumberStyle;
4798
5264
  exports.rightRoundedRectPath = rightRoundedRectPath;
4799
5265
  exports.rotatedBounds = rotatedBounds;
4800
5266
  exports.roundedBarPath = roundedBarPath;
@@ -4813,13 +5279,15 @@ exports.seriesLabelProp = seriesLabelProp;
4813
5279
  exports.seriesValueColorProp = seriesValueColorProp;
4814
5280
  exports.seriesValueProp = seriesValueProp;
4815
5281
  exports.sflToCanvasState = sflToCanvasState;
5282
+ exports.shadeFill = shadeFill;
4816
5283
  exports.stackRank = stackRank;
4817
5284
  exports.stackSequence = stackSequence;
4818
5285
  exports.stackedSegment = stackedSegment;
5286
+ exports.symbolToPath = symbolToPath;
4819
5287
  exports.tag = tag;
4820
5288
  exports.tokenizeSource = tokenizeSource;
4821
5289
  exports.topRoundedRectPath = topRoundedRectPath;
4822
5290
  exports.wrapText = wrapText;
4823
5291
  exports.zoneColorAtValue = zoneColorAtValue;
4824
- //# sourceMappingURL=chunk-CXL254BT.cjs.map
4825
- //# sourceMappingURL=chunk-CXL254BT.cjs.map
5292
+ //# sourceMappingURL=chunk-XJ4W6TW4.cjs.map
5293
+ //# sourceMappingURL=chunk-XJ4W6TW4.cjs.map