@cdx-ui/components 0.0.1-beta.185 → 0.0.1-beta.187
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/README.md +1 -1
- package/coverage.svg +1 -1
- package/lib/commonjs/components/Chip/styles.js +1 -1
- package/lib/commonjs/components/Chip/styles.js.map +1 -1
- package/lib/commonjs/components/Table/index.js +19 -34
- package/lib/commonjs/components/Table/index.js.map +1 -1
- package/lib/commonjs/components/Table/index.web.js +40 -6
- package/lib/commonjs/components/Table/index.web.js.map +1 -1
- package/lib/commonjs/components/Table/styles.js +55 -7
- package/lib/commonjs/components/Table/styles.js.map +1 -1
- package/lib/commonjs/components/TablePagination/TablePaginationContext.js +31 -0
- package/lib/commonjs/components/TablePagination/TablePaginationContext.js.map +1 -0
- package/lib/commonjs/components/TablePagination/getTablePaginationItems.js +50 -0
- package/lib/commonjs/components/TablePagination/getTablePaginationItems.js.map +1 -0
- package/lib/commonjs/components/TablePagination/index.js +395 -0
- package/lib/commonjs/components/TablePagination/index.js.map +1 -0
- package/lib/commonjs/components/TablePagination/styles.js +13 -0
- package/lib/commonjs/components/TablePagination/styles.js.map +1 -0
- package/lib/commonjs/components/index.js +12 -0
- package/lib/commonjs/components/index.js.map +1 -1
- package/lib/commonjs/styles.css +1 -0
- package/lib/module/components/Chip/styles.js +1 -1
- package/lib/module/components/Chip/styles.js.map +1 -1
- package/lib/module/components/Table/index.js +20 -35
- package/lib/module/components/Table/index.js.map +1 -1
- package/lib/module/components/Table/index.web.js +40 -6
- package/lib/module/components/Table/index.web.js.map +1 -1
- package/lib/module/components/Table/styles.js +54 -6
- package/lib/module/components/Table/styles.js.map +1 -1
- package/lib/module/components/TablePagination/TablePaginationContext.js +25 -0
- package/lib/module/components/TablePagination/TablePaginationContext.js.map +1 -0
- package/lib/module/components/TablePagination/getTablePaginationItems.js +46 -0
- package/lib/module/components/TablePagination/getTablePaginationItems.js.map +1 -0
- package/lib/module/components/TablePagination/index.js +386 -0
- package/lib/module/components/TablePagination/index.js.map +1 -0
- package/lib/module/components/TablePagination/styles.js +9 -0
- package/lib/module/components/TablePagination/styles.js.map +1 -0
- package/lib/module/components/index.js +1 -0
- package/lib/module/components/index.js.map +1 -1
- package/lib/module/styles.css +1 -0
- package/lib/typescript/components/Table/index.d.ts +1 -1
- package/lib/typescript/components/Table/index.d.ts.map +1 -1
- package/lib/typescript/components/Table/index.web.d.ts +3 -3
- package/lib/typescript/components/Table/index.web.d.ts.map +1 -1
- package/lib/typescript/components/Table/styles.d.ts +11 -1
- package/lib/typescript/components/Table/styles.d.ts.map +1 -1
- package/lib/typescript/components/Table/types.d.ts +13 -1
- package/lib/typescript/components/Table/types.d.ts.map +1 -1
- package/lib/typescript/components/TablePagination/TablePaginationContext.d.ts +20 -0
- package/lib/typescript/components/TablePagination/TablePaginationContext.d.ts.map +1 -0
- package/lib/typescript/components/TablePagination/getTablePaginationItems.d.ts +7 -0
- package/lib/typescript/components/TablePagination/getTablePaginationItems.d.ts.map +1 -0
- package/lib/typescript/components/TablePagination/index.d.ts +74 -0
- package/lib/typescript/components/TablePagination/index.d.ts.map +1 -0
- package/lib/typescript/components/TablePagination/styles.d.ts +8 -0
- package/lib/typescript/components/TablePagination/styles.d.ts.map +1 -0
- package/lib/typescript/components/index.d.ts +1 -0
- package/lib/typescript/components/index.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/components/Chip/styles.ts +1 -1
- package/src/components/Table/index.tsx +28 -58
- package/src/components/Table/index.web.tsx +40 -12
- package/src/components/Table/styles.ts +56 -3
- package/src/components/Table/types.ts +14 -1
- package/src/components/TablePagination/TablePaginationContext.tsx +37 -0
- package/src/components/TablePagination/getTablePaginationItems.ts +62 -0
- package/src/components/TablePagination/index.tsx +498 -0
- package/src/components/TablePagination/styles.ts +15 -0
- package/src/components/index.ts +1 -0
- package/src/styles.css +1 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export type TablePaginationItemToken = number | 'ellipsis';
|
|
2
|
+
|
|
3
|
+
function range(start: number, end: number): number[] {
|
|
4
|
+
if (end < start) {
|
|
5
|
+
return [];
|
|
6
|
+
}
|
|
7
|
+
return Array.from({ length: end - start + 1 }, (_, index) => start + index);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Compact pager window: first, last, current ± siblings, with ellipses in the gaps.
|
|
12
|
+
* Matches the common MUI / HeroUI compact algorithm (`siblingCount` default 1).
|
|
13
|
+
*/
|
|
14
|
+
export function getTablePaginationItems(
|
|
15
|
+
page: number,
|
|
16
|
+
count: number,
|
|
17
|
+
siblingCount = 1,
|
|
18
|
+
): TablePaginationItemToken[] {
|
|
19
|
+
if (count <= 0) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const current = Math.min(Math.max(page, 1), count);
|
|
24
|
+
const siblings = Math.max(siblingCount, 0);
|
|
25
|
+
const boundaryCount = 1;
|
|
26
|
+
const totalNumbers = siblings * 2 + 5;
|
|
27
|
+
|
|
28
|
+
if (count <= totalNumbers) {
|
|
29
|
+
return range(1, count);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const startPages = range(1, Math.min(boundaryCount, count));
|
|
33
|
+
const endPages = range(Math.max(count - boundaryCount + 1, boundaryCount + 1), count);
|
|
34
|
+
|
|
35
|
+
const siblingsStart = Math.max(
|
|
36
|
+
Math.min(current - siblings, count - boundaryCount - siblings * 2 - 1),
|
|
37
|
+
boundaryCount + 2,
|
|
38
|
+
);
|
|
39
|
+
const siblingsEnd = Math.min(
|
|
40
|
+
Math.max(current + siblings, boundaryCount + siblings * 2 + 2),
|
|
41
|
+
endPages.length > 0 ? endPages[0] - 2 : count - 1,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const items: TablePaginationItemToken[] = [...startPages];
|
|
45
|
+
|
|
46
|
+
if (siblingsStart > boundaryCount + 2) {
|
|
47
|
+
items.push('ellipsis');
|
|
48
|
+
} else if (boundaryCount + 1 < count - boundaryCount) {
|
|
49
|
+
items.push(boundaryCount + 1);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
items.push(...range(siblingsStart, siblingsEnd));
|
|
53
|
+
|
|
54
|
+
if (siblingsEnd < count - boundaryCount - 1) {
|
|
55
|
+
items.push('ellipsis');
|
|
56
|
+
} else if (count - boundaryCount > boundaryCount) {
|
|
57
|
+
items.push(count - boundaryCount);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
items.push(...endPages);
|
|
61
|
+
return items;
|
|
62
|
+
}
|
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
import { createElement, forwardRef, useCallback, useMemo, type ReactNode } from 'react';
|
|
2
|
+
import { I18nManager, Platform, View, type PressableProps, type ViewProps } from 'react-native';
|
|
3
|
+
import { ChevronLeft, ChevronRight } from '@cdx-ui/icons';
|
|
4
|
+
import { Slot, dataAttributes, mergeDataAttributes } from '@cdx-ui/primitives';
|
|
5
|
+
import { cn, composeEventHandlers, useControllableState } from '@cdx-ui/utils';
|
|
6
|
+
import { Button } from '../Button';
|
|
7
|
+
import { IconButton } from '../IconButton';
|
|
8
|
+
import { Select } from '../Select';
|
|
9
|
+
import { Text } from '../Text';
|
|
10
|
+
import {
|
|
11
|
+
TablePaginationProvider,
|
|
12
|
+
useRequiredTablePaginationContext,
|
|
13
|
+
} from './TablePaginationContext';
|
|
14
|
+
import { getTablePaginationItems } from './getTablePaginationItems';
|
|
15
|
+
import {
|
|
16
|
+
tablePaginationEllipsisVariants,
|
|
17
|
+
tablePaginationItemVariants,
|
|
18
|
+
tablePaginationPageSizeVariants,
|
|
19
|
+
tablePaginationRootVariants,
|
|
20
|
+
tablePaginationStatusVariants,
|
|
21
|
+
} from './styles';
|
|
22
|
+
|
|
23
|
+
export { getTablePaginationItems } from './getTablePaginationItems';
|
|
24
|
+
export type { TablePaginationItemToken } from './getTablePaginationItems';
|
|
25
|
+
|
|
26
|
+
export type TablePaginationPageSizeOption = number | { value: number; label: string };
|
|
27
|
+
|
|
28
|
+
export interface TablePaginationProps extends ViewProps {
|
|
29
|
+
asChild?: boolean;
|
|
30
|
+
className?: string;
|
|
31
|
+
children?: ReactNode;
|
|
32
|
+
/** 1-based current page. Controlled when set. */
|
|
33
|
+
page?: number;
|
|
34
|
+
defaultPage?: number;
|
|
35
|
+
/** Total page count. When set with no children, items are generated. */
|
|
36
|
+
count?: number;
|
|
37
|
+
onPageChange?: (page: number) => void;
|
|
38
|
+
siblingCount?: number;
|
|
39
|
+
pageSize?: number;
|
|
40
|
+
pageSizeOptions?: readonly TablePaginationPageSizeOption[];
|
|
41
|
+
onPageSizeChange?: (pageSize: number) => void;
|
|
42
|
+
disabled?: boolean;
|
|
43
|
+
'aria-label'?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface TablePaginationItemProps extends ViewProps {
|
|
47
|
+
asChild?: boolean;
|
|
48
|
+
className?: string;
|
|
49
|
+
children?: ReactNode;
|
|
50
|
+
page?: number;
|
|
51
|
+
current?: boolean;
|
|
52
|
+
disabled?: boolean;
|
|
53
|
+
onPress?: PressableProps['onPress'];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface TablePaginationControlProps extends ViewProps {
|
|
57
|
+
asChild?: boolean;
|
|
58
|
+
className?: string;
|
|
59
|
+
children?: ReactNode;
|
|
60
|
+
disabled?: boolean;
|
|
61
|
+
onPress?: PressableProps['onPress'];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface TablePaginationEllipsisProps extends ViewProps {
|
|
65
|
+
asChild?: boolean;
|
|
66
|
+
className?: string;
|
|
67
|
+
children?: ReactNode;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface TablePaginationStatusProps extends ViewProps {
|
|
71
|
+
asChild?: boolean;
|
|
72
|
+
className?: string;
|
|
73
|
+
children?: ReactNode;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface TablePaginationPageSizeProps extends ViewProps {
|
|
77
|
+
asChild?: boolean;
|
|
78
|
+
className?: string;
|
|
79
|
+
children?: ReactNode;
|
|
80
|
+
'aria-label'?: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function normalizePageSizeOptions(
|
|
84
|
+
options: readonly TablePaginationPageSizeOption[],
|
|
85
|
+
): { value: number; label: string }[] {
|
|
86
|
+
return options.map((option) =>
|
|
87
|
+
typeof option === 'number' ? { value: option, label: String(option) } : option,
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const TablePaginationRoot = forwardRef<View, TablePaginationProps>(
|
|
92
|
+
(
|
|
93
|
+
{
|
|
94
|
+
asChild,
|
|
95
|
+
className,
|
|
96
|
+
children,
|
|
97
|
+
style,
|
|
98
|
+
page: pageProp,
|
|
99
|
+
defaultPage = 1,
|
|
100
|
+
count = 1,
|
|
101
|
+
onPageChange,
|
|
102
|
+
siblingCount = 1,
|
|
103
|
+
pageSize,
|
|
104
|
+
pageSizeOptions = [25, 50, 100],
|
|
105
|
+
onPageSizeChange,
|
|
106
|
+
disabled = false,
|
|
107
|
+
accessibilityLabel,
|
|
108
|
+
'aria-label': ariaLabel,
|
|
109
|
+
...props
|
|
110
|
+
},
|
|
111
|
+
ref,
|
|
112
|
+
) => {
|
|
113
|
+
const [page, setPage] = useControllableState({
|
|
114
|
+
prop: pageProp,
|
|
115
|
+
defaultProp: defaultPage,
|
|
116
|
+
onChange: onPageChange,
|
|
117
|
+
});
|
|
118
|
+
const resolvedPage = page ?? defaultPage;
|
|
119
|
+
|
|
120
|
+
const goToPage = useCallback(
|
|
121
|
+
(nextPage: number) => {
|
|
122
|
+
if (disabled) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const clamped = Math.min(Math.max(nextPage, 1), Math.max(count, 1));
|
|
126
|
+
setPage(clamped);
|
|
127
|
+
},
|
|
128
|
+
[count, disabled, setPage],
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
const contextValue = useMemo(
|
|
132
|
+
() => ({
|
|
133
|
+
page: resolvedPage,
|
|
134
|
+
count,
|
|
135
|
+
disabled,
|
|
136
|
+
goToPage,
|
|
137
|
+
pageSize,
|
|
138
|
+
pageSizeOptions,
|
|
139
|
+
onPageSizeChange,
|
|
140
|
+
}),
|
|
141
|
+
[resolvedPage, count, disabled, goToPage, pageSize, pageSizeOptions, onPageSizeChange],
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const computedClassName = cn(tablePaginationRootVariants(), className);
|
|
145
|
+
const label = accessibilityLabel ?? ariaLabel ?? 'Table pagination';
|
|
146
|
+
const generatedItems = children
|
|
147
|
+
? null
|
|
148
|
+
: getTablePaginationItems(resolvedPage, count, siblingCount);
|
|
149
|
+
|
|
150
|
+
const content = (
|
|
151
|
+
<>
|
|
152
|
+
{children ?? (
|
|
153
|
+
<>
|
|
154
|
+
<TablePaginationStatus />
|
|
155
|
+
<TablePaginationPrevious />
|
|
156
|
+
{generatedItems?.map((token, index) =>
|
|
157
|
+
token === 'ellipsis' ? (
|
|
158
|
+
<TablePaginationEllipsis key={`ellipsis-${String(index)}`} />
|
|
159
|
+
) : (
|
|
160
|
+
<TablePaginationItem key={token} page={token} current={token === resolvedPage}>
|
|
161
|
+
{token}
|
|
162
|
+
</TablePaginationItem>
|
|
163
|
+
),
|
|
164
|
+
)}
|
|
165
|
+
<TablePaginationNext />
|
|
166
|
+
{pageSize !== undefined ? <TablePaginationPageSize /> : null}
|
|
167
|
+
</>
|
|
168
|
+
)}
|
|
169
|
+
</>
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
return (
|
|
173
|
+
<TablePaginationProvider value={contextValue}>
|
|
174
|
+
{asChild ? (
|
|
175
|
+
<Slot
|
|
176
|
+
ref={ref}
|
|
177
|
+
className={computedClassName}
|
|
178
|
+
style={style}
|
|
179
|
+
{...props}
|
|
180
|
+
{...mergeDataAttributes(props, dataAttributes({ slot: 'table-pagination' }))}
|
|
181
|
+
>
|
|
182
|
+
{content}
|
|
183
|
+
</Slot>
|
|
184
|
+
) : Platform.OS === 'web' ? (
|
|
185
|
+
createElement(
|
|
186
|
+
'nav',
|
|
187
|
+
{
|
|
188
|
+
ref,
|
|
189
|
+
'aria-label': label,
|
|
190
|
+
'data-slot': 'table-pagination',
|
|
191
|
+
},
|
|
192
|
+
<View className={computedClassName} style={style} {...props}>
|
|
193
|
+
{content}
|
|
194
|
+
</View>,
|
|
195
|
+
)
|
|
196
|
+
) : (
|
|
197
|
+
<View
|
|
198
|
+
ref={ref}
|
|
199
|
+
className={computedClassName}
|
|
200
|
+
style={style}
|
|
201
|
+
accessibilityRole="adjustable"
|
|
202
|
+
accessibilityLabel={label}
|
|
203
|
+
accessibilityValue={{ min: 1, max: Math.max(count, 1), now: resolvedPage }}
|
|
204
|
+
{...props}
|
|
205
|
+
{...mergeDataAttributes(props, dataAttributes({ slot: 'table-pagination' }))}
|
|
206
|
+
>
|
|
207
|
+
{content}
|
|
208
|
+
</View>
|
|
209
|
+
)}
|
|
210
|
+
</TablePaginationProvider>
|
|
211
|
+
);
|
|
212
|
+
},
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
TablePaginationRoot.displayName = 'TablePagination';
|
|
216
|
+
|
|
217
|
+
const TablePaginationItem = forwardRef<View, TablePaginationItemProps>(
|
|
218
|
+
(
|
|
219
|
+
{
|
|
220
|
+
asChild,
|
|
221
|
+
className,
|
|
222
|
+
children,
|
|
223
|
+
page: pageProp,
|
|
224
|
+
current = false,
|
|
225
|
+
disabled: disabledProp,
|
|
226
|
+
...props
|
|
227
|
+
},
|
|
228
|
+
ref,
|
|
229
|
+
) => {
|
|
230
|
+
const context = useRequiredTablePaginationContext();
|
|
231
|
+
const isDisabled = disabledProp ?? context.disabled;
|
|
232
|
+
const isCurrent = current || (pageProp !== undefined && pageProp === context.page);
|
|
233
|
+
|
|
234
|
+
const handlePress = composeEventHandlers(props.onPress, () => {
|
|
235
|
+
if (pageProp !== undefined) {
|
|
236
|
+
context.goToPage(pageProp);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
if (asChild) {
|
|
241
|
+
return (
|
|
242
|
+
<Slot
|
|
243
|
+
ref={ref}
|
|
244
|
+
className={cn(tablePaginationItemVariants(), className)}
|
|
245
|
+
{...props}
|
|
246
|
+
onPress={handlePress}
|
|
247
|
+
{...mergeDataAttributes(
|
|
248
|
+
props,
|
|
249
|
+
dataAttributes({ slot: 'table-pagination-item', selected: isCurrent }),
|
|
250
|
+
)}
|
|
251
|
+
>
|
|
252
|
+
{children}
|
|
253
|
+
</Slot>
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return (
|
|
258
|
+
<Button
|
|
259
|
+
ref={ref}
|
|
260
|
+
variant={isCurrent ? 'solid' : 'ghost'}
|
|
261
|
+
color="action"
|
|
262
|
+
size="small"
|
|
263
|
+
isDisabled={isDisabled}
|
|
264
|
+
className={cn(tablePaginationItemVariants(), className)}
|
|
265
|
+
accessibilityState={{ selected: isCurrent, disabled: isDisabled }}
|
|
266
|
+
{...(Platform.OS === 'web' && isCurrent ? { 'aria-current': 'page' } : {})}
|
|
267
|
+
{...props}
|
|
268
|
+
onPress={handlePress}
|
|
269
|
+
{...mergeDataAttributes(
|
|
270
|
+
props,
|
|
271
|
+
dataAttributes({ slot: 'table-pagination-item', selected: isCurrent }),
|
|
272
|
+
)}
|
|
273
|
+
>
|
|
274
|
+
<Button.Label>{children}</Button.Label>
|
|
275
|
+
</Button>
|
|
276
|
+
);
|
|
277
|
+
},
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
TablePaginationItem.displayName = 'TablePagination.Item';
|
|
281
|
+
|
|
282
|
+
const TablePaginationPrevious = forwardRef<View, TablePaginationControlProps>(
|
|
283
|
+
({ asChild, className, children, disabled: disabledProp, ...props }, ref) => {
|
|
284
|
+
const context = useRequiredTablePaginationContext();
|
|
285
|
+
const isAtStart = context.page <= 1;
|
|
286
|
+
const isDisabled = Boolean(disabledProp || context.disabled || isAtStart);
|
|
287
|
+
const glyph = I18nManager.isRTL ? ChevronRight : ChevronLeft;
|
|
288
|
+
|
|
289
|
+
const handlePress = composeEventHandlers(props.onPress, () => {
|
|
290
|
+
context.goToPage(context.page - 1);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
if (asChild) {
|
|
294
|
+
return (
|
|
295
|
+
<Slot
|
|
296
|
+
ref={ref}
|
|
297
|
+
className={className}
|
|
298
|
+
{...props}
|
|
299
|
+
onPress={handlePress}
|
|
300
|
+
{...mergeDataAttributes(props, dataAttributes({ slot: 'table-pagination-previous' }))}
|
|
301
|
+
>
|
|
302
|
+
{children}
|
|
303
|
+
</Slot>
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return (
|
|
308
|
+
<IconButton
|
|
309
|
+
ref={ref}
|
|
310
|
+
as={glyph}
|
|
311
|
+
variant="ghost"
|
|
312
|
+
color="neutral"
|
|
313
|
+
size="small"
|
|
314
|
+
isDisabled={isDisabled}
|
|
315
|
+
accessibilityLabel="Previous page"
|
|
316
|
+
accessibilityState={{ disabled: isDisabled }}
|
|
317
|
+
className={className}
|
|
318
|
+
{...props}
|
|
319
|
+
onPress={handlePress}
|
|
320
|
+
{...mergeDataAttributes(props, dataAttributes({ slot: 'table-pagination-previous' }))}
|
|
321
|
+
/>
|
|
322
|
+
);
|
|
323
|
+
},
|
|
324
|
+
);
|
|
325
|
+
|
|
326
|
+
TablePaginationPrevious.displayName = 'TablePagination.Previous';
|
|
327
|
+
|
|
328
|
+
const TablePaginationNext = forwardRef<View, TablePaginationControlProps>(
|
|
329
|
+
({ asChild, className, children, disabled: disabledProp, ...props }, ref) => {
|
|
330
|
+
const context = useRequiredTablePaginationContext();
|
|
331
|
+
const isAtEnd = context.page >= context.count;
|
|
332
|
+
const isDisabled = Boolean(disabledProp || context.disabled || isAtEnd);
|
|
333
|
+
const glyph = I18nManager.isRTL ? ChevronLeft : ChevronRight;
|
|
334
|
+
|
|
335
|
+
const handlePress = composeEventHandlers(props.onPress, () => {
|
|
336
|
+
context.goToPage(context.page + 1);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
if (asChild) {
|
|
340
|
+
return (
|
|
341
|
+
<Slot
|
|
342
|
+
ref={ref}
|
|
343
|
+
className={className}
|
|
344
|
+
{...props}
|
|
345
|
+
onPress={handlePress}
|
|
346
|
+
{...mergeDataAttributes(props, dataAttributes({ slot: 'table-pagination-next' }))}
|
|
347
|
+
>
|
|
348
|
+
{children}
|
|
349
|
+
</Slot>
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return (
|
|
354
|
+
<IconButton
|
|
355
|
+
ref={ref}
|
|
356
|
+
as={glyph}
|
|
357
|
+
variant="ghost"
|
|
358
|
+
color="neutral"
|
|
359
|
+
size="small"
|
|
360
|
+
isDisabled={isDisabled}
|
|
361
|
+
accessibilityLabel="Next page"
|
|
362
|
+
accessibilityState={{ disabled: isDisabled }}
|
|
363
|
+
className={className}
|
|
364
|
+
{...props}
|
|
365
|
+
onPress={handlePress}
|
|
366
|
+
{...mergeDataAttributes(props, dataAttributes({ slot: 'table-pagination-next' }))}
|
|
367
|
+
/>
|
|
368
|
+
);
|
|
369
|
+
},
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
TablePaginationNext.displayName = 'TablePagination.Next';
|
|
373
|
+
|
|
374
|
+
const TablePaginationEllipsis = forwardRef<View, TablePaginationEllipsisProps>(
|
|
375
|
+
({ asChild, className, children, style, ...props }, ref) => {
|
|
376
|
+
const computedClassName = cn(tablePaginationEllipsisVariants(), className);
|
|
377
|
+
const Comp = asChild ? Slot : View;
|
|
378
|
+
|
|
379
|
+
return (
|
|
380
|
+
<Comp
|
|
381
|
+
ref={ref}
|
|
382
|
+
className={computedClassName}
|
|
383
|
+
style={style}
|
|
384
|
+
accessibilityElementsHidden
|
|
385
|
+
importantForAccessibility="no-hide-descendants"
|
|
386
|
+
{...(Platform.OS === 'web' ? { 'aria-hidden': true } : {})}
|
|
387
|
+
{...props}
|
|
388
|
+
{...mergeDataAttributes(props, dataAttributes({ slot: 'table-pagination-ellipsis' }))}
|
|
389
|
+
>
|
|
390
|
+
{children ?? (
|
|
391
|
+
<Text size="md" className="text-content-tertiary">
|
|
392
|
+
…
|
|
393
|
+
</Text>
|
|
394
|
+
)}
|
|
395
|
+
</Comp>
|
|
396
|
+
);
|
|
397
|
+
},
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
TablePaginationEllipsis.displayName = 'TablePagination.Ellipsis';
|
|
401
|
+
|
|
402
|
+
const TablePaginationStatus = forwardRef<View, TablePaginationStatusProps>(
|
|
403
|
+
({ asChild, className, children, style, ...props }, ref) => {
|
|
404
|
+
const context = useRequiredTablePaginationContext();
|
|
405
|
+
const total = Math.max(context.count, 1);
|
|
406
|
+
const label = `Page ${String(context.page)} of ${String(total)}`;
|
|
407
|
+
const computedClassName = cn(tablePaginationStatusVariants(), className);
|
|
408
|
+
const Comp = asChild ? Slot : View;
|
|
409
|
+
|
|
410
|
+
return (
|
|
411
|
+
<Comp
|
|
412
|
+
ref={ref}
|
|
413
|
+
className={computedClassName}
|
|
414
|
+
style={style}
|
|
415
|
+
{...(Platform.OS === 'web'
|
|
416
|
+
? { 'aria-live': 'polite' }
|
|
417
|
+
: { accessibilityLiveRegion: 'polite' })}
|
|
418
|
+
{...props}
|
|
419
|
+
{...mergeDataAttributes(props, dataAttributes({ slot: 'table-pagination-status' }))}
|
|
420
|
+
>
|
|
421
|
+
{children ?? (
|
|
422
|
+
<Text size="md" className="text-content-secondary">
|
|
423
|
+
{label}
|
|
424
|
+
</Text>
|
|
425
|
+
)}
|
|
426
|
+
</Comp>
|
|
427
|
+
);
|
|
428
|
+
},
|
|
429
|
+
);
|
|
430
|
+
|
|
431
|
+
TablePaginationStatus.displayName = 'TablePagination.Status';
|
|
432
|
+
|
|
433
|
+
const TablePaginationPageSize = forwardRef<View, TablePaginationPageSizeProps>(
|
|
434
|
+
({ asChild, className, children, 'aria-label': ariaLabel, ...props }, ref) => {
|
|
435
|
+
const context = useRequiredTablePaginationContext();
|
|
436
|
+
const options = normalizePageSizeOptions(context.pageSizeOptions);
|
|
437
|
+
const value = context.pageSize !== undefined ? String(context.pageSize) : undefined;
|
|
438
|
+
const label = ariaLabel ?? 'Rows per page';
|
|
439
|
+
|
|
440
|
+
if (asChild) {
|
|
441
|
+
return (
|
|
442
|
+
<Slot
|
|
443
|
+
ref={ref}
|
|
444
|
+
className={cn(tablePaginationPageSizeVariants(), className)}
|
|
445
|
+
{...props}
|
|
446
|
+
{...mergeDataAttributes(props, dataAttributes({ slot: 'table-pagination-page-size' }))}
|
|
447
|
+
>
|
|
448
|
+
{children}
|
|
449
|
+
</Slot>
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
return (
|
|
454
|
+
<Select
|
|
455
|
+
items={options.map((option) => ({ value: String(option.value), label: option.label }))}
|
|
456
|
+
value={value}
|
|
457
|
+
onValueChange={(next) => context.onPageSizeChange?.(Number(next))}
|
|
458
|
+
disabled={context.disabled}
|
|
459
|
+
size="small"
|
|
460
|
+
accessibilityLabel={label}
|
|
461
|
+
className={cn(tablePaginationPageSizeVariants(), className)}
|
|
462
|
+
{...props}
|
|
463
|
+
{...mergeDataAttributes(props, dataAttributes({ slot: 'table-pagination-page-size' }))}
|
|
464
|
+
>
|
|
465
|
+
<Select.Trigger>
|
|
466
|
+
<Select.Value placeholder="Rows" />
|
|
467
|
+
</Select.Trigger>
|
|
468
|
+
<Select.Content>
|
|
469
|
+
{options.map((option) => (
|
|
470
|
+
<Select.Item key={option.value} value={String(option.value)}>
|
|
471
|
+
<Select.ItemLabel>{option.label}</Select.ItemLabel>
|
|
472
|
+
</Select.Item>
|
|
473
|
+
))}
|
|
474
|
+
</Select.Content>
|
|
475
|
+
</Select>
|
|
476
|
+
);
|
|
477
|
+
},
|
|
478
|
+
);
|
|
479
|
+
|
|
480
|
+
TablePaginationPageSize.displayName = 'TablePagination.PageSize';
|
|
481
|
+
|
|
482
|
+
type TablePaginationCompoundComponent = typeof TablePaginationRoot & {
|
|
483
|
+
Previous: typeof TablePaginationPrevious;
|
|
484
|
+
Next: typeof TablePaginationNext;
|
|
485
|
+
Item: typeof TablePaginationItem;
|
|
486
|
+
Ellipsis: typeof TablePaginationEllipsis;
|
|
487
|
+
Status: typeof TablePaginationStatus;
|
|
488
|
+
PageSize: typeof TablePaginationPageSize;
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
export const TablePagination = Object.assign(TablePaginationRoot, {
|
|
492
|
+
Previous: TablePaginationPrevious,
|
|
493
|
+
Next: TablePaginationNext,
|
|
494
|
+
Item: TablePaginationItem,
|
|
495
|
+
Ellipsis: TablePaginationEllipsis,
|
|
496
|
+
Status: TablePaginationStatus,
|
|
497
|
+
PageSize: TablePaginationPageSize,
|
|
498
|
+
}) as TablePaginationCompoundComponent;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { cva, type VariantProps } from '@cdx-ui/utils';
|
|
2
|
+
|
|
3
|
+
export const tablePaginationRootVariants = cva('flex-row flex-wrap items-center gap-1');
|
|
4
|
+
|
|
5
|
+
export const tablePaginationItemVariants = cva('min-w-9 shrink-0');
|
|
6
|
+
|
|
7
|
+
export const tablePaginationEllipsisVariants = cva(
|
|
8
|
+
'min-w-9 shrink-0 items-center justify-center px-1 body-md text-content-tertiary select-none',
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
export const tablePaginationStatusVariants = cva('me-3 shrink-0 body-md text-content-secondary');
|
|
12
|
+
|
|
13
|
+
export const tablePaginationPageSizeVariants = cva('ms-2 min-w-24');
|
|
14
|
+
|
|
15
|
+
export type TablePaginationVariantProps = VariantProps<typeof tablePaginationRootVariants>;
|
package/src/components/index.ts
CHANGED
package/src/styles.css
CHANGED