canvu-react 0.3.38 → 0.3.39
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/{asset-hydration-DrTOgDdd.d.ts → asset-hydration-DdFLdlqX.d.ts} +1 -1
- package/dist/{asset-hydration-EtEuBwb7.d.cts → asset-hydration-DowNdaOJ.d.cts} +1 -1
- package/dist/chatbot.d.cts +2 -2
- package/dist/chatbot.d.ts +2 -2
- package/dist/index.cjs +105 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +100 -1
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +32 -3
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +6 -6
- package/dist/react.d.ts +6 -6
- package/dist/react.js +32 -3
- package/dist/react.js.map +1 -1
- package/dist/realtime.d.cts +3 -3
- package/dist/realtime.d.ts +3 -3
- package/dist/{shape-builders-CsSXKCcs.d.ts → shape-builders-C7bxJBGR.d.ts} +40 -2
- package/dist/{shape-builders-CsbSRZnQ.d.cts → shape-builders-Dedcl6tw.d.cts} +40 -2
- package/dist/tldraw.cjs +134 -65
- package/dist/tldraw.cjs.map +1 -1
- package/dist/tldraw.js +134 -65
- package/dist/tldraw.js.map +1 -1
- package/dist/{types-B6PAYKzx.d.ts → types-BBb8KoyW.d.ts} +10 -1
- package/dist/{types-DWGk2_GZ.d.cts → types-DUW61Tjy.d.cts} +10 -1
- package/package.json +1 -1
package/dist/tldraw.js
CHANGED
|
@@ -44,11 +44,76 @@ function createCustomShapeItem(id, bounds, content) {
|
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
// src/scene/link-item.ts
|
|
48
|
+
var LINK_PLUGIN_KEY = "canvuLink";
|
|
49
|
+
var LINK_CARD_BORDER = "#e2e8f0";
|
|
50
|
+
var LINK_CARD_ACCENT = "#2563eb";
|
|
51
|
+
var LINK_CARD_TITLE_COLOR = "#0f172a";
|
|
52
|
+
var LINK_CARD_TEXT_COLOR = "#475569";
|
|
53
|
+
var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
54
|
+
var formatNumber = (value) => {
|
|
55
|
+
const rounded = Math.round(value * 100) / 100;
|
|
56
|
+
return Object.is(rounded, -0) ? "0" : String(rounded);
|
|
57
|
+
};
|
|
58
|
+
var escapeXmlAttribute = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
59
|
+
var escapeHtmlText = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
60
|
+
var getLinkHostname = (href) => {
|
|
61
|
+
try {
|
|
62
|
+
return new URL(href).hostname.replace(/^www\./, "");
|
|
63
|
+
} catch {
|
|
64
|
+
return href;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
var buildLinkTextBand = (band) => {
|
|
68
|
+
const lineHeight = band.fontSize * 1.3;
|
|
69
|
+
const weight = band.fontWeight != null ? `font-weight:${band.fontWeight};` : "";
|
|
70
|
+
const lineClampStyle = band.clampLines ? `display:-webkit-box;-webkit-line-clamp:${band.clampLines};-webkit-box-orient:vertical;` : "";
|
|
71
|
+
return `<foreignObject x="${formatNumber(band.x)}" y="${formatNumber(band.y)}" width="${formatNumber(Math.max(1, band.width))}" height="${formatNumber(Math.max(1, band.height))}"><div xmlns="http://www.w3.org/1999/xhtml" style="box-sizing:border-box;width:100%;height:100%;margin:0;font-family:system-ui,sans-serif;font-size:${formatNumber(band.fontSize)}px;line-height:${formatNumber(lineHeight)}px;color:${band.color};overflow:hidden;word-break:break-word;${lineClampStyle}${weight}">${escapeHtmlText(band.text)}</div></foreignObject>`;
|
|
72
|
+
};
|
|
73
|
+
function buildLinkCardSvg(width, height, link) {
|
|
74
|
+
const cardWidth = Math.max(1, width);
|
|
75
|
+
const cardHeight = Math.max(1, height);
|
|
76
|
+
const padding = 14;
|
|
77
|
+
const badgeSize = clamp(Math.min(72, cardHeight - padding * 2), 28, 96);
|
|
78
|
+
const textX = padding + badgeSize + 14;
|
|
79
|
+
const textWidth = Math.max(1, cardWidth - textX - padding);
|
|
80
|
+
const hostname = getLinkHostname(link.href);
|
|
81
|
+
const title = link.title?.trim() || hostname || "Link";
|
|
82
|
+
const description = link.description?.trim() || link.href;
|
|
83
|
+
const titleY = padding;
|
|
84
|
+
const titleHeight = clamp(cardHeight * 0.22, 18, 28);
|
|
85
|
+
const hostY = titleY + titleHeight + 2;
|
|
86
|
+
const hostHeight = 16;
|
|
87
|
+
const descY = hostY + hostHeight + 4;
|
|
88
|
+
const descHeight = Math.max(1, cardHeight - descY - padding);
|
|
89
|
+
const badge = link.favicon ? `<clipPath id="canvu-link-badge"><rect x="${formatNumber(padding)}" y="${formatNumber(padding)}" width="${formatNumber(badgeSize)}" height="${formatNumber(badgeSize)}" rx="12" /></clipPath>
|
|
90
|
+
<rect x="${formatNumber(padding)}" y="${formatNumber(padding)}" width="${formatNumber(badgeSize)}" height="${formatNumber(badgeSize)}" rx="12" fill="#f8fafc" stroke="${LINK_CARD_BORDER}" stroke-width="1" />
|
|
91
|
+
<image href="${escapeXmlAttribute(link.favicon)}" x="${formatNumber(padding)}" y="${formatNumber(padding)}" width="${formatNumber(badgeSize)}" height="${formatNumber(badgeSize)}" preserveAspectRatio="xMidYMid slice" clip-path="url(#canvu-link-badge)" />` : `<rect x="${formatNumber(padding)}" y="${formatNumber(padding)}" width="${formatNumber(badgeSize)}" height="${formatNumber(badgeSize)}" rx="12" fill="${LINK_CARD_ACCENT}" fill-opacity="0.1" stroke="${LINK_CARD_ACCENT}" stroke-opacity="0.3" stroke-width="1" />
|
|
92
|
+
<g transform="translate(${formatNumber(padding + badgeSize / 2)},${formatNumber(padding + badgeSize / 2)})" stroke="${LINK_CARD_ACCENT}" stroke-width="2.4" stroke-linecap="round" fill="none">
|
|
93
|
+
<path d="M-9 3 a6 6 0 0 1 0 -8 l4 -4 a6 6 0 0 1 8 8 l-2 2" />
|
|
94
|
+
<path d="M9 -3 a6 6 0 0 1 0 8 l-4 4 a6 6 0 0 1 -8 -8 l2 -2" />
|
|
95
|
+
</g>`;
|
|
96
|
+
const externalIconX = cardWidth - padding - 16;
|
|
97
|
+
const externalIcon = `<g transform="translate(${formatNumber(externalIconX)},${formatNumber(padding)})" stroke="${LINK_CARD_TEXT_COLOR}" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" fill="none">
|
|
98
|
+
<path d="M6 1 H11 V6" />
|
|
99
|
+
<path d="M11 1 L4.5 7.5" />
|
|
100
|
+
<path d="M9 7 V10 a1 1 0 0 1 -1 1 H2 a1 1 0 0 1 -1 -1 V4 a1 1 0 0 1 1 -1 H5" />
|
|
101
|
+
</g>`;
|
|
102
|
+
return `
|
|
103
|
+
<rect width="${formatNumber(cardWidth)}" height="${formatNumber(cardHeight)}" rx="16" fill="#ffffff" stroke="${LINK_CARD_BORDER}" stroke-width="1.5" />
|
|
104
|
+
${badge}
|
|
105
|
+
${externalIcon}
|
|
106
|
+
${buildLinkTextBand({ x: textX, y: titleY, width: textWidth - 18, height: titleHeight, text: title, fontSize: 15, color: LINK_CARD_TITLE_COLOR, fontWeight: 700, clampLines: 1 })}
|
|
107
|
+
${buildLinkTextBand({ x: textX, y: hostY, width: textWidth, height: hostHeight, text: hostname, fontSize: 12, color: LINK_CARD_ACCENT, clampLines: 1 })}
|
|
108
|
+
${buildLinkTextBand({ x: textX, y: descY, width: textWidth, height: descHeight, text: description, fontSize: 12, color: LINK_CARD_TEXT_COLOR, clampLines: 2 })}
|
|
109
|
+
`;
|
|
110
|
+
}
|
|
111
|
+
|
|
47
112
|
// src/scene/text-svg.ts
|
|
48
113
|
function escapeSvgTextContent(s) {
|
|
49
114
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
50
115
|
}
|
|
51
|
-
function
|
|
116
|
+
function escapeHtmlText2(s) {
|
|
52
117
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
53
118
|
}
|
|
54
119
|
var DEFAULT_TEXT_FONT_SIZE = 18;
|
|
@@ -152,9 +217,9 @@ function buildTextFixedBoundsSvg(content, width, height, fillColor = "#2563eb",
|
|
|
152
217
|
const lh = lineHeightFor(fontSize);
|
|
153
218
|
const trimmed = content.trim();
|
|
154
219
|
if (trimmed.length === 0) {
|
|
155
|
-
return `<foreignObject width="${w}" height="${h}"><div xmlns="http://www.w3.org/1999/xhtml" style="box-sizing:border-box;width:100%;height:100%;margin:0;padding:2px 4px;font-size:${fontSize}px;line-height:${lh}px;font-family:system-ui,sans-serif;white-space:pre-wrap;word-wrap:break-word;overflow:hidden;color:#94a3b8;font-style:italic">${
|
|
220
|
+
return `<foreignObject width="${w}" height="${h}"><div xmlns="http://www.w3.org/1999/xhtml" style="box-sizing:border-box;width:100%;height:100%;margin:0;padding:2px 4px;font-size:${fontSize}px;line-height:${lh}px;font-family:system-ui,sans-serif;white-space:pre-wrap;word-wrap:break-word;overflow:hidden;color:#94a3b8;font-style:italic">${escapeHtmlText2(PLACEHOLDER)}</div></foreignObject>`;
|
|
156
221
|
}
|
|
157
|
-
const body =
|
|
222
|
+
const body = escapeHtmlText2(content);
|
|
158
223
|
return `<foreignObject width="${w}" height="${h}"><div xmlns="http://www.w3.org/1999/xhtml" style="box-sizing:border-box;width:100%;height:100%;margin:0;padding:2px 4px;font-size:${fontSize}px;line-height:${lh}px;font-family:system-ui,sans-serif;white-space:pre-wrap;word-wrap:break-word;overflow:hidden;color:${fillColor}">${body}</div></foreignObject>`;
|
|
159
224
|
}
|
|
160
225
|
|
|
@@ -831,10 +896,10 @@ function resolveColor(value) {
|
|
|
831
896
|
function escapeXml(value) {
|
|
832
897
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
833
898
|
}
|
|
834
|
-
function
|
|
899
|
+
function escapeHtmlText3(value) {
|
|
835
900
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
836
901
|
}
|
|
837
|
-
function
|
|
902
|
+
function formatNumber2(value) {
|
|
838
903
|
if (!Number.isFinite(value)) return "0";
|
|
839
904
|
const rounded = Math.round(value * 100) / 100;
|
|
840
905
|
return Number.isInteger(rounded) ? String(rounded) : String(rounded);
|
|
@@ -886,13 +951,13 @@ function sizeToFontPx(size) {
|
|
|
886
951
|
function dashArrayForStyle(dash, strokeWidth) {
|
|
887
952
|
if (!dash || dash === "solid") return void 0;
|
|
888
953
|
if (dash === "dotted") {
|
|
889
|
-
return `${
|
|
954
|
+
return `${formatNumber2(Math.max(1.25, strokeWidth))} ${formatNumber2(Math.max(2.5, strokeWidth * 2.2))}`;
|
|
890
955
|
}
|
|
891
956
|
if (dash === "dashed") {
|
|
892
|
-
return `${
|
|
957
|
+
return `${formatNumber2(Math.max(5, strokeWidth * 4))} ${formatNumber2(Math.max(3, strokeWidth * 2.2))}`;
|
|
893
958
|
}
|
|
894
959
|
if (dash === "draw") {
|
|
895
|
-
return `${
|
|
960
|
+
return `${formatNumber2(Math.max(3, strokeWidth * 2.4))} ${formatNumber2(Math.max(2.4, strokeWidth * 1.6))}`;
|
|
896
961
|
}
|
|
897
962
|
return dash;
|
|
898
963
|
}
|
|
@@ -908,11 +973,11 @@ function strokeAttrs(style) {
|
|
|
908
973
|
const dashAttr = dashArray ? ` stroke-dasharray="${dashArray}"` : "";
|
|
909
974
|
const lineCap = style.lineCap ? ` stroke-linecap="${style.lineCap}"` : "";
|
|
910
975
|
const lineJoin = style.lineJoin ? ` stroke-linejoin="${style.lineJoin}"` : "";
|
|
911
|
-
return `stroke="${style.stroke}" stroke-width="${
|
|
976
|
+
return `stroke="${style.stroke}" stroke-width="${formatNumber2(style.strokeWidth)}"${dashAttr}${lineCap}${lineJoin}`;
|
|
912
977
|
}
|
|
913
978
|
function wrapOpacity(svg, opacity) {
|
|
914
979
|
if (opacity >= 0.999) return svg;
|
|
915
|
-
return `<g opacity="${
|
|
980
|
+
return `<g opacity="${formatNumber2(opacity)}">${svg}</g>`;
|
|
916
981
|
}
|
|
917
982
|
function buildForeignObjectTextSvg(options) {
|
|
918
983
|
const x = options.x ?? 0;
|
|
@@ -927,8 +992,8 @@ function buildForeignObjectTextSvg(options) {
|
|
|
927
992
|
const weight = options.fontWeight != null ? `font-weight:${options.fontWeight};` : "";
|
|
928
993
|
const fontStyle = options.italic ? "font-style:italic;" : "";
|
|
929
994
|
const background = options.background ? `background:${options.background};` : "";
|
|
930
|
-
const radius = options.borderRadius != null ? `border-radius:${
|
|
931
|
-
return `<foreignObject x="${
|
|
995
|
+
const radius = options.borderRadius != null ? `border-radius:${formatNumber2(options.borderRadius)}px;` : "";
|
|
996
|
+
return `<foreignObject x="${formatNumber2(x)}" y="${formatNumber2(y)}" width="${formatNumber2(w)}" height="${formatNumber2(h)}"><div xmlns="http://www.w3.org/1999/xhtml" style="box-sizing:border-box;width:100%;height:100%;margin:0;padding:${formatNumber2(padding)}px;display:flex;align-items:${vertical};justify-content:${justify};text-align:${align};white-space:pre-wrap;word-break:break-word;overflow:hidden;color:${options.color};font-size:${formatNumber2(options.fontSize)}px;line-height:${formatNumber2(lineHeight)}px;font-family:system-ui,sans-serif;${weight}${fontStyle}${background}${radius}">${escapeHtmlText3(options.text)}</div></foreignObject>`;
|
|
932
997
|
}
|
|
933
998
|
function richTextToPlainText(value) {
|
|
934
999
|
const parts = [];
|
|
@@ -1456,17 +1521,17 @@ function createCustomImportedItem(snapshot, shape, localBounds, innerSvg, style)
|
|
|
1456
1521
|
}
|
|
1457
1522
|
function polygonPath(points) {
|
|
1458
1523
|
if (points.length === 0) return "";
|
|
1459
|
-
let path = `M${
|
|
1524
|
+
let path = `M${formatNumber2(points[0]?.x ?? 0)} ${formatNumber2(points[0]?.y ?? 0)}`;
|
|
1460
1525
|
for (let index = 1; index < points.length; index++) {
|
|
1461
1526
|
const point = points[index];
|
|
1462
1527
|
if (!point) continue;
|
|
1463
|
-
path += ` L${
|
|
1528
|
+
path += ` L${formatNumber2(point.x)} ${formatNumber2(point.y)}`;
|
|
1464
1529
|
}
|
|
1465
1530
|
return `${path} Z`;
|
|
1466
1531
|
}
|
|
1467
1532
|
function cloudPath(width, height) {
|
|
1468
1533
|
const r = Math.min(width, height) * 0.15;
|
|
1469
|
-
return `M${
|
|
1534
|
+
return `M${formatNumber2(r)} ${formatNumber2(height * 0.3)} Q0 ${formatNumber2(height * 0.1)} ${formatNumber2(width * 0.15)} ${formatNumber2(height * 0.05)} Q${formatNumber2(width * 0.3)} 0 ${formatNumber2(width * 0.45)} ${formatNumber2(height * 0.1)} Q${formatNumber2(width * 0.7)} 0 ${formatNumber2(width * 0.8)} ${formatNumber2(height * 0.15)} Q${formatNumber2(width)} ${formatNumber2(height * 0.2)} ${formatNumber2(width * 0.9)} ${formatNumber2(height * 0.5)} Q${formatNumber2(width)} ${formatNumber2(height * 0.7)} ${formatNumber2(width * 0.85)} ${formatNumber2(height * 0.8)} Q${formatNumber2(width * 0.7)} ${formatNumber2(height)} ${formatNumber2(width * 0.5)} ${formatNumber2(height * 0.9)} Q${formatNumber2(width * 0.3)} ${formatNumber2(height)} ${formatNumber2(width * 0.15)} ${formatNumber2(height * 0.85)} Q0 ${formatNumber2(height * 0.8)} ${formatNumber2(r * 0.5)} ${formatNumber2(height * 0.6)} Q0 ${formatNumber2(height * 0.5)} ${formatNumber2(r)} ${formatNumber2(height * 0.3)} Z`;
|
|
1470
1535
|
}
|
|
1471
1536
|
function geoPath(geo, width, height) {
|
|
1472
1537
|
if (geo === "diamond" || geo === "rhombus") {
|
|
@@ -1545,10 +1610,10 @@ function geoPath(geo, width, height) {
|
|
|
1545
1610
|
]);
|
|
1546
1611
|
}
|
|
1547
1612
|
if (geo === "check-box") {
|
|
1548
|
-
return `M0 0 H${
|
|
1613
|
+
return `M0 0 H${formatNumber2(width)} V${formatNumber2(height)} H0 Z M${formatNumber2(width * 0.2)} ${formatNumber2(height * 0.56)} L${formatNumber2(width * 0.42)} ${formatNumber2(height * 0.78)} L${formatNumber2(width * 0.82)} ${formatNumber2(height * 0.24)}`;
|
|
1549
1614
|
}
|
|
1550
1615
|
if (geo === "x-box") {
|
|
1551
|
-
return `M0 0 H${
|
|
1616
|
+
return `M0 0 H${formatNumber2(width)} V${formatNumber2(height)} H0 Z M${formatNumber2(width * 0.22)} ${formatNumber2(height * 0.22)} L${formatNumber2(width * 0.78)} ${formatNumber2(height * 0.78)} M${formatNumber2(width * 0.78)} ${formatNumber2(height * 0.22)} L${formatNumber2(width * 0.22)} ${formatNumber2(height * 0.78)}`;
|
|
1552
1617
|
}
|
|
1553
1618
|
return null;
|
|
1554
1619
|
}
|
|
@@ -1564,7 +1629,7 @@ function renderGeoShape(snapshot, shape) {
|
|
|
1564
1629
|
const text = extractPlainText(props);
|
|
1565
1630
|
const fontSize = getNumber(props.fontSize) ?? sizeToFontPx(getString(props.size));
|
|
1566
1631
|
const customPath = geoPath(geo, width, height);
|
|
1567
|
-
const shapeMarkup = geo === "ellipse" || geo === "oval" ? `<ellipse cx="${
|
|
1632
|
+
const shapeMarkup = geo === "ellipse" || geo === "oval" ? `<ellipse cx="${formatNumber2(width / 2)}" cy="${formatNumber2(height / 2)}" rx="${formatNumber2(width / 2)}" ry="${formatNumber2(height / 2)}" ${fillAttrs(getString(props.fill), stroke)} ${strokeAttrs({ stroke, strokeWidth, dash, lineCap: "round", lineJoin: "round" })} />` : customPath ? `<path d="${customPath}" ${fillAttrs(getString(props.fill), stroke)} ${strokeAttrs({ stroke, strokeWidth, dash, lineCap: "round", lineJoin: "round" })} />` : `<rect width="${formatNumber2(width)}" height="${formatNumber2(height)}" rx="8" ${fillAttrs(getString(props.fill), stroke)} ${strokeAttrs({ stroke, strokeWidth, dash, lineCap: "round", lineJoin: "round" })} />`;
|
|
1568
1633
|
const textMarkup = text ? buildForeignObjectTextSvg({
|
|
1569
1634
|
width,
|
|
1570
1635
|
height,
|
|
@@ -1649,11 +1714,11 @@ function renderStrokeShape(snapshot, shape) {
|
|
|
1649
1714
|
}
|
|
1650
1715
|
function polylinePath(points) {
|
|
1651
1716
|
if (points.length === 0) return "";
|
|
1652
|
-
let path = `M${
|
|
1717
|
+
let path = `M${formatNumber2(points[0]?.x ?? 0)} ${formatNumber2(points[0]?.y ?? 0)}`;
|
|
1653
1718
|
for (let index = 1; index < points.length; index++) {
|
|
1654
1719
|
const point = points[index];
|
|
1655
1720
|
if (!point) continue;
|
|
1656
|
-
path += ` L${
|
|
1721
|
+
path += ` L${formatNumber2(point.x)} ${formatNumber2(point.y)}`;
|
|
1657
1722
|
}
|
|
1658
1723
|
return path;
|
|
1659
1724
|
}
|
|
@@ -1675,22 +1740,22 @@ function buildArrowHeadSvg(options) {
|
|
|
1675
1740
|
const left = { x: bx + px * (headWidth / 2), y: by + py * (headWidth / 2) };
|
|
1676
1741
|
const right = { x: bx - px * (headWidth / 2), y: by - py * (headWidth / 2) };
|
|
1677
1742
|
if (type === "triangle") {
|
|
1678
|
-
return `<polygon points="${
|
|
1743
|
+
return `<polygon points="${formatNumber2(options.tip.x)},${formatNumber2(options.tip.y)} ${formatNumber2(left.x)},${formatNumber2(left.y)} ${formatNumber2(right.x)},${formatNumber2(right.y)}" fill="${options.stroke}" />`;
|
|
1679
1744
|
}
|
|
1680
1745
|
if (type === "dot") {
|
|
1681
|
-
return `<circle cx="${
|
|
1746
|
+
return `<circle cx="${formatNumber2(options.tip.x)}" cy="${formatNumber2(options.tip.y)}" r="${formatNumber2(Math.max(3, options.strokeWidth * 1.5))}" fill="${options.stroke}" />`;
|
|
1682
1747
|
}
|
|
1683
1748
|
if (type === "diamond") {
|
|
1684
1749
|
const mid = {
|
|
1685
1750
|
x: options.tip.x - ux * (headLength / 2),
|
|
1686
1751
|
y: options.tip.y - uy * (headLength / 2)
|
|
1687
1752
|
};
|
|
1688
|
-
return `<polygon points="${
|
|
1753
|
+
return `<polygon points="${formatNumber2(options.tip.x)},${formatNumber2(options.tip.y)} ${formatNumber2(left.x)},${formatNumber2(left.y)} ${formatNumber2(mid.x - ux * (headLength / 2))},${formatNumber2(mid.y - uy * (headLength / 2))} ${formatNumber2(right.x)},${formatNumber2(right.y)}" fill="none" stroke="${options.stroke}" stroke-width="${formatNumber2(options.strokeWidth)}" stroke-linejoin="round" />`;
|
|
1689
1754
|
}
|
|
1690
1755
|
if (type === "bar") {
|
|
1691
|
-
return `<line x1="${
|
|
1756
|
+
return `<line x1="${formatNumber2(left.x)}" y1="${formatNumber2(left.y)}" x2="${formatNumber2(right.x)}" y2="${formatNumber2(right.y)}" stroke="${options.stroke}" stroke-width="${formatNumber2(options.strokeWidth)}" stroke-linecap="round" />`;
|
|
1692
1757
|
}
|
|
1693
|
-
return `<path d="M ${
|
|
1758
|
+
return `<path d="M ${formatNumber2(left.x)} ${formatNumber2(left.y)} L ${formatNumber2(options.tip.x)} ${formatNumber2(options.tip.y)} L ${formatNumber2(right.x)} ${formatNumber2(right.y)}" fill="none" stroke="${options.stroke}" stroke-width="${formatNumber2(options.strokeWidth)}" stroke-linecap="round" stroke-linejoin="round" />`;
|
|
1694
1759
|
}
|
|
1695
1760
|
function renderLineShape(snapshot, shape) {
|
|
1696
1761
|
const props = asRecord(shape.props) ?? {};
|
|
@@ -1759,7 +1824,7 @@ function renderArrowShape(snapshot, shape) {
|
|
|
1759
1824
|
const translatedPoints = route.points.map(translate);
|
|
1760
1825
|
const translatedStartRef = translate(route.startRef);
|
|
1761
1826
|
const translatedEndRef = translate(route.endRef);
|
|
1762
|
-
const shaft = route.kind === "quadratic" && route.control ? `<path d="M${
|
|
1827
|
+
const shaft = route.kind === "quadratic" && route.control ? `<path d="M${formatNumber2(translatedPoints[0]?.x ?? 0)} ${formatNumber2(translatedPoints[0]?.y ?? 0)} Q${formatNumber2(route.control.x - localBounds.x)} ${formatNumber2(route.control.y - localBounds.y)} ${formatNumber2(translatedPoints[1]?.x ?? 0)} ${formatNumber2(translatedPoints[1]?.y ?? 0)}" fill="none" ${strokeAttrs({ stroke, strokeWidth, dash, lineCap: "round", lineJoin: "round" })} />` : `<path d="${polylinePath(translatedPoints)}" fill="none" ${strokeAttrs({ stroke, strokeWidth, dash, lineCap: "round", lineJoin: "round" })} />`;
|
|
1763
1828
|
const startPoint = translatedPoints[0];
|
|
1764
1829
|
const endPoint = translatedPoints[translatedPoints.length - 1];
|
|
1765
1830
|
if (!startPoint || !endPoint) return null;
|
|
@@ -1791,9 +1856,9 @@ function renderMissingAssetPlaceholder(snapshot, shape, kind, detail) {
|
|
|
1791
1856
|
const width = localBounds.width;
|
|
1792
1857
|
const height = localBounds.height;
|
|
1793
1858
|
const inner = `
|
|
1794
|
-
<rect width="${
|
|
1795
|
-
<path d="M${
|
|
1796
|
-
<circle cx="${
|
|
1859
|
+
<rect width="${formatNumber2(width)}" height="${formatNumber2(height)}" rx="12" fill="#f4f4f5" stroke="#a1a1aa" stroke-width="1.5" stroke-dasharray="6 6" />
|
|
1860
|
+
<path d="M${formatNumber2(width * 0.18)} ${formatNumber2(height * 0.7)} L${formatNumber2(width * 0.38)} ${formatNumber2(height * 0.48)} L${formatNumber2(width * 0.56)} ${formatNumber2(height * 0.62)} L${formatNumber2(width * 0.76)} ${formatNumber2(height * 0.32)} L${formatNumber2(width * 0.84)} ${formatNumber2(height * 0.4)} L${formatNumber2(width * 0.84)} ${formatNumber2(height * 0.82)} L${formatNumber2(width * 0.18)} ${formatNumber2(height * 0.82)} Z" fill="#d4d4d8" stroke="#a1a1aa" stroke-width="1" />
|
|
1861
|
+
<circle cx="${formatNumber2(width * 0.34)}" cy="${formatNumber2(height * 0.34)}" r="${formatNumber2(Math.max(6, Math.min(width, height) * 0.05))}" fill="#a1a1aa" />
|
|
1797
1862
|
${buildForeignObjectTextSvg({ x: 10, y: height * 0.04, width: width - 20, height: height * 0.28, text: kind, fontSize: 15, color: "#18181b", fontWeight: 700, align: "center", verticalAlign: "middle" })}
|
|
1798
1863
|
${buildForeignObjectTextSvg({ x: 14, y: height * 0.78, width: width - 28, height: height * 0.16, text: detail, fontSize: 12, color: "#52525b", align: "center", verticalAlign: "middle" })}
|
|
1799
1864
|
`;
|
|
@@ -1847,10 +1912,10 @@ function renderVideoShape(snapshot, shape) {
|
|
|
1847
1912
|
const label = getString(asRecord(asset?.props)?.name) ?? "Video";
|
|
1848
1913
|
const subtitle = src ?? getString(props.assetId) ?? "Playback not supported in this importer";
|
|
1849
1914
|
const inner = `
|
|
1850
|
-
<rect width="${
|
|
1851
|
-
<rect x="${
|
|
1852
|
-
<circle cx="${
|
|
1853
|
-
<polygon points="${
|
|
1915
|
+
<rect width="${formatNumber2(width)}" height="${formatNumber2(height)}" rx="14" fill="#18181b" stroke="#3f3f46" stroke-width="1.5" />
|
|
1916
|
+
<rect x="${formatNumber2(width * 0.04)}" y="${formatNumber2(height * 0.08)}" width="${formatNumber2(width * 0.92)}" height="${formatNumber2(height * 0.66)}" rx="10" fill="#27272a" />
|
|
1917
|
+
<circle cx="${formatNumber2(width * 0.5)}" cy="${formatNumber2(height * 0.41)}" r="${formatNumber2(Math.min(width, height) * 0.12)}" fill="#fafafa" fill-opacity="0.92" />
|
|
1918
|
+
<polygon points="${formatNumber2(width * 0.48)},${formatNumber2(height * 0.35)} ${formatNumber2(width * 0.48)},${formatNumber2(height * 0.47)} ${formatNumber2(width * 0.57)},${formatNumber2(height * 0.41)}" fill="#18181b" />
|
|
1854
1919
|
${buildForeignObjectTextSvg({ x: 16, y: height * 0.76, width: width - 32, height: height * 0.12, text: label, fontSize: 15, color: "#fafafa", fontWeight: 700 })}
|
|
1855
1920
|
${buildForeignObjectTextSvg({ x: 16, y: height * 0.88, width: width - 32, height: height * 0.08, text: subtitle, fontSize: 11, color: "#d4d4d8" })}
|
|
1856
1921
|
`;
|
|
@@ -1876,8 +1941,8 @@ function renderNoteShape(snapshot, shape) {
|
|
|
1876
1941
|
const fold = Math.min(width, height) * 0.14;
|
|
1877
1942
|
const fontSize = sizeToFontPx(getString(props.size)) + numberOr(props.fontSizeAdjustment, 0);
|
|
1878
1943
|
const inner = `
|
|
1879
|
-
<path d="M0 0 H${
|
|
1880
|
-
<path d="M${
|
|
1944
|
+
<path d="M0 0 H${formatNumber2(width - fold)} L${formatNumber2(width)} ${formatNumber2(fold)} V${formatNumber2(height)} H0 Z" fill="${noteColor}" fill-opacity="0.22" stroke="${noteColor}" stroke-width="1.5" />
|
|
1945
|
+
<path d="M${formatNumber2(width - fold)} 0 V${formatNumber2(fold)} H${formatNumber2(width)}" fill="${noteColor}" fill-opacity="0.3" stroke="${noteColor}" stroke-width="1.5" />
|
|
1881
1946
|
${buildForeignObjectTextSvg({ x: 12, y: 12, width: width - 24, height: height - 24, text, fontSize, color: labelColor, padding: 4, align: getString(props.align), verticalAlign: getString(props.verticalAlign) })}
|
|
1882
1947
|
`;
|
|
1883
1948
|
return createCustomImportedItem(
|
|
@@ -1893,31 +1958,35 @@ function renderNoteShape(snapshot, shape) {
|
|
|
1893
1958
|
}
|
|
1894
1959
|
function renderBookmarkShape(snapshot, shape) {
|
|
1895
1960
|
const props = asRecord(shape.props) ?? {};
|
|
1961
|
+
const asset = resolveAsset(snapshot, shape);
|
|
1962
|
+
const assetProps = asRecord(asset?.props) ?? {};
|
|
1896
1963
|
const localBounds = resolveShapeLocalBounds(snapshot, shape.id);
|
|
1897
|
-
const
|
|
1898
|
-
const
|
|
1899
|
-
const
|
|
1900
|
-
const
|
|
1901
|
-
const
|
|
1902
|
-
const
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
return createCustomImportedItem(
|
|
1964
|
+
const href = getString(props.url) ?? getString(assetProps.src) ?? getString(props.src) ?? "";
|
|
1965
|
+
const title = getString(assetProps.title) ?? getString(props.title) ?? getString(props.label) ?? void 0;
|
|
1966
|
+
const description = getString(assetProps.description) ?? getString(props.description) ?? void 0;
|
|
1967
|
+
const image = getString(assetProps.image) ?? getString(props.image) ?? void 0;
|
|
1968
|
+
const favicon = getString(assetProps.favicon) ?? getString(props.favicon) ?? void 0;
|
|
1969
|
+
const link = {
|
|
1970
|
+
href: href || "URL unavailable",
|
|
1971
|
+
...title ? { title } : {},
|
|
1972
|
+
...description ? { description } : {},
|
|
1973
|
+
...image ? { image } : {},
|
|
1974
|
+
...favicon ? { favicon } : {}
|
|
1975
|
+
};
|
|
1976
|
+
const inner = buildLinkCardSvg(localBounds.width, localBounds.height, link);
|
|
1977
|
+
const item = createCustomImportedItem(
|
|
1912
1978
|
snapshot,
|
|
1913
1979
|
shape,
|
|
1914
1980
|
localBounds,
|
|
1915
|
-
wrapOpacity(inner, shapeOpacity(shape))
|
|
1916
|
-
{
|
|
1917
|
-
stroke,
|
|
1918
|
-
strokeWidth: 1.5
|
|
1919
|
-
}
|
|
1981
|
+
wrapOpacity(inner, shapeOpacity(shape))
|
|
1920
1982
|
);
|
|
1983
|
+
return {
|
|
1984
|
+
...item,
|
|
1985
|
+
pluginData: {
|
|
1986
|
+
...item.pluginData ?? {},
|
|
1987
|
+
[LINK_PLUGIN_KEY]: link
|
|
1988
|
+
}
|
|
1989
|
+
};
|
|
1921
1990
|
}
|
|
1922
1991
|
function renderEmbedShape(snapshot, shape) {
|
|
1923
1992
|
const props = asRecord(shape.props) ?? {};
|
|
@@ -1928,11 +1997,11 @@ function renderEmbedShape(snapshot, shape) {
|
|
|
1928
1997
|
const title = getString(props.title) ?? getString(props.embedTitle) ?? "Embed";
|
|
1929
1998
|
const url = getString(props.url) ?? getString(props.src) ?? "Embedded content";
|
|
1930
1999
|
const inner = `
|
|
1931
|
-
<rect width="${
|
|
1932
|
-
<rect x="16" y="16" width="${
|
|
1933
|
-
<circle cx="${
|
|
1934
|
-
<circle cx="${
|
|
1935
|
-
<circle cx="${
|
|
2000
|
+
<rect width="${formatNumber2(width)}" height="${formatNumber2(height)}" rx="16" fill="#0f172a" stroke="${stroke}" stroke-width="1.5" />
|
|
2001
|
+
<rect x="16" y="16" width="${formatNumber2(width - 32)}" height="${formatNumber2(height * 0.62)}" rx="12" fill="#111827" stroke="#334155" stroke-width="1" />
|
|
2002
|
+
<circle cx="${formatNumber2(width * 0.14)}" cy="${formatNumber2(height * 0.14)}" r="5" fill="#ef4444" />
|
|
2003
|
+
<circle cx="${formatNumber2(width * 0.18)}" cy="${formatNumber2(height * 0.14)}" r="5" fill="#f59e0b" />
|
|
2004
|
+
<circle cx="${formatNumber2(width * 0.22)}" cy="${formatNumber2(height * 0.14)}" r="5" fill="#22c55e" />
|
|
1936
2005
|
${buildForeignObjectTextSvg({ x: 18, y: height * 0.72, width: width - 36, height: height * 0.11, text: title, fontSize: 16, color: "#f8fafc", fontWeight: 700 })}
|
|
1937
2006
|
${buildForeignObjectTextSvg({ x: 18, y: height * 0.84, width: width - 36, height: height * 0.08, text: url, fontSize: 11, color: "#cbd5e1" })}
|
|
1938
2007
|
`;
|
|
@@ -1955,8 +2024,8 @@ function renderFrameShape(snapshot, shape) {
|
|
|
1955
2024
|
const stroke = shapeStrokeColor(shape);
|
|
1956
2025
|
const title = (getString(props.name) ?? getString(props.title) ?? extractPlainText(props)) || "Frame";
|
|
1957
2026
|
const inner = `
|
|
1958
|
-
<rect width="${
|
|
1959
|
-
<rect x="12" y="10" width="${
|
|
2027
|
+
<rect width="${formatNumber2(width)}" height="${formatNumber2(height)}" rx="14" fill="none" stroke="${stroke}" stroke-width="2" stroke-dasharray="10 6" />
|
|
2028
|
+
<rect x="12" y="10" width="${formatNumber2(Math.min(width - 24, Math.max(88, width * 0.34)))}" height="28" rx="8" fill="#ffffff" stroke="${stroke}" stroke-width="1.5" />
|
|
1960
2029
|
${buildForeignObjectTextSvg({ x: 16, y: 12, width: Math.min(width - 32, Math.max(80, width * 0.3)), height: 24, text: title, fontSize: 13, color: "#111827", fontWeight: 700, verticalAlign: "middle" })}
|
|
1961
2030
|
`;
|
|
1962
2031
|
return createCustomImportedItem(
|
|
@@ -1979,8 +2048,8 @@ function renderAnnotationShape(snapshot, shape) {
|
|
|
1979
2048
|
const fill = shape.type === "annotationBubble" ? "#3b82f6" : resolveColor(getString(props.color) ?? "#ef4444");
|
|
1980
2049
|
const text = shape.type === "label" ? extractPlainText(props) : String(getNumber(props.number) ?? "");
|
|
1981
2050
|
const inner = `
|
|
1982
|
-
<circle cx="${
|
|
1983
|
-
<text x="${
|
|
2051
|
+
<circle cx="${formatNumber2(width / 2)}" cy="${formatNumber2(height / 2)}" r="${formatNumber2(radius)}" fill="${fill}" stroke="#ffffff" stroke-width="2" />
|
|
2052
|
+
<text x="${formatNumber2(width / 2)}" y="${formatNumber2(height / 2 + 4)}" fill="#ffffff" font-size="10" font-weight="700" text-anchor="middle" dominant-baseline="central">${escapeXml(text)}</text>
|
|
1984
2053
|
`;
|
|
1985
2054
|
return createCustomImportedItem(
|
|
1986
2055
|
snapshot,
|
|
@@ -2000,7 +2069,7 @@ function renderUnsupportedShape(snapshot, shape, reason) {
|
|
|
2000
2069
|
const width = localBounds.width;
|
|
2001
2070
|
const height = localBounds.height;
|
|
2002
2071
|
const inner = `
|
|
2003
|
-
<rect width="${
|
|
2072
|
+
<rect width="${formatNumber2(width)}" height="${formatNumber2(height)}" rx="12" fill="#fafafa" stroke="#a1a1aa" stroke-width="1.5" stroke-dasharray="6 6" />
|
|
2004
2073
|
${buildForeignObjectTextSvg({ x: 12, y: 14, width: width - 24, height: 28, text: shape.type, fontSize: 14, color: "#111827", fontWeight: 700, verticalAlign: "middle" })}
|
|
2005
2074
|
${buildForeignObjectTextSvg({ x: 12, y: 50, width: width - 24, height: Math.max(20, height - 62), text: reason, fontSize: 12, color: "#52525b" })}
|
|
2006
2075
|
`;
|