@sigx/lynx-navigation 0.4.0 → 0.4.1

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 (184) hide show
  1. package/dist/components/Drawer.js +74 -0
  2. package/dist/components/Drawer.js.map +1 -0
  3. package/dist/components/EdgeBackHandle.js +144 -0
  4. package/dist/components/EdgeBackHandle.js.map +1 -0
  5. package/dist/components/EntryScope.d.ts +1 -1
  6. package/dist/components/EntryScope.d.ts.map +1 -1
  7. package/dist/components/EntryScope.js +39 -0
  8. package/dist/components/EntryScope.js.map +1 -0
  9. package/dist/components/Header.js +103 -0
  10. package/dist/components/Header.js.map +1 -0
  11. package/dist/components/Layer.d.ts +2 -2
  12. package/dist/components/Layer.d.ts.map +1 -1
  13. package/dist/components/Layer.js +66 -0
  14. package/dist/components/Layer.js.map +1 -0
  15. package/dist/components/Link.d.ts +2 -2
  16. package/dist/components/Link.d.ts.map +1 -1
  17. package/dist/components/Link.js +51 -0
  18. package/dist/components/Link.js.map +1 -0
  19. package/dist/components/NavigationRoot.d.ts +2 -2
  20. package/dist/components/NavigationRoot.d.ts.map +1 -1
  21. package/dist/components/NavigationRoot.js +67 -0
  22. package/dist/components/NavigationRoot.js.map +1 -0
  23. package/dist/components/Screen.js +98 -0
  24. package/dist/components/Screen.js.map +1 -0
  25. package/dist/components/Stack.js +257 -0
  26. package/dist/components/Stack.js.map +1 -0
  27. package/dist/components/TabBar.d.ts +1 -1
  28. package/dist/components/TabBar.d.ts.map +1 -1
  29. package/dist/components/TabBar.js +63 -0
  30. package/dist/components/TabBar.js.map +1 -0
  31. package/dist/components/Tabs.js +168 -0
  32. package/dist/components/Tabs.js.map +1 -0
  33. package/dist/define-routes.d.ts +1 -1
  34. package/dist/define-routes.d.ts.map +1 -1
  35. package/{src/define-routes.d.ts → dist/define-routes.js} +4 -2
  36. package/dist/define-routes.js.map +1 -0
  37. package/dist/hooks/use-focus.js +87 -0
  38. package/dist/hooks/use-focus.js.map +1 -0
  39. package/dist/hooks/use-hardware-back.js +84 -0
  40. package/dist/hooks/use-hardware-back.js.map +1 -0
  41. package/dist/hooks/use-linking-nav.d.ts +3 -3
  42. package/dist/hooks/use-linking-nav.d.ts.map +1 -1
  43. package/dist/hooks/use-linking-nav.js +109 -0
  44. package/dist/hooks/use-linking-nav.js.map +1 -0
  45. package/dist/hooks/use-nav-internal.d.ts +2 -2
  46. package/dist/hooks/use-nav-internal.d.ts.map +1 -1
  47. package/dist/hooks/use-nav-internal.js +55 -0
  48. package/dist/hooks/use-nav-internal.js.map +1 -0
  49. package/dist/hooks/use-nav-serializer.d.ts +1 -1
  50. package/dist/hooks/use-nav-serializer.d.ts.map +1 -1
  51. package/dist/hooks/use-nav-serializer.js +181 -0
  52. package/dist/hooks/use-nav-serializer.js.map +1 -0
  53. package/dist/hooks/use-nav.d.ts +2 -2
  54. package/dist/hooks/use-nav.d.ts.map +1 -1
  55. package/dist/hooks/use-nav.js +11 -0
  56. package/dist/hooks/use-nav.js.map +1 -0
  57. package/dist/hooks/use-params.d.ts +1 -1
  58. package/dist/hooks/use-params.d.ts.map +1 -1
  59. package/{src/hooks/use-params.d.ts → dist/hooks/use-params.js} +6 -2
  60. package/dist/hooks/use-params.js.map +1 -0
  61. package/dist/hooks/use-screen-chrome.d.ts +1 -1
  62. package/dist/hooks/use-screen-chrome.d.ts.map +1 -1
  63. package/dist/hooks/use-screen-chrome.js +102 -0
  64. package/dist/hooks/use-screen-chrome.js.map +1 -0
  65. package/dist/hooks/use-screen-options.d.ts +1 -1
  66. package/dist/hooks/use-screen-options.d.ts.map +1 -1
  67. package/dist/hooks/use-screen-options.js +43 -0
  68. package/dist/hooks/use-screen-options.js.map +1 -0
  69. package/dist/hooks/use-search.d.ts +1 -1
  70. package/dist/hooks/use-search.d.ts.map +1 -1
  71. package/{src/hooks/use-search.d.ts → dist/hooks/use-search.js} +6 -2
  72. package/dist/hooks/use-search.js.map +1 -0
  73. package/dist/href.d.ts +2 -2
  74. package/dist/href.d.ts.map +1 -1
  75. package/dist/href.js +57 -0
  76. package/dist/href.js.map +1 -0
  77. package/dist/index.d.ts +33 -33
  78. package/dist/index.d.ts.map +1 -1
  79. package/dist/index.js +30 -1160
  80. package/dist/index.js.map +1 -1
  81. package/dist/internal/layer-plan.d.ts +1 -1
  82. package/dist/internal/layer-plan.d.ts.map +1 -1
  83. package/dist/internal/layer-plan.js +102 -0
  84. package/dist/internal/layer-plan.js.map +1 -0
  85. package/dist/internal/screen-registry.d.ts +1 -1
  86. package/dist/internal/screen-registry.d.ts.map +1 -1
  87. package/{src/internal/screen-registry.d.ts → dist/internal/screen-registry.js} +32 -21
  88. package/dist/internal/screen-registry.js.map +1 -0
  89. package/{src/internal/screen-width.d.ts → dist/internal/screen-width.js} +17 -2
  90. package/dist/internal/screen-width.js.map +1 -0
  91. package/dist/navigator/core.d.ts +3 -3
  92. package/dist/navigator/core.d.ts.map +1 -1
  93. package/dist/navigator/core.js +394 -0
  94. package/dist/navigator/core.js.map +1 -0
  95. package/dist/register.d.ts +1 -1
  96. package/dist/register.d.ts.map +1 -1
  97. package/dist/register.js +2 -0
  98. package/dist/register.js.map +1 -0
  99. package/dist/types.js +9 -0
  100. package/dist/types.js.map +1 -0
  101. package/dist/url/build.js +30 -0
  102. package/dist/url/build.js.map +1 -0
  103. package/dist/url/compile.js +83 -0
  104. package/dist/url/compile.js.map +1 -0
  105. package/dist/url/format.js +102 -0
  106. package/dist/url/format.js.map +1 -0
  107. package/dist/url/index.d.ts +6 -6
  108. package/dist/url/index.d.ts.map +1 -1
  109. package/dist/url/index.js +13 -0
  110. package/dist/url/index.js.map +1 -0
  111. package/dist/url/parse.d.ts +1 -1
  112. package/dist/url/parse.d.ts.map +1 -1
  113. package/dist/url/parse.js +94 -0
  114. package/dist/url/parse.js.map +1 -0
  115. package/dist/url/registry.d.ts +2 -2
  116. package/dist/url/registry.d.ts.map +1 -1
  117. package/{src/url/registry.d.ts → dist/url/registry.js} +28 -12
  118. package/dist/url/registry.js.map +1 -0
  119. package/dist/url/validate.d.ts +1 -1
  120. package/dist/url/validate.d.ts.map +1 -1
  121. package/dist/url/validate.js +37 -0
  122. package/dist/url/validate.js.map +1 -0
  123. package/package.json +13 -12
  124. package/src/components/EdgeBackHandle.tsx +2 -2
  125. package/src/components/EntryScope.tsx +3 -3
  126. package/src/components/Header.tsx +3 -3
  127. package/src/components/Layer.tsx +3 -3
  128. package/src/components/Link.tsx +4 -4
  129. package/src/components/NavigationRoot.tsx +6 -6
  130. package/src/components/Screen.tsx +3 -3
  131. package/src/components/Stack.tsx +8 -8
  132. package/src/components/TabBar.tsx +1 -1
  133. package/src/define-routes.ts +1 -1
  134. package/src/hooks/use-focus.ts +2 -2
  135. package/src/hooks/use-hardware-back.ts +1 -1
  136. package/src/hooks/use-linking-nav.ts +4 -4
  137. package/src/hooks/use-nav-internal.ts +2 -2
  138. package/src/hooks/use-nav-serializer.ts +3 -3
  139. package/src/hooks/use-nav.ts +2 -2
  140. package/src/hooks/use-params.ts +2 -2
  141. package/src/hooks/use-screen-chrome.ts +3 -3
  142. package/src/hooks/use-screen-options.ts +3 -3
  143. package/src/hooks/use-search.ts +2 -2
  144. package/src/href.ts +6 -6
  145. package/src/index.ts +33 -33
  146. package/src/internal/layer-plan.ts +2 -2
  147. package/src/internal/screen-registry.ts +1 -1
  148. package/src/navigator/core.ts +3 -3
  149. package/src/register.ts +1 -1
  150. package/src/url/build.ts +2 -2
  151. package/src/url/index.ts +6 -6
  152. package/src/url/parse.ts +6 -6
  153. package/src/url/registry.ts +3 -3
  154. package/src/url/validate.ts +1 -1
  155. package/src/components/Drawer.d.ts +0 -55
  156. package/src/components/EdgeBackHandle.d.ts +0 -1
  157. package/src/components/EntryScope.d.ts +0 -25
  158. package/src/components/Header.d.ts +0 -6
  159. package/src/components/Layer.d.ts +0 -33
  160. package/src/components/Link.d.ts +0 -60
  161. package/src/components/NavigationRoot.d.ts +0 -36
  162. package/src/components/Screen.d.ts +0 -97
  163. package/src/components/Stack.d.ts +0 -90
  164. package/src/components/TabBar.d.ts +0 -38
  165. package/src/components/Tabs.d.ts +0 -109
  166. package/src/hooks/use-focus.d.ts +0 -45
  167. package/src/hooks/use-hardware-back.d.ts +0 -37
  168. package/src/hooks/use-linking-nav.d.ts +0 -91
  169. package/src/hooks/use-nav-internal.d.ts +0 -91
  170. package/src/hooks/use-nav-serializer.d.ts +0 -82
  171. package/src/hooks/use-nav.d.ts +0 -111
  172. package/src/hooks/use-screen-chrome.d.ts +0 -18
  173. package/src/hooks/use-screen-options.d.ts +0 -2
  174. package/src/href.d.ts +0 -54
  175. package/src/index.d.ts +0 -39
  176. package/src/internal/layer-plan.d.ts +0 -68
  177. package/src/navigator/core.d.ts +0 -96
  178. package/src/register.d.ts +0 -37
  179. package/src/types.d.ts +0 -217
  180. package/src/url/build.d.ts +0 -15
  181. package/src/url/compile.d.ts +0 -34
  182. package/src/url/format.d.ts +0 -28
  183. package/src/url/parse.d.ts +0 -20
  184. package/src/url/validate.d.ts +0 -23
