@invopop/popui 0.1.4-beta.2 → 0.1.4-beta.20
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/dist/DatePicker.svelte +77 -25
- package/dist/DropdownSelect.svelte +2 -2
- package/dist/InputText.svelte +20 -8
- package/dist/StepIconList.svelte +4 -4
- package/dist/data-table/cells/boolean-cell.svelte +1 -1
- package/dist/data-table/cells/uuid-cell.svelte +15 -0
- package/dist/data-table/cells/uuid-cell.svelte.d.ts +8 -0
- package/dist/data-table/create-columns.js +13 -2
- package/dist/data-table/data-table-pagination.svelte +72 -30
- package/dist/data-table/data-table-svelte.svelte.js +4 -0
- package/dist/data-table/data-table-types.d.ts +18 -3
- package/dist/data-table/data-table.svelte +66 -29
- package/dist/data-table/table-setup.d.ts +6 -4
- package/dist/data-table/table-setup.js +27 -8
- package/dist/data-table/table-styles.d.ts +2 -2
- package/dist/data-table/table-styles.js +18 -8
- package/dist/table/table-cell.svelte +1 -1
- package/dist/table/table-head.svelte +1 -1
- package/dist/table/table-row.svelte +1 -1
- package/dist/table/table.svelte +2 -2
- package/dist/types.d.ts +8 -1
- package/package.json +1 -1
package/dist/DatePicker.svelte
CHANGED
|
@@ -3,13 +3,16 @@
|
|
|
3
3
|
import RangeCalendar from './range-calendar/range-calendar.svelte'
|
|
4
4
|
import { parseDate, type DateValue } from '@internationalized/date'
|
|
5
5
|
import type { DateRange } from 'bits-ui'
|
|
6
|
-
import { Icon } from '@steeze-ui/svelte-icon'
|
|
7
|
-
import { Calendar } from '@invopop/ui-icons'
|
|
6
|
+
import { Icon, type IconSource } from '@steeze-ui/svelte-icon'
|
|
8
7
|
import Transition from 'svelte-transition'
|
|
9
8
|
import type { DatePickerProps } from './types'
|
|
10
9
|
import { clickOutside } from './clickOutside'
|
|
11
10
|
import BaseButton from './BaseButton.svelte'
|
|
12
|
-
import { datesFromToday, toCalendarDate } from './helpers'
|
|
11
|
+
import { datesFromToday, toCalendarDate, resolveIcon } from './helpers'
|
|
12
|
+
import { buttonVariants } from './button/button.svelte'
|
|
13
|
+
import { offset, flip, shift } from 'svelte-floating-ui/dom'
|
|
14
|
+
import { createFloatingActions } from 'svelte-floating-ui'
|
|
15
|
+
import { portal } from 'svelte-portal'
|
|
13
16
|
|
|
14
17
|
const {
|
|
15
18
|
startOfThisWeek,
|
|
@@ -109,23 +112,47 @@
|
|
|
109
112
|
|
|
110
113
|
let {
|
|
111
114
|
label = 'Date',
|
|
112
|
-
|
|
115
|
+
placement = 'bottom-start',
|
|
113
116
|
from = '',
|
|
114
117
|
to = '',
|
|
115
|
-
onSelect
|
|
118
|
+
onSelect,
|
|
119
|
+
stackLeft = false,
|
|
120
|
+
stackRight = false,
|
|
121
|
+
icon = undefined,
|
|
122
|
+
iconTheme = 'default'
|
|
116
123
|
}: DatePickerProps = $props()
|
|
117
124
|
|
|
125
|
+
const [floatingRef, floatingContent] = createFloatingActions({
|
|
126
|
+
strategy: 'absolute',
|
|
127
|
+
placement,
|
|
128
|
+
middleware: [offset(8), flip(), shift()]
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
let resolvedIcon: IconSource | undefined = $state()
|
|
132
|
+
|
|
133
|
+
$effect(() => {
|
|
134
|
+
resolveIcon(icon).then((res) => (resolvedIcon = res))
|
|
135
|
+
})
|
|
136
|
+
|
|
118
137
|
let selectedPeriod = $state('custom')
|
|
119
138
|
let value = $state<DateRange>({
|
|
120
139
|
start: undefined,
|
|
121
140
|
end: undefined
|
|
122
141
|
})
|
|
123
142
|
let isOpen = $state(false)
|
|
143
|
+
let isStacked = $derived(stackLeft || stackRight)
|
|
144
|
+
let hasSelectedDates = $derived(value.start !== undefined)
|
|
124
145
|
let styles = $derived(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
146
|
+
isStacked
|
|
147
|
+
? buttonVariants({
|
|
148
|
+
variant: 'ghost',
|
|
149
|
+
stackedLeft: stackLeft,
|
|
150
|
+
stackedRight: stackRight
|
|
151
|
+
})
|
|
152
|
+
: clsx('border backdrop-blur-sm backdrop-filter', {
|
|
153
|
+
'border-border-selected-bold shadow-active': isOpen,
|
|
154
|
+
'border-border-default-secondary hover:border-border-default-secondary-hover': !isOpen
|
|
155
|
+
})
|
|
129
156
|
)
|
|
130
157
|
let selectedLabel = $state(label)
|
|
131
158
|
|
|
@@ -137,9 +164,19 @@
|
|
|
137
164
|
|
|
138
165
|
$effect(() => {
|
|
139
166
|
if (from) {
|
|
167
|
+
const startDate = parseDate(from)
|
|
168
|
+
const endDate = to ? parseDate(to) : undefined
|
|
169
|
+
|
|
140
170
|
value = {
|
|
141
|
-
start:
|
|
142
|
-
end:
|
|
171
|
+
start: startDate,
|
|
172
|
+
end: endDate
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Update label directly without calling getLabel() to avoid circular dependency
|
|
176
|
+
if (startDate === endDate) {
|
|
177
|
+
selectedLabel = getDisplayFromValue(startDate)
|
|
178
|
+
} else {
|
|
179
|
+
selectedLabel = `${getDisplayFromValue(startDate)} → ${getDisplayFromValue(endDate)}`
|
|
143
180
|
}
|
|
144
181
|
return
|
|
145
182
|
}
|
|
@@ -183,19 +220,34 @@
|
|
|
183
220
|
</script>
|
|
184
221
|
|
|
185
222
|
<div>
|
|
186
|
-
<
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
223
|
+
<button
|
|
224
|
+
use:floatingRef
|
|
225
|
+
onclick={() => {
|
|
226
|
+
isOpen = !isOpen
|
|
227
|
+
}}
|
|
228
|
+
class="{styles} {isStacked
|
|
229
|
+
? 'h-7 py-1.5'
|
|
230
|
+
: 'py-1.5'} datepicker-trigger flex items-center w-full {resolvedIcon
|
|
231
|
+
? 'pl-7'
|
|
232
|
+
: 'pl-2'} pr-2 text-left rounded-lg bg-background cursor-pointer relative overflow-hidden"
|
|
233
|
+
>
|
|
234
|
+
{#if resolvedIcon}
|
|
235
|
+
<Icon
|
|
236
|
+
src={resolvedIcon}
|
|
237
|
+
theme={iconTheme}
|
|
238
|
+
class="h-4 w-4 absolute top-1.5 left-2 text-foreground-default-secondary"
|
|
239
|
+
/>
|
|
240
|
+
{/if}
|
|
241
|
+
<span
|
|
242
|
+
class="flex-1 text-base truncate {hasSelectedDates
|
|
243
|
+
? 'text-foreground'
|
|
244
|
+
: 'text-foreground-default-secondary'}"
|
|
192
245
|
>
|
|
193
246
|
{selectedLabel}
|
|
194
|
-
</
|
|
195
|
-
|
|
196
|
-
</div>
|
|
247
|
+
</span>
|
|
248
|
+
</button>
|
|
197
249
|
|
|
198
|
-
|
|
250
|
+
{#if isOpen}
|
|
199
251
|
<Transition
|
|
200
252
|
show={isOpen}
|
|
201
253
|
enter="transition ease-out duration-100"
|
|
@@ -207,9 +259,9 @@
|
|
|
207
259
|
>
|
|
208
260
|
<!-- @ts-ignore -->
|
|
209
261
|
<div
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
class="bg-background inline-flex flex-col shadow-lg rounded-xl absolute
|
|
262
|
+
use:portal
|
|
263
|
+
use:floatingContent
|
|
264
|
+
class="bg-background inline-flex flex-col shadow-lg rounded-xl absolute z-1001 border border-border"
|
|
213
265
|
use:clickOutside
|
|
214
266
|
onclick_outside={() => {
|
|
215
267
|
if (!isOpen) return
|
|
@@ -239,5 +291,5 @@
|
|
|
239
291
|
</div>
|
|
240
292
|
</div>
|
|
241
293
|
</Transition>
|
|
242
|
-
|
|
294
|
+
{/if}
|
|
243
295
|
</div>
|
|
@@ -76,10 +76,9 @@
|
|
|
76
76
|
function handleClick(val: AnyProp) {
|
|
77
77
|
value = val
|
|
78
78
|
|
|
79
|
-
onSelect?.(value)
|
|
80
|
-
|
|
81
79
|
if (multiple) return
|
|
82
80
|
|
|
81
|
+
onSelect?.(value)
|
|
83
82
|
selectDropdown?.toggle()
|
|
84
83
|
}
|
|
85
84
|
|
|
@@ -90,6 +89,7 @@
|
|
|
90
89
|
if (isEqual(value, val)) return
|
|
91
90
|
|
|
92
91
|
value = val
|
|
92
|
+
onSelect?.(value)
|
|
93
93
|
}
|
|
94
94
|
</script>
|
|
95
95
|
|
package/dist/InputText.svelte
CHANGED
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
disabled = false,
|
|
14
14
|
value = $bindable(''),
|
|
15
15
|
focusOnLoad = false,
|
|
16
|
+
stackLeft = false,
|
|
17
|
+
stackRight = false,
|
|
18
|
+
widthClass = '',
|
|
16
19
|
oninput,
|
|
17
20
|
onkeydown,
|
|
18
21
|
onfocus,
|
|
@@ -30,21 +33,30 @@
|
|
|
30
33
|
}, 750)
|
|
31
34
|
}
|
|
32
35
|
|
|
36
|
+
let isStacked = $derived(stackLeft || stackRight)
|
|
37
|
+
|
|
33
38
|
let inputStyles = $derived(
|
|
34
39
|
clsx(
|
|
35
|
-
'
|
|
40
|
+
'px-2 py-1 text-base tracking-tight bg-background-default-default backdrop-blur-[2px] caret-foreground-accent',
|
|
36
41
|
'placeholder:text-foreground-default-tertiary',
|
|
37
42
|
'outline-none focus:ring-0',
|
|
43
|
+
widthClass,
|
|
38
44
|
{
|
|
45
|
+
// Width defaults
|
|
46
|
+
'w-full': !isStacked && !widthClass,
|
|
47
|
+
// Stacked styles
|
|
48
|
+
'h-[26px] border-0 rounded-none hover:bg-background-default-secondary focus:bg-background-default-default':
|
|
49
|
+
isStacked,
|
|
50
|
+
'rounded-l-lg': isStacked && stackLeft && !stackRight,
|
|
51
|
+
'rounded-r-lg': isStacked && stackRight && !stackLeft,
|
|
52
|
+
// Non-stacked styles
|
|
53
|
+
'h-8 rounded-lg border': !isStacked,
|
|
39
54
|
'pointer-events-none bg-background-default-secondary border-border-default-default':
|
|
40
|
-
disabled
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
'text-foreground-critical border-border-critical-bold caret-foreground-critical': errorText
|
|
44
|
-
},
|
|
45
|
-
{
|
|
55
|
+
!isStacked && disabled,
|
|
56
|
+
'text-foreground-critical border-border-critical-bold caret-foreground-critical':
|
|
57
|
+
!isStacked && errorText,
|
|
46
58
|
'text-foreground border-border-default-secondary hover:border-border-default-secondary-hover focus:border-border-selected-bold focus:shadow-active':
|
|
47
|
-
!errorText && !disabled
|
|
59
|
+
!isStacked && !errorText && !disabled
|
|
48
60
|
}
|
|
49
61
|
)
|
|
50
62
|
)
|
package/dist/StepIconList.svelte
CHANGED
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
{/snippet}
|
|
15
15
|
|
|
16
16
|
<TooltipProvider>
|
|
17
|
-
<div class="flex flex-col space-y-2 sm:flex-row sm:space-y-0 items-center">
|
|
17
|
+
<div class="flex flex-col space-y-2 sm:flex-row sm:flex-nowrap sm:space-y-0 items-center">
|
|
18
18
|
{#each mainIcons as icon, i (i)}
|
|
19
19
|
<Tooltip>
|
|
20
20
|
<TooltipTrigger class="shrink-0">
|
|
21
21
|
<div
|
|
22
|
-
class="p-1.5 rounded-md border border-border flex items-center space-x-1 bg-background text-icon"
|
|
22
|
+
class="p-1.5 rounded-md border border-border flex items-center space-x-1 bg-background text-icon shrink-0"
|
|
23
23
|
>
|
|
24
|
-
<img src={icon.url} alt={icon.name} class="size-4" />
|
|
24
|
+
<img src={icon.url} alt={icon.name} class="size-4 shrink-0" />
|
|
25
25
|
</div>
|
|
26
26
|
</TooltipTrigger>
|
|
27
27
|
<TooltipContent>{icon.name}</TooltipContent>
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
{@render separator()}
|
|
36
36
|
<Tooltip>
|
|
37
37
|
<TooltipTrigger class="shrink-0">
|
|
38
|
-
<div class="flex items-center justify-center text-icon font-medium text-base size-7">
|
|
38
|
+
<div class="flex items-center justify-center text-icon font-medium text-base size-7 shrink-0">
|
|
39
39
|
+{restIcons.length}
|
|
40
40
|
</div>
|
|
41
41
|
</TooltipTrigger>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import ButtonUuidCopy from '../../ButtonUuidCopy.svelte'
|
|
3
|
+
import type { UuidCellConfig } from '../data-table-types.js'
|
|
4
|
+
|
|
5
|
+
let { value, config }: { value: string; config?: UuidCellConfig } = $props()
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<ButtonUuidCopy
|
|
9
|
+
uuid={value}
|
|
10
|
+
prefixLength={config?.prefixLength}
|
|
11
|
+
suffixLength={config?.suffixLength}
|
|
12
|
+
full={config?.full}
|
|
13
|
+
disabled={config?.disabled}
|
|
14
|
+
oncopied={config?.onCopy}
|
|
15
|
+
/>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { UuidCellConfig } from '../data-table-types.js';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
value: string;
|
|
4
|
+
config?: UuidCellConfig;
|
|
5
|
+
};
|
|
6
|
+
declare const UuidCell: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
|
+
type UuidCell = ReturnType<typeof UuidCell>;
|
|
8
|
+
export default UuidCell;
|
|
@@ -4,6 +4,8 @@ import BooleanCell from './cells/boolean-cell.svelte';
|
|
|
4
4
|
import TagCell from './cells/tag-cell.svelte';
|
|
5
5
|
import DateCell from './cells/date-cell.svelte';
|
|
6
6
|
import CurrencyCell from './cells/currency-cell.svelte';
|
|
7
|
+
import UuidCell from './cells/uuid-cell.svelte';
|
|
8
|
+
import { renderSnippet } from './render-helpers.js';
|
|
7
9
|
export function createColumns(columns) {
|
|
8
10
|
return columns.map((col) => {
|
|
9
11
|
const tanstackCol = {
|
|
@@ -19,10 +21,17 @@ export function createColumns(columns) {
|
|
|
19
21
|
};
|
|
20
22
|
// Cell renderer
|
|
21
23
|
if (col.cell) {
|
|
22
|
-
// Custom cell renderer
|
|
24
|
+
// Custom cell renderer - can be a Snippet or a function
|
|
23
25
|
tanstackCol.cell = ({ row }) => {
|
|
24
26
|
const value = col.accessorKey ? row.original[col.accessorKey] : undefined;
|
|
25
|
-
|
|
27
|
+
// Check if it's a function or a Snippet
|
|
28
|
+
if (typeof col.cell === 'function') {
|
|
29
|
+
return col.cell(value, row.original);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
// It's a Snippet, render it with the row data
|
|
33
|
+
return renderSnippet(col.cell, row.original);
|
|
34
|
+
}
|
|
26
35
|
};
|
|
27
36
|
}
|
|
28
37
|
else if (col.cellType) {
|
|
@@ -40,6 +49,8 @@ export function createColumns(columns) {
|
|
|
40
49
|
return renderComponent(DateCell, { value: value, config: col.cellConfig });
|
|
41
50
|
case 'currency':
|
|
42
51
|
return renderComponent(CurrencyCell, { value: value, config: col.cellConfig });
|
|
52
|
+
case 'uuid':
|
|
53
|
+
return renderComponent(UuidCell, { value: value, config: col.cellConfig });
|
|
43
54
|
default:
|
|
44
55
|
return value;
|
|
45
56
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import Button from '../button/button.svelte'
|
|
3
3
|
import InputSelect from '../InputSelect.svelte'
|
|
4
|
+
import InputText from '../InputText.svelte'
|
|
4
5
|
import { ArrowLeft, ArrowRight, ScrollLeft, ScrollRight } from '@invopop/ui-icons'
|
|
5
6
|
import { cn } from '../utils.js'
|
|
6
7
|
import type { DataTablePaginationProps } from './data-table-types.js'
|
|
@@ -16,26 +17,37 @@
|
|
|
16
17
|
selectedSlot,
|
|
17
18
|
unselectedSlot,
|
|
18
19
|
onPageChange,
|
|
19
|
-
onPageSizeChange
|
|
20
|
+
onPageSizeChange,
|
|
21
|
+
data,
|
|
22
|
+
rowCount,
|
|
23
|
+
manualPagination
|
|
20
24
|
}: DataTablePaginationProps<any> = $props()
|
|
21
25
|
|
|
22
26
|
let currentPage = $derived(table.getState().pagination.pageIndex + 1)
|
|
23
|
-
let totalPages = $derived(table.getPageCount())
|
|
24
|
-
let totalItems = $derived(table.getFilteredRowModel().rows.length)
|
|
25
27
|
let rowsPerPage = $derived(table.getState().pagination.pageSize)
|
|
28
|
+
let totalItems = $derived.by(() => {
|
|
29
|
+
// Use direct props for reactivity
|
|
30
|
+
if (manualPagination && rowCount !== undefined) {
|
|
31
|
+
return rowCount
|
|
32
|
+
}
|
|
33
|
+
// For client-side pagination, use data length directly
|
|
34
|
+
return data?.length ?? 0
|
|
35
|
+
})
|
|
36
|
+
// Calculate totalPages from reactive values instead of calling table.getPageCount()
|
|
37
|
+
let totalPages = $derived(Math.ceil(totalItems / rowsPerPage) || 1)
|
|
26
38
|
let hasSelection = $derived(Object.keys(table.getState().rowSelection).length > 0)
|
|
27
39
|
|
|
28
40
|
let pageInputValue = $derived(`${currentPage}`)
|
|
29
41
|
|
|
30
|
-
function handlePageInput(
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
42
|
+
function handlePageInput(value: string) {
|
|
43
|
+
const numValue = parseInt(value)
|
|
44
|
+
if (numValue >= 1 && numValue <= totalPages) {
|
|
45
|
+
if (manualPagination) {
|
|
46
|
+
table.setPagination({ pageIndex: numValue - 1, pageSize: rowsPerPage })
|
|
47
|
+
} else {
|
|
48
|
+
table.setPageIndex(numValue - 1)
|
|
49
|
+
}
|
|
50
|
+
onPageChange?.(numValue)
|
|
39
51
|
}
|
|
40
52
|
}
|
|
41
53
|
|
|
@@ -43,9 +55,14 @@
|
|
|
43
55
|
const target = event.target as HTMLInputElement
|
|
44
56
|
const value = parseInt(target.value)
|
|
45
57
|
if (isNaN(value) || value < 1) {
|
|
46
|
-
|
|
58
|
+
target.value = `${currentPage}`
|
|
47
59
|
} else if (value > totalPages) {
|
|
48
|
-
|
|
60
|
+
target.value = `${totalPages}`
|
|
61
|
+
if (manualPagination) {
|
|
62
|
+
table.setPagination({ pageIndex: totalPages - 1, pageSize: rowsPerPage })
|
|
63
|
+
} else {
|
|
64
|
+
table.setPageIndex(totalPages - 1)
|
|
65
|
+
}
|
|
49
66
|
onPageChange?.(totalPages)
|
|
50
67
|
}
|
|
51
68
|
}
|
|
@@ -71,7 +88,11 @@
|
|
|
71
88
|
size="md"
|
|
72
89
|
icon={ScrollLeft}
|
|
73
90
|
onclick={() => {
|
|
74
|
-
|
|
91
|
+
if (manualPagination) {
|
|
92
|
+
table.setPagination({ pageIndex: 0, pageSize: rowsPerPage })
|
|
93
|
+
} else {
|
|
94
|
+
table.setPageIndex(0)
|
|
95
|
+
}
|
|
75
96
|
onPageChange?.(1)
|
|
76
97
|
}}
|
|
77
98
|
disabled={currentPage === 1}
|
|
@@ -84,7 +105,13 @@
|
|
|
84
105
|
icon={ArrowLeft}
|
|
85
106
|
onclick={() => {
|
|
86
107
|
const newPage = currentPage - 1
|
|
87
|
-
|
|
108
|
+
if (manualPagination) {
|
|
109
|
+
// For manual pagination, bypass TanStack's navigation and use setPagination directly
|
|
110
|
+
// to avoid clamping issues with stale pageCount
|
|
111
|
+
table.setPagination({ pageIndex: newPage - 1, pageSize: rowsPerPage })
|
|
112
|
+
} else {
|
|
113
|
+
table.previousPage()
|
|
114
|
+
}
|
|
88
115
|
onPageChange?.(newPage)
|
|
89
116
|
}}
|
|
90
117
|
disabled={currentPage === 1}
|
|
@@ -93,16 +120,19 @@
|
|
|
93
120
|
/>
|
|
94
121
|
</div>
|
|
95
122
|
<div class="flex items-center gap-1.5">
|
|
96
|
-
<
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
123
|
+
<div
|
|
124
|
+
class="w-12 [&>div]:gap-0 [&_input]:!h-7 [&_input]:[appearance:textfield] [&_input]:[&::-webkit-outer-spin-button]:appearance-none [&_input]:[&::-webkit-inner-spin-button]:appearance-none"
|
|
125
|
+
>
|
|
126
|
+
<InputText
|
|
127
|
+
bind:value={pageInputValue}
|
|
128
|
+
type="number"
|
|
129
|
+
min="1"
|
|
130
|
+
max={totalPages}
|
|
131
|
+
oninput={handlePageInput}
|
|
132
|
+
onblur={handlePageBlur}
|
|
133
|
+
/>
|
|
134
|
+
</div>
|
|
135
|
+
<span class="text-base text-foreground-default-secondary whitespace-nowrap">
|
|
106
136
|
/ {totalPages}
|
|
107
137
|
</span>
|
|
108
138
|
</div>
|
|
@@ -113,7 +143,13 @@
|
|
|
113
143
|
icon={ArrowRight}
|
|
114
144
|
onclick={() => {
|
|
115
145
|
const newPage = currentPage + 1
|
|
116
|
-
|
|
146
|
+
if (manualPagination) {
|
|
147
|
+
// For manual pagination, bypass TanStack's navigation and use setPagination directly
|
|
148
|
+
// to avoid clamping issues with stale pageCount
|
|
149
|
+
table.setPagination({ pageIndex: newPage - 1, pageSize: rowsPerPage })
|
|
150
|
+
} else {
|
|
151
|
+
table.nextPage()
|
|
152
|
+
}
|
|
117
153
|
onPageChange?.(newPage)
|
|
118
154
|
}}
|
|
119
155
|
disabled={currentPage === totalPages}
|
|
@@ -125,7 +161,11 @@
|
|
|
125
161
|
size="md"
|
|
126
162
|
icon={ScrollRight}
|
|
127
163
|
onclick={() => {
|
|
128
|
-
|
|
164
|
+
if (manualPagination) {
|
|
165
|
+
table.setPagination({ pageIndex: totalPages - 1, pageSize: rowsPerPage })
|
|
166
|
+
} else {
|
|
167
|
+
table.setPageIndex(totalPages - 1)
|
|
168
|
+
}
|
|
129
169
|
onPageChange?.(totalPages)
|
|
130
170
|
}}
|
|
131
171
|
disabled={currentPage === totalPages}
|
|
@@ -135,7 +175,7 @@
|
|
|
135
175
|
</div>
|
|
136
176
|
</div>
|
|
137
177
|
{#if showRowsPerPage}
|
|
138
|
-
<div class="w-[105px]">
|
|
178
|
+
<div class="w-[105px] [&_select]:!h-7 [&_select]:!py-[4px]">
|
|
139
179
|
<InputSelect
|
|
140
180
|
value={`${rowsPerPage}`}
|
|
141
181
|
options={rowsPerPageOptions.map((size) => ({
|
|
@@ -145,7 +185,9 @@
|
|
|
145
185
|
onchange={(value) => {
|
|
146
186
|
const size = Number(value)
|
|
147
187
|
table.setPageSize(size)
|
|
188
|
+
table.setPageIndex(0)
|
|
148
189
|
onPageSizeChange?.(size)
|
|
190
|
+
onPageChange?.(1)
|
|
149
191
|
}}
|
|
150
192
|
placeholder="Rows per page"
|
|
151
193
|
disablePlaceholder={true}
|
|
@@ -155,7 +197,7 @@
|
|
|
155
197
|
{/if}
|
|
156
198
|
</div>
|
|
157
199
|
{#if totalItems > 0}
|
|
158
|
-
<span class="text-
|
|
200
|
+
<span class="text-base text-foreground-default-secondary">
|
|
159
201
|
{formatNumber(totalItems)}
|
|
160
202
|
{itemsLabel}
|
|
161
203
|
</span>
|
|
@@ -53,6 +53,10 @@ export function createSvelteTable(options) {
|
|
|
53
53
|
}
|
|
54
54
|
updateOptions();
|
|
55
55
|
$effect.pre(() => {
|
|
56
|
+
// Access data and columns to track them - this reads but doesn't write
|
|
57
|
+
// so it won't cause infinite loops
|
|
58
|
+
void options.data;
|
|
59
|
+
void options.columns;
|
|
56
60
|
updateOptions();
|
|
57
61
|
});
|
|
58
62
|
return table;
|
|
@@ -2,7 +2,7 @@ import type { Component, Snippet } from 'svelte';
|
|
|
2
2
|
import type { StatusType, AnyProp, TableAction, EmptyStateProps } from '../types.js';
|
|
3
3
|
import type { IconSource } from '@steeze-ui/svelte-icon';
|
|
4
4
|
import type { Table } from '@tanstack/table-core';
|
|
5
|
-
export type CellType = 'text' | 'boolean' | 'tag' | 'date' | 'currency' | 'custom';
|
|
5
|
+
export type CellType = 'text' | 'boolean' | 'tag' | 'date' | 'currency' | 'uuid' | 'custom';
|
|
6
6
|
export interface TextCellConfig {
|
|
7
7
|
className?: string;
|
|
8
8
|
}
|
|
@@ -26,14 +26,21 @@ export interface DateCellConfig {
|
|
|
26
26
|
export interface CurrencyCellConfig {
|
|
27
27
|
className?: string;
|
|
28
28
|
}
|
|
29
|
-
export
|
|
29
|
+
export interface UuidCellConfig {
|
|
30
|
+
prefixLength?: number;
|
|
31
|
+
suffixLength?: number;
|
|
32
|
+
full?: boolean;
|
|
33
|
+
disabled?: boolean;
|
|
34
|
+
onCopy?: (value: string) => void;
|
|
35
|
+
}
|
|
36
|
+
export type CellConfig = TextCellConfig | BooleanCellConfig | TagCellConfig | DateCellConfig | CurrencyCellConfig | UuidCellConfig;
|
|
30
37
|
export interface DataTableColumn<TData> {
|
|
31
38
|
id: string;
|
|
32
39
|
accessorKey?: keyof TData;
|
|
33
40
|
header?: string;
|
|
34
41
|
cellType?: CellType;
|
|
35
42
|
cellConfig?: CellConfig;
|
|
36
|
-
cell?: (value: any, row: TData) => Snippet | Component | string;
|
|
43
|
+
cell?: Snippet<[TData]> | ((value: any, row: TData) => Snippet | Component | string);
|
|
37
44
|
enableSorting?: boolean;
|
|
38
45
|
enableHiding?: boolean;
|
|
39
46
|
enableResizing?: boolean;
|
|
@@ -57,8 +64,13 @@ export interface DataTableProps<TData> {
|
|
|
57
64
|
filters?: Snippet;
|
|
58
65
|
paginationSelectedSlot?: Snippet;
|
|
59
66
|
paginationUnselectedSlot?: Snippet;
|
|
67
|
+
manualPagination?: boolean;
|
|
68
|
+
pageCount?: number;
|
|
69
|
+
rowCount?: number;
|
|
60
70
|
onPageChange?: (pageIndex: number) => void;
|
|
61
71
|
onPageSizeChange?: (pageSize: number) => void;
|
|
72
|
+
onSortingChange?: (columnId: string, direction: 'asc' | 'desc') => void;
|
|
73
|
+
getRowClassName?: (row: TData) => string;
|
|
62
74
|
}
|
|
63
75
|
export interface DataTablePaginationProps<T> {
|
|
64
76
|
table: Table<T>;
|
|
@@ -72,4 +84,7 @@ export interface DataTablePaginationProps<T> {
|
|
|
72
84
|
unselectedSlot?: Snippet;
|
|
73
85
|
onPageChange?: (pageIndex: number) => void;
|
|
74
86
|
onPageSizeChange?: (pageSize: number) => void;
|
|
87
|
+
data?: T[];
|
|
88
|
+
rowCount?: number;
|
|
89
|
+
manualPagination?: boolean;
|
|
75
90
|
}
|
|
@@ -46,8 +46,13 @@
|
|
|
46
46
|
filters,
|
|
47
47
|
paginationSelectedSlot,
|
|
48
48
|
paginationUnselectedSlot,
|
|
49
|
+
manualPagination = false,
|
|
50
|
+
pageCount,
|
|
51
|
+
rowCount,
|
|
49
52
|
onPageChange,
|
|
50
|
-
onPageSizeChange
|
|
53
|
+
onPageSizeChange,
|
|
54
|
+
onSortingChange,
|
|
55
|
+
getRowClassName
|
|
51
56
|
}: DataTableProps<TData> = $props()
|
|
52
57
|
|
|
53
58
|
const enableSelection = !disableSelection
|
|
@@ -71,7 +76,12 @@
|
|
|
71
76
|
|
|
72
77
|
// Build TanStack columns from config
|
|
73
78
|
const columns = $derived.by(() =>
|
|
74
|
-
buildColumns<TData>(
|
|
79
|
+
buildColumns<TData>(
|
|
80
|
+
columnConfig,
|
|
81
|
+
enableSelection,
|
|
82
|
+
RowActions,
|
|
83
|
+
getRowActions !== undefined || rowActions.length > 0
|
|
84
|
+
)
|
|
75
85
|
)
|
|
76
86
|
|
|
77
87
|
// Calculate initial column sizes based on available width
|
|
@@ -96,14 +106,13 @@
|
|
|
96
106
|
})
|
|
97
107
|
|
|
98
108
|
const table = setupTable({
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
},
|
|
102
|
-
get columns() {
|
|
103
|
-
return columns
|
|
104
|
-
},
|
|
109
|
+
getData: () => data,
|
|
110
|
+
getColumns: () => columns,
|
|
105
111
|
enableSelection,
|
|
106
112
|
enablePagination,
|
|
113
|
+
manualPagination,
|
|
114
|
+
pageCount,
|
|
115
|
+
getRowCount: () => rowCount,
|
|
107
116
|
getRowSelection: () => rowSelection,
|
|
108
117
|
getColumnVisibility: () => columnVisibility,
|
|
109
118
|
getSorting: () => sorting,
|
|
@@ -123,18 +132,23 @@
|
|
|
123
132
|
|
|
124
133
|
{#snippet StickyCellWrapper({
|
|
125
134
|
children,
|
|
126
|
-
align = 'left'
|
|
135
|
+
align = 'left',
|
|
136
|
+
isFirst = false,
|
|
137
|
+
isLast = false
|
|
127
138
|
}: {
|
|
128
139
|
children: any
|
|
129
140
|
align?: 'left' | 'right'
|
|
141
|
+
isFirst?: boolean
|
|
142
|
+
isLast?: boolean
|
|
130
143
|
})}
|
|
131
144
|
<div
|
|
132
145
|
class={cn(
|
|
133
|
-
'
|
|
134
|
-
align === 'right' ? 'justify-end
|
|
146
|
+
'absolute inset-0 flex items-center group-hover/row:bg-background-default-secondary group-data-[state=selected]/row:bg-background-selected px-3',
|
|
147
|
+
align === 'right' ? 'justify-end' : '',
|
|
148
|
+
{ 'pl-6': isFirst, 'pr-6': isLast }
|
|
135
149
|
)}
|
|
136
150
|
>
|
|
137
|
-
<div class="relative z-10">
|
|
151
|
+
<div class="relative z-10 flex items-center">
|
|
138
152
|
{@render children()}
|
|
139
153
|
</div>
|
|
140
154
|
</div>
|
|
@@ -181,7 +195,17 @@
|
|
|
181
195
|
<BaseTableHeaderOrderBy
|
|
182
196
|
sortDirection={column.getIsSorted() === 'asc' ? 'asc' : 'desc'}
|
|
183
197
|
isActive={column.getIsSorted() !== false}
|
|
184
|
-
onOrderBy={(direction) =>
|
|
198
|
+
onOrderBy={(direction) => {
|
|
199
|
+
column.toggleSorting(direction === 'desc')
|
|
200
|
+
// Reset to first page when sorting changes (same as page size change)
|
|
201
|
+
if (manualPagination) {
|
|
202
|
+
table.setPageIndex(0)
|
|
203
|
+
onPageChange?.(1)
|
|
204
|
+
}
|
|
205
|
+
if (onSortingChange) {
|
|
206
|
+
onSortingChange(column.id, direction)
|
|
207
|
+
}
|
|
208
|
+
}}
|
|
185
209
|
onHide={() => column.toggleVisibility(false)}
|
|
186
210
|
/>
|
|
187
211
|
</BaseDropdown>
|
|
@@ -189,20 +213,22 @@
|
|
|
189
213
|
{/if}
|
|
190
214
|
{/snippet}
|
|
191
215
|
|
|
192
|
-
<div class="flex flex-col h-
|
|
216
|
+
<div class="flex flex-col h-full">
|
|
193
217
|
<DataTableToolbar {table} {filters} />
|
|
194
218
|
<div class="flex-1 overflow-hidden flex flex-col">
|
|
195
|
-
<div bind:this={containerRef} class="relative bg-background flex-1 overflow-auto">
|
|
196
|
-
<Table.Root>
|
|
219
|
+
<div bind:this={containerRef} class="relative bg-background flex-1 overflow-auto" style="overscroll-behavior-x: none;">
|
|
220
|
+
<Table.Root class={data.length === 0 ? 'h-full' : 'h-auto'}>
|
|
197
221
|
<Table.Header>
|
|
198
222
|
{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
|
|
199
223
|
<Table.Row class="hover:!bg-transparent border-b border-border">
|
|
200
224
|
{#each headerGroup.headers as header, index (header.id)}
|
|
201
225
|
{@const isLastScrollable = index === headerGroup.headers.length - 2}
|
|
226
|
+
{@const isFirstHeader = index === 0}
|
|
227
|
+
{@const isLastHeader = index === headerGroup.headers.length - 1}
|
|
202
228
|
<Table.Head
|
|
203
229
|
colspan={header.colSpan}
|
|
204
230
|
style={getHeaderStyle(header, isLastScrollable)}
|
|
205
|
-
class={getHeaderClasses(header, isLastScrollable)}
|
|
231
|
+
class={getHeaderClasses(header, isLastScrollable, isFirstHeader, isLastHeader)}
|
|
206
232
|
>
|
|
207
233
|
{#if !header.isPlaceholder}
|
|
208
234
|
{#if typeof header.column.columnDef.header === 'string'}
|
|
@@ -251,24 +277,28 @@
|
|
|
251
277
|
{#each table.getRowModel().rows as row (row.id)}
|
|
252
278
|
<Table.Row
|
|
253
279
|
data-state={row.getIsSelected() ? 'selected' : undefined}
|
|
254
|
-
class=
|
|
280
|
+
class={cn('border-b border-border', getRowClassName?.(row.original as TData))}
|
|
255
281
|
onclick={() => onRowClick?.(row.original as TData)}
|
|
256
282
|
>
|
|
257
283
|
{#each row.getVisibleCells() as cell, index (cell.id)}
|
|
258
|
-
{@const isLastScrollable = index === row.getVisibleCells().length - 2}
|
|
259
284
|
{@const visibleCells = row.getVisibleCells()}
|
|
285
|
+
{@const isLastScrollable = index === visibleCells.length - 2}
|
|
260
286
|
{@const firstDataColumnIndex = visibleCells.findIndex(
|
|
261
287
|
(c) => c.column.id !== 'select' && c.column.id !== 'actions'
|
|
262
288
|
)}
|
|
263
289
|
{@const isFirstDataColumn = index === firstDataColumnIndex}
|
|
290
|
+
{@const isFirstCell = index === 0}
|
|
291
|
+
{@const isLastCell = index === visibleCells.length - 1}
|
|
264
292
|
<Table.Cell
|
|
265
293
|
style={getCellStyle(cell, isLastScrollable)}
|
|
266
|
-
class={getCellClasses(cell, isLastScrollable, isFirstDataColumn)}
|
|
294
|
+
class={getCellClasses(cell, isLastScrollable, isFirstDataColumn, isFirstCell, isLastCell)}
|
|
267
295
|
>
|
|
268
296
|
{#if cell.column.id === 'actions'}
|
|
269
297
|
{@render StickyCellWrapper({
|
|
270
298
|
align: 'right',
|
|
271
|
-
children: CellContent
|
|
299
|
+
children: CellContent,
|
|
300
|
+
isFirst: isFirstCell,
|
|
301
|
+
isLast: isLastCell
|
|
272
302
|
})}
|
|
273
303
|
{#snippet CellContent()}
|
|
274
304
|
<FlexRender
|
|
@@ -279,7 +309,9 @@
|
|
|
279
309
|
{:else if cell.column.id === 'select'}
|
|
280
310
|
{@render StickyCellWrapper({
|
|
281
311
|
align: 'left',
|
|
282
|
-
children: CellContent
|
|
312
|
+
children: CellContent,
|
|
313
|
+
isFirst: isFirstCell,
|
|
314
|
+
isLast: isLastCell
|
|
283
315
|
})}
|
|
284
316
|
{#snippet CellContent()}
|
|
285
317
|
<FlexRender
|
|
@@ -297,13 +329,15 @@
|
|
|
297
329
|
{/each}
|
|
298
330
|
</Table.Row>
|
|
299
331
|
{:else}
|
|
300
|
-
<Table.Row>
|
|
301
|
-
<Table.Cell colspan={columns.length} class="h-
|
|
302
|
-
<
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
332
|
+
<Table.Row class="hover:!bg-transparent h-full">
|
|
333
|
+
<Table.Cell colspan={columns.length} class="h-full !p-0">
|
|
334
|
+
<div class="flex items-center justify-center h-full w-full">
|
|
335
|
+
<EmptyState
|
|
336
|
+
iconSource={emptyState.iconSource}
|
|
337
|
+
title={emptyState.title}
|
|
338
|
+
description={emptyState.description}
|
|
339
|
+
/>
|
|
340
|
+
</div>
|
|
307
341
|
</Table.Cell>
|
|
308
342
|
</Table.Row>
|
|
309
343
|
{/each}
|
|
@@ -313,6 +347,9 @@
|
|
|
313
347
|
{#if enablePagination}
|
|
314
348
|
<DataTablePagination
|
|
315
349
|
{table}
|
|
350
|
+
{data}
|
|
351
|
+
{rowCount}
|
|
352
|
+
{manualPagination}
|
|
316
353
|
selectedSlot={paginationSelectedSlot}
|
|
317
354
|
unselectedSlot={paginationUnselectedSlot}
|
|
318
355
|
{onPageChange}
|
|
@@ -11,6 +11,11 @@ export declare function buildColumns<TData>(columnConfig: DataTableColumn<TData>
|
|
|
11
11
|
interface TableSetupOptions<TData> {
|
|
12
12
|
enableSelection: boolean;
|
|
13
13
|
enablePagination: boolean;
|
|
14
|
+
manualPagination?: boolean;
|
|
15
|
+
pageCount?: number;
|
|
16
|
+
getRowCount?: () => number | undefined;
|
|
17
|
+
getData?: () => TData[];
|
|
18
|
+
getColumns?: () => any[];
|
|
14
19
|
getRowSelection: () => RowSelectionState;
|
|
15
20
|
getColumnVisibility: () => VisibilityState;
|
|
16
21
|
getSorting: () => SortingState;
|
|
@@ -29,8 +34,5 @@ interface TableSetupOptions<TData> {
|
|
|
29
34
|
/**
|
|
30
35
|
* Create the TanStack table instance with all configuration
|
|
31
36
|
*/
|
|
32
|
-
export declare function setupTable<TData>(options: TableSetupOptions<TData>
|
|
33
|
-
data?: TData[];
|
|
34
|
-
columns?: any[];
|
|
35
|
-
}): import("@tanstack/table-core").Table<unknown>;
|
|
37
|
+
export declare function setupTable<TData>(options: TableSetupOptions<TData>): import("@tanstack/table-core").Table<unknown>;
|
|
36
38
|
export {};
|
|
@@ -55,6 +55,12 @@ export function setupTable(options) {
|
|
|
55
55
|
return options.getColumnOrder();
|
|
56
56
|
}
|
|
57
57
|
},
|
|
58
|
+
get data() {
|
|
59
|
+
return options.getData?.() ?? [];
|
|
60
|
+
},
|
|
61
|
+
get columns() {
|
|
62
|
+
return options.getColumns?.() ?? [];
|
|
63
|
+
},
|
|
58
64
|
enableRowSelection: options.enableSelection,
|
|
59
65
|
enableColumnResizing: true,
|
|
60
66
|
columnResizeMode: 'onChange',
|
|
@@ -116,15 +122,28 @@ export function setupTable(options) {
|
|
|
116
122
|
}
|
|
117
123
|
},
|
|
118
124
|
getCoreRowModel: getCoreRowModel(),
|
|
119
|
-
getPaginationRowModel: options.enablePagination ? getPaginationRowModel() : undefined,
|
|
120
|
-
getSortedRowModel: getSortedRowModel()
|
|
125
|
+
getPaginationRowModel: options.enablePagination && !options.manualPagination ? getPaginationRowModel() : undefined,
|
|
126
|
+
getSortedRowModel: getSortedRowModel(),
|
|
127
|
+
// Manual pagination configuration
|
|
128
|
+
manualPagination: options.manualPagination
|
|
121
129
|
};
|
|
122
|
-
//
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
130
|
+
// Only provide pageCount/rowCount for manual pagination
|
|
131
|
+
// When manualPagination is false, TanStack Table calculates it automatically
|
|
132
|
+
if (options.manualPagination) {
|
|
133
|
+
Object.assign(tableOptions, {
|
|
134
|
+
get pageCount() {
|
|
135
|
+
// Calculate pageCount from rowCount and current pageSize
|
|
136
|
+
const rowCount = options.getRowCount?.();
|
|
137
|
+
if (rowCount !== undefined) {
|
|
138
|
+
const pageSize = options.getPagination().pageSize;
|
|
139
|
+
return Math.ceil(rowCount / pageSize);
|
|
140
|
+
}
|
|
141
|
+
return options.pageCount ?? -1;
|
|
142
|
+
},
|
|
143
|
+
get rowCount() {
|
|
144
|
+
return options.getRowCount?.();
|
|
145
|
+
}
|
|
146
|
+
});
|
|
128
147
|
}
|
|
129
148
|
return createSvelteTable(tableOptions);
|
|
130
149
|
}
|
|
@@ -6,7 +6,7 @@ export declare function getHeaderStyle<TData>(header: Header<TData, unknown>, is
|
|
|
6
6
|
/**
|
|
7
7
|
* Calculate CSS classes for table headers
|
|
8
8
|
*/
|
|
9
|
-
export declare function getHeaderClasses<TData>(header: Header<TData, unknown>, isLastScrollable: boolean): string;
|
|
9
|
+
export declare function getHeaderClasses<TData>(header: Header<TData, unknown>, isLastScrollable: boolean, isFirstHeader?: boolean, isLastHeader?: boolean): string;
|
|
10
10
|
/**
|
|
11
11
|
* Calculate inline styles for table cells
|
|
12
12
|
*/
|
|
@@ -14,4 +14,4 @@ export declare function getCellStyle<TData>(cell: Cell<TData, unknown>, isLastSc
|
|
|
14
14
|
/**
|
|
15
15
|
* Calculate CSS classes for table cells
|
|
16
16
|
*/
|
|
17
|
-
export declare function getCellClasses<TData>(cell: Cell<TData, unknown>, isLastScrollable: boolean, isFirstDataColumn?: boolean): string;
|
|
17
|
+
export declare function getCellClasses<TData>(cell: Cell<TData, unknown>, isLastScrollable: boolean, isFirstDataColumn?: boolean, isFirstCell?: boolean, isLastCell?: boolean): string;
|
|
@@ -15,12 +15,18 @@ export function getHeaderStyle(header, isLastScrollable) {
|
|
|
15
15
|
/**
|
|
16
16
|
* Calculate CSS classes for table headers
|
|
17
17
|
*/
|
|
18
|
-
export function getHeaderClasses(header, isLastScrollable) {
|
|
18
|
+
export function getHeaderClasses(header, isLastScrollable, isFirstHeader = false, isLastHeader = false) {
|
|
19
|
+
const isSticky = header.id === 'actions' || header.id === 'select';
|
|
19
20
|
return clsx('relative whitespace-nowrap overflow-hidden', {
|
|
20
|
-
'sticky right-0 text-right bg-background
|
|
21
|
-
'sticky left-0 bg-background z-10
|
|
21
|
+
'sticky right-0 text-right bg-background': header.id === 'actions',
|
|
22
|
+
'sticky left-0 bg-background z-10': header.id === 'select',
|
|
22
23
|
'w-full': isLastScrollable,
|
|
23
|
-
'hover:!bg-transparent': !header.column.getCanSort()
|
|
24
|
+
'hover:!bg-transparent': !header.column.getCanSort(),
|
|
25
|
+
'!pl-6': isFirstHeader && !isSticky,
|
|
26
|
+
'!pr-6': isLastHeader && !isSticky,
|
|
27
|
+
'px-3': isSticky,
|
|
28
|
+
'pl-6': isSticky && isFirstHeader,
|
|
29
|
+
'pr-6': isSticky && isLastHeader
|
|
24
30
|
});
|
|
25
31
|
}
|
|
26
32
|
/**
|
|
@@ -39,11 +45,15 @@ export function getCellStyle(cell, isLastScrollable) {
|
|
|
39
45
|
/**
|
|
40
46
|
* Calculate CSS classes for table cells
|
|
41
47
|
*/
|
|
42
|
-
export function getCellClasses(cell, isLastScrollable, isFirstDataColumn = false) {
|
|
48
|
+
export function getCellClasses(cell, isLastScrollable, isFirstDataColumn = false, isFirstCell = false, isLastCell = false) {
|
|
49
|
+
const isSticky = cell.column.id === 'actions' || cell.column.id === 'select';
|
|
43
50
|
return clsx('whitespace-nowrap overflow-hidden', {
|
|
44
|
-
'sticky right-0 text-right
|
|
45
|
-
'sticky left-0
|
|
51
|
+
'sticky right-0 text-right': cell.column.id === 'actions',
|
|
52
|
+
'sticky left-0 z-10': cell.column.id === 'select',
|
|
53
|
+
'!p-0': isSticky,
|
|
46
54
|
'w-full': isLastScrollable,
|
|
47
|
-
'font-medium': isFirstDataColumn
|
|
55
|
+
'font-medium': isFirstDataColumn,
|
|
56
|
+
'!pl-6': isFirstCell && !isSticky,
|
|
57
|
+
'!pr-6': isLastCell && !isSticky
|
|
48
58
|
});
|
|
49
59
|
}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
bind:this={ref}
|
|
17
17
|
data-slot="table-cell"
|
|
18
18
|
class={cn(
|
|
19
|
-
'py-[9px] [&:has([role=menu])]:py-0 [&:has([data-uuid-copy])]:py-0 pl-3 pr-3 align-middle text-foreground font-normal text-base [&:has([role=menu])]:pl-1
|
|
19
|
+
'py-[9px] [&:has([role=menu])]:py-0 [&:has([data-uuid-copy])]:py-0 pl-3 pr-3 align-middle text-foreground font-normal text-base [&:has([role=menu])]:pl-1 [&:has([role=menu])]:bg-white [&:has([type=checkbox])]:bg-white',
|
|
20
20
|
className
|
|
21
21
|
)}
|
|
22
22
|
{...restProps}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
bind:this={ref}
|
|
14
14
|
data-slot="table-head"
|
|
15
15
|
class={cn(
|
|
16
|
-
'text-foreground-default-secondary text-base font-normal text-left align-middle [&:has([role=checkbox])]:pr-0 px-3 hover:bg-background-default-secondary
|
|
16
|
+
'text-foreground-default-secondary text-base font-normal text-left align-middle [&:has([role=checkbox])]:pr-0 px-3 hover:bg-background-default-secondary',
|
|
17
17
|
className
|
|
18
18
|
)}
|
|
19
19
|
{...restProps}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
bind:this={ref}
|
|
20
20
|
data-slot="table-row"
|
|
21
21
|
class={cn(
|
|
22
|
-
'group/row data-[state=selected]:bg-background-selected data-[state=checked]:bg-background-selected
|
|
22
|
+
'group/row data-[state=selected]:bg-background-selected data-[state=checked]:bg-background-selected h-10 data-[state=selected]:hover:bg-background-selected data-[state=checked]:hover:bg-background-selected',
|
|
23
23
|
className
|
|
24
24
|
)}
|
|
25
25
|
{oncontextmenu}
|
package/dist/table/table.svelte
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
}: WithElementRef<HTMLTableAttributes> = $props()
|
|
9
9
|
</script>
|
|
10
10
|
|
|
11
|
-
<div data-slot="table-container" class="relative w-full">
|
|
12
|
-
<table bind:this={ref} data-slot="table" class={cn('caption-bottom', className)}>
|
|
11
|
+
<div data-slot="table-container" class="relative w-full h-full">
|
|
12
|
+
<table bind:this={ref} data-slot="table" class={cn('caption-bottom w-full', className)}>
|
|
13
13
|
{@render children?.()}
|
|
14
14
|
</table>
|
|
15
15
|
</div>
|
package/dist/types.d.ts
CHANGED
|
@@ -368,13 +368,17 @@ export interface DataListItemProps {
|
|
|
368
368
|
}
|
|
369
369
|
export interface DatePickerProps {
|
|
370
370
|
label?: string;
|
|
371
|
-
|
|
371
|
+
placement?: Placement;
|
|
372
372
|
from?: string;
|
|
373
373
|
to?: string;
|
|
374
374
|
onSelect?: (date: {
|
|
375
375
|
from: string;
|
|
376
376
|
to: string;
|
|
377
377
|
}) => void;
|
|
378
|
+
stackLeft?: boolean;
|
|
379
|
+
stackRight?: boolean;
|
|
380
|
+
icon?: IconSource | string;
|
|
381
|
+
iconTheme?: IconTheme;
|
|
378
382
|
}
|
|
379
383
|
export interface DrawerContextProps {
|
|
380
384
|
items?: DrawerOption[];
|
|
@@ -519,6 +523,9 @@ export interface InputTextProps {
|
|
|
519
523
|
disabled?: boolean;
|
|
520
524
|
value?: string | number;
|
|
521
525
|
focusOnLoad?: boolean;
|
|
526
|
+
stackLeft?: boolean;
|
|
527
|
+
stackRight?: boolean;
|
|
528
|
+
widthClass?: string;
|
|
522
529
|
oninput?: (value: string) => void;
|
|
523
530
|
onfocus?: (event: FocusEvent) => void;
|
|
524
531
|
onblur?: (event: FocusEvent) => void;
|