svelte-tably 1.1.1 → 1.2.0
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 +8 -1
- package/dist/column/Column.svelte +1 -1
- package/dist/column/Column.svelte.d.ts +5 -5
- package/dist/column/column-state.svelte.d.ts +2 -1
- package/dist/column/column-state.svelte.js +2 -1
- package/dist/expandable/Expandable.svelte +1 -2
- package/dist/expandable/Expandable.svelte.d.ts +4 -5
- package/dist/index.d.ts +4 -0
- package/dist/panel/Panel.svelte +1 -1
- package/dist/panel/Panel.svelte.d.ts +4 -4
- package/dist/row/Row.svelte +1 -2
- package/dist/row/Row.svelte.d.ts +4 -5
- package/dist/row/row-state.svelte.d.ts +4 -1
- package/dist/size-tween.svelte.js +9 -1
- package/dist/table/Table.svelte +344 -116
- package/dist/table/Table.svelte.d.ts +24 -95
- package/dist/table/data.svelte.js +21 -8
- package/dist/table/table-state.svelte.d.ts +1 -1
- package/dist/table/virtualization.svelte.d.ts +2 -2
- package/dist/table/virtualization.svelte.js +67 -23
- package/dist/utility.svelte.d.ts +1 -1
- package/dist/utility.svelte.js +2 -2
- package/package.json +1 -1
|
@@ -1,110 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { type Snippet } from 'svelte';
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
3
2
|
import { TableState, type TableProps } from './table-state.svelte.js';
|
|
4
|
-
import
|
|
3
|
+
import Column from '../column/Column.svelte';
|
|
4
|
+
import Panel from '../panel/Panel.svelte';
|
|
5
|
+
import Expandable from '../expandable/Expandable.svelte';
|
|
6
|
+
import Row from '../row/Row.svelte';
|
|
7
|
+
type ConstructorReturnType<C extends new (...args: any[]) => any> = C extends new (...args: any[]) => infer K ? K : never;
|
|
8
|
+
type ConstructorParams<C extends new (...args: any[]) => any> = C extends new (...args: infer K) => any ? K : never;
|
|
9
|
+
export type ContentCtx<Item = any> = {
|
|
10
|
+
Column: {
|
|
11
|
+
new <V>(...args: ConstructorParams<typeof Column<Item, V>>): ConstructorReturnType<typeof Column<Item, V>>;
|
|
12
|
+
<V>(...args: Parameters<typeof Column<Item, V>>): ReturnType<typeof Column<Item, V>>;
|
|
13
|
+
};
|
|
14
|
+
Panel: typeof Panel<Item>;
|
|
15
|
+
Expandable: typeof Expandable<Item>;
|
|
16
|
+
Row: typeof Row<Item>;
|
|
17
|
+
readonly table: TableState<Item>;
|
|
18
|
+
};
|
|
19
|
+
export type ContentSnippet<Item = any> = Snippet<[context: ContentCtx<Item>]>;
|
|
5
20
|
import type { CSVOptions } from './csv.js';
|
|
6
|
-
declare class __sveltets_Render<T
|
|
21
|
+
declare class __sveltets_Render<T> {
|
|
7
22
|
props(): TableProps<T> & {
|
|
8
|
-
content?:
|
|
9
|
-
Column: {
|
|
10
|
-
<V>(internal: unknown, props: {
|
|
11
|
-
id: string;
|
|
12
|
-
table?: TableState<T> | undefined;
|
|
13
|
-
header?: string | Snippet<[ctx: import("../column/column-state.svelte.js").HeaderCtx<T>]> | undefined;
|
|
14
|
-
row?: Snippet<[item: T, ctx: RowColumnCtx<T, V>]> | undefined;
|
|
15
|
-
statusbar?: Snippet<[ctx: import("../column/column-state.svelte.js").StatusbarCtx<T>]> | undefined;
|
|
16
|
-
sticky?: boolean | undefined;
|
|
17
|
-
show?: boolean | undefined;
|
|
18
|
-
sortby?: boolean | undefined;
|
|
19
|
-
width?: number | undefined;
|
|
20
|
-
fixed?: boolean | undefined;
|
|
21
|
-
value?: ((item: T) => V) | undefined;
|
|
22
|
-
sort?: boolean | ((a: V, b: V) => number) | undefined;
|
|
23
|
-
resizeable?: boolean | undefined;
|
|
24
|
-
filter?: ((value: V) => boolean) | undefined;
|
|
25
|
-
style?: string | undefined;
|
|
26
|
-
class?: string | undefined;
|
|
27
|
-
onclick?: ((event: MouseEvent, rowColumnCtx: RowColumnCtx<T, V>) => void) | undefined;
|
|
28
|
-
pad?: "row" | "header" | "both" | undefined;
|
|
29
|
-
}): {};
|
|
30
|
-
new <V>(options: import("svelte").ComponentConstructorOptions<{
|
|
31
|
-
id: string;
|
|
32
|
-
table?: TableState<T> | undefined;
|
|
33
|
-
header?: string | Snippet<[ctx: import("../column/column-state.svelte.js").HeaderCtx<T>]> | undefined;
|
|
34
|
-
row?: Snippet<[item: T, ctx: RowColumnCtx<T, V>]> | undefined;
|
|
35
|
-
statusbar?: Snippet<[ctx: import("../column/column-state.svelte.js").StatusbarCtx<T>]> | undefined;
|
|
36
|
-
sticky?: boolean | undefined;
|
|
37
|
-
show?: boolean | undefined;
|
|
38
|
-
sortby?: boolean | undefined;
|
|
39
|
-
width?: number | undefined;
|
|
40
|
-
fixed?: boolean | undefined;
|
|
41
|
-
value?: ((item: T) => V) | undefined;
|
|
42
|
-
sort?: boolean | ((a: V, b: V) => number) | undefined;
|
|
43
|
-
resizeable?: boolean | undefined;
|
|
44
|
-
filter?: ((value: V) => boolean) | undefined;
|
|
45
|
-
style?: string | undefined;
|
|
46
|
-
class?: string | undefined;
|
|
47
|
-
onclick?: ((event: MouseEvent, rowColumnCtx: RowColumnCtx<T, V>) => void) | undefined;
|
|
48
|
-
pad?: "row" | "header" | "both" | undefined;
|
|
49
|
-
}>): SvelteComponent<{
|
|
50
|
-
id: string;
|
|
51
|
-
table?: TableState<T> | undefined;
|
|
52
|
-
header?: string | Snippet<[ctx: import("../column/column-state.svelte.js").HeaderCtx<T>]> | undefined;
|
|
53
|
-
row?: Snippet<[item: T, ctx: RowColumnCtx<T, V>]> | undefined;
|
|
54
|
-
statusbar?: Snippet<[ctx: import("../column/column-state.svelte.js").StatusbarCtx<T>]> | undefined;
|
|
55
|
-
sticky?: boolean | undefined;
|
|
56
|
-
show?: boolean | undefined;
|
|
57
|
-
sortby?: boolean | undefined;
|
|
58
|
-
width?: number | undefined;
|
|
59
|
-
fixed?: boolean | undefined;
|
|
60
|
-
value?: ((item: T) => V) | undefined;
|
|
61
|
-
sort?: boolean | ((a: V, b: V) => number) | undefined;
|
|
62
|
-
resizeable?: boolean | undefined;
|
|
63
|
-
filter?: ((value: V) => boolean) | undefined;
|
|
64
|
-
style?: string | undefined;
|
|
65
|
-
class?: string | undefined;
|
|
66
|
-
onclick?: ((event: MouseEvent, rowColumnCtx: RowColumnCtx<T, V>) => void) | undefined;
|
|
67
|
-
pad?: "row" | "header" | "both" | undefined;
|
|
68
|
-
}, {}, {}> & {
|
|
69
|
-
$$bindings?: ReturnType<() => "">;
|
|
70
|
-
} & {};
|
|
71
|
-
};
|
|
72
|
-
Panel: {
|
|
73
|
-
(internal: unknown, props: import("../index.js").PanelProps<T>): {};
|
|
74
|
-
new (options: import("svelte").ComponentConstructorOptions<import("../index.js").PanelProps<T>>): SvelteComponent<import("../index.js").PanelProps<T>, {}, {}> & {
|
|
75
|
-
$$bindings?: ReturnType<() => "">;
|
|
76
|
-
};
|
|
77
|
-
z_$$bindings?: ReturnType<() => "">;
|
|
78
|
-
};
|
|
79
|
-
Expandable: {
|
|
80
|
-
(internal: unknown, props: import("../index.js").ExpandableProps<T>): {};
|
|
81
|
-
new (options: import("svelte").ComponentConstructorOptions<import("../index.js").ExpandableProps<T>>): SvelteComponent<import("../index.js").ExpandableProps<T>, {}, {}> & {
|
|
82
|
-
$$bindings?: ReturnType<() => "">;
|
|
83
|
-
};
|
|
84
|
-
z_$$bindings?: ReturnType<() => "">;
|
|
85
|
-
};
|
|
86
|
-
Row: {
|
|
87
|
-
(internal: unknown, props: import("../index.js").RowProps<T>): {};
|
|
88
|
-
new (options: import("svelte").ComponentConstructorOptions<import("../index.js").RowProps<T>>): SvelteComponent<import("../index.js").RowProps<T>, {}, {}> & {
|
|
89
|
-
$$bindings?: ReturnType<() => "">;
|
|
90
|
-
};
|
|
91
|
-
z_$$bindings?: ReturnType<() => "">;
|
|
92
|
-
};
|
|
93
|
-
readonly table: TableState<T>;
|
|
94
|
-
}]> | undefined;
|
|
23
|
+
content?: ContentSnippet<T> | undefined;
|
|
95
24
|
};
|
|
96
25
|
events(): {};
|
|
97
26
|
slots(): {};
|
|
98
|
-
bindings(): "table" | "
|
|
27
|
+
bindings(): "table" | "data" | "selected" | "panel";
|
|
99
28
|
exports(): {
|
|
100
29
|
toCSV: (options?: CSVOptions<T>) => Promise<string>;
|
|
101
30
|
};
|
|
102
31
|
}
|
|
103
32
|
interface $$IsomorphicComponent {
|
|
104
|
-
new <T
|
|
33
|
+
new <T>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
|
|
105
34
|
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
106
35
|
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
107
|
-
<T
|
|
36
|
+
<T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
108
37
|
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
109
38
|
}
|
|
110
39
|
/**
|
|
@@ -115,5 +44,5 @@ interface $$IsomorphicComponent {
|
|
|
115
44
|
* <Component />
|
|
116
45
|
*/
|
|
117
46
|
declare const Table: $$IsomorphicComponent;
|
|
118
|
-
type Table<T
|
|
47
|
+
type Table<T> = InstanceType<typeof Table<T>>;
|
|
119
48
|
export default Table;
|
|
@@ -51,7 +51,7 @@ export class Data {
|
|
|
51
51
|
constructor(table, props) {
|
|
52
52
|
this.#table = table;
|
|
53
53
|
this.origin = props.data;
|
|
54
|
-
this.sorted = this.origin
|
|
54
|
+
this.sorted = [...this.origin];
|
|
55
55
|
this.filtered = this.sorted;
|
|
56
56
|
$effect(() => {
|
|
57
57
|
this.origin = props.data;
|
|
@@ -67,15 +67,28 @@ export class Data {
|
|
|
67
67
|
const table = this.#table;
|
|
68
68
|
if (props.reorderable)
|
|
69
69
|
return;
|
|
70
|
-
|
|
70
|
+
// Track dependencies explicitly
|
|
71
|
+
props.filters;
|
|
72
|
+
this.sorted;
|
|
71
73
|
for (const key in table.columns) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if (filter && valueOf) {
|
|
75
|
-
filters.push((item) => filter(valueOf(item)));
|
|
76
|
-
}
|
|
74
|
+
table.columns[key].options.filter;
|
|
75
|
+
table.columns[key].options.value;
|
|
77
76
|
}
|
|
78
|
-
|
|
77
|
+
const filters = untrack(() => {
|
|
78
|
+
const all = [...props.filters ?? []];
|
|
79
|
+
for (const key in table.columns) {
|
|
80
|
+
const filter = table.columns[key].options.filter;
|
|
81
|
+
const valueOf = table.columns[key].options.value;
|
|
82
|
+
if (filter && valueOf) {
|
|
83
|
+
all.push((item) => filter(valueOf(item)));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return all;
|
|
87
|
+
});
|
|
88
|
+
this.filtered =
|
|
89
|
+
filters.length === 0 ?
|
|
90
|
+
this.sorted
|
|
91
|
+
: this.sorted.filter((value) => filters.every((filter) => filter(value)));
|
|
79
92
|
});
|
|
80
93
|
}
|
|
81
94
|
}
|
|
@@ -5,7 +5,7 @@ import { Data } from './data.svelte.js';
|
|
|
5
5
|
import type { ExpandableState } from '../expandable/expandable-state.svelte.js';
|
|
6
6
|
import type { ItemState } from 'runic-reorder';
|
|
7
7
|
import type { RowState } from '../row/row-state.svelte.js';
|
|
8
|
-
import { CSVOptions } from
|
|
8
|
+
import type { CSVOptions } from './csv.js';
|
|
9
9
|
export type HeaderSelectCtx<T = any> = {
|
|
10
10
|
isSelected: boolean;
|
|
11
11
|
/** The list of selected items */
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { TableState } from './table-state.svelte.js';
|
|
2
|
-
export declare class Virtualization<T extends
|
|
2
|
+
export declare class Virtualization<T extends any> {
|
|
3
3
|
#private;
|
|
4
4
|
scrollTop: number;
|
|
5
5
|
viewport: {
|
|
6
6
|
height: number;
|
|
7
|
-
element:
|
|
7
|
+
element: HTMLElement | null;
|
|
8
8
|
};
|
|
9
9
|
get topIndex(): number;
|
|
10
10
|
get virtualTop(): number;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { untrack } from 'svelte';
|
|
2
2
|
export class Virtualization {
|
|
3
3
|
scrollTop = $state(0);
|
|
4
4
|
viewport = $state({
|
|
@@ -25,47 +25,86 @@ export class Virtualization {
|
|
|
25
25
|
requestAnimationFrame(() => ticked = true);
|
|
26
26
|
});
|
|
27
27
|
});
|
|
28
|
+
let measureRaf = 0;
|
|
29
|
+
let measureRun = 0;
|
|
28
30
|
$effect(() => {
|
|
29
31
|
if (!ticked)
|
|
30
32
|
return;
|
|
31
33
|
table.dataState.current;
|
|
34
|
+
this.viewport.element;
|
|
35
|
+
this.viewport.height;
|
|
36
|
+
let aborted = false;
|
|
37
|
+
const run = ++measureRun;
|
|
32
38
|
untrack(() => {
|
|
33
|
-
|
|
39
|
+
const target = this.viewport.element;
|
|
40
|
+
if (!target) {
|
|
34
41
|
this.#heightPerItem = 8;
|
|
35
42
|
return;
|
|
36
43
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
if (measureRaf)
|
|
45
|
+
cancelAnimationFrame(measureRaf);
|
|
46
|
+
measureRaf = requestAnimationFrame(() => {
|
|
47
|
+
if (aborted)
|
|
40
48
|
return;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
49
|
+
if (run !== measureRun)
|
|
50
|
+
return;
|
|
51
|
+
const el = this.viewport.element;
|
|
52
|
+
if (!el)
|
|
53
|
+
return;
|
|
54
|
+
const rowEls = el.querySelectorAll(':scope > tr.row');
|
|
55
|
+
const children = rowEls.length > 0 ? rowEls : el.children;
|
|
56
|
+
const count = children.length;
|
|
57
|
+
if (count === 0)
|
|
58
|
+
return;
|
|
59
|
+
const first = children[0]?.getBoundingClientRect().top;
|
|
60
|
+
const last = children[count - 1]?.getBoundingClientRect().bottom;
|
|
61
|
+
if (first === undefined || last === undefined)
|
|
62
|
+
return;
|
|
63
|
+
const height = (last - first) / count;
|
|
64
|
+
if (!Number.isFinite(height) || height <= 0)
|
|
65
|
+
return;
|
|
66
|
+
// Avoid tiny oscillations causing endless updates.
|
|
67
|
+
if (Math.abs(height - this.#heightPerItem) < 0.25)
|
|
68
|
+
return;
|
|
69
|
+
this.#heightPerItem = height;
|
|
44
70
|
});
|
|
45
71
|
});
|
|
72
|
+
return () => {
|
|
73
|
+
aborted = true;
|
|
74
|
+
if (measureRaf)
|
|
75
|
+
cancelAnimationFrame(measureRaf);
|
|
76
|
+
};
|
|
46
77
|
});
|
|
47
|
-
let
|
|
78
|
+
let virtualRaf = 0;
|
|
48
79
|
$effect(() => {
|
|
49
80
|
if (!ticked)
|
|
50
81
|
return;
|
|
51
82
|
this.scrollTop;
|
|
52
83
|
this.#heightPerItem;
|
|
84
|
+
this.viewport.height;
|
|
53
85
|
table.dataState.current.length;
|
|
54
|
-
table.dataState.current;
|
|
55
86
|
untrack(() => {
|
|
56
|
-
if (
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
|
|
87
|
+
if (virtualRaf)
|
|
88
|
+
cancelAnimationFrame(virtualRaf);
|
|
89
|
+
virtualRaf = requestAnimationFrame(() => {
|
|
90
|
+
virtualRaf = 0;
|
|
91
|
+
const heightPerItem = this.#heightPerItem || 8;
|
|
92
|
+
const spacing = this.#spacing;
|
|
93
|
+
let virtualTop = Math.max(this.scrollTop - spacing, 0);
|
|
94
|
+
if (heightPerItem > 0) {
|
|
95
|
+
virtualTop -= virtualTop % heightPerItem;
|
|
96
|
+
}
|
|
97
|
+
this.#virtualTop = virtualTop;
|
|
98
|
+
let virtualBottom = heightPerItem * table.dataState.current.length - virtualTop - spacing * 4;
|
|
99
|
+
if (!Number.isFinite(virtualBottom))
|
|
100
|
+
virtualBottom = 0;
|
|
101
|
+
this.#virtualBottom = Math.max(virtualBottom, 0);
|
|
102
|
+
});
|
|
68
103
|
});
|
|
104
|
+
return () => {
|
|
105
|
+
if (virtualRaf)
|
|
106
|
+
cancelAnimationFrame(virtualRaf);
|
|
107
|
+
};
|
|
69
108
|
});
|
|
70
109
|
$effect(() => {
|
|
71
110
|
if (!ticked)
|
|
@@ -74,10 +113,15 @@ export class Virtualization {
|
|
|
74
113
|
table.dataState.sortby;
|
|
75
114
|
this.#heightPerItem;
|
|
76
115
|
this.#virtualTop;
|
|
116
|
+
this.viewport.height;
|
|
117
|
+
this.#renderItemLength;
|
|
77
118
|
table.dataState.current.length;
|
|
78
119
|
table.dataState.current;
|
|
79
120
|
untrack(() => {
|
|
80
|
-
|
|
121
|
+
const heightPerItem = this.#heightPerItem || 8;
|
|
122
|
+
this.#topIndex = Math.round(this.#virtualTop / heightPerItem || 0);
|
|
123
|
+
if (this.#topIndex < 0)
|
|
124
|
+
this.#topIndex = 0;
|
|
81
125
|
const end = this.#topIndex + this.#renderItemLength;
|
|
82
126
|
this.#area = table.dataState.current.slice(this.#topIndex, end);
|
|
83
127
|
});
|
package/dist/utility.svelte.d.ts
CHANGED
package/dist/utility.svelte.js
CHANGED
|
@@ -4,7 +4,7 @@ export function pick(item, keys) {
|
|
|
4
4
|
}
|
|
5
5
|
export function boundPick(item, keys) {
|
|
6
6
|
const obj = {};
|
|
7
|
-
for (const key
|
|
7
|
+
for (const key of keys) {
|
|
8
8
|
obj[key] = [() => item[key], (v) => item[key] = v];
|
|
9
9
|
}
|
|
10
10
|
return Object.defineProperties({}, withSetters(obj));
|
|
@@ -30,7 +30,7 @@ export function boundAssign(item, props = {}) {
|
|
|
30
30
|
boundAssign(item[key], value);
|
|
31
31
|
continue;
|
|
32
32
|
}
|
|
33
|
-
Object.defineProperty(item,
|
|
33
|
+
Object.defineProperty(item, key, {
|
|
34
34
|
get() { return props[key]; },
|
|
35
35
|
set(v) { props[key] = v; }
|
|
36
36
|
});
|