@mapples/navigation 1.1.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 (66) hide show
  1. package/README.md +46 -0
  2. package/dist/MapplesNavigation.d.ts +10 -0
  3. package/dist/MapplesNavigation.d.ts.map +1 -0
  4. package/dist/MapplesNavigation.js +30 -0
  5. package/dist/MapplesNavigation.js.map +1 -0
  6. package/dist/NavigationActionHandler.d.ts +14 -0
  7. package/dist/NavigationActionHandler.d.ts.map +1 -0
  8. package/dist/NavigationActionHandler.js +50 -0
  9. package/dist/NavigationActionHandler.js.map +1 -0
  10. package/dist/actionCommands.d.ts +11 -0
  11. package/dist/actionCommands.d.ts.map +1 -0
  12. package/dist/actionCommands.js +45 -0
  13. package/dist/actionCommands.js.map +1 -0
  14. package/dist/buildNavigator.d.ts +14 -0
  15. package/dist/buildNavigator.d.ts.map +1 -0
  16. package/dist/buildNavigator.js +87 -0
  17. package/dist/buildNavigator.js.map +1 -0
  18. package/dist/constants.d.ts +19 -0
  19. package/dist/constants.d.ts.map +1 -0
  20. package/dist/constants.js +18 -0
  21. package/dist/constants.js.map +1 -0
  22. package/dist/index.d.ts +18 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +17 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/mappers/drawerOptions.d.ts +5 -0
  27. package/dist/mappers/drawerOptions.d.ts.map +1 -0
  28. package/dist/mappers/drawerOptions.js +26 -0
  29. package/dist/mappers/drawerOptions.js.map +1 -0
  30. package/dist/mappers/headerOptions.d.ts +10 -0
  31. package/dist/mappers/headerOptions.d.ts.map +1 -0
  32. package/dist/mappers/headerOptions.js +42 -0
  33. package/dist/mappers/headerOptions.js.map +1 -0
  34. package/dist/mappers/index.d.ts +5 -0
  35. package/dist/mappers/index.d.ts.map +1 -0
  36. package/dist/mappers/index.js +5 -0
  37. package/dist/mappers/index.js.map +1 -0
  38. package/dist/mappers/screenOptions.d.ts +13 -0
  39. package/dist/mappers/screenOptions.d.ts.map +1 -0
  40. package/dist/mappers/screenOptions.js +37 -0
  41. package/dist/mappers/screenOptions.js.map +1 -0
  42. package/dist/mappers/tabBarOptions.d.ts +5 -0
  43. package/dist/mappers/tabBarOptions.d.ts.map +1 -0
  44. package/dist/mappers/tabBarOptions.js +37 -0
  45. package/dist/mappers/tabBarOptions.js.map +1 -0
  46. package/dist/model.d.ts +90 -0
  47. package/dist/model.d.ts.map +1 -0
  48. package/dist/model.js +189 -0
  49. package/dist/model.js.map +1 -0
  50. package/dist/refs.d.ts +15 -0
  51. package/dist/refs.d.ts.map +1 -0
  52. package/dist/refs.js +21 -0
  53. package/dist/refs.js.map +1 -0
  54. package/dist/types.d.ts +126 -0
  55. package/dist/types.d.ts.map +1 -0
  56. package/dist/types.js +1 -0
  57. package/dist/types.js.map +1 -0
  58. package/dist/useRefResolvers.d.ts +10 -0
  59. package/dist/useRefResolvers.d.ts.map +1 -0
  60. package/dist/useRefResolvers.js +64 -0
  61. package/dist/useRefResolvers.js.map +1 -0
  62. package/dist/vendor.d.ts +29 -0
  63. package/dist/vendor.d.ts.map +1 -0
  64. package/dist/vendor.js +29 -0
  65. package/dist/vendor.js.map +1 -0
  66. package/package.json +46 -0
