@swan-io/lake 8.17.1 → 8.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swan-io/lake",
3
- "version": "8.17.1",
3
+ "version": "8.18.1",
4
4
  "engines": {
5
5
  "node": ">=20.9.0",
6
6
  "yarn": "^1.22.0"
@@ -10,6 +10,7 @@ export type ScrollViewRef = {
10
10
  export type ScrollViewProps = ViewProps & {
11
11
  contentContainerStyle?: StyleProp<ViewStyle>;
12
12
  horizontal?: boolean;
13
+ both?: boolean;
13
14
  onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
14
15
  scrollEventThrottle?: number;
15
16
  showsScrollIndicators?: boolean;
@@ -17,6 +18,7 @@ export type ScrollViewProps = ViewProps & {
17
18
  export declare const ScrollView: import("react").ForwardRefExoticComponent<ViewProps & {
18
19
  contentContainerStyle?: StyleProp<ViewStyle>;
19
20
  horizontal?: boolean;
21
+ both?: boolean;
20
22
  onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
21
23
  scrollEventThrottle?: number;
22
24
  showsScrollIndicators?: boolean;
@@ -16,6 +16,11 @@ const styles = StyleSheet.create({
16
16
  overflowX: "auto",
17
17
  overflowY: "hidden",
18
18
  },
19
+ both: {
20
+ flexDirection: "column",
21
+ overflowX: "auto",
22
+ overflowY: "auto",
23
+ },
19
24
  contentHorizontal: {
20
25
  flexDirection: "row",
21
26
  },
@@ -55,7 +60,7 @@ const normalizeScrollEvent = (event) => {
55
60
  };
56
61
  };
57
62
  const shouldEmitScrollEvent = (state, eventThrottle) => !state.scrolling || (eventThrottle > 0 && Date.now() - state.lastTick >= eventThrottle);
58
- export const ScrollView = forwardRef(({ children, contentContainerStyle, horizontal = false, onScroll, scrollEventThrottle = 16, showsScrollIndicators = true, style, ...viewProps }, forwardedRef) => {
63
+ export const ScrollView = forwardRef(({ children, contentContainerStyle, horizontal = false, both = false, onScroll, scrollEventThrottle = 16, showsScrollIndicators = true, style, ...viewProps }, forwardedRef) => {
59
64
  const innerRef = useRef(null);
60
65
  const stateRef = useRef({ lastTick: 0, scrolling: false });
61
66
  const timeoutRef = useRef(null);
@@ -95,6 +100,7 @@ export const ScrollView = forwardRef(({ children, contentContainerStyle, horizon
95
100
  styles.base,
96
101
  style,
97
102
  horizontal && styles.horizontal,
103
+ both && styles.both,
98
104
  !showsScrollIndicators && styles.hideScrollbars,
99
105
  ], children: _jsx(View, { style: [horizontal && styles.contentHorizontal, contentContainerStyle], children: children }) }));
100
106
  });
@@ -0,0 +1,55 @@
1
+ import { ReactElement, ReactNode } from "react";
2
+ export type ColumnTitleConfig<ExtraInfo> = {
3
+ title: string;
4
+ extraInfo: ExtraInfo;
5
+ id: string;
6
+ };
7
+ export type ColumnCellConfig<T, ExtraInfo> = {
8
+ columnId: string;
9
+ item: T;
10
+ index: number;
11
+ extraInfo: ExtraInfo;
12
+ isHovered: boolean;
13
+ };
14
+ export type ColumnConfig<T, ExtraInfo> = {
15
+ id: string;
16
+ width: number;
17
+ title: string;
18
+ renderTitle: (props: ColumnTitleConfig<ExtraInfo>) => ReactNode;
19
+ renderCell: (props: ColumnCellConfig<T, ExtraInfo>) => ReactNode;
20
+ };
21
+ export type LinkConfig<T, ExtraInfo> = {
22
+ item: T;
23
+ index: number;
24
+ extraInfo: ExtraInfo;
25
+ };
26
+ export type VirtualizedListProps<T, ExtraInfo> = {
27
+ variant: "default" | "accented";
28
+ data: T[];
29
+ keyExtractor: (item: T, index: number) => string;
30
+ highlightedRowId?: string;
31
+ headerHeight: number;
32
+ rowHeight: number;
33
+ extraInfo: ExtraInfo;
34
+ stickedToStartColumns?: ColumnConfig<T, ExtraInfo>[];
35
+ columns: ColumnConfig<T, ExtraInfo>[];
36
+ stickedToEndColumns?: ColumnConfig<T, ExtraInfo>[];
37
+ renderThreshold?: number;
38
+ onEndReached?: () => void;
39
+ onEndReachedThreshold?: number;
40
+ getRowLink?: (config: LinkConfig<T, ExtraInfo>) => ReactElement | undefined;
41
+ renderEmptyList?: () => ReactNode;
42
+ loading?: {
43
+ isLoading: boolean;
44
+ count: number;
45
+ };
46
+ };
47
+ export declare const VirtualizedList: <T, ExtraInfo>({ variant, data, stickedToStartColumns, columns, stickedToEndColumns, headerHeight, rowHeight, renderThreshold, onEndReached, onEndReachedThreshold, loading, extraInfo, keyExtractor, }: VirtualizedListProps<T, ExtraInfo>) => import("react/jsx-runtime").JSX.Element;
48
+ type VirtualizedListPlaceholderProps = {
49
+ count: number;
50
+ rowHeight: number;
51
+ groupHeaderHeight?: number;
52
+ headerHeight?: number;
53
+ };
54
+ export declare const VirtualizedListPlaceholder: ({ count, rowHeight, groupHeaderHeight, headerHeight, }: VirtualizedListPlaceholderProps) => import("react/jsx-runtime").JSX.Element;
55
+ export {};
@@ -0,0 +1,427 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Option } from "@swan-io/boxed";
3
+ import { cloneElement, memo, useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, } from "react";
4
+ import { StyleSheet, View } from "react-native";
5
+ import { commonStyles } from "../constants/commonStyles";
6
+ import { backgroundColor as backgroundColorVariants, colors, spacings } from "../constants/design";
7
+ import { useHover } from "../hooks/useHover";
8
+ import { ScrollView } from "./ScrollView";
9
+ import { Space } from "./Space";
10
+ const styles = StyleSheet.create({
11
+ container: {
12
+ ...commonStyles.fill,
13
+ height: 1,
14
+ alignSelf: "stretch",
15
+ },
16
+ headerRow: {
17
+ position: "sticky",
18
+ top: 0,
19
+ flexDirection: "row",
20
+ alignItems: "stretch",
21
+ zIndex: 2,
22
+ },
23
+ cellsContainer: {
24
+ flexDirection: "row",
25
+ transform: "translateZ(0)",
26
+ },
27
+ stickedToStartColumnGroup: {
28
+ position: "sticky",
29
+ left: 0,
30
+ zIndex: 1,
31
+ },
32
+ stickedToEndColumnGroup: {
33
+ position: "sticky",
34
+ right: 0,
35
+ zIndex: 1,
36
+ },
37
+ rowsContainer: {
38
+ position: "relative",
39
+ },
40
+ row: {
41
+ position: "absolute",
42
+ left: 0,
43
+ right: 0,
44
+ flexDirection: "row",
45
+ alignItems: "stretch",
46
+ },
47
+ headerCell: {
48
+ display: "flex",
49
+ flexDirection: "row",
50
+ flexGrow: 1,
51
+ alignItems: "center",
52
+ },
53
+ cell: {
54
+ display: "flex",
55
+ flexDirection: "row",
56
+ flexGrow: 1,
57
+ alignItems: "stretch",
58
+ boxShadow: `inset 0 -1px ${colors.gray[100]}`,
59
+ },
60
+ shadowsLayerContainer: {
61
+ position: "absolute",
62
+ top: 0,
63
+ left: 0,
64
+ right: 0,
65
+ bottom: 0,
66
+ pointerEvents: "none",
67
+ zIndex: 4,
68
+ },
69
+ shadowsLayer: {
70
+ position: "sticky",
71
+ top: 12,
72
+ flexDirection: "row",
73
+ alignItems: "stretch",
74
+ },
75
+ startColumnsShadow: {
76
+ position: "sticky",
77
+ left: 0,
78
+ top: 0,
79
+ boxShadow: "15px 0 10px -12px rgba(0, 0, 0, 0.1)",
80
+ transition: "100ms ease-in-out opacity",
81
+ },
82
+ endColumnsShadow: {
83
+ position: "sticky",
84
+ right: 0,
85
+ top: 0,
86
+ boxShadow: "-15px 0 10px -12px rgba(0, 0, 0, 0.1)",
87
+ transition: "100ms ease-in-out opacity",
88
+ },
89
+ scrollTracker: {
90
+ pointerEvents: "none",
91
+ position: "absolute",
92
+ left: 0,
93
+ bottom: 0,
94
+ right: 0,
95
+ },
96
+ placeholderRowContainer: {
97
+ position: "absolute",
98
+ alignItems: "flex-start",
99
+ top: 0,
100
+ left: 0,
101
+ right: 0,
102
+ animationKeyframes: {
103
+ "50%": {
104
+ opacity: 0.6,
105
+ },
106
+ },
107
+ animationDuration: "2000ms",
108
+ animationTimingFunction: "linear",
109
+ animationIterationCount: "infinite",
110
+ boxShadow: `inset 0 -1px ${colors.gray[100]}`,
111
+ },
112
+ placeholderRowContents: {
113
+ position: "sticky",
114
+ width: "50%",
115
+ left: 0,
116
+ flexDirection: "row",
117
+ alignItems: "center",
118
+ justifyContent: "flex-start",
119
+ flexGrow: 1,
120
+ paddingHorizontal: spacings[20],
121
+ },
122
+ loadingPlaceholder: {
123
+ position: "absolute",
124
+ left: 0,
125
+ right: 0,
126
+ },
127
+ placeholderRow: {
128
+ height: 14,
129
+ width: "30%",
130
+ backgroundColor: colors.gray[100],
131
+ },
132
+ placeholderRowEnd: {
133
+ paddingHorizontal: spacings[20],
134
+ position: "sticky",
135
+ right: 0,
136
+ flexGrow: 1,
137
+ flexDirection: "row",
138
+ alignItems: "center",
139
+ justifyContent: "flex-end",
140
+ },
141
+ smallPlaceholderRow: {
142
+ width: "10%",
143
+ },
144
+ });
145
+ export const VirtualizedList = ({ variant, data, stickedToStartColumns, columns, stickedToEndColumns, headerHeight, rowHeight, renderThreshold = 1000, onEndReached, onEndReachedThreshold = 200, loading, extraInfo, keyExtractor, }) => {
146
+ // Used for unique IDs generation (usefull for header IDs and cells aria-describedBy pointing to them)
147
+ const viewId = useId();
148
+ const scrollViewRef = useRef(null);
149
+ const scrollTrackerRef = useRef(null);
150
+ // Theoretical height of all actual data if rendered
151
+ const fullDataHeight = rowHeight * data.length;
152
+ const loadingDataPlaceholderHeight = Option.fromNullable(loading)
153
+ .flatMap(({ isLoading, count }) => (isLoading ? Option.Some(rowHeight * count) : Option.None()))
154
+ .getOr(0);
155
+ const containerContainerHeight = headerHeight + fullDataHeight + loadingDataPlaceholderHeight;
156
+ const stickedToStartColumnsWidth = useMemo(() => Option.fromNullable(stickedToStartColumns)
157
+ .map(columns => columns.reduce((acc, column) => acc + column.width, 0))
158
+ .getOr(0), [stickedToStartColumns]);
159
+ const centerColumnsWidth = useMemo(() => columns.reduce((acc, column) => acc + column.width, 0), [columns]);
160
+ const stickedToEndColumnsWidth = useMemo(() => Option.fromNullable(stickedToEndColumns)
161
+ .map(columns => columns.reduce((acc, column) => acc + column.width, 0))
162
+ .getOr(0), [stickedToEndColumns]);
163
+ const contentContainerWidth = stickedToStartColumnsWidth + centerColumnsWidth + stickedToEndColumnsWidth;
164
+ const backgroundColor = backgroundColorVariants[variant];
165
+ // We store the `startIndex` and `endIndex` rather than the scroll position
166
+ // so that it triggers way less re-renders
167
+ const [rangeToRender, setRangeToRender] = useState(undefined);
168
+ const [clientHeight, setClientHeight] = useState(undefined);
169
+ const [horizontalScrollPosition, setHasHorizontalScrollPosition] = useState(undefined);
170
+ const rowsToRender = useMemo(() => {
171
+ return Option.fromNullable(rangeToRender).map(({ startIndex, endIndex }) => ({
172
+ startIndex,
173
+ endIndex,
174
+ data: data.slice(startIndex, endIndex),
175
+ }));
176
+ }, [data, rangeToRender]);
177
+ useLayoutEffect(() => {
178
+ const element = Option.fromNullable(scrollViewRef.current).flatMap(ref => Option.fromNullable(ref.element));
179
+ setRangeToRender(previousRangeToRender => element
180
+ .map(scrollView => {
181
+ const startIndex = Math.max(0, Math.floor((scrollView.scrollTop - renderThreshold) / rowHeight));
182
+ const endIndex = Math.min(data.length, startIndex + Math.ceil((scrollView.scrollHeight + renderThreshold * 2) / rowHeight));
183
+ if ((previousRangeToRender === null || previousRangeToRender === void 0 ? void 0 : previousRangeToRender.startIndex) === startIndex &&
184
+ previousRangeToRender.endIndex === endIndex) {
185
+ return previousRangeToRender;
186
+ }
187
+ return { startIndex, endIndex };
188
+ })
189
+ .toUndefined());
190
+ setClientHeight(element.map(scrollView => scrollView.clientHeight).toUndefined());
191
+ setHasHorizontalScrollPosition(element
192
+ .map(scrollView => scrollView.scrollWidth === scrollView.clientWidth
193
+ ? "NoScroll"
194
+ : scrollView.scrollLeft <= 0
195
+ ? "Start"
196
+ : scrollView.scrollLeft >= scrollView.scrollWidth - scrollView.clientWidth
197
+ ? "End"
198
+ : "Middle")
199
+ .toUndefined());
200
+ }, [data, renderThreshold, rowHeight]);
201
+ const scrollTimeoutRef = useRef(undefined);
202
+ const rowsContainerRef = useRef(null);
203
+ const onScroll = useCallback(() => {
204
+ const element = Option.fromNullable(scrollViewRef.current).flatMap(ref => Option.fromNullable(ref.element));
205
+ // Disable interactions in cells during scroll, avoids useless
206
+ // re-renders
207
+ if (scrollTimeoutRef.current != null) {
208
+ clearTimeout(scrollTimeoutRef.current);
209
+ }
210
+ if (rowsContainerRef.current instanceof HTMLElement) {
211
+ rowsContainerRef.current.style.pointerEvents = "none";
212
+ }
213
+ scrollTimeoutRef.current = window.setTimeout(() => {
214
+ if (rowsContainerRef.current instanceof HTMLElement) {
215
+ rowsContainerRef.current.style.pointerEvents = "auto";
216
+ }
217
+ }, 100);
218
+ setRangeToRender(previousRangeToRender => element
219
+ .map(scrollView => {
220
+ const startIndex = Math.max(0, Math.floor((scrollView.scrollTop - renderThreshold) / rowHeight));
221
+ const endIndex = Math.min(data.length, startIndex + Math.ceil((scrollView.scrollHeight + renderThreshold * 2) / rowHeight));
222
+ if ((previousRangeToRender === null || previousRangeToRender === void 0 ? void 0 : previousRangeToRender.startIndex) === startIndex &&
223
+ previousRangeToRender.endIndex === endIndex) {
224
+ return previousRangeToRender;
225
+ }
226
+ return { startIndex, endIndex };
227
+ })
228
+ .toUndefined());
229
+ setHasHorizontalScrollPosition(element
230
+ .map(scrollView => scrollView.scrollWidth === scrollView.clientWidth
231
+ ? "NoScroll"
232
+ : scrollView.scrollLeft <= 0
233
+ ? "Start"
234
+ : scrollView.scrollLeft >= scrollView.scrollWidth - scrollView.clientWidth
235
+ ? "End"
236
+ : "Middle")
237
+ .toUndefined());
238
+ }, [data, renderThreshold, rowHeight]);
239
+ // tracks if the threshold to initiate the next data load is reached
240
+ useEffect(() => {
241
+ const scrollTracker = scrollTrackerRef.current;
242
+ if (scrollTracker != null) {
243
+ const scrollTrackerElement = scrollTracker;
244
+ const intersectionObserver = new IntersectionObserver(entries => {
245
+ entries.forEach(entry => {
246
+ if (entry.isIntersecting) {
247
+ if (onEndReached != null) {
248
+ onEndReached();
249
+ }
250
+ }
251
+ });
252
+ });
253
+ intersectionObserver.observe(scrollTrackerElement);
254
+ return () => intersectionObserver.unobserve(scrollTrackerElement);
255
+ }
256
+ }, [onEndReached, data.length]);
257
+ const header = useMemo(() => {
258
+ return (_jsxs(View, { style: [styles.headerRow, { height: headerHeight }], children: [Option.fromNullable(stickedToStartColumns)
259
+ .map(columns => (_jsx(View, { style: [
260
+ styles.cellsContainer,
261
+ styles.stickedToStartColumnGroup,
262
+ { width: stickedToStartColumnsWidth, backgroundColor },
263
+ ], children: columns.map(({ id, width, title, renderTitle }) => {
264
+ const columnId = `${viewId}_${id}`;
265
+ return (_jsx(View, { style: [styles.headerCell, { width }], id: columnId, children: renderTitle({ title, extraInfo, id }) }, columnId));
266
+ }) })))
267
+ .toNull(), _jsx(View, { style: [styles.cellsContainer, { width: centerColumnsWidth, backgroundColor }], children: columns.map(({ id, width, title, renderTitle }) => {
268
+ const columnId = `${viewId}_${id}`;
269
+ return (_jsx(View, { style: [styles.headerCell, { width }], id: columnId, children: renderTitle({ title, extraInfo, id }) }, columnId));
270
+ }) }), Option.fromNullable(stickedToEndColumns)
271
+ .map(columns => (_jsx(View, { style: [
272
+ styles.cellsContainer,
273
+ styles.stickedToEndColumnGroup,
274
+ { width: stickedToEndColumnsWidth, backgroundColor },
275
+ ], children: columns.map(({ id, width, title, renderTitle }) => {
276
+ const columnId = `${viewId}_${id}`;
277
+ return (_jsx(View, { style: [styles.headerCell, { width }], id: columnId, children: renderTitle({ title, extraInfo, id }) }, columnId));
278
+ }) })))
279
+ .toNull()] }));
280
+ }, [
281
+ backgroundColor,
282
+ stickedToStartColumnsWidth,
283
+ centerColumnsWidth,
284
+ stickedToEndColumnsWidth,
285
+ headerHeight,
286
+ extraInfo,
287
+ stickedToStartColumns,
288
+ columns,
289
+ stickedToEndColumns,
290
+ viewId,
291
+ ]);
292
+ const startColumnShadow = useMemo(() => {
293
+ if (stickedToStartColumnsWidth === 0) {
294
+ return Option.None();
295
+ }
296
+ return Option.Some(_jsx(View, { style: [
297
+ styles.startColumnsShadow,
298
+ {
299
+ width: stickedToStartColumnsWidth,
300
+ opacity: Option.fromNullable(horizontalScrollPosition)
301
+ .map(value => (value === "Start" || value === "NoScroll" ? 0 : 1))
302
+ .getOr(0),
303
+ },
304
+ ] }));
305
+ }, [stickedToStartColumnsWidth, horizontalScrollPosition]);
306
+ const endColumnShadow = useMemo(() => {
307
+ if (stickedToEndColumnsWidth === 0) {
308
+ return Option.None();
309
+ }
310
+ return Option.Some(_jsx(View, { style: [
311
+ styles.endColumnsShadow,
312
+ {
313
+ width: stickedToEndColumnsWidth,
314
+ opacity: Option.fromNullable(horizontalScrollPosition)
315
+ .map(value => (value === "End" || value === "NoScroll" ? 0 : 1))
316
+ .getOr(0),
317
+ },
318
+ ] }));
319
+ }, [stickedToEndColumnsWidth, horizontalScrollPosition]);
320
+ return (_jsxs(ScrollView, { ref: scrollViewRef, both: true, style: styles.container, onScroll: onScroll, scrollEventThrottle: 32, contentContainerStyle: {
321
+ height: containerContainerHeight,
322
+ width: contentContainerWidth,
323
+ }, children: [header, rowsToRender
324
+ .map(({ startIndex, endIndex, data }) => (_jsxs(View, { style: styles.rowsContainer, ref: rowsContainerRef, children: [data.map((item, index) => (_jsx(VirtualizedRow, { viewId: viewId, item: item, rowHeight: rowHeight, absoluteIndex: startIndex + index, variant: variant, stickedToStartColumnsWidth: stickedToStartColumnsWidth, centerColumnsWidth: centerColumnsWidth, stickedToEndColumnsWidth: stickedToEndColumnsWidth, stickedToStartColumns: stickedToStartColumns, columns: columns, stickedToEndColumns: stickedToEndColumns, extraInfo: extraInfo }, keyExtractor(item, startIndex + index)))), Option.fromNullable(loading)
325
+ .flatMap(({ isLoading, count }) => (isLoading ? Option.Some(count) : Option.None()))
326
+ .map(count => (_jsx(View, { "aria-busy": true, style: [
327
+ styles.loadingPlaceholder,
328
+ {
329
+ top: endIndex * rowHeight,
330
+ },
331
+ ], children: _jsx(VirtualizedListPlaceholder, { count: count, headerHeight: 0, rowHeight: rowHeight }) })))
332
+ .toNull()] })))
333
+ .toNull(), Option.fromNullable(clientHeight)
334
+ .map(clientHeight => (_jsx(View, { style: styles.shadowsLayerContainer, children: _jsxs(View, { style: [styles.shadowsLayer, { height: clientHeight - 12 }], children: [startColumnShadow.toNull(), _jsx(View, { style: { width: centerColumnsWidth } }), endColumnShadow.toNull()] }) })))
335
+ .toNull(), _jsx(View, { style: [styles.scrollTracker, { height: onEndReachedThreshold }], ref: scrollTrackerRef })] }));
336
+ };
337
+ const RawVirtualizedRow = ({ viewId, rowHeight, absoluteIndex, variant, stickedToStartColumnsWidth, centerColumnsWidth, stickedToEndColumnsWidth, stickedToStartColumns, columns, stickedToEndColumns, extraInfo, item, getRowLink, }) => {
338
+ var _a;
339
+ const [isHovered, setIsHovered] = useState(false);
340
+ const elementRef = useRef(null);
341
+ useHover(elementRef, {
342
+ onHoverStart: () => setIsHovered(true),
343
+ onHoverEnd: () => setIsHovered(false),
344
+ });
345
+ const rootElement = getRowLink != null ? (((_a = getRowLink({ item, index: absoluteIndex, extraInfo })) !== null && _a !== void 0 ? _a : _jsx(View, {}))) : (_jsx(View, {}));
346
+ return cloneElement(rootElement, {
347
+ ref: elementRef,
348
+ style: [
349
+ styles.row,
350
+ isHovered && {
351
+ backgroundColor: variant === "accented"
352
+ ? backgroundColorVariants.default
353
+ : backgroundColorVariants.accented,
354
+ },
355
+ {
356
+ backgroundColor: backgroundColorVariants[variant],
357
+ top: absoluteIndex * rowHeight,
358
+ height: rowHeight,
359
+ },
360
+ ],
361
+ children: (_jsxs(_Fragment, { children: [Option.fromNullable(stickedToStartColumns)
362
+ .map(columns => (_jsx(View, { style: [
363
+ styles.cellsContainer,
364
+ styles.stickedToStartColumnGroup,
365
+ {
366
+ width: stickedToStartColumnsWidth,
367
+ backgroundColor: isHovered
368
+ ? backgroundColorVariants[variant === "accented" ? "default" : "accented"]
369
+ : backgroundColorVariants[variant],
370
+ },
371
+ ], children: columns.map(({ id, width, renderCell }) => {
372
+ const columnId = `${viewId}_${id}`;
373
+ return (_jsx(View, { style: [styles.cell, { width }], "aria-describedby": columnId, children: renderCell({
374
+ columnId,
375
+ item,
376
+ index: absoluteIndex,
377
+ extraInfo,
378
+ isHovered: false,
379
+ }) }, columnId));
380
+ }) })))
381
+ .toNull(), _jsx(View, { style: [
382
+ styles.cellsContainer,
383
+ {
384
+ width: centerColumnsWidth,
385
+ backgroundColor: isHovered
386
+ ? backgroundColorVariants[variant === "accented" ? "default" : "accented"]
387
+ : backgroundColorVariants[variant],
388
+ },
389
+ ], children: columns.map(({ id, width, renderCell }) => {
390
+ const columnId = `${viewId}_${id}`;
391
+ return (_jsx(View, { style: [styles.cell, { width }], "aria-describedby": columnId, children: renderCell({
392
+ columnId,
393
+ item,
394
+ index: absoluteIndex,
395
+ extraInfo,
396
+ isHovered: false,
397
+ }) }, columnId));
398
+ }) }), Option.fromNullable(stickedToEndColumns)
399
+ .map(columns => (_jsx(View, { style: [
400
+ styles.cellsContainer,
401
+ styles.stickedToEndColumnGroup,
402
+ {
403
+ width: stickedToEndColumnsWidth,
404
+ backgroundColor: isHovered
405
+ ? backgroundColorVariants[variant === "accented" ? "default" : "accented"]
406
+ : backgroundColorVariants[variant],
407
+ },
408
+ ], children: columns.map(({ id, width, renderCell }) => {
409
+ const columnId = `${viewId}_${id}`;
410
+ return (_jsx(View, { style: [styles.cell, { width }], "aria-describedby": columnId, children: renderCell({
411
+ columnId,
412
+ item,
413
+ index: absoluteIndex,
414
+ extraInfo,
415
+ isHovered: false,
416
+ }) }, columnId));
417
+ }) })))
418
+ .toNull()] })),
419
+ });
420
+ };
421
+ const VirtualizedRow = memo(RawVirtualizedRow);
422
+ export const VirtualizedListPlaceholder = ({ count, rowHeight, groupHeaderHeight, headerHeight, }) => {
423
+ return (_jsxs(View, { style: styles.container, children: [headerHeight != null ? _jsx(View, { style: { height: headerHeight } }) : null, groupHeaderHeight != groupHeaderHeight ? _jsx(View, { style: { height: headerHeight } }) : null, _jsx(View, { children: Array.from({ length: count }, (_, index) => {
424
+ const top = index * rowHeight;
425
+ return (_jsx(View, { style: [styles.placeholderRowContainer, { height: rowHeight, top }], children: _jsxs(View, { style: styles.placeholderRowContents, children: [_jsx(View, { style: styles.placeholderRow }), _jsx(Space, { width: 32 }), _jsx(View, { style: [styles.placeholderRow, styles.smallPlaceholderRow] }), _jsx(Space, { width: 32 }), _jsx(View, { style: styles.placeholderRowEnd, children: _jsx(View, { style: [styles.placeholderRow, styles.smallPlaceholderRow] }) })] }) }, String(index)));
426
+ }) })] }));
427
+ };