stickyflow 0.10.0 → 0.11.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 (60) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/binding/index.cjs +9 -9
  3. package/dist/binding/index.d.cts +4 -4
  4. package/dist/binding/index.d.ts +4 -4
  5. package/dist/binding/index.js +3 -3
  6. package/dist/{chunk-5PJ55GPG.cjs → chunk-5G3BEXQU.cjs} +1069 -713
  7. package/dist/chunk-5G3BEXQU.cjs.map +1 -0
  8. package/dist/{chunk-EGUPN56K.js → chunk-BFQWCOEC.js} +3 -3
  9. package/dist/{chunk-EGUPN56K.js.map → chunk-BFQWCOEC.js.map} +1 -1
  10. package/dist/{chunk-KRSX4UZ7.cjs → chunk-F24JURN2.cjs} +293 -46
  11. package/dist/chunk-F24JURN2.cjs.map +1 -0
  12. package/dist/{chunk-TECWZVIM.cjs → chunk-FXGXUWSI.cjs} +23 -23
  13. package/dist/{chunk-TECWZVIM.cjs.map → chunk-FXGXUWSI.cjs.map} +1 -1
  14. package/dist/{chunk-HRU6VOEC.js → chunk-G6IW2IX3.js} +44 -7
  15. package/dist/chunk-G6IW2IX3.js.map +1 -0
  16. package/dist/{chunk-SDOHUNBW.js → chunk-Q6QLU6YQ.js} +428 -72
  17. package/dist/chunk-Q6QLU6YQ.js.map +1 -0
  18. package/dist/{chunk-VPNOVRWP.js → chunk-RQYZNW2I.js} +262 -15
  19. package/dist/chunk-RQYZNW2I.js.map +1 -0
  20. package/dist/{chunk-L7CEX5JV.js → chunk-UB2ANTWF.js} +4 -4
  21. package/dist/{chunk-L7CEX5JV.js.map → chunk-UB2ANTWF.js.map} +1 -1
  22. package/dist/{chunk-LSEMXRB5.cjs → chunk-UHKFJBY5.cjs} +44 -7
  23. package/dist/chunk-UHKFJBY5.cjs.map +1 -0
  24. package/dist/{chunk-SCD3AHMY.cjs → chunk-WZA3DJJH.cjs} +15 -15
  25. package/dist/{chunk-SCD3AHMY.cjs.map → chunk-WZA3DJJH.cjs.map} +1 -1
  26. package/dist/index.cjs +36 -36
  27. package/dist/index.d.cts +5 -5
  28. package/dist/index.d.ts +5 -5
  29. package/dist/index.js +5 -5
  30. package/dist/interaction/index.cjs +240 -237
  31. package/dist/interaction/index.cjs.map +1 -1
  32. package/dist/interaction/index.d.cts +3 -3
  33. package/dist/interaction/index.d.ts +3 -3
  34. package/dist/interaction/index.js +6 -3
  35. package/dist/interaction/index.js.map +1 -1
  36. package/dist/{render-DU4lYbRl.d.cts → render-BDO4S5uF.d.cts} +16 -0
  37. package/dist/{render-DU4lYbRl.d.ts → render-BDO4S5uF.d.ts} +16 -0
  38. package/dist/{runtime-Bkv7QW7H.d.cts → runtime-C-C5v9po.d.cts} +2 -2
  39. package/dist/{runtime-DJ4K4_HZ.d.ts → runtime-lCAfU-1Q.d.ts} +2 -2
  40. package/dist/{runtimeTypes-C1shzoyr.d.ts → runtimeTypes-B7p6b1Bi.d.cts} +2 -2
  41. package/dist/{runtimeTypes-BvJBZLkr.d.cts → runtimeTypes-BDA_CfWh.d.ts} +2 -2
  42. package/dist/stickyflow-diagram.global.js +197 -44
  43. package/dist/stickyflow-diagram.global.js.map +1 -1
  44. package/dist/{types-B5jrEEcF.d.cts → types-CZJzycKw.d.cts} +1 -1
  45. package/dist/{types-B7IkZ0w4.d.ts → types-Dp8JVZLB.d.ts} +1 -1
  46. package/dist/viewer/index.cjs +9 -9
  47. package/dist/viewer/index.d.cts +4 -4
  48. package/dist/viewer/index.d.ts +4 -4
  49. package/dist/viewer/index.js +4 -4
  50. package/dist/web-component/index.cjs +6 -6
  51. package/dist/web-component/index.d.cts +2 -2
  52. package/dist/web-component/index.d.ts +2 -2
  53. package/dist/web-component/index.js +4 -4
  54. package/package.json +1 -1
  55. package/dist/chunk-5PJ55GPG.cjs.map +0 -1
  56. package/dist/chunk-HRU6VOEC.js.map +0 -1
  57. package/dist/chunk-KRSX4UZ7.cjs.map +0 -1
  58. package/dist/chunk-LSEMXRB5.cjs.map +0 -1
  59. package/dist/chunk-SDOHUNBW.js.map +0 -1
  60. package/dist/chunk-VPNOVRWP.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { componentRegistryVersion, isDimensionObject, isIsometricObject, sflToCanvasState, registerComponentDescriptor, isBuiltInComponentType, getComponentDescriptor, tag, EMPTY_BOUNDS, DOM_CONTRACT_VERSION, edgePointToward, elementCenter, VISIBLE_ISOMETRIC_FACES, isometricFaceCenter, finite, freeformPathData, rotatedBounds, DEFAULT_FONT, isGenericComponent, cleanFootprint, pointAtNormalizedPort, boxBounds, cornersRoundedRectPath, calculateLinkRoute, labelGapDash, getLineMidpoint, personLabelArea, wrapText, heuristicRichMeasure, shadeFill, extrudeFootprint, isometricFaces, roundedPolygonPath, stackSequence, stackRank, topRoundedRectPath, rightRoundedRectPath, leftRoundedRectPath, bottomRoundedRectPath, paint, CHART_TITLE_PROP, chartText, isHorizontalBar, chartTicks, mapChartValue, roundedOrthogonalPathData, localShapePath, pillCornerRadius, isometricBounds, AXIS_SIN, deriveFaceFills, resolveChartShadow, CHART_COLORS, angleForAxisValue, horizontalRows, rowTop, categoryProp, isometricTopFaceCenter, ISOMETRIC_SIZE_ATTR, CORNER_RADIUS_ATTR, ISOMETRIC_LABEL_OFFSET_ATTR, PATH_POINTS_ATTR, PATH_TENSION_ATTR, PATH_CLOSED_ATTR, SYMBOL_BOUNDS_ATTR, SYMBOL_POINTS_ATTR, SYMBOL_TENSION_ATTR, SQUARE_CORNER_ATTR, labelTilt, tiltedLabelRoom, resolvePieRadii, radarCategoryCount, radarRadius, createPieGeometry, DEFAULT_HEX_RADIUS, DEFAULT_HEATMAP_ZONES, axisBands, DEFAULT_ZONE_FILL, representativeColor, computeBoxplotStats, barCategoryCount, ruleAtProp, ruleTextProp, labelBelowFrame, seriesLabelProp, axisLabelProp, seriesColorProp, seriesValueProp, radarSeriesPath, radarRadiusForValue, createPieSlicePath, renderPieLabels, interpolateHexColorStops, contrastTextColor, formatFieldValue, sameHueTint, isLightColor, barShapePath, linePathData, colorWithAlpha, estimateTextWidth, segmentedBarPath, roundedBarPath, radarPointAt, gapInsetAngle, pieUsesInnerArc, maxPieCornerRadius, pieApexRadius, maxApexCornerRadius, pieArcPoint, sameHueContrastColor, clipSegmentToRect, zoneColorAtValue, ellipsizeToWidth, barPath, labelAboveFrame, seriesValueColorProp, stackedSegment, errorBarRange, createVerticalErrorWhiskerNode, formatBarLabel, barLabelSize, CATEGORY_LABEL_ROW, BAR_LABEL, pillPath, resolveRollingNumberStyle, formatRollingNumber } from './chunk-HRU6VOEC.js';
