@trycompai/design-system 1.0.28 → 1.0.30
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,22 +1,235 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
+
import {
|
|
4
|
+
Pagination,
|
|
5
|
+
PaginationContent,
|
|
6
|
+
PaginationEllipsis,
|
|
7
|
+
PaginationItem,
|
|
8
|
+
PaginationLink,
|
|
9
|
+
PaginationNext,
|
|
10
|
+
PaginationPrevious,
|
|
11
|
+
} from './pagination';
|
|
12
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './select';
|
|
13
|
+
import { Text } from '../atoms/text';
|
|
14
|
+
|
|
15
|
+
type PaginationConfig = {
|
|
16
|
+
page: number;
|
|
17
|
+
pageCount: number;
|
|
18
|
+
onPageChange: (page: number) => void;
|
|
19
|
+
pageSize?: number;
|
|
20
|
+
pageSizeOptions?: number[];
|
|
21
|
+
onPageSizeChange?: (pageSize: number) => void;
|
|
22
|
+
siblingCount?: number;
|
|
23
|
+
showPrevNext?: boolean;
|
|
24
|
+
showEdges?: boolean;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
type PaginationItemValue = number | 'ellipsis';
|
|
28
|
+
|
|
29
|
+
function getPaginationRange({
|
|
30
|
+
page,
|
|
31
|
+
pageCount,
|
|
32
|
+
siblingCount,
|
|
33
|
+
showEdges,
|
|
34
|
+
}: {
|
|
35
|
+
page: number;
|
|
36
|
+
pageCount: number;
|
|
37
|
+
siblingCount: number;
|
|
38
|
+
showEdges: boolean;
|
|
39
|
+
}): PaginationItemValue[] {
|
|
40
|
+
if (pageCount <= 1) {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const totalNumbers = siblingCount * 2 + (showEdges ? 5 : 3);
|
|
45
|
+
if (pageCount <= totalNumbers) {
|
|
46
|
+
return Array.from({ length: pageCount }, (_, index) => index + 1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const leftSibling = Math.max(page - siblingCount, 1);
|
|
50
|
+
const rightSibling = Math.min(page + siblingCount, pageCount);
|
|
51
|
+
const showLeftEllipsis = showEdges ? leftSibling > 2 : leftSibling > 1;
|
|
52
|
+
const showRightEllipsis = showEdges ? rightSibling < pageCount - 1 : rightSibling < pageCount;
|
|
53
|
+
|
|
54
|
+
const range: PaginationItemValue[] = [];
|
|
55
|
+
if (showEdges) {
|
|
56
|
+
range.push(1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (showLeftEllipsis) {
|
|
60
|
+
range.push('ellipsis');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const start = showEdges ? Math.max(leftSibling, 2) : leftSibling;
|
|
64
|
+
const end = showEdges ? Math.min(rightSibling, pageCount - 1) : rightSibling;
|
|
65
|
+
for (let current = start; current <= end; current += 1) {
|
|
66
|
+
range.push(current);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (showRightEllipsis) {
|
|
70
|
+
range.push('ellipsis');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (showEdges) {
|
|
74
|
+
range.push(pageCount);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return range;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function renderPagination({
|
|
81
|
+
page,
|
|
82
|
+
pageCount,
|
|
83
|
+
onPageChange,
|
|
84
|
+
siblingCount = 1,
|
|
85
|
+
showPrevNext = true,
|
|
86
|
+
showEdges = true,
|
|
87
|
+
}: PaginationConfig) {
|
|
88
|
+
if (pageCount <= 1) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const range = getPaginationRange({
|
|
93
|
+
page,
|
|
94
|
+
pageCount,
|
|
95
|
+
siblingCount,
|
|
96
|
+
showEdges,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<Pagination>
|
|
101
|
+
<PaginationContent>
|
|
102
|
+
{showPrevNext && page > 1 && (
|
|
103
|
+
<PaginationItem>
|
|
104
|
+
<PaginationPrevious
|
|
105
|
+
href="#"
|
|
106
|
+
onClick={(event) => {
|
|
107
|
+
event.preventDefault();
|
|
108
|
+
onPageChange(page - 1);
|
|
109
|
+
}}
|
|
110
|
+
/>
|
|
111
|
+
</PaginationItem>
|
|
112
|
+
)}
|
|
113
|
+
{range.map((item, index) =>
|
|
114
|
+
item === 'ellipsis' ? (
|
|
115
|
+
<PaginationItem key={`ellipsis-${index}`}>
|
|
116
|
+
<PaginationEllipsis />
|
|
117
|
+
</PaginationItem>
|
|
118
|
+
) : (
|
|
119
|
+
<PaginationItem key={item}>
|
|
120
|
+
<PaginationLink
|
|
121
|
+
href="#"
|
|
122
|
+
isActive={item === page}
|
|
123
|
+
onClick={(event) => {
|
|
124
|
+
event.preventDefault();
|
|
125
|
+
onPageChange(item);
|
|
126
|
+
}}
|
|
127
|
+
>
|
|
128
|
+
{item}
|
|
129
|
+
</PaginationLink>
|
|
130
|
+
</PaginationItem>
|
|
131
|
+
),
|
|
132
|
+
)}
|
|
133
|
+
{showPrevNext && page < pageCount && (
|
|
134
|
+
<PaginationItem>
|
|
135
|
+
<PaginationNext
|
|
136
|
+
href="#"
|
|
137
|
+
onClick={(event) => {
|
|
138
|
+
event.preventDefault();
|
|
139
|
+
onPageChange(page + 1);
|
|
140
|
+
}}
|
|
141
|
+
/>
|
|
142
|
+
</PaginationItem>
|
|
143
|
+
)}
|
|
144
|
+
</PaginationContent>
|
|
145
|
+
</Pagination>
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
3
149
|
function Table({
|
|
4
150
|
variant = 'default',
|
|
151
|
+
pagination,
|
|
5
152
|
...props
|
|
6
153
|
}: Omit<React.ComponentProps<'table'>, 'className'> & {
|
|
7
154
|
variant?: 'default' | 'bordered';
|
|
155
|
+
pagination?: PaginationConfig;
|
|
8
156
|
}) {
|
|
157
|
+
const [internalPage, setInternalPage] = React.useState(pagination?.page ?? 1);
|
|
158
|
+
React.useEffect(() => {
|
|
159
|
+
if (pagination && pagination.page !== internalPage) {
|
|
160
|
+
setInternalPage(pagination.page);
|
|
161
|
+
}
|
|
162
|
+
}, [pagination, internalPage]);
|
|
163
|
+
|
|
164
|
+
const paginationContent = pagination
|
|
165
|
+
? renderPagination({
|
|
166
|
+
...pagination,
|
|
167
|
+
page: internalPage,
|
|
168
|
+
onPageChange: (nextPage) => {
|
|
169
|
+
setInternalPage(nextPage);
|
|
170
|
+
pagination.onPageChange(nextPage);
|
|
171
|
+
},
|
|
172
|
+
})
|
|
173
|
+
: null;
|
|
174
|
+
const showPageSizeSelector = Boolean(pagination?.pageSize && pagination?.onPageSizeChange);
|
|
175
|
+
const rawPageSize = pagination?.pageSize ?? 20;
|
|
176
|
+
const pageSizeOptions = pagination?.pageSizeOptions ?? [20, 50, 100];
|
|
177
|
+
const normalizedPageSizeOptions = pageSizeOptions.includes(rawPageSize)
|
|
178
|
+
? pageSizeOptions
|
|
179
|
+
: [rawPageSize, ...pageSizeOptions];
|
|
180
|
+
|
|
9
181
|
return (
|
|
10
182
|
<div
|
|
11
183
|
data-slot="table-container"
|
|
12
184
|
data-variant={variant}
|
|
13
|
-
className="relative w-full
|
|
185
|
+
className="relative w-full data-[variant=bordered]:border data-[variant=bordered]:rounded-lg"
|
|
14
186
|
>
|
|
15
|
-
<table
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
187
|
+
<div data-slot="table-scroll" className="w-full overflow-x-auto">
|
|
188
|
+
<table
|
|
189
|
+
data-slot="table"
|
|
190
|
+
className="w-full caption-bottom text-sm [&_[data-slot=text][data-default-size=true]]:text-sm"
|
|
191
|
+
{...props}
|
|
192
|
+
/>
|
|
193
|
+
</div>
|
|
194
|
+
{paginationContent && (
|
|
195
|
+
<div
|
|
196
|
+
data-slot="table-pagination"
|
|
197
|
+
data-has-size={showPageSizeSelector ? 'true' : 'false'}
|
|
198
|
+
className="grid items-center border-t bg-muted/40 px-3 py-2 data-[variant=bordered]:rounded-b-lg grid-cols-[1fr_auto_1fr] gap-3"
|
|
199
|
+
>
|
|
200
|
+
{showPageSizeSelector && (
|
|
201
|
+
<div
|
|
202
|
+
data-slot="table-pagination-size"
|
|
203
|
+
className="flex items-center gap-2 whitespace-nowrap"
|
|
204
|
+
>
|
|
205
|
+
<Text as="span" size="xs" variant="muted">
|
|
206
|
+
Rows per page
|
|
207
|
+
</Text>
|
|
208
|
+
<div className="w-20">
|
|
209
|
+
<Select
|
|
210
|
+
value={String(rawPageSize)}
|
|
211
|
+
onValueChange={(value) => pagination?.onPageSizeChange?.(Number(value))}
|
|
212
|
+
>
|
|
213
|
+
<SelectTrigger size="sm">
|
|
214
|
+
<SelectValue />
|
|
215
|
+
</SelectTrigger>
|
|
216
|
+
<SelectContent align="start">
|
|
217
|
+
{normalizedPageSizeOptions.map((option) => (
|
|
218
|
+
<SelectItem key={option} value={String(option)}>
|
|
219
|
+
{option}
|
|
220
|
+
</SelectItem>
|
|
221
|
+
))}
|
|
222
|
+
</SelectContent>
|
|
223
|
+
</Select>
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
)}
|
|
227
|
+
<div data-slot="table-pagination-controls" className="flex items-center justify-center">
|
|
228
|
+
{paginationContent}
|
|
229
|
+
</div>
|
|
230
|
+
<div data-slot="table-pagination-spacer" />
|
|
231
|
+
</div>
|
|
232
|
+
)}
|
|
20
233
|
</div>
|
|
21
234
|
);
|
|
22
235
|
}
|
|
@@ -53,7 +53,7 @@ function SheetContent({
|
|
|
53
53
|
<SheetPrimitive.Close
|
|
54
54
|
data-slot="sheet-close"
|
|
55
55
|
render={<Button variant="ghost" size="icon-sm" />}
|
|
56
|
-
className="absolute top-4 right-
|
|
56
|
+
className="absolute top-4 right-6"
|
|
57
57
|
>
|
|
58
58
|
<Close className="size-4" />
|
|
59
59
|
<span className="sr-only">Close</span>
|
|
@@ -65,18 +65,18 @@ function SheetContent({
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
function SheetHeader({ ...props }: Omit<React.ComponentProps<'div'>, 'className'>) {
|
|
68
|
-
return <div data-slot="sheet-header" className="gap-0.5 px-
|
|
68
|
+
return <div data-slot="sheet-header" className="gap-0.5 px-6 pt-4 flex flex-col" {...props} />;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
function SheetBody({ ...props }: Omit<React.ComponentProps<'div'>, 'className'>) {
|
|
72
|
-
return <div data-slot="sheet-body" className="flex-1 min-h-0 overflow-y-auto px-
|
|
72
|
+
return <div data-slot="sheet-body" className="flex-1 min-h-0 overflow-y-auto px-6 py-4" {...props} />;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
function SheetFooter({ ...props }: Omit<React.ComponentProps<'div'>, 'className'>) {
|
|
76
76
|
return (
|
|
77
77
|
<div
|
|
78
78
|
data-slot="sheet-footer"
|
|
79
|
-
className="gap-2 px-
|
|
79
|
+
className="gap-2 px-6 py-4 mt-auto flex flex-col border-t bg-background sticky bottom-0"
|
|
80
80
|
{...props}
|
|
81
81
|
/>
|
|
82
82
|
);
|