canvu-react 0.4.35 → 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.
@@ -1,5 +1,5 @@
1
1
  import { V as VectorSceneItem } from './types-BCCvY6ie.cjs';
2
- import { a as VectorViewportAssetStore } from './link-item-Dncuz2d_.cjs';
2
+ import { a as VectorViewportAssetStore } from './asset-store-TzOPvlgn.cjs';
3
3
 
4
4
  declare class IndexedDbImageStore {
5
5
  private dbPromise;
@@ -1,5 +1,5 @@
1
1
  import { V as VectorSceneItem } from './types-BCCvY6ie.js';
2
- import { a as VectorViewportAssetStore } from './link-item-voRU0Up9.js';
2
+ import { a as VectorViewportAssetStore } from './asset-store-DQPRZEcy.js';
3
3
 
4
4
  declare class IndexedDbImageStore {
5
5
  private dbPromise;
@@ -1,4 +1,4 @@
1
- import { V as VectorSceneItem, R as Rect } from './types-BCCvY6ie.js';
1
+ import { V as VectorSceneItem } from './types-BCCvY6ie.js';
2
2
 
3
3
  /**
4
4
  * Kind of binary selected through the built-in canvu asset ingestion flow.
@@ -110,42 +110,4 @@ 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: 320;
148
- readonly height: 70;
149
- };
150
-
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 };
113
+ export type { VectorViewportAssetKind as V, VectorViewportAssetStore as a, VectorViewportAssetHydrationRequest as b, VectorViewportAssetResolveRequest as c, VectorViewportAssetResolveResult as d, VectorViewportAssetUploadRequest as e, VectorViewportAssetUploadResult as f };
@@ -1,4 +1,4 @@
1
- import { V as VectorSceneItem, R as Rect } from './types-BCCvY6ie.cjs';
1
+ import { V as VectorSceneItem } from './types-BCCvY6ie.cjs';
2
2
 
3
3
  /**
4
4
  * Kind of binary selected through the built-in canvu asset ingestion flow.
@@ -110,42 +110,4 @@ 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: 320;
148
- readonly height: 70;
149
- };
150
-
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 };
113
+ export type { VectorViewportAssetKind as V, VectorViewportAssetStore as a, VectorViewportAssetHydrationRequest as b, VectorViewportAssetResolveRequest as c, VectorViewportAssetResolveResult as d, VectorViewportAssetUploadRequest as e, VectorViewportAssetUploadResult as f };
@@ -1,9 +1,10 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { C as CanvasPlugin } from './types-NBYvslB-.cjs';
2
+ import { C as CanvasPlugin } from './types-C4wI3Jyc.cjs';
3
3
  import 'react';
4
4
  import './types-BCCvY6ie.cjs';
5
5
  import './shape-builders-CKEMjivV.cjs';
6
- import './link-item-Dncuz2d_.cjs';
6
+ import './link-item-DwzXOwU5.cjs';
7
+ import './asset-store-TzOPvlgn.cjs';
7
8
  import './types-BQUbxMgz.cjs';
8
9
 
9
10
  type ChatbotPluginPanelProps = {
package/dist/chatbot.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { C as CanvasPlugin } from './types-DeDm865m.js';
2
+ import { C as CanvasPlugin } from './types-B7xZAKVJ.js';
3
3
  import 'react';
4
4
  import './types-BCCvY6ie.js';
5
5
  import './shape-builders-Cyh8zvDG.js';
6
- import './link-item-voRU0Up9.js';
6
+ import './link-item-IW4GTnxl.js';
7
+ import './asset-store-DQPRZEcy.js';
7
8
  import './types-B82WiQQh.js';
8
9
 
9
10
  type ChatbotPluginPanelProps = {
package/dist/index.d.cts CHANGED
@@ -2,8 +2,9 @@ import { C as Camera2D } from './shape-builders-CKEMjivV.cjs';
2
2
  export { a as Camera2DOptions, D as DEFAULT_STROKE_STYLE, F as FreehandSvgPayload, S as StrokeStyle, b as applyStrokeToItem, c as buildArchitecturalCloudPathD, d as buildArchitecturalCloudSvg, e as buildArrowSvg, f as buildDrawDotSvg, g as buildEllipseSvg, h as buildFreehandPathSvg, i as buildLineSvg, j as buildRectSvg, k as computeFreehandSvgPayload, l as createArchitecturalCloudItem, m as createDrawDotItem, n as createEllipseItem, o as createFreehandStrokeItem, p as createImageFromVectorTrace, q as createImageItem, r as createLineItem, s as createRectangleItem, t as createShapeId, u as createTextItem, v as lineEndpointsToLocal, w as rebuildItemSvg, x as resolveStrokeStyle } from './shape-builders-CKEMjivV.cjs';
3
3
  import { V as VectorSceneItem, A as ArrowEndpointBinding, R as Rect } from './types-BCCvY6ie.cjs';
4
4
  export { a as ArrowBindings, b as VectorPathPoint, n as normalizeRect, r as rectsIntersect } from './types-BCCvY6ie.cjs';
5
- export { H as HydratedSceneItemsWithAssetsResult, h as hydrateSceneItemsWithAssets } from './asset-hydration-BFGZ3igr.cjs';
6
- export { C as CanvuLinkData, D as DEFAULT_LINK_CARD_SIZE, L as LINK_PLUGIN_KEY, b as buildLinkCardSvg, c as createLinkItem, g as getLinkData, i as isLinkItem } from './link-item-Dncuz2d_.cjs';
5
+ export { H as HydratedSceneItemsWithAssetsResult, h as hydrateSceneItemsWithAssets } from './asset-hydration-Cy_2FyV5.cjs';
6
+ export { C as CanvuLinkData, D as DEFAULT_LINK_CARD_SIZE, L as LINK_PLUGIN_KEY, b as buildLinkCardSvg, c as createLinkItem, g as getLinkData, i as isLinkItem } from './link-item-DwzXOwU5.cjs';
7
+ import './asset-store-TzOPvlgn.cjs';
7
8
 
8
9
  type EncodeCanvasToBlobOptions = {
9
10
  mimeType?: string;
package/dist/index.d.ts CHANGED
@@ -2,8 +2,9 @@ import { C as Camera2D } from './shape-builders-Cyh8zvDG.js';
2
2
  export { a as Camera2DOptions, D as DEFAULT_STROKE_STYLE, F as FreehandSvgPayload, S as StrokeStyle, b as applyStrokeToItem, c as buildArchitecturalCloudPathD, d as buildArchitecturalCloudSvg, e as buildArrowSvg, f as buildDrawDotSvg, g as buildEllipseSvg, h as buildFreehandPathSvg, i as buildLineSvg, j as buildRectSvg, k as computeFreehandSvgPayload, l as createArchitecturalCloudItem, m as createDrawDotItem, n as createEllipseItem, o as createFreehandStrokeItem, p as createImageFromVectorTrace, q as createImageItem, r as createLineItem, s as createRectangleItem, t as createShapeId, u as createTextItem, v as lineEndpointsToLocal, w as rebuildItemSvg, x as resolveStrokeStyle } from './shape-builders-Cyh8zvDG.js';
3
3
  import { V as VectorSceneItem, A as ArrowEndpointBinding, R as Rect } from './types-BCCvY6ie.js';
4
4
  export { a as ArrowBindings, b as VectorPathPoint, n as normalizeRect, r as rectsIntersect } from './types-BCCvY6ie.js';
5
- export { H as HydratedSceneItemsWithAssetsResult, h as hydrateSceneItemsWithAssets } from './asset-hydration-D6Q3TJL1.js';
6
- export { C as CanvuLinkData, D as DEFAULT_LINK_CARD_SIZE, L as LINK_PLUGIN_KEY, b as buildLinkCardSvg, c as createLinkItem, g as getLinkData, i as isLinkItem } from './link-item-voRU0Up9.js';
5
+ export { H as HydratedSceneItemsWithAssetsResult, h as hydrateSceneItemsWithAssets } from './asset-hydration-Dc7fsnTG.js';
6
+ export { C as CanvuLinkData, D as DEFAULT_LINK_CARD_SIZE, L as LINK_PLUGIN_KEY, b as buildLinkCardSvg, c as createLinkItem, g as getLinkData, i as isLinkItem } from './link-item-IW4GTnxl.js';
7
+ import './asset-store-DQPRZEcy.js';
7
8
 
8
9
  type EncodeCanvasToBlobOptions = {
9
10
  mimeType?: string;
@@ -0,0 +1,41 @@
1
+ import { R as Rect, V as VectorSceneItem } from './types-BCCvY6ie.cjs';
2
+
3
+ /** Plugin key under which link metadata is stored on a link item's `pluginData`. */
4
+ declare const LINK_PLUGIN_KEY = "canvuLink";
5
+ /**
6
+ * Metadata describing a clickable link/bookmark item.
7
+ * `href` is required; the rest enrich the rendered card (unfurl result).
8
+ */
9
+ type CanvuLinkData = {
10
+ /** Absolute URL the card points to. */
11
+ href: string;
12
+ /** Human readable title (falls back to the hostname). */
13
+ title?: string;
14
+ /** Short description shown under the title. */
15
+ description?: string;
16
+ /** Preview image URL (og:image). */
17
+ image?: string;
18
+ /** Favicon URL shown in the leading badge. */
19
+ favicon?: string;
20
+ };
21
+ /**
22
+ * Builds the inner SVG (no outer `<svg>`) for a link/bookmark card at the given box size.
23
+ * Uses fixed pixel bands so text never overlaps regardless of the card's aspect ratio.
24
+ */
25
+ declare function buildLinkCardSvg(width: number, _height: number, link: CanvuLinkData): string;
26
+ /** Reads the link metadata from an item, or `null` when the item is not a link. */
27
+ declare function getLinkData(item: VectorSceneItem): CanvuLinkData | null;
28
+ /** True when the item carries link metadata (clickable card). */
29
+ declare function isLinkItem(item: VectorSceneItem): boolean;
30
+ /**
31
+ * Creates a clickable link/bookmark card item ready to append to the scene.
32
+ * The card resizes by scaling its authored SVG, like other custom shapes.
33
+ */
34
+ declare function createLinkItem(id: string, bounds: Rect, link: CanvuLinkData): VectorSceneItem;
35
+ /** Default card size used when placing a new link without explicit bounds. */
36
+ declare const DEFAULT_LINK_CARD_SIZE: {
37
+ readonly width: 320;
38
+ readonly height: 70;
39
+ };
40
+
41
+ export { type CanvuLinkData as C, DEFAULT_LINK_CARD_SIZE as D, LINK_PLUGIN_KEY as L, buildLinkCardSvg as b, createLinkItem as c, getLinkData as g, isLinkItem as i };
@@ -0,0 +1,41 @@
1
+ import { R as Rect, V as VectorSceneItem } from './types-BCCvY6ie.js';
2
+
3
+ /** Plugin key under which link metadata is stored on a link item's `pluginData`. */
4
+ declare const LINK_PLUGIN_KEY = "canvuLink";
5
+ /**
6
+ * Metadata describing a clickable link/bookmark item.
7
+ * `href` is required; the rest enrich the rendered card (unfurl result).
8
+ */
9
+ type CanvuLinkData = {
10
+ /** Absolute URL the card points to. */
11
+ href: string;
12
+ /** Human readable title (falls back to the hostname). */
13
+ title?: string;
14
+ /** Short description shown under the title. */
15
+ description?: string;
16
+ /** Preview image URL (og:image). */
17
+ image?: string;
18
+ /** Favicon URL shown in the leading badge. */
19
+ favicon?: string;
20
+ };
21
+ /**
22
+ * Builds the inner SVG (no outer `<svg>`) for a link/bookmark card at the given box size.
23
+ * Uses fixed pixel bands so text never overlaps regardless of the card's aspect ratio.
24
+ */
25
+ declare function buildLinkCardSvg(width: number, _height: number, link: CanvuLinkData): string;
26
+ /** Reads the link metadata from an item, or `null` when the item is not a link. */
27
+ declare function getLinkData(item: VectorSceneItem): CanvuLinkData | null;
28
+ /** True when the item carries link metadata (clickable card). */
29
+ declare function isLinkItem(item: VectorSceneItem): boolean;
30
+ /**
31
+ * Creates a clickable link/bookmark card item ready to append to the scene.
32
+ * The card resizes by scaling its authored SVG, like other custom shapes.
33
+ */
34
+ declare function createLinkItem(id: string, bounds: Rect, link: CanvuLinkData): VectorSceneItem;
35
+ /** Default card size used when placing a new link without explicit bounds. */
36
+ declare const DEFAULT_LINK_CARD_SIZE: {
37
+ readonly width: 320;
38
+ readonly height: 70;
39
+ };
40
+
41
+ export { type CanvuLinkData as C, DEFAULT_LINK_CARD_SIZE as D, LINK_PLUGIN_KEY as L, buildLinkCardSvg as b, createLinkItem as c, getLinkData as g, isLinkItem as i };
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) {
@@ -1404,6 +1449,44 @@ function smoothFreehandPointsToPathD(points) {
1404
1449
  d += ` Q ${pLast.x} ${pLast.y} ${pEnd.x} ${pEnd.y}`;
1405
1450
  return d;
1406
1451
  }
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
+ }
1407
1490
  var DEFAULT_NATIVE_IMAGE_CACHE_MAX_ENTRIES = 96;
1408
1491
  function disposeCachedImage(image) {
1409
1492
  try {
@@ -2093,7 +2176,119 @@ function localBounds(bounds) {
2093
2176
  const b = normalizeRect(bounds);
2094
2177
  return { w: Math.max(0, b.width), h: Math.max(0, b.height) };
2095
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
+ }
2096
2287
  function NativeShapeRenderer({ item }) {
2288
+ const link = getLinkData(item);
2289
+ if (link) {
2290
+ return /* @__PURE__ */ jsxRuntime.jsx(NativeLinkCardRenderer, { item, link });
2291
+ }
2097
2292
  const style = resolveStrokeStyle(item);
2098
2293
  const k = item.toolKind;
2099
2294
  if (k === "rect") {
@@ -3516,9 +3711,14 @@ var DEFAULT_NATIVE_OVERFLOW_TOOL_IDS = [
3516
3711
  "line",
3517
3712
  "marker",
3518
3713
  "laser",
3519
- "image"
3714
+ "image",
3715
+ "link"
3520
3716
  ];
3521
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
+ ];
3522
3722
  function NativeCloudToolIcon({
3523
3723
  color,
3524
3724
  size = 19,
@@ -3537,6 +3737,25 @@ function NativeCloudToolIcon({
3537
3737
  }
3538
3738
  ) }) });
3539
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
+ }
3540
3759
  var DEFAULT_NATIVE_VECTOR_TOOLS = [
3541
3760
  { id: "hand", label: "Hand", shortcutHint: "H", shortLabel: "H" },
3542
3761
  { id: "select", label: "Select", shortcutHint: "V", shortLabel: "V" },
@@ -3574,7 +3793,8 @@ var DEFAULT_NATIVE_VECTOR_TOOLS = [
3574
3793
  shortLabel: "E"
3575
3794
  },
3576
3795
  { id: "text", label: "Text", shortcutHint: "T", shortLabel: "T" },
3577
- { 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" }
3578
3798
  ];
3579
3799
  function splitToolbarTools(tools, overflowToolIds) {
3580
3800
  const overflowIds = new Set(overflowToolIds);
@@ -3836,6 +4056,9 @@ function renderNativeToolFallback(tool, foregroundColor, toolLabelStyle) {
3836
4056
  if (tool.id === "architectural-cloud") {
3837
4057
  return /* @__PURE__ */ jsxRuntime.jsx(NativeCloudToolIcon, { color: foregroundColor });
3838
4058
  }
4059
+ if (tool.id === "link") {
4060
+ return /* @__PURE__ */ jsxRuntime.jsx(NativeLinkToolIcon, { color: foregroundColor });
4061
+ }
3839
4062
  return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles2.shortLabel, { color: foregroundColor }, toolLabelStyle], children: tool.shortLabel ?? tool.label.slice(0, 1).toUpperCase() });
3840
4063
  }
