svelte-tably 1.0.0-next.9 → 1.0.1-next.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.
Files changed (40) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +299 -93
  3. package/dist/column/Column.svelte +39 -0
  4. package/dist/column/Column.svelte.d.ts +46 -0
  5. package/dist/column/column-state.svelte.d.ts +138 -0
  6. package/dist/column/column-state.svelte.js +64 -0
  7. package/dist/conditional.svelte.d.ts +10 -0
  8. package/dist/conditional.svelte.js +26 -0
  9. package/dist/expandable/Expandable.svelte +24 -0
  10. package/dist/expandable/Expandable.svelte.d.ts +26 -0
  11. package/dist/expandable/expandable-state.svelte.d.ts +48 -0
  12. package/dist/expandable/expandable-state.svelte.js +27 -0
  13. package/dist/index.d.ts +10 -3
  14. package/dist/index.js +5 -3
  15. package/dist/panel/Panel.svelte +21 -0
  16. package/dist/{Panel.svelte.d.ts → panel/Panel.svelte.d.ts} +2 -28
  17. package/dist/panel/panel-state.svelte.d.ts +25 -0
  18. package/dist/panel/panel-state.svelte.js +18 -0
  19. package/dist/row/Row.svelte +24 -0
  20. package/dist/row/Row.svelte.d.ts +26 -0
  21. package/dist/row/row-state.svelte.d.ts +43 -0
  22. package/dist/row/row-state.svelte.js +28 -0
  23. package/dist/size-tween.svelte.d.ts +16 -0
  24. package/dist/size-tween.svelte.js +33 -0
  25. package/dist/table/Table.svelte +1140 -0
  26. package/dist/table/Table.svelte.d.ts +123 -0
  27. package/dist/table/data.svelte.d.ts +14 -0
  28. package/dist/table/data.svelte.js +81 -0
  29. package/dist/table/table-state.svelte.d.ts +107 -0
  30. package/dist/table/table-state.svelte.js +76 -0
  31. package/dist/table/virtualization.svelte.d.ts +14 -0
  32. package/dist/table/virtualization.svelte.js +86 -0
  33. package/dist/utility.svelte.d.ts +24 -0
  34. package/dist/utility.svelte.js +107 -0
  35. package/package.json +29 -53
  36. package/dist/Column.svelte +0 -164
  37. package/dist/Column.svelte.d.ts +0 -115
  38. package/dist/Panel.svelte +0 -74
  39. package/dist/Table.svelte +0 -906
  40. package/dist/Table.svelte.d.ts +0 -112
