stickyflow 0.4.0 → 0.5.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 +27 -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-XEN5QIIJ.js → chunk-7VW2XKVB.js} +3 -3
  10. package/dist/{chunk-XEN5QIIJ.js.map → chunk-7VW2XKVB.js.map} +1 -1
  11. package/dist/chunk-BODZN3ZI.js +1182 -0
  12. package/dist/chunk-BODZN3ZI.js.map +1 -0
  13. package/dist/{chunk-CSXQD3ON.js → chunk-G7NRK5AG.js} +1128 -1081
  14. package/dist/chunk-G7NRK5AG.js.map +1 -0
  15. package/dist/{chunk-BYMIYXP5.js → chunk-IEHE6WVN.js} +197 -19
  16. package/dist/chunk-IEHE6WVN.js.map +1 -0
  17. package/dist/{chunk-HFOGKSNU.cjs → chunk-L3VJXZFD.cjs} +15 -15
  18. package/dist/{chunk-HFOGKSNU.cjs.map → chunk-L3VJXZFD.cjs.map} +1 -1
  19. package/dist/{chunk-65IVT4GK.js → chunk-LTGF5OHP.js} +1008 -631
  20. package/dist/chunk-LTGF5OHP.js.map +1 -0
  21. package/dist/chunk-TWDLOXRM.cjs +1189 -0
  22. package/dist/chunk-TWDLOXRM.cjs.map +1 -0
  23. package/dist/{chunk-UXDWH2JC.cjs → chunk-VK3T6O5Z.cjs} +1165 -1118
  24. package/dist/chunk-VK3T6O5Z.cjs.map +1 -0
  25. package/dist/{chunk-CXL254BT.cjs → chunk-XY2GZUHC.cjs} +204 -18
  26. package/dist/chunk-XY2GZUHC.cjs.map +1 -0
  27. package/dist/{chunk-DDCTNLLD.cjs → chunk-ZMLQIMJK.cjs} +1504 -1128
  28. package/dist/chunk-ZMLQIMJK.cjs.map +1 -0
  29. package/dist/index.cjs +53 -1013
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +22 -14
  32. package/dist/index.d.ts +22 -14
  33. package/dist/index.js +6 -993
  34. package/dist/index.js.map +1 -1
  35. package/dist/interaction/index.cjs +231 -231
  36. package/dist/interaction/index.cjs.map +1 -1
  37. package/dist/interaction/index.d.cts +2 -2
  38. package/dist/interaction/index.d.ts +2 -2
  39. package/dist/interaction/index.js +3 -3
  40. package/dist/interaction/index.js.map +1 -1
  41. package/dist/{render-C5X74hds.d.cts → render-CgX_y15a.d.cts} +193 -116
  42. package/dist/{render-C5X74hds.d.ts → render-CgX_y15a.d.ts} +193 -116
  43. package/dist/runtime-DnUxca3Y.d.ts +10 -0
  44. package/dist/runtime-reWgr7MP.d.cts +10 -0
  45. package/dist/{runtimeTypes-D8hPZ62T.d.ts → runtimeTypes-CEBGueYM.d.ts} +10 -5
  46. package/dist/{runtimeTypes-yTSAvtCn.d.cts → runtimeTypes-D60w6nyF.d.cts} +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-BDKDf4zr.d.cts → types-DYLC_lsk.d.ts} +3 -2
  50. package/dist/{types-CdgGdtoD.d.ts → types-DvhMpqrL.d.cts} +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, isIsometricObject, sflToCanvasState, registerComponentDescriptor, isBuiltInComponentType, getComponentDescriptor, tag, EMPTY_BOUNDS, DOM_CONTRACT_VERSION, edgePointToward, elementCenter, VISIBLE_ISOMETRIC_FACES, isometricFaceCenter, finite, freeformPathData, rotatedBounds, DEFAULT_FONT, isGenericComponent, isometricFaces, roundedPolygonPath, pointAtNormalizedPort, boxBounds, cornersRoundedRectPath, calculateLinkRoute, labelGapDash, getLineMidpoint, 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, resolveRollingNumberStyle, formatRollingNumber } from './chunk-IEHE6WVN.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;
@@ -790,355 +1030,669 @@ function swimlaneObject(e) {
790
1030
  };
791
1031
  }
792
1032
 
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;
1033
+ // src/renderInput/fromSfl/canvasObjects/collect.ts
1034
+ var byOrder = (items) => [...items].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
1035
+ function collectCanvasObjects(state) {
1036
+ const canvasObjects = byOrder(state.canvasObjects);
1037
+ const shaders = new Map((state.shaders ?? []).map((shader) => [shader.name, shader]));
1038
+ return {
1039
+ shapes: canvasObjects.filter((canvasObject) => canvasObject.objectType === "shape").map((shape) => shapeObject(shape, shaders)),
1040
+ frames: canvasObjects.filter((canvasObject) => canvasObject.objectType === "frame").map(frameObject),
1041
+ swimlanes: canvasObjects.filter((canvasObject) => canvasObject.objectType === "swimlane").map(swimlaneObject),
1042
+ isometricObjects: canvasObjects.filter(isIsometricObject).map(isometricObject),
1043
+ paths: canvasObjects.filter((canvasObject) => canvasObject.objectType === "path").map(pathObject),
1044
+ charts: canvasObjects.filter((canvasObject) => canvasObject.objectType === "chart").map(chartObject),
1045
+ components: canvasObjects.filter(
1046
+ (canvasObject) => canvasObject.objectType === "component" && canvasObject.component !== void 0
1047
+ ).map(componentObject),
1048
+ links: byOrder(state.links).map(linkObject),
1049
+ connections: byOrder(state.connections).map(connectionObject)
1050
+ };
798
1051
  }
