expo-router 5.2.0-canary-20250613-b29d676-1 → 5.2.0-canary-20250630-547cd82

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.
Files changed (130) hide show
  1. package/build/ExpoRoot.d.ts.map +1 -1
  2. package/build/ExpoRoot.js +13 -7
  3. package/build/ExpoRoot.js.map +1 -1
  4. package/build/exports.d.ts +2 -0
  5. package/build/exports.d.ts.map +1 -1
  6. package/build/exports.js +5 -1
  7. package/build/exports.js.map +1 -1
  8. package/build/fork/getStateFromPath-forks.d.ts.map +1 -1
  9. package/build/fork/getStateFromPath-forks.js +4 -1
  10. package/build/fork/getStateFromPath-forks.js.map +1 -1
  11. package/build/getRoutes.d.ts +1 -1
  12. package/build/getRoutes.d.ts.map +1 -1
  13. package/build/getRoutes.js +14 -6
  14. package/build/getRoutes.js.map +1 -1
  15. package/build/getRoutesCore.d.ts +7 -2
  16. package/build/getRoutesCore.d.ts.map +1 -1
  17. package/build/getRoutesCore.js +86 -58
  18. package/build/getRoutesCore.js.map +1 -1
  19. package/build/getRoutesRedirects.d.ts +2 -2
  20. package/build/getRoutesRedirects.d.ts.map +1 -1
  21. package/build/getRoutesRedirects.js +18 -24
  22. package/build/getRoutesRedirects.js.map +1 -1
  23. package/build/getRoutesSSR.d.ts +1 -1
  24. package/build/getRoutesSSR.d.ts.map +1 -1
  25. package/build/getRoutesSSR.js +2 -3
  26. package/build/getRoutesSSR.js.map +1 -1
  27. package/build/global-state/router-store.d.ts +52 -1
  28. package/build/global-state/router-store.d.ts.map +1 -1
  29. package/build/global-state/router-store.js +22 -1
  30. package/build/global-state/router-store.js.map +1 -1
  31. package/build/global-state/routing.d.ts +1 -0
  32. package/build/global-state/routing.d.ts.map +1 -1
  33. package/build/global-state/routing.js +3 -2
  34. package/build/global-state/routing.js.map +1 -1
  35. package/build/global-state/storeContext.d.ts +50 -0
  36. package/build/global-state/storeContext.d.ts.map +1 -1
  37. package/build/hooks.d.ts.map +1 -1
  38. package/build/hooks.js +33 -1
  39. package/build/hooks.js.map +1 -1
  40. package/build/layouts/StackClient.d.ts.map +1 -1
  41. package/build/layouts/StackClient.js +39 -2
  42. package/build/layouts/StackClient.js.map +1 -1
  43. package/build/link/BaseExpoRouterLink.d.ts +3 -0
  44. package/build/link/BaseExpoRouterLink.d.ts.map +1 -0
  45. package/build/link/BaseExpoRouterLink.js +63 -0
  46. package/build/link/BaseExpoRouterLink.js.map +1 -0
  47. package/build/link/ExpoLink.d.ts +3 -0
  48. package/build/link/ExpoLink.d.ts.map +1 -0
  49. package/build/link/ExpoLink.js +23 -0
  50. package/build/link/ExpoLink.js.map +1 -0
  51. package/build/link/Link.d.ts +63 -78
  52. package/build/link/Link.d.ts.map +1 -1
  53. package/build/link/Link.js +81 -99
  54. package/build/link/Link.js.map +1 -1
  55. package/build/link/LinkWithPreview.d.ts +36 -0
  56. package/build/link/LinkWithPreview.d.ts.map +1 -0
  57. package/build/link/LinkWithPreview.js +187 -0
  58. package/build/link/LinkWithPreview.js.map +1 -0
  59. package/build/link/Redirect.d.ts +58 -0
  60. package/build/link/Redirect.d.ts.map +1 -0
  61. package/build/link/Redirect.js +46 -0
  62. package/build/link/Redirect.js.map +1 -0
  63. package/build/link/preview/HrefPreview.d.ts +5 -0
  64. package/build/link/preview/HrefPreview.d.ts.map +1 -0
  65. package/build/link/preview/HrefPreview.js +99 -0
  66. package/build/link/preview/HrefPreview.js.map +1 -0
  67. package/build/link/preview/LinkPreviewContext.d.ts +7 -0
  68. package/build/link/preview/LinkPreviewContext.d.ts.map +1 -0
  69. package/build/link/preview/LinkPreviewContext.js +21 -0
  70. package/build/link/preview/LinkPreviewContext.js.map +1 -0
  71. package/build/link/preview/PreviewRouteContext.d.ts +22 -0
  72. package/build/link/preview/PreviewRouteContext.d.ts.map +1 -0
  73. package/build/link/preview/PreviewRouteContext.js +28 -0
  74. package/build/link/preview/PreviewRouteContext.js.map +1 -0
  75. package/build/link/preview/native.d.ts +31 -0
  76. package/build/link/preview/native.d.ts.map +1 -0
  77. package/build/link/preview/native.js +53 -0
  78. package/build/link/preview/native.js.map +1 -0
  79. package/build/link/preview/useNextScreenId.d.ts +3 -0
  80. package/build/link/preview/useNextScreenId.d.ts.map +1 -0
  81. package/build/link/preview/useNextScreenId.js +42 -0
  82. package/build/link/preview/useNextScreenId.js.map +1 -0
  83. package/build/link/useLinkHooks.d.ts +3 -2
  84. package/build/link/useLinkHooks.d.ts.map +1 -1
  85. package/build/link/useLinkHooks.js +1 -0
  86. package/build/link/useLinkHooks.js.map +1 -1
  87. package/build/modal/Modal.d.ts +82 -0
  88. package/build/modal/Modal.d.ts.map +1 -0
  89. package/build/modal/Modal.js +82 -0
  90. package/build/modal/Modal.js.map +1 -0
  91. package/build/modal/ModalComponent.d.ts +7 -0
  92. package/build/modal/ModalComponent.d.ts.map +1 -0
  93. package/build/modal/ModalComponent.js +10 -0
  94. package/build/modal/ModalComponent.js.map +1 -0
  95. package/build/modal/ModalContext.d.ts +22 -0
  96. package/build/modal/ModalContext.d.ts.map +1 -0
  97. package/build/modal/ModalContext.js +150 -0
  98. package/build/modal/ModalContext.js.map +1 -0
  99. package/build/typed-routes/generate.js +1 -1
  100. package/build/typed-routes/generate.js.map +1 -1
  101. package/build/useFocusEffect.d.ts.map +1 -1
  102. package/build/useFocusEffect.js +5 -3
  103. package/build/useFocusEffect.js.map +1 -1
  104. package/build/useScreens.js +1 -1
  105. package/build/useScreens.js.map +1 -1
  106. package/build/utils/stack.d.ts +5 -0
  107. package/build/utils/stack.d.ts.map +1 -0
  108. package/build/utils/stack.js +10 -0
  109. package/build/utils/stack.js.map +1 -0
  110. package/build/views/Screen.d.ts.map +1 -1
  111. package/build/views/Screen.js +13 -40
  112. package/build/views/Screen.js.map +1 -1
  113. package/build/views/Unmatched.d.ts.map +1 -1
  114. package/build/views/Unmatched.js +9 -3
  115. package/build/views/Unmatched.js.map +1 -1
  116. package/build/views/useSafeLayoutEffect.d.ts +3 -0
  117. package/build/views/useSafeLayoutEffect.d.ts.map +1 -0
  118. package/build/views/useSafeLayoutEffect.js +6 -0
  119. package/build/views/useSafeLayoutEffect.js.map +1 -0
  120. package/expo-module.config.json +1 -1
  121. package/ios/ExpoHead.podspec +1 -1
  122. package/ios/LinkPreview/LinkPreviewNativeActionView.swift +12 -0
  123. package/ios/LinkPreview/LinkPreviewNativeModule.swift +50 -0
  124. package/ios/LinkPreview/LinkPreviewNativeNavigation.h +18 -0
  125. package/ios/LinkPreview/LinkPreviewNativeNavigation.mm +108 -0
  126. package/ios/LinkPreview/LinkPreviewNativePreviewView.swift +15 -0
  127. package/ios/LinkPreview/LinkPreviewNativeTriggerView.swift +9 -0
  128. package/ios/LinkPreview/LinkPreviewNativeView.swift +193 -0
  129. package/package.json +6 -6
  130. package/plugin/options.json +29 -1
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isRoutePreloadedInStack = isRoutePreloadedInStack;
4
+ function isRoutePreloadedInStack(navigationState, route) {
5
+ if (!navigationState || navigationState.type !== 'stack') {
6
+ return false;
7
+ }
8
+ return navigationState.preloadedRoutes.some((preloaded) => preloaded.key === route.key);
9
+ }
10
+ //# sourceMappingURL=stack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stack.js","sourceRoot":"","sources":["../../src/utils/stack.ts"],"names":[],"mappings":";;AAMA,0DAUC;AAVD,SAAgB,uBAAuB,CACrC,eAA4C,EAC5C,KAAsB;IAEtB,IAAI,CAAC,eAAe,IAAI,eAAe,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QACzD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAQ,eAAuD,CAAC,eAAe,CAAC,IAAI,CAClF,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,KAAK,KAAK,CAAC,GAAG,CAC3C,CAAC;AACJ,CAAC","sourcesContent":["import type {\n NavigationState,\n ParamListBase,\n StackNavigationState,\n} from '@react-navigation/native';\n\nexport function isRoutePreloadedInStack(\n navigationState: NavigationState | undefined,\n route: { key: string }\n): boolean {\n if (!navigationState || navigationState.type !== 'stack') {\n return false;\n }\n return (navigationState as StackNavigationState<ParamListBase>).preloadedRoutes.some(\n (preloaded) => preloaded.key === route.key\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"Screen.d.ts","sourceRoot":"","sources":["../../src/views/Screen.tsx"],"names":[],"mappings":"AACA,OAAc,EAAkB,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvE,MAAM,MAAM,WAAW,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI;IACpF;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACpC,OAAO,CAAC,EAAE,QAAQ,CAAC;CACpB,CAAC;AAIF,sEAAsE;AACtE,wBAAgB,MAAM,CAAC,QAAQ,SAAS,MAAM,GAAG,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,WAAW,CAAC,QAAQ,CAAC,QAehG;AAED,wBAAgB,QAAQ,CACtB,KAAK,EAAE,SAAS,EAChB,UAAU,CAAC,EAAE,MAAM,GAClB,KAAK,IAAI,YAAY,CAAC,WAAW,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CA6BvD"}
1
+ {"version":3,"file":"Screen.d.ts","sourceRoot":"","sources":["../../src/views/Screen.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAkB,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAMhE,MAAM,MAAM,WAAW,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI;IACpF;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACpC,OAAO,CAAC,EAAE,QAAQ,CAAC;CACpB,CAAC;AAEF,sEAAsE;AACtE,wBAAgB,MAAM,CAAC,QAAQ,SAAS,MAAM,GAAG,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,WAAW,CAAC,QAAQ,CAAC,QAiBhG;AAED,wBAAgB,QAAQ,CACtB,KAAK,EAAE,SAAS,EAChB,UAAU,CAAC,EAAE,MAAM,GAClB,KAAK,IAAI,YAAY,CAAC,WAAW,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CA6BvD"}
@@ -1,55 +1,28 @@
1
1
  "use strict";
2
2
  'use client';
3
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
- if (k2 === undefined) k2 = k;
5
- var desc = Object.getOwnPropertyDescriptor(m, k);
6
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
- desc = { enumerable: true, get: function() { return m[k]; } };
8
- }
9
- Object.defineProperty(o, k2, desc);
10
- }) : (function(o, m, k, k2) {
11
- if (k2 === undefined) k2 = k;
12
- o[k2] = m[k];
13
- }));
14
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
- Object.defineProperty(o, "default", { enumerable: true, value: v });
16
- }) : function(o, v) {
17
- o["default"] = v;
18
- });
19
- var __importStar = (this && this.__importStar) || (function () {
20
- var ownKeys = function(o) {
21
- ownKeys = Object.getOwnPropertyNames || function (o) {
22
- var ar = [];
23
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
- return ar;
25
- };
26
- return ownKeys(o);
27
- };
28
- return function (mod) {
29
- if (mod && mod.__esModule) return mod;
30
- var result = {};
31
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
- __setModuleDefault(result, mod);
33
- return result;
34
- };
35
- })();
36
3
  Object.defineProperty(exports, "__esModule", { value: true });
