@invopop/popui 0.1.3 → 0.1.4-beta.1
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/AlertDialog.svelte +10 -11
- package/dist/BaseButton.svelte +29 -104
- package/dist/BaseCard.svelte +35 -30
- package/dist/BaseCounter.svelte +11 -8
- package/dist/BaseDropdown.svelte +5 -5
- package/dist/BaseFlag.svelte +5 -3
- package/dist/BaseFlag.svelte.d.ts +1 -0
- package/dist/BaseTable.svelte +16 -16
- package/dist/BaseTable.svelte.d.ts +1 -1
- package/dist/BaseTableActions.svelte +4 -6
- package/dist/BaseTableCellContent.svelte +9 -21
- package/dist/BaseTableCheckbox.svelte +9 -11
- package/dist/BaseTableHeaderContent.svelte +4 -4
- package/dist/BaseTableHeaderOrderBy.svelte +23 -12
- package/dist/BaseTableRow.svelte +12 -10
- package/dist/Breadcrumb.svelte +40 -0
- package/dist/Breadcrumb.svelte.d.ts +4 -0
- package/dist/Breadcrumbs.svelte +5 -30
- package/dist/ButtonFile.svelte +40 -30
- package/dist/ButtonUuidCopy.svelte +6 -3
- package/dist/CardCheckbox.svelte +45 -32
- package/dist/CardCheckbox.svelte.d.ts +1 -1
- package/dist/CardRelation.svelte +12 -13
- package/dist/CompanySelector.svelte +35 -7
- package/dist/CounterWidget.svelte +52 -0
- package/dist/CounterWidget.svelte.d.ts +4 -0
- package/dist/DataListItem.svelte +14 -10
- package/dist/DatePicker.svelte +20 -17
- package/dist/DrawerContext.svelte +207 -15
- package/dist/DrawerContextItem.svelte +50 -50
- package/dist/DrawerContextSeparator.svelte +1 -1
- package/dist/DropdownSelect.svelte +81 -22
- package/dist/DropdownSelectGroup.svelte +15 -0
- package/dist/DropdownSelectGroup.svelte.d.ts +7 -0
- package/dist/EmptyState.svelte +42 -0
- package/dist/EmptyState.svelte.d.ts +4 -0
- package/dist/FeedEvents.svelte +9 -5
- package/dist/FeedIconEvent.svelte +2 -2
- package/dist/FeedIconStatus.svelte +4 -4
- package/dist/FeedItem.svelte +10 -11
- package/dist/FeedItemDetail.svelte +32 -6
- package/dist/FeedViewer.svelte +1 -1
- package/dist/GlobalSearch.svelte +13 -12
- package/dist/InputCheckbox.svelte +2 -5
- package/dist/InputError.svelte +4 -9
- package/dist/InputLabel.svelte +3 -1
- package/dist/InputRadio.svelte +29 -13
- package/dist/InputRadio.svelte.d.ts +1 -1
- package/dist/InputSearch.svelte +8 -8
- package/dist/InputSelect.svelte +32 -31
- package/dist/InputText.svelte +32 -24
- package/dist/InputTextarea.svelte +25 -19
- package/dist/InputToggle.svelte +24 -18
- package/dist/MenuItem.svelte +16 -11
- package/dist/MenuItemCollapsible.svelte +7 -7
- package/dist/Notification.svelte +60 -25
- package/dist/ProfileAvatar.svelte +43 -14
- package/dist/ProgressBar.svelte +42 -0
- package/dist/ProgressBar.svelte.d.ts +4 -0
- package/dist/ProgressBarCircle.svelte +46 -0
- package/dist/ProgressBarCircle.svelte.d.ts +4 -0
- package/dist/SeparatorHorizontal.svelte +2 -2
- package/dist/ShortcutWrapper.svelte +14 -5
- package/dist/StatusLabel.svelte +4 -5
- package/dist/StepIconList.svelte +11 -9
- package/dist/TagBeta.svelte +26 -14
- package/dist/TagProgress.svelte +28 -0
- package/dist/TagProgress.svelte.d.ts +4 -0
- package/dist/TagSearch.svelte +4 -4
- package/dist/TagStatus.svelte +32 -34
- package/dist/TitleMain.svelte +1 -1
- package/dist/TitleSection.svelte +1 -1
- package/dist/UuidCopy.svelte +4 -4
- package/dist/alert-dialog/alert-dialog-action.svelte +8 -4
- package/dist/alert-dialog/alert-dialog-cancel.svelte +7 -3
- package/dist/alert-dialog/alert-dialog-content.svelte +1 -1
- package/dist/alert-dialog/alert-dialog-description.svelte +1 -1
- package/dist/alert-dialog/alert-dialog-footer.svelte +1 -1
- package/dist/alert-dialog/alert-dialog-header.svelte +1 -1
- package/dist/alert-dialog/alert-dialog-overlay.svelte +1 -1
- package/dist/alert-dialog/alert-dialog-title.svelte +1 -1
- package/dist/alert-dialog/alert-dialog-trigger.svelte +4 -2
- package/dist/button/button.svelte +224 -24
- package/dist/button/button.svelte.d.ts +77 -26
- package/dist/clickOutside.d.ts +5 -2
- package/dist/clickOutside.js +9 -3
- package/dist/data-table/cells/boolean-cell.svelte +16 -0
- package/dist/data-table/cells/boolean-cell.svelte.d.ts +8 -0
- package/dist/data-table/cells/currency-cell.svelte +10 -0
- package/dist/data-table/cells/currency-cell.svelte.d.ts +8 -0
- package/dist/data-table/cells/date-cell.svelte +10 -0
- package/dist/data-table/cells/date-cell.svelte.d.ts +8 -0
- package/dist/data-table/cells/tag-cell.svelte +12 -0
- package/dist/data-table/cells/tag-cell.svelte.d.ts +8 -0
- package/dist/data-table/cells/text-cell.svelte +10 -0
- package/dist/data-table/cells/text-cell.svelte.d.ts +8 -0
- package/dist/data-table/column-definitions.d.ts +12 -0
- package/dist/data-table/column-definitions.js +40 -0
- package/dist/data-table/column-sizing-helpers.d.ts +6 -0
- package/dist/data-table/column-sizing-helpers.js +24 -0
- package/dist/data-table/create-columns.d.ts +3 -0
- package/dist/data-table/create-columns.js +50 -0
- package/dist/data-table/data-table-pagination.svelte +173 -0
- package/dist/data-table/data-table-pagination.svelte.d.ts +4 -0
- package/dist/data-table/data-table-svelte.svelte.d.ts +40 -0
- package/dist/data-table/data-table-svelte.svelte.js +111 -0
- package/dist/data-table/data-table-toolbar.svelte +16 -0
- package/dist/data-table/data-table-toolbar.svelte.d.ts +29 -0
- package/dist/data-table/data-table-types.d.ts +74 -0
- package/dist/data-table/data-table-types.js +1 -0
- package/dist/data-table/data-table-view-options.svelte +88 -0
- package/dist/data-table/data-table-view-options.svelte.d.ts +27 -0
- package/dist/data-table/data-table.svelte +324 -0
- package/dist/data-table/data-table.svelte.d.ts +25 -0
- package/dist/data-table/flex-render.svelte +40 -0
- package/dist/data-table/flex-render.svelte.d.ts +33 -0
- package/dist/data-table/index.d.ts +13 -0
- package/dist/data-table/index.js +13 -0
- package/dist/data-table/render-helpers.d.ts +90 -0
- package/dist/data-table/render-helpers.js +99 -0
- package/dist/data-table/table-setup.d.ts +36 -0
- package/dist/data-table/table-setup.js +130 -0
- package/dist/data-table/table-styles.d.ts +17 -0
- package/dist/data-table/table-styles.js +49 -0
- package/dist/helpers.d.ts +1 -0
- package/dist/helpers.js +3 -0
- package/dist/index.d.ts +16 -7
- package/dist/index.js +33 -14
- package/dist/range-calendar/range-calendar-cell.svelte +1 -1
- package/dist/range-calendar/range-calendar-day.svelte +11 -12
- package/dist/range-calendar/range-calendar-head-cell.svelte +1 -1
- package/dist/range-calendar/range-calendar-header.svelte +1 -1
- package/dist/range-calendar/range-calendar-month-select.svelte +1 -1
- package/dist/range-calendar/range-calendar-next-button.svelte +3 -3
- package/dist/range-calendar/range-calendar-prev-button.svelte +3 -3
- package/dist/range-calendar/range-calendar.svelte +1 -1
- package/dist/sonner/index.d.ts +1 -0
- package/dist/sonner/index.js +1 -0
- package/dist/sonner/sonner.svelte +44 -0
- package/dist/sonner/sonner.svelte.d.ts +4 -0
- package/dist/svg/CheckBadge.svelte +18 -0
- package/dist/svg/CheckBadge.svelte.d.ts +26 -0
- package/dist/svg/IconDelivery.svelte +86 -0
- package/dist/svg/IconDelivery.svelte.d.ts +20 -0
- package/dist/svg/IconEmpty.svelte +113 -121
- package/dist/svg/IconOrder.svelte +81 -0
- package/dist/svg/IconOrder.svelte.d.ts +20 -0
- package/dist/svg/IconPayment.svelte +86 -0
- package/dist/svg/IconPayment.svelte.d.ts +20 -0
- package/dist/table/table-body.svelte +5 -1
- package/dist/table/table-cell.svelte +4 -2
- package/dist/table/table-footer.svelte +1 -1
- package/dist/table/table-head.svelte +4 -2
- package/dist/table/table-header.svelte +1 -1
- package/dist/table/table-row.svelte +4 -2
- package/dist/table/table.svelte +2 -2
- package/dist/tabs/tabs-list.svelte +8 -2
- package/dist/tabs/tabs-list.svelte.d.ts +4 -1
- package/dist/tabs/tabs-trigger.svelte +5 -3
- package/dist/tabs/tabs-trigger.svelte.d.ts +4 -1
- package/dist/tailwind.theme.css +998 -0
- package/dist/tooltip/tooltip-content.svelte +2 -2
- package/dist/types.d.ts +76 -50
- package/package.json +20 -10
- package/dist/CounterWorkflow.svelte +0 -19
- package/dist/CounterWorkflow.svelte.d.ts +0 -4
- package/dist/DrawerContextWorkspace.svelte +0 -126
- package/dist/DrawerContextWorkspace.svelte.d.ts +0 -4
- package/dist/EmptyStateIcon.svelte +0 -52
- package/dist/EmptyStateIcon.svelte.d.ts +0 -4
- package/dist/EmptyStateIllustration.svelte +0 -66
- package/dist/EmptyStateIllustration.svelte.d.ts +0 -4
- package/dist/FormLayoutModal.svelte +0 -14
- package/dist/FormLayoutModal.svelte.d.ts +0 -4
- package/dist/ProfileSelector.svelte +0 -41
- package/dist/ProfileSelector.svelte.d.ts +0 -4
- package/dist/SectionLayout.svelte +0 -13
- package/dist/SectionLayout.svelte.d.ts +0 -4
- package/dist/tw.theme.d.ts +0 -171
- package/dist/tw.theme.js +0 -188
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { createTable, } from "@tanstack/table-core";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a reactive TanStack table object for Svelte.
|
|
4
|
+
* @param options Table options to create the table with.
|
|
5
|
+
* @returns A reactive table object.
|
|
6
|
+
* @example
|
|
7
|
+
* ```svelte
|
|
8
|
+
* <script>
|
|
9
|
+
* const table = createSvelteTable({ ... })
|
|
10
|
+
* </script>
|
|
11
|
+
*
|
|
12
|
+
* <table>
|
|
13
|
+
* <thead>
|
|
14
|
+
* {#each table.getHeaderGroups() as headerGroup}
|
|
15
|
+
* <tr>
|
|
16
|
+
* {#each headerGroup.headers as header}
|
|
17
|
+
* <th colspan={header.colSpan}>
|
|
18
|
+
* <FlexRender content={header.column.columnDef.header} context={header.getContext()} />
|
|
19
|
+
* </th>
|
|
20
|
+
* {/each}
|
|
21
|
+
* </tr>
|
|
22
|
+
* {/each}
|
|
23
|
+
* </thead>
|
|
24
|
+
* <!-- ... -->
|
|
25
|
+
* </table>
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export function createSvelteTable(options) {
|
|
29
|
+
const resolvedOptions = mergeObjects({
|
|
30
|
+
state: {},
|
|
31
|
+
onStateChange() { },
|
|
32
|
+
renderFallbackValue: null,
|
|
33
|
+
mergeOptions: (defaultOptions, options) => {
|
|
34
|
+
return mergeObjects(defaultOptions, options);
|
|
35
|
+
},
|
|
36
|
+
}, options);
|
|
37
|
+
const table = createTable(resolvedOptions);
|
|
38
|
+
let state = $state(table.initialState);
|
|
39
|
+
function updateOptions() {
|
|
40
|
+
table.setOptions((prev) => {
|
|
41
|
+
return mergeObjects(prev, options, {
|
|
42
|
+
state: mergeObjects(state, options.state || {}),
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
44
|
+
onStateChange: (updater) => {
|
|
45
|
+
if (updater instanceof Function)
|
|
46
|
+
state = updater(state);
|
|
47
|
+
else
|
|
48
|
+
state = mergeObjects(state, updater);
|
|
49
|
+
options.onStateChange?.(updater);
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
updateOptions();
|
|
55
|
+
$effect.pre(() => {
|
|
56
|
+
updateOptions();
|
|
57
|
+
});
|
|
58
|
+
return table;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Lazily merges several objects (or thunks) while preserving
|
|
62
|
+
* getter semantics from every source.
|
|
63
|
+
*
|
|
64
|
+
* Proxy-based to avoid known WebKit recursion issue.
|
|
65
|
+
*/
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
67
|
+
export function mergeObjects(...sources) {
|
|
68
|
+
const resolve = (src) => typeof src === "function" ? (src() ?? undefined) : src;
|
|
69
|
+
const findSourceWithKey = (key) => {
|
|
70
|
+
for (let i = sources.length - 1; i >= 0; i--) {
|
|
71
|
+
const obj = resolve(sources[i]);
|
|
72
|
+
if (obj && key in obj)
|
|
73
|
+
return obj;
|
|
74
|
+
}
|
|
75
|
+
return undefined;
|
|
76
|
+
};
|
|
77
|
+
return new Proxy(Object.create(null), {
|
|
78
|
+
get(_, key) {
|
|
79
|
+
const src = findSourceWithKey(key);
|
|
80
|
+
return src?.[key];
|
|
81
|
+
},
|
|
82
|
+
has(_, key) {
|
|
83
|
+
return !!findSourceWithKey(key);
|
|
84
|
+
},
|
|
85
|
+
ownKeys() {
|
|
86
|
+
// eslint-disable-next-line svelte/prefer-svelte-reactivity
|
|
87
|
+
const all = new Set();
|
|
88
|
+
for (const s of sources) {
|
|
89
|
+
const obj = resolve(s);
|
|
90
|
+
if (obj) {
|
|
91
|
+
for (const k of Reflect.ownKeys(obj)) {
|
|
92
|
+
all.add(k);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return [...all];
|
|
97
|
+
},
|
|
98
|
+
getOwnPropertyDescriptor(_, key) {
|
|
99
|
+
const src = findSourceWithKey(key);
|
|
100
|
+
if (!src)
|
|
101
|
+
return undefined;
|
|
102
|
+
return {
|
|
103
|
+
configurable: true,
|
|
104
|
+
enumerable: true,
|
|
105
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
106
|
+
value: src[key],
|
|
107
|
+
writable: true,
|
|
108
|
+
};
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script lang="ts" generics="TData">
|
|
2
|
+
import type { Table } from '@tanstack/table-core'
|
|
3
|
+
import type { Snippet } from 'svelte'
|
|
4
|
+
import { DataTableViewOptions } from './index.js'
|
|
5
|
+
|
|
6
|
+
let { table, filters }: { table: Table<TData>; filters?: Snippet } = $props()
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<div class="flex items-center justify-between">
|
|
10
|
+
{#if filters}
|
|
11
|
+
<div class="flex-1">
|
|
12
|
+
{@render filters()}
|
|
13
|
+
</div>
|
|
14
|
+
{/if}
|
|
15
|
+
<DataTableViewOptions {table} />
|
|
16
|
+
</div>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Table } from '@tanstack/table-core';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
declare function $$render<TData>(): {
|
|
4
|
+
props: {
|
|
5
|
+
table: Table<TData>;
|
|
6
|
+
filters?: Snippet;
|
|
7
|
+
};
|
|
8
|
+
exports: {};
|
|
9
|
+
bindings: "";
|
|
10
|
+
slots: {};
|
|
11
|
+
events: {};
|
|
12
|
+
};
|
|
13
|
+
declare class __sveltets_Render<TData> {
|
|
14
|
+
props(): ReturnType<typeof $$render<TData>>['props'];
|
|
15
|
+
events(): ReturnType<typeof $$render<TData>>['events'];
|
|
16
|
+
slots(): ReturnType<typeof $$render<TData>>['slots'];
|
|
17
|
+
bindings(): "";
|
|
18
|
+
exports(): {};
|
|
19
|
+
}
|
|
20
|
+
interface $$IsomorphicComponent {
|
|
21
|
+
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']>> & {
|
|
22
|
+
$$bindings?: ReturnType<__sveltets_Render<TData>['bindings']>;
|
|
23
|
+
} & ReturnType<__sveltets_Render<TData>['exports']>;
|
|
24
|
+
<TData>(internal: unknown, props: ReturnType<__sveltets_Render<TData>['props']> & {}): ReturnType<__sveltets_Render<TData>['exports']>;
|
|
25
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
26
|
+
}
|
|
27
|
+
declare const DataTableToolbar: $$IsomorphicComponent;
|
|
28
|
+
type DataTableToolbar<TData> = InstanceType<typeof DataTableToolbar<TData>>;
|
|
29
|
+
export default DataTableToolbar;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { Component, Snippet } from 'svelte';
|
|
2
|
+
import type { StatusType, AnyProp, TableAction, EmptyStateProps } from '../types.js';
|
|
3
|
+
import type { IconSource } from '@steeze-ui/svelte-icon';
|
|
4
|
+
import type { Table } from '@tanstack/table-core';
|
|
5
|
+
export type CellType = 'text' | 'boolean' | 'tag' | 'date' | 'currency' | 'custom';
|
|
6
|
+
export interface TextCellConfig {
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface BooleanCellConfig {
|
|
10
|
+
icon?: IconSource;
|
|
11
|
+
iconClass?: string;
|
|
12
|
+
showWhenTrue?: boolean;
|
|
13
|
+
showWhenFalse?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface TagCellConfig {
|
|
16
|
+
options: Array<{
|
|
17
|
+
value: string;
|
|
18
|
+
label: string;
|
|
19
|
+
color: StatusType;
|
|
20
|
+
}>;
|
|
21
|
+
showDot?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface DateCellConfig {
|
|
24
|
+
className?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface CurrencyCellConfig {
|
|
27
|
+
className?: string;
|
|
28
|
+
}
|
|
29
|
+
export type CellConfig = TextCellConfig | BooleanCellConfig | TagCellConfig | DateCellConfig | CurrencyCellConfig;
|
|
30
|
+
export interface DataTableColumn<TData> {
|
|
31
|
+
id: string;
|
|
32
|
+
accessorKey?: keyof TData;
|
|
33
|
+
header?: string;
|
|
34
|
+
cellType?: CellType;
|
|
35
|
+
cellConfig?: CellConfig;
|
|
36
|
+
cell?: (value: any, row: TData) => Snippet | Component | string;
|
|
37
|
+
enableSorting?: boolean;
|
|
38
|
+
enableHiding?: boolean;
|
|
39
|
+
enableResizing?: boolean;
|
|
40
|
+
size?: number;
|
|
41
|
+
minSize?: number;
|
|
42
|
+
maxSize?: number;
|
|
43
|
+
}
|
|
44
|
+
export interface DataTableProps<TData> {
|
|
45
|
+
data: TData[];
|
|
46
|
+
columns: DataTableColumn<TData>[];
|
|
47
|
+
disableSelection?: boolean;
|
|
48
|
+
disablePagination?: boolean;
|
|
49
|
+
rowActions?: TableAction[];
|
|
50
|
+
onRowAction?: (action: AnyProp, row: TData) => void;
|
|
51
|
+
initialPageSize?: number;
|
|
52
|
+
pageSizeOptions?: number[];
|
|
53
|
+
emptyState?: Omit<EmptyStateProps, 'children' | 'check'>;
|
|
54
|
+
onRowClick?: (row: TData) => void;
|
|
55
|
+
onSelectionChange?: (selectedRows: TData[]) => void;
|
|
56
|
+
filters?: Snippet;
|
|
57
|
+
paginationSelectedSlot?: Snippet;
|
|
58
|
+
paginationUnselectedSlot?: Snippet;
|
|
59
|
+
onPageChange?: (pageIndex: number) => void;
|
|
60
|
+
onPageSizeChange?: (pageSize: number) => void;
|
|
61
|
+
}
|
|
62
|
+
export interface DataTablePaginationProps<T> {
|
|
63
|
+
table: Table<T>;
|
|
64
|
+
id?: string;
|
|
65
|
+
class?: string;
|
|
66
|
+
showRowsPerPage?: boolean;
|
|
67
|
+
rowsPerPageOptions?: number[];
|
|
68
|
+
itemsLabel?: string;
|
|
69
|
+
children?: Snippet;
|
|
70
|
+
selectedSlot?: Snippet;
|
|
71
|
+
unselectedSlot?: Snippet;
|
|
72
|
+
onPageChange?: (pageIndex: number) => void;
|
|
73
|
+
onPageSizeChange?: (pageSize: number) => void;
|
|
74
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<script lang="ts" generics="TData">
|
|
2
|
+
import { Sliders, Drag } from '@invopop/ui-icons'
|
|
3
|
+
import type { Table } from '@tanstack/table-core'
|
|
4
|
+
import type { DrawerOption } from '../types.js'
|
|
5
|
+
import BaseDropdown from '../BaseDropdown.svelte'
|
|
6
|
+
import DrawerContext from '../DrawerContext.svelte'
|
|
7
|
+
import InputToggle from '../InputToggle.svelte'
|
|
8
|
+
import BaseButton from '../BaseButton.svelte'
|
|
9
|
+
import { capitalize } from '../helpers.js'
|
|
10
|
+
|
|
11
|
+
let { table }: { table: Table<TData> } = $props()
|
|
12
|
+
|
|
13
|
+
let itemsWithActions = $state<DrawerOption[]>([])
|
|
14
|
+
|
|
15
|
+
// Initialize and update items when table state changes
|
|
16
|
+
$effect(() => {
|
|
17
|
+
const columnOrder = table.getState().columnOrder
|
|
18
|
+
const allColumns = table.getAllColumns()
|
|
19
|
+
|
|
20
|
+
let orderedColumns
|
|
21
|
+
// If there's a custom order, use it; otherwise use default order
|
|
22
|
+
if (columnOrder.length > 0) {
|
|
23
|
+
orderedColumns = columnOrder
|
|
24
|
+
.map((id) => allColumns.find((col) => col.id === id))
|
|
25
|
+
.filter((col) => col && col.id !== 'select' && col.id !== 'actions')
|
|
26
|
+
} else {
|
|
27
|
+
orderedColumns = allColumns.filter((col) => col.id !== 'select' && col.id !== 'actions')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const newItems = orderedColumns.map((col) => ({
|
|
31
|
+
label: (col?.columnDef.header as string) || capitalize(col?.id || ''),
|
|
32
|
+
value: col?.id,
|
|
33
|
+
icon: Drag,
|
|
34
|
+
action: toggleAction
|
|
35
|
+
})) as DrawerOption[]
|
|
36
|
+
|
|
37
|
+
// Only update if the order has actually changed (avoid overwriting during drag)
|
|
38
|
+
const currentOrder = itemsWithActions.map((i) => i.value).join(',')
|
|
39
|
+
const newOrder = newItems.map((i) => i.value).join(',')
|
|
40
|
+
|
|
41
|
+
if (currentOrder !== newOrder) {
|
|
42
|
+
itemsWithActions = newItems
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
function handleReorder(reorderedItems: any[]) {
|
|
47
|
+
// Update local items to match the drag order immediately
|
|
48
|
+
itemsWithActions = reorderedItems
|
|
49
|
+
|
|
50
|
+
const newOrder = reorderedItems.map((item) => item.value)
|
|
51
|
+
// Get all column IDs from the table
|
|
52
|
+
const allColumnIds = table.getAllColumns().map((col) => col.id)
|
|
53
|
+
|
|
54
|
+
// Filter to keep select and actions in their fixed positions
|
|
55
|
+
const selectColumn = 'select'
|
|
56
|
+
const actionsColumn = 'actions'
|
|
57
|
+
|
|
58
|
+
// Build final order: select first (if exists), reordered columns in middle, actions last (if exists)
|
|
59
|
+
const finalOrder = [
|
|
60
|
+
...(allColumnIds.includes(selectColumn) ? [selectColumn] : []),
|
|
61
|
+
...newOrder.filter((id) => id !== selectColumn && id !== actionsColumn),
|
|
62
|
+
...(allColumnIds.includes(actionsColumn) ? [actionsColumn] : [])
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
table.setColumnOrder(finalOrder)
|
|
66
|
+
}
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
{#snippet toggleAction(item: DrawerOption)}
|
|
70
|
+
{@const column = table.getColumn(String(item.value))}
|
|
71
|
+
{#if column?.getCanHide()}
|
|
72
|
+
<InputToggle
|
|
73
|
+
checked={column?.getIsVisible() ?? false}
|
|
74
|
+
onchange={(v) => column?.toggleVisibility(!!v)}
|
|
75
|
+
/>
|
|
76
|
+
{/if}
|
|
77
|
+
{/snippet}
|
|
78
|
+
|
|
79
|
+
<BaseDropdown class="ms-auto hidden lg:flex">
|
|
80
|
+
{#snippet trigger()}
|
|
81
|
+
<BaseButton icon={Sliders} variant="outline" size="md" />
|
|
82
|
+
{/snippet}
|
|
83
|
+
<DrawerContext items={itemsWithActions} draggable={true} onreorder={handleReorder}>
|
|
84
|
+
<div class="p-3 py-1.5 text-sm font-medium text-foreground-default-secondary">
|
|
85
|
+
Table options
|
|
86
|
+
</div>
|
|
87
|
+
</DrawerContext>
|
|
88
|
+
</BaseDropdown>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Table } from '@tanstack/table-core';
|
|
2
|
+
declare function $$render<TData>(): {
|
|
3
|
+
props: {
|
|
4
|
+
table: Table<TData>;
|
|
5
|
+
};
|
|
6
|
+
exports: {};
|
|
7
|
+
bindings: "";
|
|
8
|
+
slots: {};
|
|
9
|
+
events: {};
|
|
10
|
+
};
|
|
11
|
+
declare class __sveltets_Render<TData> {
|
|
12
|
+
props(): ReturnType<typeof $$render<TData>>['props'];
|
|
13
|
+
events(): ReturnType<typeof $$render<TData>>['events'];
|
|
14
|
+
slots(): ReturnType<typeof $$render<TData>>['slots'];
|
|
15
|
+
bindings(): "";
|
|
16
|
+
exports(): {};
|
|
17
|
+
}
|
|
18
|
+
interface $$IsomorphicComponent {
|
|
19
|
+
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']>> & {
|
|
20
|
+
$$bindings?: ReturnType<__sveltets_Render<TData>['bindings']>;
|
|
21
|
+
} & ReturnType<__sveltets_Render<TData>['exports']>;
|
|
22
|
+
<TData>(internal: unknown, props: ReturnType<__sveltets_Render<TData>['props']> & {}): ReturnType<__sveltets_Render<TData>['exports']>;
|
|
23
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
24
|
+
}
|
|
25
|
+
declare const DataTableViewOptions: $$IsomorphicComponent;
|
|
26
|
+
type DataTableViewOptions<TData> = InstanceType<typeof DataTableViewOptions<TData>>;
|
|
27
|
+
export default DataTableViewOptions;
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
<script lang="ts" generics="TData">
|
|
2
|
+
import {
|
|
3
|
+
type ColumnSizingState,
|
|
4
|
+
type ColumnSizingInfoState,
|
|
5
|
+
type ColumnOrderState,
|
|
6
|
+
type PaginationState,
|
|
7
|
+
type Row,
|
|
8
|
+
type RowSelectionState,
|
|
9
|
+
type SortingState,
|
|
10
|
+
type VisibilityState,
|
|
11
|
+
type Column
|
|
12
|
+
} from '@tanstack/table-core'
|
|
13
|
+
import DataTableToolbar from './data-table-toolbar.svelte'
|
|
14
|
+
import DataTablePagination from './data-table-pagination.svelte'
|
|
15
|
+
import FlexRender from './flex-render.svelte'
|
|
16
|
+
import * as Table from '../table/index.js'
|
|
17
|
+
import BaseTableActions from '../BaseTableActions.svelte'
|
|
18
|
+
import BaseDropdown from '../BaseDropdown.svelte'
|
|
19
|
+
import BaseTableHeaderOrderBy from '../BaseTableHeaderOrderBy.svelte'
|
|
20
|
+
import EmptyState from '../EmptyState.svelte'
|
|
21
|
+
import { Icon } from '@steeze-ui/svelte-icon'
|
|
22
|
+
import { ArrowUp, ArrowDown, Search } from '@invopop/ui-icons'
|
|
23
|
+
import type { HTMLAttributes } from 'svelte/elements'
|
|
24
|
+
import { cn } from '../utils.js'
|
|
25
|
+
import type { DataTableProps } from './data-table-types.js'
|
|
26
|
+
import { calculateColumnSizing } from './column-sizing-helpers.js'
|
|
27
|
+
import { getHeaderStyle, getHeaderClasses, getCellStyle, getCellClasses } from './table-styles.js'
|
|
28
|
+
import { buildColumns, setupTable } from './table-setup.js'
|
|
29
|
+
|
|
30
|
+
let {
|
|
31
|
+
data,
|
|
32
|
+
columns: columnConfig,
|
|
33
|
+
disableSelection = false,
|
|
34
|
+
disablePagination = false,
|
|
35
|
+
rowActions = [],
|
|
36
|
+
onRowAction,
|
|
37
|
+
initialPageSize = 10,
|
|
38
|
+
emptyState = {
|
|
39
|
+
iconSource: Search,
|
|
40
|
+
title: 'No results',
|
|
41
|
+
description: 'Try adjusting your filters or search query'
|
|
42
|
+
},
|
|
43
|
+
onRowClick,
|
|
44
|
+
onSelectionChange,
|
|
45
|
+
filters,
|
|
46
|
+
paginationSelectedSlot,
|
|
47
|
+
paginationUnselectedSlot,
|
|
48
|
+
onPageChange,
|
|
49
|
+
onPageSizeChange
|
|
50
|
+
}: DataTableProps<TData> = $props()
|
|
51
|
+
|
|
52
|
+
const enableSelection = !disableSelection
|
|
53
|
+
const enablePagination = !disablePagination
|
|
54
|
+
|
|
55
|
+
let rowSelection = $state<RowSelectionState>({})
|
|
56
|
+
let columnVisibility = $state<VisibilityState>({})
|
|
57
|
+
let sorting = $state<SortingState>([])
|
|
58
|
+
let pagination = $state<PaginationState>({ pageIndex: 0, pageSize: initialPageSize })
|
|
59
|
+
let columnSizing = $state<ColumnSizingState>({})
|
|
60
|
+
let columnSizingInfo = $state<ColumnSizingInfoState>({
|
|
61
|
+
columnSizingStart: [],
|
|
62
|
+
deltaOffset: null,
|
|
63
|
+
deltaPercentage: null,
|
|
64
|
+
isResizingColumn: false,
|
|
65
|
+
startOffset: null,
|
|
66
|
+
startSize: null
|
|
67
|
+
})
|
|
68
|
+
let columnOrder = $state<ColumnOrderState>([])
|
|
69
|
+
let containerRef = $state<HTMLDivElement | null>(null)
|
|
70
|
+
|
|
71
|
+
// Build TanStack columns from config
|
|
72
|
+
const columns = $derived.by(() =>
|
|
73
|
+
buildColumns<TData>(columnConfig, enableSelection, RowActions, rowActions.length > 0)
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
// Calculate initial column sizes based on available width
|
|
77
|
+
$effect(() => {
|
|
78
|
+
if (containerRef && Object.keys(columnSizing).length === 0) {
|
|
79
|
+
const containerWidth = containerRef.offsetWidth
|
|
80
|
+
const newSizing = calculateColumnSizing(columns, containerWidth)
|
|
81
|
+
if (newSizing) {
|
|
82
|
+
columnSizing = newSizing
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
// Track selection changes
|
|
88
|
+
$effect(() => {
|
|
89
|
+
if (onSelectionChange) {
|
|
90
|
+
const selectedRows = Object.keys(rowSelection)
|
|
91
|
+
.filter((key) => rowSelection[key])
|
|
92
|
+
.map((key) => data[parseInt(key)])
|
|
93
|
+
onSelectionChange(selectedRows)
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
const table = setupTable({
|
|
98
|
+
get data() {
|
|
99
|
+
return data
|
|
100
|
+
},
|
|
101
|
+
get columns() {
|
|
102
|
+
return columns
|
|
103
|
+
},
|
|
104
|
+
enableSelection,
|
|
105
|
+
enablePagination,
|
|
106
|
+
getRowSelection: () => rowSelection,
|
|
107
|
+
getColumnVisibility: () => columnVisibility,
|
|
108
|
+
getSorting: () => sorting,
|
|
109
|
+
getPagination: () => pagination,
|
|
110
|
+
getColumnSizing: () => columnSizing,
|
|
111
|
+
getColumnSizingInfo: () => columnSizingInfo,
|
|
112
|
+
getColumnOrder: () => columnOrder,
|
|
113
|
+
setRowSelection: (value) => (rowSelection = value),
|
|
114
|
+
setColumnVisibility: (value) => (columnVisibility = value),
|
|
115
|
+
setSorting: (value) => (sorting = value),
|
|
116
|
+
setPagination: (value) => (pagination = value),
|
|
117
|
+
setColumnSizing: (value) => (columnSizing = value),
|
|
118
|
+
setColumnSizingInfo: (value) => (columnSizingInfo = value),
|
|
119
|
+
setColumnOrder: (value) => (columnOrder = value)
|
|
120
|
+
})
|
|
121
|
+
</script>
|
|
122
|
+
|
|
123
|
+
{#snippet StickyCellWrapper({
|
|
124
|
+
children,
|
|
125
|
+
align = 'left'
|
|
126
|
+
}: {
|
|
127
|
+
children: any
|
|
128
|
+
align?: 'left' | 'right'
|
|
129
|
+
})}
|
|
130
|
+
<div
|
|
131
|
+
class={cn(
|
|
132
|
+
'h-10 flex items-center px-3 relative group-hover/row:bg-background-default-secondary group-data-[state=selected]/row:bg-background-selected',
|
|
133
|
+
align === 'right' ? 'justify-end' : ''
|
|
134
|
+
)}
|
|
135
|
+
>
|
|
136
|
+
<div class="relative z-10">
|
|
137
|
+
{@render children()}
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
{/snippet}
|
|
141
|
+
|
|
142
|
+
{#snippet RowActions({ row }: { row: Row<TData> })}
|
|
143
|
+
<BaseTableActions
|
|
144
|
+
actions={rowActions}
|
|
145
|
+
onclick={(action) => {
|
|
146
|
+
if (onRowAction) {
|
|
147
|
+
onRowAction(action, row.original)
|
|
148
|
+
}
|
|
149
|
+
}}
|
|
150
|
+
/>
|
|
151
|
+
{/snippet}
|
|
152
|
+
|
|
153
|
+
{#snippet ColumnHeader({
|
|
154
|
+
column,
|
|
155
|
+
title,
|
|
156
|
+
class: className,
|
|
157
|
+
...restProps
|
|
158
|
+
}: { column: Column<TData>; title?: string } & HTMLAttributes<HTMLDivElement>)}
|
|
159
|
+
{#if !column?.getCanSort()}
|
|
160
|
+
<div class={className} {...restProps}>
|
|
161
|
+
{title || ''}
|
|
162
|
+
</div>
|
|
163
|
+
{:else}
|
|
164
|
+
<div class={cn('flex items-center w-full', className)} {...restProps}>
|
|
165
|
+
<BaseDropdown fullWidth>
|
|
166
|
+
{#snippet trigger()}
|
|
167
|
+
<button
|
|
168
|
+
class="data-[state=open]:bg-accent w-full flex items-center gap-1 py-2.5 text-left"
|
|
169
|
+
>
|
|
170
|
+
<span>
|
|
171
|
+
{title || ''}
|
|
172
|
+
</span>
|
|
173
|
+
{#if column.getIsSorted() === 'desc'}
|
|
174
|
+
<Icon src={ArrowDown} class="size-4" />
|
|
175
|
+
{:else if column.getIsSorted() === 'asc'}
|
|
176
|
+
<Icon src={ArrowUp} class="size-4" />
|
|
177
|
+
{/if}
|
|
178
|
+
</button>
|
|
179
|
+
{/snippet}
|
|
180
|
+
<BaseTableHeaderOrderBy
|
|
181
|
+
sortDirection={column.getIsSorted() === 'asc' ? 'asc' : 'desc'}
|
|
182
|
+
isActive={column.getIsSorted() !== false}
|
|
183
|
+
onOrderBy={(direction) => column.toggleSorting(direction === 'desc')}
|
|
184
|
+
onHide={() => column.toggleVisibility(false)}
|
|
185
|
+
/>
|
|
186
|
+
</BaseDropdown>
|
|
187
|
+
</div>
|
|
188
|
+
{/if}
|
|
189
|
+
{/snippet}
|
|
190
|
+
|
|
191
|
+
<div class="flex flex-col gap-4">
|
|
192
|
+
<DataTableToolbar {table} {filters} />
|
|
193
|
+
<div class="flex flex-col gap-[5px]">
|
|
194
|
+
<div bind:this={containerRef} class="relative bg-background">
|
|
195
|
+
<div class="overflow-x-auto relative z-10">
|
|
196
|
+
<Table.Root>
|
|
197
|
+
<Table.Header>
|
|
198
|
+
{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
|
|
199
|
+
<Table.Row class="hover:!bg-transparent border-b border-border">
|
|
200
|
+
{#each headerGroup.headers as header, index (header.id)}
|
|
201
|
+
{@const isLastScrollable = index === headerGroup.headers.length - 2}
|
|
202
|
+
<Table.Head
|
|
203
|
+
colspan={header.colSpan}
|
|
204
|
+
style={getHeaderStyle(header, isLastScrollable)}
|
|
205
|
+
class={getHeaderClasses(header, isLastScrollable)}
|
|
206
|
+
>
|
|
207
|
+
{#if !header.isPlaceholder}
|
|
208
|
+
{#if typeof header.column.columnDef.header === 'string'}
|
|
209
|
+
{@render ColumnHeader({
|
|
210
|
+
column: header.column as Column<TData>,
|
|
211
|
+
title: header.column.columnDef.header as string
|
|
212
|
+
})}
|
|
213
|
+
{:else}
|
|
214
|
+
<FlexRender
|
|
215
|
+
content={header.column.columnDef.header}
|
|
216
|
+
context={header.getContext()}
|
|
217
|
+
/>
|
|
218
|
+
{/if}
|
|
219
|
+
{/if}
|
|
220
|
+
{#if header.column.getCanResize()}
|
|
221
|
+
<!-- Always visible vertical border -->
|
|
222
|
+
<div
|
|
223
|
+
class={cn(
|
|
224
|
+
'absolute right-0 top-1/2 -translate-y-1/2 h-3 w-px bg-background-default-tertiary',
|
|
225
|
+
header.column.getIsResizing() && 'opacity-0'
|
|
226
|
+
)}
|
|
227
|
+
></div>
|
|
228
|
+
<!-- Resize handler (larger interactive area, enhanced on hover) -->
|
|
229
|
+
<div
|
|
230
|
+
role="button"
|
|
231
|
+
tabindex="0"
|
|
232
|
+
aria-label="Resize column"
|
|
233
|
+
class="absolute right-0 top-0 h-full w-3 cursor-col-resize select-none touch-none group -mr-1.5"
|
|
234
|
+
onmousedown={header.getResizeHandler()}
|
|
235
|
+
ontouchstart={header.getResizeHandler()}
|
|
236
|
+
>
|
|
237
|
+
<div
|
|
238
|
+
class={cn(
|
|
239
|
+
'absolute right-1.5 top-0 h-full w-0.5 bg-border-default-secondary transition-opacity opacity-0',
|
|
240
|
+
!header.column.getIsResizing() && 'group-hover:opacity-100'
|
|
241
|
+
)}
|
|
242
|
+
></div>
|
|
243
|
+
</div>
|
|
244
|
+
{/if}
|
|
245
|
+
</Table.Head>
|
|
246
|
+
{/each}
|
|
247
|
+
</Table.Row>
|
|
248
|
+
{/each}
|
|
249
|
+
</Table.Header>
|
|
250
|
+
<Table.Body>
|
|
251
|
+
{#each table.getRowModel().rows as row (row.id)}
|
|
252
|
+
<Table.Row
|
|
253
|
+
data-state={row.getIsSelected() ? 'selected' : undefined}
|
|
254
|
+
class="border-b border-border"
|
|
255
|
+
onclick={() => onRowClick?.(row.original as TData)}
|
|
256
|
+
>
|
|
257
|
+
{#each row.getVisibleCells() as cell, index (cell.id)}
|
|
258
|
+
{@const isLastScrollable = index === row.getVisibleCells().length - 2}
|
|
259
|
+
{@const visibleCells = row.getVisibleCells()}
|
|
260
|
+
{@const firstDataColumnIndex = visibleCells.findIndex(
|
|
261
|
+
(c) => c.column.id !== 'select' && c.column.id !== 'actions'
|
|
262
|
+
)}
|
|
263
|
+
{@const isFirstDataColumn = index === firstDataColumnIndex}
|
|
264
|
+
<Table.Cell
|
|
265
|
+
style={getCellStyle(cell, isLastScrollable)}
|
|
266
|
+
class={getCellClasses(cell, isLastScrollable, isFirstDataColumn)}
|
|
267
|
+
>
|
|
268
|
+
{#if cell.column.id === 'actions'}
|
|
269
|
+
{@render StickyCellWrapper({
|
|
270
|
+
align: 'right',
|
|
271
|
+
children: CellContent
|
|
272
|
+
})}
|
|
273
|
+
{#snippet CellContent()}
|
|
274
|
+
<FlexRender
|
|
275
|
+
content={cell.column.columnDef.cell}
|
|
276
|
+
context={cell.getContext()}
|
|
277
|
+
/>
|
|
278
|
+
{/snippet}
|
|
279
|
+
{:else if cell.column.id === 'select'}
|
|
280
|
+
{@render StickyCellWrapper({
|
|
281
|
+
align: 'left',
|
|
282
|
+
children: CellContent
|
|
283
|
+
})}
|
|
284
|
+
{#snippet CellContent()}
|
|
285
|
+
<FlexRender
|
|
286
|
+
content={cell.column.columnDef.cell}
|
|
287
|
+
context={cell.getContext()}
|
|
288
|
+
/>
|
|
289
|
+
{/snippet}
|
|
290
|
+
{:else}
|
|
291
|
+
<FlexRender
|
|
292
|
+
content={cell.column.columnDef.cell}
|
|
293
|
+
context={cell.getContext()}
|
|
294
|
+
/>
|
|
295
|
+
{/if}
|
|
296
|
+
</Table.Cell>
|
|
297
|
+
{/each}
|
|
298
|
+
</Table.Row>
|
|
299
|
+
{:else}
|
|
300
|
+
<Table.Row>
|
|
301
|
+
<Table.Cell colspan={columns.length} class="h-48">
|
|
302
|
+
<EmptyState
|
|
303
|
+
iconSource={emptyState.iconSource}
|
|
304
|
+
title={emptyState.title}
|
|
305
|
+
description={emptyState.description}
|
|
306
|
+
/>
|
|
307
|
+
</Table.Cell>
|
|
308
|
+
</Table.Row>
|
|
309
|
+
{/each}
|
|
310
|
+
</Table.Body>
|
|
311
|
+
</Table.Root>
|
|
312
|
+
</div>
|
|
313
|
+
</div>
|
|
314
|
+
{#if enablePagination}
|
|
315
|
+
<DataTablePagination
|
|
316
|
+
{table}
|
|
317
|
+
selectedSlot={paginationSelectedSlot}
|
|
318
|
+
unselectedSlot={paginationUnselectedSlot}
|
|
319
|
+
{onPageChange}
|
|
320
|
+
{onPageSizeChange}
|
|
321
|
+
/>
|
|
322
|
+
{/if}
|
|
323
|
+
</div>
|
|
324
|
+
</div>
|