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/realtime.d.cts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { P as PlacementPreview, R as RemotePresenceMarkupStroke, A as RemotePresencePeer, D as RemotePresenceCamera, E as RealtimeConnectionState, q as VectorViewportHandle, V as VectorToolDefinition, r as VectorViewportProps, C as CanvasPlugin, e as CanvasPluginRenderContext } from './types-
|
|
2
|
-
export { F as PresenceOverlayRenderContext } from './types-
|
|
1
|
+
import { P as PlacementPreview, R as RemotePresenceMarkupStroke, A as RemotePresencePeer, D as RemotePresenceCamera, E as RealtimeConnectionState, q as VectorViewportHandle, V as VectorToolDefinition, r as VectorViewportProps, C as CanvasPlugin, e as CanvasPluginRenderContext } from './types-DUW61Tjy.cjs';
|
|
2
|
+
export { F as PresenceOverlayRenderContext } from './types-DUW61Tjy.cjs';
|
|
3
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
4
|
import { C as Camera2D } from './camera-Di5R_Rwl.cjs';
|
|
5
5
|
import { V as VectorSceneItem, R as Rect } from './types-Bnq2HtHQ.cjs';
|
|
6
6
|
import { ReactNode, RefObject } from 'react';
|
|
7
7
|
import { a as VectorCanvasRemoteAdapter } from './types-B2Na677H.cjs';
|
|
8
|
-
import './shape-builders-
|
|
8
|
+
import './shape-builders-Dedcl6tw.cjs';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Maps a local {@link PlacementPreview} stroke to {@link RemotePresenceMarkupStroke} for broadcasting.
|
package/dist/realtime.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { P as PlacementPreview, R as RemotePresenceMarkupStroke, A as RemotePresencePeer, D as RemotePresenceCamera, E as RealtimeConnectionState, q as VectorViewportHandle, V as VectorToolDefinition, r as VectorViewportProps, C as CanvasPlugin, e as CanvasPluginRenderContext } from './types-
|
|
2
|
-
export { F as PresenceOverlayRenderContext } from './types-
|
|
1
|
+
import { P as PlacementPreview, R as RemotePresenceMarkupStroke, A as RemotePresencePeer, D as RemotePresenceCamera, E as RealtimeConnectionState, q as VectorViewportHandle, V as VectorToolDefinition, r as VectorViewportProps, C as CanvasPlugin, e as CanvasPluginRenderContext } from './types-BBb8KoyW.js';
|
|
2
|
+
export { F as PresenceOverlayRenderContext } from './types-BBb8KoyW.js';
|
|
3
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
4
|
import { C as Camera2D } from './camera-AoTwBSoE.js';
|
|
5
5
|
import { V as VectorSceneItem, R as Rect } from './types-Bnq2HtHQ.js';
|
|
6
6
|
import { ReactNode, RefObject } from 'react';
|
|
7
7
|
import { a as VectorCanvasRemoteAdapter } from './types-zmUah-vP.js';
|
|
8
|
-
import './shape-builders-
|
|
8
|
+
import './shape-builders-C7bxJBGR.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Maps a local {@link PlacementPreview} stroke to {@link RemotePresenceMarkupStroke} for broadcasting.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { V as VectorSceneItem,
|
|
1
|
+
import { V as VectorSceneItem, R as Rect, L as LineEndpointsLocal, b as VectorPathPoint, a as ArrowBindings } from './types-Bnq2HtHQ.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Kind of binary selected through the built-in canvu asset ingestion flow.
|
|
@@ -110,6 +110,44 @@ type VectorViewportAssetStore = {
|
|
|
110
110
|
getHydrationRequest?: (item: VectorSceneItem) => VectorViewportAssetHydrationRequest | null;
|
|
111
111
|
};
|
|
112
112
|
|
|
113
|
+
/** Plugin key under which link metadata is stored on a link item's `pluginData`. */
|
|
114
|
+
declare const LINK_PLUGIN_KEY = "canvuLink";
|
|
115
|
+
/**
|
|
116
|
+
* Metadata describing a clickable link/bookmark item.
|
|
117
|
+
* `href` is required; the rest enrich the rendered card (unfurl result).
|
|
118
|
+
*/
|
|
119
|
+
type CanvuLinkData = {
|
|
120
|
+
/** Absolute URL the card points to. */
|
|
121
|
+
href: string;
|
|
122
|
+
/** Human readable title (falls back to the hostname). */
|
|
123
|
+
title?: string;
|
|
124
|
+
/** Short description shown under the title. */
|
|
125
|
+
description?: string;
|
|
126
|
+
/** Preview image URL (og:image). */
|
|
127
|
+
image?: string;
|
|
128
|
+
/** Favicon URL shown in the leading badge. */
|
|
129
|
+
favicon?: string;
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Builds the inner SVG (no outer `<svg>`) for a link/bookmark card at the given box size.
|
|
133
|
+
* Uses fixed pixel bands so text never overlaps regardless of the card's aspect ratio.
|
|
134
|
+
*/
|
|
135
|
+
declare function buildLinkCardSvg(width: number, height: number, link: CanvuLinkData): string;
|
|
136
|
+
/** Reads the link metadata from an item, or `null` when the item is not a link. */
|
|
137
|
+
declare function getLinkData(item: VectorSceneItem): CanvuLinkData | null;
|
|
138
|
+
/** True when the item carries link metadata (clickable card). */
|
|
139
|
+
declare function isLinkItem(item: VectorSceneItem): boolean;
|
|
140
|
+
/**
|
|
141
|
+
* Creates a clickable link/bookmark card item ready to append to the scene.
|
|
142
|
+
* The card resizes by scaling its authored SVG, like other custom shapes.
|
|
143
|
+
*/
|
|
144
|
+
declare function createLinkItem(id: string, bounds: Rect, link: CanvuLinkData): VectorSceneItem;
|
|
145
|
+
/** Default card size used when placing a new link without explicit bounds. */
|
|
146
|
+
declare const DEFAULT_LINK_CARD_SIZE: {
|
|
147
|
+
readonly width: 360;
|
|
148
|
+
readonly height: 132;
|
|
149
|
+
};
|
|
150
|
+
|
|
113
151
|
/** Resolved stroke for SVG generation. */
|
|
114
152
|
type StrokeStyle = {
|
|
115
153
|
stroke: string;
|
|
@@ -241,4 +279,4 @@ declare function createImageFromVectorTrace(id: string, bounds: Rect, imageVecto
|
|
|
241
279
|
height: number;
|
|
242
280
|
}): VectorSceneItem;
|
|
243
281
|
|
|
244
|
-
export {
|
|
282
|
+
export { rebuildItemSvg as A, resolveStrokeStyle as B, type CanvuLinkData as C, DEFAULT_LINK_CARD_SIZE as D, type VectorViewportAssetStore as E, type FreehandSvgPayload as F, type VectorViewportAssetHydrationRequest as G, type VectorViewportAssetResolveRequest as H, type VectorViewportAssetResolveResult as I, type VectorViewportAssetUploadRequest as J, type VectorViewportAssetUploadResult as K, LINK_PLUGIN_KEY as L, type StrokeStyle as S, type VectorViewportAssetKind as V, DEFAULT_STROKE_STYLE as a, applyStrokeToItem as b, buildArchitecturalCloudPathD as c, buildArchitecturalCloudSvg as d, buildArrowSvg as e, buildDrawDotSvg as f, buildEllipseSvg as g, buildFreehandPathSvg as h, buildLineSvg as i, buildLinkCardSvg as j, buildRectSvg as k, computeFreehandSvgPayload as l, createArchitecturalCloudItem as m, createDrawDotItem as n, createEllipseItem as o, createFreehandStrokeItem as p, createImageFromVectorTrace as q, createImageItem as r, createLineItem as s, createLinkItem as t, createRectangleItem as u, createShapeId as v, createTextItem as w, getLinkData as x, isLinkItem as y, lineEndpointsToLocal as z };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { V as VectorSceneItem,
|
|
1
|
+
import { V as VectorSceneItem, R as Rect, L as LineEndpointsLocal, b as VectorPathPoint, a as ArrowBindings } from './types-Bnq2HtHQ.cjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Kind of binary selected through the built-in canvu asset ingestion flow.
|
|
@@ -110,6 +110,44 @@ type VectorViewportAssetStore = {
|
|
|
110
110
|
getHydrationRequest?: (item: VectorSceneItem) => VectorViewportAssetHydrationRequest | null;
|
|
111
111
|
};
|
|
112
112
|
|
|
113
|
+
/** Plugin key under which link metadata is stored on a link item's `pluginData`. */
|
|
114
|
+
declare const LINK_PLUGIN_KEY = "canvuLink";
|
|
115
|
+
/**
|
|
116
|
+
* Metadata describing a clickable link/bookmark item.
|
|
117
|
+
* `href` is required; the rest enrich the rendered card (unfurl result).
|
|
118
|
+
*/
|
|
119
|
+
type CanvuLinkData = {
|
|
120
|
+
/** Absolute URL the card points to. */
|
|
121
|
+
href: string;
|
|
122
|
+
/** Human readable title (falls back to the hostname). */
|
|
123
|
+
title?: string;
|
|
124
|
+
/** Short description shown under the title. */
|
|
125
|
+
description?: string;
|
|
126
|
+
/** Preview image URL (og:image). */
|
|
127
|
+
image?: string;
|
|
128
|
+
/** Favicon URL shown in the leading badge. */
|
|
129
|
+
favicon?: string;
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Builds the inner SVG (no outer `<svg>`) for a link/bookmark card at the given box size.
|
|
133
|
+
* Uses fixed pixel bands so text never overlaps regardless of the card's aspect ratio.
|
|
134
|
+
*/
|
|
135
|
+
declare function buildLinkCardSvg(width: number, height: number, link: CanvuLinkData): string;
|
|
136
|
+
/** Reads the link metadata from an item, or `null` when the item is not a link. */
|
|
137
|
+
declare function getLinkData(item: VectorSceneItem): CanvuLinkData | null;
|
|
138
|
+
/** True when the item carries link metadata (clickable card). */
|
|
139
|
+
declare function isLinkItem(item: VectorSceneItem): boolean;
|
|
140
|
+
/**
|
|
141
|
+
* Creates a clickable link/bookmark card item ready to append to the scene.
|
|
142
|
+
* The card resizes by scaling its authored SVG, like other custom shapes.
|
|
143
|
+
*/
|
|
144
|
+
declare function createLinkItem(id: string, bounds: Rect, link: CanvuLinkData): VectorSceneItem;
|
|
145
|
+
/** Default card size used when placing a new link without explicit bounds. */
|
|
146
|
+
declare const DEFAULT_LINK_CARD_SIZE: {
|
|
147
|
+
readonly width: 360;
|
|
148
|
+
readonly height: 132;
|
|
149
|
+
};
|
|
150
|
+
|
|
113
151
|
/** Resolved stroke for SVG generation. */
|
|
114
152
|
type StrokeStyle = {
|
|
115
153
|
stroke: string;
|
|
@@ -241,4 +279,4 @@ declare function createImageFromVectorTrace(id: string, bounds: Rect, imageVecto
|
|
|
241
279
|
height: number;
|
|
242
280
|
}): VectorSceneItem;
|
|
243
281
|
|
|
244
|
-
export {
|
|
282
|
+
export { rebuildItemSvg as A, resolveStrokeStyle as B, type CanvuLinkData as C, DEFAULT_LINK_CARD_SIZE as D, type VectorViewportAssetStore as E, type FreehandSvgPayload as F, type VectorViewportAssetHydrationRequest as G, type VectorViewportAssetResolveRequest as H, type VectorViewportAssetResolveResult as I, type VectorViewportAssetUploadRequest as J, type VectorViewportAssetUploadResult as K, LINK_PLUGIN_KEY as L, type StrokeStyle as S, type VectorViewportAssetKind as V, DEFAULT_STROKE_STYLE as a, applyStrokeToItem as b, buildArchitecturalCloudPathD as c, buildArchitecturalCloudSvg as d, buildArrowSvg as e, buildDrawDotSvg as f, buildEllipseSvg as g, buildFreehandPathSvg as h, buildLineSvg as i, buildLinkCardSvg as j, buildRectSvg as k, computeFreehandSvgPayload as l, createArchitecturalCloudItem as m, createDrawDotItem as n, createEllipseItem as o, createFreehandStrokeItem as p, createImageFromVectorTrace as q, createImageItem as r, createLineItem as s, createLinkItem as t, createRectangleItem as u, createShapeId as v, createTextItem as w, getLinkData as x, isLinkItem as y, lineEndpointsToLocal as z };
|
package/dist/tldraw.cjs
CHANGED
|
@@ -50,11 +50,76 @@ 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;
|
|
@@ -158,9 +223,9 @@ function buildTextFixedBoundsSvg(content, width, height, fillColor = "#2563eb",
|
|
|
158
223
|
const lh = lineHeightFor(fontSize);
|
|
159
224
|
const trimmed = content.trim();
|
|
160
225
|
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: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">${
|
|
226
|
+
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>`;
|
|
162
227
|
}
|
|
163
|
-
const body =
|
|
228
|
+
const body = escapeHtmlText2(content);
|
|
164
229
|
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>`;
|
|
165
230
|
}
|
|
166
231
|
|
|
@@ -837,10 +902,10 @@ function resolveColor(value) {
|
|
|
837
902
|
function escapeXml(value) {
|
|
838
903
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
839
904
|
}
|
|
840
|
-
function
|
|
905
|
+
function escapeHtmlText3(value) {
|
|
841
906
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
842
907
|
}
|
|
843
|
-
function
|
|
908
|
+
function formatNumber2(value) {
|
|
844
909
|
if (!Number.isFinite(value)) return "0";
|
|
845
910
|
const rounded = Math.round(value * 100) / 100;
|
|
846
911
|
return Number.isInteger(rounded) ? String(rounded) : String(rounded);
|
|
@@ -892,13 +957,13 @@ function sizeToFontPx(size) {
|
|
|
892
957
|
function dashArrayForStyle(dash, strokeWidth) {
|
|
893
958
|
if (!dash || dash === "solid") return void 0;
|
|
894
959
|
if (dash === "dotted") {
|
|
895
|
-
return `${
|
|
960
|
+
return `${formatNumber2(Math.max(1.25, strokeWidth))} ${formatNumber2(Math.max(2.5, strokeWidth * 2.2))}`;
|
|
896
961
|
}
|
|
897
962
|
if (dash === "dashed") {
|
|
898
|
-
return `${
|
|
963
|
+
return `${formatNumber2(Math.max(5, strokeWidth * 4))} ${formatNumber2(Math.max(3, strokeWidth * 2.2))}`;
|
|
899
964
|
}
|
|
900
965
|
if (dash === "draw") {
|
|
901
|
-
return `${
|
|
966
|
+
return `${formatNumber2(Math.max(3, strokeWidth * 2.4))} ${formatNumber2(Math.max(2.4, strokeWidth * 1.6))}`;
|
|
902
967
|
}
|
|
903
968
|
return dash;
|
|
904
969
|
}
|
|
@@ -914,11 +979,11 @@ function strokeAttrs(style) {
|
|
|
914
979
|
const dashAttr = dashArray ? ` stroke-dasharray="${dashArray}"` : "";
|
|
915
980
|
const lineCap = style.lineCap ? ` stroke-linecap="${style.lineCap}"` : "";
|
|
916
981
|
const lineJoin = style.lineJoin ? ` stroke-linejoin="${style.lineJoin}"` : "";
|
|
917
|
-
return `stroke="${style.stroke}" stroke-width="${
|
|
982
|
+
return `stroke="${style.stroke}" stroke-width="${formatNumber2(style.strokeWidth)}"${dashAttr}${lineCap}${lineJoin}`;
|
|
918
983
|
}
|
|
919
984
|
function wrapOpacity(svg, opacity) {
|
|
920
985
|
if (opacity >= 0.999) return svg;
|
|
921
|
-
return `<g opacity="${
|
|
986
|
+
return `<g opacity="${formatNumber2(opacity)}">${svg}</g>`;
|
|
922
987
|
}
|
|
923
988
|
function buildForeignObjectTextSvg(options) {
|
|
924
989
|
const x = options.x ?? 0;
|
|
@@ -933,8 +998,8 @@ function buildForeignObjectTextSvg(options) {
|
|
|
933
998
|
const weight = options.fontWeight != null ? `font-weight:${options.fontWeight};` : "";
|
|
934
999
|
const fontStyle = options.italic ? "font-style:italic;" : "";
|
|
935
1000
|
const background = options.background ? `background:${options.background};` : "";
|
|
936
|
-
const radius = options.borderRadius != null ? `border-radius:${
|
|
937
|
-
return `<foreignObject x="${
|
|
1001
|
+
const radius = options.borderRadius != null ? `border-radius:${formatNumber2(options.borderRadius)}px;` : "";
|
|
1002
|
+
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
1003
|
}
|
|
939
1004
|
function richTextToPlainText(value) {
|
|
940
1005
|
const parts = [];
|
|
@@ -1462,17 +1527,17 @@ function createCustomImportedItem(snapshot, shape, localBounds, innerSvg, style)
|
|
|
1462
1527
|
}
|
|
1463
1528
|
function polygonPath(points) {
|
|
1464
1529
|
if (points.length === 0) return "";
|
|
1465
|
-
let path = `M${
|
|
1530
|
+
let path = `M${formatNumber2(points[0]?.x ?? 0)} ${formatNumber2(points[0]?.y ?? 0)}`;
|
|
1466
1531
|
for (let index = 1; index < points.length; index++) {
|
|
1467
1532
|
const point = points[index];
|
|
1468
1533
|
if (!point) continue;
|
|
1469
|
-
path += ` L${
|
|
1534
|
+
path += ` L${formatNumber2(point.x)} ${formatNumber2(point.y)}`;
|
|
1470
1535
|
}
|
|
1471
1536
|
return `${path} Z`;
|
|
1472
1537
|
}
|
|
1473
1538
|
function cloudPath(width, height) {
|
|
1474
1539
|
const r = Math.min(width, height) * 0.15;
|
|
1475
|
-
return `M${
|
|
1540
|
+
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
1541
|
}
|
|
1477
1542
|
function geoPath(geo, width, height) {
|
|
1478
1543
|
if (geo === "diamond" || geo === "rhombus") {
|
|
@@ -1551,10 +1616,10 @@ function geoPath(geo, width, height) {
|
|
|
1551
1616
|
]);
|
|
1552
1617
|
}
|
|
1553
1618
|
if (geo === "check-box") {
|
|
1554
|
-
return `M0 0 H${
|
|
1619
|
+
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
1620
|
}
|
|
1556
1621
|
if (geo === "x-box") {
|
|
1557
|
-
return `M0 0 H${
|
|
1622
|
+
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
1623
|
}
|
|
1559
1624
|
return null;
|
|
1560
1625
|
}
|
|
@@ -1570,7 +1635,7 @@ function renderGeoShape(snapshot, shape) {
|
|
|
1570
1635
|
const text = extractPlainText(props);
|
|
1571
1636
|
const fontSize = getNumber(props.fontSize) ?? sizeToFontPx(getString(props.size));
|
|
1572
1637
|
const customPath = geoPath(geo, width, height);
|
|
1573
|
-
const shapeMarkup = geo === "ellipse" || geo === "oval" ? `<ellipse cx="${
|
|
1638
|
+
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
1639
|
const textMarkup = text ? buildForeignObjectTextSvg({
|
|
1575
1640
|
width,
|
|
1576
1641
|
height,
|
|
@@ -1655,11 +1720,11 @@ function renderStrokeShape(snapshot, shape) {
|
|
|
1655
1720
|
}
|
|
1656
1721
|
function polylinePath(points) {
|
|
1657
1722
|
if (points.length === 0) return "";
|
|
1658
|
-
let path = `M${
|
|
1723
|
+
let path = `M${formatNumber2(points[0]?.x ?? 0)} ${formatNumber2(points[0]?.y ?? 0)}`;
|
|
1659
1724
|
for (let index = 1; index < points.length; index++) {
|
|
1660
1725
|
const point = points[index];
|
|
1661
1726
|
if (!point) continue;
|
|
1662
|
-
path += ` L${
|
|
1727
|
+
path += ` L${formatNumber2(point.x)} ${formatNumber2(point.y)}`;
|
|
1663
1728
|
}
|
|
1664
1729
|
return path;
|
|
1665
1730
|
}
|
|
@@ -1681,22 +1746,22 @@ function buildArrowHeadSvg(options) {
|
|
|
1681
1746
|
const left = { x: bx + px * (headWidth / 2), y: by + py * (headWidth / 2) };
|
|
1682
1747
|
const right = { x: bx - px * (headWidth / 2), y: by - py * (headWidth / 2) };
|
|
1683
1748
|
if (type === "triangle") {
|
|
1684
|
-
return `<polygon points="${
|
|
1749
|
+
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
1750
|
}
|
|
1686
1751
|
if (type === "dot") {
|
|
1687
|
-
return `<circle cx="${
|
|
1752
|
+
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
1753
|
}
|
|
1689
1754
|
if (type === "diamond") {
|
|
1690
1755
|
const mid = {
|
|
1691
1756
|
x: options.tip.x - ux * (headLength / 2),
|
|
1692
1757
|
y: options.tip.y - uy * (headLength / 2)
|
|
1693
1758
|
};
|
|
1694
|
-
return `<polygon points="${
|
|
1759
|
+
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
1760
|
}
|
|
1696
1761
|
if (type === "bar") {
|
|
1697
|
-
return `<line x1="${
|
|
1762
|
+
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
1763
|
}
|
|
1699
|
-
return `<path d="M ${
|
|
1764
|
+
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
1765
|
}
|
|
1701
1766
|
function renderLineShape(snapshot, shape) {
|
|
1702
1767
|
const props = asRecord(shape.props) ?? {};
|
|
@@ -1765,7 +1830,7 @@ function renderArrowShape(snapshot, shape) {
|
|
|
1765
1830
|
const translatedPoints = route.points.map(translate);
|
|
1766
1831
|
const translatedStartRef = translate(route.startRef);
|
|
1767
1832
|
const translatedEndRef = translate(route.endRef);
|
|
1768
|
-
const shaft = route.kind === "quadratic" && route.control ? `<path d="M${
|
|
1833
|
+
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
1834
|
const startPoint = translatedPoints[0];
|
|
1770
1835
|
const endPoint = translatedPoints[translatedPoints.length - 1];
|
|
1771
1836
|
if (!startPoint || !endPoint) return null;
|
|
@@ -1797,9 +1862,9 @@ function renderMissingAssetPlaceholder(snapshot, shape, kind, detail) {
|
|
|
1797
1862
|
const width = localBounds.width;
|
|
1798
1863
|
const height = localBounds.height;
|
|
1799
1864
|
const inner = `
|
|
1800
|
-
<rect width="${
|
|
1801
|
-
<path d="M${
|
|
1802
|
-
<circle cx="${
|
|
1865
|
+
<rect width="${formatNumber2(width)}" height="${formatNumber2(height)}" rx="12" fill="#f4f4f5" stroke="#a1a1aa" stroke-width="1.5" stroke-dasharray="6 6" />
|
|
1866
|
+
<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" />
|
|
1867
|
+
<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
1868
|
${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
1869
|
${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
1870
|
`;
|
|
@@ -1853,10 +1918,10 @@ function renderVideoShape(snapshot, shape) {
|
|
|
1853
1918
|
const label = getString(asRecord(asset?.props)?.name) ?? "Video";
|
|
1854
1919
|
const subtitle = src ?? getString(props.assetId) ?? "Playback not supported in this importer";
|
|
1855
1920
|
const inner = `
|
|
1856
|
-
<rect width="${
|
|
1857
|
-
<rect x="${
|
|
1858
|
-
<circle cx="${
|
|
1859
|
-
<polygon points="${
|
|
1921
|
+
<rect width="${formatNumber2(width)}" height="${formatNumber2(height)}" rx="14" fill="#18181b" stroke="#3f3f46" stroke-width="1.5" />
|
|
1922
|
+
<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" />
|
|
1923
|
+
<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" />
|
|
1924
|
+
<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
1925
|
${buildForeignObjectTextSvg({ x: 16, y: height * 0.76, width: width - 32, height: height * 0.12, text: label, fontSize: 15, color: "#fafafa", fontWeight: 700 })}
|
|
1861
1926
|
${buildForeignObjectTextSvg({ x: 16, y: height * 0.88, width: width - 32, height: height * 0.08, text: subtitle, fontSize: 11, color: "#d4d4d8" })}
|
|
1862
1927
|
`;
|
|
@@ -1882,8 +1947,8 @@ function renderNoteShape(snapshot, shape) {
|
|
|
1882
1947
|
const fold = Math.min(width, height) * 0.14;
|
|
1883
1948
|
const fontSize = sizeToFontPx(getString(props.size)) + numberOr(props.fontSizeAdjustment, 0);
|
|
1884
1949
|
const inner = `
|
|
1885
|
-
<path d="M0 0 H${
|
|
1886
|
-
<path d="M${
|
|
1950
|
+
<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" />
|
|
1951
|
+
<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
1952
|
${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
1953
|
`;
|
|
1889
1954
|
return createCustomImportedItem(
|
|
@@ -1899,31 +1964,35 @@ function renderNoteShape(snapshot, shape) {
|
|
|
1899
1964
|
}
|
|
1900
1965
|
function renderBookmarkShape(snapshot, shape) {
|
|
1901
1966
|
const props = asRecord(shape.props) ?? {};
|
|
1967
|
+
const asset = resolveAsset(snapshot, shape);
|
|
1968
|
+
const assetProps = asRecord(asset?.props) ?? {};
|
|
1902
1969
|
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(
|
|
1970
|
+
const href = getString(props.url) ?? getString(assetProps.src) ?? getString(props.src) ?? "";
|
|
1971
|
+
const title = getString(assetProps.title) ?? getString(props.title) ?? getString(props.label) ?? void 0;
|
|
1972
|
+
const description = getString(assetProps.description) ?? getString(props.description) ?? void 0;
|
|
1973
|
+
const image = getString(assetProps.image) ?? getString(props.image) ?? void 0;
|
|
1974
|
+
const favicon = getString(assetProps.favicon) ?? getString(props.favicon) ?? void 0;
|
|
1975
|
+
const link = {
|
|
1976
|
+
href: href || "URL unavailable",
|
|
1977
|
+
...title ? { title } : {},
|
|
1978
|
+
...description ? { description } : {},
|
|
1979
|
+
...image ? { image } : {},
|
|
1980
|
+
...favicon ? { favicon } : {}
|
|
1981
|
+
};
|
|
1982
|
+
const inner = buildLinkCardSvg(localBounds.width, localBounds.height, link);
|
|
1983
|
+
const item = createCustomImportedItem(
|
|
1918
1984
|
snapshot,
|
|
1919
1985
|
shape,
|
|
1920
1986
|
localBounds,
|
|
1921
|
-
wrapOpacity(inner, shapeOpacity(shape))
|
|
1922
|
-
{
|
|
1923
|
-
stroke,
|
|
1924
|
-
strokeWidth: 1.5
|
|
1925
|
-
}
|
|
1987
|
+
wrapOpacity(inner, shapeOpacity(shape))
|
|
1926
1988
|
);
|
|
1989
|
+
return {
|
|
1990
|
+
...item,
|
|
1991
|
+
pluginData: {
|
|
1992
|
+
...item.pluginData ?? {},
|
|
1993
|
+
[LINK_PLUGIN_KEY]: link
|
|
1994
|
+
}
|
|
1995
|
+
};
|
|
1927
1996
|
}
|
|
1928
1997
|
function renderEmbedShape(snapshot, shape) {
|
|
1929
1998
|
const props = asRecord(shape.props) ?? {};
|
|
@@ -1934,11 +2003,11 @@ function renderEmbedShape(snapshot, shape) {
|
|
|
1934
2003
|
const title = getString(props.title) ?? getString(props.embedTitle) ?? "Embed";
|
|
1935
2004
|
const url = getString(props.url) ?? getString(props.src) ?? "Embedded content";
|
|
1936
2005
|
const inner = `
|
|
1937
|
-
<rect width="${
|
|
1938
|
-
<rect x="16" y="16" width="${
|
|
1939
|
-
<circle cx="${
|
|
1940
|
-
<circle cx="${
|
|
1941
|
-
<circle cx="${
|
|
2006
|
+
<rect width="${formatNumber2(width)}" height="${formatNumber2(height)}" rx="16" fill="#0f172a" stroke="${stroke}" stroke-width="1.5" />
|
|
2007
|
+
<rect x="16" y="16" width="${formatNumber2(width - 32)}" height="${formatNumber2(height * 0.62)}" rx="12" fill="#111827" stroke="#334155" stroke-width="1" />
|
|
2008
|
+
<circle cx="${formatNumber2(width * 0.14)}" cy="${formatNumber2(height * 0.14)}" r="5" fill="#ef4444" />
|
|
2009
|
+
<circle cx="${formatNumber2(width * 0.18)}" cy="${formatNumber2(height * 0.14)}" r="5" fill="#f59e0b" />
|
|
2010
|
+
<circle cx="${formatNumber2(width * 0.22)}" cy="${formatNumber2(height * 0.14)}" r="5" fill="#22c55e" />
|
|
1942
2011
|
${buildForeignObjectTextSvg({ x: 18, y: height * 0.72, width: width - 36, height: height * 0.11, text: title, fontSize: 16, color: "#f8fafc", fontWeight: 700 })}
|
|
1943
2012
|
${buildForeignObjectTextSvg({ x: 18, y: height * 0.84, width: width - 36, height: height * 0.08, text: url, fontSize: 11, color: "#cbd5e1" })}
|
|
1944
2013
|
`;
|
|
@@ -1961,8 +2030,8 @@ function renderFrameShape(snapshot, shape) {
|
|
|
1961
2030
|
const stroke = shapeStrokeColor(shape);
|
|
1962
2031
|
const title = (getString(props.name) ?? getString(props.title) ?? extractPlainText(props)) || "Frame";
|
|
1963
2032
|
const inner = `
|
|
1964
|
-
<rect width="${
|
|
1965
|
-
<rect x="12" y="10" width="${
|
|
2033
|
+
<rect width="${formatNumber2(width)}" height="${formatNumber2(height)}" rx="14" fill="none" stroke="${stroke}" stroke-width="2" stroke-dasharray="10 6" />
|
|
2034
|
+
<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
2035
|
${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
2036
|
`;
|
|
1968
2037
|
return createCustomImportedItem(
|
|
@@ -1985,8 +2054,8 @@ function renderAnnotationShape(snapshot, shape) {
|
|
|
1985
2054
|
const fill = shape.type === "annotationBubble" ? "#3b82f6" : resolveColor(getString(props.color) ?? "#ef4444");
|
|
1986
2055
|
const text = shape.type === "label" ? extractPlainText(props) : String(getNumber(props.number) ?? "");
|
|
1987
2056
|
const inner = `
|
|
1988
|
-
<circle cx="${
|
|
1989
|
-
<text x="${
|
|
2057
|
+
<circle cx="${formatNumber2(width / 2)}" cy="${formatNumber2(height / 2)}" r="${formatNumber2(radius)}" fill="${fill}" stroke="#ffffff" stroke-width="2" />
|
|
2058
|
+
<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
2059
|
`;
|
|
1991
2060
|
return createCustomImportedItem(
|
|
1992
2061
|
snapshot,
|
|
@@ -2006,7 +2075,7 @@ function renderUnsupportedShape(snapshot, shape, reason) {
|
|
|
2006
2075
|
const width = localBounds.width;
|
|
2007
2076
|
const height = localBounds.height;
|
|
2008
2077
|
const inner = `
|
|
2009
|
-
<rect width="${
|
|
2078
|
+
<rect width="${formatNumber2(width)}" height="${formatNumber2(height)}" rx="12" fill="#fafafa" stroke="#a1a1aa" stroke-width="1.5" stroke-dasharray="6 6" />
|
|
2010
2079
|
${buildForeignObjectTextSvg({ x: 12, y: 14, width: width - 24, height: 28, text: shape.type, fontSize: 14, color: "#111827", fontWeight: 700, verticalAlign: "middle" })}
|
|
2011
2080
|
${buildForeignObjectTextSvg({ x: 12, y: 50, width: width - 24, height: Math.max(20, height - 62), text: reason, fontSize: 12, color: "#52525b" })}
|
|
2012
2081
|
`;
|