@effing/canvas 0.19.2 → 0.19.3
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 +55 -229
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -266,8 +266,7 @@ function layoutText(text, style, maxWidth, ctx, emojiEnabled) {
|
|
|
266
266
|
processedText = text.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
267
267
|
}
|
|
268
268
|
const noWrap = whiteSpace === "nowrap" || whiteSpace === "pre";
|
|
269
|
-
const
|
|
270
|
-
const paragraphs = preserveWhitespace ? processedText.split("\n") : processedText.split("\n");
|
|
269
|
+
const paragraphs = processedText.split("\n");
|
|
271
270
|
const lines = [];
|
|
272
271
|
for (const paragraph of paragraphs) {
|
|
273
272
|
if (noWrap) {
|
|
@@ -738,10 +737,30 @@ async function drawImage(ctx, src, x, y, width, height, style, preloadedImage) {
|
|
|
738
737
|
}
|
|
739
738
|
}
|
|
740
739
|
|
|
740
|
+
// src/jsx/draw/utils.ts
|
|
741
|
+
function parseCSSLength(value, referenceSize) {
|
|
742
|
+
if (value.endsWith("%")) return parseFloat(value) / 100 * referenceSize;
|
|
743
|
+
return parseFloat(value);
|
|
744
|
+
}
|
|
745
|
+
function toNumber(v) {
|
|
746
|
+
if (typeof v === "number") return v;
|
|
747
|
+
if (v === void 0 || v === null) return 0;
|
|
748
|
+
const n = parseFloat(String(v));
|
|
749
|
+
return isNaN(n) ? 0 : n;
|
|
750
|
+
}
|
|
751
|
+
function resolveBoxValue(v, referenceWidth) {
|
|
752
|
+
if (typeof v === "number") return v;
|
|
753
|
+
if (v === void 0 || v === null) return 0;
|
|
754
|
+
const s = String(v);
|
|
755
|
+
if (s.endsWith("%")) return parseFloat(s) / 100 * referenceWidth;
|
|
756
|
+
const n = parseFloat(s);
|
|
757
|
+
return isNaN(n) ? 0 : n;
|
|
758
|
+
}
|
|
759
|
+
|
|
741
760
|
// src/jsx/draw/rect.ts
|
|
742
761
|
function drawRect(ctx, x, y, width, height, style) {
|
|
743
|
-
const borderRadius =
|
|
744
|
-
const hasRoundedCorners = borderRadius
|
|
762
|
+
const borderRadius = getBorderRadiusFromStyle(style, width, height);
|
|
763
|
+
const hasRoundedCorners = hasRadius(borderRadius);
|
|
745
764
|
if (style.boxShadow) {
|
|
746
765
|
drawBoxShadow(ctx, x, y, width, height, style.boxShadow, borderRadius);
|
|
747
766
|
}
|
|
@@ -771,7 +790,7 @@ function resolveRadius(v, width, height) {
|
|
|
771
790
|
if (typeof v === "string") return parseCSSLength(v, Math.min(width, height));
|
|
772
791
|
return toNumber(v);
|
|
773
792
|
}
|
|
774
|
-
function
|
|
793
|
+
function getBorderRadiusFromStyle(style, width, height) {
|
|
775
794
|
return {
|
|
776
795
|
topLeft: resolveRadius(style.borderTopLeftRadius, width, height),
|
|
777
796
|
topRight: resolveRadius(style.borderTopRightRadius, width, height),
|
|
@@ -779,11 +798,8 @@ function getBorderRadius(style, width, height) {
|
|
|
779
798
|
bottomLeft: resolveRadius(style.borderBottomLeftRadius, width, height)
|
|
780
799
|
};
|
|
781
800
|
}
|
|
782
|
-
function getBorderRadiusFromStyle(style, width, height) {
|
|
783
|
-
return getBorderRadius(style, width, height);
|
|
784
|
-
}
|
|
785
801
|
function drawBorders(ctx, x, y, width, height, style, borderRadius) {
|
|
786
|
-
const hasRoundedCorners = borderRadius
|
|
802
|
+
const hasRoundedCorners = hasRadius(borderRadius);
|
|
787
803
|
const tw = resolveBoxValue(style.borderTopWidth, width);
|
|
788
804
|
const rw = resolveBoxValue(style.borderRightWidth, width);
|
|
789
805
|
const bw = resolveBoxValue(style.borderBottomWidth, width);
|
|
@@ -1573,25 +1589,22 @@ function splitTextIntoRuns(text, measureText2, emojiSize, letterSpacing = 0) {
|
|
|
1573
1589
|
const runs = [];
|
|
1574
1590
|
const segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
1575
1591
|
let currentText = "";
|
|
1592
|
+
let currentGraphemeCount = 0;
|
|
1576
1593
|
let currentX = 0;
|
|
1577
1594
|
let textStartX = 0;
|
|
1578
1595
|
for (const { segment } of segmenter.segment(text)) {
|
|
1579
1596
|
if (isEmojiGrapheme(segment)) {
|
|
1580
1597
|
if (currentText) {
|
|
1581
1598
|
const textWidth = measureText2(currentText);
|
|
1582
|
-
const graphemeCount = [
|
|
1583
|
-
...new Intl.Segmenter(void 0, { granularity: "grapheme" }).segment(
|
|
1584
|
-
currentText
|
|
1585
|
-
)
|
|
1586
|
-
].length;
|
|
1587
1599
|
runs.push({
|
|
1588
1600
|
kind: "text",
|
|
1589
1601
|
text: currentText,
|
|
1590
1602
|
x: textStartX,
|
|
1591
|
-
width: textWidth + letterSpacing *
|
|
1603
|
+
width: textWidth + letterSpacing * currentGraphemeCount
|
|
1592
1604
|
});
|
|
1593
|
-
currentX = textStartX + textWidth + letterSpacing *
|
|
1605
|
+
currentX = textStartX + textWidth + letterSpacing * currentGraphemeCount;
|
|
1594
1606
|
currentText = "";
|
|
1607
|
+
currentGraphemeCount = 0;
|
|
1595
1608
|
}
|
|
1596
1609
|
runs.push({
|
|
1597
1610
|
kind: "emoji",
|
|
@@ -1604,20 +1617,16 @@ function splitTextIntoRuns(text, measureText2, emojiSize, letterSpacing = 0) {
|
|
|
1604
1617
|
} else {
|
|
1605
1618
|
if (!currentText) textStartX = currentX;
|
|
1606
1619
|
currentText += segment;
|
|
1620
|
+
currentGraphemeCount++;
|
|
1607
1621
|
}
|
|
1608
1622
|
}
|
|
1609
1623
|
if (currentText) {
|
|
1610
1624
|
const textWidth = measureText2(currentText);
|
|
1611
|
-
const graphemeCount = [
|
|
1612
|
-
...new Intl.Segmenter(void 0, { granularity: "grapheme" }).segment(
|
|
1613
|
-
currentText
|
|
1614
|
-
)
|
|
1615
|
-
].length;
|
|
1616
1625
|
runs.push({
|
|
1617
1626
|
kind: "text",
|
|
1618
1627
|
text: currentText,
|
|
1619
1628
|
x: textStartX,
|
|
1620
|
-
width: textWidth + letterSpacing *
|
|
1629
|
+
width: textWidth + letterSpacing * currentGraphemeCount
|
|
1621
1630
|
});
|
|
1622
1631
|
}
|
|
1623
1632
|
return runs;
|
|
@@ -1680,15 +1689,12 @@ async function drawSegmentWithEmoji(ctx, seg, x, y, textShadow, emojiStyle) {
|
|
|
1680
1689
|
);
|
|
1681
1690
|
for (const run of runs) {
|
|
1682
1691
|
if (run.kind === "text") {
|
|
1692
|
+
if (textShadow) {
|
|
1693
|
+
drawTextShadow(ctx, run.text, x + run.x, y, textShadow);
|
|
1694
|
+
}
|
|
1683
1695
|
if (letterSpacing !== 0) {
|
|
1684
|
-
if (textShadow) {
|
|
1685
|
-
drawTextShadow(ctx, run.text, x + run.x, y, textShadow);
|
|
1686
|
-
}
|
|
1687
1696
|
drawTextWithLetterSpacing(ctx, run.text, x + run.x, y, letterSpacing);
|
|
1688
1697
|
} else {
|
|
1689
|
-
if (textShadow) {
|
|
1690
|
-
drawTextShadow(ctx, run.text, x + run.x, y, textShadow);
|
|
1691
|
-
}
|
|
1692
1698
|
ctx.fillText(run.text, x + run.x, y);
|
|
1693
1699
|
}
|
|
1694
1700
|
} else {
|
|
@@ -1803,7 +1809,7 @@ async function drawNode(ctx, node, parentX, parentY, debug, emojiStyle) {
|
|
|
1803
1809
|
const [offscreen, offCtx] = acquireOffscreen(bufW, bufH);
|
|
1804
1810
|
offCtx.save();
|
|
1805
1811
|
offCtx.scale(qx, qy);
|
|
1806
|
-
await
|
|
1812
|
+
await drawNodeCore(
|
|
1807
1813
|
offCtx,
|
|
1808
1814
|
node,
|
|
1809
1815
|
parentX,
|
|
@@ -1845,182 +1851,7 @@ async function drawNode(ctx, node, parentX, parentY, debug, emojiStyle) {
|
|
|
1845
1851
|
return;
|
|
1846
1852
|
}
|
|
1847
1853
|
}
|
|
1848
|
-
ctx
|
|
1849
|
-
if (opacity < 1) {
|
|
1850
|
-
ctx.globalAlpha *= opacity;
|
|
1851
|
-
}
|
|
1852
|
-
if (style.filter) {
|
|
1853
|
-
ctx.filter = style.filter;
|
|
1854
|
-
}
|
|
1855
|
-
if (style.transform) {
|
|
1856
|
-
applyTransform(
|
|
1857
|
-
ctx,
|
|
1858
|
-
style.transform,
|
|
1859
|
-
x,
|
|
1860
|
-
y,
|
|
1861
|
-
width,
|
|
1862
|
-
height,
|
|
1863
|
-
style.transformOrigin
|
|
1864
|
-
);
|
|
1865
|
-
}
|
|
1866
|
-
const isClipped = style.overflow === "hidden" || style.overflowX === "hidden" || style.overflowY === "hidden";
|
|
1867
|
-
if (isClipped) {
|
|
1868
|
-
const borderRadius = getBorderRadiusFromStyle(style, width, height);
|
|
1869
|
-
applyClip(ctx, x, y, width, height, borderRadius);
|
|
1870
|
-
}
|
|
1871
|
-
if (style.backgroundColor || style.borderTopWidth || style.borderRightWidth || style.borderBottomWidth || style.borderLeftWidth || style.boxShadow) {
|
|
1872
|
-
drawRect(ctx, x, y, width, height, style);
|
|
1873
|
-
}
|
|
1874
|
-
if (style.backgroundImage) {
|
|
1875
|
-
const layers = splitGradientArgs(style.backgroundImage);
|
|
1876
|
-
for (let i = layers.length - 1; i >= 0; i--) {
|
|
1877
|
-
const layer = layers[i].trim();
|
|
1878
|
-
const gradient = createGradientFromCSS(ctx, layer, x, y, width, height);
|
|
1879
|
-
if (gradient) {
|
|
1880
|
-
ctx.fillStyle = gradient;
|
|
1881
|
-
const borderRadius = getBorderRadiusFromStyle(style, width, height);
|
|
1882
|
-
if (borderRadius.topLeft > 0 || borderRadius.topRight > 0 || borderRadius.bottomRight > 0 || borderRadius.bottomLeft > 0) {
|
|
1883
|
-
ctx.beginPath();
|
|
1884
|
-
roundedRect(
|
|
1885
|
-
ctx,
|
|
1886
|
-
x,
|
|
1887
|
-
y,
|
|
1888
|
-
width,
|
|
1889
|
-
height,
|
|
1890
|
-
borderRadius.topLeft,
|
|
1891
|
-
borderRadius.topRight,
|
|
1892
|
-
borderRadius.bottomRight,
|
|
1893
|
-
borderRadius.bottomLeft
|
|
1894
|
-
);
|
|
1895
|
-
ctx.fill();
|
|
1896
|
-
} else {
|
|
1897
|
-
ctx.fillRect(x, y, width, height);
|
|
1898
|
-
}
|
|
1899
|
-
} else {
|
|
1900
|
-
const urlMatch = layer.match(/url\(["']?(.*?)["']?\)/);
|
|
1901
|
-
if (urlMatch) {
|
|
1902
|
-
const borderRadius = getBorderRadiusFromStyle(style, width, height);
|
|
1903
|
-
const hasRadius2 = borderRadius.topLeft > 0 || borderRadius.topRight > 0 || borderRadius.bottomRight > 0 || borderRadius.bottomLeft > 0;
|
|
1904
|
-
if (hasRadius2) {
|
|
1905
|
-
applyClip(ctx, x, y, width, height, borderRadius);
|
|
1906
|
-
}
|
|
1907
|
-
const image = await loadImage3(urlMatch[1]);
|
|
1908
|
-
const bgSize = style.backgroundSize;
|
|
1909
|
-
if (bgSize === "cover") {
|
|
1910
|
-
const r = computeCover(
|
|
1911
|
-
image.width,
|
|
1912
|
-
image.height,
|
|
1913
|
-
x,
|
|
1914
|
-
y,
|
|
1915
|
-
width,
|
|
1916
|
-
height
|
|
1917
|
-
);
|
|
1918
|
-
ctx.drawImage(
|
|
1919
|
-
image,
|
|
1920
|
-
r.sx,
|
|
1921
|
-
r.sy,
|
|
1922
|
-
r.sw,
|
|
1923
|
-
r.sh,
|
|
1924
|
-
r.dx,
|
|
1925
|
-
r.dy,
|
|
1926
|
-
r.dw,
|
|
1927
|
-
r.dh
|
|
1928
|
-
);
|
|
1929
|
-
} else {
|
|
1930
|
-
let tileW, tileH;
|
|
1931
|
-
if (bgSize === "contain") {
|
|
1932
|
-
const r = computeContain(
|
|
1933
|
-
image.width,
|
|
1934
|
-
image.height,
|
|
1935
|
-
0,
|
|
1936
|
-
0,
|
|
1937
|
-
width,
|
|
1938
|
-
height
|
|
1939
|
-
);
|
|
1940
|
-
tileW = r.dw;
|
|
1941
|
-
tileH = r.dh;
|
|
1942
|
-
} else if (bgSize === "100% 100%") {
|
|
1943
|
-
tileW = width;
|
|
1944
|
-
tileH = height;
|
|
1945
|
-
} else {
|
|
1946
|
-
tileW = image.width;
|
|
1947
|
-
tileH = image.height;
|
|
1948
|
-
}
|
|
1949
|
-
for (let ty = y; ty < y + height; ty += tileH) {
|
|
1950
|
-
for (let tx = x; tx < x + width; tx += tileW) {
|
|
1951
|
-
ctx.drawImage(image, tx, ty, tileW, tileH);
|
|
1952
|
-
}
|
|
1953
|
-
}
|
|
1954
|
-
}
|
|
1955
|
-
}
|
|
1956
|
-
}
|
|
1957
|
-
}
|
|
1958
|
-
}
|
|
1959
|
-
if (debug) {
|
|
1960
|
-
ctx.strokeStyle = "rgba(255, 0, 0, 0.5)";
|
|
1961
|
-
ctx.lineWidth = 1;
|
|
1962
|
-
ctx.strokeRect(x, y, width, height);
|
|
1963
|
-
}
|
|
1964
|
-
if (node.textContent !== void 0 && node.textContent !== "") {
|
|
1965
|
-
const paddingTop = resolveBoxValue(style.paddingTop, width);
|
|
1966
|
-
const paddingLeft = resolveBoxValue(style.paddingLeft, width);
|
|
1967
|
-
const paddingRight = resolveBoxValue(style.paddingRight, width);
|
|
1968
|
-
const borderTopW = resolveBoxValue(style.borderTopWidth, width);
|
|
1969
|
-
const borderLeftW = resolveBoxValue(style.borderLeftWidth, width);
|
|
1970
|
-
const borderRightW = resolveBoxValue(style.borderRightWidth, width);
|
|
1971
|
-
const contentX = x + paddingLeft + borderLeftW;
|
|
1972
|
-
const contentY = y + paddingTop + borderTopW;
|
|
1973
|
-
const contentWidth = width - paddingLeft - paddingRight - borderLeftW - borderRightW;
|
|
1974
|
-
const textLayout = layoutText(
|
|
1975
|
-
node.textContent,
|
|
1976
|
-
style,
|
|
1977
|
-
contentWidth,
|
|
1978
|
-
ctx,
|
|
1979
|
-
!!emojiStyle
|
|
1980
|
-
);
|
|
1981
|
-
await drawText(
|
|
1982
|
-
ctx,
|
|
1983
|
-
textLayout.segments,
|
|
1984
|
-
contentX,
|
|
1985
|
-
contentY,
|
|
1986
|
-
style.textShadow,
|
|
1987
|
-
emojiStyle
|
|
1988
|
-
);
|
|
1989
|
-
}
|
|
1990
|
-
if (node.type === "img" && node.props.src) {
|
|
1991
|
-
const paddingTop = resolveBoxValue(style.paddingTop, width);
|
|
1992
|
-
const paddingLeft = resolveBoxValue(style.paddingLeft, width);
|
|
1993
|
-
const paddingRight = resolveBoxValue(style.paddingRight, width);
|
|
1994
|
-
const paddingBottom = resolveBoxValue(style.paddingBottom, width);
|
|
1995
|
-
const imgX = x + paddingLeft;
|
|
1996
|
-
const imgY = y + paddingTop;
|
|
1997
|
-
const imgW = width - paddingLeft - paddingRight;
|
|
1998
|
-
const imgH = height - paddingTop - paddingBottom;
|
|
1999
|
-
if (!isClipped) {
|
|
2000
|
-
const borderRadius = getBorderRadiusFromStyle(style, width, height);
|
|
2001
|
-
if (borderRadius.topLeft > 0 || borderRadius.topRight > 0 || borderRadius.bottomRight > 0 || borderRadius.bottomLeft > 0) {
|
|
2002
|
-
applyClip(ctx, imgX, imgY, imgW, imgH, borderRadius);
|
|
2003
|
-
}
|
|
2004
|
-
}
|
|
2005
|
-
await drawImage(
|
|
2006
|
-
ctx,
|
|
2007
|
-
node.props.src,
|
|
2008
|
-
imgX,
|
|
2009
|
-
imgY,
|
|
2010
|
-
imgW,
|
|
2011
|
-
imgH,
|
|
2012
|
-
style,
|
|
2013
|
-
node.props.__loadedImage
|
|
2014
|
-
);
|
|
2015
|
-
}
|
|
2016
|
-
if (node.type === "svg") {
|
|
2017
|
-
drawSvgContainer(ctx, node, x, y, width, height);
|
|
2018
|
-
} else {
|
|
2019
|
-
for (const child of node.children) {
|
|
2020
|
-
await drawNode(ctx, child, x, y, debug, emojiStyle);
|
|
2021
|
-
}
|
|
2022
|
-
}
|
|
2023
|
-
ctx.restore();
|
|
1854
|
+
await drawNodeCore(ctx, node, parentX, parentY, 0, 0, debug, emojiStyle);
|
|
2024
1855
|
}
|
|
2025
1856
|
function extractScale(transform) {
|
|
2026
1857
|
const scaleMatch = transform.match(/\b(scale|scaleX|scaleY)\(([^)]+)\)/);
|
|
@@ -2032,7 +1863,7 @@ function extractScale(transform) {
|
|
|
2032
1863
|
const remaining = transform.replace(fullMatch, "").trim();
|
|
2033
1864
|
return { sx, sy, remaining };
|
|
2034
1865
|
}
|
|
2035
|
-
async function
|
|
1866
|
+
async function drawNodeCore(ctx, node, parentX, parentY, offsetX, offsetY, debug, emojiStyle, overrideTransform) {
|
|
2036
1867
|
const x = parentX + node.x + offsetX;
|
|
2037
1868
|
const y = parentY + node.y + offsetY;
|
|
2038
1869
|
const { width, height, style } = node;
|
|
@@ -2074,7 +1905,7 @@ async function drawNodeInner(ctx, node, parentX, parentY, offsetX, offsetY, debu
|
|
|
2074
1905
|
if (gradient) {
|
|
2075
1906
|
ctx.fillStyle = gradient;
|
|
2076
1907
|
const borderRadius = getBorderRadiusFromStyle(style, width, height);
|
|
2077
|
-
if (borderRadius
|
|
1908
|
+
if (hasRadius(borderRadius)) {
|
|
2078
1909
|
ctx.beginPath();
|
|
2079
1910
|
roundedRect(
|
|
2080
1911
|
ctx,
|
|
@@ -2095,8 +1926,7 @@ async function drawNodeInner(ctx, node, parentX, parentY, offsetX, offsetY, debu
|
|
|
2095
1926
|
const urlMatch = layer.match(/url\(["']?(.*?)["']?\)/);
|
|
2096
1927
|
if (urlMatch) {
|
|
2097
1928
|
const borderRadius = getBorderRadiusFromStyle(style, width, height);
|
|
2098
|
-
|
|
2099
|
-
if (hasRadius2) {
|
|
1929
|
+
if (hasRadius(borderRadius)) {
|
|
2100
1930
|
applyClip(ctx, x, y, width, height, borderRadius);
|
|
2101
1931
|
}
|
|
2102
1932
|
const image = await loadImage3(urlMatch[1]);
|
|
@@ -2193,7 +2023,7 @@ async function drawNodeInner(ctx, node, parentX, parentY, offsetX, offsetY, debu
|
|
|
2193
2023
|
const imgH = height - paddingTop - paddingBottom;
|
|
2194
2024
|
if (!isClipped) {
|
|
2195
2025
|
const borderRadius = getBorderRadiusFromStyle(style, width, height);
|
|
2196
|
-
if (borderRadius
|
|
2026
|
+
if (hasRadius(borderRadius)) {
|
|
2197
2027
|
applyClip(ctx, imgX, imgY, imgW, imgH, borderRadius);
|
|
2198
2028
|
}
|
|
2199
2029
|
}
|
|
@@ -2212,15 +2042,25 @@ async function drawNodeInner(ctx, node, parentX, parentY, offsetX, offsetY, debu
|
|
|
2212
2042
|
drawSvgContainer(ctx, node, x, y, width, height);
|
|
2213
2043
|
} else {
|
|
2214
2044
|
for (const child of node.children) {
|
|
2215
|
-
|
|
2045
|
+
if (offsetX === 0 && offsetY === 0) {
|
|
2046
|
+
await drawNode(ctx, child, x, y, debug, emojiStyle);
|
|
2047
|
+
} else {
|
|
2048
|
+
await drawNodeCore(
|
|
2049
|
+
ctx,
|
|
2050
|
+
child,
|
|
2051
|
+
x,
|
|
2052
|
+
y,
|
|
2053
|
+
0,
|
|
2054
|
+
0,
|
|
2055
|
+
debug,
|
|
2056
|
+
emojiStyle,
|
|
2057
|
+
void 0
|
|
2058
|
+
);
|
|
2059
|
+
}
|
|
2216
2060
|
}
|
|
2217
2061
|
}
|
|
2218
2062
|
ctx.restore();
|
|
2219
2063
|
}
|
|
2220
|
-
function parseCSSLength(value, referenceSize) {
|
|
2221
|
-
if (value.endsWith("%")) return parseFloat(value) / 100 * referenceSize;
|
|
2222
|
-
return parseFloat(value);
|
|
2223
|
-
}
|
|
2224
2064
|
function applyTransform(ctx, transform, x, y, width, height, transformOrigin) {
|
|
2225
2065
|
let ox = x + width / 2;
|
|
2226
2066
|
let oy = y + height / 2;
|
|
@@ -2285,20 +2125,6 @@ function parseAngle(value) {
|
|
|
2285
2125
|
if (value.endsWith("turn")) return parseFloat(value) * 2 * Math.PI;
|
|
2286
2126
|
return parseFloat(value);
|
|
2287
2127
|
}
|
|
2288
|
-
function toNumber(v) {
|
|
2289
|
-
if (typeof v === "number") return v;
|
|
2290
|
-
if (v === void 0 || v === null) return 0;
|
|
2291
|
-
const n = parseFloat(String(v));
|
|
2292
|
-
return isNaN(n) ? 0 : n;
|
|
2293
|
-
}
|
|
2294
|
-
function resolveBoxValue(v, referenceWidth) {
|
|
2295
|
-
if (typeof v === "number") return v;
|
|
2296
|
-
if (v === void 0 || v === null) return 0;
|
|
2297
|
-
const s = String(v);
|
|
2298
|
-
if (s.endsWith("%")) return parseFloat(s) / 100 * referenceWidth;
|
|
2299
|
-
const n = parseFloat(s);
|
|
2300
|
-
return isNaN(n) ? 0 : n;
|
|
2301
|
-
}
|
|
2302
2128
|
|
|
2303
2129
|
// src/jsx/font.ts
|
|
2304
2130
|
import { GlobalFonts } from "@napi-rs/canvas";
|