svelte-tably 1.0.0-next.11 → 1.0.0-next.13
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 +5 -5
- package/dist/column/Column.svelte +24 -0
- package/dist/column/Column.svelte.d.ts +24 -0
- package/dist/column/column.svelte.js +60 -0
- package/dist/conditional.svelte.d.ts +10 -0
- package/dist/conditional.svelte.js +26 -0
- package/dist/expandable/Expandable.svelte +24 -0
- package/dist/expandable/Expandable.svelte.d.ts +25 -0
- package/dist/expandable/expandable.svelte.js +20 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/panel/Panel.svelte +47 -0
- package/dist/{Panel.svelte.d.ts → panel/Panel.svelte.d.ts} +1 -19
- package/dist/panel/panel.svelte.js +19 -0
- package/dist/size-tween.svelte.d.ts +14 -0
- package/dist/size-tween.svelte.js +30 -0
- package/dist/table/Table.svelte +889 -0
- package/dist/table/Table.svelte.d.ts +31 -0
- package/dist/table/data.svelte.d.ts +14 -0
- package/dist/table/data.svelte.js +81 -0
- package/dist/table/table.svelte.js +75 -0
- package/dist/table/virtualization.svelte.d.ts +14 -0
- package/dist/table/virtualization.svelte.js +86 -0
- package/dist/utility.svelte.d.ts +16 -0
- package/dist/utility.svelte.js +68 -0
- package/package.json +2 -2
- package/dist/Column.svelte +0 -174
- package/dist/Column.svelte.d.ts +0 -121
- package/dist/Panel.svelte +0 -74
- package/dist/Table.svelte +0 -977
- package/dist/Table.svelte.d.ts +0 -107
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Work in progress. I needed a break from my primary project, so here's a little s
|
|
|
4
4
|
|
|
5
5
|
Example on [Svelte 5 Playground](https://svelte.dev/playground/a16d71c97445455e80a55b77ec1cf915?version=5)
|
|
6
6
|
|
|
7
|
-
A high performant dynamic table
|
|
7
|
+
A high performant, feature rich, dynamic table
|
|
8
8
|
|
|
9
9
|
- [x] Sticky columns
|
|
10
10
|
- [x] Show/hide columns
|
|
@@ -17,10 +17,10 @@ A high performant dynamic table
|
|
|
17
17
|
- [x] sorting
|
|
18
18
|
- [x] select
|
|
19
19
|
- [x] filtering
|
|
20
|
-
- [
|
|
20
|
+
- [x] reorderable table
|
|
21
21
|
- [ ] row context-menu
|
|
22
|
-
- [
|
|
23
|
-
- [
|
|
22
|
+
- [x] Expandable rows
|
|
23
|
+
- [x] to CSV
|
|
24
24
|
|
|
25
25
|
### Usage Notes
|
|
26
26
|
|
|
@@ -34,7 +34,7 @@ A high performant dynamic table
|
|
|
34
34
|
])
|
|
35
35
|
|
|
36
36
|
let activePanel = $state('columns') as string | undefined
|
|
37
|
-
|
|
37
|
+
let selected = $state([]) as typeof data
|
|
38
38
|
</script>
|
|
39
39
|
|
|
40
40
|
<Table {data} panel={activePanel} select bind:selected>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<!-- @component
|
|
2
|
+
|
|
3
|
+
This is a description, \
|
|
4
|
+
on how to use this.
|
|
5
|
+
|
|
6
|
+
@example
|
|
7
|
+
<Component />
|
|
8
|
+
|
|
9
|
+
-->
|
|
10
|
+
|
|
11
|
+
<script lang="ts">
|
|
12
|
+
|
|
13
|
+
import { fromProps } from '../utility.svelte.js'
|
|
14
|
+
import { ColumnState, type ColumnProps } from './column.svelte.js'
|
|
15
|
+
|
|
16
|
+
type T = $$Generic<Record<PropertyKey, any>>
|
|
17
|
+
type V = $$Generic
|
|
18
|
+
|
|
19
|
+
let {...props}: ColumnProps<T, V> = $props()
|
|
20
|
+
const properties = fromProps(props)
|
|
21
|
+
|
|
22
|
+
new ColumnState<T, V>(properties)
|
|
23
|
+
|
|
24
|
+
</script>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
declare class __sveltets_Render<T extends Record<PropertyKey, any>, V> {
|
|
2
|
+
props(): ColumnProps<T_1, V_1>;
|
|
3
|
+
events(): {};
|
|
4
|
+
slots(): {};
|
|
5
|
+
bindings(): "";
|
|
6
|
+
exports(): {};
|
|
7
|
+
}
|
|
8
|
+
interface $$IsomorphicComponent {
|
|
9
|
+
new <T extends Record<PropertyKey, any>, V>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T, V>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T, V>['props']>, ReturnType<__sveltets_Render<T, V>['events']>, ReturnType<__sveltets_Render<T, V>['slots']>> & {
|
|
10
|
+
$$bindings?: ReturnType<__sveltets_Render<T, V>['bindings']>;
|
|
11
|
+
} & ReturnType<__sveltets_Render<T, V>['exports']>;
|
|
12
|
+
<T extends Record<PropertyKey, any>, V>(internal: unknown, props: ReturnType<__sveltets_Render<T, V>['props']> & {}): ReturnType<__sveltets_Render<T, V>['exports']>;
|
|
13
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any, any>['bindings']>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* This is a description, \
|
|
17
|
+
* on how to use this.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* <Component />
|
|
21
|
+
*/
|
|
22
|
+
declare const Column: $$IsomorphicComponent;
|
|
23
|
+
type Column<T extends Record<PropertyKey, any>, V> = InstanceType<typeof Column<T, V>>;
|
|
24
|
+
export default Column;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import {} from 'svelte';
|
|
2
|
+
import { TableState } from '../table/table.svelte.js';
|
|
3
|
+
import { assign, pick } from '../utility.svelte.js';
|
|
4
|
+
export class ColumnState {
|
|
5
|
+
#props = {};
|
|
6
|
+
id = $derived(this.#props.id);
|
|
7
|
+
/**
|
|
8
|
+
* Associated table
|
|
9
|
+
*/
|
|
10
|
+
table;
|
|
11
|
+
snippets = $derived({
|
|
12
|
+
header: this.#props.header,
|
|
13
|
+
/** Title is the header-snippet, with header-ctx: `{ header: false }` */
|
|
14
|
+
title: (...args) => {
|
|
15
|
+
const getData = () => this.table.data.current;
|
|
16
|
+
return this.#props.header?.(...[args[0], () => ({
|
|
17
|
+
get header() { return false; },
|
|
18
|
+
get data() {
|
|
19
|
+
return getData();
|
|
20
|
+
}
|
|
21
|
+
})]);
|
|
22
|
+
},
|
|
23
|
+
row: this.#props.row,
|
|
24
|
+
statusbar: this.#props.statusbar
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* Variables that can be saved (e.g. localStorage)
|
|
28
|
+
* and re-provided, where these are default-fallbacks
|
|
29
|
+
*/
|
|
30
|
+
defaults = $derived({
|
|
31
|
+
sticky: this.#props.sticky ?? false,
|
|
32
|
+
show: this.#props.show ?? true,
|
|
33
|
+
sortby: this.#props.sortby ?? false,
|
|
34
|
+
width: this.#props.width ?? 150
|
|
35
|
+
});
|
|
36
|
+
/** Static options */
|
|
37
|
+
options = $derived({
|
|
38
|
+
fixed: this.#props.fixed ?? false,
|
|
39
|
+
sort: this.#props.sort ?? false,
|
|
40
|
+
filter: this.#props.filter,
|
|
41
|
+
value: this.#props.value,
|
|
42
|
+
resizeable: this.#props.resizeable ?? true,
|
|
43
|
+
});
|
|
44
|
+
toggleVisiblity() {
|
|
45
|
+
const index = this.table.positions.hidden.indexOf(this);
|
|
46
|
+
if (index > -1)
|
|
47
|
+
this.table.positions.hidden.splice(index, 1);
|
|
48
|
+
else
|
|
49
|
+
this.table.positions.hidden.push(this);
|
|
50
|
+
}
|
|
51
|
+
constructor(props) {
|
|
52
|
+
this.#props = props;
|
|
53
|
+
this.table = props.table ?? TableState.getContext();
|
|
54
|
+
if (!this.table) {
|
|
55
|
+
throw new Error('svelte-tably: Column must be associated with a Table');
|
|
56
|
+
}
|
|
57
|
+
const remove = this.table.add(this);
|
|
58
|
+
$effect(() => remove);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type Actionable<A extends unknown | unknown[]> = {
|
|
2
|
+
destroy?: () => void;
|
|
3
|
+
update?: (args: A) => void;
|
|
4
|
+
};
|
|
5
|
+
export declare function conditional<A extends unknown | unknown[]>(node: HTMLElement, arg: [
|
|
6
|
+
condition: (() => boolean) | boolean,
|
|
7
|
+
action: ((node: HTMLElement, args?: A) => void | Actionable<A>),
|
|
8
|
+
args?: A
|
|
9
|
+
]): void;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { untrack } from 'svelte';
|
|
2
|
+
/*
|
|
3
|
+
use:conditional={[condition, action, arg]}
|
|
4
|
+
use:conditional={[condition, (node) => action(node, arg), updatedArg]}
|
|
5
|
+
*/
|
|
6
|
+
export function conditional(node, arg) {
|
|
7
|
+
let prev;
|
|
8
|
+
let clean;
|
|
9
|
+
$effect(() => {
|
|
10
|
+
prev?.destroy?.();
|
|
11
|
+
clean?.();
|
|
12
|
+
if (typeof arg[0] === 'function' ? arg[0]() : arg[0]) {
|
|
13
|
+
untrack(() => {
|
|
14
|
+
prev = arg[1](node, arg[2]);
|
|
15
|
+
if (prev?.update) {
|
|
16
|
+
clean = $effect.root(() => {
|
|
17
|
+
$effect(() => {
|
|
18
|
+
prev.update(arg[2]);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
return clean;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<!-- @component
|
|
2
|
+
|
|
3
|
+
This is a description, \
|
|
4
|
+
on how to use this.
|
|
5
|
+
|
|
6
|
+
@example
|
|
7
|
+
<Component />
|
|
8
|
+
|
|
9
|
+
-->
|
|
10
|
+
|
|
11
|
+
<script lang='ts'>
|
|
12
|
+
|
|
13
|
+
import { ExpandableState, type ExpandableProps } from './expandable.svelte.js'
|
|
14
|
+
import type { AnyRecord } from '../utility.svelte.js'
|
|
15
|
+
import { fromProps } from '../utility.svelte.js'
|
|
16
|
+
|
|
17
|
+
type T = $$Generic<AnyRecord>
|
|
18
|
+
|
|
19
|
+
let { ...restProps }: ExpandableProps<T> = $props()
|
|
20
|
+
|
|
21
|
+
const properties = fromProps(restProps)
|
|
22
|
+
new ExpandableState<T>(properties)
|
|
23
|
+
|
|
24
|
+
</script>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { AnyRecord } from '../utility.svelte.js';
|
|
2
|
+
declare class __sveltets_Render<T extends AnyRecord> {
|
|
3
|
+
props(): ExpandableProps<T_1>;
|
|
4
|
+
events(): {};
|
|
5
|
+
slots(): {};
|
|
6
|
+
bindings(): "";
|
|
7
|
+
exports(): {};
|
|
8
|
+
}
|
|
9
|
+
interface $$IsomorphicComponent {
|
|
10
|
+
new <T extends AnyRecord>(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']>> & {
|
|
11
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
12
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
13
|
+
<T extends AnyRecord>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
14
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* This is a description, \
|
|
18
|
+
* on how to use this.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* <Component />
|
|
22
|
+
*/
|
|
23
|
+
declare const Expandable: $$IsomorphicComponent;
|
|
24
|
+
type Expandable<T extends AnyRecord> = InstanceType<typeof Expandable<T>>;
|
|
25
|
+
export default Expandable;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { TableState } from '../table/table.svelte.js';
|
|
2
|
+
export class ExpandableState {
|
|
3
|
+
#table;
|
|
4
|
+
#props = $state({});
|
|
5
|
+
snippets = $derived({
|
|
6
|
+
content: this.#props.content
|
|
7
|
+
});
|
|
8
|
+
options = $derived({
|
|
9
|
+
slide: this.#props.slide ?? 200
|
|
10
|
+
});
|
|
11
|
+
constructor(props) {
|
|
12
|
+
this.#props = props;
|
|
13
|
+
this.#table = TableState.getContext();
|
|
14
|
+
if (!this.#table) {
|
|
15
|
+
throw new Error('svelte-tably: Expandable must be associated with a Table');
|
|
16
|
+
}
|
|
17
|
+
this.#table.expandable = this;
|
|
18
|
+
$effect(() => () => this.#table.expandable === this && (this.#table.expandable = undefined));
|
|
19
|
+
}
|
|
20
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { default as default } from './Table.svelte';
|
|
2
|
-
export { default as Panel } from './Panel.svelte';
|
|
3
|
-
export { default as Column } from './Column.svelte';
|
|
1
|
+
export { default as default } from './table/Table.svelte';
|
|
2
|
+
export { default as Panel } from './panel/Panel.svelte';
|
|
3
|
+
export { default as Column } from './column/Column.svelte';
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { default as default } from './Table.svelte';
|
|
2
|
-
export { default as Panel } from './Panel.svelte';
|
|
3
|
-
export { default as Column } from './Column.svelte';
|
|
1
|
+
export { default as default } from './table/Table.svelte';
|
|
2
|
+
export { default as Panel } from './panel/Panel.svelte';
|
|
3
|
+
export { default as Column } from './column/Column.svelte';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<!-- @component
|
|
2
|
+
|
|
3
|
+
This is a description, \
|
|
4
|
+
on how to use this.
|
|
5
|
+
|
|
6
|
+
@example
|
|
7
|
+
<Component />
|
|
8
|
+
|
|
9
|
+
-->
|
|
10
|
+
|
|
11
|
+
<script module lang='ts'>
|
|
12
|
+
|
|
13
|
+
export class PanelTween {
|
|
14
|
+
#tween = new Tween(0, { duration: 300, easing: sineInOut })
|
|
15
|
+
current = $derived(this.#tween.current)
|
|
16
|
+
transitioning = $state(false)
|
|
17
|
+
|
|
18
|
+
/** bind:clientWidth */
|
|
19
|
+
width = $state(0)
|
|
20
|
+
|
|
21
|
+
set target(value: number) {
|
|
22
|
+
this.transitioning = true
|
|
23
|
+
this.#tween.set(value).then(() => this.transitioning = false)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
constructor(cb: () => string | undefined, added = 0) {
|
|
27
|
+
$effect.pre(() => {
|
|
28
|
+
this.target = cb() ? this.width + added : 0
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<script lang='ts' generics='T extends Record<PropertyKey, unknown>'>
|
|
36
|
+
|
|
37
|
+
import { Tween } from 'svelte/motion'
|
|
38
|
+
import { sineInOut } from 'svelte/easing'
|
|
39
|
+
import { PanelState, type PanelProps } from './panel.svelte.js'
|
|
40
|
+
import { fromProps } from '../utility.svelte.js'
|
|
41
|
+
|
|
42
|
+
let {...props}: PanelProps<T> = $props()
|
|
43
|
+
const properties = fromProps(props)
|
|
44
|
+
|
|
45
|
+
new PanelState<T>(properties)
|
|
46
|
+
|
|
47
|
+
</script>
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
export interface Panel<T extends Record<PropertyKey, unknown> = Record<PropertyKey, unknown>> {
|
|
2
|
-
/** A darkened backdrop? */
|
|
3
|
-
backdrop: boolean;
|
|
4
|
-
content: Snippet<[context: {
|
|
5
|
-
readonly table: TableState<T>;
|
|
6
|
-
readonly data: T[];
|
|
7
|
-
}]>;
|
|
8
|
-
}
|
|
9
1
|
export declare class PanelTween {
|
|
10
2
|
#private;
|
|
11
3
|
current: number;
|
|
@@ -15,18 +7,8 @@ export declare class PanelTween {
|
|
|
15
7
|
set target(value: number);
|
|
16
8
|
constructor(cb: () => string | undefined, added?: number);
|
|
17
9
|
}
|
|
18
|
-
import { type Snippet } from 'svelte';
|
|
19
|
-
import { type TableState } from './Table.svelte';
|
|
20
10
|
declare class __sveltets_Render<T extends Record<PropertyKey, unknown>> {
|
|
21
|
-
props():
|
|
22
|
-
id: string;
|
|
23
|
-
/** A darkened backdrop? */
|
|
24
|
-
backdrop?: boolean;
|
|
25
|
-
children: Snippet<[context: {
|
|
26
|
-
readonly table: TableState<T>;
|
|
27
|
-
readonly data: T[];
|
|
28
|
-
}]>;
|
|
29
|
-
};
|
|
11
|
+
props(): PanelProps<T_1>;
|
|
30
12
|
events(): {};
|
|
31
13
|
slots(): {};
|
|
32
14
|
bindings(): "";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { TableState } from '../table/table.svelte.js';
|
|
2
|
+
import {} from '../utility.svelte.js';
|
|
3
|
+
export class PanelState {
|
|
4
|
+
#props = {};
|
|
5
|
+
table;
|
|
6
|
+
id = $derived(this.#props.id);
|
|
7
|
+
backdrop = $derived(this.#props.backdrop ?? true);
|
|
8
|
+
children = $derived(this.#props.children);
|
|
9
|
+
constructor(props) {
|
|
10
|
+
this.#props = props;
|
|
11
|
+
const table = props.table ?? TableState.getContext();
|
|
12
|
+
if (!table) {
|
|
13
|
+
throw new Error('svelte-tably: Panel must be associated with a Table');
|
|
14
|
+
}
|
|
15
|
+
this.table = table;
|
|
16
|
+
const remove = table.add(this);
|
|
17
|
+
$effect(() => remove);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface SizeOptions {
|
|
2
|
+
min?: number;
|
|
3
|
+
duration?: number;
|
|
4
|
+
}
|
|
5
|
+
export declare class SizeTween {
|
|
6
|
+
#private;
|
|
7
|
+
current: number;
|
|
8
|
+
transitioning: boolean;
|
|
9
|
+
/** bind:offsetWidth bind:offsetHeight */
|
|
10
|
+
size: number;
|
|
11
|
+
set target(value: number);
|
|
12
|
+
constructor(cb: () => boolean | undefined, opts?: SizeOptions);
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { tick, untrack } from 'svelte';
|
|
2
|
+
import { sineInOut } from 'svelte/easing';
|
|
3
|
+
import { Tween } from 'svelte/motion';
|
|
4
|
+
export class SizeTween {
|
|
5
|
+
#tweenOptions = { duration: 300, easing: sineInOut };
|
|
6
|
+
#tween = new Tween(0, this.#tweenOptions);
|
|
7
|
+
current = $derived(this.#tween.current);
|
|
8
|
+
transitioning = $state(false);
|
|
9
|
+
/** bind:offsetWidth bind:offsetHeight */
|
|
10
|
+
size = $state(0);
|
|
11
|
+
set target(value) {
|
|
12
|
+
this.transitioning = true;
|
|
13
|
+
this.#tween.set(value, this.#tweenOptions).then(() => this.transitioning = false);
|
|
14
|
+
}
|
|
15
|
+
constructor(cb, opts = {}) {
|
|
16
|
+
if ('duration' in opts) {
|
|
17
|
+
this.#tweenOptions.duration = opts.duration;
|
|
18
|
+
}
|
|
19
|
+
untrack(() => {
|
|
20
|
+
if (cb()) {
|
|
21
|
+
requestAnimationFrame(() => {
|
|
22
|
+
this.#tween.set(Math.max(this.size, opts.min ?? 0), { duration: 0 });
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
$effect.pre(() => {
|
|
27
|
+
this.target = cb() ? Math.max(this.size, opts.min ?? 0) : 0;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|