1
+ import { componentRegistryVersion, isDimensionObject, isIsometricObject, sflToCanvasState, registerComponentDescriptor, isBuiltInComponentType, getComponentDescriptor, tag, EMPTY_BOUNDS, DOM_CONTRACT_VERSION, edgePointToward, elementCenter, VISIBLE_ISOMETRIC_FACES, isometricFaceCenter, finite, freeformPathData, rotatedBounds, DEFAULT_FONT, isGenericComponent, cleanFootprint, pointAtNormalizedPort, boxBounds, cornersRoundedRectPath, calculateLinkRoute, labelGapDash, getLineMidpoint, personLabelArea, wrapText, heuristicRichMeasure, shadeFill, extrudeFootprint, isometricFaces, roundedPolygonPath, stackSequence, stackRank, topRoundedRectPath, rightRoundedRectPath, leftRoundedRectPath, bottomRoundedRectPath, paint, CHART_TITLE_PROP, chartText, isHorizontalBar, chartTicks, mapChartValue, roundedOrthogonalPathData, localShapePath, pillCornerRadius, isometricBounds, AXIS_SIN, deriveFaceFills, resolveChartShadow, CHART_COLORS, angleForAxisValue, horizontalRows, rowTop, categoryProp, isometricTopFaceCenter, ISOMETRIC_SIZE_ATTR, CORNER_RADIUS_ATTR, ISOMETRIC_LABEL_OFFSET_ATTR, PATH_POINTS_ATTR, PATH_TENSION_ATTR, PATH_CLOSED_ATTR, SYMBOL_BOUNDS_ATTR, SYMBOL_POINTS_ATTR, SYMBOL_TENSION_ATTR, SQUARE_CORNER_ATTR, labelTilt, tiltedLabelRoom, resolvePieRadii, radarCategoryCount, radarRadius, createPieGeometry, DEFAULT_HEX_RADIUS, DEFAULT_HEATMAP_ZONES, axisBands, DEFAULT_ZONE_FILL, representativeColor, computeBoxplotStats, barCategoryCount, ruleAtProp, ruleTextProp, labelBelowFrame, seriesLabelProp, axisLabelProp, seriesColorProp, seriesValueProp, radarSeriesPath, radarRadiusForValue, createPieSlicePath, renderPieLabels, interpolateHexColorStops, contrastTextColor, formatFieldValue, sameHueTint, isLightColor, barShapePath, linePathData, colorWithAlpha, estimateTextWidth, segmentedBarPath, roundedBarPath, radarPointAt, gapInsetAngle, pieUsesInnerArc, maxPieCornerRadius, pieApexRadius, maxApexCornerRadius, pieArcPoint, sameHueContrastColor, clipSegmentToRect, zoneColorAtValue, ellipsizeToWidth, barPath, labelAboveFrame, seriesValueColorProp, stackedSegment, errorBarRange, createVerticalErrorWhiskerNode, formatBarLabel, barLabelSize, CATEGORY_LABEL_ROW, BAR_LABEL, pillPath, resolveRollingNumberStyle, formatRollingNumber, parseHexRgb } from './chunk-G6IW2IX3.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-]*`;
@@ -117,8 +117,8 @@ function dashArray(value) {
117
117
  if (!Array.isArray(parsed)) {
118
118
  return void 0;
119
119
  }
120
- const numbers = parsed.filter((entry) => typeof entry === "number" && Number.isFinite(entry));
121
- return numbers.length === parsed.length ? numbers : void 0;
120
+ const numbers2 = parsed.filter((entry) => typeof entry === "number" && Number.isFinite(entry));
121
+ return numbers2.length === parsed.length ? numbers2 : void 0;
122
122
  }
