canvu-react 0.4.31 → 0.4.33
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 +173 -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 +173 -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 +220 -3
- package/dist/native.cjs.map +1 -1
- package/dist/native.js +220 -3
- package/dist/native.js.map +1 -1
- package/dist/react.cjs +244 -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 +244 -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 +121 -39
- package/dist/tldraw.cjs.map +1 -1
- package/dist/tldraw.js +121 -39
- 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/tldraw.cjs
CHANGED
|
@@ -52,16 +52,21 @@ function createCustomShapeItem(id, bounds, content) {
|
|
|
52
52
|
|
|
53
53
|
// src/scene/link-item.ts
|
|
54
54
|
var LINK_PLUGIN_KEY = "canvuLink";
|
|
55
|
-
var
|
|
56
|
-
var
|
|
57
|
-
var
|
|
58
|
-
var
|
|
55
|
+
var DEFAULT_LINK_CARD_WIDTH = 320;
|
|
56
|
+
var DEFAULT_LINK_CARD_HEIGHT = 70;
|
|
57
|
+
var LINK_CARD_MIN_SCALE = 0.6;
|
|
58
|
+
var LINK_CARD_MAX_SCALE = 6;
|
|
59
|
+
var LINK_CARD_BORDER = "oklch(0.918 0.008 255)";
|
|
60
|
+
var LINK_CARD_BORDER_STRONG = "oklch(0.86 0.012 255)";
|
|
61
|
+
var LINK_CARD_ACCENT = "oklch(0.55 0.19 264)";
|
|
62
|
+
var LINK_CARD_ACCENT_DEEP = "oklch(0.46 0.18 264)";
|
|
63
|
+
var LINK_CARD_TITLE_COLOR = "oklch(0.26 0.022 265)";
|
|
64
|
+
var LINK_CARD_TEXT_COLOR = "oklch(0.55 0.022 265)";
|
|
59
65
|
var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
60
66
|
var formatNumber = (value) => {
|
|
61
67
|
const rounded = Math.round(value * 100) / 100;
|
|
62
68
|
return Object.is(rounded, -0) ? "0" : String(rounded);
|
|
63
69
|
};
|
|
64
|
-
var escapeXmlAttribute = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
65
70
|
var escapeHtmlText = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
66
71
|
var getLinkHostname = (href) => {
|
|
67
72
|
try {
|
|
@@ -71,49 +76,123 @@ var getLinkHostname = (href) => {
|
|
|
71
76
|
}
|
|
72
77
|
};
|
|
73
78
|
var buildLinkTextBand = (band) => {
|
|
74
|
-
const lineHeight = band.
|
|
79
|
+
const lineHeight = band.height;
|
|
75
80
|
const weight = band.fontWeight != null ? `font-weight:${band.fontWeight};` : "";
|
|
76
|
-
|
|
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>`;
|
|
81
|
+
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>`;
|
|
78
82
|
};
|
|
79
|
-
|
|
83
|
+
var getLinkProtocol = (href) => {
|
|
84
|
+
try {
|
|
85
|
+
return new URL(href).protocol;
|
|
86
|
+
} catch {
|
|
87
|
+
return "";
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
var getLinkInitial = (hostname) => {
|
|
91
|
+
const first = hostname.trim().charAt(0).toUpperCase();
|
|
92
|
+
return first || "L";
|
|
93
|
+
};
|
|
94
|
+
var getStableLinkIdSuffix = (value) => {
|
|
95
|
+
let hash = 0;
|
|
96
|
+
for (const char of value) {
|
|
97
|
+
hash = hash * 31 + char.charCodeAt(0) >>> 0;
|
|
98
|
+
}
|
|
99
|
+
return hash.toString(36);
|
|
100
|
+
};
|
|
101
|
+
function buildLinkCardSvg(width, _height, link) {
|
|
80
102
|
const cardWidth = Math.max(1, width);
|
|
81
|
-
const
|
|
103
|
+
const scale = cardWidth / DEFAULT_LINK_CARD_WIDTH;
|
|
104
|
+
const contentWidth = DEFAULT_LINK_CARD_WIDTH;
|
|
105
|
+
const contentHeight = DEFAULT_LINK_CARD_HEIGHT;
|
|
82
106
|
const padding = 14;
|
|
83
|
-
const badgeSize =
|
|
84
|
-
const
|
|
85
|
-
const
|
|
107
|
+
const badgeSize = 42;
|
|
108
|
+
const gap = 13;
|
|
109
|
+
const buttonSize = 34;
|
|
110
|
+
const textX = padding + badgeSize + gap;
|
|
111
|
+
const textWidth = Math.max(1, contentWidth - textX - buttonSize - gap - padding);
|
|
86
112
|
const hostname = getLinkHostname(link.href);
|
|
87
113
|
const title = link.title?.trim() || hostname || "Link";
|
|
88
|
-
const
|
|
89
|
-
const
|
|
90
|
-
const
|
|
91
|
-
const
|
|
92
|
-
const
|
|
93
|
-
const
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
|
|
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>`;
|
|
114
|
+
const protocol = getLinkProtocol(link.href);
|
|
115
|
+
const subtitle = hostname || link.href;
|
|
116
|
+
const idSuffix = getStableLinkIdSuffix(`${hostname}:${link.href}`);
|
|
117
|
+
const gradientId = `canvu-link-favicon-gradient-${idSuffix}`;
|
|
118
|
+
const buttonX = contentWidth - padding - buttonSize;
|
|
119
|
+
const buttonY = (contentHeight - buttonSize) / 2;
|
|
120
|
+
const isSecure = protocol === "https:";
|
|
121
|
+
const subtitleX = isSecure ? textX + 13 : textX;
|
|
122
|
+
const subtitleWidth = isSecure ? textWidth - 13 : textWidth;
|
|
108
123
|
return `
|
|
109
|
-
<
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
124
|
+
<style>
|
|
125
|
+
.canvu-link-card-root .canvu-link-card { transition: transform .18s ease, filter .18s ease, stroke .18s ease; }
|
|
126
|
+
.canvu-link-card-root .canvu-link-open { opacity: 0; transform: translateX(-4px); transition: opacity .18s ease, transform .18s ease; }
|
|
127
|
+
.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}; }
|
|
128
|
+
.canvu-link-card-root:hover .canvu-link-open { opacity: 1; transform: translateX(0); }
|
|
129
|
+
</style>
|
|
130
|
+
<g class="canvu-link-card-root" transform="scale(${formatNumber(scale)})">
|
|
131
|
+
<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))" />
|
|
132
|
+
<defs>
|
|
133
|
+
<linearGradient id="${gradientId}" x1="8" y1="48" x2="48" y2="8" gradientUnits="userSpaceOnUse">
|
|
134
|
+
<stop stop-color="${LINK_CARD_ACCENT}" />
|
|
135
|
+
<stop offset="1" stop-color="${LINK_CARD_ACCENT_DEEP}" />
|
|
136
|
+
</linearGradient>
|
|
137
|
+
</defs>
|
|
138
|
+
<rect x="${formatNumber(padding)}" y="${formatNumber(padding)}" width="${formatNumber(badgeSize)}" height="${formatNumber(badgeSize)}" rx="11" fill="url(#${gradientId})" />
|
|
139
|
+
<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>
|
|
140
|
+
${buildLinkTextBand({ x: textX, y: 16, width: textWidth, height: 19, text: title, fontSize: 14.5, color: LINK_CARD_TITLE_COLOR, fontWeight: 700 })}
|
|
141
|
+
${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>` : ""}
|
|
142
|
+
${buildLinkTextBand({ x: subtitleX, y: 36, width: subtitleWidth, height: 17, text: subtitle, fontSize: 12.5, color: LINK_CARD_TEXT_COLOR })}
|
|
143
|
+
<g class="canvu-link-open" transform="translate(${formatNumber(buttonX)},${formatNumber(buttonY)})">
|
|
144
|
+
<rect width="${formatNumber(buttonSize)}" height="${formatNumber(buttonSize)}" rx="10" fill="#ffffff" stroke="${LINK_CARD_BORDER}" stroke-width="1" />
|
|
145
|
+
<g transform="translate(10,10)" stroke="${LINK_CARD_TEXT_COLOR}" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" fill="none">
|
|
146
|
+
<path d="M8 2 H14 V8" />
|
|
147
|
+
<path d="M14 2 L7 9" />
|
|
148
|
+
<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" />
|
|
149
|
+
</g>
|
|
150
|
+
</g>
|
|
151
|
+
</g>
|
|
115
152
|
`;
|
|
116
153
|
}
|
|
154
|
+
var isCanvuLinkData = (value) => {
|
|
155
|
+
if (!value || typeof value !== "object") return false;
|
|
156
|
+
const candidate = value;
|
|
157
|
+
return typeof candidate.href === "string" && candidate.href.length > 0;
|
|
158
|
+
};
|
|
159
|
+
function getLinkData(item) {
|
|
160
|
+
const entry = item.pluginData?.[LINK_PLUGIN_KEY];
|
|
161
|
+
return isCanvuLinkData(entry) ? entry : null;
|
|
162
|
+
}
|
|
163
|
+
function rebuildLinkItemSvg(item) {
|
|
164
|
+
const link = getLinkData(item);
|
|
165
|
+
if (!link) return item;
|
|
166
|
+
const scale = clamp(
|
|
167
|
+
item.bounds.width / DEFAULT_LINK_CARD_WIDTH,
|
|
168
|
+
LINK_CARD_MIN_SCALE,
|
|
169
|
+
LINK_CARD_MAX_SCALE
|
|
170
|
+
);
|
|
171
|
+
const width = DEFAULT_LINK_CARD_WIDTH * scale;
|
|
172
|
+
const height = DEFAULT_LINK_CARD_HEIGHT * scale;
|
|
173
|
+
const bounds = {
|
|
174
|
+
...item.bounds,
|
|
175
|
+
width,
|
|
176
|
+
height
|
|
177
|
+
};
|
|
178
|
+
const customInnerSvg = buildLinkCardSvg(
|
|
179
|
+
DEFAULT_LINK_CARD_WIDTH,
|
|
180
|
+
DEFAULT_LINK_CARD_HEIGHT,
|
|
181
|
+
link
|
|
182
|
+
);
|
|
183
|
+
return {
|
|
184
|
+
...item,
|
|
185
|
+
x: bounds.x,
|
|
186
|
+
y: bounds.y,
|
|
187
|
+
bounds,
|
|
188
|
+
customIntrinsicSize: {
|
|
189
|
+
width: DEFAULT_LINK_CARD_WIDTH,
|
|
190
|
+
height: DEFAULT_LINK_CARD_HEIGHT
|
|
191
|
+
},
|
|
192
|
+
customInnerSvg,
|
|
193
|
+
childrenSvg: buildLinkCardSvg(width, height, link)
|
|
194
|
+
};
|
|
195
|
+
}
|
|
117
196
|
|
|
118
197
|
// src/scene/text-svg.ts
|
|
119
198
|
function escapeSvgTextContent(s) {
|
|
@@ -817,6 +896,9 @@ function rebuildItemSvg(item) {
|
|
|
817
896
|
)
|
|
818
897
|
};
|
|
819
898
|
}
|
|
899
|
+
if (getLinkData(item)) {
|
|
900
|
+
return rebuildLinkItemSvg(item);
|
|
901
|
+
}
|
|
820
902
|
if (k === "custom" && item.customIntrinsicSize && item.customInnerSvg) {
|
|
821
903
|
const b = normalizeRect(item.bounds);
|
|
822
904
|
return {
|