3841
4064
  var styles2 = reactNative.StyleSheet.create({
@@ -4516,6 +4739,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
4516
4739
  onSelectionChange,
4517
4740
  onItemsChange,
4518
4741
  onToolChangeRequest,
4742
+ onLinkToolRequest,
4519
4743
  onWorldPointerDown,
4520
4744
  onWorldPointerMove,
4521
4745
  onWorldPointerLeave,
@@ -4535,6 +4759,8 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
4535
4759
  toolLockedRef.current = toolLocked;
4536
4760
  const onToolChangeRequestRef = react.useRef(onToolChangeRequest);
4537
4761
  onToolChangeRequestRef.current = onToolChangeRequest;
4762
+ const onLinkToolRequestRef = react.useRef(onLinkToolRequest);
4763
+ onLinkToolRequestRef.current = onLinkToolRequest;
4538
4764
  const onWorldPointerDownRef = react.useRef(onWorldPointerDown);
4539
4765
  onWorldPointerDownRef.current = onWorldPointerDown;
4540
4766
  const onWorldPointerMoveRef = react.useRef(onWorldPointerMove);
@@ -4877,7 +5103,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
4877
5103
  });
4878
5104
  return;
4879
5105
  }
4880
- if (tool === "note" || tool === "text") {
5106
+ if (tool === "link" || tool === "note" || tool === "text") {
4881
5107
  dragStateRef.current = {
4882
5108
  kind: "tap",
4883
5109
  tool,
@@ -5213,6 +5439,44 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
5213
5439
  const screenDy = point.y - st.startScreen.y;
5214
5440
  if (Math.hypot(screenDx, screenDy) > TAP_PX) return;
5215
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
+ }
5216
5480
  if (!change) return;
5217
5481
  if (st.tool === "text") {
5218
5482
  const id = createShapeId();
@@ -5480,6 +5744,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
5480
5744
  );
5481
5745
  });
