@invopop/popui 0.1.35 → 0.1.40

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.
Files changed (119) hide show
  1. package/dist/BaseButton.svelte +4 -0
  2. package/dist/BaseDropdown.svelte +42 -3
  3. package/dist/BaseDropdown.svelte.d.ts +1 -0
  4. package/dist/BaseTableHeaderOrderBy.svelte +35 -12
  5. package/dist/ButtonSearch.svelte +82 -0
  6. package/dist/ButtonSearch.svelte.d.ts +4 -0
  7. package/dist/ButtonUuidCopy.svelte +1 -0
  8. package/dist/DatePicker.svelte +96 -27
  9. package/dist/DatePicker.svelte.d.ts +5 -1
  10. package/dist/DrawerContext.svelte +443 -34
  11. package/dist/DrawerContextItem.svelte +36 -29
  12. package/dist/DropdownSelect.svelte +68 -18
  13. package/dist/DropdownSelect.svelte.d.ts +4 -1
  14. package/dist/DropdownSelectGroup.svelte +15 -0
  15. package/dist/DropdownSelectGroup.svelte.d.ts +7 -0
  16. package/dist/EmptyState.svelte +6 -2
  17. package/dist/InputSearch.svelte +45 -5
  18. package/dist/InputSelect.svelte +12 -3
  19. package/dist/InputText.svelte +25 -8
  20. package/dist/InputToggle.svelte +23 -6
  21. package/dist/StepIcon.svelte +35 -0
  22. package/dist/StepIcon.svelte.d.ts +4 -0
  23. package/dist/StepIconList.svelte +24 -31
  24. package/dist/TagStatus.svelte +1 -1
  25. package/dist/button/button.svelte +34 -3
  26. package/dist/button/button.svelte.d.ts +29 -0
  27. package/dist/clickOutside.d.ts +5 -2
  28. package/dist/clickOutside.js +9 -3
  29. package/dist/data-table/cells/boolean-cell.svelte +29 -0
  30. package/dist/data-table/cells/boolean-cell.svelte.d.ts +8 -0
  31. package/dist/data-table/cells/cell-skeleton.svelte +35 -0
  32. package/dist/data-table/cells/cell-skeleton.svelte.d.ts +4 -0
  33. package/dist/data-table/cells/currency-cell.svelte +10 -0
  34. package/dist/data-table/cells/currency-cell.svelte.d.ts +8 -0
  35. package/dist/data-table/cells/date-cell.svelte +10 -0
  36. package/dist/data-table/cells/date-cell.svelte.d.ts +8 -0
  37. package/dist/data-table/cells/tag-cell.svelte +12 -0
  38. package/dist/data-table/cells/tag-cell.svelte.d.ts +8 -0
  39. package/dist/data-table/cells/text-cell.svelte +10 -0
  40. package/dist/data-table/cells/text-cell.svelte.d.ts +8 -0
  41. package/dist/data-table/cells/uuid-cell.svelte +17 -0
  42. package/dist/data-table/cells/uuid-cell.svelte.d.ts +8 -0
  43. package/dist/data-table/column-definitions.d.ts +12 -0
  44. package/dist/data-table/column-definitions.js +42 -0
  45. package/dist/data-table/column-sizing-helpers.d.ts +6 -0
  46. package/dist/data-table/column-sizing-helpers.js +24 -0
  47. package/dist/data-table/create-columns.d.ts +3 -0
  48. package/dist/data-table/create-columns.js +67 -0
  49. package/dist/data-table/data-table-cell.svelte +94 -0
  50. package/dist/data-table/data-table-cell.svelte.d.ts +25 -0
  51. package/dist/data-table/data-table-header-cell.svelte +188 -0
  52. package/dist/data-table/data-table-header-cell.svelte.d.ts +25 -0
  53. package/dist/data-table/data-table-helpers.d.ts +10 -0
  54. package/dist/data-table/data-table-helpers.js +124 -0
  55. package/dist/data-table/data-table-pagination.svelte +214 -0
  56. package/dist/data-table/data-table-pagination.svelte.d.ts +4 -0
  57. package/dist/data-table/data-table-row.svelte +57 -0
  58. package/dist/data-table/data-table-row.svelte.d.ts +25 -0
  59. package/dist/data-table/data-table-svelte.svelte.d.ts +40 -0
  60. package/dist/data-table/data-table-svelte.svelte.js +115 -0
  61. package/dist/data-table/data-table-toolbar.svelte +19 -0
  62. package/dist/data-table/data-table-toolbar.svelte.d.ts +32 -0
  63. package/dist/data-table/data-table-types.d.ts +194 -0
  64. package/dist/data-table/data-table-types.js +1 -0
  65. package/dist/data-table/data-table-view-options.svelte +126 -0
  66. package/dist/data-table/data-table-view-options.svelte.d.ts +29 -0
  67. package/dist/data-table/data-table.svelte +428 -0
  68. package/dist/data-table/data-table.svelte.d.ts +25 -0
  69. package/dist/data-table/flex-render.svelte +40 -0
  70. package/dist/data-table/flex-render.svelte.d.ts +33 -0
  71. package/dist/data-table/index.d.ts +13 -0
  72. package/dist/data-table/index.js +13 -0
  73. package/dist/data-table/render-helpers.d.ts +90 -0
  74. package/dist/data-table/render-helpers.js +99 -0
  75. package/dist/data-table/table-setup.d.ts +39 -0
  76. package/dist/data-table/table-setup.js +151 -0
  77. package/dist/data-table/table-styles.d.ts +17 -0
  78. package/dist/data-table/table-styles.js +70 -0
  79. package/dist/drawer-dnd-helpers.d.ts +30 -0
  80. package/dist/drawer-dnd-helpers.js +72 -0
  81. package/dist/helpers.d.ts +1 -0
  82. package/dist/helpers.js +3 -0
  83. package/dist/index.d.ts +15 -3
  84. package/dist/index.js +28 -5
  85. package/dist/skeleton/index.d.ts +5 -0
  86. package/dist/skeleton/index.js +7 -0
  87. package/dist/skeleton/skeleton-avatar.svelte +14 -0
  88. package/dist/skeleton/skeleton-avatar.svelte.d.ts +7 -0
  89. package/dist/skeleton/skeleton-card.svelte +22 -0
  90. package/dist/skeleton/skeleton-card.svelte.d.ts +9 -0
  91. package/dist/skeleton/skeleton-list.svelte +25 -0
  92. package/dist/skeleton/skeleton-list.svelte.d.ts +8 -0
  93. package/dist/skeleton/skeleton.svelte +17 -0
  94. package/dist/skeleton/skeleton.svelte.d.ts +5 -0
  95. package/dist/svg/IconDelivery.svelte +1 -1
  96. package/dist/svg/IconOrder.svelte +1 -1
  97. package/dist/svg/IconPayment.svelte +1 -1
  98. package/dist/table/table-cell.svelte +4 -2
  99. package/dist/table/table-head.svelte +4 -2
  100. package/dist/table/table-header.svelte +1 -1
  101. package/dist/table/table-row.svelte +4 -2
  102. package/dist/table/table.svelte +2 -2
  103. package/dist/tailwind.theme.css +30 -6
  104. package/dist/tooltip/index.d.ts +2 -1
  105. package/dist/tooltip/index.js +3 -2
  106. package/dist/tooltip/tooltip-auto-hide.svelte +31 -0
  107. package/dist/tooltip/tooltip-auto-hide.svelte.d.ts +7 -0
  108. package/dist/types.d.ts +51 -73
  109. package/package.json +14 -8
  110. package/dist/BaseTable.svelte +0 -391
  111. package/dist/BaseTable.svelte.d.ts +0 -4
  112. package/dist/BaseTableCellContent.svelte +0 -58
  113. package/dist/BaseTableCellContent.svelte.d.ts +0 -4
  114. package/dist/BaseTableCheckbox.svelte +0 -33
  115. package/dist/BaseTableCheckbox.svelte.d.ts +0 -4
  116. package/dist/BaseTableHeaderContent.svelte +0 -67
  117. package/dist/BaseTableHeaderContent.svelte.d.ts +0 -4
  118. package/dist/BaseTableRow.svelte +0 -127
  119. package/dist/BaseTableRow.svelte.d.ts +0 -4
