@makolabs/ripple 0.0.1-dev.8 → 0.0.1-dev.80
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/dist/adapters/storage/BaseAdapter.d.ts +20 -0
- package/dist/adapters/storage/BaseAdapter.js +171 -0
- package/dist/adapters/storage/S3Adapter.d.ts +21 -0
- package/dist/adapters/storage/S3Adapter.js +194 -0
- package/dist/adapters/storage/index.d.ts +3 -0
- package/dist/adapters/storage/index.js +3 -0
- package/dist/adapters/storage/types.d.ts +102 -0
- package/dist/adapters/storage/types.js +4 -0
- package/dist/charts/Chart.svelte +59 -47
- package/dist/charts/Chart.svelte.d.ts +1 -1
- package/dist/drawer/drawer.js +3 -3
- package/dist/elements/accordion/Accordion.svelte +98 -0
- package/dist/elements/accordion/Accordion.svelte.d.ts +4 -0
- package/dist/elements/accordion/accordion.d.ts +227 -0
- package/dist/elements/accordion/accordion.js +138 -0
- package/dist/elements/alert/Alert.svelte +7 -3
- package/dist/elements/dropdown/Dropdown.svelte +74 -107
- package/dist/elements/dropdown/Select.svelte +81 -62
- package/dist/elements/dropdown/dropdown.js +1 -1
- package/dist/elements/dropdown/select.js +8 -8
- package/dist/elements/file-upload/FileUpload.svelte +17 -95
- package/dist/elements/file-upload/FilesPreview.svelte +93 -0
- package/dist/elements/file-upload/FilesPreview.svelte.d.ts +4 -0
- package/dist/elements/progress/Progress.svelte +83 -25
- package/dist/file-browser/FileBrowser.svelte +837 -0
- package/dist/file-browser/FileBrowser.svelte.d.ts +14 -0
- package/dist/file-browser/index.d.ts +1 -0
- package/dist/file-browser/index.js +1 -0
- package/dist/filters/CompactFilters.svelte +147 -0
- package/dist/filters/CompactFilters.svelte.d.ts +4 -0
- package/dist/filters/index.d.ts +1 -0
- package/dist/filters/index.js +1 -0
- package/dist/forms/Checkbox.svelte +2 -2
- package/dist/forms/DateRange.svelte +21 -21
- package/dist/forms/Input.svelte +3 -3
- package/dist/forms/NumberInput.svelte +1 -1
- package/dist/forms/RadioInputs.svelte +3 -3
- package/dist/forms/Tags.svelte +5 -5
- package/dist/forms/Toggle.svelte +3 -3
- package/dist/forms/slider.js +4 -4
- package/dist/index.d.ts +254 -143
- package/dist/index.js +19 -2
- package/dist/layout/card/MetricCard.svelte +64 -0
- package/dist/layout/card/MetricCard.svelte.d.ts +4 -0
- package/dist/layout/card/StatsCard.svelte +4 -3
- package/dist/layout/card/StatsCard.svelte.d.ts +1 -1
- package/dist/layout/card/metric-card.d.ts +49 -0
- package/dist/layout/card/metric-card.js +10 -0
- package/dist/layout/card/stats-card.d.ts +0 -15
- package/dist/layout/card/stats-card.js +1 -1
- package/dist/layout/sidebar/NavGroup.svelte +8 -9
- package/dist/layout/sidebar/NavItem.svelte +2 -2
- package/dist/layout/sidebar/Sidebar.svelte +102 -49
- package/dist/layout/table/Table.svelte +464 -87
- package/dist/layout/table/Table.svelte.d.ts +1 -1
- package/dist/layout/table/table.d.ts +0 -47
- package/dist/layout/table/table.js +0 -8
- package/dist/layout/tabs/Tab.svelte +9 -6
- package/dist/layout/tabs/Tab.svelte.d.ts +1 -1
- package/dist/layout/tabs/TabContent.svelte +1 -2
- package/dist/layout/tabs/TabContent.svelte.d.ts +1 -1
- package/dist/layout/tabs/TabGroup.svelte +10 -5
- package/dist/layout/tabs/TabGroup.svelte.d.ts +2 -2
- package/dist/layout/tabs/tabs.d.ts +61 -76
- package/dist/layout/tabs/tabs.js +170 -28
- package/dist/modal/Modal.svelte +3 -3
- package/dist/modal/modal.js +3 -3
- package/dist/utils/Portal.svelte +108 -0
- package/dist/utils/Portal.svelte.d.ts +8 -0
- package/dist/utils/dateUtils.d.ts +7 -0
- package/dist/utils/dateUtils.js +26 -0
- package/dist/variants.d.ts +11 -1
- package/dist/variants.js +17 -0
- package/package.json +2 -2
- package/dist/header/pageheaders.d.ts +0 -10
- package/dist/header/pageheaders.js +0 -1
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { cn } from '../../helper/cls.js';
|
|
3
|
-
import { table
|
|
3
|
+
import { table } from './table.js';
|
|
4
|
+
import type { TableProps, SortDirection, SortState } from '../../index.js';
|
|
4
5
|
|
|
5
6
|
let {
|
|
6
7
|
data = [],
|
|
7
8
|
columns = [],
|
|
8
|
-
color = 'default',
|
|
9
|
-
size = 'base',
|
|
10
9
|
bordered = true,
|
|
11
10
|
striped = false,
|
|
12
11
|
pageSize = 10,
|
|
12
|
+
currentPage: externalCurrentPage,
|
|
13
|
+
totalItems,
|
|
13
14
|
selectable = false,
|
|
14
15
|
selected = $bindable([]),
|
|
15
|
-
onrowclick
|
|
16
|
+
onrowclick,
|
|
16
17
|
onsort = () => {},
|
|
17
18
|
onselect = () => {},
|
|
19
|
+
onpagechange,
|
|
20
|
+
onpagesizechange,
|
|
18
21
|
class: classname = '',
|
|
19
22
|
wrapperclass: wrapperClass = '',
|
|
20
23
|
tableclass: tableClass = '',
|
|
@@ -24,56 +27,93 @@
|
|
|
24
27
|
thclass: thClass = '',
|
|
25
28
|
tdclass: tdClass = '',
|
|
26
29
|
footerclass: footerClass = '',
|
|
30
|
+
paginationclass: paginationClass = '',
|
|
27
31
|
rowclass = () => '',
|
|
28
|
-
loading = false
|
|
32
|
+
loading = false,
|
|
33
|
+
expandedContent,
|
|
34
|
+
pagination = true,
|
|
35
|
+
showPagination = true,
|
|
36
|
+
showPageSize = false,
|
|
37
|
+
pageSizeOptions = [5, 10, 25, 50, 100],
|
|
38
|
+
paginationPosition = 'bottom',
|
|
39
|
+
paginationTemplate = 'full'
|
|
29
40
|
}: TableProps<any> = $props();
|
|
30
41
|
|
|
31
42
|
let sortColumn = $state('');
|
|
32
43
|
let sortDirection = $state<SortDirection>(null);
|
|
33
|
-
let
|
|
44
|
+
let internalCurrentPage = $state(externalCurrentPage || 1);
|
|
45
|
+
let internalPageSize = $state(pageSize);
|
|
34
46
|
|
|
35
|
-
//
|
|
36
|
-
|
|
47
|
+
// Use external current page if provided
|
|
48
|
+
$effect(() => {
|
|
49
|
+
if (externalCurrentPage !== undefined) {
|
|
50
|
+
internalCurrentPage = externalCurrentPage;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Pagination is automatically determined by pageSize and pagination prop
|
|
55
|
+
const showPaginationControls = $derived(
|
|
56
|
+
pagination &&
|
|
57
|
+
showPagination &&
|
|
58
|
+
(data.length > internalPageSize || totalItems > internalPageSize)
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
// Calculate total items and pages
|
|
62
|
+
const effectiveTotalItems = $derived(totalItems !== undefined ? totalItems : data.length);
|
|
63
|
+
const totalPages = $derived(Math.ceil(effectiveTotalItems / internalPageSize));
|
|
37
64
|
|
|
38
65
|
const {
|
|
39
|
-
base,
|
|
40
|
-
wrapper,
|
|
66
|
+
base: baseClass,
|
|
67
|
+
wrapper: wrapperBaseClass,
|
|
41
68
|
table: tableBaseClass,
|
|
42
|
-
thead,
|
|
43
|
-
tbody,
|
|
44
|
-
tr,
|
|
45
|
-
th,
|
|
46
|
-
td,
|
|
47
|
-
footer,
|
|
48
|
-
pagination:
|
|
49
|
-
emptyState,
|
|
50
|
-
sortButton,
|
|
51
|
-
sortIcon
|
|
69
|
+
thead: theadBaseClass,
|
|
70
|
+
tbody: tbodyBaseClass,
|
|
71
|
+
tr: trBaseClass,
|
|
72
|
+
th: thBaseClass,
|
|
73
|
+
td: tdBaseClass,
|
|
74
|
+
footer: footerBaseClass,
|
|
75
|
+
pagination: paginationBaseClass,
|
|
76
|
+
emptyState: emptyStateBaseClass,
|
|
77
|
+
sortButton: sortButtonBaseClass,
|
|
78
|
+
sortIcon: sortIconBaseClass
|
|
52
79
|
} = $derived(
|
|
53
80
|
table({
|
|
54
|
-
size,
|
|
55
|
-
color,
|
|
56
81
|
bordered,
|
|
57
82
|
striped
|
|
58
83
|
})
|
|
59
84
|
);
|
|
60
85
|
|
|
61
|
-
const baseClasses = $derived(cn(
|
|
62
|
-
const wrapperClasses = $derived(cn(
|
|
86
|
+
const baseClasses = $derived(cn(baseClass(), classname));
|
|
87
|
+
const wrapperClasses = $derived(cn(wrapperBaseClass(), wrapperClass));
|
|
63
88
|
const tableClasses = $derived(cn(tableBaseClass(), tableClass));
|
|
64
|
-
const theadClasses = $derived(cn(
|
|
65
|
-
const tbodyClasses = $derived(cn(
|
|
66
|
-
const trClasses = $derived(cn(
|
|
67
|
-
const thClasses = $derived(cn(
|
|
68
|
-
const tdClasses = $derived(cn(
|
|
69
|
-
const footerClasses = $derived(cn(
|
|
70
|
-
const
|
|
89
|
+
const theadClasses = $derived(cn(theadBaseClass(), theadClass));
|
|
90
|
+
const tbodyClasses = $derived(cn(tbodyBaseClass(), tbodyClass));
|
|
91
|
+
const trClasses = $derived(cn(trBaseClass(), trClass));
|
|
92
|
+
const thClasses = $derived(cn(thBaseClass(), thClass));
|
|
93
|
+
const tdClasses = $derived(cn(tdBaseClass(), tdClass));
|
|
94
|
+
const footerClasses = $derived(cn(footerBaseClass(), footerClass));
|
|
95
|
+
const paginationClasses = $derived(cn(paginationBaseClass(), paginationClass));
|
|
96
|
+
const emptyStateClasses = $derived(emptyStateBaseClass());
|
|
71
97
|
|
|
72
98
|
// Handle pagination
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
pagination
|
|
76
|
-
|
|
99
|
+
function getPaginatedData() {
|
|
100
|
+
// If no pagination or all data fits on one page, return all data
|
|
101
|
+
if (!pagination || data.length <= internalPageSize) {
|
|
102
|
+
return data;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// If external data source might be handling pagination
|
|
106
|
+
if (totalItems !== undefined) {
|
|
107
|
+
// If data.length is less than or equal to pageSize, assume it's already paginated
|
|
108
|
+
if (data.length <= internalPageSize) {
|
|
109
|
+
return data;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Otherwise, handle pagination internally
|
|
114
|
+
const startIndex = (internalCurrentPage - 1) * internalPageSize;
|
|
115
|
+
return data.slice(startIndex, startIndex + internalPageSize);
|
|
116
|
+
}
|
|
77
117
|
|
|
78
118
|
// Handle sorting
|
|
79
119
|
function toggleSort(column: string) {
|
|
@@ -117,35 +157,271 @@
|
|
|
117
157
|
}
|
|
118
158
|
|
|
119
159
|
function handleRowClick(row: any, index: number) {
|
|
120
|
-
onrowclick(row, index);
|
|
160
|
+
onrowclick?.(row, index);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function goToFirstPage() {
|
|
164
|
+
if (internalCurrentPage !== 1) {
|
|
165
|
+
internalCurrentPage = 1;
|
|
166
|
+
onpagechange?.(internalCurrentPage);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function goToLastPage() {
|
|
171
|
+
if (internalCurrentPage !== totalPages) {
|
|
172
|
+
internalCurrentPage = totalPages;
|
|
173
|
+
onpagechange?.(internalCurrentPage);
|
|
174
|
+
}
|
|
121
175
|
}
|
|
122
176
|
|
|
123
177
|
function nextPage() {
|
|
124
|
-
if (
|
|
125
|
-
|
|
178
|
+
if (internalCurrentPage < totalPages) {
|
|
179
|
+
internalCurrentPage++;
|
|
180
|
+
onpagechange?.(internalCurrentPage);
|
|
126
181
|
}
|
|
127
182
|
}
|
|
128
183
|
|
|
129
184
|
function prevPage() {
|
|
130
|
-
if (
|
|
131
|
-
|
|
185
|
+
if (internalCurrentPage > 1) {
|
|
186
|
+
internalCurrentPage--;
|
|
187
|
+
onpagechange?.(internalCurrentPage);
|
|
132
188
|
}
|
|
133
189
|
}
|
|
134
190
|
|
|
135
191
|
function goToPage(page: number) {
|
|
136
|
-
if (page >= 1 && page <= totalPages) {
|
|
137
|
-
|
|
192
|
+
if (page >= 1 && page <= totalPages && page !== internalCurrentPage) {
|
|
193
|
+
internalCurrentPage = page;
|
|
194
|
+
onpagechange?.(internalCurrentPage);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function handlePageSizeChange(event: Event) {
|
|
199
|
+
const select = event.target as HTMLSelectElement;
|
|
200
|
+
const newPageSize = parseInt(select.value, 10);
|
|
201
|
+
internalPageSize = newPageSize;
|
|
202
|
+
|
|
203
|
+
// Adjust current page if it would exceed the new total pages
|
|
204
|
+
const newTotalPages = Math.ceil(effectiveTotalItems / newPageSize);
|
|
205
|
+
if (internalCurrentPage > newTotalPages) {
|
|
206
|
+
internalCurrentPage = newTotalPages || 1;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
onpagesizechange?.(newPageSize);
|
|
210
|
+
onpagechange?.(internalCurrentPage);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function getPageNumbers(): number[] {
|
|
214
|
+
const pages: number[] = [];
|
|
215
|
+
const maxPages = 5;
|
|
216
|
+
const halfMax = Math.floor(maxPages / 2);
|
|
217
|
+
|
|
218
|
+
let start = Math.max(1, internalCurrentPage - halfMax);
|
|
219
|
+
let end = Math.min(totalPages, start + maxPages - 1);
|
|
220
|
+
|
|
221
|
+
if (end - start + 1 < maxPages) {
|
|
222
|
+
start = Math.max(1, end - maxPages + 1);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
for (let i = start; i <= end; i++) {
|
|
226
|
+
pages.push(i);
|
|
138
227
|
}
|
|
228
|
+
|
|
229
|
+
return pages;
|
|
139
230
|
}
|
|
140
231
|
</script>
|
|
141
232
|
|
|
142
233
|
<div class={baseClasses}>
|
|
234
|
+
{#if showPaginationControls && (paginationPosition === 'top' || paginationPosition === 'both')}
|
|
235
|
+
<div class={footerClasses}>
|
|
236
|
+
<div class={paginationClasses}>
|
|
237
|
+
<div class="flex items-center gap-2">
|
|
238
|
+
{#if showPageSize}
|
|
239
|
+
<div class="flex items-center gap-2">
|
|
240
|
+
<label for="table-page-size" class="text-default-500 text-sm">Show</label>
|
|
241
|
+
<select
|
|
242
|
+
id="table-page-size"
|
|
243
|
+
class="border-default-200 rounded-md border px-2 py-1 text-sm"
|
|
244
|
+
value={internalPageSize}
|
|
245
|
+
onchange={handlePageSizeChange}
|
|
246
|
+
>
|
|
247
|
+
{#each pageSizeOptions as option}
|
|
248
|
+
<option value={option}>{option}</option>
|
|
249
|
+
{/each}
|
|
250
|
+
</select>
|
|
251
|
+
<span class="text-default-500 text-sm">entries</span>
|
|
252
|
+
</div>
|
|
253
|
+
{/if}
|
|
254
|
+
<span class="text-default-500 text-sm">
|
|
255
|
+
Showing {Math.min(
|
|
256
|
+
(internalCurrentPage - 1) * internalPageSize + 1,
|
|
257
|
+
effectiveTotalItems
|
|
258
|
+
)}
|
|
259
|
+
to {Math.min(internalCurrentPage * internalPageSize, effectiveTotalItems)} of {effectiveTotalItems}
|
|
260
|
+
entries
|
|
261
|
+
</span>
|
|
262
|
+
</div>
|
|
263
|
+
|
|
264
|
+
<div class="flex items-center gap-1">
|
|
265
|
+
{#if paginationTemplate === 'full'}
|
|
266
|
+
<!-- First page button -->
|
|
267
|
+
<button
|
|
268
|
+
type="button"
|
|
269
|
+
class={cn(
|
|
270
|
+
'relative inline-flex items-center rounded-md px-2 py-1 text-sm font-medium',
|
|
271
|
+
internalCurrentPage === 1
|
|
272
|
+
? 'text-default-300 cursor-not-allowed'
|
|
273
|
+
: 'text-default-700 hover:bg-default-100'
|
|
274
|
+
)}
|
|
275
|
+
onclick={goToFirstPage}
|
|
276
|
+
disabled={internalCurrentPage === 1}
|
|
277
|
+
aria-label="First page"
|
|
278
|
+
>
|
|
279
|
+
<!-- Double Chevron Left SVG -->
|
|
280
|
+
<svg
|
|
281
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
282
|
+
width="16"
|
|
283
|
+
height="16"
|
|
284
|
+
viewBox="0 0 24 24"
|
|
285
|
+
fill="none"
|
|
286
|
+
stroke="currentColor"
|
|
287
|
+
stroke-width="2"
|
|
288
|
+
stroke-linecap="round"
|
|
289
|
+
stroke-linejoin="round"
|
|
290
|
+
class="h-4 w-4"
|
|
291
|
+
>
|
|
292
|
+
<path d="m11 17-5-5 5-5"></path>
|
|
293
|
+
<path d="m18 17-5-5 5-5"></path>
|
|
294
|
+
</svg>
|
|
295
|
+
</button>
|
|
296
|
+
{/if}
|
|
297
|
+
|
|
298
|
+
<!-- Previous page button -->
|
|
299
|
+
<button
|
|
300
|
+
type="button"
|
|
301
|
+
class={cn(
|
|
302
|
+
'relative inline-flex items-center rounded-md px-2 py-1 text-sm font-medium',
|
|
303
|
+
internalCurrentPage === 1
|
|
304
|
+
? 'text-default-300 cursor-not-allowed'
|
|
305
|
+
: 'text-default-700 hover:bg-default-100'
|
|
306
|
+
)}
|
|
307
|
+
onclick={prevPage}
|
|
308
|
+
disabled={internalCurrentPage === 1}
|
|
309
|
+
aria-label="Previous page"
|
|
310
|
+
>
|
|
311
|
+
<!-- Chevron Left SVG -->
|
|
312
|
+
<svg
|
|
313
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
314
|
+
width="16"
|
|
315
|
+
height="16"
|
|
316
|
+
viewBox="0 0 24 24"
|
|
317
|
+
fill="none"
|
|
318
|
+
stroke="currentColor"
|
|
319
|
+
stroke-width="2"
|
|
320
|
+
stroke-linecap="round"
|
|
321
|
+
stroke-linejoin="round"
|
|
322
|
+
class="h-4 w-4"
|
|
323
|
+
>
|
|
324
|
+
<path d="m15 18-6-6 6-6"></path>
|
|
325
|
+
</svg>
|
|
326
|
+
</button>
|
|
327
|
+
|
|
328
|
+
<!-- Page numbers -->
|
|
329
|
+
{#if paginationTemplate === 'full'}
|
|
330
|
+
{#each getPageNumbers() as pageNum}
|
|
331
|
+
<button
|
|
332
|
+
type="button"
|
|
333
|
+
class={cn(
|
|
334
|
+
'relative inline-flex items-center rounded-md px-3 py-1 text-sm font-medium',
|
|
335
|
+
internalCurrentPage === pageNum
|
|
336
|
+
? 'bg-primary-100 text-primary-700'
|
|
337
|
+
: 'text-default-700 hover:bg-default-100'
|
|
338
|
+
)}
|
|
339
|
+
onclick={() => goToPage(pageNum)}
|
|
340
|
+
aria-label={`Page ${pageNum}`}
|
|
341
|
+
aria-current={internalCurrentPage === pageNum ? 'page' : undefined}
|
|
342
|
+
>
|
|
343
|
+
{pageNum}
|
|
344
|
+
</button>
|
|
345
|
+
{/each}
|
|
346
|
+
{:else}
|
|
347
|
+
<span class="text-default-500 px-2 text-sm">
|
|
348
|
+
Page {internalCurrentPage} of {totalPages}
|
|
349
|
+
</span>
|
|
350
|
+
{/if}
|
|
351
|
+
|
|
352
|
+
<!-- Next page button -->
|
|
353
|
+
<button
|
|
354
|
+
type="button"
|
|
355
|
+
class={cn(
|
|
356
|
+
'relative inline-flex items-center rounded-md px-2 py-1 text-sm font-medium',
|
|
357
|
+
internalCurrentPage === totalPages
|
|
358
|
+
? 'text-default-300 cursor-not-allowed'
|
|
359
|
+
: 'text-default-700 hover:bg-default-100'
|
|
360
|
+
)}
|
|
361
|
+
onclick={nextPage}
|
|
362
|
+
disabled={internalCurrentPage === totalPages}
|
|
363
|
+
aria-label="Next page"
|
|
364
|
+
>
|
|
365
|
+
<!-- Chevron Right SVG -->
|
|
366
|
+
<svg
|
|
367
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
368
|
+
width="16"
|
|
369
|
+
height="16"
|
|
370
|
+
viewBox="0 0 24 24"
|
|
371
|
+
fill="none"
|
|
372
|
+
stroke="currentColor"
|
|
373
|
+
stroke-width="2"
|
|
374
|
+
stroke-linecap="round"
|
|
375
|
+
stroke-linejoin="round"
|
|
376
|
+
class="h-4 w-4"
|
|
377
|
+
>
|
|
378
|
+
<path d="m9 18 6-6-6-6"></path>
|
|
379
|
+
</svg>
|
|
380
|
+
</button>
|
|
381
|
+
|
|
382
|
+
{#if paginationTemplate === 'full'}
|
|
383
|
+
<!-- Last page button -->
|
|
384
|
+
<button
|
|
385
|
+
type="button"
|
|
386
|
+
class={cn(
|
|
387
|
+
'relative inline-flex items-center rounded-md px-2 py-1 text-sm font-medium',
|
|
388
|
+
internalCurrentPage === totalPages
|
|
389
|
+
? 'text-default-300 cursor-not-allowed'
|
|
390
|
+
: 'text-default-700 hover:bg-default-100'
|
|
391
|
+
)}
|
|
392
|
+
onclick={goToLastPage}
|
|
393
|
+
disabled={internalCurrentPage === totalPages}
|
|
394
|
+
aria-label="Last page"
|
|
395
|
+
>
|
|
396
|
+
<!-- Double Chevron Right SVG -->
|
|
397
|
+
<svg
|
|
398
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
399
|
+
width="16"
|
|
400
|
+
height="16"
|
|
401
|
+
viewBox="0 0 24 24"
|
|
402
|
+
fill="none"
|
|
403
|
+
stroke="currentColor"
|
|
404
|
+
stroke-width="2"
|
|
405
|
+
stroke-linecap="round"
|
|
406
|
+
stroke-linejoin="round"
|
|
407
|
+
class="h-4 w-4"
|
|
408
|
+
>
|
|
409
|
+
<path d="m13 17 5-5-5-5"></path>
|
|
410
|
+
<path d="m6 17 5-5-5-5"></path>
|
|
411
|
+
</svg>
|
|
412
|
+
</button>
|
|
413
|
+
{/if}
|
|
414
|
+
</div>
|
|
415
|
+
</div>
|
|
416
|
+
</div>
|
|
417
|
+
{/if}
|
|
418
|
+
|
|
143
419
|
<div class={wrapperClasses}>
|
|
144
420
|
<table class={tableClasses}>
|
|
145
421
|
<thead class={theadClasses}>
|
|
146
422
|
<tr>
|
|
147
423
|
{#if selectable}
|
|
148
|
-
<th class={thClasses}>
|
|
424
|
+
<th class={cn(thClasses, 'text-center')}>
|
|
149
425
|
<input
|
|
150
426
|
type="checkbox"
|
|
151
427
|
onchange={() => {
|
|
@@ -175,12 +451,12 @@
|
|
|
175
451
|
{#if column.sortable}
|
|
176
452
|
<button
|
|
177
453
|
type="button"
|
|
178
|
-
class={
|
|
454
|
+
class={sortButtonBaseClass()}
|
|
179
455
|
onclick={() => toggleSort(column.sortKey || column.key)}
|
|
180
456
|
aria-label={`Sort by ${column.header}`}
|
|
181
457
|
>
|
|
182
458
|
{column.header}
|
|
183
|
-
<span class={
|
|
459
|
+
<span class={sortIconBaseClass()}>
|
|
184
460
|
{#if sortColumn === (column.sortKey || column.key)}
|
|
185
461
|
{#if sortDirection === 'asc'}
|
|
186
462
|
<svg
|
|
@@ -262,7 +538,7 @@
|
|
|
262
538
|
</div>
|
|
263
539
|
</td>
|
|
264
540
|
</tr>
|
|
265
|
-
{:else if
|
|
541
|
+
{:else if getPaginatedData().length === 0}
|
|
266
542
|
<tr>
|
|
267
543
|
<td
|
|
268
544
|
colspan={selectable ? columns.length + 1 : columns.length}
|
|
@@ -272,18 +548,17 @@
|
|
|
272
548
|
</td>
|
|
273
549
|
</tr>
|
|
274
550
|
{:else}
|
|
275
|
-
{#each
|
|
551
|
+
{#each getPaginatedData() as row, rowIndex}
|
|
276
552
|
<tr
|
|
277
|
-
class={cn(
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
)}
|
|
553
|
+
class={cn(trClasses, rowclass(row, rowIndex), {
|
|
554
|
+
'bg-primary-100': selectable && isRowSelected(row),
|
|
555
|
+
'cursor-pointer': onrowclick
|
|
556
|
+
})}
|
|
282
557
|
onclick={() => handleRowClick(row, rowIndex)}
|
|
283
558
|
aria-selected={selectable && isRowSelected(row)}
|
|
284
559
|
>
|
|
285
560
|
{#if selectable}
|
|
286
|
-
<td class={tdClasses}>
|
|
561
|
+
<td class={cn(tdClasses, 'text-center')}>
|
|
287
562
|
<input
|
|
288
563
|
type="checkbox"
|
|
289
564
|
checked={isRowSelected(row)}
|
|
@@ -315,97 +590,199 @@
|
|
|
315
590
|
</td>
|
|
316
591
|
{/each}
|
|
317
592
|
</tr>
|
|
593
|
+
{#if expandedContent}
|
|
594
|
+
<tr class="expandedContent-row">
|
|
595
|
+
<td colspan={selectable ? columns.length + 1 : columns.length} class="border-0 p-0">
|
|
596
|
+
{@render expandedContent(row)}
|
|
597
|
+
</td>
|
|
598
|
+
</tr>
|
|
599
|
+
{/if}
|
|
318
600
|
{/each}
|
|
319
601
|
{/if}
|
|
320
602
|
</tbody>
|
|
321
603
|
</table>
|
|
322
604
|
</div>
|
|
323
605
|
|
|
324
|
-
{#if
|
|
606
|
+
{#if showPaginationControls && (paginationPosition === 'bottom' || paginationPosition === 'both')}
|
|
325
607
|
<div class={footerClasses}>
|
|
326
|
-
<div class={
|
|
608
|
+
<div class={paginationClasses}>
|
|
327
609
|
<div class="flex items-center gap-2">
|
|
610
|
+
{#if showPageSize}
|
|
611
|
+
<div class="flex items-center gap-2">
|
|
612
|
+
<label for="table-page-size-bottom" class="text-default-500 text-sm">Show</label>
|
|
613
|
+
<select
|
|
614
|
+
id="table-page-size-bottom"
|
|
615
|
+
class="border-default-200 rounded-md border px-2 py-1 text-sm"
|
|
616
|
+
value={internalPageSize}
|
|
617
|
+
onchange={handlePageSizeChange}
|
|
618
|
+
>
|
|
619
|
+
{#each pageSizeOptions as option}
|
|
620
|
+
<option value={option}>{option}</option>
|
|
621
|
+
{/each}
|
|
622
|
+
</select>
|
|
623
|
+
<span class="text-default-500 text-sm">entries</span>
|
|
624
|
+
</div>
|
|
625
|
+
{/if}
|
|
328
626
|
<span class="text-default-500 text-sm">
|
|
329
|
-
Showing {Math.min(
|
|
330
|
-
|
|
627
|
+
Showing {Math.min(
|
|
628
|
+
(internalCurrentPage - 1) * internalPageSize + 1,
|
|
629
|
+
effectiveTotalItems
|
|
630
|
+
)}
|
|
631
|
+
to {Math.min(internalCurrentPage * internalPageSize, effectiveTotalItems)} of {effectiveTotalItems}
|
|
632
|
+
entries
|
|
331
633
|
</span>
|
|
332
634
|
</div>
|
|
333
635
|
|
|
334
636
|
<div class="flex items-center gap-1">
|
|
637
|
+
{#if paginationTemplate === 'full'}
|
|
638
|
+
<!-- First page button -->
|
|
639
|
+
<button
|
|
640
|
+
type="button"
|
|
641
|
+
class={cn(
|
|
642
|
+
'relative inline-flex items-center rounded-md px-2 py-1 text-sm font-medium',
|
|
643
|
+
internalCurrentPage === 1
|
|
644
|
+
? 'text-default-300 cursor-not-allowed'
|
|
645
|
+
: 'text-default-700 hover:bg-default-100'
|
|
646
|
+
)}
|
|
647
|
+
onclick={goToFirstPage}
|
|
648
|
+
disabled={internalCurrentPage === 1}
|
|
649
|
+
aria-label="First page"
|
|
650
|
+
>
|
|
651
|
+
<!-- Double Chevron Left SVG -->
|
|
652
|
+
<svg
|
|
653
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
654
|
+
width="16"
|
|
655
|
+
height="16"
|
|
656
|
+
viewBox="0 0 24 24"
|
|
657
|
+
fill="none"
|
|
658
|
+
stroke="currentColor"
|
|
659
|
+
stroke-width="2"
|
|
660
|
+
stroke-linecap="round"
|
|
661
|
+
stroke-linejoin="round"
|
|
662
|
+
class="h-4 w-4"
|
|
663
|
+
>
|
|
664
|
+
<path d="m11 17-5-5 5-5"></path>
|
|
665
|
+
<path d="m18 17-5-5 5-5"></path>
|
|
666
|
+
</svg>
|
|
667
|
+
</button>
|
|
668
|
+
{/if}
|
|
669
|
+
|
|
670
|
+
<!-- Previous page button -->
|
|
335
671
|
<button
|
|
336
672
|
type="button"
|
|
337
673
|
class={cn(
|
|
338
674
|
'relative inline-flex items-center rounded-md px-2 py-1 text-sm font-medium',
|
|
339
|
-
|
|
675
|
+
internalCurrentPage === 1
|
|
340
676
|
? 'text-default-300 cursor-not-allowed'
|
|
341
677
|
: 'text-default-700 hover:bg-default-100'
|
|
342
678
|
)}
|
|
343
679
|
onclick={prevPage}
|
|
344
|
-
disabled={
|
|
680
|
+
disabled={internalCurrentPage === 1}
|
|
345
681
|
aria-label="Previous page"
|
|
346
682
|
>
|
|
683
|
+
<!-- Chevron Left SVG -->
|
|
347
684
|
<svg
|
|
348
685
|
xmlns="http://www.w3.org/2000/svg"
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
686
|
+
width="16"
|
|
687
|
+
height="16"
|
|
688
|
+
viewBox="0 0 24 24"
|
|
689
|
+
fill="none"
|
|
690
|
+
stroke="currentColor"
|
|
691
|
+
stroke-width="2"
|
|
692
|
+
stroke-linecap="round"
|
|
693
|
+
stroke-linejoin="round"
|
|
694
|
+
class="h-4 w-4"
|
|
352
695
|
>
|
|
353
|
-
<path
|
|
354
|
-
d="M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z"
|
|
355
|
-
/>
|
|
696
|
+
<path d="m15 18-6-6 6-6"></path>
|
|
356
697
|
</svg>
|
|
357
698
|
</button>
|
|
358
699
|
|
|
359
|
-
<!--
|
|
360
|
-
{#
|
|
361
|
-
{
|
|
362
|
-
currentPage <= 3
|
|
363
|
-
? i + 1
|
|
364
|
-
: currentPage >= totalPages - 2
|
|
365
|
-
? totalPages - 4 + i
|
|
366
|
-
: currentPage - 2 + i}
|
|
367
|
-
|
|
368
|
-
{#if pageNum > 0 && pageNum <= totalPages}
|
|
700
|
+
<!-- Page numbers -->
|
|
701
|
+
{#if paginationTemplate === 'full'}
|
|
702
|
+
{#each getPageNumbers() as pageNum}
|
|
369
703
|
<button
|
|
370
704
|
type="button"
|
|
371
705
|
class={cn(
|
|
372
706
|
'relative inline-flex items-center rounded-md px-3 py-1 text-sm font-medium',
|
|
373
|
-
|
|
707
|
+
internalCurrentPage === pageNum
|
|
374
708
|
? 'bg-primary-100 text-primary-700'
|
|
375
709
|
: 'text-default-700 hover:bg-default-100'
|
|
376
710
|
)}
|
|
377
711
|
onclick={() => goToPage(pageNum)}
|
|
378
712
|
aria-label={`Page ${pageNum}`}
|
|
379
|
-
aria-current={
|
|
713
|
+
aria-current={internalCurrentPage === pageNum ? 'page' : undefined}
|
|
380
714
|
>
|
|
381
715
|
{pageNum}
|
|
382
716
|
</button>
|
|
383
|
-
{/
|
|
384
|
-
{
|
|
717
|
+
{/each}
|
|
718
|
+
{:else}
|
|
719
|
+
<span class="text-default-500 px-2 text-sm">
|
|
720
|
+
Page {internalCurrentPage} of {totalPages}
|
|
721
|
+
</span>
|
|
722
|
+
{/if}
|
|
385
723
|
|
|
724
|
+
<!-- Next page button -->
|
|
386
725
|
<button
|
|
387
726
|
type="button"
|
|
388
727
|
class={cn(
|
|
389
728
|
'relative inline-flex items-center rounded-md px-2 py-1 text-sm font-medium',
|
|
390
|
-
|
|
729
|
+
internalCurrentPage === totalPages
|
|
391
730
|
? 'text-default-300 cursor-not-allowed'
|
|
392
731
|
: 'text-default-700 hover:bg-default-100'
|
|
393
732
|
)}
|
|
394
733
|
onclick={nextPage}
|
|
395
|
-
disabled={
|
|
734
|
+
disabled={internalCurrentPage === totalPages}
|
|
396
735
|
aria-label="Next page"
|
|
397
736
|
>
|
|
737
|
+
<!-- Chevron Right SVG -->
|
|
398
738
|
<svg
|
|
399
739
|
xmlns="http://www.w3.org/2000/svg"
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
740
|
+
width="16"
|
|
741
|
+
height="16"
|
|
742
|
+
viewBox="0 0 24 24"
|
|
743
|
+
fill="none"
|
|
744
|
+
stroke="currentColor"
|
|
745
|
+
stroke-width="2"
|
|
746
|
+
stroke-linecap="round"
|
|
747
|
+
stroke-linejoin="round"
|
|
748
|
+
class="h-4 w-4"
|
|
403
749
|
>
|
|
404
|
-
<path
|
|
405
|
-
d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z"
|
|
406
|
-
/>
|
|
750
|
+
<path d="m9 18 6-6-6-6"></path>
|
|
407
751
|
</svg>
|
|
408
752
|
</button>
|
|
753
|
+
|
|
754
|
+
{#if paginationTemplate === 'full'}
|
|
755
|
+
<!-- Last page button -->
|
|
756
|
+
<button
|
|
757
|
+
type="button"
|
|
758
|
+
class={cn(
|
|
759
|
+
'relative inline-flex items-center rounded-md px-2 py-1 text-sm font-medium',
|
|
760
|
+
internalCurrentPage === totalPages
|
|
761
|
+
? 'text-default-300 cursor-not-allowed'
|
|
762
|
+
: 'text-default-700 hover:bg-default-100'
|
|
763
|
+
)}
|
|
764
|
+
onclick={goToLastPage}
|
|
765
|
+
disabled={internalCurrentPage === totalPages}
|
|
766
|
+
aria-label="Last page"
|
|
767
|
+
>
|
|
768
|
+
<!-- Double Chevron Right SVG -->
|
|
769
|
+
<svg
|
|
770
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
771
|
+
width="16"
|
|
772
|
+
height="16"
|
|
773
|
+
viewBox="0 0 24 24"
|
|
774
|
+
fill="none"
|
|
775
|
+
stroke="currentColor"
|
|
776
|
+
stroke-width="2"
|
|
777
|
+
stroke-linecap="round"
|
|
778
|
+
stroke-linejoin="round"
|
|
779
|
+
class="h-4 w-4"
|
|
780
|
+
>
|
|
781
|
+
<path d="m13 17 5-5-5-5"></path>
|
|
782
|
+
<path d="m6 17 5-5-5-5"></path>
|
|
783
|
+
</svg>
|
|
784
|
+
</button>
|
|
785
|
+
{/if}
|
|
409
786
|
</div>
|
|
410
787
|
</div>
|
|
411
788
|
</div>
|