@@ -0,0 +1,123 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import { type Snippet } from 'svelte';
3
+ import { TableState, type TableProps } from './table-state.svelte.js';
4
+ import { type RowColumnCtx } from '../column/column-state.svelte.js';
5
+ declare class __sveltets_Render<T extends Record<PropertyKey, unknown>> {
6
+ props(): TableProps<T> & {
7
+ content?: Snippet<[context: {
8
+ Column: {
9
+ <V>(internal: unknown, props: {
10
+ id: string;
11
+ table?: TableState<T> | undefined;
12
+ header?: string | Snippet<[ctx: import("../column/column-state.svelte.js").HeaderCtx<T>]> | undefined;
13
+ row?: Snippet<[item: T, ctx: RowColumnCtx<T, V>]> | undefined;
14
+ statusbar?: Snippet<[ctx: import("../column/column-state.svelte.js").StatusbarCtx<T>]> | undefined;
15
+ sticky?: boolean | undefined;
16
+ show?: boolean | undefined;
17
+ sortby?: boolean | undefined;
18
+ width?: number | undefined;
19
+ fixed?: boolean | undefined;
20
+ value?: ((item: T) => V) | undefined;
21
+ sort?: boolean | ((a: V, b: V) => number) | undefined;
22
+ resizeable?: boolean | undefined;
23
+ filter?: ((value: V) => boolean) | undefined;
24
+ style?: string | undefined;
25
+ class?: string | undefined;
26
+ onclick?: ((event: MouseEvent, rowColumnCtx: RowColumnCtx<T, V>) => void) | undefined;
27
+ pad?: "row" | "header" | "both" | undefined;
28
+ }): {};
29
+ new <V>(options: import("svelte").ComponentConstructorOptions<{
30
+ id: string;
31
+ table?: TableState<T> | undefined;
32
+ header?: string | Snippet<[ctx: import("../column/column-state.svelte.js").HeaderCtx<T>]> | undefined;
33
+ row?: Snippet<[item: T, ctx: RowColumnCtx<T, V>]> | undefined;
34
+ statusbar?: Snippet<[ctx: import("../column/column-state.svelte.js").StatusbarCtx<T>]> | undefined;
35
+ sticky?: boolean | undefined;
36
+ show?: boolean | undefined;
37
+ sortby?: boolean | undefined;
38
+ width?: number | undefined;
39
+ fixed?: boolean | undefined;
40
+ value?: ((item: T) => V) | undefined;
41
+ sort?: boolean | ((a: V, b: V) => number) | undefined;
42
+ resizeable?: boolean | undefined;
43
+ filter?: ((value: V) => boolean) | undefined;
44
+ style?: string | undefined;
45
+ class?: string | undefined;
46
+ onclick?: ((event: MouseEvent, rowColumnCtx: RowColumnCtx<T, V>) => void) | undefined;
47
+ pad?: "row" | "header" | "both" | undefined;
48
+ }>): SvelteComponent<{
49
+ id: string;
50
+ table?: TableState<T> | undefined;
51
+ header?: string | Snippet<[ctx: import("../column/column-state.svelte.js").HeaderCtx<T>]> | undefined;
52
+ row?: Snippet<[item: T, ctx: RowColumnCtx<T, V>]> | undefined;
53
+ statusbar?: Snippet<[ctx: import("../column/column-state.svelte.js").StatusbarCtx<T>]> | undefined;
54
+ sticky?: boolean | undefined;
55
+ show?: boolean | undefined;
56
+ sortby?: boolean | undefined;
57
+ width?: number | undefined;
58
+ fixed?: boolean | undefined;
59
+ value?: ((item: T) => V) | undefined;
60
+ sort?: boolean | ((a: V, b: V) => number) | undefined;
61
+ resizeable?: boolean | undefined;
62
+ filter?: ((value: V) => boolean) | undefined;
63
+ style?: string | undefined;
64
+ class?: string | undefined;
65
+ onclick?: ((event: MouseEvent, rowColumnCtx: RowColumnCtx<T, V>) => void) | undefined;
66
+ pad?: "row" | "header" | "both" | undefined;
67
+ }, {}, {}> & {
68
+ $$bindings?: ReturnType<() => "">;
69
+ } & {};
70
+ };
71
+ Panel: {
72
+ (internal: unknown, props: import("../index.js").PanelProps<T>): {};
73
+ new (options: import("svelte").ComponentConstructorOptions<import("../index.js").PanelProps<T>>): SvelteComponent<import("../index.js").PanelProps<T>, {}, {}> & {
74
+ $$bindings?: ReturnType<() => "">;
75
+ };
76
+ z_$$bindings?: ReturnType<() => "">;
77
+ };
78
+ Expandable: {
79
+ (internal: unknown, props: import("../index.js").ExpandableProps<T>): {};
80
+ new (options: import("svelte").ComponentConstructorOptions<import("../index.js").ExpandableProps<T>>): SvelteComponent<import("../index.js").ExpandableProps<T>, {}, {}> & {
81
+ $$bindings?: ReturnType<() => "">;
82
+ };
83
+ z_$$bindings?: ReturnType<() => "">;
84
+ };
85
+ Row: {
86
+ (internal: unknown, props: import("../index.js").RowProps<T>): {};
87
+ new (options: import("svelte").ComponentConstructorOptions<import("../index.js").RowProps<T>>): SvelteComponent<import("../index.js").RowProps<T>, {}, {}> & {
88
+ $$bindings?: ReturnType<() => "">;
89
+ };
90
+ z_$$bindings?: ReturnType<() => "">;
91
+ };
92
+ readonly table: TableState<T>;
93
+ }]> | undefined;
94
+ };
95
+ events(): {};
96
+ slots(): {};
97
+ bindings(): "selected" | "panel" | "data";
98
+ exports(): {
99
+ toCSV: (opts?: {
100
+ /** Semi-colons as separator? */
101
+ semicolon?: boolean;
102
+ /** Only selected rows */
103
+ selected?: boolean;
104
+ }) => Promise<string>;
105
+ };
106
+ }
107
+ interface $$IsomorphicComponent {
108
+ 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']>> & {
109
+ $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
110
+ } & ReturnType<__sveltets_Render<T>['exports']>;
111
+ <T extends Record<PropertyKey, unknown>>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
112
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
113
+ }
114
+ /**
115
+ * This is a description, \
116
+ * on how to use this.
117
+ *
118
+ * @example
119
+ * <Component />
120
+ */
121
+ declare const Table: $$IsomorphicComponent;
122
+ type Table<T extends Record<PropertyKey, unknown>> = InstanceType<typeof Table<T>>;
123
+ export default Table;
@@ -0,0 +1,14 @@
1
+ import type { TableProps, TableState } from './table-state.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,107 @@
1
+ import { type Snippet } from 'svelte';
2
+ import { ColumnState, type RowColumnCtx } from '../column/column-state.svelte.js';
3
+ import { PanelState } from '../panel/panel-state.svelte.js';
4
+ import { Data } from './data.svelte.js';
5
+ import { type AnyRecord } from '../utility.svelte.js';
6
+ import type { ExpandableState } from '../expandable/expandable-state.svelte.js';
7
+ import type { ItemState } from 'runic-reorder';
8
+ import type { RowState } from '../row/row-state.svelte.js';
9
+ export type HeaderSelectCtx<T extends AnyRecord = any> = {
10
+ isSelected: boolean;
11
+ /** The list of selected items */
12
+ readonly selected: T[];
13
+ /**
14
+ * See [MDN :indeterminate](https://developer.mozilla.org/en-US/docs/Web/CSS/:indeterminate)
15
+ */
16
+ readonly indeterminate: boolean;
17
+ };
18
+ export type RowSelectCtx<T extends AnyRecord = any> = {
19
+ readonly item: T;
20
+ readonly row: RowColumnCtx<T, unknown>;
21
+ data: T[];
22
+ isSelected: boolean;
23
+ };
24
+ export interface RowCtx<T extends AnyRecord> {
25
+ readonly rowHovered: boolean;
26
+ readonly index: number;
27
+ readonly itemState: ItemState<T> | undefined;
28
+ selected: boolean;
29
+ expanded: boolean;
30
+ }
31
+ type SelectOptions<T extends AnyRecord> = {
32
+ /**
33
+ * The style, in which the selection is shown
34
+ *
35
+ * NOTE: If using `edge` | 'side', "show" will always be `hover`. This is due to
36
+ * an inconsistency/limitation of matching the scroll between the selection div and the rows.
37
+ *
38
+ * @default 'column'
39
+ */
40
+ style?: 'column';
41
+ /**
42
+ * When to show the row-select, when not selected?
43
+ * @default 'hover'
44
+ */
45
+ show?: 'hover' | 'always' | 'never';
46
+ /**
47
+ * Custom snippet
48
+ */
49
+ headerSnippet?: Snippet<[context: HeaderSelectCtx]>;
50
+ rowSnippet?: Snippet<[context: RowSelectCtx<T>]>;
51
+ };
52
+ export type TableProps<T extends AnyRecord> = {
53
+ id?: string;
54
+ data: T[];
55
+ selected?: T[];
56
+ /** Current visible panel */
57
+ panel?: string;
58
+ filters?: ((item: T) => boolean)[];
59
+ /**
60
+ * **For a reorderable table, the data is mutated when reordered.**
61
+ *
62
+ * Reorderable tables cannot
63
+ * - Be filtered
64
+ * - Be sorted
65
+ * @default false
66
+ */
67
+ reorderable?: boolean;
68
+ /** Whether columns in this table can be resized */
69
+ resizeable?: boolean;
70
+ /** Whether to enable selection */
71
+ select?: boolean | SelectOptions<T>;
72
+ /** Create missing columns automatically. */
73
+ auto?: boolean;
74
+ };
75
+ export declare class TableState<T extends AnyRecord> {
76
+ #private;
77
+ id: string;
78
+ dataState: Data<T>;
79
+ data: T[];
80
+ columns: Record<string, ColumnState<T, any>>;
81
+ panels: Record<string, PanelState<T>>;
82
+ expandable: undefined | ExpandableState<T>;
83
+ row: undefined | RowState<T>;
84
+ /** Currently selected items */
85
+ get selected(): T[];
86
+ set selected(items: T[]);
87
+ /** Column positions based on column ids */
88
+ positions: {
89
+ fixed: ColumnState<T, any>[];
90
+ sticky: ColumnState<T, any>[];
91
+ scroll: ColumnState<T, any>[];
92
+ hidden: ColumnState<T, any>[];
93
+ };
94
+ /** Primarily externally managed options */
95
+ options: {
96
+ panel: string | undefined;
97
+ filters: boolean | ((item: T) => boolean)[];
98
+ resizeable: boolean;
99
+ reorderable: boolean;
100
+ select: boolean | SelectOptions<T>;
101
+ auto: boolean;
102
+ };
103
+ add(state: ColumnState<T, any> | PanelState<T>): (() => void) | undefined;
104
+ static getContext<T extends AnyRecord>(): TableState<T> | undefined;
105
+ constructor(tableProps: TableProps<T>);
106
+ }
107
+ export {};
@@ -0,0 +1,76 @@
1
+ import { getContext, setContext } from 'svelte';
2
+ import { ColumnState } from '../column/column-state.svelte.js';
3
+ import { PanelState } from '../panel/panel-state.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-state.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,24 @@
1
+ import { Snippet } from 'svelte';
2
+ export type Simplify<T> = T extends infer V ? {
3
+ [K in keyof V]: V[K];
4
+ } : never;
5
+ export type AnyRecord = Record<PropertyKey, any>;
6
+ export declare function pick<T extends Record<PropertyKey, any>, K extends (keyof T)[]>(item: T, keys: K): Simplify<Pick<T, K[number]>>;
7
+ export declare function boundPick<T extends Record<PropertyKey, any>, K extends (keyof T)[]>(item: T, keys: K): {};
8
+ export declare function assign(item: Record<PropertyKey, any>, props?: Partial<Record<PropertyKey, any>>): void;
9
+ export declare function boundAssign(item: Record<PropertyKey, any>, props?: Partial<Record<PropertyKey, any>>): void;
10
+ export declare function mounted(): {
11
+ readonly isMounted: boolean;
12
+ };
13
+ export declare function getters<T extends AnyRecord>(obj: T): { readonly [K in keyof T]: T[K]; };
14
+ type SetterRecord = Record<PropertyKey, [() => any, (v: any) => void]>;
15
+ export declare function withSetters<T extends SetterRecord>(obj: T): T;
16
+ 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]; }>;
17
+ export declare function assignDescriptors<T extends AnyRecord, B extends AnyRecord>(target: T, source: B): T & B;
18
+ /** Capitalize by space */
19
+ export declare function capitalize(str: string): string;
20
+ /** Split words when going from lower case to uppercase; `someWords-split` -> `some Word Split...` */
21
+ export declare function segmentize(str: string): string;
22
+ type SnippetLiteralProperties<K extends unknown[], Result extends (() => unknown)[] = []> = K extends [infer First, ...infer Rest] ? SnippetLiteralProperties<Rest, [...Result, () => First]> : Result;
23
+ export declare function snippetLiteral<K extends unknown[]>(snippet: Snippet<K>): ((anchor: Comment, ...args: SnippetLiteralProperties<K>) => ReturnType<typeof snippet>);
24
+ export {};
@@ -0,0 +1,107 @@
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
+ }
105
+ export function snippetLiteral(snippet) {
106
+ return snippet;
107
+ }