@emamid/svelte-data-table 0.0.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/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # create-svelte
2
+
3
+ Everything you need to build a Svelte library, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).
4
+
5
+ Read more about creating a library [in the docs](https://kit.svelte.dev/docs/packaging).
6
+
7
+ ## Creating a project
8
+
9
+ If you're seeing this, you've probably already done this step. Congrats!
10
+
11
+ ```bash
12
+ # create a new project in the current directory
13
+ npm create svelte@latest
14
+
15
+ # create a new project in my-app
16
+ npm create svelte@latest my-app
17
+ ```
18
+
19
+ ## Developing
20
+
21
+ Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
22
+
23
+ ```bash
24
+ npm run dev
25
+
26
+ # or start the server and open the app in a new browser tab
27
+ npm run dev -- --open
28
+ ```
29
+
30
+ Everything inside `src/lib` is part of your library, everything inside `src/routes` can be used as a showcase or preview app.
31
+
32
+ ## Building
33
+
34
+ To build your library:
35
+
36
+ ```bash
37
+ npm run package
38
+ ```
39
+
40
+ To create a production version of your showcase app:
41
+
42
+ ```bash
43
+ npm run build
44
+ ```
45
+
46
+ You can preview the production build with `npm run preview`.
47
+
48
+ > To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
49
+
50
+ ## Publishing
51
+
52
+ Go into the `package.json` and give your package the desired name through the `"name"` option. Also consider adding a `"license"` field and point it to a `LICENSE` file which you can create from a template (one popular option is the [MIT license](https://opensource.org/license/mit/)).
53
+
54
+ To publish your library to [npm](https://www.npmjs.com):
55
+
56
+ ```bash
57
+ npm publish
58
+ ```
@@ -0,0 +1,200 @@
1
+ <script>import { createEventDispatcher } from "svelte";
2
+ import { Table, TableBody, TableBodyRow, TableHead } from "flowbite-svelte";
3
+ import DataTableDataCell from "./DataTableDataCell.svelte";
4
+ import DataTableHeaderCell from "./DataTableHeaderCell.svelte";
5
+ import { joinClasses } from "./common.ts";
6
+ export let columns = [];
7
+ export let items = [];
8
+ export let sortKey = "";
9
+ export let sortFunction = null;
10
+ export let reverseSort = false;
11
+ export let sortColumnID = null;
12
+ export let itemKey = null;
13
+ export let enterAction = "next";
14
+ export let divClassAppend = "";
15
+ export let divClassOverride = "";
16
+ const divClassDefault = "relative overflow-x-auto overflow-y-auto";
17
+ export let tableClassAppend = "";
18
+ export let tableClassOverride = "";
19
+ const tableClassDefault = "";
20
+ export let theadClassAppend = "";
21
+ export let theadClassOverride = "";
22
+ const theadClassDefault = "text-xs uppercase sticky top-0";
23
+ export let thClassAppend = "";
24
+ export let thClassOverride = "";
25
+ const thClassDefault = "";
26
+ export let tableBodyClassAppend = "";
27
+ export let tableBodyClassOverride = "";
28
+ const tableBodyClassDefault = "";
29
+ export let tdClassAppend = "";
30
+ export let tdClassOverride = "";
31
+ const tdClassDefault = "px-6 py-4 whitespace-nowrap font-medium";
32
+ export let tdFocusedClassAppend = "";
33
+ export let tdFocusedClassOverride = "";
34
+ const tdFocusedClassDefault = "px-6 py-4 whitespace-nowrap font-medium";
35
+ export let trClassAppend = "";
36
+ export let trClassOverride = "";
37
+ const trClassDefault = "";
38
+ export let trClassGetter = null;
39
+ let sortedItems = [];
40
+ let focusedColumnKeyID = null;
41
+ let focusedItemKey = null;
42
+ const sortBySortKey = (a, b) => {
43
+ const aValue = a[sortKey];
44
+ const bValue = b[sortKey];
45
+ if (typeof aValue === "string") {
46
+ return aValue.localeCompare(bValue);
47
+ }
48
+ if (isFinite(aValue) && isFinite(bValue)) {
49
+ return aValue - bValue;
50
+ }
51
+ return JSON.stringify(aValue).localeCompare(JSON.stringify(bValue));
52
+ };
53
+ $: {
54
+ sortedItems = sortFunction ? items.toSorted(sortFunction) : sortKey ? items.toSorted(sortBySortKey) : [...items];
55
+ if (reverseSort) {
56
+ sortedItems.reverse();
57
+ }
58
+ }
59
+ const dispatch = createEventDispatcher();
60
+ const getItemKey = (item) => item ? itemKey ? item[itemKey] || null : items.indexOf(item).toString() : null;
61
+ const getColumnID = (column) => column ? column.id || null : null;
62
+ const divClass = joinClasses(divClassOverride || divClassDefault, divClassAppend);
63
+ const tableClass = joinClasses(tableClassOverride || tableClassDefault, tableClassAppend);
64
+ const theadClass = joinClasses(theadClassOverride || theadClassDefault, theadClassAppend);
65
+ const thClass = joinClasses(thClassOverride || thClassDefault, thClassAppend);
66
+ const tableBodyClass = joinClasses(tableBodyClassOverride || tableBodyClassDefault, tableBodyClassAppend);
67
+ const trClass = joinClasses(trClassOverride || trClassDefault, trClassAppend);
68
+ const tdClass = joinClasses(tdClassOverride || tdClassDefault, tdClassAppend);
69
+ const tdFocusedClass = joinClasses(tdFocusedClassOverride || tdFocusedClassDefault, tdFocusedClassAppend);
70
+ const getTRClass = (item, isRowFocused) => trClassGetter ? trClassGetter(item, isRowFocused, trClass, trClassDefault, trClassAppend, trClassOverride) : trClass;
71
+ const internalColumns = columns.map((column) => {
72
+ const columnTDClass = joinClasses(column.tdClassOverride || tdClass, column.tdClassAppend);
73
+ const columnFocusedTDClass = joinClasses(column.tdFocusedClassOverride || tdFocusedClass, column.tdFocusedClassAppend);
74
+ let getTDClass;
75
+ const tdClassGetter = column.tdClassGetter;
76
+ if (tdClassGetter) {
77
+ getTDClass = (item, value, isFocused) => tdClassGetter(item, column, value, isFocused, columnTDClass, tdClassDefault, tdClassAppend, tdClassOverride);
78
+ } else {
79
+ getTDClass = (_item, _value, isFocused) => isFocused ? columnFocusedTDClass : columnTDClass;
80
+ }
81
+ return {
82
+ ...column,
83
+ sortKey: column.sortKey || column.key,
84
+ id: column.id || column.key,
85
+ getTDClass
86
+ };
87
+ });
88
+ const focusableColumns = internalColumns.filter((column) => column.canFocus);
89
+ const prevTab = (event) => {
90
+ const { item, column } = event.detail;
91
+ let nextColumn = null;
92
+ let nextItem = null;
93
+ if (column === focusableColumns[0]) {
94
+ if (item !== sortedItems[0]) {
95
+ nextColumn = focusableColumns[focusableColumns.length - 1];
96
+ nextItem = sortedItems[sortedItems.indexOf(item) - 1];
97
+ }
98
+ } else {
99
+ nextColumn = focusableColumns[focusableColumns.indexOf(column) - 1];
100
+ nextItem = item;
101
+ }
102
+ focusedColumnKeyID = getColumnID(nextColumn);
103
+ focusedItemKey = getItemKey(nextItem);
104
+ };
105
+ const nextTab = (event) => {
106
+ const { item, column } = event.detail;
107
+ let nextColumn = null;
108
+ let nextItem = null;
109
+ if (column === focusableColumns.at(-1)) {
110
+ if (item !== sortedItems.at(-1)) {
111
+ nextColumn = focusableColumns[0];
112
+ nextItem = sortedItems[sortedItems.indexOf(item) + 1];
113
+ }
114
+ } else {
115
+ nextColumn = focusableColumns[focusableColumns.indexOf(column) + 1];
116
+ nextItem = item;
117
+ }
118
+ focusedColumnKeyID = getColumnID(nextColumn);
119
+ focusedItemKey = getItemKey(nextItem);
120
+ };
121
+ const enterPressed = (event) => {
122
+ if (enterAction === "stay") {
123
+ return;
124
+ }
125
+ if (enterAction === "next") {
126
+ return nextTab(event);
127
+ }
128
+ const { item } = event.detail;
129
+ const itemIndex = sortedItems.indexOf(item);
130
+ if (itemIndex !== sortedItems.length - 1) {
131
+ focusedItemKey = getItemKey(sortedItems[itemIndex + 1]);
132
+ }
133
+ };
134
+ const cellClicked = (item, column) => {
135
+ focusedColumnKeyID = null;
136
+ focusedItemKey = null;
137
+ if (column.canFocus) {
138
+ focusedColumnKeyID = getColumnID(column);
139
+ focusedItemKey = getItemKey(item);
140
+ }
141
+ dispatch("cellClicked", {
142
+ item,
143
+ column
144
+ });
145
+ };
146
+ const headerClicked = (column) => {
147
+ if (column.id && column.canSort) {
148
+ if (sortColumnID === column.id) {
149
+ reverseSort = !reverseSort;
150
+ } else {
151
+ reverseSort = false;
152
+ sortColumnID = column.id;
153
+ sortKey = column.sortKey || "";
154
+ sortFunction = column.sortFunction;
155
+ }
156
+ }
157
+ dispatch("headerClicked", {
158
+ column,
159
+ sortColumnID,
160
+ sortKey,
161
+ sortFunction,
162
+ reverseSort
163
+ });
164
+ };
165
+ const rowClicked = (item) => {
166
+ dispatch("rowClicked", {
167
+ item
168
+ });
169
+ };
170
+ </script>
171
+
172
+ <Table class={tableClass} {divClass}>
173
+ <TableHead defaultRow={false} {theadClass}>
174
+ {#each internalColumns as column}
175
+ <DataTableHeaderCell {column} isSorted={!!sortColumnID && getColumnID(column) === sortColumnID} {reverseSort} {thClass} on:click={() => headerClicked(column)}/>
176
+ {/each}
177
+ </TableHead>
178
+ <TableBody {tableBodyClass}>
179
+ {#each sortedItems as item}
180
+ {@const isRowFocused = !!focusedItemKey && focusedItemKey === getItemKey(item)}
181
+ <TableBodyRow class={getTRClass(item, isRowFocused)} on:click={() => rowClicked(item)}>
182
+ {#each internalColumns as column}
183
+ {@const isCellFocused = isRowFocused && focusedColumnKeyID && focusedColumnKeyID === getColumnID(column)}
184
+ <DataTableDataCell
185
+ {column}
186
+ {isCellFocused}
187
+ {item}
188
+ on:click={() => cellClicked(item, column)}
189
+ on:enterPressed={enterPressed}
190
+ on:prevTab={prevTab}
191
+ on:nextTab={nextTab}
192
+ on:action
193
+ on:cellChanged
194
+ on:cellInput
195
+ />
196
+ {/each}
197
+ </TableBodyRow>
198
+ {/each}
199
+ </TableBody>
200
+ </Table>
@@ -0,0 +1,48 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { ColumnConfig, EnterAction, RowClassFunction, SortFunction } from './common.ts';
3
+ declare const __propDef: {
4
+ props: {
5
+ columns?: ColumnConfig[] | undefined;
6
+ items?: any[] | undefined;
7
+ sortKey?: string | undefined;
8
+ sortFunction?: SortFunction | undefined | null;
9
+ reverseSort?: boolean | undefined;
10
+ sortColumnID?: string | null | undefined;
11
+ itemKey?: string | null | undefined;
12
+ enterAction?: EnterAction | undefined;
13
+ divClassAppend?: string | undefined;
14
+ divClassOverride?: string | undefined;
15
+ tableClassAppend?: string | undefined;
16
+ tableClassOverride?: string | undefined;
17
+ theadClassAppend?: string | undefined;
18
+ theadClassOverride?: string | undefined;
19
+ thClassAppend?: string | undefined;
20
+ thClassOverride?: string | undefined;
21
+ tableBodyClassAppend?: string | undefined;
22
+ tableBodyClassOverride?: string | undefined;
23
+ tdClassAppend?: string | undefined;
24
+ tdClassOverride?: string | undefined;
25
+ tdFocusedClassAppend?: string | undefined;
26
+ tdFocusedClassOverride?: string | undefined;
27
+ trClassAppend?: string | undefined;
28
+ trClassOverride?: string | undefined;
29
+ trClassGetter?: RowClassFunction | null | undefined;
30
+ };
31
+ events: {
32
+ action: any;
33
+ cellChanged: any;
34
+ cellInput: any;
35
+ cellClicked: CustomEvent<any>;
36
+ headerClicked: CustomEvent<any>;
37
+ rowClicked: CustomEvent<any>;
38
+ } & {
39
+ [evt: string]: CustomEvent<any>;
40
+ };
41
+ slots: {};
42
+ };
43
+ export type DataTableProps = typeof __propDef.props;
44
+ export type DataTableEvents = typeof __propDef.events;
45
+ export type DataTableSlots = typeof __propDef.slots;
46
+ export default class DataTable extends SvelteComponent<DataTableProps, DataTableEvents, DataTableSlots> {
47
+ }
48
+ export {};
@@ -0,0 +1,50 @@
1
+ <script>import { TableBodyCell } from "flowbite-svelte";
2
+ import { defaultCellRenderer } from "./common.ts";
3
+ export let column;
4
+ export let item;
5
+ export let isCellFocused;
6
+ </script>
7
+
8
+ {#await (column.cellRenderer || defaultCellRenderer)(column, item)}
9
+ <TableBodyCell tdClass={column.getTDClass(item, '', isCellFocused)}/>
10
+ {:then {dataValue, displayValue}}
11
+ <TableBodyCell tdClass={column.getTDClass(item, dataValue, isCellFocused)} on:click>
12
+ {#if column.viewComponent}
13
+ <svelte:component
14
+ this={column.viewComponent}
15
+ {column}
16
+ {item}
17
+ value={dataValue}
18
+ on:action
19
+ on:cellChanged
20
+ on:cellInput
21
+ on:click
22
+ on:enterPressed
23
+ on:prevTab
24
+ on:nextTab
25
+ {...column.viewComponentConfig}
26
+ />
27
+ {:else}
28
+ {#if column.focusComponent && isCellFocused}
29
+ <svelte:component
30
+ this={column.focusComponent}
31
+ {column}
32
+ {item}
33
+ value={dataValue}
34
+ on:action
35
+ on:cellChanged
36
+ on:cellInput
37
+ on:click
38
+ on:enterPressed
39
+ on:prevTab
40
+ on:nextTab
41
+ {...column.focusComponentConfig}
42
+ />
43
+ {:else}
44
+ {displayValue}
45
+ {/if}
46
+ {/if}
47
+ </TableBodyCell>
48
+ {:catch}
49
+ <TableBodyCell tdClass={column.getTDClass(item, '', isCellFocused)} />
50
+ {/await}
@@ -0,0 +1,27 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { InternalColumnConfig } from './common.ts';
3
+ declare const __propDef: {
4
+ props: {
5
+ column: InternalColumnConfig;
6
+ item: any;
7
+ isCellFocused: boolean;
8
+ };
9
+ events: {
10
+ click: any;
11
+ action: any;
12
+ cellChanged: any;
13
+ cellInput: any;
14
+ enterPressed: any;
15
+ prevTab: any;
16
+ nextTab: any;
17
+ } & {
18
+ [evt: string]: CustomEvent<any>;
19
+ };
20
+ slots: {};
21
+ };
22
+ export type DataTableDataCellProps = typeof __propDef.props;
23
+ export type DataTableDataCellEvents = typeof __propDef.events;
24
+ export type DataTableDataCellSlots = typeof __propDef.slots;
25
+ export default class DataTableDataCell extends SvelteComponent<DataTableDataCellProps, DataTableDataCellEvents, DataTableDataCellSlots> {
26
+ }
27
+ export {};
@@ -0,0 +1,22 @@
1
+ <script>import { TableHeadCell } from "flowbite-svelte";
2
+ import { ArrowDownSolid, ArrowUpSolid } from "flowbite-svelte-icons";
3
+ import { joinClasses } from "./common.ts";
4
+ export let column;
5
+ export let reverseSort;
6
+ export let isSorted;
7
+ export let thClass;
8
+ </script>
9
+
10
+ <TableHeadCell
11
+ class={joinClasses(thClass || column.thClassOverride, column.thClassAppend)}
12
+ on:click
13
+ >
14
+ {#if isSorted}
15
+ {#if reverseSort}
16
+ <ArrowUpSolid class="inline"/>
17
+ {:else}
18
+ <ArrowDownSolid class="inline"/>
19
+ {/if}
20
+ {/if}
21
+ <span>{column.title}</span>
22
+ </TableHeadCell>
@@ -0,0 +1,22 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { InternalColumnConfig } from './common.ts';
3
+ declare const __propDef: {
4
+ props: {
5
+ column: InternalColumnConfig;
6
+ reverseSort: boolean;
7
+ isSorted: boolean;
8
+ thClass: string;
9
+ };
10
+ events: {
11
+ click: MouseEvent;
12
+ } & {
13
+ [evt: string]: CustomEvent<any>;
14
+ };
15
+ slots: {};
16
+ };
17
+ export type DataTableHeaderCellProps = typeof __propDef.props;
18
+ export type DataTableHeaderCellEvents = typeof __propDef.events;
19
+ export type DataTableHeaderCellSlots = typeof __propDef.slots;
20
+ export default class DataTableHeaderCell extends SvelteComponent<DataTableHeaderCellProps, DataTableHeaderCellEvents, DataTableHeaderCellSlots> {
21
+ }
22
+ export {};
@@ -0,0 +1,11 @@
1
+ import type { Action } from './ActionsCell.svelte';
2
+ export declare const bookmarkAction: Action;
3
+ export declare const deleteAction: Action;
4
+ export declare const downAction: Action;
5
+ export declare const editAction: Action;
6
+ export declare const favoriteAction: Action;
7
+ export declare const infoAction: Action;
8
+ export declare const notificationAction: Action;
9
+ export declare const settingsAction: Action;
10
+ export declare const shareAction: Action;
11
+ export declare const upAction: Action;
@@ -0,0 +1,41 @@
1
+ import { ArrowDownSolid, ArrowUpSolid, BellActiveOutline, BookmarkOutline, CogOutline, EditOutline, HeartSolid, InfoCircleOutline, ShareNodesOutline, TrashBinOutline, } from 'flowbite-svelte-icons';
2
+ export const bookmarkAction = {
3
+ icon: BookmarkOutline,
4
+ name: 'bookmark',
5
+ };
6
+ export const deleteAction = {
7
+ icon: TrashBinOutline,
8
+ name: 'delete',
9
+ };
10
+ export const downAction = {
11
+ icon: ArrowDownSolid,
12
+ name: 'down',
13
+ };
14
+ export const editAction = {
15
+ icon: EditOutline,
16
+ name: 'edit',
17
+ };
18
+ export const favoriteAction = {
19
+ icon: HeartSolid,
20
+ name: 'favorite',
21
+ };
22
+ export const infoAction = {
23
+ icon: InfoCircleOutline,
24
+ name: 'info',
25
+ };
26
+ export const notificationAction = {
27
+ icon: BellActiveOutline,
28
+ name: 'notification',
29
+ };
30
+ export const settingsAction = {
31
+ icon: CogOutline,
32
+ name: 'settings',
33
+ };
34
+ export const shareAction = {
35
+ icon: ShareNodesOutline,
36
+ name: 'share',
37
+ };
38
+ export const upAction = {
39
+ icon: ArrowUpSolid,
40
+ name: 'up',
41
+ };
@@ -0,0 +1,30 @@
1
+ <script context="module"></script>
2
+
3
+ <script>import { createEventDispatcher } from "svelte";
4
+ import { Button } from "flowbite-svelte";
5
+ export let buttonClass = "border-0 p-1";
6
+ export let buttonColor = "light";
7
+ export let iconClass = "w-4 h-4";
8
+ export let column;
9
+ export let item;
10
+ export let actions = [];
11
+ const dispatch = createEventDispatcher();
12
+ const actionClicked = (action) => {
13
+ dispatch("action", {
14
+ action: action.name,
15
+ column,
16
+ item
17
+ });
18
+ };
19
+ </script>
20
+
21
+ {#each actions as action}
22
+ <Button
23
+ class={action.buttonClass || buttonClass}
24
+ color={action.buttonColor || buttonColor}
25
+ disabled={action.isDisabled?.(item, column, action)}
26
+ on:click={() => actionClicked(action)}>
27
+ <svelte:component this={action.icon} class={action.iconClass || iconClass}/>
28
+ {#if action.caption}{action.caption}{/if}
29
+ </Button>
30
+ {/each}
@@ -0,0 +1,34 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { ColumnConfig } from '../common.ts';
3
+ type ButtonColor = 'red' | 'yellow' | 'green' | 'purple' | 'blue' | 'light' | 'dark' | 'primary' | 'none' | 'alternative' | undefined;
4
+ export interface Action {
5
+ buttonClass?: string;
6
+ buttonColor?: ButtonColor;
7
+ caption?: string;
8
+ name: string;
9
+ icon: ConstructorOfATypedSvelteComponent;
10
+ iconClass?: string;
11
+ isDisabled?: (item: any, column: ColumnConfig, action: Action) => boolean;
12
+ }
13
+ declare const __propDef: {
14
+ props: {
15
+ buttonClass?: string | undefined;
16
+ buttonColor?: ButtonColor;
17
+ iconClass?: string | undefined;
18
+ column: ColumnConfig;
19
+ item: any;
20
+ actions?: Action[] | undefined;
21
+ };
22
+ events: {
23
+ action: CustomEvent<any>;
24
+ } & {
25
+ [evt: string]: CustomEvent<any>;
26
+ };
27
+ slots: {};
28
+ };
29
+ export type ActionsCellProps = typeof __propDef.props;
30
+ export type ActionsCellEvents = typeof __propDef.events;
31
+ export type ActionsCellSlots = typeof __propDef.slots;
32
+ export default class ActionsCell extends SvelteComponent<ActionsCellProps, ActionsCellEvents, ActionsCellSlots> {
33
+ }
34
+ export {};
@@ -0,0 +1,15 @@
1
+ <script>import { createEventDispatcher } from "svelte";
2
+ import { Button } from "flowbite-svelte";
3
+ export let caption = "";
4
+ export let column;
5
+ export let item;
6
+ const dispatch = createEventDispatcher();
7
+ const buttonClicked = () => {
8
+ dispatch("click", {
9
+ column,
10
+ item
11
+ });
12
+ };
13
+ </script>
14
+
15
+ <Button {...$$props} on:click={buttonClicked}>{#if caption}{caption}{/if}</Button>
@@ -0,0 +1,22 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { ColumnConfig } from '../common.ts';
3
+ declare const __propDef: {
4
+ props: {
5
+ [x: string]: any;
6
+ caption?: string | undefined;
7
+ column: ColumnConfig;
8
+ item: any;
9
+ };
10
+ events: {
11
+ click: CustomEvent<any>;
12
+ } & {
13
+ [evt: string]: CustomEvent<any>;
14
+ };
15
+ slots: {};
16
+ };
17
+ export type ButtonCellProps = typeof __propDef.props;
18
+ export type ButtonCellEvents = typeof __propDef.events;
19
+ export type ButtonCellSlots = typeof __propDef.slots;
20
+ export default class ButtonCell extends SvelteComponent<ButtonCellProps, ButtonCellEvents, ButtonCellSlots> {
21
+ }
22
+ export {};
@@ -0,0 +1,19 @@
1
+ <script>import { createEventDispatcher } from "svelte";
2
+ import { Checkbox } from "flowbite-svelte";
3
+ export let caption = "";
4
+ export let column;
5
+ export let item;
6
+ export let value;
7
+ let localValue = value;
8
+ const dispatch = createEventDispatcher();
9
+ const toggleChanged = () => {
10
+ dispatch("cellChanged", {
11
+ column,
12
+ item,
13
+ oldValue: value,
14
+ newValue: localValue
15
+ });
16
+ };
17
+ </script>
18
+
19
+ <Checkbox {...$$props} bind:checked={localValue} on:change={toggleChanged}>{#if caption}{caption}{/if}</Checkbox>
@@ -0,0 +1,23 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { ColumnConfig } from '../common.ts';
3
+ declare const __propDef: {
4
+ props: {
5
+ [x: string]: any;
6
+ caption?: string | undefined;
7
+ column: ColumnConfig;
8
+ item: any;
9
+ value: any;
10
+ };
11
+ events: {
12
+ cellChanged: CustomEvent<any>;
13
+ } & {
14
+ [evt: string]: CustomEvent<any>;
15
+ };
16
+ slots: {};
17
+ };
18
+ export type CheckboxCellProps = typeof __propDef.props;
19
+ export type CheckboxCellEvents = typeof __propDef.events;
20
+ export type CheckboxCellSlots = typeof __propDef.slots;
21
+ export default class CheckboxCell extends SvelteComponent<CheckboxCellProps, CheckboxCellEvents, CheckboxCellSlots> {
22
+ }
23
+ export {};
@@ -0,0 +1,49 @@
1
+ <script>import { createEventDispatcher } from "svelte";
2
+ import { Input } from "flowbite-svelte";
3
+ import TabWrapper from "./TabWrapper.svelte";
4
+ export let inputType = "text";
5
+ export let item;
6
+ export let column;
7
+ export let value;
8
+ let internalValue;
9
+ $:
10
+ internalValue = value;
11
+ const dispatch = createEventDispatcher();
12
+ const dispatchCellChanged = () => {
13
+ if (value !== internalValue) {
14
+ dispatch("cellChanged", {
15
+ column,
16
+ item,
17
+ oldValue: value,
18
+ newValue: internalValue
19
+ });
20
+ }
21
+ };
22
+ const keypress = (event) => {
23
+ if (event.key === "Enter") {
24
+ dispatch("enterPressed", {
25
+ column,
26
+ item
27
+ });
28
+ dispatchCellChanged();
29
+ }
30
+ };
31
+ const prevTab = (_event) => {
32
+ dispatch("prevTab", {
33
+ column,
34
+ item
35
+ });
36
+ dispatchCellChanged();
37
+ };
38
+ const nextTab = (_event) => {
39
+ dispatch("nextTab", {
40
+ column,
41
+ item
42
+ });
43
+ dispatchCellChanged();
44
+ };
45
+ </script>
46
+
47
+ <TabWrapper on:prevTab={prevTab} on:nextTab={nextTab}>
48
+ <Input type={inputType} bind:value={internalValue} {...$$props} on:keypress={keypress} autofocus/>
49
+ </TabWrapper>
@@ -0,0 +1,26 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { ColumnConfig } from '../common.ts';
3
+ declare const __propDef: {
4
+ props: {
5
+ [x: string]: any;
6
+ inputType?: string | undefined;
7
+ item: any;
8
+ column: ColumnConfig;
9
+ value: string;
10
+ };
11
+ events: {
12
+ cellChanged: CustomEvent<any>;
13
+ enterPressed: CustomEvent<any>;
14
+ prevTab: CustomEvent<any>;
15
+ nextTab: CustomEvent<any>;
16
+ } & {
17
+ [evt: string]: CustomEvent<any>;
18
+ };
19
+ slots: {};
20
+ };
21
+ export type InputCellProps = typeof __propDef.props;
22
+ export type InputCellEvents = typeof __propDef.events;
23
+ export type InputCellSlots = typeof __propDef.slots;
24
+ export default class InputCell extends SvelteComponent<InputCellProps, InputCellEvents, InputCellSlots> {
25
+ }
26
+ export {};
@@ -0,0 +1,48 @@
1
+ <script>import { createEventDispatcher } from "svelte";
2
+ import { NumberInput } from "flowbite-svelte";
3
+ import TabWrapper from "./TabWrapper.svelte";
4
+ export let item;
5
+ export let column;
6
+ export let value;
7
+ let internalValue;
8
+ $:
9
+ internalValue = value;
10
+ const dispatch = createEventDispatcher();
11
+ const dispatchCellChanged = () => {
12
+ if (value !== internalValue) {
13
+ dispatch("cellChanged", {
14
+ column,
15
+ item,
16
+ oldValue: value,
17
+ newValue: internalValue
18
+ });
19
+ }
20
+ };
21
+ const keypress = async (event) => {
22
+ if (event.key === "Enter") {
23
+ dispatch("enterPressed", {
24
+ column,
25
+ item
26
+ });
27
+ dispatchCellChanged();
28
+ }
29
+ };
30
+ const prevTab = (_event) => {
31
+ dispatch("prevTab", {
32
+ column,
33
+ item
34
+ });
35
+ dispatchCellChanged();
36
+ };
37
+ const nextTab = (_event) => {
38
+ dispatch("nextTab", {
39
+ column,
40
+ item
41
+ });
42
+ dispatchCellChanged();
43
+ };
44
+ </script>
45
+
46
+ <TabWrapper on:prevTab={prevTab} on:nextTab={nextTab}>
47
+ <NumberInput bind:value={internalValue} {...$$props} on:keypress={keypress} autofocus/>
48
+ </TabWrapper>
@@ -0,0 +1,25 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { ColumnConfig } from '../common.ts';
3
+ declare const __propDef: {
4
+ props: {
5
+ [x: string]: any;
6
+ item: any;
7
+ column: ColumnConfig;
8
+ value: number;
9
+ };
10
+ events: {
11
+ cellChanged: CustomEvent<any>;
12
+ enterPressed: CustomEvent<any>;
13
+ prevTab: CustomEvent<any>;
14
+ nextTab: CustomEvent<any>;
15
+ } & {
16
+ [evt: string]: CustomEvent<any>;
17
+ };
18
+ slots: {};
19
+ };
20
+ export type NumberInputCellProps = typeof __propDef.props;
21
+ export type NumberInputCellEvents = typeof __propDef.events;
22
+ export type NumberInputCellSlots = typeof __propDef.slots;
23
+ export default class NumberInputCell extends SvelteComponent<NumberInputCellProps, NumberInputCellEvents, NumberInputCellSlots> {
24
+ }
25
+ export {};
@@ -0,0 +1,30 @@
1
+ <script>import { createEventDispatcher } from "svelte";
2
+ import { Select } from "flowbite-svelte";
3
+ import TabWrapper from "./TabWrapper.svelte";
4
+ export let item;
5
+ export let column;
6
+ export let displayProp = "name";
7
+ export let valueProp = "id";
8
+ export let items = [];
9
+ export let value;
10
+ let newValue = value;
11
+ const dispatch = createEventDispatcher();
12
+ $:
13
+ if (value !== newValue) {
14
+ dispatch("cellChanged", {
15
+ column,
16
+ item,
17
+ oldValue: value,
18
+ newValue
19
+ });
20
+ }
21
+ </script>
22
+
23
+ <TabWrapper {column} {item} on:prevTab on:nextTab>
24
+ <Select
25
+ {...$$props}
26
+ items={items.map(item => ({ value: item[valueProp], name: item[displayProp]}))}
27
+ bind:value={newValue}
28
+ autofocus
29
+ />
30
+ </TabWrapper>
@@ -0,0 +1,27 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { ColumnConfig } from '../common.ts';
3
+ declare const __propDef: {
4
+ props: {
5
+ [x: string]: any;
6
+ item: any;
7
+ column: ColumnConfig;
8
+ displayProp?: string | undefined;
9
+ valueProp?: string | undefined;
10
+ items?: any[] | undefined;
11
+ value: any;
12
+ };
13
+ events: {
14
+ prevTab: CustomEvent<any>;
15
+ nextTab: CustomEvent<any>;
16
+ cellChanged: CustomEvent<any>;
17
+ } & {
18
+ [evt: string]: CustomEvent<any>;
19
+ };
20
+ slots: {};
21
+ };
22
+ export type SelectCellProps = typeof __propDef.props;
23
+ export type SelectCellEvents = typeof __propDef.events;
24
+ export type SelectCellSlots = typeof __propDef.slots;
25
+ export default class SelectCell extends SvelteComponent<SelectCellProps, SelectCellEvents, SelectCellSlots> {
26
+ }
27
+ export {};
@@ -0,0 +1,47 @@
1
+ <script>import { createEventDispatcher } from "svelte";
2
+ import { Button } from "flowbite-svelte";
3
+ import { MinusSolid, PlusSolid } from "flowbite-svelte-icons";
4
+ export let item;
5
+ export let column;
6
+ export let value;
7
+ export let decValue = 1;
8
+ export let incValue = 1;
9
+ export let minValue = void 0;
10
+ export let maxValue = void 0;
11
+ export let minusIcon = MinusSolid;
12
+ export let minusIconClass = "pr-1 w-3 h-3";
13
+ export let plusIcon = PlusSolid;
14
+ export let plusIconClass = "pr-1 w-3 h-3";
15
+ const dispatch = createEventDispatcher();
16
+ const decrement = () => {
17
+ dispatch("cellChanged", {
18
+ column,
19
+ item,
20
+ oldValue: value,
21
+ newValue: (value || 0) - decValue
22
+ });
23
+ };
24
+ const increment = () => {
25
+ dispatch("cellChanged", {
26
+ column,
27
+ item,
28
+ oldValue: value,
29
+ newValue: (value || 0) + incValue
30
+ });
31
+ };
32
+ </script>
33
+
34
+ <div class="spinner">
35
+ <Button color="none" class="pr-1" on:click={decrement} disabled={minValue !== undefined && (value - decValue) < minValue}><svelte:component this={minusIcon} class={minusIconClass}/></Button>
36
+ {value || 0}
37
+ <Button color="none" class="pl-1" on:click={increment} disabled={maxValue !== undefined && (value + incValue) > maxValue}><svelte:component this={plusIcon} class={plusIconClass}/></Button>
38
+ </div>
39
+
40
+ <style>
41
+ .spinner {
42
+ display: flex;
43
+ flex-direction: row;
44
+ justify-content: center;
45
+ align-items: center;
46
+ }
47
+ </style>
@@ -0,0 +1,29 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { ColumnConfig } from '../common.ts';
3
+ declare const __propDef: {
4
+ props: {
5
+ item: any;
6
+ column: ColumnConfig;
7
+ value: any;
8
+ decValue?: number | undefined;
9
+ incValue?: number | undefined;
10
+ minValue?: number | undefined;
11
+ maxValue?: number | undefined;
12
+ minusIcon?: ConstructorOfATypedSvelteComponent | undefined;
13
+ minusIconClass?: string | undefined;
14
+ plusIcon?: ConstructorOfATypedSvelteComponent | undefined;
15
+ plusIconClass?: string | undefined;
16
+ };
17
+ events: {
18
+ cellChanged: CustomEvent<any>;
19
+ } & {
20
+ [evt: string]: CustomEvent<any>;
21
+ };
22
+ slots: {};
23
+ };
24
+ export type SpinCellProps = typeof __propDef.props;
25
+ export type SpinCellEvents = typeof __propDef.events;
26
+ export type SpinCellSlots = typeof __propDef.slots;
27
+ export default class SpinCell extends SvelteComponent<SpinCellProps, SpinCellEvents, SpinCellSlots> {
28
+ }
29
+ export {};
@@ -0,0 +1,23 @@
1
+ <script>import { createEventDispatcher } from "svelte";
2
+ export let item = null;
3
+ export let column = null;
4
+ const dispatch = createEventDispatcher();
5
+ const prevTab = (_event) => {
6
+ dispatch("prevTab", {
7
+ column,
8
+ item
9
+ });
10
+ };
11
+ const nextTab = (_event) => {
12
+ dispatch("nextTab", {
13
+ column,
14
+ item
15
+ });
16
+ };
17
+ </script>
18
+
19
+ <!-- svelte-ignore a11y-no-noninteractive-tabindex-->
20
+ <div tabindex="0" on:focus={prevTab}/>
21
+ <slot />
22
+ <!-- svelte-ignore a11y-no-noninteractive-tabindex-->
23
+ <div tabindex="0" on:focus={nextTab}/>
@@ -0,0 +1,23 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { ColumnConfig } from '../common.ts';
3
+ declare const __propDef: {
4
+ props: {
5
+ item?: any;
6
+ column?: ColumnConfig | null | undefined;
7
+ };
8
+ events: {
9
+ prevTab: CustomEvent<any>;
10
+ nextTab: CustomEvent<any>;
11
+ } & {
12
+ [evt: string]: CustomEvent<any>;
13
+ };
14
+ slots: {
15
+ default: {};
16
+ };
17
+ };
18
+ export type TabWrapperProps = typeof __propDef.props;
19
+ export type TabWrapperEvents = typeof __propDef.events;
20
+ export type TabWrapperSlots = typeof __propDef.slots;
21
+ export default class TabWrapper extends SvelteComponent<TabWrapperProps, TabWrapperEvents, TabWrapperSlots> {
22
+ }
23
+ export {};
@@ -0,0 +1,19 @@
1
+ <script>import { createEventDispatcher } from "svelte";
2
+ import { Toggle } from "flowbite-svelte";
3
+ export let caption = "";
4
+ export let column;
5
+ export let item;
6
+ export let value;
7
+ let localValue = value;
8
+ const dispatch = createEventDispatcher();
9
+ const toggleChanged = () => {
10
+ dispatch("cellChanged", {
11
+ column,
12
+ item,
13
+ oldValue: value,
14
+ newValue: localValue
15
+ });
16
+ };
17
+ </script>
18
+
19
+ <Toggle {...$$props} bind:checked={localValue} on:change={toggleChanged}>{#if caption}{caption}{/if}</Toggle>
@@ -0,0 +1,23 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { ColumnConfig } from '../common.ts';
3
+ declare const __propDef: {
4
+ props: {
5
+ [x: string]: any;
6
+ caption?: string | undefined;
7
+ column: ColumnConfig;
8
+ item: any;
9
+ value: any;
10
+ };
11
+ events: {
12
+ cellChanged: CustomEvent<any>;
13
+ } & {
14
+ [evt: string]: CustomEvent<any>;
15
+ };
16
+ slots: {};
17
+ };
18
+ export type ToggleCellProps = typeof __propDef.props;
19
+ export type ToggleCellEvents = typeof __propDef.events;
20
+ export type ToggleCellSlots = typeof __propDef.slots;
21
+ export default class ToggleCell extends SvelteComponent<ToggleCellProps, ToggleCellEvents, ToggleCellSlots> {
22
+ }
23
+ export {};
@@ -0,0 +1,10 @@
1
+ export * from './Actions';
2
+ export * from './ActionsCell.svelte';
3
+ export * from './ButtonCell.svelte';
4
+ export * from './CheckboxCell.svelte';
5
+ export * from './InputCell.svelte';
6
+ export * from './NumberInputCell.svelte';
7
+ export * from './SelectCell.svelte';
8
+ export * from './SpinCell.svelte';
9
+ export * from './TabWrapper.svelte';
10
+ export * from './ToggleCell.svelte';
@@ -0,0 +1,10 @@
1
+ export * from './Actions';
2
+ export * from './ActionsCell.svelte';
3
+ export * from './ButtonCell.svelte';
4
+ export * from './CheckboxCell.svelte';
5
+ export * from './InputCell.svelte';
6
+ export * from './NumberInputCell.svelte';
7
+ export * from './SelectCell.svelte';
8
+ export * from './SpinCell.svelte';
9
+ export * from './TabWrapper.svelte';
10
+ export * from './ToggleCell.svelte';
@@ -0,0 +1,36 @@
1
+ export interface ColumnConfig {
2
+ id?: string;
3
+ key?: string;
4
+ title?: string;
5
+ cellRenderer?: CellRenderer;
6
+ viewComponent?: ConstructorOfATypedSvelteComponent;
7
+ viewComponentConfig?: any;
8
+ focusComponent?: ConstructorOfATypedSvelteComponent;
9
+ focusComponentConfig?: any;
10
+ tdClassAppend?: string;
11
+ tdClassOverride?: string;
12
+ tdFocusedClassAppend?: string;
13
+ tdFocusedClassOverride?: string;
14
+ tdClassGetter?: DataCellClassFunction;
15
+ thClassAppend?: string;
16
+ thClassOverride?: string;
17
+ canFocus?: boolean;
18
+ canSort?: boolean;
19
+ sortFunction?: SortFunction;
20
+ sortKey?: string;
21
+ }
22
+ export type CellRenderer = (columnConfig: ColumnConfig, item: any) => Promise<any>;
23
+ export type SortFunction = (a: any, b: any) => number;
24
+ export type RowClassFunction = (item: any, isFocused: boolean, calcClass: string, defaultClass: string, appendClass: string, overrideClass: string) => string;
25
+ export type DataCellClassFunction = (item: any, column: ColumnConfig, value: any, isFocused: boolean, calcClass: string, defaultClass: string, appendClass: string, overrideClass: string) => string;
26
+ export declare const joinClasses: (...classes: (string | false | null | undefined)[]) => string;
27
+ export type GetTDClassFunction = (item: any, value: any, isFocused: boolean) => string;
28
+ export interface InternalColumnConfig extends ColumnConfig {
29
+ getTDClass: GetTDClassFunction;
30
+ }
31
+ export declare const blankCellValues: {
32
+ dataValue: null;
33
+ displayValue: string;
34
+ };
35
+ export declare const defaultCellRenderer: CellRenderer;
36
+ export type EnterAction = 'next' | 'down' | 'stay';
package/dist/common.js ADDED
@@ -0,0 +1,6 @@
1
+ export const joinClasses = (...classes) => (classes || []).filter(value => !!value).join(' ');
2
+ export const blankCellValues = {
3
+ dataValue: null,
4
+ displayValue: '',
5
+ };
6
+ export const defaultCellRenderer = async (column, item) => column.key ? { dataValue: item[column.key], displayValue: item[column.key] || '' } : blankCellValues;
@@ -0,0 +1,4 @@
1
+ import DataTable from './DataTable.svelte';
2
+ export type { CellRenderer, ColumnConfig, DataCellClassFunction, RowClassFunction, SortFunction } from './common.ts';
3
+ export * from './cells/index.ts';
4
+ export default DataTable;
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import DataTable from './DataTable.svelte';
2
+ export * from './cells/index.ts';
3
+ export default DataTable;
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@emamid/svelte-data-table",
3
+ "version": "0.0.1",
4
+ "scripts": {
5
+ "dev": "vite dev",
6
+ "build": "vite build && npm run package",
7
+ "preview": "vite preview",
8
+ "package": "svelte-kit sync && svelte-package && publint",
9
+ "prepublishOnly": "npm run package",
10
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
11
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
12
+ "test": "vitest",
13
+ "lint": "prettier --check . && eslint .",
14
+ "format": "prettier --write ."
15
+ },
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "svelte": "./dist/index.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "!dist/**/*.test.*",
25
+ "!dist/**/*.spec.*"
26
+ ],
27
+ "peerDependencies": {
28
+ "svelte": "^4.0.0"
29
+ },
30
+ "devDependencies": {
31
+ "@sveltejs/adapter-auto": "^3.0.0",
32
+ "@sveltejs/kit": "^2.0.0",
33
+ "@sveltejs/package": "^2.0.0",
34
+ "@sveltejs/vite-plugin-svelte": "^3.0.0",
35
+ "@types/eslint": "8.56.0",
36
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
37
+ "@typescript-eslint/parser": "^6.0.0",
38
+ "eslint": "^8.56.0",
39
+ "eslint-config-prettier": "^9.1.0",
40
+ "eslint-plugin-svelte": "^2.35.1",
41
+ "flowbite": "^2.2.1",
42
+ "flowbite-svelte": "^0.44.22",
43
+ "flowbite-svelte-icons": "^1.0.2",
44
+ "prettier": "^3.1.1",
45
+ "prettier-plugin-svelte": "^3.1.2",
46
+ "publint": "^0.1.9",
47
+ "svelte": "^4.2.7",
48
+ "svelte-check": "^3.6.0",
49
+ "tslib": "^2.4.1",
50
+ "typescript": "^5.0.0",
51
+ "vite": "^5.0.3",
52
+ "vitest": "^1.0.0"
53
+ },
54
+ "svelte": "./dist/index.js",
55
+ "types": "./dist/index.d.ts",
56
+ "type": "module"
57
+ }