@ims360/svelte-ivory 0.0.4 → 0.0.7
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 +7 -0
- package/dist/components/ai/AiMessage.svelte.d.ts +1 -0
- package/dist/components/ai/AiMessage.svelte.d.ts.map +1 -0
- package/dist/components/ai/AttachedFile.svelte.d.ts +1 -0
- package/dist/components/ai/AttachedFile.svelte.d.ts.map +1 -0
- package/dist/components/ai/Chat.svelte.d.ts +1 -0
- package/dist/components/ai/Chat.svelte.d.ts.map +1 -0
- package/dist/components/ai/Markdown.svelte.d.ts +1 -0
- package/dist/components/ai/Markdown.svelte.d.ts.map +1 -0
- package/dist/components/ai/UserMessage.svelte.d.ts +1 -0
- package/dist/components/ai/UserMessage.svelte.d.ts.map +1 -0
- package/dist/components/ai/index.d.ts +1 -0
- package/dist/components/ai/index.d.ts.map +1 -0
- package/dist/components/basic/checkbox/Checkbox.svelte.d.ts +1 -0
- package/dist/components/basic/checkbox/Checkbox.svelte.d.ts.map +1 -0
- package/dist/components/basic/index.d.ts +1 -0
- package/dist/components/basic/index.d.ts.map +1 -0
- package/dist/components/basic/toggle/Toggle.svelte +5 -3
- package/dist/components/basic/toggle/Toggle.svelte.d.ts +1 -0
- package/dist/components/basic/toggle/Toggle.svelte.d.ts.map +1 -0
- package/dist/components/buttons/CopyToClipboardButton.svelte.d.ts +1 -0
- package/dist/components/buttons/CopyToClipboardButton.svelte.d.ts.map +1 -0
- package/dist/components/layout/drawer/Drawer.svelte.d.ts +1 -0
- package/dist/components/layout/drawer/Drawer.svelte.d.ts.map +1 -0
- package/dist/components/layout/heading/Heading.svelte +1 -1
- package/dist/components/layout/heading/Heading.svelte.d.ts +1 -0
- package/dist/components/layout/heading/Heading.svelte.d.ts.map +1 -0
- package/dist/components/layout/heading/index.d.ts +1 -0
- package/dist/components/layout/heading/index.d.ts.map +1 -0
- package/dist/components/layout/hiddenBackground/HiddenBackground.svelte +3 -3
- package/dist/components/layout/hiddenBackground/HiddenBackground.svelte.d.ts +2 -1
- package/dist/components/layout/hiddenBackground/HiddenBackground.svelte.d.ts.map +1 -0
- package/dist/components/layout/hiddenBackground/index.d.ts +7 -0
- package/dist/components/layout/hiddenBackground/index.d.ts.map +1 -0
- package/dist/components/layout/index.d.ts +2 -1
- package/dist/components/layout/index.d.ts.map +1 -0
- package/dist/components/layout/modal/Modal.svelte +60 -48
- package/dist/components/layout/modal/Modal.svelte.d.ts +1 -0
- package/dist/components/layout/modal/Modal.svelte.d.ts.map +1 -0
- package/dist/components/layout/modal/ModalTest.svelte.d.ts +1 -0
- package/dist/components/layout/modal/ModalTest.svelte.d.ts.map +1 -0
- package/dist/components/layout/popover/Popover.svelte.d.ts +1 -0
- package/dist/components/layout/popover/Popover.svelte.d.ts.map +1 -0
- package/dist/components/layout/portal/Portal.svelte.d.ts +1 -0
- package/dist/components/layout/portal/Portal.svelte.d.ts.map +1 -0
- package/dist/components/layout/tabs/Tab.svelte +3 -3
- package/dist/components/layout/tabs/Tab.svelte.d.ts +2 -1
- package/dist/components/layout/tabs/Tab.svelte.d.ts.map +1 -0
- package/dist/components/layout/tabs/TabPanel.svelte.d.ts +1 -0
- package/dist/components/layout/tabs/TabPanel.svelte.d.ts.map +1 -0
- package/dist/components/layout/tabs/Tabs.svelte.d.ts +1 -0
- package/dist/components/layout/tabs/Tabs.svelte.d.ts.map +1 -0
- package/dist/components/layout/tabs/index.d.ts +2 -1
- package/dist/components/layout/tabs/index.d.ts.map +1 -0
- package/dist/components/layout/tooltip/Tooltip.svelte +12 -11
- package/dist/components/layout/tooltip/Tooltip.svelte.d.ts +1 -0
- package/dist/components/layout/tooltip/Tooltip.svelte.d.ts.map +1 -0
- package/dist/components/table/index.d.ts +6 -0
- package/dist/components/table/index.d.ts.map +1 -0
- package/dist/components/table/index.js +5 -0
- package/dist/components/table/plugins/expandAll.svelte.d.ts +7 -0
- package/dist/components/table/plugins/expandAll.svelte.d.ts.map +1 -0
- package/dist/components/table/plugins/expandAll.svelte.js +24 -0
- package/dist/components/table/plugins/search.svelte.d.ts +13 -0
- package/dist/components/table/plugins/search.svelte.d.ts.map +1 -0
- package/dist/components/table/plugins/search.svelte.js +52 -0
- package/dist/components/table/table/Column.svelte +78 -0
- package/dist/components/table/table/Column.svelte.d.ts +16 -0
- package/dist/components/table/table/Column.svelte.d.ts.map +1 -0
- package/dist/components/table/table/ColumnHead.svelte +73 -0
- package/dist/components/table/table/ColumnHead.svelte.d.ts +11 -0
- package/dist/components/table/table/ColumnHead.svelte.d.ts.map +1 -0
- package/dist/components/table/table/Row.svelte +67 -0
- package/dist/components/table/table/Row.svelte.d.ts +13 -0
- package/dist/components/table/table/Row.svelte.d.ts.map +1 -0
- package/dist/components/table/table/Table.svelte +137 -0
- package/dist/components/table/table/Table.svelte.d.ts +52 -0
- package/dist/components/table/table/Table.svelte.d.ts.map +1 -0
- package/dist/components/table/table/VirtualList.svelte +101 -0
- package/dist/components/table/table/VirtualList.svelte.d.ts +41 -0
- package/dist/components/table/table/VirtualList.svelte.d.ts.map +1 -0
- package/dist/components/table/table/column.svelte.d.ts +21 -0
- package/dist/components/table/table/column.svelte.d.ts.map +1 -0
- package/dist/components/table/table/column.svelte.js +47 -0
- package/dist/components/table/table/index.js +11 -0
- package/dist/components/table/table/table.svelte.d.ts +36 -0
- package/dist/components/table/table/table.svelte.d.ts.map +1 -0
- package/dist/components/table/table/table.svelte.js +92 -0
- package/dist/components/toast/Toast.svelte.d.ts +1 -0
- package/dist/components/toast/Toast.svelte.d.ts.map +1 -0
- package/dist/components/toast/index.d.ts +1 -0
- package/dist/components/toast/index.d.ts.map +1 -0
- package/dist/components/toast/toasts.svelte.d.ts +1 -0
- package/dist/components/toast/toasts.svelte.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/utils/actions/clickOutside.d.ts +1 -0
- package/dist/utils/actions/clickOutside.d.ts.map +1 -0
- package/dist/utils/actions/focusTrap.d.ts +1 -0
- package/dist/utils/actions/focusTrap.d.ts.map +1 -0
- package/dist/utils/actions/index.d.ts +2 -0
- package/dist/utils/actions/index.d.ts.map +1 -0
- package/dist/utils/actions/index.js +1 -0
- package/dist/utils/actions/portal.d.ts +1 -0
- package/dist/utils/actions/portal.d.ts.map +1 -0
- package/dist/utils/actions/resize.d.ts +6 -0
- package/dist/utils/actions/resize.d.ts.map +1 -0
- package/dist/utils/actions/resize.js +25 -0
- package/dist/utils/actions/shortcut.d.ts +1 -0
- package/dist/utils/actions/shortcut.d.ts.map +1 -0
- package/dist/utils/actions/visible.d.ts +1 -0
- package/dist/utils/actions/visible.d.ts.map +1 -0
- package/dist/utils/functions/cookie.d.ts +1 -0
- package/dist/utils/functions/cookie.d.ts.map +1 -0
- package/dist/utils/functions/index.d.ts +1 -0
- package/dist/utils/functions/index.d.ts.map +1 -0
- package/dist/utils/functions/pseudoRandomId.d.ts +1 -0
- package/dist/utils/functions/pseudoRandomId.d.ts.map +1 -0
- package/dist/utils/functions/queryParams.d.ts +1 -0
- package/dist/utils/functions/queryParams.d.ts.map +1 -0
- package/package.json +9 -2
- package/src/lib/components/basic/toggle/Toggle.svelte +5 -3
- package/src/lib/components/layout/heading/Heading.svelte +1 -1
- package/src/lib/components/layout/hiddenBackground/HiddenBackground.svelte +3 -3
- package/src/lib/components/layout/index.ts +1 -1
- package/src/lib/components/layout/modal/Modal.svelte +60 -48
- package/src/lib/components/layout/tabs/Tab.svelte +3 -3
- package/src/lib/components/layout/tooltip/Tooltip.svelte +12 -11
- package/src/lib/components/table/index.ts +5 -0
- package/src/lib/components/table/plugins/expandAll.svelte.ts +34 -0
- package/src/lib/components/table/plugins/search.svelte.ts +75 -0
- package/src/lib/components/table/table/Column.svelte +78 -0
- package/src/lib/components/table/table/ColumnHead.svelte +73 -0
- package/src/lib/components/table/table/Row.svelte +67 -0
- package/src/lib/components/table/table/Table.svelte +137 -0
- package/src/lib/components/table/table/VirtualList.svelte +101 -0
- package/src/lib/components/table/table/column.svelte.ts +59 -0
- package/src/lib/components/table/table/index.ts +15 -0
- package/src/lib/components/table/table/table.svelte.ts +124 -0
- package/src/lib/utils/actions/index.ts +1 -0
- package/src/lib/utils/actions/resize.ts +35 -0
- package/dist/components/index.d.ts +0 -0
- package/dist/components/index.js +0 -1
- package/src/lib/components/basic/checkbox/checkbox.svelte.spec.ts +0 -39
- package/src/lib/components/basic/toggle/toggle.svelte.spec.ts +0 -19
- package/src/lib/components/index.ts +0 -0
- package/src/lib/components/layout/modal/modal.svelte.spec.ts +0 -39
- package/src/lib/components/layout/tabs/Tabs.test.svelte +0 -5
- package/src/lib/utils/actions/clickOutside.svelte.spec.ts +0 -67
- package/src/lib/utils/actions/shortcut.svelte.spec.ts +0 -19
- package/src/lib/utils/functions/cookie.svelte.spec.ts +0 -55
- package/src/lib/utils/functions/pseudoRandomId.spec.ts +0 -19
- package/src/lib/utils/functions/queryParams.spec.ts +0 -25
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
<script lang="ts" generics="T extends { id: string }">
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
import { onMount, type Snippet } from 'svelte';
|
|
4
|
+
import type { ClassValue } from 'svelte/elements';
|
|
5
|
+
import { twMerge } from 'tailwind-merge';
|
|
6
|
+
|
|
7
|
+
type Props<T> = {
|
|
8
|
+
class?: ClassValue;
|
|
9
|
+
data: T[];
|
|
10
|
+
children: Snippet<[{ row: T; domIndex: number; index: number }]>;
|
|
11
|
+
header?: Snippet;
|
|
12
|
+
b_scrollTop?: number;
|
|
13
|
+
rowHeight: number;
|
|
14
|
+
overscan?: number;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
let {
|
|
18
|
+
class: clazz,
|
|
19
|
+
data,
|
|
20
|
+
children,
|
|
21
|
+
header,
|
|
22
|
+
b_scrollTop = $bindable(0),
|
|
23
|
+
rowHeight,
|
|
24
|
+
overscan = 2
|
|
25
|
+
}: Props<T> = $props();
|
|
26
|
+
|
|
27
|
+
let scroll_top = $state(b_scrollTop);
|
|
28
|
+
let scroll_left = $state(0);
|
|
29
|
+
let header_width = $state(0);
|
|
30
|
+
let viewport = $state<HTMLElement>();
|
|
31
|
+
let viewport_height = $state(0);
|
|
32
|
+
|
|
33
|
+
const start = $derived(Math.max(0, Math.floor(scroll_top / rowHeight) - overscan));
|
|
34
|
+
|
|
35
|
+
const end = $derived(
|
|
36
|
+
Math.min(data.length, Math.ceil((scroll_top + viewport_height) / rowHeight) + overscan)
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const visible = $derived(
|
|
40
|
+
data.slice(start, end).map((data, i) => {
|
|
41
|
+
return { index: i + start, data };
|
|
42
|
+
})
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const top = $derived(start * rowHeight);
|
|
46
|
+
const bottom = $derived((data.length - end) * rowHeight);
|
|
47
|
+
|
|
48
|
+
function onscroll() {
|
|
49
|
+
if (!viewport) return;
|
|
50
|
+
scroll_top = viewport.scrollTop;
|
|
51
|
+
scroll_left = viewport.scrollLeft;
|
|
52
|
+
b_scrollTop = scroll_top;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
onMount(() => {
|
|
56
|
+
if (!viewport) return;
|
|
57
|
+
viewport.scrollTop = b_scrollTop;
|
|
58
|
+
});
|
|
59
|
+
</script>
|
|
60
|
+
|
|
61
|
+
<div
|
|
62
|
+
class={twMerge(
|
|
63
|
+
clsx(['scroll relative flex grow flex-col overflow-hidden border-inherit', clazz])
|
|
64
|
+
)}
|
|
65
|
+
>
|
|
66
|
+
{#if header}
|
|
67
|
+
<div class="h-fit w-full border-inherit">
|
|
68
|
+
<div
|
|
69
|
+
class="w-fit min-w-full border-inherit"
|
|
70
|
+
style="transform: translateX(-{scroll_left}px);"
|
|
71
|
+
bind:clientWidth={header_width}
|
|
72
|
+
>
|
|
73
|
+
{@render header?.()}
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
{/if}
|
|
77
|
+
<div
|
|
78
|
+
class="flex !min-w-full grow overflow-auto [scrollbar-gutter:stable]"
|
|
79
|
+
bind:this={viewport}
|
|
80
|
+
bind:offsetHeight={viewport_height}
|
|
81
|
+
{onscroll}
|
|
82
|
+
>
|
|
83
|
+
<div
|
|
84
|
+
class="flex h-fit shrink-0 flex-col"
|
|
85
|
+
style="padding-top: {top}px; padding-bottom: {bottom}px; min-width: max(100%, {header_width}px) !important;"
|
|
86
|
+
>
|
|
87
|
+
{#each visible as row, i (row.data.id)}
|
|
88
|
+
<virtual-list-row
|
|
89
|
+
class="flex w-full shrink-0 grow flex-row items-center overflow-hidden"
|
|
90
|
+
style="height: {rowHeight}px !important;"
|
|
91
|
+
>
|
|
92
|
+
{@render children({
|
|
93
|
+
row: row.data,
|
|
94
|
+
domIndex: i,
|
|
95
|
+
index: row.index
|
|
96
|
+
})}
|
|
97
|
+
</virtual-list-row>
|
|
98
|
+
{/each}
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
|
|
3
|
+
const DEFAULT_WIDTH = 250;
|
|
4
|
+
const MINIMAL_WIDTH_MULTIPLIER = 0.5;
|
|
5
|
+
|
|
6
|
+
export interface ColumnConfig {
|
|
7
|
+
id: string;
|
|
8
|
+
width?: number;
|
|
9
|
+
minWidth?: number;
|
|
10
|
+
resizable?: boolean;
|
|
11
|
+
header: Snippet | string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class Column {
|
|
15
|
+
id = $state('');
|
|
16
|
+
header = $state<Snippet | string>('');
|
|
17
|
+
|
|
18
|
+
// resizing
|
|
19
|
+
width = $state<number>();
|
|
20
|
+
private minimalWidth = $state(DEFAULT_WIDTH);
|
|
21
|
+
hovering = $state(false);
|
|
22
|
+
resizable = $state(false);
|
|
23
|
+
dragging = $state(false);
|
|
24
|
+
|
|
25
|
+
constructor(conf: ColumnConfig) {
|
|
26
|
+
this.id = conf.id;
|
|
27
|
+
this.updateConfig(conf);
|
|
28
|
+
|
|
29
|
+
$effect(() => {
|
|
30
|
+
this.updateConfig(conf);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
updateConfig(conf: ColumnConfig) {
|
|
35
|
+
if (conf.minWidth !== undefined) {
|
|
36
|
+
this.minimalWidth = conf.minWidth;
|
|
37
|
+
} else {
|
|
38
|
+
this.minimalWidth = (conf.width ?? DEFAULT_WIDTH) * MINIMAL_WIDTH_MULTIPLIER;
|
|
39
|
+
}
|
|
40
|
+
if (this.width === undefined) {
|
|
41
|
+
const newWidth = conf.width ?? DEFAULT_WIDTH;
|
|
42
|
+
this.width = newWidth;
|
|
43
|
+
}
|
|
44
|
+
if (!this.header) this.header = conf.header;
|
|
45
|
+
const newResizable = conf.resizable ?? false;
|
|
46
|
+
if (newResizable !== this.resizable) {
|
|
47
|
+
this.resizable = newResizable;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
resize(newWidth?: number) {
|
|
52
|
+
if (newWidth === undefined) return;
|
|
53
|
+
if (newWidth < this.minimalWidth) {
|
|
54
|
+
this.width = this.minimalWidth;
|
|
55
|
+
} else {
|
|
56
|
+
this.width = newWidth;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import Column from './Column.svelte';
|
|
2
|
+
import Row from './Row.svelte';
|
|
3
|
+
import TableComponent, { getTableContext } from './Table.svelte';
|
|
4
|
+
import { TableController } from './table.svelte';
|
|
5
|
+
|
|
6
|
+
const Table = Object.assign(
|
|
7
|
+
TableComponent<{ id: string }> as typeof TableComponent<{ id: string }>,
|
|
8
|
+
{
|
|
9
|
+
Column,
|
|
10
|
+
Row,
|
|
11
|
+
getContext: getTableContext,
|
|
12
|
+
Controller: TableController
|
|
13
|
+
}
|
|
14
|
+
);
|
|
15
|
+
export default Table;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { SvelteSet } from 'svelte/reactivity';
|
|
2
|
+
import { Column, type ColumnConfig } from './column.svelte';
|
|
3
|
+
|
|
4
|
+
export type TableRow<T> = { id: string; children?: T[] };
|
|
5
|
+
export type TablePlugin<T extends TableRow<T>> = (state: TableState<T>) => TableState<T>;
|
|
6
|
+
|
|
7
|
+
export interface TableConfig<T extends TableRow<T>> {
|
|
8
|
+
data: T[];
|
|
9
|
+
plugins?: TablePlugin<T>[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface TableState<T extends TableRow<T>> {
|
|
13
|
+
data: T[];
|
|
14
|
+
expanded: Set<string>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface TreeRow<T> {
|
|
18
|
+
node: T;
|
|
19
|
+
nestingLevel: number;
|
|
20
|
+
id: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class TableController<T extends TableRow<T>> {
|
|
24
|
+
columns = $state<Column[]>([]);
|
|
25
|
+
data = $state<T[]>([]);
|
|
26
|
+
expanded: Set<string> = new SvelteSet<string>();
|
|
27
|
+
scrollTop = $state(0);
|
|
28
|
+
|
|
29
|
+
readonly results = $derived(treeWalker(this.data, this.expanded));
|
|
30
|
+
|
|
31
|
+
refresh(conf: TableConfig<T>) {
|
|
32
|
+
let intitalState: TableState<T> = {
|
|
33
|
+
data: structuredClone(conf.data),
|
|
34
|
+
expanded: this.expanded
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
for (const plugin of conf.plugins ?? []) {
|
|
38
|
+
intitalState = plugin(intitalState);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
this.data = intitalState.data;
|
|
42
|
+
this.expanded = new SvelteSet(intitalState.expanded);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
registerColumn(config: ColumnConfig): Column {
|
|
46
|
+
// only register a column once
|
|
47
|
+
let existingColumn: Column | undefined = undefined;
|
|
48
|
+
for (const column of this.columns) {
|
|
49
|
+
if (column.id !== config.id) continue;
|
|
50
|
+
existingColumn = column;
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
if (existingColumn) return existingColumn;
|
|
54
|
+
const col = new Column(config);
|
|
55
|
+
this.columns.push(col);
|
|
56
|
+
return col;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
toggleExpansion(id: string) {
|
|
60
|
+
if (this.expanded.has(id)) this.expanded.delete(id);
|
|
61
|
+
else this.expanded.add(id);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Walks though a tree strucure and turns it into a flat list, needed since the `VirtualList` needs a list, not a tree */
|
|
66
|
+
function treeWalker<T extends TableRow<T>>(data: T[], expanded: Set<string>) {
|
|
67
|
+
const stack: { node: T; nestingLevel: number }[] = [];
|
|
68
|
+
|
|
69
|
+
// push the root nodes of the trees onto the stack
|
|
70
|
+
for (let i = 0; i < data.length; i++) {
|
|
71
|
+
stack.push({
|
|
72
|
+
node: data[data.length - i - 1],
|
|
73
|
+
nestingLevel: 0
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const entries: TreeRow<T>[] = []; // the final result
|
|
78
|
+
|
|
79
|
+
let someHaveChildren = false; // used to determine whether to show the tree utility buttons
|
|
80
|
+
let maxNestingLevel = 0;
|
|
81
|
+
while (stack.length !== 0) {
|
|
82
|
+
const stackEntry = stack.pop();
|
|
83
|
+
if (!stackEntry) break;
|
|
84
|
+
|
|
85
|
+
const { node, nestingLevel } = stackEntry;
|
|
86
|
+
const children = node.children;
|
|
87
|
+
|
|
88
|
+
if (children && children.length > 0) {
|
|
89
|
+
someHaveChildren = true;
|
|
90
|
+
// only show the children of expanded elements
|
|
91
|
+
if (expanded.has(node.id)) {
|
|
92
|
+
maxNestingLevel = Math.max(maxNestingLevel, nestingLevel + 1);
|
|
93
|
+
stack.push(
|
|
94
|
+
...children
|
|
95
|
+
.map((c) => ({
|
|
96
|
+
node: c,
|
|
97
|
+
nestingLevel: nestingLevel + 1
|
|
98
|
+
}))
|
|
99
|
+
.reverse()
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
entries.push({
|
|
105
|
+
id: node.id,
|
|
106
|
+
node,
|
|
107
|
+
nestingLevel
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
entries,
|
|
113
|
+
someHaveChildren,
|
|
114
|
+
maxNestingLevel
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function getAllIds<T extends TableRow<T>>(...nodes: T[]): string[] {
|
|
119
|
+
const ids = nodes.map((n) => n.id);
|
|
120
|
+
for (const node of nodes) {
|
|
121
|
+
ids.push(...getAllIds(...(node.children ?? [])));
|
|
122
|
+
}
|
|
123
|
+
return ids;
|
|
124
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Action } from 'svelte/action';
|
|
2
|
+
|
|
3
|
+
export const resize: Action<
|
|
4
|
+
HTMLElement,
|
|
5
|
+
{ resized: (mouseX: number) => void; dragging: (dragging: boolean) => void }
|
|
6
|
+
> = (node: HTMLElement, { resized, dragging }) => {
|
|
7
|
+
const onResize = (e: PointerEvent) => {
|
|
8
|
+
resized(e.clientX);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const onResizeEnd = () => {
|
|
12
|
+
dragging(false);
|
|
13
|
+
window.removeEventListener('pointermove', onResize);
|
|
14
|
+
window.removeEventListener('pointerup', onResizeEnd);
|
|
15
|
+
window.removeEventListener('pointercancel', onResizeEnd);
|
|
16
|
+
|
|
17
|
+
document.getElementsByTagName('html')[0].style.userSelect = '';
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const onResizeStart = () => {
|
|
21
|
+
dragging(true);
|
|
22
|
+
window.addEventListener('pointermove', onResize);
|
|
23
|
+
window.addEventListener('pointerup', onResizeEnd);
|
|
24
|
+
window.addEventListener('pointercancel', onResizeEnd);
|
|
25
|
+
|
|
26
|
+
document.getElementsByTagName('html')[0].style.userSelect = 'none';
|
|
27
|
+
};
|
|
28
|
+
node.addEventListener('pointerdown', onResizeStart);
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
destroy() {
|
|
32
|
+
node.removeEventListener('pointerdown', onResizeStart);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
};
|
|
File without changes
|
package/dist/components/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import '@testing-library/jest-dom/vitest';
|
|
2
|
-
import { render, screen } from '@testing-library/svelte';
|
|
3
|
-
import { userEvent } from '@testing-library/user-event';
|
|
4
|
-
import { fn } from '@vitest/spy';
|
|
5
|
-
import { describe, expect, it } from 'vitest';
|
|
6
|
-
import { Checkbox } from '../index';
|
|
7
|
-
|
|
8
|
-
const testId = 'checkbox';
|
|
9
|
-
|
|
10
|
-
describe('Basic/Checkbox', () => {
|
|
11
|
-
it('renders the checked icon', async () => {
|
|
12
|
-
render(Checkbox, { testId, checked: true });
|
|
13
|
-
|
|
14
|
-
const checkbox = screen.getByTestId(testId);
|
|
15
|
-
expect(checkbox).toBeVisible();
|
|
16
|
-
const icon = checkbox.querySelector('svg');
|
|
17
|
-
expect(icon).toBeVisible();
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('fires click event when clicked', async () => {
|
|
21
|
-
const callback = fn();
|
|
22
|
-
render(Checkbox, { testId, onclick: callback });
|
|
23
|
-
|
|
24
|
-
const checkbox = screen.getByTestId(testId);
|
|
25
|
-
expect(checkbox).toBeVisible();
|
|
26
|
-
checkbox.click();
|
|
27
|
-
expect(callback).toHaveBeenCalledOnce();
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it("doesn't fire click event when disabled", async () => {
|
|
31
|
-
const callback = fn();
|
|
32
|
-
render(Checkbox, { testId, onclick: callback, disabled: true });
|
|
33
|
-
|
|
34
|
-
const checkbox = screen.getByTestId(testId);
|
|
35
|
-
expect(checkbox).toBeVisible();
|
|
36
|
-
await userEvent.click(checkbox);
|
|
37
|
-
expect(callback).not.toHaveBeenCalled();
|
|
38
|
-
});
|
|
39
|
-
});
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import '@testing-library/jest-dom/vitest';
|
|
2
|
-
import { render, screen } from '@testing-library/svelte';
|
|
3
|
-
import { fn } from '@vitest/spy';
|
|
4
|
-
import { describe, expect, it } from 'vitest';
|
|
5
|
-
import Toggle from './Toggle.svelte';
|
|
6
|
-
|
|
7
|
-
const testId = 'toggle';
|
|
8
|
-
|
|
9
|
-
describe('Basic/Toggle', () => {
|
|
10
|
-
it('fires click event when clicked', async () => {
|
|
11
|
-
const callback = fn();
|
|
12
|
-
render(Toggle, { testId, onclick: callback });
|
|
13
|
-
|
|
14
|
-
const toggle = screen.getByTestId(testId);
|
|
15
|
-
expect(toggle).toBeVisible();
|
|
16
|
-
toggle.click();
|
|
17
|
-
expect(callback).toHaveBeenCalledOnce();
|
|
18
|
-
});
|
|
19
|
-
});
|
|
File without changes
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import '@testing-library/jest-dom/vitest';
|
|
2
|
-
import { render, screen } from '@testing-library/svelte';
|
|
3
|
-
import { createRawSnippet } from 'svelte';
|
|
4
|
-
import { describe, expect, it } from 'vitest';
|
|
5
|
-
import ModalTest from './ModalTest.svelte';
|
|
6
|
-
|
|
7
|
-
const testId = 'modal';
|
|
8
|
-
const contentTestId = 'modal-content';
|
|
9
|
-
|
|
10
|
-
const children = createRawSnippet(() => ({
|
|
11
|
-
render: () => `<p data-testId="${contentTestId}">Content</p>`
|
|
12
|
-
}));
|
|
13
|
-
|
|
14
|
-
describe('Layout/Modal', () => {
|
|
15
|
-
it('renders', async () => {
|
|
16
|
-
render(ModalTest, {
|
|
17
|
-
open: true,
|
|
18
|
-
testId,
|
|
19
|
-
children
|
|
20
|
-
});
|
|
21
|
-
const modal = screen.getByTestId(testId);
|
|
22
|
-
expect(modal).toBeVisible();
|
|
23
|
-
const content = screen.getByTestId(contentTestId);
|
|
24
|
-
expect(content).toBeVisible();
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
// this is bugged for some f'ing reason
|
|
28
|
-
// it('closes when clicking outside', async () => {
|
|
29
|
-
// render(ModalTest, {
|
|
30
|
-
// open: true,
|
|
31
|
-
// testId,
|
|
32
|
-
// children
|
|
33
|
-
// });
|
|
34
|
-
// const modal = screen.getByTestId(testId);
|
|
35
|
-
// const background = screen.getByTestId(HiddenBackground.TEST_ID);
|
|
36
|
-
// await userEvent.click(background!);
|
|
37
|
-
// expect(modal).not.toBeVisible();
|
|
38
|
-
// });
|
|
39
|
-
});
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import '@testing-library/jest-dom/vitest';
|
|
2
|
-
import userEvent from '@testing-library/user-event';
|
|
3
|
-
import { fn } from '@vitest/spy';
|
|
4
|
-
import { describe, expect, it } from 'vitest';
|
|
5
|
-
import { clickOutside } from './clickOutside';
|
|
6
|
-
|
|
7
|
-
describe('clickOutside', () => {
|
|
8
|
-
it('should fire when an element outside the node is clicked', async () => {
|
|
9
|
-
const node = document.createElement('div');
|
|
10
|
-
document.body.appendChild(node);
|
|
11
|
-
const otherNode = document.createElement('div');
|
|
12
|
-
document.body.appendChild(otherNode);
|
|
13
|
-
|
|
14
|
-
const callback = fn();
|
|
15
|
-
clickOutside(node, callback);
|
|
16
|
-
|
|
17
|
-
await userEvent.click(otherNode);
|
|
18
|
-
|
|
19
|
-
expect(callback).toHaveBeenCalledOnce();
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('should not fire when the target is inside the node', async () => {
|
|
23
|
-
const node = document.createElement('div');
|
|
24
|
-
document.body.appendChild(node);
|
|
25
|
-
const nestedNode = node.appendChild(document.createElement('div'));
|
|
26
|
-
const otherNode = document.createElement('div');
|
|
27
|
-
document.body.appendChild(otherNode);
|
|
28
|
-
|
|
29
|
-
const callback = fn();
|
|
30
|
-
clickOutside(node, callback);
|
|
31
|
-
|
|
32
|
-
await userEvent.click(nestedNode);
|
|
33
|
-
|
|
34
|
-
expect(callback).not.toHaveBeenCalled();
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('should fire when the callback is passed in as an object', async () => {
|
|
38
|
-
const node = document.createElement('div');
|
|
39
|
-
document.body.appendChild(node);
|
|
40
|
-
const otherNode = document.createElement('div');
|
|
41
|
-
document.body.appendChild(otherNode);
|
|
42
|
-
|
|
43
|
-
const callback = fn();
|
|
44
|
-
clickOutside(node, { callback });
|
|
45
|
-
|
|
46
|
-
await userEvent.click(otherNode);
|
|
47
|
-
|
|
48
|
-
expect(callback).toHaveBeenCalledOnce();
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('should not fire when the target is inside the passed target', async () => {
|
|
52
|
-
const node = document.createElement('div');
|
|
53
|
-
document.body.appendChild(node);
|
|
54
|
-
|
|
55
|
-
const otherNode = document.createElement('div');
|
|
56
|
-
document.body.appendChild(otherNode);
|
|
57
|
-
const nestedNode = otherNode.appendChild(document.createElement('div'));
|
|
58
|
-
|
|
59
|
-
const callback = fn();
|
|
60
|
-
clickOutside(node, { callback, target: otherNode });
|
|
61
|
-
|
|
62
|
-
await userEvent.click(nestedNode);
|
|
63
|
-
await userEvent.click(otherNode);
|
|
64
|
-
|
|
65
|
-
expect(callback).not.toHaveBeenCalled();
|
|
66
|
-
});
|
|
67
|
-
});
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import '@testing-library/jest-dom/vitest';
|
|
2
|
-
import userEvent from '@testing-library/user-event';
|
|
3
|
-
import { fn } from '@vitest/spy';
|
|
4
|
-
import { describe, expect, it } from 'vitest';
|
|
5
|
-
import { shortcut } from './shortcut';
|
|
6
|
-
|
|
7
|
-
describe('shortcut', () => {
|
|
8
|
-
it('should call the callback when the key is pressed', async () => {
|
|
9
|
-
const node = document.createElement('div');
|
|
10
|
-
const keyCode = 'Enter';
|
|
11
|
-
const callback = fn();
|
|
12
|
-
shortcut(node, {
|
|
13
|
-
callback,
|
|
14
|
-
code: keyCode
|
|
15
|
-
});
|
|
16
|
-
await userEvent.keyboard(`{${keyCode}}`);
|
|
17
|
-
expect(callback).toHaveBeenCalledOnce();
|
|
18
|
-
});
|
|
19
|
-
});
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import '@testing-library/jest-dom/vitest';
|
|
2
|
-
import { describe, expect, it } from 'vitest';
|
|
3
|
-
import { cookie } from './cookie';
|
|
4
|
-
|
|
5
|
-
describe('cookie', () => {
|
|
6
|
-
it('sets correctly', () => {
|
|
7
|
-
const name = 'test';
|
|
8
|
-
const value = 'test';
|
|
9
|
-
const days = 1;
|
|
10
|
-
// this is a hack to get the value back that is actually being set
|
|
11
|
-
const setCookie = cookie.set({ name, value, days });
|
|
12
|
-
expect(setCookie).toBe(
|
|
13
|
-
`${name}=${value}; expires=${new Date(new Date().getTime() + days * 24 * 60 * 60 * 1000).toUTCString()}; path=/`
|
|
14
|
-
);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('gets correctly', () => {
|
|
18
|
-
const name = 'test';
|
|
19
|
-
const value = 'test';
|
|
20
|
-
const days = 1;
|
|
21
|
-
cookie.set({ name, value, days });
|
|
22
|
-
expect(cookie.get(name)).toBe(value);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it("preserves existing cookie's path", () => {
|
|
26
|
-
const cookie1 = {
|
|
27
|
-
name: 'test',
|
|
28
|
-
value: 'test'
|
|
29
|
-
};
|
|
30
|
-
const cookie2 = {
|
|
31
|
-
name: 'test2',
|
|
32
|
-
value: 'test2'
|
|
33
|
-
};
|
|
34
|
-
cookie.set(cookie1);
|
|
35
|
-
cookie.set(cookie2);
|
|
36
|
-
expect(cookie.get(cookie1.name)).toBe(cookie1.value);
|
|
37
|
-
expect(cookie.get(cookie2.name)).toBe(cookie2.value);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('updates cookies correctly', () => {
|
|
41
|
-
const cookie1 = {
|
|
42
|
-
name: 'test',
|
|
43
|
-
value: 'test'
|
|
44
|
-
};
|
|
45
|
-
const cookie2 = {
|
|
46
|
-
name: 'test2',
|
|
47
|
-
value: 'test2'
|
|
48
|
-
};
|
|
49
|
-
cookie.set(cookie1);
|
|
50
|
-
cookie.set(cookie2);
|
|
51
|
-
cookie.set({ name: cookie1.name, value: 'newValue' });
|
|
52
|
-
expect(cookie.get(cookie1.name)).toBe('newValue');
|
|
53
|
-
expect(cookie.get(cookie2.name)).toBe(cookie2.value);
|
|
54
|
-
});
|
|
55
|
-
});
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { pseudoRandomId } from './pseudoRandomId';
|
|
3
|
-
|
|
4
|
-
describe('pseudoRandomId', () => {
|
|
5
|
-
it('generates different values', () => {
|
|
6
|
-
const a = pseudoRandomId();
|
|
7
|
-
const b = pseudoRandomId();
|
|
8
|
-
expect(a).not.toBe(b);
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
it('generates values that start with the prefix', () => {
|
|
12
|
-
const prefix = 'test-';
|
|
13
|
-
const a = pseudoRandomId(prefix);
|
|
14
|
-
const b = pseudoRandomId(prefix);
|
|
15
|
-
expect(a.startsWith(prefix)).toBe(true);
|
|
16
|
-
expect(b.startsWith(prefix)).toBe(true);
|
|
17
|
-
expect(a).not.toBe(b);
|
|
18
|
-
});
|
|
19
|
-
});
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { queryParams } from './queryParams';
|
|
3
|
-
|
|
4
|
-
describe('queryParams', () => {
|
|
5
|
-
it('adds all query params', () => {
|
|
6
|
-
const params = {
|
|
7
|
-
a: 0,
|
|
8
|
-
b: '2',
|
|
9
|
-
c: 3
|
|
10
|
-
};
|
|
11
|
-
const query = queryParams(params);
|
|
12
|
-
expect(query).toBe('?a=0&b=2&c=3');
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it('removes nullish values', () => {
|
|
16
|
-
const params = {
|
|
17
|
-
a: 0,
|
|
18
|
-
b: undefined,
|
|
19
|
-
c: 3,
|
|
20
|
-
d: null
|
|
21
|
-
};
|
|
22
|
-
const query = queryParams(params);
|
|
23
|
-
expect(query).toBe('?a=0&c=3');
|
|
24
|
-
});
|
|
25
|
-
});
|