canvu-react 0.4.36 → 0.4.37

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/native.d.cts CHANGED
@@ -226,13 +226,25 @@ type NativeLinkToolInsertOptions = {
226
226
  readonly id?: string;
227
227
  readonly bounds?: Rect;
228
228
  };
229
+ /**
230
+ * Copy used by the built-in native link dialog.
231
+ *
232
+ * Pass this only when you need localized or product-specific text. Omit it for
233
+ * the default plug-and-play `"link"` tool flow.
234
+ */
235
+ type NativeLinkToolDialogLabels = {
236
+ readonly title?: string;
237
+ readonly description?: string;
238
+ readonly inputPlaceholder?: string;
239
+ readonly cancelLabel?: string;
240
+ readonly addLabel?: string;
241
+ };
229
242
  /**
230
243
  * Detail passed when the built-in native `"link"` tool receives a tap.
231
244
  *
232
- * This is the high-level native integration point: show an app-native URL
233
- * dialog, then call {@link NativeLinkToolRequestDetail.insertLink} with the
234
- * submitted link metadata. Use `onWorldPointerDown` only for fully custom tools
235
- * or when you do not want canvu to insert the card.
245
+ * The default flow shows canvu's built-in URL dialog and inserts the card after
246
+ * submit. Use this detail only when overriding that dialog through
247
+ * `onLinkToolRequest`.
236
248
  *
237
249
  * @example
238
250
  * ```tsx
@@ -266,13 +278,14 @@ type NativeVectorViewportProps = {
266
278
  readonly onItemsChange?: (items: VectorSceneItem[]) => void;
267
279
  readonly onToolChangeRequest?: (toolId: string) => void;
268
280
  /**
269
- * Called after the built-in native `"link"` tool is tapped on the canvas.
281
+ * Optional override for the built-in native link dialog.
270
282
  *
271
- * Use this to open your app's native modal or sheet for URL entry. Call
272
- * `detail.insertLink(...)` after the user confirms to append and select the
273
- * link card at the tapped world point.
283
+ * Omit this for the plug-and-play first-party link tool. When supplied,
284
+ * canvu will not show its default dialog; your app is responsible for
285
+ * calling `detail.insertLink(...)`.
274
286
  */
275
287
  readonly onLinkToolRequest?: (detail: NativeLinkToolRequestDetail) => void;
288
+ readonly linkToolDialogLabels?: NativeLinkToolDialogLabels;
276
289
  readonly onWorldPointerDown?: (detail: NativeWorldPointerDownDetail) => void;
