@ankhorage/contracts 11.1.0 → 12.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/dist/appManifest/navigator.js +1 -7
- package/dist/appManifest/navigator.js.map +1 -1
- package/dist/appManifest/navigatorOptions.js +18 -17
- package/dist/appManifest/navigatorOptions.js.map +1 -1
- package/dist/navigator/catalog.d.ts +42 -0
- package/dist/navigator/catalog.d.ts.map +1 -0
- package/dist/navigator/catalog.js +2 -0
- package/dist/navigator/catalog.js.map +1 -0
- package/dist/navigator/generation.d.ts +14 -4
- package/dist/navigator/generation.d.ts.map +1 -1
- package/dist/navigator/generation.js.map +1 -1
- package/dist/navigator/planning.d.ts +9 -9
- package/dist/navigator/planning.d.ts.map +1 -1
- package/dist/navigator/planning.js.map +1 -1
- package/dist/navigator.d.ts +20 -24
- package/dist/navigator.d.ts.map +1 -1
- package/dist/navigator.js +9 -9
- package/dist/navigator.js.map +1 -1
- package/package.json +2 -2
- package/src/appManifest/navigator.ts +1 -10
- package/src/appManifest/navigatorOptions.ts +19 -18
- package/src/navigator/catalog.ts +79 -0
- package/src/navigator/generation.ts +22 -4
- package/src/navigator/planning.ts +10 -9
- package/src/navigator-runtime-contracts.test.ts +54 -3
- package/src/navigator-validation.test.ts +31 -4
- package/src/navigator.test.ts +37 -16
- package/src/navigator.ts +39 -30
package/dist/navigator.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigator.d.ts","sourceRoot":"","sources":["../src/navigator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAEvD,eAAO,MAAM,eAAe,sEAAuE,CAAC;AACpG,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D,eAAO,MAAM,iBAAiB,
|
|
1
|
+
{"version":3,"file":"navigator.d.ts","sourceRoot":"","sources":["../src/navigator.ts"],"names":[],"mappings":"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"}
|
package/dist/navigator.js
CHANGED
|
@@ -4,16 +4,16 @@ export const NAVIGATOR_PRESETS = [
|
|
|
4
4
|
'stack',
|
|
5
5
|
'tabs',
|
|
6
6
|
'tabs-stack',
|
|
7
|
+
'stack-tabs',
|
|
8
|
+
'stack-tabs-stack',
|
|
7
9
|
'drawer',
|
|
8
10
|
'drawer-stack',
|
|
11
|
+
'stack-drawer',
|
|
12
|
+
'stack-drawer-stack',
|
|
9
13
|
'drawer-tabs',
|
|
10
14
|
'drawer-tabs-stack',
|
|
11
|
-
'
|
|
12
|
-
'
|
|
13
|
-
'root-stack-drawer',
|
|
14
|
-
'root-stack-drawer-stack',
|
|
15
|
-
'root-stack-drawer-tabs',
|
|
16
|
-
'root-stack-drawer-tabs-stack',
|
|
15
|
+
'stack-drawer-tabs',
|
|
16
|
+
'stack-drawer-tabs-stack',
|
|
17
17
|
'split-view',
|
|
18
18
|
'custom',
|
|
19
19
|
];
|
|
@@ -30,9 +30,9 @@ export const STACK_PRESENTATIONS = [
|
|
|
30
30
|
export const JAVASCRIPT_STACK_PRESENTATIONS = ['card', 'modal', 'transparentModal'];
|
|
31
31
|
export const DRAWER_POSITIONS = ['left', 'right'];
|
|
32
32
|
export const DRAWER_TYPES = ['front', 'back', 'slide', 'permanent'];
|
|
33
|
-
export const
|
|
34
|
-
export const
|
|
35
|
-
...
|
|
33
|
+
export const FIXED_HEADLESS_TABS_PRESENTATIONS = ['bottom', 'top', 'rail', 'sidebar'];
|
|
34
|
+
export const HEADLESS_TABS_PRESENTATIONS = [
|
|
35
|
+
...FIXED_HEADLESS_TABS_PRESENTATIONS,
|
|
36
36
|
'responsive',
|
|
37
37
|
'custom',
|
|
38
38
|
];
|
package/dist/navigator.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigator.js","sourceRoot":"","sources":["../src/navigator.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,CAAU,CAAC;AAGpG,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,MAAM;IACN,OAAO;IACP,MAAM;IACN,YAAY;IACZ,QAAQ;IACR,cAAc;IACd,aAAa;IACb,mBAAmB;IACnB,iBAAiB;IACjB,uBAAuB;IACvB,mBAAmB;IACnB,yBAAyB;IACzB,wBAAwB;IACxB,8BAA8B;IAC9B,YAAY;IACZ,QAAQ;CACA,CAAC;AAGX,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,QAAQ,EAAE,YAAY,EAAE,cAAc,CAAU,CAAC;AAGvF,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,MAAM;IACN,OAAO;IACP,kBAAkB;IAClB,gBAAgB;IAChB,2BAA2B;IAC3B,iBAAiB;IACjB,WAAW;CACH,CAAC;AAGX,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,kBAAkB,CAAU,CAAC;AA4C7F,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,MAAM,EAAE,OAAO,CAAU,CAAC;AAG3D,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,CAAU,CAAC;AAU7E,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,CAAU,CAAC;AAG7F,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,GAAG,+BAA+B;IAClC,YAAY;IACZ,QAAQ;CACA,CAAC;AAGX,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAU,CAAC;AAGxE,MAAM,CAAC,MAAM,8BAA8B,GAAG;IAC5C,WAAW;IACX,OAAO;IACP,cAAc;IACd,YAAY;CACJ,CAAC","sourcesContent":["import type { IconSpec, ManifestValue } from './types';\n\nexport const NAVIGATOR_TYPES = ['slot', 'stack', 'tabs', 'drawer', 'split-view', 'custom'] as const;\nexport type NavigatorType = (typeof NAVIGATOR_TYPES)[number];\n\nexport const NAVIGATOR_PRESETS = [\n 'slot',\n 'stack',\n 'tabs',\n 'tabs-stack',\n 'drawer',\n 'drawer-stack',\n 'drawer-tabs',\n 'drawer-tabs-stack',\n 'root-stack-tabs',\n 'root-stack-tabs-stack',\n 'root-stack-drawer',\n 'root-stack-drawer-stack',\n 'root-stack-drawer-tabs',\n 'root-stack-drawer-tabs-stack',\n 'split-view',\n 'custom',\n] as const;\nexport type NavigatorPreset = (typeof NAVIGATOR_PRESETS)[number];\n\nexport const STACK_IMPLEMENTATIONS = ['native', 'javascript', 'experimental'] as const;\nexport type StackImplementation = (typeof STACK_IMPLEMENTATIONS)[number];\n\nexport const STACK_PRESENTATIONS = [\n 'card',\n 'modal',\n 'transparentModal',\n 'containedModal',\n 'containedTransparentModal',\n 'fullScreenModal',\n 'formSheet',\n] as const;\nexport type StackPresentation = (typeof STACK_PRESENTATIONS)[number];\n\nexport const JAVASCRIPT_STACK_PRESENTATIONS = ['card', 'modal', 'transparentModal'] as const;\nexport type JavaScriptStackPresentation = (typeof JAVASCRIPT_STACK_PRESENTATIONS)[number];\n\nexport interface StackHeaderOptions {\n title?: string;\n headerShown?: boolean;\n headerTransparent?: boolean;\n headerBackVisible?: boolean;\n}\n\nexport type StackScreenOptions = StackHeaderOptions &\n (\n | {\n presentation?: Exclude<StackPresentation, 'formSheet'>;\n sheetAllowedDetents?: never;\n sheetGrabberVisible?: never;\n }\n | {\n presentation: 'formSheet';\n sheetAllowedDetents?: 'fitToContents' | number[];\n sheetGrabberVisible?: boolean;\n }\n );\n\nexport type JavaScriptStackScreenOptions = StackHeaderOptions & {\n presentation?: JavaScriptStackPresentation;\n};\n\nexport type StackImplementationConfig =\n | {\n /** Omission selects the stable native stack implementation. */\n implementation?: 'native';\n options?: StackScreenOptions;\n }\n | {\n implementation: 'javascript';\n options?: JavaScriptStackScreenOptions;\n }\n | {\n /** Expo Router Experimental Stack is alpha, native-only, and available from SDK 56. */\n implementation: 'experimental';\n options?: StackHeaderOptions;\n };\n\nexport const DRAWER_POSITIONS = ['left', 'right'] as const;\nexport type DrawerPosition = (typeof DRAWER_POSITIONS)[number];\n\nexport const DRAWER_TYPES = ['front', 'back', 'slide', 'permanent'] as const;\nexport type DrawerType = (typeof DRAWER_TYPES)[number];\n\nexport interface DrawerNavigatorOptions {\n drawerPosition?: DrawerPosition;\n drawerType?: DrawerType;\n swipeEnabled?: boolean;\n headerShown?: boolean;\n}\n\nexport const FIXED_CUSTOM_TABS_PRESENTATIONS = ['bottom', 'top', 'rail', 'sidebar'] as const;\nexport type FixedCustomTabsPresentation = (typeof FIXED_CUSTOM_TABS_PRESENTATIONS)[number];\n\nexport const CUSTOM_TABS_PRESENTATIONS = [\n ...FIXED_CUSTOM_TABS_PRESENTATIONS,\n 'responsive',\n 'custom',\n] as const;\nexport type CustomTabsPresentation = (typeof CUSTOM_TABS_PRESENTATIONS)[number];\n\nexport const JAVASCRIPT_TABS_PRESENTATIONS = ['bottom', 'top'] as const;\nexport type JavaScriptTabsPresentation = (typeof JAVASCRIPT_TABS_PRESENTATIONS)[number];\n\nexport const NATIVE_TABS_MINIMIZE_BEHAVIORS = [\n 'automatic',\n 'never',\n 'onScrollDown',\n 'onScrollUp',\n] as const;\nexport type NativeTabsMinimizeBehavior = (typeof NATIVE_TABS_MINIMIZE_BEHAVIORS)[number];\n\nexport interface ResponsiveTabsPresentation {\n compact: FixedCustomTabsPresentation;\n medium?: FixedCustomTabsPresentation;\n expanded: FixedCustomTabsPresentation;\n}\n\nexport type CustomTabsPresentationConfig =\n | {\n presentation: FixedCustomTabsPresentation;\n responsive?: never;\n customPresentationId?: never;\n }\n | {\n presentation: 'responsive';\n responsive: ResponsiveTabsPresentation;\n customPresentationId?: never;\n }\n | {\n presentation: 'custom';\n responsive?: never;\n /** Serializable registered presentation id. */\n customPresentationId: string;\n };\n\nexport type CustomTabsConfig = {\n implementation: 'custom';\n} & CustomTabsPresentationConfig;\n\nexport type CustomTabsWebConfig = CustomTabsPresentationConfig;\n\nexport interface NavigatorScreenReference {\n screenId: string;\n}\n\nexport interface NativeTabsConfig {\n implementation: 'native';\n /** Expo Router Native Tabs is alpha; minimizing is available on iOS 26+ from SDK 55. */\n minimizeBehavior?: NativeTabsMinimizeBehavior;\n /** Registered screen rendered through NativeTabs.BottomAccessory, available from SDK 55. */\n bottomAccessory?: NavigatorScreenReference;\n}\n\nexport interface JavaScriptTabsConfig {\n implementation: 'javascript';\n presentation?: JavaScriptTabsPresentation;\n}\n\nexport interface AdaptiveTabsConfig {\n /** Omission selects the canonical adaptive default. */\n implementation?: 'adaptive';\n /** Android/iOS branch. Expo Router may expose this implementation as unstable. */\n native?: NativeTabsConfig;\n /** Web branch rendered through headless custom tabs. */\n web?: CustomTabsWebConfig;\n}\n\nexport type TabsImplementationConfig =\n AdaptiveTabsConfig | CustomTabsConfig | JavaScriptTabsConfig | NativeTabsConfig;\n\ninterface NavigatorNodeBase {\n initialRouteName?: string;\n routes: RouteDefinition[];\n}\n\nexport interface SlotNavigatorNode extends NavigatorNodeBase {\n type: 'slot';\n}\n\nexport type StackNavigatorNode = NavigatorNodeBase & {\n type: 'stack';\n} & StackImplementationConfig;\n\nexport interface DrawerNavigatorNode extends NavigatorNodeBase {\n type: 'drawer';\n options?: DrawerNavigatorOptions;\n}\n\nexport type TabsNavigatorConfig = {\n type: 'tabs';\n} & TabsImplementationConfig;\n\nexport type TabsNavigatorNode = NavigatorNodeBase & TabsNavigatorConfig;\n\nexport interface SplitViewNavigatorNode extends NavigatorNodeBase {\n type: 'split-view';\n columns: {\n primary: NavigatorScreenReference;\n supplementary?: NavigatorScreenReference;\n };\n inspector?: NavigatorScreenReference;\n /** Split View is alpha and iOS-only; other platforms fall back to Slot. */\n topColumnForCollapsing?: 'primary' | 'supplementary' | 'secondary';\n}\n\nexport interface CustomNavigatorNode extends NavigatorNodeBase {\n type: 'custom';\n navigatorId: string;\n config?: Readonly<Record<string, ManifestValue>>;\n}\n\nexport type NavigatorNode =\n | CustomNavigatorNode\n | DrawerNavigatorNode\n | SlotNavigatorNode\n | SplitViewNavigatorNode\n | StackNavigatorNode\n | TabsNavigatorNode;\n\nexport interface RouteDefinition {\n name: string;\n path?: string;\n label?: string;\n icon?: IconSpec;\n /** Hide this route from primary Tabs/Drawer presentation without making it unnavigable. */\n showInPrimaryNavigation?: boolean;\n guards?: string[];\n screenId?: string;\n /** Presentation applied by the resolved parent stack implementation. */\n stackOptions?: StackScreenOptions;\n navigator?: NavigatorNode;\n}\n\nexport interface NavigatorFlows {\n onboarding?: boolean;\n authentication?: boolean;\n}\n\nexport interface NavigatorDefaults {\n tabs?: TabsImplementationConfig;\n stack?: StackImplementationConfig;\n}\n\nexport interface NavigatorPlatformConfig {\n tabs?: TabsImplementationConfig;\n stack?: StackImplementationConfig;\n}\n\nexport interface NavigatorPlatforms {\n android?: NavigatorPlatformConfig;\n ios?: NavigatorPlatformConfig;\n web?: NavigatorPlatformConfig;\n}\n\n/**\n * Serializable desired state for `AppManifest.navigator`.\n *\n * The manifest slice is the root navigator tree itself; optional authoring metadata does not add\n * a redundant `root` wrapper. The standalone Navigator capability consumes this slice directly.\n */\nexport type AppNavigatorManifest = NavigatorNode & {\n preset?: NavigatorPreset;\n flows?: NavigatorFlows;\n defaults?: NavigatorDefaults;\n platforms?: NavigatorPlatforms;\n};\n\nexport type {\n CustomNavigatorConfigIssue,\n CustomNavigatorRegistration,\n CustomNavigatorRegistry,\n} from './navigator/extensions';\nexport type {\n NavigatorGeneratedFile,\n NavigatorGenerationBindings,\n NavigatorGenerationOptions,\n NavigatorScreenModule,\n} from './navigator/generation';\nexport type {\n CreateNavigatorPlanOptions,\n ExpoRouterNavigatorModule,\n NavigatorAdapterId,\n NavigatorAdapterPlan,\n NavigatorApiStability,\n NavigatorDiagnostic,\n NavigatorNodePlan,\n NavigatorPlan,\n NavigatorResponsiveSize,\n NavigatorRoutePlan,\n NavigatorRuntimePlatform,\n NavigatorSupportStatus,\n NavigatorValidationContext,\n ResolvedCustomTabsPresentation,\n ResolvedTabsImplementation,\n ResolvedTabsPresentation,\n TabsNavigatorPlan,\n} from './navigator/planning';\n"]}
|
|
1
|
+
{"version":3,"file":"navigator.js","sourceRoot":"","sources":["../src/navigator.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,CAAU,CAAC;AAGpG,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,MAAM;IACN,OAAO;IACP,MAAM;IACN,YAAY;IACZ,YAAY;IACZ,kBAAkB;IAClB,QAAQ;IACR,cAAc;IACd,cAAc;IACd,oBAAoB;IACpB,aAAa;IACb,mBAAmB;IACnB,mBAAmB;IACnB,yBAAyB;IACzB,YAAY;IACZ,QAAQ;CACA,CAAC;AAGX,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,QAAQ,EAAE,YAAY,EAAE,cAAc,CAAU,CAAC;AAGvF,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,MAAM;IACN,OAAO;IACP,kBAAkB;IAClB,gBAAgB;IAChB,2BAA2B;IAC3B,iBAAiB;IACjB,WAAW;CACH,CAAC;AAGX,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,kBAAkB,CAAU,CAAC;AA4C7F,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,MAAM,EAAE,OAAO,CAAU,CAAC;AAG3D,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,CAAU,CAAC;AAU7E,MAAM,CAAC,MAAM,iCAAiC,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,CAAU,CAAC;AAG/F,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,GAAG,iCAAiC;IACpC,YAAY;IACZ,QAAQ;CACA,CAAC;AAGX,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAU,CAAC;AAGxE,MAAM,CAAC,MAAM,8BAA8B,GAAG;IAC5C,WAAW;IACX,OAAO;IACP,cAAc;IACd,YAAY;CACJ,CAAC","sourcesContent":["import type { IconSpec, ManifestValue } from './types';\n\nexport const NAVIGATOR_TYPES = ['slot', 'stack', 'tabs', 'drawer', 'split-view', 'custom'] as const;\nexport type NavigatorType = (typeof NAVIGATOR_TYPES)[number];\n\nexport const NAVIGATOR_PRESETS = [\n 'slot',\n 'stack',\n 'tabs',\n 'tabs-stack',\n 'stack-tabs',\n 'stack-tabs-stack',\n 'drawer',\n 'drawer-stack',\n 'stack-drawer',\n 'stack-drawer-stack',\n 'drawer-tabs',\n 'drawer-tabs-stack',\n 'stack-drawer-tabs',\n 'stack-drawer-tabs-stack',\n 'split-view',\n 'custom',\n] as const;\nexport type NavigatorPreset = (typeof NAVIGATOR_PRESETS)[number];\n\nexport const STACK_IMPLEMENTATIONS = ['native', 'javascript', 'experimental'] as const;\nexport type StackImplementation = (typeof STACK_IMPLEMENTATIONS)[number];\n\nexport const STACK_PRESENTATIONS = [\n 'card',\n 'modal',\n 'transparentModal',\n 'containedModal',\n 'containedTransparentModal',\n 'fullScreenModal',\n 'formSheet',\n] as const;\nexport type StackPresentation = (typeof STACK_PRESENTATIONS)[number];\n\nexport const JAVASCRIPT_STACK_PRESENTATIONS = ['card', 'modal', 'transparentModal'] as const;\nexport type JavaScriptStackPresentation = (typeof JAVASCRIPT_STACK_PRESENTATIONS)[number];\n\nexport interface StackHeaderOptions {\n title?: string;\n headerShown?: boolean;\n headerTransparent?: boolean;\n headerBackVisible?: boolean;\n}\n\nexport type StackScreenOptions = StackHeaderOptions &\n (\n | {\n presentation?: Exclude<StackPresentation, 'formSheet'>;\n sheetAllowedDetents?: never;\n sheetGrabberVisible?: never;\n }\n | {\n presentation: 'formSheet';\n sheetAllowedDetents?: 'fitToContents' | number[];\n sheetGrabberVisible?: boolean;\n }\n );\n\nexport type JavaScriptStackScreenOptions = StackHeaderOptions & {\n presentation?: JavaScriptStackPresentation;\n};\n\nexport type StackImplementationConfig =\n | {\n /** Omission selects the stable native stack implementation. */\n implementation?: 'native';\n options?: StackScreenOptions;\n }\n | {\n implementation: 'javascript';\n options?: JavaScriptStackScreenOptions;\n }\n | {\n /** Expo Router Experimental Stack is alpha, native-only, and available from SDK 56. */\n implementation: 'experimental';\n options?: StackHeaderOptions;\n };\n\nexport const DRAWER_POSITIONS = ['left', 'right'] as const;\nexport type DrawerPosition = (typeof DRAWER_POSITIONS)[number];\n\nexport const DRAWER_TYPES = ['front', 'back', 'slide', 'permanent'] as const;\nexport type DrawerType = (typeof DRAWER_TYPES)[number];\n\nexport interface DrawerNavigatorOptions {\n drawerPosition?: DrawerPosition;\n drawerType?: DrawerType;\n swipeEnabled?: boolean;\n headerShown?: boolean;\n}\n\nexport const FIXED_HEADLESS_TABS_PRESENTATIONS = ['bottom', 'top', 'rail', 'sidebar'] as const;\nexport type FixedHeadlessTabsPresentation = (typeof FIXED_HEADLESS_TABS_PRESENTATIONS)[number];\n\nexport const HEADLESS_TABS_PRESENTATIONS = [\n ...FIXED_HEADLESS_TABS_PRESENTATIONS,\n 'responsive',\n 'custom',\n] as const;\nexport type HeadlessTabsPresentation = (typeof HEADLESS_TABS_PRESENTATIONS)[number];\n\nexport const JAVASCRIPT_TABS_PRESENTATIONS = ['bottom', 'top'] as const;\nexport type JavaScriptTabsPresentation = (typeof JAVASCRIPT_TABS_PRESENTATIONS)[number];\n\nexport const NATIVE_TABS_MINIMIZE_BEHAVIORS = [\n 'automatic',\n 'never',\n 'onScrollDown',\n 'onScrollUp',\n] as const;\nexport type NativeTabsMinimizeBehavior = (typeof NATIVE_TABS_MINIMIZE_BEHAVIORS)[number];\n\nexport interface ResponsiveTabsPresentation {\n compact: FixedHeadlessTabsPresentation;\n medium?: FixedHeadlessTabsPresentation;\n expanded: FixedHeadlessTabsPresentation;\n}\n\nexport type HeadlessTabsPresentationConfig =\n | {\n presentation: FixedHeadlessTabsPresentation;\n responsive?: never;\n customPresentationId?: never;\n }\n | {\n presentation: 'responsive';\n responsive: ResponsiveTabsPresentation;\n customPresentationId?: never;\n }\n | {\n presentation: 'custom';\n responsive?: never;\n /** Serializable registered presentation id. */\n customPresentationId: string;\n };\n\nexport type HeadlessTabsConfig = {\n implementation: 'headless';\n} & HeadlessTabsPresentationConfig;\n\nexport type HeadlessTabsWebConfig = HeadlessTabsPresentationConfig;\n\nexport interface NavigatorScreenReference {\n screenId: string;\n}\n\nexport interface NativeTabsConfig {\n implementation: 'native';\n /** Expo Router Native Tabs is alpha; minimizing is available on iOS 26+ from SDK 55. */\n minimizeBehavior?: NativeTabsMinimizeBehavior;\n /** Registered screen rendered through NativeTabs.BottomAccessory, available from SDK 55. */\n bottomAccessory?: NavigatorScreenReference;\n}\n\nexport interface JavaScriptTabsConfig {\n implementation: 'javascript';\n presentation?: JavaScriptTabsPresentation;\n}\n\nexport interface AdaptiveTabsConfig {\n /** Omission selects the canonical adaptive default. */\n implementation?: 'adaptive';\n /** Android/iOS branch. Expo Router may expose this implementation as unstable. */\n native?: NativeTabsConfig;\n /** Web branch rendered through headless tabs. */\n web?: HeadlessTabsWebConfig;\n}\n\nexport type TabsImplementationConfig =\n AdaptiveTabsConfig | HeadlessTabsConfig | JavaScriptTabsConfig | NativeTabsConfig;\n\ninterface NavigatorNodeBase {\n initialRouteName?: string;\n routes: RouteDefinition[];\n}\n\nexport interface SlotNavigatorNode extends NavigatorNodeBase {\n type: 'slot';\n}\n\nexport type StackNavigatorNode = NavigatorNodeBase & {\n type: 'stack';\n} & StackImplementationConfig;\n\nexport interface DrawerNavigatorNode extends NavigatorNodeBase {\n type: 'drawer';\n options?: DrawerNavigatorOptions;\n}\n\nexport type TabsNavigatorConfig = {\n type: 'tabs';\n} & TabsImplementationConfig;\n\nexport type TabsNavigatorNode = NavigatorNodeBase & TabsNavigatorConfig;\n\nexport interface SplitViewNavigatorNode extends NavigatorNodeBase {\n type: 'split-view';\n columns: {\n primary: NavigatorScreenReference;\n supplementary?: NavigatorScreenReference;\n };\n inspector?: NavigatorScreenReference;\n /** Split View is alpha and iOS-only; other platforms fall back to Slot. */\n topColumnForCollapsing?: 'primary' | 'supplementary' | 'secondary';\n}\n\nexport interface CustomNavigatorNode extends NavigatorNodeBase {\n type: 'custom';\n navigatorId: string;\n config?: Readonly<Record<string, ManifestValue>>;\n}\n\nexport type NavigatorNode =\n | CustomNavigatorNode\n | DrawerNavigatorNode\n | SlotNavigatorNode\n | SplitViewNavigatorNode\n | StackNavigatorNode\n | TabsNavigatorNode;\n\nexport interface RouteDefinition {\n name: string;\n path?: string;\n label?: string;\n icon?: IconSpec;\n /** Hide this route from primary Tabs/Drawer presentation without making it unnavigable. */\n showInPrimaryNavigation?: boolean;\n guards?: string[];\n screenId?: string;\n /** Presentation applied by the resolved parent stack implementation. */\n stackOptions?: StackScreenOptions;\n navigator?: NavigatorNode;\n}\n\nexport interface NavigatorDefaults {\n tabs?: TabsImplementationConfig;\n stack?: StackImplementationConfig;\n}\n\nexport interface NavigatorPlatformConfig {\n tabs?: TabsImplementationConfig;\n stack?: StackImplementationConfig;\n}\n\nexport interface NavigatorPlatforms {\n android?: NavigatorPlatformConfig;\n ios?: NavigatorPlatformConfig;\n web?: NavigatorPlatformConfig;\n}\n\n/**\n * Serializable desired state for `AppManifest.navigator`.\n *\n * The manifest slice is the root navigator tree itself; optional authoring metadata does not add\n * a redundant `root` wrapper. The standalone Navigator capability consumes this slice directly.\n */\nexport type AppNavigatorManifest = NavigatorNode & {\n preset?: NavigatorPreset;\n defaults?: NavigatorDefaults;\n platforms?: NavigatorPlatforms;\n};\n\nexport type {\n NavigatorCapabilityDescriptor,\n NavigatorCapabilityRequirement,\n NavigatorCapabilityTarget,\n NavigatorCapabilityVerification,\n NavigatorCatalog,\n NavigatorImplementation,\n NavigatorPresentation,\n NavigatorPresetDescriptor,\n NavigatorVerificationKind,\n NavigatorVerificationStatus,\n} from './navigator/catalog';\nexport type {\n CustomNavigatorConfigIssue,\n CustomNavigatorRegistration,\n CustomNavigatorRegistry,\n} from './navigator/extensions';\nexport type {\n NavigatorDependencyRequirement,\n NavigatorGeneratedFile,\n NavigatorGenerationBindings,\n NavigatorGenerationOptions,\n NavigatorGenerationResult,\n NavigatorScreenModule,\n} from './navigator/generation';\nexport type {\n CreateNavigatorPlanOptions,\n ExpoRouterNavigatorModule,\n NavigatorAdapterId,\n NavigatorAdapterPlan,\n NavigatorApiStability,\n NavigatorCapabilityId,\n NavigatorDiagnostic,\n NavigatorNodePlan,\n NavigatorPlan,\n NavigatorResponsiveSize,\n NavigatorRoutePlan,\n NavigatorRuntimePlatform,\n NavigatorSupportStatus,\n NavigatorValidationContext,\n ResolvedHeadlessTabsPresentation,\n ResolvedTabsImplementation,\n ResolvedTabsPresentation,\n TabsNavigatorPlan,\n} from './navigator/planning';\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ankhorage/contracts",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "12.0.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"ankh": {
|
|
6
6
|
"category": "contracts",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"@ankhorage/color-theory": "^0.3.0"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
|
-
"@ankhorage/devtools": "^1.
|
|
16
|
+
"@ankhorage/devtools": "^1.12.0",
|
|
17
17
|
"@ankhorage/paradox": "^0.1.24",
|
|
18
18
|
"@types/bun": "^1.4.1",
|
|
19
19
|
"@types/node": "^25.2.3",
|
|
@@ -20,7 +20,7 @@ export function isAppNavigatorManifest(value: unknown): boolean {
|
|
|
20
20
|
isNavigatorNode(value) &&
|
|
21
21
|
(value.preset === undefined ||
|
|
22
22
|
(typeof value.preset === 'string' && NAVIGATOR_PRESET_SET.has(value.preset))) &&
|
|
23
|
-
|
|
23
|
+
value.flows === undefined &&
|
|
24
24
|
(value.defaults === undefined || isNavigatorDefaults(value.defaults)) &&
|
|
25
25
|
(value.platforms === undefined || isNavigatorPlatforms(value.platforms))
|
|
26
26
|
);
|
|
@@ -134,15 +134,6 @@ function isNavigatorJsonValue(value: unknown, ancestors: Set<object>): boolean {
|
|
|
134
134
|
return isValid;
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
/*** Validate optional app-level navigator flow intent. */
|
|
138
|
-
function isNavigatorFlows(value: unknown): boolean {
|
|
139
|
-
return (
|
|
140
|
-
isRecord(value) &&
|
|
141
|
-
isOptionalBoolean(value.onboarding) &&
|
|
142
|
-
isOptionalBoolean(value.authentication)
|
|
143
|
-
);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
137
|
/*** Validate package-owned navigator defaults without requiring a navigator node type. */
|
|
147
138
|
function isNavigatorDefaults(value: unknown): boolean {
|
|
148
139
|
return (
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
-
CUSTOM_TABS_PRESENTATIONS,
|
|
3
2
|
DRAWER_POSITIONS,
|
|
4
3
|
DRAWER_TYPES,
|
|
5
|
-
|
|
4
|
+
FIXED_HEADLESS_TABS_PRESENTATIONS,
|
|
5
|
+
HEADLESS_TABS_PRESENTATIONS,
|
|
6
6
|
JAVASCRIPT_STACK_PRESENTATIONS,
|
|
7
7
|
JAVASCRIPT_TABS_PRESENTATIONS,
|
|
8
8
|
NATIVE_TABS_MINIMIZE_BEHAVIORS,
|
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
} from '../navigator';
|
|
11
11
|
import { isOptionalBoolean, isOptionalString, isRecord } from './shared';
|
|
12
12
|
|
|
13
|
-
const
|
|
13
|
+
const HEADLESS_TABS_PRESENTATION_SET = new Set<string>(HEADLESS_TABS_PRESENTATIONS);
|
|
14
14
|
const DRAWER_POSITION_SET = new Set<string>(DRAWER_POSITIONS);
|
|
15
15
|
const DRAWER_TYPE_SET = new Set<string>(DRAWER_TYPES);
|
|
16
|
-
const
|
|
16
|
+
const FIXED_HEADLESS_TABS_PRESENTATION_SET = new Set<string>(FIXED_HEADLESS_TABS_PRESENTATIONS);
|
|
17
17
|
const JAVASCRIPT_STACK_PRESENTATION_SET = new Set<string>(JAVASCRIPT_STACK_PRESENTATIONS);
|
|
18
18
|
const JAVASCRIPT_TABS_PRESENTATION_SET = new Set<string>(JAVASCRIPT_TABS_PRESENTATIONS);
|
|
19
19
|
const NATIVE_TABS_MINIMIZE_BEHAVIOR_SET = new Set<string>(NATIVE_TABS_MINIMIZE_BEHAVIORS);
|
|
@@ -98,9 +98,9 @@ export function isTabsImplementationConfig(value: Record<string, unknown>): bool
|
|
|
98
98
|
if (value.implementation === 'native') return isFullNativeTabsConfig(value);
|
|
99
99
|
if (value.implementation === 'javascript') return isJavaScriptTabsConfig(value);
|
|
100
100
|
return (
|
|
101
|
-
value.implementation === '
|
|
101
|
+
value.implementation === 'headless' &&
|
|
102
102
|
hasNoDefinedKeys(value, ['options', 'native', 'web', 'minimizeBehavior', 'bottomAccessory']) &&
|
|
103
|
-
|
|
103
|
+
isHeadlessTabsPresentationConfig(value)
|
|
104
104
|
);
|
|
105
105
|
}
|
|
106
106
|
|
|
@@ -181,7 +181,7 @@ function isAdaptiveTabsConfig(value: Record<string, unknown>): boolean {
|
|
|
181
181
|
'bottomAccessory',
|
|
182
182
|
]) &&
|
|
183
183
|
(value.native === undefined || isNativeTabsConfig(value.native)) &&
|
|
184
|
-
(value.web === undefined ||
|
|
184
|
+
(value.web === undefined || isHeadlessTabsWebConfig(value.web))
|
|
185
185
|
);
|
|
186
186
|
}
|
|
187
187
|
|
|
@@ -237,20 +237,20 @@ function isNativeTabsFields(value: Record<string, unknown>): boolean {
|
|
|
237
237
|
);
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
-
/*** Validate the implementation-free
|
|
241
|
-
function
|
|
240
|
+
/*** Validate the implementation-free headless-tabs Web branch inside adaptive tabs. */
|
|
241
|
+
function isHeadlessTabsWebConfig(value: unknown): boolean {
|
|
242
242
|
return (
|
|
243
243
|
isRecord(value) &&
|
|
244
244
|
hasOnlyKeys(value, ['presentation', 'responsive', 'customPresentationId']) &&
|
|
245
|
-
|
|
245
|
+
isHeadlessTabsPresentationConfig(value)
|
|
246
246
|
);
|
|
247
247
|
}
|
|
248
248
|
|
|
249
|
-
/*** Validate
|
|
250
|
-
function
|
|
249
|
+
/*** Validate headless-tab presentation and its conditional serializable configuration. */
|
|
250
|
+
function isHeadlessTabsPresentationConfig(value: Record<string, unknown>): boolean {
|
|
251
251
|
if (
|
|
252
252
|
typeof value.presentation !== 'string' ||
|
|
253
|
-
!
|
|
253
|
+
!HEADLESS_TABS_PRESENTATION_SET.has(value.presentation)
|
|
254
254
|
) {
|
|
255
255
|
return false;
|
|
256
256
|
}
|
|
@@ -258,7 +258,7 @@ function isCustomTabsPresentationConfig(value: Record<string, unknown>): boolean
|
|
|
258
258
|
return false;
|
|
259
259
|
}
|
|
260
260
|
if (!isOptionalString(value.customPresentationId)) return false;
|
|
261
|
-
if (
|
|
261
|
+
if (FIXED_HEADLESS_TABS_PRESENTATION_SET.has(value.presentation)) {
|
|
262
262
|
return value.responsive === undefined && value.customPresentationId === undefined;
|
|
263
263
|
}
|
|
264
264
|
if (value.presentation === 'responsive') {
|
|
@@ -271,17 +271,18 @@ function isCustomTabsPresentationConfig(value: Record<string, unknown>): boolean
|
|
|
271
271
|
);
|
|
272
272
|
}
|
|
273
273
|
|
|
274
|
-
/*** Validate semantic compact/medium/expanded
|
|
274
|
+
/*** Validate semantic compact/medium/expanded headless-tab presentation mapping. */
|
|
275
275
|
function isResponsiveTabsPresentation(value: unknown): boolean {
|
|
276
276
|
return (
|
|
277
277
|
isRecord(value) &&
|
|
278
278
|
hasOnlyKeys(value, ['compact', 'medium', 'expanded']) &&
|
|
279
279
|
typeof value.compact === 'string' &&
|
|
280
|
-
|
|
280
|
+
FIXED_HEADLESS_TABS_PRESENTATION_SET.has(value.compact) &&
|
|
281
281
|
(value.medium === undefined ||
|
|
282
|
-
(typeof value.medium === 'string' &&
|
|
282
|
+
(typeof value.medium === 'string' &&
|
|
283
|
+
FIXED_HEADLESS_TABS_PRESENTATION_SET.has(value.medium))) &&
|
|
283
284
|
typeof value.expanded === 'string' &&
|
|
284
|
-
|
|
285
|
+
FIXED_HEADLESS_TABS_PRESENTATION_SET.has(value.expanded)
|
|
285
286
|
);
|
|
286
287
|
}
|
|
287
288
|
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
HeadlessTabsPresentation,
|
|
3
|
+
JavaScriptTabsPresentation,
|
|
4
|
+
NavigatorPreset,
|
|
5
|
+
NavigatorType,
|
|
6
|
+
StackPresentation,
|
|
7
|
+
} from '../navigator';
|
|
8
|
+
import type { NavigatorDependencyRequirement } from './generation';
|
|
9
|
+
import type {
|
|
10
|
+
NavigatorApiStability,
|
|
11
|
+
NavigatorCapabilityId,
|
|
12
|
+
NavigatorRuntimePlatform,
|
|
13
|
+
NavigatorSupportStatus,
|
|
14
|
+
} from './planning';
|
|
15
|
+
|
|
16
|
+
export type NavigatorVerificationKind =
|
|
17
|
+
| 'structural'
|
|
18
|
+
| 'generation'
|
|
19
|
+
| 'format'
|
|
20
|
+
| 'lint'
|
|
21
|
+
| 'dependency'
|
|
22
|
+
| 'typescript'
|
|
23
|
+
| 'install'
|
|
24
|
+
| 'build'
|
|
25
|
+
| 'export'
|
|
26
|
+
| 'browser'
|
|
27
|
+
| 'simulator'
|
|
28
|
+
| 'device';
|
|
29
|
+
|
|
30
|
+
export type NavigatorVerificationStatus = 'verified' | 'unverified';
|
|
31
|
+
|
|
32
|
+
export type NavigatorImplementation = 'native' | 'javascript' | 'headless' | 'experimental';
|
|
33
|
+
|
|
34
|
+
export type NavigatorPresentation =
|
|
35
|
+
| StackPresentation
|
|
36
|
+
| HeadlessTabsPresentation
|
|
37
|
+
| JavaScriptTabsPresentation
|
|
38
|
+
| 'two-column'
|
|
39
|
+
| 'three-column';
|
|
40
|
+
|
|
41
|
+
export interface NavigatorCapabilityVerification {
|
|
42
|
+
kind: NavigatorVerificationKind;
|
|
43
|
+
status: NavigatorVerificationStatus;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface NavigatorCapabilityTarget {
|
|
47
|
+
platform: NavigatorRuntimePlatform;
|
|
48
|
+
support: NavigatorSupportStatus;
|
|
49
|
+
verification: readonly NavigatorCapabilityVerification[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface NavigatorCapabilityRequirement {
|
|
53
|
+
id: string;
|
|
54
|
+
description: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface NavigatorCapabilityDescriptor {
|
|
58
|
+
id: NavigatorCapabilityId;
|
|
59
|
+
topology: NavigatorType;
|
|
60
|
+
implementation?: NavigatorImplementation;
|
|
61
|
+
presentation?: NavigatorPresentation;
|
|
62
|
+
stability: NavigatorApiStability;
|
|
63
|
+
targets: readonly NavigatorCapabilityTarget[];
|
|
64
|
+
dependencies: readonly NavigatorDependencyRequirement[];
|
|
65
|
+
requirements: readonly NavigatorCapabilityRequirement[];
|
|
66
|
+
incompatibilities: readonly NavigatorCapabilityId[];
|
|
67
|
+
limitations: readonly string[];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface NavigatorPresetDescriptor {
|
|
71
|
+
id: NavigatorPreset;
|
|
72
|
+
description: string;
|
|
73
|
+
topology: readonly NavigatorType[];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface NavigatorCatalog {
|
|
77
|
+
capabilities: readonly NavigatorCapabilityDescriptor[];
|
|
78
|
+
presets: readonly NavigatorPresetDescriptor[];
|
|
79
|
+
}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
NavigatorCapabilityId,
|
|
3
|
+
NavigatorDiagnostic,
|
|
4
|
+
NavigatorPlan,
|
|
5
|
+
NavigatorSupportStatus,
|
|
6
|
+
} from './planning';
|
|
7
|
+
|
|
1
8
|
export interface NavigatorGeneratedFile {
|
|
2
9
|
path: string;
|
|
3
10
|
contents: string;
|
|
@@ -7,13 +14,24 @@ export interface NavigatorGenerationBindings {
|
|
|
7
14
|
screens: Readonly<Record<string, NavigatorScreenModule>>;
|
|
8
15
|
guards: Readonly<Record<string, NavigatorScreenModule>>;
|
|
9
16
|
iconSourceResolver?: NavigatorScreenModule;
|
|
10
|
-
flows?: {
|
|
11
|
-
onboardingRoute?: string;
|
|
12
|
-
authenticationRoute?: string;
|
|
13
|
-
};
|
|
14
17
|
tabPresentations?: Readonly<Record<string, NavigatorScreenModule>>;
|
|
15
18
|
}
|
|
16
19
|
|
|
20
|
+
export interface NavigatorDependencyRequirement {
|
|
21
|
+
packageName: string;
|
|
22
|
+
versionRange: string;
|
|
23
|
+
kind: 'dependency' | 'peerDependency';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface NavigatorGenerationResult {
|
|
27
|
+
support: NavigatorSupportStatus;
|
|
28
|
+
capabilityIds: readonly NavigatorCapabilityId[];
|
|
29
|
+
dependencies: readonly NavigatorDependencyRequirement[];
|
|
30
|
+
diagnostics: readonly NavigatorDiagnostic[];
|
|
31
|
+
plan: NavigatorPlan;
|
|
32
|
+
files: readonly NavigatorGeneratedFile[];
|
|
33
|
+
}
|
|
34
|
+
|
|
17
35
|
/** Options for placing Navigator-owned files inside a consumer-owned Expo Router app shell. */
|
|
18
36
|
export interface NavigatorGenerationOptions {
|
|
19
37
|
/** Directory that receives the root navigator layout. Must be `src/app` or one of its safe descendants. */
|
|
@@ -7,13 +7,14 @@ import type {
|
|
|
7
7
|
StackScreenOptions,
|
|
8
8
|
} from '../navigator';
|
|
9
9
|
import type { CustomNavigatorRegistry } from './extensions';
|
|
10
|
+
import type { NavigatorDependencyRequirement } from './generation';
|
|
10
11
|
|
|
11
|
-
export interface
|
|
12
|
+
export interface ResolvedHeadlessTabsPresentation {
|
|
12
13
|
presentation: ResolvedTabsPresentation;
|
|
13
14
|
customPresentationId?: string;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
export type ResolvedTabsImplementation = '
|
|
17
|
+
export type ResolvedTabsImplementation = 'headless' | 'javascript' | 'native';
|
|
17
18
|
|
|
18
19
|
export type ResolvedTabsPresentation = 'bottom' | 'top' | 'rail' | 'sidebar' | 'custom';
|
|
19
20
|
|
|
@@ -60,7 +61,7 @@ export type NavigatorAdapterId =
|
|
|
60
61
|
| 'drawer'
|
|
61
62
|
| 'tabs.native'
|
|
62
63
|
| 'tabs.javascript'
|
|
63
|
-
| 'tabs.
|
|
64
|
+
| 'tabs.headless'
|
|
64
65
|
| 'split-view'
|
|
65
66
|
| 'custom';
|
|
66
67
|
|
|
@@ -76,6 +77,8 @@ export interface NavigatorAdapterPlan {
|
|
|
76
77
|
|
|
77
78
|
export type NavigatorApiStability = 'stable' | 'alpha';
|
|
78
79
|
|
|
80
|
+
export type NavigatorCapabilityId = string;
|
|
81
|
+
|
|
79
82
|
export interface NavigatorDiagnostic {
|
|
80
83
|
code: string;
|
|
81
84
|
severity: 'error' | 'warning';
|
|
@@ -115,11 +118,9 @@ export interface NavigatorPlan {
|
|
|
115
118
|
context: NavigatorValidationContext;
|
|
116
119
|
root: NavigatorNodePlan;
|
|
117
120
|
diagnostics: readonly NavigatorDiagnostic[];
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
authentication: boolean;
|
|
122
|
-
};
|
|
121
|
+
support: NavigatorSupportStatus;
|
|
122
|
+
capabilityIds: readonly NavigatorCapabilityId[];
|
|
123
|
+
dependencies: readonly NavigatorDependencyRequirement[];
|
|
123
124
|
}
|
|
124
125
|
|
|
125
126
|
export type NavigatorResponsiveSize = 'compact' | 'medium' | 'expanded';
|
|
@@ -138,7 +139,7 @@ export interface NavigatorRoutePlan {
|
|
|
138
139
|
|
|
139
140
|
export type NavigatorRuntimePlatform = 'android' | 'ios' | 'web';
|
|
140
141
|
|
|
141
|
-
export type NavigatorSupportStatus = 'supported' | '
|
|
142
|
+
export type NavigatorSupportStatus = 'supported' | 'testing-only' | 'unsupported';
|
|
142
143
|
|
|
143
144
|
export interface NavigatorValidationContext {
|
|
144
145
|
platform: NavigatorRuntimePlatform;
|
|
@@ -2,8 +2,10 @@ import { expect, test } from 'bun:test';
|
|
|
2
2
|
|
|
3
3
|
import type {
|
|
4
4
|
CustomNavigatorRegistration,
|
|
5
|
+
NavigatorCatalog,
|
|
5
6
|
NavigatorGeneratedFile,
|
|
6
7
|
NavigatorGenerationBindings,
|
|
8
|
+
NavigatorGenerationResult,
|
|
7
9
|
NavigatorPlan,
|
|
8
10
|
} from './navigator';
|
|
9
11
|
|
|
@@ -32,10 +34,59 @@ test('keeps generation bindings and plan output portable across package boundari
|
|
|
32
34
|
routes: [],
|
|
33
35
|
},
|
|
34
36
|
diagnostics: [],
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
support: 'supported',
|
|
38
|
+
capabilityIds: ['slot'],
|
|
39
|
+
dependencies: [],
|
|
37
40
|
};
|
|
38
|
-
|
|
41
|
+
const result: NavigatorGenerationResult = {
|
|
42
|
+
support: plan.support,
|
|
43
|
+
capabilityIds: plan.capabilityIds,
|
|
44
|
+
dependencies: plan.dependencies,
|
|
45
|
+
diagnostics: plan.diagnostics,
|
|
46
|
+
plan,
|
|
47
|
+
files: [file],
|
|
48
|
+
};
|
|
49
|
+
expect(JSON.parse(JSON.stringify({ bindings, result }))).toEqual({ bindings, result });
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('separates capability taxonomy, target support, stability, and verification', () => {
|
|
53
|
+
const catalog: NavigatorCatalog = {
|
|
54
|
+
capabilities: [
|
|
55
|
+
{
|
|
56
|
+
id: 'tabs.headless.sidebar',
|
|
57
|
+
topology: 'tabs',
|
|
58
|
+
implementation: 'headless',
|
|
59
|
+
presentation: 'sidebar',
|
|
60
|
+
stability: 'stable',
|
|
61
|
+
targets: [
|
|
62
|
+
{
|
|
63
|
+
platform: 'web',
|
|
64
|
+
support: 'supported',
|
|
65
|
+
verification: [{ kind: 'browser', status: 'verified' }],
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
platform: 'ios',
|
|
69
|
+
support: 'testing-only',
|
|
70
|
+
verification: [{ kind: 'device', status: 'unverified' }],
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
dependencies: [],
|
|
74
|
+
requirements: [],
|
|
75
|
+
incompatibilities: [],
|
|
76
|
+
limitations: [],
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
presets: [
|
|
80
|
+
{
|
|
81
|
+
id: 'drawer',
|
|
82
|
+
description: 'Drawer as the root navigator with direct routes.',
|
|
83
|
+
topology: ['drawer'],
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
expect(catalog.capabilities[0]?.targets[1]?.support).toBe('testing-only');
|
|
89
|
+
expect(catalog.presets[0]?.topology).toEqual(['drawer']);
|
|
39
90
|
});
|
|
40
91
|
|
|
41
92
|
test('describes a custom extension without importing Navigator or a UI runtime', () => {
|
|
@@ -6,7 +6,7 @@ import { describe, expect, it } from 'bun:test';
|
|
|
6
6
|
import { isAppNavigatorManifest } from './appManifest/screens';
|
|
7
7
|
import type {
|
|
8
8
|
CustomNavigatorNode,
|
|
9
|
-
|
|
9
|
+
HeadlessTabsConfig,
|
|
10
10
|
NavigatorNode,
|
|
11
11
|
StackImplementationConfig,
|
|
12
12
|
} from './navigator';
|
|
@@ -20,9 +20,9 @@ describe('app navigator manifest type discrimination', () => {
|
|
|
20
20
|
implementation: 'experimental',
|
|
21
21
|
options: { presentation: 'modal' },
|
|
22
22
|
};
|
|
23
|
-
// @ts-expect-error Fixed
|
|
24
|
-
const tabs:
|
|
25
|
-
implementation: '
|
|
23
|
+
// @ts-expect-error Fixed headless tabs do not accept a registered custom presentation id.
|
|
24
|
+
const tabs: HeadlessTabsConfig = {
|
|
25
|
+
implementation: 'headless',
|
|
26
26
|
presentation: 'sidebar',
|
|
27
27
|
customPresentationId: 'workspace-tabs',
|
|
28
28
|
};
|
|
@@ -70,6 +70,33 @@ describe('app navigator manifest stack validation', () => {
|
|
|
70
70
|
});
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
+
describe('app navigator manifest removed fields', () => {
|
|
74
|
+
it('rejects flow metadata and the superseded custom Tabs implementation', () => {
|
|
75
|
+
expect(
|
|
76
|
+
isAppNavigatorManifest({
|
|
77
|
+
type: 'stack',
|
|
78
|
+
flows: { onboarding: true },
|
|
79
|
+
routes: [],
|
|
80
|
+
}),
|
|
81
|
+
).toBe(false);
|
|
82
|
+
expect(
|
|
83
|
+
isAppNavigatorManifest({
|
|
84
|
+
type: 'tabs',
|
|
85
|
+
implementation: 'custom',
|
|
86
|
+
presentation: 'bottom',
|
|
87
|
+
routes: [],
|
|
88
|
+
}),
|
|
89
|
+
).toBe(false);
|
|
90
|
+
expect(
|
|
91
|
+
isAppNavigatorManifest({
|
|
92
|
+
type: 'stack',
|
|
93
|
+
preset: 'root-stack-tabs',
|
|
94
|
+
routes: [],
|
|
95
|
+
}),
|
|
96
|
+
).toBe(false);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
73
100
|
describe('app navigator manifest sheet validation', () => {
|
|
74
101
|
it('validates native form-sheet detents and their presentation discriminant', () => {
|
|
75
102
|
for (const sheetAllowedDetents of [[], [0.8, 0.4], [0.4, 0.4], [0], [1.1], [Number.NaN]]) {
|