canvu-react 0.4.34 → 0.4.36
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-BFGZ3igr.d.cts → asset-hydration-Cy_2FyV5.d.cts} +1 -1
- package/dist/{asset-hydration-D6Q3TJL1.d.ts → asset-hydration-Dc7fsnTG.d.ts} +1 -1
- package/dist/{link-item-voRU0Up9.d.ts → asset-store-DQPRZEcy.d.ts} +2 -40
- package/dist/{link-item-Dncuz2d_.d.cts → asset-store-TzOPvlgn.d.cts} +2 -40
- package/dist/chatbot.d.cts +3 -2
- package/dist/chatbot.d.ts +3 -2
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/link-item-DwzXOwU5.d.cts +41 -0
- package/dist/link-item-IW4GTnxl.d.ts +41 -0
- package/dist/native.cjs +409 -6
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.cts +52 -2
- package/dist/native.d.ts +52 -2
- package/dist/native.js +407 -8
- package/dist/native.js.map +1 -1
- package/dist/react.d.cts +7 -6
- package/dist/react.d.ts +7 -6
- package/dist/realtime.d.cts +3 -2
- package/dist/realtime.d.ts +3 -2
- package/dist/{types-DeDm865m.d.ts → types-B7xZAKVJ.d.ts} +2 -1
- package/dist/{types-NBYvslB-.d.cts → types-C4wI3Jyc.d.cts} +2 -1
- package/package.json +1 -1
package/dist/native.cjs
CHANGED
|
@@ -10,8 +10,6 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
10
10
|
|
|
11
11
|
var getStroke__default = /*#__PURE__*/_interopDefault(getStroke);
|
|
12
12
|
|
|
13
|
-
// src/scene/shape-builders.ts
|
|
14
|
-
|
|
15
13
|
// src/math/rect.ts
|
|
16
14
|
function rectsIntersect(a, b) {
|
|
17
15
|
return a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y;
|
|
@@ -28,12 +26,36 @@ function normalizeRect(r) {
|
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
// src/scene/custom-shape.ts
|
|
29
|
+
function expandCustomShapeTemplate(template, width, height) {
|
|
30
|
+
return template.replace(/\{\{w\}\}/g, String(width)).replace(/\{\{h\}\}/g, String(height)).replace(/\{\{width\}\}/g, String(width)).replace(/\{\{height\}\}/g, String(height));
|
|
31
|
+
}
|
|
32
|
+
function resolveCustomInner(content, size) {
|
|
33
|
+
if ("render" in content) {
|
|
34
|
+
return content.render(size);
|
|
35
|
+
}
|
|
36
|
+
return expandCustomShapeTemplate(content.svg, size.width, size.height);
|
|
37
|
+
}
|
|
31
38
|
function buildCustomShapeChildrenSvg(inner, intrinsic, bounds) {
|
|
32
39
|
const b = normalizeRect(bounds);
|
|
33
40
|
const sx = b.width / intrinsic.width;
|
|
34
41
|
const sy = b.height / intrinsic.height;
|
|
35
42
|
return `<g transform="scale(${sx},${sy})">${inner}</g>`;
|
|
36
43
|
}
|
|
44
|
+
function createCustomShapeItem(id, bounds, content) {
|
|
45
|
+
const r = normalizeRect(bounds);
|
|
46
|
+
const intrinsic = { width: r.width, height: r.height };
|
|
47
|
+
const inner = resolveCustomInner(content, intrinsic);
|
|
48
|
+
return {
|
|
49
|
+
id,
|
|
50
|
+
x: r.x,
|
|
51
|
+
y: r.y,
|
|
52
|
+
bounds: { ...r },
|
|
53
|
+
toolKind: "custom",
|
|
54
|
+
customIntrinsicSize: intrinsic,
|
|
55
|
+
customInnerSvg: inner,
|
|
56
|
+
childrenSvg: buildCustomShapeChildrenSvg(inner, intrinsic, r)
|
|
57
|
+
};
|
|
58
|
+
}
|
|
37
59
|
|
|
38
60
|
// src/scene/link-item.ts
|
|
39
61
|
var LINK_PLUGIN_KEY = "canvuLink";
|
|
@@ -146,6 +168,9 @@ function getLinkData(item) {
|
|
|
146
168
|
const entry = item.pluginData?.[LINK_PLUGIN_KEY];
|
|
147
169
|
return isCanvuLinkData(entry) ? entry : null;
|
|
148
170
|
}
|
|
171
|
+
function isLinkItem(item) {
|
|
172
|
+
return getLinkData(item) != null;
|
|
173
|
+
}
|
|
149
174
|
function rebuildLinkItemSvg(item) {
|
|
150
175
|
const link = getLinkData(item);
|
|
151
176
|
if (!link) return item;
|
|
@@ -179,6 +204,26 @@ function rebuildLinkItemSvg(item) {
|
|
|
179
204
|
childrenSvg: buildLinkCardSvg(width, height, link)
|
|
180
205
|
};
|
|
181
206
|
}
|
|
207
|
+
function createLinkItem(id, bounds, link) {
|
|
208
|
+
const width = bounds.width || DEFAULT_LINK_CARD_WIDTH;
|
|
209
|
+
const height = bounds.height || DEFAULT_LINK_CARD_HEIGHT;
|
|
210
|
+
const item = createCustomShapeItem(
|
|
211
|
+
id,
|
|
212
|
+
{ ...bounds, width, height },
|
|
213
|
+
{ render: (size) => buildLinkCardSvg(size.width, size.height, link) }
|
|
214
|
+
);
|
|
215
|
+
return rebuildLinkItemSvg({
|
|
216
|
+
...item,
|
|
217
|
+
pluginData: {
|
|
218
|
+
...item.pluginData ?? {},
|
|
219
|
+
[LINK_PLUGIN_KEY]: link
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
var DEFAULT_LINK_CARD_SIZE = {
|
|
224
|
+
width: DEFAULT_LINK_CARD_WIDTH,
|
|
225
|
+
height: DEFAULT_LINK_CARD_HEIGHT
|
|
226
|
+
};
|
|
182
227
|
|
|
183
228
|
// src/scene/text-svg.ts
|
|
184
229
|
function escapeSvgTextContent(s) {
|
|
@@ -1405,6 +1450,179 @@ function smoothFreehandPointsToPathD(points) {
|
|
|
1405
1450
|
return d;
|
|
1406
1451
|
}
|
|
1407
1452
|
|
|
1453
|
+
// src/native/native-link-card.ts
|
|
1454
|
+
function linkHostname(href) {
|
|
1455
|
+
try {
|
|
1456
|
+
return new URL(href).hostname.replace(/^www\./, "");
|
|
1457
|
+
} catch {
|
|
1458
|
+
return href;
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
function linkProtocol(href) {
|
|
1462
|
+
try {
|
|
1463
|
+
return new URL(href).protocol;
|
|
1464
|
+
} catch {
|
|
1465
|
+
return "";
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
function linkInitial(value) {
|
|
1469
|
+
const first = value.trim().charAt(0).toUpperCase();
|
|
1470
|
+
return first || "L";
|
|
1471
|
+
}
|
|
1472
|
+
function buildNativeLinkCardDisplay(link) {
|
|
1473
|
+
const hostname = linkHostname(link.href);
|
|
1474
|
+
const title = link.title?.trim() || hostname || "Link";
|
|
1475
|
+
return {
|
|
1476
|
+
title,
|
|
1477
|
+
subtitle: hostname || link.href,
|
|
1478
|
+
initial: linkInitial(hostname || title),
|
|
1479
|
+
secure: linkProtocol(link.href) === "https:"
|
|
1480
|
+
};
|
|
1481
|
+
}
|
|
1482
|
+
function createNativeLinkCardBoundsAtPoint(point) {
|
|
1483
|
+
return {
|
|
1484
|
+
x: point.x - DEFAULT_LINK_CARD_SIZE.width / 2,
|
|
1485
|
+
y: point.y - DEFAULT_LINK_CARD_SIZE.height / 2,
|
|
1486
|
+
width: DEFAULT_LINK_CARD_SIZE.width,
|
|
1487
|
+
height: DEFAULT_LINK_CARD_SIZE.height
|
|
1488
|
+
};
|
|
1489
|
+
}
|
|
1490
|
+
var DEFAULT_NATIVE_IMAGE_CACHE_MAX_ENTRIES = 96;
|
|
1491
|
+
function disposeCachedImage(image) {
|
|
1492
|
+
try {
|
|
1493
|
+
image.dispose?.();
|
|
1494
|
+
} catch {
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
function createNativeImageCache({
|
|
1498
|
+
loadImage,
|
|
1499
|
+
maxEntries = DEFAULT_NATIVE_IMAGE_CACHE_MAX_ENTRIES
|
|
1500
|
+
}) {
|
|
1501
|
+
const safeMaxEntries = Math.max(1, Math.round(maxEntries));
|
|
1502
|
+
const entries = /* @__PURE__ */ new Map();
|
|
1503
|
+
let clock = 0;
|
|
1504
|
+
const touchEntry = (entry) => {
|
|
1505
|
+
clock += 1;
|
|
1506
|
+
entry.lastUsed = clock;
|
|
1507
|
+
};
|
|
1508
|
+
const createEntry = () => {
|
|
1509
|
+
clock += 1;
|
|
1510
|
+
return {
|
|
1511
|
+
lastUsed: clock,
|
|
1512
|
+
retainCount: 0
|
|
1513
|
+
};
|
|
1514
|
+
};
|
|
1515
|
+
const prune = () => {
|
|
1516
|
+
const cachedEntries = [...entries.entries()].filter(
|
|
1517
|
+
(entry) => entry[1].image != null && entry[1].retainCount === 0
|
|
1518
|
+
);
|
|
1519
|
+
if (cachedEntries.length <= safeMaxEntries) return;
|
|
1520
|
+
const evictedEntries = cachedEntries.sort(
|
|
1521
|
+
(leftEntry, rightEntry) => leftEntry[1].lastUsed - rightEntry[1].lastUsed
|
|
1522
|
+
).slice(0, cachedEntries.length - safeMaxEntries);
|
|
1523
|
+
for (const [href, entry] of evictedEntries) {
|
|
1524
|
+
entries.delete(href);
|
|
1525
|
+
disposeCachedImage(entry.image);
|
|
1526
|
+
}
|
|
1527
|
+
};
|
|
1528
|
+
const getCached = (href) => {
|
|
1529
|
+
const entry = entries.get(href);
|
|
1530
|
+
if (!entry?.image) return null;
|
|
1531
|
+
touchEntry(entry);
|
|
1532
|
+
return entry.image;
|
|
1533
|
+
};
|
|
1534
|
+
const load = async (href) => {
|
|
1535
|
+
const cachedImage = getCached(href);
|
|
1536
|
+
if (cachedImage) return cachedImage;
|
|
1537
|
+
const existingEntry = entries.get(href);
|
|
1538
|
+
if (existingEntry?.promise) return await existingEntry.promise;
|
|
1539
|
+
const entry = existingEntry ?? createEntry();
|
|
1540
|
+
const promise = loadImage(href).then((image) => {
|
|
1541
|
+
if (!image) {
|
|
1542
|
+
if (entry.retainCount === 0) entries.delete(href);
|
|
1543
|
+
return null;
|
|
1544
|
+
}
|
|
1545
|
+
entry.image = image;
|
|
1546
|
+
entry.promise = void 0;
|
|
1547
|
+
touchEntry(entry);
|
|
1548
|
+
prune();
|
|
1549
|
+
return image;
|
|
1550
|
+
}).catch((error) => {
|
|
1551
|
+
entries.delete(href);
|
|
1552
|
+
throw error;
|
|
1553
|
+
});
|
|
1554
|
+
entry.promise = promise;
|
|
1555
|
+
entries.set(href, entry);
|
|
1556
|
+
return await promise;
|
|
1557
|
+
};
|
|
1558
|
+
const retain = (href) => {
|
|
1559
|
+
const entry = entries.get(href) ?? createEntry();
|
|
1560
|
+
entry.retainCount += 1;
|
|
1561
|
+
touchEntry(entry);
|
|
1562
|
+
entries.set(href, entry);
|
|
1563
|
+
let released = false;
|
|
1564
|
+
return () => {
|
|
1565
|
+
if (released) return;
|
|
1566
|
+
released = true;
|
|
1567
|
+
entry.retainCount = Math.max(0, entry.retainCount - 1);
|
|
1568
|
+
if (!entry.image && !entry.promise && entry.retainCount === 0) {
|
|
1569
|
+
entries.delete(href);
|
|
1570
|
+
return;
|
|
1571
|
+
}
|
|
1572
|
+
prune();
|
|
1573
|
+
};
|
|
1574
|
+
};
|
|
1575
|
+
const clear = () => {
|
|
1576
|
+
for (const entry of entries.values()) {
|
|
1577
|
+
if (entry.image) disposeCachedImage(entry.image);
|
|
1578
|
+
}
|
|
1579
|
+
entries.clear();
|
|
1580
|
+
};
|
|
1581
|
+
const size = () => [...entries.values()].filter((entry) => entry.image != null).length;
|
|
1582
|
+
return { getCached, load, retain, clear, size };
|
|
1583
|
+
}
|
|
1584
|
+
async function loadSkiaImageFromHref(href) {
|
|
1585
|
+
const { Skia } = await import('@shopify/react-native-skia');
|
|
1586
|
+
const data = await Skia.Data.fromURI(href);
|
|
1587
|
+
return Skia.Image.MakeImageFromEncoded(data);
|
|
1588
|
+
}
|
|
1589
|
+
var nativeSkiaImageCache = createNativeImageCache({
|
|
1590
|
+
loadImage: loadSkiaImageFromHref
|
|
1591
|
+
});
|
|
1592
|
+
function useCachedSkiaImage(href) {
|
|
1593
|
+
const [loadedImage, setLoadedImage] = react.useState(
|
|
1594
|
+
() => href ? { href, image: nativeSkiaImageCache.getCached(href) } : null
|
|
1595
|
+
);
|
|
1596
|
+
react.useEffect(() => {
|
|
1597
|
+
if (!href) {
|
|
1598
|
+
setLoadedImage(null);
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
const releaseImage = nativeSkiaImageCache.retain(href);
|
|
1602
|
+
const cachedImage = nativeSkiaImageCache.getCached(href);
|
|
1603
|
+
if (cachedImage) {
|
|
1604
|
+
setLoadedImage({ href, image: cachedImage });
|
|
1605
|
+
return releaseImage;
|
|
1606
|
+
}
|
|
1607
|
+
let active = true;
|
|
1608
|
+
setLoadedImage({ href, image: null });
|
|
1609
|
+
void nativeSkiaImageCache.load(href).then(
|
|
1610
|
+
(loadedImage2) => {
|
|
1611
|
+
if (active) setLoadedImage({ href, image: loadedImage2 });
|
|
1612
|
+
},
|
|
1613
|
+
() => {
|
|
1614
|
+
if (active) setLoadedImage({ href, image: null });
|
|
1615
|
+
}
|
|
1616
|
+
);
|
|
1617
|
+
return () => {
|
|
1618
|
+
active = false;
|
|
1619
|
+
releaseImage();
|
|
1620
|
+
};
|
|
1621
|
+
}, [href]);
|
|
1622
|
+
if (!href || loadedImage?.href !== href) return null;
|
|
1623
|
+
return loadedImage.image;
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1408
1626
|
// src/native/skia-transform.ts
|
|
1409
1627
|
function parseNum(s) {
|
|
1410
1628
|
return Number(s);
|
|
@@ -1668,7 +1886,7 @@ function SvgNodeItem({ node }) {
|
|
|
1668
1886
|
function SvgImageNodeItem({
|
|
1669
1887
|
node
|
|
1670
1888
|
}) {
|
|
1671
|
-
const image =
|
|
1889
|
+
const image = useCachedSkiaImage(node.href);
|
|
1672
1890
|
if (!image) return null;
|
|
1673
1891
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1674
1892
|
reactNativeSkia.Image,
|
|
@@ -1958,7 +2176,119 @@ function localBounds(bounds) {
|
|
|
1958
2176
|
const b = normalizeRect(bounds);
|
|
1959
2177
|
return { w: Math.max(0, b.width), h: Math.max(0, b.height) };
|
|
1960
2178
|
}
|
|
2179
|
+
function truncateText(value, maxChars) {
|
|
2180
|
+
if (value.length <= maxChars) return value;
|
|
2181
|
+
return `${value.slice(0, Math.max(0, maxChars - 3)).trimEnd()}...`;
|
|
2182
|
+
}
|
|
2183
|
+
function NativeLinkCardRenderer({
|
|
2184
|
+
item,
|
|
2185
|
+
link
|
|
2186
|
+
}) {
|
|
2187
|
+
const bounds = normalizeRect(item.bounds);
|
|
2188
|
+
const scaleX = Math.max(0.01, bounds.width / DEFAULT_LINK_CARD_SIZE.width);
|
|
2189
|
+
const scaleY = Math.max(0.01, bounds.height / DEFAULT_LINK_CARD_SIZE.height);
|
|
2190
|
+
const display = buildNativeLinkCardDisplay(link);
|
|
2191
|
+
const titleFont = reactNativeSkia.matchFont({ fontSize: 14.5, fontWeight: "700" });
|
|
2192
|
+
const subtitleFont = reactNativeSkia.matchFont({ fontSize: 12.5 });
|
|
2193
|
+
const initialFont = reactNativeSkia.matchFont({ fontSize: 17, fontWeight: "700" });
|
|
2194
|
+
const title = truncateText(display.title, 28);
|
|
2195
|
+
const subtitle = truncateText(display.subtitle, display.secure ? 28 : 31);
|
|
2196
|
+
const subtitleX = display.secure ? 82 : 69;
|
|
2197
|
+
const subtitleWidth = display.secure ? 188 : 201;
|
|
2198
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNativeSkia.Group, { transform: [{ scaleX }, { scaleY }], children: [
|
|
2199
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2200
|
+
reactNativeSkia.RoundedRect,
|
|
2201
|
+
{
|
|
2202
|
+
x: 0,
|
|
2203
|
+
y: 0,
|
|
2204
|
+
width: DEFAULT_LINK_CARD_SIZE.width,
|
|
2205
|
+
height: DEFAULT_LINK_CARD_SIZE.height,
|
|
2206
|
+
r: 16,
|
|
2207
|
+
color: "#ffffff",
|
|
2208
|
+
style: "fill",
|
|
2209
|
+
antiAlias: true
|
|
2210
|
+
}
|
|
2211
|
+
),
|
|
2212
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2213
|
+
reactNativeSkia.RoundedRect,
|
|
2214
|
+
{
|
|
2215
|
+
x: 0.5,
|
|
2216
|
+
y: 0.5,
|
|
2217
|
+
width: DEFAULT_LINK_CARD_SIZE.width - 1,
|
|
2218
|
+
height: DEFAULT_LINK_CARD_SIZE.height - 1,
|
|
2219
|
+
r: 15.5,
|
|
2220
|
+
color: "#dfe4ea",
|
|
2221
|
+
style: "stroke",
|
|
2222
|
+
strokeWidth: 1,
|
|
2223
|
+
antiAlias: true
|
|
2224
|
+
}
|
|
2225
|
+
),
|
|
2226
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2227
|
+
reactNativeSkia.RoundedRect,
|
|
2228
|
+
{
|
|
2229
|
+
x: 14,
|
|
2230
|
+
y: 14,
|
|
2231
|
+
width: 42,
|
|
2232
|
+
height: 42,
|
|
2233
|
+
r: 11,
|
|
2234
|
+
color: "#315bd6",
|
|
2235
|
+
style: "fill",
|
|
2236
|
+
antiAlias: true
|
|
2237
|
+
}
|
|
2238
|
+
),
|
|
2239
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2240
|
+
reactNativeSkia.Text,
|
|
2241
|
+
{
|
|
2242
|
+
x: 29.5,
|
|
2243
|
+
y: 41,
|
|
2244
|
+
text: display.initial,
|
|
2245
|
+
color: "#ffffff",
|
|
2246
|
+
font: initialFont
|
|
2247
|
+
}
|
|
2248
|
+
),
|
|
2249
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNativeSkia.Group, { clip: { x: 69, y: 13, width: 215, height: 24 }, children: /* @__PURE__ */ jsxRuntime.jsx(reactNativeSkia.Text, { x: 69, y: 32, text: title, color: "#1f2937", font: titleFont }) }),
|
|
2250
|
+
display.secure ? /* @__PURE__ */ jsxRuntime.jsxs(reactNativeSkia.Group, { transform: [{ translateX: 69 }, { translateY: 41 }], children: [
|
|
2251
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2252
|
+
reactNativeSkia.Rect,
|
|
2253
|
+
{
|
|
2254
|
+
x: 1.5,
|
|
2255
|
+
y: 4.5,
|
|
2256
|
+
width: 7,
|
|
2257
|
+
height: 6,
|
|
2258
|
+
color: "#6b7280",
|
|
2259
|
+
style: "stroke",
|
|
2260
|
+
strokeWidth: 1.3
|
|
2261
|
+
}
|
|
2262
|
+
),
|
|
2263
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2264
|
+
reactNativeSkia.Path,
|
|
2265
|
+
{
|
|
2266
|
+
path: "M3 4.5 V3 a2 2 0 0 1 4 0 v1.5",
|
|
2267
|
+
color: "#6b7280",
|
|
2268
|
+
style: "stroke",
|
|
2269
|
+
strokeWidth: 1.3,
|
|
2270
|
+
strokeCap: "round",
|
|
2271
|
+
strokeJoin: "round"
|
|
2272
|
+
}
|
|
2273
|
+
)
|
|
2274
|
+
] }) : null,
|
|
2275
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNativeSkia.Group, { clip: { x: subtitleX, y: 34, width: subtitleWidth, height: 22 }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2276
|
+
reactNativeSkia.Text,
|
|
2277
|
+
{
|
|
2278
|
+
x: subtitleX,
|
|
2279
|
+
y: 51,
|
|
2280
|
+
text: subtitle,
|
|
2281
|
+
color: "#6b7280",
|
|
2282
|
+
font: subtitleFont
|
|
2283
|
+
}
|
|
2284
|
+
) })
|
|
2285
|
+
] });
|
|
2286
|
+
}
|
|
1961
2287
|
function NativeShapeRenderer({ item }) {
|
|
2288
|
+
const link = getLinkData(item);
|
|
2289
|
+
if (link) {
|
|
2290
|
+
return /* @__PURE__ */ jsxRuntime.jsx(NativeLinkCardRenderer, { item, link });
|
|
2291
|
+
}
|
|
1962
2292
|
const style = resolveStrokeStyle(item);
|
|
1963
2293
|
const k = item.toolKind;
|
|
1964
2294
|
if (k === "rect") {
|
|
@@ -3381,9 +3711,14 @@ var DEFAULT_NATIVE_OVERFLOW_TOOL_IDS = [
|
|
|
3381
3711
|
"line",
|
|
3382
3712
|
"marker",
|
|
3383
3713
|
"laser",
|
|
3384
|
-
"image"
|
|
3714
|
+
"image",
|
|
3715
|
+
"link"
|
|
3385
3716
|
];
|
|
3386
3717
|
var CLOUD_TOOL_ICON_PATH = "M17.5 19H8.5a6.5 6.5 0 1 1 6.17-8.55A4.75 4.75 0 0 1 17.5 9.5a4.75 4.75 0 0 1 0 9.5Z";
|
|
3718
|
+
var LINK_TOOL_ICON_PATHS = [
|
|
3719
|
+
"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71",
|
|
3720
|
+
"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"
|
|
3721
|
+
];
|
|
3387
3722
|
function NativeCloudToolIcon({
|
|
3388
3723
|
color,
|
|
3389
3724
|
size = 19,
|
|
@@ -3402,6 +3737,25 @@ function NativeCloudToolIcon({
|
|
|
3402
3737
|
}
|
|
3403
3738
|
) }) });
|
|
3404
3739
|
}
|
|
3740
|
+
function NativeLinkToolIcon({
|
|
3741
|
+
color,
|
|
3742
|
+
size = 20,
|
|
3743
|
+
strokeWidth = 2.4
|
|
3744
|
+
}) {
|
|
3745
|
+
const scale = size / 24;
|
|
3746
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNativeSkia.Canvas, { style: { width: size, height: size }, children: /* @__PURE__ */ jsxRuntime.jsx(reactNativeSkia.Group, { transform: [{ scale }], children: LINK_TOOL_ICON_PATHS.map((path) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3747
|
+
reactNativeSkia.Path,
|
|
3748
|
+
{
|
|
3749
|
+
path,
|
|
3750
|
+
color,
|
|
3751
|
+
style: "stroke",
|
|
3752
|
+
strokeWidth,
|
|
3753
|
+
strokeCap: "round",
|
|
3754
|
+
strokeJoin: "round"
|
|
3755
|
+
},
|
|
3756
|
+
path
|
|
3757
|
+
)) }) });
|
|
3758
|
+
}
|
|
3405
3759
|
var DEFAULT_NATIVE_VECTOR_TOOLS = [
|
|
3406
3760
|
{ id: "hand", label: "Hand", shortcutHint: "H", shortLabel: "H" },
|
|
3407
3761
|
{ id: "select", label: "Select", shortcutHint: "V", shortLabel: "V" },
|
|
@@ -3439,7 +3793,8 @@ var DEFAULT_NATIVE_VECTOR_TOOLS = [
|
|
|
3439
3793
|
shortLabel: "E"
|
|
3440
3794
|
},
|
|
3441
3795
|
{ id: "text", label: "Text", shortcutHint: "T", shortLabel: "T" },
|
|
3442
|
-
{ id: "image", label: "File", shortcutHint: "I", shortLabel: "I" }
|
|
3796
|
+
{ id: "image", label: "File", shortcutHint: "I", shortLabel: "I" },
|
|
3797
|
+
{ id: "link", label: "Link", shortcutHint: "N", shortLabel: "L" }
|
|
3443
3798
|
];
|
|
3444
3799
|
function splitToolbarTools(tools, overflowToolIds) {
|
|
3445
3800
|
const overflowIds = new Set(overflowToolIds);
|
|
@@ -3701,6 +4056,9 @@ function renderNativeToolFallback(tool, foregroundColor, toolLabelStyle) {
|
|
|
3701
4056
|
if (tool.id === "architectural-cloud") {
|
|
3702
4057
|
return /* @__PURE__ */ jsxRuntime.jsx(NativeCloudToolIcon, { color: foregroundColor });
|
|
3703
4058
|
}
|
|
4059
|
+
if (tool.id === "link") {
|
|
4060
|
+
return /* @__PURE__ */ jsxRuntime.jsx(NativeLinkToolIcon, { color: foregroundColor });
|
|
4061
|
+
}
|
|
3704
4062
|
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles2.shortLabel, { color: foregroundColor }, toolLabelStyle], children: tool.shortLabel ?? tool.label.slice(0, 1).toUpperCase() });
|
|
3705
4063
|
}
|
|
3706
4064
|
var styles2 = reactNative.StyleSheet.create({
|
|
@@ -4381,6 +4739,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
4381
4739
|
onSelectionChange,
|
|
4382
4740
|
onItemsChange,
|
|
4383
4741
|
onToolChangeRequest,
|
|
4742
|
+
onLinkToolRequest,
|
|
4384
4743
|
onWorldPointerDown,
|
|
4385
4744
|
onWorldPointerMove,
|
|
4386
4745
|
onWorldPointerLeave,
|
|
@@ -4400,6 +4759,8 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
4400
4759
|
toolLockedRef.current = toolLocked;
|
|
4401
4760
|
const onToolChangeRequestRef = react.useRef(onToolChangeRequest);
|
|
4402
4761
|
onToolChangeRequestRef.current = onToolChangeRequest;
|
|
4762
|
+
const onLinkToolRequestRef = react.useRef(onLinkToolRequest);
|
|
4763
|
+
onLinkToolRequestRef.current = onLinkToolRequest;
|
|
4403
4764
|
const onWorldPointerDownRef = react.useRef(onWorldPointerDown);
|
|
4404
4765
|
onWorldPointerDownRef.current = onWorldPointerDown;
|
|
4405
4766
|
const onWorldPointerMoveRef = react.useRef(onWorldPointerMove);
|
|
@@ -4742,7 +5103,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
4742
5103
|
});
|
|
4743
5104
|
return;
|
|
4744
5105
|
}
|
|
4745
|
-
if (tool === "note" || tool === "text") {
|
|
5106
|
+
if (tool === "link" || tool === "note" || tool === "text") {
|
|
4746
5107
|
dragStateRef.current = {
|
|
4747
5108
|
kind: "tap",
|
|
4748
5109
|
tool,
|
|
@@ -5078,6 +5439,44 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
5078
5439
|
const screenDy = point.y - st.startScreen.y;
|
|
5079
5440
|
if (Math.hypot(screenDx, screenDy) > TAP_PX) return;
|
|
5080
5441
|
const change = onItemsChangeRef.current;
|
|
5442
|
+
if (st.tool === "link") {
|
|
5443
|
+
const suggestedBounds = createNativeLinkCardBoundsAtPoint(st.startWorld);
|
|
5444
|
+
const insertLink = (link, options = {}) => {
|
|
5445
|
+
const currentChange = onItemsChangeRef.current;
|
|
5446
|
+
if (!currentChange) return null;
|
|
5447
|
+
const id = options.id ?? createShapeId();
|
|
5448
|
+
const item = createLinkItem(id, options.bounds ?? suggestedBounds, link);
|
|
5449
|
+
currentChange([...itemsRef.current, item]);
|
|
5450
|
+
onSelectionChangeRef.current?.([id]);
|
|
5451
|
+
requestSelectToolAfterUse();
|
|
5452
|
+
return item;
|
|
5453
|
+
};
|
|
5454
|
+
const requestLink = onLinkToolRequestRef.current;
|
|
5455
|
+
if (requestLink) {
|
|
5456
|
+
requestLink({
|
|
5457
|
+
toolId: "link",
|
|
5458
|
+
worldX: st.startWorld.x,
|
|
5459
|
+
worldY: st.startWorld.y,
|
|
5460
|
+
screenX: st.startScreen.x,
|
|
5461
|
+
screenY: st.startScreen.y,
|
|
5462
|
+
suggestedBounds,
|
|
5463
|
+
insertLink
|
|
5464
|
+
});
|
|
5465
|
+
return;
|
|
5466
|
+
}
|
|
5467
|
+
const handleWorldPointerDown = onWorldPointerDownRef.current;
|
|
5468
|
+
if (handleWorldPointerDown) {
|
|
5469
|
+
handleWorldPointerDown({
|
|
5470
|
+
toolId: "link",
|
|
5471
|
+
worldX: st.startWorld.x,
|
|
5472
|
+
worldY: st.startWorld.y,
|
|
5473
|
+
screenX: st.startScreen.x,
|
|
5474
|
+
screenY: st.startScreen.y
|
|
5475
|
+
});
|
|
5476
|
+
requestSelectToolAfterUse();
|
|
5477
|
+
}
|
|
5478
|
+
return;
|
|
5479
|
+
}
|
|
5081
5480
|
if (!change) return;
|
|
5082
5481
|
if (st.tool === "text") {
|
|
5083
5482
|
const id = createShapeId();
|
|
@@ -5345,6 +5744,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
5345
5744
|
);
|
|
5346
5745
|
});
|
|
5347
5746
|
|
|
5747
|
+
exports.DEFAULT_LINK_CARD_SIZE = DEFAULT_LINK_CARD_SIZE;
|
|
5348
5748
|
exports.DEFAULT_NATIVE_OVERFLOW_TOOL_IDS = DEFAULT_NATIVE_OVERFLOW_TOOL_IDS;
|
|
5349
5749
|
exports.DEFAULT_NATIVE_VECTOR_TOOLS = DEFAULT_NATIVE_VECTOR_TOOLS;
|
|
5350
5750
|
exports.NATIVE_STYLE_PALETTE = NATIVE_STYLE_PALETTE;
|
|
@@ -5356,7 +5756,10 @@ exports.NativeVectorToolbar = NativeVectorToolbar;
|
|
|
5356
5756
|
exports.NativeVectorViewport = NativeVectorViewport;
|
|
5357
5757
|
exports.createFreehandStrokeItem = createFreehandStrokeItem;
|
|
5358
5758
|
exports.createImageItem = createImageItem;
|
|
5759
|
+
exports.createLinkItem = createLinkItem;
|
|
5359
5760
|
exports.createShapeId = createShapeId;
|
|
5761
|
+
exports.getLinkData = getLinkData;
|
|
5762
|
+
exports.isLinkItem = isLinkItem;
|
|
5360
5763
|
exports.nativeStyleColorWithOpacity = nativeStyleColorWithOpacity;
|
|
5361
5764
|
exports.normalizeNativeStyleHex = normalizeNativeStyleHex;
|
|
5362
5765
|
exports.parseSvgFragment = parseSvgFragment;
|