@symbiote-native/navigation 2.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +11 -10
- package/build/angular/drawer/index.d.ts +0 -76
- package/build/angular/drawer/index.js +0 -508
- package/build/angular/drawer-screen.directive.d.ts +0 -14
- package/build/angular/drawer-screen.directive.js +0 -87
- package/build/angular/index.d.ts +0 -23
- package/build/angular/index.js +0 -22
- package/build/angular/injectors/index.d.ts +0 -13
- package/build/angular/injectors/index.js +0 -8
- package/build/angular/injectors/inject-drawer-navigation.d.ts +0 -4
- package/build/angular/injectors/inject-drawer-navigation.js +0 -12
- package/build/angular/injectors/inject-focus-effect.d.ts +0 -2
- package/build/angular/injectors/inject-focus-effect.js +0 -29
- package/build/angular/injectors/inject-is-focused.d.ts +0 -2
- package/build/angular/injectors/inject-is-focused.js +0 -20
- package/build/angular/injectors/inject-navigation-state.d.ts +0 -3
- package/build/angular/injectors/inject-navigation-state.js +0 -35
- package/build/angular/injectors/inject-navigation.d.ts +0 -7
- package/build/angular/injectors/inject-navigation.js +0 -16
- package/build/angular/injectors/inject-route.d.ts +0 -3
- package/build/angular/injectors/inject-route.js +0 -20
- package/build/angular/injectors/inject-stack-navigation.d.ts +0 -4
- package/build/angular/injectors/inject-stack-navigation.js +0 -15
- package/build/angular/injectors/inject-tab-navigation.d.ts +0 -4
- package/build/angular/injectors/inject-tab-navigation.js +0 -11
- package/build/angular/linking.d.ts +0 -3
- package/build/angular/linking.js +0 -43
- package/build/angular/navigation-context.service.d.ts +0 -13
- package/build/angular/navigation-context.service.js +0 -105
- package/build/angular/navigation-scope.directive.d.ts +0 -10
- package/build/angular/navigation-scope.directive.js +0 -90
- package/build/angular/screen.directive.d.ts +0 -22
- package/build/angular/screen.directive.js +0 -90
- package/build/angular/search-bar-ref.directive.d.ts +0 -10
- package/build/angular/search-bar-ref.directive.js +0 -88
- package/build/angular/stack/index.d.ts +0 -55
- package/build/angular/stack/index.js +0 -386
- package/build/angular/tab-screen.directive.d.ts +0 -14
- package/build/angular/tab-screen.directive.js +0 -87
- package/build/angular/tabs/index.d.ts +0 -42
- package/build/angular/tabs/index.js +0 -263
- package/build/core/constants.d.ts +0 -27
- package/build/core/constants.js +0 -61
- package/build/core/drawer-options/index.d.ts +0 -64
- package/build/core/drawer-options/index.js +0 -200
- package/build/core/drawer-router-state/index.d.ts +0 -21
- package/build/core/drawer-router-state/index.js +0 -40
- package/build/core/guards.d.ts +0 -2
- package/build/core/guards.js +0 -22
- package/build/core/header-bar-buttons.d.ts +0 -9
- package/build/core/header-bar-buttons.js +0 -163
- package/build/core/index.d.ts +0 -29
- package/build/core/index.js +0 -32
- package/build/core/linking-config/index.d.ts +0 -13
- package/build/core/linking-config/index.js +0 -171
- package/build/core/navigation-events/index.d.ts +0 -16
- package/build/core/navigation-events/index.js +0 -57
- package/build/core/navigator-handles/index.d.ts +0 -30
- package/build/core/navigator-handles/index.js +0 -15
- package/build/core/navigator-props.d.ts +0 -216
- package/build/core/navigator-props.js +0 -7
- package/build/core/navigator-state/index.d.ts +0 -36
- package/build/core/navigator-state/index.js +0 -81
- package/build/core/render-drawer.d.ts +0 -13
- package/build/core/render-drawer.js +0 -88
- package/build/core/render-stack.d.ts +0 -35
- package/build/core/render-stack.js +0 -294
- package/build/core/render-tabs.d.ts +0 -20
- package/build/core/render-tabs.js +0 -97
- package/build/core/screen-options.d.ts +0 -4
- package/build/core/screen-options.js +0 -133
- package/build/core/search-bar-commands.d.ts +0 -10
- package/build/core/search-bar-commands.js +0 -42
- package/build/core/state-persistence/index.d.ts +0 -3
- package/build/core/state-persistence/index.js +0 -23
- package/build/core/tab-options.d.ts +0 -13
- package/build/core/tab-options.js +0 -10
- package/build/core/tab-router-state/index.d.ts +0 -19
- package/build/core/tab-router-state/index.js +0 -51
- package/build/react/collect-registry.d.ts +0 -4
- package/build/react/collect-registry.js +0 -15
- package/build/react/drawer/index.d.ts +0 -29
- package/build/react/drawer/index.js +0 -277
- package/build/react/drawer-screen.d.ts +0 -14
- package/build/react/drawer-screen.js +0 -8
- package/build/react/hooks/index.d.ts +0 -12
- package/build/react/hooks/index.js +0 -8
- package/build/react/hooks/use-drawer-navigation.d.ts +0 -4
- package/build/react/hooks/use-drawer-navigation.js +0 -12
- package/build/react/hooks/use-focus-effect.d.ts +0 -2
- package/build/react/hooks/use-focus-effect.js +0 -29
- package/build/react/hooks/use-is-focused.d.ts +0 -1
- package/build/react/hooks/use-is-focused.js +0 -22
- package/build/react/hooks/use-navigation-state/index.d.ts +0 -2
- package/build/react/hooks/use-navigation-state/index.js +0 -39
- package/build/react/hooks/use-navigation.d.ts +0 -7
- package/build/react/hooks/use-navigation.js +0 -16
- package/build/react/hooks/use-route.d.ts +0 -2
- package/build/react/hooks/use-route.js +0 -8
- package/build/react/hooks/use-stack-navigation.d.ts +0 -4
- package/build/react/hooks/use-stack-navigation.js +0 -14
- package/build/react/hooks/use-tab-navigation.d.ts +0 -4
- package/build/react/hooks/use-tab-navigation.js +0 -12
- package/build/react/index.d.ts +0 -24
- package/build/react/index.js +0 -21
- package/build/react/linking.d.ts +0 -3
- package/build/react/linking.js +0 -47
- package/build/react/navigation-context.d.ts +0 -10
- package/build/react/navigation-context.js +0 -22
- package/build/react/screen.d.ts +0 -22
- package/build/react/screen.js +0 -7
- package/build/react/stack/index.d.ts +0 -13
- package/build/react/stack/index.js +0 -202
- package/build/react/tab-screen.d.ts +0 -15
- package/build/react/tab-screen.js +0 -8
- package/build/react/tabs/index.d.ts +0 -12
- package/build/react/tabs/index.js +0 -116
- package/build/register.d.ts +0 -7
- package/build/register.js +0 -58
- package/build/vue/composables/index.d.ts +0 -12
- package/build/vue/composables/index.js +0 -8
- package/build/vue/composables/use-drawer-navigation.d.ts +0 -5
- package/build/vue/composables/use-drawer-navigation.js +0 -15
- package/build/vue/composables/use-focus-effect.d.ts +0 -1
- package/build/vue/composables/use-focus-effect.js +0 -31
- package/build/vue/composables/use-is-focused.d.ts +0 -2
- package/build/vue/composables/use-is-focused.js +0 -28
- package/build/vue/composables/use-navigation-state.d.ts +0 -3
- package/build/vue/composables/use-navigation-state.js +0 -29
- package/build/vue/composables/use-navigation.d.ts +0 -8
- package/build/vue/composables/use-navigation.js +0 -13
- package/build/vue/composables/use-route.d.ts +0 -3
- package/build/vue/composables/use-route.js +0 -9
- package/build/vue/composables/use-stack-navigation.d.ts +0 -5
- package/build/vue/composables/use-stack-navigation.js +0 -18
- package/build/vue/composables/use-tab-navigation.d.ts +0 -5
- package/build/vue/composables/use-tab-navigation.js +0 -15
- package/build/vue/drawer/index.d.ts +0 -19
- package/build/vue/drawer/index.js +0 -390
- package/build/vue/drawer-screen.d.ts +0 -14
- package/build/vue/drawer-screen.js +0 -12
- package/build/vue/index.d.ts +0 -21
- package/build/vue/index.js +0 -19
- package/build/vue/linking.d.ts +0 -3
- package/build/vue/linking.js +0 -57
- package/build/vue/navigation-context.d.ts +0 -16
- package/build/vue/navigation-context.js +0 -65
- package/build/vue/screen.d.ts +0 -21
- package/build/vue/screen.js +0 -12
- package/build/vue/stack/index.d.ts +0 -9
- package/build/vue/stack/index.js +0 -279
- package/build/vue/tab-screen.d.ts +0 -14
- package/build/vue/tab-screen.js +0 -11
- package/build/vue/tabs/index.d.ts +0 -10
- package/build/vue/tabs/index.js +0 -209
|
@@ -1,294 +0,0 @@
|
|
|
1
|
-
// Navigator: framework-agnostic render half. A screen's content is an arbitrary framework
|
|
2
|
-
// subtree the adapter owns (unlike the slider's one native leaf), so these resolvers hand back
|
|
3
|
-
// plain props objects for the RNSScreen/RNSScreenStack leaves the adapter builds itself with real
|
|
4
|
-
// children, and one full Descriptor for the header config. The header config Descriptor never
|
|
5
|
-
// takes framework children (headerLeftBarButtonItems/headerRightBarButtonItems are native config
|
|
6
|
-
// arrays from screen-options.ts, not elements), but can nest one RNSSearchBar leaf wrapped in an
|
|
7
|
-
// RNSScreenStackHeaderSubview(type: 'searchBar'), matching how react-native-screens' own
|
|
8
|
-
// ScreenStackHeaderSearchBarView mounts it. RNSScreenStackHeaderConfig.mm's mountChildComponentView
|
|
9
|
-
// rejects a bare RNSSearchBar child natively ("only accepts children of type
|
|
10
|
-
// ScreenStackHeaderSubview") and reads the search bar back out via `subview.subviews[0]`.
|
|
11
|
-
import { el } from '@symbiote-native/components';
|
|
12
|
-
import { HEADER_ON_PRESS_BAR_BUTTON_ITEM, HEADER_ON_PRESS_BAR_BUTTON_MENU_ITEM, RNS_MODAL_SCREEN_VIEW_NAME, RNS_SCREEN_STACK_HEADER_CONFIG_VIEW_NAME, RNS_SCREEN_STACK_HEADER_SUBVIEW_VIEW_NAME, RNS_SCREEN_VIEW_NAME, RNS_SEARCH_BAR_VIEW_NAME, SEARCH_BAR_ON_BLUR, SEARCH_BAR_ON_CANCEL_BUTTON_PRESS, SEARCH_BAR_ON_CHANGE_TEXT, SEARCH_BAR_ON_CLOSE, SEARCH_BAR_ON_FOCUS, SEARCH_BAR_ON_OPEN, SEARCH_BAR_ON_SEARCH_BUTTON_PRESS, STACK_DEFAULT_ANIMATION, STACK_DEFAULT_PRESENTATION, } from './constants.js';
|
|
13
|
-
import { computeActivityState } from './navigator-state/index.js';
|
|
14
|
-
import { resolveHeaderConfigView, resolveScreenView, resolveSearchBarView } from './screen-options.js';
|
|
15
|
-
// Mirrors react-native-screens' ScreenStackItem.tsx (getPositioningStyle): a formSheet's content
|
|
16
|
-
// wrapper does not get `flex: 1`. RNSScreen.mm's updateBounds pushes the sheet's live native size
|
|
17
|
-
// into Fabric's shadow state on every frame of a detent drag, and a `bottom: 0`-pinned wrapper
|
|
18
|
-
// forces React to set a strict frame on every update, causing the flicker PR #1870 fixed by
|
|
19
|
-
// switching to `absoluteWithNoBottom` (RNSScreen.mm: "we do not set bottom: 0 in JS for wrapper of
|
|
20
|
-
// the screen content, causing React to not set strict frame every time the sheet size is updated").
|
|
21
|
-
// Tradeoff: content shorter than the sheet's current detent leaves a gap below it.
|
|
22
|
-
// RNSScreenContentWrapper.mm's coerceChildScrollViewComponentSizeToSize fixes that natively, but
|
|
23
|
-
// only for a ScrollView child, which it resizes directly to the sheet's real frame bypassing
|
|
24
|
-
// Yoga/flex, not something reachable from a style choice here.
|
|
25
|
-
const SCREEN_CONTENT_WRAPPER_FLEX_STYLE = { flex: 1 };
|
|
26
|
-
const SHEET_CONTENT_WRAPPER_STYLE = {
|
|
27
|
-
position: 'absolute',
|
|
28
|
-
top: 0,
|
|
29
|
-
start: 0,
|
|
30
|
-
end: 0,
|
|
31
|
-
bottom: undefined,
|
|
32
|
-
};
|
|
33
|
-
// Android's native header (react-native-screens' CustomToolbar in a CoordinatorLayout alongside
|
|
34
|
-
// an AppBarLayout) auto-offsets screen content below the header via a Material
|
|
35
|
-
// `AppBarLayout.ScrollingViewBehavior` (ScreenStackFragment.kt's setToolbarTranslucent: `behavior
|
|
36
|
-
// = if (translucent) null else ScrollingViewBehavior()`). A plain (non-translucent) header gets
|
|
37
|
-
// this offset for free and needs no JS compensation. `headerTranslucent: true` removes that
|
|
38
|
-
// behavior: react-native-screens' contract for translucent is "background goes away AND content
|
|
39
|
-
// is no longer auto-pushed below it", meant for a screen painting under a see-through header. An
|
|
40
|
-
// app that sets headerTranslucent just for a custom (still opaque) header look, while relying on
|
|
41
|
-
// its own SafeAreaView for safe-area content, loses the free offset and gets clipped:
|
|
42
|
-
// SafeAreaView's Android inset only reflects WindowInsetsCompat's systemBars() (status
|
|
43
|
-
// bar/cutout), with no awareness of the sibling Toolbar, so content paints its first 56dp under
|
|
44
|
-
// the header. Verified empirically (2026-07-10) via `adb shell uiautomator dump`: a
|
|
45
|
-
// translucent-header screen's content measured starting at y=0 (see the
|
|
46
|
-
// navigation-header-content-offset skill for the full incident). iOS's UINavigationController
|
|
47
|
-
// already lays out below its real nav bar regardless of translucency, so this compensation is
|
|
48
|
-
// Android-only and applies only when translucent (a non-translucent header already gets the
|
|
49
|
-
// native offset; padding there would double it).
|
|
50
|
-
const ANDROID_HEADER_TOOLBAR_HEIGHT = 56;
|
|
51
|
-
// react-native-screens' own Screen.tsx picks a different Fabric component for a modally-presented
|
|
52
|
-
// screen ('RNSModalScreen' instead of plain 'RNSScreen') because "there is a need for different
|
|
53
|
-
// shadow nodes" (its own comment). RNSScreen.mm's updateLayoutMetrics only skips applying Yoga's
|
|
54
|
-
// computed frame for `[self isKindOfClass:RNSModalScreen.class]` ("the available space is most
|
|
55
|
-
// likely restricted & differs from what Yoga resolves during first layout - we want to rely on
|
|
56
|
-
// native layout here"). Emitting plain 'RNSScreen' for a formSheet/modal means that check never
|
|
57
|
-
// matches, so Yoga's frame (computed as an ordinary push-stack sibling) applies uncorrected,
|
|
58
|
-
// shifting the modal down by one full screen height (see register.ts's incident note). Mirrors
|
|
59
|
-
// Screen.tsx's `shouldUseModalScreenComponent` exactly, including the iOS-only scope (Android
|
|
60
|
-
// sizes modals natively regardless of Fabric view name).
|
|
61
|
-
export function resolveScreenViewName(stackPresentation, isAndroid) {
|
|
62
|
-
if (isAndroid)
|
|
63
|
-
return RNS_SCREEN_VIEW_NAME;
|
|
64
|
-
const isPlainPresentation = stackPresentation === undefined ||
|
|
65
|
-
stackPresentation === 'push' ||
|
|
66
|
-
stackPresentation === 'containedModal' ||
|
|
67
|
-
stackPresentation === 'containedTransparentModal';
|
|
68
|
-
return isPlainPresentation ? RNS_SCREEN_VIEW_NAME : RNS_MODAL_SCREEN_VIEW_NAME;
|
|
69
|
-
}
|
|
70
|
-
export function resolveScreenContentWrapperStyle(stackPresentation, headerHidden, headerTranslucent, isAndroid) {
|
|
71
|
-
let baseStyles;
|
|
72
|
-
if (stackPresentation !== 'formSheet') {
|
|
73
|
-
baseStyles = SCREEN_CONTENT_WRAPPER_FLEX_STYLE;
|
|
74
|
-
}
|
|
75
|
-
else if (isAndroid) {
|
|
76
|
-
baseStyles = {
|
|
77
|
-
...SHEET_CONTENT_WRAPPER_STYLE,
|
|
78
|
-
bottom: 0,
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
baseStyles = SHEET_CONTENT_WRAPPER_STYLE;
|
|
83
|
-
}
|
|
84
|
-
// paddingTop compensates the Android-only ScrollingViewBehavior removal above; iOS never needs
|
|
85
|
-
// it, so the `!isAndroid` check must stay.
|
|
86
|
-
if (!isAndroid || headerHidden || !headerTranslucent)
|
|
87
|
-
return baseStyles;
|
|
88
|
-
return { ...baseStyles, paddingTop: ANDROID_HEADER_TOOLBAR_HEIGHT };
|
|
89
|
-
}
|
|
90
|
-
// A modally-presented screen (anything but 'push') has no UINavigationController on iOS, so
|
|
91
|
-
// RNSScreenStackHeaderConfig has nothing to attach a header bar to. react-native-screens' own
|
|
92
|
-
// ScreenStackItem.tsx (isHeaderInModal) works around this by nesting header + content inside a
|
|
93
|
-
// second, inner RNSScreenStack/RNSScreen pair purely to host the native nav bar. This is a UIKit
|
|
94
|
-
// constraint, not a React-renderer one, so it applies identically here. Android has no such
|
|
95
|
-
// requirement (its header draws without a nav-controller host).
|
|
96
|
-
export function isHeaderInModal(stackPresentation, headerHidden, isAndroid) {
|
|
97
|
-
if (isAndroid)
|
|
98
|
-
return false;
|
|
99
|
-
return (stackPresentation ?? STACK_DEFAULT_PRESENTATION) !== 'push' && !headerHidden;
|
|
100
|
-
}
|
|
101
|
-
// Inner-modal wrapper styles for isHeaderInModal: the inner RNSScreenStack fills its outer
|
|
102
|
-
// RNSScreen, and the inner RNSScreen fills the stack absolutely on all four edges. This mirrors
|
|
103
|
-
// react-native-screens' own `styles.container` / `StyleSheet.absoluteFill` for this exact pair.
|
|
104
|
-
const HEADER_IN_MODAL_STACK_STYLE = { flex: 1 };
|
|
105
|
-
const HEADER_IN_MODAL_SCREEN_STYLE = { position: 'absolute', top: 0, start: 0, end: 0, bottom: 0 };
|
|
106
|
-
export function resolveHeaderInModalStackStyle() {
|
|
107
|
-
return HEADER_IN_MODAL_STACK_STYLE;
|
|
108
|
-
}
|
|
109
|
-
export function resolveHeaderInModalScreenStyle() {
|
|
110
|
-
return HEADER_IN_MODAL_SCREEN_STYLE;
|
|
111
|
-
}
|
|
112
|
-
// The RNSScreen leaf's own props; the adapter spreads this record directly onto the element it
|
|
113
|
-
// builds and appends the header config child and real screen content itself, not here.
|
|
114
|
-
export function resolveScreenProps(view) {
|
|
115
|
-
return {
|
|
116
|
-
...view.passthrough,
|
|
117
|
-
screenId: view.screenId,
|
|
118
|
-
activityState: view.activityState,
|
|
119
|
-
gestureEnabled: view.gestureEnabled,
|
|
120
|
-
stackAnimation: view.stackAnimation ?? STACK_DEFAULT_ANIMATION,
|
|
121
|
-
stackPresentation: view.stackPresentation ?? STACK_DEFAULT_PRESENTATION,
|
|
122
|
-
// Off by default upstream; a formSheet's updateBounds pushes the sheet's live native size
|
|
123
|
-
// into Fabric's shadow state on every drag frame, and this switches that push from
|
|
124
|
-
// Asynchronous to EventQueue::UpdateMode::unstable_Immediate. The ScrollView-frame correction
|
|
125
|
-
// that fills a taller detent (RNSScreenContentWrapper.mm's
|
|
126
|
-
// coerceChildScrollViewComponentSizeToSize) is driven by that same state, so an async push
|
|
127
|
-
// likely lags one step behind a fast drag. Scoped to formSheet: push/plain-modal screens have
|
|
128
|
-
// no comparable live-resize need.
|
|
129
|
-
synchronousShadowStateUpdatesEnabled: view.stackPresentation === 'formSheet',
|
|
130
|
-
transitionDuration: view.transitionDuration,
|
|
131
|
-
sheetAllowedDetents: view.sheetAllowedDetents,
|
|
132
|
-
// Native RNSScreen's real prop names carry an "Index" suffix (react-native-screens' own
|
|
133
|
-
// types.tsx); without it the value never reaches the native view and silently falls back to
|
|
134
|
-
// RNS's default.
|
|
135
|
-
sheetLargestUndimmedDetentIndex: view.sheetLargestUndimmedDetent,
|
|
136
|
-
sheetInitialDetentIndex: view.sheetInitialDetent,
|
|
137
|
-
sheetGrabberVisible: view.sheetGrabberVisible,
|
|
138
|
-
sheetCornerRadius: view.sheetCornerRadius,
|
|
139
|
-
sheetExpandsWhenScrolledToEdge: view.sheetExpandsWhenScrolledToEdge,
|
|
140
|
-
sheetElevation: view.sheetElevation,
|
|
141
|
-
sheetShouldOverflowTopInset: view.sheetShouldOverflowTopInset,
|
|
142
|
-
sheetDefaultResizeAnimationEnabled: view.sheetDefaultResizeAnimationEnabled,
|
|
143
|
-
statusBarStyle: view.statusBarStyle,
|
|
144
|
-
statusBarHidden: view.statusBarHidden,
|
|
145
|
-
statusBarAnimation: view.statusBarAnimation,
|
|
146
|
-
screenOrientation: view.screenOrientation,
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
// `style: {flex: 1}` is ours, not react-native-screens': RNSScreenStackView sizes its nav
|
|
150
|
-
// controller to `self.bounds`, which Yoga would otherwise collapse to zero, and (unlike RN's
|
|
151
|
-
// own ScreenStack.tsx) we drive the native view directly (<third_party_rn_packages_are_react_only>).
|
|
152
|
-
export function resolveStackProps(view) {
|
|
153
|
-
return { style: { flex: 1 }, ...view.passthrough };
|
|
154
|
-
}
|
|
155
|
-
// The RNSScreenStackHeaderConfig leaf is a full Descriptor since it never hosts framework children,
|
|
156
|
-
// so the adapter bridges it verbatim (descriptorToReact/descriptorToVue) as the screen's first
|
|
157
|
-
// child, ahead of the real content. `searchBarProps` nests as an RNSSearchBar wrapped in an
|
|
158
|
-
// RNSScreenStackHeaderSubview(type: 'searchBar'), matching how react-native-screens' own JS
|
|
159
|
-
// component mounts it (see resolveSearchBarView's comment in screen-options.ts); omitted when the
|
|
160
|
-
// screen has no search bar.
|
|
161
|
-
export function renderHeaderConfig(view, searchBarProps) {
|
|
162
|
-
const props = {
|
|
163
|
-
...view.passthrough,
|
|
164
|
-
title: view.title,
|
|
165
|
-
hidden: view.hidden,
|
|
166
|
-
// Android-only (CustomToolbar.kt gates its WindowInsets padding on these; iOS's
|
|
167
|
-
// UINavigationController lays out under the safe area regardless). Upstream's JS
|
|
168
|
-
// ScreenStackHeaderConfig computes these via an EdgeInsetApplicationContext that coordinates a
|
|
169
|
-
// "consume once" top inset across nested headers; we drive RNSScreenStackHeaderConfig directly
|
|
170
|
-
// and skip that layer, so without this the native default (false) leaves the header glued
|
|
171
|
-
// under the status bar/cutout on Android. Every adapter renders one active header at a time,
|
|
172
|
-
// so consuming all four edges matches upstream's default for the common case; a genuine
|
|
173
|
-
// nested-header edge case would need upstream's same coordination.
|
|
174
|
-
consumeTopInset: !view.hidden,
|
|
175
|
-
consumeLeftInset: !view.hidden,
|
|
176
|
-
consumeRightInset: !view.hidden,
|
|
177
|
-
consumeBottomInset: !view.hidden,
|
|
178
|
-
backTitle: view.backTitle,
|
|
179
|
-
backTitleVisible: view.backTitleVisible,
|
|
180
|
-
backButtonDisplayMode: view.backButtonDisplayMode,
|
|
181
|
-
largeTitle: view.largeTitle,
|
|
182
|
-
translucent: view.translucent,
|
|
183
|
-
color: view.color,
|
|
184
|
-
titleColor: view.titleColor,
|
|
185
|
-
backgroundColor: view.backgroundColor,
|
|
186
|
-
largeTitleBackgroundColor: view.largeTitleBackgroundColor,
|
|
187
|
-
userInterfaceStyle: view.userInterfaceStyle,
|
|
188
|
-
headerLeftBarButtonItems: view.headerLeftBarButtonItems,
|
|
189
|
-
headerRightBarButtonItems: view.headerRightBarButtonItems,
|
|
190
|
-
[HEADER_ON_PRESS_BAR_BUTTON_ITEM]: view.onPressHeaderBarButtonItem,
|
|
191
|
-
[HEADER_ON_PRESS_BAR_BUTTON_MENU_ITEM]: view.onPressHeaderBarButtonMenuItem,
|
|
192
|
-
};
|
|
193
|
-
const children = searchBarProps
|
|
194
|
-
? [
|
|
195
|
-
el(RNS_SCREEN_STACK_HEADER_SUBVIEW_VIEW_NAME, { type: 'searchBar' }, [
|
|
196
|
-
el(RNS_SEARCH_BAR_VIEW_NAME, searchBarProps),
|
|
197
|
-
]),
|
|
198
|
-
]
|
|
199
|
-
: [];
|
|
200
|
-
return el(RNS_SCREEN_STACK_HEADER_CONFIG_VIEW_NAME, props, children);
|
|
201
|
-
}
|
|
202
|
-
// The RNSSearchBar leaf's static config props; event handlers ride in `passthrough`.
|
|
203
|
-
// renderHeaderConfig wraps this into the RNSSearchBar Descriptor and nests it as the header
|
|
204
|
-
// config's child.
|
|
205
|
-
export function resolveSearchBarProps(view) {
|
|
206
|
-
return {
|
|
207
|
-
...view.passthrough,
|
|
208
|
-
placeholder: view.placeholder,
|
|
209
|
-
autoCapitalize: view.autoCapitalize,
|
|
210
|
-
placement: view.placement,
|
|
211
|
-
hideWhenScrolling: view.hideWhenScrolling,
|
|
212
|
-
allowToolbarIntegration: view.allowToolbarIntegration,
|
|
213
|
-
obscureBackground: view.obscureBackground,
|
|
214
|
-
hideNavigationBar: view.hideNavigationBar,
|
|
215
|
-
cancelButtonText: view.cancelButtonText,
|
|
216
|
-
barTintColor: view.barTintColor,
|
|
217
|
-
tintColor: view.tintColor,
|
|
218
|
-
textColor: view.textColor,
|
|
219
|
-
autoFocus: view.autoFocus,
|
|
220
|
-
disableBackButtonOverride: view.disableBackButtonOverride,
|
|
221
|
-
inputType: view.inputType,
|
|
222
|
-
hintTextColor: view.hintTextColor,
|
|
223
|
-
headerIconColor: view.headerIconColor,
|
|
224
|
-
shouldShowHintSearchIcon: view.shouldShowHintSearchIcon,
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
// The 7 search-bar event keys -> option-callback passthrough: zero lifecycle dependency, so every
|
|
228
|
-
// adapter built the identical map by hand. `log` is an optional per-event hook so an adapter can
|
|
229
|
-
// still attach its own route-scoped dlog line (React/Vue do; Angular doesn't) without forking the
|
|
230
|
-
// map itself.
|
|
231
|
-
export function buildSearchBarPassthrough(options, log) {
|
|
232
|
-
return {
|
|
233
|
-
[SEARCH_BAR_ON_FOCUS]: () => {
|
|
234
|
-
log?.('search bar focused');
|
|
235
|
-
options.onFocus?.();
|
|
236
|
-
},
|
|
237
|
-
[SEARCH_BAR_ON_BLUR]: () => {
|
|
238
|
-
log?.('search bar blurred');
|
|
239
|
-
options.onBlur?.();
|
|
240
|
-
},
|
|
241
|
-
[SEARCH_BAR_ON_CHANGE_TEXT]: (event) => {
|
|
242
|
-
const { text } = event.nativeEvent;
|
|
243
|
-
const changedText = typeof text === 'string' ? text : '';
|
|
244
|
-
log?.(`search text changed: ${changedText}`);
|
|
245
|
-
options.onChangeText?.(changedText);
|
|
246
|
-
},
|
|
247
|
-
[SEARCH_BAR_ON_SEARCH_BUTTON_PRESS]: (event) => {
|
|
248
|
-
const { text } = event.nativeEvent;
|
|
249
|
-
const pressedText = typeof text === 'string' ? text : '';
|
|
250
|
-
log?.(`search button pressed: ${pressedText}`);
|
|
251
|
-
options.onSearchButtonPress?.(pressedText);
|
|
252
|
-
},
|
|
253
|
-
[SEARCH_BAR_ON_CANCEL_BUTTON_PRESS]: () => {
|
|
254
|
-
log?.('search bar cancel pressed');
|
|
255
|
-
options.onCancelButtonPress?.();
|
|
256
|
-
},
|
|
257
|
-
[SEARCH_BAR_ON_CLOSE]: () => {
|
|
258
|
-
log?.('search bar closed');
|
|
259
|
-
options.onClose?.();
|
|
260
|
-
},
|
|
261
|
-
[SEARCH_BAR_ON_OPEN]: () => {
|
|
262
|
-
log?.('search bar opened');
|
|
263
|
-
options.onOpen?.();
|
|
264
|
-
},
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
export function resolveScreenRenderPlan(input) {
|
|
268
|
-
const { options, isAndroid } = input;
|
|
269
|
-
const headerHidden = options?.headerShown === false;
|
|
270
|
-
const activityState = computeActivityState(input.index, input.routeCount);
|
|
271
|
-
const screenProps = resolveScreenProps(resolveScreenView(input.screenId, activityState, options, input.screenPassthrough));
|
|
272
|
-
const searchBarOptions = options?.headerSearchBarOptions;
|
|
273
|
-
const searchBarProps = searchBarOptions
|
|
274
|
-
? resolveSearchBarProps(resolveSearchBarView(searchBarOptions, input.searchBarPassthrough ?? {}))
|
|
275
|
-
: undefined;
|
|
276
|
-
// See renderHeaderConfig's own header comment for why `props` never reflects `searchBarProps` --
|
|
277
|
-
// only `children` does -- so passing it here unconditionally is safe even for Angular, which
|
|
278
|
-
// never reads `children` off the result.
|
|
279
|
-
const headerConfig = renderHeaderConfig(resolveHeaderConfigView(options, input.platform), searchBarProps);
|
|
280
|
-
return {
|
|
281
|
-
activityState,
|
|
282
|
-
screenViewName: resolveScreenViewName(options?.stackPresentation, isAndroid),
|
|
283
|
-
screenProps,
|
|
284
|
-
headerConfig,
|
|
285
|
-
searchBarProps,
|
|
286
|
-
contentWrapperProps: {
|
|
287
|
-
style: resolveScreenContentWrapperStyle(options?.stackPresentation, headerHidden, options?.headerTranslucent, isAndroid),
|
|
288
|
-
collapsable: false,
|
|
289
|
-
},
|
|
290
|
-
inModal: isHeaderInModal(options?.stackPresentation, headerHidden, isAndroid),
|
|
291
|
-
innerStackStyle: resolveHeaderInModalStackStyle(),
|
|
292
|
-
innerScreenStyle: resolveHeaderInModalScreenStyle(),
|
|
293
|
-
};
|
|
294
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { IDescriptor } from '@symbiote-native/components';
|
|
2
|
-
import type { IColorValue, IViewStyle, IStyleProp } from '@symbiote-native/engine';
|
|
3
|
-
import type { ITabBarIcon } from './tab-options';
|
|
4
|
-
export type ITabBarItemView = {
|
|
5
|
-
key: string;
|
|
6
|
-
focused: boolean;
|
|
7
|
-
label: string;
|
|
8
|
-
icon?: ITabBarIcon;
|
|
9
|
-
badge?: string | number;
|
|
10
|
-
activeTintColor?: IColorValue;
|
|
11
|
-
inactiveTintColor?: IColorValue;
|
|
12
|
-
passthrough: Record<string, unknown>;
|
|
13
|
-
};
|
|
14
|
-
export type ITabBarViewProps = {
|
|
15
|
-
items: readonly ITabBarItemView[];
|
|
16
|
-
style?: IStyleProp<IViewStyle>;
|
|
17
|
-
passthrough: Record<string, unknown>;
|
|
18
|
-
};
|
|
19
|
-
export declare function renderTabBarItem(item: ITabBarItemView): IDescriptor;
|
|
20
|
-
export declare function renderTabBar(view: ITabBarViewProps): IDescriptor;
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
// TabBar: the render half (framework-agnostic). A bottom-tabs bar is a PURE-JS UI - unlike
|
|
2
|
-
// Stack, which drives real native RNSScreen/RNSScreenStack views, this paints ordinary
|
|
3
|
-
// `symbiote-view`/`symbiote-text` primitives, so it needs no react-native-screens ViewConfig
|
|
4
|
-
// work at all (see the task brief in packages/navigation's skill notes). Mirrors renderSwitch's
|
|
5
|
-
// shape: pure prop-driven functions building a `Descriptor` tree from pre-resolved view props;
|
|
6
|
-
// the adapter supplies focus state, tint-color resolution inputs, and the press wiring via
|
|
7
|
-
// `passthrough` (exactly like Stack wires onDismissed/onHeaderBackButtonClicked into
|
|
8
|
-
// resolveScreenView's passthrough) - this layer never invents an onPress/responder pair itself.
|
|
9
|
-
import { el, txt } from '@symbiote-native/components';
|
|
10
|
-
// react-navigation's own bottom-tabs default to the surrounding theme's primary/text colors;
|
|
11
|
-
// symbiote's navigation package has no app-level theme yet, so these are placeholder defaults -
|
|
12
|
-
// the same iOS-system-blue/neutral-grey pair render-button.ts already uses for its default
|
|
13
|
-
// tint/disabled colors, reused here rather than inventing a third pair (no shared semantic color
|
|
14
|
-
// tokens exist yet in @symbiote-native/engine as of this writing).
|
|
15
|
-
const DEFAULT_ACTIVE_TINT_COLOR = '#007AFF';
|
|
16
|
-
const DEFAULT_INACTIVE_TINT_COLOR = '#8e8e93';
|
|
17
|
-
const BADGE_BACKGROUND_COLOR = '#FF3B30';
|
|
18
|
-
const BADGE_TEXT_COLOR = '#ffffff';
|
|
19
|
-
const TAB_BAR_HEIGHT = 49;
|
|
20
|
-
const TAB_ICON_FONT_SIZE = 20;
|
|
21
|
-
const TAB_LABEL_FONT_SIZE = 10;
|
|
22
|
-
const BADGE_SIZE = 16;
|
|
23
|
-
const BADGE_BORDER_RADIUS = BADGE_SIZE / 2;
|
|
24
|
-
const BADGE_OFFSET_TOP = -4;
|
|
25
|
-
const BADGE_OFFSET_RIGHT = -8;
|
|
26
|
-
const TAB_BAR_STYLE = {
|
|
27
|
-
flexDirection: 'row',
|
|
28
|
-
height: TAB_BAR_HEIGHT,
|
|
29
|
-
};
|
|
30
|
-
const TAB_ITEM_STYLE = {
|
|
31
|
-
flex: 1,
|
|
32
|
-
alignItems: 'center',
|
|
33
|
-
justifyContent: 'center',
|
|
34
|
-
};
|
|
35
|
-
const ICON_WRAPPER_STYLE = {
|
|
36
|
-
alignItems: 'center',
|
|
37
|
-
justifyContent: 'center',
|
|
38
|
-
};
|
|
39
|
-
const BADGE_STYLE = {
|
|
40
|
-
position: 'absolute',
|
|
41
|
-
top: BADGE_OFFSET_TOP,
|
|
42
|
-
right: BADGE_OFFSET_RIGHT,
|
|
43
|
-
minWidth: BADGE_SIZE,
|
|
44
|
-
height: BADGE_SIZE,
|
|
45
|
-
borderRadius: BADGE_BORDER_RADIUS,
|
|
46
|
-
backgroundColor: BADGE_BACKGROUND_COLOR,
|
|
47
|
-
alignItems: 'center',
|
|
48
|
-
justifyContent: 'center',
|
|
49
|
-
paddingHorizontal: 3,
|
|
50
|
-
};
|
|
51
|
-
const BADGE_TEXT_STYLE = {
|
|
52
|
-
color: BADGE_TEXT_COLOR,
|
|
53
|
-
fontSize: 8,
|
|
54
|
-
fontWeight: '600',
|
|
55
|
-
};
|
|
56
|
-
function resolveTintColor(item) {
|
|
57
|
-
if (item.focused)
|
|
58
|
-
return item.activeTintColor ?? DEFAULT_ACTIVE_TINT_COLOR;
|
|
59
|
-
return item.inactiveTintColor ?? DEFAULT_INACTIVE_TINT_COLOR;
|
|
60
|
-
}
|
|
61
|
-
// A string icon paints as a glyph (an emoji/ligature font name - same convention a caller uses
|
|
62
|
-
// for a vector-icon-font label); an IDescriptor icon (an <Image>/vector-icon element the adapter
|
|
63
|
-
// already resolved) is spliced in verbatim, exactly like renderHeaderConfig treats a pre-built
|
|
64
|
-
// Descriptor child.
|
|
65
|
-
function renderIcon(icon, color) {
|
|
66
|
-
if (icon === undefined)
|
|
67
|
-
return undefined;
|
|
68
|
-
if (typeof icon === 'string')
|
|
69
|
-
return txt({ style: { color, fontSize: TAB_ICON_FONT_SIZE } }, [icon]);
|
|
70
|
-
return icon;
|
|
71
|
-
}
|
|
72
|
-
function renderBadge(badge) {
|
|
73
|
-
if (badge === undefined)
|
|
74
|
-
return undefined;
|
|
75
|
-
return el('symbiote-view', { style: BADGE_STYLE }, [
|
|
76
|
-
txt({ style: BADGE_TEXT_STYLE }, [String(badge)]),
|
|
77
|
-
]);
|
|
78
|
-
}
|
|
79
|
-
export function renderTabBarItem(item) {
|
|
80
|
-
const color = resolveTintColor(item);
|
|
81
|
-
const icon = renderIcon(item.icon, color);
|
|
82
|
-
const badge = renderBadge(item.badge);
|
|
83
|
-
const iconChildren = [];
|
|
84
|
-
if (icon)
|
|
85
|
-
iconChildren.push(icon);
|
|
86
|
-
if (badge)
|
|
87
|
-
iconChildren.push(badge);
|
|
88
|
-
const children = [];
|
|
89
|
-
if (iconChildren.length > 0)
|
|
90
|
-
children.push(el('symbiote-view', { style: ICON_WRAPPER_STYLE }, iconChildren));
|
|
91
|
-
children.push(txt({ style: { color, fontSize: TAB_LABEL_FONT_SIZE } }, [item.label]));
|
|
92
|
-
return el('symbiote-view', { ...item.passthrough, style: TAB_ITEM_STYLE, accessibilityRole: 'tab' }, children, item.key);
|
|
93
|
-
}
|
|
94
|
-
export function renderTabBar(view) {
|
|
95
|
-
const items = view.items.map(renderTabBarItem);
|
|
96
|
-
return el('symbiote-view', { ...view.passthrough, style: [TAB_BAR_STYLE, view.style] }, items);
|
|
97
|
-
}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { IHeaderConfigViewProps, INavigatorPlatform, IScreenOptions, IScreenViewProps, ISearchBarOptions, ISearchBarViewProps } from './navigator-props';
|
|
2
|
-
export declare function resolveHeaderConfigView(options: IScreenOptions | undefined, platform: INavigatorPlatform, passthrough?: Record<string, unknown>): IHeaderConfigViewProps;
|
|
3
|
-
export declare function resolveScreenView(screenId: string, activityState: number, options: IScreenOptions | undefined, passthrough?: Record<string, unknown>): IScreenViewProps;
|
|
4
|
-
export declare function resolveSearchBarView(options: ISearchBarOptions | undefined, passthrough?: Record<string, unknown>): ISearchBarViewProps;
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
// Pure folds from a route's agnostic IScreenOptions into the native view-props shapes
|
|
2
|
-
// (RNSScreen + RNSScreenStackHeaderConfig + RNSSearchBar paint from). Framework-agnostic and
|
|
3
|
-
// shared verbatim by every adapter - the adapter's own job is only wiring identity (screenId),
|
|
4
|
-
// position (activityState via computeActivityState) and the lifecycle event handlers into
|
|
5
|
-
// `passthrough`.
|
|
6
|
-
//
|
|
7
|
-
// The header bar-button payload+dispatch cluster (id-tagging, onPress lookup) lives in
|
|
8
|
-
// header-bar-buttons.ts - self-contained, consumed here only as a black box by
|
|
9
|
-
// resolveHeaderConfigView.
|
|
10
|
-
import { buildHeaderBarButtonDispatch, prepareHeaderBarButtonItems } from './header-bar-buttons.js';
|
|
11
|
-
// These sentinels must be kept in sync with react-native-screens' native side - they are RNS's
|
|
12
|
-
// own compat values for the 'fitToContents'/'large'/'medium'/'all' legacy presets, replicated
|
|
13
|
-
// here because we drive RNSScreen directly (no react-native-screens JS component in the path).
|
|
14
|
-
const SHEET_FIT_TO_CONTENTS = [-1];
|
|
15
|
-
const SHEET_COMPAT_LARGE = [1.0];
|
|
16
|
-
const SHEET_COMPAT_MEDIUM = [0.5];
|
|
17
|
-
const SHEET_COMPAT_ALL = [0.5, 1.0];
|
|
18
|
-
const SHEET_DIMMED_ALWAYS = -1;
|
|
19
|
-
function resolveSheetAllowedDetents(compat) {
|
|
20
|
-
if (compat === undefined)
|
|
21
|
-
return SHEET_COMPAT_LARGE;
|
|
22
|
-
if (Array.isArray(compat))
|
|
23
|
-
return compat;
|
|
24
|
-
switch (compat) {
|
|
25
|
-
case 'fitToContents':
|
|
26
|
-
return SHEET_FIT_TO_CONTENTS;
|
|
27
|
-
case 'large':
|
|
28
|
-
return SHEET_COMPAT_LARGE;
|
|
29
|
-
case 'medium':
|
|
30
|
-
return SHEET_COMPAT_MEDIUM;
|
|
31
|
-
case 'all':
|
|
32
|
-
return SHEET_COMPAT_ALL;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
function resolveSheetLargestUndimmedDetent(compat, lastDetentIndex) {
|
|
36
|
-
if (typeof compat === 'number')
|
|
37
|
-
return compat;
|
|
38
|
-
switch (compat) {
|
|
39
|
-
case 'last':
|
|
40
|
-
return lastDetentIndex;
|
|
41
|
-
case 'large':
|
|
42
|
-
return 1;
|
|
43
|
-
case 'medium':
|
|
44
|
-
return 0;
|
|
45
|
-
case 'none':
|
|
46
|
-
case 'all':
|
|
47
|
-
case undefined:
|
|
48
|
-
return SHEET_DIMMED_ALWAYS;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
function resolveSheetInitialDetent(compat, lastDetentIndex) {
|
|
52
|
-
if (compat === 'last')
|
|
53
|
-
return lastDetentIndex;
|
|
54
|
-
if (compat === undefined)
|
|
55
|
-
return 0;
|
|
56
|
-
return compat;
|
|
57
|
-
}
|
|
58
|
-
function toOptionalBooleanNativeProp(value) {
|
|
59
|
-
if (value === undefined)
|
|
60
|
-
return 'undefined';
|
|
61
|
-
return value ? 'true' : 'false';
|
|
62
|
-
}
|
|
63
|
-
export function resolveHeaderConfigView(options, platform, passthrough = {}) {
|
|
64
|
-
return {
|
|
65
|
-
title: options?.title,
|
|
66
|
-
hidden: options?.headerShown === false,
|
|
67
|
-
backTitle: options?.headerBackTitle,
|
|
68
|
-
backTitleVisible: platform.defaultHeaderBackTitleVisible,
|
|
69
|
-
backButtonDisplayMode: options?.headerBackButtonDisplayMode,
|
|
70
|
-
largeTitle: options?.headerLargeTitle,
|
|
71
|
-
translucent: options?.headerTranslucent,
|
|
72
|
-
color: options?.headerTintColor,
|
|
73
|
-
titleColor: options?.headerTitleColor,
|
|
74
|
-
backgroundColor: options?.headerStyle?.backgroundColor,
|
|
75
|
-
largeTitleBackgroundColor: options?.headerLargeStyle?.backgroundColor,
|
|
76
|
-
userInterfaceStyle: options?.headerUserInterfaceStyle,
|
|
77
|
-
headerLeftBarButtonItems: prepareHeaderBarButtonItems(options?.headerLeftBarButtonItems, 'left'),
|
|
78
|
-
headerRightBarButtonItems: prepareHeaderBarButtonItems(options?.headerRightBarButtonItems, 'right'),
|
|
79
|
-
...buildHeaderBarButtonDispatch(options?.headerLeftBarButtonItems, options?.headerRightBarButtonItems),
|
|
80
|
-
passthrough,
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
export function resolveScreenView(screenId, activityState, options, passthrough = {}) {
|
|
84
|
-
const sheetAllowedDetents = resolveSheetAllowedDetents(options?.sheetAllowedDetents);
|
|
85
|
-
const lastDetentIndex = sheetAllowedDetents.length - 1;
|
|
86
|
-
return {
|
|
87
|
-
screenId,
|
|
88
|
-
activityState,
|
|
89
|
-
gestureEnabled: options?.gestureEnabled,
|
|
90
|
-
stackAnimation: options?.stackAnimation,
|
|
91
|
-
stackPresentation: options?.stackPresentation,
|
|
92
|
-
transitionDuration: options?.transitionDuration,
|
|
93
|
-
sheetAllowedDetents,
|
|
94
|
-
sheetLargestUndimmedDetent: resolveSheetLargestUndimmedDetent(options?.sheetLargestUndimmedDetentIndex, lastDetentIndex),
|
|
95
|
-
sheetInitialDetent: resolveSheetInitialDetent(options?.sheetInitialDetentIndex, lastDetentIndex),
|
|
96
|
-
sheetGrabberVisible: options?.sheetGrabberVisible,
|
|
97
|
-
sheetCornerRadius: options?.sheetCornerRadius,
|
|
98
|
-
sheetExpandsWhenScrolledToEdge: options?.sheetExpandsWhenScrolledToEdge,
|
|
99
|
-
sheetElevation: options?.sheetElevation,
|
|
100
|
-
sheetShouldOverflowTopInset: options?.sheetShouldOverflowTopInset,
|
|
101
|
-
sheetDefaultResizeAnimationEnabled: options?.sheetDefaultResizeAnimationEnabled,
|
|
102
|
-
statusBarStyle: options?.statusBarStyle,
|
|
103
|
-
statusBarHidden: options?.statusBarHidden,
|
|
104
|
-
statusBarAnimation: options?.statusBarAnimation,
|
|
105
|
-
screenOrientation: options?.screenOrientation,
|
|
106
|
-
passthrough,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
// RNSSearchBar is a standalone Fabric leaf (react-native-screens mounts it as a header-subview
|
|
110
|
-
// child in its own JS component) - resolveSearchBarView only folds the static config surface;
|
|
111
|
-
// where/how the adapter mounts the resulting leaf in the header tree is an adapter concern.
|
|
112
|
-
export function resolveSearchBarView(options, passthrough = {}) {
|
|
113
|
-
return {
|
|
114
|
-
placeholder: options?.placeholder,
|
|
115
|
-
autoCapitalize: options?.autoCapitalize,
|
|
116
|
-
placement: options?.placement,
|
|
117
|
-
hideWhenScrolling: options?.hideWhenScrolling,
|
|
118
|
-
allowToolbarIntegration: options?.allowToolbarIntegration,
|
|
119
|
-
obscureBackground: toOptionalBooleanNativeProp(options?.obscureBackground),
|
|
120
|
-
hideNavigationBar: toOptionalBooleanNativeProp(options?.hideNavigationBar),
|
|
121
|
-
cancelButtonText: options?.cancelButtonText,
|
|
122
|
-
barTintColor: options?.barTintColor,
|
|
123
|
-
tintColor: options?.tintColor,
|
|
124
|
-
textColor: options?.textColor,
|
|
125
|
-
autoFocus: options?.autoFocus,
|
|
126
|
-
disableBackButtonOverride: options?.disableBackButtonOverride,
|
|
127
|
-
inputType: options?.inputType,
|
|
128
|
-
hintTextColor: options?.hintTextColor,
|
|
129
|
-
headerIconColor: options?.headerIconColor,
|
|
130
|
-
shouldShowHintSearchIcon: options?.shouldShowHintSearchIcon,
|
|
131
|
-
passthrough,
|
|
132
|
-
};
|
|
133
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { type ISymbioteNode } from '@symbiote-native/engine';
|
|
2
|
-
export interface ISearchBarCommands {
|
|
3
|
-
focus(): void;
|
|
4
|
-
blur(): void;
|
|
5
|
-
clearText(): void;
|
|
6
|
-
setText(text: string): void;
|
|
7
|
-
cancelSearch(): void;
|
|
8
|
-
toggleCancelButton(show: boolean): void;
|
|
9
|
-
}
|
|
10
|
-
export declare function buildSearchBarHandle(getNode: () => ISymbioteNode | null): ISearchBarCommands;
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
// The imperative API react-native-screens' own SearchBarProps exposes via its `ref` field
|
|
2
|
-
// (SearchBarCommands): each method dispatches a native view command on the RNSSearchBar node
|
|
3
|
-
// (SearchBarNativeComponent's supportedCommands: blur/focus/clearText/toggleCancelButton/
|
|
4
|
-
// setText/cancelSearch). Framework-agnostic - mirrors @symbiote-native/components'
|
|
5
|
-
// buildScrollViewHandle exactly (same lazy-getter shape); the adapter supplies the node getter
|
|
6
|
-
// and its own framework-specific ref field (see react/screen.ts's IReactSearchBarOptions - the
|
|
7
|
-
// ref itself is per-adapter, same split as IPressableProps).
|
|
8
|
-
import { dispatchViewCommand, dlog } from '@symbiote-native/engine';
|
|
9
|
-
// dispatchViewCommand itself dlogs a "node not committed" skip; this null case (the ref never
|
|
10
|
-
// attached to a live RNSSearchBar at all - e.g. the header's search bar isn't mounted, or a
|
|
11
|
-
// stale handle outlived its screen) was the one unlogged gap, silently indistinguishable from
|
|
12
|
-
// "the command fired but did nothing". Investigation instrumentation (HeaderOptionsScreen
|
|
13
|
-
// unresponsive-buttons bug); kept behind DEBUG per <keep_logs_gate_behind_DEBUG>, never removed.
|
|
14
|
-
function warnIfDetached(command, node) {
|
|
15
|
-
if (node !== null)
|
|
16
|
-
return true;
|
|
17
|
-
dlog(`SearchBarCommands.${command}: skipped, node is null (ref never attached) at t=${Date.now()}`);
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
// Every command is the same 3-line dance: get the (lazily-read) node, bail with a dlog'd warning
|
|
21
|
-
// if it's detached, dispatch the native view command. Factored once so the six methods below
|
|
22
|
-
// differ only in which command name they dispatch.
|
|
23
|
-
function makeCommand(getNode, command) {
|
|
24
|
-
return (...args) => {
|
|
25
|
-
const node = getNode();
|
|
26
|
-
if (!warnIfDetached(command, node))
|
|
27
|
-
return;
|
|
28
|
-
dispatchViewCommand(node, command, args);
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
// `getNode` is a LAZY getter, read on every call - see buildScrollViewHandle's comment for why
|
|
32
|
-
// an eager capture would freeze `null`.
|
|
33
|
-
export function buildSearchBarHandle(getNode) {
|
|
34
|
-
return {
|
|
35
|
-
focus: makeCommand(getNode, 'focus'),
|
|
36
|
-
blur: makeCommand(getNode, 'blur'),
|
|
37
|
-
clearText: makeCommand(getNode, 'clearText'),
|
|
38
|
-
setText: makeCommand(getNode, 'setText'),
|
|
39
|
-
cancelSearch: makeCommand(getNode, 'cancelSearch'),
|
|
40
|
-
toggleCancelButton: makeCommand(getNode, 'toggleCancelButton'),
|
|
41
|
-
};
|
|
42
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
// Lightweight state persistence: pure serialize/deserialize for INavigatorState, the primitive
|
|
2
|
-
// @react-navigation's `initialState`/`onStateChange` persistence recipe is built on. Routes are
|
|
3
|
-
// already `{key, name, params}` - plain data, no functions/refs/class instances - so a JSON-safe
|
|
4
|
-
// passthrough is sufficient; no framework wiring lives here yet (that's an adapter-level task).
|
|
5
|
-
import { isRecord } from '../guards.js';
|
|
6
|
-
// No `'params' in value` check: a route pushed with no params serializes to `{key, name,
|
|
7
|
-
// params: undefined}`, and JSON.stringify drops undefined-valued keys - a JSON round trip of a
|
|
8
|
-
// perfectly valid route legitimately arrives here without a `params` key at all.
|
|
9
|
-
function isRoute(value) {
|
|
10
|
-
return isRecord(value) && typeof value.key === 'string' && typeof value.name === 'string';
|
|
11
|
-
}
|
|
12
|
-
function isNavigatorState(value) {
|
|
13
|
-
return isRecord(value) && Array.isArray(value.routes) && value.routes.every(isRoute);
|
|
14
|
-
}
|
|
15
|
-
export function serializeNavigatorState(state) {
|
|
16
|
-
return state;
|
|
17
|
-
}
|
|
18
|
-
export function deserializeNavigatorState(raw) {
|
|
19
|
-
if (!isNavigatorState(raw)) {
|
|
20
|
-
throw new Error('deserializeNavigatorState: persisted value is not a valid navigator state');
|
|
21
|
-
}
|
|
22
|
-
return raw;
|
|
23
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { IColorValue } from '@symbiote-native/engine';
|
|
2
|
-
import type { IViewStyle, IStyleProp } from '@symbiote-native/engine';
|
|
3
|
-
import type { IDescriptor } from '@symbiote-native/components';
|
|
4
|
-
export type ITabBarIcon = IDescriptor | string;
|
|
5
|
-
export type ITabOptions = {
|
|
6
|
-
title?: string;
|
|
7
|
-
tabBarLabel?: string;
|
|
8
|
-
tabBarIcon?: ITabBarIcon;
|
|
9
|
-
tabBarBadge?: string | number;
|
|
10
|
-
tabBarActiveTintColor?: IColorValue;
|
|
11
|
-
tabBarInactiveTintColor?: IColorValue;
|
|
12
|
-
tabBarStyle?: IStyleProp<IViewStyle>;
|
|
13
|
-
};
|