799
- function fontFamily(value) {
800
- return value && CSS_FONT_FAMILY.test(value) ? value : void 0;
1052
+
1053
+ // src/renderInput/fromSfl/endpoint.ts
1054
+ function sidePoint(canvasObject, endpoint) {
1055
+ const offset = endpoint.offset ?? 0.5;
1056
+ switch (endpoint.side) {
1057
+ case "top":
1058
+ return { x: canvasObject.x + canvasObject.width * offset, y: canvasObject.y };
1059
+ case "right":
1060
+ return { x: canvasObject.x + canvasObject.width, y: canvasObject.y + canvasObject.height * offset };
1061
+ case "bottom":
1062
+ return { x: canvasObject.x + canvasObject.width * offset, y: canvasObject.y + canvasObject.height };
1063
+ case "left":
1064
+ return { x: canvasObject.x, y: canvasObject.y + canvasObject.height * offset };
1065
+ }
801
1066
  }
802
- var FONT_WEIGHT = /^(?:[1-9]00|normal|bold)$/;
803
- function variant(value) {
804
- return value === "plain" || value === "flip" ? value : void 0;
1067
+ function namedPortPoint(canvasObject, endpoint) {
1068
+ const port = canvasObject.symbol?.ports?.find((candidate) => candidate.name === endpoint.port);
1069
+ if (!port) {
1070
+ return elementCenter(canvasObject);
1071
+ }
1072
+ return pointAtNormalizedPort(
1073
+ {
1074
+ x: canvasObject.x,
1075
+ y: canvasObject.y,
1076
+ width: canvasObject.width,
1077
+ height: canvasObject.height,
1078
+ rotation: canvasObject.rotation ?? void 0
1079
+ },
1080
+ port.at
1081
+ );
805
1082
  }
806
- function motion(value) {
807
- return value === "roll" || value === "fade" ? value : void 0;
1083
+ function resolveLinkEndpoint(link, end, canvasObjects) {
1084
+ const selected = selectLinkEndpoint(link, end);
1085
+ const absolutePoint = explicitAbsolutePoint(selected.explicit);
1086
+ if (absolutePoint) {
1087
+ return absolutePoint;
1088
+ }
1089
+ const canvasObject = findPositionedCanvasObject(canvasObjects, selected.canvasObjectId);
1090
+ if (!canvasObject) {
1091
+ return { x: 0, y: 0 };
1092
+ }
1093
+ const anchoredPoint = explicitAnchorPoint(canvasObject, selected.explicit);
1094
+ if (anchoredPoint) {
1095
+ return anchoredPoint;
1096
+ }
1097
+ return automaticEndpointPoint(
1098
+ canvasObject,
1099
+ findPositionedCanvasObject(canvasObjects, selected.oppositeCanvasObjectId)
1100
+ );
808
1101
  }
809
- function positiveNumber(value) {
810
- const number = Number(value);
811
- return value !== void 0 && Number.isFinite(number) && number > 0 ? number : void 0;
1102
+ function selectLinkEndpoint(link, end) {
1103
+ return end === "from" ? { canvasObjectId: link.fromId, oppositeCanvasObjectId: link.toId, explicit: link.fromPoint } : { canvasObjectId: link.toId, oppositeCanvasObjectId: link.fromId, explicit: link.toPoint };
812
1104
  }
813
- function fontWeight(value) {
814
- return value && FONT_WEIGHT.test(value) ? value : void 0;
1105
+ function explicitAbsolutePoint(endpoint) {
1106
+ return endpoint?.kind === "absolute" ? { x: endpoint.x, y: endpoint.y } : null;
815
1107
  }
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
- }
1108
+ function explicitAnchorPoint(canvasObject, endpoint) {
1109
+ if (endpoint?.kind === "port") {
1110
+ return namedPortPoint(canvasObject, endpoint);
836
1111
  }
837
- for (const key of TICK_SCALE_COLORS) {
838
- const value = color(properties[key]);
839
- if (value) {
840
- parameters[key] = value;
841
- }
1112
+ if (endpoint?.kind === "side") {
1113
+ return sidePoint(canvasObject, endpoint);
1114
+ }
1115
+ return null;
1116
+ }
1117
+ function automaticEndpointPoint(canvasObject, opposite) {
1118
+ return opposite ? edgePointToward(canvasObject, opposite) : elementCenter(canvasObject);
1119
+ }
1120
+ function findPositionedCanvasObject(canvasObjects, id) {
1121
+ return canvasObjects.find((candidate) => candidate.id === id);
1122
+ }
1123
+
1124
+ // src/renderInput/fromSfl/links.ts
1125
+ var ISOMETRIC_SEQUENCE_BASE = 15e3;
1126
+ function positionedCanvasObjects(canvasObjects) {
1127
+ return [
1128
+ ...canvasObjects.shapes,
1129
+ ...canvasObjects.frames,
1130
+ ...canvasObjects.swimlanes,
1131
+ ...canvasObjects.paths,
1132
+ ...canvasObjects.charts
1133
+ ];
1134
+ }
1135
+ function connectionEndpointPoint(object, face) {
1136
+ return object ? isometricFaceCenter(object, face) : { x: 0, y: 0 };
1137
+ }
1138
+ function isometricStackPosition(isometricObjects, id) {
1139
+ const index = isometricObjects.findIndex((object2) => object2.id === id);
1140
+ if (index < 0) {
1141
+ return void 0;
842
1142
  }
1143
+ const object = isometricObjects[index];
1144
+ return { rank: object.order ?? 0, sequence: object.sourceIndex ?? ISOMETRIC_SEQUENCE_BASE + index };
1145
+ }
1146
+ function connectionStack(isometricObjects, connection) {
1147
+ if (typeof connection.order === "number") {
1148
+ return { order: connection.order, sourceIndex: connection.sourceIndex };
1149
+ }
1150
+ const behind = [
1151
+ VISIBLE_ISOMETRIC_FACES.has(connection.fromFace) ? void 0 : isometricStackPosition(isometricObjects, connection.fromId),
1152
+ VISIBLE_ISOMETRIC_FACES.has(connection.toFace) ? void 0 : isometricStackPosition(isometricObjects, connection.toId)
1153
+ ].filter((position) => position !== void 0);
1154
+ if (!behind.length) {
1155
+ return { sourceIndex: connection.sourceIndex };
1156
+ }
1157
+ const lowest = behind.reduce(
1158
+ (best, position) => position.rank < best.rank || position.rank === best.rank && position.sequence < best.sequence ? position : best
1159
+ );
1160
+ return { order: lowest.rank, sourceIndex: lowest.sequence - 0.5 };
1161
+ }
1162
+ function createRenderInputConnections(canvasObjects) {
1163
+ const isometricById = new Map(canvasObjects.isometricObjects.map((object) => [object.id, object]));
1164
+ return canvasObjects.connections.map((connection) => {
1165
+ const link = {
1166
+ id: connection.id,
1167
+ fromId: connection.fromId,
1168
+ toId: connection.toId,
1169
+ fromPoint: { kind: "face", face: connection.fromFace },
1170
+ toPoint: { kind: "face", face: connection.toFace },
1171
+ style: connection.style,
1172
+ ...connectionStack(canvasObjects.isometricObjects, connection)
1173
+ };
1174
+ return {
1175
+ link,
1176
+ from: connectionEndpointPoint(isometricById.get(connection.fromId ?? ""), connection.fromFace),
1177
+ to: connectionEndpointPoint(isometricById.get(connection.toId ?? ""), connection.toFace),
1178
+ kind: "connection"
1179
+ };
1180
+ });
1181
+ }
1182
+ function createRenderInputLinks(canvasObjects) {
1183
+ const positionedObjects = positionedCanvasObjects(canvasObjects);
1184
+ const links = canvasObjects.links.map((link) => ({
1185
+ link,
1186
+ from: resolveLinkEndpoint(link, "from", positionedObjects),
1187
+ to: resolveLinkEndpoint(link, "to", positionedObjects)
1188
+ }));
1189
+ return [...links, ...createRenderInputConnections(canvasObjects)];
1190
+ }
1191
+
1192
+ // src/renderInput/fromSfl/index.ts
1193
+ function sflToRenderInput(sfl) {
1194
+ const state = sflToCanvasState(sfl);
1195
+ const canvasObjects = collectCanvasObjects(state);
843
1196
  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
1197
+ shapes: canvasObjects.shapes,
1198
+ frames: canvasObjects.frames,
1199
+ swimlanes: canvasObjects.swimlanes,
1200
+ isometricObjects: canvasObjects.isometricObjects,
1201
+ paths: canvasObjects.paths,
1202
+ charts: canvasObjects.charts,
1203
+ components: canvasObjects.components,
1204
+ links: createRenderInputLinks(canvasObjects),
1205
+ diagnostics: state.diagnostics
865
1206
  };
866
1207
  }
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;
1208
+
1209
+ // src/renderScene/artifacts/component/placeholder.ts
1210
+ var STROKE = "#94a3b8";
1211
+ function buildPlaceholder(component, index) {
1212
+ const x = finite(component.x, 0);
1213
+ const y = finite(component.y, 0);
1214
+ const width = Math.max(0, finite(component.width, 120));
1215
+ const height = Math.max(0, finite(component.height, 60));
1216
+ const rotation = finite(component.rotation, 0);
1217
+ const order = 1e4 + index;
1218
+ const bounds = rotatedBounds({ x, y, width, height }, rotation, 2);
1219
+ return [
1220
+ {
1221
+ id: `widget-${component.id}`,
1222
+ type: "rect",
1223
+ order,
1224
+ bounds,
1225
+ x,
1226
+ y,
1227
+ width,
1228
+ height,
1229
+ rx: 6,
1230
+ rotation,
1231
+ style: { fill: { kind: "none" }, stroke: { kind: "solid", color: STROKE }, strokeWidth: 1, dash: [4, 3] }
1232
+ },
1233
+ {
1234
+ id: `widget-${component.id}-label`,
1235
+ type: "text",
1236
+ order: order + 0.1,
1237
+ bounds,
1238
+ x,
1239
+ y,
1240
+ width,
1241
+ height,
1242
+ lines: [component.type],
1243
+ fontFamily: DEFAULT_FONT,
1244
+ fontSize: 12,
1245
+ fontWeight: "normal",
1246
+ color: STROKE,
1247
+ align: "center",
1248
+ verticalAlign: "middle",
1249
+ lineHeight: 1.3,
1250
+ rotation
890
1251
  }
1252
+ ];
1253
+ }
1254
+
1255
+ // src/renderScene/artifacts/component/builtIn.ts
1256
+ function buildRollingNumber(component, index) {
1257
+ const x = finite(component.x, 0);
1258
+ const y = finite(component.y, 0);
1259
+ const width = Math.max(0, finite(component.width, 160));
1260
+ const height = Math.max(0, finite(component.height, 90));
1261
+ const rotation = finite(component.rotation, 0);
1262
+ return [
1263
+ {
1264
+ id: `widget-${component.id}`,
1265
+ type: "rolling-number",
1266
+ order: 1e4 + index,
1267
+ bounds: rotatedBounds({ x, y, width, height }, rotation, 2),
1268
+ x,
1269
+ y,
1270
+ width,
1271
+ height,
1272
+ rotation,
1273
+ value: formatRollingNumber(component.value, component.digits),
1274
+ digits: component.digits,
1275
+ duration: Math.max(0, finite(component.duration, 420)),
1276
+ label: component.label,
1277
+ componentStyle: resolveRollingNumberStyle(component.style)
1278
+ }
1279
+ ];
1280
+ }
1281
+ function buildTickScale(component, index) {
1282
+ const x = finite(component.x, 0);
1283
+ const y = finite(component.y, 0);
1284
+ const width = Math.max(0, finite(component.width, 200));
1285
+ const height = Math.max(0, finite(component.height, 200));
1286
+ const rotation = finite(component.rotation, 0);
1287
+ const max = finite(component.max, 100) || 100;
1288
+ const progress = Math.min(1, Math.max(0, finite(Number(component.value), 0) / max));
1289
+ const nodes = [
1290
+ {
1291
+ id: `widget-${component.id}`,
1292
+ type: "shader-surface",
1293
+ order: 1e4 + index,
1294
+ bounds: rotatedBounds({ x, y, width, height }, rotation, 2),
1295
+ x,
1296
+ y,
1297
+ width,
1298
+ height,
1299
+ rotation,
1300
+ shader: { name: component.id, program: "tickScale", parameters: { ...component.parameters, progress, max } },
1301
+ mask: "ellipse"
1302
+ }
1303
+ ];
1304
+ if (component.labels) {
1305
+ nodes.push(...buildTickLabels(component, { x, y, width, height, max, order: 1e4 + index }));
891
1306
  }
892
- for (const key of RULER_COLORS) {
893
- parameters[key] = color(properties[key]) ?? RULER_DEFAULTS[key];
1307
+ return nodes;
1308
+ }
1309
+ function buildTickLabels(component, box) {
1310
+ const labels = component.labels ?? {};
1311
+ const ticks = Math.max(1, finite(Number(component.parameters.ticks), 48));
1312
+ const major = Math.max(1, finite(Number(component.parameters.major), 5));
1313
+ const start = finite(Number(component.parameters.start), 225) * Math.PI / 180;
1314
+ const sweep = finite(Number(component.parameters.sweep), 270) * Math.PI / 180;
1315
+ const radius = finite(Number(component.parameters.radius), 0.9) + finite(labels.offset, 0.08);
1316
+ const fontSize = finite(labels.size, 12);
1317
+ const centerX = box.x + box.width / 2;
1318
+ const centerY = box.y + box.height / 2;
1319
+ const count = Math.floor(ticks / major);
1320
+ const nodes = [];
1321
+ for (let step = 0; step <= count; step += 1) {
1322
+ const fraction = step * major / ticks;
1323
+ const angle = start - fraction * sweep;
1324
+ const labelX2 = centerX + Math.cos(angle) * radius * (box.width / 2);
1325
+ const labelY = centerY - Math.sin(angle) * radius * (box.height / 2);
1326
+ const labelBox = { x: labelX2 - 24, y: labelY - fontSize, width: 48, height: fontSize * 2 };
1327
+ nodes.push({
1328
+ id: `widget-${component.id}-label-${step}`,
1329
+ type: "text",
1330
+ order: box.order + 0.1,
1331
+ bounds: rotatedBounds(labelBox, 0, 2),
1332
+ ...labelBox,
1333
+ lines: [String(Math.round(box.max * fraction * 10) / 10)],
1334
+ fontFamily: labels.fontFamily || DEFAULT_FONT,
1335
+ fontSize,
1336
+ fontWeight: labels.weight ?? "normal",
1337
+ color: labels.color || "#8f95c4",
1338
+ align: "center",
1339
+ verticalAlign: "middle",
1340
+ lineHeight: 1.3
1341
+ });
894
1342
  }
895
- for (const key of RULER_OPTIONAL_COLORS) {
896
- const value = color(properties[key]);
897
- if (value) {
898
- parameters[key] = value;
1343
+ return nodes;
1344
+ }
1345
+ function buildRuler(component, index) {
1346
+ const x = finite(component.x, 0);
1347
+ const y = finite(component.y, 0);
1348
+ const width = Math.max(0, finite(component.width, 120));
1349
+ const height = Math.max(0, finite(component.height, 360));
1350
+ const rotation = finite(component.rotation, 0);
1351
+ const min = finite(component.min, 0);
1352
+ const max = finite(component.max, 100);
1353
+ const progress = max === min ? 0 : Math.min(1, Math.max(0, (finite(Number(component.value), min) - min) / (max - min)));
1354
+ const nodes = [
1355
+ {
1356
+ id: `widget-${component.id}`,
1357
+ type: "shader-surface",
1358
+ order: 1e4 + index,
1359
+ bounds: rotatedBounds({ x, y, width, height }, rotation, 2),
1360
+ x,
1361
+ y,
1362
+ width,
1363
+ height,
1364
+ rotation,
1365
+ shader: { name: component.id, program: "ruler", parameters: { ...component.parameters, progress, min, max } },
1366
+ mask: "rect"
899
1367
  }
1368
+ ];
1369
+ if (component.labels) {
1370
+ nodes.push(...buildRulerLabels(component, { x, y, width, height, min, max, order: 1e4 + index }));
900
1371
  }
901
- parameters.axis = properties.axis === "horizontal" ? "horizontal" : "vertical";
902
- if (properties.knob) {
903
- parameters.knob = properties.knob;
1372
+ return nodes;
1373
+ }
1374
+ function buildRulerLabels(component, box) {
1375
+ const labels = component.labels ?? {};
1376
+ const horizontal = component.parameters.axis === "horizontal";
1377
+ const ticks = Math.max(1, finite(Number(component.parameters.ticks), 50));
1378
+ const major = Math.max(1, finite(Number(component.parameters.major), 5));
1379
+ const inset = finite(Number(component.parameters.inset), 0.05) > 0 ? finite(Number(component.parameters.inset), 0.05) : 0.05;
1380
+ const line = finite(Number(component.parameters.line), 0.7) > 0 ? finite(Number(component.parameters.line), 0.7) : 0.7;
1381
+ const across = horizontal ? box.height : box.width;
1382
+ const tickLength = (finite(Number(component.parameters.length), 0.1) > 0 ? finite(Number(component.parameters.length), 0.1) : 0.1) * across * 1.9;
1383
+ const edge = line * across - 0.12 * across - tickLength - finite(labels.offset, 0.04) * across;
1384
+ const fontSize = finite(labels.size, 12);
1385
+ const count = Math.floor(ticks / major);
1386
+ const nodes = [];
1387
+ for (let step = 0; step <= count; step += 1) {
1388
+ const fraction = step * major / ticks;
1389
+ const along = inset + (1 - 2 * inset) * fraction;
1390
+ 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 };
1391
+ nodes.push({
1392
+ id: `widget-${component.id}-label-${step}`,
1393
+ type: "text",
1394
+ order: box.order + 0.1,
1395
+ bounds: rotatedBounds(labelBox, 0, 2),
1396
+ ...labelBox,
1397
+ lines: [String(Math.round((box.min + (box.max - box.min) * fraction) * 10) / 10)],
1398
+ fontFamily: labels.fontFamily || DEFAULT_FONT,
1399
+ fontSize,
1400
+ fontWeight: labels.weight ?? "normal",
1401
+ color: labels.color || "#8f95c4",
1402
+ align: horizontal ? "center" : "right",
1403
+ verticalAlign: "middle",
1404
+ lineHeight: 1.3
1405
+ });
904
1406
  }
1407
+ return nodes;
1408
+ }
1409
+
1410
+ // src/renderScene/artifacts/component/controlParts.ts
1411
+ var DISABLED_INK = "#94a3b8";
1412
+ function controlBox(component, index, fallback) {
905
1413
  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
1414
+ x: finite(component.x, 0),
1415
+ y: finite(component.y, 0),
1416
+ width: Math.max(1, finite(component.width, fallback.width)),
1417
+ height: Math.max(1, finite(component.height, fallback.height)),
1418
+ order: 1e4 + index
928
1419
  };
929
1420
  }
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;
1421
+ var textProperty = (component, key) => String(component.properties[key] ?? "");
1422
+ var numberProperty2 = (component, key) => Number(component.properties[key] ?? 0);
1423
+ var solid = (color) => ({ kind: "solid", color });
1424
+ var ink = (component, color) => component.disabled ? DISABLED_INK : color;
1425
+ function fade(component, style) {
1426
+ return component.disabled ? { ...style, opacity: 0.4 } : style;
1427
+ }
1428
+ function hitArea(component, box) {
938
1429
  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
- }
1430
+ id: `widget-${component.id}`,
1431
+ type: "rect",
1432
+ order: box.order,
1433
+ bounds: rotatedBounds(box, 0, 0),
1434
+ x: box.x,
1435
+ y: box.y,
1436
+ width: box.width,
1437
+ height: box.height,
1438
+ style: { fill: { kind: "none" }, stroke: { kind: "none" }, pointerEvents: "all" }
964
1439
  };
965
1440
  }
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]));
1441
+ function labelText(component, part, area, label, order) {
972
1442
  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)
1443
+ id: `widget-${component.id}-${part}`,
1444
+ type: "text",
1445
+ order,
1446
+ bounds: rotatedBounds(area, 0, 0),
1447
+ x: area.x,
1448
+ y: area.y,
1449
+ width: area.width,
1450
+ height: area.height,
1451
+ lines: [label.text],
1452
+ fontFamily: DEFAULT_FONT,
1453
+ fontSize: label.fontSize,
1454
+ fontWeight: "600",
1455
+ color: label.color,
1456
+ align: label.align,
1457
+ verticalAlign: "middle",
1458
+ lineHeight: 1.3
984
1459
  };