277
290
  readonly onWorldPointerMove?: (world: {
278
291
  readonly x: number;
@@ -419,4 +432,4 @@ type SvgNode = SvgRectNode | SvgEllipseNode | SvgCircleNode | SvgLineNode | SvgP
419
432
  */
420
433
  declare function parseSvgFragment(xml: string): SvgNode[];
421
434
 
422
- export { CanvuLinkData, DEFAULT_NATIVE_OVERFLOW_TOOL_IDS, DEFAULT_NATIVE_VECTOR_TOOLS, NATIVE_STYLE_PALETTE, type NativeCustomShapePlacementOptions, NativeInteractionOverlay, type NativeInteractionOverlayProps, type NativeLinkToolInsertOptions, type NativeLinkToolRequestDetail, NativeSceneRenderer, type NativeSceneRendererProps, NativeShapeRenderer, type NativeShapeRendererProps, type NativeStyleColor, NativeVectorStyleInspector, type NativeVectorStyleInspectorProps, type NativeVectorStyleToolId, type NativeVectorToolDefinition, NativeVectorToolbar, type NativeVectorToolbarDensity, type NativeVectorToolbarProps, type NativeVectorToolbarRenderOverflowInput, type NativeVectorToolbarRenderToolInput, type NativeVectorToolbarRenderToolLockInput, NativeVectorViewport, type NativeVectorViewportHandle, type NativeVectorViewportProps, type NativeWorldPointerDownDetail, type PlacementPreview, type SvgNode, VectorSceneItem, nativeStyleColorWithOpacity, normalizeNativeStyleHex, parseSvgFragment };
435
+ export { CanvuLinkData, DEFAULT_NATIVE_OVERFLOW_TOOL_IDS, DEFAULT_NATIVE_VECTOR_TOOLS, NATIVE_STYLE_PALETTE, type NativeCustomShapePlacementOptions, NativeInteractionOverlay, type NativeInteractionOverlayProps, type NativeLinkToolDialogLabels, type NativeLinkToolInsertOptions, type NativeLinkToolRequestDetail, NativeSceneRenderer, type NativeSceneRendererProps, NativeShapeRenderer, type NativeShapeRendererProps, type NativeStyleColor, NativeVectorStyleInspector, type NativeVectorStyleInspectorProps, type NativeVectorStyleToolId, type NativeVectorToolDefinition, NativeVectorToolbar, type NativeVectorToolbarDensity, type NativeVectorToolbarProps, type NativeVectorToolbarRenderOverflowInput, type NativeVectorToolbarRenderToolInput, type NativeVectorToolbarRenderToolLockInput, NativeVectorViewport, type NativeVectorViewportHandle, type NativeVectorViewportProps, type NativeWorldPointerDownDetail, type PlacementPreview, type SvgNode, VectorSceneItem, nativeStyleColorWithOpacity, normalizeNativeStyleHex, parseSvgFragment };
package/dist/native.d.ts CHANGED
@@ -226,13 +226,25 @@ type NativeLinkToolInsertOptions = {
226
226
  readonly id?: string;
227
227
  readonly bounds?: Rect;
228
228
  };
229
+ /**
230
+ * Copy used by the built-in native link dialog.
231
+ *
232
+ * Pass this only when you need localized or product-specific text. Omit it for
233
+ * the default plug-and-play `"link"` tool flow.
234
+ */
235
+ type NativeLinkToolDialogLabels = {
236
+ readonly title?: string;
237
+ readonly description?: string;
238
+ readonly inputPlaceholder?: string;
239
+ readonly cancelLabel?: string;
240
+ readonly addLabel?: string;
241
+ };
229
242
  /**
230
243
  * Detail passed when the built-in native `"link"` tool receives a tap.
231
244
  *
232
- * This is the high-level native integration point: show an app-native URL
233
- * dialog, then call {@link NativeLinkToolRequestDetail.insertLink} with the
234
- * submitted link metadata. Use `onWorldPointerDown` only for fully custom tools
235
- * or when you do not want canvu to insert the card.
245
+ * The default flow shows canvu's built-in URL dialog and inserts the card after
246
+ * submit. Use this detail only when overriding that dialog through
247
+ * `onLinkToolRequest`.
236
248
  *
237
249
  * @example
238
250
  * ```tsx
@@ -266,13 +278,14 @@ type NativeVectorViewportProps = {
266
278
  readonly onItemsChange?: (items: VectorSceneItem[]) => void;
267
279
  readonly onToolChangeRequest?: (toolId: string) => void;
268
280
  /**
269
- * Called after the built-in native `"link"` tool is tapped on the canvas.
281
+ * Optional override for the built-in native link dialog.
270
282
  *
271
- * Use this to open your app's native modal or sheet for URL entry. Call
272
- * `detail.insertLink(...)` after the user confirms to append and select the
273
- * link card at the tapped world point.
283
+ * Omit this for the plug-and-play first-party link tool. When supplied,
284
+ * canvu will not show its default dialog; your app is responsible for
285
+ * calling `detail.insertLink(...)`.
274
286
  */
275
287
  readonly onLinkToolRequest?: (detail: NativeLinkToolRequestDetail) => void;
288
+ readonly linkToolDialogLabels?: NativeLinkToolDialogLabels;
276
289
  readonly onWorldPointerDown?: (detail: NativeWorldPointerDownDetail) => void;
277
290
  readonly onWorldPointerMove?: (world: {
278
291
  readonly x: number;
@@ -419,4 +432,4 @@ type SvgNode = SvgRectNode | SvgEllipseNode | SvgCircleNode | SvgLineNode | SvgP
419
432
  */
420
433
  declare function parseSvgFragment(xml: string): SvgNode[];
421
434
 
422
- export { CanvuLinkData, DEFAULT_NATIVE_OVERFLOW_TOOL_IDS, DEFAULT_NATIVE_VECTOR_TOOLS, NATIVE_STYLE_PALETTE, type NativeCustomShapePlacementOptions, NativeInteractionOverlay, type NativeInteractionOverlayProps, type NativeLinkToolInsertOptions, type NativeLinkToolRequestDetail, NativeSceneRenderer, type NativeSceneRendererProps, NativeShapeRenderer, type NativeShapeRendererProps, type NativeStyleColor, NativeVectorStyleInspector, type NativeVectorStyleInspectorProps, type NativeVectorStyleToolId, type NativeVectorToolDefinition, NativeVectorToolbar, type NativeVectorToolbarDensity, type NativeVectorToolbarProps, type NativeVectorToolbarRenderOverflowInput, type NativeVectorToolbarRenderToolInput, type NativeVectorToolbarRenderToolLockInput, NativeVectorViewport, type NativeVectorViewportHandle, type NativeVectorViewportProps, type NativeWorldPointerDownDetail, type PlacementPreview, type SvgNode, VectorSceneItem, nativeStyleColorWithOpacity, normalizeNativeStyleHex, parseSvgFragment };
435
+ export { CanvuLinkData, DEFAULT_NATIVE_OVERFLOW_TOOL_IDS, DEFAULT_NATIVE_VECTOR_TOOLS, NATIVE_STYLE_PALETTE, type NativeCustomShapePlacementOptions, NativeInteractionOverlay, type NativeInteractionOverlayProps, type NativeLinkToolDialogLabels, type NativeLinkToolInsertOptions, type NativeLinkToolRequestDetail, NativeSceneRenderer, type NativeSceneRendererProps, NativeShapeRenderer, type NativeShapeRendererProps, type NativeStyleColor, NativeVectorStyleInspector, type NativeVectorStyleInspectorProps, type NativeVectorStyleToolId, type NativeVectorToolDefinition, NativeVectorToolbar, type NativeVectorToolbarDensity, type NativeVectorToolbarProps, type NativeVectorToolbarRenderOverflowInput, type NativeVectorToolbarRenderToolInput, type NativeVectorToolbarRenderToolLockInput, NativeVectorViewport, type NativeVectorViewportHandle, type NativeVectorViewportProps, type NativeWorldPointerDownDetail, type PlacementPreview, type SvgNode, VectorSceneItem, nativeStyleColorWithOpacity, normalizeNativeStyleHex, parseSvgFragment };
package/dist/native.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import getStroke from 'perfect-freehand';
2
- import { Group, Canvas, Rect, Circle, Path, RoundedRect, Oval, DashPathEffect, Line, vec, matchFont, Text, Image } from '@shopify/react-native-skia';
2
+ import { Group, Canvas, Rect, Circle, Path, RoundedRect, Oval, DashPathEffect, Line, vec, matchFont, Text as Text$1, Image } from '@shopify/react-native-skia';
3
3
  import { memo, forwardRef, useState, useRef, useCallback, useEffect, useMemo, useImperativeHandle } from 'react';
4
4
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
- import { StyleSheet, PanResponder, View, Pressable, Text as Text$1, ScrollView } from 'react-native';
5
+ import { StyleSheet, PanResponder, View, Modal, Text, TextInput, Pressable, ScrollView } from 'react-native';
6
6
 
7
7
  // src/math/rect.ts
8
8
  function rectsIntersect(a, b) {
@@ -1463,6 +1463,12 @@ function linkInitial(value) {
1463
1463
  const first = value.trim().charAt(0).toUpperCase();
1464
1464
  return first || "L";
1465
1465
  }
1466
+ function normalizeNativeLinkHref(value) {
1467
+ const trimmed = value.trim();
1468
+ if (!trimmed) return null;
1469
+ if (/^[a-z][a-z0-9+.-]*:/i.test(trimmed)) return trimmed;
1470
+ return `https://${trimmed}`;
1471
+ }
1466
1472
  function buildNativeLinkCardDisplay(link) {
1467
1473
  const hostname = linkHostname(link.href);
1468
1474
  const title = link.title?.trim() || hostname || "Link";
@@ -1840,7 +1846,7 @@ function SvgNodeItem({ node }) {
1840
1846
  const fs = node.fontSize != null ? toNum(node.fontSize) : 16;
1841
1847
  const font = matchFont({ fontSize: fs });
1842
1848
  return /* @__PURE__ */ jsx(Fragment, { children: node.children.map((tspan, i) => /* @__PURE__ */ jsx(
1843
- Text,
1849
+ Text$1,
1844
1850
  {
1845
1851
  x: tspan.x != null ? toNum(tspan.x) : node.x != null ? toNum(node.x) : 0,
1846
1852
  y: tspan.dy != null ? (node.y != null ? toNum(node.y) : fs) + toNum(tspan.dy) : (node.y != null ? toNum(node.y) : fs) + i * fs * 1.2,
@@ -2231,7 +2237,7 @@ function NativeLinkCardRenderer({
2231
2237
  }
2232
2238
  ),
2233
2239
  /* @__PURE__ */ jsx(
2234
- Text,
2240
+ Text$1,
2235
2241
  {
2236
2242
  x: 29.5,
2237
2243
  y: 41,
@@ -2240,7 +2246,7 @@ function NativeLinkCardRenderer({
2240
2246
  font: initialFont
2241
2247
  }
2242
2248
  ),
2243
- /* @__PURE__ */ jsx(Group, { clip: { x: 69, y: 13, width: 215, height: 24 }, children: /* @__PURE__ */ jsx(Text, { x: 69, y: 32, text: title, color: "#1f2937", font: titleFont }) }),
2249
+ /* @__PURE__ */ jsx(Group, { clip: { x: 69, y: 13, width: 215, height: 24 }, children: /* @__PURE__ */ jsx(Text$1, { x: 69, y: 32, text: title, color: "#1f2937", font: titleFont }) }),
2244
2250
  display.secure ? /* @__PURE__ */ jsxs(Group, { transform: [{ translateX: 69 }, { translateY: 41 }], children: [
2245
2251
  /* @__PURE__ */ jsx(
2246
2252
  Rect,
@@ -2267,7 +2273,7 @@ function NativeLinkCardRenderer({
2267
2273
  )
2268
2274
  ] }) : null,
2269
2275
  /* @__PURE__ */ jsx(Group, { clip: { x: subtitleX, y: 34, width: subtitleWidth, height: 22 }, children: /* @__PURE__ */ jsx(
2270
- Text,
2276
+ Text$1,
2271
2277
  {
2272
2278
  x: subtitleX,
2273
2279
  y: 51,
@@ -2415,7 +2421,7 @@ function NativeShapeRenderer({ item }) {
2415
2421
  const lines = item.text.split("\n");
2416
2422
  const font = matchFont({ fontSize: fs });
2417
2423
  return /* @__PURE__ */ jsx(Fragment, { children: lines.map((line, i) => /* @__PURE__ */ jsx(
2418
- Text,
2424
+ Text$1,
2419
2425
  {
2420
2426
  x: 0,
2421
2427
  y: fs + i * fs * 1.2,
@@ -3161,7 +3167,7 @@ function NativeInteractionOverlay({
3161
3167
  }
3162
3168
  ),
3163
3169
  peer.displayName ? /* @__PURE__ */ jsx(
3164
- Text,
3170
+ Text$1,
3165
3171
  {
3166
3172
  x: cursor.x + labelOffsetX,
3167
3173
  y: cursor.y + labelOffsetY,
@@ -3435,7 +3441,7 @@ function RangeControl({
3435
3441
  ]
3436
3442
  }
3437
3443
  ),
3438
- valueLabel ? /* @__PURE__ */ jsx(Text$1, { style: styles.rangeValue, children: valueLabel }) : null
3444
+ valueLabel ? /* @__PURE__ */ jsx(Text, { style: styles.rangeValue, children: valueLabel }) : null
3439
3445
  ] });
3440
3446
  }
3441
3447
  function InspectorSection({
@@ -3443,7 +3449,7 @@ function InspectorSection({
3443
3449
  children
3444
3450
  }) {
3445
3451
  return /* @__PURE__ */ jsxs(View, { style: styles.section, children: [
3446
- /* @__PURE__ */ jsx(Text$1, { style: styles.sectionLabel, children: label }),
3452
+ /* @__PURE__ */ jsx(Text, { style: styles.sectionLabel, children: label }),
3447
3453
  children
3448
3454
  ] });
3449
3455
  }
@@ -3465,7 +3471,7 @@ function SegmentControl({
3465
3471
  children: [
3466
3472
  segment.preview,
3467
3473
  /* @__PURE__ */ jsx(
3468
- Text$1,
3474
+ Text,
3469
3475
  {
3470
3476
  style: [
3471
3477
  styles.segmentLabel,
@@ -3911,7 +3917,7 @@ function NativeVectorToolbar({
3911
3917
  disabled: toolLockDisabled,
3912
3918
  foregroundColor: "#18181b",
3913
3919
  onToggle: toggleToolLock
3914
- }) ?? /* @__PURE__ */ jsx(Text$1, { style: styles2.lockGlyph, children: toolLocked ? "L" : "U" })
3920
+ }) ?? /* @__PURE__ */ jsx(Text, { style: styles2.lockGlyph, children: toolLocked ? "L" : "U" })
3915
3921
  }
3916
3922
  ),
3917
3923
  /* @__PURE__ */ jsx(View, { style: styles2.toolLockDivider })
@@ -3958,8 +3964,8 @@ function NativeVectorToolbar({
3958
3964
  disabled,
3959
3965
  foregroundColor: "#18181b",
3960
3966
  onSelect: () => onChange(activeOverflowTool.id)
3961
- }) ?? renderNativeToolFallback(activeOverflowTool, "#18181b") : renderOverflowIcon?.(overflowRenderInput) ?? /* @__PURE__ */ jsx(Text$1, { style: styles2.shapesGlyph, children: "S" }) }),
3962
- renderOverflowChevronIcon?.(overflowRenderInput) ?? /* @__PURE__ */ jsx(Text$1, { style: styles2.chevronGlyph, children: overflowOpen ? "^" : "v" })
3967
+ }) ?? renderNativeToolFallback(activeOverflowTool, "#18181b") : renderOverflowIcon?.(overflowRenderInput) ?? /* @__PURE__ */ jsx(Text, { style: styles2.shapesGlyph, children: "S" }) }),
3968
+ renderOverflowChevronIcon?.(overflowRenderInput) ?? /* @__PURE__ */ jsx(Text, { style: styles2.chevronGlyph, children: overflowOpen ? "^" : "v" })
3963
3969
  ]
3964
3970
  }
3965
3971
  ) : null
@@ -4029,7 +4035,7 @@ function renderNativeToolButton(input) {
4029
4035
  children: [
4030
4036
  /* @__PURE__ */ jsx(View, { style: styles2.iconSlot, children: icon }),
4031
4037
  input.density === "comfortable" ? /* @__PURE__ */ jsx(
4032
- Text$1,
4038
+ Text,
4033
4039
  {
4034
4040
  numberOfLines: 1,
4035
4041
  style: [
@@ -4053,7 +4059,7 @@ function renderNativeToolFallback(tool, foregroundColor, toolLabelStyle) {
4053
4059
  if (tool.id === "link") {
4054
4060
  return /* @__PURE__ */ jsx(NativeLinkToolIcon, { color: foregroundColor });
4055
4061
  }
4056
- return /* @__PURE__ */ jsx(Text$1, { style: [styles2.shortLabel, { color: foregroundColor }, toolLabelStyle], children: tool.shortLabel ?? tool.label.slice(0, 1).toUpperCase() });
4062
+ return /* @__PURE__ */ jsx(Text, { style: [styles2.shortLabel, { color: foregroundColor }, toolLabelStyle], children: tool.shortLabel ?? tool.label.slice(0, 1).toUpperCase() });
4057
4063
  }
4058
4064
  var styles2 = StyleSheet.create({
4059
4065
  shell: {
@@ -4651,6 +4657,13 @@ function resizeItemByHandle(item, start, handle, currentWorld) {
4651
4657
  }
4652
4658
  return { ...item, x: nb.x, y: nb.y, bounds: nb };
4653
4659
  }
4660
+ var DEFAULT_NATIVE_LINK_TOOL_DIALOG_LABELS = {
4661
+ title: "Add link",
4662
+ description: "Paste the link you want to add to the board.",
4663
+ inputPlaceholder: "https://example.com",
4664
+ cancelLabel: "Cancel",
4665
+ addLabel: "Add"
4666
+ };
4654
4667
  var MIN_PLACE_SIZE = 8;
4655
4668
  var MIN_ARROW_DRAG_PX = 8;
4656
4669
  var TAP_PX = 20;
@@ -4734,6 +4747,7 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
4734
4747
  onItemsChange,
4735
4748
  onToolChangeRequest,
4736
4749
  onLinkToolRequest,
4750
+ linkToolDialogLabels,
4737
4751
  onWorldPointerDown,
4738
4752
  onWorldPointerMove,
4739
4753
  onWorldPointerLeave,
@@ -4788,6 +4802,8 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
4788
4802
  );
4789
4803
  const [eraserTrail, setEraserTrail] = useState([]);
4790
4804
  const [laserTrail, setLaserTrail] = useState([]);
4805
+ const [pendingNativeLinkRequest, setPendingNativeLinkRequest] = useState(null);
4806
+ const [nativeLinkInputValue, setNativeLinkInputValue] = useState("");
4791
4807
  const laserClearTimerRef = useRef(null);
4792
4808
  const strokeStyleRef = useRef({ ...DEFAULT_STROKE_STYLE });
4793
4809
  const markerStrokeStyleRef = useRef({ ...MARKER_TOOL_STYLE });
@@ -4865,6 +4881,21 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
4865
4881
  onToolChangeRequestRef.current?.("select");
4866
4882
  }
4867
4883
  }, []);
4884
+ const requestSelectToolAfterNativeLinkUse = useCallback(() => {
4885
+ onToolChangeRequestRef.current?.("select");
4886
+ }, []);
4887
+ const closeNativeLinkDialog = useCallback(() => {
4888
+ setPendingNativeLinkRequest(null);
4889
+ setNativeLinkInputValue("");
4890
+ }, []);
4891
+ const submitNativeLinkDialog = useCallback(() => {
4892
+ const href = normalizeNativeLinkHref(nativeLinkInputValue);
4893
+ if (!href || !pendingNativeLinkRequest) return;
4894
+ const inserted = pendingNativeLinkRequest.insertLink({ href });
4895
+ if (inserted) {
4896
+ closeNativeLinkDialog();
4897
+ }
4898
+ }, [closeNativeLinkDialog, nativeLinkInputValue, pendingNativeLinkRequest]);
4868
4899
  if (!cameraRef.current) {
4869
4900
  cameraRef.current = new Camera2D({ minZoom: 0.05, maxZoom: 32 });
4870
4901
  }
@@ -5442,7 +5473,7 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
5442
5473
  const item = createLinkItem(id, options.bounds ?? suggestedBounds, link);
5443
5474
  currentChange([...itemsRef.current, item]);
5444
5475
  onSelectionChangeRef.current?.([id]);
5445
- requestSelectToolAfterUse();
5476
+ requestSelectToolAfterNativeLinkUse();
5446
5477
  return item;
5447
5478
  };
5448
5479
  const requestLink = onLinkToolRequestRef.current;
@@ -5458,17 +5489,16 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
5458
5489
  });
5459
5490
  return;
5460
5491
  }
5461
- const handleWorldPointerDown = onWorldPointerDownRef.current;
5462
- if (handleWorldPointerDown) {
5463
- handleWorldPointerDown({
5464
- toolId: "link",
5465
- worldX: st.startWorld.x,
5466
- worldY: st.startWorld.y,
5467
- screenX: st.startScreen.x,
5468
- screenY: st.startScreen.y
5469
- });
5470
- requestSelectToolAfterUse();
5471
- }
5492
+ setNativeLinkInputValue("");
5493
+ setPendingNativeLinkRequest({
5494
+ toolId: "link",
5495
+ worldX: st.startWorld.x,
5496
+ worldY: st.startWorld.y,
5497
+ screenX: st.startScreen.x,
5498
+ screenY: st.startScreen.y,
5499
+ suggestedBounds,
5500
+ insertLink
5501
+ });
5472
5502
  return;
5473
5503
  }
5474
5504
  if (!change) return;
@@ -5518,6 +5548,7 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
5518
5548
  dragStateRef.current = { kind: "idle" };
5519
5549
  },
5520
5550
  [
5551
+ requestSelectToolAfterNativeLinkUse,
5521
5552
  requestSelectToolAfterUse,
5522
5553
  screenToWorld,
5523
5554
  setRealtimePlacementPreview,
@@ -5649,7 +5680,13 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
5649
5680
  [requestRender, size]
5650
5681
  );
5651
5682
  const activeStyleToolId = toolId === "draw" || toolId === "marker" ? toolId : null;
5652
- return /* @__PURE__ */ jsx(
5683
+ const nativeLinkDialogLabels = {
5684
+ ...DEFAULT_NATIVE_LINK_TOOL_DIALOG_LABELS,
5685
+ ...linkToolDialogLabels ?? {}
5686
+ };
5687
+ const normalizedNativeLinkHref = normalizeNativeLinkHref(nativeLinkInputValue);
5688
+ const nativeLinkCanSubmit = pendingNativeLinkRequest !== null && normalizedNativeLinkHref !== null && onItemsChange != null;
5689
+ return /* @__PURE__ */ jsxs(
5653
5690
  View,
5654
5691
  {
5655
5692
  style: { flex: 1, overflow: "hidden" },
@@ -5663,80 +5700,225 @@ var NativeVectorViewport = forwardRef(function NativeVectorViewport2({
5663
5700
  notifyWorldPointerLeave();
5664
5701
  },
5665
5702
  ...panResponder.panHandlers,
5666
- children: size.width > 0 && size.height > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
5703
+ children: [
5704
+ size.width > 0 && size.height > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
5705
+ /* @__PURE__ */ jsx(
5706
+ NativeSceneRenderer,
5707
+ {
5708
+ items: sceneItems,
5709
+ camera,
5710
+ width: size.width,
5711
+ height: size.height
5712
+ }
5713
+ ),
5714
+ interactive && /* @__PURE__ */ jsx(
5715
+ NativeInteractionOverlay,
5716
+ {
5717
+ camera,
5718
+ width: size.width,
5719
+ height: size.height,
5720
+ selectedItems,
5721
+ showResizeHandles,
5722
+ placementPreview,
5723
+ laserTrail,
5724
+ eraserTrail,
5725
+ eraserPreviewItems: items.filter(
5726
+ (it) => eraserPreviewIds.includes(it.id)
5727
+ ),
5728
+ previewStrokeStyle: strokeStyleState,
5729
+ remotePresence
5730
+ }
5731
+ ),
5732
+ interactive && showStyleInspector && activeStyleToolId ? /* @__PURE__ */ jsx(
5733
+ View,
5734
+ {
5735
+ pointerEvents: "box-none",
5736
+ style: styleInspectorPlacement === "top-left" ? {
5737
+ position: "absolute",
5738
+ left: 16,
5739
+ top: 104,
5740
+ alignItems: "flex-start"
5741
+ } : {
5742
+ position: "absolute",
5743
+ left: 16,
5744
+ right: 16,
5745
+ bottom: 84,
5746
+ alignItems: "center"
5747
+ },
5748
+ children: /* @__PURE__ */ jsx(
5749
+ NativeVectorStyleInspector,
5750
+ {
5751
+ toolId: activeStyleToolId,
5752
+ value: strokeStyleState,
5753
+ onChange: patchCurrentStrokeStyle
5754
+ }
5755
+ )
5756
+ }
5757
+ ) : null,
5758
+ toolbar && /* @__PURE__ */ jsx(
5759
+ View,
5760
+ {
5761
+ style: {
5762
+ position: "absolute",
5763
+ bottom: 16,
5764
+ left: 16,
5765
+ right: 16,
5766
+ flexDirection: "row",
5767
+ justifyContent: "center",
5768
+ alignItems: "center"
5769
+ },
5770
+ pointerEvents: "box-none",
5771
+ children: toolbar
5772
+ }
5773
+ )
5774
+ ] }),
5667
5775
  /* @__PURE__ */ jsx(
5668
- NativeSceneRenderer,
5669
- {
5670
- items: sceneItems,
5671
- camera,
5672
- width: size.width,
5673
- height: size.height
5674
- }
5675
- ),
5676
- interactive && /* @__PURE__ */ jsx(
5677
- NativeInteractionOverlay,
5678
- {
5679
- camera,
5680
- width: size.width,
5681
- height: size.height,
5682
- selectedItems,
5683
- showResizeHandles,
5684
- placementPreview,
5685
- laserTrail,
5686
- eraserTrail,
5687
- eraserPreviewItems: items.filter(
5688
- (it) => eraserPreviewIds.includes(it.id)
5689
- ),
5690
- previewStrokeStyle: strokeStyleState,
5691
- remotePresence
5692
- }
5693
- ),
5694
- interactive && showStyleInspector && activeStyleToolId ? /* @__PURE__ */ jsx(
5695
- View,
5776
+ Modal,
5696
5777
  {
5697
- pointerEvents: "box-none",
5698
- style: styleInspectorPlacement === "top-left" ? {
5699
- position: "absolute",
5700
- left: 16,
5701
- top: 104,
5702
- alignItems: "flex-start"
5703
- } : {
5704
- position: "absolute",
5705
- left: 16,
5706
- right: 16,
5707
- bottom: 84,
5708
- alignItems: "center"
5709
- },
5710
- children: /* @__PURE__ */ jsx(
5711
- NativeVectorStyleInspector,
5712
- {
5713
- toolId: activeStyleToolId,
5714
- value: strokeStyleState,
5715
- onChange: patchCurrentStrokeStyle
5716
- }
5717
- )
5718
- }
5719
- ) : null,
5720
- toolbar && /* @__PURE__ */ jsx(
5721
- View,
5722
- {
5723
- style: {
5724
- position: "absolute",
5725
- bottom: 16,
5726
- left: 16,
5727
- right: 16,
5728
- flexDirection: "row",
5729
- justifyContent: "center",
5730
- alignItems: "center"
5731
- },
5732
- pointerEvents: "box-none",
5733
- children: toolbar
5778
+ animationType: "fade",
5779
+ transparent: true,
5780
+ visible: pendingNativeLinkRequest !== null,
5781
+ onRequestClose: closeNativeLinkDialog,
5782
+ children: /* @__PURE__ */ jsx(View, { style: styles3.nativeLinkDialogBackdrop, children: /* @__PURE__ */ jsxs(View, { style: styles3.nativeLinkDialogCard, children: [
5783
+ /* @__PURE__ */ jsx(Text, { style: styles3.nativeLinkDialogTitle, children: nativeLinkDialogLabels.title }),
5784
+ /* @__PURE__ */ jsx(Text, { style: styles3.nativeLinkDialogDescription, children: nativeLinkDialogLabels.description }),
5785
+ /* @__PURE__ */ jsx(
5786
+ TextInput,
5787
+ {
5788
+ accessibilityLabel: nativeLinkDialogLabels.title,
5789
+ autoCapitalize: "none",
5790
+ autoCorrect: false,
5791
+ keyboardType: "url",
5792
+ onChangeText: setNativeLinkInputValue,
5793
+ onSubmitEditing: submitNativeLinkDialog,
5794
+ placeholder: nativeLinkDialogLabels.inputPlaceholder,
5795
+ returnKeyType: "done",
5796
+ style: styles3.nativeLinkDialogInput,
5797
+ value: nativeLinkInputValue
5798
+ }
5799
+ ),
5800
+ /* @__PURE__ */ jsxs(View, { style: styles3.nativeLinkDialogActions, children: [
5801
+ /* @__PURE__ */ jsx(
5802
+ Pressable,
5803
+ {
5804
+ accessibilityRole: "button",
5805
+ onPress: closeNativeLinkDialog,
5806
+ style: ({ pressed }) => [
5807
+ styles3.nativeLinkDialogButton,
5808
+ pressed ? styles3.nativeLinkDialogButtonPressed : void 0
5809
+ ],
5810
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.nativeLinkDialogButtonText, children: nativeLinkDialogLabels.cancelLabel })
5811
+ }
5812
+ ),
5813
+ /* @__PURE__ */ jsx(
5814
+ Pressable,
5815
+ {
5816
+ accessibilityRole: "button",
5817
+ accessibilityState: { disabled: !nativeLinkCanSubmit },
5818
+ disabled: !nativeLinkCanSubmit,
5819
+ onPress: submitNativeLinkDialog,
5820
+ style: ({ pressed }) => [
5821
+ styles3.nativeLinkDialogButton,
5822
+ styles3.nativeLinkDialogPrimaryButton,
5823
+ pressed && nativeLinkCanSubmit ? styles3.nativeLinkDialogPrimaryButtonPressed : void 0,
5824
+ !nativeLinkCanSubmit ? styles3.nativeLinkDialogDisabledButton : void 0
5825
+ ],
5826
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.nativeLinkDialogPrimaryButtonText, children: nativeLinkDialogLabels.addLabel })
5827
+ }
5828
+ )
5829
+ ] })
5830
+ ] }) })
5734
5831
  }
5735
5832
  )
5736
- ] })
5833
+ ]
5737
5834
  }
5738
5835
  );
5739
5836
  });
5837
+ var styles3 = StyleSheet.create({
5838
+ nativeLinkDialogBackdrop: {
5839
+ flex: 1,
5840
+ alignItems: "center",
5841
+ justifyContent: "center",
5842
+ paddingHorizontal: 24,
5843
+ backgroundColor: "rgba(0, 0, 0, 0.45)"
5844
+ },
5845
+ nativeLinkDialogCard: {
5846
+ width: "100%",
5847
+ maxWidth: 480,
5848
+ padding: 24,
5849
+ borderRadius: 16,
5850
+ backgroundColor: "#ffffff",
5851
+ shadowColor: "#000000",
5852
+ shadowOpacity: 0.18,
5853
+ shadowRadius: 24,
5854
+ shadowOffset: { width: 0, height: 8 },
5855
+ elevation: 12
5856
+ },
5857
+ nativeLinkDialogTitle: {
5858
+ color: "#111827",
5859
+ fontSize: 24,
5860
+ fontWeight: "700",
5861
+ lineHeight: 30
5862
+ },
5863
+ nativeLinkDialogDescription: {
5864
+ marginTop: 12,
5865
+ color: "#6b7280",
5866
+ fontSize: 16,
5867
+ lineHeight: 22
5868
+ },
5869
+ nativeLinkDialogInput: {
5870
+ marginTop: 24,
5871
+ height: 52,
5872
+ paddingHorizontal: 14,
5873
+ borderRadius: 10,
5874
+ borderWidth: StyleSheet.hairlineWidth,
5875
+ borderColor: "#d1d5db",
5876
+ color: "#111827",
5877
+ fontSize: 18,
5878
+ backgroundColor: "#ffffff"
5879
+ },
5880
+ nativeLinkDialogActions: {
5881
+ marginTop: 24,
5882
+ flexDirection: "row",
5883
+ justifyContent: "flex-end",
5884
+ gap: 12
5885
+ },
5886
+ nativeLinkDialogButton: {
5887
+ minWidth: 92,
5888
+ height: 48,
5889
+ alignItems: "center",
5890
+ justifyContent: "center",
5891
+ borderRadius: 10,
5892
+ borderWidth: StyleSheet.hairlineWidth,
5893
+ borderColor: "#d1d5db",
5894
+ backgroundColor: "#ffffff",
5895
+ paddingHorizontal: 18
5896
+ },
5897
+ nativeLinkDialogButtonPressed: {
5898
+ backgroundColor: "#f3f4f6"
5899
+ },
5900
+ nativeLinkDialogButtonText: {
5901
+ color: "#111827",
5902
+ fontSize: 17,
5903
+ fontWeight: "600"
5904
+ },
5905
+ nativeLinkDialogPrimaryButton: {
5906
+ borderColor: "#18181b",
5907
+ backgroundColor: "#18181b"
5908
+ },
5909
+ nativeLinkDialogPrimaryButtonPressed: {
5910
+ backgroundColor: "#27272a"
5911
+ },
5912
+ nativeLinkDialogDisabledButton: {
5913
+ borderColor: "#9ca3af",
5914
+ backgroundColor: "#9ca3af"
5915
+ },
5916
+ nativeLinkDialogPrimaryButtonText: {
5917
+ color: "#ffffff",
5918
+ fontSize: 17,
5919
+ fontWeight: "700"
5920
+ }
5921
+ });
5740
5922
 
5741
5923
  export { DEFAULT_LINK_CARD_SIZE, DEFAULT_NATIVE_OVERFLOW_TOOL_IDS, DEFAULT_NATIVE_VECTOR_TOOLS, NATIVE_STYLE_PALETTE, NativeInteractionOverlay, NativeSceneRenderer, NativeShapeRenderer, NativeVectorStyleInspector, NativeVectorToolbar, NativeVectorViewport, createFreehandStrokeItem, createImageItem, createLinkItem, createShapeId, getLinkData, isLinkItem, nativeStyleColorWithOpacity, normalizeNativeStyleHex, parseSvgFragment };
5742
5924
  //# sourceMappingURL=native.js.map