@@ -0,0 +1,188 @@
1
+ <script lang="ts" generics="TData">
2
+ import type { DataTableHeaderCellProps } from './data-table-types.js'
3
+ import type { Column, Header } from '@tanstack/table-core'
4
+ import type { HTMLAttributes } from 'svelte/elements'
5
+ import * as Table from '../table/index.js'
6
+ import BaseDropdown from '../BaseDropdown.svelte'
7
+ import BaseTableHeaderOrderBy from '../BaseTableHeaderOrderBy.svelte'
8
+ import FlexRender from './flex-render.svelte'
9
+ import { Icon } from '@steeze-ui/svelte-icon'
10
+ import { ArrowUp, ArrowDown } from '@invopop/ui-icons'
11
+ import { cn } from '../utils.js'
12
+ import { calculateFrozenOffset } from './data-table-helpers.js'
13
+ import { getHeaderStyle, getHeaderClasses } from './table-styles.js'
14
+ import clsx from 'clsx'
15
+
16
+ let {
17
+ header,
18
+ index,
19
+ headers,
20
+ frozenColumns,
21
+ columnDropdowns = $bindable({}),
22
+ onSortingChange,
23
+ onFilterChange,
24
+ onFreezeChange,
25
+ loading = false
26
+ }: DataTableHeaderCellProps<TData> = $props()
27
+
28
+ const isLastScrollable = $derived(index === headers.length - 2)
29
+ const isFirstHeader = $derived(index === 0)
30
+ const isLastHeader = $derived(index === headers.length - 1)
31
+ const prevHeader = $derived(index > 0 ? headers[index - 1] : null)
32
+ const isFrozen = $derived(frozenColumns.has(header.id))
33
+ const lastFrozenHeaderId = $derived(
34
+ headers
35
+ .slice()
36
+ .reverse()
37
+ .find((h) => frozenColumns.has(h.id))?.id
38
+ )
39
+ const isLastFrozenHeader = $derived(isFrozen && header.id === lastFrozenHeaderId)
40
+ const frozenOffset = $derived(isFrozen ? calculateFrozenOffset(header.id, headers, frozenColumns) : 0)
41
+ const hasSelectColumn = $derived(headers.some((h) => h.id === 'select'))
42
+ </script>
43
+
44
+ {#snippet ResizeHandle({
45
+ side,
46
+ targetHeader,
47
+ label
48
+ }: {
49
+ side: 'left' | 'right'
50
+ targetHeader: Header<TData, unknown>
51
+ label: string
52
+ })}
53
+ <div
54
+ role="button"
55
+ tabindex="0"
56
+ aria-label={label}
57
+ class={cn(
58
+ 'absolute top-0 h-full w-6 cursor-col-resize select-none touch-none group z-0',
59
+ side === 'left' ? 'left-0 -ml-3' : 'right-0 -mr-3'
60
+ )}
61
+ onmousedown={targetHeader.getResizeHandler()}
62
+ ontouchstart={targetHeader.getResizeHandler()}
63
+ >
64
+ <div
65
+ class={cn(
66
+ 'absolute top-0 h-full w-0.5 bg-border-default-secondary transition-opacity opacity-0',
67
+ side === 'left' ? 'left-1.5' : 'right-1.5',
68
+ !targetHeader.column.getIsResizing() && 'group-hover:opacity-100'
69
+ )}
70
+ ></div>
71
+ </div>
72
+ {/snippet}
73
+
74
+ {#snippet ColumnHeader({
75
+ column,
76
+ title,
77
+ class: className,
78
+ isFirst = false,
79
+ hasSelectColumn = false,
80
+ ...restProps
81
+ }: {
82
+ column: Column<TData>
83
+ title?: string
84
+ isFirst?: boolean
85
+ hasSelectColumn?: boolean
86
+ } & HTMLAttributes<HTMLDivElement>)}
87
+ {@const isCurrency = column.columnDef.meta?.cellType === 'currency'}
88
+ {@const needsEdgePadding = isFirst && !hasSelectColumn}
89
+ <div
90
+ class={cn(
91
+ 'flex items-center w-full [th[data-last-frozen=true]_&]:border-r [th[data-last-frozen=true]_&]:border-border',
92
+ className
93
+ )}
94
+ oncontextmenu={(e) => {
95
+ e.preventDefault()
96
+ columnDropdowns[column.id]?.toggle()
97
+ }}
98
+ {...restProps}
99
+ >
100
+ <BaseDropdown bind:this={columnDropdowns[column.id]} fullWidth usePortal={false}>
101
+ {#snippet trigger()}
102
+ <button
103
+ class={clsx(
104
+ 'data-[state=open]:bg-accent hover:bg-background-default-secondary w-full flex items-center gap-1 py-2.5',
105
+ {
106
+ 'justify-end': isCurrency,
107
+ 'text-left': !isCurrency,
108
+ 'pl-4 pr-3': needsEdgePadding,
109
+ 'px-3': !needsEdgePadding
110
+ }
111
+ )}
112
+ >
113
+ <span>
114
+ {title || ''}
115
+ </span>
116
+ {#if column.getIsSorted() === 'desc'}
117
+ <Icon src={ArrowDown} class="size-4" />
118
+ {:else if column.getIsSorted() === 'asc'}
119
+ <Icon src={ArrowUp} class="size-4" />
120
+ {/if}
121
+ </button>
122
+ {/snippet}
123
+ <BaseTableHeaderOrderBy
124
+ sortDirection={column.getIsSorted() === 'asc' ? 'asc' : 'desc'}
125
+ isActive={column.getIsSorted() !== false}
126
+ isFrozen={frozenColumns.has(column.id)}
127
+ showSortOptions={column.getCanSort()}
128
+ showFilterOption={!column.columnDef.meta?.disableColumnFilter}
129
+ onOrderBy={(direction) => {
130
+ column.toggleSorting(direction === 'desc')
131
+ if (onSortingChange) {
132
+ onSortingChange(column.id, direction)
133
+ }
134
+ columnDropdowns[column.id]?.toggle()
135
+ }}
136
+ onHide={() => {
137
+ column.toggleVisibility(false)
138
+ columnDropdowns[column.id]?.toggle()
139
+ }}
140
+ onFilter={() => {
141
+ onFilterChange?.(column.id)
142
+ columnDropdowns[column.id]?.toggle()
143
+ }}
144
+ onFreeze={() => {
145
+ onFreezeChange?.(column.id)
146
+ columnDropdowns[column.id]?.toggle()
147
+ }}
148
+ />
149
+ </BaseDropdown>
150
+ </div>
151
+ {/snippet}
152
+
153
+ <Table.Head
154
+ colspan={header.colSpan}
155
+ style={getHeaderStyle(header, isLastScrollable, isFrozen, frozenOffset)}
156
+ class={getHeaderClasses(
157
+ header,
158
+ isLastScrollable,
159
+ isFirstHeader,
160
+ isLastHeader,
161
+ isFrozen,
162
+ isLastFrozenHeader
163
+ )}
164
+ data-last-frozen={isFrozen && isLastFrozenHeader ? 'true' : undefined}
165
+ >
166
+ {#if !header.isPlaceholder}
167
+ {#if typeof header.column.columnDef.header === 'string'}
168
+ {@render ColumnHeader({
169
+ column: header.column as Column<TData>,
170
+ title: header.column.columnDef.header as string,
171
+ isFirst: isFirstHeader,
172
+ hasSelectColumn
173
+ })}
174
+ {:else if header.id === 'select'}
175
+ <div class={cn('flex items-center', loading && 'opacity-30')}>
176
+ <FlexRender content={header.column.columnDef.header} context={header.getContext()} />
177
+ </div>
178
+ {:else}
179
+ <FlexRender content={header.column.columnDef.header} context={header.getContext()} />
180
+ {/if}
181
+ {/if}
182
+ {#if prevHeader && prevHeader.column.getCanResize()}
183
+ {@render ResizeHandle({ side: 'left', targetHeader: prevHeader, label: 'Resize previous column' })}
184
+ {/if}
185
+ {#if header.column.getCanResize()}
186
+ {@render ResizeHandle({ side: 'right', targetHeader: header, label: 'Resize column' })}
187
+ {/if}
188
+ </Table.Head>
@@ -0,0 +1,25 @@
1
+ import type { DataTableHeaderCellProps } from './data-table-types.js';
2
+ declare function $$render<TData>(): {
3
+ props: DataTableHeaderCellProps<TData>;
4
+ exports: {};
5
+ bindings: "columnDropdowns";
6
+ slots: {};
7
+ events: {};
8
+ };
9
+ declare class __sveltets_Render<TData> {
10
+ props(): ReturnType<typeof $$render<TData>>['props'];
11
+ events(): ReturnType<typeof $$render<TData>>['events'];
12
+ slots(): ReturnType<typeof $$render<TData>>['slots'];
13
+ bindings(): "columnDropdowns";
14
+ exports(): {};
15
+ }
16
+ interface $$IsomorphicComponent {
17
+ new <TData>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TData>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TData>['props']>, ReturnType<__sveltets_Render<TData>['events']>, ReturnType<__sveltets_Render<TData>['slots']>> & {
18
+ $$bindings?: ReturnType<__sveltets_Render<TData>['bindings']>;
19
+ } & ReturnType<__sveltets_Render<TData>['exports']>;
20
+ <TData>(internal: unknown, props: ReturnType<__sveltets_Render<TData>['props']> & {}): ReturnType<__sveltets_Render<TData>['exports']>;
21
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
22
+ }
23
+ declare const DataTableHeaderCell: $$IsomorphicComponent;
24
+ type DataTableHeaderCell<TData> = InstanceType<typeof DataTableHeaderCell<TData>>;
25
+ export default DataTableHeaderCell;
@@ -0,0 +1,10 @@
1
+ import type { Table, Row } from '@tanstack/table-core';
2
+ import type BaseDropdown from '../BaseDropdown.svelte';
3
+ export declare function reorderFrozenColumn<TData>(columnId: string, table: Table<TData>, frozenColumns: Set<string>): void;
4
+ export declare function reorderUnfrozenColumn<TData>(columnId: string, table: Table<TData>, frozenColumns: Set<string>): void;
5
+ export declare function calculateFrozenOffset(columnId: string, headers: any[], frozenColumns: Set<string>): number;
6
+ export declare function handleScrollEvent(event: Event, lastScrollLeft: number, columnDropdowns: Record<string, BaseDropdown>): number;
7
+ export declare function shouldIgnoreKeyEvent(event: KeyboardEvent): boolean;
8
+ export declare function handleArrowDown<TData>(currentIndex: number, rows: Row<TData>[], shiftKey: boolean, enableSelection: boolean, onScroll: () => void): number;
9
+ export declare function handleArrowUp<TData>(currentIndex: number, rows: Row<TData>[], shiftKey: boolean, enableSelection: boolean, onScroll: () => void): number;
10
+ export declare function handleSelectKey<TData>(currentIndex: number, rows: Row<TData>[], enableSelection: boolean): void;
@@ -0,0 +1,124 @@
1
+ export function reorderFrozenColumn(columnId, table, frozenColumns) {
2
+ const currentOrder = table.getState().columnOrder.length > 0
3
+ ? table.getState().columnOrder
4
+ : table.getAllLeafColumns().map((col) => col.id);
5
+ const newOrder = [...currentOrder];
6
+ const columnIndex = newOrder.indexOf(columnId);
7
+ if (columnIndex > -1) {
8
+ newOrder.splice(columnIndex, 1);
9
+ const selectIndex = newOrder.indexOf('select');
10
+ const insertIndex = selectIndex >= 0 ? selectIndex + 1 : 0;
11
+ let lastFrozenIndex = insertIndex;
12
+ for (let i = insertIndex; i < newOrder.length; i++) {
13
+ if (frozenColumns.has(newOrder[i])) {
14
+ lastFrozenIndex = i + 1;
15
+ }
16
+ else {
17
+ break;
18
+ }
19
+ }
20
+ newOrder.splice(lastFrozenIndex, 0, columnId);
21
+ table.setColumnOrder(newOrder);
22
+ }
23
+ }
24
+ export function reorderUnfrozenColumn(columnId, table, frozenColumns) {
25
+ const currentOrder = table.getState().columnOrder.length > 0
26
+ ? table.getState().columnOrder
27
+ : table.getAllLeafColumns().map((col) => col.id);
28
+ const newOrder = [...currentOrder];
29
+ const columnIndex = newOrder.indexOf(columnId);
30
+ if (columnIndex > -1) {
31
+ newOrder.splice(columnIndex, 1);
32
+ const selectIndex = newOrder.indexOf('select');
33
+ const insertIndex = selectIndex >= 0 ? selectIndex + 1 : 0;
34
+ // Find the first unfrozen column position (after all frozen columns)
35
+ let firstUnfrozenIndex = insertIndex;
36
+ for (let i = insertIndex; i < newOrder.length; i++) {
37
+ if (frozenColumns.has(newOrder[i])) {
38
+ firstUnfrozenIndex = i + 1;
39
+ }
40
+ else {
41
+ break;
42
+ }
43
+ }
44
+ newOrder.splice(firstUnfrozenIndex, 0, columnId);
45
+ table.setColumnOrder(newOrder);
46
+ }
47
+ }
48
+ export function calculateFrozenOffset(columnId, headers, frozenColumns) {
49
+ let offset = 0;
50
+ // Find the position of current column
51
+ for (const header of headers) {
52
+ if (header.id === columnId) {
53
+ break;
54
+ }
55
+ // Only add width of previous frozen columns that are visible (or select column)
56
+ const isVisible = header.column?.getIsVisible?.() ?? true;
57
+ if (isVisible && (frozenColumns.has(header.id) || header.id === 'select')) {
58
+ offset += header.getSize();
59
+ }
60
+ }
61
+ return offset;
62
+ }
63
+ export function handleScrollEvent(event, lastScrollLeft, columnDropdowns) {
64
+ const target = event.target;
65
+ if (target.scrollLeft !== lastScrollLeft) {
66
+ // Close all column dropdowns
67
+ Object.values(columnDropdowns).forEach((dropdown) => {
68
+ if (dropdown) {
69
+ dropdown.close();
70
+ }
71
+ });
72
+ return target.scrollLeft;
73
+ }
74
+ return lastScrollLeft;
75
+ }
76
+ // Keyboard navigation helpers
77
+ export function shouldIgnoreKeyEvent(event) {
78
+ const targetTag = event.target.tagName;
79
+ return targetTag === 'INPUT' || targetTag === 'TEXTAREA';
80
+ }
81
+ export function handleArrowDown(currentIndex, rows, shiftKey, enableSelection, onScroll) {
82
+ if (currentIndex === -1 && rows.length > 0) {
83
+ // No row focused, focus first row
84
+ const newIndex = 0;
85
+ onScroll();
86
+ if (shiftKey && enableSelection) {
87
+ rows[newIndex].toggleSelected(true);
88
+ }
89
+ return newIndex;
90
+ }
91
+ else if (currentIndex < rows.length - 1) {
92
+ // Move down
93
+ const newIndex = currentIndex + 1;
94
+ onScroll();
95
+ if (shiftKey && enableSelection) {
96
+ rows[newIndex].toggleSelected(true);
97
+ }
98
+ return newIndex;
99
+ }
100
+ return currentIndex;
101
+ }
102
+ export function handleArrowUp(currentIndex, rows, shiftKey, enableSelection, onScroll) {
103
+ // Deselect current row first when going up with shift
104
+ if (shiftKey && enableSelection && currentIndex >= 0) {
105
+ rows[currentIndex].toggleSelected(false);
106
+ }
107
+ if (currentIndex === -1 && rows.length > 0) {
108
+ // No row focused, focus first row
109
+ onScroll();
110
+ return 0;
111
+ }
112
+ else if (currentIndex > 0) {
113
+ // Move up
114
+ const newIndex = currentIndex - 1;
115
+ onScroll();
116
+ return newIndex;
117
+ }
118
+ return currentIndex;
119
+ }
120
+ export function handleSelectKey(currentIndex, rows, enableSelection) {
121
+ if (currentIndex >= 0 && currentIndex < rows.length && enableSelection) {
122
+ rows[currentIndex].toggleSelected();
123
+ }
124
+ }
@@ -0,0 +1,214 @@
1
+ <script lang="ts">
2
+ import Button from '../button/button.svelte'
3
+ import InputSelect from '../InputSelect.svelte'
4
+ import InputText from '../InputText.svelte'
5
+ import { ArrowLeft, ArrowRight, ScrollLeft, ScrollRight } from '@invopop/ui-icons'
6
+ import { cn } from '../utils.js'
7
+ import clsx from 'clsx'
8
+ import type { DataTablePaginationProps } from './data-table-types.js'
9
+
10
+ let {
11
+ table,
12
+ id,
13
+ class: className,
14
+ showRowsPerPage = true,
15
+ rowsPerPageOptions = [10, 25, 50, 100],
16
+ itemsLabel = 'items',
17
+ children,
18
+ onPageChange,
19
+ onPageSizeChange,
20
+ data,
21
+ rowCount,
22
+ manualPagination,
23
+ disabled = false
24
+ }: DataTablePaginationProps<any> = $props()
25
+
26
+ let currentPage = $derived(table.getState().pagination.pageIndex + 1)
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)
38
+
39
+ let pageInputValue = $derived(`${currentPage}`)
40
+
41
+ function handlePageInput(value: string) {
42
+ const numValue = parseInt(value)
43
+ if (numValue >= 1 && numValue <= totalPages) {
44
+ if (manualPagination) {
45
+ table.setPagination({ pageIndex: numValue - 1, pageSize: rowsPerPage })
46
+ } else {
47
+ table.setPageIndex(numValue - 1)
48
+ }
49
+ onPageChange?.(numValue)
50
+ }
51
+ }
52
+
53
+ function handlePageBlur(event: Event) {
54
+ const target = event.target as HTMLInputElement
55
+ const value = parseInt(target.value)
56
+ if (isNaN(value) || value < 1) {
57
+ target.value = `${currentPage}`
58
+ } else if (value > totalPages) {
59
+ target.value = `${totalPages}`
60
+ if (manualPagination) {
61
+ table.setPagination({ pageIndex: totalPages - 1, pageSize: rowsPerPage })
62
+ } else {
63
+ table.setPageIndex(totalPages - 1)
64
+ }
65
+ onPageChange?.(totalPages)
66
+ }
67
+ }
68
+
69
+ function formatNumber(num: number): string {
70
+ return new Intl.NumberFormat('en-US').format(num)
71
+ }
72
+ </script>
73
+
74
+ <div
75
+ {id}
76
+ class={cn(
77
+ 'flex items-center justify-between h-11 px-4 py-[5px] bg-background backdrop-blur-[10px] border-t border-border',
78
+ className
79
+ )}
80
+ >
81
+ <div class={clsx('flex items-center gap-3', {
82
+ 'pointer-events-none opacity-30': disabled
83
+ })}>
84
+ <div class="flex items-center gap-2">
85
+ <div class="flex items-center gap-1.5">
86
+ <div class="flex items-center">
87
+ <Button
88
+ variant="ghost"
89
+ size="md"
90
+ icon={ScrollLeft}
91
+ onclick={() => {
92
+ if (manualPagination) {
93
+ table.setPagination({ pageIndex: 0, pageSize: rowsPerPage })
94
+ } else {
95
+ table.setPageIndex(0)
96
+ }
97
+ onPageChange?.(1)
98
+ }}
99
+ disabled={currentPage === 1}
100
+ class={cn(currentPage === 1 && 'pointer-events-none opacity-30')}
101
+ aria-label="First page"
102
+ />
103
+ <Button
104
+ variant="ghost"
105
+ size="md"
106
+ icon={ArrowLeft}
107
+ onclick={() => {
108
+ const newPage = currentPage - 1
109
+ if (manualPagination) {
110
+ // For manual pagination, bypass TanStack's navigation and use setPagination directly
111
+ // to avoid clamping issues with stale pageCount
112
+ table.setPagination({ pageIndex: newPage - 1, pageSize: rowsPerPage })
113
+ } else {
114
+ table.previousPage()
115
+ }
116
+ onPageChange?.(newPage)
117
+ }}
118
+ disabled={currentPage === 1}
119
+ class={cn(currentPage === 1 && 'pointer-events-none opacity-30')}
120
+ aria-label="Previous page"
121
+ />
122
+ </div>
123
+ <div class="flex items-center gap-1.5">
124
+ <div
125
+ class="w-12 [&>div]:gap-0 [&_input]:[appearance:textfield] [&_input]:[&::-webkit-outer-spin-button]:appearance-none [&_input]:[&::-webkit-inner-spin-button]:appearance-none"
126
+ >
127
+ <InputText
128
+ bind:value={pageInputValue}
129
+ type="number"
130
+ min="1"
131
+ max={totalPages}
132
+ size="sm"
133
+ oninput={handlePageInput}
134
+ onblur={handlePageBlur}
135
+ />
136
+ </div>
137
+ <span class="text-base text-foreground-default-secondary whitespace-nowrap">
138
+ / {totalPages}
139
+ </span>
140
+ </div>
141
+ <div class="flex items-center">
142
+ <Button
143
+ variant="ghost"
144
+ size="md"
145
+ icon={ArrowRight}
146
+ onclick={() => {
147
+ const newPage = currentPage + 1
148
+ if (manualPagination) {
149
+ // For manual pagination, bypass TanStack's navigation and use setPagination directly
150
+ // to avoid clamping issues with stale pageCount
151
+ table.setPagination({ pageIndex: newPage - 1, pageSize: rowsPerPage })
152
+ } else {
153
+ table.nextPage()
154
+ }
155
+ onPageChange?.(newPage)
156
+ }}
157
+ disabled={currentPage === totalPages}
158
+ class={cn(currentPage === totalPages && 'pointer-events-none opacity-30')}
159
+ aria-label="Next page"
160
+ />
161
+ <Button
162
+ variant="ghost"
163
+ size="md"
164
+ icon={ScrollRight}
165
+ onclick={() => {
166
+ if (manualPagination) {
167
+ table.setPagination({ pageIndex: totalPages - 1, pageSize: rowsPerPage })
168
+ } else {
169
+ table.setPageIndex(totalPages - 1)
170
+ }
171
+ onPageChange?.(totalPages)
172
+ }}
173
+ disabled={currentPage === totalPages}
174
+ class={cn(currentPage === totalPages && 'pointer-events-none opacity-30')}
175
+ aria-label="Last page"
176
+ />
177
+ </div>
178
+ </div>
179
+ {#if showRowsPerPage}
180
+ <div class="w-[105px]">
181
+ <InputSelect
182
+ value={`${rowsPerPage}`}
183
+ options={rowsPerPageOptions.map((size) => ({
184
+ value: `${size}`,
185
+ label: `${size} rows`
186
+ }))}
187
+ size="sm"
188
+ onchange={(value) => {
189
+ const size = Number(value)
190
+ table.setPageSize(size)
191
+ table.setPageIndex(0)
192
+ onPageSizeChange?.(size)
193
+ onPageChange?.(1)
194
+ }}
195
+ placeholder="Rows per page"
196
+ disablePlaceholder={true}
197
+ aria-label="Rows per page"
198
+ />
199
+ </div>
200
+ {/if}
201
+ </div>
202
+ {#if totalItems > 0}
203
+ <span class="text-base text-foreground-default-secondary">
204
+ {formatNumber(totalItems)}
205
+ {itemsLabel}
206
+ </span>
207
+ {/if}
208
+ </div>
209
+ {#if children}
210
+ <div class="flex items-center gap-2">
211
+ {@render children()}
212
+ </div>
213
+ {/if}
214
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { DataTablePaginationProps } from './data-table-types.js';
2
+ declare const DataTablePagination: import("svelte").Component<DataTablePaginationProps<any>, {}, "">;
3
+ type DataTablePagination = ReturnType<typeof DataTablePagination>;
4
+ export default DataTablePagination;
@@ -0,0 +1,57 @@
1
+ <script lang="ts" generics="TData">
2
+ import type { DataTableRowProps } from './data-table-types.js'
3
+ import * as Table from '../table/index.js'
4
+ import DataTableCell from './data-table-cell.svelte'
5
+ import { cn } from '../utils.js'
6
+ import clsx from 'clsx'
7
+
8
+ let {
9
+ row,
10
+ rowIndex,
11
+ frozenColumns,
12
+ focusedRowIndex,
13
+ loading = false,
14
+ onRowClick,
15
+ getRowClassName,
16
+ getRowState,
17
+ StickyCellWrapper
18
+ }: DataTableRowProps<TData> = $props()
19
+
20
+ const rowState = $derived(getRowState?.(row.original as TData))
21
+ const isError = $derived(rowState?.isError ?? false)
22
+ const isSuccess = $derived(rowState?.isSuccess ?? false)
23
+ const isWarning = $derived(rowState?.isWarning ?? false)
24
+ const dataState = $derived.by(() => {
25
+ if (row.getIsSelected()) return 'selected'
26
+ if (isError) return 'error'
27
+ if (isWarning) return 'warning'
28
+ if (isSuccess) return 'success'
29
+ return undefined
30
+ })
31
+ </script>
32
+
33
+ <Table.Row
34
+ data-state={dataState}
35
+ data-row-index={rowIndex}
36
+ data-focused={focusedRowIndex === rowIndex ? 'true' : undefined}
37
+ class={cn(
38
+ clsx('shadow-[inset_0_-1px_0_0_var(--color-border)]', {
39
+ 'cursor-pointer': onRowClick && !loading,
40
+ 'pointer-events-none': loading
41
+ }),
42
+ getRowClassName?.(row.original as TData)
43
+ )}
44
+ onclick={() => !loading && onRowClick?.(row.original as TData)}
45
+ >
46
+ {#each row.getVisibleCells() as cell, index (cell.id)}
47
+ <DataTableCell
48
+ {cell}
49
+ {index}
50
+ visibleCells={row.getVisibleCells()}
51
+ allCells={row.getAllCells()}
52
+ {frozenColumns}
53
+ {loading}
54
+ {StickyCellWrapper}
55
+ />
56
+ {/each}
57
+ </Table.Row>
@@ -0,0 +1,25 @@
1
+ import type { DataTableRowProps } from './data-table-types.js';
2
+ declare function $$render<TData>(): {
3
+ props: DataTableRowProps<TData>;
4
+ exports: {};
5
+ bindings: "";
6
+ slots: {};
7
+ events: {};
8
+ };
9
+ declare class __sveltets_Render<TData> {
10
+ props(): ReturnType<typeof $$render<TData>>['props'];
11
+ events(): ReturnType<typeof $$render<TData>>['events'];
12
+ slots(): ReturnType<typeof $$render<TData>>['slots'];
13
+ bindings(): "";
14
+ exports(): {};
15
+ }
16
+ interface $$IsomorphicComponent {
17
+ new <TData>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TData>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TData>['props']>, ReturnType<__sveltets_Render<TData>['events']>, ReturnType<__sveltets_Render<TData>['slots']>> & {
18
+ $$bindings?: ReturnType<__sveltets_Render<TData>['bindings']>;
19
+ } & ReturnType<__sveltets_Render<TData>['exports']>;
20
+ <TData>(internal: unknown, props: ReturnType<__sveltets_Render<TData>['props']> & {}): ReturnType<__sveltets_Render<TData>['exports']>;
21
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
22
+ }
23
+ declare const DataTableRow: $$IsomorphicComponent;
24
+ type DataTableRow<TData> = InstanceType<typeof DataTableRow<TData>>;
25
+ export default DataTableRow;