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,238 +1,260 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type ComponentPropsWithoutRef,
|
|
3
|
+
type ComponentPropsWithRef,
|
|
3
4
|
type ComponentType,
|
|
4
5
|
type ElementType,
|
|
6
|
+
forwardRef,
|
|
5
7
|
type ReactElement,
|
|
8
|
+
type Ref,
|
|
9
|
+
type RefAttributes,
|
|
6
10
|
useMemo,
|
|
7
11
|
} from "react";
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
type NativeSyntheticEvent,
|
|
12
|
-
type StyleProp,
|
|
13
|
-
View,
|
|
14
|
-
type ViewStyle,
|
|
15
|
-
} from "react-native";
|
|
16
|
-
|
|
17
|
-
import Animated, {
|
|
18
|
-
type AnimatedRef,
|
|
19
|
-
useAnimatedScrollHandler,
|
|
20
|
-
useComposedEventHandler,
|
|
21
|
-
} from "react-native-reanimated";
|
|
12
|
+
import { FlatList, type FlatListProps, type ListRenderItem, View } from "react-native";
|
|
13
|
+
|
|
14
|
+
import Animated from "react-native-reanimated";
|
|
22
15
|
import { StyleSheet } from "react-native-unistyles";
|
|
23
16
|
|
|
24
|
-
import {
|
|
17
|
+
import { resolveScreenPadding } from "#theme/screen-padding";
|
|
25
18
|
import { PortalHost } from "../portal";
|
|
26
|
-
import {
|
|
19
|
+
import { useScreenRef } from "./hooks/use-screen-ref";
|
|
20
|
+
import { useScreenScrollHandler } from "./hooks/use-screen-scroll-handler";
|
|
27
21
|
import { renderScreenPlaceholder } from "./parts/ScreenPlaceholder";
|
|
28
22
|
import { SCREEN_HEADER_PORTAL_HOST, useScreen } from "./ScreenContext";
|
|
29
|
-
import type {
|
|
30
|
-
import {
|
|
23
|
+
import type { ScreenContentPadding, ScreenScrollableProps } from "./types";
|
|
24
|
+
import { hasHorizontalPadding, hasVerticalPadding, renderListComponent } from "./utils";
|
|
31
25
|
|
|
26
|
+
/** Minimal row information supported by custom list adapters. FlatList also supplies separators. */
|
|
32
27
|
export interface ScreenListRenderItemInfo<T> {
|
|
33
28
|
item: T;
|
|
34
29
|
index: number;
|
|
35
30
|
}
|
|
31
|
+
/** Native viewability token with the item inferred from data. */
|
|
32
|
+
type NativeViewToken = Parameters<
|
|
33
|
+
NonNullable<FlatListProps<unknown>["onViewableItemsChanged"]>
|
|
34
|
+
>[0]["viewableItems"][number];
|
|
35
|
+
export type ScreenListViewToken<T> = Omit<NativeViewToken, "item"> & { item: T };
|
|
36
|
+
|
|
37
|
+
type ViewabilityCallback<T> = (info: {
|
|
38
|
+
viewableItems: ScreenListViewToken<T>[];
|
|
39
|
+
changed: ScreenListViewToken<T>[];
|
|
40
|
+
}) => void;
|
|
41
|
+
|
|
42
|
+
type ListLayoutProps = ScreenScrollableProps & {
|
|
43
|
+
/** @deprecated Use extraBottomPadding. This replaces themed bottom padding; safeArea belongs to Screen. */
|
|
44
|
+
bottomInset?: number;
|
|
45
|
+
};
|
|
36
46
|
|
|
37
|
-
|
|
47
|
+
/** Native FlatList props with item inference retained across callbacks and refs. */
|
|
48
|
+
type NativeScreenListProps<T> = ListLayoutProps &
|
|
38
49
|
Omit<
|
|
39
|
-
|
|
50
|
+
FlatListProps<T>,
|
|
51
|
+
| keyof ListLayoutProps
|
|
40
52
|
| "data"
|
|
41
53
|
| "renderItem"
|
|
42
|
-
| "
|
|
43
|
-
| "
|
|
44
|
-
| "contentContainerStyle"
|
|
45
|
-
| "onScroll"
|
|
46
|
-
| "ListHeaderComponent"
|
|
47
|
-
| "ListFooterComponent"
|
|
48
|
-
| "ListEmptyComponent"
|
|
49
|
-
| keyof ScreenScrollableProps
|
|
54
|
+
| "onViewableItemsChanged"
|
|
55
|
+
| "viewabilityConfigCallbackPairs"
|
|
50
56
|
> & {
|
|
51
|
-
/**
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
* (`data`, `renderItem`, `ListHeaderComponent`, …), e.g. `FlashList`
|
|
55
|
-
* from `@shopify/flash-list`, or a custom virtualized list.
|
|
56
|
-
*
|
|
57
|
-
* Only the default `FlatList` binds the screen's shared imperative
|
|
58
|
-
* scroll ref — a custom `as` is responsible for its own ref if it needs
|
|
59
|
-
* one, since not every list exposes a Reanimated-compatible ref (e.g.
|
|
60
|
-
* `FlashList`'s ref exposes a different, non Reanimated-compatible
|
|
61
|
-
* imperative API).
|
|
62
|
-
*/
|
|
63
|
-
as?: As;
|
|
57
|
+
/** Native FlatList is used by default. */
|
|
58
|
+
as?: typeof FlatList;
|
|
59
|
+
/** Null, undefined, and empty data use the empty slot. */
|
|
64
60
|
data?: readonly T[] | null;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
* Extra bottom padding on the list content — clearance for a tab bar or
|
|
75
|
-
* home indicator. Defaults to the `layout.screen.margin.y` token when
|
|
76
|
-
* margins are enabled, otherwise `0`.
|
|
77
|
-
*/
|
|
78
|
-
bottomInset?: number;
|
|
61
|
+
/** Render a row, including native separator helpers. */
|
|
62
|
+
renderItem: ListRenderItem<T>;
|
|
63
|
+
/** Item-typed native viewability callback. */
|
|
64
|
+
onViewableItemsChanged?: ViewabilityCallback<T> | null;
|
|
65
|
+
/** Item-typed native viewability callback/configuration pairs. */
|
|
66
|
+
viewabilityConfigCallbackPairs?: {
|
|
67
|
+
viewabilityConfig: NonNullable<FlatListProps<T>["viewabilityConfig"]>;
|
|
68
|
+
onViewableItemsChanged: ViewabilityCallback<T>;
|
|
69
|
+
}[];
|
|
79
70
|
};
|
|
80
71
|
|
|
81
|
-
/**
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
*/
|
|
103
|
-
export function ScreenList<T = unknown, As extends ElementType = typeof FlatList>({
|
|
104
|
-
as,
|
|
105
|
-
data,
|
|
106
|
-
renderItem,
|
|
107
|
-
style,
|
|
108
|
-
contentContainerStyle,
|
|
109
|
-
ListHeaderComponent,
|
|
110
|
-
ListFooterComponent,
|
|
111
|
-
ListEmptyComponent,
|
|
112
|
-
horizontal = false,
|
|
113
|
-
loading = false,
|
|
114
|
-
LoadingComponent,
|
|
115
|
-
EmptyComponent,
|
|
116
|
-
margins,
|
|
117
|
-
bottomInset,
|
|
118
|
-
onScroll,
|
|
119
|
-
...rest
|
|
120
|
-
}: ScreenListProps<T, As>) {
|
|
121
|
-
const isDefaultFlatList = as === undefined;
|
|
122
|
-
const Component = (as ?? FlatList) as ComponentType<Record<string, unknown>>;
|
|
72
|
+
/** Props an adapter must accept and forward to its scrollable list implementation. */
|
|
73
|
+
export type ScreenListAdapterProps<T> = Pick<
|
|
74
|
+
FlatListProps<T>,
|
|
75
|
+
| "style"
|
|
76
|
+
| "contentContainerStyle"
|
|
77
|
+
| "onScroll"
|
|
78
|
+
| "ListHeaderComponent"
|
|
79
|
+
| "ListFooterComponent"
|
|
80
|
+
| "ListEmptyComponent"
|
|
81
|
+
| "horizontal"
|
|
82
|
+
| "scrollEventThrottle"
|
|
83
|
+
| "contentInsetAdjustmentBehavior"
|
|
84
|
+
| "automaticallyAdjustContentInsets"
|
|
85
|
+
| "automaticallyAdjustsScrollIndicatorInsets"
|
|
86
|
+
| "showsVerticalScrollIndicator"
|
|
87
|
+
| "snapToOffsets"
|
|
88
|
+
> & {
|
|
89
|
+
data?: readonly T[] | null;
|
|
90
|
+
renderItem: (info: ScreenListRenderItemInfo<T>) => ReactElement | null;
|
|
91
|
+
keyExtractor?: (item: T, index: number) => string;
|
|
92
|
+
};
|
|
123
93
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
94
|
+
type AdapterKeys =
|
|
95
|
+
| "data"
|
|
96
|
+
| "renderItem"
|
|
97
|
+
| "onScroll"
|
|
98
|
+
| "contentContainerStyle"
|
|
99
|
+
| "ListHeaderComponent"
|
|
100
|
+
| "ListFooterComponent"
|
|
101
|
+
| "ListEmptyComponent";
|
|
102
|
+
|
|
103
|
+
/** Custom lists must accept the adapter contract and forward a ref for Reanimated. */
|
|
104
|
+
export type ScreenCustomListProps<T, As extends ElementType> = ListLayoutProps &
|
|
105
|
+
ScreenListAdapterProps<T> &
|
|
106
|
+
Omit<ComponentPropsWithoutRef<As>, keyof ListLayoutProps | keyof ScreenListAdapterProps<T>> & {
|
|
107
|
+
as: As &
|
|
108
|
+
(As extends typeof FlatList
|
|
109
|
+
? never
|
|
110
|
+
: AdapterKeys extends keyof ComponentPropsWithoutRef<As>
|
|
111
|
+
? readonly T[] extends NonNullable<ComponentPropsWithoutRef<As>["data"]>
|
|
112
|
+
? "ref" extends keyof ComponentPropsWithRef<As>
|
|
113
|
+
? unknown
|
|
114
|
+
: never
|
|
115
|
+
: never
|
|
116
|
+
: never);
|
|
117
|
+
ref?: ComponentPropsWithRef<As>["ref"];
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/** Screen list props, optionally parameterized by a custom adapter component. */
|
|
121
|
+
export type ScreenListProps<
|
|
122
|
+
T = unknown,
|
|
123
|
+
As extends ElementType = typeof FlatList,
|
|
124
|
+
> = As extends typeof FlatList ? NativeScreenListProps<T> : ScreenCustomListProps<T, As>;
|
|
129
125
|
|
|
126
|
+
interface ScreenListComponent {
|
|
127
|
+
<T>(props: ScreenListProps<T> & RefAttributes<FlatList<T>>): ReactElement | null;
|
|
128
|
+
<T, As extends ElementType>(props: ScreenCustomListProps<T, As>): ReactElement | null;
|
|
129
|
+
displayName?: string;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
type ImplementationProps = Omit<ScreenListProps<unknown>, "as" | "renderItem"> & {
|
|
133
|
+
as?: ElementType;
|
|
134
|
+
renderItem: (info: never) => ReactElement | null;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const ScreenListBase = forwardRef(function ScreenList(
|
|
138
|
+
{
|
|
139
|
+
as,
|
|
140
|
+
data,
|
|
141
|
+
renderItem,
|
|
142
|
+
style,
|
|
143
|
+
contentContainerStyle,
|
|
144
|
+
ListHeaderComponent,
|
|
145
|
+
ListFooterComponent,
|
|
146
|
+
ListEmptyComponent,
|
|
147
|
+
horizontal = false,
|
|
148
|
+
isLoading,
|
|
149
|
+
loading = false,
|
|
150
|
+
loadingContent,
|
|
151
|
+
LoadingComponent,
|
|
152
|
+
emptyContent,
|
|
153
|
+
EmptyComponent,
|
|
154
|
+
contentPadding,
|
|
155
|
+
margins,
|
|
156
|
+
bottomInset,
|
|
157
|
+
extraBottomPadding = 0,
|
|
158
|
+
scrollHandler: externalScrollHandler,
|
|
159
|
+
onScroll,
|
|
160
|
+
...rest
|
|
161
|
+
}: ImplementationProps,
|
|
162
|
+
ref: Ref<unknown>
|
|
163
|
+
) {
|
|
164
|
+
const isDefaultFlatList = as === undefined || as === FlatList;
|
|
165
|
+
const Component = (as ?? FlatList) as ComponentType<Record<string, unknown>>;
|
|
166
|
+
// Stable wrappers preserve the native list and its scroll position across renders.
|
|
167
|
+
const AnimatedComponent = useMemo(() => Animated.createAnimatedComponent(Component), [Component]);
|
|
130
168
|
const {
|
|
131
169
|
background,
|
|
132
170
|
scrollRef,
|
|
133
171
|
scrollHandler,
|
|
134
172
|
headerSnapOffsets,
|
|
135
|
-
|
|
173
|
+
contentPadding: screenPadding,
|
|
136
174
|
hasHeader,
|
|
137
175
|
} = useScreen();
|
|
138
|
-
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
// list, so the header portal, scroll binding and snap offsets all stay put.
|
|
142
|
-
// While loading the list is fed an empty `data` so that slot is the one that
|
|
143
|
-
// renders.
|
|
176
|
+
const mergedRef = useScreenRef(isDefaultFlatList ? scrollRef : undefined, ref);
|
|
177
|
+
const resolvedPadding = contentPadding ?? margins ?? screenPadding;
|
|
178
|
+
const resolvedLoading = isLoading ?? loading;
|
|
144
179
|
const placeholder = renderScreenPlaceholder({
|
|
145
|
-
|
|
146
|
-
LoadingComponent,
|
|
147
|
-
EmptyComponent,
|
|
180
|
+
isLoading: resolvedLoading,
|
|
181
|
+
loadingContent: loadingContent !== undefined ? loadingContent : (LoadingComponent ?? undefined),
|
|
182
|
+
emptyContent: emptyContent !== undefined ? emptyContent : EmptyComponent,
|
|
148
183
|
isEmpty: !data || data.length === 0,
|
|
149
184
|
});
|
|
150
|
-
|
|
151
|
-
const
|
|
152
|
-
(event) => {
|
|
153
|
-
if (onScroll) onScroll(event as unknown as NativeSyntheticEvent<NativeScrollEvent>);
|
|
154
|
-
},
|
|
155
|
-
[onScroll]
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
const composedHandler = useComposedEventHandler([scrollHandler, jsScrollHandler]);
|
|
159
|
-
|
|
160
|
-
// A caller naming its own `bottomInset` has taken the bottom over entirely,
|
|
161
|
-
// and a horizontal list has no bottom edge to clear.
|
|
162
|
-
const needsBottomSafeArea = bottomInset === undefined && !horizontal;
|
|
163
|
-
|
|
164
|
-
const footerComponent = (
|
|
165
|
-
<>
|
|
166
|
-
{renderListHeader(ListFooterComponent)}
|
|
167
|
-
{needsBottomSafeArea ? <BottomSafeArea /> : null}
|
|
168
|
-
</>
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
const headerComponent = (
|
|
185
|
+
const composedScrollHandler = useScreenScrollHandler(scrollHandler, onScroll, externalScrollHandler);
|
|
186
|
+
const header = (
|
|
172
187
|
<>
|
|
173
|
-
{
|
|
174
|
-
content padding for the portaled header (`LargeTitlePortalContent`
|
|
175
|
-
etc. manage their own horizontal padding) — a caller's own
|
|
176
|
-
`ListHeaderComponent` has no such self-padding, so it stays outside
|
|
177
|
-
this wrapper and gets the list's normal item padding instead. */}
|
|
178
|
-
<View style={styles.headerWrapper(resolvedMargins)}>
|
|
188
|
+
<View style={styles.headerWrapper(resolvedPadding)}>
|
|
179
189
|
<PortalHost name={SCREEN_HEADER_PORTAL_HOST} />
|
|
180
190
|
</View>
|
|
181
|
-
{
|
|
191
|
+
{renderListComponent(ListHeaderComponent)}
|
|
182
192
|
</>
|
|
183
193
|
);
|
|
184
194
|
|
|
185
195
|
return (
|
|
186
196
|
<AnimatedComponent
|
|
187
|
-
ref={
|
|
188
|
-
data={
|
|
197
|
+
ref={mergedRef}
|
|
198
|
+
data={resolvedLoading ? [] : data}
|
|
189
199
|
renderItem={renderItem}
|
|
190
200
|
style={[{ backgroundColor: background }, style]}
|
|
191
201
|
horizontal={horizontal}
|
|
192
|
-
contentInsetAdjustmentBehavior=
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
202
|
+
contentInsetAdjustmentBehavior="never"
|
|
203
|
+
automaticallyAdjustContentInsets={false}
|
|
204
|
+
automaticallyAdjustsScrollIndicatorInsets={false}
|
|
205
|
+
contentContainerStyle={[
|
|
206
|
+
styles.content(resolvedPadding, hasHeader, bottomInset, extraBottomPadding),
|
|
207
|
+
contentContainerStyle,
|
|
208
|
+
]}
|
|
209
|
+
ListHeaderComponent={header}
|
|
210
|
+
ListFooterComponent={ListFooterComponent}
|
|
196
211
|
ListEmptyComponent={placeholder ?? ListEmptyComponent}
|
|
197
212
|
showsVerticalScrollIndicator={false}
|
|
198
213
|
scrollEventThrottle={16}
|
|
199
214
|
snapToOffsets={headerSnapOffsets}
|
|
200
215
|
{...rest}
|
|
201
|
-
onScroll={
|
|
216
|
+
onScroll={composedScrollHandler}
|
|
202
217
|
/>
|
|
203
218
|
);
|
|
204
|
-
}
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Virtualized Screen content. FlatList is the default and its native ref and
|
|
223
|
+
* item callbacks retain their types. Native refreshing keeps rows visible;
|
|
224
|
+
* isLoading replaces them with loadingContent (a Spinner by default).
|
|
225
|
+
*
|
|
226
|
+
* Custom `as` components must implement ScreenListAdapterProps, forward their
|
|
227
|
+
* ref, and forward the supplied scroll events, styles, and header/footer slots.
|
|
228
|
+
* Their native ref is forwarded to callers; useScreen().scrollRef is FlatList-only here.
|
|
229
|
+
* JS onScroll receives nativeEvent data without SyntheticEvent methods.
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* ```tsx
|
|
233
|
+
* <Screen safeArea="auto">
|
|
234
|
+
* <Screen.List data={items} renderItem={({ item }) => <Row item={item} />}
|
|
235
|
+
* isLoading={isLoading} refreshing={isRefreshing} onRefresh={refresh} />
|
|
236
|
+
* </Screen>
|
|
237
|
+
* ```
|
|
238
|
+
*/
|
|
239
|
+
export const ScreenList = ScreenListBase as ScreenListComponent;
|
|
205
240
|
ScreenList.displayName = "Screen.List";
|
|
206
241
|
|
|
207
|
-
// `resolveScreenMargin` is called *inside* each dynamic function below, not
|
|
208
|
-
// hoisted to the factory's top level — the Babel plugin only attributes a
|
|
209
|
-
// runtime dependency (here, breakpoint) to a style key when the `rt`/
|
|
210
|
-
// `runtime` read it derives from sits inside that key's own value. Hoisting
|
|
211
|
-
// it would silently drop the dependency, so the margin would freeze at
|
|
212
|
-
// whatever breakpoint was active on mount and never update on rotation.
|
|
213
242
|
const styles = StyleSheet.create((theme, runtime) => ({
|
|
214
|
-
content: (
|
|
215
|
-
|
|
243
|
+
content: (
|
|
244
|
+
padding: ScreenContentPadding,
|
|
245
|
+
hasHeader: boolean,
|
|
246
|
+
bottomInset: number | undefined,
|
|
247
|
+
extraBottomPadding: number
|
|
248
|
+
) => {
|
|
249
|
+
const { x, y } = resolveScreenPadding(theme, runtime.breakpoint);
|
|
216
250
|
return {
|
|
217
251
|
flexGrow: 1,
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
// that means `disableAutomaticContentInsets` on the tab, or the two
|
|
222
|
-
// insets are counted twice.
|
|
223
|
-
paddingTop:
|
|
224
|
-
(hasHeader ? theme.layout.header.height + runtime.insets.top : 0) +
|
|
225
|
-
(hasYMargin(margins) ? marginY : 0),
|
|
226
|
-
paddingHorizontal: hasXMargin(margins) ? marginX : 0,
|
|
227
|
-
// The safe area is `BottomSafeArea`'s job; counting it here as well
|
|
228
|
-
// would leave a gap the height of the gesture bar.
|
|
229
|
-
paddingBottom: bottomInset ?? (hasYMargin(margins) ? marginY : 0),
|
|
230
|
-
};
|
|
231
|
-
},
|
|
232
|
-
headerWrapper: (margins: ScreenMargins) => {
|
|
233
|
-
const { x: marginX } = resolveScreenMargin(theme, runtime.breakpoint);
|
|
234
|
-
return {
|
|
235
|
-
marginHorizontal: hasXMargin(margins) ? -marginX : 0,
|
|
252
|
+
paddingTop: (hasHeader ? theme.layout.header.height : 0) + (hasVerticalPadding(padding) ? y : 0),
|
|
253
|
+
paddingHorizontal: hasHorizontalPadding(padding) ? x : 0,
|
|
254
|
+
paddingBottom: (bottomInset ?? (hasVerticalPadding(padding) ? y : 0)) + extraBottomPadding,
|
|
236
255
|
};
|
|
237
256
|
},
|
|
257
|
+
headerWrapper: (padding: ScreenContentPadding) => ({
|
|
258
|
+
marginHorizontal: hasHorizontalPadding(padding) ? -resolveScreenPadding(theme, runtime.breakpoint).x : 0,
|
|
259
|
+
}),
|
|
238
260
|
}));
|