@@ -0,0 +1,37 @@
1
+ import { mapHeaderOptions } from './headerOptions';
2
+ /**
3
+ * Per-route native-stack options: the route's header overrides
4
+ * ({@link RouteNode.options} extends `Partial<HeaderOptions>`) plus its
5
+ * `presentation`.
6
+ */
7
+ export const mapStackScreenOptions = (route, resolvers) => {
8
+ const patch = {
9
+ ...mapHeaderOptions(route.options, resolvers),
10
+ };
11
+ if (route.presentation !== undefined)
12
+ patch.presentation = route.presentation;
13
+ return patch;
14
+ };
15
+ /** Per-route bottom-tabs item options (label + icon). */
16
+ export const mapTabItemOptions = (route, resolvers) => {
17
+ const patch = {};
18
+ if (route.options?.tabLabel !== undefined) {
19
+ patch.tabBarLabel = route.options.tabLabel;
20
+ }
21
+ const icon = resolvers.resolveIcon(route.options?.tabIcon);
22
+ if (icon)
23
+ patch.tabBarIcon = icon;
24
+ return patch;
25
+ };
26
+ /** Per-route drawer item options (label + icon). */
27
+ export const mapDrawerItemOptions = (route, resolvers) => {
28
+ const patch = {};
29
+ if (route.options?.drawerLabel !== undefined) {
30
+ patch.drawerLabel = route.options.drawerLabel;
31
+ }
32
+ const icon = resolvers.resolveIcon(route.options?.drawerIcon);
33
+ if (icon)
34
+ patch.drawerIcon = icon;
35
+ return patch;
36
+ };
37
+ //# sourceMappingURL=screenOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screenOptions.js","sourceRoot":"","sources":["../../src/mappers/screenOptions.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,KAAgB,EAChB,SAAuB,EACE,EAAE;IAC3B,MAAM,KAAK,GAA4B;QACrC,GAAG,gBAAgB,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,CAAC;KAC9C,CAAC;IACF,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS;QAAE,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,YAAY,CAAC;IAC9E,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,yDAAyD;AACzD,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,KAAgB,EAChB,SAAuB,EACF,EAAE;IACvB,MAAM,KAAK,GAAwB,EAAE,CAAC;IACtC,IAAI,KAAK,CAAC,OAAO,EAAE,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC1C,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;IAC7C,CAAC;IACD,MAAM,IAAI,GAAG,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC3D,IAAI,IAAI;QAAE,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC;IAClC,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,oDAAoD;AACpD,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,KAAgB,EAChB,SAAuB,EACC,EAAE;IAC1B,MAAM,KAAK,GAA2B,EAAE,CAAC;IACzC,IAAI,KAAK,CAAC,OAAO,EAAE,WAAW,KAAK,SAAS,EAAE,CAAC;QAC7C,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC;IAChD,CAAC;IACD,MAAM,IAAI,GAAG,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAC9D,IAAI,IAAI;QAAE,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC;IAClC,OAAO,KAAK,CAAC;AACf,CAAC,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { TabBarOptions } from '@mapples/types';
2
+ import { RefResolvers, TabBarOptionsPatch } from '../types';
3
+ /** Map {@link TabBarOptions} to a bottom-tabs navigator options patch. */
4
+ export declare const mapTabBarOptions: (tabBar: TabBarOptions | undefined, resolvers: RefResolvers) => TabBarOptionsPatch;
5
+ //# sourceMappingURL=tabBarOptions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabBarOptions.d.ts","sourceRoot":"","sources":["../../src/mappers/tabBarOptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAE5D,0EAA0E;AAC1E,eAAO,MAAM,gBAAgB,GAC3B,QAAQ,aAAa,GAAG,SAAS,EACjC,WAAW,YAAY,KACtB,kBAkCF,CAAC"}
@@ -0,0 +1,37 @@
1
+ /** Map {@link TabBarOptions} to a bottom-tabs navigator options patch. */
2
+ export const mapTabBarOptions = (tabBar, resolvers) => {
3
+ const patch = {};
4
+ if (!tabBar)
5
+ return patch;
6
+ const style = {};
7
+ if (tabBar.visible !== undefined) {
8
+ style.display = tabBar.visible ? 'flex' : 'none';
9
+ }
10
+ const backgroundColor = resolvers.resolveColor(tabBar.backgroundColor);
11
+ if (backgroundColor)
12
+ style.backgroundColor = backgroundColor;
13
+ if (Object.keys(style).length)
14
+ patch.tabBarStyle = style;
15
+ const activeTintColor = resolvers.resolveColor(tabBar.activeTintColor);
16
+ if (activeTintColor)
17
+ patch.tabBarActiveTintColor = activeTintColor;
18
+ const inactiveTintColor = resolvers.resolveColor(tabBar.inactiveTintColor);
19
+ if (inactiveTintColor)
20
+ patch.tabBarInactiveTintColor = inactiveTintColor;
21
+ if (tabBar.labelVisible !== undefined) {
22
+ patch.tabBarShowLabel = tabBar.labelVisible;
23
+ }
24
+ if (tabBar.labelStyle) {
25
+ const labelStyle = {};
26
+ if (tabBar.labelStyle.fontFamily) {
27
+ labelStyle.fontFamily = tabBar.labelStyle.fontFamily;
28
+ }
29
+ if (tabBar.labelStyle.fontSize !== undefined) {
30
+ labelStyle.fontSize = tabBar.labelStyle.fontSize;
31
+ }
32
+ if (Object.keys(labelStyle).length)
33
+ patch.tabBarLabelStyle = labelStyle;
34
+ }
35
+ return patch;
36
+ };
37
+ //# sourceMappingURL=tabBarOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabBarOptions.js","sourceRoot":"","sources":["../../src/mappers/tabBarOptions.ts"],"names":[],"mappings":"AAIA,0EAA0E;AAC1E,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,MAAiC,EACjC,SAAuB,EACH,EAAE;IACtB,MAAM,KAAK,GAAuB,EAAE,CAAC;IACrC,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAE1B,MAAM,KAAK,GAAmD,EAAE,CAAC;IACjE,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACjC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IACnD,CAAC;IACD,MAAM,eAAe,GAAG,SAAS,CAAC,YAAY,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IACvE,IAAI,eAAe;QAAE,KAAK,CAAC,eAAe,GAAG,eAAe,CAAC;IAC7D,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM;QAAE,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC;IAEzD,MAAM,eAAe,GAAG,SAAS,CAAC,YAAY,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IACvE,IAAI,eAAe;QAAE,KAAK,CAAC,qBAAqB,GAAG,eAAe,CAAC;IAEnE,MAAM,iBAAiB,GAAG,SAAS,CAAC,YAAY,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;IAC3E,IAAI,iBAAiB;QAAE,KAAK,CAAC,uBAAuB,GAAG,iBAAiB,CAAC;IAEzE,IAAI,MAAM,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;QACtC,KAAK,CAAC,eAAe,GAAG,MAAM,CAAC,YAAY,CAAC;IAC9C,CAAC;IAED,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACtB,MAAM,UAAU,GAAwD,EAAE,CAAC;QAC3E,IAAI,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC;YACjC,UAAU,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC;QACvD,CAAC;QACD,IAAI,MAAM,CAAC,UAAU,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC7C,UAAU,CAAC,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC;QACnD,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM;YAAE,KAAK,CAAC,gBAAgB,GAAG,UAAU,CAAC;IAC1E,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC,CAAC"}
@@ -0,0 +1,90 @@
1
+ import { NavigationDocument, NavigatorNode, NavigatorType, RouteNode } from '@mapples/types';
2
+ /**
3
+ * Build the navigator-qualified screen name for a route.
4
+ *
5
+ * Route names are unique only *within* a navigator (the validator allows two
6
+ * stacks to each own an `index` route), so a bare name like `index` is
7
+ * ambiguous as a `navigate` target. Navigator names are unique per document, so
8
+ * `<navigatorName>:<routeName>` is a stable, unambiguous screen name. This is
9
+ * the name registered with React Navigation and stored as the action target.
10
+ */
11
+ export declare const qualifyRouteName: (navigatorName: string, routeName: string) => string;
12
+ /** A screen within a {@link NavigatorModel}. */
13
+ export interface ScreenModel {
14
+ /** Navigator-qualified screen name (`<navigatorName>:<routeName>`). */
15
+ routeName: string;
16
+ routeId: string;
17
+ route: RouteNode;
18
+ /** Page leaf, or a nested navigator already expanded into a child model. */
19
+ target: {
20
+ kind: 'page';
21
+ pageUuid: string;
22
+ } | {
23
+ kind: 'navigator';
24
+ child: NavigatorModel;
25
+ };
26
+ }
27
+ /** A fully-expanded navigator ready to be rendered. */
28
+ export interface NavigatorModel {
29
+ id: string;
30
+ type: NavigatorType;
31
+ name: string;
32
+ node: NavigatorNode;
33
+ /** Resolved initial route name (defaults to the first screen). */
34
+ initialRouteName?: string;
35
+ screens: ScreenModel[];
36
+ }
37
+ /**
38
+ * Expand a {@link NavigationDocument} into a navigator tree by following
39
+ * `navigator` route targets from the root. Pure and side-effect free — it does
40
+ * not touch React Navigation, so it can be asserted on directly in tests.
41
+ *
42
+ * Assumes a validated document (see `validateNavigationDocument`); a missing or
43
+ * cyclic navigator reference simply stops that branch rather than throwing.
44
+ */
45
+ export declare const buildNavigationModel: (document: NavigationDocument) => NavigatorModel | null;
46
+ /**
47
+ * The navigator-qualified screen name of the first route (anywhere in the
48
+ * document) that targets a given page. Used to resolve `pageUuid` navigation
49
+ * targets to a screen name.
50
+ */
51
+ export declare const findRouteNameForPage: (document: NavigationDocument, pageUuid: string) => string | null;
52
+ /**
53
+ * Resolve a navigation target to the qualified screen name the runtime
54
+ * navigates to.
55
+ *
56
+ * - An exact `<navigator>:<route>` match is returned as-is.
57
+ * - A bare legacy route name (no navigator prefix) resolves to the first route
58
+ * with that name, qualified, with a one-time warning — backward compatibility
59
+ * for documents authored before targets were qualified.
60
+ *
61
+ * Returns `null` when nothing matches.
62
+ */
63
+ export declare const resolveScreenName: (document: NavigationDocument, target: string) => string | null;
64
+ /**
65
+ * The set of route ids nested beneath a tree node — every screen reachable
66
+ * under a navigator, or under a route that targets a navigator. The editor uses
67
+ * this to keep a parent node selected while the preview shows one of its
68
+ * descendant screens.
69
+ */
70
+ export declare const collectDescendantRouteIds: (document: NavigationDocument, nodeId: string) => Set<string>;
71
+ /** A React Navigation `navigate` call: a screen name plus optional nested params. */
72
+ export interface ScreenNavigateTarget {
73
+ name: string;
74
+ params?: object;
75
+ }
76
+ /**
77
+ * Build the (possibly nested) navigate target for a qualified screen name.
78
+ *
79
+ * React Navigation can't reach a screen inside a nested navigator by a flat
80
+ * name — it descends via `navigate(parent, { screen, params })`. We walk the
81
+ * document from the root to the target route and nest the qualified screen
82
+ * names so the action lands in the right navigator. Returns `null` when the
83
+ * name resolves to no route.
84
+ *
85
+ * @example
86
+ * // screen "HomeStack:Feed" nested under the "Root:HomeTab" route →
87
+ * { name: 'Root:HomeTab', params: { screen: 'HomeStack:Feed', params: undefined } }
88
+ */
89
+ export declare const buildScreenNavigateTarget: (document: NavigationDocument, screenName: string, params?: object) => ScreenNavigateTarget | null;
90
+ //# sourceMappingURL=model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,SAAS,EACV,MAAM,gBAAgB,CAAC;AAExB;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,GAC3B,eAAe,MAAM,EACrB,WAAW,MAAM,KAChB,MAAyC,CAAC;AAE7C,gDAAgD;AAChD,MAAM,WAAW,WAAW;IAC1B,uEAAuE;IACvE,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,SAAS,CAAC;IACjB,4EAA4E;IAC5E,MAAM,EACF;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAClC;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,KAAK,EAAE,cAAc,CAAA;KAAE,CAAC;CAClD;AAED,uDAAuD;AACvD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,CAAC;IACpB,kEAAkE;IAClE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAC/B,UAAU,kBAAkB,KAC3B,cAAc,GAAG,IA+CnB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAC/B,UAAU,kBAAkB,EAC5B,UAAU,MAAM,KACf,MAAM,GAAG,IASX,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,GAC5B,UAAU,kBAAkB,EAC5B,QAAQ,MAAM,KACb,MAAM,GAAG,IAuBX,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,GACpC,UAAU,kBAAkB,EAC5B,QAAQ,MAAM,KACb,GAAG,CAAC,MAAM,CA8BZ,CAAC;AAEF,qFAAqF;AACrF,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAwBD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,yBAAyB,GACpC,UAAU,kBAAkB,EAC5B,YAAY,MAAM,EAClB,SAAS,MAAM,KACd,oBAAoB,GAAG,IAYzB,CAAC"}
package/dist/model.js ADDED
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Build the navigator-qualified screen name for a route.
3
+ *
4
+ * Route names are unique only *within* a navigator (the validator allows two
5
+ * stacks to each own an `index` route), so a bare name like `index` is
6
+ * ambiguous as a `navigate` target. Navigator names are unique per document, so
7
+ * `<navigatorName>:<routeName>` is a stable, unambiguous screen name. This is
8
+ * the name registered with React Navigation and stored as the action target.
9
+ */
10
+ export const qualifyRouteName = (navigatorName, routeName) => `${navigatorName}:${routeName}`;
11
+ /**
12
+ * Expand a {@link NavigationDocument} into a navigator tree by following
13
+ * `navigator` route targets from the root. Pure and side-effect free — it does
14
+ * not touch React Navigation, so it can be asserted on directly in tests.
15
+ *
16
+ * Assumes a validated document (see `validateNavigationDocument`); a missing or
17
+ * cyclic navigator reference simply stops that branch rather than throwing.
18
+ */
19
+ export const buildNavigationModel = (document) => {
20
+ const build = (navigatorId, seen) => {
21
+ const node = document.navigators[navigatorId];
22
+ if (!node || seen.has(navigatorId))
23
+ return null;
24
+ const nextSeen = new Set(seen).add(navigatorId);
25
+ const screens = [];
26
+ for (const route of node.routes) {
27
+ const routeName = qualifyRouteName(node.name, route.name);
28
+ if (route.target.kind === 'page') {
29
+ screens.push({
30
+ routeName,
31
+ routeId: route.id,
32
+ route,
33
+ target: { kind: 'page', pageUuid: route.target.pageUuid },
34
+ });
35
+ }
36
+ else {
37
+ const child = build(route.target.navigatorId, nextSeen);
38
+ if (!child)
39
+ continue;
40
+ screens.push({
41
+ routeName,
42
+ routeId: route.id,
43
+ route,
44
+ target: { kind: 'navigator', child },
45
+ });
46
+ }
47
+ }
48
+ const initialRouteName = screens.find((screen) => screen.routeId === node.initialRouteId)
49
+ ?.routeName ?? screens[0]?.routeName;
50
+ return {
51
+ id: node.id,
52
+ type: node.type,
53
+ name: node.name,
54
+ node,
55
+ screens,
56
+ initialRouteName,
57
+ };
58
+ };
59
+ return build(document.rootNavigatorId, new Set());
60
+ };
61
+ /**
62
+ * The navigator-qualified screen name of the first route (anywhere in the
63
+ * document) that targets a given page. Used to resolve `pageUuid` navigation
64
+ * targets to a screen name.
65
+ */
66
+ export const findRouteNameForPage = (document, pageUuid) => {
67
+ for (const navigator of Object.values(document.navigators)) {
68
+ for (const route of navigator.routes) {
69
+ if (route.target.kind === 'page' && route.target.pageUuid === pageUuid) {
70
+ return qualifyRouteName(navigator.name, route.name);
71
+ }
72
+ }
73
+ }
74
+ return null;
75
+ };
76
+ /**
77
+ * Resolve a navigation target to the qualified screen name the runtime
78
+ * navigates to.
79
+ *
80
+ * - An exact `<navigator>:<route>` match is returned as-is.
81
+ * - A bare legacy route name (no navigator prefix) resolves to the first route
82
+ * with that name, qualified, with a one-time warning — backward compatibility
83
+ * for documents authored before targets were qualified.
84
+ *
85
+ * Returns `null` when nothing matches.
86
+ */
87
+ export const resolveScreenName = (document, target) => {
88
+ let firstBareMatch = null;
89
+ for (const navigator of Object.values(document.navigators)) {
90
+ for (const route of navigator.routes) {
91
+ const qualified = qualifyRouteName(navigator.name, route.name);
92
+ if (qualified === target)
93
+ return qualified;
94
+ if (route.name === target && firstBareMatch === null) {
95
+ firstBareMatch = qualified;
96
+ }
97
+ }
98
+ }
99
+ if (firstBareMatch) {
100
+ console.warn(`[mapples-navigation] navigation target "${target}" is a bare route name ` +
101
+ `and was resolved to "${firstBareMatch}". Re-save the navigation ` +
102
+ `document to store the qualified "navigator:route" target.`);
103
+ return firstBareMatch;
104
+ }
105
+ return null;
106
+ };
107
+ /**
108
+ * The set of route ids nested beneath a tree node — every screen reachable
109
+ * under a navigator, or under a route that targets a navigator. The editor uses
110
+ * this to keep a parent node selected while the preview shows one of its
111
+ * descendant screens.
112
+ */
113
+ export const collectDescendantRouteIds = (document, nodeId) => {
114
+ const result = new Set();
115
+ const collect = (navigatorId, seen) => {
116
+ const navigator = document.navigators[navigatorId];
117
+ if (!navigator || seen.has(navigatorId))
118
+ return;
119
+ const next = new Set(seen).add(navigatorId);
120
+ for (const route of navigator.routes) {
121
+ result.add(route.id);
122
+ if (route.target.kind === 'navigator') {
123
+ collect(route.target.navigatorId, next);
124
+ }
125
+ }
126
+ };
127
+ if (document.navigators[nodeId]) {
128
+ collect(nodeId, new Set());
129
+ return result;
130
+ }
131
+ for (const navigator of Object.values(document.navigators)) {
132
+ const route = navigator.routes.find((r) => r.id === nodeId);
133
+ if (route) {
134
+ if (route.target.kind === 'navigator') {
135
+ collect(route.target.navigatorId, new Set());
136
+ }
137
+ break;
138
+ }
139
+ }
140
+ return result;
141
+ };
142
+ /** Qualified screen names from the root navigator down to `screenName`. */
143
+ const findScreenPath = (document, screenName) => {
144
+ const visit = (navigatorId, seen) => {
145
+ const navigator = document.navigators[navigatorId];
146
+ if (!navigator || seen.has(navigatorId))
147
+ return null;
148
+ const next = new Set(seen).add(navigatorId);
149
+ for (const route of navigator.routes) {
150
+ const qualified = qualifyRouteName(navigator.name, route.name);
151
+ if (qualified === screenName)
152
+ return [qualified];
153
+ if (route.target.kind === 'navigator') {
154
+ const sub = visit(route.target.navigatorId, next);
155
+ if (sub)
156
+ return [qualified, ...sub];
157
+ }
158
+ }
159
+ return null;
160
+ };
161
+ return visit(document.rootNavigatorId, new Set());
162
+ };
163
+ /**
164
+ * Build the (possibly nested) navigate target for a qualified screen name.
165
+ *
166
+ * React Navigation can't reach a screen inside a nested navigator by a flat
167
+ * name — it descends via `navigate(parent, { screen, params })`. We walk the
168
+ * document from the root to the target route and nest the qualified screen
169
+ * names so the action lands in the right navigator. Returns `null` when the
170
+ * name resolves to no route.
171
+ *
172
+ * @example
173
+ * // screen "HomeStack:Feed" nested under the "Root:HomeTab" route →
174
+ * { name: 'Root:HomeTab', params: { screen: 'HomeStack:Feed', params: undefined } }
175
+ */
176
+ export const buildScreenNavigateTarget = (document, screenName, params) => {
177
+ const names = findScreenPath(document, screenName);
178
+ if (!names)
179
+ return null;
180
+ let target = { name: names[names.length - 1], params };
181
+ for (let i = names.length - 2; i >= 0; i--) {
182
+ target = {
183
+ name: names[i],
184
+ params: { screen: target.name, params: target.params },
185
+ };
186
+ }
187
+ return target;
188
+ };
189
+ //# sourceMappingURL=model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
package/dist/refs.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Parsing for the shared `ref(assetType:uuid:name)` grammar (same grammar as
3
+ * `@mapples/render`'s `RefPropsMap`). Used to resolve `ref(theme:…)` colours and
4
+ * `ref(icon:…)` icons at render time.
5
+ */
6
+ export interface ParsedRef {
7
+ type: string;
8
+ uuid: string;
9
+ name: string;
10
+ }
11
+ /** Parse a `ref(type:uuid:name)` string, or `null` if it isn't one. */
12
+ export declare const parseRef: (value?: string) => ParsedRef | null;
13
+ /** Whether a value is a `ref(...)` string (of `type`, if given). */
14
+ export declare const isRef: (value?: string, type?: string) => boolean;
15
+ //# sourceMappingURL=refs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refs.d.ts","sourceRoot":"","sources":["../src/refs.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAID,uEAAuE;AACvE,eAAO,MAAM,QAAQ,GAAI,QAAQ,MAAM,KAAG,SAAS,GAAG,IAKrD,CAAC;AAEF,oEAAoE;AACpE,eAAO,MAAM,KAAK,GAAI,QAAQ,MAAM,EAAE,OAAO,MAAM,KAAG,OAGrD,CAAC"}
package/dist/refs.js ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Parsing for the shared `ref(assetType:uuid:name)` grammar (same grammar as
3
+ * `@mapples/render`'s `RefPropsMap`). Used to resolve `ref(theme:…)` colours and
4
+ * `ref(icon:…)` icons at render time.
5
+ */
6
+ const REF_PATTERN = /^ref\(([^:]+):([^:]+):(.+)\)$/;
7
+ /** Parse a `ref(type:uuid:name)` string, or `null` if it isn't one. */
8
+ export const parseRef = (value) => {
9
+ if (!value)
10
+ return null;
11
+ const match = REF_PATTERN.exec(value);
12
+ if (!match)
13
+ return null;
14
+ return { type: match[1], uuid: match[2], name: match[3] };
15
+ };
16
+ /** Whether a value is a `ref(...)` string (of `type`, if given). */
17
+ export const isRef = (value, type) => {
18
+ const parsed = parseRef(value);
19
+ return !!parsed && (!type || parsed.type === type);
20
+ };
21
+ //# sourceMappingURL=refs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refs.js","sourceRoot":"","sources":["../src/refs.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,MAAM,WAAW,GAAG,+BAA+B,CAAC;AAEpD,uEAAuE;AACvE,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAoB,EAAE;IAC3D,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAC5D,CAAC,CAAC;AAEF,oEAAoE;AACpE,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,KAAc,EAAE,IAAa,EAAW,EAAE;IAC9D,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC/B,OAAO,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AACrD,CAAC,CAAC"}
@@ -0,0 +1,126 @@
1
+ import { ComponentType, ReactNode } from 'react';
2
+ import { NavigationDocument } from '@mapples/types';
3
+ /** Renders an icon for a tab/drawer item, given the runtime colour/size. */
4
+ export type IconRenderer = (props: {
5
+ color?: string;
6
+ size?: number;
7
+ }) => ReactNode;
8
+ /**
9
+ * Resolves `ref(…)` option values to concrete runtime values. Supplied by the
10
+ * host (from `@mapples/style` + `@mapples/render` contexts); stubbed in tests.
11
+ */
12
+ export interface RefResolvers {
13
+ /** Resolve a colour value or `ref(theme:…)` to a concrete colour. */
14
+ resolveColor: (value?: string) => string | undefined;
15
+ /** Resolve `ref(icon:…)` to an icon renderer. */
16
+ resolveIcon: (value?: string) => IconRenderer | undefined;
17
+ }
18
+ /** Subset of native-stack header options the runtime sets. */
19
+ export interface StackHeaderOptionsPatch {
20
+ headerShown?: boolean;
21
+ title?: string;
22
+ headerStyle?: {
23
+ backgroundColor?: string;
24
+ };
25
+ headerTintColor?: string;
26
+ headerTitleStyle?: {
27
+ fontFamily?: string;
28
+ fontSize?: number;
29
+ color?: string;
30
+ };
31
+ headerBackVisible?: boolean;
32
+ headerShadowVisible?: boolean;
33
+ }
34
+ /** Per-route native-stack options (header overrides + presentation). */
35
+ export interface StackScreenOptionsPatch extends StackHeaderOptionsPatch {
36
+ presentation?: 'card' | 'modal' | 'transparentModal';
37
+ }
38
+ /** Subset of bottom-tabs navigator options the runtime sets. */
39
+ export interface TabBarOptionsPatch {
40
+ tabBarStyle?: {
41
+ display?: 'flex' | 'none';
42
+ backgroundColor?: string;
43
+ };
44
+ tabBarActiveTintColor?: string;
45
+ tabBarInactiveTintColor?: string;
46
+ tabBarShowLabel?: boolean;
47
+ tabBarLabelStyle?: {
48
+ fontFamily?: string;
49
+ fontSize?: number;
50
+ };
51
+ }
52
+ /** Per-route bottom-tabs item options. */
53
+ export interface TabItemOptionsPatch {
54
+ tabBarLabel?: string;
55
+ tabBarIcon?: IconRenderer;
56
+ }
57
+ /** Subset of drawer navigator options the runtime sets. */
58
+ export interface DrawerOptionsPatch {
59
+ drawerPosition?: 'left' | 'right';
60
+ drawerType?: 'front' | 'back' | 'slide';
61
+ drawerStyle?: {
62
+ backgroundColor?: string;
63
+ width?: number;
64
+ };
65
+ drawerActiveTintColor?: string;
66
+ drawerInactiveTintColor?: string;
67
+ }
68
+ /** Per-route drawer item options. */
69
+ export interface DrawerItemOptionsPatch {
70
+ drawerLabel?: string;
71
+ drawerIcon?: IconRenderer;
72
+ }
73
+ /** A resolved navigation intent, applied to the navigation container ref. */
74
+ export type NavigationCommand = {
75
+ kind: 'navigate';
76
+ routeName: string;
77
+ params?: Record<string, unknown>;
78
+ } | {
79
+ kind: 'goBack';
80
+ } | {
81
+ kind: 'openDrawer';
82
+ } | {
83
+ kind: 'closeDrawer';
84
+ } | {
85
+ kind: 'switchTab';
86
+ routeName: string;
87
+ };
88
+ /**
89
+ * Structural subset of React Navigation's container ref the runtime uses.
90
+ * Typed here (rather than importing `@react-navigation/native`) so this module
91
+ * stays free of the React Navigation dependency. A real
92
+ * `NavigationContainerRef` satisfies it.
93
+ */
94
+ export interface MapplesNavigationRef {
95
+ isReady: () => boolean;
96
+ canGoBack: () => boolean;
97
+ goBack: () => void;
98
+ navigate: (name: string, params?: object) => void;
99
+ dispatch: (action: unknown) => void;
100
+ getCurrentRoute: () => {
101
+ name: string;
102
+ } | undefined;
103
+ addListener: (type: string, callback: (...args: unknown[]) => void) => () => void;
104
+ }
105
+ /** Props for {@link MapplesNavigation}. */
106
+ export interface MapplesNavigationProps {
107
+ document: NavigationDocument;
108
+ /** pageUuid → component rendered for that page. */
109
+ pages: Record<string, ComponentType<Record<string, unknown>>>;
110
+ /** Rendered when a route references a missing page. */
111
+ fallback?: ComponentType<{
112
+ pageUuid: string;
113
+ }>;
114
+ /**
115
+ * Render inside `NavigationIndependentTree` instead of a `NavigationContainer`
116
+ * — required when the host app already owns a container (expo-router / Creator).
117
+ */
118
+ independent?: boolean;
119
+ /**
120
+ * Externally-created container ref. Supply one to observe/drive navigation
121
+ * from the host (e.g. the Creator preview's selection sync). When omitted, an
122
+ * internal ref is created.
123
+ */
124
+ navigationRef?: MapplesNavigationRef;
125
+ }
126
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,10 @@
1
+ import { RefResolvers } from './types';
2
+ /**
3
+ * Builds {@link RefResolvers} from the host's style + render contexts:
4
+ * `ref(theme:…)` resolves against `@mapples/style`'s active theme, `ref(icon:…)`
5
+ * against `@mapples/render`'s assets map. Unresolvable refs warn and fall back to
6
+ * a default rather than crashing.
7
+ */
8
+ declare const useRefResolvers: () => RefResolvers;
9
+ export default useRefResolvers;
10
+ //# sourceMappingURL=useRefResolvers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRefResolvers.d.ts","sourceRoot":"","sources":["../src/useRefResolvers.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAgB,YAAY,EAAE,MAAM,SAAS,CAAC;AAYrD;;;;;GAKG;AACH,QAAA,MAAM,eAAe,QAAO,YA8C3B,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -0,0 +1,64 @@
1
+ import { createElement } from 'react';
2
+ import { useRender } from '@mapples/render';
3
+ import { useTheme } from '@mapples/style';
4
+ import { Image } from 'react-native';
5
+ import { parseRef } from './refs';
6
+ /** Resolve a dot-path (e.g. `primary.main`) against the active theme map. */
7
+ const lookupToken = (map, path) => {
8
+ let current = map;
9
+ for (const key of path.split('.')) {
10
+ if (current == null || typeof current === 'string')
11
+ return undefined;
12
+ current = current[key];
13
+ }
14
+ return typeof current === 'string' ? current : undefined;
15
+ };
16
+ /**
17
+ * Builds {@link RefResolvers} from the host's style + render contexts:
18
+ * `ref(theme:…)` resolves against `@mapples/style`'s active theme, `ref(icon:…)`
19
+ * against `@mapples/render`'s assets map. Unresolvable refs warn and fall back to
20
+ * a default rather than crashing.
21
+ */
22
+ const useRefResolvers = () => {
23
+ const { theme, themeConfig } = useTheme();
24
+ const { assets } = useRender();
25
+ const resolveColor = (value) => {
26
+ if (!value)
27
+ return undefined;
28
+ const parsed = parseRef(value);
29
+ if (!parsed)
30
+ return value; // already a concrete colour value
31
+ if (parsed.type !== 'theme')
32
+ return undefined;
33
+ const resolved = lookupToken(theme, parsed.name);
34
+ if (resolved)
35
+ return resolved;
36
+ console.warn(`[@mapples/navigation] unresolved theme ref: ${value}`);
37
+ return themeConfig.defaultColor;
38
+ };
39
+ const resolveIcon = (value) => {
40
+ if (!value)
41
+ return undefined;
42
+ const parsed = parseRef(value);
43
+ if (!parsed || parsed.type !== 'icon')
44
+ return undefined;
45
+ const asset = assets[value];
46
+ if (asset == null) {
47
+ console.warn(`[@mapples/navigation] unresolved icon ref: ${value}`);
48
+ return undefined;
49
+ }
50
+ const source = typeof asset === 'string'
51
+ ? { uri: asset }
52
+ : asset;
53
+ // The returned value is a React Navigation icon option callback, not a
54
+ // component, so it needs no display name.
55
+ // eslint-disable-next-line react/display-name
56
+ return ({ size }) => createElement(Image, {
57
+ source,
58
+ style: { width: size ?? 24, height: size ?? 24 },
59
+ });
60
+ };
61
+ return { resolveColor, resolveIcon };
62
+ };
63
+ export default useRefResolvers;
64
+ //# sourceMappingURL=useRefResolvers.js.map