react-native-terra-ui 0.7.2 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -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
|
@@ -1,193 +1,118 @@
|
|
|
1
|
-
import { Children, type ReactNode } from "react";
|
|
2
|
-
import { type
|
|
1
|
+
import { Children, type ComponentRef, forwardRef, type ReactNode } from "react";
|
|
2
|
+
import { type ScrollView, type ScrollViewProps, type StyleProp, View, type ViewStyle } from "react-native";
|
|
3
3
|
|
|
4
|
-
import Animated
|
|
5
|
-
type ScrollHandlerProcessed,
|
|
6
|
-
useAnimatedScrollHandler,
|
|
7
|
-
useComposedEventHandler,
|
|
8
|
-
} from "react-native-reanimated";
|
|
4
|
+
import Animated from "react-native-reanimated";
|
|
9
5
|
import { StyleSheet } from "react-native-unistyles";
|
|
10
|
-
import { scheduleOnRN } from "react-native-worklets";
|
|
11
6
|
|
|
12
|
-
import {
|
|
7
|
+
import { resolveScreenPadding } from "#theme/screen-padding";
|
|
13
8
|
import { PortalHost } from "../portal";
|
|
14
|
-
import {
|
|
9
|
+
import { useScreenRef } from "./hooks/use-screen-ref";
|
|
10
|
+
import { useScreenScrollHandler } from "./hooks/use-screen-scroll-handler";
|
|
15
11
|
import { renderScreenPlaceholder } from "./parts/ScreenPlaceholder";
|
|
16
12
|
import { SCREEN_HEADER_PORTAL_HOST, useScreen } from "./ScreenContext";
|
|
17
|
-
import type {
|
|
18
|
-
import {
|
|
13
|
+
import type { ScreenContentPadding, ScreenScrollableProps } from "./types";
|
|
14
|
+
import { hasHorizontalPadding, hasVerticalPadding } from "./utils";
|
|
19
15
|
|
|
16
|
+
/** Native ScrollView props plus Screen layout, placeholders, and worklet support. */
|
|
20
17
|
export interface ScreenScrollViewProps extends Omit<ScrollViewProps, "horizontal">, ScreenScrollableProps {
|
|
18
|
+
/** Content replaced while loading or empty. */
|
|
21
19
|
children?: ReactNode;
|
|
22
|
-
/**
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
* `onScroll` instead; it doesn't require writing a worklet.
|
|
27
|
-
*/
|
|
28
|
-
scrollHandler?: ScrollHandlerProcessed<Record<string, unknown>>;
|
|
20
|
+
/** Style the inner content View, excluding the header portal. */
|
|
21
|
+
contentStyle?: StyleProp<ViewStyle>;
|
|
22
|
+
/** Override empty-child detection, for example when a child component renders null. */
|
|
23
|
+
isEmpty?: boolean;
|
|
29
24
|
}
|
|
30
25
|
|
|
31
26
|
/**
|
|
32
|
-
* Scrollable content
|
|
33
|
-
*
|
|
34
|
-
* header content is injected), and applies token-driven content padding.
|
|
27
|
+
* Scrollable content with a header portal and shared scroll tracking.
|
|
28
|
+
* Must be inside Screen. The ref exposes native ScrollView methods.
|
|
35
29
|
*
|
|
36
|
-
*
|
|
37
|
-
* `
|
|
38
|
-
*
|
|
39
|
-
* thread alongside the screen's own handler, with no JS-thread round trip.
|
|
30
|
+
* `contentContainerStyle` styles the native container, including header content.
|
|
31
|
+
* Use `contentStyle` for the inner content only. `onScroll` receives nativeEvent
|
|
32
|
+
* data on JS, without SyntheticEvent methods; `scrollHandler` runs on the UI thread.
|
|
40
33
|
*
|
|
41
34
|
* @example
|
|
42
35
|
* ```tsx
|
|
43
|
-
* <Screen
|
|
44
|
-
* <Text>
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* @example Loading placeholder instead of a per-screen spinner branch
|
|
49
|
-
* ```tsx
|
|
50
|
-
* const { data, loading } = useQuery();
|
|
51
|
-
*
|
|
52
|
-
* <Screen.ScrollView loading={loading}>
|
|
53
|
-
* <Text>{data?.title}</Text>
|
|
54
|
-
* </Screen.ScrollView>
|
|
55
|
-
* ```
|
|
56
|
-
*
|
|
57
|
-
* @example Empty placeholder when there is nothing to render
|
|
58
|
-
* ```tsx
|
|
59
|
-
* <Screen.ScrollView EmptyComponent={<EmptyState icon="status.info" title="Nothing yet" fill />}>
|
|
60
|
-
* {items.map((item) => <Row key={item.id} item={item} />)}
|
|
61
|
-
* </Screen.ScrollView>
|
|
62
|
-
* ```
|
|
63
|
-
*
|
|
64
|
-
* @example Simple JS-side scroll callback
|
|
65
|
-
* ```tsx
|
|
66
|
-
* <Screen.ScrollView onScroll={(e) => console.log(e.nativeEvent.contentOffset.y)}>
|
|
67
|
-
* <Text>Scrollable content</Text>
|
|
68
|
-
* </Screen.ScrollView>
|
|
69
|
-
* ```
|
|
70
|
-
*
|
|
71
|
-
* @example Custom scroll-driven animation
|
|
72
|
-
* ```tsx
|
|
73
|
-
* const headerOpacity = useSharedValue(1);
|
|
74
|
-
* const scrollHandler = useAnimatedScrollHandler({
|
|
75
|
-
* onScroll: (event) => {
|
|
76
|
-
* headerOpacity.value = interpolate(event.contentOffset.y, [0, 100], [1, 0]);
|
|
77
|
-
* // Need a JS-side side effect too? Call scheduleOnRN(fn, ...args) here.
|
|
78
|
-
* },
|
|
79
|
-
* });
|
|
80
|
-
*
|
|
81
|
-
* <Screen.ScrollView scrollHandler={scrollHandler}>
|
|
82
|
-
* <Text>Scrollable content</Text>
|
|
83
|
-
* </Screen.ScrollView>
|
|
36
|
+
* <Screen safeArea="auto" contentPadding="x">
|
|
37
|
+
* <Screen.ScrollView isLoading={isLoading} emptyContent={<Text>Nothing yet</Text>}>
|
|
38
|
+
* {items.map(item => <Row key={item.id} item={item} />)}
|
|
39
|
+
* </Screen.ScrollView>
|
|
40
|
+
* </Screen>
|
|
84
41
|
* ```
|
|
85
42
|
*/
|
|
86
|
-
export
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const resolvedMargins = margins ?? screenMargins;
|
|
108
|
-
// `toArray` drops the nullish/boolean children a conditional render leaves
|
|
109
|
-
// behind, so `{items.map(...)}` over an empty array counts as empty.
|
|
110
|
-
const placeholder = renderScreenPlaceholder({
|
|
111
|
-
loading,
|
|
112
|
-
LoadingComponent,
|
|
113
|
-
EmptyComponent,
|
|
114
|
-
isEmpty: Children.toArray(children).length === 0,
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
const jsScrollHandler = useAnimatedScrollHandler({
|
|
118
|
-
onScroll: (event) => {
|
|
119
|
-
if (onScrollProp) {
|
|
120
|
-
scheduleOnRN(onScrollProp, {
|
|
121
|
-
nativeEvent: event,
|
|
122
|
-
} as unknown as NativeSyntheticEvent<NativeScrollEvent>);
|
|
123
|
-
}
|
|
43
|
+
export const ScreenScrollView = forwardRef<ComponentRef<typeof ScrollView>, ScreenScrollViewProps>(
|
|
44
|
+
function ScreenScrollView(
|
|
45
|
+
{
|
|
46
|
+
children,
|
|
47
|
+
style,
|
|
48
|
+
contentContainerStyle,
|
|
49
|
+
contentStyle,
|
|
50
|
+
scrollHandler: externalScrollHandler,
|
|
51
|
+
onScroll,
|
|
52
|
+
horizontal = false,
|
|
53
|
+
isLoading,
|
|
54
|
+
loading = false,
|
|
55
|
+
loadingContent,
|
|
56
|
+
LoadingComponent,
|
|
57
|
+
emptyContent,
|
|
58
|
+
EmptyComponent,
|
|
59
|
+
contentPadding,
|
|
60
|
+
margins,
|
|
61
|
+
extraBottomPadding = 0,
|
|
62
|
+
isEmpty,
|
|
63
|
+
...rest
|
|
124
64
|
},
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
65
|
+
ref
|
|
66
|
+
) {
|
|
67
|
+
const { scrollRef, scrollHandler, contentPadding: screenPadding, hasHeader, background } = useScreen();
|
|
68
|
+
const resolvedPadding = contentPadding ?? margins ?? screenPadding;
|
|
69
|
+
const mergedRef = useScreenRef(scrollRef, ref);
|
|
70
|
+
const placeholder = renderScreenPlaceholder({
|
|
71
|
+
isLoading: isLoading ?? loading,
|
|
72
|
+
loadingContent: loadingContent !== undefined ? loadingContent : (LoadingComponent ?? undefined),
|
|
73
|
+
emptyContent: emptyContent !== undefined ? emptyContent : EmptyComponent,
|
|
74
|
+
isEmpty: isEmpty ?? Children.toArray(children).length === 0,
|
|
75
|
+
});
|
|
76
|
+
const composedScrollHandler = useScreenScrollHandler(scrollHandler, onScroll, externalScrollHandler);
|
|
134
77
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const styles = StyleSheet.create((theme, rt) => ({
|
|
164
|
-
// `resolveScreenMargin` is called *inside* each dynamic function, not
|
|
165
|
-
// hoisted above `return` — the Babel plugin only attributes a runtime
|
|
166
|
-
// dependency (here, breakpoint) to a style key when the `rt` read it
|
|
167
|
-
// derives from sits inside that key's own value. Hoisting it to the
|
|
168
|
-
// factory's top level silently drops the dependency, so the margin would
|
|
169
|
-
// freeze at whatever breakpoint was active on mount and never update on
|
|
170
|
-
// rotation.
|
|
171
|
-
scrollContent: (hasHeader: boolean, margins: ScreenMargins) => {
|
|
172
|
-
const { y: marginY } = resolveScreenMargin(theme, rt.breakpoint);
|
|
173
|
-
return {
|
|
174
|
-
flexGrow: 1,
|
|
175
|
-
// The header inset and the safe area are structural — they apply
|
|
176
|
-
// whether or not margins are on; the y margin stacks on top of them.
|
|
177
|
-
paddingTop:
|
|
178
|
-
(hasHeader ? theme.layout.header.height + rt.insets.top : 0) + (hasYMargin(margins) ? marginY : 0),
|
|
179
|
-
// The safe area is `BottomSafeArea`'s job; counting it here as well
|
|
180
|
-
// would leave a gap the height of the gesture bar.
|
|
181
|
-
paddingBottom: hasYMargin(margins) ? marginY : 0,
|
|
182
|
-
};
|
|
183
|
-
},
|
|
78
|
+
return (
|
|
79
|
+
<Animated.ScrollView
|
|
80
|
+
ref={mergedRef}
|
|
81
|
+
style={[{ backgroundColor: background }, style]}
|
|
82
|
+
horizontal={horizontal}
|
|
83
|
+
contentInsetAdjustmentBehavior="never"
|
|
84
|
+
automaticallyAdjustContentInsets={false}
|
|
85
|
+
automaticallyAdjustsScrollIndicatorInsets={false}
|
|
86
|
+
showsVerticalScrollIndicator={false}
|
|
87
|
+
scrollEventThrottle={16}
|
|
88
|
+
contentContainerStyle={[
|
|
89
|
+
styles.scrollContent(hasHeader, resolvedPadding, extraBottomPadding),
|
|
90
|
+
contentContainerStyle,
|
|
91
|
+
]}
|
|
92
|
+
{...rest}
|
|
93
|
+
onScroll={composedScrollHandler}
|
|
94
|
+
>
|
|
95
|
+
<View style={styles.headerWrapper(resolvedPadding)}>
|
|
96
|
+
<PortalHost name={SCREEN_HEADER_PORTAL_HOST} />
|
|
97
|
+
</View>
|
|
98
|
+
<View style={[styles.content(horizontal), contentStyle]}>{placeholder ?? children}</View>
|
|
99
|
+
</Animated.ScrollView>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
);
|
|
184
103
|
|
|
185
|
-
|
|
186
|
-
|
|
104
|
+
const styles = StyleSheet.create((theme, runtime) => ({
|
|
105
|
+
scrollContent: (hasHeader: boolean, padding: ScreenContentPadding, extraBottomPadding: number) => {
|
|
106
|
+
const { x, y } = resolveScreenPadding(theme, runtime.breakpoint);
|
|
187
107
|
return {
|
|
188
108
|
flexGrow: 1,
|
|
189
|
-
|
|
190
|
-
|
|
109
|
+
paddingTop: (hasHeader ? theme.layout.header.height : 0) + (hasVerticalPadding(padding) ? y : 0),
|
|
110
|
+
paddingHorizontal: hasHorizontalPadding(padding) ? x : 0,
|
|
111
|
+
paddingBottom: (hasVerticalPadding(padding) ? y : 0) + extraBottomPadding,
|
|
191
112
|
};
|
|
192
113
|
},
|
|
114
|
+
headerWrapper: (padding: ScreenContentPadding) => ({
|
|
115
|
+
marginHorizontal: hasHorizontalPadding(padding) ? -resolveScreenPadding(theme, runtime.breakpoint).x : 0,
|
|
116
|
+
}),
|
|
117
|
+
content: (horizontal: boolean) => ({ flexGrow: 1, flexDirection: horizontal ? "row" : "column" }),
|
|
193
118
|
}));
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type Ref, useCallback } from "react";
|
|
2
|
+
|
|
3
|
+
import type { ScreenScrollRef } from "../ScreenContext";
|
|
4
|
+
|
|
5
|
+
/** Bind the animated ref and the caller's native ref to the same instance. */
|
|
6
|
+
export function useScreenRef<T>(screenRef: ScreenScrollRef | undefined, ref: Ref<T> | undefined) {
|
|
7
|
+
return useCallback(
|
|
8
|
+
(instance: T | null) => {
|
|
9
|
+
if (typeof screenRef === "function") screenRef(instance as never);
|
|
10
|
+
else if (screenRef) (screenRef as { current: unknown }).current = instance;
|
|
11
|
+
if (typeof ref === "function") {
|
|
12
|
+
const cleanup = ref(instance);
|
|
13
|
+
if (cleanup)
|
|
14
|
+
return () => {
|
|
15
|
+
if (typeof screenRef === "function") screenRef(null);
|
|
16
|
+
else if (screenRef) (screenRef as { current: unknown }).current = null;
|
|
17
|
+
cleanup();
|
|
18
|
+
};
|
|
19
|
+
} else if (ref) ref.current = instance;
|
|
20
|
+
return undefined;
|
|
21
|
+
},
|
|
22
|
+
[screenRef, ref]
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { NativeScrollEvent, NativeSyntheticEvent, ScrollViewProps } from "react-native";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
type ScrollHandlerProcessed,
|
|
5
|
+
useAnimatedScrollHandler,
|
|
6
|
+
useComposedEventHandler,
|
|
7
|
+
} from "react-native-reanimated";
|
|
8
|
+
import { scheduleOnRN } from "react-native-worklets";
|
|
9
|
+
|
|
10
|
+
/** Keeps scroll tracking on the UI thread and schedules optional JS callbacks on RN. */
|
|
11
|
+
export function useScreenScrollHandler(
|
|
12
|
+
screenScrollHandler: ScrollHandlerProcessed<Record<string, unknown>>,
|
|
13
|
+
onScroll?: ScrollViewProps["onScroll"],
|
|
14
|
+
externalScrollHandler?: ScrollHandlerProcessed<Record<string, unknown>>
|
|
15
|
+
) {
|
|
16
|
+
const jsScrollHandler = useAnimatedScrollHandler({
|
|
17
|
+
onScroll: (event) => {
|
|
18
|
+
if (onScroll) {
|
|
19
|
+
scheduleOnRN(onScroll, {
|
|
20
|
+
nativeEvent: event,
|
|
21
|
+
} as unknown as NativeSyntheticEvent<NativeScrollEvent>);
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return useComposedEventHandler([
|
|
27
|
+
screenScrollHandler,
|
|
28
|
+
externalScrollHandler ?? null,
|
|
29
|
+
onScroll ? jsScrollHandler : null,
|
|
30
|
+
]);
|
|
31
|
+
}
|
|
@@ -4,8 +4,14 @@ export type { ScreenContextValue } from "./ScreenContext";
|
|
|
4
4
|
export { useScreen } from "./ScreenContext";
|
|
5
5
|
export type { ScreenFlatListProps } from "./ScreenFlatList";
|
|
6
6
|
export { ScreenFlatList } from "./ScreenFlatList";
|
|
7
|
-
export type {
|
|
7
|
+
export type {
|
|
8
|
+
ScreenCustomListProps,
|
|
9
|
+
ScreenListAdapterProps,
|
|
10
|
+
ScreenListProps,
|
|
11
|
+
ScreenListRenderItemInfo,
|
|
12
|
+
ScreenListViewToken,
|
|
13
|
+
} from "./ScreenList";
|
|
8
14
|
export { ScreenList } from "./ScreenList";
|
|
9
15
|
export type { ScreenScrollViewProps } from "./ScreenScrollView";
|
|
10
16
|
export { ScreenScrollView } from "./ScreenScrollView";
|
|
11
|
-
export type { ScreenMargins, ScreenScrollableProps } from "./types";
|
|
17
|
+
export type { ScreenContentPadding, ScreenMargins, ScreenSafeArea, ScreenScrollableProps } from "./types";
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type PropsWithChildren, useCallback, useContext, useState } from "react";
|
|
2
|
+
import { type LayoutChangeEvent, View } from "react-native";
|
|
3
|
+
|
|
4
|
+
import Animated from "react-native-reanimated";
|
|
5
|
+
import { StyleSheet } from "react-native-unistyles";
|
|
6
|
+
|
|
7
|
+
import type { ScreenSafeAreaEdges } from "../types";
|
|
8
|
+
import { ScreenHeaderAppearanceContext } from "./ScreenHeaderAppearance";
|
|
9
|
+
import { ScreenSafeArea } from "./ScreenSafeArea";
|
|
10
|
+
|
|
11
|
+
export function ScreenFrame({ children, edges }: PropsWithChildren<{ edges: ScreenSafeAreaEdges }>) {
|
|
12
|
+
const appearance = useContext(ScreenHeaderAppearanceContext);
|
|
13
|
+
const [topInset, setTopInset] = useState(0);
|
|
14
|
+
const onLayout = useCallback((event: LayoutChangeEvent) => {
|
|
15
|
+
// This is the actual native padding, including navigator and orientation changes.
|
|
16
|
+
setTopInset(event.nativeEvent.layout.y);
|
|
17
|
+
}, []);
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<>
|
|
21
|
+
<ScreenSafeArea edges={edges}>
|
|
22
|
+
<View style={styles.content} onLayout={onLayout}>
|
|
23
|
+
{children}
|
|
24
|
+
</View>
|
|
25
|
+
</ScreenSafeArea>
|
|
26
|
+
{edges.top && appearance?.background !== undefined && (
|
|
27
|
+
<Animated.View
|
|
28
|
+
pointerEvents="none"
|
|
29
|
+
style={[
|
|
30
|
+
styles.topSafeArea(topInset, appearance.background.color),
|
|
31
|
+
appearance.background.animatedStyle,
|
|
32
|
+
]}
|
|
33
|
+
/>
|
|
34
|
+
)}
|
|
35
|
+
</>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const styles = StyleSheet.create(() => ({
|
|
40
|
+
content: { flex: 1 },
|
|
41
|
+
topSafeArea: (height: number, backgroundColor: string) => ({
|
|
42
|
+
position: "absolute",
|
|
43
|
+
top: 0,
|
|
44
|
+
left: 0,
|
|
45
|
+
right: 0,
|
|
46
|
+
height,
|
|
47
|
+
backgroundColor,
|
|
48
|
+
}),
|
|
49
|
+
}));
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
type Dispatch,
|
|
4
|
+
type PropsWithChildren,
|
|
5
|
+
type SetStateAction,
|
|
6
|
+
useContext,
|
|
7
|
+
useLayoutEffect,
|
|
8
|
+
useMemo,
|
|
9
|
+
useState,
|
|
10
|
+
} from "react";
|
|
11
|
+
|
|
12
|
+
import type { useAnimatedStyle } from "react-native-reanimated";
|
|
13
|
+
|
|
14
|
+
type HeaderOpacityStyle = ReturnType<typeof useAnimatedStyle<{ opacity: number }>>;
|
|
15
|
+
|
|
16
|
+
interface HeaderBackground {
|
|
17
|
+
color: string;
|
|
18
|
+
animatedStyle?: HeaderOpacityStyle;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface HeaderAppearance {
|
|
22
|
+
background: HeaderBackground | undefined;
|
|
23
|
+
setBackground: Dispatch<SetStateAction<HeaderBackground | undefined>>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const ScreenHeaderAppearanceContext = createContext<HeaderAppearance | null>(null);
|
|
27
|
+
const HeaderSlotContext = createContext<HeaderAppearance["setBackground"] | undefined>(undefined);
|
|
28
|
+
|
|
29
|
+
export function ScreenHeaderAppearanceProvider({ children }: PropsWithChildren) {
|
|
30
|
+
const [background, setBackground] = useState<HeaderBackground>();
|
|
31
|
+
const value = useMemo(() => ({ background, setBackground }), [background]);
|
|
32
|
+
return (
|
|
33
|
+
<ScreenHeaderAppearanceContext.Provider value={value}>{children}</ScreenHeaderAppearanceContext.Provider>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Only the designated header slot controls the screen's top safe-area color. */
|
|
38
|
+
export function ScreenHeaderAppearanceSlot({ children }: PropsWithChildren) {
|
|
39
|
+
const appearance = useContext(ScreenHeaderAppearanceContext);
|
|
40
|
+
return (
|
|
41
|
+
<HeaderSlotContext.Provider value={appearance?.setBackground}>{children}</HeaderSlotContext.Provider>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Share the overlay's animated style so safe-area fading stays on the UI thread. */
|
|
46
|
+
export function useHeaderBackground(color: string, animatedStyle?: HeaderOpacityStyle) {
|
|
47
|
+
const setBackground = useContext(HeaderSlotContext);
|
|
48
|
+
useLayoutEffect(() => {
|
|
49
|
+
setBackground?.({ color, animatedStyle });
|
|
50
|
+
return () => setBackground?.(undefined);
|
|
51
|
+
}, [color, animatedStyle, setBackground]);
|
|
52
|
+
}
|
|
@@ -7,36 +7,36 @@ import { Spinner } from "../../spinner";
|
|
|
7
7
|
import type { ScreenScrollableProps } from "../types";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Centres a
|
|
11
|
-
*
|
|
12
|
-
* hugging the top, which needs the content container to grow as well.
|
|
10
|
+
* Centres a placeholder in the available space. The parent must also grow
|
|
11
|
+
* to fill the viewport.
|
|
13
12
|
*/
|
|
14
13
|
export function ScreenPlaceholder({ children }: { children: ReactNode }) {
|
|
15
14
|
return <View style={styles.placeholder}>{children}</View>;
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
interface
|
|
19
|
-
extends Pick<ScreenScrollableProps, "
|
|
17
|
+
interface ScreenPlaceholderOptions
|
|
18
|
+
extends Pick<ScreenScrollableProps, "isLoading" | "loadingContent" | "emptyContent"> {
|
|
20
19
|
/** Whether the container has nothing to render (empty `data`, no children). */
|
|
21
20
|
isEmpty: boolean;
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* flight there is nothing to be empty about yet.
|
|
24
|
+
* Resolves the loading or empty placeholder, or null to keep the content.
|
|
25
|
+
* Loading takes precedence over the empty state.
|
|
28
26
|
*/
|
|
29
27
|
export function renderScreenPlaceholder({
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
isLoading,
|
|
29
|
+
loadingContent,
|
|
30
|
+
emptyContent,
|
|
33
31
|
isEmpty,
|
|
34
|
-
}:
|
|
35
|
-
if (
|
|
36
|
-
return
|
|
32
|
+
}: ScreenPlaceholderOptions): ReactElement | null {
|
|
33
|
+
if (isLoading) {
|
|
34
|
+
return (
|
|
35
|
+
<ScreenPlaceholder>{loadingContent === undefined ? <Spinner /> : loadingContent}</ScreenPlaceholder>
|
|
36
|
+
);
|
|
37
37
|
}
|
|
38
|
-
if (isEmpty &&
|
|
39
|
-
return <ScreenPlaceholder>{
|
|
38
|
+
if (isEmpty && emptyContent !== undefined) {
|
|
39
|
+
return <ScreenPlaceholder>{emptyContent}</ScreenPlaceholder>;
|
|
40
40
|
}
|
|
41
41
|
return null;
|
|
42
42
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ComponentType, PropsWithChildren } from "react";
|
|
2
|
+
import type { ViewProps } from "react-native";
|
|
3
|
+
|
|
4
|
+
import { StyleSheet } from "react-native-unistyles";
|
|
5
|
+
|
|
6
|
+
import type { ScreenSafeAreaEdges } from "../types";
|
|
7
|
+
|
|
8
|
+
// Keep native codegen declarations outside the library's generated public types.
|
|
9
|
+
const { SafeAreaView } = require("react-native-screens/src/components/safe-area") as {
|
|
10
|
+
SafeAreaView: ComponentType<ViewProps & { edges: ScreenSafeAreaEdges; insetType: "all" }>;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/** Android combines system and native interface insets and consumes the selected edges. */
|
|
14
|
+
export function ScreenSafeArea({ children, edges }: PropsWithChildren<{ edges: ScreenSafeAreaEdges }>) {
|
|
15
|
+
return (
|
|
16
|
+
<SafeAreaView edges={edges} insetType="all" style={styles.fill}>
|
|
17
|
+
{children}
|
|
18
|
+
</SafeAreaView>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const styles = StyleSheet.create(() => ({ fill: { flex: 1 } }));
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { PropsWithChildren } from "react";
|
|
2
|
+
|
|
3
|
+
import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context";
|
|
4
|
+
import { StyleSheet } from "react-native-unistyles";
|
|
5
|
+
|
|
6
|
+
import type { ScreenSafeAreaEdges } from "../types";
|
|
7
|
+
|
|
8
|
+
export function ScreenSafeArea({ children, edges }: PropsWithChildren<{ edges: ScreenSafeAreaEdges }>) {
|
|
9
|
+
const enabledEdges = (Object.keys(edges) as (keyof ScreenSafeAreaEdges)[]).filter((edge) => edges[edge]);
|
|
10
|
+
// A local provider measures remaining UIKit/browser insets, including native iOS bars.
|
|
11
|
+
return (
|
|
12
|
+
<SafeAreaProvider style={styles.fill}>
|
|
13
|
+
<SafeAreaView edges={enabledEdges} style={styles.fill}>
|
|
14
|
+
{children}
|
|
15
|
+
</SafeAreaView>
|
|
16
|
+
</SafeAreaProvider>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const styles = StyleSheet.create(() => ({ fill: { flex: 1 } }));
|
|
@@ -1,42 +1,39 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
* Which axes of the `layout.screen.margin` token a scroll container pads its
|
|
5
|
-
* content with.
|
|
6
|
-
*
|
|
7
|
-
* `'y'` pads the top and bottom of the content area. It stacks on top of the
|
|
8
|
-
* structural insets — the header height and the safe area — which apply
|
|
9
|
-
* whether or not margins are on.
|
|
10
|
-
*/
|
|
11
|
-
export type ScreenMargins = "all" | "x" | "y" | "none";
|
|
3
|
+
import type { ScrollHandlerProcessed } from "react-native-reanimated";
|
|
12
4
|
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
5
|
+
/** Axes that receive the theme's screen content padding. */
|
|
6
|
+
export type ScreenContentPadding = "all" | "x" | "y" | "none";
|
|
7
|
+
/** @deprecated Use ScreenContentPadding. */
|
|
8
|
+
export type ScreenMargins = ScreenContentPadding;
|
|
9
|
+
/** Edges protected by the Screen root. An empty array is equivalent to `"none"`. */
|
|
10
|
+
export type ScreenSafeArea = "auto" | "none" | readonly ("top" | "bottom" | "left" | "right")[];
|
|
11
|
+
|
|
12
|
+
/** Shared content layout and placeholders. Native props retain React Native names. */
|
|
17
13
|
export interface ScreenScrollableProps {
|
|
18
|
-
/**
|
|
14
|
+
/** Scroll horizontally. @defaultValue false */
|
|
19
15
|
horizontal?: boolean;
|
|
20
|
-
/**
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
/** Replace content with a loading placeholder; `refreshing` keeps list rows visible. */
|
|
17
|
+
isLoading?: boolean;
|
|
18
|
+
/** Loading element. Undefined uses a Spinner; null renders a blank placeholder. */
|
|
19
|
+
loadingContent?: ReactNode;
|
|
20
|
+
/** Empty-state element. Lists otherwise use their native ListEmptyComponent. */
|
|
21
|
+
emptyContent?: ReactNode;
|
|
22
|
+
/** Override the root's themed content-padding axes. */
|
|
23
|
+
contentPadding?: ScreenContentPadding;
|
|
24
|
+
/** Additional bottom padding in layout points, added to themed padding. @defaultValue 0 */
|
|
25
|
+
extraBottomPadding?: number;
|
|
26
|
+
/** UI-thread worklet composed with Screen tracking. Native onScroll runs on the JS thread. */
|
|
27
|
+
scrollHandler?: ScrollHandlerProcessed<Record<string, unknown>>;
|
|
28
|
+
/** @deprecated Use isLoading. Ignored when isLoading is supplied. */
|
|
25
29
|
loading?: boolean;
|
|
26
|
-
/**
|
|
27
|
-
* Node shown while `loading`. Defaults to a `Spinner`; it is centred in the
|
|
28
|
-
* content area either way.
|
|
29
|
-
*/
|
|
30
|
+
/** @deprecated Pass an element through loadingContent. */
|
|
30
31
|
LoadingComponent?: ReactNode;
|
|
31
|
-
/**
|
|
32
|
-
* Node shown, centred, when there is nothing to render and `loading` is
|
|
33
|
-
* false — an empty `data` array on the list containers, no children on
|
|
34
|
-
* `Screen.ScrollView`. Omit it to render nothing.
|
|
35
|
-
*/
|
|
32
|
+
/** @deprecated Pass an element through emptyContent. */
|
|
36
33
|
EmptyComponent?: ReactNode;
|
|
37
|
-
/**
|
|
38
|
-
* Which axes get `layout.screen.margin` padding. Defaults to the enclosing
|
|
39
|
-
* `Screen`'s `margins`.
|
|
40
|
-
*/
|
|
34
|
+
/** @deprecated Use contentPadding. */
|
|
41
35
|
margins?: ScreenMargins;
|
|
42
36
|
}
|
|
37
|
+
|
|
38
|
+
/** Internal edge flags shared by the platform safe-area wrappers. */
|
|
39
|
+
export type ScreenSafeAreaEdges = Record<"top" | "bottom" | "left" | "right", boolean>;
|