canvu-react 0.4.30 → 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 +260 -21
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +9 -7
- package/dist/react.d.ts +9 -7
- package/dist/react.js +261 -22
- 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
|
@@ -132,7 +132,7 @@ type CanvuLinkData = {
|
|
|
132
132
|
* Builds the inner SVG (no outer `<svg>`) for a link/bookmark card at the given box size.
|
|
133
133
|
* Uses fixed pixel bands so text never overlaps regardless of the card's aspect ratio.
|
|
134
134
|
*/
|
|
135
|
-
declare function buildLinkCardSvg(width: number,
|
|
135
|
+
declare function buildLinkCardSvg(width: number, _height: number, link: CanvuLinkData): string;
|
|
136
136
|
/** Reads the link metadata from an item, or `null` when the item is not a link. */
|
|
137
137
|
declare function getLinkData(item: VectorSceneItem): CanvuLinkData | null;
|
|
138
138
|
/** True when the item carries link metadata (clickable card). */
|
|
@@ -144,8 +144,8 @@ declare function isLinkItem(item: VectorSceneItem): boolean;
|
|
|
144
144
|
declare function createLinkItem(id: string, bounds: Rect, link: CanvuLinkData): VectorSceneItem;
|
|
145
145
|
/** Default card size used when placing a new link without explicit bounds. */
|
|
146
146
|
declare const DEFAULT_LINK_CARD_SIZE: {
|
|
147
|
-
readonly width:
|
|
148
|
-
readonly height:
|
|
147
|
+
readonly width: 320;
|
|
148
|
+
readonly height: 70;
|
|
149
149
|
};
|
|
150
150
|
|
|
151
151
|
export { type CanvuLinkData as C, DEFAULT_LINK_CARD_SIZE as D, LINK_PLUGIN_KEY as L, type VectorViewportAssetKind as V, type VectorViewportAssetStore as a, buildLinkCardSvg as b, createLinkItem as c, type VectorViewportAssetHydrationRequest as d, type VectorViewportAssetResolveRequest as e, type VectorViewportAssetResolveResult as f, getLinkData as g, type VectorViewportAssetUploadRequest as h, isLinkItem as i, type VectorViewportAssetUploadResult as j };
|
|
@@ -132,7 +132,7 @@ type CanvuLinkData = {
|
|
|
132
132
|
* Builds the inner SVG (no outer `<svg>`) for a link/bookmark card at the given box size.
|
|
133
133
|
* Uses fixed pixel bands so text never overlaps regardless of the card's aspect ratio.
|
|
134
134
|
*/
|
|
135
|
-
declare function buildLinkCardSvg(width: number,
|
|
135
|
+
declare function buildLinkCardSvg(width: number, _height: number, link: CanvuLinkData): string;
|
|
136
136
|
/** Reads the link metadata from an item, or `null` when the item is not a link. */
|
|
137
137
|
declare function getLinkData(item: VectorSceneItem): CanvuLinkData | null;
|
|
138
138
|
/** True when the item carries link metadata (clickable card). */
|
|
@@ -144,8 +144,8 @@ declare function isLinkItem(item: VectorSceneItem): boolean;
|
|
|
144
144
|
declare function createLinkItem(id: string, bounds: Rect, link: CanvuLinkData): VectorSceneItem;
|
|
145
145
|
/** Default card size used when placing a new link without explicit bounds. */
|
|
146
146
|
declare const DEFAULT_LINK_CARD_SIZE: {
|
|
147
|
-
readonly width:
|
|
148
|
-
readonly height:
|
|
147
|
+
readonly width: 320;
|
|
148
|
+
readonly height: 70;
|
|
149
149
|
};
|
|
150
150
|
|
|
151
151
|
export { type CanvuLinkData as C, DEFAULT_LINK_CARD_SIZE as D, LINK_PLUGIN_KEY as L, type VectorViewportAssetKind as V, type VectorViewportAssetStore as a, buildLinkCardSvg as b, createLinkItem as c, type VectorViewportAssetHydrationRequest as d, type VectorViewportAssetResolveRequest as e, type VectorViewportAssetResolveResult as f, getLinkData as g, type VectorViewportAssetUploadRequest as h, isLinkItem as i, type VectorViewportAssetUploadResult as j };
|
package/dist/native.cjs
CHANGED
|
@@ -35,11 +35,165 @@ function buildCustomShapeChildrenSvg(inner, intrinsic, bounds) {
|
|
|
35
35
|
return `<g transform="scale(${sx},${sy})">${inner}</g>`;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
// src/scene/link-item.ts
|
|
39
|
+
var LINK_PLUGIN_KEY = "canvuLink";
|
|
40
|
+
var DEFAULT_LINK_CARD_WIDTH = 320;
|
|
41
|
+
var DEFAULT_LINK_CARD_HEIGHT = 70;
|
|
42
|
+
var LINK_CARD_MIN_SCALE = 0.6;
|
|
43
|
+
var LINK_CARD_MAX_SCALE = 2.5;
|
|
44
|
+
var LINK_CARD_ASPECT = DEFAULT_LINK_CARD_WIDTH / DEFAULT_LINK_CARD_HEIGHT;
|
|
45
|
+
var LINK_CARD_BORDER = "oklch(0.918 0.008 255)";
|
|
46
|
+
var LINK_CARD_BORDER_STRONG = "oklch(0.86 0.012 255)";
|
|
47
|
+
var LINK_CARD_ACCENT = "oklch(0.55 0.19 264)";
|
|
48
|
+
var LINK_CARD_ACCENT_DEEP = "oklch(0.46 0.18 264)";
|
|
49
|
+
var LINK_CARD_TITLE_COLOR = "oklch(0.26 0.022 265)";
|
|
50
|
+
var LINK_CARD_TEXT_COLOR = "oklch(0.55 0.022 265)";
|
|
51
|
+
var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
52
|
+
var formatNumber = (value) => {
|
|
53
|
+
const rounded = Math.round(value * 100) / 100;
|
|
54
|
+
return Object.is(rounded, -0) ? "0" : String(rounded);
|
|
55
|
+
};
|
|
56
|
+
var escapeXmlAttribute = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
57
|
+
var escapeHtmlText = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
58
|
+
var getLinkHostname = (href) => {
|
|
59
|
+
try {
|
|
60
|
+
return new URL(href).hostname.replace(/^www\./, "");
|
|
61
|
+
} catch {
|
|
62
|
+
return href;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
var buildLinkTextBand = (band) => {
|
|
66
|
+
const lineHeight = band.height;
|
|
67
|
+
const weight = band.fontWeight != null ? `font-weight:${band.fontWeight};` : "";
|
|
68
|
+
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>`;
|
|
69
|
+
};
|
|
70
|
+
var getLinkProtocol = (href) => {
|
|
71
|
+
try {
|
|
72
|
+
return new URL(href).protocol;
|
|
73
|
+
} catch {
|
|
74
|
+
return "";
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
var getLinkInitial = (hostname) => {
|
|
78
|
+
const first = hostname.trim().charAt(0).toUpperCase();
|
|
79
|
+
return first || "L";
|
|
80
|
+
};
|
|
81
|
+
var buildGoogleFaviconUrl = (hostname) => hostname ? `https://www.google.com/s2/favicons?domain=${encodeURIComponent(hostname)}&sz=64` : null;
|
|
82
|
+
var getStableLinkIdSuffix = (value) => {
|
|
83
|
+
let hash = 0;
|
|
84
|
+
for (const char of value) {
|
|
85
|
+
hash = hash * 31 + char.charCodeAt(0) >>> 0;
|
|
86
|
+
}
|
|
87
|
+
return hash.toString(36);
|
|
88
|
+
};
|
|
89
|
+
function buildLinkCardSvg(width, _height, link) {
|
|
90
|
+
const cardWidth = Math.max(1, width);
|
|
91
|
+
const scale = cardWidth / DEFAULT_LINK_CARD_WIDTH;
|
|
92
|
+
const contentWidth = DEFAULT_LINK_CARD_WIDTH;
|
|
93
|
+
const contentHeight = DEFAULT_LINK_CARD_HEIGHT;
|
|
94
|
+
const padding = 14;
|
|
95
|
+
const badgeSize = 42;
|
|
96
|
+
const gap = 13;
|
|
97
|
+
const buttonSize = 34;
|
|
98
|
+
const textX = padding + badgeSize + gap;
|
|
99
|
+
const textWidth = Math.max(1, contentWidth - textX - buttonSize - gap - padding);
|
|
100
|
+
const hostname = getLinkHostname(link.href);
|
|
101
|
+
const title = link.title?.trim() || hostname || "Link";
|
|
102
|
+
const protocol = getLinkProtocol(link.href);
|
|
103
|
+
const subtitle = hostname || link.href;
|
|
104
|
+
const favicon = link.favicon?.trim() || buildGoogleFaviconUrl(hostname);
|
|
105
|
+
const idSuffix = getStableLinkIdSuffix(`${hostname}:${link.href}`);
|
|
106
|
+
const clipId = `canvu-link-favicon-${idSuffix}`;
|
|
107
|
+
const gradientId = `canvu-link-favicon-gradient-${idSuffix}`;
|
|
108
|
+
const buttonX = contentWidth - padding - buttonSize;
|
|
109
|
+
const buttonY = (contentHeight - buttonSize) / 2;
|
|
110
|
+
const isSecure = protocol === "https:";
|
|
111
|
+
const subtitleX = isSecure ? textX + 13 : textX;
|
|
112
|
+
const subtitleWidth = isSecure ? textWidth - 13 : textWidth;
|
|
113
|
+
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})" />` : "";
|
|
114
|
+
return `
|
|
115
|
+
<style>
|
|
116
|
+
.canvu-link-card-root .canvu-link-card { transition: transform .18s ease, filter .18s ease, stroke .18s ease; }
|
|
117
|
+
.canvu-link-card-root .canvu-link-open { opacity: 0; transform: translateX(-4px); transition: opacity .18s ease, transform .18s ease; }
|
|
118
|
+
.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}; }
|
|
119
|
+
.canvu-link-card-root:hover .canvu-link-open { opacity: 1; transform: translateX(0); }
|
|
120
|
+
</style>
|
|
121
|
+
<g class="canvu-link-card-root" transform="scale(${formatNumber(scale)})">
|
|
122
|
+
<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))" />
|
|
123
|
+
<defs>
|
|
124
|
+
<linearGradient id="${gradientId}" x1="8" y1="48" x2="48" y2="8" gradientUnits="userSpaceOnUse">
|
|
125
|
+
<stop stop-color="${LINK_CARD_ACCENT}" />
|
|
126
|
+
<stop offset="1" stop-color="${LINK_CARD_ACCENT_DEEP}" />
|
|
127
|
+
</linearGradient>
|
|
128
|
+
<clipPath id="${clipId}">
|
|
129
|
+
<rect x="${formatNumber(padding)}" y="${formatNumber(padding)}" width="${formatNumber(badgeSize)}" height="${formatNumber(badgeSize)}" rx="11" />
|
|
130
|
+
</clipPath>
|
|
131
|
+
</defs>
|
|
132
|
+
<rect x="${formatNumber(padding)}" y="${formatNumber(padding)}" width="${formatNumber(badgeSize)}" height="${formatNumber(badgeSize)}" rx="11" fill="url(#${gradientId})" />
|
|
133
|
+
<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>
|
|
134
|
+
${faviconImage}
|
|
135
|
+
${buildLinkTextBand({ x: textX, y: 16, width: textWidth, height: 19, text: title, fontSize: 14.5, color: LINK_CARD_TITLE_COLOR, fontWeight: 700 })}
|
|
136
|
+
${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>` : ""}
|
|
137
|
+
${buildLinkTextBand({ x: subtitleX, y: 36, width: subtitleWidth, height: 17, text: subtitle, fontSize: 12.5, color: LINK_CARD_TEXT_COLOR })}
|
|
138
|
+
<g class="canvu-link-open" transform="translate(${formatNumber(buttonX)},${formatNumber(buttonY)})">
|
|
139
|
+
<rect width="${formatNumber(buttonSize)}" height="${formatNumber(buttonSize)}" rx="10" fill="#ffffff" stroke="${LINK_CARD_BORDER}" stroke-width="1" />
|
|
140
|
+
<g transform="translate(10,10)" stroke="${LINK_CARD_TEXT_COLOR}" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" fill="none">
|
|
141
|
+
<path d="M8 2 H14 V8" />
|
|
142
|
+
<path d="M14 2 L7 9" />
|
|
143
|
+
<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" />
|
|
144
|
+
</g>
|
|
145
|
+
</g>
|
|
146
|
+
</g>
|
|
147
|
+
`;
|
|
148
|
+
}
|
|
149
|
+
var isCanvuLinkData = (value) => {
|
|
150
|
+
if (!value || typeof value !== "object") return false;
|
|
151
|
+
const candidate = value;
|
|
152
|
+
return typeof candidate.href === "string" && candidate.href.length > 0;
|
|
153
|
+
};
|
|
154
|
+
function getLinkData(item) {
|
|
155
|
+
const entry = item.pluginData?.[LINK_PLUGIN_KEY];
|
|
156
|
+
return isCanvuLinkData(entry) ? entry : null;
|
|
157
|
+
}
|
|
158
|
+
function rebuildLinkItemSvg(item) {
|
|
159
|
+
const link = getLinkData(item);
|
|
160
|
+
if (!link) return item;
|
|
161
|
+
const scale = clamp(
|
|
162
|
+
item.bounds.width / DEFAULT_LINK_CARD_WIDTH,
|
|
163
|
+
LINK_CARD_MIN_SCALE,
|
|
164
|
+
LINK_CARD_MAX_SCALE
|
|
165
|
+
);
|
|
166
|
+
const width = DEFAULT_LINK_CARD_WIDTH * scale;
|
|
167
|
+
const height = DEFAULT_LINK_CARD_HEIGHT * scale;
|
|
168
|
+
const bounds = {
|
|
169
|
+
...item.bounds,
|
|
170
|
+
width,
|
|
171
|
+
height
|
|
172
|
+
};
|
|
173
|
+
const customInnerSvg = buildLinkCardSvg(
|
|
174
|
+
DEFAULT_LINK_CARD_WIDTH,
|
|
175
|
+
DEFAULT_LINK_CARD_HEIGHT,
|
|
176
|
+
link
|
|
177
|
+
);
|
|
178
|
+
return {
|
|
179
|
+
...item,
|
|
180
|
+
x: bounds.x,
|
|
181
|
+
y: bounds.y,
|
|
182
|
+
bounds,
|
|
183
|
+
customIntrinsicSize: {
|
|
184
|
+
width: DEFAULT_LINK_CARD_WIDTH,
|
|
185
|
+
height: DEFAULT_LINK_CARD_HEIGHT
|
|
186
|
+
},
|
|
187
|
+
customInnerSvg,
|
|
188
|
+
childrenSvg: buildLinkCardSvg(width, height, link)
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
38
192
|
// src/scene/text-svg.ts
|
|
39
193
|
function escapeSvgTextContent(s) {
|
|
40
194
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
41
195
|
}
|
|
42
|
-
function
|
|
196
|
+
function escapeHtmlText2(s) {
|
|
43
197
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
44
198
|
}
|
|
45
199
|
var DEFAULT_TEXT_FONT_SIZE = 18;
|
|
@@ -154,9 +308,9 @@ function buildTextFixedBoundsSvg(content, width, height, fillColor = "#1d1d1d",
|
|
|
154
308
|
const trimmed = content.trim();
|
|
155
309
|
const padTop = EDIT_TOP_PAD_RATIO * fontSize;
|
|
156
310
|
if (trimmed.length === 0) {
|
|
157
|
-
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">${
|
|
311
|
+
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>`;
|
|
158
312
|
}
|
|
159
|
-
const body =
|
|
313
|
+
const body = escapeHtmlText2(content);
|
|
160
314
|
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>`;
|
|
161
315
|
}
|
|
162
316
|
|
|
@@ -754,6 +908,9 @@ function rebuildItemSvg(item) {
|
|
|
754
908
|
)
|
|
755
909
|
};
|
|
756
910
|
}
|
|
911
|
+
if (getLinkData(item)) {
|
|
912
|
+
return rebuildLinkItemSvg(item);
|
|
913
|
+
}
|
|
757
914
|
if (k === "custom" && item.customIntrinsicSize && item.customInnerSvg) {
|
|
758
915
|
const b = normalizeRect(item.bounds);
|
|
759
916
|
return {
|
|
@@ -3716,8 +3873,77 @@ function collectEraserTargetsAtWorldPoint(items, worldX, worldY, options) {
|
|
|
3716
3873
|
}
|
|
3717
3874
|
|
|
3718
3875
|
// src/interaction/mutations.ts
|
|
3876
|
+
var LINK_CORNER_HANDLES = /* @__PURE__ */ new Set(["nw", "ne", "se", "sw"]);
|
|
3877
|
+
var clamp2 = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
3878
|
+
var clampLinkResizeBounds = (startBounds, nextBounds, handle, intrinsicWidth) => {
|
|
3879
|
+
const next = normalizeRect(nextBounds);
|
|
3880
|
+
const scale = clamp2(
|
|
3881
|
+
next.width / Math.max(1e-9, intrinsicWidth),
|
|
3882
|
+
LINK_CARD_MIN_SCALE,
|
|
3883
|
+
LINK_CARD_MAX_SCALE
|
|
3884
|
+
);
|
|
3885
|
+
const width = intrinsicWidth * scale;
|
|
3886
|
+
const height = width / LINK_CARD_ASPECT;
|
|
3887
|
+
const start = normalizeRect(startBounds);
|
|
3888
|
+
const x0 = start.x;
|
|
3889
|
+
const y0 = start.y;
|
|
3890
|
+
const x1 = start.x + start.width;
|
|
3891
|
+
const y1 = start.y + start.height;
|
|
3892
|
+
switch (handle) {
|
|
3893
|
+
case "nw":
|
|
3894
|
+
return { x: x1 - width, y: y1 - height, width, height };
|
|
3895
|
+
case "ne":
|
|
3896
|
+
return { x: x0, y: y1 - height, width, height };
|
|
3897
|
+
case "sw":
|
|
3898
|
+
return { x: x1 - width, y: y0, width, height };
|
|
3899
|
+
default:
|
|
3900
|
+
return { x: x0, y: y0, width, height };
|
|
3901
|
+
}
|
|
3902
|
+
};
|
|
3719
3903
|
function computeNewBoundsForResize(item, sb, handle, currentWorld) {
|
|
3720
3904
|
const rot = getItemRotationRad(item);
|
|
3905
|
+
const link = getLinkData(item);
|
|
3906
|
+
if (link && item.customIntrinsicSize) {
|
|
3907
|
+
if (!LINK_CORNER_HANDLES.has(handle)) return sb;
|
|
3908
|
+
const intrinsicWidth = Math.max(1e-9, item.customIntrinsicSize.width);
|
|
3909
|
+
if (Math.abs(rot) < 1e-12) {
|
|
3910
|
+
const next = computeResizeBoundsFixedAspect(
|
|
3911
|
+
sb,
|
|
3912
|
+
handle,
|
|
3913
|
+
currentWorld,
|
|
3914
|
+
LINK_CARD_ASPECT
|
|
3915
|
+
);
|
|
3916
|
+
return clampLinkResizeBounds(sb, next, handle, intrinsicWidth);
|
|
3917
|
+
}
|
|
3918
|
+
const local2 = worldToItemLocal(
|
|
3919
|
+
currentWorld.x,
|
|
3920
|
+
currentWorld.y,
|
|
3921
|
+
sb.x,
|
|
3922
|
+
sb.y,
|
|
3923
|
+
sb.width,
|
|
3924
|
+
sb.height,
|
|
3925
|
+
rot
|
|
3926
|
+
);
|
|
3927
|
+
const localBounds3 = { x: 0, y: 0, width: sb.width, height: sb.height };
|
|
3928
|
+
const nextLocal = computeResizeBoundsFixedAspect(
|
|
3929
|
+
localBounds3,
|
|
3930
|
+
handle,
|
|
3931
|
+
local2,
|
|
3932
|
+
LINK_CARD_ASPECT
|
|
3933
|
+
);
|
|
3934
|
+
const clamped = clampLinkResizeBounds(
|
|
3935
|
+
localBounds3,
|
|
3936
|
+
nextLocal,
|
|
3937
|
+
handle,
|
|
3938
|
+
intrinsicWidth
|
|
3939
|
+
);
|
|
3940
|
+
return {
|
|
3941
|
+
x: sb.x + clamped.x,
|
|
3942
|
+
y: sb.y + clamped.y,
|
|
3943
|
+
width: clamped.width,
|
|
3944
|
+
height: clamped.height
|
|
3945
|
+
};
|
|
3946
|
+
}
|
|
3721
3947
|
if (Math.abs(rot) < 1e-12) {
|
|
3722
3948
|
if (item.toolKind === "image") {
|
|
3723
3949
|
let aspect;
|