react-native-terra-ui 0.7.2 → 0.8.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/CHANGELOG.md +34 -0
- package/README.md +1 -1
- package/lib/module/components/avatar/Avatar.js +20 -20
- package/lib/module/components/avatar/Avatar.js.map +1 -1
- package/lib/module/components/button/Button.js +11 -11
- package/lib/module/components/button/Button.js.map +1 -1
- package/lib/module/components/chip/Chip.js +32 -32
- package/lib/module/components/chip/Chip.js.map +1 -1
- package/lib/module/components/empty-state/EmptyState.js +3 -3
- package/lib/module/components/empty-state/EmptyState.js.map +1 -1
- package/lib/module/components/header/variants/LargeTitleHeader/index.js +30 -32
- package/lib/module/components/header/variants/LargeTitleHeader/index.js.map +1 -1
- package/lib/module/components/header/variants/TitleHeader/index.js +26 -18
- package/lib/module/components/header/variants/TitleHeader/index.js.map +1 -1
- package/lib/module/components/icon/Icon.js +3 -3
- package/lib/module/components/page-indicator/hooks/use-page-indicator-colors.js +2 -2
- package/lib/module/components/screen/Screen.js +63 -34
- package/lib/module/components/screen/Screen.js.map +1 -1
- package/lib/module/components/screen/ScreenContext.js +28 -9
- package/lib/module/components/screen/ScreenContext.js.map +1 -1
- package/lib/module/components/screen/ScreenFlatList.js +4 -162
- package/lib/module/components/screen/ScreenFlatList.js.map +1 -1
- package/lib/module/components/screen/ScreenList.js +81 -97
- package/lib/module/components/screen/ScreenList.js.map +1 -1
- package/lib/module/components/screen/ScreenScrollView.js +64 -115
- package/lib/module/components/screen/ScreenScrollView.js.map +1 -1
- package/lib/module/components/screen/hooks/use-screen-ref.js +18 -0
- package/lib/module/components/screen/hooks/use-screen-ref.js.map +1 -0
- package/lib/module/components/screen/hooks/use-screen-scroll-handler.js +19 -0
- package/lib/module/components/screen/hooks/use-screen-scroll-handler.js.map +1 -0
- package/lib/module/components/screen/index.js.map +1 -1
- package/lib/module/components/screen/parts/ScreenFrame.js +47 -0
- package/lib/module/components/screen/parts/ScreenFrame.js.map +1 -0
- package/lib/module/components/screen/parts/ScreenHeaderAppearance.js +43 -0
- package/lib/module/components/screen/parts/ScreenHeaderAppearance.js.map +1 -0
- package/lib/module/components/screen/parts/ScreenPlaceholder.js +11 -13
- package/lib/module/components/screen/parts/ScreenPlaceholder.js.map +1 -1
- package/lib/module/components/screen/parts/ScreenSafeArea.android.js +27 -0
- package/lib/module/components/screen/parts/ScreenSafeArea.android.js.map +1 -0
- package/lib/module/components/screen/parts/ScreenSafeArea.js +26 -0
- package/lib/module/components/screen/parts/ScreenSafeArea.js.map +1 -0
- package/lib/module/components/screen/utils.js +18 -9
- package/lib/module/components/screen/utils.js.map +1 -1
- package/lib/module/components/spinner/Spinner.js +2 -2
- package/lib/module/components/text/Text.js +1 -1
- package/lib/module/components/toast/Toast.js +13 -13
- package/lib/module/components/toast/Toast.js.map +1 -1
- package/lib/module/components/toolbar/Toolbar.js +2 -2
- package/lib/module/context/ThemeProvider.js +22 -39
- package/lib/module/context/ThemeProvider.js.map +1 -1
- package/lib/module/context/index.js +1 -1
- package/lib/module/context/index.js.map +1 -1
- package/lib/module/theme/breakpoints.js +1 -1
- package/lib/module/theme/define-config.js +21 -0
- package/lib/module/theme/define-config.js.map +1 -0
- package/lib/module/theme/diagnostics.js +13 -0
- package/lib/module/theme/diagnostics.js.map +1 -0
- package/lib/module/theme/errors.js +15 -0
- package/lib/module/theme/errors.js.map +1 -0
- package/lib/module/theme/index.js +7 -1
- package/lib/module/theme/index.js.map +1 -1
- package/lib/module/theme/legacy-tokens.js +119 -0
- package/lib/module/theme/legacy-tokens.js.map +1 -0
- package/lib/module/theme/registry.js +122 -130
- package/lib/module/theme/registry.js.map +1 -1
- package/lib/module/theme/resolve-config.js +346 -0
- package/lib/module/theme/resolve-config.js.map +1 -0
- package/lib/module/theme/runtime.js +57 -12
- package/lib/module/theme/runtime.js.map +1 -1
- package/lib/module/theme/screen-margin.js +6 -14
- package/lib/module/theme/screen-margin.js.map +1 -1
- package/lib/module/theme/screen-padding.js +17 -0
- package/lib/module/theme/screen-padding.js.map +1 -0
- package/lib/module/theme/selection-store.js +75 -0
- package/lib/module/theme/selection-store.js.map +1 -0
- package/lib/module/theme/theme.js +81 -36
- package/lib/module/theme/theme.js.map +1 -1
- package/lib/module/theme/tokens/canonical-color-keys.js +102 -0
- package/lib/module/theme/tokens/canonical-color-keys.js.map +1 -0
- package/lib/module/theme/tokens/dark.js +72 -88
- package/lib/module/theme/tokens/dark.js.map +1 -1
- package/lib/module/theme/tokens/light.js +69 -83
- package/lib/module/theme/tokens/light.js.map +1 -1
- package/lib/module/theme/tokens/primitives.js +14 -14
- package/lib/module/theme/tokens/primitives.js.map +1 -1
- package/lib/module/theme/tokens/validate.js +238 -0
- package/lib/module/theme/tokens/validate.js.map +1 -0
- package/lib/module/theme/unistyles-adapter.js +77 -0
- package/lib/module/theme/unistyles-adapter.js.map +1 -0
- package/lib/module/utils/accent-generator.js +476 -0
- package/lib/module/utils/accent-generator.js.map +1 -0
- package/lib/module/utils/accent-utils.js +52 -35
- package/lib/module/utils/accent-utils.js.map +1 -1
- package/lib/module/utils/color-utils.js +224 -7
- package/lib/module/utils/color-utils.js.map +1 -1
- package/lib/module/utils/deep-merge.js +1 -1
- package/lib/module/utils/deep-merge.js.map +1 -1
- package/lib/module/utils/resolve-theme-color.js +2 -2
- package/lib/typescript/src/components/chip/types.d.ts +1 -1
- package/lib/typescript/src/components/empty-state/EmptyState.d.ts +1 -1
- package/lib/typescript/src/components/empty-state/EmptyState.d.ts.map +1 -1
- package/lib/typescript/src/components/header/variants/LargeTitleHeader/index.d.ts +6 -5
- package/lib/typescript/src/components/header/variants/LargeTitleHeader/index.d.ts.map +1 -1
- package/lib/typescript/src/components/header/variants/TitleHeader/index.d.ts +11 -5
- package/lib/typescript/src/components/header/variants/TitleHeader/index.d.ts.map +1 -1
- package/lib/typescript/src/components/icon/Icon.d.ts +2 -2
- package/lib/typescript/src/components/screen/Screen.d.ts +45 -16
- package/lib/typescript/src/components/screen/Screen.d.ts.map +1 -1
- package/lib/typescript/src/components/screen/ScreenContext.d.ts +42 -26
- package/lib/typescript/src/components/screen/ScreenContext.d.ts.map +1 -1
- package/lib/typescript/src/components/screen/ScreenFlatList.d.ts +5 -46
- package/lib/typescript/src/components/screen/ScreenFlatList.d.ts.map +1 -1
- package/lib/typescript/src/components/screen/ScreenList.d.ts +62 -50
- package/lib/typescript/src/components/screen/ScreenList.d.ts.map +1 -1
- package/lib/typescript/src/components/screen/ScreenScrollView.d.ts +18 -58
- package/lib/typescript/src/components/screen/ScreenScrollView.d.ts.map +1 -1
- package/lib/typescript/src/components/screen/hooks/use-screen-ref.d.ts +5 -0
- package/lib/typescript/src/components/screen/hooks/use-screen-ref.d.ts.map +1 -0
- package/lib/typescript/src/components/screen/hooks/use-screen-scroll-handler.d.ts +53 -0
- package/lib/typescript/src/components/screen/hooks/use-screen-scroll-handler.d.ts.map +1 -0
- package/lib/typescript/src/components/screen/index.d.ts +2 -2
- package/lib/typescript/src/components/screen/index.d.ts.map +1 -1
- package/lib/typescript/src/components/screen/parts/ScreenFrame.d.ts +6 -0
- package/lib/typescript/src/components/screen/parts/ScreenFrame.d.ts.map +1 -0
- package/lib/typescript/src/components/screen/parts/ScreenHeaderAppearance.d.ts +21 -0
- package/lib/typescript/src/components/screen/parts/ScreenHeaderAppearance.d.ts.map +1 -0
- package/lib/typescript/src/components/screen/parts/ScreenPlaceholder.d.ts +6 -8
- package/lib/typescript/src/components/screen/parts/ScreenPlaceholder.d.ts.map +1 -1
- package/lib/typescript/src/components/screen/parts/ScreenSafeArea.android.d.ts +7 -0
- package/lib/typescript/src/components/screen/parts/ScreenSafeArea.android.d.ts.map +1 -0
- package/lib/typescript/src/components/screen/parts/ScreenSafeArea.d.ts +6 -0
- package/lib/typescript/src/components/screen/parts/ScreenSafeArea.d.ts.map +1 -0
- package/lib/typescript/src/components/screen/types.d.ts +27 -32
- package/lib/typescript/src/components/screen/types.d.ts.map +1 -1
- package/lib/typescript/src/components/screen/utils.d.ts +9 -8
- package/lib/typescript/src/components/screen/utils.d.ts.map +1 -1
- package/lib/typescript/src/components/text/Text.d.ts +1 -1
- package/lib/typescript/src/components/text/Text.d.ts.map +1 -1
- package/lib/typescript/src/components/toolbar/Toolbar.d.ts +2 -2
- package/lib/typescript/src/context/ThemeProvider.d.ts +29 -12
- package/lib/typescript/src/context/ThemeProvider.d.ts.map +1 -1
- package/lib/typescript/src/context/index.d.ts +1 -1
- package/lib/typescript/src/context/index.d.ts.map +1 -1
- package/lib/typescript/src/theme/breakpoints.d.ts +1 -1
- package/lib/typescript/src/theme/define-config.d.ts +23 -0
- package/lib/typescript/src/theme/define-config.d.ts.map +1 -0
- package/lib/typescript/src/theme/diagnostics.d.ts +4 -0
- package/lib/typescript/src/theme/diagnostics.d.ts.map +1 -0
- package/lib/typescript/src/theme/errors.d.ts +10 -0
- package/lib/typescript/src/theme/errors.d.ts.map +1 -0
- package/lib/typescript/src/theme/index.d.ts +10 -2
- package/lib/typescript/src/theme/index.d.ts.map +1 -1
- package/lib/typescript/src/theme/legacy-tokens.d.ts +187 -0
- package/lib/typescript/src/theme/legacy-tokens.d.ts.map +1 -0
- package/lib/typescript/src/theme/registry.d.ts +12 -17
- package/lib/typescript/src/theme/registry.d.ts.map +1 -1
- package/lib/typescript/src/theme/resolve-config.d.ts +99 -0
- package/lib/typescript/src/theme/resolve-config.d.ts.map +1 -0
- package/lib/typescript/src/theme/runtime.d.ts +25 -4
- package/lib/typescript/src/theme/runtime.d.ts.map +1 -1
- package/lib/typescript/src/theme/screen-margin.d.ts +6 -14
- package/lib/typescript/src/theme/screen-margin.d.ts.map +1 -1
- package/lib/typescript/src/theme/screen-padding.d.ts +15 -0
- package/lib/typescript/src/theme/screen-padding.d.ts.map +1 -0
- package/lib/typescript/src/theme/selection-store.d.ts +41 -0
- package/lib/typescript/src/theme/selection-store.d.ts.map +1 -0
- package/lib/typescript/src/theme/theme.d.ts +54 -1
- package/lib/typescript/src/theme/theme.d.ts.map +1 -1
- package/lib/typescript/src/theme/tokens/canonical-color-keys.d.ts +95 -0
- package/lib/typescript/src/theme/tokens/canonical-color-keys.d.ts.map +1 -0
- package/lib/typescript/src/theme/tokens/dark.d.ts +56 -63
- package/lib/typescript/src/theme/tokens/dark.d.ts.map +1 -1
- package/lib/typescript/src/theme/tokens/light.d.ts +56 -71
- package/lib/typescript/src/theme/tokens/light.d.ts.map +1 -1
- package/lib/typescript/src/theme/tokens/primitives.d.ts +11 -10
- package/lib/typescript/src/theme/tokens/primitives.d.ts.map +1 -1
- package/lib/typescript/src/theme/tokens/validate.d.ts +34 -0
- package/lib/typescript/src/theme/tokens/validate.d.ts.map +1 -0
- package/lib/typescript/src/theme/types.d.ts +166 -86
- package/lib/typescript/src/theme/types.d.ts.map +1 -1
- package/lib/typescript/src/theme/unistyles-adapter.d.ts +33 -0
- package/lib/typescript/src/theme/unistyles-adapter.d.ts.map +1 -0
- package/lib/typescript/src/utils/accent-generator.d.ts +103 -0
- package/lib/typescript/src/utils/accent-generator.d.ts.map +1 -0
- package/lib/typescript/src/utils/accent-utils.d.ts +15 -2
- package/lib/typescript/src/utils/accent-utils.d.ts.map +1 -1
- package/lib/typescript/src/utils/color-utils.d.ts +59 -2
- package/lib/typescript/src/utils/color-utils.d.ts.map +1 -1
- package/lib/typescript/src/utils/deep-merge.d.ts +1 -0
- package/lib/typescript/src/utils/deep-merge.d.ts.map +1 -1
- package/lib/typescript/src/utils/resolve-theme-color.d.ts +2 -2
- package/package.json +1 -1
- package/src/components/avatar/Avatar.tsx +20 -20
- package/src/components/button/Button.tsx +11 -11
- package/src/components/chip/Chip.tsx +32 -32
- package/src/components/chip/types.ts +1 -1
- package/src/components/empty-state/EmptyState.tsx +4 -4
- package/src/components/header/variants/LargeTitleHeader/index.tsx +31 -30
- package/src/components/header/variants/TitleHeader/index.tsx +33 -22
- package/src/components/icon/Icon.tsx +4 -4
- package/src/components/page-indicator/hooks/use-page-indicator-colors.ts +2 -2
- package/src/components/screen/Screen.tsx +89 -43
- package/src/components/screen/ScreenContext.tsx +48 -28
- package/src/components/screen/ScreenFlatList.tsx +5 -191
- package/src/components/screen/ScreenList.tsx +197 -175
- package/src/components/screen/ScreenScrollView.tsx +92 -167
- package/src/components/screen/hooks/use-screen-ref.ts +24 -0
- package/src/components/screen/hooks/use-screen-scroll-handler.ts +31 -0
- package/src/components/screen/index.ts +8 -2
- package/src/components/screen/parts/ScreenFrame.tsx +49 -0
- package/src/components/screen/parts/ScreenHeaderAppearance.tsx +52 -0
- package/src/components/screen/parts/ScreenPlaceholder.tsx +16 -16
- package/src/components/screen/parts/ScreenSafeArea.android.tsx +22 -0
- package/src/components/screen/parts/ScreenSafeArea.tsx +20 -0
- package/src/components/screen/types.ts +29 -32
- package/src/components/screen/utils.ts +24 -11
- package/src/components/spinner/Spinner.tsx +2 -2
- package/src/components/text/Text.tsx +2 -2
- package/src/components/toast/Toast.tsx +13 -13
- package/src/components/toolbar/Toolbar.tsx +4 -4
- package/src/context/ThemeProvider.tsx +47 -51
- package/src/context/index.ts +1 -1
- package/src/theme/breakpoints.ts +1 -1
- package/src/theme/define-config.ts +27 -0
- package/src/theme/diagnostics.ts +11 -0
- package/src/theme/errors.ts +14 -0
- package/src/theme/index.ts +40 -1
- package/src/theme/legacy-tokens.ts +227 -0
- package/src/theme/registry.ts +119 -137
- package/src/theme/resolve-config.ts +406 -0
- package/src/theme/runtime.ts +52 -14
- package/src/theme/screen-margin.ts +6 -25
- package/src/theme/screen-padding.ts +26 -0
- package/src/theme/selection-store.ts +76 -0
- package/src/theme/theme.ts +104 -39
- package/src/theme/tokens/canonical-color-keys.ts +107 -0
- package/src/theme/tokens/dark.ts +91 -98
- package/src/theme/tokens/light.ts +88 -93
- package/src/theme/tokens/primitives.ts +14 -14
- package/src/theme/tokens/validate.ts +271 -0
- package/src/theme/types.ts +184 -95
- package/src/theme/unistyles-adapter.ts +75 -0
- package/src/utils/accent-generator.ts +530 -0
- package/src/utils/accent-utils.ts +66 -39
- package/src/utils/color-utils.ts +225 -8
- package/src/utils/deep-merge.ts +1 -1
- package/src/utils/resolve-theme-color.ts +2 -2
- package/lib/module/components/screen/parts/BottomSafeArea.js +0 -62
- package/lib/module/components/screen/parts/BottomSafeArea.js.map +0 -1
- package/lib/typescript/src/components/screen/parts/BottomSafeArea.d.ts +0 -30
- package/lib/typescript/src/components/screen/parts/BottomSafeArea.d.ts.map +0 -1
- package/src/components/screen/parts/BottomSafeArea.tsx +0 -59
|
@@ -7,6 +7,7 @@ import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
|
|
7
7
|
import { resolveThemeColor } from "#utils/resolve-theme-color";
|
|
8
8
|
import { FONT_WEIGHT_VALUE } from "#utils/typography";
|
|
9
9
|
import { Portal } from "../../../portal";
|
|
10
|
+
import { useHeaderBackground } from "../../../screen/parts/ScreenHeaderAppearance";
|
|
10
11
|
import { SCREEN_HEADER_PORTAL_HOST, useScreen } from "../../../screen/ScreenContext";
|
|
11
12
|
import { Toolbar } from "../../../toolbar";
|
|
12
13
|
import { HeaderDismissButton } from "../../header-buttons";
|
|
@@ -88,11 +89,12 @@ function LargeTitlePortalContent({
|
|
|
88
89
|
/**
|
|
89
90
|
* iOS-style collapsing large-title header. The large title is injected (via the
|
|
90
91
|
* `Screen`'s portal) into the top of the scroll content, so it scrolls away
|
|
91
|
-
* naturally; the compact
|
|
92
|
-
*
|
|
93
|
-
*
|
|
92
|
+
* naturally; the compact title cross-fades over the theme header height.
|
|
93
|
+
* The top safe area and bar overlay fade from transparent when expanded to
|
|
94
|
+
* the header background when collapsed. The large-title content stays transparent.
|
|
95
|
+
* Snapping is opt-in through the scroll container's snapToOffsets.
|
|
94
96
|
*
|
|
95
|
-
* Must be used inside a `Screen` with a `Screen.ScrollView`
|
|
97
|
+
* Must be used inside a `Screen` with a `Screen.ScrollView` or `Screen.List`.
|
|
96
98
|
*
|
|
97
99
|
* @example
|
|
98
100
|
* ```tsx
|
|
@@ -109,6 +111,8 @@ export function LargeTitleHeader({
|
|
|
109
111
|
title,
|
|
110
112
|
overline,
|
|
111
113
|
subtitle,
|
|
114
|
+
leadingActions,
|
|
115
|
+
trailingActions,
|
|
112
116
|
LeftToolbar,
|
|
113
117
|
RightToolbar,
|
|
114
118
|
dismissAction = "none",
|
|
@@ -116,15 +120,19 @@ export function LargeTitleHeader({
|
|
|
116
120
|
onDismiss,
|
|
117
121
|
titleAlignment = "center",
|
|
118
122
|
isLargeTitleHidden = false,
|
|
119
|
-
|
|
123
|
+
background,
|
|
124
|
+
bg,
|
|
120
125
|
}: LargeTitleHeaderProps) {
|
|
121
126
|
const { theme } = useUnistyles();
|
|
122
127
|
|
|
123
|
-
const
|
|
128
|
+
const { scrollY, background: screenBackground } = useScreen();
|
|
129
|
+
const colorToken = background ?? bg;
|
|
130
|
+
const bgColor =
|
|
131
|
+
(colorToken ? resolveThemeColor(colorToken, theme) : screenBackground) ?? theme.color["surface.canvas"];
|
|
132
|
+
const leadingContent = leadingActions !== undefined ? leadingActions : LeftToolbar;
|
|
133
|
+
const trailingContent = trailingActions !== undefined ? trailingActions : RightToolbar;
|
|
124
134
|
|
|
125
|
-
const
|
|
126
|
-
const gradientColor = isTransparent ? theme.color.background : bgColor;
|
|
127
|
-
const { scrollY } = useScreen();
|
|
135
|
+
const gradientColor = bgColor;
|
|
128
136
|
const isLargeTitleHiddenValue = useSharedValue(isLargeTitleHidden);
|
|
129
137
|
const headerCollapseHeight = theme.layout.header.height;
|
|
130
138
|
styles.useVariants({ titleAlignment });
|
|
@@ -143,6 +151,8 @@ export function LargeTitleHeader({
|
|
|
143
151
|
};
|
|
144
152
|
});
|
|
145
153
|
|
|
154
|
+
useHeaderBackground(bgColor, gradientOpacityStyle);
|
|
155
|
+
|
|
146
156
|
const compactTitleAnimatedStyle = useAnimatedStyle(() => {
|
|
147
157
|
if (isLargeTitleHiddenValue.value) {
|
|
148
158
|
return { opacity: 1, transform: [{ translateY: 0 }] };
|
|
@@ -174,20 +184,20 @@ export function LargeTitleHeader({
|
|
|
174
184
|
dismissAction === "back" ? (
|
|
175
185
|
<>
|
|
176
186
|
<HeaderDismissButton dismissAction={dismissAction} navigation={navigation} onDismiss={onDismiss} />
|
|
177
|
-
{
|
|
187
|
+
{leadingContent}
|
|
178
188
|
</>
|
|
179
189
|
) : (
|
|
180
|
-
|
|
190
|
+
leadingContent
|
|
181
191
|
);
|
|
182
192
|
|
|
183
193
|
const trailing =
|
|
184
194
|
dismissAction === "close" ? (
|
|
185
195
|
<>
|
|
186
|
-
{
|
|
196
|
+
{trailingContent}
|
|
187
197
|
<HeaderDismissButton dismissAction={dismissAction} navigation={navigation} onDismiss={onDismiss} />
|
|
188
198
|
</>
|
|
189
199
|
) : (
|
|
190
|
-
|
|
200
|
+
trailingContent
|
|
191
201
|
);
|
|
192
202
|
|
|
193
203
|
return (
|
|
@@ -202,7 +212,6 @@ export function LargeTitleHeader({
|
|
|
202
212
|
/>
|
|
203
213
|
</Portal>
|
|
204
214
|
)}
|
|
205
|
-
<Animated.View style={[styles.safeArea(gradientColor), gradientOpacityStyle]} />
|
|
206
215
|
<View style={styles.bar}>
|
|
207
216
|
<Animated.View style={[styles.gradient, gradientOpacityStyle]} pointerEvents="none">
|
|
208
217
|
<HeaderGradientOverlay color={gradientColor} />
|
|
@@ -222,7 +231,7 @@ export function LargeTitleHeader({
|
|
|
222
231
|
);
|
|
223
232
|
}
|
|
224
233
|
|
|
225
|
-
const styles = StyleSheet.create((theme
|
|
234
|
+
const styles = StyleSheet.create((theme) => ({
|
|
226
235
|
container: {
|
|
227
236
|
position: "absolute",
|
|
228
237
|
top: 0,
|
|
@@ -230,14 +239,7 @@ const styles = StyleSheet.create((theme, runtime) => ({
|
|
|
230
239
|
right: 0,
|
|
231
240
|
zIndex: 1000,
|
|
232
241
|
},
|
|
233
|
-
|
|
234
|
-
height: runtime.insets.top,
|
|
235
|
-
backgroundColor: bgColor,
|
|
236
|
-
}),
|
|
237
|
-
// Overhangs the bar by `HEADER_FADE_EXTENT` so the fade has room to finish
|
|
238
|
-
// below it — confined to the bar, the curve would be steep enough to read as a
|
|
239
|
-
// band. Nothing on the path clips and the overlay is `pointerEvents="none"`,
|
|
240
|
-
// so the spill costs neither layout nor touches.
|
|
242
|
+
// Let the fade extend below the bar without intercepting touches.
|
|
241
243
|
gradient: {
|
|
242
244
|
position: "absolute",
|
|
243
245
|
top: 0,
|
|
@@ -249,7 +251,7 @@ const styles = StyleSheet.create((theme, runtime) => ({
|
|
|
249
251
|
height: theme.layout.header.height,
|
|
250
252
|
flexDirection: "row",
|
|
251
253
|
alignItems: "center",
|
|
252
|
-
paddingHorizontal: theme.layout.screen.
|
|
254
|
+
paddingHorizontal: theme.layout.screen.padding.x,
|
|
253
255
|
gap: theme.spacing["3"],
|
|
254
256
|
justifyContent: "space-between",
|
|
255
257
|
},
|
|
@@ -259,16 +261,15 @@ const styles = StyleSheet.create((theme, runtime) => ({
|
|
|
259
261
|
portalContent: {
|
|
260
262
|
gap: 2,
|
|
261
263
|
minHeight: theme.layout.header.height,
|
|
262
|
-
// paddingTop: theme.spacing['1'],
|
|
263
264
|
paddingBottom: theme.spacing["3"],
|
|
264
|
-
paddingHorizontal: theme.layout.screen.
|
|
265
|
+
paddingHorizontal: theme.layout.screen.padding.x,
|
|
265
266
|
},
|
|
266
267
|
overline: {
|
|
267
268
|
fontSize: theme.typography.variants["label-sm"].fontSize,
|
|
268
269
|
lineHeight: theme.typography.variants["label-sm"].lineHeight,
|
|
269
270
|
letterSpacing: theme.typography.variants["label-sm"].letterSpacing,
|
|
270
271
|
fontWeight: FONT_WEIGHT_VALUE[theme.typography.variants["label-sm"].fontWeight],
|
|
271
|
-
color: (theme.color as unknown as Record<string, string | undefined>)["text.
|
|
272
|
+
color: (theme.color as unknown as Record<string, string | undefined>)["text.tertiary"] ?? "",
|
|
272
273
|
variants: {
|
|
273
274
|
titleAlignment: {
|
|
274
275
|
center: { textAlign: "center" },
|
|
@@ -281,7 +282,7 @@ const styles = StyleSheet.create((theme, runtime) => ({
|
|
|
281
282
|
lineHeight: theme.typography.variants["headline-lg"].lineHeight,
|
|
282
283
|
letterSpacing: theme.typography.variants["headline-lg"].letterSpacing,
|
|
283
284
|
fontWeight: FONT_WEIGHT_VALUE[theme.typography.variants["headline-lg"].fontWeight],
|
|
284
|
-
color: (theme.color as unknown as Record<string, string | undefined>)["text.
|
|
285
|
+
color: (theme.color as unknown as Record<string, string | undefined>)["text.primary"] ?? "",
|
|
285
286
|
variants: {
|
|
286
287
|
titleAlignment: {
|
|
287
288
|
center: { textAlign: "center" },
|
|
@@ -293,7 +294,7 @@ const styles = StyleSheet.create((theme, runtime) => ({
|
|
|
293
294
|
fontSize: theme.typography.variants["body-lg"].fontSize,
|
|
294
295
|
lineHeight: theme.typography.variants["body-lg"].lineHeight,
|
|
295
296
|
letterSpacing: theme.typography.variants["body-lg"].letterSpacing,
|
|
296
|
-
color: (theme.color as unknown as Record<string, string | undefined>)["text.
|
|
297
|
+
color: (theme.color as unknown as Record<string, string | undefined>)["text.tertiary"] ?? "",
|
|
297
298
|
variants: {
|
|
298
299
|
titleAlignment: {
|
|
299
300
|
center: { textAlign: "center" },
|
|
@@ -306,7 +307,7 @@ const styles = StyleSheet.create((theme, runtime) => ({
|
|
|
306
307
|
lineHeight: theme.typography.variants["title-md"].lineHeight,
|
|
307
308
|
letterSpacing: theme.typography.variants["title-md"].letterSpacing,
|
|
308
309
|
fontWeight: FONT_WEIGHT_VALUE[theme.typography.variants["title-md"].fontWeight],
|
|
309
|
-
color: (theme.color as unknown as Record<string, string | undefined>)["text.
|
|
310
|
+
color: (theme.color as unknown as Record<string, string | undefined>)["text.primary"] ?? "",
|
|
310
311
|
variants: {
|
|
311
312
|
titleAlignment: {
|
|
312
313
|
center: { textAlign: "center" },
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ReactNode, useContext } from "react";
|
|
2
2
|
import { Text, View } from "react-native";
|
|
3
3
|
|
|
4
4
|
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
|
@@ -6,6 +6,8 @@ import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
|
|
6
6
|
import type { ColorToken } from "#theme/types";
|
|
7
7
|
import { resolveThemeColor } from "#utils/resolve-theme-color";
|
|
8
8
|
import { FONT_WEIGHT_VALUE } from "#utils/typography";
|
|
9
|
+
import { useHeaderBackground } from "../../../screen/parts/ScreenHeaderAppearance";
|
|
10
|
+
import { ScreenContext } from "../../../screen/ScreenContext";
|
|
9
11
|
import { Toolbar } from "../../../toolbar";
|
|
10
12
|
import { HeaderDismissButton, type HeaderDismissProps } from "../../header-buttons";
|
|
11
13
|
import { HEADER_FADE_EXTENT, HeaderGradientOverlay } from "../../parts/HeaderGradientOverlay";
|
|
@@ -16,21 +18,27 @@ export interface TitleHeaderProps extends HeaderDismissProps {
|
|
|
16
18
|
* Leading-side actions, wrapped in a `Toolbar` row. Pass `Toolbar.Group` /
|
|
17
19
|
* `Toolbar.Button` children directly — no `Toolbar` of your own.
|
|
18
20
|
*/
|
|
21
|
+
leadingActions?: ReactNode;
|
|
22
|
+
/** @deprecated Use leadingActions. */
|
|
19
23
|
LeftToolbar?: ReactNode;
|
|
20
24
|
/**
|
|
21
25
|
* Trailing-side actions, wrapped in a `Toolbar` row. Pass `Toolbar.Group` /
|
|
22
26
|
* `Toolbar.Button` children directly — no `Toolbar` of your own.
|
|
23
27
|
*/
|
|
28
|
+
trailingActions?: ReactNode;
|
|
29
|
+
/** @deprecated Use trailingActions. */
|
|
24
30
|
RightToolbar?: ReactNode;
|
|
25
31
|
/** Title placement within the bar. Defaults to `'center'`. */
|
|
26
32
|
titleAlignment?: "center" | "left";
|
|
27
|
-
/**
|
|
33
|
+
/** Color token for the top safe area and fading bar overlay. Defaults to the Screen background. */
|
|
34
|
+
background?: ColorToken;
|
|
35
|
+
/** @deprecated Use background. */
|
|
28
36
|
bg?: ColorToken;
|
|
29
37
|
}
|
|
30
38
|
|
|
31
39
|
/**
|
|
32
40
|
* Compact title bar (leading slot · title · trailing slot) with a top safe-area
|
|
33
|
-
* inset. The inline counterpart to `Header.LargeTitle`; use it for screens that
|
|
41
|
+
* inset outside Screen. Within Screen, the root owns safe-area clearance. The inline counterpart to `Header.LargeTitle`; use it for screens that
|
|
34
42
|
* don't need a collapsing large title.
|
|
35
43
|
*
|
|
36
44
|
* @example
|
|
@@ -38,7 +46,7 @@ export interface TitleHeaderProps extends HeaderDismissProps {
|
|
|
38
46
|
* <Screen.Header>
|
|
39
47
|
* <Header.Title
|
|
40
48
|
* title="Stats"
|
|
41
|
-
*
|
|
49
|
+
* trailingActions={
|
|
42
50
|
* <Toolbar.Button icon="add" accessibilityLabel="Add" onPress={add} />
|
|
43
51
|
* }
|
|
44
52
|
* />
|
|
@@ -47,46 +55,52 @@ export interface TitleHeaderProps extends HeaderDismissProps {
|
|
|
47
55
|
*/
|
|
48
56
|
export function TitleHeader({
|
|
49
57
|
title,
|
|
58
|
+
leadingActions,
|
|
59
|
+
trailingActions,
|
|
50
60
|
LeftToolbar,
|
|
51
61
|
RightToolbar,
|
|
52
62
|
dismissAction = "none",
|
|
53
63
|
navigation,
|
|
54
64
|
onDismiss,
|
|
55
65
|
titleAlignment = "center",
|
|
56
|
-
|
|
66
|
+
background,
|
|
67
|
+
bg,
|
|
57
68
|
}: TitleHeaderProps) {
|
|
58
69
|
const { theme } = useUnistyles();
|
|
59
70
|
|
|
71
|
+
const screen = useContext(ScreenContext);
|
|
72
|
+
const colorToken = background ?? bg;
|
|
60
73
|
const bgColor =
|
|
61
|
-
resolveThemeColor(
|
|
62
|
-
|
|
63
|
-
|
|
74
|
+
(colorToken ? resolveThemeColor(colorToken, theme) : screen?.background) ?? theme.color["surface.canvas"];
|
|
75
|
+
useHeaderBackground(bgColor);
|
|
76
|
+
const leadingContent = leadingActions !== undefined ? leadingActions : LeftToolbar;
|
|
77
|
+
const trailingContent = trailingActions !== undefined ? trailingActions : RightToolbar;
|
|
64
78
|
const isTransparent = bgColor === "transparent";
|
|
65
|
-
const gradientColor =
|
|
79
|
+
const gradientColor = bgColor;
|
|
66
80
|
styles.useVariants({ titleAlignment });
|
|
67
81
|
|
|
68
82
|
const leading =
|
|
69
83
|
dismissAction === "back" ? (
|
|
70
84
|
<>
|
|
71
85
|
<HeaderDismissButton dismissAction={dismissAction} navigation={navigation} onDismiss={onDismiss} />
|
|
72
|
-
{
|
|
86
|
+
{leadingContent}
|
|
73
87
|
</>
|
|
74
88
|
) : (
|
|
75
|
-
|
|
89
|
+
leadingContent
|
|
76
90
|
);
|
|
77
91
|
|
|
78
92
|
const trailing =
|
|
79
93
|
dismissAction === "close" ? (
|
|
80
94
|
<>
|
|
81
|
-
{
|
|
95
|
+
{trailingContent}
|
|
82
96
|
<HeaderDismissButton dismissAction={dismissAction} navigation={navigation} onDismiss={onDismiss} />
|
|
83
97
|
</>
|
|
84
98
|
) : (
|
|
85
|
-
|
|
99
|
+
trailingContent
|
|
86
100
|
);
|
|
87
101
|
return (
|
|
88
102
|
<View style={styles.container}>
|
|
89
|
-
<View style={styles.safeArea(isTransparent, bgColor)} />
|
|
103
|
+
<View style={styles.safeArea(isTransparent, bgColor, screen !== null)} />
|
|
90
104
|
<View style={styles.bar}>
|
|
91
105
|
<View style={styles.gradient} pointerEvents="none">
|
|
92
106
|
<HeaderGradientOverlay color={gradientColor} />
|
|
@@ -109,14 +123,11 @@ const styles = StyleSheet.create((theme, runtime) => ({
|
|
|
109
123
|
right: 0,
|
|
110
124
|
zIndex: 1000,
|
|
111
125
|
},
|
|
112
|
-
safeArea: (isTransparent, bgColor) => ({
|
|
113
|
-
height: runtime.insets.top,
|
|
126
|
+
safeArea: (isTransparent: boolean, bgColor: string, withinScreen: boolean) => ({
|
|
127
|
+
height: withinScreen ? 0 : runtime.insets.top,
|
|
114
128
|
backgroundColor: isTransparent ? "transparent" : bgColor,
|
|
115
129
|
}),
|
|
116
|
-
//
|
|
117
|
-
// below it — confined to the bar, the curve would be steep enough to read as a
|
|
118
|
-
// band. Nothing on the path clips and the overlay is `pointerEvents="none"`,
|
|
119
|
-
// so the spill costs neither layout nor touches.
|
|
130
|
+
// Extend the fade below the bar without clipping content or intercepting touches.
|
|
120
131
|
gradient: {
|
|
121
132
|
position: "absolute",
|
|
122
133
|
top: 0,
|
|
@@ -128,7 +139,7 @@ const styles = StyleSheet.create((theme, runtime) => ({
|
|
|
128
139
|
height: theme.layout.header.height,
|
|
129
140
|
flexDirection: "row",
|
|
130
141
|
alignItems: "center",
|
|
131
|
-
paddingHorizontal: theme.layout.screen.
|
|
142
|
+
paddingHorizontal: theme.layout.screen.padding.x,
|
|
132
143
|
gap: theme.spacing["3"],
|
|
133
144
|
justifyContent: "space-between",
|
|
134
145
|
},
|
|
@@ -156,7 +167,7 @@ const styles = StyleSheet.create((theme, runtime) => ({
|
|
|
156
167
|
lineHeight: theme.typography.variants["title-md"].lineHeight,
|
|
157
168
|
letterSpacing: theme.typography.variants["title-md"].letterSpacing,
|
|
158
169
|
fontWeight: FONT_WEIGHT_VALUE[theme.typography.variants["title-md"].fontWeight],
|
|
159
|
-
color: (theme.color as unknown as Record<string, string | undefined>)["text.
|
|
170
|
+
color: (theme.color as unknown as Record<string, string | undefined>)["text.primary"] ?? "",
|
|
160
171
|
variants: {
|
|
161
172
|
titleAlignment: {
|
|
162
173
|
center: { textAlign: "center" },
|
|
@@ -13,7 +13,7 @@ export interface IconProps extends Omit<ViewProps, "children"> {
|
|
|
13
13
|
name: TerraIconName;
|
|
14
14
|
/** Icon size in density-independent pixels. Defaults to `20`. */
|
|
15
15
|
size?: number;
|
|
16
|
-
/** Theme color token or raw CSS color. Defaults to `text.
|
|
16
|
+
/** Theme color token or raw CSS color. Defaults to `text.primary`. */
|
|
17
17
|
color?: ColorToken;
|
|
18
18
|
strokeWidth?: number;
|
|
19
19
|
}
|
|
@@ -24,11 +24,11 @@ export interface IconProps extends Omit<ViewProps, "children"> {
|
|
|
24
24
|
*
|
|
25
25
|
* @example
|
|
26
26
|
* ```tsx
|
|
27
|
-
* <Icon name="navigation.close" size={24} color="text.
|
|
27
|
+
* <Icon name="navigation.close" size={24} color="text.primary" />
|
|
28
28
|
* ```
|
|
29
29
|
*/
|
|
30
30
|
export const Icon = forwardRef<ComponentRef<typeof View>, IconProps>(function Icon(
|
|
31
|
-
{ name, size = 20, color = "text.
|
|
31
|
+
{ name, size = 20, color = "text.primary", strokeWidth, style, ...rest },
|
|
32
32
|
ref
|
|
33
33
|
) {
|
|
34
34
|
const { theme } = useUnistyles();
|
|
@@ -43,7 +43,7 @@ export const Icon = forwardRef<ComponentRef<typeof View>, IconProps>(function Ic
|
|
|
43
43
|
|
|
44
44
|
const resolvedColor =
|
|
45
45
|
resolveThemeColor(color, theme) ??
|
|
46
|
-
(theme.color as unknown as Record<string, string | undefined>)["text.
|
|
46
|
+
(theme.color as unknown as Record<string, string | undefined>)["text.primary"] ??
|
|
47
47
|
"";
|
|
48
48
|
|
|
49
49
|
return (
|
|
@@ -19,7 +19,7 @@ export type PageIndicatorColorInput = {
|
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
const DEFAULT_COLOR_TOKENS: Required<PageIndicatorColorInput> = {
|
|
22
|
-
activeColor: "text.
|
|
22
|
+
activeColor: "text.primary",
|
|
23
23
|
inactiveColor: "text.disabled",
|
|
24
24
|
loadingColor: "text.disabled",
|
|
25
25
|
};
|
|
@@ -31,7 +31,7 @@ export function usePageIndicatorColors(colors: PageIndicatorColorInput = {}): Re
|
|
|
31
31
|
() => ({
|
|
32
32
|
activeColor:
|
|
33
33
|
resolveThemeColor(colors.activeColor ?? DEFAULT_COLOR_TOKENS.activeColor, theme) ??
|
|
34
|
-
(theme.color as unknown as Record<string, string | undefined>)["text.
|
|
34
|
+
(theme.color as unknown as Record<string, string | undefined>)["text.primary"] ??
|
|
35
35
|
"",
|
|
36
36
|
inactiveColor:
|
|
37
37
|
resolveThemeColor(colors.inactiveColor ?? DEFAULT_COLOR_TOKENS.inactiveColor, theme) ??
|
|
@@ -10,37 +10,40 @@ import {
|
|
|
10
10
|
type ReactNode,
|
|
11
11
|
useMemo,
|
|
12
12
|
} from "react";
|
|
13
|
-
import { View } from "react-native";
|
|
13
|
+
import { View, type ViewProps } from "react-native";
|
|
14
14
|
|
|
15
|
-
import type { ViewProps } from "react-native-svg/lib/typescript/fabric/utils";
|
|
16
15
|
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
|
17
16
|
|
|
18
17
|
import type { ColorToken } from "#theme/types";
|
|
19
18
|
import { resolveThemeColor } from "#utils/resolve-theme-color";
|
|
20
19
|
import { PortalProvider } from "../portal";
|
|
20
|
+
import { ScreenFrame } from "./parts/ScreenFrame";
|
|
21
|
+
import { ScreenHeaderAppearanceProvider, ScreenHeaderAppearanceSlot } from "./parts/ScreenHeaderAppearance";
|
|
21
22
|
import { ScreenScrollProvider } from "./ScreenContext";
|
|
22
23
|
import { ScreenFlatList } from "./ScreenFlatList";
|
|
23
24
|
import { ScreenList } from "./ScreenList";
|
|
24
25
|
import { ScreenScrollView } from "./ScreenScrollView";
|
|
25
|
-
import type { ScreenMargins } from "./types";
|
|
26
|
+
import type { ScreenContentPadding, ScreenMargins, ScreenSafeArea as ScreenSafeAreaPolicy } from "./types";
|
|
27
|
+
import { resolveSafeAreaEdges } from "./utils";
|
|
26
28
|
|
|
29
|
+
/** Props for `Screen.Header`, including the props accepted by its `as` component. */
|
|
27
30
|
export type ScreenHeaderProps<T extends ElementType = typeof Fragment> = PropsWithChildren<
|
|
28
31
|
{
|
|
29
32
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
+
* Header component or container.
|
|
34
|
+
* Additional props are forwarded to this component.
|
|
35
|
+
* @defaultValue Fragment
|
|
33
36
|
*/
|
|
34
37
|
as?: T;
|
|
35
38
|
} & Omit<ComponentPropsWithoutRef<T>, "children">
|
|
36
39
|
>;
|
|
37
40
|
|
|
38
41
|
/**
|
|
39
|
-
*
|
|
40
|
-
* `Screen` detect a header synchronously and drop the `top` safe-area edge
|
|
41
|
-
* (the header manages its own top inset).
|
|
42
|
+
* Marks a child as the screen header so scroll containers reserve the header bar height.
|
|
42
43
|
*
|
|
43
|
-
* Place
|
|
44
|
+
* Place this slot under `Screen`, optionally inside fragments. Custom wrapper
|
|
45
|
+
* components are not inspected. Use `as` to render a reusable custom header. Reserved
|
|
46
|
+
* space uses the theme's header height, not the custom header's measured height.
|
|
44
47
|
*
|
|
45
48
|
* @example
|
|
46
49
|
* ```tsx
|
|
@@ -53,77 +56,103 @@ function ScreenHeader<T extends ElementType = typeof Fragment>({
|
|
|
53
56
|
...rest
|
|
54
57
|
}: ScreenHeaderProps<T>) {
|
|
55
58
|
const Component = as ?? Fragment;
|
|
56
|
-
return
|
|
59
|
+
return (
|
|
60
|
+
<ScreenHeaderAppearanceSlot>
|
|
61
|
+
<Component {...rest}>{children}</Component>
|
|
62
|
+
</ScreenHeaderAppearanceSlot>
|
|
63
|
+
);
|
|
57
64
|
}
|
|
58
65
|
ScreenHeader.displayName = "Screen.Header";
|
|
59
66
|
|
|
60
|
-
/**
|
|
67
|
+
/** Inspect fragments, but do not execute arbitrary child components. */
|
|
61
68
|
function hasScreenHeader(children: ReactNode): boolean {
|
|
62
69
|
let found = false;
|
|
63
70
|
Children.forEach(children, (child) => {
|
|
64
71
|
if (found) return;
|
|
72
|
+
if (!isValidElement(child)) return;
|
|
73
|
+
// Fast Refresh can retain an older function identity in existing child elements.
|
|
65
74
|
if (
|
|
66
|
-
|
|
67
|
-
typeof child.type !== "string" &&
|
|
75
|
+
child.type === ScreenHeader ||
|
|
68
76
|
(child.type as { displayName?: string }).displayName === "Screen.Header"
|
|
69
77
|
)
|
|
70
78
|
found = true;
|
|
79
|
+
if (child.type === Fragment) found = hasScreenHeader((child.props as PropsWithChildren).children);
|
|
71
80
|
});
|
|
72
81
|
return found;
|
|
73
82
|
}
|
|
74
83
|
|
|
84
|
+
/** Props for the screen root. Additional View props are forwarded to the root View. */
|
|
75
85
|
export interface ScreenProps extends ViewProps {
|
|
86
|
+
/** Header, content, and overlays within the screen's scroll and portal providers. */
|
|
76
87
|
children: ReactNode;
|
|
77
|
-
/**
|
|
88
|
+
/**
|
|
89
|
+
* Background color token shared by the root and scroll containers.
|
|
90
|
+
* A root `style.backgroundColor` override does not update the shared color.
|
|
91
|
+
* @defaultValue "surface.canvas"
|
|
92
|
+
*/
|
|
78
93
|
background?: ColorToken;
|
|
79
|
-
/**
|
|
94
|
+
/** @deprecated Has no effect. Bottom safe-area clearance is detected automatically. */
|
|
80
95
|
inTabView?: boolean;
|
|
81
96
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
97
|
+
* Axes that receive `layout.screen.padding` content padding in scroll containers.
|
|
98
|
+
* Does not pad the root View. Each scroll container can override this value.
|
|
99
|
+
* @defaultValue "all"
|
|
84
100
|
*/
|
|
101
|
+
contentPadding?: ScreenContentPadding;
|
|
102
|
+
/** Native safe-area edges applied once to the root. @defaultValue "auto" */
|
|
103
|
+
safeArea?: ScreenSafeAreaPolicy;
|
|
104
|
+
/** @deprecated Use contentPadding. */
|
|
85
105
|
margins?: ScreenMargins;
|
|
86
106
|
/**
|
|
87
|
-
* @deprecated Use `
|
|
88
|
-
* `margins` is set.
|
|
107
|
+
* @deprecated Use `contentPadding`. False maps to "none".
|
|
89
108
|
*/
|
|
90
109
|
hasMargins?: boolean;
|
|
91
110
|
}
|
|
92
111
|
|
|
93
112
|
type ScreenComponent = ReturnType<typeof forwardRef<ComponentRef<typeof View>, ScreenProps>> & {
|
|
113
|
+
/** Header slot; supports direct children and fragments. */
|
|
94
114
|
Header: typeof ScreenHeader;
|
|
115
|
+
/** Scrollable content with themed padding and loading/empty placeholders. */
|
|
95
116
|
ScrollView: typeof ScreenScrollView;
|
|
96
117
|
/** @deprecated Use {@link ScreenList} (`Screen.List`) instead. */
|
|
97
118
|
FlatList: typeof ScreenFlatList;
|
|
119
|
+
/** Virtualized content using FlatList or a compatible custom list. */
|
|
98
120
|
List: typeof ScreenList;
|
|
99
121
|
};
|
|
100
122
|
|
|
101
|
-
/**
|
|
102
|
-
* Themed page container: solid themed background, safe-area handling, and a
|
|
103
|
-
* shared scroll context for headers. Pair with `Screen.ScrollView` /
|
|
104
|
-
* `Screen.List` and a `Header.LargeTitle` / `Header.Title`.
|
|
105
|
-
*
|
|
106
|
-
* @example
|
|
107
|
-
* ```tsx
|
|
108
|
-
* <Screen>
|
|
109
|
-
* <Screen.Header as={Header.LargeTitle} title="Meditate" />
|
|
110
|
-
* <Screen.ScrollView>{content}</Screen.ScrollView>
|
|
111
|
-
* </Screen>
|
|
112
|
-
* ```
|
|
113
|
-
*/
|
|
114
123
|
const ScreenBase = forwardRef<ComponentRef<typeof View>, ScreenProps>(function Screen(
|
|
115
|
-
{
|
|
116
|
-
|
|
124
|
+
{
|
|
125
|
+
children,
|
|
126
|
+
background = "surface.canvas",
|
|
127
|
+
contentPadding,
|
|
128
|
+
safeArea = "auto",
|
|
129
|
+
margins,
|
|
130
|
+
hasMargins,
|
|
131
|
+
inTabView: _inTabView,
|
|
132
|
+
style,
|
|
133
|
+
...rest
|
|
134
|
+
},
|
|
135
|
+
ref
|
|
117
136
|
) {
|
|
118
137
|
const hasHeader = useMemo(() => hasScreenHeader(children), [children]);
|
|
119
|
-
const resolvedMargins = margins ?? (hasMargins === false ? "none" : "all");
|
|
138
|
+
const resolvedMargins = contentPadding ?? margins ?? (hasMargins === false ? "none" : "all");
|
|
139
|
+
const edges = useMemo(() => resolveSafeAreaEdges(safeArea), [safeArea]);
|
|
120
140
|
const { theme } = useUnistyles();
|
|
121
|
-
const resolvedBackground = resolveThemeColor(background, theme) ?? theme.color.
|
|
141
|
+
const resolvedBackground = resolveThemeColor(background, theme) ?? theme.color["surface.canvas"];
|
|
122
142
|
|
|
123
143
|
return (
|
|
124
|
-
<View style={[styles.container, style]} {...rest}>
|
|
125
|
-
<ScreenScrollProvider
|
|
126
|
-
|
|
144
|
+
<View ref={ref} style={[styles.container(resolvedBackground), style]} {...rest}>
|
|
145
|
+
<ScreenScrollProvider
|
|
146
|
+
background={resolvedBackground}
|
|
147
|
+
contentPadding={resolvedMargins}
|
|
148
|
+
safeArea={safeArea}
|
|
149
|
+
hasHeader={hasHeader}
|
|
150
|
+
>
|
|
151
|
+
<ScreenHeaderAppearanceProvider>
|
|
152
|
+
<ScreenFrame edges={edges}>
|
|
153
|
+
<PortalProvider>{children}</PortalProvider>
|
|
154
|
+
</ScreenFrame>
|
|
155
|
+
</ScreenHeaderAppearanceProvider>
|
|
127
156
|
</ScreenScrollProvider>
|
|
128
157
|
</View>
|
|
129
158
|
);
|
|
@@ -134,10 +163,27 @@ ScreenBase.ScrollView = ScreenScrollView;
|
|
|
134
163
|
ScreenBase.FlatList = ScreenFlatList;
|
|
135
164
|
ScreenBase.List = ScreenList;
|
|
136
165
|
|
|
166
|
+
/**
|
|
167
|
+
* Themed screen root with shared scroll state and a local header portal.
|
|
168
|
+
*
|
|
169
|
+
* Pair a `Screen.Header` child with one primary `Screen.ScrollView`
|
|
170
|
+
* or `Screen.List`. The root applies safe-area clearance to all children;
|
|
171
|
+
* scroll containers add themed content padding and header clearance. The ref targets
|
|
172
|
+
* the root View, not the scroll container.
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```tsx
|
|
176
|
+
* <Screen contentPadding="x" safeArea="auto">
|
|
177
|
+
* <Screen.Header as={Header.LargeTitle} title="Meditate" />
|
|
178
|
+
* <Screen.ScrollView>{content}</Screen.ScrollView>
|
|
179
|
+
* </Screen>
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
137
182
|
export const Screen = ScreenBase;
|
|
138
183
|
|
|
139
|
-
const styles = StyleSheet.create((
|
|
140
|
-
container: {
|
|
184
|
+
const styles = StyleSheet.create(() => ({
|
|
185
|
+
container: (backgroundColor: string) => ({
|
|
141
186
|
flex: 1,
|
|
142
|
-
|
|
187
|
+
backgroundColor,
|
|
188
|
+
}),
|
|
143
189
|
}));
|