5482
5746
 
5747
+ exports.DEFAULT_LINK_CARD_SIZE = DEFAULT_LINK_CARD_SIZE;
5483
5748
  exports.DEFAULT_NATIVE_OVERFLOW_TOOL_IDS = DEFAULT_NATIVE_OVERFLOW_TOOL_IDS;
5484
5749
  exports.DEFAULT_NATIVE_VECTOR_TOOLS = DEFAULT_NATIVE_VECTOR_TOOLS;
5485
5750
  exports.NATIVE_STYLE_PALETTE = NATIVE_STYLE_PALETTE;
@@ -5491,7 +5756,10 @@ exports.NativeVectorToolbar = NativeVectorToolbar;
5491
5756
  exports.NativeVectorViewport = NativeVectorViewport;
5492
5757
  exports.createFreehandStrokeItem = createFreehandStrokeItem;
5493
5758
  exports.createImageItem = createImageItem;
5759
+ exports.createLinkItem = createLinkItem;
5494
5760
  exports.createShapeId = createShapeId;
5761
+ exports.getLinkData = getLinkData;
5762
+ exports.isLinkItem = isLinkItem;
5495
5763
  exports.nativeStyleColorWithOpacity = nativeStyleColorWithOpacity;
5496
5764
  exports.normalizeNativeStyleHex = normalizeNativeStyleHex;
5497
5765
  exports.parseSvgFragment = parseSvgFragment;