@warkypublic/svelix 0.1.46 → 0.2.1
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 +93 -33
- package/dist/components/BetterMenu/BetterMenu.svelte +21 -37
- package/dist/components/BetterMenu/BetterMenuAsyncButton.svelte +21 -31
- package/dist/components/BetterMenu/BetterMenuPreview.svelte +27 -29
- package/dist/components/BetterMenu/MenuRenderer.svelte +40 -51
- package/dist/components/Boxer/Boxer.svelte +492 -602
- package/dist/components/Boxer/BoxerTarget.svelte +6 -46
- package/dist/components/Boxer/BoxerTarget.svelte.d.ts +1 -0
- package/dist/components/Boxer/types.d.ts +0 -1
- package/dist/components/Button.svelte +19 -43
- package/dist/components/ButtonPreview.svelte +2 -11
- package/dist/components/CardGrid/CardGrid.svelte +489 -614
- package/dist/components/CardGrid/CardGrid.svelte.d.ts +4 -0
- package/dist/components/CardGrid/CardGridFilterPanel.svelte +111 -90
- package/dist/components/CardGrid/DefaultCard.svelte +86 -97
- package/dist/components/CardGrid/DefaultCard.svelte.d.ts +1 -0
- package/dist/components/CardGrid/ImageCardStory.svelte +87 -36
- package/dist/components/CardGrid/cardGrid.d.ts +24 -0
- package/dist/components/CardGrid/cardGrid.js +20 -0
- package/dist/components/ContentEditor/CollaboraInsertTextDemo.svelte +5 -10
- package/dist/components/ContentEditor/ContentEditor.svelte +24 -50
- package/dist/components/ContentEditor/subcomponents/AudioPlayer.svelte +17 -17
- package/dist/components/ContentEditor/subcomponents/CollaboraEditor.svelte +244 -309
- package/dist/components/ContentEditor/subcomponents/EmailViewer.svelte +2 -3
- package/dist/components/ContentEditor/subcomponents/ImageViewer.svelte +14 -15
- package/dist/components/ContentEditor/subcomponents/MarkdownViewer.svelte +74 -90
- package/dist/components/ContentEditor/subcomponents/MonacoEditor.svelte +75 -103
- package/dist/components/ContentEditor/subcomponents/Office365Editor.svelte +234 -297
- package/dist/components/ContentEditor/subcomponents/PdfViewer.svelte +14 -20
- package/dist/components/ContentEditor/subcomponents/TextEditor.svelte +122 -150
- package/dist/components/ContentEditor/subcomponents/UnknownFile.svelte +105 -126
- package/dist/components/ContentEditor/subcomponents/VideoPlayer.svelte +17 -17
- package/dist/components/ContentEditor/subcomponents/ZipViewer.svelte +2 -3
- package/dist/components/ErrorBoundary/ErrorBoundary.svelte +41 -58
- package/dist/components/ErrorBoundary/ErrorBoundaryPreview.svelte +8 -16
- package/dist/components/Former/Former.svelte +306 -424
- package/dist/components/Former/FormerButtonArea.svelte +17 -68
- package/dist/components/Former/FormerDrawer.svelte +16 -80
- package/dist/components/Former/FormerDrawerPreview.svelte +99 -89
- package/dist/components/Former/FormerModal.svelte +16 -74
- package/dist/components/Former/FormerModalPreview.svelte +99 -89
- package/dist/components/Former/FormerPreview.svelte +76 -78
- package/dist/components/Former/FormerRestApiPreview.svelte +55 -48
- package/dist/components/Former/formerOverlayHelpers.svelte.d.ts +11 -0
- package/dist/components/Former/formerOverlayHelpers.svelte.js +38 -0
- package/dist/components/Former/index.d.ts +1 -0
- package/dist/components/Former/index.js +1 -0
- package/dist/components/FormerControllers/ButtonCtrl.svelte +13 -49
- package/dist/components/FormerControllers/CtrlFieldShell.svelte +15 -0
- package/dist/components/FormerControllers/CtrlFieldShell.svelte.d.ts +12 -0
- package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrl.svelte +285 -457
- package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrlCalendar.svelte +95 -136
- package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrlPickerPanel.svelte +3 -62
- package/dist/components/FormerControllers/DateTimeCtrl/DateTimeCtrlTimeFields.svelte +143 -217
- package/dist/components/FormerControllers/IconButtonCtrl.svelte +13 -47
- package/dist/components/FormerControllers/InlineWrapper.svelte +12 -41
- package/dist/components/FormerControllers/InlineWrapperPreview.svelte +4 -26
- package/dist/components/FormerControllers/NativeSelectCtrl.svelte +7 -39
- package/dist/components/FormerControllers/NumberInputCtrl.svelte +21 -43
- package/dist/components/FormerControllers/PasswordInputCtrl.svelte +8 -33
- package/dist/components/FormerControllers/SwitchCtrl.svelte +4 -20
- package/dist/components/FormerControllers/TextAreaCtrl.svelte +7 -34
- package/dist/components/FormerControllers/TextInputCtrl.svelte +7 -34
- package/dist/components/FormerControllers/ctrlLoading.svelte.d.ts +8 -0
- package/dist/components/FormerControllers/ctrlLoading.svelte.js +43 -0
- package/dist/components/FormerControllers/index.d.ts +2 -0
- package/dist/components/FormerControllers/index.js +2 -0
- package/dist/components/FormerControllers/utils.d.ts +1 -0
- package/dist/components/FormerControllers/utils.js +3 -0
- package/dist/components/GlobalStateStore/GlobalStateStoreProvider.svelte +73 -120
- package/dist/components/Gridler/components/Gridler.svelte +344 -442
- package/dist/components/Gridler/components/GridlerCanvas.svelte +720 -1115
- package/dist/components/Gridler/components/GridlerEditor.svelte +2 -15
- package/dist/components/Gridler/components/GridlerFull.svelte +521 -841
- package/dist/components/Gridler/components/GridlerFull.svelte.d.ts +1 -1
- package/dist/components/Gridler/components/GridlerFullWithFormerPreview.svelte +194 -147
- package/dist/components/Gridler/components/GridlerSearch.svelte +7 -16
- package/dist/components/Gridler/components/GridlerSearchToggle.svelte +7 -19
- package/dist/components/Gridler/types.d.ts +1 -1
- package/dist/components/Gridler/utils/serverPaging.d.ts +1 -0
- package/dist/components/Gridler/utils/serverPaging.js +7 -0
- package/dist/components/Icons/IconAdd.svelte +1 -3
- package/dist/components/Icons/IconAlertCircle.svelte +1 -3
- package/dist/components/Icons/IconAlertTriangle.svelte +1 -3
- package/dist/components/Icons/IconCamera.svelte +1 -3
- package/dist/components/Icons/IconClose.svelte +1 -3
- package/dist/components/Icons/IconEdit.svelte +1 -3
- package/dist/components/Icons/IconFilter.svelte +1 -3
- package/dist/components/Icons/IconSearch.svelte +1 -3
- package/dist/components/Icons/IconSort.svelte +1 -3
- package/dist/components/Icons/IconTrash.svelte +1 -3
- package/dist/components/Portal/Portal.svelte +14 -38
- package/dist/components/Screenshot/Screenshot.svelte +7 -13
- package/dist/components/Svark/Svark.svelte +680 -852
- package/dist/components/Svark/SvarkContextMenu.svelte +44 -63
- package/dist/components/Svark/SvarkInfiniteLoader.svelte +2 -6
- package/dist/components/Svark/SvarkPager.svelte +2 -28
- package/dist/components/Svark/SvarkSelectionDemo.svelte +4 -8
- package/dist/components/Svark/SvarkTopBar.svelte +9 -74
- package/dist/components/SvarkGrid/SvarkGrid.svelte +877 -1123
- package/dist/components/SvarkGrid/components/SvarkColumnFilterForm.svelte +45 -58
- package/dist/components/SvarkGrid/components/SvarkContextMenu.svelte +44 -63
- package/dist/components/SvarkGrid/components/SvarkHeaderFilterCell.svelte +41 -75
- package/dist/components/SvarkGrid/components/SvarkInfiniteLoader.svelte +2 -6
- package/dist/components/SvarkGrid/components/SvarkPager.svelte +2 -28
- package/dist/components/SvarkGrid/components/SvarkSearchPopover.svelte +8 -16
- package/dist/components/SvarkGrid/components/SvarkTopBar.svelte +6 -62
- package/dist/components/SvarkGrid/internal/SvarkGridView.svelte +345 -507
- package/dist/components/VTree/VTree.svelte +454 -431
- package/dist/components/VTree/VTree.utils.d.ts +23 -0
- package/dist/components/VTree/VTree.utils.js +73 -0
- package/dist/components/VTree/VTreeContextMenu.svelte +21 -33
- package/dist/components/VTree/VTreeControlledSelectionDemo.svelte +20 -0
- package/dist/components/VTree/VTreeControlledSelectionDemo.svelte.d.ts +18 -0
- package/dist/components/VTree/VTreeCustomizationDemo.svelte +23 -0
- package/dist/components/VTree/VTreeCustomizationDemo.svelte.d.ts +18 -0
- package/dist/components/VTree/VTreeEventsDemo.svelte +48 -58
- package/dist/components/VTree/VTreeInteractionDemo.svelte +29 -0
- package/dist/components/VTree/VTreeInteractionDemo.svelte.d.ts +18 -0
- package/dist/components/VTree/VTreeMultiSelectDemo.svelte +27 -0
- package/dist/components/VTree/VTreeMultiSelectDemo.svelte.d.ts +18 -0
- package/dist/components/VTree/VTreeRow.svelte +77 -115
- package/dist/components/VTree/VTreeRow.svelte.d.ts +34 -18
- package/dist/components/VTree/VTreeSearch.svelte +6 -13
- package/dist/components/VTree/VTreeVirtualViewport.svelte +54 -143
- package/dist/components/VTree/VTreeVirtualViewport.svelte.d.ts +35 -18
- package/dist/components/VTree/types.d.ts +39 -1
- package/llm/COMPONENT_GUIDE.md +25 -0
- package/package.json +51 -50
|
@@ -1,68 +1,50 @@
|
|
|
1
|
-
<script lang="ts">
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
onrowcontext,
|
|
49
|
-
ontogglerow
|
|
50
|
-
}: Props = $props();
|
|
51
|
-
|
|
52
|
-
const rowClasses = $derived(
|
|
53
|
-
[
|
|
54
|
-
'grid grid-cols-[1fr_auto] items-center select-none border-b border-surface-200-700 hover:bg-surface-100-800',
|
|
55
|
-
isFocused ? 'bg-primary-100 dark:bg-primary-900/35' : '',
|
|
56
|
-
isSelected ? 'bg-primary-200 dark:bg-primary-900/60' : ''
|
|
57
|
-
].join(' ')
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
const sectionArgs = $derived({
|
|
61
|
-
node: row.node,
|
|
62
|
-
level: row.level,
|
|
63
|
-
rowIndex: index,
|
|
64
|
-
treeData: treeDataSnapshot
|
|
65
|
-
});
|
|
1
|
+
<script lang="ts">import { isImageLikeValue, mergeClasses } from "./VTree.utils.js";
|
|
2
|
+
const { row, index, rowHeight, autoMeasure = false, indent, isFocused, isSelected, multiple = false, selectionMode = "modifier", isChecked = false, iconValue, icon, showRowSeparator = true, hoverEffect = true, classes, getNodeLabel, getNodeDescription, treeDataSnapshot, leftSection, rightSection, onselectrow, oncheckboxselect, onrowdoubleclick, onrowcontext, ontogglerow, onrowlongpress, onrowhover, onrowhoverend, longPressDelay = 500, longPressMoveTolerance = 10 } = $props();
|
|
3
|
+
const DEFAULT_CLASSES = {
|
|
4
|
+
row: "grid grid-cols-[1fr_auto] items-center select-none",
|
|
5
|
+
rowSeparator: "border-b border-surface-200-700",
|
|
6
|
+
rowFocused: "bg-primary-100 dark:bg-primary-900/35",
|
|
7
|
+
rowSelected: "bg-primary-200 dark:bg-primary-900/60",
|
|
8
|
+
rowHover: "hover:bg-surface-100-800",
|
|
9
|
+
expandIcon: "inline-flex h-5 w-5 shrink-0 items-center justify-center rounded text-surface-700-200-token hover:bg-surface-200-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500",
|
|
10
|
+
indentGuide: "min-w-0 flex items-center gap-1.5 pr-2 text-surface-900-100-token",
|
|
11
|
+
label: "truncate text-sm",
|
|
12
|
+
description: "truncate text-xs text-surface-500-400-token",
|
|
13
|
+
iconWrapper: "inline-flex h-5 w-5 shrink-0 items-center justify-center text-sm"
|
|
14
|
+
};
|
|
15
|
+
let longPressTimer;
|
|
16
|
+
let startX = 0;
|
|
17
|
+
let startY = 0;
|
|
18
|
+
let suppressNextClick = false;
|
|
19
|
+
const sectionArgs = $derived({
|
|
20
|
+
node: row.node,
|
|
21
|
+
level: row.level,
|
|
22
|
+
rowIndex: index,
|
|
23
|
+
treeData: treeDataSnapshot
|
|
24
|
+
});
|
|
25
|
+
const rowClasses = $derived([
|
|
26
|
+
mergeClasses(DEFAULT_CLASSES.row, classes?.row),
|
|
27
|
+
showRowSeparator ? mergeClasses(DEFAULT_CLASSES.rowSeparator, classes?.rowSeparator) : "",
|
|
28
|
+
hoverEffect ? mergeClasses(DEFAULT_CLASSES.rowHover, classes?.rowHover) : "",
|
|
29
|
+
isFocused ? mergeClasses(DEFAULT_CLASSES.rowFocused, classes?.rowFocused) : "",
|
|
30
|
+
isSelected ? mergeClasses(DEFAULT_CLASSES.rowSelected, classes?.rowSelected) : ""
|
|
31
|
+
].filter(Boolean).join(" "));
|
|
32
|
+
function cancelLongPress() {
|
|
33
|
+
clearTimeout(longPressTimer);
|
|
34
|
+
longPressTimer = undefined;
|
|
35
|
+
}
|
|
36
|
+
function handlePointerDown(event) {
|
|
37
|
+
startX = event.clientX;
|
|
38
|
+
startY = event.clientY;
|
|
39
|
+
cancelLongPress();
|
|
40
|
+
longPressTimer = setTimeout(() => {
|
|
41
|
+
suppressNextClick = true;
|
|
42
|
+
onrowlongpress?.(index, event);
|
|
43
|
+
}, longPressDelay);
|
|
44
|
+
}
|
|
45
|
+
function handlePointerMove(event) {
|
|
46
|
+
if (Math.hypot(event.clientX - startX, event.clientY - startY) > longPressMoveTolerance) cancelLongPress();
|
|
47
|
+
}
|
|
66
48
|
</script>
|
|
67
49
|
|
|
68
50
|
<div
|
|
@@ -72,65 +54,45 @@
|
|
|
72
54
|
aria-expanded={row.hasChildren ? row.expanded : undefined}
|
|
73
55
|
aria-selected={isSelected}
|
|
74
56
|
tabindex="-1"
|
|
75
|
-
style={`height: ${rowHeight}px;`}
|
|
76
|
-
onclick={(event) =>
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
event.stopPropagation();
|
|
80
|
-
onrowcontext?.(index, event);
|
|
81
|
-
}}
|
|
82
|
-
onkeydown={(event) => {
|
|
83
|
-
if (event.key !== 'Enter' && event.key !== ' ') return;
|
|
84
|
-
event.preventDefault();
|
|
85
|
-
onselectrow?.(index, new MouseEvent('click'));
|
|
86
|
-
if (row.hasChildren) {
|
|
87
|
-
ontogglerow?.(row.node);
|
|
88
|
-
}
|
|
57
|
+
style={autoMeasure ? `min-height: ${rowHeight}px;` : `height: ${rowHeight}px;`}
|
|
58
|
+
onclick={(event) => {
|
|
59
|
+
if (suppressNextClick) { suppressNextClick = false; return; }
|
|
60
|
+
onselectrow?.(index, event);
|
|
89
61
|
}}
|
|
62
|
+
ondblclick={(event) => onrowdoubleclick?.(index, event)}
|
|
63
|
+
oncontextmenu={(event) => { event.stopPropagation(); onrowcontext?.(index, event); }}
|
|
64
|
+
onkeydown={() => undefined}
|
|
65
|
+
onpointerdown={handlePointerDown}
|
|
66
|
+
onpointermove={handlePointerMove}
|
|
67
|
+
onpointerup={cancelLongPress}
|
|
68
|
+
onpointercancel={cancelLongPress}
|
|
69
|
+
onpointerenter={(event) => onrowhover?.(index, event)}
|
|
70
|
+
onpointerleave={(event) => { cancelLongPress(); onrowhoverend?.(index, event); }}
|
|
90
71
|
>
|
|
91
|
-
<div
|
|
92
|
-
class="min-w-0 flex items-center gap-1.5 pr-2 text-surface-900-100-token"
|
|
93
|
-
style={`padding-left: ${(row.level - 1) * indent}px;`}
|
|
94
|
-
>
|
|
72
|
+
<div class={mergeClasses(DEFAULT_CLASSES.indentGuide, classes?.indentGuide)} style={`padding-left: ${(row.level - 1) * indent}px;`}>
|
|
95
73
|
{#if leftSection}
|
|
96
|
-
<span class="inline-flex shrink-0 items-center">
|
|
74
|
+
<span class="inline-flex shrink-0 items-center">
|
|
75
|
+
{@render leftSection(sectionArgs)}
|
|
76
|
+
</span>
|
|
97
77
|
{/if}
|
|
98
|
-
|
|
99
78
|
{#if row.hasChildren}
|
|
100
|
-
<button
|
|
101
|
-
class="
|
|
102
|
-
type="button"
|
|
103
|
-
aria-label={row.expanded ? 'Collapse node' : 'Expand node'}
|
|
104
|
-
onclick={(event) => {
|
|
105
|
-
event.stopPropagation();
|
|
106
|
-
ontogglerow?.(row.node);
|
|
107
|
-
}}
|
|
108
|
-
>
|
|
109
|
-
{#if row.loading}
|
|
110
|
-
<span
|
|
111
|
-
class="h-3 w-3 animate-spin rounded-full border-2 border-surface-400/30 border-t-surface-700 dark:border-surface-300/30 dark:border-t-surface-100"
|
|
112
|
-
aria-hidden="true"
|
|
113
|
-
></span>
|
|
114
|
-
{:else}
|
|
115
|
-
{row.expanded ? '▾' : '▸'}
|
|
116
|
-
{/if}
|
|
79
|
+
<button class={mergeClasses(DEFAULT_CLASSES.expandIcon, classes?.expandIcon)} type="button" aria-label={row.expanded ? 'Collapse node' : 'Expand node'} onclick={(event) => { event.stopPropagation(); ontogglerow?.(row.node); }}>
|
|
80
|
+
{#if row.loading}<span class="h-3 w-3 animate-spin rounded-full border-2 border-surface-400/30 border-t-surface-700 dark:border-surface-300/30 dark:border-t-surface-100" aria-hidden="true"></span>{:else}{row.expanded ? '▾' : '▸'}{/if}
|
|
117
81
|
</button>
|
|
118
|
-
{:else}
|
|
119
|
-
|
|
82
|
+
{:else}<span class="inline-flex h-5 w-5 shrink-0" aria-hidden="true"></span>{/if}
|
|
83
|
+
{#if multiple && selectionMode === 'checkbox'}
|
|
84
|
+
<input class="h-4 w-4 shrink-0" type="checkbox" checked={isChecked} aria-label={`Select ${getNodeLabel(row.node)}`} onclick={(event) => { event.stopPropagation(); oncheckboxselect?.(index, event); }} />
|
|
120
85
|
{/if}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
{
|
|
124
|
-
<span class="
|
|
86
|
+
{#if icon}
|
|
87
|
+
<span class={mergeClasses(DEFAULT_CLASSES.iconWrapper, classes?.iconWrapper)}>{@render icon(sectionArgs)}</span>
|
|
88
|
+
{:else if iconValue !== undefined && iconValue !== null && iconValue !== ''}
|
|
89
|
+
<span class={mergeClasses(DEFAULT_CLASSES.iconWrapper, classes?.iconWrapper)}>{#if isImageLikeValue(iconValue)}<img class="h-4 w-4 object-contain" src={String(iconValue)} alt="" />{:else}{String(iconValue)}{/if}</span>
|
|
125
90
|
{/if}
|
|
91
|
+
<span class={mergeClasses(DEFAULT_CLASSES.label, classes?.label)} class:font-semibold={row.matched}>{getNodeLabel(row.node)}</span>
|
|
92
|
+
{#if getNodeDescription(row.node)}<span class={mergeClasses(DEFAULT_CLASSES.description, classes?.description)}>{getNodeDescription(row.node)}</span>{/if}
|
|
126
93
|
</div>
|
|
127
|
-
|
|
128
94
|
<div class="flex items-center gap-2 pr-2">
|
|
129
|
-
{#if row.error}
|
|
130
|
-
|
|
131
|
-
{/if}
|
|
132
|
-
{#if rightSection}
|
|
133
|
-
<span class="inline-flex items-center">{@render rightSection(sectionArgs)}</span>
|
|
134
|
-
{/if}
|
|
95
|
+
{#if row.error}<span class="text-xs text-error-500">{row.error}</span>{/if}
|
|
96
|
+
{#if rightSection}<span class="inline-flex items-center">{@render rightSection(sectionArgs)}</span>{/if}
|
|
135
97
|
</div>
|
|
136
98
|
</div>
|
|
@@ -1,36 +1,52 @@
|
|
|
1
|
-
import type { VTreeFlatRow } from './VTree.models.js';
|
|
2
|
-
import type { VTreeRecord } from './types.js';
|
|
3
1
|
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { VTreeFlatRow } from './VTree.models.js';
|
|
3
|
+
import type { VTreeClassOverrides, VTreeRecord } from './types.js';
|
|
4
4
|
export interface Props<T extends VTreeRecord = VTreeRecord> {
|
|
5
5
|
row: VTreeFlatRow<T>;
|
|
6
6
|
index: number;
|
|
7
7
|
rowHeight: number;
|
|
8
|
+
autoMeasure?: boolean;
|
|
8
9
|
indent: number;
|
|
9
10
|
isFocused: boolean;
|
|
10
11
|
isSelected: boolean;
|
|
12
|
+
multiple?: boolean;
|
|
13
|
+
selectionMode?: 'modifier' | 'checkbox';
|
|
14
|
+
isChecked?: boolean;
|
|
15
|
+
iconValue?: unknown;
|
|
16
|
+
icon?: Snippet<[{
|
|
17
|
+
node: T;
|
|
18
|
+
level: number;
|
|
19
|
+
rowIndex: number;
|
|
20
|
+
treeData: T[];
|
|
21
|
+
}]>;
|
|
22
|
+
showRowSeparator?: boolean;
|
|
23
|
+
hoverEffect?: boolean;
|
|
24
|
+
classes?: VTreeClassOverrides;
|
|
11
25
|
getNodeLabel: (node: T) => string;
|
|
12
26
|
getNodeDescription: (node: T) => string;
|
|
13
27
|
treeDataSnapshot: T[];
|
|
14
|
-
leftSection?: Snippet<[
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
rowIndex: number;
|
|
27
|
-
treeData: T[];
|
|
28
|
-
}
|
|
29
|
-
]>;
|
|
28
|
+
leftSection?: Snippet<[{
|
|
29
|
+
node: T;
|
|
30
|
+
level: number;
|
|
31
|
+
rowIndex: number;
|
|
32
|
+
treeData: T[];
|
|
33
|
+
}]>;
|
|
34
|
+
rightSection?: Snippet<[{
|
|
35
|
+
node: T;
|
|
36
|
+
level: number;
|
|
37
|
+
rowIndex: number;
|
|
38
|
+
treeData: T[];
|
|
39
|
+
}]>;
|
|
30
40
|
onselectrow?: (index: number, event: MouseEvent) => void;
|
|
41
|
+
oncheckboxselect?: (index: number, event: MouseEvent) => void;
|
|
31
42
|
onrowdoubleclick?: (index: number, event: MouseEvent) => void;
|
|
32
43
|
onrowcontext?: (index: number, event: MouseEvent) => void;
|
|
33
44
|
ontogglerow?: (node: T) => void;
|
|
45
|
+
onrowlongpress?: (index: number, event: PointerEvent) => void;
|
|
46
|
+
onrowhover?: (index: number, event: PointerEvent) => void;
|
|
47
|
+
onrowhoverend?: (index: number, event: PointerEvent) => void;
|
|
48
|
+
longPressDelay?: number;
|
|
49
|
+
longPressMoveTolerance?: number;
|
|
34
50
|
}
|
|
35
51
|
declare const VTreeRow: import("svelte").Component<Props<VTreeRecord>, {}, "">;
|
|
36
52
|
type VTreeRow = ReturnType<typeof VTreeRow>;
|
|
@@ -1,16 +1,9 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const { value, placeholder = 'Search tree...', oninputvalue }: Props = $props();
|
|
9
|
-
|
|
10
|
-
function handleInput(event: Event) {
|
|
11
|
-
const target = event.currentTarget as HTMLInputElement;
|
|
12
|
-
oninputvalue?.(target.value);
|
|
13
|
-
}
|
|
1
|
+
<script lang="ts">const { value, placeholder = "Search tree...", oninputvalue } = $props();
|
|
2
|
+
function handleInput(event) {
|
|
3
|
+
const target = event.currentTarget;
|
|
4
|
+
oninputvalue?.(target.value);
|
|
5
|
+
}
|
|
6
|
+
export {};
|
|
14
7
|
</script>
|
|
15
8
|
|
|
16
9
|
<div class="flex">
|
|
@@ -1,154 +1,65 @@
|
|
|
1
|
-
<script lang="ts">
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
indent,
|
|
47
|
-
overscan,
|
|
48
|
-
focusedIndex,
|
|
49
|
-
selectedId,
|
|
50
|
-
loadingRoot,
|
|
51
|
-
loadingMessage,
|
|
52
|
-
emptyMessage,
|
|
53
|
-
getNodeLabel,
|
|
54
|
-
getNodeDescription,
|
|
55
|
-
treeDataSnapshot,
|
|
56
|
-
leftSection,
|
|
57
|
-
rightSection,
|
|
58
|
-
onselectrow,
|
|
59
|
-
onrowdoubleclick,
|
|
60
|
-
onrowcontext,
|
|
61
|
-
onviewportcontext,
|
|
62
|
-
ontogglerow,
|
|
63
|
-
ontreekeydown
|
|
64
|
-
}: Props = $props();
|
|
65
|
-
|
|
66
|
-
let viewportRef = $state<HTMLDivElement | null>(null);
|
|
67
|
-
let virtualizerInstance = $state<SvelteVirtualizer<HTMLDivElement, HTMLDivElement> | null>(null);
|
|
68
|
-
|
|
69
|
-
function toCssSize(value: string | number): string {
|
|
70
|
-
return typeof value === 'number' ? `${value}px` : value;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function scrollToIndex(index: number) {
|
|
74
|
-
virtualizerInstance?.scrollToIndex(index, { align: 'auto' });
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
$effect(() => {
|
|
78
|
-
if (!viewportRef) {
|
|
79
|
-
virtualizerInstance = null;
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const virtualizer = createVirtualizer<HTMLDivElement, HTMLDivElement>({
|
|
84
|
-
count: rows.length,
|
|
85
|
-
estimateSize: () => rowHeight,
|
|
86
|
-
overscan,
|
|
87
|
-
getScrollElement: () => viewportRef
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
return virtualizer.subscribe((instance) => {
|
|
91
|
-
virtualizerInstance = instance;
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
$effect(() => {
|
|
96
|
-
if (!virtualizerInstance || !viewportRef) return;
|
|
97
|
-
virtualizerInstance.setOptions({
|
|
98
|
-
count: rows.length,
|
|
99
|
-
estimateSize: () => rowHeight,
|
|
100
|
-
overscan,
|
|
101
|
-
getScrollElement: () => viewportRef
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
const virtualItems = $derived(virtualizerInstance?.getVirtualItems() ?? []);
|
|
106
|
-
const totalSize = $derived(virtualizerInstance?.getTotalSize() ?? 0);
|
|
1
|
+
<script lang="ts">import { createVirtualizer } from "@tanstack/svelte-virtual";
|
|
2
|
+
import VTreeRow from "./VTreeRow.svelte";
|
|
3
|
+
import { resolveRowHeight } from "./VTree.utils.js";
|
|
4
|
+
const { rows, rowHeight, autoMeasure = false, height, indent, overscan, focusedIndex, selectedId, selectedNodeId, selectedItemIds = [], loadingRoot, loadingMessage, emptyMessage, multiple = false, selectionMode = "modifier", iconField, icon, classes, showRowSeparator = true, hoverEffect = true, getNodeLabel, getNodeDescription, treeDataSnapshot, leftSection, rightSection, onselectrow, oncheckboxselect, onrowdoubleclick, onrowcontext, onviewportcontext, ontogglerow, onrowlongpress, onrowhover, onrowhoverend, longPressDelay, longPressMoveTolerance, ontreekeydown } = $props();
|
|
5
|
+
let viewportRef = $state(null);
|
|
6
|
+
let virtualizerInstance = $state(null);
|
|
7
|
+
function toCssSize(value) {
|
|
8
|
+
return typeof value === "number" ? `${value}px` : value;
|
|
9
|
+
}
|
|
10
|
+
function estimate(index) {
|
|
11
|
+
const row = rows[index];
|
|
12
|
+
return resolveRowHeight(rowHeight, row?.node, row?.level ?? 1, index);
|
|
13
|
+
}
|
|
14
|
+
export function scrollToIndex(index) {
|
|
15
|
+
virtualizerInstance?.scrollToIndex(index, { align: "auto" });
|
|
16
|
+
}
|
|
17
|
+
function measure(node) {
|
|
18
|
+
if (autoMeasure) virtualizerInstance?.measureElement(node);
|
|
19
|
+
}
|
|
20
|
+
$effect(() => {
|
|
21
|
+
if (!viewportRef) {
|
|
22
|
+
virtualizerInstance = null;
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const virtualizer = createVirtualizer({
|
|
26
|
+
count: rows.length,
|
|
27
|
+
estimateSize: estimate,
|
|
28
|
+
overscan,
|
|
29
|
+
getScrollElement: () => viewportRef
|
|
30
|
+
});
|
|
31
|
+
return virtualizer.subscribe((instance) => {
|
|
32
|
+
virtualizerInstance = instance;
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
$effect(() => {
|
|
36
|
+
if (!virtualizerInstance || !viewportRef) return;
|
|
37
|
+
virtualizerInstance.setOptions({
|
|
38
|
+
count: rows.length,
|
|
39
|
+
estimateSize: estimate,
|
|
40
|
+
overscan,
|
|
41
|
+
getScrollElement: () => viewportRef
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
const virtualItems = $derived(virtualizerInstance?.getVirtualItems() ?? []);
|
|
45
|
+
const totalSize = $derived(virtualizerInstance?.getTotalSize() ?? 0);
|
|
107
46
|
</script>
|
|
108
47
|
|
|
109
|
-
<div
|
|
110
|
-
class="card overflow-auto border border-surface-300-700 bg-surface-50-950 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500"
|
|
111
|
-
bind:this={viewportRef}
|
|
112
|
-
style={`height: ${toCssSize(height)};`}
|
|
113
|
-
onkeydown={(event) => ontreekeydown?.(event)}
|
|
114
|
-
oncontextmenu={(event) => onviewportcontext?.(event)}
|
|
115
|
-
tabindex="0"
|
|
116
|
-
role="tree"
|
|
117
|
-
aria-label="Virtual tree"
|
|
118
|
-
>
|
|
48
|
+
<div class="card overflow-auto border border-surface-300-700 bg-surface-50-950 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500" bind:this={viewportRef} style={`height: ${toCssSize(height)};`} onkeydown={(event) => ontreekeydown?.(event)} oncontextmenu={(event) => onviewportcontext?.(event)} tabindex="0" role="tree" aria-label="Virtual tree">
|
|
119
49
|
{#if loadingRoot}
|
|
120
50
|
<div class="grid min-h-24 place-items-center px-3 text-sm text-surface-500-400-token">{loadingMessage}</div>
|
|
121
51
|
{:else if rows.length === 0}
|
|
122
52
|
<div class="grid min-h-24 place-items-center px-3 text-sm text-surface-500-400-token">{emptyMessage}</div>
|
|
123
53
|
{:else}
|
|
124
54
|
<div class="relative w-full" style={`height: ${totalSize}px;`}>
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
row={row}
|
|
134
|
-
index={item.index}
|
|
135
|
-
{rowHeight}
|
|
136
|
-
{indent}
|
|
137
|
-
isFocused={item.index === focusedIndex}
|
|
138
|
-
isSelected={row.id === selectedId}
|
|
139
|
-
{getNodeLabel}
|
|
140
|
-
{getNodeDescription}
|
|
141
|
-
{treeDataSnapshot}
|
|
142
|
-
{leftSection}
|
|
143
|
-
{rightSection}
|
|
144
|
-
{onselectrow}
|
|
145
|
-
{onrowdoubleclick}
|
|
146
|
-
{onrowcontext}
|
|
147
|
-
{ontogglerow}
|
|
148
|
-
/>
|
|
149
|
-
{/if}
|
|
150
|
-
{/each}
|
|
151
|
-
</div>
|
|
55
|
+
{#each virtualItems as item (item.key)}
|
|
56
|
+
{@const row = rows[item.index]}
|
|
57
|
+
{#if row}
|
|
58
|
+
<div class="absolute left-0 top-0 w-full" style={`transform: translateY(${item.start}px);`} {@attach measure}>
|
|
59
|
+
<VTreeRow row={row} index={item.index} rowHeight={estimate(item.index)} {autoMeasure} {indent} isFocused={item.index === focusedIndex} isSelected={row.id === (selectedNodeId || selectedId)} {multiple} {selectionMode} isChecked={selectedItemIds.includes(row.id)} iconValue={iconField ? row.node[iconField] : undefined} {icon} {classes} {showRowSeparator} {hoverEffect} {getNodeLabel} {getNodeDescription} {treeDataSnapshot} {leftSection} {rightSection} {onselectrow} {oncheckboxselect} {onrowdoubleclick} {onrowcontext} {ontogglerow} {onrowlongpress} {onrowhover} {onrowhoverend} {longPressDelay} {longPressMoveTolerance} />
|
|
60
|
+
</div>
|
|
61
|
+
{/if}
|
|
62
|
+
{/each}
|
|
152
63
|
</div>
|
|
153
64
|
{/if}
|
|
154
65
|
</div>
|
|
@@ -1,41 +1,58 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
2
|
import type { VTreeFlatRow } from './VTree.models.js';
|
|
3
|
-
import type { VTreeRecord } from './types.js';
|
|
3
|
+
import type { VTreeClassOverrides, VTreeRecord } from './types.js';
|
|
4
4
|
export interface Props<T extends VTreeRecord = VTreeRecord> {
|
|
5
5
|
rows: VTreeFlatRow<T>[];
|
|
6
|
-
rowHeight: number;
|
|
6
|
+
rowHeight: number | ((node: T, level: number, index: number) => number);
|
|
7
|
+
autoMeasure?: boolean;
|
|
7
8
|
height: string | number;
|
|
8
9
|
indent: number;
|
|
9
10
|
overscan: number;
|
|
10
11
|
focusedIndex: number;
|
|
11
12
|
selectedId: string | null;
|
|
13
|
+
selectedNodeId?: string;
|
|
14
|
+
selectedItemIds?: string[];
|
|
12
15
|
loadingRoot: boolean;
|
|
13
16
|
loadingMessage: string;
|
|
14
17
|
emptyMessage: string;
|
|
18
|
+
multiple?: boolean;
|
|
19
|
+
selectionMode?: 'modifier' | 'checkbox';
|
|
20
|
+
iconField?: keyof T & string;
|
|
21
|
+
icon?: Snippet<[{
|
|
22
|
+
node: T;
|
|
23
|
+
level: number;
|
|
24
|
+
rowIndex: number;
|
|
25
|
+
treeData: T[];
|
|
26
|
+
}]>;
|
|
27
|
+
classes?: VTreeClassOverrides;
|
|
28
|
+
showRowSeparator?: boolean;
|
|
29
|
+
hoverEffect?: boolean;
|
|
15
30
|
getNodeLabel: (node: T) => string;
|
|
16
31
|
getNodeDescription: (node: T) => string;
|
|
17
32
|
treeDataSnapshot: T[];
|
|
18
|
-
leftSection?: Snippet<[
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
rowIndex: number;
|
|
31
|
-
treeData: T[];
|
|
32
|
-
}
|
|
33
|
-
]>;
|
|
33
|
+
leftSection?: Snippet<[{
|
|
34
|
+
node: T;
|
|
35
|
+
level: number;
|
|
36
|
+
rowIndex: number;
|
|
37
|
+
treeData: T[];
|
|
38
|
+
}]>;
|
|
39
|
+
rightSection?: Snippet<[{
|
|
40
|
+
node: T;
|
|
41
|
+
level: number;
|
|
42
|
+
rowIndex: number;
|
|
43
|
+
treeData: T[];
|
|
44
|
+
}]>;
|
|
34
45
|
onselectrow?: (index: number, event: MouseEvent) => void;
|
|
46
|
+
oncheckboxselect?: (index: number, event: MouseEvent) => void;
|
|
35
47
|
onrowdoubleclick?: (index: number, event: MouseEvent) => void;
|
|
36
48
|
onrowcontext?: (index: number, event: MouseEvent) => void;
|
|
37
49
|
onviewportcontext?: (event: MouseEvent) => void;
|
|
38
50
|
ontogglerow?: (node: T) => void;
|
|
51
|
+
onrowlongpress?: (index: number, event: PointerEvent) => void;
|
|
52
|
+
onrowhover?: (index: number, event: PointerEvent) => void;
|
|
53
|
+
onrowhoverend?: (index: number, event: PointerEvent) => void;
|
|
54
|
+
longPressDelay?: number;
|
|
55
|
+
longPressMoveTolerance?: number;
|
|
39
56
|
ontreekeydown?: (event: KeyboardEvent) => void;
|
|
40
57
|
}
|
|
41
58
|
declare const VTreeVirtualViewport: import("svelte").Component<Props<VTreeRecord>, {
|
|
@@ -45,7 +45,8 @@ export interface VTreeProps<T extends VTreeRecord = VTreeRecord> {
|
|
|
45
45
|
childrenField?: keyof T & string;
|
|
46
46
|
hasChildrenField?: keyof T & string;
|
|
47
47
|
height?: number | string;
|
|
48
|
-
rowHeight?: number;
|
|
48
|
+
rowHeight?: number | ((node: T, level: number, index: number) => number);
|
|
49
|
+
autoMeasure?: boolean;
|
|
49
50
|
indent?: number;
|
|
50
51
|
overscan?: number;
|
|
51
52
|
searchable?: boolean;
|
|
@@ -80,4 +81,41 @@ export interface VTreeProps<T extends VTreeRecord = VTreeRecord> {
|
|
|
80
81
|
ontoggle?: (node: T, expanded: boolean) => void;
|
|
81
82
|
onsearch?: (query: string) => void;
|
|
82
83
|
onloaderror?: (error: unknown, node?: T) => void;
|
|
84
|
+
iconField?: keyof T & string;
|
|
85
|
+
icon?: Snippet<[{
|
|
86
|
+
node: T;
|
|
87
|
+
level: number;
|
|
88
|
+
rowIndex: number;
|
|
89
|
+
treeData: T[];
|
|
90
|
+
}]>;
|
|
91
|
+
classes?: VTreeClassOverrides;
|
|
92
|
+
showRowSeparator?: boolean;
|
|
93
|
+
hoverEffect?: boolean;
|
|
94
|
+
/** Controlled single-selection. Undefined means uncontrolled; null means explicitly empty. */
|
|
95
|
+
selected?: T | null;
|
|
96
|
+
/** Enables selectedItems/onSelectedItemsChange multi-selection. */
|
|
97
|
+
multiple?: boolean;
|
|
98
|
+
selectionMode?: 'modifier' | 'checkbox';
|
|
99
|
+
onSelectedChange?: (node: T | null) => void;
|
|
100
|
+
selectedItems?: T[];
|
|
101
|
+
onSelectedItemsChange?: (items: T[]) => void;
|
|
102
|
+
onsingleclick?: (node: T, treeData: T[], event: MouseEvent) => void;
|
|
103
|
+
singleClickDelay?: number;
|
|
104
|
+
onlongpress?: (node: T, treeData: T[], event: PointerEvent) => void;
|
|
105
|
+
longPressDelay?: number;
|
|
106
|
+
longPressMoveTolerance?: number;
|
|
107
|
+
onrowhover?: (node: T, treeData: T[], rowIndex: number, event: PointerEvent) => void;
|
|
108
|
+
onrowhoverend?: (node: T, treeData: T[], rowIndex: number, event: PointerEvent) => void;
|
|
109
|
+
}
|
|
110
|
+
export interface VTreeClassOverrides {
|
|
111
|
+
row?: string;
|
|
112
|
+
rowSeparator?: string;
|
|
113
|
+
rowFocused?: string;
|
|
114
|
+
rowSelected?: string;
|
|
115
|
+
rowHover?: string;
|
|
116
|
+
expandIcon?: string;
|
|
117
|
+
indentGuide?: string;
|
|
118
|
+
label?: string;
|
|
119
|
+
description?: string;
|
|
120
|
+
iconWrapper?: string;
|
|
83
121
|
}
|