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.d.cts
CHANGED
package/dist/tldraw.d.ts
CHANGED
package/dist/tldraw.js
CHANGED
|
@@ -44,19 +44,87 @@ 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;
|
|
120
|
+
var TEXT_FONT_FAMILY = "Inter, -apple-system, BlinkMacSystemFont, ui-sans-serif, system-ui, sans-serif";
|
|
55
121
|
var LINE_HEIGHT_RATIO = 22 / 18;
|
|
56
|
-
var FIRST_LINE_BASELINE_RATIO =
|
|
122
|
+
var FIRST_LINE_BASELINE_RATIO = 20 / 18;
|
|
123
|
+
var EDIT_TOP_PAD_RATIO = 4 / 18;
|
|
124
|
+
var BOTTOM_PAD_RATIO = 4 / 18;
|
|
57
125
|
var PLACEHOLDER = "Tap to type";
|
|
58
126
|
var MIN_TEXT_BOX_W = 40;
|
|
59
|
-
var MIN_TEXT_BOX_H =
|
|
127
|
+
var MIN_TEXT_BOX_H = 26;
|
|
60
128
|
var TEXT_PAD_X = 4;
|
|
61
129
|
var MAX_TEXT_MEASURE_CACHE_ENTRIES = 2e3;
|
|
62
130
|
var sharedMeasureContext;
|
|
@@ -102,7 +170,7 @@ function measureTextBoundsLocal(content, fontSize = DEFAULT_TEXT_FONT_SIZE) {
|
|
|
102
170
|
let maxInnerW = 0;
|
|
103
171
|
const ctx = getSharedMeasureContext();
|
|
104
172
|
if (ctx) {
|
|
105
|
-
ctx.font = `${fontSize}px
|
|
173
|
+
ctx.font = `${fontSize}px ${TEXT_FONT_FAMILY}`;
|
|
106
174
|
for (const line of lines) {
|
|
107
175
|
const toMeasure = trimmed.length === 0 ? PLACEHOLDER : line.length === 0 ? " " : line;
|
|
108
176
|
maxInnerW = Math.max(maxInnerW, ctx.measureText(toMeasure).width);
|
|
@@ -118,22 +186,22 @@ function measureTextBoundsLocal(content, fontSize = DEFAULT_TEXT_FONT_SIZE) {
|
|
|
118
186
|
const width = Math.max(minW, TEXT_PAD_X * 2 + maxInnerW);
|
|
119
187
|
const height = Math.max(
|
|
120
188
|
MIN_TEXT_BOX_H,
|
|
121
|
-
baselineY + (lines.length - 1) * lh + Math.max(
|
|
189
|
+
baselineY + (lines.length - 1) * lh + Math.max(4, fontSize * BOTTOM_PAD_RATIO)
|
|
122
190
|
);
|
|
123
191
|
const measured = { width, height };
|
|
124
192
|
cacheMeasuredBounds(cacheKey, measured);
|
|
125
193
|
return measured;
|
|
126
194
|
}
|
|
127
|
-
function buildTextSvg(content, _width, _height, fillColor = "#
|
|
195
|
+
function buildTextSvg(content, _width, _height, fillColor = "#1d1d1d", fontSize = DEFAULT_TEXT_FONT_SIZE) {
|
|
128
196
|
const lh = lineHeightFor(fontSize);
|
|
129
197
|
const y0 = firstLineBaselineY(fontSize);
|
|
130
198
|
const trimmed = content.trim();
|
|
131
199
|
if (trimmed.length === 0) {
|
|
132
|
-
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="
|
|
200
|
+
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="${TEXT_FONT_FAMILY}" fill="#94a3b8" font-style="italic">${escapeSvgTextContent(PLACEHOLDER)}</text>`;
|
|
133
201
|
}
|
|
134
202
|
const lines = content.split("\n");
|
|
135
203
|
if (lines.length === 1) {
|
|
136
|
-
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="
|
|
204
|
+
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="${TEXT_FONT_FAMILY}" fill="${fillColor}">${escapeSvgTextContent(lines[0] ?? "")}</text>`;
|
|
137
205
|
}
|
|
138
206
|
const parts = [];
|
|
139
207
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -144,23 +212,24 @@ function buildTextSvg(content, _width, _height, fillColor = "#2563eb", fontSize
|
|
|
144
212
|
parts.push(`<tspan x="4" dy="${lh}">${escapeSvgTextContent(line)}</tspan>`);
|
|
145
213
|
}
|
|
146
214
|
}
|
|
147
|
-
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="
|
|
215
|
+
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="${TEXT_FONT_FAMILY}" fill="${fillColor}">${parts.join("")}</text>`;
|
|
148
216
|
}
|
|
149
|
-
function buildTextFixedBoundsSvg(content, width, height, fillColor = "#
|
|
217
|
+
function buildTextFixedBoundsSvg(content, width, height, fillColor = "#1d1d1d", fontSize = DEFAULT_TEXT_FONT_SIZE) {
|
|
150
218
|
const w = Math.max(1, width);
|
|
151
219
|
const h = Math.max(1, height);
|
|
152
220
|
const lh = lineHeightFor(fontSize);
|
|
153
221
|
const trimmed = content.trim();
|
|
222
|
+
const padTop = EDIT_TOP_PAD_RATIO * fontSize;
|
|
154
223
|
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
|
|
224
|
+
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>`;
|
|
156
225
|
}
|
|
157
|
-
const body =
|
|
158
|
-
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
|
|
226
|
+
const body = escapeHtmlText2(content);
|
|
227
|
+
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>`;
|
|
159
228
|
}
|
|
160
229
|
|
|
161
230
|
// src/scene/shape-builders.ts
|
|
162
231
|
var DEFAULT_STROKE_STYLE = {
|
|
163
|
-
stroke: "#
|
|
232
|
+
stroke: "#1d1d1d",
|
|
164
233
|
strokeWidth: 2
|
|
165
234
|
};
|
|
166
235
|
function perfectFreehandOptions(toolKind, style, strokeComplete, pressureAware = false) {
|
|
@@ -211,7 +280,8 @@ function resolveStrokeStyle(item) {
|
|
|
211
280
|
return {
|
|
212
281
|
stroke: item.stroke ?? DEFAULT_STROKE_STYLE.stroke,
|
|
213
282
|
strokeWidth: item.strokeWidth ?? DEFAULT_STROKE_STYLE.strokeWidth,
|
|
214
|
-
strokeOpacity: item.strokeOpacity
|
|
283
|
+
strokeOpacity: item.strokeOpacity,
|
|
284
|
+
strokeDash: item.strokeDash
|
|
215
285
|
};
|
|
216
286
|
}
|
|
217
287
|
function strokeOpacityAttr(style) {
|
|
@@ -540,6 +610,30 @@ function buildDrawDotSvg(r, style = DEFAULT_STROKE_STYLE) {
|
|
|
540
610
|
const op = style.strokeOpacity != null ? ` fill-opacity="${style.strokeOpacity}"` : "";
|
|
541
611
|
return `<circle cx="${r}" cy="${r}" r="${r}" fill="${style.stroke}" shape-rendering="geometricPrecision"${op} />`;
|
|
542
612
|
}
|
|
613
|
+
function dashArrayForDrawStroke(strokeWidth) {
|
|
614
|
+
const dash = Math.max(strokeWidth * 1.8, 4);
|
|
615
|
+
const gap = Math.max(strokeWidth * 1.4, 3);
|
|
616
|
+
return `${dash} ${gap}`;
|
|
617
|
+
}
|
|
618
|
+
function buildSmoothedCenterlinePath(points) {
|
|
619
|
+
if (points.length < 2) return null;
|
|
620
|
+
const first = points[0];
|
|
621
|
+
if (!first) return null;
|
|
622
|
+
let d = `M ${first.x} ${first.y}`;
|
|
623
|
+
for (let i = 1; i < points.length - 1; i++) {
|
|
624
|
+
const a = points[i];
|
|
625
|
+
const b = points[i + 1];
|
|
626
|
+
if (!a || !b) continue;
|
|
627
|
+
const midX = (a.x + b.x) / 2;
|
|
628
|
+
const midY = (a.y + b.y) / 2;
|
|
629
|
+
d += ` Q ${a.x} ${a.y} ${midX} ${midY}`;
|
|
630
|
+
}
|
|
631
|
+
const last = points[points.length - 1];
|
|
632
|
+
if (last) {
|
|
633
|
+
d += ` L ${last.x} ${last.y}`;
|
|
634
|
+
}
|
|
635
|
+
return d;
|
|
636
|
+
}
|
|
543
637
|
function computeFreehandSvgPayload(pathPointsLocal, style, toolKind, strokeComplete = true) {
|
|
544
638
|
if (pathPointsLocal.length === 0) return null;
|
|
545
639
|
if (pathPointsLocal.length === 1) {
|
|
@@ -554,6 +648,18 @@ function computeFreehandSvgPayload(pathPointsLocal, style, toolKind, strokeCompl
|
|
|
554
648
|
fillOpacity: style.strokeOpacity
|
|
555
649
|
};
|
|
556
650
|
}
|
|
651
|
+
if (style.strokeDash === "dashed" && (toolKind === "draw" || toolKind === "pencil")) {
|
|
652
|
+
const d2 = buildSmoothedCenterlinePath(pathPointsLocal);
|
|
653
|
+
if (!d2) return null;
|
|
654
|
+
return {
|
|
655
|
+
kind: "strokePath",
|
|
656
|
+
d: d2,
|
|
657
|
+
stroke: style.stroke,
|
|
658
|
+
strokeWidth: style.strokeWidth,
|
|
659
|
+
strokeOpacity: style.strokeOpacity,
|
|
660
|
+
strokeDasharray: dashArrayForDrawStroke(style.strokeWidth)
|
|
661
|
+
};
|
|
662
|
+
}
|
|
557
663
|
const hasPressure = pathPointsLocal.some(
|
|
558
664
|
(p) => p.pressure != null && Number.isFinite(p.pressure)
|
|
559
665
|
);
|
|
@@ -596,7 +702,8 @@ function freehandPayloadToSvgString(payload) {
|
|
|
596
702
|
strokeWidth: payload.strokeWidth,
|
|
597
703
|
strokeOpacity: payload.strokeOpacity
|
|
598
704
|
});
|
|
599
|
-
|
|
705
|
+
const dash = payload.strokeDasharray ? ` stroke-dasharray="${payload.strokeDasharray}"` : "";
|
|
706
|
+
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} />`;
|
|
600
707
|
}
|
|
601
708
|
function buildFreehandPathSvg(pathPointsLocal, style, toolKind, strokeComplete = true) {
|
|
602
709
|
const payload = computeFreehandSvgPayload(
|
|
@@ -831,10 +938,10 @@ function resolveColor(value) {
|
|
|
831
938
|
function escapeXml(value) {
|
|
832
939
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
833
940
|
}
|
|
834
|
-
function
|
|
941
|
+
function escapeHtmlText3(value) {
|
|
835
942
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
836
943
|
}
|
|
837
|
-
function
|
|
944
|
+
function formatNumber2(value) {
|
|
838
945
|
if (!Number.isFinite(value)) return "0";
|
|
839
946
|
const rounded = Math.round(value * 100) / 100;
|
|
840
947
|
return Number.isInteger(rounded) ? String(rounded) : String(rounded);
|
|
@@ -886,13 +993,13 @@ function sizeToFontPx(size) {
|
|
|
886
993
|
function dashArrayForStyle(dash, strokeWidth) {
|
|
887
994
|
if (!dash || dash === "solid") return void 0;
|
|
888
995
|
if (dash === "dotted") {
|
|
889
|
-
return `${
|
|
996
|
+
return `${formatNumber2(Math.max(1.25, strokeWidth))} ${formatNumber2(Math.max(2.5, strokeWidth * 2.2))}`;
|
|
890
997
|
}
|
|
891
998
|
if (dash === "dashed") {
|
|
892
|
-
return `${
|
|
999
|
+
return `${formatNumber2(Math.max(5, strokeWidth * 4))} ${formatNumber2(Math.max(3, strokeWidth * 2.2))}`;
|
|
893
1000
|
}
|
|
894
1001
|
if (dash === "draw") {
|
|
895
|
-
return `${
|
|
1002
|
+
return `${formatNumber2(Math.max(3, strokeWidth * 2.4))} ${formatNumber2(Math.max(2.4, strokeWidth * 1.6))}`;
|
|
896
1003
|
}
|
|
897
1004
|
return dash;
|
|
898
1005
|
}
|
|
@@ -908,11 +1015,11 @@ function strokeAttrs(style) {
|
|
|
908
1015
|
const dashAttr = dashArray ? ` stroke-dasharray="${dashArray}"` : "";
|
|
909
1016
|
const lineCap = style.lineCap ? ` stroke-linecap="${style.lineCap}"` : "";
|
|
910
1017
|
const lineJoin = style.lineJoin ? ` stroke-linejoin="${style.lineJoin}"` : "";
|
|
911
|
-
return `stroke="${style.stroke}" stroke-width="${
|
|
1018
|
+
return `stroke="${style.stroke}" stroke-width="${formatNumber2(style.strokeWidth)}"${dashAttr}${lineCap}${lineJoin}`;
|
|
912
1019
|
}
|
|
913
1020
|
function wrapOpacity(svg, opacity) {
|
|
914
1021
|
if (opacity >= 0.999) return svg;
|
|
915
|
-
return `<g opacity="${
|
|
1022
|
+
return `<g opacity="${formatNumber2(opacity)}">${svg}</g>`;
|
|
916
1023
|
}
|
|
917
1024
|
function buildForeignObjectTextSvg(options) {
|
|
918
1025
|
const x = options.x ?? 0;
|
|
@@ -927,8 +1034,8 @@ function buildForeignObjectTextSvg(options) {
|
|
|
927
1034
|
const weight = options.fontWeight != null ? `font-weight:${options.fontWeight};` : "";
|
|
928
1035
|
const fontStyle = options.italic ? "font-style:italic;" : "";
|
|
929
1036
|
const background = options.background ? `background:${options.background};` : "";
|
|
930
|
-
const radius = options.borderRadius != null ? `border-radius:${
|
|
931
|
-
return `<foreignObject x="${
|
|
1037
|
+
const radius = options.borderRadius != null ? `border-radius:${formatNumber2(options.borderRadius)}px;` : "";
|
|
1038
|
+
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
1039
|
}
|
|
933
1040
|
function richTextToPlainText(value) {
|
|
934
1041
|
const parts = [];
|
|
@@ -1456,17 +1563,17 @@ function createCustomImportedItem(snapshot, shape, localBounds, innerSvg, style)
|
|
|
1456
1563
|
}
|
|
1457
1564
|
function polygonPath(points) {
|
|
1458
1565
|
if (points.length === 0) return "";
|
|
1459
|
-
let path = `M${
|
|
1566
|
+
let path = `M${formatNumber2(points[0]?.x ?? 0)} ${formatNumber2(points[0]?.y ?? 0)}`;
|
|
1460
1567
|
for (let index = 1; index < points.length; index++) {
|
|
1461
1568
|
const point = points[index];
|
|
1462
1569
|
if (!point) continue;
|
|
1463
|
-
path += ` L${
|
|
1570
|
+
path += ` L${formatNumber2(point.x)} ${formatNumber2(point.y)}`;
|
|
1464
1571
|
}
|
|
1465
1572
|
return `${path} Z`;
|
|
1466
1573
|
}
|
|
1467
1574
|
function cloudPath(width, height) {
|
|
1468
1575
|
const r = Math.min(width, height) * 0.15;
|
|
1469
|
-
return `M${
|
|
1576
|
+
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
1577
|
}
|
|
1471
1578
|
function geoPath(geo, width, height) {
|
|
1472
1579
|
if (geo === "diamond" || geo === "rhombus") {
|
|
@@ -1545,10 +1652,10 @@ function geoPath(geo, width, height) {
|
|
|
1545
1652
|
]);
|
|
1546
1653
|
}
|
|
1547
1654
|
if (geo === "check-box") {
|
|
1548
|
-
return `M0 0 H${
|
|
1655
|
+
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
1656
|
}
|
|
1550
1657
|
if (geo === "x-box") {
|
|
1551
|
-
return `M0 0 H${
|
|
1658
|
+
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
1659
|
}
|
|
1553
1660
|
return null;
|
|
1554
1661
|
}
|
|
@@ -1564,7 +1671,7 @@ function renderGeoShape(snapshot, shape) {
|
|
|
1564
1671
|
const text = extractPlainText(props);
|
|
1565
1672
|
const fontSize = getNumber(props.fontSize) ?? sizeToFontPx(getString(props.size));
|
|
1566
1673
|
const customPath = geoPath(geo, width, height);
|
|
1567
|
-
const shapeMarkup = geo === "ellipse" || geo === "oval" ? `<ellipse cx="${
|
|
1674
|
+
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
1675
|
const textMarkup = text ? buildForeignObjectTextSvg({
|
|
1569
1676
|
width,
|
|
1570
1677
|
height,
|
|
@@ -1649,11 +1756,11 @@ function renderStrokeShape(snapshot, shape) {
|
|
|
1649
1756
|
}
|
|
1650
1757
|
function polylinePath(points) {
|
|
1651
1758
|
if (points.length === 0) return "";
|
|
1652
|
-
let path = `M${
|
|
1759
|
+
let path = `M${formatNumber2(points[0]?.x ?? 0)} ${formatNumber2(points[0]?.y ?? 0)}`;
|
|
1653
1760
|
for (let index = 1; index < points.length; index++) {
|
|
1654
1761
|
const point = points[index];
|
|
1655
1762
|
if (!point) continue;
|
|
1656
|
-
path += ` L${
|
|
1763
|
+
path += ` L${formatNumber2(point.x)} ${formatNumber2(point.y)}`;
|
|
1657
1764
|
}
|
|
1658
1765
|
return path;
|
|
1659
1766
|
}
|
|
@@ -1675,22 +1782,22 @@ function buildArrowHeadSvg(options) {
|
|
|
1675
1782
|
const left = { x: bx + px * (headWidth / 2), y: by + py * (headWidth / 2) };
|
|
1676
1783
|
const right = { x: bx - px * (headWidth / 2), y: by - py * (headWidth / 2) };
|
|
1677
1784
|
if (type === "triangle") {
|
|
1678
|
-
return `<polygon points="${
|
|
1785
|
+
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
1786
|
}
|
|
1680
1787
|
if (type === "dot") {
|
|
1681
|
-
return `<circle cx="${
|
|
1788
|
+
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
1789
|
}
|
|
1683
1790
|
if (type === "diamond") {
|
|
1684
1791
|
const mid = {
|
|
1685
1792
|
x: options.tip.x - ux * (headLength / 2),
|
|
1686
1793
|
y: options.tip.y - uy * (headLength / 2)
|
|
1687
1794
|
};
|
|
1688
|
-
return `<polygon points="${
|
|
1795
|
+
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
1796
|
}
|
|
1690
1797
|
if (type === "bar") {
|
|
1691
|
-
return `<line x1="${
|
|
1798
|
+
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
1799
|
}
|
|
1693
|
-
return `<path d="M ${
|
|
1800
|
+
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
1801
|
}
|
|
1695
1802
|
function renderLineShape(snapshot, shape) {
|
|
1696
1803
|
const props = asRecord(shape.props) ?? {};
|
|
@@ -1759,7 +1866,7 @@ function renderArrowShape(snapshot, shape) {
|
|
|
1759
1866
|
const translatedPoints = route.points.map(translate);
|
|
1760
1867
|
const translatedStartRef = translate(route.startRef);
|
|
1761
1868
|
const translatedEndRef = translate(route.endRef);
|
|
1762
|
-
const shaft = route.kind === "quadratic" && route.control ? `<path d="M${
|
|
1869
|
+
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
1870
|
const startPoint = translatedPoints[0];
|
|
1764
1871
|
const endPoint = translatedPoints[translatedPoints.length - 1];
|
|
1765
1872
|
if (!startPoint || !endPoint) return null;
|
|
@@ -1791,9 +1898,9 @@ function renderMissingAssetPlaceholder(snapshot, shape, kind, detail) {
|
|
|
1791
1898
|
const width = localBounds.width;
|
|
1792
1899
|
const height = localBounds.height;
|
|
1793
1900
|
const inner = `
|
|
1794
|
-
<rect width="${
|
|
1795
|
-
<path d="M${
|
|
1796
|
-
<circle cx="${
|
|
1901
|
+
<rect width="${formatNumber2(width)}" height="${formatNumber2(height)}" rx="12" fill="#f4f4f5" stroke="#a1a1aa" stroke-width="1.5" stroke-dasharray="6 6" />
|
|
1902
|
+
<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" />
|
|
1903
|
+
<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
1904
|
${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
1905
|
${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
1906
|
`;
|
|
@@ -1847,10 +1954,10 @@ function renderVideoShape(snapshot, shape) {
|
|
|
1847
1954
|
const label = getString(asRecord(asset?.props)?.name) ?? "Video";
|
|
1848
1955
|
const subtitle = src ?? getString(props.assetId) ?? "Playback not supported in this importer";
|
|
1849
1956
|
const inner = `
|
|
1850
|
-
<rect width="${
|
|
1851
|
-
<rect x="${
|
|
1852
|
-
<circle cx="${
|
|
1853
|
-
<polygon points="${
|
|
1957
|
+
<rect width="${formatNumber2(width)}" height="${formatNumber2(height)}" rx="14" fill="#18181b" stroke="#3f3f46" stroke-width="1.5" />
|
|
1958
|
+
<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" />
|
|
1959
|
+
<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" />
|
|
1960
|
+
<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
1961
|
${buildForeignObjectTextSvg({ x: 16, y: height * 0.76, width: width - 32, height: height * 0.12, text: label, fontSize: 15, color: "#fafafa", fontWeight: 700 })}
|
|
1855
1962
|
${buildForeignObjectTextSvg({ x: 16, y: height * 0.88, width: width - 32, height: height * 0.08, text: subtitle, fontSize: 11, color: "#d4d4d8" })}
|
|
1856
1963
|
`;
|
|
@@ -1876,8 +1983,8 @@ function renderNoteShape(snapshot, shape) {
|
|
|
1876
1983
|
const fold = Math.min(width, height) * 0.14;
|
|
1877
1984
|
const fontSize = sizeToFontPx(getString(props.size)) + numberOr(props.fontSizeAdjustment, 0);
|
|
1878
1985
|
const inner = `
|
|
1879
|
-
<path d="M0 0 H${
|
|
1880
|
-
<path d="M${
|
|
1986
|
+
<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" />
|
|
1987
|
+
<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
1988
|
${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
1989
|
`;
|
|
1883
1990
|
return createCustomImportedItem(
|
|
@@ -1893,31 +2000,35 @@ function renderNoteShape(snapshot, shape) {
|
|
|
1893
2000
|
}
|
|
1894
2001
|
function renderBookmarkShape(snapshot, shape) {
|
|
1895
2002
|
const props = asRecord(shape.props) ?? {};
|
|
2003
|
+
const asset = resolveAsset(snapshot, shape);
|
|
2004
|
+
const assetProps = asRecord(asset?.props) ?? {};
|
|
1896
2005
|
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(
|
|
2006
|
+
const href = getString(props.url) ?? getString(assetProps.src) ?? getString(props.src) ?? "";
|
|
2007
|
+
const title = getString(assetProps.title) ?? getString(props.title) ?? getString(props.label) ?? void 0;
|
|
2008
|
+
const description = getString(assetProps.description) ?? getString(props.description) ?? void 0;
|
|
2009
|
+
const image = getString(assetProps.image) ?? getString(props.image) ?? void 0;
|
|
2010
|
+
const favicon = getString(assetProps.favicon) ?? getString(props.favicon) ?? void 0;
|
|
2011
|
+
const link = {
|
|
2012
|
+
href: href || "URL unavailable",
|
|
2013
|
+
...title ? { title } : {},
|
|
2014
|
+
...description ? { description } : {},
|
|
2015
|
+
...image ? { image } : {},
|
|
2016
|
+
...favicon ? { favicon } : {}
|
|
2017
|
+
};
|
|
2018
|
+
const inner = buildLinkCardSvg(localBounds.width, localBounds.height, link);
|
|
2019
|
+
const item = createCustomImportedItem(
|
|
1912
2020
|
snapshot,
|
|
1913
2021
|
shape,
|
|
1914
2022
|
localBounds,
|
|
1915
|
-
wrapOpacity(inner, shapeOpacity(shape))
|
|
1916
|
-
{
|
|
1917
|
-
stroke,
|
|
1918
|
-
strokeWidth: 1.5
|
|
1919
|
-
}
|
|
2023
|
+
wrapOpacity(inner, shapeOpacity(shape))
|
|
1920
2024
|
);
|
|
2025
|
+
return {
|
|
2026
|
+
...item,
|
|
2027
|
+
pluginData: {
|
|
2028
|
+
...item.pluginData ?? {},
|
|
2029
|
+
[LINK_PLUGIN_KEY]: link
|
|
2030
|
+
}
|
|
2031
|
+
};
|
|
1921
2032
|
}
|
|
1922
2033
|
function renderEmbedShape(snapshot, shape) {
|
|
1923
2034
|
const props = asRecord(shape.props) ?? {};
|
|
@@ -1928,11 +2039,11 @@ function renderEmbedShape(snapshot, shape) {
|
|
|
1928
2039
|
const title = getString(props.title) ?? getString(props.embedTitle) ?? "Embed";
|
|
1929
2040
|
const url = getString(props.url) ?? getString(props.src) ?? "Embedded content";
|
|
1930
2041
|
const inner = `
|
|
1931
|
-
<rect width="${
|
|
1932
|
-
<rect x="16" y="16" width="${
|
|
1933
|
-
<circle cx="${
|
|
1934
|
-
<circle cx="${
|
|
1935
|
-
<circle cx="${
|
|
2042
|
+
<rect width="${formatNumber2(width)}" height="${formatNumber2(height)}" rx="16" fill="#0f172a" stroke="${stroke}" stroke-width="1.5" />
|
|
2043
|
+
<rect x="16" y="16" width="${formatNumber2(width - 32)}" height="${formatNumber2(height * 0.62)}" rx="12" fill="#111827" stroke="#334155" stroke-width="1" />
|
|
2044
|
+
<circle cx="${formatNumber2(width * 0.14)}" cy="${formatNumber2(height * 0.14)}" r="5" fill="#ef4444" />
|
|
2045
|
+
<circle cx="${formatNumber2(width * 0.18)}" cy="${formatNumber2(height * 0.14)}" r="5" fill="#f59e0b" />
|
|
2046
|
+
<circle cx="${formatNumber2(width * 0.22)}" cy="${formatNumber2(height * 0.14)}" r="5" fill="#22c55e" />
|
|
1936
2047
|
${buildForeignObjectTextSvg({ x: 18, y: height * 0.72, width: width - 36, height: height * 0.11, text: title, fontSize: 16, color: "#f8fafc", fontWeight: 700 })}
|
|
1937
2048
|
${buildForeignObjectTextSvg({ x: 18, y: height * 0.84, width: width - 36, height: height * 0.08, text: url, fontSize: 11, color: "#cbd5e1" })}
|
|
1938
2049
|
`;
|
|
@@ -1955,8 +2066,8 @@ function renderFrameShape(snapshot, shape) {
|
|
|
1955
2066
|
const stroke = shapeStrokeColor(shape);
|
|
1956
2067
|
const title = (getString(props.name) ?? getString(props.title) ?? extractPlainText(props)) || "Frame";
|
|
1957
2068
|
const inner = `
|
|
1958
|
-
<rect width="${
|
|
1959
|
-
<rect x="12" y="10" width="${
|
|
2069
|
+
<rect width="${formatNumber2(width)}" height="${formatNumber2(height)}" rx="14" fill="none" stroke="${stroke}" stroke-width="2" stroke-dasharray="10 6" />
|
|
2070
|
+
<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
2071
|
${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
2072
|
`;
|
|
1962
2073
|
return createCustomImportedItem(
|
|
@@ -1979,8 +2090,8 @@ function renderAnnotationShape(snapshot, shape) {
|
|
|
1979
2090
|
const fill = shape.type === "annotationBubble" ? "#3b82f6" : resolveColor(getString(props.color) ?? "#ef4444");
|
|
1980
2091
|
const text = shape.type === "label" ? extractPlainText(props) : String(getNumber(props.number) ?? "");
|
|
1981
2092
|
const inner = `
|
|
1982
|
-
<circle cx="${
|
|
1983
|
-
<text x="${
|
|
2093
|
+
<circle cx="${formatNumber2(width / 2)}" cy="${formatNumber2(height / 2)}" r="${formatNumber2(radius)}" fill="${fill}" stroke="#ffffff" stroke-width="2" />
|
|
2094
|
+
<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
2095
|
`;
|
|
1985
2096
|
return createCustomImportedItem(
|
|
1986
2097
|
snapshot,
|
|
@@ -2000,7 +2111,7 @@ function renderUnsupportedShape(snapshot, shape, reason) {
|
|
|
2000
2111
|
const width = localBounds.width;
|
|
2001
2112
|
const height = localBounds.height;
|
|
2002
2113
|
const inner = `
|
|
2003
|
-
<rect width="${
|
|
2114
|
+
<rect width="${formatNumber2(width)}" height="${formatNumber2(height)}" rx="12" fill="#fafafa" stroke="#a1a1aa" stroke-width="1.5" stroke-dasharray="6 6" />
|
|
2004
2115
|
${buildForeignObjectTextSvg({ x: 12, y: 14, width: width - 24, height: 28, text: shape.type, fontSize: 14, color: "#111827", fontWeight: 700, verticalAlign: "middle" })}
|
|
2005
2116
|
${buildForeignObjectTextSvg({ x: 12, y: 50, width: width - 24, height: Math.max(20, height - 62), text: reason, fontSize: 12, color: "#52525b" })}
|
|
2006
2117
|
`;
|