svelte-tably 1.0.0-next.8 → 1.0.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/LICENSE +21 -0
- package/README.md +299 -92
- package/dist/column/Column.svelte +41 -0
- package/dist/column/Column.svelte.d.ts +27 -0
- package/dist/column/column.svelte.js +64 -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 +27 -0
- package/dist/index.d.ts +10 -3
- package/dist/index.js +5 -3
- package/dist/panel/Panel.svelte +21 -0
- package/dist/{Panel.svelte.d.ts → panel/Panel.svelte.d.ts} +1 -28
- package/dist/panel/panel.svelte.js +18 -0
- package/dist/row/Row.svelte +24 -0
- package/dist/row/Row.svelte.d.ts +25 -0
- package/dist/row/row.svelte.js +28 -0
- package/dist/size-tween.svelte.d.ts +16 -0
- package/dist/size-tween.svelte.js +33 -0
- package/dist/table/Table.svelte +1139 -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 +76 -0
- package/dist/table/virtualization.svelte.d.ts +14 -0
- package/dist/table/virtualization.svelte.js +86 -0
- package/dist/utility.svelte.d.ts +21 -0
- package/dist/utility.svelte.js +104 -0
- package/package.json +34 -53
- package/dist/Column.svelte +0 -119
- package/dist/Column.svelte.d.ts +0 -75
- package/dist/Panel.svelte +0 -74
- package/dist/Table.svelte +0 -763
- package/dist/Table.svelte.d.ts +0 -154
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
declare class __sveltets_Render<T extends Record<PropertyKey, unknown>> {
|
|
2
|
+
props(): any;
|
|
3
|
+
events(): {};
|
|
4
|
+
slots(): {};
|
|
5
|
+
bindings(): "data" | "selected" | "panel";
|
|
6
|
+
exports(): {
|
|
7
|
+
toCSV: (opts?: {
|
|
8
|
+
/** Semi-colons as separator? */
|
|
9
|
+
semicolon?: boolean;
|
|
10
|
+
/** Only selected rows */
|
|
11
|
+
selected?: boolean;
|
|
12
|
+
}) => Promise<string>;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
interface $$IsomorphicComponent {
|
|
16
|
+
new <T extends Record<PropertyKey, unknown>>(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']>> & {
|
|
17
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
18
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
19
|
+
<T extends Record<PropertyKey, unknown>>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
20
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* This is a description, \
|
|
24
|
+
* on how to use this.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* <Component />
|
|
28
|
+
*/
|
|
29
|
+
declare const Table: $$IsomorphicComponent;
|
|
30
|
+
type Table<T extends Record<PropertyKey, unknown>> = InstanceType<typeof Table<T>>;
|
|
31
|
+
export default Table;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { TableProps, TableState } from './table.svelte.js';
|
|
2
|
+
export declare class Data<T extends Record<PropertyKey, unknown>> {
|
|
3
|
+
#private;
|
|
4
|
+
origin: T[];
|
|
5
|
+
sorted: T[];
|
|
6
|
+
filtered: T[];
|
|
7
|
+
sortby: string | undefined;
|
|
8
|
+
sortReverse: boolean;
|
|
9
|
+
current: T[];
|
|
10
|
+
sortBy(column: string): void;
|
|
11
|
+
sortAction(node: HTMLElement, column: string): void;
|
|
12
|
+
sortTable(): void;
|
|
13
|
+
constructor(table: TableState<T>, props: TableProps<T>);
|
|
14
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { on } from 'svelte/events';
|
|
2
|
+
import { untrack } from 'svelte';
|
|
3
|
+
export class Data {
|
|
4
|
+
#table = $state();
|
|
5
|
+
origin = $state([]);
|
|
6
|
+
sorted = $state([]);
|
|
7
|
+
filtered = $state([]);
|
|
8
|
+
sortby = $state();
|
|
9
|
+
sortReverse = $state(false);
|
|
10
|
+
current = $derived(this.#table?.options.reorderable ? this.origin : this.filtered);
|
|
11
|
+
sortBy(column) {
|
|
12
|
+
if (this.#table.options.reorderable)
|
|
13
|
+
return;
|
|
14
|
+
const { sort, value } = this.#table.columns[column].options;
|
|
15
|
+
if (!sort || !value)
|
|
16
|
+
return;
|
|
17
|
+
if (this.sortby === column) {
|
|
18
|
+
this.sortReverse = !this.sortReverse;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
this.sortReverse = false;
|
|
22
|
+
this.sortby = column;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
sortAction(node, column) {
|
|
26
|
+
$effect(() => on(node, 'click', () => {
|
|
27
|
+
this.sortBy(column);
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
30
|
+
sortTable() {
|
|
31
|
+
if (!this.sortby || this.#table.options.reorderable) {
|
|
32
|
+
this.sorted = [...this.origin];
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const column = this.#table.columns[this.sortby];
|
|
36
|
+
let { sort, value } = column?.options ?? {};
|
|
37
|
+
if (!sort || !value) {
|
|
38
|
+
this.sorted = [...this.origin];
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (sort === true) {
|
|
42
|
+
sort = (a, b) => String(a).localeCompare(String(b));
|
|
43
|
+
}
|
|
44
|
+
if (this.sortReverse) {
|
|
45
|
+
this.sorted = this.origin.toSorted((a, b) => sort(value(b), value(a)));
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
this.sorted = this.origin.toSorted((a, b) => sort(value(a), value(b)));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
constructor(table, props) {
|
|
52
|
+
this.#table = table;
|
|
53
|
+
this.origin = props.data;
|
|
54
|
+
this.sorted = this.origin.toSorted();
|
|
55
|
+
this.filtered = this.sorted;
|
|
56
|
+
$effect(() => {
|
|
57
|
+
this.origin = props.data;
|
|
58
|
+
if (this.#table.options.reorderable)
|
|
59
|
+
return;
|
|
60
|
+
props.data;
|
|
61
|
+
props.data.length;
|
|
62
|
+
this.sortby;
|
|
63
|
+
this.sortReverse;
|
|
64
|
+
untrack(() => this.sortTable());
|
|
65
|
+
});
|
|
66
|
+
$effect(() => {
|
|
67
|
+
const table = this.#table;
|
|
68
|
+
if (props.reorderable)
|
|
69
|
+
return;
|
|
70
|
+
const filters = [...props.filters ?? []];
|
|
71
|
+
for (const key in table.columns) {
|
|
72
|
+
const filter = table.columns[key].options.filter;
|
|
73
|
+
const valueOf = table.columns[key].options.value;
|
|
74
|
+
if (filter && valueOf) {
|
|
75
|
+
filters.push((item) => filter(valueOf(item)));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
this.filtered = filters.length === 0 ? this.sorted : this.sorted.filter((value) => filters.every((filter) => filter(value)));
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { getContext, setContext } from 'svelte';
|
|
2
|
+
import { ColumnState } from '../column/column.svelte.js';
|
|
3
|
+
import { PanelState } from '../panel/panel.svelte.js';
|
|
4
|
+
import { Data } from './data.svelte.js';
|
|
5
|
+
export class TableState {
|
|
6
|
+
#props = {};
|
|
7
|
+
id = $state();
|
|
8
|
+
dataState = $state({});
|
|
9
|
+
data = $derived(this.dataState.current ?? []);
|
|
10
|
+
columns = $state({});
|
|
11
|
+
panels = $state({});
|
|
12
|
+
expandable = $state();
|
|
13
|
+
row = $state();
|
|
14
|
+
/** Currently selected items */
|
|
15
|
+
get selected() { return this.#props.selected ??= []; }
|
|
16
|
+
set selected(items) { this.#props.selected = items; }
|
|
17
|
+
/** Column positions based on column ids */
|
|
18
|
+
positions = $state({
|
|
19
|
+
fixed: [],
|
|
20
|
+
sticky: [],
|
|
21
|
+
scroll: [],
|
|
22
|
+
hidden: []
|
|
23
|
+
});
|
|
24
|
+
/** Primarily externally managed options */
|
|
25
|
+
options = $derived({
|
|
26
|
+
panel: this.#props.panel,
|
|
27
|
+
filters: this.#props.reorderable ? false : (this.#props.filters ?? []),
|
|
28
|
+
resizeable: this.#props.resizeable ?? true,
|
|
29
|
+
reorderable: this.#props.reorderable ?? false,
|
|
30
|
+
select: this.#props.select ?? false,
|
|
31
|
+
auto: this.#props.auto ?? false
|
|
32
|
+
});
|
|
33
|
+
add(state) {
|
|
34
|
+
if (state instanceof ColumnState) {
|
|
35
|
+
const key = state.id;
|
|
36
|
+
this.columns[key] = state;
|
|
37
|
+
const clean = () => {
|
|
38
|
+
delete this.columns[key];
|
|
39
|
+
this.positions.fixed = this.positions.fixed.filter((column) => column !== state);
|
|
40
|
+
this.positions.sticky = this.positions.sticky.filter((column) => column !== state);
|
|
41
|
+
this.positions.scroll = this.positions.scroll.filter((column) => column !== state);
|
|
42
|
+
this.positions.hidden = this.positions.hidden.filter((column) => column !== state);
|
|
43
|
+
};
|
|
44
|
+
if (state.defaults.sortby)
|
|
45
|
+
this.dataState.sortBy(key);
|
|
46
|
+
if (state.options.fixed) {
|
|
47
|
+
this.positions.fixed.push(state);
|
|
48
|
+
return clean;
|
|
49
|
+
}
|
|
50
|
+
if (state.defaults.show === false) {
|
|
51
|
+
this.positions.hidden.push(state);
|
|
52
|
+
}
|
|
53
|
+
if (state.defaults.sticky) {
|
|
54
|
+
this.positions.sticky.push(state);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
this.positions.scroll.push(state);
|
|
58
|
+
}
|
|
59
|
+
return clean;
|
|
60
|
+
}
|
|
61
|
+
if (state instanceof PanelState) {
|
|
62
|
+
const key = state.id;
|
|
63
|
+
this.panels[key] = state;
|
|
64
|
+
return () => delete this.panels[key];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
static getContext() {
|
|
68
|
+
return getContext('svelte-tably');
|
|
69
|
+
}
|
|
70
|
+
constructor(tableProps) {
|
|
71
|
+
this.#props = tableProps;
|
|
72
|
+
this.id = tableProps.id ?? Array.from({ length: 12 }, () => String.fromCharCode(Math.floor(Math.random() * 26) + 97)).join('');
|
|
73
|
+
this.dataState = new Data(this, tableProps);
|
|
74
|
+
setContext('svelte-tably', this);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { TableState } from './table.svelte.js';
|
|
2
|
+
export declare class Virtualization<T extends Record<PropertyKey, unknown>> {
|
|
3
|
+
#private;
|
|
4
|
+
scrollTop: number;
|
|
5
|
+
viewport: {
|
|
6
|
+
height: number;
|
|
7
|
+
element: HTMLDivElement | null;
|
|
8
|
+
};
|
|
9
|
+
get topIndex(): number;
|
|
10
|
+
get virtualTop(): number;
|
|
11
|
+
get virtualBottom(): number;
|
|
12
|
+
get area(): T[];
|
|
13
|
+
constructor(table: TableState<T>);
|
|
14
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { tick, untrack } from 'svelte';
|
|
2
|
+
export class Virtualization {
|
|
3
|
+
scrollTop = $state(0);
|
|
4
|
+
viewport = $state({
|
|
5
|
+
height: 0,
|
|
6
|
+
element: null
|
|
7
|
+
});
|
|
8
|
+
get topIndex() { return this.#topIndex; }
|
|
9
|
+
get virtualTop() { return this.#virtualTop; }
|
|
10
|
+
get virtualBottom() { return this.#virtualBottom; }
|
|
11
|
+
get area() { return this.#area; }
|
|
12
|
+
#topIndex = 0;
|
|
13
|
+
#heightPerItem = $state(8);
|
|
14
|
+
#virtualTop = $state(0);
|
|
15
|
+
#virtualBottom = $state(0);
|
|
16
|
+
#area = $state([]);
|
|
17
|
+
#spacing = $derived(this.viewport.height / 2);
|
|
18
|
+
#renderItemLength = $derived(Math.ceil(Math.max(30, (this.viewport.height / this.#heightPerItem) * 2)));
|
|
19
|
+
constructor(table) {
|
|
20
|
+
let ticked = $state(false);
|
|
21
|
+
$effect.pre(() => {
|
|
22
|
+
table.dataState.origin;
|
|
23
|
+
untrack(() => {
|
|
24
|
+
ticked = false;
|
|
25
|
+
requestAnimationFrame(() => ticked = true);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
$effect(() => {
|
|
29
|
+
if (!ticked)
|
|
30
|
+
return;
|
|
31
|
+
table.dataState.current;
|
|
32
|
+
untrack(() => {
|
|
33
|
+
if (!this.viewport.element) {
|
|
34
|
+
this.#heightPerItem = 8;
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
tick().then(() => {
|
|
38
|
+
const target = this.viewport.element;
|
|
39
|
+
if (target.children.length === 0)
|
|
40
|
+
return;
|
|
41
|
+
const firstRow = target.children[0]?.getBoundingClientRect().top;
|
|
42
|
+
const lastRow = target.children[target.children.length - 1].getBoundingClientRect().bottom;
|
|
43
|
+
this.#heightPerItem = (lastRow - firstRow) / this.#area.length;
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
let waitAnimationFrame = false;
|
|
48
|
+
$effect(() => {
|
|
49
|
+
if (!ticked)
|
|
50
|
+
return;
|
|
51
|
+
this.scrollTop;
|
|
52
|
+
this.#heightPerItem;
|
|
53
|
+
table.dataState.current.length;
|
|
54
|
+
table.dataState.current;
|
|
55
|
+
untrack(() => {
|
|
56
|
+
if (!waitAnimationFrame) {
|
|
57
|
+
setTimeout(() => {
|
|
58
|
+
waitAnimationFrame = false;
|
|
59
|
+
let virtualTop = Math.max(this.scrollTop - this.#spacing, 0);
|
|
60
|
+
virtualTop -= virtualTop % this.#heightPerItem;
|
|
61
|
+
this.#virtualTop = virtualTop;
|
|
62
|
+
let virtualBottom = this.#heightPerItem * table.dataState.current.length - virtualTop - this.#spacing * 4;
|
|
63
|
+
virtualBottom = Math.max(virtualBottom, 0);
|
|
64
|
+
this.#virtualBottom = virtualBottom;
|
|
65
|
+
}, 1000 / 60);
|
|
66
|
+
}
|
|
67
|
+
waitAnimationFrame = true;
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
$effect(() => {
|
|
71
|
+
if (!ticked)
|
|
72
|
+
return;
|
|
73
|
+
table.dataState.sortReverse;
|
|
74
|
+
table.dataState.sortby;
|
|
75
|
+
this.#heightPerItem;
|
|
76
|
+
this.#virtualTop;
|
|
77
|
+
table.dataState.current.length;
|
|
78
|
+
table.dataState.current;
|
|
79
|
+
untrack(() => {
|
|
80
|
+
this.#topIndex = Math.round(this.#virtualTop / this.#heightPerItem || 0);
|
|
81
|
+
const end = this.#topIndex + this.#renderItemLength;
|
|
82
|
+
this.#area = table.dataState.current.slice(this.#topIndex, end);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type Simplify<T> = T extends infer V ? {
|
|
2
|
+
[K in keyof V]: V[K];
|
|
3
|
+
} : never;
|
|
4
|
+
export type AnyRecord = Record<PropertyKey, any>;
|
|
5
|
+
export declare function pick<T extends Record<PropertyKey, any>, K extends (keyof T)[]>(item: T, keys: K): Simplify<Pick<T, K[number]>>;
|
|
6
|
+
export declare function boundPick<T extends Record<PropertyKey, any>, K extends (keyof T)[]>(item: T, keys: K): {};
|
|
7
|
+
export declare function assign(item: Record<PropertyKey, any>, props?: Partial<Record<PropertyKey, any>>): void;
|
|
8
|
+
export declare function boundAssign(item: Record<PropertyKey, any>, props?: Partial<Record<PropertyKey, any>>): void;
|
|
9
|
+
export declare function mounted(): {
|
|
10
|
+
readonly isMounted: boolean;
|
|
11
|
+
};
|
|
12
|
+
export declare function getters<T extends AnyRecord>(obj: T): { readonly [K in keyof T]: T[K]; };
|
|
13
|
+
type SetterRecord = Record<PropertyKey, [() => any, (v: any) => void]>;
|
|
14
|
+
export declare function withSetters<T extends SetterRecord>(obj: T): T;
|
|
15
|
+
export declare function fromProps<T extends AnyRecord, B extends SetterRecord>(props: T, boundProps?: B): Simplify<{ [K in keyof B]: ReturnType<B[K][0]>; } & { readonly [K in keyof T]: T[K]; }>;
|
|
16
|
+
export declare function assignDescriptors<T extends AnyRecord, B extends AnyRecord>(target: T, source: B): T & B;
|
|
17
|
+
/** Capitalize by space */
|
|
18
|
+
export declare function capitalize(str: string): string;
|
|
19
|
+
/** Split words when going from lower case to uppercase; `someWords-split` -> `some Word Split...` */
|
|
20
|
+
export declare function segmentize(str: string): string;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { onMount } from 'svelte';
|
|
2
|
+
export function pick(item, keys) {
|
|
3
|
+
return keys.reduce((acc, key) => ({ ...acc, [key]: item[key] }), {});
|
|
4
|
+
}
|
|
5
|
+
export function boundPick(item, keys) {
|
|
6
|
+
const obj = {};
|
|
7
|
+
for (const key in keys) {
|
|
8
|
+
obj[key] = [() => item[key], (v) => item[key] = v];
|
|
9
|
+
}
|
|
10
|
+
return Object.defineProperties({}, withSetters(obj));
|
|
11
|
+
}
|
|
12
|
+
export function assign(item, props = {}) {
|
|
13
|
+
for (const key in props) {
|
|
14
|
+
const value = props[key];
|
|
15
|
+
if (value === undefined)
|
|
16
|
+
continue;
|
|
17
|
+
if (typeof value === 'object') {
|
|
18
|
+
assign(item[key], value);
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
item[key] = value;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function boundAssign(item, props = {}) {
|
|
25
|
+
for (const key in props) {
|
|
26
|
+
const value = props[key];
|
|
27
|
+
if (value === undefined)
|
|
28
|
+
continue;
|
|
29
|
+
if (typeof value === 'object') {
|
|
30
|
+
boundAssign(item[key], value);
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
Object.defineProperty(item, value, {
|
|
34
|
+
get() { return props[key]; },
|
|
35
|
+
set(v) { props[key] = v; }
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export function mounted() {
|
|
40
|
+
let isMounted = $state(false);
|
|
41
|
+
onMount(() => { isMounted = true; });
|
|
42
|
+
return {
|
|
43
|
+
get isMounted() { return isMounted; }
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export function getters(obj) {
|
|
47
|
+
let items = {};
|
|
48
|
+
for (const key in obj) {
|
|
49
|
+
items[key] = { get: () => obj[key] };
|
|
50
|
+
}
|
|
51
|
+
return items;
|
|
52
|
+
}
|
|
53
|
+
export function withSetters(obj) {
|
|
54
|
+
let items = {};
|
|
55
|
+
for (const key in obj) {
|
|
56
|
+
items[key] = {
|
|
57
|
+
get: () => obj[key][0](),
|
|
58
|
+
set: (v) => obj[key][1](v)
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return items;
|
|
62
|
+
}
|
|
63
|
+
export function fromProps(props, boundProps) {
|
|
64
|
+
return Object.defineProperties({}, {
|
|
65
|
+
...getters(props),
|
|
66
|
+
...withSetters(boundProps ?? {})
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
export function assignDescriptors(target, source) {
|
|
70
|
+
for (const key of Object.keys(source)) {
|
|
71
|
+
const descriptor = Object.getOwnPropertyDescriptor(source, key);
|
|
72
|
+
if (descriptor) {
|
|
73
|
+
Object.defineProperty(target, key, descriptor);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
target[key] = source[key]; // Copy regular values if descriptor is missing
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return target;
|
|
80
|
+
}
|
|
81
|
+
/** Capitalize by space */
|
|
82
|
+
export function capitalize(str) {
|
|
83
|
+
let parts = str.split(' ');
|
|
84
|
+
let result = '';
|
|
85
|
+
for (let part of parts) {
|
|
86
|
+
result += part.charAt(0).toUpperCase() + part.slice(1) + ' ';
|
|
87
|
+
}
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
/** Split words when going from lower case to uppercase; `someWords-split` -> `some Word Split...` */
|
|
91
|
+
export function segmentize(str) {
|
|
92
|
+
let result = '';
|
|
93
|
+
for (let i = 0; i < str.length; i++) {
|
|
94
|
+
const char = str[i];
|
|
95
|
+
const prevChar = i > 0 ? str[i - 1] : '';
|
|
96
|
+
if ((char === '-' || char === char.toUpperCase()) && prevChar !== ' ' && prevChar !== prevChar.toUpperCase()) {
|
|
97
|
+
result += ' ';
|
|
98
|
+
if (char === '-')
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
result += char;
|
|
102
|
+
}
|
|
103
|
+
return result.trim();
|
|
104
|
+
}
|
package/package.json
CHANGED
|
@@ -1,54 +1,35 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"scripts": {
|
|
37
|
-
"dev": "vite dev",
|
|
38
|
-
"build": "vite build && npm run package",
|
|
39
|
-
"preview": "vite preview",
|
|
40
|
-
"package": "svelte-kit sync && svelte-package && publint",
|
|
41
|
-
"prepublishOnly": "npm run package",
|
|
42
|
-
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
43
|
-
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
|
44
|
-
},
|
|
45
|
-
"sideEffects": [
|
|
46
|
-
"**/*.css"
|
|
47
|
-
],
|
|
48
|
-
"svelte": "./dist/index.js",
|
|
49
|
-
"type": "module",
|
|
50
|
-
"types": "./dist/index.d.ts",
|
|
51
|
-
"dependencies": {
|
|
52
|
-
"@faker-js/faker": "^9.3.0"
|
|
53
|
-
}
|
|
54
|
-
}
|
|
2
|
+
"name": "svelte-tably",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/Refzlund/svelte-tably.git"
|
|
7
|
+
},
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"bugs": {
|
|
10
|
+
"url": "https://github.com/Refzlund/svelte-tably/issues"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"!dist/**/*.test.*",
|
|
15
|
+
"!dist/**/*.spec.*"
|
|
16
|
+
],
|
|
17
|
+
"sideEffects": [
|
|
18
|
+
"**/*.css"
|
|
19
|
+
],
|
|
20
|
+
"svelte": "./dist/index.js",
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"type": "module",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"default": "./dist/index.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"runic-reorder": "^1.0.0"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"svelte": "^5.0.0"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/dist/Column.svelte
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
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 type RowCtx<V> = {
|
|
14
|
-
readonly value: V
|
|
15
|
-
readonly isHovered: boolean
|
|
16
|
-
readonly index: number
|
|
17
|
-
selected: boolean
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface Column<T = unknown, V = unknown> {
|
|
21
|
-
header?: Snippet<[
|
|
22
|
-
/**
|
|
23
|
-
* Is true when displaying in the header,
|
|
24
|
-
* so additional content can be shown if desired,
|
|
25
|
-
* so the header snippet can be re-used.
|
|
26
|
-
*/
|
|
27
|
-
header?: boolean
|
|
28
|
-
]>
|
|
29
|
-
row: Snippet<[item: T, row: RowCtx<V>]>
|
|
30
|
-
statusbar?: Snippet
|
|
31
|
-
|
|
32
|
-
fixed?: boolean
|
|
33
|
-
|
|
34
|
-
/** Default options for initial table */
|
|
35
|
-
defaults: {
|
|
36
|
-
sticky?: boolean
|
|
37
|
-
sort?: boolean
|
|
38
|
-
show?: boolean
|
|
39
|
-
width?: number
|
|
40
|
-
}
|
|
41
|
-
/** More options */
|
|
42
|
-
options: {
|
|
43
|
-
value?: (item: T) => V
|
|
44
|
-
sorting?: unknown extends V ? (a: T, b: T) => number : (a: V, b: V) => number
|
|
45
|
-
resizeable: boolean
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
</script>
|
|
50
|
-
|
|
51
|
-
<script lang='ts' generics='T extends Record<PropertyKey, any>, V = unknown'>
|
|
52
|
-
|
|
53
|
-
import { onDestroy, type Snippet } from 'svelte'
|
|
54
|
-
import { getTableState, type TableState } from './Table.svelte'
|
|
55
|
-
|
|
56
|
-
interface Props {
|
|
57
|
-
header?: Column<T, V>['header']
|
|
58
|
-
row: Column<T, V>['row']
|
|
59
|
-
statusbar?: Column<T, V>['statusbar']
|
|
60
|
-
|
|
61
|
-
id: string
|
|
62
|
-
|
|
63
|
-
// options
|
|
64
|
-
sticky?: boolean
|
|
65
|
-
/** Fixed is like sticky, but in its own category — meant to not be moved/hidden ex. select-boxes */
|
|
66
|
-
fixed?: boolean
|
|
67
|
-
sort?: boolean
|
|
68
|
-
show?: boolean
|
|
69
|
-
width?: number
|
|
70
|
-
value?: Column<T, V>['options']['value']
|
|
71
|
-
sorting?: Column<T, V>['options']['sorting']
|
|
72
|
-
/** @default true */
|
|
73
|
-
resizeable?: boolean
|
|
74
|
-
|
|
75
|
-
/** Optional: Provide the table it is a part of */
|
|
76
|
-
table?: TableState
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
let {
|
|
80
|
-
header, row, statusbar, id,
|
|
81
|
-
|
|
82
|
-
sticky = false,
|
|
83
|
-
fixed = false,
|
|
84
|
-
sort = false,
|
|
85
|
-
show = true,
|
|
86
|
-
width,
|
|
87
|
-
|
|
88
|
-
resizeable = true,
|
|
89
|
-
value, sorting,
|
|
90
|
-
|
|
91
|
-
table
|
|
92
|
-
}: Props = $props()
|
|
93
|
-
|
|
94
|
-
const column: Column<T, V> = $state({
|
|
95
|
-
header,
|
|
96
|
-
row,
|
|
97
|
-
statusbar,
|
|
98
|
-
fixed,
|
|
99
|
-
defaults: {
|
|
100
|
-
sticky,
|
|
101
|
-
sort,
|
|
102
|
-
show,
|
|
103
|
-
width
|
|
104
|
-
},
|
|
105
|
-
options: {
|
|
106
|
-
value,
|
|
107
|
-
sorting,
|
|
108
|
-
resizeable
|
|
109
|
-
}
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
table ??= getTableState()
|
|
113
|
-
table.addColumn(id, column as Column)
|
|
114
|
-
|
|
115
|
-
onDestroy(() => {
|
|
116
|
-
table.removeColumn(id)
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
</script>
|