@apexnative/navigation 1.0.0-alpha.2 → 1.0.0-alpha.4
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 +31 -0
- package/android/CLAUDE.md +38 -9
- package/android/CORE.md +11 -4
- package/android/RECIPES.md +9 -3
- package/android/src/main/java/dev/apexnative/navigation/NavigationActivity.kt +29 -1
- package/android/src/main/java/dev/apexnative/navigation/NavigationApplication.kt +34 -13
- package/android/src/main/java/dev/apexnative/navigation/layout/LayoutChecks.kt +5 -1
- package/android/src/main/java/dev/apexnative/navigation/layout/LayoutNode.kt +6 -2
- package/android/src/main/java/dev/apexnative/navigation/nativescreen/NativeScreenContext.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/ButtonMenuOptions.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/ButtonOptions.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/OptionsCache.kt +8 -4
- package/android/src/main/java/dev/apexnative/navigation/options/StatusBarOptions.kt +7 -3
- package/android/src/main/java/dev/apexnative/navigation/options/UserChoices.kt +159 -0
- package/android/src/main/java/dev/apexnative/navigation/react/CommandAnswer.kt +2 -24
- package/android/src/main/java/dev/apexnative/navigation/react/CommandContract.kt +59 -0
- package/android/src/main/java/dev/apexnative/navigation/react/Hinge.kt +27 -19
- package/android/src/main/java/dev/apexnative/navigation/react/NavigationTurboModule.kt +5 -4
- package/android/src/main/java/dev/apexnative/navigation/react/PendingCalls.kt +48 -0
- package/android/src/main/java/dev/apexnative/navigation/react/events/AppearanceDispatcher.kt +17 -7
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotContainers.kt +10 -7
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotView.kt +4 -3
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotViews.kt +40 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/ImageKey.kt +66 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/ImageLoader.kt +7 -89
- package/android/src/main/java/dev/apexnative/navigation/utils/ImageRequests.kt +76 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/OptionImages.kt +262 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/ViewController.kt +3 -1
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/SecondaryScreenPresenter.kt +13 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/AppliedTabCalls.kt +49 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +92 -19
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsPresenter.kt +25 -24
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentPresenter.kt +28 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ContentReadiness.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/RenderWait.kt +27 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenFrame.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalAnimations.kt +22 -24
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +79 -13
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalRecord.kt +21 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +29 -12
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +22 -18
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackState.kt +4 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +45 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/RootCoordinator.kt +35 -9
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/overlay/OverlayCoordinator.kt +10 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/Capabilities.kt +11 -4
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ContainerBackground.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt +3 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuController.kt +5 -1
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitPanes.kt +23 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitViewController.kt +72 -16
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt +287 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackCommands.kt +28 -18
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +164 -13
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackDisplay.kt +26 -1
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +136 -40
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackTransitions.kt +26 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +107 -4
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabPresenter.kt +7 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/StackSearchPresenter.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/MenuChecks.kt +13 -56
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +131 -9
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ViewController.kt +75 -21
- package/android/src/main/java/dev/apexnative/navigation/views/animations/Curves.kt +29 -11
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabs.kt +4 -2
- package/android/src/main/java/dev/apexnative/navigation/views/stack/ScreenEdge.kt +15 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/StackLayout.kt +137 -1
- package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/Fab.kt +14 -10
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TitleBar.kt +8 -1
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TopBar.kt +26 -4
- package/cli/doctor/checks/app.js +61 -13
- package/cli/migrate/native.js +18 -0
- package/cli/setup/source.js +2 -1
- package/cli/setup/steps/mainApplication.js +134 -19
- package/docs-md/architecture/transitions.md +12 -7
- package/docs-md/containers/modals.md +4 -2
- package/docs-md/containers/overlays.md +3 -1
- package/docs-md/containers/side-menu.md +4 -2
- package/docs-md/containers/tabs.md +2 -0
- package/docs-md/flows/forms-in-a-modal.md +1 -1
- package/docs-md/help/glossary.md +2 -2
- package/docs-md/help/troubleshooting.md +20 -3
- package/docs-md/index.json +12 -0
- package/docs-md/migration/from-react-native-navigation.md +8 -2
- package/docs-md/screen-ui/back-and-gestures.md +8 -2
- package/docs-md/screen-ui/system-ui.md +1 -1
- package/docs-md/start/installation.md +3 -1
- package/ios/CLAUDE.md +17 -5
- package/ios/CORE.md +13 -8
- package/ios/Contract/ANNCommandAnswer.mm +5 -20
- package/ios/Contract/ANNCommandContract.h +15 -0
- package/ios/Contract/ANNCommandContract.mm +78 -0
- package/ios/Core/ANNAppearanceDispatcher.mm +1 -1
- package/ios/Core/ANNErrorHandler.h +1 -1
- package/ios/Core/ANNErrorHandler.mm +3 -1
- package/ios/Core/ANNEventEmitter.h +1 -1
- package/ios/Core/ANNEventEmitter.mm +2 -2
- package/ios/Core/ANNJavaScriptCalls.h +34 -0
- package/ios/Core/ANNJavaScriptCalls.mm +61 -0
- package/ios/Core/ANNNavigationState.h +7 -3
- package/ios/Core/ANNNavigationState.mm +10 -5
- package/ios/Core/ANNNodeHelper.h +32 -12
- package/ios/Core/ANNNodeHelper.mm +100 -3
- package/ios/Core/ANNRenderWait.h +15 -1
- package/ios/Core/ANNRenderWait.mm +119 -17
- package/ios/Core/UIViewController+LayoutProtocol.h +9 -2
- package/ios/Core/UIViewController+LayoutProtocol.mm +8 -0
- package/ios/Layouts/Modal/ANNModalCoordinator.h +1 -1
- package/ios/Layouts/Modal/ANNModalCoordinator.mm +55 -14
- package/ios/Layouts/Screen/ANNComponentViewController.h +8 -0
- package/ios/Layouts/Screen/ANNComponentViewController.mm +32 -5
- package/ios/Layouts/Screen/ANNScreenPlace.h +41 -0
- package/ios/Layouts/Screen/ANNScreenPlace.mm +175 -0
- package/ios/Layouts/SplitView/ANNSplitViewCommands.h +3 -2
- package/ios/Layouts/SplitView/ANNSplitViewCommands.mm +105 -39
- package/ios/Layouts/SplitView/ANNSplitViewController.mm +4 -2
- package/ios/Layouts/Stack/ANNStackCommands.mm +1 -0
- package/ios/Layouts/Stack/ANNStackController.mm +26 -3
- package/ios/Layouts/Stack/ANNStackQueue.h +3 -1
- package/ios/Layouts/Stack/ANNStackQueue.mm +56 -43
- package/ios/Layouts/Stack/UINavigationController+ANNCommands.h +4 -2
- package/ios/Layouts/Stack/UINavigationController+ANNCommands.mm +2 -3
- package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.h +4 -0
- package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.mm +11 -0
- package/ios/Layouts/Tabs/ANNBottomTabsController.mm +13 -5
- package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +2 -2
- package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +109 -7
- package/ios/Options/ANNOptionsCache.h +7 -6
- package/ios/Options/ANNSearchBarOptions.h +4 -3
- package/ios/Options/ANNUserChoice.h +57 -0
- package/ios/Options/ANNUserChoice.mm +44 -0
- package/ios/Options/Params/ANNImageSource.h +61 -0
- package/ios/Options/Params/ANNImageSource.mm +101 -0
- package/ios/Options/Params/ANNOptionImages.h +37 -0
- package/ios/Options/Params/ANNOptionImages.mm +284 -0
- package/ios/Options/Params/Image.h +11 -2
- package/ios/Options/Params/Image.mm +15 -2
- package/ios/Options/Params/ImageParser.h +5 -5
- package/ios/Options/Params/ImageParser.mm +28 -46
- package/ios/Public/ApexNavigation/ApexNavigation.h +1 -1
- package/ios/RECIPES.md +11 -5
- package/ios/React/Slots/ANNSlotComponentView.mm +24 -17
- package/ios/React/Slots/ANNSlotContainers.h +14 -6
- package/ios/React/Slots/ANNSlotContainers.mm +75 -2
- package/ios/TopBar/ANNBarButtons.h +9 -5
- package/ios/TopBar/ANNBarButtons.mm +211 -63
- package/ios/TopBar/ANNIconButtonImage.h +1 -0
- package/ios/TopBar/ANNIconButtonImage.mm +34 -1
- package/ios/TopBar/ANNLargeTitlePresenter.h +13 -0
- package/ios/TopBar/ANNLargeTitlePresenter.mm +26 -3
- package/ios/TopBar/ANNSearchPresenter.mm +170 -19
- package/ios/TopBar/ANNTopBarPresenter.h +5 -0
- package/ios/TopBar/ANNTopBarPresenter.mm +60 -11
- package/ios/TurboModules/ANNTurboModule.mm +39 -21
- package/lib/module/ARCHITECTURE.md +18 -18
- package/lib/module/adapters/NativeANNTurboModule.js.map +1 -1
- package/lib/module/api/hooks/useNavigation.js +8 -3
- package/lib/module/api/hooks/useNavigation.js.map +1 -1
- package/lib/module/api/navigation.js.map +1 -1
- package/lib/module/engine/commands.js +9 -7
- package/lib/module/engine/commands.js.map +1 -1
- package/lib/module/engine/layout.js +13 -9
- package/lib/module/engine/layout.js.map +1 -1
- package/lib/module/engine/options.js +44 -11
- package/lib/module/engine/options.js.map +1 -1
- package/lib/module/engine/places.js +44 -7
- package/lib/module/engine/places.js.map +1 -1
- package/lib/module/engine/props.js +30 -1
- package/lib/module/engine/props.js.map +1 -1
- package/lib/module/engine/rememberedOptions.js +1 -1
- package/lib/module/engine/rememberedOptions.js.map +1 -1
- package/lib/module/engine/screens.js +22 -12
- package/lib/module/engine/screens.js.map +1 -1
- package/lib/module/interfaces/contract/commands.json +101 -0
- package/lib/typescript/adapters/NativeANNTurboModule.d.ts +5 -2
- package/lib/typescript/adapters/NativeANNTurboModule.d.ts.map +1 -1
- package/lib/typescript/api/events/navigationEvents.d.ts +1 -1
- package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
- package/lib/typescript/api/hooks/useNavigation.d.ts +1 -1
- package/lib/typescript/api/hooks/useNavigation.d.ts.map +1 -1
- package/lib/typescript/api/navigation.d.ts +4 -1
- package/lib/typescript/api/navigation.d.ts.map +1 -1
- package/lib/typescript/engine/commands.d.ts.map +1 -1
- package/lib/typescript/engine/options.d.ts +5 -2
- package/lib/typescript/engine/options.d.ts.map +1 -1
- package/lib/typescript/engine/places.d.ts +5 -2
- package/lib/typescript/engine/places.d.ts.map +1 -1
- package/lib/typescript/engine/props.d.ts +8 -1
- package/lib/typescript/engine/props.d.ts.map +1 -1
- package/lib/typescript/engine/rememberedOptions.d.ts.map +1 -1
- package/lib/typescript/engine/screens.d.ts.map +1 -1
- package/lib/typescript/interfaces/ComponentEvents.d.ts +2 -2
- package/lib/typescript/interfaces/ComponentEvents.d.ts.map +1 -1
- package/lib/typescript/interfaces/Events.d.ts +19 -10
- package/lib/typescript/interfaces/Events.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/animations.d.ts +15 -7
- package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/buttons.d.ts +13 -5
- package/lib/typescript/interfaces/options/buttons.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/modals.d.ts +18 -13
- package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/system.d.ts +6 -3
- package/lib/typescript/interfaces/options/system.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/topBar.d.ts +22 -9
- package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/ARCHITECTURE.md +18 -18
- package/src/adapters/NativeANNTurboModule.ts +5 -2
- package/src/api/events/navigationEvents.ts +1 -1
- package/src/api/hooks/useNavigation.ts +9 -4
- package/src/api/navigation.ts +4 -1
- package/src/engine/commands.ts +19 -7
- package/src/engine/layout.ts +16 -9
- package/src/engine/options.ts +39 -11
- package/src/engine/places.ts +56 -7
- package/src/engine/props.ts +30 -1
- package/src/engine/rememberedOptions.ts +4 -1
- package/src/engine/screens.tsx +23 -13
- package/src/interfaces/ComponentEvents.ts +2 -2
- package/src/interfaces/Events.ts +19 -10
- package/src/interfaces/contract/commands.json +101 -0
- package/src/interfaces/options/animations.ts +15 -7
- package/src/interfaces/options/buttons.ts +13 -5
- package/src/interfaces/options/modals.ts +18 -13
- package/src/interfaces/options/system.ts +6 -3
- package/src/interfaces/options/topBar.ts +22 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"topBar.d.ts","sourceRoot":"","sources":["../../../../src/interfaces/options/topBar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,cAAW,CAAC;AACnB,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAU,CAAC;AAExF;;;;GAIG;AACH,MAAM,WAAW,2BAA2B;IAC1C
|
|
1
|
+
{"version":3,"file":"topBar.d.ts","sourceRoot":"","sources":["../../../../src/interfaces/options/topBar.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/ARCHITECTURE.md
CHANGED
|
@@ -85,24 +85,24 @@ form of `src/api/events/navigationEvents.ts`. Everything in `src/engine` is inte
|
|
|
85
85
|
|
|
86
86
|
## `src/engine` — the engine
|
|
87
87
|
|
|
88
|
-
| Module | What it does
|
|
89
|
-
| --------------------------- |
|
|
90
|
-
| `native.ts` | `commands`: the TurboModule (`src/adapters/NativeANNTurboModule.ts`). `onNativeEvent(name, listener)`: one native event, `ANN.<name>`. iOS sends events through `ANNTurboEventEmitter`; Android without a module. `getLaunchLink()`: the URL that launched the native side, null without the native side (Jest). `getStartInfo()`: `{ coldStart, splashLogo, arrangements }`, asked once; without the native side a cold start without a logo and without arrangements.
|
|
91
|
-
| `layout.ts` | `toNativeLayout(layout)`: a `LayoutNode`, `{ id, type, data: { name, options, passProps?, functions?, key?, columns? }, children }`. For a screen, in this order: a name that shows a pair becomes an `Arrangement` node (see Pairs, regions and the hinge), an unknown name fails, its id, its own options under those of the show, the press handlers of its buttons taken out; then a native screen goes as an external component (`showNativeScreen`), a React screen with its `key`, its props kept here, as a slot in one tree.
|
|
92
|
-
| `options.ts` | `toNativeOptions(options)`: colors (iOS: a number, `DynamicColorIOS` or `'NoColor'`; Android: `{ light, dark }`), images (`require` resolved), components in options (`componentId`, their props kept here), the props of buttons with a component, the roots of the bar buttons' components (`*Buttons`, the toolbar's `buttons`) remembered. Options come in their own form only.
|
|
93
|
-
| `commands.ts` | `setRoot`, `push`, `pop`, `popTo`, `popToRoot`, `setStackRoot`, `showInColumn`, `setColumnShown`, `showModal`, `dismissModal`, `dismissAllModals`, `showOverlay`, `dismissOverlay`, `dismissAllOverlays`, `mergeOptions`, `setDefaultOptions`. One that shows screens waits for lazy ones (`afterLoading`), checks the ids (`checkIds`), notes the places and waits for the hooks of native screens (`whenNativeScreensReady`). On Android, in one tree, a push goes through `preparePush` first (see One command).
|
|
94
|
-
| `screens.tsx` | The screens by name: a React component with its options, `key`, `load` (a lazy screen) and `arrangement` (its pair, if it has a secondary), a native screen (`nativeName`, the controller of its `useProps`, `arrangement`), or a pair entry of `defineArrangement` (`pair`). `arrangementOf(name)`: the pair a name shows; `checkArrangements` at registration, `checkArrangement` when a lazy screen's pair shows. `loadScreens`/`afterLoading`: a command goes once its lazy screens loaded, at once when none waits. A React screen is registered with `AppRegistry` as a root (`screenRoot`) that renders it with the props left for its id. After a JavaScript reload React Native starts the old roots again under the new screens' ids:
|
|
95
|
-
| `nativeScreens.ts` | The native screens shown, by id. Data props go as JSON (`passProps`); functions stay here, their names in `data.functions`, and the native side calls them (`ANN.NativeScreenCall`, answered with `resolveNativeScreenCall`). With `useProps`: the hidden host runs the hook (`startHost`, 5 s to start), the command waits for its first result, later changes go with `updateNativeScreenProps`. `ANN.NativeScreenReleased` forgets one.
|
|
96
|
-
| `props.ts` | The props of screens and of components in options, by id: a command puts them here before the native side creates the view; React Native passes a root only its id. Also which roots are the components of bar buttons (`isButtonRoot`): on iOS their wrapper centers the content in the slot.
|
|
97
|
-
| `events.ts` | `toScreenEvent(event)`: an event of a screen as `listeners`, `navigation.on`, the screen hooks and `onPress` get it: the screen as `screen: { id, name }`, without the fields of the native side.
|
|
98
|
-
| `places.ts` | Where each screen is, noted as the commands build their layouts: the root, a modal or an overlay, its stack and its index there, its side menu, its pair (`arrangement`: the pair's id and its placement; `alone` for a primary shown without one, `noteAlone`). The column of a split view each stack shows (`columnOf`, `stackOfColumn`), and whether a split view's columns show as one stack (`ANN.SplitViewColumnsStacked`, `listenToSplitViews`): `showInColumn` notes its screen first in the column's stack, or over the screen that asks in the compact column, and the first screen of a column over the one before it can pop (`coversColumn`). `canPop`, `canDismiss`, `dismiss` and `placeFor` read it at once; `isGone` knows the last screens that went.
|
|
99
|
-
| `buttons.ts` | The `onPress` handlers of the buttons of each screen and of their menu items, called on `NavigationButtonPressed`; the API gives the event its form (`setPressEvent`).
|
|
100
|
-
| `tabs.ts` | The press handlers of `Tab().onPress()`: they come with the tabs' layout, stay under the id the tabs are shown with, and go once every React screen shown in the tabs (pushed ones too) unmounted.
|
|
101
|
-
| `slots.ts` | One tree (`appProvider`): `slotName` sends a React screen as `slot:<name>`, the native side gives it an empty container, and the slot with its id in `SlotHost` renders it. `withSlots` takes back the slots of a failed command; `ANN.SlotDestroyed` removes one. For a push on Android: `holdSlot` (nothing renders until the native side laid the screen out), `showSlot` (at its `SlotFrame`; resolves once React committed it, `slotCommitted`), `preparedPadding` (the first padding of its safe area view).
|
|
102
|
-
| `launchState.ts` | The last root and default options: Android destroys the activity while JavaScript lives on and sends `AppLaunched` again; the app sets them again.
|
|
103
|
-
| `backListeners.ts` | Android: wraps `BackHandler.addEventListener` at the launch to count the listeners, and tells the native side whether there is one (`setBackListeners`): the navigation takes the back button only while it can go back or JavaScript listens. A listener added before the launch isn't counted.
|
|
104
|
-
| `reactMeasures.ts` | Development only: every command that shows or closes screens drops React's `performance.measure` entries of component renders (named after the component with U+200B in front). React Native keeps them without a limit, and a long session ran out of memory; the app's own measures stay.
|
|
105
|
-
| `ids.ts`, `mergeOptions.ts` | `nextId` and the merge of options; see Ids and Options in layers.
|
|
88
|
+
| Module | What it does |
|
|
89
|
+
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
90
|
+
| `native.ts` | `commands`: the TurboModule (`src/adapters/NativeANNTurboModule.ts`). `onNativeEvent(name, listener)`: one native event, `ANN.<name>`. iOS sends events through `ANNTurboEventEmitter`; Android without a module. `getLaunchLink()`: the URL that launched the native side, null without the native side (Jest). `getStartInfo()`: `{ coldStart, splashLogo, arrangements }`, asked once; without the native side a cold start without a logo and without arrangements. |
|
|
91
|
+
| `layout.ts` | `toNativeLayout(layout)`: a `LayoutNode`, `{ id, type, data: { name, options, passProps?, functions?, key?, columns? }, children }`. For a screen, in this order: a name that shows a pair becomes an `Arrangement` node (see Pairs, regions and the hinge), an unknown name fails, its id, its own options under those of the show, the press handlers of its buttons taken out; then a native screen goes as an external component (`showNativeScreen`), a React screen with its `key`, its props kept here, as a slot in one tree. |
|
|
92
|
+
| `options.ts` | `toNativeOptions(options, owner)`: colors (iOS: a number, `DynamicColorIOS` or `'NoColor'`; Android: `{ light, dark }`), images (`require` resolved), components in options (`componentId`, their props kept here; without an `id` of their own, `<owner>/<place>/<name>`, e.g. `Component12/topBar.title/Clock`, a list item by its id where it has one (`topBar.rightButtons[Save]`), the same on every `mergeOptions` of the node, so the native side keeps the mounted root), the props of buttons with a component, the roots of the bar buttons' components (`*Buttons`, the toolbar's `buttons`) remembered. Options come in their own form only. |
|
|
93
|
+
| `commands.ts` | `setRoot`, `push`, `pop`, `popTo`, `popToRoot`, `setStackRoot`, `showInColumn`, `setColumnShown`, `showModal`, `dismissModal`, `dismissAllModals`, `showOverlay`, `dismissOverlay`, `dismissAllOverlays`, `mergeOptions`, `setDefaultOptions`. One that shows screens waits for lazy ones (`afterLoading`), checks the ids (`checkIds`), notes the places and waits for the hooks of native screens (`whenNativeScreensReady`). On Android, in one tree, a push goes through `preparePush` first (see One command). |
|
|
94
|
+
| `screens.tsx` | The screens by name: a React component with its options, `key`, `load` (a lazy screen) and `arrangement` (its pair, if it has a secondary), a native screen (`nativeName`, the controller of its `useProps`, `arrangement`), or a pair entry of `defineArrangement` (`pair`). `arrangementOf(name)`: the pair a name shows; `checkArrangements` at registration, `checkArrangement` when a lazy screen's pair shows. `loadScreens`/`afterLoading`: a command goes once its lazy screens loaded, at once when none waits. A React screen is registered with `AppRegistry` as a root (`screenRoot`) that renders it with the props left for its id. After a JavaScript reload React Native starts the old roots again under the new screens' ids: a root that unmounts while another root of the id is mounted leaves the screen alone. The props of a component the library named in options go with its node, not with a root (several roots may show one default). |
|
|
95
|
+
| `nativeScreens.ts` | The native screens shown, by id. Data props go as JSON (`passProps`); functions stay here, their names in `data.functions`, and the native side calls them (`ANN.NativeScreenCall`, answered with `resolveNativeScreenCall`). With `useProps`: the hidden host runs the hook (`startHost`, 5 s to start), the command waits for its first result, later changes go with `updateNativeScreenProps`. `ANN.NativeScreenReleased` forgets one. |
|
|
96
|
+
| `props.ts` | The props of screens and of components in options, by id: a command puts them here before the native side creates the view; React Native passes a root only its id. Also which roots are the components of bar buttons (`isButtonRoot`): on iOS their wrapper centers the content in the slot. |
|
|
97
|
+
| `events.ts` | `toScreenEvent(event)`: an event of a screen as `listeners`, `navigation.on`, the screen hooks and `onPress` get it: the screen as `screen: { id, name }`, without the fields of the native side. |
|
|
98
|
+
| `places.ts` | Where each screen is, noted as the commands build their layouts: the root, a modal or an overlay, its stack and its index there, its side menu, its pair (`arrangement`: the pair's id and its placement; `alone` for a primary shown without one, `noteAlone`). The column of a split view each stack shows (`columnOf`, `stackOfColumn`), and whether a split view's columns show as one stack (`ANN.SplitViewColumnsStacked`, `listenToSplitViews`): `showInColumn` notes its screen first in the column's stack, or over the screen that asks in the compact column, and the first screen of a column over the one before it can pop (`coversColumn`). `canPop`, `canDismiss`, `dismiss` and `placeFor` read it at once; `isGone` knows the last screens that went. It also notes the layouts each screen shows in (`layoutsOf`): a layout whose last screen went is gone, and so are the props of the components named in its options. |
|
|
99
|
+
| `buttons.ts` | The `onPress` handlers of the buttons of each screen and of their menu items, called on `NavigationButtonPressed`; the API gives the event its form (`setPressEvent`). |
|
|
100
|
+
| `tabs.ts` | The press handlers of `Tab().onPress()`: they come with the tabs' layout, stay under the id the tabs are shown with, and go once every React screen shown in the tabs (pushed ones too) unmounted. |
|
|
101
|
+
| `slots.ts` | One tree (`appProvider`): `slotName` sends a React screen as `slot:<name>`, the native side gives it an empty container, and the slot with its id in `SlotHost` renders it. `withSlots` takes back the slots of a failed command; `ANN.SlotDestroyed` removes one. For a push on Android: `holdSlot` (nothing renders until the native side laid the screen out), `showSlot` (at its `SlotFrame`; resolves once React committed it, `slotCommitted`), `preparedPadding` (the first padding of its safe area view). |
|
|
102
|
+
| `launchState.ts` | The last root and default options: Android destroys the activity while JavaScript lives on and sends `AppLaunched` again; the app sets them again. |
|
|
103
|
+
| `backListeners.ts` | Android: wraps `BackHandler.addEventListener` at the launch to count the listeners, and tells the native side whether there is one (`setBackListeners`): the navigation takes the back button only while it can go back or JavaScript listens. A listener added before the launch isn't counted. |
|
|
104
|
+
| `reactMeasures.ts` | Development only: every command that shows or closes screens drops React's `performance.measure` entries of component renders (named after the component with U+200B in front). React Native keeps them without a limit, and a long session ran out of memory; the app's own measures stay. |
|
|
105
|
+
| `ids.ts`, `mergeOptions.ts` | `nextId` and the merge of options; see Ids and Options in layers. |
|
|
106
106
|
|
|
107
107
|
## The start of the app
|
|
108
108
|
|
|
@@ -14,7 +14,7 @@ export interface Spec extends TurboModule {
|
|
|
14
14
|
setDefaultOptions(options: CodegenTypes.UnsafeObject): void;
|
|
15
15
|
/** Merges options into the layout with the id and applies them to what shows; an unknown id does nothing. */
|
|
16
16
|
mergeOptions(componentId: string, options: CodegenTypes.UnsafeObject): void;
|
|
17
|
-
/** Pushes a layout over the screen in its stack; resolves with the id of the screen that shows. */
|
|
17
|
+
/** Pushes a layout over the screen in its stack; resolves with the id of the screen that shows (of a pair: its id). */
|
|
18
18
|
push(commandId: string, componentId: string, layout: CodegenTypes.UnsafeObject): Promise<string>;
|
|
19
19
|
/**
|
|
20
20
|
* (Android, one React tree) Lays the screen of a coming push out in its stack before React renders it, and resolves
|
|
@@ -67,7 +67,10 @@ export interface Spec extends TurboModule {
|
|
|
67
67
|
column: string,
|
|
68
68
|
layout: CodegenTypes.UnsafeObject
|
|
69
69
|
): Promise<string>;
|
|
70
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* Shows or hides a column of the screen's split view; resolves once the columns stopped moving, with nothing (on
|
|
72
|
+
* Android `null`).
|
|
73
|
+
*/
|
|
71
74
|
setColumnShown(
|
|
72
75
|
commandId: string,
|
|
73
76
|
componentId: string,
|
|
@@ -48,7 +48,7 @@ export interface NavigationEvents {
|
|
|
48
48
|
searchCancelled: ScreenEventOf<SearchBarCancelPressedEvent>;
|
|
49
49
|
/** #### (iOS 16+, Android) The user picked a suggestion of `searchBar.suggestions`; the text stays. */
|
|
50
50
|
searchSuggestionPicked: ScreenEventOf<NativeSearchSuggestionPickedEvent>;
|
|
51
|
-
/**
|
|
51
|
+
/** The user dragged a sheet to another detent. */
|
|
52
52
|
sheetDetentChanged: ScreenEventOf<NativeSheetDetentChangedEvent>;
|
|
53
53
|
/** #### (iOS specific) */
|
|
54
54
|
splitViewDisplayModeChanged: NativeSplitViewDisplayModeChangedEvent;
|
|
@@ -22,7 +22,7 @@ import type { ScreenName, ShowArgs } from '../types';
|
|
|
22
22
|
interface ScreenCommands {
|
|
23
23
|
/** The screen the commands act from. */
|
|
24
24
|
readonly screen: ScreenInfo;
|
|
25
|
-
/** Shows a screen over this one in its stack; resolves with the id of the screen shown. */
|
|
25
|
+
/** Shows a screen over this one in its stack; resolves with the id of the screen shown (for a pair, the pair's id). */
|
|
26
26
|
push<Name extends ScreenName>(name: Name, ...args: ShowArgs<Name, PushConfig>): Promise<string>;
|
|
27
27
|
/**
|
|
28
28
|
* Goes back to the screen before this one in its stack. The first screen of a split view column shown over the list
|
|
@@ -177,14 +177,19 @@ function stackCommands(id: string): StackCommands {
|
|
|
177
177
|
};
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
/**
|
|
180
|
+
/**
|
|
181
|
+
* The commands of the center for a menu screen: the menu closes as the center changes, and the command resolves once
|
|
182
|
+
* both are done.
|
|
183
|
+
*/
|
|
181
184
|
function fromCenter(center: string, menuScreen: string): StackCommands {
|
|
182
185
|
const centerCommands = stackCommands(center);
|
|
186
|
+
// As in the system's apps, the menu starts to close at the pick and the center changes as it goes, so a push is seen
|
|
187
|
+
// sliding in. The command settles after both, so the next one acts from the center; either one's error rejects it.
|
|
183
188
|
const closing =
|
|
184
189
|
<Args extends unknown[], Result>(run: (...args: Args) => Promise<Result>) =>
|
|
185
190
|
async (...args: Args) => {
|
|
186
|
-
const
|
|
187
|
-
await
|
|
191
|
+
const closed = closeMenu(menuScreen);
|
|
192
|
+
const [result] = await Promise.all([run(...args), closed]);
|
|
188
193
|
return result;
|
|
189
194
|
};
|
|
190
195
|
return {
|
package/src/api/navigation.ts
CHANGED
|
@@ -55,7 +55,10 @@ export interface AppNavigation {
|
|
|
55
55
|
switchTo<const Layout extends Exclude<RootLayout, string>>(
|
|
56
56
|
layout: Layout & NoInfer<CheckedScreens<UsesOfRoot<Layout>, RegisteredScreens>>
|
|
57
57
|
): Promise<void>;
|
|
58
|
-
/**
|
|
58
|
+
/**
|
|
59
|
+
* Shows a screen in the stack of the screen the user sees; resolves with the id of the screen shown (for a pair, the
|
|
60
|
+
* pair's id).
|
|
61
|
+
*/
|
|
59
62
|
push<Name extends ScreenName>(name: Name, ...args: ShowArgs<Name, PushConfig>): Promise<string>;
|
|
60
63
|
/** Goes back in the stack of the screen the user sees; see `useNavigation().pop`. */
|
|
61
64
|
pop(): Promise<string>;
|
package/src/engine/commands.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { whenNativeScreensReady } from './nativeScreens';
|
|
|
9
9
|
import { commands as native } from './native';
|
|
10
10
|
import { toNativeOptions } from './options';
|
|
11
11
|
import { dropReactRenderMeasures } from './reactMeasures';
|
|
12
|
-
import { columnOf, forgetPlace, notePlaces, placeOf, stackOfColumn } from './places';
|
|
12
|
+
import { columnOf, forgetPlace, layoutsOf, notePlaces, placeOf, stackOfColumn } from './places';
|
|
13
13
|
import { forgetProps } from './props';
|
|
14
14
|
import {
|
|
15
15
|
forgetMergedOptions,
|
|
@@ -122,7 +122,7 @@ export function setRoot(root: LayoutRoot): Promise<string> {
|
|
|
122
122
|
|
|
123
123
|
export function setDefaultOptions(options: Options): void {
|
|
124
124
|
rememberDefaultOptions(options);
|
|
125
|
-
native.setDefaultOptions(toNativeOptions(options));
|
|
125
|
+
native.setDefaultOptions(toNativeOptions(options, 'defaultOptions'));
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
// The show commands that wait in JS, by number: for lazy screens to load, for the first props of native screens, for a
|
|
@@ -141,7 +141,7 @@ const preparedScreens = new Set<string>();
|
|
|
141
141
|
* engine remembers them by the node's id, so the root set again for a new launch of the native side shows them too.
|
|
142
142
|
*/
|
|
143
143
|
export function mergeOptions(componentId: string, options: Options): void {
|
|
144
|
-
const nativeOptions = toNativeOptions(options);
|
|
144
|
+
const nativeOptions = toNativeOptions(options, componentId);
|
|
145
145
|
const send = () => {
|
|
146
146
|
rememberMergedOptions(componentId, options);
|
|
147
147
|
native.mergeOptions(componentId, nativeOptions);
|
|
@@ -225,7 +225,8 @@ export function push(
|
|
|
225
225
|
from?.stack ?? null,
|
|
226
226
|
(from?.index ?? 0) + 1,
|
|
227
227
|
from?.menu,
|
|
228
|
-
from?.layer
|
|
228
|
+
from?.layer,
|
|
229
|
+
layoutsOf(componentId)
|
|
229
230
|
);
|
|
230
231
|
return whenNativeScreensReady([node], () =>
|
|
231
232
|
sendPush(commandId, componentId, node, prepares, wanted, goneOut).then((shownId) => {
|
|
@@ -363,7 +364,8 @@ export function setStackRoot(componentId: string, children: Layout[]): Promise<s
|
|
|
363
364
|
from?.stack ?? null,
|
|
364
365
|
index,
|
|
365
366
|
from?.menu,
|
|
366
|
-
from?.layer
|
|
367
|
+
from?.layer,
|
|
368
|
+
layoutsOf(componentId)
|
|
367
369
|
)
|
|
368
370
|
);
|
|
369
371
|
return whenNativeScreensReady(nodes, () =>
|
|
@@ -383,7 +385,17 @@ export function showInColumn(componentId: string, column: string, layout: Layout
|
|
|
383
385
|
showScreensFrom(componentId, node);
|
|
384
386
|
const from = placeOf(componentId);
|
|
385
387
|
const at = columnPlace(componentId, column);
|
|
386
|
-
|
|
388
|
+
// In the split view of the screen it comes from, and in the column's stack.
|
|
389
|
+
const within = at.stack ? [...layoutsOf(componentId), at.stack] : layoutsOf(componentId);
|
|
390
|
+
notePlaces(
|
|
391
|
+
node,
|
|
392
|
+
from?.container ?? 'root',
|
|
393
|
+
at.stack,
|
|
394
|
+
at.index,
|
|
395
|
+
from?.menu,
|
|
396
|
+
from?.layer,
|
|
397
|
+
within
|
|
398
|
+
);
|
|
387
399
|
return whenNativeScreensReady([node], () =>
|
|
388
400
|
inOrder(() =>
|
|
389
401
|
sendShow(goneOut, () => native.showInColumn(commandId, componentId, column, node))
|
|
@@ -431,7 +443,7 @@ export function dismissModal(componentId: string, options?: Options): Promise<st
|
|
|
431
443
|
dropReactRenderMeasures();
|
|
432
444
|
const commandId = nextId('dismissModal');
|
|
433
445
|
return inOrder(() =>
|
|
434
|
-
native.dismissModal(commandId, componentId, options && toNativeOptions(options))
|
|
446
|
+
native.dismissModal(commandId, componentId, options && toNativeOptions(options, componentId))
|
|
435
447
|
);
|
|
436
448
|
}
|
|
437
449
|
|
package/src/engine/layout.ts
CHANGED
|
@@ -122,7 +122,7 @@ function screen(component: LayoutComponent, inPair = false, keyed = !inPair): La
|
|
|
122
122
|
type: 'Component',
|
|
123
123
|
data: {
|
|
124
124
|
name: rendersInSlot(name) ? slotName(id, name) : name,
|
|
125
|
-
options: toNativeOptions(options),
|
|
125
|
+
options: toNativeOptions(options, id),
|
|
126
126
|
...(key !== undefined && { key }),
|
|
127
127
|
},
|
|
128
128
|
children: [],
|
|
@@ -167,12 +167,13 @@ function arrangement(
|
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
function external(component: ExternalComponent): LayoutNode {
|
|
170
|
+
const id = component.id || nextId('ExternalComponent');
|
|
170
171
|
return {
|
|
171
|
-
id
|
|
172
|
+
id,
|
|
172
173
|
type: 'ExternalComponent',
|
|
173
174
|
data: {
|
|
174
175
|
name: String(component.name),
|
|
175
|
-
options: toNativeOptions(component.options),
|
|
176
|
+
options: toNativeOptions(component.options, id),
|
|
176
177
|
passProps: component.passProps,
|
|
177
178
|
},
|
|
178
179
|
children: [],
|
|
@@ -185,10 +186,11 @@ function parent(
|
|
|
185
186
|
options: Options | undefined,
|
|
186
187
|
children: Layout[] = []
|
|
187
188
|
): LayoutNode {
|
|
189
|
+
const nodeId = id || nextId(type);
|
|
188
190
|
return {
|
|
189
|
-
id:
|
|
191
|
+
id: nodeId,
|
|
190
192
|
type,
|
|
191
|
-
data: { options: toNativeOptions(options) },
|
|
193
|
+
data: { options: toNativeOptions(options, nodeId) },
|
|
192
194
|
children: children.map(toNativeLayout),
|
|
193
195
|
};
|
|
194
196
|
}
|
|
@@ -213,10 +215,11 @@ function sideMenu(menu: LayoutSideMenu): LayoutNode {
|
|
|
213
215
|
data: {},
|
|
214
216
|
children: [toNativeLayout(content)],
|
|
215
217
|
});
|
|
218
|
+
const id = menu.id || nextId('SideMenuRoot');
|
|
216
219
|
return {
|
|
217
|
-
id
|
|
220
|
+
id,
|
|
218
221
|
type: 'SideMenuRoot',
|
|
219
|
-
data: { options: toNativeOptions(menu.options) },
|
|
222
|
+
data: { options: toNativeOptions(menu.options, id) },
|
|
220
223
|
children: [
|
|
221
224
|
...(menu.left ? [side('SideMenuLeft', menu.left)] : []),
|
|
222
225
|
side('SideMenuCenter', menu.center),
|
|
@@ -238,10 +241,14 @@ function splitView(split: LayoutSplitView): LayoutNode {
|
|
|
238
241
|
] as [string, Layout | undefined][]
|
|
239
242
|
).filter((column): column is [string, Layout] => column[1] !== undefined);
|
|
240
243
|
const present = split.master && split.detail ? columns : [];
|
|
244
|
+
const id = split.id || nextId('SplitView');
|
|
241
245
|
return {
|
|
242
|
-
id
|
|
246
|
+
id,
|
|
243
247
|
type: 'SplitView',
|
|
244
|
-
data: {
|
|
248
|
+
data: {
|
|
249
|
+
options: toNativeOptions(split.options, id),
|
|
250
|
+
columns: present.map(([column]) => column),
|
|
251
|
+
},
|
|
245
252
|
children: present.map(([, content]) => toNativeLayout(content)),
|
|
246
253
|
};
|
|
247
254
|
}
|
package/src/engine/options.ts
CHANGED
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
import { DynamicColorIOS, Image, Platform, processColor } from 'react-native';
|
|
2
2
|
import type { ColorValue, ImageSourcePropType } from 'react-native';
|
|
3
3
|
import { nextId } from './ids';
|
|
4
|
-
import { rememberButtonRoot, setProps } from './props';
|
|
4
|
+
import { rememberButtonRoot, rememberOptionsComponent, setProps } from './props';
|
|
5
5
|
|
|
6
6
|
type Fields = Record<string, unknown>;
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* The options as the native side reads them: colors in the format of the platform, images resolved, and every
|
|
10
10
|
* component in them with an id of its own (its props stay in JavaScript). Options come in their own form only:
|
|
11
|
-
* animations with `enter` and `exit`, `searchBar` and `interpolation` as objects.
|
|
11
|
+
* animations with `enter` and `exit`, `searchBar` and `interpolation` as objects. `owner` is the id of the node the
|
|
12
|
+
* options are for, or `'defaultOptions'`: a component without an id of its own gets one made of the owner, its place
|
|
13
|
+
* in the options and its name, the same for every `mergeOptions` of the node, so the native side keeps the mounted
|
|
14
|
+
* component and only its props change. Without an owner each conversion gives it a new one.
|
|
12
15
|
*/
|
|
13
|
-
export function toNativeOptions<T>(options: T): T {
|
|
14
|
-
return convert(options) as T;
|
|
16
|
+
export function toNativeOptions<T>(options: T, owner?: string): T {
|
|
17
|
+
return convert(options, undefined, { owner, path: '' }) as T;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Where a value is in the options being converted: the node they are for, and the path to the value
|
|
21
|
+
// (`topBar.rightButtons[0].component`).
|
|
22
|
+
interface Place {
|
|
23
|
+
owner: string | undefined;
|
|
24
|
+
path: string;
|
|
15
25
|
}
|
|
16
26
|
|
|
17
27
|
/**
|
|
@@ -35,11 +45,16 @@ function isGroup(value: unknown): value is Fields {
|
|
|
35
45
|
return isFields(value) && !Array.isArray(value);
|
|
36
46
|
}
|
|
37
47
|
|
|
38
|
-
function convert(value: unknown, key
|
|
48
|
+
function convert(value: unknown, key: string | undefined, place: Place): unknown {
|
|
39
49
|
if (key !== undefined && isColor(key)) return nativeColor(value);
|
|
40
50
|
if (key !== undefined && isImage(key)) return nativeImage(value);
|
|
41
51
|
if (Array.isArray(value)) {
|
|
42
|
-
|
|
52
|
+
// An item is known by its id where it has one (a button, a suggestion), so a component keeps its root when the
|
|
53
|
+
// list around it changes; by its place in the list otherwise.
|
|
54
|
+
const items = value.map((item, index) => {
|
|
55
|
+
const id = isFields(item) && typeof item.id === 'string' && item.id ? item.id : index;
|
|
56
|
+
return convert(item, undefined, { ...place, path: `${place.path}[${id}]` });
|
|
57
|
+
});
|
|
43
58
|
if (key?.endsWith('Buttons') || key === 'buttons') items.forEach(noteButtonRoot);
|
|
44
59
|
return key?.endsWith('Buttons') ? items.map(takeButtonProps) : items;
|
|
45
60
|
}
|
|
@@ -47,9 +62,12 @@ function convert(value: unknown, key?: string): unknown {
|
|
|
47
62
|
const result: Fields = {};
|
|
48
63
|
for (const [name, item] of Object.entries(withSymbols(value))) {
|
|
49
64
|
// The props of a component are its own, not options.
|
|
50
|
-
|
|
65
|
+
const path = place.path ? `${place.path}.${name}` : name;
|
|
66
|
+
result[name] = name === 'passProps' ? item : convert(item, name, { ...place, path });
|
|
51
67
|
}
|
|
52
|
-
return key === 'component' || key === 'resultsComponent'
|
|
68
|
+
return key === 'component' || key === 'resultsComponent'
|
|
69
|
+
? takeComponentProps(result, place)
|
|
70
|
+
: result;
|
|
53
71
|
}
|
|
54
72
|
|
|
55
73
|
function isColor(key: string): boolean {
|
|
@@ -105,13 +123,23 @@ function isFields(value: unknown): value is Fields {
|
|
|
105
123
|
return typeof value === 'object' && value !== null;
|
|
106
124
|
}
|
|
107
125
|
|
|
108
|
-
// A component in the options gets an id; the native side creates it with that id, and its props wait here.
|
|
109
|
-
|
|
110
|
-
|
|
126
|
+
// A component in the options gets an id; the native side creates it with that id, and its props wait here. Without
|
|
127
|
+
// an id of its own it is the owner's, the place of the component (`topBar.title`, `topBar.rightButtons[Save]` by the
|
|
128
|
+
// button's id, `topBar.searchBar.resultsComponent`) and its name: another name there is another component.
|
|
129
|
+
function takeComponentProps({ passProps, ...component }: Fields, place: Place): Fields {
|
|
130
|
+
const componentId = (component.id as string | undefined) || componentIdAt(place, component.name);
|
|
111
131
|
if (passProps) setProps(componentId, passProps as object);
|
|
112
132
|
return { ...component, componentId };
|
|
113
133
|
}
|
|
114
134
|
|
|
135
|
+
function componentIdAt({ owner, path }: Place, name: unknown): string {
|
|
136
|
+
if (owner === undefined) return nextId('CustomComponent');
|
|
137
|
+
const at = path.endsWith('.component') ? path.slice(0, -'.component'.length) : path;
|
|
138
|
+
const id = `${owner}/${at}/${String(name)}`;
|
|
139
|
+
rememberOptionsComponent(owner, id);
|
|
140
|
+
return id;
|
|
141
|
+
}
|
|
142
|
+
|
|
115
143
|
// The component of a bar button (the top bar's `*Buttons`, the toolbar's `buttons`) is a root the native side only
|
|
116
144
|
// sizes: its wrapper centers the content in the button's slot.
|
|
117
145
|
function noteButtonRoot(button: unknown): void {
|
package/src/engine/places.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { SplitViewColumnsStackedEvent } from '../interfaces/Events';
|
|
2
2
|
import type { LayoutNode } from './layout';
|
|
3
3
|
import { onNativeEvent } from './native';
|
|
4
|
+
import { forgetProps } from './props';
|
|
4
5
|
import { screenNameOf } from './slots';
|
|
5
6
|
|
|
6
7
|
// Where each screen is, noted as the engine builds the layouts of the commands: what it shows in and its place in its
|
|
@@ -51,6 +52,11 @@ const stackedSplits = new Set<string>();
|
|
|
51
52
|
let listeningToSplitViews = false;
|
|
52
53
|
// The primaries of pairs shown alone, noted as their node is built, until their place is noted.
|
|
53
54
|
const alone = new Set<string>();
|
|
55
|
+
// The layouts each screen shows in (its stack, pair, tabs, menu, split view, and the root of its layer), and how many
|
|
56
|
+
// live screens each layout holds. A layout whose last screen went is gone, and with it the props of the components the
|
|
57
|
+
// library named in its options: they stay as long as any of its screens may show them again.
|
|
58
|
+
const layoutsOfScreen = new Map<string, readonly string[]>();
|
|
59
|
+
const screensInLayout = new Map<string, number>();
|
|
54
60
|
// The last screens that went, so a command from one of them can say so; a screen the engine never saw is not one.
|
|
55
61
|
const gone = new Set<string>();
|
|
56
62
|
const GONE_KEPT = 200;
|
|
@@ -69,9 +75,15 @@ export function isGone(screenId: string): boolean {
|
|
|
69
75
|
return gone.has(screenId);
|
|
70
76
|
}
|
|
71
77
|
|
|
78
|
+
/** The layouts the screen shows in, outermost first: those whose screens come with it in a command go in it too. */
|
|
79
|
+
export function layoutsOf(screenId: string): readonly string[] {
|
|
80
|
+
return layoutsOfScreen.get(screenId) ?? [];
|
|
81
|
+
}
|
|
82
|
+
|
|
72
83
|
/**
|
|
73
84
|
* Notes the screens of a layout, the first of a stack at `index`. A modal or an overlay given as a whole is a layer of
|
|
74
|
-
* its own; screens added to one, such as a push, take the layer of the screen they come from
|
|
85
|
+
* its own; screens added to one, such as a push, take the layer of the screen they come from, and `within`, the
|
|
86
|
+
* layouts they show in (`layoutsOf` that screen).
|
|
75
87
|
*/
|
|
76
88
|
export function notePlaces(
|
|
77
89
|
node: LayoutNode,
|
|
@@ -79,12 +91,14 @@ export function notePlaces(
|
|
|
79
91
|
stack: string | null = null,
|
|
80
92
|
index = 0,
|
|
81
93
|
menu?: ScreenPlace['menu'],
|
|
82
|
-
layer: string = container === 'root' ? 'root' : node.id
|
|
94
|
+
layer: string = container === 'root' ? 'root' : node.id,
|
|
95
|
+
within: readonly string[] = []
|
|
83
96
|
): void {
|
|
84
97
|
if (node.type === 'Component' || node.type === 'ExternalComponent') {
|
|
85
98
|
const name = node.data.name ?? '';
|
|
86
99
|
gone.delete(node.id);
|
|
87
100
|
columnOfScreen.delete(node.id);
|
|
101
|
+
noteLayouts(node.id, within);
|
|
88
102
|
places.set(node.id, {
|
|
89
103
|
name: screenNameOf(name),
|
|
90
104
|
container,
|
|
@@ -99,7 +113,7 @@ export function notePlaces(
|
|
|
99
113
|
} else if (node.type === 'Arrangement') {
|
|
100
114
|
// One entry of its stack: both screens have its place there, and each knows the pair.
|
|
101
115
|
node.children.forEach((child, childIndex) => {
|
|
102
|
-
notePlaces(child, container, stack, index, menu, layer);
|
|
116
|
+
notePlaces(child, container, stack, index, menu, layer, [...within, node.id]);
|
|
103
117
|
const place = places.get(child.id);
|
|
104
118
|
if (place) {
|
|
105
119
|
const placement = childIndex === 0 ? 'primary' : 'secondary';
|
|
@@ -109,7 +123,7 @@ export function notePlaces(
|
|
|
109
123
|
} else if (node.type === 'Stack') {
|
|
110
124
|
columnOfStack.delete(node.id);
|
|
111
125
|
node.children.forEach((child, childIndex) =>
|
|
112
|
-
notePlaces(child, container, node.id, childIndex, menu, layer)
|
|
126
|
+
notePlaces(child, container, node.id, childIndex, menu, layer, [...within, node.id])
|
|
113
127
|
);
|
|
114
128
|
} else if (node.type === 'SplitView') {
|
|
115
129
|
// A split view sent again with its id starts anew: its columns are noted again, and it isn't one stack until the
|
|
@@ -118,7 +132,7 @@ export function notePlaces(
|
|
|
118
132
|
const columns = node.data.columns ?? [];
|
|
119
133
|
const stacks: Partial<Record<string, string>> = {};
|
|
120
134
|
node.children.forEach((child, childIndex) => {
|
|
121
|
-
notePlaces(child, container, null, 0, menu, layer);
|
|
135
|
+
notePlaces(child, container, null, 0, menu, layer, [...within, node.id]);
|
|
122
136
|
const column = columns[childIndex];
|
|
123
137
|
if (!column) return;
|
|
124
138
|
if (child.type === 'Stack') stacks[column] = child.id;
|
|
@@ -128,12 +142,46 @@ export function notePlaces(
|
|
|
128
142
|
} else if (node.type === 'SideMenuRoot') {
|
|
129
143
|
for (const part of node.children) {
|
|
130
144
|
const side = MENU_PARTS[part.type];
|
|
145
|
+
const parts = [...within, node.id, part.id];
|
|
131
146
|
part.children.forEach((child) =>
|
|
132
|
-
notePlaces(
|
|
147
|
+
notePlaces(
|
|
148
|
+
child,
|
|
149
|
+
container,
|
|
150
|
+
null,
|
|
151
|
+
0,
|
|
152
|
+
side ? { id: node.id, part: side } : menu,
|
|
153
|
+
layer,
|
|
154
|
+
parts
|
|
155
|
+
)
|
|
133
156
|
);
|
|
134
157
|
}
|
|
135
158
|
} else {
|
|
136
|
-
node.children.forEach((child) =>
|
|
159
|
+
node.children.forEach((child) =>
|
|
160
|
+
notePlaces(child, container, null, 0, menu, layer, [...within, node.id])
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// A screen noted again under its id (a layout sent again) leaves the layouts it was in before.
|
|
166
|
+
function noteLayouts(screenId: string, within: readonly string[]): void {
|
|
167
|
+
leaveLayouts(screenId);
|
|
168
|
+
const layouts = [...new Set(within)];
|
|
169
|
+
layoutsOfScreen.set(screenId, layouts);
|
|
170
|
+
for (const layout of layouts) screensInLayout.set(layout, (screensInLayout.get(layout) ?? 0) + 1);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function leaveLayouts(screenId: string): void {
|
|
174
|
+
const layouts = layoutsOfScreen.get(screenId);
|
|
175
|
+
if (!layouts) return;
|
|
176
|
+
layoutsOfScreen.delete(screenId);
|
|
177
|
+
for (const layout of layouts) {
|
|
178
|
+
const count = (screensInLayout.get(layout) ?? 1) - 1;
|
|
179
|
+
if (count > 0) {
|
|
180
|
+
screensInLayout.set(layout, count);
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
screensInLayout.delete(layout);
|
|
184
|
+
forgetProps(layout);
|
|
137
185
|
}
|
|
138
186
|
}
|
|
139
187
|
|
|
@@ -198,6 +246,7 @@ export function listenToSplitViews(): void {
|
|
|
198
246
|
|
|
199
247
|
/** The screen is gone. */
|
|
200
248
|
export function forgetPlace(screenId: string): void {
|
|
249
|
+
leaveLayouts(screenId);
|
|
201
250
|
places.delete(screenId);
|
|
202
251
|
columnOfScreen.delete(screenId);
|
|
203
252
|
gone.add(screenId);
|