985
1460
  }
986
1461
 
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(
1462
+ // src/renderScene/artifacts/component/button.ts
1463
+ function buildButton(component, index) {
1464
+ const box = controlBox(component, index, { width: 120, height: 40 });
1465
+ const nodes = [
1466
+ hitArea(component, box),
1007
1467
  {
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;
1468
+ id: `widget-${component.id}-face`,
1469
+ type: "rect",
1470
+ order: box.order + 0.1,
1471
+ bounds: rotatedBounds(box, 0, 0),
1472
+ x: box.x,
1473
+ y: box.y,
1474
+ width: box.width,
1475
+ height: box.height,
1476
+ rx: Math.min(numberProperty2(component, "radius"), box.height / 2),
1477
+ style: fade(component, { fill: solid(textProperty(component, "accent")), stroke: { kind: "none" } })
1478
+ }
1479
+ ];
1480
+ if (component.label) {
1481
+ const label = {
1482
+ text: component.label,
1483
+ color: ink(component, textProperty(component, "textColor")),
1484
+ fontSize: numberProperty2(component, "fontSize"),
1485
+ align: "center"
1486
+ };
1487
+ nodes.push(labelText(component, "label", box, label, box.order + 0.2));
1030
1488
  }
1031
- return automaticEndpointPoint(
1032
- canvasObject,
1033
- findPositionedCanvasObject(canvasObjects, selected.oppositeCanvasObjectId)
1034
- );
1035
- }
1036
- function selectLinkEndpoint(link, end) {
1037
- return end === "from" ? { canvasObjectId: link.fromId, oppositeCanvasObjectId: link.toId, explicit: link.fromPoint } : { canvasObjectId: link.toId, oppositeCanvasObjectId: link.fromId, explicit: link.toPoint };
1489
+ return nodes;
1038
1490
  }
1039
- function explicitAbsolutePoint(endpoint) {
1040
- return endpoint?.kind === "absolute" ? { x: endpoint.x, y: endpoint.y } : null;
1491
+
1492
+ // src/renderScene/artifacts/component/checkbox.ts
1493
+ var CORNER_RATIO = 0.22;
1494
+ var LABEL_GAP_RATIO = 0.5;
1495
+ var CHECK_MARK = [
1496
+ [0.24, 0.52],
1497
+ [0.43, 0.72],
1498
+ [0.78, 0.3]
1499
+ ];
1500
+ function checkPath(square) {
1501
+ const [first, ...rest] = CHECK_MARK.map(([u, v]) => `${square.x + u * square.width} ${square.y + v * square.width}`);
1502
+ return `M ${first} ${rest.map((point) => `L ${point}`).join(" ")}`;
1041
1503
  }
1042
- function explicitAnchorPoint(canvasObject, endpoint) {
1043
- if (endpoint?.kind === "port") {
1044
- return namedPortPoint(canvasObject, endpoint);
1045
- }
1046
- if (endpoint?.kind === "side") {
1047
- return sidePoint(canvasObject, endpoint);
1048
- }
1049
- return null;
1504
+ function boxNode(component, box, square) {
1505
+ const on = component.value === true;
1506
+ return {
1507
+ id: `widget-${component.id}-box`,
1508
+ type: "rect",
1509
+ order: box.order + 0.1,
1510
+ bounds: rotatedBounds(square, 0, 2),
1511
+ ...square,
1512
+ rx: square.width * CORNER_RATIO,
1513
+ style: fade(component, {
1514
+ fill: on ? solid(textProperty(component, "accent")) : { kind: "none" },
1515
+ stroke: solid(on ? textProperty(component, "accent") : textProperty(component, "stroke")),
1516
+ strokeWidth: 1.5
1517
+ })
1518
+ };
1050
1519
  }
1051
- function automaticEndpointPoint(canvasObject, opposite) {
1052
- return opposite ? edgePointToward(canvasObject, opposite) : elementCenter(canvasObject);
1520
+ function checkNode(component, box, square) {
1521
+ return {
1522
+ id: `widget-${component.id}-check`,
1523
+ type: "path",
1524
+ order: box.order + 0.2,
1525
+ bounds: rotatedBounds(square, 0, 0),
1526
+ d: checkPath(square),
1527
+ style: fade(component, {
1528
+ fill: { kind: "none" },
1529
+ stroke: solid(textProperty(component, "check")),
1530
+ strokeWidth: Math.max(1.5, square.width * 0.12),
1531
+ lineCap: "round",
1532
+ lineJoin: "round"
1533
+ })
1534
+ };
1053
1535
  }
1054
- function findPositionedCanvasObject(canvasObjects, id) {
1055
- return canvasObjects.find((candidate) => candidate.id === id);
1536
+ function labelNode(component, box, side, text) {
1537
+ const gap = side * LABEL_GAP_RATIO;
1538
+ const area = { x: box.x + side + gap, y: box.y, width: Math.max(0, box.width - side - gap), height: box.height };
1539
+ const label = {
1540
+ text,
1541
+ color: ink(component, textProperty(component, "textColor")),
1542
+ fontSize: numberProperty2(component, "fontSize"),
1543
+ align: "left"
1544
+ };
1545
+ return labelText(component, "label", area, label, box.order + 0.3);
1056
1546
  }
1057
-
1058
- // src/renderInput/fromSfl/links.ts
1059
- var ISOMETRIC_SEQUENCE_BASE = 15e3;
1060
- function positionedCanvasObjects(canvasObjects) {
1547
+ function buildCheckbox(component, index) {
1548
+ const box = controlBox(component, index, { width: 160, height: 24 });
1549
+ const side = Math.min(box.height, box.width);
1550
+ const square = { x: box.x, y: box.y + (box.height - side) / 2, width: side, height: side };
1061
1551
  return [
1062
- ...canvasObjects.shapes,
1063
- ...canvasObjects.frames,
1064
- ...canvasObjects.swimlanes,
1065
- ...canvasObjects.paths,
1066
- ...canvasObjects.charts
1552
+ hitArea(component, box),
1553
+ boxNode(component, box, square),
1554
+ ...component.value === true ? [checkNode(component, box, square)] : [],
1555
+ ...component.label ? [labelNode(component, box, side, component.label)] : []
1067
1556
  ];
1068
1557
  }
1069
- function connectionEndpointPoint(object, face) {
1070
- return object ? isometricFaceCenter(object, face) : { x: 0, y: 0 };
1071
- }
1072
- function isometricStackPosition(isometricObjects, id) {
1073
- const index = isometricObjects.findIndex((object2) => object2.id === id);
1074
- if (index < 0) {
1075
- return void 0;
1076
- }
1077
- const object = isometricObjects[index];
1078
- return { rank: object.order ?? 0, sequence: object.sourceIndex ?? ISOMETRIC_SEQUENCE_BASE + index };
1558
+
1559
+ // src/renderScene/artifacts/component/switch.ts
1560
+ var PADDING_RATIO = 0.12;
1561
+ function buildSwitch(component, index) {
1562
+ const box = controlBox(component, index, { width: 52, height: 30 });
1563
+ const on = component.value === true;
1564
+ const padding = box.height * PADDING_RATIO;
1565
+ const radius = box.height / 2 - padding;
1566
+ const centerX = on ? box.x + box.width - box.height / 2 : box.x + box.height / 2;
1567
+ const thumb = { x: centerX - radius, y: box.y + padding, width: radius * 2, height: radius * 2 };
1568
+ return [
1569
+ hitArea(component, box),
1570
+ {
1571
+ id: `widget-${component.id}-track`,
1572
+ type: "rect",
1573
+ order: box.order + 0.1,
1574
+ bounds: rotatedBounds(box, 0, 0),
1575
+ x: box.x,
1576
+ y: box.y,
1577
+ width: box.width,
1578
+ height: box.height,
1579
+ rx: box.height / 2,
1580
+ style: fade(component, {
1581
+ fill: solid(textProperty(component, on ? "accent" : "track")),
1582
+ stroke: { kind: "none" }
1583
+ })
1584
+ },
1585
+ {
1586
+ id: `widget-${component.id}-thumb`,
1587
+ type: "ellipse",
1588
+ order: box.order + 0.2,
1589
+ bounds: rotatedBounds(thumb, 0, 0),
1590
+ cx: centerX,
1591
+ cy: box.y + box.height / 2,
1592
+ rx: radius,
1593
+ ry: radius,
1594
+ style: fade(component, {
1595
+ fill: solid(textProperty(component, "thumb")),
1596
+ stroke: { kind: "none" },
1597
+ shadow: { color: "#000000", opacity: 0.25, blur: 2, dx: 0, dy: 1 }
1598
+ })
1599
+ }
1600
+ ];
1079
1601
  }
1080
- function connectionStack(isometricObjects, connection) {
1081
- if (typeof connection.order === "number") {
1082
- return { order: connection.order, sourceIndex: connection.sourceIndex };
1083
- }
1084
- const behind = [
1085
- VISIBLE_ISOMETRIC_FACES.has(connection.fromFace) ? void 0 : isometricStackPosition(isometricObjects, connection.fromId),
1086
- VISIBLE_ISOMETRIC_FACES.has(connection.toFace) ? void 0 : isometricStackPosition(isometricObjects, connection.toId)
1087
- ].filter((position) => position !== void 0);
1088
- if (!behind.length) {
1089
- return { sourceIndex: connection.sourceIndex };
1602
+
1603
+ // src/renderScene/artifacts/component/toggleButton.ts
1604
+ function buildToggleButton(component, index) {
1605
+ const box = controlBox(component, index, { width: 120, height: 40 });
1606
+ const on = component.value === true;
1607
+ const nodes = [
1608
+ hitArea(component, box),
1609
+ {
1610
+ id: `widget-${component.id}-face`,
1611
+ type: "rect",
1612
+ order: box.order + 0.1,
1613
+ bounds: rotatedBounds(box, 0, 2),
1614
+ x: box.x,
1615
+ y: box.y,
1616
+ width: box.width,
1617
+ height: box.height,
1618
+ rx: box.height / 2,
1619
+ style: fade(component, {
1620
+ fill: on ? solid(textProperty(component, "accent")) : { kind: "none" },
1621
+ stroke: solid(on ? textProperty(component, "accent") : textProperty(component, "stroke")),
1622
+ strokeWidth: 1.5
1623
+ })
1624
+ }
1625
+ ];
1626
+ if (component.label) {
1627
+ const label = {
1628
+ text: component.label,
1629
+ color: ink(component, textProperty(component, on ? "onTextColor" : "textColor")),
1630
+ fontSize: numberProperty2(component, "fontSize"),
1631
+ align: "center"
1632
+ };
1633
+ nodes.push(labelText(component, "label", box, label, box.order + 0.2));
1090
1634
  }
1091
- const lowest = behind.reduce(
1092
- (best, position) => position.rank < best.rank || position.rank === best.rank && position.sequence < best.sequence ? position : best
1093
- );
1094
- return { order: lowest.rank, sourceIndex: lowest.sequence - 0.5 };
1635
+ return nodes;
1095
1636
  }
1096
- function createRenderInputConnections(canvasObjects) {
1097
- const isometricById = new Map(canvasObjects.isometricObjects.map((object) => [object.id, object]));
1098
- return canvasObjects.connections.map((connection) => {
1099
- const link = {
1100
- id: connection.id,
1101
- fromId: connection.fromId,
1102
- toId: connection.toId,
1103
- fromPoint: { kind: "face", face: connection.fromFace },
1104
- toPoint: { kind: "face", face: connection.toFace },
1105
- style: connection.style,
1106
- ...connectionStack(canvasObjects.isometricObjects, connection)
1107
- };
1108
- return {
1109
- link,
1110
- from: connectionEndpointPoint(isometricById.get(connection.fromId ?? ""), connection.fromFace),
1111
- to: connectionEndpointPoint(isometricById.get(connection.toId ?? ""), connection.toFace),
1112
- kind: "connection"
1113
- };
1114
- });
1637
+
1638
+ // src/renderScene/artifacts/component/registry.ts
1639
+ var asComponentBuilder = (build) => (component, index) => build(component, index);
1640
+ var builders = /* @__PURE__ */ new Map([
1641
+ ["rollingNumber", asComponentBuilder(buildRollingNumber)],
1642
+ ["tickScale", asComponentBuilder(buildTickScale)],
1643
+ ["ruler", asComponentBuilder(buildRuler)],
1644
+ ["switch", asComponentBuilder(buildSwitch)],
1645
+ ["checkbox", asComponentBuilder(buildCheckbox)],
1646
+ ["toggleButton", asComponentBuilder(buildToggleButton)],
1647
+ ["button", asComponentBuilder(buildButton)]
1648
+ ]);
1649
+ function registerComponentBuilder(type, builder) {
1650
+ builders.set(type, builder);
1651
+ return () => {
1652
+ if (builders.get(type) === builder) {
1653
+ builders.delete(type);
1654
+ }
1655
+ };
1115
1656
  }
1116
- function createRenderInputLinks(canvasObjects) {
1117
- const positionedObjects = positionedCanvasObjects(canvasObjects);
1118
- const links = canvasObjects.links.map((link) => ({
1119
- link,
1120
- from: resolveLinkEndpoint(link, "from", positionedObjects),
1121
- to: resolveLinkEndpoint(link, "to", positionedObjects)
1122
- }));
1123
- return [...links, ...createRenderInputConnections(canvasObjects)];
1657
+ function getComponentBuilder(type) {
1658
+ return builders.get(type);
1124
1659
  }
1125
1660
 
1126
- // src/renderInput/fromSfl/index.ts
1127
- function sflToRenderInput(sfl) {
1128
- const state = sflToCanvasState(sfl);
1129
- const canvasObjects = collectCanvasObjects(state);
1661
+ // src/renderScene/artifacts/component/build.ts
1662
+ function ariaOf(component) {
1663
+ const role = getComponentDescriptor(component.type)?.role;
1664
+ if (!role || !isGenericComponent(component)) {
1665
+ return void 0;
1666
+ }
1667
+ const flag = typeof component.value === "boolean" ? component.value : void 0;
1130
1668
  return {
1131
- shapes: canvasObjects.shapes,
1132
- frames: canvasObjects.frames,
1133
- swimlanes: canvasObjects.swimlanes,
1134
- isometricObjects: canvasObjects.isometricObjects,
1135
- paths: canvasObjects.paths,
1136
- charts: canvasObjects.charts,
1137
- widgets: canvasObjects.widgets,
1138
- links: createRenderInputLinks(canvasObjects),
1139
- diagnostics: state.diagnostics
1669
+ role,
1670
+ ...flag === void 0 ? {} : role === "button" ? { pressed: flag } : { checked: flag },
1671
+ ...component.disabled ? { disabled: true } : {}
1140
1672
  };
1141
1673
  }
1674
+ function labelOf(component) {
1675
+ return component.label ?? (isGenericComponent(component) ? component.id : String(component.value));
1676
+ }
1677
+ function buildComponents(components) {
1678
+ return components.flatMap((component, index) => {
1679
+ const build = getComponentBuilder(component.type) ?? buildPlaceholder;
1680
+ const nodes = tag(
1681
+ build(component, index),
1682
+ "widget",
1683
+ component.id,
1684
+ component.type,
1685
+ labelOf(component),
1686
+ component.parentFrameId
1687
+ );
1688
+ const aria = ariaOf(component);
1689
+ const primary = nodes.find((node) => node.identity?.primary);
1690
+ if (aria && primary?.identity) {
1691
+ primary.identity.aria = aria;
1692
+ }
1693
+ return nodes;
1694
+ });
1695
+ }
1142
1696
 
1143
1697
  // src/renderScene/artifacts/container/style.ts
1144
1698
  function simpleContainerStyle(fill2, stroke, strokeWidth, dash) {
@@ -1578,12 +2132,12 @@ function faceNodes(context, faces, hullClip) {
1578
2132
  const noStroke = { ...common.style, stroke: { kind: "none" } };
1579
2133
  const faceFills = deriveFaceFills(object.fill ?? "#f8fafc");
1580
2134
  const colorProp = { prop: "style.fill", propKind: "color", propSolidOnly: true };
1581
- const face = (name, offset, points, color2) => ({
2135
+ const face = (name, offset, points, color) => ({
1582
2136
  ...common,
1583
2137
  id: `isometric-${object.id}-${name}`,
1584
2138
  order: order + offset,
1585
2139
  d: roundedPolygonPath(points, 0),
1586
- style: { ...noStroke, fill: { kind: "solid", color: color2 }, clip: hullClip },
2140
+ style: { ...noStroke, fill: { kind: "solid", color }, clip: hullClip },
1587
2141
  ...colorProp
1588
2142
  });
1589
2143
  return [
@@ -1872,13 +2426,13 @@ function labelLayout(link, measureText) {
1872
2426
  const lines = visible ? wrapText(link.text ?? "", width, fontSize, metrics) : [];
1873
2427
  return { visible, fontSize, width, height: lines.length * fontSize * 1.4, lines };
1874
2428
  }
1875
- function linkStyle(item, strokeWidth, color2, dash) {
2429
+ function linkStyle(item, strokeWidth, color, dash) {
1876
2430
  const link = item.link;
1877
2431
  const stroke = typeof link.style?.color === "object" && link.style.color.type === "gradient" ? {
1878
2432
  kind: "linear-gradient",
1879
2433
  angle: 0,
1880
2434
  stops: link.style.color.stops.map((stop) => ({ offset: stop.position, color: stop.color }))
1881
- } : { kind: "solid", color: color2 };
2435
+ } : { kind: "solid", color };
1882
2436
  return {
1883
2437
  fill: { kind: "none" },
1884
2438
  stroke,
@@ -1895,7 +2449,7 @@ function createLinkRenderContext(item, index, measureText) {
1895
2449
  const pathType = link.style?.pathType ?? "orthogonal";
1896
2450
  const { points, segments } = calculateLinkRoute(link, from, to, pathType);
1897
2451
  const strokeWidth = finite(link.style?.strokeWidth, 2);
1898
- const color2 = getLinkStrokeColor(link.style?.color) || "#64748b";
2452
+ const color = getLinkStrokeColor(link.style?.color) || "#64748b";
1899
2453
  const label = labelLayout(link, measureText);
1900
2454
  const contentDash = getDashArray(strokeWidth, link.style?.strokeStyle ?? "solid");
1901
2455
  const gap = label.visible && !contentDash ? labelGapDash(points, pathType, label.width, label.height) : null;
@@ -1908,9 +2462,9 @@ function createLinkRenderContext(item, index, measureText) {
1908
2462
  midpoint: getLineMidpoint(points, pathType, from, to),
1909
2463
  strokeWidth,
1910
2464
  bounds: linkBounds(points, strokeWidth + 14),
1911
- color: color2,
2465
+ color,
1912
2466
  order: 2e4 + index,
1913
- style: linkStyle(item, strokeWidth, color2, dash),
2467
+ style: linkStyle(item, strokeWidth, color, dash),
1914
2468
  label,
1915
2469
  hasLabelGap: Boolean(gap)
1916
2470
  };
@@ -2510,211 +3064,6 @@ function buildShapes(shapes, diagnostics, measureText) {
2510
3064
  );
2511
3065
  }
2512
3066
 
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
3067
  // src/renderScene/charts/decorations/axisLabels.ts
2719
3068
  function buildXAxisLabel(chart, layout, order) {
2720
3069
  if (!chart.axisX.label) {
@@ -2869,7 +3218,7 @@ function createLegendSwatch(render2, item) {
2869
3218
  const { chart, bounds, diagnostics } = render2;
2870
3219
  const fallback = CHART_COLORS[item.seriesIndex % CHART_COLORS.length];
2871
3220
  const solidOnly = chart.chartType === "line";
2872
- const color2 = solidOnly ? representativeColor(item.series.color, fallback) : item.series.color ?? fallback;
3221
+ const color = solidOnly ? representativeColor(item.series.color, fallback) : item.series.color ?? fallback;
2873
3222
  return {
2874
3223
  type: "rect",
2875
3224
  id: `chart-legend-swatch-${chart.id}-${item.series.id}`,
@@ -2883,7 +3232,7 @@ function createLegendSwatch(render2, item) {
2883
3232
  prop: seriesColorProp(item.series.id),
2884
3233
  propKind: "color",
2885
3234
  propSolidOnly: solidOnly,
2886
- style: { fill: paint(color2, diagnostics, chart.id) }
3235
+ style: { fill: paint(color, diagnostics, chart.id) }
2887
3236
  };
2888
3237
  }
2889
3238
  function createLegendLabel(render2, item) {
@@ -3614,7 +3963,7 @@ function createGlassBackdropNodes(context, id, d) {
3614
3963
  }
3615
3964
 
3616
3965
  // src/renderScene/charts/renderers/bar/glow.ts
3617
- function createBarGlowNode(context, id, d, color2, glow, bounds = context.bounds) {
3966
+ function createBarGlowNode(context, id, d, color, glow, bounds = context.bounds) {
3618
3967
  const { chart, diagnostics, nextOrder } = context;
3619
3968
  return {
3620
3969
  type: "path",
@@ -3623,8 +3972,8 @@ function createBarGlowNode(context, id, d, color2, glow, bounds = context.bounds
3623
3972
  bounds,
3624
3973
  d,
3625
3974
  style: {
3626
- fill: paint(color2, diagnostics, chart.id),
3627
- shadow: { color: representativeColor(color2, "#ffffff"), opacity: 0.9, blur: glow, dx: 0, dy: 0 },
3975
+ fill: paint(color, diagnostics, chart.id),
3976
+ shadow: { color: representativeColor(color, "#ffffff"), opacity: 0.9, blur: glow, dx: 0, dy: 0 },
3628
3977
  pointerEvents: "none"
3629
3978
  }
3630
3979
  };
@@ -3644,7 +3993,7 @@ function labelTop(placement, frame, height) {
3644
3993
  }
3645
3994
  return placement === "inside" ? frame.y + BAR_LABEL.gap : frame.y + frame.height / 2 - height / 2;
3646
3995
  }
3647
- function createPillNode(context, id, box, color2) {
3996
+ function createPillNode(context, id, box, color) {
3648
3997
  const { chart, bounds, diagnostics, nextOrder } = context;
3649
3998
  const config = chart.config;
3650
3999
  return {
@@ -3655,13 +4004,13 @@ function createPillNode(context, id, box, color2) {
3655
4004
  d: pillPath(box.left, box.top, box.width, box.height),
3656
4005
  style: {
3657
4006
  fill: config?.barLabelPillColor ? paint(config.barLabelPillColor, diagnostics, chart.id) : { kind: "none" },
3658
- stroke: paint(config?.barLabelBorderColor ?? color2, diagnostics, chart.id),
4007
+ stroke: paint(config?.barLabelBorderColor ?? color, diagnostics, chart.id),
3659
4008
  strokeWidth: finite(config?.barLabelBorderWidth, 1),
3660
4009
  pointerEvents: "none"
3661
4010
  }
3662
4011
  };
3663
4012
  }
3664
- function createTextNode(context, id, box, text, placement, fontSize, color2) {
4013
+ function createTextNode(context, id, box, text, placement, fontSize, color) {
3665
4014
  const { chart, bounds, nextOrder } = context;
3666
4015
  const config = chart.config;
3667
4016
  return {
@@ -3675,7 +4024,7 @@ function createTextNode(context, id, box, text, placement, fontSize, color2) {
3675
4024
  align: "center"
3676
4025
  }),
3677
4026
  mark: `bar-label|${placement}|${config?.barLabelFormat ?? ""}`,
3678
- color: color2,
4027
+ color,
3679
4028
  fontSize,
3680
4029
  fontFamily: config?.barLabelFontFamily ?? chart.fontFamily ?? "Inter, sans-serif",
3681
4030
  fontWeight: config?.barLabelFontWeight ?? "normal"
@@ -3733,12 +4082,12 @@ function createBarLabelNodes(context, target) {
3733
4082
  left: target.frame.x + target.frame.width / 2 - size.width / 2,
3734
4083
  top: labelTop(placement, target.frame, size.height)
3735
4084
  };
3736
- const color2 = config?.barLabelColor ?? chart.textColor ?? "#0f172a";
4085
+ const color = config?.barLabelColor ?? chart.textColor ?? "#0f172a";
3737
4086
  const nodes = [];
3738
4087
  if (pill) {
3739
- nodes.push(createPillNode(context, target.id, box, color2));
4088
+ nodes.push(createPillNode(context, target.id, box, color));
3740
4089
  }
3741
- nodes.push(createTextNode(context, target.id, box, text, placement, fontSize, color2));
4090
+ nodes.push(createTextNode(context, target.id, box, text, placement, fontSize, color));
3742
4091
  return nodes;
3743
4092
  }
3744
4093
 
@@ -4474,12 +4823,12 @@ function renderBoxplotSeries(context, layout, series, seriesIndex) {
4474
4823
  return [];
4475
4824
  }
4476
4825
  const geometry = createBoxplotGeometry(context, layout, seriesIndex, stats);
4477
- const color2 = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
4826
+ const color = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
4478
4827
  const mark = {
4479
4828
  id: `${context.chart.id}-${series.id}`,
4480
4829
  series,
4481
4830
  seriesIndex,
4482
- color: color2,
4831
+ color,
4483
4832
  geometry
4484
4833
  };
4485
4834
  const nodes = renderBoxAndWhiskers(context, layout, mark);
@@ -4541,9 +4890,9 @@ function customPointPosition(context, value) {
4541
4890
  };
4542
4891
  }
4543
4892
  function customSeriesStyle(context, series, seriesIndex) {
4544
- const color2 = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
4893
+ const color = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
4545
4894
  return {
4546
- fill: paint(color2, context.diagnostics, context.chart.id),
4895
+ fill: paint(color, context.diagnostics, context.chart.id),
4547
4896
  stroke: series.stroke ? { kind: "solid", color: series.stroke } : void 0,
4548
4897
  strokeWidth: series.stroke ? finite(series.strokeWidth, 1) : void 0
4549
4898
  };
@@ -4642,7 +4991,7 @@ function connectorDash(text) {
4642
4991
  const parts = (text ?? "").split(/[ ,]+/).map(Number).filter((part) => Number.isFinite(part) && part > 0);
4643
4992
  return parts.length > 0 ? parts : void 0;
4644
4993
  }
4645
- function createConnectorLine(context, index, from, to, color2) {
4994
+ function createConnectorLine(context, index, from, to, color) {
4646
4995
  const { chart } = context;
4647
4996
  return {
4648
4997
  type: "path",
@@ -4652,7 +5001,7 @@ function createConnectorLine(context, index, from, to, color2) {
4652
5001
  d: `M ${from.x} ${from.y} L ${to.x} ${to.y}`,
4653
5002
  style: {
4654
5003
  fill: { kind: "none" },
4655
- stroke: { kind: "solid", color: color2 },
5004
+ stroke: { kind: "solid", color },
4656
5005
  strokeWidth: finite(chart.config?.customConnectorWidth, 2),
4657
5006
  opacity: chart.config?.customConnectorOpacity,
4658
5007
  dash: connectorDash(chart.config?.customConnectorDash)
@@ -4956,7 +5305,7 @@ function createFieldCell(context, grid, row, column) {
4956
5305
  const { chart, plot, bounds, nextOrder } = context;
4957
5306
  const centerX = plot.x + plot.width * (column / (grid.columns - 1));
4958
5307
  const centerY = plot.y + plot.height * (row / (grid.rows - 1));
4959
- const color2 = colorAtRamp(chart.config?.scale, grid.values[row * grid.columns + column]);
5308
+ const color = colorAtRamp(chart.config?.scale, grid.values[row * grid.columns + column]);
4960
5309
  return {
4961
5310
  type: "rect",
4962
5311
  id: `chart-field-cell-${chart.id}-${row}-${column}`,
@@ -4966,7 +5315,7 @@ function createFieldCell(context, grid, row, column) {
4966
5315
  y: centerY - grid.cellHeight / 2,
4967
5316
  width: grid.cellWidth,
4968
5317
  height: grid.cellHeight,
4969
- style: { fill: { kind: "solid", color: color2 }, clip: fieldSurfaceClip(chart, plot) }
5318
+ style: { fill: { kind: "solid", color }, clip: fieldSurfaceClip(chart, plot) }
4970
5319
  };
4971
5320
  }
4972
5321
  function renderIsolines(context, grid) {
@@ -5020,14 +5369,14 @@ function createIsoline(context, grid, threshold, thresholdIndex) {
5020
5369
  function renderVectorField(context, seriesList) {
5021
5370
  const nodes = [];
5022
5371
  seriesList.forEach((series, seriesIndex) => {
5023
- const color2 = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
5372
+ const color = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
5024
5373
  series.values.forEach((vector, vectorIndex) => {
5025
- nodes.push(createVectorNode(context, series.id, vector, vectorIndex, color2));
5374
+ nodes.push(createVectorNode(context, series.id, vector, vectorIndex, color));
5026
5375
  });
5027
5376
  });
5028
5377
  return nodes;
5029
5378
  }
5030
- function createVectorNode(context, seriesId, vector, vectorIndex, color2) {
5379
+ function createVectorNode(context, seriesId, vector, vectorIndex, color) {
5031
5380
  const { chart, plot, bounds, diagnostics, nextOrder } = context;
5032
5381
  const [x, y, angle, magnitude] = vector;
5033
5382
  const startX = plot.x + mapChartValue(x, chart.axisX, plot.width);
@@ -5043,7 +5392,7 @@ function createVectorNode(context, seriesId, vector, vectorIndex, color2) {
5043
5392
  markerEnd: "filled_arrow",
5044
5393
  style: {
5045
5394
  fill: { kind: "none" },
5046
- stroke: paint(color2, diagnostics, chart.id),
5395
+ stroke: paint(color, diagnostics, chart.id),
5047
5396
  strokeWidth: 2
5048
5397
  }
5049
5398
  };
@@ -5697,11 +6046,11 @@ function renderHexbin(context) {
5697
6046
  }));
5698
6047
  const bins = computeHexBins(pixelPoints2, hexRadius);
5699
6048
  const maxCount = Math.max(1, ...bins.map((bin) => bin.count));
5700
- const color2 = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
6049
+ const color = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
5701
6050
  const ramp = config?.scale;
5702
6051
  bins.forEach((bin, i) => {
5703
6052
  const share = bin.count / maxCount;
5704
- const fill2 = ramp ? colorAtRamp(ramp, share) : color2;
6053
+ const fill2 = ramp ? colorAtRamp(ramp, share) : color;
5705
6054
  nodes.push({
5706
6055
  type: "path",
5707
6056
  id: `chart-hexbin-${chart.id}-${series.id}-${i}`,
@@ -5738,7 +6087,7 @@ function pixelPoints(context, pairs) {
5738
6087
  }
5739
6088
 
5740
6089
  // src/renderScene/charts/renderers/line/area.ts
5741
- function createLineAreaFill(context, series, points, color2, tension, areaOpacity) {
6090
+ function createLineAreaFill(context, series, points, color, tension, areaOpacity) {
5742
6091
  const { chart, plot, nextOrder } = context;
5743
6092
  const baselineY = plot.y + plot.height;
5744
6093
  const first = points[0];
@@ -5765,8 +6114,8 @@ function createLineAreaFill(context, series, points, color2, tension, areaOpacit
5765
6114
  kind: "linear-gradient",
5766
6115
  angle: 90,
5767
6116
  stops: [
5768
- { offset: 0, color: colorWithAlpha(color2, areaOpacity) },
5769
- { offset: 100, color: colorWithAlpha(color2, 0) }
6117
+ { offset: 0, color: colorWithAlpha(color, areaOpacity) },
6118
+ { offset: 100, color: colorWithAlpha(color, 0) }
5770
6119
  ]
5771
6120
  },
5772
6121
  stroke: { kind: "none" },
@@ -5816,7 +6165,7 @@ function dotNode(context, mark) {
5816
6165
  }
5817
6166
  };
5818
6167
  }
5819
- function labelNode(context, mark, value) {
6168
+ function labelNode2(context, mark, value) {
5820
6169
  const { chart, bounds, nextOrder } = context;
5821
6170
  const config = chart.config;
5822
6171
  const fontSize = Math.max(9, chart.fontSize ?? 12);
@@ -5841,7 +6190,7 @@ function labelNode(context, mark, value) {
5841
6190
  fontWeight: "bold"
5842
6191
  };
5843
6192
  }
5844
- function renderLineHighlights(context, series, color2) {
6193
+ function renderLineHighlights(context, series, color) {
5845
6194
  const { chart } = context;
5846
6195
  const config = chart.config;
5847
6196
  const wanted = config?.highlightPoints;
@@ -5862,28 +6211,28 @@ function renderLineHighlights(context, series, color2) {
5862
6211
  point,
5863
6212
  index,
5864
6213
  radius: config?.highlightSize ?? 6,
5865
- color: config?.highlightColor ?? color2
6214
+ color: config?.highlightColor ?? color
5866
6215
  };
5867
6216
  if (config?.highlightGuide) {
5868
6217
  nodes.push(guideNode(context, mark));
5869
6218
  }
5870
6219
  nodes.push(dotNode(context, mark));
5871
6220
  if (config?.highlightLabels) {
5872
- nodes.push(labelNode(context, mark, pairs[index][1]));
6221
+ nodes.push(labelNode2(context, mark, pairs[index][1]));
5873
6222
  }
5874
6223
  }
5875
6224
  return nodes;
5876
6225
  }
5877
6226
 
5878
6227
  // src/renderScene/charts/renderers/line/marks.ts
5879
- function createLinePointMarks(series, pairs, points, color2) {
6228
+ function createLinePointMarks(series, pairs, points, color) {
5880
6229
  return points.map((position, valueIndex) => ({
5881
6230
  seriesId: series.id,
5882
6231
  valueIndex,
5883
6232
  value: pairs[valueIndex][1],
5884
6233
  error: series.error?.[valueIndex],
5885
6234
  position,
5886
- color: color2
6235
+ color
5887
6236
  }));
5888
6237
  }
5889
6238
  function renderLineMarks(context, marks) {
@@ -5944,7 +6293,7 @@ function createLinePoint(context, mark) {
5944
6293
  }
5945
6294
 
5946
6295
  // src/renderScene/charts/renderers/line/path.ts
5947
- function createLinePath(context, series, points, color2, tension) {
6296
+ function createLinePath(context, series, points, color, tension) {
5948
6297
  const { chart, plot, bounds, diagnostics, nextOrder } = context;
5949
6298
  const config = chart.config;
5950
6299
  const source = series.color;
@@ -5959,12 +6308,12 @@ function createLinePath(context, series, points, color2, tension) {
5959
6308
  d: linePathData(points, tension),
5960
6309
  style: {
5961
6310
  fill: { kind: "none" },
5962
- stroke: paint(gradient ?? color2, diagnostics, chart.id),
6311
+ stroke: paint(gradient ?? color, diagnostics, chart.id),
5963
6312
  strokeWidth: series.strokeWidth ?? config?.lineWidth ?? 2,
5964
6313
  dash: series.dash,
5965
6314
  lineCap: config?.lineWidth === void 0 ? void 0 : "round",
5966
6315
  lineJoin: "round",
5967
- shadow: glow ? { color: color2, opacity: 0.9, blur: glow, dx: 0, dy: 0 } : resolveChartShadow(chart.shadowStyle)
6316
+ shadow: glow ? { color, opacity: 0.9, blur: glow, dx: 0, dy: 0 } : resolveChartShadow(chart.shadowStyle)
5968
6317
  }
5969
6318
  };
5970
6319
  }
@@ -5978,23 +6327,23 @@ function renderLineSeriesArea(context, series, seriesIndex) {
5978
6327
  if (areaOpacity === void 0 || areaOpacity <= 0) {
5979
6328
  return [];
5980
6329
  }
5981
- const color2 = seriesColor(series, seriesIndex);
6330
+ const color = seriesColor(series, seriesIndex);
5982
6331
  const tension = context.chart.config?.lineTension ?? 0;
5983
6332
  const points = pixelPoints(context, seriesValuePairs(context.chart, series));
5984
- return points.length > 1 ? [createLineAreaFill(context, series, points, color2, tension, areaOpacity)] : [];
6333
+ return points.length > 1 ? [createLineAreaFill(context, series, points, color, tension, areaOpacity)] : [];
5985
6334
  }
5986
6335
  function renderLineSeries(context, series, seriesIndex) {
5987
- const color2 = seriesColor(series, seriesIndex);
6336
+ const color = seriesColor(series, seriesIndex);
5988
6337
  const tension = context.chart.config?.lineTension ?? 0;
5989
6338
  const pairs = seriesValuePairs(context.chart, series);
5990
6339
  const points = pixelPoints(context, pairs);
5991
6340
  const nodes = [];
5992
6341
  if (points.length) {
5993
- nodes.push(createLinePath(context, series, points, color2, tension));
6342
+ nodes.push(createLinePath(context, series, points, color, tension));
5994
6343
  }
5995
- const marks = createLinePointMarks(series, pairs, points, color2);
6344
+ const marks = createLinePointMarks(series, pairs, points, color);
5996
6345
  nodes.push(...renderLineMarks(context, marks));
5997
- nodes.push(...renderLineHighlights(context, series, color2));
6346
+ nodes.push(...renderLineHighlights(context, series, color));
5998
6347
  return nodes;
5999
6348
  }
6000
6349
 
@@ -6203,13 +6552,13 @@ function calculateColumnSegments(seriesList, layout, columnIndex) {
6203
6552
  const height = (column.total > 0 ? value / column.total : 0) * column.height;
6204
6553
  const y = column.y + cumulativeHeight;
6205
6554
  cumulativeHeight += height;
6206
- const color2 = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
6555
+ const color = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
6207
6556
  segments.push({
6208
6557
  columnIndex,
6209
6558
  seriesId: series.id,
6210
6559
  seriesLabel: series.label,
6211
6560
  value,
6212
- color: color2,
6561
+ color,
6213
6562
  isTop: seriesIndex === 0,
6214
6563
  frame: {
6215
6564
  x: column.x,
@@ -6566,7 +6915,7 @@ function clampedCorner(layout, outerRadius, angles) {
6566
6915
  function wedgeNodes(context, layout, series, angles, outerRadius, value, rawColor) {
6567
6916
  const { chart, bounds, diagnostics, nextOrder } = context;
6568
6917
  const { centerX, centerY, innerRadius, maxRadius, gapPx } = layout;
6569
- const color2 = paint(rawColor, diagnostics, chart.id);
6918
+ const color = paint(rawColor, diagnostics, chart.id);
6570
6919
  const shadow = resolveChartShadow(chart.shadowStyle);
6571
6920
  const trackPath = createPieSlicePath(
6572
6921
  { centerX, centerY, outerRadius: maxRadius, innerRadius },
@@ -6598,7 +6947,7 @@ function wedgeNodes(context, layout, series, angles, outerRadius, value, rawColo
6598
6947
  order: nextOrder(),
6599
6948
  bounds,
6600
6949
  d: wedgePath,
6601
- style: { fill: color2, shadow, clip: { type: "path", d: trackPath } }
6950
+ style: { fill: color, shadow, clip: { type: "path", d: trackPath } }
6602
6951
  } : void 0;
6603
6952
  const wedge = {
6604
6953
  type: "path",
@@ -6616,7 +6965,7 @@ function wedgeNodes(context, layout, series, angles, outerRadius, value, rawColo
6616
6965
  pieValue: value
6617
6966
  },
6618
6967
  prop: seriesValueProp(series.id, 0),
6619
- style: { fill: color2, innerShadow: shadow, ...wedgeStroke(context) }
6968
+ style: { fill: color, innerShadow: shadow, ...wedgeStroke(context) }
6620
6969
  };
6621
6970
  return shadowCaster ? [track, shadowCaster, wedge] : [track, wedge];
6622
6971
  }
@@ -6711,11 +7060,11 @@ function labelPlacement2(context, geometry, angles, series, fillColor) {
6711
7060
  const outside = hasManualOffset || !fitsInline;
6712
7061
  const tickStart = pieArcPoint(geometry, mid, geometry.outerRadius + LEADER_INSET);
6713
7062
  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(
7063
+ const color = outside ? outsideLabels && context.chart.textColor ? context.chart.textColor : sameHueTint(representativeColor(fillColor, OUTSIDE_FALLBACK_COLOR), OUTSIDE_TINT_LIGHTNESS) ?? OUTSIDE_FALLBACK_COLOR : sameHueContrastColor(
6715
7064
  representativeColor(fillColor, "#0f172a"),
6716
7065
  contrastTextColor(representativeColor(fillColor, "#0f172a"))
6717
7066
  );
6718
- return { point, color: color2, outside, mid, tickStart };
7067
+ return { point, color, outside, mid, tickStart };
6719
7068
  }
6720
7069
  function createWedgeLabel(context, geometry, angles, series, value, fillColor) {
6721
7070
  const placement = labelPlacement2(context, geometry, angles, series, fillColor);
@@ -6723,7 +7072,7 @@ function createWedgeLabel(context, geometry, angles, series, value, fillColor) {
6723
7072
  return [];
6724
7073
  }
6725
7074
  const { chart, bounds, nextOrder } = context;
6726
- const { point, color: color2, outside, mid, tickStart } = placement;
7075
+ const { point, color, outside, mid, tickStart } = placement;
6727
7076
  const { nameSize, valueSize } = labelSizes(chart);
6728
7077
  const lineHeight = Math.max(nameSize, valueSize) * 1.2;
6729
7078
  const tickEnd = outside ? clipSegmentToRect(tickStart, point, LABEL_WIDTH / 2, lineHeight) : tickStart;
@@ -6734,7 +7083,7 @@ function createWedgeLabel(context, geometry, angles, series, value, fillColor) {
6734
7083
  bounds,
6735
7084
  d: `M ${tickStart.x} ${tickStart.y} L ${tickEnd.x} ${tickEnd.y}`,
6736
7085
  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" } }
7086
+ style: outside ? { stroke: { kind: "solid", color }, strokeWidth: 1.5 } : { stroke: { kind: "none" } }
6738
7087
  };
6739
7088
  const detail = {
6740
7089
  of: "chartSeries",
@@ -6752,7 +7101,7 @@ function createWedgeLabel(context, geometry, angles, series, value, fillColor) {
6752
7101
  align: "center",
6753
7102
  verticalAlign: "middle",
6754
7103
  lineHeight: 1.2,
6755
- color: color2
7104
+ color
6756
7105
  };
6757
7106
  const valueFirst = chart.config?.polarValueFirst ?? false;
6758
7107
  const nameHeight = nameSize * 1.2;
@@ -6953,13 +7302,13 @@ function renderRadarSeries(context, geometry) {
6953
7302
  return nodes;
6954
7303
  }
6955
7304
  function renderSeries(context, geometry, series, seriesIndex) {
6956
- const color2 = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
7305
+ const color = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
6957
7306
  const points = seriesPoints(series, context, geometry);
6958
7307
  const path = radarSeriesPath(points, geometry.circular, geometry.tension);
6959
7308
  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) : []
7309
+ createSeriesFill(context, geometry, series, path, color),
7310
+ ...geometry.strokeWidth > 0 ? [createSeriesStroke(context, geometry, series, path, color)] : [],
7311
+ ...geometry.pointSize > 0 ? createSeriesPoints(context, geometry, series, points, color) : []
6963
7312
  ];
6964
7313
  }
6965
7314
  function seriesPoints(series, context, geometry) {
@@ -6968,7 +7317,7 @@ function seriesPoints(series, context, geometry) {
6968
7317
  (_, categoryIndex) => geometry.pointAt(geometry.radiusForValue(values[categoryIndex] ?? context.chart.axisY.min), categoryIndex)
6969
7318
  );
6970
7319
  }
6971
- function createSeriesFill(context, geometry, series, path, color2) {
7320
+ function createSeriesFill(context, geometry, series, path, color) {
6972
7321
  const { chart, bounds, diagnostics, nextOrder } = context;
6973
7322
  return {
6974
7323
  type: "path",
@@ -6978,13 +7327,13 @@ function createSeriesFill(context, geometry, series, path, color2) {
6978
7327
  d: path,
6979
7328
  detail: { of: "chartSeries", series: series.id },
6980
7329
  style: {
6981
- fill: paint(color2, diagnostics, chart.id),
7330
+ fill: paint(color, diagnostics, chart.id),
6982
7331
  stroke: { kind: "none" },
6983
7332
  opacity: Math.max(0, Math.min(1, series.opacity ?? geometry.areaOpacity))
6984
7333
  }
6985
7334
  };
6986
7335
  }
6987
- function createSeriesStroke(context, geometry, series, path, color2) {
7336
+ function createSeriesStroke(context, geometry, series, path, color) {
6988
7337
  const { chart, bounds, diagnostics, nextOrder } = context;
6989
7338
  return {
6990
7339
  type: "path",
@@ -6995,14 +7344,14 @@ function createSeriesStroke(context, geometry, series, path, color2) {
6995
7344
  detail: { of: "chartSeries", series: series.id },
6996
7345
  style: {
6997
7346
  fill: { kind: "none" },
6998
- stroke: paint(color2, diagnostics, chart.id),
7347
+ stroke: paint(color, diagnostics, chart.id),
6999
7348
  strokeWidth: geometry.strokeWidth,
7000
7349
  lineJoin: "round",
7001
7350
  shadow: resolveChartShadow(chart.shadowStyle)
7002
7351
  }
7003
7352
  };
7004
7353
  }
7005
- function createSeriesPoints(context, geometry, series, points, color2) {
7354
+ function createSeriesPoints(context, geometry, series, points, color) {
7006
7355
  const { chart, bounds, diagnostics, nextOrder } = context;
7007
7356
  return points.map((point, pointIndex) => ({
7008
7357
  type: "ellipse",
@@ -7015,7 +7364,7 @@ function createSeriesPoints(context, geometry, series, points, color2) {
7015
7364
  ry: geometry.pointSize,
7016
7365
  detail: { of: "chartValue", series: series.id, valueIndex: pointIndex, mark: "radar-vertex" },
7017
7366
  prop: seriesValueProp(series.id, pointIndex),
7018
- style: { fill: paint(color2, diagnostics, chart.id) }
7367
+ style: { fill: paint(color, diagnostics, chart.id) }
7019
7368
  }));
7020
7369
  }
7021
7370
 
@@ -7084,7 +7433,7 @@ function layoutOf2(context) {
7084
7433
  cap: chart.config?.ringCap ?? "round"
7085
7434
  };
7086
7435
  }
7087
- function ringEndShadows(context, layout, series, radius, sweep, color2) {
7436
+ function ringEndShadows(context, layout, series, radius, sweep, color) {
7088
7437
  const { chart, bounds, nextOrder } = context;
7089
7438
  const { centerX, centerY, ringThickness, start } = layout;
7090
7439
  const shadow = resolveChartShadow(chart.shadowStyle);
@@ -7106,7 +7455,7 @@ function ringEndShadows(context, layout, series, radius, sweep, color2) {
7106
7455
  d: arcSegmentPath(centerX, centerY, radius, from, to),
7107
7456
  style: {
7108
7457
  fill: { kind: "none" },
7109
- stroke: color2,
7458
+ stroke: color,
7110
7459
  strokeWidth: ringThickness,
7111
7460
  lineCap: layout.cap,
7112
7461
  shadow: clampedShadow,
@@ -7125,12 +7474,12 @@ function ringNodes2(context, layout, series, index) {
7125
7474
  if (radius <= ringThickness / 2) {
7126
7475
  return [];
7127
7476
  }
7128
- const color2 = paint(series.color ?? CHART_COLORS[index % CHART_COLORS.length], diagnostics, chart.id);
7477
+ const color = paint(series.color ?? CHART_COLORS[index % CHART_COLORS.length], diagnostics, chart.id);
7129
7478
  const value = Math.max(0, finite(series.values[0], 0));
7130
7479
  const fraction = range > 0 ? Math.min(1, Math.max(0, (value - axisMin) / range)) : 0;
7131
7480
  const trackStyle = {
7132
7481
  fill: { kind: "none" },
7133
- stroke: color2,
7482
+ stroke: color,
7134
7483
  strokeWidth: ringThickness,
7135
7484
  opacity: trackOpacity
7136
7485
  };
@@ -7156,7 +7505,7 @@ function ringNodes2(context, layout, series, index) {
7156
7505
  return [track];
7157
7506
  }
7158
7507
  const sweep = fraction * total;
7159
- const casters = ringEndShadows(context, layout, series, radius, sweep, color2);
7508
+ const casters = ringEndShadows(context, layout, series, radius, sweep, color);
7160
7509
  const progress = {
7161
7510
  type: "path",
7162
7511
  id: `chart-radial-bar-ring-${chart.id}-${series.id}`,
@@ -7165,7 +7514,7 @@ function ringNodes2(context, layout, series, index) {
7165
7514
  d: ringProgressPath(centerX, centerY, radius, sweep, start),
7166
7515
  detail: { of: "chartValue", series: series.id, valueIndex: 0, mark: "radial-bar-ring" },
7167
7516
  prop: seriesValueProp(series.id, 0),
7168
- style: { fill: { kind: "none" }, stroke: color2, strokeWidth: ringThickness, lineCap: cap }
7517
+ style: { fill: { kind: "none" }, stroke: color, strokeWidth: ringThickness, lineCap: cap }
7169
7518
  };
7170
7519
  return [track, ...casters, progress];
7171
7520
  }
@@ -7340,8 +7689,8 @@ function createNodeLabel(context, data, node) {
7340
7689
  node.color,
7341
7690
  isLightColor(fallback) ? OUTSIDE_LABEL_LIGHTNESS_ON_DARK_BG : OUTSIDE_LABEL_LIGHTNESS_ON_LIGHT_BG
7342
7691
  ) ?? fallback;
7343
- const color2 = chart.config?.labelColor ?? defaultColor;
7344
- return { ...label, color: color2, detail: { of: "chartSeries", series: node.id, mark: "sankey-node-label" } };
7692
+ const color = chart.config?.labelColor ?? defaultColor;
7693
+ return { ...label, color, detail: { of: "chartSeries", series: node.id, mark: "sankey-node-label" } };
7345
7694
  }
7346
7695
  function createOutsideLabel(context, data, node) {
7347
7696
  const { chart, bounds, nextOrder } = context;
@@ -7471,15 +7820,15 @@ function renderScatter(context) {
7471
7820
  const nodes = [];
7472
7821
  const shadow = resolveChartShadow(context.chart.shadowStyle);
7473
7822
  context.chart.series.forEach((series, seriesIndex) => {
7474
- const color2 = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
7823
+ const color = series.color ?? CHART_COLORS[seriesIndex % CHART_COLORS.length];
7475
7824
  const points = pixelPoints(context, seriesValuePairs(context.chart, series));
7476
7825
  points.forEach((point, pointIndex) => {
7477
- nodes.push(createScatterPoint(context, series, point, pointIndex, color2, shadow));
7826
+ nodes.push(createScatterPoint(context, series, point, pointIndex, color, shadow));
7478
7827
  });
7479
7828
  });
7480
7829
  return nodes;
7481
7830
  }
7482
- function createScatterPoint(context, series, point, pointIndex, color2, shadow) {
7831
+ function createScatterPoint(context, series, point, pointIndex, color, shadow) {
7483
7832
  const { chart, bounds, diagnostics, nextOrder } = context;
7484
7833
  const config = chart.config;
7485
7834
  const radius = config?.pointSize ?? DEFAULT_POINT_SIZE;
@@ -7495,8 +7844,8 @@ function createScatterPoint(context, series, point, pointIndex, color2, shadow)
7495
7844
  ry: radius,
7496
7845
  detail: { of: "chartValue", series: series.id, valueIndex: pointIndex },
7497
7846
  style: {
7498
- fill: paint(color2, diagnostics, chart.id),
7499
- stroke: strokeWidth > 0 ? paint(config?.pointStrokeColor ?? color2, diagnostics, chart.id) : void 0,
7847
+ fill: paint(color, diagnostics, chart.id),
7848
+ stroke: strokeWidth > 0 ? paint(config?.pointStrokeColor ?? color, diagnostics, chart.id) : void 0,
7500
7849
  strokeWidth: strokeWidth > 0 ? strokeWidth : void 0,
7501
7850
  opacity: config?.pointOpacity,
7502
7851
  shadow
@@ -7772,15 +8121,15 @@ function renderTreemapHeader(context, layout, header, index) {
7772
8121
  return [background, label];
7773
8122
  }
7774
8123
  function renderTile(context, layout, tile, nextTile) {
7775
- const color2 = treemapLeafColor(tile.item.leaf, layout);
8124
+ const color = treemapLeafColor(tile.item.leaf, layout);
7776
8125
  const nextColor = nextTile ? treemapLeafColor(nextTile.item.leaf, layout) : void 0;
7777
- const nodes = [createTileNode(context, layout, tile, color2, nextColor)];
8126
+ const nodes = [createTileNode(context, layout, tile, color, nextColor)];
7778
8127
  if (context.showLabels && tile.width >= 34 && tile.height >= 18) {
7779
- nodes.push(...createTileLabel(context, layout, tile, color2));
8128
+ nodes.push(...createTileLabel(context, layout, tile, color));
7780
8129
  }
7781
8130
  return nodes;
7782
8131
  }
7783
- function createTileNode(context, layout, tile, color2, nextColor) {
8132
+ function createTileNode(context, layout, tile, color, nextColor) {
7784
8133
  const { chart, plot, bounds, diagnostics, nextOrder } = context;
7785
8134
  const gap = layout.cellGap;
7786
8135
  const shadow = resolveChartShadow(chart.shadowStyle);
@@ -7800,10 +8149,10 @@ function createTileNode(context, layout, tile, color2, nextColor) {
7800
8149
  kind: "linear-gradient",
7801
8150
  angle: 0,
7802
8151
  stops: [
7803
- { offset: 0, color: representativeColor(color2, fallback) },
8152
+ { offset: 0, color: representativeColor(color, fallback) },
7804
8153
  { offset: 100, color: representativeColor(nextColor, fallback) }
7805
8154
  ]
7806
- } : paint(color2, diagnostics, chart.id);
8155
+ } : paint(color, diagnostics, chart.id);
7807
8156
  return {
7808
8157
  type: "rect",
7809
8158
  id: `chart-treemap-tile-${chart.id}-${tile.item.leaf.id}`,
@@ -7823,7 +8172,7 @@ function createTileNode(context, layout, tile, color2, nextColor) {
7823
8172
  }
7824
8173
  };
7825
8174
  }
7826
- function createTileLabel(context, layout, tile, color2) {
8175
+ function createTileLabel(context, layout, tile, color) {
7827
8176
  const { chart, plot, bounds, nextOrder } = context;
7828
8177
  const { leaf, value } = tile.item;
7829
8178
  const gap = layout.cellGap;
@@ -7832,7 +8181,7 @@ function createTileLabel(context, layout, tile, color2) {
7832
8181
  const height = Math.max(1, tile.height - gap - pad * 1.5);
7833
8182
  const x = plot.x + tile.x + gap / 2 + pad;
7834
8183
  const y = plot.y + tile.y + gap / 2 + pad * 0.75;
7835
- const textColor = chart.config?.tileTextColor ?? contrastTextColor(representativeColor(color2, "#ffffff"));
8184
+ const textColor = chart.config?.tileTextColor ?? contrastTextColor(representativeColor(color, "#ffffff"));
7836
8185
  const lineHeight = layout.labelSize * 1.2;
7837
8186
  const maxLines = Math.max(1, Math.floor(height / lineHeight));
7838
8187
  const labelLines = wrapText(leaf.label, width, layout.labelSize).slice(0, maxLines).map((line) => ellipsizeToWidth(line, width, layout.labelSize, true));
@@ -8154,7 +8503,7 @@ function stackingOf(input) {
8154
8503
  add("frame", input.frames, 0);
8155
8504
  add("swimlane", input.swimlanes, 5e3);
8156
8505
  add("shape", input.shapes, 1e4);
8157
- add("widget", input.widgets ?? [], 1e4);
8506
+ add("widget", input.components ?? input.widgets ?? [], 1e4);
8158
8507
  add("isometric", input.isometricObjects ?? [], 15e3);
8159
8508
  add(
8160
8509
  "link",
@@ -8182,7 +8531,7 @@ function buildRenderScene(input, options = {}) {
8182
8531
  ...buildCharts(input.charts ?? [], diagnostics),
8183
8532
  ...buildLinks(input.links, measureText),
8184
8533
  ...buildShapes(input.shapes, diagnostics, measureText),
8185
- ...buildWidgets(input.widgets ?? []),
8534
+ ...buildComponents(input.components ?? input.widgets ?? []),
8186
8535
  ...buildIsometricObjects(input.isometricObjects ?? [])
8187
8536
  ];
8188
8537
  stampStacking(nodes, input);
@@ -8286,21 +8635,21 @@ function innerShadowPrimitives(shadow) {
8286
8635
  }
8287
8636
 
8288
8637
  // src/svg/markerBodies.ts
8289
- function markerBody(type, size, color2, strokeWidth) {
8638
+ function markerBody(type, size, color, strokeWidth) {
8290
8639
  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"/>`
8640
+ 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"/>`,
8641
+ 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"/>`,
8642
+ circle: `<circle cx="0" cy="0" r="${num(size * 0.5)}" fill="white" stroke="${color}" stroke-width="${num(strokeWidth)}"/>`,
8643
+ filled_circle: `<circle cx="0" cy="0" r="${num(size * 0.5)}" fill="${color}"/>`,
8644
+ 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)}"/>`,
8645
+ 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)}"/>`,
8646
+ bar: `<path d="M 0 ${num(-size * 0.6)} V ${num(size * 0.6)}" stroke="${color}" stroke-width="${num(strokeWidth)}" stroke-linecap="round"/>`,
8647
+ 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"/>`,
8648
+ 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)}"/>`,
8649
+ 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)}"/>`,
8650
+ 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"/>`,
8651
+ 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"/>`,
8652
+ 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
8653
  };
8305
8654
  return bodies[type];
8306
8655
  }
@@ -8321,11 +8670,11 @@ var SvgMarkerDefinitions = class {
8321
8670
  addDefinition;
8322
8671
  prefix;
8323
8672
  ids = /* @__PURE__ */ new Map();
8324
- marker(type, color2, strokeWidth) {
8673
+ marker(type, color, strokeWidth) {
8325
8674
  if (!type || type === "none") {
8326
8675
  return void 0;
8327
8676
  }
8328
- const key = `${type}:${color2}:${strokeWidth}`;
8677
+ const key = `${type}:${color}:${strokeWidth}`;
8329
8678
  let id = this.ids.get(key);
8330
8679
  if (id) {
8331
8680
  return id;
@@ -8335,7 +8684,7 @@ var SvgMarkerDefinitions = class {
8335
8684
  const size = 12 + (strokeWidth - 2) * 3;
8336
8685
  const extent = markerExtent(type, size, strokeWidth);
8337
8686
  const attributes = markerAttributes(id, extent);
8338
- this.addDefinition(`<marker ${attributes}>${markerBody(type, size, xml(color2), strokeWidth)}</marker>`);
8687
+ this.addDefinition(`<marker ${attributes}>${markerBody(type, size, xml(color), strokeWidth)}</marker>`);
8339
8688
  return id;
8340
8689
  }
8341
8690
  };
@@ -8415,8 +8764,8 @@ var SvgDefinitionRegistry = class {
8415
8764
  filter(style, nodeId, size) {
8416
8765
  return this.filters.filter(style, nodeId, size);
8417
8766
  }
8418
- marker(type, color2, strokeWidth) {
8419
- return this.markers.marker(type, color2, strokeWidth);
8767
+ marker(type, color, strokeWidth) {
8768
+ return this.markers.marker(type, color, strokeWidth);
8420
8769
  }
8421
8770
  clip(style) {
8422
8771
  return this.clips.clip(style);
@@ -8546,13 +8895,22 @@ function imageAttrs(node, defs) {
8546
8895
  function domRole(identity) {
8547
8896
  return identity.role === "shape" ? "entity" : identity.role;
8548
8897
  }
8898
+ function ariaAttrs(aria) {
8899
+ return [
8900
+ `role="${xml(aria.role)}"`,
8901
+ aria.checked === void 0 ? void 0 : `aria-checked="${aria.checked}"`,
8902
+ aria.pressed === void 0 ? void 0 : `aria-pressed="${aria.pressed}"`,
8903
+ aria.disabled ? 'aria-disabled="true"' : void 0
8904
+ ];
8905
+ }
8549
8906
  function identityAttrs(identity) {
8550
8907
  return [
8551
8908
  `data-sf-role="${domRole(identity)}"`,
8552
8909
  `data-sf-id="${xml(identity.id)}"`,
8553
8910
  identity.kind ? `data-sf-kind="${xml(identity.kind)}"` : void 0,
8554
8911
  identity.primary ? 'data-sf-primary="true"' : void 0,
8555
- identity.parentFrameId ? `data-sf-parent-frame="${xml(identity.parentFrameId)}"` : void 0
8912
+ identity.parentFrameId ? `data-sf-parent-frame="${xml(identity.parentFrameId)}"` : void 0,
8913
+ ...identity.aria ? ariaAttrs(identity.aria) : []
8556
8914
  ];
8557
8915
  }
8558
8916
  function detailAttrs(detail) {
@@ -8737,7 +9095,7 @@ function shaderSurfaceSvg(node, defs) {
8737
9095
  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
9096
  }
8739
9097
  function rollingDigitSvg(character, node) {
8740
- const style = node.widgetStyle;
9098
+ const style = node.componentStyle;
8741
9099
  if (style.variant === "plain") {
8742
9100
  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
9101
  }
@@ -8745,11 +9103,11 @@ function rollingDigitSvg(character, node) {
8745
9103
  }
8746
9104
  function rollingNumberSvg(node, defs) {
8747
9105
  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>` : "";
9106
+ const fontSize = node.componentStyle.fontSize > 0 ? node.componentStyle.fontSize : Math.max(1, Math.min(node.width, node.height) * 0.28);
9107
+ 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
9108
  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>`;
9109
+ const componentStyle = xml(JSON.stringify(node.componentStyle));
9110
+ 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
9111
  }
8754
9112
  function nodeSvg(node, defs) {
8755
9113
  if (node.type === "text") {
@@ -8804,7 +9162,13 @@ function renderCanvas(input, options = {}) {
8804
9162
  }
8805
9163
  var SCENE_CACHE_LIMIT = 50;
8806
9164
  var sceneCache = /* @__PURE__ */ new Map();
9165
+ var cachedForRegistry = componentRegistryVersion();
8807
9166
  function cachedRenderScene(source) {
9167
+ const registry = componentRegistryVersion();
9168
+ if (registry !== cachedForRegistry) {
9169
+ sceneCache.clear();
9170
+ cachedForRegistry = registry;
9171
+ }
8808
9172
  const cached = sceneCache.get(source);
8809
9173
  if (cached) {
8810
9174
  sceneCache.delete(source);
@@ -8829,7 +9193,20 @@ function render(source, options = {}) {
8829
9193
  const { svg, width, height, diagnostics } = renderSceneToSvg(scene, options);
8830
9194
  return { svg, width, height, diagnostics, scene };
8831
9195
  }
9196
+ var SCENE_ORDER_BASE = 1e4;
9197
+ function defineComponent(definition) {
9198
+ const { scene, ...descriptor } = definition;
9199
+ const unregisterDescriptor = registerComponentDescriptor(descriptor);
9200
+ const unregisterBuilder = registerComponentBuilder(
9201
+ descriptor.type,
9202
+ (component, index) => scene(component, { order: SCENE_ORDER_BASE + index })
9203
+ );
9204
+ return () => {
9205
+ unregisterBuilder();
9206
+ unregisterDescriptor();
9207
+ };
9208
+ }
8832
9209
 
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
9210
+ export { collectCanvasObjects, decodeColor, decodeShadow, defineComponent, render, renderCanvas, sflToRenderInput };
9211
+ //# sourceMappingURL=chunk-LTGF5OHP.js.map
9212
+ //# sourceMappingURL=chunk-LTGF5OHP.js.map