37
4
  exports.Screen = Screen;
38
5
  exports.isScreen = isScreen;
39
- const react_1 = __importStar(require("react"));
6
+ const native_1 = require("@react-navigation/native");
7
+ const react_1 = require("react");
40
8
  const useNavigation_1 = require("../useNavigation");
41
- const useLayoutEffect = typeof window !== 'undefined' ? react_1.default.useLayoutEffect : function () { };
9
+ const useSafeLayoutEffect_1 = require("./useSafeLayoutEffect");
10
+ const stack_1 = require("../utils/stack");
42
11
  /** Component for setting the current screen's options dynamically. */
43
12
  function Screen({ name, options }) {
13
+ const route = (0, native_1.useRoute)();
44
14
  const navigation = (0, useNavigation_1.useNavigation)(name);
45
- useLayoutEffect(() => {
46
- if (options &&
15
+ const isFocused = navigation.isFocused();
16
+ const isPreloaded = (0, stack_1.isRoutePreloadedInStack)(navigation.getState(), route);
17
+ (0, useSafeLayoutEffect_1.useSafeLayoutEffect)(() => {
18
+ if (options && Object.keys(options).length) {
47
19
  // React Navigation will infinitely loop in some cases if an empty object is passed to setOptions.
48
20
  // https://github.com/expo/router/issues/452
49
- Object.keys(options).length) {
50
- navigation.setOptions(options);
21
+ if (!isPreloaded || (isPreloaded && isFocused)) {
22
+ navigation.setOptions(options);
23
+ }
51
24
  }
52
- }, [navigation, options]);
25
+ }, [isFocused, isPreloaded, navigation, options]);
53
26
  return null;
54
27
  }
55
28
  function isScreen(child, contextKey) {
@@ -1 +1 @@
1
- {"version":3,"file":"Screen.js","sourceRoot":"","sources":["../../src/views/Screen.tsx"],"names":[],"mappings":";AAAA,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqBb,wBAeC;AAED,4BAgCC;AArED,+CAAuE;AAEvE,oDAAiD;AAejD,MAAM,eAAe,GAAG,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,eAAK,CAAC,eAAe,CAAC,CAAC,CAAC,cAAa,CAAC,CAAC;AAE/F,sEAAsE;AACtE,SAAgB,MAAM,CAAmC,EAAE,IAAI,EAAE,OAAO,EAAyB;IAC/F,MAAM,UAAU,GAAG,IAAA,6BAAa,EAAC,IAAI,CAAC,CAAC;IAEvC,eAAe,CAAC,GAAG,EAAE;QACnB,IACE,OAAO;YACP,kGAAkG;YAClG,4CAA4C;YAC5C,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,EAC3B,CAAC;YACD,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACjC,CAAC;IACH,CAAC,EAAE,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IAE1B,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAgB,QAAQ,CACtB,KAAgB,EAChB,UAAmB;IAEnB,IAAI,IAAA,sBAAc,EAAC,KAAK,CAAC,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC5D,IACE,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ;YAC/B,KAAK,CAAC,KAAK;YACX,MAAM,IAAI,KAAK,CAAC,KAAK;YACrB,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EACjB,CAAC;YACD,MAAM,IAAI,KAAK,CACb,sDAAsD,UAAU,8EAA8E,CAC/I,CAAC;QACJ,CAAC;QAED,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;YAC1C,IACE,CAAC,UAAU,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC,IAAI,CAC5C,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,GAAG,IAAI,KAAK,CAAC,KAAK,CAC9E,EACD,CAAC;gBACD,MAAM,IAAI,KAAK,CACb,sDAAsD,UAAU,yHAAyH,CAC1L,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["'use client';\nimport React, { isValidElement, ReactElement, ReactNode } from 'react';\n\nimport { useNavigation } from '../useNavigation';\n\nexport type ScreenProps<TOptions extends Record<string, any> = Record<string, any>> = {\n /**\n * Name is required when used inside a Layout component.\n *\n * When used in a route, this can be an absolute path like `/(root)` to the parent route or a relative path like `../../` to the parent route.\n * This should not be used inside of a Layout component.\n * @example `/(root)` maps to a layout route `/app/(root).tsx`.\n */\n name?: string;\n initialParams?: Record<string, any>;\n options?: TOptions;\n};\n\nconst useLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : function () {};\n\n/** Component for setting the current screen's options dynamically. */\nexport function Screen<TOptions extends object = object>({ name, options }: ScreenProps<TOptions>) {\n const navigation = useNavigation(name);\n\n useLayoutEffect(() => {\n if (\n options &&\n // React Navigation will infinitely loop in some cases if an empty object is passed to setOptions.\n // https://github.com/expo/router/issues/452\n Object.keys(options).length\n ) {\n navigation.setOptions(options);\n }\n }, [navigation, options]);\n\n return null;\n}\n\nexport function isScreen(\n child: ReactNode,\n contextKey?: string\n): child is ReactElement<ScreenProps & { name: string }> {\n if (isValidElement(child) && child && child.type === Screen) {\n if (\n typeof child.props === 'object' &&\n child.props &&\n 'name' in child.props &&\n !child.props.name\n ) {\n throw new Error(\n `<Screen /> component in \\`default export\\` at \\`app${contextKey}/_layout\\` must have a \\`name\\` prop when used as a child of a Layout Route.`\n );\n }\n\n if (process.env.NODE_ENV !== 'production') {\n if (\n ['children', 'component', 'getComponent'].some(\n (key) => child.props && typeof child.props === 'object' && key in child.props\n )\n ) {\n throw new Error(\n `<Screen /> component in \\`default export\\` at \\`app${contextKey}/_layout\\` must not have a \\`children\\`, \\`component\\`, or \\`getComponent\\` prop when used as a child of a Layout Route`\n );\n }\n }\n\n return true;\n }\n\n return false;\n}\n"]}
1
+ {"version":3,"file":"Screen.js","sourceRoot":"","sources":["../../src/views/Screen.tsx"],"names":[],"mappings":";AAAA,YAAY,CAAC;;AAsBb,wBAiBC;AAED,4BAgCC;AAxED,qDAAoD;AACpD,iCAAgE;AAEhE,oDAAiD;AACjD,+DAA4D;AAC5D,0CAAyD;AAezD,sEAAsE;AACtE,SAAgB,MAAM,CAAmC,EAAE,IAAI,EAAE,OAAO,EAAyB;IAC/F,MAAM,KAAK,GAAG,IAAA,iBAAQ,GAAE,CAAC;IACzB,MAAM,UAAU,GAAG,IAAA,6BAAa,EAAC,IAAI,CAAC,CAAC;IACvC,MAAM,SAAS,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC;IACzC,MAAM,WAAW,GAAG,IAAA,+BAAuB,EAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,KAAK,CAAC,CAAC;IAE1E,IAAA,yCAAmB,EAAC,GAAG,EAAE;QACvB,IAAI,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC;YAC3C,kGAAkG;YAClG,4CAA4C;YAC5C,IAAI,CAAC,WAAW,IAAI,CAAC,WAAW,IAAI,SAAS,CAAC,EAAE,CAAC;gBAC/C,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;IACH,CAAC,EAAE,CAAC,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IAElD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAgB,QAAQ,CACtB,KAAgB,EAChB,UAAmB;IAEnB,IAAI,IAAA,sBAAc,EAAC,KAAK,CAAC,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC5D,IACE,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ;YAC/B,KAAK,CAAC,KAAK;YACX,MAAM,IAAI,KAAK,CAAC,KAAK;YACrB,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EACjB,CAAC;YACD,MAAM,IAAI,KAAK,CACb,sDAAsD,UAAU,8EAA8E,CAC/I,CAAC;QACJ,CAAC;QAED,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;YAC1C,IACE,CAAC,UAAU,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC,IAAI,CAC5C,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,GAAG,IAAI,KAAK,CAAC,KAAK,CAC9E,EACD,CAAC;gBACD,MAAM,IAAI,KAAK,CACb,sDAAsD,UAAU,yHAAyH,CAC1L,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["'use client';\nimport { useRoute } from '@react-navigation/native';\nimport { isValidElement, ReactElement, ReactNode } from 'react';\n\nimport { useNavigation } from '../useNavigation';\nimport { useSafeLayoutEffect } from './useSafeLayoutEffect';\nimport { isRoutePreloadedInStack } from '../utils/stack';\n\nexport type ScreenProps<TOptions extends Record<string, any> = Record<string, any>> = {\n /**\n * Name is required when used inside a Layout component.\n *\n * When used in a route, this can be an absolute path like `/(root)` to the parent route or a relative path like `../../` to the parent route.\n * This should not be used inside of a Layout component.\n * @example `/(root)` maps to a layout route `/app/(root).tsx`.\n */\n name?: string;\n initialParams?: Record<string, any>;\n options?: TOptions;\n};\n\n/** Component for setting the current screen's options dynamically. */\nexport function Screen<TOptions extends object = object>({ name, options }: ScreenProps<TOptions>) {\n const route = useRoute();\n const navigation = useNavigation(name);\n const isFocused = navigation.isFocused();\n const isPreloaded = isRoutePreloadedInStack(navigation.getState(), route);\n\n useSafeLayoutEffect(() => {\n if (options && Object.keys(options).length) {\n // React Navigation will infinitely loop in some cases if an empty object is passed to setOptions.\n // https://github.com/expo/router/issues/452\n if (!isPreloaded || (isPreloaded && isFocused)) {\n navigation.setOptions(options);\n }\n }\n }, [isFocused, isPreloaded, navigation, options]);\n\n return null;\n}\n\nexport function isScreen(\n child: ReactNode,\n contextKey?: string\n): child is ReactElement<ScreenProps & { name: string }> {\n if (isValidElement(child) && child && child.type === Screen) {\n if (\n typeof child.props === 'object' &&\n child.props &&\n 'name' in child.props &&\n !child.props.name\n ) {\n throw new Error(\n `<Screen /> component in \\`default export\\` at \\`app${contextKey}/_layout\\` must have a \\`name\\` prop when used as a child of a Layout Route.`\n );\n }\n\n if (process.env.NODE_ENV !== 'production') {\n if (\n ['children', 'component', 'getComponent'].some(\n (key) => child.props && typeof child.props === 'object' && key in child.props\n )\n ) {\n throw new Error(\n `<Screen /> component in \\`default export\\` at \\`app${contextKey}/_layout\\` must not have a \\`children\\`, \\`component\\`, or \\`getComponent\\` prop when used as a child of a Layout Route`\n );\n }\n }\n\n return true;\n }\n\n return false;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"Unmatched.d.ts","sourceRoot":"","sources":["../../src/views/Unmatched.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAU1B;;;;GAIG;AACH,wBAAgB,SAAS,sBAqHxB"}
1
+ {"version":3,"file":"Unmatched.d.ts","sourceRoot":"","sources":["../../src/views/Unmatched.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,MAAM,OAAO,CAAC;AAU1B;;;;GAIG;AACH,wBAAgB,SAAS,sBA2HxB"}
@@ -6,14 +6,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
6
6
  };
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
8
  exports.Unmatched = Unmatched;
9
+ const native_1 = require("@react-navigation/native");
9
10
  const expo_linking_1 = require("expo-linking");
10
11
  const react_1 = __importDefault(require("react"));
11
12
  const react_native_1 = require("react-native");
12
13
  const hooks_1 = require("../hooks");
13
14
  const Link_1 = require("../link/Link");
14
15
  const useNavigation_1 = require("../useNavigation");
16
+ const useSafeLayoutEffect_1 = require("./useSafeLayoutEffect");
17
+ const stack_1 = require("../utils/stack");
15
18
  const Pressable_1 = require("../views/Pressable");
16
- const useLayoutEffect = typeof window !== 'undefined' ? react_1.default.useLayoutEffect : function () { };
17
19
  /**
18
20
  * Default screen for unmatched routes.
19
21
  *
@@ -22,17 +24,21 @@ const useLayoutEffect = typeof window !== 'undefined' ? react_1.default.useLayou
22
24
  function Unmatched() {
23
25
  const [render, setRender] = react_1.default.useState(false);
24
26
  const router = (0, hooks_1.useRouter)();
27
+ const route = (0, native_1.useRoute)();
25
28
  const navigation = (0, useNavigation_1.useNavigation)();
26
29
  const pathname = (0, hooks_1.usePathname)();
27
30
  const url = (0, expo_linking_1.createURL)(pathname);
28
31
  react_1.default.useEffect(() => {
29
32
  setRender(true);
30
33
  }, []);
31
- useLayoutEffect(() => {
34
+ const isFocused = navigation.isFocused();
35
+ const isPreloaded = (0, stack_1.isRoutePreloadedInStack)(navigation.getState(), route);
36
+ /** This route may be prefetched if a <Link prefetch href="/<unmatched>" /> is used */
37
+ (0, useSafeLayoutEffect_1.useSafeLayoutEffect)(() => {
32
38
  navigation.setOptions({
33
39
  title: 'Not Found',
34
40
  });
35
- }, [navigation]);
41
+ }, [isFocused, isPreloaded, navigation]);
36
42
  return (<react_native_1.View style={styles.container}>
37
43
  <NotFoundAsset />
38
44
  <react_native_1.Text role="heading" aria-level={1} style={styles.title}>
@@ -1 +1 @@
1
- {"version":3,"file":"Unmatched.js","sourceRoot":"","sources":["../../src/views/Unmatched.tsx"],"names":[],"mappings":"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","sourcesContent":["// Copyright © 2024 650 Industries.\n'use client';\n\nimport { createURL } from 'expo-linking';\nimport React from 'react';\nimport { StyleSheet, Text, View, Platform, Image } from 'react-native';\n\nimport { usePathname, useRouter } from '../hooks';\nimport { Link } from '../link/Link';\nimport { useNavigation } from '../useNavigation';\nimport { Pressable } from '../views/Pressable';\n\nconst useLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : function () {};\n\n/**\n * Default screen for unmatched routes.\n *\n * @hidden\n */\nexport function Unmatched() {\n const [render, setRender] = React.useState(false);\n\n const router = useRouter();\n const navigation = useNavigation();\n const pathname = usePathname();\n const url = createURL(pathname);\n\n React.useEffect(() => {\n setRender(true);\n }, []);\n\n useLayoutEffect(() => {\n navigation.setOptions({\n title: 'Not Found',\n });\n }, [navigation]);\n\n return (\n <View style={styles.container}>\n <NotFoundAsset />\n <Text role=\"heading\" aria-level={1} style={styles.title}>\n Unmatched Route\n </Text>\n <Text role=\"heading\" aria-level={2} style={[styles.subtitle, styles.secondaryText]}>\n Page could not be found.\n </Text>\n {render ? (\n <Link href={pathname} replace {...Platform.select({ native: { asChild: true } })}>\n <Pressable>\n {({ hovered, pressed }) => (\n <Text\n style={[\n styles.pageLink,\n styles.secondaryText,\n Platform.select({\n web: {\n transitionDuration: '200ms',\n opacity: 1,\n },\n }),\n hovered && {\n opacity: 0.8,\n textDecorationLine: 'underline',\n },\n pressed && {\n opacity: 0.8,\n },\n ]}>\n {url}\n </Text>\n )}\n </Pressable>\n </Link>\n ) : (\n <View style={[styles.pageLink, styles.placeholder]} />\n )}\n <View style={styles.linkContainer}>\n <Pressable>\n {({ hovered, pressed }) => (\n <Text\n onPress={() => {\n if (router.canGoBack()) {\n router.back();\n } else {\n router.replace('/');\n }\n }}\n style={[\n styles.link,\n Platform.select({\n web: {\n transitionDuration: '200ms',\n opacity: 1,\n },\n }),\n hovered && {\n opacity: 0.8,\n textDecorationLine: 'underline',\n },\n pressed && {\n opacity: 0.8,\n },\n ]}>\n Go back\n </Text>\n )}\n </Pressable>\n <Text style={[styles.linkSeparator, styles.secondaryText]}>•</Text>\n <Link href=\"/_sitemap\" replace {...Platform.select({ native: { asChild: true } })}>\n <Pressable>\n {({ hovered, pressed }) => (\n <Text\n style={[\n styles.link,\n Platform.select({\n web: {\n transitionDuration: '200ms',\n opacity: 1,\n },\n }),\n hovered && {\n opacity: 0.8,\n textDecorationLine: 'underline',\n },\n pressed && {\n opacity: 0.8,\n },\n ]}>\n Sitemap\n </Text>\n )}\n </Pressable>\n </Link>\n </View>\n </View>\n );\n}\n\nfunction NotFoundAsset() {\n return <Image source={require('expo-router/assets/unmatched.png')} style={styles.image} />;\n}\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n backgroundColor: 'black',\n padding: 24,\n paddingBottom: 64,\n alignItems: 'center',\n justifyContent: 'center',\n },\n image: {\n width: 270,\n height: 168,\n resizeMode: 'contain',\n marginBottom: 28,\n },\n title: {\n ...Platform.select({\n web: {\n fontSize: 64,\n lineHeight: 64,\n },\n default: {\n fontSize: 56,\n lineHeight: 56,\n },\n }),\n color: '#fff',\n fontWeight: '800',\n textAlign: 'center',\n },\n subtitle: {\n fontSize: 34,\n marginTop: 4,\n marginBottom: 12,\n fontWeight: '200',\n textAlign: 'center',\n },\n pageLink: {\n minHeight: 20,\n },\n secondaryText: {\n color: '#9ba1a6',\n },\n placeholder: {\n backgroundColor: '#9ba1a644',\n minWidth: 180,\n borderRadius: 5,\n },\n linkContainer: {\n marginTop: 28,\n flexDirection: 'row',\n gap: 12,\n },\n link: {\n fontSize: 20,\n textAlign: 'center',\n color: '#52a9ff',\n },\n linkSeparator: {\n fontSize: 20,\n },\n});\n"]}
1
+ {"version":3,"file":"Unmatched.js","sourceRoot":"","sources":["../../src/views/Unmatched.tsx"],"names":[],"mappings":"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","sourcesContent":["// Copyright © 2024 650 Industries.\n'use client';\n\nimport { useRoute } from '@react-navigation/native';\nimport { createURL } from 'expo-linking';\nimport React from 'react';\nimport { StyleSheet, Text, View, Platform, Image } from 'react-native';\n\nimport { usePathname, useRouter } from '../hooks';\nimport { Link } from '../link/Link';\nimport { useNavigation } from '../useNavigation';\nimport { useSafeLayoutEffect } from './useSafeLayoutEffect';\nimport { isRoutePreloadedInStack } from '../utils/stack';\nimport { Pressable } from '../views/Pressable';\n\n/**\n * Default screen for unmatched routes.\n *\n * @hidden\n */\nexport function Unmatched() {\n const [render, setRender] = React.useState(false);\n\n const router = useRouter();\n const route = useRoute();\n\n const navigation = useNavigation();\n const pathname = usePathname();\n const url = createURL(pathname);\n\n React.useEffect(() => {\n setRender(true);\n }, []);\n\n const isFocused = navigation.isFocused();\n const isPreloaded = isRoutePreloadedInStack(navigation.getState(), route);\n\n /** This route may be prefetched if a <Link prefetch href=\"/<unmatched>\" /> is used */\n useSafeLayoutEffect(() => {\n navigation.setOptions({\n title: 'Not Found',\n });\n }, [isFocused, isPreloaded, navigation]);\n\n return (\n <View style={styles.container}>\n <NotFoundAsset />\n <Text role=\"heading\" aria-level={1} style={styles.title}>\n Unmatched Route\n </Text>\n <Text role=\"heading\" aria-level={2} style={[styles.subtitle, styles.secondaryText]}>\n Page could not be found.\n </Text>\n {render ? (\n <Link href={pathname} replace {...Platform.select({ native: { asChild: true } })}>\n <Pressable>\n {({ hovered, pressed }) => (\n <Text\n style={[\n styles.pageLink,\n styles.secondaryText,\n Platform.select({\n web: {\n transitionDuration: '200ms',\n opacity: 1,\n },\n }),\n hovered && {\n opacity: 0.8,\n textDecorationLine: 'underline',\n },\n pressed && {\n opacity: 0.8,\n },\n ]}>\n {url}\n </Text>\n )}\n </Pressable>\n </Link>\n ) : (\n <View style={[styles.pageLink, styles.placeholder]} />\n )}\n <View style={styles.linkContainer}>\n <Pressable>\n {({ hovered, pressed }) => (\n <Text\n onPress={() => {\n if (router.canGoBack()) {\n router.back();\n } else {\n router.replace('/');\n }\n }}\n style={[\n styles.link,\n Platform.select({\n web: {\n transitionDuration: '200ms',\n opacity: 1,\n },\n }),\n hovered && {\n opacity: 0.8,\n textDecorationLine: 'underline',\n },\n pressed && {\n opacity: 0.8,\n },\n ]}>\n Go back\n </Text>\n )}\n </Pressable>\n <Text style={[styles.linkSeparator, styles.secondaryText]}>•</Text>\n <Link href=\"/_sitemap\" replace {...Platform.select({ native: { asChild: true } })}>\n <Pressable>\n {({ hovered, pressed }) => (\n <Text\n style={[\n styles.link,\n Platform.select({\n web: {\n transitionDuration: '200ms',\n opacity: 1,\n },\n }),\n hovered && {\n opacity: 0.8,\n textDecorationLine: 'underline',\n },\n pressed && {\n opacity: 0.8,\n },\n ]}>\n Sitemap\n </Text>\n )}\n </Pressable>\n </Link>\n </View>\n </View>\n );\n}\n\nfunction NotFoundAsset() {\n return <Image source={require('expo-router/assets/unmatched.png')} style={styles.image} />;\n}\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n backgroundColor: 'black',\n padding: 24,\n paddingBottom: 64,\n alignItems: 'center',\n justifyContent: 'center',\n },\n image: {\n width: 270,\n height: 168,\n resizeMode: 'contain',\n marginBottom: 28,\n },\n title: {\n ...Platform.select({\n web: {\n fontSize: 64,\n lineHeight: 64,\n },\n default: {\n fontSize: 56,\n lineHeight: 56,\n },\n }),\n color: '#fff',\n fontWeight: '800',\n textAlign: 'center',\n },\n subtitle: {\n fontSize: 34,\n marginTop: 4,\n marginBottom: 12,\n fontWeight: '200',\n textAlign: 'center',\n },\n pageLink: {\n minHeight: 20,\n },\n secondaryText: {\n color: '#9ba1a6',\n },\n placeholder: {\n backgroundColor: '#9ba1a644',\n minWidth: 180,\n borderRadius: 5,\n },\n linkContainer: {\n marginTop: 28,\n flexDirection: 'row',\n gap: 12,\n },\n link: {\n fontSize: 20,\n textAlign: 'center',\n color: '#52a9ff',\n },\n linkSeparator: {\n fontSize: 20,\n },\n});\n"]}
@@ -0,0 +1,3 @@
1
+ import { useLayoutEffect } from 'react';
2
+ export declare const useSafeLayoutEffect: typeof useLayoutEffect;
3
+ //# sourceMappingURL=useSafeLayoutEffect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSafeLayoutEffect.d.ts","sourceRoot":"","sources":["../../src/views/useSafeLayoutEffect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAExC,eAAO,MAAM,mBAAmB,wBAAmE,CAAC"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useSafeLayoutEffect = void 0;
4
+ const react_1 = require("react");
5
+ exports.useSafeLayoutEffect = typeof window !== 'undefined' ? react_1.useLayoutEffect : function () { };
6
+ //# sourceMappingURL=useSafeLayoutEffect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSafeLayoutEffect.js","sourceRoot":"","sources":["../../src/views/useSafeLayoutEffect.ts"],"names":[],"mappings":";;;AAAA,iCAAwC;AAE3B,QAAA,mBAAmB,GAAG,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,uBAAe,CAAC,CAAC,CAAC,cAAa,CAAC,CAAC","sourcesContent":["import { useLayoutEffect } from 'react';\n\nexport const useSafeLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : function () {};\n"]}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "platforms": ["apple", "web"],
3
3
  "apple": {
4
- "modules": ["ExpoHeadModule"],
4
+ "modules": ["ExpoHeadModule", "LinkPreviewNativeModule"],
5
5
  "appDelegateSubscribers": ["ExpoHeadAppDelegateSubscriber"]
6
6
  }
7
7
  }
@@ -29,6 +29,6 @@ Pod::Spec.new do |s|
29
29
  s.source_files = "**/*.h"
30
30
  s.vendored_frameworks = "#{s.name}.xcframework"
31
31
  else
32
- s.source_files = "**/*.{h,m,swift}"
32
+ s.source_files = "**/*.{h,m,swift,mm,cpp}"
33
33
  end
34
34
  end
@@ -0,0 +1,12 @@
1
+ import ExpoModulesCore
2
+ import WebKit
3
+
4
+ class LinkPreviewNativeActionView: ExpoView {
5
+ var id: String = ""
6
+ var title: String = ""
7
+
8
+ required init(appContext: AppContext? = nil) {
9
+ super.init(appContext: appContext)
10
+ clipsToBounds = true
11
+ }
12
+ }
@@ -0,0 +1,50 @@
1
+ import ExpoModulesCore
2
+
3
+ public class LinkPreviewNativeModule: Module {
4
+ public func definition() -> ModuleDefinition {
5
+ Name("ExpoRouterNativeLinkPreview")
6
+
7
+ View(NativeLinkPreviewView.self) {
8
+ Prop("nextScreenId") { (view: NativeLinkPreviewView, nextScreenId: String) in
9
+ view.setNextScreenId(nextScreenId)
10
+ }
11
+
12
+ Events(
13
+ "onPreviewTapped",
14
+ "onWillPreviewOpen",
15
+ "onDidPreviewOpen",
16
+ "onPreviewWillClose",
17
+ "onPreviewDidClose",
18
+ "onActionSelected"
19
+ )
20
+ }
21
+
22
+ View(NativeLinkPreviewContentView.self) {
23
+ Prop("preferredContentSize") { (view: NativeLinkPreviewContentView, size: [String: Float]) in
24
+ let width = size["width", default: 0]
25
+ let height = size["height", default: 0]
26
+
27
+ guard width >= 0, height >= 0 else {
28
+ print("Preferred content size cannot be negative (\(width), \(height))")
29
+ return
30
+ }
31
+
32
+ view.preferredContentSize = CGSize(
33
+ width: CGFloat(width),
34
+ height: CGFloat(height)
35
+ )
36
+ }
37
+ }
38
+
39
+ View(LinkPreviewNativeActionView.self) {
40
+ Prop("id") { (view: LinkPreviewNativeActionView, id: String) in
41
+ view.id = id
42
+ }
43
+ Prop("title") { (view: LinkPreviewNativeActionView, title: String) in
44
+ view.title = title
45
+ }
46
+ }
47
+
48
+ View(NativeLinkPreviewTrigger.self) {}
49
+ }
50
+ }
@@ -0,0 +1,18 @@
1
+ // Copyright 2015-present 650 Industries. All rights reserved.
2
+
3
+ @interface LinkPreviewNativeNavigation: NSObject
4
+
5
+ /*
6
+ * Updates the preloaded view with the given screenId and UIResponder.
7
+ * This function will go through the responder's view hierarchy to find the screen view with the given screenId and activity state 0.
8
+ */
9
+ - (void)updatePreloadedView:(NSString *)screenId withUiResponder:(UIResponder *)responder;
10
+
11
+ /*
12
+ * Pushes the previously preloaded view.
13
+ * This function will set the activity state of the preloaded screen view to 2
14
+ */
15
+ - (void)pushPreloadedView;
16
+
17
+ @end
18
+
@@ -0,0 +1,108 @@
1
+ // Copyright 2015-present 650 Industries. All rights reserved.
2
+
3
+ #import "LinkPreviewNativeNavigation.h"
4
+ #import <Foundation/Foundation.h>
5
+ #import <RNScreens/RNSScreen.h>
6
+ #import <RNScreens/RNSScreenStack.h>
7
+
8
+ @implementation LinkPreviewNativeNavigation {
9
+ RNSScreenView *preloadedScreenView;
10
+ RNSScreenStackView *stackView;
11
+ }
12
+
13
+ - (void)pushPreloadedView {
14
+ if (preloadedScreenView != nil && stackView != nil) {
15
+ // Instead of pushing the preloaded screen view, we set its activity state
16
+ // React native screens will then handle the rest.
17
+ [preloadedScreenView setActivityState:2];
18
+ [stackView markChildUpdated];
19
+ NSLog(@"ExpoRouter: Preloaded screen view pushed.");
20
+ } else {
21
+ NSLog(@"ExpoRouter: No preloaded screen view found. Relying on JS "
22
+ @"navigation.");
23
+ }
24
+ }
25
+
26
+ - (void)updatePreloadedView:(nullable NSString *)screenId
27
+ withUiResponder:(nonnull UIResponder *)responder {
28
+ if (screenId != nil && [screenId length] > 0) {
29
+ if ([self setPreloadedScreenViewWithScreenId:screenId
30
+ withUiResponder:responder]) {
31
+ NSLog(@"ExpoRouter: Preloaded screen view updated.");
32
+ } else {
33
+ NSLog(@"ExpoRouter: No native screen view found with screenId: %@",
34
+ screenId);
35
+ }
36
+ } else {
37
+ preloadedScreenView = nil;
38
+ }
39
+ }
40
+
41
+ - (nonnull NSArray<RNSScreenStackView *> *)findAllScreenStackViewsInResponderChain:
42
+ (nonnull UIResponder *)responder {
43
+ NSMutableArray<RNSScreenStackView *> *stackViews = [NSMutableArray array];
44
+
45
+ while (responder) {
46
+ responder = [responder nextResponder];
47
+ if ([responder isKindOfClass:[RNSScreenStackView class]]) {
48
+ [stackViews addObject:(RNSScreenStackView *)responder];
49
+ }
50
+ }
51
+
52
+ return stackViews;
53
+ }
54
+
55
+ - (nonnull NSArray<RNSScreenView *> *)extractScreenViewsFromSubviews:
56
+ (nonnull NSArray<UIView *> *)subviews {
57
+ NSMutableArray<RNSScreenView *> *screenViews = [NSMutableArray array];
58
+
59
+ for (UIView *subview in subviews) {
60
+ if ([subview isKindOfClass:[RNSScreenView class]]) {
61
+ [screenViews addObject:(RNSScreenView *)subview];
62
+ }
63
+ }
64
+ return screenViews;
65
+ }
66
+
67
+ - (BOOL)setPreloadedScreenViewWithScreenId:(nonnull NSString *)screenId
68
+ withUiResponder:(nonnull UIResponder *)responder {
69
+ NSArray<RNSScreenStackView *> *stacks =
70
+ [self findAllScreenStackViewsInResponderChain:responder];
71
+
72
+ for (RNSScreenStackView *stack in stacks) {
73
+ if ([stack.screenIds containsObject:screenId] &&
74
+ [self setPreloadedScreenViewWithScreenId:screenId
75
+ withStackView:stack]) {
76
+ return YES;
77
+ }
78
+ }
79
+ return NO;
80
+ }
81
+
82
+ - (BOOL)setPreloadedScreenViewWithScreenId:(nonnull NSString *)screenId
83
+ withStackView:(nonnull RNSScreenStackView *)stack {
84
+ NSArray<RNSScreenView *> *screenSubviews =
85
+ [self extractScreenViewsFromSubviews:stack.reactSubviews];
86
+ RNSScreenView *screenView = [self findPreloadedScreenView:screenSubviews
87
+ withScreenId:screenId];
88
+ if (screenView != nil) {
89
+ preloadedScreenView = screenView;
90
+ stackView = stack;
91
+ return YES;
92
+ }
93
+ return NO;
94
+ }
95
+
96
+ - (nullable RNSScreenView *)findPreloadedScreenView:
97
+ (nonnull NSArray<RNSScreenView *> *)screenViews
98
+ withScreenId:(nonnull NSString *)screenId {
99
+ for (RNSScreenView *screenView in screenViews) {
100
+ if (screenView.activityState == 0 &&
101
+ [screenView.screenId isEqualToString:screenId]) {
102
+ return screenView;
103
+ }
104
+ }
105
+ return nil;
106
+ }
107
+
108
+ @end
@@ -0,0 +1,15 @@
1
+ import ExpoModulesCore
2
+ import WebKit
3
+
4
+ class NativeLinkPreviewContentView: ExpoView {
5
+ var preferredContentSize: CGSize = .zero
6
+
7
+ required init(appContext: AppContext? = nil) {
8
+ super.init(appContext: appContext)
9
+ clipsToBounds = true
10
+ }
11
+
12
+ func setInitialSize(bounds: CGRect) {
13
+ self.setShadowNodeSize(Float(bounds.width), height: Float(bounds.height))
14
+ }
15
+ }
@@ -0,0 +1,9 @@
1
+ import ExpoModulesCore
2
+ import WebKit
3
+
4
+ class NativeLinkPreviewTrigger: ExpoView {
5
+ required init(appContext: AppContext? = nil) {
6
+ super.init(appContext: appContext)
7
+ clipsToBounds = true
8
+ }
9
+ }