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
@@ -1,4 +1,4 @@
1
- import { isIsometricObject, sflToCanvasState, tag, EMPTY_BOUNDS, DOM_CONTRACT_VERSION, edgePointToward, elementCenter, VISIBLE_ISOMETRIC_FACES, isometricFaceCenter, finite, freeformPathData, rotatedBounds, isometricFaces, roundedPolygonPath, pointAtNormalizedPort, boxBounds, cornersRoundedRectPath, calculateLinkRoute, labelGapDash, getLineMidpoint, DEFAULT_FONT, personLabelArea, wrapText, heuristicRichMeasure, isometricBounds, deriveFaceFills, stackSequence, stackRank, topRoundedRectPath, rightRoundedRectPath, leftRoundedRectPath, bottomRoundedRectPath, isHorizontalBar, paint, CHART_TITLE_PROP, chartText, chartTicks, mapChartValue, roundedOrthogonalPathData, localShapePath, pillCornerRadius, isometricTopFaceCenter, resolveChartShadow, CHART_COLORS, angleForAxisValue, horizontalRows, rowTop, categoryProp, ISOMETRIC_SIZE_ATTR, CORNER_RADIUS_ATTR, ISOMETRIC_LABEL_OFFSET_ATTR, PATH_POINTS_ATTR, PATH_TENSION_ATTR, PATH_CLOSED_ATTR, SYMBOL_BOUNDS_ATTR, SYMBOL_POINTS_ATTR, SYMBOL_TENSION_ATTR, SQUARE_CORNER_ATTR, resolvePieRadii, radarCategoryCount, radarRadius, createPieGeometry, DEFAULT_HEX_RADIUS, DEFAULT_HEATMAP_ZONES, axisBands, DEFAULT_ZONE_FILL, representativeColor, computeBoxplotStats, barCategoryCount, ruleAtProp, ruleTextProp, seriesLabelProp, axisLabelProp, seriesColorProp, seriesValueProp, radarSeriesPath, radarRadiusForValue, createPieSlicePath, clipSegmentToRect, formatFieldValue, renderPieLabels, interpolateHexColorStops, contrastTextColor, sameHueTint, isLightColor, barShapePath, linePathData, colorWithAlpha, estimateTextWidth, segmentedBarPath, roundedBarPath, radarPointAt, gapInsetAngle, pieUsesInnerArc, maxPieCornerRadius, pieApexRadius, maxApexCornerRadius, pieArcPoint, sameHueContrastColor, zoneColorAtValue, ellipsizeToWidth, barPath, seriesValueColorProp, stackedSegment, errorBarRange, createVerticalErrorWhiskerNode, formatBarLabel, barLabelSize, CATEGORY_LABEL_ROW, BAR_LABEL, pillPath } from './chunk-BYMIYXP5.js';
1
+ import { componentRegistryVersion, isDimensionObject, isIsometricObject, sflToCanvasState, registerComponentDescriptor, isBuiltInComponentType, getComponentDescriptor, tag, EMPTY_BOUNDS, DOM_CONTRACT_VERSION, edgePointToward, elementCenter, VISIBLE_ISOMETRIC_FACES, isometricFaceCenter, finite, freeformPathData, rotatedBounds, DEFAULT_FONT, isGenericComponent, cleanFootprint, pointAtNormalizedPort, boxBounds, cornersRoundedRectPath, calculateLinkRoute, labelGapDash, getLineMidpoint, personLabelArea, wrapText, heuristicRichMeasure, shadeFill, extrudeFootprint, isometricFaces, roundedPolygonPath, stackSequence, stackRank, topRoundedRectPath, rightRoundedRectPath, leftRoundedRectPath, bottomRoundedRectPath, isHorizontalBar, paint, CHART_TITLE_PROP, chartText, chartTicks, mapChartValue, roundedOrthogonalPathData, localShapePath, pillCornerRadius, isometricBounds, AXIS_SIN, deriveFaceFills, resolveChartShadow, CHART_COLORS, angleForAxisValue, horizontalRows, rowTop, categoryProp, isometricTopFaceCenter, ISOMETRIC_SIZE_ATTR, CORNER_RADIUS_ATTR, ISOMETRIC_LABEL_OFFSET_ATTR, PATH_POINTS_ATTR, PATH_TENSION_ATTR, PATH_CLOSED_ATTR, SYMBOL_BOUNDS_ATTR, SYMBOL_POINTS_ATTR, SYMBOL_TENSION_ATTR, SQUARE_CORNER_ATTR, resolvePieRadii, radarCategoryCount, radarRadius, createPieGeometry, DEFAULT_HEX_RADIUS, DEFAULT_HEATMAP_ZONES, axisBands, DEFAULT_ZONE_FILL, representativeColor, computeBoxplotStats, barCategoryCount, ruleAtProp, ruleTextProp, seriesLabelProp, axisLabelProp, seriesColorProp, seriesValueProp, radarSeriesPath, radarRadiusForValue, createPieSlicePath, clipSegmentToRect, formatFieldValue, renderPieLabels, interpolateHexColorStops, contrastTextColor, sameHueTint, isLightColor, barShapePath, linePathData, colorWithAlpha, estimateTextWidth, segmentedBarPath, roundedBarPath, radarPointAt, gapInsetAngle, pieUsesInnerArc, maxPieCornerRadius, pieApexRadius, maxApexCornerRadius, pieArcPoint, sameHueContrastColor, zoneColorAtValue, ellipsizeToWidth, barPath, seriesValueColorProp, stackedSegment, errorBarRange, createVerticalErrorWhiskerNode, formatBarLabel, barLabelSize, CATEGORY_LABEL_ROW, BAR_LABEL, pillPath, resolveRollingNumberStyle, formatRollingNumber } from './chunk-4G2R7PEL.js';
2
2
 
3
3
  // src/renderInput/styleDecoding/colorToken.ts
4
4
  var COLOR_TOKEN_PATTERN = String.raw`rgba?\([^)]*\)|#[0-9a-fA-F]+|[a-zA-Z][\w-]*`;
@@ -124,6 +124,10 @@ function solidColor(value) {
124
124
  const decoded = decodeColor(value);
125
125
  return typeof decoded === "string" ? decoded : void 0;
126
126
  }
