canvu-react 0.3.38 → 0.3.40
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-EtEuBwb7.d.cts → asset-hydration-B7yMDQE-.d.cts} +2 -2
- package/dist/{asset-hydration-DrTOgDdd.d.ts → asset-hydration-CbwQVAwh.d.ts} +2 -2
- package/dist/{camera-Di5R_Rwl.d.cts → camera-CVVG7z56.d.cts} +1 -1
- package/dist/{camera-AoTwBSoE.d.ts → camera-CoRYN_IV.d.ts} +1 -1
- package/dist/chatbot.d.cts +4 -4
- package/dist/chatbot.d.ts +4 -4
- package/dist/index.cjs +164 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +159 -16
- package/dist/index.js.map +1 -1
- package/dist/native.cjs +57 -14
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.cts +2 -2
- package/dist/native.d.ts +2 -2
- package/dist/native.js +57 -14
- package/dist/native.js.map +1 -1
- package/dist/react.cjs +731 -258
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +10 -10
- package/dist/react.d.ts +10 -10
- package/dist/react.js +731 -258
- package/dist/react.js.map +1 -1
- package/dist/realtime.cjs +36 -0
- package/dist/realtime.cjs.map +1 -1
- package/dist/realtime.d.cts +6 -6
- package/dist/realtime.d.ts +6 -6
- package/dist/realtime.js +36 -0
- package/dist/realtime.js.map +1 -1
- package/dist/{shape-builders-CsbSRZnQ.d.cts → shape-builders-BAWu-PxX.d.cts} +46 -4
- package/dist/{shape-builders-CsSXKCcs.d.ts → shape-builders-ClKv9tz9.d.ts} +46 -4
- package/dist/tldraw.cjs +189 -78
- package/dist/tldraw.cjs.map +1 -1
- package/dist/tldraw.d.cts +1 -1
- package/dist/tldraw.d.ts +1 -1
- package/dist/tldraw.js +189 -78
- package/dist/tldraw.js.map +1 -1
- package/dist/{types-DWGk2_GZ.d.cts → types-BC9Xgfu6.d.cts} +20 -6
- package/dist/{types-Bnq2HtHQ.d.cts → types-BCCvY6ie.d.cts} +2 -0
- package/dist/{types-Bnq2HtHQ.d.ts → types-BCCvY6ie.d.ts} +2 -0
- package/dist/{types-B2Na677H.d.cts → types-BUPc2Zgw.d.cts} +1 -1
- package/dist/{types-zmUah-vP.d.ts → types-CYtq9Pr9.d.ts} +1 -1
- package/dist/{types-B6PAYKzx.d.ts → types-DlSVGX0w.d.ts} +20 -6
- package/package.json +1 -1
package/dist/tldraw.cjs
CHANGED
|
@@ -50,19 +50,87 @@ function createCustomShapeItem(id, bounds, content) {
|
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
// src/scene/link-item.ts
|
|
54
|
+
var LINK_PLUGIN_KEY = "canvuLink";
|
|
55
|
+
var LINK_CARD_BORDER = "#e2e8f0";
|
|
56
|
+
var LINK_CARD_ACCENT = "#2563eb";
|
|
57
|
+
var LINK_CARD_TITLE_COLOR = "#0f172a";
|
|
58
|
+
var LINK_CARD_TEXT_COLOR = "#475569";
|
|
59
|
+
var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
60
|
+
var formatNumber = (value) => {
|
|
61
|
+
const rounded = Math.round(value * 100) / 100;
|
|
62
|
+
return Object.is(rounded, -0) ? "0" : String(rounded);
|
|
63
|
+
};
|
|
64
|
+
var escapeXmlAttribute = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
65
|
+
var escapeHtmlText = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
66
|
+
var getLinkHostname = (href) => {
|
|
67
|
+
try {
|
|
68
|
+
return new URL(href).hostname.replace(/^www\./, "");
|
|
69
|
+
} catch {
|
|
70
|
+
return href;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
var buildLinkTextBand = (band) => {
|
|
74
|
+
const lineHeight = band.fontSize * 1.3;
|
|
75
|
+
const weight = band.fontWeight != null ? `font-weight:${band.fontWeight};` : "";
|
|
76
|
+
const lineClampStyle = band.clampLines ? `display:-webkit-box;-webkit-line-clamp:${band.clampLines};-webkit-box-orient:vertical;` : "";
|
|
77
|
+
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>`;
|
|
78
|
+
};
|
|
79
|
+
function buildLinkCardSvg(width, height, link) {
|
|
80
|
+
const cardWidth = Math.max(1, width);
|
|
81
|
+
const cardHeight = Math.max(1, height);
|
|
82
|
+
const padding = 14;
|
|
83
|
+
const badgeSize = clamp(Math.min(72, cardHeight - padding * 2), 28, 96);
|
|
84
|
+
const textX = padding + badgeSize + 14;
|
|
85
|
+
const textWidth = Math.max(1, cardWidth - textX - padding);
|
|
86
|
+
const hostname = getLinkHostname(link.href);
|
|
87
|
+
const title = link.title?.trim() || hostname || "Link";
|
|
88
|
+
const description = link.description?.trim() || link.href;
|
|
89
|
+
const titleY = padding;
|
|
90
|
+
const titleHeight = clamp(cardHeight * 0.22, 18, 28);
|
|
91
|
+
const hostY = titleY + titleHeight + 2;
|
|
92
|
+
const hostHeight = 16;
|
|
93
|
+
const descY = hostY + hostHeight + 4;
|
|
94
|
+
const descHeight = Math.max(1, cardHeight - descY - padding);
|
|
95
|
+
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>
|
|
96
|
+
<rect x="${formatNumber(padding)}" y="${formatNumber(padding)}" width="${formatNumber(badgeSize)}" height="${formatNumber(badgeSize)}" rx="12" fill="#f8fafc" stroke="${LINK_CARD_BORDER}" stroke-width="1" />
|
|
97
|
+
<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" />
|
|
98
|
+
<g transform="translate(${formatNumber(padding + badgeSize / 2)},${formatNumber(padding + badgeSize / 2)})" stroke="${LINK_CARD_ACCENT}" stroke-width="2.4" stroke-linecap="round" fill="none">
|
|
99
|
+
<path d="M-9 3 a6 6 0 0 1 0 -8 l4 -4 a6 6 0 0 1 8 8 l-2 2" />
|
|
100
|
+
<path d="M9 -3 a6 6 0 0 1 0 8 l-4 4 a6 6 0 0 1 -8 -8 l2 -2" />
|
|
101
|
+
</g>`;
|
|
102
|
+
const externalIconX = cardWidth - padding - 16;
|
|
103
|
+
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">
|
|
104
|
+
<path d="M6 1 H11 V6" />
|
|
105
|
+
<path d="M11 1 L4.5 7.5" />
|
|
106
|
+
<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" />
|
|
107
|
+
</g>`;
|
|
108
|
+
return `
|
|
109
|
+
<rect width="${formatNumber(cardWidth)}" height="${formatNumber(cardHeight)}" rx="16" fill="#ffffff" stroke="${LINK_CARD_BORDER}" stroke-width="1.5" />
|
|
110
|
+
${badge}
|
|
111
|
+
${externalIcon}
|
|
112
|
+
${buildLinkTextBand({ x: textX, y: titleY, width: textWidth - 18, height: titleHeight, text: title, fontSize: 15, color: LINK_CARD_TITLE_COLOR, fontWeight: 700, clampLines: 1 })}
|
|
113
|
+
${buildLinkTextBand({ x: textX, y: hostY, width: textWidth, height: hostHeight, text: hostname, fontSize: 12, color: LINK_CARD_ACCENT, clampLines: 1 })}
|
|
114
|
+
${buildLinkTextBand({ x: textX, y: descY, width: textWidth, height: descHeight, text: description, fontSize: 12, color: LINK_CARD_TEXT_COLOR, clampLines: 2 })}
|
|
115
|
+
`;
|
|
116
|
+
}
|
|
117
|
+
|
|
53
118
|
// src/scene/text-svg.ts
|
|
54
119
|
function escapeSvgTextContent(s) {
|
|
55
120
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
56
121
|
}
|
|
57
|
-
function
|
|
122
|
+
function escapeHtmlText2(s) {
|
|
58
123
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
59
124
|
}
|
|
60
125
|
var DEFAULT_TEXT_FONT_SIZE = 18;
|
|
126
|
+
var TEXT_FONT_FAMILY = "Inter, -apple-system, BlinkMacSystemFont, ui-sans-serif, system-ui, sans-serif";
|
|
61
127
|
var LINE_HEIGHT_RATIO = 22 / 18;
|
|
62
|
-
var FIRST_LINE_BASELINE_RATIO =
|
|
128
|
+
var FIRST_LINE_BASELINE_RATIO = 20 / 18;
|
|
129
|
+
var EDIT_TOP_PAD_RATIO = 4 / 18;
|
|
130
|
+
var BOTTOM_PAD_RATIO = 4 / 18;
|
|
63
131
|
var PLACEHOLDER = "Tap to type";
|
|
64
132
|
var MIN_TEXT_BOX_W = 40;
|
|
65
|
-
var MIN_TEXT_BOX_H =
|
|
133
|
+
var MIN_TEXT_BOX_H = 26;
|
|
66
134
|
var TEXT_PAD_X = 4;
|
|
67
135
|
var MAX_TEXT_MEASURE_CACHE_ENTRIES = 2e3;
|
|
68
136
|
var sharedMeasureContext;
|
|
@@ -108,7 +176,7 @@ function measureTextBoundsLocal(content, fontSize = DEFAULT_TEXT_FONT_SIZE) {
|
|
|
108
176
|
let maxInnerW = 0;
|
|
109
177
|
const ctx = getSharedMeasureContext();
|
|
110
178
|
if (ctx) {
|
|
111
|
-
ctx.font = `${fontSize}px
|
|
179
|
+
ctx.font = `${fontSize}px ${TEXT_FONT_FAMILY}`;
|
|
112
180
|
for (const line of lines) {
|
|
113
181
|
const toMeasure = trimmed.length === 0 ? PLACEHOLDER : line.length === 0 ? " " : line;
|
|
114
182
|
maxInnerW = Math.max(maxInnerW, ctx.measureText(toMeasure).width);
|
|
@@ -124,22 +192,22 @@ function measureTextBoundsLocal(content, fontSize = DEFAULT_TEXT_FONT_SIZE) {
|
|
|
124
192
|
const width = Math.max(minW, TEXT_PAD_X * 2 + maxInnerW);
|
|
125
193
|
const height = Math.max(
|
|
126
194
|
MIN_TEXT_BOX_H,
|
|
127
|
-
baselineY + (lines.length - 1) * lh + Math.max(
|
|
195
|
+
baselineY + (lines.length - 1) * lh + Math.max(4, fontSize * BOTTOM_PAD_RATIO)
|
|
128
196
|
);
|
|
129
197
|
const measured = { width, height };
|
|
130
198
|
cacheMeasuredBounds(cacheKey, measured);
|
|
131
199
|
return measured;
|
|
132
200
|
}
|
|
133
|
-
function buildTextSvg(content, _width, _height, fillColor = "#
|
|
201
|
+
function buildTextSvg(content, _width, _height, fillColor = "#1d1d1d", fontSize = DEFAULT_TEXT_FONT_SIZE) {
|
|
134
202
|
const lh = lineHeightFor(fontSize);
|
|
135
203
|
const y0 = firstLineBaselineY(fontSize);
|
|
136
204
|
const trimmed = content.trim();
|
|
137
205
|
if (trimmed.length === 0) {
|
|
138
|
-
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="
|
|
206
|
+
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="${TEXT_FONT_FAMILY}" fill="#94a3b8" font-style="italic">${escapeSvgTextContent(PLACEHOLDER)}</text>`;
|
|
139
207
|
}
|
|
140
208
|
const lines = content.split("\n");
|
|
141
209
|
if (lines.length === 1) {
|
|
142
|
-
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="
|
|
210
|
+
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="${TEXT_FONT_FAMILY}" fill="${fillColor}">${escapeSvgTextContent(lines[0] ?? "")}</text>`;
|
|
143
211
|
}
|
|
144
212
|
const parts = [];
|
|
145
213
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -150,23 +218,24 @@ function buildTextSvg(content, _width, _height, fillColor = "#2563eb", fontSize
|
|
|
150
218
|
parts.push(`<tspan x="4" dy="${lh}">${escapeSvgTextContent(line)}</tspan>`);
|
|
151
219
|
}
|
|
152
220
|
}
|
|
153
|
-
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="
|
|
221
|
+
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="${TEXT_FONT_FAMILY}" fill="${fillColor}">${parts.join("")}</text>`;
|
|
154
222
|
}
|
|
155
|
-
function buildTextFixedBoundsSvg(content, width, height, fillColor = "#
|
|
223
|
+
function buildTextFixedBoundsSvg(content, width, height, fillColor = "#1d1d1d", fontSize = DEFAULT_TEXT_FONT_SIZE) {
|
|
156
224
|
const w = Math.max(1, width);
|
|
157
225
|
const h = Math.max(1, height);
|
|
158
226
|
const lh = lineHeightFor(fontSize);
|
|
159
227
|
const trimmed = content.trim();
|
|
228
|
+
const padTop = EDIT_TOP_PAD_RATIO * fontSize;
|
|
160
229
|
if (trimmed.length === 0) {
|
|
161
|
-
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
|
|
230
|
+
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:${padTop}px 4px 0 4px;font-size:${fontSize}px;line-height:${lh}px;font-family:${TEXT_FONT_FAMILY};white-space:pre-wrap;word-wrap:break-word;overflow:hidden;color:#94a3b8;font-style:italic">${escapeHtmlText2(PLACEHOLDER)}</div></foreignObject>`;
|
|
162
231
|
}
|
|
163
|
-
const body =
|
|
164
|
-
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
|
|
232
|
+
const body = escapeHtmlText2(content);
|
|
233
|
+
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:${padTop}px 4px 0 4px;font-size:${fontSize}px;line-height:${lh}px;font-family:${TEXT_FONT_FAMILY};white-space:pre-wrap;word-wrap:break-word;overflow:hidden;color:${fillColor}">${body}</div></foreignObject>`;
|
|
165
234
|
}
|
|
166
235
|
|
|
167
236
|
// src/scene/shape-builders.ts
|
|
168
237
|
var DEFAULT_STROKE_STYLE = {
|
|
169
|
-
stroke: "#
|
|
238
|
+
stroke: "#1d1d1d",
|
|
170
239
|
strokeWidth: 2
|
|
171
240
|
};
|
|
172
241
|
function perfectFreehandOptions(toolKind, style, strokeComplete, pressureAware = false) {
|
|
@@ -217,7 +286,8 @@ function resolveStrokeStyle(item) {
|
|
|
217
286
|
return {
|
|
218
287
|
stroke: item.stroke ?? DEFAULT_STROKE_STYLE.stroke,
|
|
219
288
|
strokeWidth: item.strokeWidth ?? DEFAULT_STROKE_STYLE.strokeWidth,
|
|
220
|
-
strokeOpacity: item.strokeOpacity
|
|
289
|
+
strokeOpacity: item.strokeOpacity,
|
|
290
|
+
strokeDash: item.strokeDash
|
|
221
291
|
};
|
|
222
292
|
}
|
|
223
293
|
function strokeOpacityAttr(style) {
|
|
@@ -546,6 +616,30 @@ function buildDrawDotSvg(r, style = DEFAULT_STROKE_STYLE) {
|
|
|
546
616
|
const op = style.strokeOpacity != null ? ` fill-opacity="${style.strokeOpacity}"` : "";
|
|
547
617
|
return `<circle cx="${r}" cy="${r}" r="${r}" fill="${style.stroke}" shape-rendering="geometricPrecision"${op} />`;
|
|
548
618
|
}
|
|
619
|
+
function dashArrayForDrawStroke(strokeWidth) {
|
|
620
|
+
const dash = Math.max(strokeWidth * 1.8, 4);
|
|
621
|
+
const gap = Math.max(strokeWidth * 1.4, 3);
|
|
622
|
+
return `${dash} ${gap}`;
|
|
623
|
+
}
|
|
624
|
+
function buildSmoothedCenterlinePath(points) {
|
|
625
|
+
if (points.length < 2) return null;
|
|
626
|
+
const first = points[0];
|
|
627
|
+
if (!first) return null;
|
|
628
|
+
let d = `M ${first.x} ${first.y}`;
|
|
629
|
+
for (let i = 1; i < points.length - 1; i++) {
|
|
630
|
+
const a = points[i];
|
|
631
|
+
const b = points[i + 1];
|
|
632
|
+
if (!a || !b) continue;
|
|
633
|
+
const midX = (a.x + b.x) / 2;
|
|
634
|
+
const midY = (a.y + b.y) / 2;
|
|
635
|
+
d += ` Q ${a.x} ${a.y} ${midX} ${midY}`;
|
|
636
|
+
}
|
|
637
|
+
const last = points[points.length - 1];
|
|
638
|
+
if (last) {
|
|
639
|
+
d += ` L ${last.x} ${last.y}`;
|
|
640
|
+
}
|
|
641
|
+
return d;
|
|
642
|
+
}
|
|
549
643
|
function computeFreehandSvgPayload(pathPointsLocal, style, toolKind, strokeComplete = true) {
|
|
550
644
|
if (pathPointsLocal.length === 0) return null;
|
|
551
645
|
if (pathPointsLocal.length === 1) {
|
|
@@ -560,6 +654,18 @@ function computeFreehandSvgPayload(pathPointsLocal, style, toolKind, strokeCompl
|
|
|
560
654
|
fillOpacity: style.strokeOpacity
|
|
561
655
|
};
|
|
562
656
|
}
|
|
657
|
+
if (style.strokeDash === "dashed" && (toolKind === "draw" || toolKind === "pencil")) {
|
|
658
|
+
const d2 = buildSmoothedCenterlinePath(pathPointsLocal);
|
|
659
|
+
if (!d2) return null;
|
|
660
|
+
return {
|
|
661
|
+
kind: "strokePath",
|
|
662
|
+
d: d2,
|
|
663
|
+
stroke: style.stroke,
|
|
664
|
+
strokeWidth: style.strokeWidth,
|
|
665
|
+
strokeOpacity: style.strokeOpacity,
|
|
666
|
+
strokeDasharray: dashArrayForDrawStroke(style.strokeWidth)
|
|
667
|
+
};
|
|
668
|
+
}
|
|
563
669
|
const hasPressure = pathPointsLocal.some(
|
|
564
670
|
(p) => p.pressure != null && Number.isFinite(p.pressure)
|
|
565
671
|
);
|
|
@@ -602,7 +708,8 @@ function freehandPayloadToSvgString(payload) {
|
|
|
602
708
|
strokeWidth: payload.strokeWidth,
|
|
603
709
|
strokeOpacity: payload.strokeOpacity
|
|
604
710
|
});
|
|
605
|
-
|
|
711
|
+
const dash = payload.strokeDasharray ? ` stroke-dasharray="${payload.strokeDasharray}"` : "";
|
|
712
|
+
return `<path d="${payload.d}" fill="none" stroke="${payload.stroke}" stroke-width="${payload.strokeWidth}" stroke-linecap="round" stroke-linejoin="round" shape-rendering="geometricPrecision"${op}${dash} />`;
|
|
606
713
|
}
|
|
607
714
|
function buildFreehandPathSvg(pathPointsLocal, style, toolKind, strokeComplete = true) {
|
|
608
715
|
const payload = computeFreehandSvgPayload(
|
|
@@ -837,10 +944,10 @@ function resolveColor(value) {
|
|
|
837
944
|
function escapeXml(value) {
|
|
838
945
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
839
946
|
}
|
|
840
|
-
function
|
|
947
|
+
function escapeHtmlText3(value) {
|
|
841
948
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
842
949
|
}
|
|
843
|
-
function
|
|
950
|
+
function formatNumber2(value) {
|
|
844
951
|
if (!Number.isFinite(value)) return "0";
|
|
845
952
|
const rounded = Math.round(value * 100) / 100;
|
|
846
953
|
return Number.isInteger(rounded) ? String(rounded) : String(rounded);
|
|
@@ -892,13 +999,13 @@ function sizeToFontPx(size) {
|
|
|
892
999
|
function dashArrayForStyle(dash, strokeWidth) {
|
|
893
1000
|
if (!dash || dash === "solid") return void 0;
|
|
894
1001
|
if (dash === "dotted") {
|
|
895
|
-
return `${
|
|
1002
|
+
return `${formatNumber2(Math.max(1.25, strokeWidth))} ${formatNumber2(Math.max(2.5, strokeWidth * 2.2))}`;
|
|
896
1003
|
}
|
|
897
1004
|
if (dash === "dashed") {
|
|
898
|
-
return `${
|
|
1005
|
+
return `${formatNumber2(Math.max(5, strokeWidth * 4))} ${formatNumber2(Math.max(3, strokeWidth * 2.2))}`;
|
|
899
1006
|
}
|
|
900
1007
|
if (dash === "draw") {
|
|
901
|
-
return `${
|
|
1008
|
+
return `${formatNumber2(Math.max(3, strokeWidth * 2.4))} ${formatNumber2(Math.max(2.4, strokeWidth * 1.6))}`;
|
|
902
1009
|
}
|
|
903
1010
|
return dash;
|
|
904
1011
|
}
|
|
@@ -914,11 +1021,11 @@ function strokeAttrs(style) {
|
|
|
914
1021
|
const dashAttr = dashArray ? ` stroke-dasharray="${dashArray}"` : "";
|
|
915
1022
|
const lineCap = style.lineCap ? ` stroke-linecap="${style.lineCap}"` : "";
|
|
916
1023
|
const lineJoin = style.lineJoin ? ` stroke-linejoin="${style.lineJoin}"` : "";
|
|
917
|
-
return `stroke="${style.stroke}" stroke-width="${
|
|
1024
|
+
return `stroke="${style.stroke}" stroke-width="${formatNumber2(style.strokeWidth)}"${dashAttr}${lineCap}${lineJoin}`;
|
|
918
1025
|
}
|
|
919
1026
|
function wrapOpacity(svg, opacity) {
|
|
920
1027
|
if (opacity >= 0.999) return svg;
|
|
921
|
-
return `<g opacity="${
|
|
1028
|
+
return `<g opacity="${formatNumber2(opacity)}">${svg}</g>`;
|
|
922
1029
|
}
|
|
923
1030
|
function buildForeignObjectTextSvg(options) {
|
|
924
1031
|
const x = options.x ?? 0;
|
|
@@ -933,8 +1040,8 @@ function buildForeignObjectTextSvg(options) {
|
|
|
933
1040
|
const weight = options.fontWeight != null ? `font-weight:${options.fontWeight};` : "";
|
|
934
1041
|
const fontStyle = options.italic ? "font-style:italic;" : "";
|
|
935
1042
|
const background = options.background ? `background:${options.background};` : "";
|
|
936
|
-
const radius = options.borderRadius != null ? `border-radius:${
|
|
937
|
-
return `<foreignObject x="${
|
|
1043
|
+
const radius = options.borderRadius != null ? `border-radius:${formatNumber2(options.borderRadius)}px;` : "";
|
|
1044
|
+
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>`;
|
|
938
1045
|
}
|
|
939
1046
|
function richTextToPlainText(value) {
|
|
940
1047
|
const parts = [];
|
|
@@ -1462,17 +1569,17 @@ function createCustomImportedItem(snapshot, shape, localBounds, innerSvg, style)
|
|
|
1462
1569
|
}
|
|
1463
1570
|
function polygonPath(points) {
|
|
1464
1571
|
if (points.length === 0) return "";
|
|
1465
|
-
let path = `M${
|
|
1572
|
+
let path = `M${formatNumber2(points[0]?.x ?? 0)} ${formatNumber2(points[0]?.y ?? 0)}`;
|
|
1466
1573
|
for (let index = 1; index < points.length; index++) {
|
|
1467
1574
|
const point = points[index];
|
|
1468
1575
|
if (!point) continue;
|
|
1469
|
-
path += ` L${
|
|
1576
|
+
path += ` L${formatNumber2(point.x)} ${formatNumber2(point.y)}`;
|
|
1470
1577
|
}
|
|
1471
1578
|
return `${path} Z`;
|
|
1472
1579
|
}
|
|
1473
1580
|
function cloudPath(width, height) {
|
|
1474
1581
|
const r = Math.min(width, height) * 0.15;
|
|
1475
|
-
return `M${
|
|
1582
|
+
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`;
|
|
1476
1583
|
}
|
|
1477
1584
|
function geoPath(geo, width, height) {
|
|
1478
1585
|
if (geo === "diamond" || geo === "rhombus") {
|
|
@@ -1551,10 +1658,10 @@ function geoPath(geo, width, height) {
|
|
|
1551
1658
|
]);
|
|
1552
1659
|
}
|
|
1553
1660
|
if (geo === "check-box") {
|
|
1554
|
-
return `M0 0 H${
|
|
1661
|
+
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)}`;
|
|
1555
1662
|
}
|
|
1556
1663
|
if (geo === "x-box") {
|
|
1557
|
-
return `M0 0 H${
|
|
1664
|
+
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)}`;
|
|
1558
1665
|
}
|
|
1559
1666
|
return null;
|
|
1560
1667
|
}
|
|
@@ -1570,7 +1677,7 @@ function renderGeoShape(snapshot, shape) {
|
|
|
1570
1677
|
const text = extractPlainText(props);
|
|
1571
1678
|
const fontSize = getNumber(props.fontSize) ?? sizeToFontPx(getString(props.size));
|
|
1572
1679
|
const customPath = geoPath(geo, width, height);
|
|
1573
|
-
const shapeMarkup = geo === "ellipse" || geo === "oval" ? `<ellipse cx="${
|
|
1680
|
+
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" })} />`;
|
|
1574
1681
|
const textMarkup = text ? buildForeignObjectTextSvg({
|
|
1575
1682
|
width,
|
|
1576
1683
|
height,
|
|
@@ -1655,11 +1762,11 @@ function renderStrokeShape(snapshot, shape) {
|
|
|
1655
1762
|
}
|
|
1656
1763
|
function polylinePath(points) {
|
|
1657
1764
|
if (points.length === 0) return "";
|
|
1658
|
-
let path = `M${
|
|
1765
|
+
let path = `M${formatNumber2(points[0]?.x ?? 0)} ${formatNumber2(points[0]?.y ?? 0)}`;
|
|
1659
1766
|
for (let index = 1; index < points.length; index++) {
|
|
1660
1767
|
const point = points[index];
|
|
1661
1768
|
if (!point) continue;
|
|
1662
|
-
path += ` L${
|
|
1769
|
+
path += ` L${formatNumber2(point.x)} ${formatNumber2(point.y)}`;
|
|
1663
1770
|
}
|
|
1664
1771
|
return path;
|
|
1665
1772
|
}
|
|
@@ -1681,22 +1788,22 @@ function buildArrowHeadSvg(options) {
|
|
|
1681
1788
|
const left = { x: bx + px * (headWidth / 2), y: by + py * (headWidth / 2) };
|
|
1682
1789
|
const right = { x: bx - px * (headWidth / 2), y: by - py * (headWidth / 2) };
|
|
1683
1790
|
if (type === "triangle") {
|
|
1684
|
-
return `<polygon points="${
|
|
1791
|
+
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}" />`;
|
|
1685
1792
|
}
|
|
1686
1793
|
if (type === "dot") {
|
|
1687
|
-
return `<circle cx="${
|
|
1794
|
+
return `<circle cx="${formatNumber2(options.tip.x)}" cy="${formatNumber2(options.tip.y)}" r="${formatNumber2(Math.max(3, options.strokeWidth * 1.5))}" fill="${options.stroke}" />`;
|
|
1688
1795
|
}
|
|
1689
1796
|
if (type === "diamond") {
|
|
1690
1797
|
const mid = {
|
|
1691
1798
|
x: options.tip.x - ux * (headLength / 2),
|
|
1692
1799
|
y: options.tip.y - uy * (headLength / 2)
|
|
1693
1800
|
};
|
|
1694
|
-
return `<polygon points="${
|
|
1801
|
+
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" />`;
|
|
1695
1802
|
}
|
|
1696
1803
|
if (type === "bar") {
|
|
1697
|
-
return `<line x1="${
|
|
1804
|
+
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" />`;
|
|
1698
1805
|
}
|
|
1699
|
-
return `<path d="M ${
|
|
1806
|
+
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" />`;
|
|
1700
1807
|
}
|
|
1701
1808
|
function renderLineShape(snapshot, shape) {
|
|
1702
1809
|
const props = asRecord(shape.props) ?? {};
|
|
@@ -1765,7 +1872,7 @@ function renderArrowShape(snapshot, shape) {
|
|
|
1765
1872
|
const translatedPoints = route.points.map(translate);
|
|
1766
1873
|
const translatedStartRef = translate(route.startRef);
|
|
1767
1874
|
const translatedEndRef = translate(route.endRef);
|
|
1768
|
-
const shaft = route.kind === "quadratic" && route.control ? `<path d="M${
|
|
1875
|
+
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" })} />`;
|
|
1769
1876
|
const startPoint = translatedPoints[0];
|
|
1770
1877
|
const endPoint = translatedPoints[translatedPoints.length - 1];
|
|
1771
1878
|
if (!startPoint || !endPoint) return null;
|
|
@@ -1797,9 +1904,9 @@ function renderMissingAssetPlaceholder(snapshot, shape, kind, detail) {
|
|
|
1797
1904
|
const width = localBounds.width;
|
|
1798
1905
|
const height = localBounds.height;
|
|
1799
1906
|
const inner = `
|
|
1800
|
-
<rect width="${
|
|
1801
|
-
<path d="M${
|
|
1802
|
-
<circle cx="${
|
|
1907
|
+
<rect width="${formatNumber2(width)}" height="${formatNumber2(height)}" rx="12" fill="#f4f4f5" stroke="#a1a1aa" stroke-width="1.5" stroke-dasharray="6 6" />
|
|
1908
|
+
<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" />
|
|
1909
|
+
<circle cx="${formatNumber2(width * 0.34)}" cy="${formatNumber2(height * 0.34)}" r="${formatNumber2(Math.max(6, Math.min(width, height) * 0.05))}" fill="#a1a1aa" />
|
|
1803
1910
|
${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" })}
|
|
1804
1911
|
${buildForeignObjectTextSvg({ x: 14, y: height * 0.78, width: width - 28, height: height * 0.16, text: detail, fontSize: 12, color: "#52525b", align: "center", verticalAlign: "middle" })}
|
|
1805
1912
|
`;
|
|
@@ -1853,10 +1960,10 @@ function renderVideoShape(snapshot, shape) {
|
|
|
1853
1960
|
const label = getString(asRecord(asset?.props)?.name) ?? "Video";
|
|
1854
1961
|
const subtitle = src ?? getString(props.assetId) ?? "Playback not supported in this importer";
|
|
1855
1962
|
const inner = `
|
|
1856
|
-
<rect width="${
|
|
1857
|
-
<rect x="${
|
|
1858
|
-
<circle cx="${
|
|
1859
|
-
<polygon points="${
|
|
1963
|
+
<rect width="${formatNumber2(width)}" height="${formatNumber2(height)}" rx="14" fill="#18181b" stroke="#3f3f46" stroke-width="1.5" />
|
|
1964
|
+
<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" />
|
|
1965
|
+
<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" />
|
|
1966
|
+
<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" />
|
|
1860
1967
|
${buildForeignObjectTextSvg({ x: 16, y: height * 0.76, width: width - 32, height: height * 0.12, text: label, fontSize: 15, color: "#fafafa", fontWeight: 700 })}
|
|
1861
1968
|
${buildForeignObjectTextSvg({ x: 16, y: height * 0.88, width: width - 32, height: height * 0.08, text: subtitle, fontSize: 11, color: "#d4d4d8" })}
|
|
1862
1969
|
`;
|
|
@@ -1882,8 +1989,8 @@ function renderNoteShape(snapshot, shape) {
|
|
|
1882
1989
|
const fold = Math.min(width, height) * 0.14;
|
|
1883
1990
|
const fontSize = sizeToFontPx(getString(props.size)) + numberOr(props.fontSizeAdjustment, 0);
|
|
1884
1991
|
const inner = `
|
|
1885
|
-
<path d="M0 0 H${
|
|
1886
|
-
<path d="M${
|
|
1992
|
+
<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" />
|
|
1993
|
+
<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" />
|
|
1887
1994
|
${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) })}
|
|
1888
1995
|
`;
|
|
1889
1996
|
return createCustomImportedItem(
|
|
@@ -1899,31 +2006,35 @@ function renderNoteShape(snapshot, shape) {
|
|
|
1899
2006
|
}
|
|
1900
2007
|
function renderBookmarkShape(snapshot, shape) {
|
|
1901
2008
|
const props = asRecord(shape.props) ?? {};
|
|
2009
|
+
const asset = resolveAsset(snapshot, shape);
|
|
2010
|
+
const assetProps = asRecord(asset?.props) ?? {};
|
|
1902
2011
|
const localBounds = resolveShapeLocalBounds(snapshot, shape.id);
|
|
1903
|
-
const
|
|
1904
|
-
const
|
|
1905
|
-
const
|
|
1906
|
-
const
|
|
1907
|
-
const
|
|
1908
|
-
const
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
return createCustomImportedItem(
|
|
2012
|
+
const href = getString(props.url) ?? getString(assetProps.src) ?? getString(props.src) ?? "";
|
|
2013
|
+
const title = getString(assetProps.title) ?? getString(props.title) ?? getString(props.label) ?? void 0;
|
|
2014
|
+
const description = getString(assetProps.description) ?? getString(props.description) ?? void 0;
|
|
2015
|
+
const image = getString(assetProps.image) ?? getString(props.image) ?? void 0;
|
|
2016
|
+
const favicon = getString(assetProps.favicon) ?? getString(props.favicon) ?? void 0;
|
|
2017
|
+
const link = {
|
|
2018
|
+
href: href || "URL unavailable",
|
|
2019
|
+
...title ? { title } : {},
|
|
2020
|
+
...description ? { description } : {},
|
|
2021
|
+
...image ? { image } : {},
|
|
2022
|
+
...favicon ? { favicon } : {}
|
|
2023
|
+
};
|
|
2024
|
+
const inner = buildLinkCardSvg(localBounds.width, localBounds.height, link);
|
|
2025
|
+
const item = createCustomImportedItem(
|
|
1918
2026
|
snapshot,
|
|
1919
2027
|
shape,
|
|
1920
2028
|
localBounds,
|
|
1921
|
-
wrapOpacity(inner, shapeOpacity(shape))
|
|
1922
|
-
{
|
|
1923
|
-
stroke,
|
|
1924
|
-
strokeWidth: 1.5
|
|
1925
|
-
}
|
|
2029
|
+
wrapOpacity(inner, shapeOpacity(shape))
|
|
1926
2030
|
);
|
|
2031
|
+
return {
|
|
2032
|
+
...item,
|
|
2033
|
+
pluginData: {
|
|
2034
|
+
...item.pluginData ?? {},
|
|
2035
|
+
[LINK_PLUGIN_KEY]: link
|
|
2036
|
+
}
|
|
2037
|
+
};
|
|
1927
2038
|
}
|
|
1928
2039
|
function renderEmbedShape(snapshot, shape) {
|
|
1929
2040
|
const props = asRecord(shape.props) ?? {};
|
|
@@ -1934,11 +2045,11 @@ function renderEmbedShape(snapshot, shape) {
|
|
|
1934
2045
|
const title = getString(props.title) ?? getString(props.embedTitle) ?? "Embed";
|
|
1935
2046
|
const url = getString(props.url) ?? getString(props.src) ?? "Embedded content";
|
|
1936
2047
|
const inner = `
|
|
1937
|
-
<rect width="${
|
|
1938
|
-
<rect x="16" y="16" width="${
|
|
1939
|
-
<circle cx="${
|
|
1940
|
-
<circle cx="${
|
|
1941
|
-
<circle cx="${
|
|
2048
|
+
<rect width="${formatNumber2(width)}" height="${formatNumber2(height)}" rx="16" fill="#0f172a" stroke="${stroke}" stroke-width="1.5" />
|
|
2049
|
+
<rect x="16" y="16" width="${formatNumber2(width - 32)}" height="${formatNumber2(height * 0.62)}" rx="12" fill="#111827" stroke="#334155" stroke-width="1" />
|
|
2050
|
+
<circle cx="${formatNumber2(width * 0.14)}" cy="${formatNumber2(height * 0.14)}" r="5" fill="#ef4444" />
|
|
2051
|
+
<circle cx="${formatNumber2(width * 0.18)}" cy="${formatNumber2(height * 0.14)}" r="5" fill="#f59e0b" />
|
|
2052
|
+
<circle cx="${formatNumber2(width * 0.22)}" cy="${formatNumber2(height * 0.14)}" r="5" fill="#22c55e" />
|
|
1942
2053
|
${buildForeignObjectTextSvg({ x: 18, y: height * 0.72, width: width - 36, height: height * 0.11, text: title, fontSize: 16, color: "#f8fafc", fontWeight: 700 })}
|
|
1943
2054
|
${buildForeignObjectTextSvg({ x: 18, y: height * 0.84, width: width - 36, height: height * 0.08, text: url, fontSize: 11, color: "#cbd5e1" })}
|
|
1944
2055
|
`;
|
|
@@ -1961,8 +2072,8 @@ function renderFrameShape(snapshot, shape) {
|
|
|
1961
2072
|
const stroke = shapeStrokeColor(shape);
|
|
1962
2073
|
const title = (getString(props.name) ?? getString(props.title) ?? extractPlainText(props)) || "Frame";
|
|
1963
2074
|
const inner = `
|
|
1964
|
-
<rect width="${
|
|
1965
|
-
<rect x="12" y="10" width="${
|
|
2075
|
+
<rect width="${formatNumber2(width)}" height="${formatNumber2(height)}" rx="14" fill="none" stroke="${stroke}" stroke-width="2" stroke-dasharray="10 6" />
|
|
2076
|
+
<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" />
|
|
1966
2077
|
${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" })}
|
|
1967
2078
|
`;
|
|
1968
2079
|
return createCustomImportedItem(
|
|
@@ -1985,8 +2096,8 @@ function renderAnnotationShape(snapshot, shape) {
|
|
|
1985
2096
|
const fill = shape.type === "annotationBubble" ? "#3b82f6" : resolveColor(getString(props.color) ?? "#ef4444");
|
|
1986
2097
|
const text = shape.type === "label" ? extractPlainText(props) : String(getNumber(props.number) ?? "");
|
|
1987
2098
|
const inner = `
|
|
1988
|
-
<circle cx="${
|
|
1989
|
-
<text x="${
|
|
2099
|
+
<circle cx="${formatNumber2(width / 2)}" cy="${formatNumber2(height / 2)}" r="${formatNumber2(radius)}" fill="${fill}" stroke="#ffffff" stroke-width="2" />
|
|
2100
|
+
<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>
|
|
1990
2101
|
`;
|
|
1991
2102
|
return createCustomImportedItem(
|
|
1992
2103
|
snapshot,
|
|
@@ -2006,7 +2117,7 @@ function renderUnsupportedShape(snapshot, shape, reason) {
|
|
|
2006
2117
|
const width = localBounds.width;
|
|
2007
2118
|
const height = localBounds.height;
|
|
2008
2119
|
const inner = `
|
|
2009
|
-
<rect width="${
|
|
2120
|
+
<rect width="${formatNumber2(width)}" height="${formatNumber2(height)}" rx="12" fill="#fafafa" stroke="#a1a1aa" stroke-width="1.5" stroke-dasharray="6 6" />
|
|
2010
2121
|
${buildForeignObjectTextSvg({ x: 12, y: 14, width: width - 24, height: 28, text: shape.type, fontSize: 14, color: "#111827", fontWeight: 700, verticalAlign: "middle" })}
|
|
2011
2122
|
${buildForeignObjectTextSvg({ x: 12, y: 50, width: width - 24, height: Math.max(20, height - 62), text: reason, fontSize: 12, color: "#52525b" })}
|
|
2012
2123
|
`;
|