canvu-react 0.4.31 → 0.4.32
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-CWhld14A.d.cts → asset-hydration-BFGZ3igr.d.cts} +1 -1
- package/dist/{asset-hydration-D35mHbUP.d.ts → asset-hydration-D6Q3TJL1.d.ts} +1 -1
- package/dist/chatbot.d.cts +2 -2
- package/dist/chatbot.d.ts +2 -2
- package/dist/index.cjs +182 -102
- 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 +182 -102
- package/dist/index.js.map +1 -1
- package/dist/{link-item-D870_X6P.d.cts → link-item-Dncuz2d_.d.cts} +3 -3
- package/dist/{link-item-Bg5vj0RI.d.ts → link-item-voRU0Up9.d.ts} +3 -3
- package/dist/native.cjs +229 -3
- package/dist/native.cjs.map +1 -1
- package/dist/native.js +229 -3
- package/dist/native.js.map +1 -1
- package/dist/react.cjs +253 -18
- 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 +253 -18
- package/dist/react.js.map +1 -1
- package/dist/realtime.cjs.map +1 -1
- package/dist/realtime.d.cts +3 -3
- package/dist/realtime.d.ts +3 -3
- package/dist/realtime.js.map +1 -1
- package/dist/tldraw.cjs +129 -38
- package/dist/tldraw.cjs.map +1 -1
- package/dist/tldraw.js +129 -38
- package/dist/tldraw.js.map +1 -1
- package/dist/{types-Bw1SdC9v.d.cts → types-BS-YG8Hx.d.cts} +1 -1
- package/dist/{types-DeXFfs7Y.d.ts → types-UZYYwK-v.d.ts} +1 -1
- package/package.json +1 -1
package/dist/react.cjs
CHANGED
|
@@ -56,11 +56,170 @@ var init_custom_shape = __esm({
|
|
|
56
56
|
}
|
|
57
57
|
});
|
|
58
58
|
|
|
59
|
+
// src/scene/link-item.ts
|
|
60
|
+
function buildLinkCardSvg(width, _height, link) {
|
|
61
|
+
const cardWidth = Math.max(1, width);
|
|
62
|
+
const scale = cardWidth / DEFAULT_LINK_CARD_WIDTH;
|
|
63
|
+
const contentWidth = DEFAULT_LINK_CARD_WIDTH;
|
|
64
|
+
const contentHeight = DEFAULT_LINK_CARD_HEIGHT;
|
|
65
|
+
const padding = 14;
|
|
66
|
+
const badgeSize = 42;
|
|
67
|
+
const gap = 13;
|
|
68
|
+
const buttonSize = 34;
|
|
69
|
+
const textX = padding + badgeSize + gap;
|
|
70
|
+
const textWidth = Math.max(1, contentWidth - textX - buttonSize - gap - padding);
|
|
71
|
+
const hostname = getLinkHostname(link.href);
|
|
72
|
+
const title = link.title?.trim() || hostname || "Link";
|
|
73
|
+
const protocol = getLinkProtocol(link.href);
|
|
74
|
+
const subtitle = hostname || link.href;
|
|
75
|
+
const favicon = link.favicon?.trim() || buildGoogleFaviconUrl(hostname);
|
|
76
|
+
const idSuffix = getStableLinkIdSuffix(`${hostname}:${link.href}`);
|
|
77
|
+
const clipId = `canvu-link-favicon-${idSuffix}`;
|
|
78
|
+
const gradientId = `canvu-link-favicon-gradient-${idSuffix}`;
|
|
79
|
+
const buttonX = contentWidth - padding - buttonSize;
|
|
80
|
+
const buttonY = (contentHeight - buttonSize) / 2;
|
|
81
|
+
const isSecure = protocol === "https:";
|
|
82
|
+
const subtitleX = isSecure ? textX + 13 : textX;
|
|
83
|
+
const subtitleWidth = isSecure ? textWidth - 13 : textWidth;
|
|
84
|
+
const faviconImage = favicon ? `<image class="canvu-link-favicon-img" href="${escapeXmlAttribute(favicon)}" x="${formatNumber(padding)}" y="${formatNumber(padding)}" width="${formatNumber(badgeSize)}" height="${formatNumber(badgeSize)}" preserveAspectRatio="xMidYMid slice" clip-path="url(#${clipId})" />` : "";
|
|
85
|
+
return `
|
|
86
|
+
<style>
|
|
87
|
+
.canvu-link-card-root .canvu-link-card { transition: transform .18s ease, filter .18s ease, stroke .18s ease; }
|
|
88
|
+
.canvu-link-card-root .canvu-link-open { opacity: 0; transform: translateX(-4px); transition: opacity .18s ease, transform .18s ease; }
|
|
89
|
+
.canvu-link-card-root:hover .canvu-link-card { transform: translateY(-2px); filter: drop-shadow(0 4px 14px oklch(0.4 0.05 265 / .08)) drop-shadow(0 1px 3px oklch(0.4 0.05 265 / .06)); stroke: ${LINK_CARD_BORDER_STRONG}; }
|
|
90
|
+
.canvu-link-card-root:hover .canvu-link-open { opacity: 1; transform: translateX(0); }
|
|
91
|
+
</style>
|
|
92
|
+
<g class="canvu-link-card-root" transform="scale(${formatNumber(scale)})">
|
|
93
|
+
<rect class="canvu-link-card" width="${formatNumber(contentWidth)}" height="${formatNumber(contentHeight)}" rx="16" fill="#ffffff" stroke="${LINK_CARD_BORDER}" stroke-width="1" filter="drop-shadow(0 1px 2px oklch(0.4 0.03 265 / .05)) drop-shadow(0 1px 1px oklch(0.4 0.03 265 / .04))" />
|
|
94
|
+
<defs>
|
|
95
|
+
<linearGradient id="${gradientId}" x1="8" y1="48" x2="48" y2="8" gradientUnits="userSpaceOnUse">
|
|
96
|
+
<stop stop-color="${LINK_CARD_ACCENT}" />
|
|
97
|
+
<stop offset="1" stop-color="${LINK_CARD_ACCENT_DEEP}" />
|
|
98
|
+
</linearGradient>
|
|
99
|
+
<clipPath id="${clipId}">
|
|
100
|
+
<rect x="${formatNumber(padding)}" y="${formatNumber(padding)}" width="${formatNumber(badgeSize)}" height="${formatNumber(badgeSize)}" rx="11" />
|
|
101
|
+
</clipPath>
|
|
102
|
+
</defs>
|
|
103
|
+
<rect x="${formatNumber(padding)}" y="${formatNumber(padding)}" width="${formatNumber(badgeSize)}" height="${formatNumber(badgeSize)}" rx="11" fill="url(#${gradientId})" />
|
|
104
|
+
<text x="${formatNumber(padding + badgeSize / 2)}" y="${formatNumber(padding + badgeSize / 2 + 5)}" text-anchor="middle" font-family="system-ui,sans-serif" font-size="17" font-weight="700" fill="#ffffff">${escapeHtmlText(getLinkInitial(hostname))}</text>
|
|
105
|
+
${faviconImage}
|
|
106
|
+
${buildLinkTextBand({ x: textX, y: 16, width: textWidth, height: 19, text: title, fontSize: 14.5, color: LINK_CARD_TITLE_COLOR, fontWeight: 700 })}
|
|
107
|
+
${isSecure ? `<g transform="translate(${formatNumber(textX)},40)" stroke="${LINK_CARD_TEXT_COLOR}" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" fill="none"><rect x="1.5" y="4.5" width="7" height="6" rx="1" /><path d="M3 4.5 V3 a2 2 0 0 1 4 0 v1.5" /></g>` : ""}
|
|
108
|
+
${buildLinkTextBand({ x: subtitleX, y: 36, width: subtitleWidth, height: 17, text: subtitle, fontSize: 12.5, color: LINK_CARD_TEXT_COLOR })}
|
|
109
|
+
<g class="canvu-link-open" transform="translate(${formatNumber(buttonX)},${formatNumber(buttonY)})">
|
|
110
|
+
<rect width="${formatNumber(buttonSize)}" height="${formatNumber(buttonSize)}" rx="10" fill="#ffffff" stroke="${LINK_CARD_BORDER}" stroke-width="1" />
|
|
111
|
+
<g transform="translate(10,10)" stroke="${LINK_CARD_TEXT_COLOR}" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" fill="none">
|
|
112
|
+
<path d="M8 2 H14 V8" />
|
|
113
|
+
<path d="M14 2 L7 9" />
|
|
114
|
+
<path d="M12 10 V13 a1 1 0 0 1 -1 1 H3 a1 1 0 0 1 -1 -1 V5 a1 1 0 0 1 1 -1 H6" />
|
|
115
|
+
</g>
|
|
116
|
+
</g>
|
|
117
|
+
</g>
|
|
118
|
+
`;
|
|
119
|
+
}
|
|
120
|
+
function getLinkData(item) {
|
|
121
|
+
const entry = item.pluginData?.[LINK_PLUGIN_KEY];
|
|
122
|
+
return isCanvuLinkData(entry) ? entry : null;
|
|
123
|
+
}
|
|
124
|
+
function rebuildLinkItemSvg(item) {
|
|
125
|
+
const link = getLinkData(item);
|
|
126
|
+
if (!link) return item;
|
|
127
|
+
const scale = clamp(
|
|
128
|
+
item.bounds.width / DEFAULT_LINK_CARD_WIDTH,
|
|
129
|
+
LINK_CARD_MIN_SCALE,
|
|
130
|
+
LINK_CARD_MAX_SCALE
|
|
131
|
+
);
|
|
132
|
+
const width = DEFAULT_LINK_CARD_WIDTH * scale;
|
|
133
|
+
const height = DEFAULT_LINK_CARD_HEIGHT * scale;
|
|
134
|
+
const bounds = {
|
|
135
|
+
...item.bounds,
|
|
136
|
+
width,
|
|
137
|
+
height
|
|
138
|
+
};
|
|
139
|
+
const customInnerSvg = buildLinkCardSvg(
|
|
140
|
+
DEFAULT_LINK_CARD_WIDTH,
|
|
141
|
+
DEFAULT_LINK_CARD_HEIGHT,
|
|
142
|
+
link
|
|
143
|
+
);
|
|
144
|
+
return {
|
|
145
|
+
...item,
|
|
146
|
+
x: bounds.x,
|
|
147
|
+
y: bounds.y,
|
|
148
|
+
bounds,
|
|
149
|
+
customIntrinsicSize: {
|
|
150
|
+
width: DEFAULT_LINK_CARD_WIDTH,
|
|
151
|
+
height: DEFAULT_LINK_CARD_HEIGHT
|
|
152
|
+
},
|
|
153
|
+
customInnerSvg,
|
|
154
|
+
childrenSvg: buildLinkCardSvg(width, height, link)
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
var LINK_PLUGIN_KEY, DEFAULT_LINK_CARD_WIDTH, DEFAULT_LINK_CARD_HEIGHT, LINK_CARD_MIN_SCALE, LINK_CARD_MAX_SCALE, LINK_CARD_ASPECT, LINK_CARD_BORDER, LINK_CARD_BORDER_STRONG, LINK_CARD_ACCENT, LINK_CARD_ACCENT_DEEP, LINK_CARD_TITLE_COLOR, LINK_CARD_TEXT_COLOR, clamp, formatNumber, escapeXmlAttribute, escapeHtmlText, getLinkHostname, buildLinkTextBand, getLinkProtocol, getLinkInitial, buildGoogleFaviconUrl, getStableLinkIdSuffix, isCanvuLinkData;
|
|
158
|
+
var init_link_item = __esm({
|
|
159
|
+
"src/scene/link-item.ts"() {
|
|
160
|
+
LINK_PLUGIN_KEY = "canvuLink";
|
|
161
|
+
DEFAULT_LINK_CARD_WIDTH = 320;
|
|
162
|
+
DEFAULT_LINK_CARD_HEIGHT = 70;
|
|
163
|
+
LINK_CARD_MIN_SCALE = 0.6;
|
|
164
|
+
LINK_CARD_MAX_SCALE = 2.5;
|
|
165
|
+
LINK_CARD_ASPECT = DEFAULT_LINK_CARD_WIDTH / DEFAULT_LINK_CARD_HEIGHT;
|
|
166
|
+
LINK_CARD_BORDER = "oklch(0.918 0.008 255)";
|
|
167
|
+
LINK_CARD_BORDER_STRONG = "oklch(0.86 0.012 255)";
|
|
168
|
+
LINK_CARD_ACCENT = "oklch(0.55 0.19 264)";
|
|
169
|
+
LINK_CARD_ACCENT_DEEP = "oklch(0.46 0.18 264)";
|
|
170
|
+
LINK_CARD_TITLE_COLOR = "oklch(0.26 0.022 265)";
|
|
171
|
+
LINK_CARD_TEXT_COLOR = "oklch(0.55 0.022 265)";
|
|
172
|
+
clamp = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
173
|
+
formatNumber = (value) => {
|
|
174
|
+
const rounded = Math.round(value * 100) / 100;
|
|
175
|
+
return Object.is(rounded, -0) ? "0" : String(rounded);
|
|
176
|
+
};
|
|
177
|
+
escapeXmlAttribute = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
178
|
+
escapeHtmlText = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
179
|
+
getLinkHostname = (href) => {
|
|
180
|
+
try {
|
|
181
|
+
return new URL(href).hostname.replace(/^www\./, "");
|
|
182
|
+
} catch {
|
|
183
|
+
return href;
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
buildLinkTextBand = (band) => {
|
|
187
|
+
const lineHeight = band.height;
|
|
188
|
+
const weight = band.fontWeight != null ? `font-weight:${band.fontWeight};` : "";
|
|
189
|
+
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;letter-spacing:-0.01em;color:${band.color};overflow:hidden;white-space:nowrap;text-overflow:ellipsis;${weight}">${escapeHtmlText(band.text)}</div></foreignObject>`;
|
|
190
|
+
};
|
|
191
|
+
getLinkProtocol = (href) => {
|
|
192
|
+
try {
|
|
193
|
+
return new URL(href).protocol;
|
|
194
|
+
} catch {
|
|
195
|
+
return "";
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
getLinkInitial = (hostname) => {
|
|
199
|
+
const first = hostname.trim().charAt(0).toUpperCase();
|
|
200
|
+
return first || "L";
|
|
201
|
+
};
|
|
202
|
+
buildGoogleFaviconUrl = (hostname) => hostname ? `https://www.google.com/s2/favicons?domain=${encodeURIComponent(hostname)}&sz=64` : null;
|
|
203
|
+
getStableLinkIdSuffix = (value) => {
|
|
204
|
+
let hash = 0;
|
|
205
|
+
for (const char of value) {
|
|
206
|
+
hash = hash * 31 + char.charCodeAt(0) >>> 0;
|
|
207
|
+
}
|
|
208
|
+
return hash.toString(36);
|
|
209
|
+
};
|
|
210
|
+
isCanvuLinkData = (value) => {
|
|
211
|
+
if (!value || typeof value !== "object") return false;
|
|
212
|
+
const candidate = value;
|
|
213
|
+
return typeof candidate.href === "string" && candidate.href.length > 0;
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
59
218
|
// src/scene/text-svg.ts
|
|
60
219
|
function escapeSvgTextContent(s) {
|
|
61
220
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
62
221
|
}
|
|
63
|
-
function
|
|
222
|
+
function escapeHtmlText2(s) {
|
|
64
223
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
65
224
|
}
|
|
66
225
|
function getSharedMeasureContext() {
|
|
@@ -161,9 +320,9 @@ function buildTextFixedBoundsSvg(content, width, height, fillColor = "#1d1d1d",
|
|
|
161
320
|
const trimmed = content.trim();
|
|
162
321
|
const padTop = EDIT_TOP_PAD_RATIO * fontSize;
|
|
163
322
|
if (trimmed.length === 0) {
|
|
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:${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">${
|
|
323
|
+
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>`;
|
|
165
324
|
}
|
|
166
|
-
const body =
|
|
325
|
+
const body = escapeHtmlText2(content);
|
|
167
326
|
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>`;
|
|
168
327
|
}
|
|
169
328
|
var DEFAULT_TEXT_FONT_SIZE, DEFAULT_TEXT_TOOL_FONT_SIZE, TEXT_FONT_FAMILY, LINE_HEIGHT_RATIO, FIRST_LINE_BASELINE_RATIO, EDIT_TOP_PAD_RATIO, BOTTOM_PAD_RATIO, PLACEHOLDER, MIN_TEXT_BOX_W, MIN_TEXT_BOX_H, TEXT_PAD_X, MAX_TEXT_MEASURE_CACHE_ENTRIES, sharedMeasureContext, textMeasureCache;
|
|
@@ -820,6 +979,9 @@ function rebuildItemSvg(item) {
|
|
|
820
979
|
)
|
|
821
980
|
};
|
|
822
981
|
}
|
|
982
|
+
if (getLinkData(item)) {
|
|
983
|
+
return rebuildLinkItemSvg(item);
|
|
984
|
+
}
|
|
823
985
|
if (k === "custom" && item.customIntrinsicSize && item.customInnerSvg) {
|
|
824
986
|
const b = normalizeRect(item.bounds);
|
|
825
987
|
return {
|
|
@@ -1045,6 +1207,7 @@ var init_shape_builders = __esm({
|
|
|
1045
1207
|
"src/scene/shape-builders.ts"() {
|
|
1046
1208
|
init_rect();
|
|
1047
1209
|
init_custom_shape();
|
|
1210
|
+
init_link_item();
|
|
1048
1211
|
init_text_svg();
|
|
1049
1212
|
DEFAULT_STROKE_STYLE = {
|
|
1050
1213
|
stroke: "#1d1d1d",
|
|
@@ -6362,10 +6525,80 @@ function collectEraserTargetsAtWorldPoint(items, worldX, worldY, options) {
|
|
|
6362
6525
|
|
|
6363
6526
|
// src/interaction/mutations.ts
|
|
6364
6527
|
init_rect();
|
|
6528
|
+
init_link_item();
|
|
6365
6529
|
init_shape_builders();
|
|
6366
6530
|
init_text_svg();
|
|
6531
|
+
var LINK_CORNER_HANDLES = /* @__PURE__ */ new Set(["nw", "ne", "se", "sw"]);
|
|
6532
|
+
var clamp2 = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
6533
|
+
var clampLinkResizeBounds = (startBounds, nextBounds, handle, intrinsicWidth) => {
|
|
6534
|
+
const next = normalizeRect(nextBounds);
|
|
6535
|
+
const scale = clamp2(
|
|
6536
|
+
next.width / Math.max(1e-9, intrinsicWidth),
|
|
6537
|
+
LINK_CARD_MIN_SCALE,
|
|
6538
|
+
LINK_CARD_MAX_SCALE
|
|
6539
|
+
);
|
|
6540
|
+
const width = intrinsicWidth * scale;
|
|
6541
|
+
const height = width / LINK_CARD_ASPECT;
|
|
6542
|
+
const start = normalizeRect(startBounds);
|
|
6543
|
+
const x0 = start.x;
|
|
6544
|
+
const y0 = start.y;
|
|
6545
|
+
const x1 = start.x + start.width;
|
|
6546
|
+
const y1 = start.y + start.height;
|
|
6547
|
+
switch (handle) {
|
|
6548
|
+
case "nw":
|
|
6549
|
+
return { x: x1 - width, y: y1 - height, width, height };
|
|
6550
|
+
case "ne":
|
|
6551
|
+
return { x: x0, y: y1 - height, width, height };
|
|
6552
|
+
case "sw":
|
|
6553
|
+
return { x: x1 - width, y: y0, width, height };
|
|
6554
|
+
default:
|
|
6555
|
+
return { x: x0, y: y0, width, height };
|
|
6556
|
+
}
|
|
6557
|
+
};
|
|
6367
6558
|
function computeNewBoundsForResize(item, sb, handle, currentWorld) {
|
|
6368
6559
|
const rot = getItemRotationRad(item);
|
|
6560
|
+
const link = getLinkData(item);
|
|
6561
|
+
if (link && item.customIntrinsicSize) {
|
|
6562
|
+
if (!LINK_CORNER_HANDLES.has(handle)) return sb;
|
|
6563
|
+
const intrinsicWidth = Math.max(1e-9, item.customIntrinsicSize.width);
|
|
6564
|
+
if (Math.abs(rot) < 1e-12) {
|
|
6565
|
+
const next = computeResizeBoundsFixedAspect(
|
|
6566
|
+
sb,
|
|
6567
|
+
handle,
|
|
6568
|
+
currentWorld,
|
|
6569
|
+
LINK_CARD_ASPECT
|
|
6570
|
+
);
|
|
6571
|
+
return clampLinkResizeBounds(sb, next, handle, intrinsicWidth);
|
|
6572
|
+
}
|
|
6573
|
+
const local2 = worldToItemLocal(
|
|
6574
|
+
currentWorld.x,
|
|
6575
|
+
currentWorld.y,
|
|
6576
|
+
sb.x,
|
|
6577
|
+
sb.y,
|
|
6578
|
+
sb.width,
|
|
6579
|
+
sb.height,
|
|
6580
|
+
rot
|
|
6581
|
+
);
|
|
6582
|
+
const localBounds2 = { x: 0, y: 0, width: sb.width, height: sb.height };
|
|
6583
|
+
const nextLocal = computeResizeBoundsFixedAspect(
|
|
6584
|
+
localBounds2,
|
|
6585
|
+
handle,
|
|
6586
|
+
local2,
|
|
6587
|
+
LINK_CARD_ASPECT
|
|
6588
|
+
);
|
|
6589
|
+
const clamped = clampLinkResizeBounds(
|
|
6590
|
+
localBounds2,
|
|
6591
|
+
nextLocal,
|
|
6592
|
+
handle,
|
|
6593
|
+
intrinsicWidth
|
|
6594
|
+
);
|
|
6595
|
+
return {
|
|
6596
|
+
x: sb.x + clamped.x,
|
|
6597
|
+
y: sb.y + clamped.y,
|
|
6598
|
+
width: clamped.width,
|
|
6599
|
+
height: clamped.height
|
|
6600
|
+
};
|
|
6601
|
+
}
|
|
6369
6602
|
if (Math.abs(rot) < 1e-12) {
|
|
6370
6603
|
if (item.toolKind === "image") {
|
|
6371
6604
|
let aspect;
|
|
@@ -6838,17 +7071,8 @@ var SvgVectorRenderer = class {
|
|
|
6838
7071
|
}
|
|
6839
7072
|
};
|
|
6840
7073
|
|
|
6841
|
-
// src/
|
|
6842
|
-
|
|
6843
|
-
var isCanvuLinkData = (value) => {
|
|
6844
|
-
if (!value || typeof value !== "object") return false;
|
|
6845
|
-
const candidate = value;
|
|
6846
|
-
return typeof candidate.href === "string" && candidate.href.length > 0;
|
|
6847
|
-
};
|
|
6848
|
-
function getLinkData(item) {
|
|
6849
|
-
const entry = item.pluginData?.[LINK_PLUGIN_KEY];
|
|
6850
|
-
return isCanvuLinkData(entry) ? entry : null;
|
|
6851
|
-
}
|
|
7074
|
+
// src/react/VectorViewport.tsx
|
|
7075
|
+
init_link_item();
|
|
6852
7076
|
|
|
6853
7077
|
// src/scene/scene.ts
|
|
6854
7078
|
var VectorScene = class {
|
|
@@ -6942,8 +7166,10 @@ function smoothFreehandPointsToPathD(points) {
|
|
|
6942
7166
|
}
|
|
6943
7167
|
|
|
6944
7168
|
// src/react/InteractionOverlay.tsx
|
|
7169
|
+
init_link_item();
|
|
6945
7170
|
init_shape_builders();
|
|
6946
7171
|
var HANDLE_ORDER = ["nw", "n", "ne", "e", "se", "s", "sw", "w"];
|
|
7172
|
+
var LINK_HANDLE_ORDER = ["nw", "ne", "se", "sw"];
|
|
6947
7173
|
var ERASER_TINT = "#cbd5e1";
|
|
6948
7174
|
var ERASER_TINT_OPACITY = 0.95;
|
|
6949
7175
|
var ERASER_PREVIEW_OPACITY = 0.3;
|
|
@@ -6996,7 +7222,7 @@ function InteractionOverlay({
|
|
|
6996
7222
|
) }, it.id);
|
|
6997
7223
|
}),
|
|
6998
7224
|
showResizeHandles && bSingle && single && rotHandlePos && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
6999
|
-
HANDLE_ORDER.map((hid) => {
|
|
7225
|
+
(getLinkData(single) ? LINK_HANDLE_ORDER : HANDLE_ORDER).map((hid) => {
|
|
7000
7226
|
const p = getHandleWorldPositionRotated(bSingle, hid, rotSingle);
|
|
7001
7227
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7002
7228
|
"circle",
|
|
@@ -7810,6 +8036,7 @@ function defaultPlacementWorld(tool, center) {
|
|
|
7810
8036
|
lineWorld: [a, b]
|
|
7811
8037
|
};
|
|
7812
8038
|
}
|
|
8039
|
+
var LINK_CORNER_HANDLES2 = /* @__PURE__ */ new Set(["nw", "ne", "se", "sw"]);
|
|
7813
8040
|
function pointInSelectedItemBounds(item, worldX, worldY) {
|
|
7814
8041
|
const bounds = normalizeRect(item.bounds);
|
|
7815
8042
|
const local = worldToItemLocal(
|
|
@@ -8287,7 +8514,11 @@ var VectorViewport = react.forwardRef(
|
|
|
8287
8514
|
setEffectiveSelectedIdsRef.current = setEffectiveSelectedIds;
|
|
8288
8515
|
toolIdRef.current = toolId;
|
|
8289
8516
|
interactiveRef.current = interactive;
|
|
8290
|
-
|
|
8517
|
+
const normalizedItems = react.useMemo(
|
|
8518
|
+
() => items.map((item) => getLinkData(item) ? rebuildLinkItemSvg(item) : item),
|
|
8519
|
+
[items]
|
|
8520
|
+
);
|
|
8521
|
+
itemsRef.current = normalizedItems;
|
|
8291
8522
|
onWorldPointerDownRef.current = onWorldPointerDown;
|
|
8292
8523
|
const originalOnItemsChangeRef = react.useRef(onItemsChange);
|
|
8293
8524
|
originalOnItemsChangeRef.current = onItemsChange;
|
|
@@ -8308,7 +8539,10 @@ var VectorViewport = react.forwardRef(
|
|
|
8308
8539
|
autoResetToolToRef.current = autoResetToolTo;
|
|
8309
8540
|
const onToolChangeRequestRef = react.useRef(onToolChangeRequest);
|
|
8310
8541
|
onToolChangeRequestRef.current = onToolChangeRequest;
|
|
8311
|
-
const resolvedItems = react.useMemo(
|
|
8542
|
+
const resolvedItems = react.useMemo(
|
|
8543
|
+
() => resolveArrowBindingsInScene(normalizedItems),
|
|
8544
|
+
[normalizedItems]
|
|
8545
|
+
);
|
|
8312
8546
|
const resolvedItemsRef = react.useRef(resolvedItems);
|
|
8313
8547
|
resolvedItemsRef.current = resolvedItems;
|
|
8314
8548
|
const liveId = react.useId();
|
|
@@ -9729,7 +9963,8 @@ var VectorViewport = react.forwardRef(
|
|
|
9729
9963
|
handleRadiusWorld,
|
|
9730
9964
|
rot
|
|
9731
9965
|
);
|
|
9732
|
-
|
|
9966
|
+
const isLinkResizeHandle = hb && getLinkData(selected) ? LINK_CORNER_HANDLES2.has(hb) : Boolean(hb);
|
|
9967
|
+
if (hb && isLinkResizeHandle) {
|
|
9733
9968
|
const snapRs = bakedSnapshot(selected.id);
|
|
9734
9969
|
if (!snapRs) return;
|
|
9735
9970
|
dragStateRef.current = {
|