react-native-terra-ui 0.4.0 → 0.5.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 +37 -0
- package/lib/module/components/header/parts/HeaderGradientOverlay.js +1 -1
- package/lib/module/components/header/parts/HeaderGradientOverlay.js.map +1 -1
- package/lib/module/components/screen/Screen.js +3 -3
- package/lib/module/components/screen/Screen.js.map +1 -1
- package/lib/module/components/screen/ScreenFlatList.js +52 -31
- package/lib/module/components/screen/ScreenFlatList.js.map +1 -1
- package/lib/module/components/screen/ScreenList.js +160 -0
- package/lib/module/components/screen/ScreenList.js.map +1 -0
- package/lib/module/components/screen/ScreenScrollView.js +26 -14
- package/lib/module/components/screen/ScreenScrollView.js.map +1 -1
- package/lib/module/components/screen/index.js +1 -1
- package/lib/module/components/screen/index.js.map +1 -1
- package/lib/module/components/toast/Toast.js +2 -2
- package/lib/module/components/toolbar/Toolbar.js +3 -1
- package/lib/module/components/toolbar/Toolbar.js.map +1 -1
- package/lib/module/theme/tokens/primitives.js +11 -6
- package/lib/module/theme/tokens/primitives.js.map +1 -1
- package/lib/typescript/src/components/screen/Screen.d.ts +3 -2
- package/lib/typescript/src/components/screen/Screen.d.ts.map +1 -1
- package/lib/typescript/src/components/screen/ScreenContext.d.ts +2 -2
- package/lib/typescript/src/components/screen/ScreenFlatList.d.ts +11 -0
- package/lib/typescript/src/components/screen/ScreenFlatList.d.ts.map +1 -1
- package/lib/typescript/src/components/screen/ScreenList.d.ts +65 -0
- package/lib/typescript/src/components/screen/ScreenList.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/types.d.ts +2 -3
- package/lib/typescript/src/components/screen/types.d.ts.map +1 -1
- package/lib/typescript/src/theme/tokens/primitives.d.ts +5 -0
- package/lib/typescript/src/theme/tokens/primitives.d.ts.map +1 -1
- package/lib/typescript/src/theme/types.d.ts +1 -1
- package/lib/typescript/src/theme/types.d.ts.map +1 -1
- package/package.json +2 -4
- package/src/components/header/parts/HeaderGradientOverlay.tsx +1 -1
- package/src/components/screen/Screen.tsx +5 -4
- package/src/components/screen/ScreenContext.tsx +2 -2
- package/src/components/screen/ScreenFlatList.tsx +52 -30
- package/src/components/screen/ScreenList.tsx +270 -0
- package/src/components/screen/ScreenScrollView.tsx +19 -10
- package/src/components/screen/index.ts +2 -2
- package/src/components/screen/types.ts +2 -3
- package/src/components/toast/Toast.tsx +2 -2
- package/src/components/toolbar/Toolbar.tsx +2 -0
- package/src/theme/tokens/primitives.ts +12 -6
- package/src/theme/types.ts +1 -1
- package/lib/module/components/screen/ScreenFlashList.js +0 -153
- package/lib/module/components/screen/ScreenFlashList.js.map +0 -1
- package/lib/typescript/src/components/screen/ScreenFlashList.d.ts +0 -43
- package/lib/typescript/src/components/screen/ScreenFlashList.d.ts.map +0 -1
- package/src/components/screen/ScreenFlashList.tsx +0 -203
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ComponentPropsWithoutRef,
|
|
3
|
+
type ComponentType,
|
|
4
|
+
type ElementType,
|
|
5
|
+
type ReactElement,
|
|
6
|
+
useMemo,
|
|
7
|
+
} from 'react';
|
|
8
|
+
import {
|
|
9
|
+
FlatList,
|
|
10
|
+
type NativeScrollEvent,
|
|
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';
|
|
22
|
+
import { StyleSheet } from 'react-native-unistyles';
|
|
23
|
+
|
|
24
|
+
import { resolveScreenMargin } from '#theme/screen-margin';
|
|
25
|
+
import { PortalHost } from '../portal';
|
|
26
|
+
import { BottomSafeArea } from './parts/BottomSafeArea';
|
|
27
|
+
import { renderScreenPlaceholder } from './parts/ScreenPlaceholder';
|
|
28
|
+
import { SCREEN_HEADER_PORTAL_HOST, useScreen } from './ScreenContext';
|
|
29
|
+
import type { ScreenMargins, ScreenScrollableProps } from './types';
|
|
30
|
+
import {
|
|
31
|
+
hasXMargin,
|
|
32
|
+
hasYMargin,
|
|
33
|
+
type ListHeaderComponent,
|
|
34
|
+
renderListHeader,
|
|
35
|
+
} from './utils';
|
|
36
|
+
|
|
37
|
+
export interface ScreenListRenderItemInfo<T> {
|
|
38
|
+
item: T;
|
|
39
|
+
index: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type ScreenListProps<
|
|
43
|
+
T = unknown,
|
|
44
|
+
As extends ElementType = typeof FlatList,
|
|
45
|
+
> = ScreenScrollableProps &
|
|
46
|
+
Omit<
|
|
47
|
+
ComponentPropsWithoutRef<As>,
|
|
48
|
+
| 'data'
|
|
49
|
+
| 'renderItem'
|
|
50
|
+
| 'keyExtractor'
|
|
51
|
+
| 'style'
|
|
52
|
+
| 'contentContainerStyle'
|
|
53
|
+
| 'onScroll'
|
|
54
|
+
| 'ListHeaderComponent'
|
|
55
|
+
| 'ListFooterComponent'
|
|
56
|
+
| 'ListEmptyComponent'
|
|
57
|
+
| keyof ScreenScrollableProps
|
|
58
|
+
> & {
|
|
59
|
+
/**
|
|
60
|
+
* Which list component to render as. Defaults to React Native's
|
|
61
|
+
* `FlatList` — pass any list with a FlatList-shaped prop surface
|
|
62
|
+
* (`data`, `renderItem`, `ListHeaderComponent`, …), e.g. `FlashList`
|
|
63
|
+
* from `@shopify/flash-list`, or a custom virtualized list.
|
|
64
|
+
*
|
|
65
|
+
* Only the default `FlatList` binds the screen's shared imperative
|
|
66
|
+
* scroll ref — a custom `as` is responsible for its own ref if it needs
|
|
67
|
+
* one, since not every list exposes a Reanimated-compatible ref (e.g.
|
|
68
|
+
* `FlashList`'s ref exposes a different, non Reanimated-compatible
|
|
69
|
+
* imperative API).
|
|
70
|
+
*/
|
|
71
|
+
as?: As;
|
|
72
|
+
data?: readonly T[] | null;
|
|
73
|
+
renderItem?: (info: ScreenListRenderItemInfo<T>) => ReactElement | null;
|
|
74
|
+
keyExtractor?: (item: T, index: number) => string;
|
|
75
|
+
ListHeaderComponent?: ListHeaderComponent;
|
|
76
|
+
ListFooterComponent?: ListHeaderComponent;
|
|
77
|
+
ListEmptyComponent?: ListHeaderComponent;
|
|
78
|
+
style?: StyleProp<ViewStyle>;
|
|
79
|
+
contentContainerStyle?: StyleProp<ViewStyle>;
|
|
80
|
+
onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
81
|
+
/**
|
|
82
|
+
* Extra bottom padding on the list content — clearance for a tab bar or
|
|
83
|
+
* home indicator. Defaults to the `layout.screen.margin.y` token when
|
|
84
|
+
* margins are enabled, otherwise `0`.
|
|
85
|
+
*/
|
|
86
|
+
bottomInset?: number;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Polymorphic list container — renders whichever list `as` names (defaults
|
|
91
|
+
* to `FlatList`), applying the same margin/header/safe-area/scroll-handler
|
|
92
|
+
* chrome regardless of which one it is. A screen can swap list
|
|
93
|
+
* implementations by changing `as`, without relearning the surrounding API.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```tsx
|
|
97
|
+
* <Screen.List data={items} renderItem={({ item }) => <Row item={item} />} />
|
|
98
|
+
* ```
|
|
99
|
+
*
|
|
100
|
+
* @example Any other list component
|
|
101
|
+
* ```tsx
|
|
102
|
+
* import { FlashList } from '@shopify/flash-list';
|
|
103
|
+
*
|
|
104
|
+
* <Screen.List
|
|
105
|
+
* as={FlashList}
|
|
106
|
+
* data={items}
|
|
107
|
+
* renderItem={({ item }) => <Row item={item} />}
|
|
108
|
+
* />
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
export function ScreenList<
|
|
112
|
+
T = unknown,
|
|
113
|
+
As extends ElementType = typeof FlatList,
|
|
114
|
+
>({
|
|
115
|
+
as,
|
|
116
|
+
data,
|
|
117
|
+
renderItem,
|
|
118
|
+
style,
|
|
119
|
+
contentContainerStyle,
|
|
120
|
+
ListHeaderComponent,
|
|
121
|
+
ListFooterComponent,
|
|
122
|
+
ListEmptyComponent,
|
|
123
|
+
horizontal = false,
|
|
124
|
+
loading = false,
|
|
125
|
+
LoadingComponent,
|
|
126
|
+
EmptyComponent,
|
|
127
|
+
margins,
|
|
128
|
+
bottomInset,
|
|
129
|
+
onScroll,
|
|
130
|
+
...rest
|
|
131
|
+
}: ScreenListProps<T, As>) {
|
|
132
|
+
const isDefaultFlatList = as === undefined;
|
|
133
|
+
const Component = (as ?? FlatList) as ComponentType<Record<string, unknown>>;
|
|
134
|
+
|
|
135
|
+
// `Animated.createAnimatedComponent` should only run once per component,
|
|
136
|
+
// not on every render — `as` is arbitrary here (not a fixed module-scope
|
|
137
|
+
// reference like `Screen.FlatList` uses), so it's memoized on the resolved
|
|
138
|
+
// component instead of hoisted to module scope.
|
|
139
|
+
const AnimatedComponent = useMemo(
|
|
140
|
+
() => Animated.createAnimatedComponent(Component),
|
|
141
|
+
[Component]
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const {
|
|
145
|
+
background,
|
|
146
|
+
scrollRef,
|
|
147
|
+
scrollHandler,
|
|
148
|
+
headerSnapOffsets,
|
|
149
|
+
margins: screenMargins,
|
|
150
|
+
hasHeader,
|
|
151
|
+
} = useScreen();
|
|
152
|
+
|
|
153
|
+
const resolvedMargins = margins ?? screenMargins;
|
|
154
|
+
// The placeholder rides in on `ListEmptyComponent` rather than replacing the
|
|
155
|
+
// list, so the header portal, scroll binding and snap offsets all stay put.
|
|
156
|
+
// While loading the list is fed an empty `data` so that slot is the one that
|
|
157
|
+
// renders.
|
|
158
|
+
const placeholder = renderScreenPlaceholder({
|
|
159
|
+
loading,
|
|
160
|
+
LoadingComponent,
|
|
161
|
+
EmptyComponent,
|
|
162
|
+
isEmpty: !data || data.length === 0,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
const jsScrollHandler = useAnimatedScrollHandler(
|
|
166
|
+
(event) => {
|
|
167
|
+
if (onScroll)
|
|
168
|
+
onScroll(event as unknown as NativeSyntheticEvent<NativeScrollEvent>);
|
|
169
|
+
},
|
|
170
|
+
[onScroll]
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
const composedHandler = useComposedEventHandler([
|
|
174
|
+
scrollHandler,
|
|
175
|
+
jsScrollHandler,
|
|
176
|
+
]);
|
|
177
|
+
|
|
178
|
+
// A caller naming its own `bottomInset` has taken the bottom over entirely,
|
|
179
|
+
// and a horizontal list has no bottom edge to clear.
|
|
180
|
+
const needsBottomSafeArea = bottomInset === undefined && !horizontal;
|
|
181
|
+
|
|
182
|
+
const footerComponent = (
|
|
183
|
+
<>
|
|
184
|
+
{renderListHeader(ListFooterComponent)}
|
|
185
|
+
{needsBottomSafeArea ? <BottomSafeArea /> : null}
|
|
186
|
+
</>
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
const headerComponent = (
|
|
190
|
+
<>
|
|
191
|
+
{/* `headerWrapper`'s negative margin cancels the list's inherited
|
|
192
|
+
content padding for the portaled header (`LargeTitlePortalContent`
|
|
193
|
+
etc. manage their own horizontal padding) — a caller's own
|
|
194
|
+
`ListHeaderComponent` has no such self-padding, so it stays outside
|
|
195
|
+
this wrapper and gets the list's normal item padding instead. */}
|
|
196
|
+
<View style={styles.headerWrapper(resolvedMargins)}>
|
|
197
|
+
<PortalHost name={SCREEN_HEADER_PORTAL_HOST} />
|
|
198
|
+
</View>
|
|
199
|
+
{renderListHeader(ListHeaderComponent)}
|
|
200
|
+
</>
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
return (
|
|
204
|
+
<AnimatedComponent
|
|
205
|
+
ref={
|
|
206
|
+
isDefaultFlatList
|
|
207
|
+
? (scrollRef as unknown as AnimatedRef<never>)
|
|
208
|
+
: undefined
|
|
209
|
+
}
|
|
210
|
+
data={loading ? [] : data}
|
|
211
|
+
renderItem={renderItem}
|
|
212
|
+
style={[{ backgroundColor: background }, style]}
|
|
213
|
+
horizontal={horizontal}
|
|
214
|
+
contentInsetAdjustmentBehavior={hasHeader ? 'never' : undefined}
|
|
215
|
+
contentContainerStyle={[
|
|
216
|
+
styles.content(resolvedMargins, hasHeader, bottomInset),
|
|
217
|
+
contentContainerStyle,
|
|
218
|
+
]}
|
|
219
|
+
ListHeaderComponent={headerComponent}
|
|
220
|
+
ListFooterComponent={footerComponent}
|
|
221
|
+
ListEmptyComponent={placeholder ?? ListEmptyComponent}
|
|
222
|
+
showsVerticalScrollIndicator={false}
|
|
223
|
+
scrollEventThrottle={16}
|
|
224
|
+
snapToOffsets={headerSnapOffsets}
|
|
225
|
+
{...rest}
|
|
226
|
+
onScroll={composedHandler}
|
|
227
|
+
/>
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
ScreenList.displayName = 'Screen.List';
|
|
231
|
+
|
|
232
|
+
// `resolveScreenMargin` is called *inside* each dynamic function below, not
|
|
233
|
+
// hoisted to the factory's top level — the Babel plugin only attributes a
|
|
234
|
+
// runtime dependency (here, breakpoint) to a style key when the `rt`/
|
|
235
|
+
// `runtime` read it derives from sits inside that key's own value. Hoisting
|
|
236
|
+
// it would silently drop the dependency, so the margin would freeze at
|
|
237
|
+
// whatever breakpoint was active on mount and never update on rotation.
|
|
238
|
+
const styles = StyleSheet.create((theme, runtime) => ({
|
|
239
|
+
content: (
|
|
240
|
+
margins: ScreenMargins,
|
|
241
|
+
hasHeader: boolean,
|
|
242
|
+
bottomInset: number | undefined
|
|
243
|
+
) => {
|
|
244
|
+
const { x: marginX, y: marginY } = resolveScreenMargin(
|
|
245
|
+
theme,
|
|
246
|
+
runtime.breakpoint
|
|
247
|
+
);
|
|
248
|
+
return {
|
|
249
|
+
flexGrow: 1,
|
|
250
|
+
// The header is absolutely positioned, so the list reserves its full
|
|
251
|
+
// height — bar plus top safe area. This assumes the scroll view does not
|
|
252
|
+
// also get UIKit's automatic inset adjustment: on a native tab screen
|
|
253
|
+
// that means `disableAutomaticContentInsets` on the tab, or the two
|
|
254
|
+
// insets are counted twice.
|
|
255
|
+
paddingTop:
|
|
256
|
+
(hasHeader ? theme.layout.header.height + runtime.insets.top : 0) +
|
|
257
|
+
(hasYMargin(margins) ? marginY : 0),
|
|
258
|
+
paddingHorizontal: hasXMargin(margins) ? marginX : 0,
|
|
259
|
+
// The safe area is `BottomSafeArea`'s job; counting it here as well
|
|
260
|
+
// would leave a gap the height of the gesture bar.
|
|
261
|
+
paddingBottom: bottomInset ?? (hasYMargin(margins) ? marginY : 0),
|
|
262
|
+
};
|
|
263
|
+
},
|
|
264
|
+
headerWrapper: (margins: ScreenMargins) => {
|
|
265
|
+
const { x: marginX } = resolveScreenMargin(theme, runtime.breakpoint);
|
|
266
|
+
return {
|
|
267
|
+
marginHorizontal: hasXMargin(margins) ? -marginX : 0,
|
|
268
|
+
};
|
|
269
|
+
},
|
|
270
|
+
}));
|
|
@@ -172,11 +172,17 @@ export function ScreenScrollView({
|
|
|
172
172
|
);
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
const styles = StyleSheet.create((theme, rt) => {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
175
|
+
const styles = StyleSheet.create((theme, rt) => ({
|
|
176
|
+
// `resolveScreenMargin` is called *inside* each dynamic function, not
|
|
177
|
+
// hoisted above `return` — the Babel plugin only attributes a runtime
|
|
178
|
+
// dependency (here, breakpoint) to a style key when the `rt` read it
|
|
179
|
+
// derives from sits inside that key's own value. Hoisting it to the
|
|
180
|
+
// factory's top level silently drops the dependency, so the margin would
|
|
181
|
+
// freeze at whatever breakpoint was active on mount and never update on
|
|
182
|
+
// rotation.
|
|
183
|
+
scrollContent: (hasHeader: boolean, margins: ScreenMargins) => {
|
|
184
|
+
const { y: marginY } = resolveScreenMargin(theme, rt.breakpoint);
|
|
185
|
+
return {
|
|
180
186
|
flexGrow: 1,
|
|
181
187
|
// The header inset and the safe area are structural — they apply
|
|
182
188
|
// whether or not margins are on; the y margin stacks on top of them.
|
|
@@ -186,12 +192,15 @@ const styles = StyleSheet.create((theme, rt) => {
|
|
|
186
192
|
// The safe area is `BottomSafeArea`'s job; counting it here as well
|
|
187
193
|
// would leave a gap the height of the gesture bar.
|
|
188
194
|
paddingBottom: hasYMargin(margins) ? marginY : 0,
|
|
189
|
-
}
|
|
195
|
+
};
|
|
196
|
+
},
|
|
190
197
|
|
|
191
|
-
|
|
198
|
+
content: (horizontal: boolean, margins: ScreenMargins) => {
|
|
199
|
+
const { x: marginX } = resolveScreenMargin(theme, rt.breakpoint);
|
|
200
|
+
return {
|
|
192
201
|
flexGrow: 1,
|
|
193
202
|
paddingHorizontal: hasXMargin(margins) ? marginX : 0,
|
|
194
203
|
flexDirection: horizontal ? 'row' : 'column',
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
});
|
|
204
|
+
};
|
|
205
|
+
},
|
|
206
|
+
}));
|
|
@@ -2,10 +2,10 @@ export type { ScreenHeaderProps, ScreenProps } from './Screen';
|
|
|
2
2
|
export { Screen } from './Screen';
|
|
3
3
|
export type { ScreenContextValue } from './ScreenContext';
|
|
4
4
|
export { useScreen } from './ScreenContext';
|
|
5
|
-
export type { ScreenFlashListProps } from './ScreenFlashList';
|
|
6
|
-
export { ScreenFlashList } from './ScreenFlashList';
|
|
7
5
|
export type { ScreenFlatListProps } from './ScreenFlatList';
|
|
8
6
|
export { ScreenFlatList } from './ScreenFlatList';
|
|
7
|
+
export type { ScreenListProps } from './ScreenList';
|
|
8
|
+
export { ScreenList } from './ScreenList';
|
|
9
9
|
export type { ScreenScrollViewProps } from './ScreenScrollView';
|
|
10
10
|
export { ScreenScrollView } from './ScreenScrollView';
|
|
11
11
|
export type { ScreenMargins, ScreenScrollableProps } from './types';
|
|
@@ -11,9 +11,8 @@ import type { ReactNode } from 'react';
|
|
|
11
11
|
export type ScreenMargins = 'all' | 'x' | 'y' | 'none';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* Props shared by `Screen.ScrollView`, `Screen.FlatList` and
|
|
15
|
-
*
|
|
16
|
-
* relearning its API.
|
|
14
|
+
* Props shared by `Screen.ScrollView`, `Screen.FlatList` and `Screen.List`, so
|
|
15
|
+
* a screen can swap one container for another without relearning its API.
|
|
17
16
|
*/
|
|
18
17
|
export interface ScreenScrollableProps {
|
|
19
18
|
/** Lay content out along the x axis. Defaults to `false`. */
|
|
@@ -150,7 +150,7 @@ const ToastRoot = forwardRef<ComponentRef<typeof View>, ToastProps>(
|
|
|
150
150
|
p="4"
|
|
151
151
|
row
|
|
152
152
|
align="center"
|
|
153
|
-
gap="
|
|
153
|
+
gap="2"
|
|
154
154
|
accessibilityRole={accessibilityRole}
|
|
155
155
|
accessibilityLiveRegion="polite"
|
|
156
156
|
borderWidth="hairline"
|
|
@@ -415,7 +415,7 @@ export function DefaultToast({
|
|
|
415
415
|
{shouldRenderIcon ? (
|
|
416
416
|
<Box alignSelf="start">{icon ?? <ToastIcon />}</Box>
|
|
417
417
|
) : null}
|
|
418
|
-
<Box flex={1} gap="
|
|
418
|
+
<Box flex={1} gap="0">
|
|
419
419
|
{label ? <ToastTitle>{label}</ToastTitle> : null}
|
|
420
420
|
{description ? (
|
|
421
421
|
<ToastDescription>{description}</ToastDescription>
|
|
@@ -310,6 +310,7 @@ const styles = StyleSheet.create((theme) => ({
|
|
|
310
310
|
backgroundColor: resolveThemeColor(background, theme),
|
|
311
311
|
borderWidth: StyleSheet.hairlineWidth,
|
|
312
312
|
borderColor: theme.color['border.subtle'],
|
|
313
|
+
...theme.elevation.xs,
|
|
313
314
|
}),
|
|
314
315
|
// Geometry is two finite axes, so it belongs in `variants` rather than in
|
|
315
316
|
// conditionals: an icon-only cell is an exact square, a labelled one keeps the
|
|
@@ -333,6 +334,7 @@ const styles = StyleSheet.create((theme) => ({
|
|
|
333
334
|
paddingHorizontal: 10,
|
|
334
335
|
borderWidth: StyleSheet.hairlineWidth,
|
|
335
336
|
borderColor: theme.color['border.subtle'],
|
|
337
|
+
...theme.elevation.xs,
|
|
336
338
|
},
|
|
337
339
|
},
|
|
338
340
|
},
|
|
@@ -326,20 +326,26 @@ export const primitives = {
|
|
|
326
326
|
'elevation.none.shadowOffset.height': 0,
|
|
327
327
|
'elevation.none.elevation': 0,
|
|
328
328
|
|
|
329
|
+
'elevation.xs.shadowOpacity': 0.03,
|
|
330
|
+
'elevation.xs.shadowRadius': 2,
|
|
331
|
+
'elevation.xs.shadowOffset.width': 0,
|
|
332
|
+
'elevation.xs.shadowOffset.height': 0.5,
|
|
333
|
+
'elevation.xs.elevation': 1,
|
|
334
|
+
|
|
329
335
|
'elevation.sm.shadowOpacity': 0.1,
|
|
330
|
-
'elevation.sm.shadowRadius':
|
|
336
|
+
'elevation.sm.shadowRadius': 4,
|
|
331
337
|
'elevation.sm.shadowOffset.width': 0,
|
|
332
338
|
'elevation.sm.shadowOffset.height': 1,
|
|
333
339
|
'elevation.sm.elevation': 1,
|
|
334
340
|
|
|
335
341
|
'elevation.md.shadowOpacity': 0.14,
|
|
336
|
-
'elevation.md.shadowRadius':
|
|
342
|
+
'elevation.md.shadowRadius': 6,
|
|
337
343
|
'elevation.md.shadowOffset.width': 0,
|
|
338
344
|
'elevation.md.shadowOffset.height': 2,
|
|
339
345
|
'elevation.md.elevation': 3,
|
|
340
346
|
|
|
341
347
|
'elevation.lg.shadowOpacity': 0.16,
|
|
342
|
-
'elevation.lg.shadowRadius':
|
|
348
|
+
'elevation.lg.shadowRadius': 12,
|
|
343
349
|
'elevation.lg.shadowOffset.width': 0,
|
|
344
350
|
'elevation.lg.shadowOffset.height': 4,
|
|
345
351
|
'elevation.lg.elevation': 6,
|
|
@@ -460,11 +466,11 @@ export const primitives = {
|
|
|
460
466
|
'layout.screen.margin.y.xs': 16,
|
|
461
467
|
'layout.screen.margin.y.sm': 16,
|
|
462
468
|
'layout.screen.margin.y.md': 24,
|
|
463
|
-
'layout.screen.margin.y.lg':
|
|
464
|
-
'layout.screen.margin.y.xl':
|
|
469
|
+
'layout.screen.margin.y.lg': 24,
|
|
470
|
+
'layout.screen.margin.y.xl': 24,
|
|
465
471
|
|
|
466
472
|
// ── header layout ─────────────────────────────────────────────────────────
|
|
467
473
|
// Header bar height (compact nav bar / collapsed large-title bar). 56dp aligns
|
|
468
474
|
// to the 4dp spacing grid (= spacing.14) and a standard app-bar height.
|
|
469
|
-
'layout.header.height':
|
|
475
|
+
'layout.header.height': 54,
|
|
470
476
|
};
|
package/src/theme/types.ts
CHANGED
|
@@ -66,7 +66,7 @@ export interface ElevationStyle {
|
|
|
66
66
|
elevation: number;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
export type ElevationKey = 'none' | 'sm' | 'md' | 'lg' | 'xl';
|
|
69
|
+
export type ElevationKey = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
70
70
|
|
|
71
71
|
export type ElevationScale = Record<ElevationKey, ElevationStyle>;
|
|
72
72
|
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
import { View } from "react-native-unistyles/components/native/View";
|
|
4
|
-
import { FlashList } from '@shopify/flash-list';
|
|
5
|
-
import Animated, { useAnimatedScrollHandler, useComposedEventHandler } from 'react-native-reanimated';
|
|
6
|
-
import { StyleSheet } from 'react-native-unistyles';
|
|
7
|
-
import { resolveScreenMargin } from "../../theme/screen-margin.js";
|
|
8
|
-
import { PortalHost } from "../portal/index.js";
|
|
9
|
-
import { BottomSafeArea } from "./parts/BottomSafeArea.js";
|
|
10
|
-
import { renderScreenPlaceholder } from "./parts/ScreenPlaceholder.js";
|
|
11
|
-
import { SCREEN_HEADER_PORTAL_HOST, useScreen } from "./ScreenContext.js";
|
|
12
|
-
import { hasXMargin, hasYMargin, renderListHeader } from "./utils.js";
|
|
13
|
-
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
14
|
-
const AnimatedFlashList = Animated.createAnimatedComponent(FlashList);
|
|
15
|
-
/**
|
|
16
|
-
* `FlashList` variant of `Screen.ScrollView`: mirrors scroll offset into the
|
|
17
|
-
* screen's shared `scrollY`, hosts the portal target above the list, and
|
|
18
|
-
* applies token-driven content padding.
|
|
19
|
-
*
|
|
20
|
-
* Requires `@shopify/flash-list` — it is a peer dependency of
|
|
21
|
-
* `react-native-terra-ui` and must be installed in the consuming app.
|
|
22
|
-
*
|
|
23
|
-
* Note: unlike `Screen.FlatList`, this does not bind the screen's shared
|
|
24
|
-
* imperative `scrollRef` — `FlashList`'s ref exposes a different (non
|
|
25
|
-
* Reanimated-compatible) imperative API.
|
|
26
|
-
*
|
|
27
|
-
* Shares `loading` / `LoadingComponent` / `EmptyComponent` / `margins` /
|
|
28
|
-
* `horizontal` with `Screen.ScrollView`, so a screen can swap one container for
|
|
29
|
-
* another without relearning its API.
|
|
30
|
-
*
|
|
31
|
-
* @example
|
|
32
|
-
* ```tsx
|
|
33
|
-
* <Screen.FlashList data={items} renderItem={({ item }) => <Row item={item} />} />
|
|
34
|
-
* ```
|
|
35
|
-
*
|
|
36
|
-
* @example Loading and empty placeholders
|
|
37
|
-
* ```tsx
|
|
38
|
-
* <Screen.FlashList
|
|
39
|
-
* data={items}
|
|
40
|
-
* loading={isLoading}
|
|
41
|
-
* EmptyComponent={<EmptyState icon="status.info" title="Nothing yet" fill />}
|
|
42
|
-
* renderItem={({ item }) => <Row item={item} />}
|
|
43
|
-
* />
|
|
44
|
-
* ```
|
|
45
|
-
*/
|
|
46
|
-
export function ScreenFlashList({
|
|
47
|
-
data,
|
|
48
|
-
style,
|
|
49
|
-
contentContainerStyle,
|
|
50
|
-
ListHeaderComponent,
|
|
51
|
-
ListFooterComponent,
|
|
52
|
-
ListEmptyComponent,
|
|
53
|
-
horizontal = false,
|
|
54
|
-
loading = false,
|
|
55
|
-
LoadingComponent,
|
|
56
|
-
EmptyComponent,
|
|
57
|
-
margins,
|
|
58
|
-
bottomInset,
|
|
59
|
-
onScroll,
|
|
60
|
-
...rest
|
|
61
|
-
}) {
|
|
62
|
-
if (FlashList == null) {
|
|
63
|
-
throw new Error('[react-native-terra-ui] Screen.FlashList requires "@shopify/flash-list" to be installed in your app. Run `yarn add @shopify/flash-list` (or the npm/pnpm equivalent) and rebuild.');
|
|
64
|
-
}
|
|
65
|
-
const {
|
|
66
|
-
background,
|
|
67
|
-
scrollHandler,
|
|
68
|
-
headerSnapOffsets,
|
|
69
|
-
margins: screenMargins,
|
|
70
|
-
hasHeader
|
|
71
|
-
} = useScreen();
|
|
72
|
-
const resolvedMargins = margins ?? screenMargins;
|
|
73
|
-
// The placeholder rides in on `ListEmptyComponent` rather than replacing the
|
|
74
|
-
// list, so the header portal and snap offsets stay put. While loading the
|
|
75
|
-
// list is fed an empty `data` so that slot is the one that renders.
|
|
76
|
-
const placeholder = renderScreenPlaceholder({
|
|
77
|
-
loading,
|
|
78
|
-
LoadingComponent,
|
|
79
|
-
EmptyComponent,
|
|
80
|
-
isEmpty: !data || data.length === 0
|
|
81
|
-
});
|
|
82
|
-
const jsScrollHandler = useAnimatedScrollHandler(event => {
|
|
83
|
-
if (onScroll) onScroll(event);
|
|
84
|
-
}, [onScroll]);
|
|
85
|
-
const composedHandler = useComposedEventHandler([scrollHandler, jsScrollHandler]);
|
|
86
|
-
|
|
87
|
-
// `AnimatedFlashList` is typed for `unknown` items, so the remaining props
|
|
88
|
-
// are cast back to its prop type — minus the ones set explicitly below,
|
|
89
|
-
// which the spread would otherwise re-supply.
|
|
90
|
-
const listProps = rest;
|
|
91
|
-
|
|
92
|
-
// A caller naming its own `bottomInset` has taken the bottom over entirely,
|
|
93
|
-
// and a horizontal list has no bottom edge to clear.
|
|
94
|
-
const needsBottomSafeArea = bottomInset === undefined && !horizontal;
|
|
95
|
-
const footerComponent = /*#__PURE__*/_jsxs(_Fragment, {
|
|
96
|
-
children: [renderListHeader(ListFooterComponent), needsBottomSafeArea ? /*#__PURE__*/_jsx(BottomSafeArea, {}) : null]
|
|
97
|
-
});
|
|
98
|
-
const headerComponent = /*#__PURE__*/_jsxs(View, {
|
|
99
|
-
style: styles.headerWrapper(resolvedMargins),
|
|
100
|
-
children: [/*#__PURE__*/_jsx(PortalHost, {
|
|
101
|
-
name: SCREEN_HEADER_PORTAL_HOST
|
|
102
|
-
}), renderListHeader(ListHeaderComponent)]
|
|
103
|
-
});
|
|
104
|
-
return /*#__PURE__*/_jsx(AnimatedFlashList, {
|
|
105
|
-
data: loading ? [] : data,
|
|
106
|
-
style: [{
|
|
107
|
-
backgroundColor: background
|
|
108
|
-
}, style],
|
|
109
|
-
horizontal: horizontal,
|
|
110
|
-
contentInsetAdjustmentBehavior: hasHeader ? 'never' : undefined,
|
|
111
|
-
contentContainerStyle: [styles.content(resolvedMargins, hasHeader, bottomInset), contentContainerStyle],
|
|
112
|
-
ListHeaderComponent: headerComponent,
|
|
113
|
-
ListFooterComponent: footerComponent,
|
|
114
|
-
ListEmptyComponent: placeholder ?? ListEmptyComponent,
|
|
115
|
-
showsVerticalScrollIndicator: false,
|
|
116
|
-
scrollEventThrottle: 16,
|
|
117
|
-
snapToOffsets: headerSnapOffsets,
|
|
118
|
-
...listProps,
|
|
119
|
-
onScroll: composedHandler
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
const styles = StyleSheet.create((theme, runtime) => {
|
|
123
|
-
const {
|
|
124
|
-
x: marginX,
|
|
125
|
-
y: marginY
|
|
126
|
-
} = resolveScreenMargin(theme, runtime.breakpoint);
|
|
127
|
-
return {
|
|
128
|
-
content: (margins, hasHeader, bottomInset) => {
|
|
129
|
-
return {
|
|
130
|
-
flexGrow: 1,
|
|
131
|
-
// The header is absolutely positioned, so the list reserves its full
|
|
132
|
-
// height — bar plus top safe area. This assumes the scroll view does not
|
|
133
|
-
// also get UIKit's automatic inset adjustment: on a native tab screen
|
|
134
|
-
// that means `disableAutomaticContentInsets` on the tab, or the two
|
|
135
|
-
// insets are counted twice.
|
|
136
|
-
paddingTop: (hasHeader ? theme.layout.header.height + runtime.insets.top : 0) + (hasYMargin(margins) ? marginY : 0),
|
|
137
|
-
paddingHorizontal: hasXMargin(margins) ? marginX : 0,
|
|
138
|
-
// The safe area is `BottomSafeArea`'s job; counting it here as well
|
|
139
|
-
// would leave a gap the height of the gesture bar.
|
|
140
|
-
paddingBottom: bottomInset ?? (hasYMargin(margins) ? marginY : 0),
|
|
141
|
-
uni__dependencies: [0, 9]
|
|
142
|
-
};
|
|
143
|
-
},
|
|
144
|
-
safeArea: {
|
|
145
|
-
height: runtime.insets.top,
|
|
146
|
-
uni__dependencies: [9]
|
|
147
|
-
},
|
|
148
|
-
headerWrapper: margins => ({
|
|
149
|
-
marginHorizontal: hasXMargin(margins) ? -marginX : 0
|
|
150
|
-
})
|
|
151
|
-
};
|
|
152
|
-
});
|
|
153
|
-
//# sourceMappingURL=ScreenFlashList.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["FlashList","Animated","useAnimatedScrollHandler","useComposedEventHandler","StyleSheet","resolveScreenMargin","PortalHost","BottomSafeArea","renderScreenPlaceholder","SCREEN_HEADER_PORTAL_HOST","useScreen","hasXMargin","hasYMargin","renderListHeader","jsx","_jsx","Fragment","_Fragment","jsxs","_jsxs","AnimatedFlashList","createAnimatedComponent","ScreenFlashList","data","style","contentContainerStyle","ListHeaderComponent","ListFooterComponent","ListEmptyComponent","horizontal","loading","LoadingComponent","EmptyComponent","margins","bottomInset","onScroll","rest","Error","background","scrollHandler","headerSnapOffsets","screenMargins","hasHeader","resolvedMargins","placeholder","isEmpty","length","jsScrollHandler","event","composedHandler","listProps","needsBottomSafeArea","undefined","footerComponent","children","headerComponent","View","styles","headerWrapper","name","backgroundColor","contentInsetAdjustmentBehavior","content","showsVerticalScrollIndicator","scrollEventThrottle","snapToOffsets","create","theme","runtime","x","marginX","y","marginY","breakpoint","flexGrow","paddingTop","layout","header","height","insets","top","paddingHorizontal","paddingBottom","uni__dependencies","safeArea","marginHorizontal"],"sourceRoot":"../../../../src","sources":["components/screen/ScreenFlashList.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { type FlashListProps } from '@shopify/flash-list';
|
|
2
|
-
import type { ScreenScrollableProps } from './types.js';
|
|
3
|
-
export interface ScreenFlashListProps<T> extends Omit<FlashListProps<T>, 'horizontal'>, ScreenScrollableProps {
|
|
4
|
-
/**
|
|
5
|
-
* Extra bottom padding on the list content — clearance for a tab bar or home
|
|
6
|
-
* indicator. Defaults to the `layout.screen.margin.y` token when margins are
|
|
7
|
-
* enabled, otherwise `0`.
|
|
8
|
-
*/
|
|
9
|
-
bottomInset?: number;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* `FlashList` variant of `Screen.ScrollView`: mirrors scroll offset into the
|
|
13
|
-
* screen's shared `scrollY`, hosts the portal target above the list, and
|
|
14
|
-
* applies token-driven content padding.
|
|
15
|
-
*
|
|
16
|
-
* Requires `@shopify/flash-list` — it is a peer dependency of
|
|
17
|
-
* `react-native-terra-ui` and must be installed in the consuming app.
|
|
18
|
-
*
|
|
19
|
-
* Note: unlike `Screen.FlatList`, this does not bind the screen's shared
|
|
20
|
-
* imperative `scrollRef` — `FlashList`'s ref exposes a different (non
|
|
21
|
-
* Reanimated-compatible) imperative API.
|
|
22
|
-
*
|
|
23
|
-
* Shares `loading` / `LoadingComponent` / `EmptyComponent` / `margins` /
|
|
24
|
-
* `horizontal` with `Screen.ScrollView`, so a screen can swap one container for
|
|
25
|
-
* another without relearning its API.
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* ```tsx
|
|
29
|
-
* <Screen.FlashList data={items} renderItem={({ item }) => <Row item={item} />} />
|
|
30
|
-
* ```
|
|
31
|
-
*
|
|
32
|
-
* @example Loading and empty placeholders
|
|
33
|
-
* ```tsx
|
|
34
|
-
* <Screen.FlashList
|
|
35
|
-
* data={items}
|
|
36
|
-
* loading={isLoading}
|
|
37
|
-
* EmptyComponent={<EmptyState icon="status.info" title="Nothing yet" fill />}
|
|
38
|
-
* renderItem={({ item }) => <Row item={item} />}
|
|
39
|
-
* />
|
|
40
|
-
* ```
|
|
41
|
-
*/
|
|
42
|
-
export declare function ScreenFlashList<T>({ data, style, contentContainerStyle, ListHeaderComponent, ListFooterComponent, ListEmptyComponent, horizontal, loading, LoadingComponent, EmptyComponent, margins, bottomInset, onScroll, ...rest }: ScreenFlashListProps<T>): import("react").JSX.Element;
|
|
43
|
-
//# sourceMappingURL=ScreenFlashList.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ScreenFlashList.d.ts","sourceRoot":"","sources":["../../../../../src/components/screen/ScreenFlashList.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAmBrE,OAAO,KAAK,EAAiB,qBAAqB,EAAE,MAAM,YAAS,CAAC;AAOpE,MAAM,WAAW,oBAAoB,CAAC,CAAC,CACrC,SAAQ,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,EAC3C,qBAAqB;IACvB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,EACjC,IAAI,EACJ,KAAK,EACL,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAClB,UAAkB,EAClB,OAAe,EACf,gBAAgB,EAChB,cAAc,EACd,OAAO,EACP,WAAW,EACX,QAAQ,EACR,GAAG,IAAI,EACR,EAAE,oBAAoB,CAAC,CAAC,CAAC,+BAkFzB"}
|