123
123
  function solidColor(value) {
124
124
  const decoded = decodeColor(value);
@@ -630,7 +630,7 @@ function readProperty(descriptor, raw) {
630
630
  case "boolean":
631
631
  return raw === void 0 ? descriptor.default : raw === "true";
632
632
  case "color":
633
- return cssColor(raw) ?? descriptor.default;
633
+ return descriptor.optional && raw === "none" ? "none" : cssColor(raw) ?? descriptor.default;
634
634
  case "enum":
635
635
  return raw !== void 0 && descriptor.options.includes(raw) ? raw : descriptor.default;
636
636
  case "string":
@@ -1010,12 +1010,29 @@ function pathObject(e) {
1010
1010
  }
1011
1011
 
1012
1012
  // src/renderInput/fromSfl/canvasObjects/shape.ts
1013
+ var IMAGE_FITS = ["cover", "contain", "fill"];
1013
1014
  function shapeTypeOf(value) {
1014
1015
  return value || "rectangle";
1015
1016
  }
1017
+ function numbers(value, count) {
1018
+ const parts = value?.split(",").map(Number);
1019
+ return parts?.length === count && parts.every(Number.isFinite) ? parts : void 0;
1020
+ }
1021
+ function imageOf(p) {
1022
+ const size = numbers(p.imageSize, 2);
1023
+ const crop = numbers(p.crop, 4);
1024
+ return {
1025
+ src: p.src,
1026
+ fit: oneOf(p.fit, IMAGE_FITS, "cover"),
1027
+ pixels: size && size[0] > 0 && size[1] > 0 ? [size[0], size[1]] : void 0,
1028
+ crop: crop && crop[2] > 0 && crop[3] > 0 ? { x: crop[0], y: crop[1], width: crop[2], height: crop[3] } : void 0
1029
+ };
1030
+ }
1016
1031
  function shapeObject(e, shaders) {
1017
1032
  const p = e.props;
1018
1033
  const isText = e.kind === "text";
1034
+ const isImage = e.kind === "image";
1035
+ const unpainted = isText || isImage;
1019
1036
  return {
1020
1037
  id: e.id,
1021
1038
  type: "shape",
@@ -1029,8 +1046,8 @@ function shapeObject(e, shaders) {
1029
1046
  w: e.width,
1030
1047
  h: e.height,
1031
1048
  rotation: e.rotation ?? 0,
1032
- fillColor: decodeColor(p.fill ?? (isText ? "none" : void 0)),
1033
- strokeColor: strokePaint(p.stroke ?? (isText ? "none" : void 0)),
1049
+ fillColor: decodeColor(p.fill ?? (unpainted ? "none" : void 0)),
1050
+ strokeColor: strokePaint(p.stroke ?? (unpainted ? "none" : void 0)),
1034
1051
  isText: isText || void 0,
1035
1052
  strokeWidth: numOf(p.strokeWidth),
1036
1053
  textColor: p.textColor,
@@ -1051,7 +1068,8 @@ function shapeObject(e, shaders) {
1051
1068
  parentFrameId: e.parentFrameId,
1052
1069
  order: e.order,
1053
1070
  sourceIndex: e.sourceIndex,
1054
- shader: p.shader ? shaders.get(p.shader) : void 0
1071
+ shader: p.shader ? shaders.get(p.shader) : void 0,
1072
+ image: isImage && p.src ? imageOf(p) : void 0
1055
1073
  };
1056
1074
  }
1057
1075
 
@@ -1482,7 +1500,7 @@ function fade(component, style) {
1482
1500
  const shown = component.disabled ? { ...style, opacity: 0.4 } : style;
1483
1501
  return animate > 0 ? { ...shown, transition: animate } : shown;
1484
1502
  }
1485
- function hitArea(component, box) {
1503
+ function hitArea(component, box, takesClicks = true) {
1486
1504
  return {
1487
1505
  id: `widget-${component.id}`,
1488
1506
  type: "rect",
@@ -1492,7 +1510,7 @@ function hitArea(component, box) {
1492
1510
  y: box.y,
1493
1511
  width: box.width,
1494
1512
  height: box.height,
1495
- style: { fill: { kind: "none" }, stroke: { kind: "none" }, pointerEvents: "all" }
1513
+ style: { fill: { kind: "none" }, stroke: { kind: "none" }, pointerEvents: takesClicks ? "all" : "none" }
1496
1514
  };
1497
1515
  }
1498
1516
  function labelText(component, part, area, label, order) {
@@ -1613,6 +1631,268 @@ function buildCheckbox(component, index) {
1613
1631
  ];
1614
1632
  }
1615
1633
 
1634
+ // src/renderScene/artifacts/component/hand.ts
1635
+ var MIN_TIP = 0.25;
1636
+ function withAlpha(color, alpha) {
1637
+ const rgb = parseHexRgb(color);
1638
+ return rgb && alpha < 1 ? `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]}, ${Number(alpha.toFixed(3))})` : color;
1639
+ }
1640
+ var num = (value) => String(Number(value.toFixed(3)));
1641
+ var isOff = (component, key) => textProperty(component, key) === "none";
1642
+ var colorOr = (component, key, fallback) => isOff(component, key) ? fallback : textProperty(component, key) || fallback;
1643
+ function handOf(component, box) {
1644
+ const radius = Math.min(box.width, box.height) / 2;
1645
+ const root = Math.max(0.5, numberProperty2(component, "width"));
1646
+ const taper = Math.min(1, Math.max(0, numberProperty2(component, "taper")));
1647
+ return {
1648
+ cx: box.x + box.width / 2,
1649
+ cy: box.y + box.height / 2,
1650
+ radius,
1651
+ length: Math.max(1, numberProperty2(component, "length") * radius),
1652
+ tail: Math.max(0, numberProperty2(component, "tail") * radius),
1653
+ gap: Math.max(0, numberProperty2(component, "gap") * radius),
1654
+ rootHalf: root / 2,
1655
+ tipHalf: Math.max(MIN_TIP, root * taper / 2)
1656
+ };
1657
+ }
1658
+ function outline({ cx, cy, length, tail, gap, rootHalf, tipHalf }) {
1659
+ const root = gap > 0 ? cy - gap : cy;
1660
+ const back = gap > 0 ? 0 : tail;
1661
+ const tipLeft = `L${num(cx - tipHalf)} ${num(cy - length)}`;
1662
+ const tip = `A${num(tipHalf)} ${num(tipHalf)} 0 0 1 ${num(cx + tipHalf)} ${num(cy - length)}`;
1663
+ const round2 = `A${num(rootHalf)} ${num(rootHalf)} 0 0 1 ${num(cx - rootHalf)} ${num(root + back)}`;
1664
+ if (gap > 0) {
1665
+ return `M${num(cx - rootHalf)} ${num(root)}${tipLeft}${tip}L${num(cx + rootHalf)} ${num(root)}${round2}Z`;
1666
+ }
1667
+ return [
1668
+ `M${num(cx - rootHalf)} ${num(root + back)}`,
1669
+ `L${num(cx - rootHalf)} ${num(root)}`,
1670
+ tipLeft,
1671
+ tip,
1672
+ `L${num(cx + rootHalf)} ${num(root)}`,
1673
+ `L${num(cx + rootHalf)} ${num(root + back)}`,
1674
+ back > 0 ? round2 : `L${num(cx - rootHalf)} ${num(root)}`,
1675
+ "Z"
1676
+ ].join("");
1677
+ }
1678
+ function shaped(hand, layer) {
1679
+ const rootHalf = hand.rootHalf * layer.scale;
1680
+ const tipHalf = layer.taper === void 0 ? hand.tipHalf * layer.scale : rootHalf * layer.taper;
1681
+ return { ...hand, length: hand.length * (layer.length ?? 1), rootHalf, tipHalf: Math.max(MIN_TIP, tipHalf) };
1682
+ }
1683
+ function stopsPaint(hand, stops, fadeOut, clear) {
1684
+ const tail = hand.gap > 0 ? 0 : hand.tail;
1685
+ const offset = (along2) => (tail + along2 * hand.length) / (hand.length + tail) * 100;
1686
+ const [, firstColor, firstAlpha] = stops[0];
1687
+ return {
1688
+ kind: "linear-gradient",
1689
+ angle: -90,
1690
+ stops: [
1691
+ ...tail > 0 ? [{ offset: 0, color: withAlpha(firstColor, firstAlpha * (clear ? 0 : 1 - fadeOut)) }] : [],
1692
+ ...stops.map(([along2, color, alpha], position) => ({
1693
+ offset: offset(along2),
1694
+ color: withAlpha(color, clear && position === 0 ? 0 : alpha)
1695
+ }))
1696
+ ]
1697
+ };
1698
+ }
1699
+ function plainPaint(hand, layer, fadeOut, tipFade) {
1700
+ if (fadeOut <= 0 && tipFade <= 0 && !layer.clear) {
1701
+ return solid(layer.color);
1702
+ }
1703
+ return {
1704
+ kind: "linear-gradient",
1705
+ angle: -90,
1706
+ stops: [
1707
+ { offset: 0, color: withAlpha(layer.root, layer.clear ? 0 : 1 - fadeOut) },
1708
+ // A tail is lit at the pivot and dissolves at its end.
1709
+ ...hand.gap === 0 && hand.tail > 0 ? [{ offset: hand.tail / (hand.length + hand.tail) * 100, color: layer.root }] : [],
1710
+ { offset: 100, color: withAlpha(layer.color, 1 - tipFade) }
1711
+ ]
1712
+ };
1713
+ }
1714
+ function handLayer(component, box, base, angle, layer, order) {
1715
+ const hand = shaped(base, layer);
1716
+ const fadeOut = Math.min(1, Math.max(0, numberProperty2(component, "fade")));
1717
+ const tipFade = Math.min(1, Math.max(0, layer.tipFade ?? numberProperty2(component, "tipFade")));
1718
+ const glow = numberProperty2(component, "glow");
1719
+ const soft = layer.blur > 0;
1720
+ const reach = Math.max(hand.rootHalf, hand.tipHalf);
1721
+ const near = hand.gap > 0 ? -hand.gap : hand.tail;
1722
+ const extent = { x: hand.cx - reach, y: hand.cy - hand.length, width: reach * 2, height: hand.length + near };
1723
+ return {
1724
+ id: `widget-${component.id}-${layer.part}`,
1725
+ type: "path",
1726
+ order: box.order + order,
1727
+ bounds: rotatedBounds(extent, 0, 0),
1728
+ d: outline(hand),
1729
+ rotation: angle,
1730
+ rotationCenter: { x: hand.cx, y: hand.cy },
1731
+ style: fade(component, {
1732
+ // The gradient runs from the tail to the tip, and turns with the hand.
1733
+ fill: layer.stops ? stopsPaint(hand, layer.stops, fadeOut, Boolean(layer.clear)) : plainPaint(hand, layer, fadeOut, tipFade),
1734
+ stroke: { kind: "none" },
1735
+ ...soft ? { blur: layer.blur, opacity: layer.opacity } : {},
1736
+ ...!soft && glow > 0 && !isOff(component, "glowColor") ? {
1737
+ shadow: {
1738
+ color: colorOr(component, "glowColor", layer.color),
1739
+ opacity: 1,
1740
+ blur: glow,
1741
+ dx: 0,
1742
+ dy: 0
1743
+ }
1744
+ } : {}
1745
+ })
1746
+ };
1747
+ }
1748
+ function trailLayers(color, root, light, soft, clear, lit) {
1749
+ const trail = [
1750
+ {
1751
+ part: "hand-light",
1752
+ scale: 4.5,
1753
+ length: 0.55,
1754
+ taper: 0.15,
1755
+ blur: soft * 3,
1756
+ opacity: 1,
1757
+ color: light,
1758
+ root: light,
1759
+ stops: [
1760
+ [0, light, 0.95],
1761
+ [0.35, light, 0.45],
1762
+ [1, light, 0]
1763
+ ]
1764
+ },
1765
+ {
1766
+ part: "hand-body",
1767
+ scale: 1.6,
1768
+ taper: 0.25,
1769
+ blur: soft,
1770
+ opacity: 1,
1771
+ color,
1772
+ root,
1773
+ clear,
1774
+ stops: [
1775
+ [0, root, 1],
1776
+ [0.18, color, 1],
1777
+ [0.6, color, 0.55],
1778
+ [1, color, 0]
1779
+ ]
1780
+ },
1781
+ {
1782
+ part: "hand",
1783
+ scale: 0.55,
1784
+ length: 0.8,
1785
+ taper: 0.3,
1786
+ blur: soft * 0.3,
1787
+ opacity: 1,
1788
+ color: root,
1789
+ root,
1790
+ clear,
1791
+ stops: [
1792
+ [0, root, 1],
1793
+ [0.45, root, 0.6],
1794
+ [1, root, 0]
1795
+ ]
1796
+ }
1797
+ ];
1798
+ return lit ? trail : trail.slice(1);
1799
+ }
1800
+ function handLayers(component, box, hand, angle) {
1801
+ const color = textProperty(component, "color");
1802
+ const root = colorOr(component, "root", color);
1803
+ const light = colorOr(component, "glowColor", color);
1804
+ const lit = !isOff(component, "glowColor");
1805
+ const clear = isOff(component, "root");
1806
+ const soft = numberProperty2(component, "soft");
1807
+ const bloom = numberProperty2(component, "bloom");
1808
+ if (soft > 0) {
1809
+ return trailLayers(color, root, light, soft, clear, lit).map(
1810
+ (layer, position) => handLayer(component, box, hand, angle, layer, 0.26 + position * 0.02)
1811
+ );
1812
+ }
1813
+ return [
1814
+ // A blurred light under the hand, bright at the pivot and dark at the tip.
1815
+ ...bloom > 0 && lit ? [
1816
+ handLayer(
1817
+ component,
1818
+ box,
1819
+ hand,
1820
+ angle,
1821
+ { part: "hand-bloom", scale: 4, blur: bloom, opacity: 0.9, color: light, root: light, tipFade: 1 },
1822
+ 0.26
1823
+ )
1824
+ ] : [],
1825
+ handLayer(component, box, hand, angle, { part: "hand", scale: 1, blur: 0, opacity: 1, color, root, clear }, 0.3)
1826
+ ];
1827
+ }
1828
+ function hubNode(component, box, hand, radius) {
1829
+ const ringWidth = numberProperty2(component, "hubRing");
1830
+ return {
1831
+ id: `widget-${component.id}-hub`,
1832
+ type: "ellipse",
1833
+ order: box.order + 0.4,
1834
+ bounds: rotatedBounds(
1835
+ { x: hand.cx - radius, y: hand.cy - radius, width: radius * 2, height: radius * 2 },
1836
+ 0,
1837
+ ringWidth
1838
+ ),
1839
+ cx: hand.cx,
1840
+ cy: hand.cy,
1841
+ rx: Math.max(0.5, radius - ringWidth / 2),
1842
+ ry: Math.max(0.5, radius - ringWidth / 2),
1843
+ style: fade(component, {
1844
+ fill: isOff(component, "hubFill") ? { kind: "none" } : solid(textProperty(component, "hubFill")),
1845
+ stroke: ringWidth > 0 ? solid(textProperty(component, "color")) : { kind: "none" },
1846
+ strokeWidth: ringWidth,
1847
+ ...numberProperty2(component, "glow") > 0 && !isOff(component, "glowColor") ? {
1848
+ shadow: {
1849
+ color: colorOr(component, "glowColor", textProperty(component, "color")),
1850
+ opacity: 1,
1851
+ blur: numberProperty2(component, "glow"),
1852
+ dx: 0,
1853
+ dy: 0
1854
+ }
1855
+ } : {}
1856
+ })
1857
+ };
1858
+ }
1859
+ var HIT_HALF = 8;
1860
+ function pickNodes(component, box, hand, angle) {
1861
+ const reach = { ...hand, rootHalf: Math.max(hand.rootHalf, HIT_HALF), tipHalf: Math.max(hand.tipHalf, HIT_HALF) };
1862
+ const near = reach.gap > 0 ? -reach.gap : reach.tail;
1863
+ const extent = {
1864
+ x: reach.cx - HIT_HALF,
1865
+ y: reach.cy - reach.length,
1866
+ width: HIT_HALF * 2,
1867
+ height: reach.length + near
1868
+ };
1869
+ return [
1870
+ hitArea(component, box, false),
1871
+ {
1872
+ id: `widget-${component.id}-pick`,
1873
+ type: "path",
1874
+ order: box.order + 0.5,
1875
+ bounds: rotatedBounds(extent, 0, 0),
1876
+ d: outline(reach),
1877
+ rotation: angle,
1878
+ rotationCenter: { x: reach.cx, y: reach.cy },
1879
+ style: { fill: { kind: "none" }, stroke: { kind: "none" }, pointerEvents: "all" }
1880
+ }
1881
+ ];
1882
+ }
1883
+ function buildHand(component, index) {
1884
+ const box = controlBox(component, index, { width: 200, height: 200 });
1885
+ const hand = handOf(component, box);
1886
+ const max = numberProperty2(component, "max") || 1;
1887
+ const angle = numberProperty2(component, "start") + Number(component.value) / max * 360;
1888
+ const hub = numberProperty2(component, "hub");
1889
+ return [
1890
+ ...pickNodes(component, box, hand, angle),
1891
+ ...handLayers(component, box, hand, angle),
1892
+ ...hub > 0 ? [hubNode(component, box, hand, hub)] : []
1893
+ ];
1894
+ }
1895
+
1616
1896
  // src/renderScene/artifacts/component/knob.ts
1617
1897
  var DOT_RATIO = 0.62;
1618
1898
  function decimals(step) {
@@ -2190,6 +2470,7 @@ var builders = /* @__PURE__ */ new Map([
2190
2470
  ["progress", asComponentBuilder(buildProgress)],
2191
2471
  ["segmented", asComponentBuilder(buildSegmented)],
2192
2472
  ["knob", asComponentBuilder(buildKnob)],
2473
+ ["hand", asComponentBuilder(buildHand)],
2193
2474
  ["range", asComponentBuilder(buildSlider)]
2194
2475
  ]);
2195
2476
  function registerComponentBuilder(type, builder) {
@@ -3595,6 +3876,68 @@ function renderShapeGeometry(context) {
3595
3876
  return renderer(context);
3596
3877
  }
3597
3878
 
3879
+ // src/renderScene/artifacts/shape/image.ts
3880
+ function clipOf(outline2, box) {
3881
+ if (outline2?.type === "path") {
3882
+ return { type: "path", d: outline2.d };
3883
+ }
3884
+ if (outline2?.type === "ellipse") {
3885
+ const { cx, cy, rx, ry } = outline2;
3886
+ return {
3887
+ type: "path",
3888
+ d: `M${cx - rx} ${cy}A${rx} ${ry} 0 1 0 ${cx + rx} ${cy}A${rx} ${ry} 0 1 0 ${cx - rx} ${cy}Z`
3889
+ };
3890
+ }
3891
+ return { type: "rect", ...box, rx: outline2?.type === "rect" ? outline2.rx ?? 0 : 0 };
3892
+ }
3893
+ function croppedBox(image, crop, pixels, box) {
3894
+ const scaleX = box.width / crop.width;
3895
+ const scaleY = box.height / crop.height;
3896
+ const scale = image.fit === "contain" ? Math.min(scaleX, scaleY) : Math.max(scaleX, scaleY);
3897
+ const [sx, sy] = image.fit === "fill" ? [scaleX, scaleY] : [scale, scale];
3898
+ return {
3899
+ x: box.x + (box.width - crop.width * sx) / 2 - crop.x * sx,
3900
+ y: box.y + (box.height - crop.height * sy) / 2 - crop.y * sy,
3901
+ width: pixels[0] * sx,
3902
+ height: pixels[1] * sy
3903
+ };
3904
+ }
3905
+ var ASPECTS = { cover: "slice", contain: "meet", fill: "none" };
3906
+ function renderShapeImage(context, outline2, diagnostics) {
3907
+ const image = context.shape.image;
3908
+ if (!image) {
3909
+ return void 0;
3910
+ }
3911
+ if (image.crop && !image.pixels) {
3912
+ diagnostics.push({
3913
+ severity: "warning",
3914
+ code: "image-crop-without-size",
3915
+ ownerId: context.shape.id,
3916
+ message: `The image '${context.shape.id}' has a crop but no imageSize, so it is shown uncropped. Give it the size of the file, as imageSize: width, height.`
3917
+ });
3918
+ }
3919
+ const box = { x: context.x, y: context.y, width: context.width, height: context.height };
3920
+ const cropped = image.crop && image.pixels;
3921
+ return {
3922
+ type: "image",
3923
+ id: `${context.id}-image`,
3924
+ order: context.order,
3925
+ bounds: context.bounds,
3926
+ ...cropped ? croppedBox(image, image.crop, image.pixels, box) : box,
3927
+ href: image.src,
3928
+ aspect: cropped ? "none" : ASPECTS[image.fit],
3929
+ rotation: context.rotation,
3930
+ rotationCenter: context.rotationCenter,
3931
+ style: {
3932
+ opacity: context.style.opacity,
3933
+ blur: context.style.blur,
3934
+ blend: context.style.blend,
3935
+ clip: clipOf(outline2, box),
3936
+ pointerEvents: "none"
3937
+ }
3938
+ };
3939
+ }
3940
+
3598
3941
  // src/renderScene/artifacts/shape/shaderSurface.ts
3599
3942
  var RECT_PROGRAMS = /* @__PURE__ */ new Set([
3600
3943
  "reactivePanel",
@@ -3901,6 +4244,15 @@ function buildShape(shape, index, diagnostics, measureText) {
3901
4244
  }
3902
4245
  nodes.push(shader);
3903
4246
  }
4247
+ const image = renderShapeImage(context, nodes[0], diagnostics);
4248
+ if (image) {
4249
+ for (const node of nodes) {
4250
+ if (node.type === "ellipse" || node.type === "path" || node.type === "rect") {
4251
+ node.style = { ...node.style, pointerEvents: "all" };
4252
+ }
4253
+ }
4254
+ nodes.push(image);
4255
+ }
3904
4256
  const text = renderShapeText(context, strokeWidth, measureText);
3905
4257
  if (text) {
3906
4258
  nodes.push(text);
@@ -9713,7 +10065,7 @@ function buildRenderScene(input, options = {}) {
9713
10065
 
9714
10066
  // src/svg/format.ts
9715
10067
  var xml = (value) => String(value).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
9716
- var num = (value) => Number(value.toFixed(3)).toString();
10068
+ var num2 = (value) => Number(value.toFixed(3)).toString();
9717
10069
  var safeId = (value) => `sf-${value.replace(/[^A-Za-z0-9_.:-]/g, "-")}`;
9718
10070
 
9719
10071
  // src/svg/clipDefinitions.ts
@@ -9735,7 +10087,7 @@ var SvgClipDefinitions = class {
9735
10087
  const outer = clip.within ? this.define(clip.within) : void 0;
9736
10088
  id = safeId(`${this.prefix}clip-${this.ids.size}`);
9737
10089
  this.ids.set(key, id);
9738
- const shape = clip.type === "path" ? `<path clip-rule="evenodd" d="${xml(clip.d)}"/>` : `<rect x="${num(clip.x)}" y="${num(clip.y)}" width="${num(clip.width)}" height="${num(clip.height)}" rx="${num(clip.rx)}"/>`;
10090
+ const shape = clip.type === "path" ? `<path clip-rule="evenodd" d="${xml(clip.d)}"/>` : `<rect x="${num2(clip.x)}" y="${num2(clip.y)}" width="${num2(clip.width)}" height="${num2(clip.height)}" rx="${num2(clip.rx)}"/>`;
9739
10091
  this.addDefinition(`<clipPath id="${id}"${outer ? ` clip-path="url(#${outer})"` : ""}>${shape}</clipPath>`);
9740
10092
  }
9741
10093
  return id;
@@ -9777,18 +10129,18 @@ var SvgFilterDefinitions = class {
9777
10129
  id = safeId(`${this.prefix}shadow-${nodeId}-${this.ids.size}`);
9778
10130
  this.ids.set(key, id);
9779
10131
  this.addDefinition(
9780
- `<filter id="${id}" x="${num(-margin * 100)}%" y="${num(-margin * 100)}%" width="${num((1 + margin * 2) * 100)}%" height="${num((1 + margin * 2) * 100)}%">${primitives(value)}</filter>`
10132
+ `<filter id="${id}" x="${num2(-margin * 100)}%" y="${num2(-margin * 100)}%" width="${num2((1 + margin * 2) * 100)}%" height="${num2((1 + margin * 2) * 100)}%">${primitives(value)}</filter>`
9781
10133
  );
9782
10134
  }
9783
10135
  return id;
9784
10136
  }
9785
10137
  };
9786
10138
  function outerShadowPrimitives(shadow) {
9787
- return `<feDropShadow dx="${num(shadow.dx)}" dy="${num(shadow.dy)}" stdDeviation="${num(shadow.blur / 2)}" flood-color="${xml(shadow.color)}" flood-opacity="${num(shadow.opacity)}"/>`;
10139
+ return `<feDropShadow dx="${num2(shadow.dx)}" dy="${num2(shadow.dy)}" stdDeviation="${num2(shadow.blur / 2)}" flood-color="${xml(shadow.color)}" flood-opacity="${num2(shadow.opacity)}"/>`;
9788
10140
  }
9789
10141
  function blurPrimitives(effect) {
9790
- const blur = effect.blur > 0 ? `<feGaussianBlur stdDeviation="${num(effect.blur / 2)}"/>` : "";
9791
- const saturate = effect.saturate === 1 ? "" : `<feColorMatrix type="saturate" values="${num(effect.saturate)}"/>`;
10142
+ const blur = effect.blur > 0 ? `<feGaussianBlur stdDeviation="${num2(effect.blur / 2)}"/>` : "";
10143
+ const saturate = effect.saturate === 1 ? "" : `<feColorMatrix type="saturate" values="${num2(effect.saturate)}"/>`;
9792
10144
  return blur + saturate;
9793
10145
  }
9794
10146
  function innerShadowPrimitives(shadow) {
@@ -9796,9 +10148,9 @@ function innerShadowPrimitives(shadow) {
9796
10148
  '<feComponentTransfer in="SourceAlpha" result="sf-inverted-alpha">',
9797
10149
  '<feFuncA type="table" tableValues="1 0"/>',
9798
10150
  "</feComponentTransfer>",
9799
- `<feGaussianBlur in="sf-inverted-alpha" stdDeviation="${num(shadow.blur / 2)}" result="sf-blurred"/>`,
9800
- `<feOffset in="sf-blurred" dx="${num(shadow.dx)}" dy="${num(shadow.dy)}" result="sf-offset"/>`,
9801
- `<feFlood flood-color="${xml(shadow.color)}" flood-opacity="${num(shadow.opacity)}" result="sf-color"/>`,
10151
+ `<feGaussianBlur in="sf-inverted-alpha" stdDeviation="${num2(shadow.blur / 2)}" result="sf-blurred"/>`,
10152
+ `<feOffset in="sf-blurred" dx="${num2(shadow.dx)}" dy="${num2(shadow.dy)}" result="sf-offset"/>`,
10153
+ `<feFlood flood-color="${xml(shadow.color)}" flood-opacity="${num2(shadow.opacity)}" result="sf-color"/>`,
9802
10154
  '<feComposite in="sf-color" in2="sf-offset" operator="in" result="sf-halo"/>',
9803
10155
  '<feComposite in="sf-halo" in2="SourceGraphic" operator="in" result="sf-inset"/>',
9804
10156
  '<feComposite in="sf-inset" in2="SourceGraphic" operator="over"/>'
@@ -9808,19 +10160,19 @@ function innerShadowPrimitives(shadow) {
9808
10160
  // src/svg/markerBodies.ts
9809
10161
  function markerBody(type, size, color, strokeWidth) {
9810
10162
  const bodies = {
9811
- 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"/>`,
9812
- 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"/>`,
9813
- circle: `<circle cx="0" cy="0" r="${num(size * 0.5)}" fill="white" stroke="${color}" stroke-width="${num(strokeWidth)}"/>`,
9814
- filled_circle: `<circle cx="0" cy="0" r="${num(size * 0.5)}" fill="${color}"/>`,
9815
- 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)}"/>`,
9816
- 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)}"/>`,
9817
- bar: `<path d="M 0 ${num(-size * 0.6)} V ${num(size * 0.6)}" stroke="${color}" stroke-width="${num(strokeWidth)}" stroke-linecap="round"/>`,
9818
- 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"/>`,
9819
- 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)}"/>`,
9820
- 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)}"/>`,
9821
- 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"/>`,
9822
- 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"/>`,
9823
- 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"/>`
10163
+ arrow: `<path d="M ${num2(-size)} ${num2(-size * 0.6)} L 0 0 L ${num2(-size)} ${num2(size * 0.6)}" fill="none" stroke="${color}" stroke-width="${num2(strokeWidth)}" stroke-linecap="round" stroke-linejoin="round"/>`,
10164
+ filled_arrow: `<path d="M ${num2(-size)} ${num2(-size * 0.6)} L 0 0 L ${num2(-size)} ${num2(size * 0.6)} Z" fill="${color}" stroke="${color}" stroke-width="${num2(strokeWidth * 0.5)}" stroke-linejoin="round"/>`,
10165
+ circle: `<circle cx="0" cy="0" r="${num2(size * 0.5)}" fill="white" stroke="${color}" stroke-width="${num2(strokeWidth)}"/>`,
10166
+ filled_circle: `<circle cx="0" cy="0" r="${num2(size * 0.5)}" fill="${color}"/>`,
10167
+ diamond: `<path d="M ${num2(-size * 0.6)} 0 L 0 ${num2(-size * 0.6)} L ${num2(size * 0.6)} 0 L 0 ${num2(size * 0.6)} Z" fill="white" stroke="${color}" stroke-width="${num2(strokeWidth)}"/>`,
10168
+ filled_diamond: `<path d="M ${num2(-size * 0.6)} 0 L 0 ${num2(-size * 0.6)} L ${num2(size * 0.6)} 0 L 0 ${num2(size * 0.6)} Z" fill="${color}" stroke="${color}" stroke-width="${num2(strokeWidth * 0.5)}"/>`,
10169
+ bar: `<path d="M 0 ${num2(-size * 0.6)} V ${num2(size * 0.6)}" stroke="${color}" stroke-width="${num2(strokeWidth)}" stroke-linecap="round"/>`,
10170
+ triangle: `<path d="M ${num2(-size)} ${num2(-size * 0.72)} L 0 0 L ${num2(-size)} ${num2(size * 0.72)} Z" fill="white" stroke="${color}" stroke-width="${num2(strokeWidth)}" stroke-linejoin="round"/>`,
10171
+ one: `<path d="M 0 ${num2(-size * 0.62)} V ${num2(size * 0.62)} M ${num2(-size * 0.72)} ${num2(-size * 0.62)} V ${num2(size * 0.62)}" stroke="${color}" stroke-width="${num2(strokeWidth)}"/>`,
10172
+ zero_one: `<circle cx="${num2(-size * 0.8)}" cy="0" r="${num2(size * 0.38)}" fill="white" stroke="${color}" stroke-width="${num2(strokeWidth)}"/><path d="M 0 ${num2(-size * 0.62)} V ${num2(size * 0.62)}" stroke="${color}" stroke-width="${num2(strokeWidth)}"/>`,
10173
+ many: `<path d="M ${num2(-size)} ${num2(-size * 0.72)} L 0 0 M ${num2(-size)} 0 L 0 0 M ${num2(-size)} ${num2(size * 0.72)} L 0 0" stroke="${color}" stroke-width="${num2(strokeWidth)}" stroke-linecap="round"/>`,
10174
+ one_many: `<path d="M ${num2(-size)} ${num2(-size * 0.72)} L 0 0 M ${num2(-size)} 0 L 0 0 M ${num2(-size)} ${num2(size * 0.72)} L 0 0 M ${num2(-size * 1.45)} ${num2(-size * 0.62)} V ${num2(size * 0.62)}" stroke="${color}" stroke-width="${num2(strokeWidth)}" stroke-linecap="round"/>`,
10175
+ zero_many: `<circle cx="${num2(-size * 1.45)}" cy="0" r="${num2(size * 0.38)}" fill="white" stroke="${color}" stroke-width="${num2(strokeWidth)}"/><path d="M ${num2(-size)} ${num2(-size * 0.72)} L 0 0 M ${num2(-size)} 0 L 0 0 M ${num2(-size)} ${num2(size * 0.72)} L 0 0" stroke="${color}" stroke-width="${num2(strokeWidth)}" stroke-linecap="round"/>`
9824
10176
  };
9825
10177
  return bodies[type];
9826
10178
  }
@@ -9831,7 +10183,7 @@ function markerExtent(type, size, strokeWidth) {
9831
10183
  return Math.max(size * (isCompoundErMarker ? 2 : 1.4), strokeWidth * 2);
9832
10184
  }
9833
10185
  function markerAttributes(id, extent) {
9834
- return `id="${id}" markerWidth="${num(extent * 2)}" markerHeight="${num(extent * 2)}" viewBox="${num(-extent)} ${num(-extent)} ${num(extent * 2)} ${num(extent * 2)}" refX="0" refY="0" orient="auto-start-reverse" markerUnits="userSpaceOnUse" overflow="visible"`;
10186
+ return `id="${id}" markerWidth="${num2(extent * 2)}" markerHeight="${num2(extent * 2)}" viewBox="${num2(-extent)} ${num2(-extent)} ${num2(extent * 2)} ${num2(extent * 2)}" refX="0" refY="0" orient="auto-start-reverse" markerUnits="userSpaceOnUse" overflow="visible"`;
9835
10187
  }
9836
10188
  var SvgMarkerDefinitions = class {
9837
10189
  constructor(addDefinition, prefix) {
@@ -9866,7 +10218,7 @@ function meshGradientDefinition(id, paint2) {
9866
10218
  const radialDefinitions = paint2.points.map((point, index) => {
9867
10219
  const centerX = Math.max(0, Math.min(100, point.x));
9868
10220
  const centerY = Math.max(0, Math.min(100, point.y));
9869
- return `<radialGradient id="${radialIds[index]}" gradientUnits="objectBoundingBox" cx="${num(centerX)}%" cy="${num(centerY)}%" r="75%"><stop offset="0%" stop-color="${xml(point.color)}" stop-opacity="1"/><stop offset="100%" stop-color="${xml(point.color)}" stop-opacity="0"/></radialGradient>`;
10221
+ return `<radialGradient id="${radialIds[index]}" gradientUnits="objectBoundingBox" cx="${num2(centerX)}%" cy="${num2(centerY)}%" r="75%"><stop offset="0%" stop-color="${xml(point.color)}" stop-opacity="1"/><stop offset="100%" stop-color="${xml(point.color)}" stop-opacity="0"/></radialGradient>`;
9870
10222
  }).join("");
9871
10223
  const layers = paint2.points.map((_point, index) => `<rect width="1" height="1" fill="url(#${radialIds[index]})"/>`).join("");
9872
10224
  return `${radialDefinitions}<pattern id="${id}" patternUnits="objectBoundingBox" patternContentUnits="objectBoundingBox" width="1" height="1"><rect width="1" height="1" fill="${xml(paint2.points[0]?.color ?? "transparent")}"/>${layers}</pattern>`;
@@ -9878,8 +10230,8 @@ function linearGradientDefinition(id, paint2, bounds) {
9878
10230
  const radius = Math.max(bounds.maxX - bounds.minX, bounds.maxY - bounds.minY) / 2;
9879
10231
  const deltaX = Math.cos(angle) * radius;
9880
10232
  const deltaY = Math.sin(angle) * radius;
9881
- const stops = paint2.stops.map((stop) => `<stop offset="${num(Math.max(0, Math.min(100, stop.offset)))}%" stop-color="${xml(stop.color)}"/>`).join("");
9882
- return `<linearGradient id="${id}" gradientUnits="userSpaceOnUse" x1="${num(centerX - deltaX)}" y1="${num(centerY - deltaY)}" x2="${num(centerX + deltaX)}" y2="${num(centerY + deltaY)}">${stops}</linearGradient>`;
10233
+ const stops = paint2.stops.map((stop) => `<stop offset="${num2(Math.max(0, Math.min(100, stop.offset)))}%" stop-color="${xml(stop.color)}"/>`).join("");
10234
+ return `<linearGradient id="${id}" gradientUnits="userSpaceOnUse" x1="${num2(centerX - deltaX)}" y1="${num2(centerY - deltaY)}" x2="${num2(centerX + deltaX)}" y2="${num2(centerY + deltaY)}">${stops}</linearGradient>`;
9883
10235
  }
9884
10236
  var SvgPaintDefinitions = class {
9885
10237
  constructor(addDefinition, prefix) {
@@ -9996,10 +10348,10 @@ function styleAttrs(node, defs) {
9996
10348
  }
9997
10349
  function addStrokeAttrs(attrs, style) {
9998
10350
  if (style.strokeWidth !== void 0) {
9999
- attrs.push(`stroke-width="${num(style.strokeWidth)}"`);
10351
+ attrs.push(`stroke-width="${num2(style.strokeWidth)}"`);
10000
10352
  }
10001
10353
  if (style.dash?.length) {
10002
- attrs.push(`stroke-dasharray="${style.dash.map(num).join(" ")}"`);
10354
+ attrs.push(`stroke-dasharray="${style.dash.map(num2).join(" ")}"`);
10003
10355
  }
10004
10356
  if (style.lineCap) {
10005
10357
  attrs.push(`stroke-linecap="${style.lineCap}"`);
@@ -10008,14 +10360,14 @@ function addStrokeAttrs(attrs, style) {
10008
10360
  attrs.push(`stroke-linejoin="${style.lineJoin}"`);
10009
10361
  }
10010
10362
  if (style.opacity !== void 0) {
10011
- attrs.push(`opacity="${num(style.opacity)}"`);
10363
+ attrs.push(`opacity="${num2(style.opacity)}"`);
10012
10364
  }
10013
10365
  if (style.pointerEvents) {
10014
10366
  attrs.push(`pointer-events="${style.pointerEvents}"`);
10015
10367
  }
10016
10368
  const css = [];
10017
10369
  if (style.transition && style.transition > 0) {
10018
- const time = `${num(style.transition)}ms ease`;
10370
+ const time = `${num2(style.transition)}ms ease`;
10019
10371
  css.push(
10020
10372
  `transition: x ${time}, y ${time}, width ${time}, height ${time}, cx ${time}, cy ${time}, rx ${time}, ry ${time}, fill ${time}, stroke ${time}, stroke-width ${time}, stroke-dasharray ${time}, opacity ${time}`
10021
10373
  );
@@ -10035,6 +10387,10 @@ function elementSize(node) {
10035
10387
  if (shape.type === "rect" && shape.width !== void 0 && shape.height !== void 0) {
10036
10388
  return Math.min(shape.width, shape.height);
10037
10389
  }
10390
+ if (shape.type === "path" && shape.bounds) {
10391
+ const side = Math.min(shape.bounds.maxX - shape.bounds.minX, shape.bounds.maxY - shape.bounds.minY);
10392
+ return side > 0 ? side : void 0;
10393
+ }
10038
10394
  return void 0;
10039
10395
  }
10040
10396
  function addVisualEffectAttrs(attrs, node, defs) {
@@ -10061,12 +10417,12 @@ function addPathMarkerAttrs(attrs, node, defs) {
10061
10417
  }
10062
10418
  }
10063
10419
  function transform(rotation, center) {
10064
- return rotation && center ? ` transform="rotate(${num(rotation)} ${num(center.x)} ${num(center.y)})"` : "";
10420
+ return rotation && center ? ` transform="rotate(${num2(rotation)} ${num2(center.x)} ${num2(center.y)})"` : "";
10065
10421
  }
10066
10422
  function imageAttrs(node, defs) {
10067
10423
  const attrs = [];
10068
10424
  if (node.style.opacity !== void 0) {
10069
- attrs.push(`opacity="${num(node.style.opacity)}"`);
10425
+ attrs.push(`opacity="${num2(node.style.opacity)}"`);
10070
10426
  }
10071
10427
  if (node.style.pointerEvents) {
10072
10428
  attrs.push(`pointer-events="${node.style.pointerEvents}"`);
@@ -10128,12 +10484,12 @@ function chartValueAttrs(detail) {
10128
10484
  `data-sf-series="${xml(detail.series)}"`,
10129
10485
  `data-sf-value-index="${detail.valueIndex}"`,
10130
10486
  detail.mark ? `data-sf-mark="${detail.mark}"` : void 0,
10131
- detail.radius !== void 0 ? `data-sf-bar-radius="${num(detail.radius)}"` : void 0,
10487
+ detail.radius !== void 0 ? `data-sf-bar-radius="${num2(detail.radius)}"` : void 0,
10132
10488
  detail.colorProp ? `data-sf-color-prop="${xml(detail.colorProp)}"` : void 0,
10133
10489
  detail.hasColorOverride ? 'data-sf-color-override="true"' : void 0,
10134
- detail.pieStart !== void 0 ? `data-sf-pie-start="${num(detail.pieStart)}"` : void 0,
10135
- detail.pieEnd !== void 0 ? `data-sf-pie-end="${num(detail.pieEnd)}"` : void 0,
10136
- detail.pieValue !== void 0 ? `data-sf-pie-value="${num(detail.pieValue)}"` : void 0
10490
+ detail.pieStart !== void 0 ? `data-sf-pie-start="${num2(detail.pieStart)}"` : void 0,
10491
+ detail.pieEnd !== void 0 ? `data-sf-pie-end="${num2(detail.pieEnd)}"` : void 0,
10492
+ detail.pieValue !== void 0 ? `data-sf-pie-value="${num2(detail.pieValue)}"` : void 0
10137
10493
  ];
10138
10494
  }
10139
10495
  function pieGeometryAttrs(detail) {
@@ -10148,39 +10504,39 @@ function chartScaleAttrs(detail) {
10148
10504
  function chartSeriesAttrs(detail) {
10149
10505
  return [
10150
10506
  `data-sf-series="${xml(detail.series)}"`,
10151
- detail.lineTension !== void 0 ? `data-sf-line-tension="${num(detail.lineTension)}"` : void 0,
10507
+ detail.lineTension !== void 0 ? `data-sf-line-tension="${num2(detail.lineTension)}"` : void 0,
10152
10508
  detail.mark ? `data-sf-mark="${xml(detail.mark)}"` : void 0,
10153
10509
  detail.pulled ? 'data-sf-label-pulled="true"' : void 0,
10154
- detail.midAngle !== void 0 ? `data-sf-pie-mid-angle="${num(detail.midAngle)}"` : void 0,
10155
- detail.wedgeRadius !== void 0 ? `data-sf-pie-wedge-radius="${num(detail.wedgeRadius)}"` : void 0
10510
+ detail.midAngle !== void 0 ? `data-sf-pie-mid-angle="${num2(detail.midAngle)}"` : void 0,
10511
+ detail.wedgeRadius !== void 0 ? `data-sf-pie-wedge-radius="${num2(detail.wedgeRadius)}"` : void 0
10156
10512
  ];
10157
10513
  }
10158
10514
  function frameBoundaryAttrs(detail) {
10159
- return [`${CORNER_RADIUS_ATTR}="${num(detail.cornerRadius)}"`, `${SQUARE_CORNER_ATTR}="${detail.squareCorner}"`];
10515
+ return [`${CORNER_RADIUS_ATTR}="${num2(detail.cornerRadius)}"`, `${SQUARE_CORNER_ATTR}="${detail.squareCorner}"`];
10160
10516
  }
10161
10517
  function declaredBoundsAttr(bounds) {
10162
- return `${SYMBOL_BOUNDS_ATTR}="${num(bounds.x)},${num(bounds.y)},${num(bounds.width)},${num(bounds.height)}"`;
10518
+ return `${SYMBOL_BOUNDS_ATTR}="${num2(bounds.x)},${num2(bounds.y)},${num2(bounds.width)},${num2(bounds.height)}"`;
10163
10519
  }
10164
10520
  function symbolGeometryAttrs(detail) {
10165
10521
  return [
10166
10522
  `${SYMBOL_POINTS_ATTR}="${xml(JSON.stringify(detail.points))}"`,
10167
- `${SYMBOL_TENSION_ATTR}="${num(detail.tension)}"`,
10523
+ `${SYMBOL_TENSION_ATTR}="${num2(detail.tension)}"`,
10168
10524
  declaredBoundsAttr(detail.declaredBounds)
10169
10525
  ];
10170
10526
  }
10171
10527
  function pathGeometryAttrs(detail) {
10172
10528
  return [
10173
10529
  `${PATH_POINTS_ATTR}="${xml(JSON.stringify(detail.points))}"`,
10174
- `${PATH_TENSION_ATTR}="${num(detail.tension)}"`,
10530
+ `${PATH_TENSION_ATTR}="${num2(detail.tension)}"`,
10175
10531
  `${PATH_CLOSED_ATTR}="${detail.closed}"`
10176
10532
  ];
10177
10533
  }
10178
10534
  function isometricGeometryAttrs(detail) {
10179
10535
  return [
10180
- `${ISOMETRIC_SIZE_ATTR}="${num(detail.width)},${num(detail.height)},${num(detail.depth)}"`,
10181
- `${CORNER_RADIUS_ATTR}="${num(detail.cornerRadius)}"`,
10536
+ `${ISOMETRIC_SIZE_ATTR}="${num2(detail.width)},${num2(detail.height)},${num2(detail.depth)}"`,
10537
+ `${CORNER_RADIUS_ATTR}="${num2(detail.cornerRadius)}"`,
10182
10538
  declaredBoundsAttr(detail.bounds),
10183
- `${ISOMETRIC_LABEL_OFFSET_ATTR}="${num(detail.labelOffsetX)},${num(detail.labelOffsetY)}"`
10539
+ `${ISOMETRIC_LABEL_OFFSET_ATTR}="${num2(detail.labelOffsetX)},${num2(detail.labelOffsetY)}"`
10184
10540
  ];
10185
10541
  }
10186
10542
  function linkDetailAttrs(detail) {
@@ -10206,8 +10562,8 @@ function contractAttrs(node) {
10206
10562
  node.propSolidOnly ? 'data-sf-prop-solid-only="true"' : void 0,
10207
10563
  node.mark ? `data-sf-mark="${xml(node.mark)}"` : void 0,
10208
10564
  node.zoneGradient ? 'data-sf-zone-gradient="true"' : void 0,
10209
- node.zoneGradient ? `data-sf-zone-axis-min="${num(node.zoneGradient.min)}"` : void 0,
10210
- node.zoneGradient ? `data-sf-zone-axis-max="${num(node.zoneGradient.max)}"` : void 0,
10565
+ node.zoneGradient ? `data-sf-zone-axis-min="${num2(node.zoneGradient.min)}"` : void 0,
10566
+ node.zoneGradient ? `data-sf-zone-axis-max="${num2(node.zoneGradient.max)}"` : void 0,
10211
10567
  label ? `tabindex="0" aria-label="${xml(label.replace(/\s+/g, " ").trim())}"` : void 0
10212
10568
  ].filter((attribute) => attribute !== void 0);
10213
10569
  return attributes.length ? ` ${attributes.join(" ")}` : "";
@@ -10216,7 +10572,7 @@ function contractAttrs(node) {
10216
10572
  // src/svg/text.ts
10217
10573
  function richLineTspans(words, x, dy, fontSize) {
10218
10574
  if (!words.length) {
10219
- return `<tspan x="${num(x)}"${dy} font-size="${fontSize}"></tspan>`;
10575
+ return `<tspan x="${num2(x)}"${dy} font-size="${fontSize}"></tspan>`;
10220
10576
  }
10221
10577
  const groups = [];
10222
10578
  for (const word of words) {
@@ -10231,15 +10587,15 @@ function richLineTspans(words, x, dy, fontSize) {
10231
10587
  }
10232
10588
  }
10233
10589
  return groups.map(
10234
- (group, i) => `<tspan${i === 0 ? ` x="${num(x)}"${dy}` : ""} font-size="${fontSize}" font-weight="${group.bold ? "bold" : "normal"}">${xml(group.text)}</tspan>`
10590
+ (group, i) => `<tspan${i === 0 ? ` x="${num2(x)}"${dy}` : ""} font-size="${fontSize}" font-weight="${group.bold ? "bold" : "normal"}">${xml(group.text)}</tspan>`
10235
10591
  ).join("");
10236
10592
  }
10237
10593
  function textSvg(node, defs) {
10238
10594
  const position = textPosition(node);
10239
- const fontSize = `${num(node.fontSize)}px`;
10595
+ const fontSize = `${num2(node.fontSize)}px`;
10240
10596
  const content = textContent(node, position, fontSize);
10241
10597
  const preserve = node.richLines ? ' xml:space="preserve"' : "";
10242
- return `<text id="${defs.elementId(node.id)}"${contractAttrs(node)} x="${num(position.x)}" y="${num(position.firstY)}" font-family="${xml(node.fontFamily)}" font-size="${fontSize}" font-weight="${node.fontWeight}"${node.letterSpacing ? ` letter-spacing="${num(node.letterSpacing)}"` : ""} fill="${xml(node.color)}" text-anchor="${position.anchor}" data-sf-valign="${node.verticalAlign}" data-sf-line-height="${num(node.lineHeight)}"${preserve}${transform(node.rotation, node.rotationCenter)}>${content}</text>`;
10598
+ return `<text id="${defs.elementId(node.id)}"${contractAttrs(node)} x="${num2(position.x)}" y="${num2(position.firstY)}" font-family="${xml(node.fontFamily)}" font-size="${fontSize}" font-weight="${node.fontWeight}"${node.letterSpacing ? ` letter-spacing="${num2(node.letterSpacing)}"` : ""} fill="${xml(node.color)}" text-anchor="${position.anchor}" data-sf-valign="${node.verticalAlign}" data-sf-line-height="${num2(node.lineHeight)}"${preserve}${transform(node.rotation, node.rotationCenter)}>${content}</text>`;
10243
10599
  }
10244
10600
  function textPosition(node) {
10245
10601
  const linePx = node.fontSize * node.lineHeight;
@@ -10265,10 +10621,10 @@ function textContent(node, position, fontSize) {
10265
10621
  return node.lines.map((line, index) => lineTspan(line, index, position, fontSize)).join("");
10266
10622
  }
10267
10623
  function lineTspan(line, index, position, fontSize) {
10268
- return `<tspan x="${num(position.x)}" font-size="${fontSize}"${lineOffset(index, position.linePx)}>${xml(line)}</tspan>`;
10624
+ return `<tspan x="${num2(position.x)}" font-size="${fontSize}"${lineOffset(index, position.linePx)}>${xml(line)}</tspan>`;
10269
10625
  }
10270
10626
  function lineOffset(index, linePx) {
10271
- return index ? ` dy="${num(linePx)}px"` : "";
10627
+ return index ? ` dy="${num2(linePx)}px"` : "";
10272
10628
  }
10273
10629
 
10274
10630
  // src/svg/nodes.ts
@@ -10277,7 +10633,7 @@ function shaderSurfaceSvg(node, defs) {
10277
10633
  const parameters = xml(JSON.stringify(node.shader.parameters));
10278
10634
  const surfacePadding = node.shader.surfacePadding ?? 0;
10279
10635
  const fillColor = node.fillColor ? ` data-sf-shader-fill="${xml(node.fillColor)}"` : "";
10280
- 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}" data-sf-shader-padding="${num(surfacePadding)}"${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>`;
10636
+ 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}" data-sf-shader-padding="${num2(surfacePadding)}"${fillColor} x="${num2(node.x)}" y="${num2(node.y)}" width="${num2(node.width)}" height="${num2(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>`;
10281
10637
  }
10282
10638
  function rollingDigitSvg(character, node) {
10283
10639
  const style = node.componentStyle;
@@ -10292,7 +10648,7 @@ function rollingNumberSvg(node, defs) {
10292
10648
  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>` : "";
10293
10649
  const digits = [...node.value].map((character) => rollingDigitSvg(character, node)).join("");
10294
10650
  const componentStyle = xml(JSON.stringify(node.componentStyle));
10295
- 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>`;
10651
+ 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="${num2(node.duration)}" data-sf-widget-style="${componentStyle}" x="${num2(node.x)}" y="${num2(node.y)}" width="${num2(node.width)}" height="${num2(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:${num2(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>`;
10296
10652
  }
10297
10653
  function nodeSvg(node, defs) {
10298
10654
  if (node.type === "text") {
@@ -10305,14 +10661,14 @@ function nodeSvg(node, defs) {
10305
10661
  return rollingNumberSvg(node, defs);
10306
10662
  }
10307
10663
  if (node.type === "image") {
10308
- return `<image id="${defs.elementId(node.id)}"${contractAttrs(node)} ${imageAttrs(node, defs)} href="${xml(node.href)}" x="${num(node.x)}" y="${num(node.y)}" width="${num(node.width)}" height="${num(node.height)}" preserveAspectRatio="xMidYMid slice"/>`;
10664
+ return `<image id="${defs.elementId(node.id)}"${contractAttrs(node)} ${imageAttrs(node, defs)} href="${xml(node.href)}" x="${num2(node.x)}" y="${num2(node.y)}" width="${num2(node.width)}" height="${num2(node.height)}" preserveAspectRatio="${node.aspect === "none" ? "none" : `xMidYMid ${node.aspect ?? "slice"}`}"${transform(node.rotation, node.rotationCenter)}/>`;
10309
10665
  }
10310
10666
  const attrs = `id="${defs.elementId(node.id)}"${contractAttrs(node)} ${styleAttrs(node, defs)}`;
10311
10667
  if (node.type === "rect") {
10312
- return `<rect ${attrs} x="${num(node.x)}" y="${num(node.y)}" width="${num(node.width)}" height="${num(node.height)}"${node.rx ? ` rx="${num(node.rx)}"` : ""}${transform(node.rotation, { x: node.x + node.width / 2, y: node.y + node.height / 2 })}/>`;
10668
+ return `<rect ${attrs} x="${num2(node.x)}" y="${num2(node.y)}" width="${num2(node.width)}" height="${num2(node.height)}"${node.rx ? ` rx="${num2(node.rx)}"` : ""}${transform(node.rotation, { x: node.x + node.width / 2, y: node.y + node.height / 2 })}/>`;
10313
10669
  }
10314
10670
  if (node.type === "ellipse") {
10315
- return `<ellipse ${attrs} cx="${num(node.cx)}" cy="${num(node.cy)}" rx="${num(node.rx)}" ry="${num(node.ry)}"${transform(node.rotation, { x: node.cx, y: node.cy })}/>`;
10671
+ return `<ellipse ${attrs} cx="${num2(node.cx)}" cy="${num2(node.cy)}" rx="${num2(node.rx)}" ry="${num2(node.ry)}"${transform(node.rotation, { x: node.cx, y: node.cy })}/>`;
10316
10672
  }
10317
10673
  return `<path ${attrs} d="${xml(node.d)}"${transform(node.rotation, node.rotationCenter)}/>`;
10318
10674
  }
@@ -10322,12 +10678,12 @@ function renderSvgDocument(scene, options = {}) {
10322
10678
  const padding = options.padding ?? 16;
10323
10679
  const width = Math.max(1, scene.bounds.maxX - scene.bounds.minX + padding * 2);
10324
10680
  const height = Math.max(1, scene.bounds.maxY - scene.bounds.minY + padding * 2);
10325
- const viewBox = `${num(scene.bounds.minX - padding)} ${num(scene.bounds.minY - padding)} ${num(width)} ${num(height)}`;
10681
+ const viewBox = `${num2(scene.bounds.minX - padding)} ${num2(scene.bounds.minY - padding)} ${num2(width)} ${num2(height)}`;
10326
10682
  const defs = new SvgDefinitionRegistry(options.idPrefix ? `${options.idPrefix}-` : "");
10327
10683
  const nodes = options.linkHitAreas ? withLinkHitAreas(scene.nodes) : scene.nodes;
10328
10684
  const body = nodes.map((node) => nodeSvg(node, defs)).join("\n ");
10329
10685
  const declaration = options.includeXmlDeclaration === false ? "" : '<?xml version="1.0" encoding="UTF-8"?>\n';
10330
- const svg = `${declaration}<svg xmlns="http://www.w3.org/2000/svg" width="${num(width)}px" height="${num(height)}px" viewBox="${viewBox}" role="img" data-sf-contract="${DOM_CONTRACT_VERSION}">
10686
+ const svg = `${declaration}<svg xmlns="http://www.w3.org/2000/svg" width="${num2(width)}px" height="${num2(height)}px" viewBox="${viewBox}" role="img" data-sf-contract="${DOM_CONTRACT_VERSION}">
10331
10687
  <defs>${defs.entries.join("")}</defs>
10332
10688
  ${body}
10333
10689
  </svg>`;
@@ -10393,5 +10749,5 @@ function defineComponent(definition) {
10393
10749
  }
10394
10750
 
10395
10751
  export { collectCanvasObjects, decodeColor, decodeShadow, defineComponent, render, renderCanvas, sflToRenderInput, sliderReach };
10396
- //# sourceMappingURL=chunk-SDOHUNBW.js.map
10397
- //# sourceMappingURL=chunk-SDOHUNBW.js.map
10752
+ //# sourceMappingURL=chunk-Q6QLU6YQ.js.map
10753
+ //# sourceMappingURL=chunk-Q6QLU6YQ.js.map