@effing/canvas 0.22.0 → 0.22.1

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.
package/dist/index.js CHANGED
@@ -1041,6 +1041,7 @@ function drawBoxShadow(ctx, x, y, width, height, boxShadow, borderRadius) {
1041
1041
 
1042
1042
  // src/jsx/draw/svg.ts
1043
1043
  import { Path2D } from "@napi-rs/canvas";
1044
+ import parseCssColor from "parse-css-color";
1044
1045
  function resolveCurrentColor(value, color) {
1045
1046
  if (value?.toLowerCase() === "currentcolor") return color;
1046
1047
  return value;
@@ -1098,10 +1099,10 @@ function parseFrac(value, fallback) {
1098
1099
  }
1099
1100
  function applyOpacity(color, opacity) {
1100
1101
  if (opacity >= 1) return color;
1101
- const m = color.match(/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i);
1102
- if (m)
1103
- return `rgba(${parseInt(m[1], 16)}, ${parseInt(m[2], 16)}, ${parseInt(m[3], 16)}, ${opacity})`;
1104
- return color;
1102
+ const parsed = parseCssColor(color);
1103
+ if (!parsed) return color;
1104
+ const [r, g, b] = parsed.values;
1105
+ return `rgba(${r}, ${g}, ${b}, ${parsed.alpha * opacity})`;
1105
1106
  }
1106
1107
  function addGradientStops(gradient, def) {
1107
1108
  for (const stop of normalizeChildren(def)) {
@@ -1438,7 +1439,14 @@ function drawSvgContainer(ctx, node, x, y, width, height) {
1438
1439
  }
1439
1440
  const color = node.style.color ?? "black";
1440
1441
  const merged = mergeStyleIntoProps(node.props);
1441
- const inheritedFill = resolveCurrentColor(merged.fill, color) ?? "black";
1442
+ const inherited = {
1443
+ fill: resolveCurrentColor(merged.fill, color) ?? "black",
1444
+ stroke: resolveCurrentColor(merged.stroke, color),
1445
+ strokeWidth: merged.strokeWidth ?? merged["stroke-width"],
1446
+ strokeLinecap: merged.strokeLinecap ?? merged["stroke-linecap"],
1447
+ strokeLinejoin: merged.strokeLinejoin ?? merged["stroke-linejoin"],
1448
+ strokeOpacity: merged.strokeOpacity ?? merged["stroke-opacity"]
1449
+ };
1442
1450
  const children = node.props.children;
1443
1451
  if (children != null) {
1444
1452
  const childArray = Array.isArray(children) ? children : [children];
@@ -1447,7 +1455,7 @@ function drawSvgContainer(ctx, node, x, y, width, height) {
1447
1455
  );
1448
1456
  const defs = collectDefs(svgChildren);
1449
1457
  for (const child of svgChildren) {
1450
- drawSvgChild(ctx, child, inheritedFill, color, defs, vbW, vbH);
1458
+ drawSvgChild(ctx, child, inherited, color, defs, vbW, vbH);
1451
1459
  }
1452
1460
  }
1453
1461
  ctx.restore();
@@ -1604,7 +1612,7 @@ function applyFilter(filterDef, sourceGraphic, w, h) {
1604
1612
  }
1605
1613
  return lastResult;
1606
1614
  }
1607
- function drawSvgChild(ctx, child, inheritedFill, color, defs = EMPTY_DEFS, vbW = 0, vbH = 0) {
1615
+ function drawSvgChild(ctx, child, inherited, color, defs = EMPTY_DEFS, vbW = 0, vbH = 0) {
1608
1616
  const { type } = child;
1609
1617
  const props = mergeStyleIntoProps(child.props);
1610
1618
  if (type === "defs" || type === "clipPath" || type === "mask" || type === "filter")
@@ -1632,28 +1640,28 @@ function drawSvgChild(ctx, child, inheritedFill, color, defs = EMPTY_DEFS, vbW =
1632
1640
  })() : ctx;
1633
1641
  switch (type) {
1634
1642
  case "path":
1635
- drawPath(targetCtx, props, inheritedFill, color, defs);
1643
+ drawPath(targetCtx, props, inherited, color, defs);
1636
1644
  break;
1637
1645
  case "circle":
1638
- drawCircle(targetCtx, props, inheritedFill, color, defs, vbW, vbH);
1646
+ drawCircle(targetCtx, props, inherited, color, defs, vbW, vbH);
1639
1647
  break;
1640
1648
  case "rect":
1641
- drawSvgRect(targetCtx, props, inheritedFill, color, defs, vbW, vbH);
1649
+ drawSvgRect(targetCtx, props, inherited, color, defs, vbW, vbH);
1642
1650
  break;
1643
1651
  case "line":
1644
- drawLine(targetCtx, props, color, defs, vbW, vbH);
1652
+ drawLine(targetCtx, props, inherited, color, defs, vbW, vbH);
1645
1653
  break;
1646
1654
  case "ellipse":
1647
- drawEllipse(targetCtx, props, inheritedFill, color, defs, vbW, vbH);
1655
+ drawEllipse(targetCtx, props, inherited, color, defs, vbW, vbH);
1648
1656
  break;
1649
1657
  case "polygon":
1650
- drawPolygon(targetCtx, props, inheritedFill, color, defs);
1658
+ drawPolygon(targetCtx, props, inherited, color, defs);
1651
1659
  break;
1652
1660
  case "polyline":
1653
- drawPolyline(targetCtx, props, inheritedFill, color, defs);
1661
+ drawPolyline(targetCtx, props, inherited, color, defs);
1654
1662
  break;
1655
1663
  case "g":
1656
- drawGroup(targetCtx, child, inheritedFill, color, defs, vbW, vbH);
1664
+ drawGroup(targetCtx, child, inherited, color, defs, vbW, vbH);
1657
1665
  break;
1658
1666
  }
1659
1667
  if (needsOffscreen && elemCanvas) {
@@ -1663,7 +1671,15 @@ function drawSvgChild(ctx, child, inheritedFill, color, defs = EMPTY_DEFS, vbW =
1663
1671
  Math.ceil(vbH)
1664
1672
  );
1665
1673
  for (const shape of maskShapes) {
1666
- drawSvgChild(maskCtx, shape, "white", "white", defs, vbW, vbH);
1674
+ drawSvgChild(
1675
+ maskCtx,
1676
+ shape,
1677
+ { fill: "white" },
1678
+ "white",
1679
+ defs,
1680
+ vbW,
1681
+ vbH
1682
+ );
1667
1683
  }
1668
1684
  targetCtx.globalCompositeOperation = "destination-in";
1669
1685
  targetCtx.drawImage(maskCanvas, 0, 0);
@@ -1687,14 +1703,14 @@ function drawSvgChild(ctx, child, inheritedFill, color, defs = EMPTY_DEFS, vbW =
1687
1703
  if (clipPath) ctx.restore();
1688
1704
  if (transform) ctx.restore();
1689
1705
  }
1690
- function drawPath(ctx, props, inheritedFill, color, defs) {
1706
+ function drawPath(ctx, props, inherited, color, defs) {
1691
1707
  const d = props.d;
1692
1708
  if (!d) return;
1693
1709
  const path = new Path2D(d);
1694
1710
  const bbox = pathBBox(d);
1695
- applyFillAndStroke(ctx, props, path, inheritedFill, color, defs, bbox);
1711
+ applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);
1696
1712
  }
1697
- function drawCircle(ctx, props, inheritedFill, color, defs, vbW = 0, vbH = 0) {
1713
+ function drawCircle(ctx, props, inherited, color, defs, vbW = 0, vbH = 0) {
1698
1714
  const cx = svgLength(props.cx, vbW);
1699
1715
  const cy = svgLength(props.cy, vbH);
1700
1716
  const r = svgLength(props.r, Math.min(vbW, vbH));
@@ -1702,9 +1718,9 @@ function drawCircle(ctx, props, inheritedFill, color, defs, vbW = 0, vbH = 0) {
1702
1718
  const path = new Path2D();
1703
1719
  path.arc(cx, cy, r, 0, Math.PI * 2);
1704
1720
  const bbox = { x: cx - r, y: cy - r, width: 2 * r, height: 2 * r };
1705
- applyFillAndStroke(ctx, props, path, inheritedFill, color, defs, bbox);
1721
+ applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);
1706
1722
  }
1707
- function drawSvgRect(ctx, props, inheritedFill, color, defs, vbW = 0, vbH = 0) {
1723
+ function drawSvgRect(ctx, props, inherited, color, defs, vbW = 0, vbH = 0) {
1708
1724
  const x = svgLength(props.x, vbW);
1709
1725
  const y = svgLength(props.y, vbH);
1710
1726
  const w = svgLength(props.width, vbW);
@@ -1723,9 +1739,9 @@ function drawSvgRect(ctx, props, inheritedFill, color, defs, vbW = 0, vbH = 0) {
1723
1739
  path.rect(x, y, w, h);
1724
1740
  }
1725
1741
  const bbox = { x, y, width: w, height: h };
1726
- applyFillAndStroke(ctx, props, path, inheritedFill, color, defs, bbox);
1742
+ applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);
1727
1743
  }
1728
- function drawLine(ctx, props, color, defs, vbW = 0, vbH = 0) {
1744
+ function drawLine(ctx, props, inherited, color, defs, vbW = 0, vbH = 0) {
1729
1745
  const x1 = svgLength(props.x1, vbW);
1730
1746
  const y1 = svgLength(props.y1, vbH);
1731
1747
  const x2 = svgLength(props.x2, vbW);
@@ -1739,9 +1755,9 @@ function drawLine(ctx, props, color, defs, vbW = 0, vbH = 0) {
1739
1755
  width: Math.abs(x2 - x1),
1740
1756
  height: Math.abs(y2 - y1)
1741
1757
  };
1742
- applyStroke(ctx, props, path, color, defs, bbox);
1758
+ applyStroke(ctx, props, path, inherited, color, defs, bbox);
1743
1759
  }
1744
- function drawEllipse(ctx, props, inheritedFill, color, defs, vbW = 0, vbH = 0) {
1760
+ function drawEllipse(ctx, props, inherited, color, defs, vbW = 0, vbH = 0) {
1745
1761
  const cx = svgLength(props.cx, vbW);
1746
1762
  const cy = svgLength(props.cy, vbH);
1747
1763
  const rx = svgLength(props.rx, vbW);
@@ -1755,9 +1771,9 @@ function drawEllipse(ctx, props, inheritedFill, color, defs, vbW = 0, vbH = 0) {
1755
1771
  width: 2 * rx,
1756
1772
  height: 2 * ry
1757
1773
  };
1758
- applyFillAndStroke(ctx, props, path, inheritedFill, color, defs, bbox);
1774
+ applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);
1759
1775
  }
1760
- function drawPolygon(ctx, props, inheritedFill, color, defs) {
1776
+ function drawPolygon(ctx, props, inherited, color, defs) {
1761
1777
  const points = parsePoints(props.points);
1762
1778
  if (points.length < 2) return;
1763
1779
  const path = new Path2D();
@@ -1767,9 +1783,9 @@ function drawPolygon(ctx, props, inheritedFill, color, defs) {
1767
1783
  }
1768
1784
  path.closePath();
1769
1785
  const bbox = pointsBBox(points);
1770
- applyFillAndStroke(ctx, props, path, inheritedFill, color, defs, bbox);
1786
+ applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);
1771
1787
  }
1772
- function drawPolyline(ctx, props, inheritedFill, color, defs) {
1788
+ function drawPolyline(ctx, props, inherited, color, defs) {
1773
1789
  const points = parsePoints(props.points);
1774
1790
  if (points.length < 2) return;
1775
1791
  const path = new Path2D();
@@ -1778,7 +1794,7 @@ function drawPolyline(ctx, props, inheritedFill, color, defs) {
1778
1794
  path.lineTo(points[i][0], points[i][1]);
1779
1795
  }
1780
1796
  const bbox = pointsBBox(points);
1781
- applyFillAndStroke(ctx, props, path, inheritedFill, color, defs, bbox);
1797
+ applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox);
1782
1798
  }
1783
1799
  function applySvgTransform(ctx, transform) {
1784
1800
  const re = /\b(translate|scale|rotate|skewX|skewY|matrix)\s*\(([^)]*)\)/g;
@@ -1841,11 +1857,18 @@ function applySvgTransform(ctx, transform) {
1841
1857
  }
1842
1858
  }
1843
1859
  }
1844
- function drawGroup(ctx, node, inheritedFill, color, defs = EMPTY_DEFS, vbW = 0, vbH = 0) {
1860
+ function drawGroup(ctx, node, inherited, color, defs = EMPTY_DEFS, vbW = 0, vbH = 0) {
1845
1861
  const children = normalizeChildren(node);
1846
1862
  if (children.length === 0) return;
1847
1863
  const merged = mergeStyleIntoProps(node.props);
1848
- const groupFill = resolveCurrentColor(merged.fill, color) ?? inheritedFill;
1864
+ const groupInherited = {
1865
+ fill: resolveCurrentColor(merged.fill, color) ?? inherited.fill,
1866
+ stroke: resolveCurrentColor(merged.stroke, color) ?? inherited.stroke,
1867
+ strokeWidth: merged.strokeWidth ?? merged["stroke-width"] ?? inherited.strokeWidth,
1868
+ strokeLinecap: merged.strokeLinecap ?? merged["stroke-linecap"] ?? inherited.strokeLinecap,
1869
+ strokeLinejoin: merged.strokeLinejoin ?? merged["stroke-linejoin"] ?? inherited.strokeLinejoin,
1870
+ strokeOpacity: merged.strokeOpacity ?? merged["stroke-opacity"] ?? inherited.strokeOpacity
1871
+ };
1849
1872
  const transform = merged.transform;
1850
1873
  if (transform) {
1851
1874
  ctx.save();
@@ -1853,7 +1876,7 @@ function drawGroup(ctx, node, inheritedFill, color, defs = EMPTY_DEFS, vbW = 0,
1853
1876
  }
1854
1877
  for (const child of children) {
1855
1878
  if (child != null && typeof child === "object") {
1856
- drawSvgChild(ctx, child, groupFill, color, defs, vbW, vbH);
1879
+ drawSvgChild(ctx, child, groupInherited, color, defs, vbW, vbH);
1857
1880
  }
1858
1881
  }
1859
1882
  if (transform) {
@@ -1869,8 +1892,8 @@ function parsePoints(value) {
1869
1892
  }
1870
1893
  return result;
1871
1894
  }
1872
- function applyFillAndStroke(ctx, props, path, inheritedFill, color, defs, bbox) {
1873
- const fill = resolveCurrentColor(props.fill, color) ?? inheritedFill;
1895
+ function applyFillAndStroke(ctx, props, path, inherited, color, defs, bbox) {
1896
+ const fill = resolveCurrentColor(props.fill, color) ?? inherited.fill;
1874
1897
  const fillRule = props.fillRule ?? props["fill-rule"];
1875
1898
  const fillOpacity = Number(props.fillOpacity ?? props["fill-opacity"] ?? 1);
1876
1899
  const fillRef = parseUrlRef(fill);
@@ -1902,17 +1925,19 @@ function applyFillAndStroke(ctx, props, path, inheritedFill, color, defs, bbox)
1902
1925
  ctx.fillStyle = applyOpacity(fill, fillOpacity);
1903
1926
  ctx.fill(path, fillRule ?? "nonzero");
1904
1927
  }
1905
- applyStroke(ctx, props, path, color, defs, bbox);
1928
+ applyStroke(ctx, props, path, inherited, color, defs, bbox);
1906
1929
  }
1907
- function applyStroke(ctx, props, path, color, defs, bbox) {
1908
- const stroke = resolveCurrentColor(props.stroke, color);
1930
+ function applyStroke(ctx, props, path, inherited, color, defs, bbox) {
1931
+ const stroke = resolveCurrentColor(props.stroke, color) ?? inherited.stroke;
1909
1932
  if (!stroke || stroke === "none") return;
1910
1933
  const strokeOpacity = Number(
1911
- props.strokeOpacity ?? props["stroke-opacity"] ?? 1
1934
+ props.strokeOpacity ?? props["stroke-opacity"] ?? inherited.strokeOpacity ?? 1
1935
+ );
1936
+ ctx.lineWidth = Number(
1937
+ props.strokeWidth ?? props["stroke-width"] ?? inherited.strokeWidth ?? 1
1912
1938
  );
1913
- ctx.lineWidth = Number(props.strokeWidth ?? props["stroke-width"] ?? 1);
1914
- ctx.lineCap = props.strokeLinecap ?? props["stroke-linecap"] ?? "butt";
1915
- ctx.lineJoin = props.strokeLinejoin ?? props["stroke-linejoin"] ?? "miter";
1939
+ ctx.lineCap = props.strokeLinecap ?? props["stroke-linecap"] ?? inherited.strokeLinecap ?? "butt";
1940
+ ctx.lineJoin = props.strokeLinejoin ?? props["stroke-linejoin"] ?? inherited.strokeLinejoin ?? "miter";
1916
1941
  const strokeRef = parseUrlRef(stroke);
1917
1942
  if (strokeRef) {
1918
1943
  const gradientDef = defs.gradients.get(strokeRef);