@@ -1,60 +0,0 @@
1
- import type { RouteId, RouteParams, RouteSearch } from '../register';
2
- import type { RoutesWithParams } from '../hooks/use-nav';
3
- /**
4
- * Per-route conditional props for `<Link>`.
5
- *
6
- * Mapped over `RouteId`, then indexed by `RouteId` to flatten into a union.
7
- * Each branch enforces the `params`-required-iff-route-has-schema rule:
8
- *
9
- * - `<Link to="profile" />` → TS error (profile requires params)
10
- * - `<Link to="profile" params={...} />` → ok
11
- * - `<Link to="home" />` → ok (home has no params)
12
- * - `<Link to="home" params={...} />` → TS error (home accepts no params)
13
- *
14
- * Same per-route discrimination as `nav.push`, expressed as a JSX-friendly
15
- * union rather than overloads.
16
- */
17
- type LinkPropsByRoute = {
18
- [K in RouteId]: K extends RoutesWithParams ? {
19
- to: K;
20
- params: RouteParams<K>;
21
- search?: RouteSearch<K>;
22
- } : {
23
- to: K;
24
- params?: undefined;
25
- search?: RouteSearch<K>;
26
- };
27
- }[RouteId];
28
- /**
29
- * Public type for `<Link>`'s props. The conditional `LinkPropsByRoute` carries
30
- * the typed `to`/`params`/`search` triple; the rest are simple optionals.
31
- *
32
- * `children` is declared explicitly because the public type is exposed via a
33
- * type-cast (so JSX sees a function-shaped signature). The cast strips sigx's
34
- * built-in `Define.Slot<'default'>` → JSX-children wiring, so we add a
35
- * permissive `children?` slot ourselves.
36
- */
37
- export type LinkProps = LinkPropsByRoute & {
38
- /** Use `replace` instead of `push` (no new history entry). */
39
- replace?: boolean;
40
- /** Link content rendered inside the tappable container. */
41
- children?: unknown;
42
- };
43
- /**
44
- * Declarative navigation. Same typing as `nav.push` — pass `params` only when
45
- * the route declares a schema. Wraps a `<view>` that fires `nav.push` (or
46
- * `nav.replace` if `replace` is set) on tap.
47
- *
48
- * @example
49
- * ```tsx
50
- * <Link to="home">Home</Link>
51
- * <Link to="profile" params={{ id: '42' }}>View profile</Link>
52
- * <Link to="profile" params={{ id: '42' }} search={{ tab: 'about' }}>About</Link>
53
- * <Link to="settings" replace>Settings (no back)</Link>
54
- * ```
55
- *
56
- * The cast widens the inferred prop type from the loose impl to the strict
57
- * `LinkProps` so JSX usage gets per-route discrimination. Runtime is identical.
58
- */
59
- export declare const Link: (props: LinkProps) => unknown;
60
- export {};
@@ -1,36 +0,0 @@
1
- import { type Define } from '@sigx/lynx';
2
- import type { RouteId } from '../register';
3
- import type { RouteMap } from '../types';
4
- type NavigationRootProps = Define.Prop<'routes', RouteMap, true> & Define.Prop<'initialRoute', RouteId> & Define.Prop<'initialParams', Record<string, unknown>> & Define.Prop<'initialSearch', Record<string, unknown>>
5
- /**
6
- * Enable slide-from-right transitions on push/pop. Defaults to true.
7
- * Tests against `@sigx/lynx-testing` (which doesn't have an MT runtime)
8
- * should pass `animated={false}` so navigations commit synchronously.
9
- */
10
- & Define.Prop<'animated', boolean>
11
- /**
12
- * Enable the iOS-style edge-swipe-back gesture. Defaults to true. Set
13
- * to false if it conflicts with screen content on the leftmost 20px,
14
- * or while debugging gesture issues.
15
- */
16
- & Define.Prop<'edgeSwipeEnabled', boolean> & Define.Slot<'default'>;
17
- /**
18
- * Root of a navigator subtree.
19
- *
20
- * Creates a fresh `NavigatorState` from `routes` and provides it via
21
- * `defineProvide`, so descendant `<Stack>` / `<Screen>` components and any
22
- * `useNav()` / `useParams()` calls resolve through this instance.
23
- *
24
- * The bottom-of-stack entry is built from `initialRoute` (defaults to the
25
- * first key in `routes`). For routes that declare a params schema, you must
26
- * pass `initialParams` matching that schema.
27
- *
28
- * Mirrors the install pattern of `@sigx/router` (see
29
- * `packages/router/src/router.ts:519-528`), but at component scope rather than
30
- * `app.use(router)` — no app-wide singleton, so multi-navigator apps and
31
- * tests get isolated state for free.
32
- */
33
- export declare const NavigationRoot: import("@sigx/runtime-core").ComponentFactory<NavigationRootProps, void, {
34
- default: () => import("@sigx/runtime-core").JSXElement | import("@sigx/runtime-core").JSXElement[] | null;
35
- }>;
36
- export {};
@@ -1,97 +0,0 @@
1
- /**
2
- * `<Screen>` — declarative per-screen options + slot fills.
3
- *
4
- * Usage:
5
- *
6
- * ```tsx
7
- * const ProfileScreen = component(() => () => (
8
- * <Screen title="Profile" headerShown gestureEnabled>
9
- * <Screen.HeaderRight>
10
- * <text bindtap={onEdit}>Edit</text>
11
- * </Screen.HeaderRight>
12
- * <view>body…</view>
13
- * </Screen>
14
- * ));
15
- * ```
16
- *
17
- * `<Screen>` itself renders its `default` slot inline — so the body lives
18
- * where you'd expect with no extra layout wrapper. The sub-components
19
- * (`Screen.Header`, `Screen.HeaderLeft`, `Screen.HeaderRight`,
20
- * `Screen.TabBarItem`) render `null` and write into the entry's
21
- * `ScreenRegistry`. The navigator's persistent chrome reads from there.
22
- *
23
- * Note: `<Screen.TabBarItem>` registers a scoped slot fill on the entry's
24
- * `ScreenRegistry`, but the built-in `<TabBar>` doesn't read it yet — the
25
- * fill is exposed for custom tab-bar renderers (pass `renderTab` and look
26
- * up the active entry's registry yourself).
27
- *
28
- * Sub-component placement inside `<Screen>` is conventional — sigx scopes
29
- * are by component tree, so they work anywhere under the same EntryScope.
30
- * Placing them as direct children of `<Screen>` keeps the call site
31
- * declarative and grep-friendly.
32
- */
33
- import { type Define } from '@sigx/lynx';
34
- type ScreenProps = Define.Prop<'title', string | (() => string)> & Define.Prop<'headerShown', boolean> & Define.Prop<'gestureEnabled', boolean> & Define.Slot<'default'>;
35
- type SimpleSlotProps = Define.Slot<'default'>;
36
- /**
37
- * `<Screen.TabBarItem>` — scoped slot. The default slot is a function that
38
- * receives `{ active }`; whatever it returns is the tab-bar item content.
39
- *
40
- * Sigx's `Define.Slot<'default', { active: boolean }>` would express this
41
- * directly on the component, but since `<Screen.TabBarItem>`'s parent
42
- * (the user's tree, not the navigator) doesn't actually pass `active`, we
43
- * accept a plain default slot whose body is itself a function. The
44
- * navigator's TabBar invokes that function with the active flag.
45
- */
46
- type TabBarItemProps = Define.Slot<'default'>;
47
- /**
48
- * Compound export. `Screen` is callable as a JSX element and exposes the
49
- * sub-components as properties (`Screen.Header`, etc.) for the declarative
50
- * call site shown in the file header.
51
- */
52
- export declare const Screen: ((props: {
53
- gestureEnabled?: boolean | undefined;
54
- headerShown?: boolean | undefined;
55
- title?: string | (() => string) | undefined;
56
- } & {} & {
57
- slots?: Partial<{
58
- default: () => import("@sigx/runtime-core").JSXElement | import("@sigx/runtime-core").JSXElement[] | null;
59
- }> | undefined;
60
- } & {} & JSX.IntrinsicAttributes & import("@sigx/runtime-core").ComponentAttributeExtensions & {
61
- ref?: import("@sigx/runtime-core").Ref<void> | undefined;
62
- children?: any;
63
- }) => import("@sigx/runtime-core").JSXElement) & {
64
- __setup: import("@sigx/runtime-core").SetupFn<{
65
- gestureEnabled?: boolean | undefined;
66
- headerShown?: boolean | undefined;
67
- title?: string | (() => string) | undefined;
68
- }, ScreenProps, void, {
69
- default: () => import("@sigx/runtime-core").JSXElement | import("@sigx/runtime-core").JSXElement[] | null;
70
- }>;
71
- __name?: string;
72
- __islandId?: string;
73
- __props: {
74
- gestureEnabled?: boolean | undefined;
75
- headerShown?: boolean | undefined;
76
- title?: string | (() => string) | undefined;
77
- };
78
- __events: ScreenProps;
79
- __ref: void;
80
- __slots: {
81
- default: () => import("@sigx/runtime-core").JSXElement | import("@sigx/runtime-core").JSXElement[] | null;
82
- };
83
- } & {
84
- Header: import("@sigx/runtime-core").ComponentFactory<SimpleSlotProps, void, {
85
- default: () => import("@sigx/runtime-core").JSXElement | import("@sigx/runtime-core").JSXElement[] | null;
86
- }>;
87
- HeaderLeft: import("@sigx/runtime-core").ComponentFactory<SimpleSlotProps, void, {
88
- default: () => import("@sigx/runtime-core").JSXElement | import("@sigx/runtime-core").JSXElement[] | null;
89
- }>;
90
- HeaderRight: import("@sigx/runtime-core").ComponentFactory<SimpleSlotProps, void, {
91
- default: () => import("@sigx/runtime-core").JSXElement | import("@sigx/runtime-core").JSXElement[] | null;
92
- }>;
93
- TabBarItem: import("@sigx/runtime-core").ComponentFactory<TabBarItemProps, void, {
94
- default: () => import("@sigx/runtime-core").JSXElement | import("@sigx/runtime-core").JSXElement[] | null;
95
- }>;
96
- };
97
- export {};
@@ -1,90 +0,0 @@
1
- import { type Define } from '@sigx/lynx';
2
- type StackProps =
3
- /**
4
- * Mint a nested navigator with this route at its base. When set, the
5
- * `<Stack>` becomes the owner of a new `NavigatorState` and provides
6
- * `useNav` / `useNavInternals` / `useNavRoutes` to its subtree, so
7
- * `nav.push('card-route', …)` from inside the stack stays *inside* it
8
- * (e.g. for per-tab stacks). Routes presented as `modal` / `fullScreen` /
9
- * `transparent-modal` automatically escalate to the parent navigator
10
- * via `nav.parent`, walking up until they reach the root — so modals
11
- * still overlay the whole app.
12
- *
13
- * Omit to render the *enclosing* navigator's stack (the default — this
14
- * is how `<NavigationRoot> → <Stack />` works).
15
- */
16
- Define.Prop<'initialRoute', string>
17
- /** Initial params for the nested-stack base entry. */
18
- & Define.Prop<'initialParams', Record<string, unknown>>
19
- /** Initial search for the nested-stack base entry. */
20
- & Define.Prop<'initialSearch', Record<string, unknown>>
21
- /**
22
- * Optional chrome rendered *above* the active screen, **inside this
23
- * Stack's nav scope**. The intended use is `<Header />`, which needs
24
- * to resolve `useNav()` to the per-stack nav (not the enclosing one)
25
- * so it can react to pushes inside this stack — e.g. show a back
26
- * button when a card is pushed onto a per-tab stack.
27
- *
28
- * Without this, a `<Header />` placed as a sibling of `<Stack>`
29
- * would see the enclosing nav and never update when pushes happen
30
- * inside the nested stack.
31
- */
32
- & Define.Slot<'default'>;
33
- /**
34
- * Stack navigator — renders the topmost stack entry's component at rest, or
35
- * the top + underneath entries during a transition.
36
- *
37
- * Two modes:
38
- *
39
- * **Bound** (no `initialRoute`): renders the enclosing navigator's stack.
40
- * This is the shape used directly under `<NavigationRoot>` and is what
41
- * single-stack apps want.
42
- *
43
- * **Nested-owner** (`initialRoute="…"`): mints a fresh `NavigatorState` with
44
- * its own progress `SharedValue` and edge-back gesture, and provides
45
- * `useNav` / `useNavInternals` / `useNavRoutes` to its subtree. `useNav()`
46
- * inside this stack returns the nested nav; `nav.parent` points to the
47
- * enclosing one. Per-tab stacks are the canonical use case:
48
- *
49
- * ```tsx
50
- * <Tabs initialTab="trips">
51
- * <Tabs.Screen name="trips"><Stack initialRoute="tripsHome" /></Tabs.Screen>
52
- * <Tabs.Screen name="map"><Stack initialRoute="mapHome" /></Tabs.Screen>
53
- * </Tabs>
54
- * ```
55
- *
56
- * Modal/fullScreen pushes escalate up the parent chain automatically — so
57
- * `nav.push('newTrip')` from inside Trips (where `newTrip` is `modal`)
58
- * walks to root and overlays the whole UI. `replace` stays strictly local
59
- * (asymmetric with `push`) so a modal `replace` never wipes the root stack.
60
- *
61
- * **Render strategy.** Stack always emits the same JSX shape — a
62
- * relative wrapper containing one `<Layer>` per entry returned by
63
- * `computeLayers(stack, transition, progress)`. Each Layer is an
64
- * absolutely-positioned host view with optional MT-bound translate
65
- * animation. The pure layer-plan function decides:
66
- *
67
- * - **Idle.** Topmost non-overlay base + any overlays above it. All
68
- * static (no transform). Overlays (`modal` / `fullScreen` /
69
- * `transparent-modal`) keep their underneath mounted; cards
70
- * replace their underneath in the base layer.
71
- * - **Card transition.** Both top and underneath animate (slide-in
72
- * + parallax). After settle, idle rules apply — the underneath
73
- * unmounts because the new top is the sole base.
74
- * - **Overlay transition.** The full idle layer stack up through
75
- * the underneath stays static; only the animated top has a
76
- * transform. After settle, the overlay either joins the static
77
- * idle stack (push) or unmounts (pop).
78
- *
79
- * Layer keys are `layer-${entry.key}-${animationVariant}`. The variant
80
- * suffix forces a remount when an entry transitions from animated to
81
- * static (or vice versa) — `useAnimatedStyle` binds once at setup and
82
- * can't switch its mapper at runtime. Modal underneath layers never
83
- * animate, so their key is stable across the modal lifecycle and the
84
- * subtree's state (per-tab Stack navigators, scroll positions,
85
- * in-flight inputs) survives.
86
- */
87
- export declare const Stack: import("@sigx/runtime-core").ComponentFactory<StackProps, void, {
88
- default: () => import("@sigx/runtime-core").JSXElement | import("@sigx/runtime-core").JSXElement[] | null;
89
- }>;
90
- export {};
@@ -1,38 +0,0 @@
1
- /**
2
- * `<TabBar>` — headless default chrome for `<Tabs>`.
3
- *
4
- * Renders the active-tab buttons reading from the enclosing `useTabs()`
5
- * navigator. Intentionally **unstyled** — this lives in the (theme-less)
6
- * navigation package, so it ships pure structure + accessibility wiring.
7
- * Themed chrome belongs in a UI-kit package: see `<NavTabBar />` in
8
- * `@sigx/lynx-daisyui` for the daisy-themed equivalent.
9
- *
10
- * Use this directly only if you want to handle styling yourself via the
11
- * `renderTab` prop. For a "looks like a tab bar out of the box" component,
12
- * pull `<NavTabBar />` from `@sigx/lynx-daisyui` (or your own UI kit).
13
- *
14
- * Customization:
15
- * - `renderTab`: a function `(info, ctx) => JSX` that fully replaces the
16
- * default button rendering for each tab. `ctx.active` tells the
17
- * consumer whether this tab is currently focused; `ctx.onPress`
18
- * activates the tab. **Recommended** for any visual treatment.
19
- *
20
- * Accessibility (baked into the default button — the one structural
21
- * concern this component keeps):
22
- * - `accessibility-label` from `info.accessibilityLabel ?? info.label ?? info.name`.
23
- * - `accessibility-element="true"` so screen readers see the whole pill.
24
- * - `accessibility-trait="button"` and a `selected` flag on the active
25
- * one so VoiceOver/TalkBack announces focus state on tab switch.
26
- */
27
- import { type JSXElement } from '@sigx/lynx';
28
- import { type TabInfo } from './Tabs';
29
- /** Rendering context passed to a `renderTab` consumer. */
30
- export interface TabRenderContext {
31
- /** True when this tab is currently active. Reactive — re-runs render on change. */
32
- readonly active: boolean;
33
- /** Activates this tab. Use as a `bindtap` handler on the rendered node. */
34
- onPress(): void;
35
- }
36
- export declare const TabBar: import("@sigx/runtime-core").ComponentFactory<{
37
- renderTab?: ((info: TabInfo, ctx: TabRenderContext) => JSXElement) | undefined;
38
- }, void, {}>;
@@ -1,109 +0,0 @@
1
- /**
2
- * `<Tabs>` — Lynx tab navigator.
3
- *
4
- * Usage:
5
- *
6
- * ```tsx
7
- * <NavigationRoot routes={routes} initialRoute="root">
8
- * <Stack />
9
- * </NavigationRoot>
10
- *
11
- * // The route "root" component renders:
12
- * <Tabs initialTab="feed">
13
- * <Tabs.Screen name="feed" icon={<FeedIcon />} label="Feed">
14
- * <Stack initialRoute="feedHome" />
15
- * </Tabs.Screen>
16
- * <Tabs.Screen name="me" icon={<MeIcon />} label="Profile">
17
- * <Stack initialRoute="profileHome" />
18
- * </Tabs.Screen>
19
- * <TabBar />
20
- * </Tabs>
21
- * ```
22
- *
23
- * Tab bodies stay mounted across switches (the inactive ones render with
24
- * `display: 'none'`), so each tab's nested `<Stack>` keeps its history when
25
- * the user flips back to it. The active tab is reactive via `useTabs()`.
26
- *
27
- * Per-tab stacks: each `<Tabs.Screen>` can host a `<Stack initialRoute="…">`
28
- * which mints its own navigator. `useNav()` inside that subtree resolves to
29
- * the tab's stack, so `nav.push('card-route', …)` stays inside the tab.
30
- * Routes presented as `modal` / `fullScreen` / `transparent-modal` escalate
31
- * up `nav.parent` to the root navigator automatically — they overlay the
32
- * tabs UI (TabBar included) and dismiss back into the originating tab.
33
- */
34
- import { type Define, type JSXElement } from '@sigx/lynx';
35
- /** Metadata about a registered `<Tabs.Screen>`. */
36
- export interface TabInfo {
37
- /** Stable tab id, used by `setActive`. */
38
- readonly name: string;
39
- /** Optional icon node — passed through to the default tab bar. */
40
- readonly icon?: JSXElement;
41
- /** Optional human-readable label. Defaults to `name`. */
42
- readonly label?: string;
43
- /**
44
- * Accessibility label announced by screen readers. Falls back to
45
- * `label`, then `name`. Surfaced as `accessibility-label` on the
46
- * default `<TabBar>` button.
47
- */
48
- readonly accessibilityLabel?: string;
49
- }
50
- /** Reactive controller exposed by `useTabs()`. */
51
- export interface TabsNav {
52
- /** Currently-active tab name. Reactive — accessing inside render/effect tracks. */
53
- readonly active: string;
54
- /** Switch the active tab. Triggers reactive updates in any consumer. */
55
- setActive(name: string): void;
56
- /** Snapshot of registered tabs in registration order. Reactive. */
57
- readonly tabs: ReadonlyArray<TabInfo>;
58
- }
59
- /**
60
- * Access the enclosing Tabs navigator. Throws when called outside `<Tabs>`.
61
- */
62
- export declare const useTabs: import("@sigx/runtime-core").InjectableFunction<TabsNav>;
63
- /**
64
- * @internal
65
- * Provided by each `<Tabs.Screen>` so a nested `<Stack initialRoute>` can
66
- * discover *which* tab it's hosted by, and gate its focus state on that
67
- * tab being active. Throws when called outside a `<Tabs.Screen>` body so
68
- * the gate degrades to "always active" via the caller's try/catch.
69
- */
70
- export declare const useTabScreenName: import("@sigx/runtime-core").InjectableFunction<string>;
71
- type TabsProps = Define.Prop<'initialTab', string> & Define.Slot<'default'>;
72
- type TabsScreenProps = Define.Prop<'name', string, true> & Define.Prop<'icon', JSXElement> & Define.Prop<'label', string> & Define.Prop<'accessibilityLabel', string> & Define.Slot<'default'>;
73
- /**
74
- * Compound export. `Tabs` is the parent component; `Tabs.Screen` registers
75
- * an individual tab. Matches the `Screen` / `Screen.Header` shape used
76
- * elsewhere in this package and the daisyui `Modal` / `Modal.Header`
77
- * convention.
78
- */
79
- export declare const Tabs: ((props: {
80
- initialTab?: string | undefined;
81
- } & {} & {
82
- slots?: Partial<{
83
- default: () => JSXElement | JSXElement[] | null;
84
- }> | undefined;
85
- } & {} & JSX.IntrinsicAttributes & import("@sigx/runtime-core").ComponentAttributeExtensions & {
86
- ref?: import("@sigx/runtime-core").Ref<void> | undefined;
87
- children?: any;
88
- }) => JSXElement) & {
89
- __setup: import("@sigx/runtime-core").SetupFn<{
90
- initialTab?: string | undefined;
91
- }, TabsProps, void, {
92
- default: () => JSXElement | JSXElement[] | null;
93
- }>;
94
- __name?: string;
95
- __islandId?: string;
96
- __props: {
97
- initialTab?: string | undefined;
98
- };
99
- __events: TabsProps;
100
- __ref: void;
101
- __slots: {
102
- default: () => JSXElement | JSXElement[] | null;
103
- };
104
- } & {
105
- Screen: import("@sigx/runtime-core").ComponentFactory<TabsScreenProps, void, {
106
- default: () => JSXElement | JSXElement[] | null;
107
- }>;
108
- };
109
- export {};
@@ -1,45 +0,0 @@
1
- import { type Computed } from '@sigx/lynx';
2
- /**
3
- * Reactive "is this screen the focused entry?" signal.
4
- *
5
- * Must be called from inside a component rendered as a route by `<Stack>` (or
6
- * any other navigator that uses `<EntryScope>`); throws otherwise. The
7
- * returned `Computed` reads `nav.current.key` and compares it to the entry
8
- * the calling screen was mounted for, so any nav mutation that changes the
9
- * top entry flips the value.
10
- *
11
- * Note: screens stay mounted when something is pushed on top of them — they
12
- * just lose focus. Pop the new top off and they regain focus.
13
- *
14
- * @example
15
- * ```tsx
16
- * const Profile = component(() => {
17
- * const isFocused = useIsFocused();
18
- * return () => <text>{isFocused.value ? 'visible' : 'hidden'}</text>;
19
- * });
20
- * ```
21
- */
22
- export declare function useIsFocused(): Computed<boolean>;
23
- /**
24
- * Run `cb` whenever this screen gains focus; run the returned cleanup when it
25
- * loses focus or unmounts. Mirrors React Navigation's `useFocusEffect`.
26
- *
27
- * Lifecycle:
28
- * - cb runs immediately if the screen is already focused at mount.
29
- * - When the screen loses focus (something pushed on top), cleanup runs.
30
- * - When focus returns (the cover is popped), `cb` runs again — yielding a
31
- * fresh cleanup for the next blur.
32
- * - On unmount, cleanup runs once if still focused.
33
- *
34
- * Common uses: subscribe to a data source while visible, track an analytics
35
- * "screen view" event, start/stop a polling loop.
36
- *
37
- * @example
38
- * ```tsx
39
- * useFocusEffect(() => {
40
- * const id = setInterval(refresh, 5000);
41
- * return () => clearInterval(id);
42
- * });
43
- * ```
44
- */
45
- export declare function useFocusEffect(cb: () => void | (() => void)): void;
@@ -1,37 +0,0 @@
1
- /**
2
- * Wire the Android hardware back button to the active navigator.
3
- *
4
- * Listens for `hardwareBackPress` events from `@sigx/lynx-linking`'s
5
- * `BackHandler` (which the native side dispatches from
6
- * `MainActivity.onBackPressed`). On press the handler walks to the
7
- * deepest currently-focused navigator (per-tab `<Stack>`s register with
8
- * their parent), then walks back up the `parent` chain looking for the
9
- * first nav that `canGoBack`:
10
- *
11
- * - If any nav in the chain can go back → `nav.pop()` on that nav.
12
- * - Otherwise → `BackHandler.exitApp()` (Android: `moveTaskToBack(true)`,
13
- * keeps the bundle warm; iOS: rejects, since iOS doesn't permit
14
- * programmatic termination).
15
- *
16
- * The traversal means you only need to call this once at the root — a
17
- * back press from inside a tab pops that tab's nested stack first, only
18
- * exiting the app once every level is at its base entry.
19
- *
20
- * Call this once in any component under `<NavigationRoot>` (typically a
21
- * thin wrapper sibling to `<Stack />`). iOS doesn't fire the event so the
22
- * hook is a no-op there.
23
- *
24
- * @example
25
- * ```tsx
26
- * const BackHandlerWiring = component(() => {
27
- * useHardwareBack();
28
- * return () => null;
29
- * });
30
- *
31
- * <NavigationRoot routes={routes}>
32
- * <BackHandlerWiring />
33
- * <Stack />
34
- * </NavigationRoot>
35
- * ```
36
- */
37
- export declare function useHardwareBack(): void;
@@ -1,91 +0,0 @@
1
- import { type Href } from '../href';
2
- import { type Nav } from './use-nav';
3
- import type { RouteMap } from '../types';
4
- export interface UseLinkingNavOptions {
5
- /**
6
- * Schemes/prefixes to strip before parsing. Matched in order; the first
7
- * match wins. Example: `['myapp://', 'https://myapp.com']` lets
8
- * `https://myapp.com/users/42` parse against the same routes as
9
- * `/users/42`.
10
- *
11
- * After stripping, a leading `/` is added if missing so the result is a
12
- * valid pathname.
13
- */
14
- prefixes?: string[];
15
- /**
16
- * Custom handler invoked instead of the default dispatch. Use this when
17
- * you need to intercept (e.g. for auth callbacks, analytics) before
18
- * routing. If you call `nav.push` / `nav.replace` from here, the default
19
- * dispatch is skipped — return `void`.
20
- */
21
- onURL?: (url: string, nav: Nav) => void;
22
- /**
23
- * Called when an incoming URL doesn't match any registered route's `path`
24
- * template (or fails schema validation). Defaults to a no-op so unknown
25
- * URLs are dropped silently. Use this to surface "page not found" UX or
26
- * to forward to a catch-all route.
27
- */
28
- onUnmatched?: (url: string) => void;
29
- /**
30
- * Whether to use `nav.replace` instead of `nav.push` for the cold-start
31
- * initial URL. Defaults to `true` — restoring an app into a deep link
32
- * shouldn't leave a stray "initial route" entry beneath it that the back
33
- * button can return to.
34
- *
35
- * Runtime URLs (from `addEventListener`) always `push`.
36
- */
37
- replaceInitial?: boolean;
38
- }
39
- /**
40
- * Bridge `@sigx/lynx-linking` URL events into a `@sigx/lynx-navigation`
41
- * navigator. Call once inside a `<NavigationRoot>` subtree.
42
- *
43
- * Handles both delivery modes:
44
- * - **cold start** — `Linking.getInitialURL()` is read on mount and, if
45
- * present, dispatched (replacing the initial route by default).
46
- * - **warm start** — `Linking.addEventListener('url', ...)` subscribes for
47
- * URLs delivered while the app is already running; each one is pushed.
48
- *
49
- * URL → route dispatch goes through `parseHref`, which matches the URL's
50
- * pathname against the route registry seeded by `<NavigationRoot>`. Routes
51
- * without a `path` template are never matched by deep links — only typed
52
- * `<Link>` / `nav.push` calls reach them.
53
- *
54
- * @example
55
- * ```tsx
56
- * import { useLinkingNav } from '@sigx/lynx-navigation';
57
- *
58
- * const DeepLinks = component(() => {
59
- * useLinkingNav({
60
- * prefixes: ['myapp://', 'https://myapp.com'],
61
- * onUnmatched: (url) => console.warn('Unknown deep link:', url),
62
- * });
63
- * return () => null;
64
- * });
65
- *
66
- * <NavigationRoot routes={routes}>
67
- * <DeepLinks />
68
- * <Stack />
69
- * </NavigationRoot>
70
- * ```
71
- */
72
- export declare function useLinkingNav(opts?: UseLinkingNavOptions): void;
73
- /**
74
- * Strip the first matching prefix from `url`, returning a pathname-like
75
- * string. If no prefixes are provided, or none match, the original URL is
76
- * returned unchanged so `parseHref` can still handle scheme-prefixed forms
77
- * via `@sigx/lynx-linking`'s `parse`.
78
- *
79
- * Exported for unit testing — not part of the package public API.
80
- */
81
- export declare function _stripPrefix(url: string, prefixes?: string[]): string;
82
- /**
83
- * Call the right `nav.push` / `nav.replace` overload for `href`. The
84
- * overloads differ in positional layout: routes with a params schema take
85
- * `(name, params, search?, options?)`; routes without take `(name, search?,
86
- * options?)`. Calling the wrong shape silently shifts `search` into the
87
- * `options` slot, so we look the route up in the registry and branch.
88
- *
89
- * Exported for unit testing — not part of the package public API.
90
- */
91
- export declare function _navigateToHref(nav: Nav, routes: RouteMap, href: Href, kind: 'push' | 'replace'): void;