127
+ var CSS_COLOR = /^(?:#[0-9a-f]{3,8}|rgba?\([\d.,%\s]+\)|[a-z][\w-]*)$/i;
128
+ function cssColor(value) {
129
+ return value && CSS_COLOR.test(value) ? value : void 0;
130
+ }
127
131
  function oneOf(value, allowed, fallback) {
128
132
  return allowed.includes(value) ? value : fallback;
129
133
  }
@@ -583,6 +587,242 @@ function typedChart(base, chartType, config) {
583
587
  return { ...base, chartType, config };
584
588
  }
585
589
 
590
+ // src/renderInput/fromSfl/canvasObjects/genericComponent.ts
591
+ function numberProperty(descriptor, raw) {
592
+ const value = Number(raw);
593
+ if (raw === void 0 || raw === "" || !Number.isFinite(value)) {
594
+ return descriptor.default;
595
+ }
596
+ const atLeast = descriptor.min === void 0 ? value : Math.max(descriptor.min, value);
597
+ return descriptor.max === void 0 ? atLeast : Math.min(descriptor.max, atLeast);
598
+ }
599
+ function readProperty(descriptor, raw) {
600
+ switch (descriptor.type) {
601
+ case "number":
602
+ return numberProperty(descriptor, raw);
603
+ case "boolean":
604
+ return raw === void 0 ? descriptor.default : raw === "true";
605
+ case "color":
606
+ return cssColor(raw) ?? descriptor.default;
607
+ case "enum":
608
+ return raw !== void 0 && descriptor.options.includes(raw) ? raw : descriptor.default;
609
+ case "string":
610
+ return raw ?? descriptor.default;
611
+ }
612
+ }
613
+ function readComponentProperties(descriptor, props) {
614
+ const properties = {};
615
+ for (const [key, property] of Object.entries(descriptor?.properties ?? {})) {
616
+ properties[key] = readProperty(property, props[key]);
617
+ }
618
+ return properties;
619
+ }
620
+ function readComponentValue(descriptor, raw) {
621
+ if (!descriptor) {
622
+ return "";
623
+ }
624
+ if (descriptor.type === "boolean") {
625
+ return raw === "true";
626
+ }
627
+ if (descriptor.type === "number") {
628
+ const value = Number(raw);
629
+ return Number.isFinite(value) ? value : descriptor.default;
630
+ }
631
+ return raw;
632
+ }
633
+ function genericComponentObject(canvasObject) {
634
+ const descriptor = getComponentDescriptor(canvasObject.component.type);
635
+ return {
636
+ id: canvasObject.id,
637
+ type: canvasObject.component.type,
638
+ value: descriptor ? readComponentValue(descriptor.value, canvasObject.component.value) : canvasObject.component.value,
639
+ disabled: canvasObject.props.disabled === "true",
640
+ label: canvasObject.component.label,
641
+ x: canvasObject.x,
642
+ y: canvasObject.y,
643
+ width: canvasObject.width,
644
+ height: canvasObject.height,
645
+ rotation: canvasObject.rotation,
646
+ order: canvasObject.order,
647
+ sourceIndex: canvasObject.sourceIndex,
648
+ parentFrameId: canvasObject.parentFrameId,
649
+ properties: readComponentProperties(descriptor, canvasObject.props)
650
+ };
651
+ }
652
+
653
+ // src/renderInput/fromSfl/canvasObjects/component.ts
654
+ var CSS_FONT_FAMILY = /^[\w\s,'"-]+$/;
655
+ function fontFamily(value) {
656
+ return value && CSS_FONT_FAMILY.test(value) ? value : void 0;
657
+ }
658
+ var FONT_WEIGHT = /^(?:[1-9]00|normal|bold)$/;
659
+ function variant(value) {
660
+ return value === "plain" || value === "flip" ? value : void 0;
661
+ }
662
+ function motion(value) {
663
+ return value === "roll" || value === "fade" ? value : void 0;
664
+ }
665
+ function positiveNumber(value) {
666
+ const number = Number(value);
667
+ return value !== void 0 && Number.isFinite(number) && number > 0 ? number : void 0;
668
+ }
669
+ function fontWeight(value) {
670
+ return value && FONT_WEIGHT.test(value) ? value : void 0;
671
+ }
672
+ var TICK_SCALE_NUMBERS = [
673
+ "ticks",
674
+ "major",
675
+ "radius",
676
+ "length",
677
+ "thickness",
678
+ "round",
679
+ "start",
680
+ "sweep",
681
+ "intensity"
682
+ ];
683
+ var TICK_SCALE_COLORS = ["color", "accent"];
684
+ function tickScaleObject(canvasObject) {
685
+ const properties = canvasObject.props;
686
+ const parameters = {};
687
+ for (const key of TICK_SCALE_NUMBERS) {
688
+ const value = Number(properties[key]);
689
+ if (properties[key] !== void 0 && Number.isFinite(value)) {
690
+ parameters[key] = value;
691
+ }
692
+ }
693
+ for (const key of TICK_SCALE_COLORS) {
694
+ const value = cssColor(properties[key]);
695
+ if (value) {
696
+ parameters[key] = value;
697
+ }
698
+ }
699
+ return {
700
+ id: canvasObject.id,
701
+ type: "tickScale",
702
+ value: canvasObject.component.value,
703
+ max: canvasObject.component.max,
704
+ label: canvasObject.component.label,
705
+ x: canvasObject.x,
706
+ y: canvasObject.y,
707
+ width: canvasObject.width,
708
+ height: canvasObject.height,
709
+ rotation: canvasObject.rotation,
710
+ order: canvasObject.order,
711
+ sourceIndex: canvasObject.sourceIndex,
712
+ parentFrameId: canvasObject.parentFrameId,
713
+ parameters,
714
+ labels: properties.labels === "true" ? {
715
+ size: Number.isFinite(Number(properties.labelSize)) && properties.labelSize !== void 0 ? Number(properties.labelSize) : void 0,
716
+ color: cssColor(properties.labelColor),
717
+ offset: Number.isFinite(Number(properties.labelOffset)) && properties.labelOffset !== void 0 ? Number(properties.labelOffset) : void 0,
718
+ weight: fontWeight(properties.labelWeight),
719
+ fontFamily: fontFamily(properties.labelFont)
720
+ } : void 0
721
+ };
722
+ }
723
+ var RULER_NUMBERS = [
724
+ "ticks",
725
+ "major",
726
+ "length",
727
+ "thickness",
728
+ "round",
729
+ "dent",
730
+ "spread",
731
+ "inset",
732
+ "line",
733
+ "gap",
734
+ "intensity"
735
+ ];
736
+ var RULER_COLORS = ["color", "accent", "glow"];
737
+ var RULER_DEFAULTS = { color: "#8f95c4", accent: "#d9f270", glow: "#3ddc84" };
738
+ var RULER_OPTIONAL_COLORS = ["core", "peak"];
739
+ function rulerObject(canvasObject) {
740
+ const properties = canvasObject.props;
741
+ const parameters = {};
742
+ for (const key of RULER_NUMBERS) {
743
+ const value = Number(properties[key]);
744
+ if (properties[key] !== void 0 && Number.isFinite(value)) {
745
+ parameters[key] = value;
746
+ }
747
+ }
748
+ for (const key of RULER_COLORS) {
749
+ parameters[key] = cssColor(properties[key]) ?? RULER_DEFAULTS[key];
750
+ }
751
+ for (const key of RULER_OPTIONAL_COLORS) {
752
+ const value = cssColor(properties[key]);
753
+ if (value) {
754
+ parameters[key] = value;
755
+ }
756
+ }
757
+ parameters.axis = properties.axis === "horizontal" ? "horizontal" : "vertical";
758
+ if (properties.knob) {
759
+ parameters.knob = properties.knob;
760
+ }
761
+ return {
762
+ id: canvasObject.id,
763
+ type: "ruler",
764
+ value: canvasObject.component.value,
765
+ min: canvasObject.component.min,
766
+ max: canvasObject.component.max,
767
+ label: canvasObject.component.label,
768
+ x: canvasObject.x,
769
+ y: canvasObject.y,
770
+ width: canvasObject.width,
771
+ height: canvasObject.height,
772
+ rotation: canvasObject.rotation,
773
+ order: canvasObject.order,
774
+ sourceIndex: canvasObject.sourceIndex,
775
+ parentFrameId: canvasObject.parentFrameId,
776
+ parameters,
777
+ labels: properties.labels === "true" ? {
778
+ size: Number.isFinite(Number(properties.labelSize)) && properties.labelSize !== void 0 ? Number(properties.labelSize) : void 0,
779
+ color: cssColor(properties.labelColor),
780
+ offset: Number.isFinite(Number(properties.labelOffset)) && properties.labelOffset !== void 0 ? Number(properties.labelOffset) : void 0,
781
+ weight: fontWeight(properties.labelWeight),
782
+ fontFamily: fontFamily(properties.labelFont)
783
+ } : void 0
784
+ };
785
+ }
786
+ function rollingNumberObject(canvasObject) {
787
+ const properties = canvasObject.props;
788
+ return {
789
+ id: canvasObject.id,
790
+ type: "rollingNumber",
791
+ value: canvasObject.component.value,
792
+ digits: canvasObject.component.digits,
793
+ duration: canvasObject.component.duration,
794
+ label: canvasObject.component.label,
795
+ x: canvasObject.x,
796
+ y: canvasObject.y,
797
+ width: canvasObject.width,
798
+ height: canvasObject.height,
799
+ rotation: canvasObject.rotation,
800
+ order: canvasObject.order,
801
+ sourceIndex: canvasObject.sourceIndex,
802
+ parentFrameId: canvasObject.parentFrameId,
803
+ style: {
804
+ color: cssColor(properties.color),
805
+ surface: cssColor(properties.surface),
806
+ divider: cssColor(properties.divider),
807
+ labelColor: cssColor(properties.labelColor),
808
+ fontFamily: fontFamily(properties.fontFamily),
809
+ variant: variant(properties.variant),
810
+ motion: motion(properties.motion),
811
+ fontWeight: fontWeight(properties.fontWeight),
812
+ fontSize: positiveNumber(properties.fontSize)
813
+ }
814
+ };
815
+ }
816
+ var BUILT_IN_OBJECTS = {
817
+ rollingNumber: rollingNumberObject,
818
+ tickScale: tickScaleObject,
819
+ ruler: rulerObject
820
+ };
821
+ function componentObject(canvasObject) {
822
+ const type = canvasObject.component.type;
823
+ return isBuiltInComponentType(type) ? BUILT_IN_OBJECTS[type](canvasObject) : genericComponentObject(canvasObject);
824
+ }
825
+
586
826
  // src/renderInput/fromSfl/canvasObjects/connection.ts
587
827
  function connectionObject(c) {
588
828
  const p = c.props;
@@ -604,6 +844,26 @@ function connectionObject(c) {
604
844
  };
605
845
  }
606
846
 
847
+ // src/renderInput/fromSfl/canvasObjects/dimension.ts
848
+ function dimensionObject(canvasObject) {
849
+ const presentation = canvasObject.props;
850
+ return {
851
+ id: canvasObject.id,
852
+ start: canvasObject.dimension.start,
853
+ end: canvasObject.dimension.end,
854
+ offset: canvasObject.dimension.offset,
855
+ text: canvasObject.text,
856
+ unit: canvasObject.dimension.unit,
857
+ strokeColor: solidColor(presentation.stroke),
858
+ strokeWidth: numOf(presentation.strokeWidth),
859
+ textColor: solidColor(presentation.textColor),
860
+ fontSize: numOf(presentation.fontSize),
861
+ order: canvasObject.order,
862
+ sourceIndex: canvasObject.sourceIndex,
863
+ parentFrameId: canvasObject.parentFrameId
864
+ };
865
+ }
866
+
607
867
  // src/renderInput/fromSfl/canvasObjects/frame.ts
608
868
  function frameObject(e) {
609
869
  const p = e.props;
@@ -642,6 +902,8 @@ function isometricObject(canvasObject) {
642
902
  width: canvasObject.width,
643
903
  height: canvasObject.height,
644
904
  depth: canvasObject.isometric.depth,
905
+ footprint: canvasObject.isometric.footprint,
906
+ form: canvasObject.isometric.form,
645
907
  rotation: canvasObject.rotation,
646
908
  order: canvasObject.order,
647
909
  sourceIndex: canvasObject.sourceIndex,
@@ -650,7 +912,7 @@ function isometricObject(canvasObject) {
650
912
  fill: solidColor(presentation.fill) ?? "#f8fafc",
651
913
  strokeColor: solidColor(presentation.stroke) ?? "#111827",
652
914
  strokeWidth: numOf(presentation.strokeWidth) ?? 1,
653
- cornerRadius: numOf(presentation.cornerRadius) ?? 8,
915
+ cornerRadius: numOf(presentation.cornerRadius) ?? (canvasObject.isometric.footprint ? 0 : 8),
654
916
  hasShadow: shadowStyle?.enabled ?? false,
655
917
  shadowStyle,
656
918
  labelOffsetX: numOf(presentation.labelOffsetX) ?? 0,
@@ -790,248 +1052,75 @@ function swimlaneObject(e) {
790
1052
  };
791
1053
  }
792
1054
 
793
- // src/renderInput/fromSfl/canvasObjects/widget.ts
794
- var CSS_COLOR = /^(?:#[0-9a-f]{3,8}|rgba?\([\d.,%\s]+\)|[a-z][\w-]*)$/i;
795
- var CSS_FONT_FAMILY = /^[\w\s,'"-]+$/;
796
- function color(value) {
797
- return value && CSS_COLOR.test(value) ? value : void 0;
1055
+ // src/renderInput/fromSfl/canvasObjects/collect.ts
1056
+ var byOrder = (items) => [...items].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
1057
+ function collectCanvasObjects(state) {
1058
+ const canvasObjects = byOrder(state.canvasObjects);
1059
+ const shaders = new Map((state.shaders ?? []).map((shader) => [shader.name, shader]));
1060
+ return {
1061
+ shapes: canvasObjects.filter((canvasObject) => canvasObject.objectType === "shape").map((shape) => shapeObject(shape, shaders)),
1062
+ frames: canvasObjects.filter((canvasObject) => canvasObject.objectType === "frame").map(frameObject),
1063
+ swimlanes: canvasObjects.filter((canvasObject) => canvasObject.objectType === "swimlane").map(swimlaneObject),
1064
+ isometricObjects: canvasObjects.filter(isIsometricObject).map(isometricObject),
1065
+ paths: canvasObjects.filter((canvasObject) => canvasObject.objectType === "path").map(pathObject),
1066
+ dimensions: canvasObjects.filter(isDimensionObject).map(dimensionObject),
1067
+ charts: canvasObjects.filter((canvasObject) => canvasObject.objectType === "chart").map(chartObject),
1068
+ components: canvasObjects.filter(
1069
+ (canvasObject) => canvasObject.objectType === "component" && canvasObject.component !== void 0
1070
+ ).map(componentObject),
1071
+ links: byOrder(state.links).map(linkObject),
1072
+ connections: byOrder(state.connections).map(connectionObject)
1073
+ };
798
1074
  }
799
- function fontFamily(value) {
800
- return value && CSS_FONT_FAMILY.test(value) ? value : void 0;
1075
+
1076
+ // src/renderInput/fromSfl/endpoint.ts
1077
+ function sidePoint(canvasObject, endpoint) {
1078
+ const offset = endpoint.offset ?? 0.5;
1079
+ switch (endpoint.side) {
1080
+ case "top":
1081
+ return { x: canvasObject.x + canvasObject.width * offset, y: canvasObject.y };
1082
+ case "right":
1083
+ return { x: canvasObject.x + canvasObject.width, y: canvasObject.y + canvasObject.height * offset };
1084
+ case "bottom":
1085
+ return { x: canvasObject.x + canvasObject.width * offset, y: canvasObject.y + canvasObject.height };
1086
+ case "left":
1087
+ return { x: canvasObject.x, y: canvasObject.y + canvasObject.height * offset };
1088
+ }
801
1089
  }
802
- var FONT_WEIGHT = /^(?:[1-9]00|normal|bold)$/;
803
- function variant(value) {
804
- return value === "plain" || value === "flip" ? value : void 0;
1090
+ function namedPortPoint(canvasObject, endpoint) {
1091
+ const port = canvasObject.symbol?.ports?.find((candidate) => candidate.name === endpoint.port);
1092
+ if (!port) {
1093
+ return elementCenter(canvasObject);
1094
+ }
1095
+ return pointAtNormalizedPort(
1096
+ {
1097
+ x: canvasObject.x,
1098
+ y: canvasObject.y,
1099
+ width: canvasObject.width,
1100
+ height: canvasObject.height,
1101
+ rotation: canvasObject.rotation ?? void 0
1102
+ },
1103
+ port.at
1104
+ );
805
1105
  }
806
- function motion(value) {
807
- return value === "roll" || value === "fade" ? value : void 0;
808
- }
809
- function positiveNumber(value) {
810
- const number = Number(value);
811
- return value !== void 0 && Number.isFinite(number) && number > 0 ? number : void 0;
812
- }
813
- function fontWeight(value) {
814
- return value && FONT_WEIGHT.test(value) ? value : void 0;
815
- }
816
- var TICK_SCALE_NUMBERS = [
817
- "ticks",
818
- "major",
819
- "radius",
820
- "length",
821
- "thickness",
822
- "round",
823
- "start",
824
- "sweep",
825
- "intensity"
826
- ];
827
- var TICK_SCALE_COLORS = ["color", "accent"];
828
- function tickScaleObject(canvasObject) {
829
- const properties = canvasObject.props;
830
- const parameters = {};
831
- for (const key of TICK_SCALE_NUMBERS) {
832
- const value = Number(properties[key]);
833
- if (properties[key] !== void 0 && Number.isFinite(value)) {
834
- parameters[key] = value;
835
- }
836
- }
837
- for (const key of TICK_SCALE_COLORS) {
838
- const value = color(properties[key]);
839
- if (value) {
840
- parameters[key] = value;
841
- }
842
- }
843
- return {
844
- id: canvasObject.id,
845
- type: "tickScale",
846
- value: canvasObject.widget.value,
847
- max: canvasObject.widget.max,
848
- label: canvasObject.widget.label,
849
- x: canvasObject.x,
850
- y: canvasObject.y,
851
- width: canvasObject.width,
852
- height: canvasObject.height,
853
- rotation: canvasObject.rotation,
854
- order: canvasObject.order,
855
- sourceIndex: canvasObject.sourceIndex,
856
- parentFrameId: canvasObject.parentFrameId,
857
- parameters,
858
- labels: properties.labels === "true" ? {
859
- size: Number.isFinite(Number(properties.labelSize)) && properties.labelSize !== void 0 ? Number(properties.labelSize) : void 0,
860
- color: color(properties.labelColor),
861
- offset: Number.isFinite(Number(properties.labelOffset)) && properties.labelOffset !== void 0 ? Number(properties.labelOffset) : void 0,
862
- weight: fontWeight(properties.labelWeight),
863
- fontFamily: fontFamily(properties.labelFont)
864
- } : void 0
865
- };
866
- }
867
- var RULER_NUMBERS = [
868
- "ticks",
869
- "major",
870
- "length",
871
- "thickness",
872
- "round",
873
- "dent",
874
- "spread",
875
- "inset",
876
- "line",
877
- "gap",
878
- "intensity"
879
- ];
880
- var RULER_COLORS = ["color", "accent", "glow"];
881
- var RULER_DEFAULTS = { color: "#8f95c4", accent: "#d9f270", glow: "#3ddc84" };
882
- var RULER_OPTIONAL_COLORS = ["core", "peak"];
883
- function rulerObject(canvasObject) {
884
- const properties = canvasObject.props;
885
- const parameters = {};
886
- for (const key of RULER_NUMBERS) {
887
- const value = Number(properties[key]);
888
- if (properties[key] !== void 0 && Number.isFinite(value)) {
889
- parameters[key] = value;
890
- }
891
- }
892
- for (const key of RULER_COLORS) {
893
- parameters[key] = color(properties[key]) ?? RULER_DEFAULTS[key];
894
- }
895
- for (const key of RULER_OPTIONAL_COLORS) {
896
- const value = color(properties[key]);
897
- if (value) {
898
- parameters[key] = value;
899
- }
900
- }
901
- parameters.axis = properties.axis === "horizontal" ? "horizontal" : "vertical";
902
- if (properties.knob) {
903
- parameters.knob = properties.knob;
904
- }
905
- return {
906
- id: canvasObject.id,
907
- type: "ruler",
908
- value: canvasObject.widget.value,
909
- min: canvasObject.widget.min,
910
- max: canvasObject.widget.max,
911
- label: canvasObject.widget.label,
912
- x: canvasObject.x,
913
- y: canvasObject.y,
914
- width: canvasObject.width,
915
- height: canvasObject.height,
916
- rotation: canvasObject.rotation,
917
- order: canvasObject.order,
918
- sourceIndex: canvasObject.sourceIndex,
919
- parentFrameId: canvasObject.parentFrameId,
920
- parameters,
921
- labels: properties.labels === "true" ? {
922
- size: Number.isFinite(Number(properties.labelSize)) && properties.labelSize !== void 0 ? Number(properties.labelSize) : void 0,
923
- color: color(properties.labelColor),
924
- offset: Number.isFinite(Number(properties.labelOffset)) && properties.labelOffset !== void 0 ? Number(properties.labelOffset) : void 0,
925
- weight: fontWeight(properties.labelWeight),
926
- fontFamily: fontFamily(properties.labelFont)
927
- } : void 0
928
- };
929
- }
930
- function widgetObject(canvasObject) {
931
- if (canvasObject.widget.type === "tickScale") {
932
- return tickScaleObject(canvasObject);
933
- }
934
- if (canvasObject.widget.type === "ruler") {
935
- return rulerObject(canvasObject);
936
- }
937
- const properties = canvasObject.props;
938
- return {
939
- id: canvasObject.id,
940
- type: "rollingNumber",
941
- value: canvasObject.widget.value,
942
- digits: canvasObject.widget.digits,
943
- duration: canvasObject.widget.duration,
944
- label: canvasObject.widget.label,
945
- x: canvasObject.x,
946
- y: canvasObject.y,
947
- width: canvasObject.width,
948
- height: canvasObject.height,
949
- rotation: canvasObject.rotation,
950
- order: canvasObject.order,
951
- sourceIndex: canvasObject.sourceIndex,
952
- parentFrameId: canvasObject.parentFrameId,
953
- style: {
954
- color: color(properties.color),
955
- surface: color(properties.surface),
956
- divider: color(properties.divider),
957
- labelColor: color(properties.labelColor),
958
- fontFamily: fontFamily(properties.fontFamily),
959
- variant: variant(properties.variant),
960
- motion: motion(properties.motion),
961
- fontWeight: fontWeight(properties.fontWeight),
962
- fontSize: positiveNumber(properties.fontSize)
963
- }
964
- };
965
- }
966
-
967
- // src/renderInput/fromSfl/canvasObjects/collect.ts
968
- var byOrder = (items) => [...items].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
969
- function collectCanvasObjects(state) {
970
- const canvasObjects = byOrder(state.canvasObjects);
971
- const shaders = new Map((state.shaders ?? []).map((shader) => [shader.name, shader]));
972
- return {
973
- shapes: canvasObjects.filter((canvasObject) => canvasObject.objectType === "shape").map((shape) => shapeObject(shape, shaders)),
974
- frames: canvasObjects.filter((canvasObject) => canvasObject.objectType === "frame").map(frameObject),
975
- swimlanes: canvasObjects.filter((canvasObject) => canvasObject.objectType === "swimlane").map(swimlaneObject),
976
- isometricObjects: canvasObjects.filter(isIsometricObject).map(isometricObject),
977
- paths: canvasObjects.filter((canvasObject) => canvasObject.objectType === "path").map(pathObject),
978
- charts: canvasObjects.filter((canvasObject) => canvasObject.objectType === "chart").map(chartObject),
979
- widgets: canvasObjects.filter(
980
- (canvasObject) => canvasObject.objectType === "widget" && ["rollingNumber", "tickScale", "ruler"].includes(canvasObject.widget?.type ?? "")
981
- ).map(widgetObject),
982
- links: byOrder(state.links).map(linkObject),
983
- connections: byOrder(state.connections).map(connectionObject)
984
- };
985
- }
986
-
987
- // src/renderInput/fromSfl/endpoint.ts
988
- function sidePoint(canvasObject, endpoint) {
989
- const offset = endpoint.offset ?? 0.5;
990
- switch (endpoint.side) {
991
- case "top":
992
- return { x: canvasObject.x + canvasObject.width * offset, y: canvasObject.y };
993
- case "right":
994
- return { x: canvasObject.x + canvasObject.width, y: canvasObject.y + canvasObject.height * offset };
995
- case "bottom":
996
- return { x: canvasObject.x + canvasObject.width * offset, y: canvasObject.y + canvasObject.height };
997
- case "left":
998
- return { x: canvasObject.x, y: canvasObject.y + canvasObject.height * offset };
999
- }
1000
- }
1001
- function namedPortPoint(canvasObject, endpoint) {
1002
- const port = canvasObject.symbol?.ports?.find((candidate) => candidate.name === endpoint.port);
1003
- if (!port) {
1004
- return elementCenter(canvasObject);
1005
- }
1006
- return pointAtNormalizedPort(
1007
- {
1008
- x: canvasObject.x,
1009
- y: canvasObject.y,
1010
- width: canvasObject.width,
1011
- height: canvasObject.height,
1012
- rotation: canvasObject.rotation ?? void 0
1013
- },
1014
- port.at
1015
- );
1016
- }
1017
- function resolveLinkEndpoint(link, end, canvasObjects) {
1018
- const selected = selectLinkEndpoint(link, end);
1019
- const absolutePoint = explicitAbsolutePoint(selected.explicit);
1020
- if (absolutePoint) {
1021
- return absolutePoint;
1022
- }
1023
- const canvasObject = findPositionedCanvasObject(canvasObjects, selected.canvasObjectId);
1024
- if (!canvasObject) {
1025
- return { x: 0, y: 0 };
1026
- }
1027
- const anchoredPoint = explicitAnchorPoint(canvasObject, selected.explicit);
1028
- if (anchoredPoint) {
1029
- return anchoredPoint;
1030
- }
1031
- return automaticEndpointPoint(
1032
- canvasObject,
1033
- findPositionedCanvasObject(canvasObjects, selected.oppositeCanvasObjectId)
1034
- );
1106
+ function resolveLinkEndpoint(link, end, canvasObjects) {
1107
+ const selected = selectLinkEndpoint(link, end);
1108
+ const absolutePoint = explicitAbsolutePoint(selected.explicit);
1109
+ if (absolutePoint) {
1110
+ return absolutePoint;
1111
+ }
1112
+ const canvasObject = findPositionedCanvasObject(canvasObjects, selected.canvasObjectId);
1113
+ if (!canvasObject) {
1114
+ return { x: 0, y: 0 };
1115
+ }
1116
+ const anchoredPoint = explicitAnchorPoint(canvasObject, selected.explicit);
1117
+ if (anchoredPoint) {
1118
+ return anchoredPoint;
1119
+ }
1120
+ return automaticEndpointPoint(
1121
+ canvasObject,
1122
+ findPositionedCanvasObject(canvasObjects, selected.oppositeCanvasObjectId)
1123
+ );
1035
1124
  }
1036
1125
  function selectLinkEndpoint(link, end) {
1037
1126
  return end === "from" ? { canvasObjectId: link.fromId, oppositeCanvasObjectId: link.toId, explicit: link.fromPoint } : { canvasObjectId: link.toId, oppositeCanvasObjectId: link.fromId, explicit: link.toPoint };
@@ -1133,13 +1222,502 @@ function sflToRenderInput(sfl) {
1133
1222
  swimlanes: canvasObjects.swimlanes,
1134
1223
  isometricObjects: canvasObjects.isometricObjects,
1135
1224
  paths: canvasObjects.paths,
1225
+ dimensions: canvasObjects.dimensions,
1136
1226
  charts: canvasObjects.charts,
1137
- widgets: canvasObjects.widgets,
1227
+ components: canvasObjects.components,
1138
1228
  links: createRenderInputLinks(canvasObjects),
1139
1229
  diagnostics: state.diagnostics
1140
1230
  };
1141
1231
  }
1142
1232
 
1233
+ // src/renderScene/artifacts/component/placeholder.ts
1234
+ var STROKE = "#94a3b8";
1235
+ function buildPlaceholder(component, index) {
1236
+ const x = finite(component.x, 0);
1237
+ const y = finite(component.y, 0);
1238
+ const width = Math.max(0, finite(component.width, 120));
1239
+ const height = Math.max(0, finite(component.height, 60));
1240
+ const rotation = finite(component.rotation, 0);
1241
+ const order = 1e4 + index;
1242
+ const bounds = rotatedBounds({ x, y, width, height }, rotation, 2);
1243
+ return [
1244
+ {
1245
+ id: `widget-${component.id}`,
1246
+ type: "rect",
1247
+ order,
1248
+ bounds,
1249
+ x,
1250
+ y,
1251
+ width,
1252
+ height,
1253
+ rx: 6,
1254
+ rotation,
1255
+ style: { fill: { kind: "none" }, stroke: { kind: "solid", color: STROKE }, strokeWidth: 1, dash: [4, 3] }
1256
+ },
1257
+ {
1258
+ id: `widget-${component.id}-label`,
1259
+ type: "text",
1260
+ order: order + 0.1,
1261
+ bounds,
1262
+ x,
1263
+ y,
1264
+ width,
1265
+ height,
1266
+ lines: [component.type],
1267
+ fontFamily: DEFAULT_FONT,
1268
+ fontSize: 12,
1269
+ fontWeight: "normal",
1270
+ color: STROKE,
1271
+ align: "center",
1272
+ verticalAlign: "middle",
1273
+ lineHeight: 1.3,
1274
+ rotation
1275
+ }
1276
+ ];
1277
+ }
1278
+
1279
+ // src/renderScene/artifacts/component/builtIn.ts
1280
+ function buildRollingNumber(component, index) {
1281
+ const x = finite(component.x, 0);
1282
+ const y = finite(component.y, 0);
1283
+ const width = Math.max(0, finite(component.width, 160));
1284
+ const height = Math.max(0, finite(component.height, 90));
1285
+ const rotation = finite(component.rotation, 0);
1286
+ return [
1287
+ {
1288
+ id: `widget-${component.id}`,
1289
+ type: "rolling-number",
1290
+ order: 1e4 + index,
1291
+ bounds: rotatedBounds({ x, y, width, height }, rotation, 2),
1292
+ x,
1293
+ y,
1294
+ width,
1295
+ height,
1296
+ rotation,
1297
+ value: formatRollingNumber(component.value, component.digits),
1298
+ digits: component.digits,
1299
+ duration: Math.max(0, finite(component.duration, 420)),
1300
+ label: component.label,
1301
+ componentStyle: resolveRollingNumberStyle(component.style)
1302
+ }
1303
+ ];
1304
+ }
1305
+ function buildTickScale(component, index) {
1306
+ const x = finite(component.x, 0);
1307
+ const y = finite(component.y, 0);
1308
+ const width = Math.max(0, finite(component.width, 200));
1309
+ const height = Math.max(0, finite(component.height, 200));
1310
+ const rotation = finite(component.rotation, 0);
1311
+ const max = finite(component.max, 100) || 100;
1312
+ const progress = Math.min(1, Math.max(0, finite(Number(component.value), 0) / max));
1313
+ const nodes = [
1314
+ {
1315
+ id: `widget-${component.id}`,
1316
+ type: "shader-surface",
1317
+ order: 1e4 + index,
1318
+ bounds: rotatedBounds({ x, y, width, height }, rotation, 2),
1319
+ x,
1320
+ y,
1321
+ width,
1322
+ height,
1323
+ rotation,
1324
+ shader: { name: component.id, program: "tickScale", parameters: { ...component.parameters, progress, max } },
1325
+ mask: "ellipse"
1326
+ }
1327
+ ];
1328
+ if (component.labels) {
1329
+ nodes.push(...buildTickLabels(component, { x, y, width, height, max, order: 1e4 + index }));
1330
+ }
1331
+ return nodes;
1332
+ }
1333
+ function buildTickLabels(component, box) {
1334
+ const labels = component.labels ?? {};
1335
+ const ticks = Math.max(1, finite(Number(component.parameters.ticks), 48));
1336
+ const major = Math.max(1, finite(Number(component.parameters.major), 5));
1337
+ const start = finite(Number(component.parameters.start), 225) * Math.PI / 180;
1338
+ const sweep = finite(Number(component.parameters.sweep), 270) * Math.PI / 180;
1339
+ const radius = finite(Number(component.parameters.radius), 0.9) + finite(labels.offset, 0.08);
1340
+ const fontSize = finite(labels.size, 12);
1341
+ const centerX = box.x + box.width / 2;
1342
+ const centerY = box.y + box.height / 2;
1343
+ const count = Math.floor(ticks / major);
1344
+ const nodes = [];
1345
+ for (let step = 0; step <= count; step += 1) {
1346
+ const fraction = step * major / ticks;
1347
+ const angle = start - fraction * sweep;
1348
+ const labelX2 = centerX + Math.cos(angle) * radius * (box.width / 2);
1349
+ const labelY = centerY - Math.sin(angle) * radius * (box.height / 2);
1350
+ const labelBox = { x: labelX2 - 24, y: labelY - fontSize, width: 48, height: fontSize * 2 };
1351
+ nodes.push({
1352
+ id: `widget-${component.id}-label-${step}`,
1353
+ type: "text",
1354
+ order: box.order + 0.1,
1355
+ bounds: rotatedBounds(labelBox, 0, 2),
1356
+ ...labelBox,
1357
+ lines: [String(Math.round(box.max * fraction * 10) / 10)],
1358
+ fontFamily: labels.fontFamily || DEFAULT_FONT,
1359
+ fontSize,
1360
+ fontWeight: labels.weight ?? "normal",
1361
+ color: labels.color || "#8f95c4",
1362
+ align: "center",
1363
+ verticalAlign: "middle",
1364
+ lineHeight: 1.3
1365
+ });
1366
+ }
1367
+ return nodes;
1368
+ }
1369
+ function buildRuler(component, index) {
1370
+ const x = finite(component.x, 0);
1371
+ const y = finite(component.y, 0);
1372
+ const width = Math.max(0, finite(component.width, 120));
1373
+ const height = Math.max(0, finite(component.height, 360));
1374
+ const rotation = finite(component.rotation, 0);
1375
+ const min = finite(component.min, 0);
1376
+ const max = finite(component.max, 100);
1377
+ const progress = max === min ? 0 : Math.min(1, Math.max(0, (finite(Number(component.value), min) - min) / (max - min)));
1378
+ const nodes = [
1379
+ {
1380
+ id: `widget-${component.id}`,
1381
+ type: "shader-surface",
1382
+ order: 1e4 + index,
1383
+ bounds: rotatedBounds({ x, y, width, height }, rotation, 2),
1384
+ x,
1385
+ y,
1386
+ width,
1387
+ height,
1388
+ rotation,
1389
+ shader: { name: component.id, program: "ruler", parameters: { ...component.parameters, progress, min, max } },
1390
+ mask: "rect"
1391
+ }
1392
+ ];
1393
+ if (component.labels) {
1394
+ nodes.push(...buildRulerLabels(component, { x, y, width, height, min, max, order: 1e4 + index }));
1395
+ }
1396
+ return nodes;
1397
+ }
1398
+ function buildRulerLabels(component, box) {
1399
+ const labels = component.labels ?? {};
1400
+ const horizontal = component.parameters.axis === "horizontal";
1401
+ const ticks = Math.max(1, finite(Number(component.parameters.ticks), 50));
1402
+ const major = Math.max(1, finite(Number(component.parameters.major), 5));
1403
+ const inset = finite(Number(component.parameters.inset), 0.05) > 0 ? finite(Number(component.parameters.inset), 0.05) : 0.05;
1404
+ const line = finite(Number(component.parameters.line), 0.7) > 0 ? finite(Number(component.parameters.line), 0.7) : 0.7;
1405
+ const across = horizontal ? box.height : box.width;
1406
+ const tickLength = (finite(Number(component.parameters.length), 0.1) > 0 ? finite(Number(component.parameters.length), 0.1) : 0.1) * across * 1.9;
1407
+ const edge = line * across - 0.12 * across - tickLength - finite(labels.offset, 0.04) * across;
1408
+ const fontSize = finite(labels.size, 12);
1409
+ const count = Math.floor(ticks / major);
1410
+ const nodes = [];
1411
+ for (let step = 0; step <= count; step += 1) {
1412
+ const fraction = step * major / ticks;
1413
+ const along2 = inset + (1 - 2 * inset) * fraction;
1414
+ const labelBox = horizontal ? { x: box.x + box.width * along2 - 24, y: box.y + edge - fontSize * 2, width: 48, height: fontSize * 2 } : { x: box.x + edge - 48, y: box.y + box.height * (1 - along2) - fontSize, width: 48, height: fontSize * 2 };
1415
+ nodes.push({
1416
+ id: `widget-${component.id}-label-${step}`,
1417
+ type: "text",
1418
+ order: box.order + 0.1,
1419
+ bounds: rotatedBounds(labelBox, 0, 2),
1420
+ ...labelBox,
1421
+ lines: [String(Math.round((box.min + (box.max - box.min) * fraction) * 10) / 10)],
1422
+ fontFamily: labels.fontFamily || DEFAULT_FONT,
1423
+ fontSize,
1424
+ fontWeight: labels.weight ?? "normal",
1425
+ color: labels.color || "#8f95c4",
1426
+ align: horizontal ? "center" : "right",
1427
+ verticalAlign: "middle",
1428
+ lineHeight: 1.3
1429
+ });
1430
+ }
1431
+ return nodes;
1432
+ }
1433
+
1434
+ // src/renderScene/artifacts/component/controlParts.ts
1435
+ var DISABLED_INK = "#94a3b8";
1436
+ function controlBox(component, index, fallback) {
1437
+ return {
1438
+ x: finite(component.x, 0),
1439
+ y: finite(component.y, 0),
1440
+ width: Math.max(1, finite(component.width, fallback.width)),
1441
+ height: Math.max(1, finite(component.height, fallback.height)),
1442
+ order: 1e4 + index
1443
+ };
1444
+ }
1445
+ var textProperty = (component, key) => String(component.properties[key] ?? "");
1446
+ var numberProperty2 = (component, key) => Number(component.properties[key] ?? 0);
1447
+ var solid = (color) => ({ kind: "solid", color });
1448
+ var ink = (component, color) => component.disabled ? DISABLED_INK : color;
1449
+ function fade(component, style) {
1450
+ return component.disabled ? { ...style, opacity: 0.4 } : style;
1451
+ }
1452
+ function hitArea(component, box) {
1453
+ return {
1454
+ id: `widget-${component.id}`,
1455
+ type: "rect",
1456
+ order: box.order,
1457
+ bounds: rotatedBounds(box, 0, 0),
1458
+ x: box.x,
1459
+ y: box.y,
1460
+ width: box.width,
1461
+ height: box.height,
1462
+ style: { fill: { kind: "none" }, stroke: { kind: "none" }, pointerEvents: "all" }
1463
+ };
1464
+ }
1465
+ function labelText(component, part, area, label, order) {
1466
+ return {
1467
+ id: `widget-${component.id}-${part}`,
1468
+ type: "text",
1469
+ order,
1470
+ bounds: rotatedBounds(area, 0, 0),
1471
+ x: area.x,
1472
+ y: area.y,
1473
+ width: area.width,
1474
+ height: area.height,
1475
+ lines: [label.text],
1476
+ fontFamily: DEFAULT_FONT,
1477
+ fontSize: label.fontSize,
1478
+ fontWeight: "600",
1479
+ color: label.color,
1480
+ align: label.align,
1481
+ verticalAlign: "middle",
1482
+ lineHeight: 1.3
1483
+ };
1484
+ }
1485
+
1486
+ // src/renderScene/artifacts/component/button.ts
1487
+ function buildButton(component, index) {
1488
+ const box = controlBox(component, index, { width: 120, height: 40 });
1489
+ const nodes = [
1490
+ hitArea(component, box),
1491
+ {
1492
+ id: `widget-${component.id}-face`,
1493
+ type: "rect",
1494
+ order: box.order + 0.1,
1495
+ bounds: rotatedBounds(box, 0, 0),
1496
+ x: box.x,
1497
+ y: box.y,
1498
+ width: box.width,
1499
+ height: box.height,
1500
+ rx: Math.min(numberProperty2(component, "radius"), box.height / 2),
1501
+ style: fade(component, { fill: solid(textProperty(component, "accent")), stroke: { kind: "none" } })
1502
+ }
1503
+ ];
1504
+ if (component.label) {
1505
+ const label = {
1506
+ text: component.label,
1507
+ color: ink(component, textProperty(component, "textColor")),
1508
+ fontSize: numberProperty2(component, "fontSize"),
1509
+ align: "center"
1510
+ };
1511
+ nodes.push(labelText(component, "label", box, label, box.order + 0.2));
1512
+ }
1513
+ return nodes;
1514
+ }
1515
+
1516
+ // src/renderScene/artifacts/component/checkbox.ts
1517
+ var CORNER_RATIO = 0.22;
1518
+ var LABEL_GAP_RATIO = 0.5;
1519
+ var CHECK_MARK = [
1520
+ [0.24, 0.52],
1521
+ [0.43, 0.72],
1522
+ [0.78, 0.3]
1523
+ ];
1524
+ function checkPath(square) {
1525
+ const [first, ...rest] = CHECK_MARK.map(([u, v]) => `${square.x + u * square.width} ${square.y + v * square.width}`);
1526
+ return `M ${first} ${rest.map((point) => `L ${point}`).join(" ")}`;
1527
+ }
1528
+ function boxNode(component, box, square) {
1529
+ const on = component.value === true;
1530
+ return {
1531
+ id: `widget-${component.id}-box`,
1532
+ type: "rect",
1533
+ order: box.order + 0.1,
1534
+ bounds: rotatedBounds(square, 0, 2),
1535
+ ...square,
1536
+ rx: square.width * CORNER_RATIO,
1537
+ style: fade(component, {
1538
+ fill: on ? solid(textProperty(component, "accent")) : { kind: "none" },
1539
+ stroke: solid(on ? textProperty(component, "accent") : textProperty(component, "stroke")),
1540
+ strokeWidth: 1.5
1541
+ })
1542
+ };
1543
+ }
1544
+ function checkNode(component, box, square) {
1545
+ return {
1546
+ id: `widget-${component.id}-check`,
1547
+ type: "path",
1548
+ order: box.order + 0.2,
1549
+ bounds: rotatedBounds(square, 0, 0),
1550
+ d: checkPath(square),
1551
+ style: fade(component, {
1552
+ fill: { kind: "none" },
1553
+ stroke: solid(textProperty(component, "check")),
1554
+ strokeWidth: Math.max(1.5, square.width * 0.12),
1555
+ lineCap: "round",
1556
+ lineJoin: "round"
1557
+ })
1558
+ };
1559
+ }
1560
+ function labelNode(component, box, side, text) {
1561
+ const gap = side * LABEL_GAP_RATIO;
1562
+ const area = { x: box.x + side + gap, y: box.y, width: Math.max(0, box.width - side - gap), height: box.height };
1563
+ const label = {
1564
+ text,
1565
+ color: ink(component, textProperty(component, "textColor")),
1566
+ fontSize: numberProperty2(component, "fontSize"),
1567
+ align: "left"
1568
+ };
1569
+ return labelText(component, "label", area, label, box.order + 0.3);
1570
+ }
1571
+ function buildCheckbox(component, index) {
1572
+ const box = controlBox(component, index, { width: 160, height: 24 });
1573
+ const side = Math.min(box.height, box.width);
1574
+ const square = { x: box.x, y: box.y + (box.height - side) / 2, width: side, height: side };
1575
+ return [
1576
+ hitArea(component, box),
1577
+ boxNode(component, box, square),
1578
+ ...component.value === true ? [checkNode(component, box, square)] : [],
1579
+ ...component.label ? [labelNode(component, box, side, component.label)] : []
1580
+ ];
1581
+ }
1582
+
1583
+ // src/renderScene/artifacts/component/switch.ts
1584
+ var PADDING_RATIO = 0.12;
1585
+ function buildSwitch(component, index) {
1586
+ const box = controlBox(component, index, { width: 52, height: 30 });
1587
+ const on = component.value === true;
1588
+ const padding = box.height * PADDING_RATIO;
1589
+ const radius = box.height / 2 - padding;
1590
+ const centerX = on ? box.x + box.width - box.height / 2 : box.x + box.height / 2;
1591
+ const thumb = { x: centerX - radius, y: box.y + padding, width: radius * 2, height: radius * 2 };
1592
+ return [
1593
+ hitArea(component, box),
1594
+ {
1595
+ id: `widget-${component.id}-track`,
1596
+ type: "rect",
1597
+ order: box.order + 0.1,
1598
+ bounds: rotatedBounds(box, 0, 0),
1599
+ x: box.x,
1600
+ y: box.y,
1601
+ width: box.width,
1602
+ height: box.height,
1603
+ rx: box.height / 2,
1604
+ style: fade(component, {
1605
+ fill: solid(textProperty(component, on ? "accent" : "track")),
1606
+ stroke: { kind: "none" }
1607
+ })
1608
+ },
1609
+ {
1610
+ id: `widget-${component.id}-thumb`,
1611
+ type: "ellipse",
1612
+ order: box.order + 0.2,
1613
+ bounds: rotatedBounds(thumb, 0, 0),
1614
+ cx: centerX,
1615
+ cy: box.y + box.height / 2,
1616
+ rx: radius,
1617
+ ry: radius,
1618
+ style: fade(component, {
1619
+ fill: solid(textProperty(component, "thumb")),
1620
+ stroke: { kind: "none" },
1621
+ shadow: { color: "#000000", opacity: 0.25, blur: 2, dx: 0, dy: 1 }
1622
+ })
1623
+ }
1624
+ ];
1625
+ }
1626
+
1627
+ // src/renderScene/artifacts/component/toggleButton.ts
1628
+ function buildToggleButton(component, index) {
1629
+ const box = controlBox(component, index, { width: 120, height: 40 });
1630
+ const on = component.value === true;
1631
+ const nodes = [
1632
+ hitArea(component, box),
1633
+ {
1634
+ id: `widget-${component.id}-face`,
1635
+ type: "rect",
1636
+ order: box.order + 0.1,
1637
+ bounds: rotatedBounds(box, 0, 2),
1638
+ x: box.x,
1639
+ y: box.y,
1640
+ width: box.width,
1641
+ height: box.height,
1642
+ rx: box.height / 2,
1643
+ style: fade(component, {
1644
+ fill: on ? solid(textProperty(component, "accent")) : { kind: "none" },
1645
+ stroke: solid(on ? textProperty(component, "accent") : textProperty(component, "stroke")),
1646
+ strokeWidth: 1.5
1647
+ })
1648
+ }
1649
+ ];
1650
+ if (component.label) {
1651
+ const label = {
1652
+ text: component.label,
1653
+ color: ink(component, textProperty(component, on ? "onTextColor" : "textColor")),
1654
+ fontSize: numberProperty2(component, "fontSize"),
1655
+ align: "center"
1656
+ };
1657
+ nodes.push(labelText(component, "label", box, label, box.order + 0.2));
1658
+ }
1659
+ return nodes;
1660
+ }
1661
+
1662
+ // src/renderScene/artifacts/component/registry.ts
1663
+ var asComponentBuilder = (build) => (component, index) => build(component, index);
1664
+ var builders = /* @__PURE__ */ new Map([
1665
+ ["rollingNumber", asComponentBuilder(buildRollingNumber)],
1666
+ ["tickScale", asComponentBuilder(buildTickScale)],
1667
+ ["ruler", asComponentBuilder(buildRuler)],
1668
+ ["switch", asComponentBuilder(buildSwitch)],
1669
+ ["checkbox", asComponentBuilder(buildCheckbox)],
1670
+ ["toggleButton", asComponentBuilder(buildToggleButton)],
1671
+ ["button", asComponentBuilder(buildButton)]
1672
+ ]);
1673
+ function registerComponentBuilder(type, builder) {
1674
+ builders.set(type, builder);
1675
+ return () => {
1676
+ if (builders.get(type) === builder) {
1677
+ builders.delete(type);
1678
+ }
1679
+ };
1680
+ }
1681
+ function getComponentBuilder(type) {
1682
+ return builders.get(type);
1683
+ }
1684
+
1685
+ // src/renderScene/artifacts/component/build.ts
1686
+ function ariaOf(component) {
1687
+ const role = getComponentDescriptor(component.type)?.role;
1688
+ if (!role || !isGenericComponent(component)) {
1689
+ return void 0;
1690
+ }
1691
+ const flag = typeof component.value === "boolean" ? component.value : void 0;
1692
+ return {
1693
+ role,
1694
+ ...flag === void 0 ? {} : role === "button" ? { pressed: flag } : { checked: flag },
1695
+ ...component.disabled ? { disabled: true } : {}
1696
+ };
1697
+ }
1698
+ function labelOf(component) {
1699
+ return component.label ?? (isGenericComponent(component) ? component.id : String(component.value));
1700
+ }
1701
+ function buildComponents(components) {
1702
+ return components.flatMap((component, index) => {
1703
+ const build = getComponentBuilder(component.type) ?? buildPlaceholder;
1704
+ const nodes = tag(
1705
+ build(component, index),
1706
+ "widget",
1707
+ component.id,
1708
+ component.type,
1709
+ labelOf(component),
1710
+ component.parentFrameId
1711
+ );
1712
+ const aria = ariaOf(component);
1713
+ const primary = nodes.find((node) => node.identity?.primary);
1714
+ if (aria && primary?.identity) {
1715
+ primary.identity.aria = aria;
1716
+ }
1717
+ return nodes;
1718
+ });
1719
+ }
1720
+
1143
1721
  // src/renderScene/artifacts/container/style.ts
1144
1722
  function simpleContainerStyle(fill2, stroke, strokeWidth, dash) {
1145
1723
  return {
@@ -1504,7 +2082,130 @@ function buildContainers(input) {
1504
2082
  ];
1505
2083
  }
1506
2084
 
1507
- // src/renderScene/artifacts/isometric.ts
2085
+ // src/model/dimension/geometry.ts
2086
+ var GAP = 4;
2087
+ var OVERSHOOT = 6;
2088
+ var along = (origin, direction, distance) => ({
2089
+ x: origin.x + direction.x * distance,
2090
+ y: origin.y + direction.y * distance
2091
+ });
2092
+ function dimensionLength(dimension) {
2093
+ return Math.hypot(dimension.end.x - dimension.start.x, dimension.end.y - dimension.start.y);
2094
+ }
2095
+ function dimensionText(dimension) {
2096
+ if (dimension.text !== void 0) {
2097
+ return dimension.text;
2098
+ }
2099
+ const length = Math.round(dimensionLength(dimension) * 10) / 10;
2100
+ return `${length}${dimension.unit ? ` ${dimension.unit}` : ""}`;
2101
+ }
2102
+ function dimensionGeometry(dimension) {
2103
+ const length = dimensionLength(dimension);
2104
+ const direction = length === 0 ? { x: 1, y: 0 } : { x: (dimension.end.x - dimension.start.x) / length, y: (dimension.end.y - dimension.start.y) / length };
2105
+ const normal = { x: direction.y, y: -direction.x };
2106
+ const side = dimension.offset < 0 ? -1 : 1;
2107
+ const line = [
2108
+ along(dimension.start, normal, dimension.offset),
2109
+ along(dimension.end, normal, dimension.offset)
2110
+ ];
2111
+ const extensions = Math.abs(dimension.offset) <= GAP ? [] : [dimension.start, dimension.end].map((point) => [
2112
+ along(point, normal, GAP * side),
2113
+ along(point, normal, dimension.offset + OVERSHOOT * side)
2114
+ ]);
2115
+ const lift = ((dimension.fontSize ?? 11) * 0.75 + 2) * side;
2116
+ const middle = { x: (line[0].x + line[1].x) / 2, y: (line[0].y + line[1].y) / 2 };
2117
+ let angle = Math.atan2(direction.y, direction.x) * 180 / Math.PI;
2118
+ if (angle > 90) {
2119
+ angle -= 180;
2120
+ } else if (angle <= -90) {
2121
+ angle += 180;
2122
+ }
2123
+ return { length, line, extensions, label: { center: along(middle, normal, lift), angle } };
2124
+ }
2125
+
2126
+ // src/renderScene/artifacts/dimension.ts
2127
+ var DEFAULT_COLOR = "#475569";
2128
+ var CHAR_WIDTH = 0.6;
2129
+ var pathData = (segments) => segments.map(([from, to]) => `M ${from.x} ${from.y} L ${to.x} ${to.y}`).join(" ");
2130
+ function pathNode(dimension, name, order, segments) {
2131
+ const strokeWidth = Math.max(0, finite(dimension.strokeWidth, 1));
2132
+ const points = segments.flat();
2133
+ return {
2134
+ type: "path",
2135
+ id: `dimension-${dimension.id}-${name}`,
2136
+ order,
2137
+ bounds: {
2138
+ minX: Math.min(...points.map((point) => point.x)) - strokeWidth,
2139
+ minY: Math.min(...points.map((point) => point.y)) - strokeWidth,
2140
+ maxX: Math.max(...points.map((point) => point.x)) + strokeWidth,
2141
+ maxY: Math.max(...points.map((point) => point.y)) + strokeWidth
2142
+ },
2143
+ d: pathData(segments),
2144
+ style: {
2145
+ fill: { kind: "none" },
2146
+ stroke: { kind: "solid", color: dimension.strokeColor ?? DEFAULT_COLOR },
2147
+ strokeWidth,
2148
+ lineCap: "round"
2149
+ }
2150
+ };
2151
+ }
2152
+ function labelNode2(dimension, order, text, center, angle) {
2153
+ const fontSize = finite(dimension.fontSize, 11);
2154
+ const width = Math.max(24, text.length * fontSize * CHAR_WIDTH + 8);
2155
+ const height = fontSize * 1.3;
2156
+ return {
2157
+ type: "text",
2158
+ id: `dimension-${dimension.id}-label`,
2159
+ order,
2160
+ bounds: {
2161
+ minX: center.x - width / 2,
2162
+ minY: center.y - height / 2,
2163
+ maxX: center.x + width / 2,
2164
+ maxY: center.y + height / 2
2165
+ },
2166
+ x: center.x - width / 2,
2167
+ y: center.y - height / 2,
2168
+ width,
2169
+ height,
2170
+ lines: [text],
2171
+ fontFamily: DEFAULT_FONT,
2172
+ fontSize,
2173
+ fontWeight: "normal",
2174
+ color: dimension.textColor ?? dimension.strokeColor ?? DEFAULT_COLOR,
2175
+ align: "center",
2176
+ verticalAlign: "middle",
2177
+ lineHeight: 1.2,
2178
+ rotation: angle,
2179
+ rotationCenter: center
2180
+ };
2181
+ }
2182
+ function buildDimension(dimension, index) {
2183
+ const geometry = dimensionGeometry(dimension);
2184
+ const order = 31e3 + index;
2185
+ const line = {
2186
+ ...pathNode(dimension, "line", order + 0.1, [geometry.line]),
2187
+ markerStart: "filled_arrow",
2188
+ markerEnd: "filled_arrow"
2189
+ };
2190
+ const extensions = geometry.extensions.length > 0 ? [pathNode(dimension, "extensions", order, geometry.extensions)] : [];
2191
+ const text = dimensionText(dimension);
2192
+ return [...extensions, line, labelNode2(dimension, order + 0.2, text, geometry.label.center, geometry.label.angle)];
2193
+ }
2194
+ function buildDimensions(dimensions) {
2195
+ return dimensions.flatMap(
2196
+ (dimension, index) => tag(
2197
+ buildDimension(dimension, index),
2198
+ "dimension",
2199
+ dimension.id,
2200
+ "dimension",
2201
+ dimensionText(dimension),
2202
+ dimension.parentFrameId
2203
+ )
2204
+ );
2205
+ }
2206
+
2207
+ // src/renderScene/artifacts/isometric/context.ts
2208
+ var FILL_PROP = { prop: "style.fill", propKind: "color", propSolidOnly: true };
1508
2209
  function isometricContext(object, index) {
1509
2210
  const strokeWidth = Math.max(0, finite(object.strokeWidth, 1));
1510
2211
  const rotation = finite(object.rotation, 0);
@@ -1529,85 +2230,22 @@ function isometricContext(object, index) {
1529
2230
  lineJoin: "round"
1530
2231
  }
1531
2232
  }
1532
- };
1533
- }
1534
- function groundShadowNode(context, faces) {
1535
- const { object, index, rotation, rotationCenter } = context;
1536
- if (!object.hasShadow) {
1537
- return void 0;
1538
- }
1539
- const height = Math.max(0, object.height);
1540
- const heightFactor = 0.6 + Math.min(1, height / 150) * 0.7;
1541
- const shadowDrop = height + finite(object.shadowStyle?.distance, 0);
1542
- const contactFootprint = faces.top.map((point) => ({ x: point.x, y: point.y + shadowDrop }));
1543
- const footprintCenter = {
1544
- x: contactFootprint.reduce((sum, point) => sum + point.x, 0) / contactFootprint.length,
1545
- y: contactFootprint.reduce((sum, point) => sum + point.y, 0) / contactFootprint.length
1546
- };
1547
- const shadowSpread = 1.3;
1548
- const footprint = contactFootprint.map((point) => ({
1549
- x: footprintCenter.x + (point.x - footprintCenter.x) * shadowSpread,
1550
- y: footprintCenter.y + (point.y - footprintCenter.y) * shadowSpread
1551
- }));
1552
- const footprintXs = footprint.map((point) => point.x);
1553
- const footprintYs = footprint.map((point) => point.y);
1554
- return {
1555
- type: "path",
1556
- id: `isometric-${object.id}-ground-shadow`,
1557
- order: 14e3 + index,
1558
- bounds: {
1559
- minX: Math.min(...footprintXs),
1560
- minY: Math.min(...footprintYs),
1561
- maxX: Math.max(...footprintXs),
1562
- maxY: Math.max(...footprintYs)
1563
- },
1564
- d: roundedPolygonPath(footprint, 0),
1565
- rotation,
1566
- rotationCenter,
1567
- style: {
1568
- fill: { kind: "solid", color: object.shadowStyle?.color ?? "#000000" },
1569
- stroke: { kind: "none" },
1570
- opacity: Math.min(1, (object.shadowStyle?.opacity ?? 0.18) * heightFactor),
1571
- blur: finite(object.shadowStyle?.blur, 8),
1572
- pointerEvents: "none"
1573
- }
1574
- };
1575
- }
1576
- function faceNodes(context, faces, hullClip) {
1577
- const { object, order, common } = context;
1578
- const noStroke = { ...common.style, stroke: { kind: "none" } };
1579
- const faceFills = deriveFaceFills(object.fill ?? "#f8fafc");
1580
- const colorProp = { prop: "style.fill", propKind: "color", propSolidOnly: true };
1581
- const face = (name, offset, points, color2) => ({
1582
- ...common,
1583
- id: `isometric-${object.id}-${name}`,
1584
- order: order + offset,
1585
- d: roundedPolygonPath(points, 0),
1586
- style: { ...noStroke, fill: { kind: "solid", color: color2 }, clip: hullClip },
1587
- ...colorProp
1588
- });
1589
- return [
1590
- face("top", 0, faces.top, faceFills.topFill),
1591
- face("front", 0.1, faces.front, faceFills.frontFill),
1592
- face("side", 0.2, faces.right, faceFills.sideFill)
1593
- ];
2233
+ };
1594
2234
  }
1595
- function seamsNode(context, faces, hullClip) {
1596
- const { object, order, common, strokeWidth } = context;
2235
+ function faceNode(context, name, offset, points, style) {
1597
2236
  return {
1598
- ...common,
1599
- id: `isometric-${object.id}-seams`,
1600
- order: order + 0.22,
1601
- d: `M ${faces.top[3].x} ${faces.top[3].y} L ${faces.top[2].x} ${faces.top[2].y} L ${faces.top[1].x} ${faces.top[1].y} M ${faces.top[2].x} ${faces.top[2].y} L ${faces.front[2].x} ${faces.front[2].y}`,
1602
- style: {
1603
- ...common.style,
1604
- fill: { kind: "none" },
1605
- stroke: { kind: "solid", color: "#cbd5e1" },
1606
- strokeWidth: Math.min(strokeWidth, 1),
1607
- clip: hullClip
1608
- }
2237
+ ...context.common,
2238
+ id: `isometric-${context.object.id}-${name}`,
2239
+ order: context.order + offset,
2240
+ d: roundedPolygonPath([...points], 0),
2241
+ style,
2242
+ ...FILL_PROP
1609
2243
  };
1610
2244
  }
2245
+ function silhouette(object) {
2246
+ const faces = isometricFaces(object);
2247
+ return [faces.top[0], faces.top[1], faces.right[2], faces.front[2], faces.front[3], faces.top[3]];
2248
+ }
1611
2249
  function hullNode(context, hullPath, cornerRadius) {
1612
2250
  const { object, order, common, box } = context;
1613
2251
  return {
@@ -1628,6 +2266,14 @@ function hullNode(context, hullPath, cornerRadius) {
1628
2266
  style: { ...common.style, fill: { kind: "none" } }
1629
2267
  };
1630
2268
  }
2269
+ function unseenHullNode(context) {
2270
+ return {
2271
+ ...hullNode(context, roundedPolygonPath(silhouette(context.object), 0), 0),
2272
+ style: { ...context.common.style, fill: { kind: "none" }, stroke: { kind: "none" } }
2273
+ };
2274
+ }
2275
+
2276
+ // src/renderScene/artifacts/isometric/label.ts
1631
2277
  var LABEL_HEIGHT = 20;
1632
2278
  var LABEL_GAP = 12;
1633
2279
  var LABEL_PADDING_X = 6;
@@ -1723,20 +2369,232 @@ function labelNodes(context, text) {
1723
2369
  }
1724
2370
  return [guide, labelBackgroundNode(context, placement, text, background), label];
1725
2371
  }
1726
- function buildIsometricObject(object, index) {
2372
+
2373
+ // src/renderScene/artifacts/isometric/shadow.ts
2374
+ function groundShadowNode(context, topOutline) {
2375
+ const { object, index, rotation, rotationCenter } = context;
2376
+ if (!object.hasShadow) {
2377
+ return void 0;
2378
+ }
2379
+ const height = Math.max(0, object.height);
2380
+ const heightFactor = 0.6 + Math.min(1, height / 150) * 0.7;
2381
+ const shadowDrop = height + finite(object.shadowStyle?.distance, 0);
2382
+ const contactFootprint = topOutline.map((point) => ({ x: point.x, y: point.y + shadowDrop }));
2383
+ const footprintCenter = {
2384
+ x: contactFootprint.reduce((sum, point) => sum + point.x, 0) / contactFootprint.length,
2385
+ y: contactFootprint.reduce((sum, point) => sum + point.y, 0) / contactFootprint.length
2386
+ };
2387
+ const shadowSpread = 1.3;
2388
+ const footprint = contactFootprint.map((point) => ({
2389
+ x: footprintCenter.x + (point.x - footprintCenter.x) * shadowSpread,
2390
+ y: footprintCenter.y + (point.y - footprintCenter.y) * shadowSpread
2391
+ }));
2392
+ const footprintXs = footprint.map((point) => point.x);
2393
+ const footprintYs = footprint.map((point) => point.y);
2394
+ return {
2395
+ type: "path",
2396
+ id: `isometric-${object.id}-ground-shadow`,
2397
+ order: 14e3 + index,
2398
+ bounds: {
2399
+ minX: Math.min(...footprintXs),
2400
+ minY: Math.min(...footprintYs),
2401
+ maxX: Math.max(...footprintXs),
2402
+ maxY: Math.max(...footprintYs)
2403
+ },
2404
+ d: roundedPolygonPath(footprint, 0),
2405
+ rotation,
2406
+ rotationCenter,
2407
+ style: {
2408
+ fill: { kind: "solid", color: object.shadowStyle?.color ?? "#000000" },
2409
+ stroke: { kind: "none" },
2410
+ opacity: Math.min(1, (object.shadowStyle?.opacity ?? 0.18) * heightFactor),
2411
+ blur: finite(object.shadowStyle?.blur, 8),
2412
+ pointerEvents: "none"
2413
+ }
2414
+ };
2415
+ }
2416
+ function sphereShadowNode(context, radius) {
2417
+ const { object, index, box } = context;
2418
+ if (!object.hasShadow) {
2419
+ return void 0;
2420
+ }
2421
+ const width = Math.max(0, object.width);
2422
+ const depth = Math.max(0, object.depth);
2423
+ const center = {
2424
+ x: box.x + box.width / 2,
2425
+ y: object.y + Math.max(0, object.height) + (width + depth) * AXIS_SIN / 2
2426
+ };
2427
+ return {
2428
+ type: "ellipse",
2429
+ id: `isometric-${object.id}-ground-shadow`,
2430
+ order: 14e3 + index,
2431
+ bounds: {
2432
+ minX: center.x - radius * 1.1,
2433
+ minY: center.y - radius * 0.6,
2434
+ maxX: center.x + radius * 1.1,
2435
+ maxY: center.y + radius * 0.6
2436
+ },
2437
+ cx: center.x,
2438
+ cy: center.y,
2439
+ rx: radius * 1.05,
2440
+ ry: radius * 0.52,
2441
+ style: {
2442
+ fill: { kind: "solid", color: object.shadowStyle?.color ?? "#000000" },
2443
+ stroke: { kind: "none" },
2444
+ opacity: object.shadowStyle?.opacity ?? 0.2,
2445
+ blur: finite(object.shadowStyle?.blur, 8),
2446
+ pointerEvents: "none"
2447
+ }
2448
+ };
2449
+ }
2450
+
2451
+ // src/renderScene/artifacts/isometric/box.ts
2452
+ function faceNodes(context, faces, hullClip) {
2453
+ const { object, common } = context;
2454
+ const noStroke = { ...common.style, stroke: { kind: "none" } };
2455
+ const fills = deriveFaceFills(object.fill ?? "#f8fafc");
2456
+ const face = (name, offset, points, color) => faceNode(context, name, offset, points, { ...noStroke, fill: { kind: "solid", color }, clip: hullClip });
2457
+ return [
2458
+ face("top", 0, faces.top, fills.topFill),
2459
+ face("front", 0.1, faces.front, fills.frontFill),
2460
+ face("side", 0.2, faces.right, fills.sideFill)
2461
+ ];
2462
+ }
2463
+ function seamsNode(context, faces, hullClip) {
2464
+ const { object, order, common, strokeWidth } = context;
2465
+ return {
2466
+ ...common,
2467
+ id: `isometric-${object.id}-seams`,
2468
+ order: order + 0.22,
2469
+ d: `M ${faces.top[3].x} ${faces.top[3].y} L ${faces.top[2].x} ${faces.top[2].y} L ${faces.top[1].x} ${faces.top[1].y} M ${faces.top[2].x} ${faces.top[2].y} L ${faces.front[2].x} ${faces.front[2].y}`,
2470
+ style: {
2471
+ ...common.style,
2472
+ fill: { kind: "none" },
2473
+ stroke: { kind: "solid", color: "#cbd5e1" },
2474
+ strokeWidth: Math.min(strokeWidth, 1),
2475
+ clip: hullClip
2476
+ }
2477
+ };
2478
+ }
2479
+ function buildBox(object, index) {
1727
2480
  const context = isometricContext(object, index);
1728
2481
  const faces = isometricFaces(object);
1729
2482
  const cornerRadius = Math.max(0, finite(object.cornerRadius, 8));
1730
- const silhouette = [faces.top[0], faces.top[1], faces.right[2], faces.front[2], faces.front[3], faces.top[3]];
1731
- const hullPath = roundedPolygonPath(silhouette, cornerRadius);
2483
+ const hullPath = roundedPolygonPath(silhouette(object), cornerRadius);
1732
2484
  const hullClip = { type: "path", d: hullPath };
1733
- const groundShadow = groundShadowNode(context, faces);
2485
+ const groundShadow = groundShadowNode(context, faces.top);
1734
2486
  const seams = seamsNode(context, faces, hullClip);
1735
2487
  const hull = hullNode(context, hullPath, cornerRadius);
1736
2488
  const facesNodes = faceNodes(context, faces, hullClip);
1737
2489
  const objectNodes = groundShadow ? [hull, ...facesNodes, groundShadow, seams] : [hull, ...facesNodes, seams];
1738
2490
  return object.text ? [...objectNodes, ...labelNodes(context, object.text)] : objectNodes;
1739
2491
  }
2492
+
2493
+ // src/renderScene/artifacts/isometric/extruded.ts
2494
+ function wallNode(context, side, index, fill2) {
2495
+ const color = shadeFill(fill2, side.light);
2496
+ return faceNode(context, `side-${index}`, 0.05 + index * 1e-3, side.points, {
2497
+ ...context.common.style,
2498
+ stroke: { kind: "solid", color },
2499
+ strokeWidth: 0.6,
2500
+ fill: { kind: "solid", color }
2501
+ });
2502
+ }
2503
+ function wallEdgesNode(context, side, index) {
2504
+ const [topFrom, topTo, bottomTo, bottomFrom] = side.points;
2505
+ const lines = [
2506
+ `M ${bottomFrom.x} ${bottomFrom.y} L ${bottomTo.x} ${bottomTo.y}`,
2507
+ ...side.smoothStart ? [] : [`M ${topFrom.x} ${topFrom.y} L ${bottomFrom.x} ${bottomFrom.y}`],
2508
+ ...side.smoothEnd ? [] : [`M ${topTo.x} ${topTo.y} L ${bottomTo.x} ${bottomTo.y}`]
2509
+ ];
2510
+ return {
2511
+ ...context.common,
2512
+ id: `isometric-${context.object.id}-side-${index}-edges`,
2513
+ order: context.order + 0.0505 + index * 1e-3,
2514
+ d: lines.join(" "),
2515
+ style: { ...context.common.style, fill: { kind: "none" } }
2516
+ };
2517
+ }
2518
+ function buildExtruded(object, index, footprint) {
2519
+ const context = isometricContext(object, index);
2520
+ const { top, sides } = extrudeFootprint(object, footprint, Math.max(0, finite(object.cornerRadius, 0)));
2521
+ const fill2 = object.fill ?? "#f8fafc";
2522
+ const groundShadow = groundShadowNode(context, top);
2523
+ const topFace = faceNode(context, "top", 0.2, top, { ...context.common.style, fill: { kind: "solid", color: fill2 } });
2524
+ const nodes = [
2525
+ unseenHullNode(context),
2526
+ ...groundShadow ? [groundShadow] : [],
2527
+ ...sides.flatMap((side, i) => [wallNode(context, side, i, fill2), wallEdgesNode(context, side, i)]),
2528
+ topFace
2529
+ ];
2530
+ return object.text ? [...nodes, ...labelNodes(context, object.text)] : nodes;
2531
+ }
2532
+
2533
+ // src/renderScene/artifacts/isometric/sphere.ts
2534
+ function buildSphere(object, index) {
2535
+ const context = isometricContext(object, index);
2536
+ const { order, common, box } = context;
2537
+ const radius = Math.max(0, Math.min(object.width, object.height, object.depth)) / 2;
2538
+ const cx = box.x + box.width / 2;
2539
+ const cy = box.y + box.height / 2;
2540
+ const fill2 = object.fill ?? "#f8fafc";
2541
+ const bounds = { minX: cx - radius, minY: cy - radius, maxX: cx + radius, maxY: cy + radius };
2542
+ const body = {
2543
+ type: "ellipse",
2544
+ id: `isometric-${object.id}-sphere`,
2545
+ order: order + 0.1,
2546
+ bounds,
2547
+ cx,
2548
+ cy,
2549
+ rx: radius,
2550
+ ry: radius,
2551
+ style: {
2552
+ ...common.style,
2553
+ fill: {
2554
+ kind: "linear-gradient",
2555
+ angle: 135,
2556
+ stops: [
2557
+ { offset: 0, color: shadeFill(fill2, 1.22) },
2558
+ { offset: 0.5, color: fill2 },
2559
+ { offset: 1, color: shadeFill(fill2, 0.82) }
2560
+ ]
2561
+ }
2562
+ },
2563
+ prop: "style.fill",
2564
+ propKind: "color",
2565
+ propSolidOnly: true
2566
+ };
2567
+ const highlight = {
2568
+ type: "ellipse",
2569
+ id: `isometric-${object.id}-highlight`,
2570
+ order: order + 0.2,
2571
+ bounds,
2572
+ cx: cx - radius * 0.32,
2573
+ cy: cy - radius * 0.38,
2574
+ rx: radius * 0.26,
2575
+ ry: radius * 0.18,
2576
+ rotation: -35,
2577
+ style: {
2578
+ fill: { kind: "solid", color: "#ffffff" },
2579
+ stroke: { kind: "none" },
2580
+ opacity: 0.45,
2581
+ blur: radius * 0.1,
2582
+ pointerEvents: "none"
2583
+ }
2584
+ };
2585
+ const shadow = sphereShadowNode(context, radius);
2586
+ const nodes = [unseenHullNode(context), ...shadow ? [shadow] : [], body, highlight];
2587
+ return object.text ? [...nodes, ...labelNodes(context, object.text)] : nodes;
2588
+ }
2589
+
2590
+ // src/renderScene/artifacts/isometric/index.ts
2591
+ function buildIsometricObject(object, index) {
2592
+ if (object.form === "sphere") {
2593
+ return buildSphere(object, index);
2594
+ }
2595
+ const footprint = cleanFootprint(object.footprint);
2596
+ return footprint.length > 0 ? buildExtruded(object, index, footprint) : buildBox(object, index);
2597
+ }
1740
2598
  function buildIsometricObjects(objects) {
1741
2599
  return objects.flatMap(
1742
2600
  (object, index) => tag(
@@ -1872,13 +2730,13 @@ function labelLayout(link, measureText) {
1872
2730
  const lines = visible ? wrapText(link.text ?? "", width, fontSize, metrics) : [];
1873
2731
  return { visible, fontSize, width, height: lines.length * fontSize * 1.4, lines };
1874
2732
  }
1875
- function linkStyle(item, strokeWidth, color2, dash) {
2733
+ function linkStyle(item, strokeWidth, color, dash) {
1876
2734
  const link = item.link;
1877
2735
  const stroke = typeof link.style?.color === "object" && link.style.color.type === "gradient" ? {
1878
2736
  kind: "linear-gradient",
1879
2737
  angle: 0,
1880
2738
  stops: link.style.color.stops.map((stop) => ({ offset: stop.position, color: stop.color }))
1881
- } : { kind: "solid", color: color2 };
2739
+ } : { kind: "solid", color };
1882
2740
  return {
1883
2741
  fill: { kind: "none" },
1884
2742
  stroke,
@@ -1895,7 +2753,7 @@ function createLinkRenderContext(item, index, measureText) {
1895
2753
  const pathType = link.style?.pathType ?? "orthogonal";
1896
2754
  const { points, segments } = calculateLinkRoute(link, from, to, pathType);
1897
2755
  const strokeWidth = finite(link.style?.strokeWidth, 2);
1898
- const color2 = getLinkStrokeColor(link.style?.color) || "#64748b";
2756
+ const color = getLinkStrokeColor(link.style?.color) || "#64748b";
1899
2757
  const label = labelLayout(link, measureText);
1900
2758
  const contentDash = getDashArray(strokeWidth, link.style?.strokeStyle ?? "solid");
1901
2759
  const gap = label.visible && !contentDash ? labelGapDash(points, pathType, label.width, label.height) : null;
@@ -1908,9 +2766,9 @@ function createLinkRenderContext(item, index, measureText) {
1908
2766
  midpoint: getLineMidpoint(points, pathType, from, to),
1909
2767
  strokeWidth,
1910
2768
  bounds: linkBounds(points, strokeWidth + 14),
1911
- color: color2,
2769
+ color,
1912
2770
  order: 2e4 + index,
1913
- style: linkStyle(item, strokeWidth, color2, dash),
2771
+ style: linkStyle(item, strokeWidth, color, dash),
1914
2772
  label,
1915
2773
  hasLabelGap: Boolean(gap)
1916
2774
  };
@@ -1943,7 +2801,7 @@ function polylinePathData(points) {
1943
2801
  }
1944
2802
  return path;
1945
2803
  }
1946
- function pathData(points, pathType, segments, strokeWidth) {
2804
+ function pathData2(points, pathType, segments, strokeWidth) {
1947
2805
  if (points.length < 4) {
1948
2806
  return "";
1949
2807
  }
@@ -1977,7 +2835,7 @@ function renderLinkPath(context) {
1977
2835
  id: `link-${link.id}`,
1978
2836
  order: context.order,
1979
2837
  bounds: context.bounds,
1980
- d: pathData(context.points, context.pathType, context.segments, context.strokeWidth),
2838
+ d: pathData2(context.points, context.pathType, context.segments, context.strokeWidth),
1981
2839
  style: context.style,
1982
2840
  markerStart: markerForEnd(link, "start"),
1983
2841
  markerEnd: markerForEnd(link, "end"),
@@ -2510,211 +3368,6 @@ function buildShapes(shapes, diagnostics, measureText) {
2510
3368
  );
2511
3369
  }
2512
3370
 
2513
- // src/model/widget/format.ts
2514
- function formatRollingNumber(value, digits) {
2515
- const text = String(value);
2516
- if (digits === void 0) {
2517
- return text;
2518
- }
2519
- if (!Number.isInteger(digits) || digits < 1) {
2520
- return text;
2521
- }
2522
- return text.padStart(digits, "0");
2523
- }
2524
-
2525
- // src/model/widget/theme.ts
2526
- var DEFAULT_ROLLING_NUMBER_STYLE = {
2527
- color: "#000000",
2528
- surface: "rgba(255, 255, 255, 0.28)",
2529
- divider: "rgba(0, 0, 0, 0.2)",
2530
- labelColor: "rgba(0, 0, 0, 0.62)",
2531
- fontFamily: "'Roboto Mono', 'SFMono-Regular', Consolas, monospace",
2532
- variant: "flip",
2533
- motion: "roll",
2534
- fontWeight: "300",
2535
- fontSize: 0
2536
- };
2537
- function resolveRollingNumberStyle(style) {
2538
- return {
2539
- color: style.color ?? DEFAULT_ROLLING_NUMBER_STYLE.color,
2540
- surface: style.surface ?? DEFAULT_ROLLING_NUMBER_STYLE.surface,
2541
- divider: style.divider ?? DEFAULT_ROLLING_NUMBER_STYLE.divider,
2542
- labelColor: style.labelColor ?? DEFAULT_ROLLING_NUMBER_STYLE.labelColor,
2543
- fontFamily: style.fontFamily ?? DEFAULT_ROLLING_NUMBER_STYLE.fontFamily,
2544
- variant: style.variant ?? DEFAULT_ROLLING_NUMBER_STYLE.variant,
2545
- motion: style.motion ?? DEFAULT_ROLLING_NUMBER_STYLE.motion,
2546
- fontWeight: style.fontWeight ?? DEFAULT_ROLLING_NUMBER_STYLE.fontWeight,
2547
- fontSize: style.fontSize ?? DEFAULT_ROLLING_NUMBER_STYLE.fontSize
2548
- };
2549
- }
2550
-
2551
- // src/renderScene/artifacts/widget.ts
2552
- function buildRollingNumber(widget, index) {
2553
- const x = finite(widget.x, 0);
2554
- const y = finite(widget.y, 0);
2555
- const width = Math.max(0, finite(widget.width, 160));
2556
- const height = Math.max(0, finite(widget.height, 90));
2557
- const rotation = finite(widget.rotation, 0);
2558
- return [
2559
- {
2560
- id: `widget-${widget.id}`,
2561
- type: "rolling-number",
2562
- order: 1e4 + index,
2563
- bounds: rotatedBounds({ x, y, width, height }, rotation, 2),
2564
- x,
2565
- y,
2566
- width,
2567
- height,
2568
- rotation,
2569
- value: formatRollingNumber(widget.value, widget.digits),
2570
- digits: widget.digits,
2571
- duration: Math.max(0, finite(widget.duration, 420)),
2572
- label: widget.label,
2573
- widgetStyle: resolveRollingNumberStyle(widget.style)
2574
- }
2575
- ];
2576
- }
2577
- function buildTickScale(widget, index) {
2578
- const x = finite(widget.x, 0);
2579
- const y = finite(widget.y, 0);
2580
- const width = Math.max(0, finite(widget.width, 200));
2581
- const height = Math.max(0, finite(widget.height, 200));
2582
- const rotation = finite(widget.rotation, 0);
2583
- const max = finite(widget.max, 100) || 100;
2584
- const progress = Math.min(1, Math.max(0, finite(Number(widget.value), 0) / max));
2585
- const nodes = [
2586
- {
2587
- id: `widget-${widget.id}`,
2588
- type: "shader-surface",
2589
- order: 1e4 + index,
2590
- bounds: rotatedBounds({ x, y, width, height }, rotation, 2),
2591
- x,
2592
- y,
2593
- width,
2594
- height,
2595
- rotation,
2596
- shader: { name: widget.id, program: "tickScale", parameters: { ...widget.parameters, progress, max } },
2597
- mask: "ellipse"
2598
- }
2599
- ];
2600
- if (widget.labels) {
2601
- nodes.push(...buildTickLabels(widget, { x, y, width, height, max, order: 1e4 + index }));
2602
- }
2603
- return nodes;
2604
- }
2605
- function buildTickLabels(widget, box) {
2606
- const labels = widget.labels ?? {};
2607
- const ticks = Math.max(1, finite(Number(widget.parameters.ticks), 48));
2608
- const major = Math.max(1, finite(Number(widget.parameters.major), 5));
2609
- const start = finite(Number(widget.parameters.start), 225) * Math.PI / 180;
2610
- const sweep = finite(Number(widget.parameters.sweep), 270) * Math.PI / 180;
2611
- const radius = finite(Number(widget.parameters.radius), 0.9) + finite(labels.offset, 0.08);
2612
- const fontSize = finite(labels.size, 12);
2613
- const centerX = box.x + box.width / 2;
2614
- const centerY = box.y + box.height / 2;
2615
- const count = Math.floor(ticks / major);
2616
- const nodes = [];
2617
- for (let step = 0; step <= count; step += 1) {
2618
- const fraction = step * major / ticks;
2619
- const angle = start - fraction * sweep;
2620
- const labelX2 = centerX + Math.cos(angle) * radius * (box.width / 2);
2621
- const labelY = centerY - Math.sin(angle) * radius * (box.height / 2);
2622
- const labelBox = { x: labelX2 - 24, y: labelY - fontSize, width: 48, height: fontSize * 2 };
2623
- nodes.push({
2624
- id: `widget-${widget.id}-label-${step}`,
2625
- type: "text",
2626
- order: box.order + 0.1,
2627
- bounds: rotatedBounds(labelBox, 0, 2),
2628
- ...labelBox,
2629
- lines: [String(Math.round(box.max * fraction * 10) / 10)],
2630
- fontFamily: labels.fontFamily || DEFAULT_FONT,
2631
- fontSize,
2632
- fontWeight: labels.weight ?? "normal",
2633
- color: labels.color || "#8f95c4",
2634
- align: "center",
2635
- verticalAlign: "middle",
2636
- lineHeight: 1.3
2637
- });
2638
- }
2639
- return nodes;
2640
- }
2641
- function buildRuler(widget, index) {
2642
- const x = finite(widget.x, 0);
2643
- const y = finite(widget.y, 0);
2644
- const width = Math.max(0, finite(widget.width, 120));
2645
- const height = Math.max(0, finite(widget.height, 360));
2646
- const rotation = finite(widget.rotation, 0);
2647
- const min = finite(widget.min, 0);
2648
- const max = finite(widget.max, 100);
2649
- const progress = max === min ? 0 : Math.min(1, Math.max(0, (finite(Number(widget.value), min) - min) / (max - min)));
2650
- const nodes = [
2651
- {
2652
- id: `widget-${widget.id}`,
2653
- type: "shader-surface",
2654
- order: 1e4 + index,
2655
- bounds: rotatedBounds({ x, y, width, height }, rotation, 2),
2656
- x,
2657
- y,
2658
- width,
2659
- height,
2660
- rotation,
2661
- shader: { name: widget.id, program: "ruler", parameters: { ...widget.parameters, progress, min, max } },
2662
- mask: "rect"
2663
- }
2664
- ];
2665
- if (widget.labels) {
2666
- nodes.push(...buildRulerLabels(widget, { x, y, width, height, min, max, order: 1e4 + index }));
2667
- }
2668
- return nodes;
2669
- }
2670
- function buildRulerLabels(widget, box) {
2671
- const labels = widget.labels ?? {};
2672
- const horizontal = widget.parameters.axis === "horizontal";
2673
- const ticks = Math.max(1, finite(Number(widget.parameters.ticks), 50));
2674
- const major = Math.max(1, finite(Number(widget.parameters.major), 5));
2675
- const inset = finite(Number(widget.parameters.inset), 0.05) > 0 ? finite(Number(widget.parameters.inset), 0.05) : 0.05;
2676
- const line = finite(Number(widget.parameters.line), 0.7) > 0 ? finite(Number(widget.parameters.line), 0.7) : 0.7;
2677
- const across = horizontal ? box.height : box.width;
2678
- const tickLength = (finite(Number(widget.parameters.length), 0.1) > 0 ? finite(Number(widget.parameters.length), 0.1) : 0.1) * across * 1.9;
2679
- const edge = line * across - 0.12 * across - tickLength - finite(labels.offset, 0.04) * across;
2680
- const fontSize = finite(labels.size, 12);
2681
- const count = Math.floor(ticks / major);
2682
- const nodes = [];
2683
- for (let step = 0; step <= count; step += 1) {
2684
- const fraction = step * major / ticks;
2685
- const along = inset + (1 - 2 * inset) * fraction;
2686
- const labelBox = horizontal ? { x: box.x + box.width * along - 24, y: box.y + edge - fontSize * 2, width: 48, height: fontSize * 2 } : { x: box.x + edge - 48, y: box.y + box.height * (1 - along) - fontSize, width: 48, height: fontSize * 2 };
2687
- nodes.push({
2688
- id: `widget-${widget.id}-label-${step}`,
2689
- type: "text",
2690
- order: box.order + 0.1,
2691
- bounds: rotatedBounds(labelBox, 0, 2),
2692
- ...labelBox,
2693
- lines: [String(Math.round((box.min + (box.max - box.min) * fraction) * 10) / 10)],
2694
- fontFamily: labels.fontFamily || DEFAULT_FONT,
2695
- fontSize,
2696
- fontWeight: labels.weight ?? "normal",
2697
- color: labels.color || "#8f95c4",
2698
- align: horizontal ? "center" : "right",
2699
- verticalAlign: "middle",
2700
- lineHeight: 1.3
2701
- });
2702
- }
2703
- return nodes;
2704
- }
2705
- function buildWidgets(widgets) {
2706
- return widgets.flatMap(
2707
- (widget, index) => tag(
2708
- widget.type === "tickScale" ? buildTickScale(widget, index) : widget.type === "ruler" ? buildRuler(widget, index) : buildRollingNumber(widget, index),
2709
- "widget",
2710
- widget.id,
2711
- widget.type,
2712
- widget.label ?? widget.value,
2713
- widget.parentFrameId
2714
- )
2715
- );
2716
- }
2717
-
2718
3371
  // src/renderScene/charts/decorations/axisLabels.ts
2719
3372
  function buildXAxisLabel(chart, layout, order) {
2720
3373
  if (!chart.axisX.label) {
@@ -2869,7 +3522,7 @@ function createLegendSwatch(render2, item) {
2869
3522
  const { chart, bounds, diagnostics } = render2;
2870
3523
  const fallback = CHART_COLORS[item.seriesIndex % CHART_COLORS.length];
2871
3524
  const solidOnly = chart.chartType === "line";
2872
- const color2 = solidOnly ? representativeColor(item.series.color, fallback) : item.series.color ?? fallback;
3525
+ const color = solidOnly ? representativeColor(item.series.color, fallback) : item.series.color ?? fallback;
2873
3526
  return {
2874
3527
  type: "rect",
2875
3528
  id: `chart-legend-swatch-${chart.id}-${item.series.id}`,
@@ -2883,7 +3536,7 @@ function createLegendSwatch(render2, item) {
2883
3536
  prop: seriesColorProp(item.series.id),
2884
3537
  propKind: "color",
2885
3538
  propSolidOnly: solidOnly,
2886
- style: { fill: paint(color2, diagnostics, chart.id) }
3539
+ style: { fill: paint(color, diagnostics, chart.id) }
2887
3540
  };
2888
3541
  }
2889
3542
  function createLegendLabel(render2, item) {
@@ -3614,7 +4267,7 @@ function createGlassBackdropNodes(context, id, d) {
3614
4267
  }
3615
4268
 
3616
4269
  // src/renderScene/charts/renderers/bar/glow.ts
3617
- function createBarGlowNode(context, id, d, color2, glow, bounds = context.bounds) {
4270
+ function createBarGlowNode(context, id, d, color, glow, bounds = context.bounds) {
3618
4271
  const { chart, diagnostics, nextOrder } = context;
3619
4272
  return {
3620
4273
  type: "path",
@@ -3623,8 +4276,8 @@ function createBarGlowNode(context, id, d, color2, glow, bounds = context.bounds
3623
4276
  bounds,
3624
4277
  d,
3625
4278
  style: {
3626
- fill: paint(color2, diagnostics, chart.id),
3627
- shadow: { color: representativeColor(color2, "#ffffff"), opacity: 0.9, blur: glow, dx: 0, dy: 0 },
4279
+ fill: paint(color, diagnostics, chart.id),
4280
+ shadow: { color: representativeColor(color, "#ffffff"), opacity: 0.9, blur: glow, dx: 0, dy: 0 },
3628
4281
  pointerEvents: "none"
3629
4282
  }
3630
4283
  };
@@ -3644,7 +4297,7 @@ function labelTop(placement, frame, height) {
3644
4297
  }
3645
4298
  return placement === "inside" ? frame.y + BAR_LABEL.gap : frame.y + frame.height / 2 - height / 2;
3646
4299
  }
3647
- function createPillNode(context, id, box, color2) {
4300
+ function createPillNode(context, id, box, color) {
3648
4301
  const { chart, bounds, diagnostics, nextOrder } = context;
3649
4302
  const config = chart.config;
3650
4303
  return {
@@ -3655,13 +4308,13 @@ function createPillNode(context, id, box, color2) {
3655
4308
  d: pillPath(box.left, box.top, box.width, box.height),
3656
4309
  style: {
3657
4310
  fill: config?.barLabelPillColor ? paint(config.barLabelPillColor, diagnostics, chart.id) : { kind: "none" },
3658
- stroke: paint(config?.barLabelBorderColor ?? color2, diagnostics, chart.id),
4311
+ stroke: paint(config?.barLabelBorderColor ?? color, diagnostics, chart.id),
3659
4312
  strokeWidth: finite(config?.barLabelBorderWidth, 1),
3660
4313
  pointerEvents: "none"
3661
4314
  }
3662
4315
  };
3663
4316
  }
3664
- function createTextNode(context, id, box, text, placement, fontSize, color2) {
4317
+ function createTextNode(context, id, box, text, placement, fontSize, color) {
3665
4318
  const { chart, bounds, nextOrder } = context;
3666
4319
  const config = chart.config;
3667
4320
  return {
@@ -3675,7 +4328,7 @@ function createTextNode(context, id, box, text, placement, fontSize, color2) {
3675
4328
  align: "center"
3676
4329
  }),
3677
4330
  mark: `bar-label|${placement}|${config?.barLabelFormat ?? ""}`,
3678
- color: color2,
4331
+ color,
3679
4332
  fontSize,
3680
4333
  fontFamily: config?.barLabelFontFamily ?? chart.fontFamily ?? "Inter, sans-serif",
3681
4334
  fontWeight: config?.barLabelFontWeight ?? "normal"
@@ -3733,12 +4386,12 @@ function createBarLabelNodes(context, target) {
3733
4386
  left: target.frame.x + target.frame.width / 2 - size.width / 2,
3734
4387
  top: labelTop(placement, target.frame, size.height)
3735
4388
  };
3736
- const color2 = config?.barLabelColor ?? chart.textColor ?? "#0f172a";
4389
+ const color = config?.barLabelColor ?? chart.textColor ?? "#0f172a";
3737
4390
  const nodes = [];
3738
4391
  if (pill) {
3739
- nodes.push(createPillNode(context, target.id, box, color2));
4392
+ nodes.push(createPillNode(context, target.id, box, color));
3740
4393
  }
3741
- nodes.push(createTextNode(context, target.id, box, text, placement, fontSize, color2));
4394
+ nodes.push(createTextNode(context, target.id, box, text, placement, fontSize, color));
3742
4395
  return nodes;
3743
4396
  }
3744
4397
 
@@ -4474,12 +5127,12 @@ function renderBoxplotSeries(context, layout, series, seriesIndex) {
4474
5127
  return [];
4475
5128
  }
4476
5129
  const geometry = createBoxplotGeometry(context, layout, seriesIndex, stats);
4477
- const color2 = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
5130
+ const color = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
4478
5131
  const mark = {
4479
5132
  id: `${context.chart.id}-${series.id}`,
4480
5133
  series,
4481
5134
  seriesIndex,
4482
- color: color2,
5135
+ color,
4483
5136
  geometry
4484
5137
  };
4485
5138
  const nodes = renderBoxAndWhiskers(context, layout, mark);
@@ -4541,9 +5194,9 @@ function customPointPosition(context, value) {
4541
5194
  };
4542
5195
  }
4543
5196
  function customSeriesStyle(context, series, seriesIndex) {
4544
- const color2 = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
5197
+ const color = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
4545
5198
  return {
4546
- fill: paint(color2, context.diagnostics, context.chart.id),
5199
+ fill: paint(color, context.diagnostics, context.chart.id),
4547
5200
  stroke: series.stroke ? { kind: "solid", color: series.stroke } : void 0,
4548
5201
  strokeWidth: series.stroke ? finite(series.strokeWidth, 1) : void 0
4549
5202
  };
@@ -4642,7 +5295,7 @@ function connectorDash(text) {
4642
5295
  const parts = (text ?? "").split(/[ ,]+/).map(Number).filter((part) => Number.isFinite(part) && part > 0);
4643
5296
  return parts.length > 0 ? parts : void 0;
4644
5297
  }
4645
- function createConnectorLine(context, index, from, to, color2) {
5298
+ function createConnectorLine(context, index, from, to, color) {
4646
5299
  const { chart } = context;
4647
5300
  return {
4648
5301
  type: "path",
@@ -4652,7 +5305,7 @@ function createConnectorLine(context, index, from, to, color2) {
4652
5305
  d: `M ${from.x} ${from.y} L ${to.x} ${to.y}`,
4653
5306
  style: {
4654
5307
  fill: { kind: "none" },
4655
- stroke: { kind: "solid", color: color2 },
5308
+ stroke: { kind: "solid", color },
4656
5309
  strokeWidth: finite(chart.config?.customConnectorWidth, 2),
4657
5310
  opacity: chart.config?.customConnectorOpacity,
4658
5311
  dash: connectorDash(chart.config?.customConnectorDash)
@@ -4956,7 +5609,7 @@ function createFieldCell(context, grid, row, column) {
4956
5609
  const { chart, plot, bounds, nextOrder } = context;
4957
5610
  const centerX = plot.x + plot.width * (column / (grid.columns - 1));
4958
5611
  const centerY = plot.y + plot.height * (row / (grid.rows - 1));
4959
- const color2 = colorAtRamp(chart.config?.scale, grid.values[row * grid.columns + column]);
5612
+ const color = colorAtRamp(chart.config?.scale, grid.values[row * grid.columns + column]);
4960
5613
  return {
4961
5614
  type: "rect",
4962
5615
  id: `chart-field-cell-${chart.id}-${row}-${column}`,
@@ -4966,7 +5619,7 @@ function createFieldCell(context, grid, row, column) {
4966
5619
  y: centerY - grid.cellHeight / 2,
4967
5620
  width: grid.cellWidth,
4968
5621
  height: grid.cellHeight,
4969
- style: { fill: { kind: "solid", color: color2 }, clip: fieldSurfaceClip(chart, plot) }
5622
+ style: { fill: { kind: "solid", color }, clip: fieldSurfaceClip(chart, plot) }
4970
5623
  };
4971
5624
  }
4972
5625
  function renderIsolines(context, grid) {
@@ -5020,14 +5673,14 @@ function createIsoline(context, grid, threshold, thresholdIndex) {
5020
5673
  function renderVectorField(context, seriesList) {
5021
5674
  const nodes = [];
5022
5675
  seriesList.forEach((series, seriesIndex) => {
5023
- const color2 = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
5676
+ const color = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
5024
5677
  series.values.forEach((vector, vectorIndex) => {
5025
- nodes.push(createVectorNode(context, series.id, vector, vectorIndex, color2));
5678
+ nodes.push(createVectorNode(context, series.id, vector, vectorIndex, color));
5026
5679
  });
5027
5680
  });
5028
5681
  return nodes;
5029
5682
  }
5030
- function createVectorNode(context, seriesId, vector, vectorIndex, color2) {
5683
+ function createVectorNode(context, seriesId, vector, vectorIndex, color) {
5031
5684
  const { chart, plot, bounds, diagnostics, nextOrder } = context;
5032
5685
  const [x, y, angle, magnitude] = vector;
5033
5686
  const startX = plot.x + mapChartValue(x, chart.axisX, plot.width);
@@ -5043,7 +5696,7 @@ function createVectorNode(context, seriesId, vector, vectorIndex, color2) {
5043
5696
  markerEnd: "filled_arrow",
5044
5697
  style: {
5045
5698
  fill: { kind: "none" },
5046
- stroke: paint(color2, diagnostics, chart.id),
5699
+ stroke: paint(color, diagnostics, chart.id),
5047
5700
  strokeWidth: 2
5048
5701
  }
5049
5702
  };
@@ -5697,11 +6350,11 @@ function renderHexbin(context) {
5697
6350
  }));
5698
6351
  const bins = computeHexBins(pixelPoints2, hexRadius);
5699
6352
  const maxCount = Math.max(1, ...bins.map((bin) => bin.count));
5700
- const color2 = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
6353
+ const color = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
5701
6354
  const ramp = config?.scale;
5702
6355
  bins.forEach((bin, i) => {
5703
6356
  const share = bin.count / maxCount;
5704
- const fill2 = ramp ? colorAtRamp(ramp, share) : color2;
6357
+ const fill2 = ramp ? colorAtRamp(ramp, share) : color;
5705
6358
  nodes.push({
5706
6359
  type: "path",
5707
6360
  id: `chart-hexbin-${chart.id}-${series.id}-${i}`,
@@ -5738,7 +6391,7 @@ function pixelPoints(context, pairs) {
5738
6391
  }
5739
6392
 
5740
6393
  // src/renderScene/charts/renderers/line/area.ts
5741
- function createLineAreaFill(context, series, points, color2, tension, areaOpacity) {
6394
+ function createLineAreaFill(context, series, points, color, tension, areaOpacity) {
5742
6395
  const { chart, plot, nextOrder } = context;
5743
6396
  const baselineY = plot.y + plot.height;
5744
6397
  const first = points[0];
@@ -5765,8 +6418,8 @@ function createLineAreaFill(context, series, points, color2, tension, areaOpacit
5765
6418
  kind: "linear-gradient",
5766
6419
  angle: 90,
5767
6420
  stops: [
5768
- { offset: 0, color: colorWithAlpha(color2, areaOpacity) },
5769
- { offset: 100, color: colorWithAlpha(color2, 0) }
6421
+ { offset: 0, color: colorWithAlpha(color, areaOpacity) },
6422
+ { offset: 100, color: colorWithAlpha(color, 0) }
5770
6423
  ]
5771
6424
  },
5772
6425
  stroke: { kind: "none" },
@@ -5816,7 +6469,7 @@ function dotNode(context, mark) {
5816
6469
  }
5817
6470
  };
5818
6471
  }
5819
- function labelNode(context, mark, value) {
6472
+ function labelNode3(context, mark, value) {
5820
6473
  const { chart, bounds, nextOrder } = context;
5821
6474
  const config = chart.config;
5822
6475
  const fontSize = Math.max(9, chart.fontSize ?? 12);
@@ -5841,7 +6494,7 @@ function labelNode(context, mark, value) {
5841
6494
  fontWeight: "bold"
5842
6495
  };
5843
6496
  }
5844
- function renderLineHighlights(context, series, color2) {
6497
+ function renderLineHighlights(context, series, color) {
5845
6498
  const { chart } = context;
5846
6499
  const config = chart.config;
5847
6500
  const wanted = config?.highlightPoints;
@@ -5862,28 +6515,28 @@ function renderLineHighlights(context, series, color2) {
5862
6515
  point,
5863
6516
  index,
5864
6517
  radius: config?.highlightSize ?? 6,
5865
- color: config?.highlightColor ?? color2
6518
+ color: config?.highlightColor ?? color
5866
6519
  };
5867
6520
  if (config?.highlightGuide) {
5868
6521
  nodes.push(guideNode(context, mark));
5869
6522
  }
5870
6523
  nodes.push(dotNode(context, mark));
5871
6524
  if (config?.highlightLabels) {
5872
- nodes.push(labelNode(context, mark, pairs[index][1]));
6525
+ nodes.push(labelNode3(context, mark, pairs[index][1]));
5873
6526
  }
5874
6527
  }
5875
6528
  return nodes;
5876
6529
  }
5877
6530
 
5878
6531
  // src/renderScene/charts/renderers/line/marks.ts
5879
- function createLinePointMarks(series, pairs, points, color2) {
6532
+ function createLinePointMarks(series, pairs, points, color) {
5880
6533
  return points.map((position, valueIndex) => ({
5881
6534
  seriesId: series.id,
5882
6535
  valueIndex,
5883
6536
  value: pairs[valueIndex][1],
5884
6537
  error: series.error?.[valueIndex],
5885
6538
  position,
5886
- color: color2
6539
+ color
5887
6540
  }));
5888
6541
  }
5889
6542
  function renderLineMarks(context, marks) {
@@ -5944,7 +6597,7 @@ function createLinePoint(context, mark) {
5944
6597
  }
5945
6598
 
5946
6599
  // src/renderScene/charts/renderers/line/path.ts
5947
- function createLinePath(context, series, points, color2, tension) {
6600
+ function createLinePath(context, series, points, color, tension) {
5948
6601
  const { chart, plot, bounds, diagnostics, nextOrder } = context;
5949
6602
  const config = chart.config;
5950
6603
  const source = series.color;
@@ -5959,12 +6612,12 @@ function createLinePath(context, series, points, color2, tension) {
5959
6612
  d: linePathData(points, tension),
5960
6613
  style: {
5961
6614
  fill: { kind: "none" },
5962
- stroke: paint(gradient ?? color2, diagnostics, chart.id),
6615
+ stroke: paint(gradient ?? color, diagnostics, chart.id),
5963
6616
  strokeWidth: series.strokeWidth ?? config?.lineWidth ?? 2,
5964
6617
  dash: series.dash,
5965
6618
  lineCap: config?.lineWidth === void 0 ? void 0 : "round",
5966
6619
  lineJoin: "round",
5967
- shadow: glow ? { color: color2, opacity: 0.9, blur: glow, dx: 0, dy: 0 } : resolveChartShadow(chart.shadowStyle)
6620
+ shadow: glow ? { color, opacity: 0.9, blur: glow, dx: 0, dy: 0 } : resolveChartShadow(chart.shadowStyle)
5968
6621
  }
5969
6622
  };
5970
6623
  }
@@ -5978,23 +6631,23 @@ function renderLineSeriesArea(context, series, seriesIndex) {
5978
6631
  if (areaOpacity === void 0 || areaOpacity <= 0) {
5979
6632
  return [];
5980
6633
  }
5981
- const color2 = seriesColor(series, seriesIndex);
6634
+ const color = seriesColor(series, seriesIndex);
5982
6635
  const tension = context.chart.config?.lineTension ?? 0;
5983
6636
  const points = pixelPoints(context, seriesValuePairs(context.chart, series));
5984
- return points.length > 1 ? [createLineAreaFill(context, series, points, color2, tension, areaOpacity)] : [];
6637
+ return points.length > 1 ? [createLineAreaFill(context, series, points, color, tension, areaOpacity)] : [];
5985
6638
  }
5986
6639
  function renderLineSeries(context, series, seriesIndex) {
5987
- const color2 = seriesColor(series, seriesIndex);
6640
+ const color = seriesColor(series, seriesIndex);
5988
6641
  const tension = context.chart.config?.lineTension ?? 0;
5989
6642
  const pairs = seriesValuePairs(context.chart, series);
5990
6643
  const points = pixelPoints(context, pairs);
5991
6644
  const nodes = [];
5992
6645
  if (points.length) {
5993
- nodes.push(createLinePath(context, series, points, color2, tension));
6646
+ nodes.push(createLinePath(context, series, points, color, tension));
5994
6647
  }
5995
- const marks = createLinePointMarks(series, pairs, points, color2);
6648
+ const marks = createLinePointMarks(series, pairs, points, color);
5996
6649
  nodes.push(...renderLineMarks(context, marks));
5997
- nodes.push(...renderLineHighlights(context, series, color2));
6650
+ nodes.push(...renderLineHighlights(context, series, color));
5998
6651
  return nodes;
5999
6652
  }
6000
6653
 
@@ -6203,13 +6856,13 @@ function calculateColumnSegments(seriesList, layout, columnIndex) {
6203
6856
  const height = (column.total > 0 ? value / column.total : 0) * column.height;
6204
6857
  const y = column.y + cumulativeHeight;
6205
6858
  cumulativeHeight += height;
6206
- const color2 = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
6859
+ const color = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
6207
6860
  segments.push({
6208
6861
  columnIndex,
6209
6862
  seriesId: series.id,
6210
6863
  seriesLabel: series.label,
6211
6864
  value,
6212
- color: color2,
6865
+ color,
6213
6866
  isTop: seriesIndex === 0,
6214
6867
  frame: {
6215
6868
  x: column.x,
@@ -6566,7 +7219,7 @@ function clampedCorner(layout, outerRadius, angles) {
6566
7219
  function wedgeNodes(context, layout, series, angles, outerRadius, value, rawColor) {
6567
7220
  const { chart, bounds, diagnostics, nextOrder } = context;
6568
7221
  const { centerX, centerY, innerRadius, maxRadius, gapPx } = layout;
6569
- const color2 = paint(rawColor, diagnostics, chart.id);
7222
+ const color = paint(rawColor, diagnostics, chart.id);
6570
7223
  const shadow = resolveChartShadow(chart.shadowStyle);
6571
7224
  const trackPath = createPieSlicePath(
6572
7225
  { centerX, centerY, outerRadius: maxRadius, innerRadius },
@@ -6598,7 +7251,7 @@ function wedgeNodes(context, layout, series, angles, outerRadius, value, rawColo
6598
7251
  order: nextOrder(),
6599
7252
  bounds,
6600
7253
  d: wedgePath,
6601
- style: { fill: color2, shadow, clip: { type: "path", d: trackPath } }
7254
+ style: { fill: color, shadow, clip: { type: "path", d: trackPath } }
6602
7255
  } : void 0;
6603
7256
  const wedge = {
6604
7257
  type: "path",
@@ -6616,7 +7269,7 @@ function wedgeNodes(context, layout, series, angles, outerRadius, value, rawColo
6616
7269
  pieValue: value
6617
7270
  },
6618
7271
  prop: seriesValueProp(series.id, 0),
6619
- style: { fill: color2, innerShadow: shadow, ...wedgeStroke(context) }
7272
+ style: { fill: color, innerShadow: shadow, ...wedgeStroke(context) }
6620
7273
  };
6621
7274
  return shadowCaster ? [track, shadowCaster, wedge] : [track, wedge];
6622
7275
  }
@@ -6711,11 +7364,11 @@ function labelPlacement2(context, geometry, angles, series, fillColor) {
6711
7364
  const outside = hasManualOffset || !fitsInline;
6712
7365
  const tickStart = pieArcPoint(geometry, mid, geometry.outerRadius + LEADER_INSET);
6713
7366
  const point = outside ? hasManualOffset ? addOffset(pieArcPoint(geometry, mid, geometry.outerRadius), labelOffsetX, labelOffsetY) : pieArcPoint(geometry, mid, geometry.outerRadius + OUTSIDE_GAP) : pieArcPoint(geometry, mid, geometry.innerRadius + ringThickness * LABEL_RADIUS_FRACTION);
6714
- const color2 = outside ? outsideLabels && context.chart.textColor ? context.chart.textColor : sameHueTint(representativeColor(fillColor, OUTSIDE_FALLBACK_COLOR), OUTSIDE_TINT_LIGHTNESS) ?? OUTSIDE_FALLBACK_COLOR : sameHueContrastColor(
7367
+ const color = outside ? outsideLabels && context.chart.textColor ? context.chart.textColor : sameHueTint(representativeColor(fillColor, OUTSIDE_FALLBACK_COLOR), OUTSIDE_TINT_LIGHTNESS) ?? OUTSIDE_FALLBACK_COLOR : sameHueContrastColor(
6715
7368
  representativeColor(fillColor, "#0f172a"),
6716
7369
  contrastTextColor(representativeColor(fillColor, "#0f172a"))
6717
7370
  );
6718
- return { point, color: color2, outside, mid, tickStart };
7371
+ return { point, color, outside, mid, tickStart };
6719
7372
  }
6720
7373
  function createWedgeLabel(context, geometry, angles, series, value, fillColor) {
6721
7374
  const placement = labelPlacement2(context, geometry, angles, series, fillColor);
@@ -6723,7 +7376,7 @@ function createWedgeLabel(context, geometry, angles, series, value, fillColor) {
6723
7376
  return [];
6724
7377
  }
6725
7378
  const { chart, bounds, nextOrder } = context;
6726
- const { point, color: color2, outside, mid, tickStart } = placement;
7379
+ const { point, color, outside, mid, tickStart } = placement;
6727
7380
  const { nameSize, valueSize } = labelSizes(chart);
6728
7381
  const lineHeight = Math.max(nameSize, valueSize) * 1.2;
6729
7382
  const tickEnd = outside ? clipSegmentToRect(tickStart, point, LABEL_WIDTH / 2, lineHeight) : tickStart;
@@ -6734,7 +7387,7 @@ function createWedgeLabel(context, geometry, angles, series, value, fillColor) {
6734
7387
  bounds,
6735
7388
  d: `M ${tickStart.x} ${tickStart.y} L ${tickEnd.x} ${tickEnd.y}`,
6736
7389
  detail: { of: "chartSeries", series: series.id, mark: "polar-area-label-tick" },
6737
- style: outside ? { stroke: { kind: "solid", color: color2 }, strokeWidth: 1.5 } : { stroke: { kind: "none" } }
7390
+ style: outside ? { stroke: { kind: "solid", color }, strokeWidth: 1.5 } : { stroke: { kind: "none" } }
6738
7391
  };
6739
7392
  const detail = {
6740
7393
  of: "chartSeries",
@@ -6752,7 +7405,7 @@ function createWedgeLabel(context, geometry, angles, series, value, fillColor) {
6752
7405
  align: "center",
6753
7406
  verticalAlign: "middle",
6754
7407
  lineHeight: 1.2,
6755
- color: color2
7408
+ color
6756
7409
  };
6757
7410
  const valueFirst = chart.config?.polarValueFirst ?? false;
6758
7411
  const nameHeight = nameSize * 1.2;
@@ -6953,13 +7606,13 @@ function renderRadarSeries(context, geometry) {
6953
7606
  return nodes;
6954
7607
  }
6955
7608
  function renderSeries(context, geometry, series, seriesIndex) {
6956
- const color2 = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
7609
+ const color = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
6957
7610
  const points = seriesPoints(series, context, geometry);
6958
7611
  const path = radarSeriesPath(points, geometry.circular, geometry.tension);
6959
7612
  return [
6960
- createSeriesFill(context, geometry, series, path, color2),
6961
- ...geometry.strokeWidth > 0 ? [createSeriesStroke(context, geometry, series, path, color2)] : [],
6962
- ...geometry.pointSize > 0 ? createSeriesPoints(context, geometry, series, points, color2) : []
7613
+ createSeriesFill(context, geometry, series, path, color),
7614
+ ...geometry.strokeWidth > 0 ? [createSeriesStroke(context, geometry, series, path, color)] : [],
7615
+ ...geometry.pointSize > 0 ? createSeriesPoints(context, geometry, series, points, color) : []
6963
7616
  ];
6964
7617
  }
6965
7618
  function seriesPoints(series, context, geometry) {
@@ -6968,7 +7621,7 @@ function seriesPoints(series, context, geometry) {
6968
7621
  (_, categoryIndex) => geometry.pointAt(geometry.radiusForValue(values[categoryIndex] ?? context.chart.axisY.min), categoryIndex)
6969
7622
  );
6970
7623
  }
6971
- function createSeriesFill(context, geometry, series, path, color2) {
7624
+ function createSeriesFill(context, geometry, series, path, color) {
6972
7625
  const { chart, bounds, diagnostics, nextOrder } = context;
6973
7626
  return {
6974
7627
  type: "path",
@@ -6978,13 +7631,13 @@ function createSeriesFill(context, geometry, series, path, color2) {
6978
7631
  d: path,
6979
7632
  detail: { of: "chartSeries", series: series.id },
6980
7633
  style: {
6981
- fill: paint(color2, diagnostics, chart.id),
7634
+ fill: paint(color, diagnostics, chart.id),
6982
7635
  stroke: { kind: "none" },
6983
7636
  opacity: Math.max(0, Math.min(1, series.opacity ?? geometry.areaOpacity))
6984
7637
  }
6985
7638
  };
6986
7639
  }
6987
- function createSeriesStroke(context, geometry, series, path, color2) {
7640
+ function createSeriesStroke(context, geometry, series, path, color) {
6988
7641
  const { chart, bounds, diagnostics, nextOrder } = context;
6989
7642
  return {
6990
7643
  type: "path",
@@ -6995,14 +7648,14 @@ function createSeriesStroke(context, geometry, series, path, color2) {
6995
7648
  detail: { of: "chartSeries", series: series.id },
6996
7649
  style: {
6997
7650
  fill: { kind: "none" },
6998
- stroke: paint(color2, diagnostics, chart.id),
7651
+ stroke: paint(color, diagnostics, chart.id),
6999
7652
  strokeWidth: geometry.strokeWidth,
7000
7653
  lineJoin: "round",
7001
7654
  shadow: resolveChartShadow(chart.shadowStyle)
7002
7655
  }
7003
7656
  };
7004
7657
  }
7005
- function createSeriesPoints(context, geometry, series, points, color2) {
7658
+ function createSeriesPoints(context, geometry, series, points, color) {
7006
7659
  const { chart, bounds, diagnostics, nextOrder } = context;
7007
7660
  return points.map((point, pointIndex) => ({
7008
7661
  type: "ellipse",
@@ -7015,7 +7668,7 @@ function createSeriesPoints(context, geometry, series, points, color2) {
7015
7668
  ry: geometry.pointSize,
7016
7669
  detail: { of: "chartValue", series: series.id, valueIndex: pointIndex, mark: "radar-vertex" },
7017
7670
  prop: seriesValueProp(series.id, pointIndex),
7018
- style: { fill: paint(color2, diagnostics, chart.id) }
7671
+ style: { fill: paint(color, diagnostics, chart.id) }
7019
7672
  }));
7020
7673
  }
7021
7674
 
@@ -7084,7 +7737,7 @@ function layoutOf2(context) {
7084
7737
  cap: chart.config?.ringCap ?? "round"
7085
7738
  };
7086
7739
  }
7087
- function ringEndShadows(context, layout, series, radius, sweep, color2) {
7740
+ function ringEndShadows(context, layout, series, radius, sweep, color) {
7088
7741
  const { chart, bounds, nextOrder } = context;
7089
7742
  const { centerX, centerY, ringThickness, start } = layout;
7090
7743
  const shadow = resolveChartShadow(chart.shadowStyle);
@@ -7106,7 +7759,7 @@ function ringEndShadows(context, layout, series, radius, sweep, color2) {
7106
7759
  d: arcSegmentPath(centerX, centerY, radius, from, to),
7107
7760
  style: {
7108
7761
  fill: { kind: "none" },
7109
- stroke: color2,
7762
+ stroke: color,
7110
7763
  strokeWidth: ringThickness,
7111
7764
  lineCap: layout.cap,
7112
7765
  shadow: clampedShadow,
@@ -7125,12 +7778,12 @@ function ringNodes2(context, layout, series, index) {
7125
7778
  if (radius <= ringThickness / 2) {
7126
7779
  return [];
7127
7780
  }
7128
- const color2 = paint(series.color ?? CHART_COLORS[index % CHART_COLORS.length], diagnostics, chart.id);
7781
+ const color = paint(series.color ?? CHART_COLORS[index % CHART_COLORS.length], diagnostics, chart.id);
7129
7782
  const value = Math.max(0, finite(series.values[0], 0));
7130
7783
  const fraction = range > 0 ? Math.min(1, Math.max(0, (value - axisMin) / range)) : 0;
7131
7784
  const trackStyle = {
7132
7785
  fill: { kind: "none" },
7133
- stroke: color2,
7786
+ stroke: color,
7134
7787
  strokeWidth: ringThickness,
7135
7788
  opacity: trackOpacity
7136
7789
  };
@@ -7156,7 +7809,7 @@ function ringNodes2(context, layout, series, index) {
7156
7809
  return [track];
7157
7810
  }
7158
7811
  const sweep = fraction * total;
7159
- const casters = ringEndShadows(context, layout, series, radius, sweep, color2);
7812
+ const casters = ringEndShadows(context, layout, series, radius, sweep, color);
7160
7813
  const progress = {
7161
7814
  type: "path",
7162
7815
  id: `chart-radial-bar-ring-${chart.id}-${series.id}`,
@@ -7165,7 +7818,7 @@ function ringNodes2(context, layout, series, index) {
7165
7818
  d: ringProgressPath(centerX, centerY, radius, sweep, start),
7166
7819
  detail: { of: "chartValue", series: series.id, valueIndex: 0, mark: "radial-bar-ring" },
7167
7820
  prop: seriesValueProp(series.id, 0),
7168
- style: { fill: { kind: "none" }, stroke: color2, strokeWidth: ringThickness, lineCap: cap }
7821
+ style: { fill: { kind: "none" }, stroke: color, strokeWidth: ringThickness, lineCap: cap }
7169
7822
  };
7170
7823
  return [track, ...casters, progress];
7171
7824
  }
@@ -7340,8 +7993,8 @@ function createNodeLabel(context, data, node) {
7340
7993
  node.color,
7341
7994
  isLightColor(fallback) ? OUTSIDE_LABEL_LIGHTNESS_ON_DARK_BG : OUTSIDE_LABEL_LIGHTNESS_ON_LIGHT_BG
7342
7995
  ) ?? fallback;
7343
- const color2 = chart.config?.labelColor ?? defaultColor;
7344
- return { ...label, color: color2, detail: { of: "chartSeries", series: node.id, mark: "sankey-node-label" } };
7996
+ const color = chart.config?.labelColor ?? defaultColor;
7997
+ return { ...label, color, detail: { of: "chartSeries", series: node.id, mark: "sankey-node-label" } };
7345
7998
  }
7346
7999
  function createOutsideLabel(context, data, node) {
7347
8000
  const { chart, bounds, nextOrder } = context;
@@ -7471,15 +8124,15 @@ function renderScatter(context) {
7471
8124
  const nodes = [];
7472
8125
  const shadow = resolveChartShadow(context.chart.shadowStyle);
7473
8126
  context.chart.series.forEach((series, seriesIndex) => {
7474
- const color2 = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
8127
+ const color = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
7475
8128
  const points = pixelPoints(context, seriesValuePairs(context.chart, series));
7476
8129
  points.forEach((point, pointIndex) => {
7477
- nodes.push(createScatterPoint(context, series, point, pointIndex, color2, shadow));
8130
+ nodes.push(createScatterPoint(context, series, point, pointIndex, color, shadow));
7478
8131
  });
7479
8132
  });
7480
8133
  return nodes;
7481
8134
  }
7482
- function createScatterPoint(context, series, point, pointIndex, color2, shadow) {
8135
+ function createScatterPoint(context, series, point, pointIndex, color, shadow) {
7483
8136
  const { chart, bounds, diagnostics, nextOrder } = context;
7484
8137
  const config = chart.config;
7485
8138
  const radius = config?.pointSize ?? DEFAULT_POINT_SIZE;
@@ -7495,8 +8148,8 @@ function createScatterPoint(context, series, point, pointIndex, color2, shadow)
7495
8148
  ry: radius,
7496
8149
  detail: { of: "chartValue", series: series.id, valueIndex: pointIndex },
7497
8150
  style: {
7498
- fill: paint(color2, diagnostics, chart.id),
7499
- stroke: strokeWidth > 0 ? paint(config?.pointStrokeColor ?? color2, diagnostics, chart.id) : void 0,
8151
+ fill: paint(color, diagnostics, chart.id),
8152
+ stroke: strokeWidth > 0 ? paint(config?.pointStrokeColor ?? color, diagnostics, chart.id) : void 0,
7500
8153
  strokeWidth: strokeWidth > 0 ? strokeWidth : void 0,
7501
8154
  opacity: config?.pointOpacity,
7502
8155
  shadow
@@ -7772,15 +8425,15 @@ function renderTreemapHeader(context, layout, header, index) {
7772
8425
  return [background, label];
7773
8426
  }
7774
8427
  function renderTile(context, layout, tile, nextTile) {
7775
- const color2 = treemapLeafColor(tile.item.leaf, layout);
8428
+ const color = treemapLeafColor(tile.item.leaf, layout);
7776
8429
  const nextColor = nextTile ? treemapLeafColor(nextTile.item.leaf, layout) : void 0;
7777
- const nodes = [createTileNode(context, layout, tile, color2, nextColor)];
8430
+ const nodes = [createTileNode(context, layout, tile, color, nextColor)];
7778
8431
  if (context.showLabels && tile.width >= 34 && tile.height >= 18) {
7779
- nodes.push(...createTileLabel(context, layout, tile, color2));
8432
+ nodes.push(...createTileLabel(context, layout, tile, color));
7780
8433
  }
7781
8434
  return nodes;
7782
8435
  }
7783
- function createTileNode(context, layout, tile, color2, nextColor) {
8436
+ function createTileNode(context, layout, tile, color, nextColor) {
7784
8437
  const { chart, plot, bounds, diagnostics, nextOrder } = context;
7785
8438
  const gap = layout.cellGap;
7786
8439
  const shadow = resolveChartShadow(chart.shadowStyle);
@@ -7800,10 +8453,10 @@ function createTileNode(context, layout, tile, color2, nextColor) {
7800
8453
  kind: "linear-gradient",
7801
8454
  angle: 0,
7802
8455
  stops: [
7803
- { offset: 0, color: representativeColor(color2, fallback) },
8456
+ { offset: 0, color: representativeColor(color, fallback) },
7804
8457
  { offset: 100, color: representativeColor(nextColor, fallback) }
7805
8458
  ]
7806
- } : paint(color2, diagnostics, chart.id);
8459
+ } : paint(color, diagnostics, chart.id);
7807
8460
  return {
7808
8461
  type: "rect",
7809
8462
  id: `chart-treemap-tile-${chart.id}-${tile.item.leaf.id}`,
@@ -7823,7 +8476,7 @@ function createTileNode(context, layout, tile, color2, nextColor) {
7823
8476
  }
7824
8477
  };
7825
8478
  }
7826
- function createTileLabel(context, layout, tile, color2) {
8479
+ function createTileLabel(context, layout, tile, color) {
7827
8480
  const { chart, plot, bounds, nextOrder } = context;
7828
8481
  const { leaf, value } = tile.item;
7829
8482
  const gap = layout.cellGap;
@@ -7832,7 +8485,7 @@ function createTileLabel(context, layout, tile, color2) {
7832
8485
  const height = Math.max(1, tile.height - gap - pad * 1.5);
7833
8486
  const x = plot.x + tile.x + gap / 2 + pad;
7834
8487
  const y = plot.y + tile.y + gap / 2 + pad * 0.75;
7835
- const textColor = chart.config?.tileTextColor ?? contrastTextColor(representativeColor(color2, "#ffffff"));
8488
+ const textColor = chart.config?.tileTextColor ?? contrastTextColor(representativeColor(color, "#ffffff"));
7836
8489
  const lineHeight = layout.labelSize * 1.2;
7837
8490
  const maxLines = Math.max(1, Math.floor(height / lineHeight));
7838
8491
  const labelLines = wrapText(leaf.label, width, layout.labelSize).slice(0, maxLines).map((line) => ellipsizeToWidth(line, width, layout.labelSize, true));
@@ -8154,7 +8807,7 @@ function stackingOf(input) {
8154
8807
  add("frame", input.frames, 0);
8155
8808
  add("swimlane", input.swimlanes, 5e3);
8156
8809
  add("shape", input.shapes, 1e4);
8157
- add("widget", input.widgets ?? [], 1e4);
8810
+ add("widget", input.components ?? input.widgets ?? [], 1e4);
8158
8811
  add("isometric", input.isometricObjects ?? [], 15e3);
8159
8812
  add(
8160
8813
  "link",
@@ -8163,6 +8816,7 @@ function stackingOf(input) {
8163
8816
  );
8164
8817
  add("chart", input.charts ?? [], 2e4);
8165
8818
  add("path", input.paths ?? [], 3e4);
8819
+ add("dimension", input.dimensions ?? [], 31e3);
8166
8820
  return stacking;
8167
8821
  }
8168
8822
  function stampStacking(nodes, input) {
@@ -8182,8 +8836,9 @@ function buildRenderScene(input, options = {}) {
8182
8836
  ...buildCharts(input.charts ?? [], diagnostics),
8183
8837
  ...buildLinks(input.links, measureText),
8184
8838
  ...buildShapes(input.shapes, diagnostics, measureText),
8185
- ...buildWidgets(input.widgets ?? []),
8186
- ...buildIsometricObjects(input.isometricObjects ?? [])
8839
+ ...buildComponents(input.components ?? input.widgets ?? []),
8840
+ ...buildIsometricObjects(input.isometricObjects ?? []),
8841
+ ...buildDimensions(input.dimensions ?? [])
8187
8842
  ];
8188
8843
  stampStacking(nodes, input);
8189
8844
  nodes.sort(
@@ -8286,21 +8941,21 @@ function innerShadowPrimitives(shadow) {
8286
8941
  }
8287
8942
 
8288
8943
  // src/svg/markerBodies.ts
8289
- function markerBody(type, size, color2, strokeWidth) {
8944
+ function markerBody(type, size, color, strokeWidth) {
8290
8945
  const bodies = {
8291
- arrow: `<path d="M ${num(-size)} ${num(-size * 0.6)} L 0 0 L ${num(-size)} ${num(size * 0.6)}" fill="none" stroke="${color2}" stroke-width="${num(strokeWidth)}" stroke-linecap="round" stroke-linejoin="round"/>`,
8292
- filled_arrow: `<path d="M ${num(-size)} ${num(-size * 0.6)} L 0 0 L ${num(-size)} ${num(size * 0.6)} Z" fill="${color2}" stroke="${color2}" stroke-width="${num(strokeWidth * 0.5)}" stroke-linejoin="round"/>`,
8293
- circle: `<circle cx="0" cy="0" r="${num(size * 0.5)}" fill="white" stroke="${color2}" stroke-width="${num(strokeWidth)}"/>`,
8294
- filled_circle: `<circle cx="0" cy="0" r="${num(size * 0.5)}" fill="${color2}"/>`,
8295
- diamond: `<path d="M ${num(-size * 0.6)} 0 L 0 ${num(-size * 0.6)} L ${num(size * 0.6)} 0 L 0 ${num(size * 0.6)} Z" fill="white" stroke="${color2}" stroke-width="${num(strokeWidth)}"/>`,
8296
- filled_diamond: `<path d="M ${num(-size * 0.6)} 0 L 0 ${num(-size * 0.6)} L ${num(size * 0.6)} 0 L 0 ${num(size * 0.6)} Z" fill="${color2}" stroke="${color2}" stroke-width="${num(strokeWidth * 0.5)}"/>`,
8297
- bar: `<path d="M 0 ${num(-size * 0.6)} V ${num(size * 0.6)}" stroke="${color2}" stroke-width="${num(strokeWidth)}" stroke-linecap="round"/>`,
8298
- triangle: `<path d="M ${num(-size)} ${num(-size * 0.72)} L 0 0 L ${num(-size)} ${num(size * 0.72)} Z" fill="white" stroke="${color2}" stroke-width="${num(strokeWidth)}" stroke-linejoin="round"/>`,
8299
- one: `<path d="M 0 ${num(-size * 0.62)} V ${num(size * 0.62)} M ${num(-size * 0.72)} ${num(-size * 0.62)} V ${num(size * 0.62)}" stroke="${color2}" stroke-width="${num(strokeWidth)}"/>`,
8300
- zero_one: `<circle cx="${num(-size * 0.8)}" cy="0" r="${num(size * 0.38)}" fill="white" stroke="${color2}" stroke-width="${num(strokeWidth)}"/><path d="M 0 ${num(-size * 0.62)} V ${num(size * 0.62)}" stroke="${color2}" stroke-width="${num(strokeWidth)}"/>`,
8301
- many: `<path d="M ${num(-size)} ${num(-size * 0.72)} L 0 0 M ${num(-size)} 0 L 0 0 M ${num(-size)} ${num(size * 0.72)} L 0 0" stroke="${color2}" stroke-width="${num(strokeWidth)}" stroke-linecap="round"/>`,
8302
- one_many: `<path d="M ${num(-size)} ${num(-size * 0.72)} L 0 0 M ${num(-size)} 0 L 0 0 M ${num(-size)} ${num(size * 0.72)} L 0 0 M ${num(-size * 1.45)} ${num(-size * 0.62)} V ${num(size * 0.62)}" stroke="${color2}" stroke-width="${num(strokeWidth)}" stroke-linecap="round"/>`,
8303
- zero_many: `<circle cx="${num(-size * 1.45)}" cy="0" r="${num(size * 0.38)}" fill="white" stroke="${color2}" stroke-width="${num(strokeWidth)}"/><path d="M ${num(-size)} ${num(-size * 0.72)} L 0 0 M ${num(-size)} 0 L 0 0 M ${num(-size)} ${num(size * 0.72)} L 0 0" stroke="${color2}" stroke-width="${num(strokeWidth)}" stroke-linecap="round"/>`
8946
+ arrow: `<path d="M ${num(-size)} ${num(-size * 0.6)} L 0 0 L ${num(-size)} ${num(size * 0.6)}" fill="none" stroke="${color}" stroke-width="${num(strokeWidth)}" stroke-linecap="round" stroke-linejoin="round"/>`,
8947
+ filled_arrow: `<path d="M ${num(-size)} ${num(-size * 0.6)} L 0 0 L ${num(-size)} ${num(size * 0.6)} Z" fill="${color}" stroke="${color}" stroke-width="${num(strokeWidth * 0.5)}" stroke-linejoin="round"/>`,
8948
+ circle: `<circle cx="0" cy="0" r="${num(size * 0.5)}" fill="white" stroke="${color}" stroke-width="${num(strokeWidth)}"/>`,
8949
+ filled_circle: `<circle cx="0" cy="0" r="${num(size * 0.5)}" fill="${color}"/>`,
8950
+ diamond: `<path d="M ${num(-size * 0.6)} 0 L 0 ${num(-size * 0.6)} L ${num(size * 0.6)} 0 L 0 ${num(size * 0.6)} Z" fill="white" stroke="${color}" stroke-width="${num(strokeWidth)}"/>`,
8951
+ filled_diamond: `<path d="M ${num(-size * 0.6)} 0 L 0 ${num(-size * 0.6)} L ${num(size * 0.6)} 0 L 0 ${num(size * 0.6)} Z" fill="${color}" stroke="${color}" stroke-width="${num(strokeWidth * 0.5)}"/>`,
8952
+ bar: `<path d="M 0 ${num(-size * 0.6)} V ${num(size * 0.6)}" stroke="${color}" stroke-width="${num(strokeWidth)}" stroke-linecap="round"/>`,
8953
+ triangle: `<path d="M ${num(-size)} ${num(-size * 0.72)} L 0 0 L ${num(-size)} ${num(size * 0.72)} Z" fill="white" stroke="${color}" stroke-width="${num(strokeWidth)}" stroke-linejoin="round"/>`,
8954
+ one: `<path d="M 0 ${num(-size * 0.62)} V ${num(size * 0.62)} M ${num(-size * 0.72)} ${num(-size * 0.62)} V ${num(size * 0.62)}" stroke="${color}" stroke-width="${num(strokeWidth)}"/>`,
8955
+ zero_one: `<circle cx="${num(-size * 0.8)}" cy="0" r="${num(size * 0.38)}" fill="white" stroke="${color}" stroke-width="${num(strokeWidth)}"/><path d="M 0 ${num(-size * 0.62)} V ${num(size * 0.62)}" stroke="${color}" stroke-width="${num(strokeWidth)}"/>`,
8956
+ many: `<path d="M ${num(-size)} ${num(-size * 0.72)} L 0 0 M ${num(-size)} 0 L 0 0 M ${num(-size)} ${num(size * 0.72)} L 0 0" stroke="${color}" stroke-width="${num(strokeWidth)}" stroke-linecap="round"/>`,
8957
+ one_many: `<path d="M ${num(-size)} ${num(-size * 0.72)} L 0 0 M ${num(-size)} 0 L 0 0 M ${num(-size)} ${num(size * 0.72)} L 0 0 M ${num(-size * 1.45)} ${num(-size * 0.62)} V ${num(size * 0.62)}" stroke="${color}" stroke-width="${num(strokeWidth)}" stroke-linecap="round"/>`,
8958
+ zero_many: `<circle cx="${num(-size * 1.45)}" cy="0" r="${num(size * 0.38)}" fill="white" stroke="${color}" stroke-width="${num(strokeWidth)}"/><path d="M ${num(-size)} ${num(-size * 0.72)} L 0 0 M ${num(-size)} 0 L 0 0 M ${num(-size)} ${num(size * 0.72)} L 0 0" stroke="${color}" stroke-width="${num(strokeWidth)}" stroke-linecap="round"/>`
8304
8959
  };
8305
8960
  return bodies[type];
8306
8961
  }
@@ -8321,11 +8976,11 @@ var SvgMarkerDefinitions = class {
8321
8976
  addDefinition;
8322
8977
  prefix;
8323
8978
  ids = /* @__PURE__ */ new Map();
8324
- marker(type, color2, strokeWidth) {
8979
+ marker(type, color, strokeWidth) {
8325
8980
  if (!type || type === "none") {
8326
8981
  return void 0;
8327
8982
  }
8328
- const key = `${type}:${color2}:${strokeWidth}`;
8983
+ const key = `${type}:${color}:${strokeWidth}`;
8329
8984
  let id = this.ids.get(key);
8330
8985
  if (id) {
8331
8986
  return id;
@@ -8335,7 +8990,7 @@ var SvgMarkerDefinitions = class {
8335
8990
  const size = 12 + (strokeWidth - 2) * 3;
8336
8991
  const extent = markerExtent(type, size, strokeWidth);
8337
8992
  const attributes = markerAttributes(id, extent);
8338
- this.addDefinition(`<marker ${attributes}>${markerBody(type, size, xml(color2), strokeWidth)}</marker>`);
8993
+ this.addDefinition(`<marker ${attributes}>${markerBody(type, size, xml(color), strokeWidth)}</marker>`);
8339
8994
  return id;
8340
8995
  }
8341
8996
  };
@@ -8415,8 +9070,8 @@ var SvgDefinitionRegistry = class {
8415
9070
  filter(style, nodeId, size) {
8416
9071
  return this.filters.filter(style, nodeId, size);
8417
9072
  }
8418
- marker(type, color2, strokeWidth) {
8419
- return this.markers.marker(type, color2, strokeWidth);
9073
+ marker(type, color, strokeWidth) {
9074
+ return this.markers.marker(type, color, strokeWidth);
8420
9075
  }
8421
9076
  clip(style) {
8422
9077
  return this.clips.clip(style);
@@ -8546,13 +9201,22 @@ function imageAttrs(node, defs) {
8546
9201
  function domRole(identity) {
8547
9202
  return identity.role === "shape" ? "entity" : identity.role;
8548
9203
  }
9204
+ function ariaAttrs(aria) {
9205
+ return [
9206
+ `role="${xml(aria.role)}"`,
9207
+ aria.checked === void 0 ? void 0 : `aria-checked="${aria.checked}"`,
9208
+ aria.pressed === void 0 ? void 0 : `aria-pressed="${aria.pressed}"`,
9209
+ aria.disabled ? 'aria-disabled="true"' : void 0
9210
+ ];
9211
+ }
8549
9212
  function identityAttrs(identity) {
8550
9213
  return [
8551
9214
  `data-sf-role="${domRole(identity)}"`,
8552
9215
  `data-sf-id="${xml(identity.id)}"`,
8553
9216
  identity.kind ? `data-sf-kind="${xml(identity.kind)}"` : void 0,
8554
9217
  identity.primary ? 'data-sf-primary="true"' : void 0,
8555
- identity.parentFrameId ? `data-sf-parent-frame="${xml(identity.parentFrameId)}"` : void 0
9218
+ identity.parentFrameId ? `data-sf-parent-frame="${xml(identity.parentFrameId)}"` : void 0,
9219
+ ...identity.aria ? ariaAttrs(identity.aria) : []
8556
9220
  ];
8557
9221
  }
8558
9222
  function detailAttrs(detail) {
@@ -8737,7 +9401,7 @@ function shaderSurfaceSvg(node, defs) {
8737
9401
  return `<foreignObject id="${defs.elementId(node.id)}"${contractAttrs(node)} data-sf-shader="${xml(node.shader.program)}" data-sf-shader-name="${xml(node.shader.name)}" data-sf-shader-params="${parameters}" data-sf-shader-mask="${node.mask}"${fillColor} x="${num(node.x)}" y="${num(node.y)}" width="${num(node.width)}" height="${num(node.height)}"${rotation} pointer-events="${node.shader.program === "ruler" || node.identity?.role === "widget" ? "all" : "none"}"><canvas xmlns="http://www.w3.org/1999/xhtml" data-sf-shader-canvas="true" style="display:block;width:100%;height:100%;pointer-events:none"></canvas></foreignObject>`;
8738
9402
  }
8739
9403
  function rollingDigitSvg(character, node) {
8740
- const style = node.widgetStyle;
9404
+ const style = node.componentStyle;
8741
9405
  if (style.variant === "plain") {
8742
9406
  return `<span xmlns="http://www.w3.org/1999/xhtml" data-sf-rolling-digit="true" style="position:relative;display:inline-block;width:.62em;height:1.1em;overflow:hidden"><span data-sf-rolling-current="true" style="position:absolute;inset:0;display:grid;place-items:center;color:${xml(style.color)};font-weight:${xml(style.fontWeight)};line-height:1">${xml(character)}</span></span>`;
8743
9407
  }
@@ -8745,11 +9409,11 @@ function rollingDigitSvg(character, node) {
8745
9409
  }
8746
9410
  function rollingNumberSvg(node, defs) {
8747
9411
  const rotation = transform(node.rotation, { x: node.x + node.width / 2, y: node.y + node.height / 2 });
8748
- const fontSize = node.widgetStyle.fontSize > 0 ? node.widgetStyle.fontSize : Math.max(1, Math.min(node.width, node.height) * 0.28);
8749
- const label = node.label ? `<span xmlns="http://www.w3.org/1999/xhtml" style="margin-bottom:.14em;color:${xml(node.widgetStyle.labelColor)};font-size:.16em;font-weight:600;letter-spacing:.24em;line-height:1">${xml(node.label)}</span>` : "";
9412
+ const fontSize = node.componentStyle.fontSize > 0 ? node.componentStyle.fontSize : Math.max(1, Math.min(node.width, node.height) * 0.28);
9413
+ const label = node.label ? `<span xmlns="http://www.w3.org/1999/xhtml" style="margin-bottom:.14em;color:${xml(node.componentStyle.labelColor)};font-size:.16em;font-weight:600;letter-spacing:.24em;line-height:1">${xml(node.label)}</span>` : "";
8750
9414
  const digits = [...node.value].map((character) => rollingDigitSvg(character, node)).join("");
8751
- const widgetStyle = xml(JSON.stringify(node.widgetStyle));
8752
- return `<foreignObject id="${defs.elementId(node.id)}"${contractAttrs(node)} data-sf-widget="rollingNumber" data-sf-widget-value="${xml(node.value)}" data-sf-widget-digits="${node.digits ?? ""}" data-sf-widget-duration="${num(node.duration)}" data-sf-widget-style="${widgetStyle}" x="${num(node.x)}" y="${num(node.y)}" width="${num(node.width)}" height="${num(node.height)}"${rotation}><div xmlns="http://www.w3.org/1999/xhtml" style="width:100%;height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;font-family:${xml(node.widgetStyle.fontFamily)};font-size:${num(fontSize)}px">${label}<div data-sf-rolling-digits="true" aria-label="${xml(node.value)}" style="display:flex;gap:${node.widgetStyle.variant === "plain" ? ".02em" : ".1em"};font-size:1em">${digits}</div></div></foreignObject>`;
9415
+ const componentStyle = xml(JSON.stringify(node.componentStyle));
9416
+ return `<foreignObject id="${defs.elementId(node.id)}"${contractAttrs(node)} data-sf-widget="rollingNumber" data-sf-widget-value="${xml(node.value)}" data-sf-widget-digits="${node.digits ?? ""}" data-sf-widget-duration="${num(node.duration)}" data-sf-widget-style="${componentStyle}" x="${num(node.x)}" y="${num(node.y)}" width="${num(node.width)}" height="${num(node.height)}"${rotation}><div xmlns="http://www.w3.org/1999/xhtml" style="width:100%;height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;font-family:${xml(node.componentStyle.fontFamily)};font-size:${num(fontSize)}px">${label}<div data-sf-rolling-digits="true" aria-label="${xml(node.value)}" style="display:flex;gap:${node.componentStyle.variant === "plain" ? ".02em" : ".1em"};font-size:1em">${digits}</div></div></foreignObject>`;
8753
9417
  }
8754
9418
  function nodeSvg(node, defs) {
8755
9419
  if (node.type === "text") {
@@ -8804,7 +9468,13 @@ function renderCanvas(input, options = {}) {
8804
9468
  }
8805
9469
  var SCENE_CACHE_LIMIT = 50;
8806
9470
  var sceneCache = /* @__PURE__ */ new Map();
9471
+ var cachedForRegistry = componentRegistryVersion();
8807
9472
  function cachedRenderScene(source) {
9473
+ const registry = componentRegistryVersion();
9474
+ if (registry !== cachedForRegistry) {
9475
+ sceneCache.clear();
9476
+ cachedForRegistry = registry;
9477
+ }
8808
9478
  const cached = sceneCache.get(source);
8809
9479
  if (cached) {
8810
9480
  sceneCache.delete(source);
@@ -8829,7 +9499,20 @@ function render(source, options = {}) {
8829
9499
  const { svg, width, height, diagnostics } = renderSceneToSvg(scene, options);
8830
9500
  return { svg, width, height, diagnostics, scene };
8831
9501
  }
9502
+ var SCENE_ORDER_BASE = 1e4;
9503
+ function defineComponent(definition) {
9504
+ const { scene, ...descriptor } = definition;
9505
+ const unregisterDescriptor = registerComponentDescriptor(descriptor);
9506
+ const unregisterBuilder = registerComponentBuilder(
9507
+ descriptor.type,
9508
+ (component, index) => scene(component, { order: SCENE_ORDER_BASE + index })
9509
+ );
9510
+ return () => {
9511
+ unregisterBuilder();
9512
+ unregisterDescriptor();
9513
+ };
9514
+ }
8832
9515
 
8833
- export { DEFAULT_ROLLING_NUMBER_STYLE, collectCanvasObjects, decodeColor, decodeShadow, formatRollingNumber, render, renderCanvas, sflToRenderInput };
8834
- //# sourceMappingURL=chunk-65IVT4GK.js.map
8835
- //# sourceMappingURL=chunk-65IVT4GK.js.map
9516
+ export { collectCanvasObjects, decodeColor, decodeShadow, defineComponent, render, renderCanvas, sflToRenderInput };
9517
+ //# sourceMappingURL=chunk-FVHVOJS2.js.map
9518
+ //# sourceMappingURL=chunk-FVHVOJS2.js.map