sv5ui-plus 4.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 +62 -0
- package/dist/adapters/notify.d.ts +29 -0
- package/dist/adapters/notify.js +88 -0
- package/dist/compat.d.ts +6 -0
- package/dist/compat.js +6 -0
- package/dist/components/BentoGrid/BentoCard.svelte +45 -0
- package/dist/components/BentoGrid/BentoCard.svelte.d.ts +4 -0
- package/dist/components/BentoGrid/BentoGrid.svelte +9 -0
- package/dist/components/BentoGrid/BentoGrid.svelte.d.ts +4 -0
- package/dist/components/BentoGrid/bento-grid.types.d.ts +47 -0
- package/dist/components/BentoGrid/bento-grid.types.js +1 -0
- package/dist/components/BentoGrid/bento-grid.variants.d.ts +30 -0
- package/dist/components/BentoGrid/bento-grid.variants.js +16 -0
- package/dist/components/BentoGrid/index.d.ts +5 -0
- package/dist/components/BentoGrid/index.js +5 -0
- package/dist/components/Chart/Chart.svelte +62 -0
- package/dist/components/Chart/Chart.svelte.d.ts +4 -0
- package/dist/components/Chart/chart.types.d.ts +16 -0
- package/dist/components/Chart/chart.types.js +1 -0
- package/dist/components/Chart/index.d.ts +2 -0
- package/dist/components/Chart/index.js +2 -0
- package/dist/components/Chat/ChatBubble.svelte +30 -0
- package/dist/components/Chat/ChatBubble.svelte.d.ts +4 -0
- package/dist/components/Chat/ChatInput.svelte +50 -0
- package/dist/components/Chat/ChatInput.svelte.d.ts +4 -0
- package/dist/components/Chat/ChatMessage.svelte +15 -0
- package/dist/components/Chat/ChatMessage.svelte.d.ts +4 -0
- package/dist/components/Chat/chat.types.d.ts +63 -0
- package/dist/components/Chat/chat.types.js +1 -0
- package/dist/components/Chat/chat.variants.d.ts +117 -0
- package/dist/components/Chat/chat.variants.js +47 -0
- package/dist/components/Chat/index.d.ts +6 -0
- package/dist/components/Chat/index.js +6 -0
- package/dist/components/CodeBlock/CodeBlock.svelte +66 -0
- package/dist/components/CodeBlock/CodeBlock.svelte.d.ts +5 -0
- package/dist/components/CodeBlock/code-block.types.d.ts +15 -0
- package/dist/components/CodeBlock/code-block.types.js +1 -0
- package/dist/components/CodeBlock/code-block.variants.d.ts +288 -0
- package/dist/components/CodeBlock/code-block.variants.js +69 -0
- package/dist/components/CodeBlock/index.d.ts +2 -0
- package/dist/components/CodeBlock/index.js +1 -0
- package/dist/components/ColorPicker/ColorPicker.svelte +109 -0
- package/dist/components/ColorPicker/ColorPicker.svelte.d.ts +4 -0
- package/dist/components/ColorPicker/color-picker.types.d.ts +26 -0
- package/dist/components/ColorPicker/color-picker.types.js +1 -0
- package/dist/components/ColorPicker/color-picker.variants.d.ts +69 -0
- package/dist/components/ColorPicker/color-picker.variants.js +13 -0
- package/dist/components/ColorPicker/index.d.ts +4 -0
- package/dist/components/ColorPicker/index.js +4 -0
- package/dist/components/ConfirmDialog/ConfirmDialog.svelte +175 -0
- package/dist/components/ConfirmDialog/ConfirmDialog.svelte.d.ts +10 -0
- package/dist/components/ConfirmDialog/confirm.d.ts +9 -0
- package/dist/components/ConfirmDialog/confirm.js +24 -0
- package/dist/components/ConfirmDialog/confirm.types.d.ts +21 -0
- package/dist/components/ConfirmDialog/confirm.types.js +1 -0
- package/dist/components/ConfirmDialog/index.d.ts +4 -0
- package/dist/components/ConfirmDialog/index.js +2 -0
- package/dist/components/Fonts/Fonts.svelte +32 -0
- package/dist/components/Fonts/Fonts.svelte.d.ts +5 -0
- package/dist/components/Fonts/fonts.d.ts +12 -0
- package/dist/components/Fonts/fonts.js +126 -0
- package/dist/components/Fonts/fonts.types.d.ts +40 -0
- package/dist/components/Fonts/fonts.types.js +1 -0
- package/dist/components/Fonts/index.d.ts +3 -0
- package/dist/components/Fonts/index.js +2 -0
- package/dist/components/List/List.svelte +14 -0
- package/dist/components/List/List.svelte.d.ts +4 -0
- package/dist/components/List/ListItem.svelte +64 -0
- package/dist/components/List/ListItem.svelte.d.ts +4 -0
- package/dist/components/List/index.d.ts +5 -0
- package/dist/components/List/index.js +5 -0
- package/dist/components/List/list.types.d.ts +62 -0
- package/dist/components/List/list.types.js +1 -0
- package/dist/components/List/list.variants.d.ts +99 -0
- package/dist/components/List/list.variants.js +42 -0
- package/dist/components/LocaleButton/LocaleButton.svelte +181 -0
- package/dist/components/LocaleButton/LocaleButton.svelte.d.ts +5 -0
- package/dist/components/LocaleButton/index.d.ts +2 -0
- package/dist/components/LocaleButton/index.js +1 -0
- package/dist/components/LocaleButton/locale-button.types.d.ts +208 -0
- package/dist/components/LocaleButton/locale-button.types.js +1 -0
- package/dist/components/LocaleButton/locale-button.variants.d.ts +245 -0
- package/dist/components/LocaleButton/locale-button.variants.js +98 -0
- package/dist/components/Marquee/Marquee.svelte +50 -0
- package/dist/components/Marquee/Marquee.svelte.d.ts +4 -0
- package/dist/components/Marquee/index.d.ts +4 -0
- package/dist/components/Marquee/index.js +4 -0
- package/dist/components/Marquee/marquee.types.d.ts +38 -0
- package/dist/components/Marquee/marquee.types.js +1 -0
- package/dist/components/Marquee/marquee.variants.d.ts +78 -0
- package/dist/components/Marquee/marquee.variants.js +28 -0
- package/dist/components/NavigationMenu/NavigationMenu.svelte +623 -0
- package/dist/components/NavigationMenu/NavigationMenu.svelte.d.ts +5 -0
- package/dist/components/NavigationMenu/index.d.ts +2 -0
- package/dist/components/NavigationMenu/index.js +1 -0
- package/dist/components/NavigationMenu/navigation-menu.types.d.ts +245 -0
- package/dist/components/NavigationMenu/navigation-menu.types.js +1 -0
- package/dist/components/NavigationMenu/navigation-menu.variants.d.ts +543 -0
- package/dist/components/NavigationMenu/navigation-menu.variants.js +287 -0
- package/dist/components/NumberTicker/NumberTicker.svelte +59 -0
- package/dist/components/NumberTicker/NumberTicker.svelte.d.ts +4 -0
- package/dist/components/NumberTicker/index.d.ts +4 -0
- package/dist/components/NumberTicker/index.js +4 -0
- package/dist/components/NumberTicker/number-ticker.types.d.ts +26 -0
- package/dist/components/NumberTicker/number-ticker.types.js +1 -0
- package/dist/components/NumberTicker/number-ticker.variants.d.ts +27 -0
- package/dist/components/NumberTicker/number-ticker.variants.js +6 -0
- package/dist/components/PasswordInput/PasswordInput.svelte +182 -0
- package/dist/components/PasswordInput/PasswordInput.svelte.d.ts +5 -0
- package/dist/components/PasswordInput/index.d.ts +2 -0
- package/dist/components/PasswordInput/index.js +1 -0
- package/dist/components/PasswordInput/password-input.types.d.ts +111 -0
- package/dist/components/PasswordInput/password-input.types.js +1 -0
- package/dist/components/PasswordInput/password-input.variants.d.ts +273 -0
- package/dist/components/PasswordInput/password-input.variants.js +105 -0
- package/dist/components/Prose/Prose.svelte +13 -0
- package/dist/components/Prose/Prose.svelte.d.ts +4 -0
- package/dist/components/Prose/index.d.ts +4 -0
- package/dist/components/Prose/index.js +4 -0
- package/dist/components/Prose/prose.types.d.ts +22 -0
- package/dist/components/Prose/prose.types.js +1 -0
- package/dist/components/Prose/prose.variants.d.ts +45 -0
- package/dist/components/Prose/prose.variants.js +45 -0
- package/dist/components/Resizable/Resizable.svelte +9 -0
- package/dist/components/Resizable/Resizable.svelte.d.ts +4 -0
- package/dist/components/Resizable/index.d.ts +4 -0
- package/dist/components/Resizable/index.js +4 -0
- package/dist/components/Resizable/resizable.types.d.ts +18 -0
- package/dist/components/Resizable/resizable.types.js +1 -0
- package/dist/components/Resizable/resizable.variants.d.ts +48 -0
- package/dist/components/Resizable/resizable.variants.js +17 -0
- package/dist/components/ScrollArea/ScrollArea.svelte +54 -0
- package/dist/components/ScrollArea/ScrollArea.svelte.d.ts +4 -0
- package/dist/components/ScrollArea/index.d.ts +4 -0
- package/dist/components/ScrollArea/index.js +4 -0
- package/dist/components/ScrollArea/scroll-area.types.d.ts +27 -0
- package/dist/components/ScrollArea/scroll-area.types.js +1 -0
- package/dist/components/ScrollArea/scroll-area.variants.d.ts +45 -0
- package/dist/components/ScrollArea/scroll-area.variants.js +27 -0
- package/dist/components/Search/Search.svelte +94 -0
- package/dist/components/Search/Search.svelte.d.ts +4 -0
- package/dist/components/Search/index.d.ts +2 -0
- package/dist/components/Search/index.js +1 -0
- package/dist/components/Search/search.types.d.ts +40 -0
- package/dist/components/Search/search.types.js +1 -0
- package/dist/components/SortableGroup/SortableGroup.svelte +53 -0
- package/dist/components/SortableGroup/SortableGroup.svelte.d.ts +13 -0
- package/dist/components/SortableGroup/index.d.ts +1 -0
- package/dist/components/SortableGroup/index.js +1 -0
- package/dist/components/SortableList/SortableList.svelte +81 -0
- package/dist/components/SortableList/SortableList.svelte.d.ts +26 -0
- package/dist/components/SortableList/index.d.ts +2 -0
- package/dist/components/SortableList/index.js +1 -0
- package/dist/components/SortableList/sortable-list.types.d.ts +21 -0
- package/dist/components/SortableList/sortable-list.types.js +1 -0
- package/dist/components/Spotlight/Spotlight.svelte +31 -0
- package/dist/components/Spotlight/Spotlight.svelte.d.ts +4 -0
- package/dist/components/Spotlight/index.d.ts +4 -0
- package/dist/components/Spotlight/index.js +4 -0
- package/dist/components/Spotlight/spotlight.types.d.ts +22 -0
- package/dist/components/Spotlight/spotlight.types.js +1 -0
- package/dist/components/Spotlight/spotlight.variants.d.ts +39 -0
- package/dist/components/Spotlight/spotlight.variants.js +8 -0
- package/dist/components/TableBulkActionBar/TableBulkActionBar.svelte +38 -0
- package/dist/components/TableBulkActionBar/TableBulkActionBar.svelte.d.ts +5 -0
- package/dist/components/TableBulkActionBar/index.d.ts +2 -0
- package/dist/components/TableBulkActionBar/index.js +1 -0
- package/dist/components/TableBulkActionBar/table-bulk-action-bar.types.d.ts +31 -0
- package/dist/components/TableBulkActionBar/table-bulk-action-bar.types.js +1 -0
- package/dist/components/TableBulkActionBar/table-bulk-action-bar.variants.d.ts +52 -0
- package/dist/components/TableBulkActionBar/table-bulk-action-bar.variants.js +10 -0
- package/dist/components/TreeView/TreeView.svelte +95 -0
- package/dist/components/TreeView/TreeView.svelte.d.ts +4 -0
- package/dist/components/TreeView/index.d.ts +4 -0
- package/dist/components/TreeView/index.js +3 -0
- package/dist/components/TreeView/tree-view.types.d.ts +68 -0
- package/dist/components/TreeView/tree-view.types.js +1 -0
- package/dist/components/TreeView/tree-view.variants.d.ts +69 -0
- package/dist/components/TreeView/tree-view.variants.js +30 -0
- package/dist/config.d.ts +91 -0
- package/dist/config.js +124 -0
- package/dist/editor.d.ts +2 -0
- package/dist/editor.js +2 -0
- package/dist/form/resolve-form-field-name.d.ts +5 -0
- package/dist/form/resolve-form-field-name.js +11 -0
- package/dist/hooks/internal/DragDropProviderScope.svelte +29 -0
- package/dist/hooks/internal/DragDropProviderScope.svelte.d.ts +7 -0
- package/dist/hooks/internal/SortableProvider.svelte +68 -0
- package/dist/hooks/internal/SortableProvider.svelte.d.ts +30 -0
- package/dist/hooks/internal/drag-drop-context.d.ts +12 -0
- package/dist/hooks/internal/drag-drop-context.js +1 -0
- package/dist/hooks/internal/sortable-context.d.ts +26 -0
- package/dist/hooks/internal/sortable-context.js +2 -0
- package/dist/hooks/useDragDrop/index.d.ts +1 -0
- package/dist/hooks/useDragDrop/index.js +1 -0
- package/dist/hooks/useDragDrop/useDragDrop.svelte.d.ts +40 -0
- package/dist/hooks/useDragDrop/useDragDrop.svelte.js +128 -0
- package/dist/hooks/useSortable/index.d.ts +2 -0
- package/dist/hooks/useSortable/index.js +2 -0
- package/dist/hooks/useSortable/sortable-utils.d.ts +1 -0
- package/dist/hooks/useSortable/sortable-utils.js +13 -0
- package/dist/hooks/useSortable/useSortable.svelte.d.ts +60 -0
- package/dist/hooks/useSortable/useSortable.svelte.js +151 -0
- package/dist/hooks/utils.d.ts +1 -0
- package/dist/hooks/utils.js +3 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +30 -0
- package/dist/mcp/cursor.mcp.json +12 -0
- package/dist/mcp/install-template.mjs +55 -0
- package/dist/mcp/server.mjs +338 -0
- package/dist/mcp/sv5ui-plus-docs.data.json +17 -0
- package/dist/theme.css +64 -0
- package/package.json +176 -0
package/dist/config.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SV5UI Plus Global Configuration
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* import { defineSV5UIPlusConfig } from 'sv5ui-plus'
|
|
7
|
+
*
|
|
8
|
+
* defineSV5UIPlusConfig({
|
|
9
|
+
* fonts: {
|
|
10
|
+
* families: [
|
|
11
|
+
* {
|
|
12
|
+
* name: 'Inter',
|
|
13
|
+
* variable: '--font-sans-family',
|
|
14
|
+
* weights: [400, 500, 600, 700]
|
|
15
|
+
* }
|
|
16
|
+
* ]
|
|
17
|
+
* },
|
|
18
|
+
* button: {
|
|
19
|
+
* defaultVariants: { variant: 'outline', color: 'secondary' },
|
|
20
|
+
* slots: { base: 'shadow-md', label: 'font-bold' }
|
|
21
|
+
* },
|
|
22
|
+
* avatar: {
|
|
23
|
+
* defaultVariants: { size: 'lg' },
|
|
24
|
+
* slots: { root: 'ring-2 ring-primary' }
|
|
25
|
+
* },
|
|
26
|
+
* icons: { loading: 'svg-spinners:ring-resize' }
|
|
27
|
+
* })
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
// ==================== ICONS DEFAULTS ====================
|
|
31
|
+
/**
|
|
32
|
+
* Default icons used across components
|
|
33
|
+
*/
|
|
34
|
+
export const iconsDefaults = {
|
|
35
|
+
loading: 'lucide:loader-circle',
|
|
36
|
+
chevronDown: 'lucide:chevron-down',
|
|
37
|
+
chevronLeft: 'lucide:chevron-left',
|
|
38
|
+
chevronRight: 'lucide:chevron-right',
|
|
39
|
+
chevronsLeft: 'lucide:chevrons-left',
|
|
40
|
+
chevronsRight: 'lucide:chevrons-right',
|
|
41
|
+
ellipsis: 'lucide:ellipsis',
|
|
42
|
+
close: 'lucide:x',
|
|
43
|
+
menu: 'lucide:menu',
|
|
44
|
+
external: 'lucide:arrow-up-right',
|
|
45
|
+
check: 'lucide:check',
|
|
46
|
+
light: 'lucide:sun',
|
|
47
|
+
dark: 'lucide:moon',
|
|
48
|
+
upload: 'lucide:upload',
|
|
49
|
+
file: 'lucide:file',
|
|
50
|
+
zoomIn: 'lucide:zoom-in',
|
|
51
|
+
trash: 'lucide:trash-2',
|
|
52
|
+
search: 'lucide:search',
|
|
53
|
+
star: 'lucide:star',
|
|
54
|
+
folder: 'lucide:folder',
|
|
55
|
+
folderOpen: 'lucide:folder-open',
|
|
56
|
+
sortAsc: 'lucide:chevron-up',
|
|
57
|
+
sortDesc: 'lucide:chevron-down',
|
|
58
|
+
sortDefault: 'lucide:chevrons-up-down',
|
|
59
|
+
panelLeft: 'lucide:panel-left',
|
|
60
|
+
dragHandle: 'lucide:grip-vertical'
|
|
61
|
+
};
|
|
62
|
+
// ==================== GLOBAL STATE ====================
|
|
63
|
+
let globalConfig = {};
|
|
64
|
+
let cachedConfigs = {};
|
|
65
|
+
// ==================== PUBLIC API ====================
|
|
66
|
+
/**
|
|
67
|
+
* Define global configuration for SV5UI Plus components
|
|
68
|
+
*/
|
|
69
|
+
export function defineConfig(config) {
|
|
70
|
+
globalConfig = config;
|
|
71
|
+
cachedConfigs = {};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get the current global configuration
|
|
75
|
+
*/
|
|
76
|
+
export function getConfig() {
|
|
77
|
+
return globalConfig;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Reset configuration to defaults
|
|
81
|
+
*/
|
|
82
|
+
export function resetConfig() {
|
|
83
|
+
globalConfig = {};
|
|
84
|
+
cachedConfigs = {};
|
|
85
|
+
}
|
|
86
|
+
// ==================== COMPONENT CONFIG GETTER ====================
|
|
87
|
+
/**
|
|
88
|
+
* Deep merge utility for config objects
|
|
89
|
+
*/
|
|
90
|
+
function deepMerge(target, source) {
|
|
91
|
+
const result = { ...target };
|
|
92
|
+
for (const key in source) {
|
|
93
|
+
const sourceValue = source[key];
|
|
94
|
+
const targetValue = target[key];
|
|
95
|
+
if (sourceValue !== undefined &&
|
|
96
|
+
typeof sourceValue === 'object' &&
|
|
97
|
+
sourceValue !== null &&
|
|
98
|
+
!Array.isArray(sourceValue) &&
|
|
99
|
+
typeof targetValue === 'object' &&
|
|
100
|
+
targetValue !== null &&
|
|
101
|
+
!Array.isArray(targetValue)) {
|
|
102
|
+
result[key] = deepMerge(targetValue, sourceValue);
|
|
103
|
+
}
|
|
104
|
+
else if (sourceValue !== undefined) {
|
|
105
|
+
result[key] = sourceValue;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Get merged config for a component (memoized).
|
|
112
|
+
* Each component passes its own defaults, so config.ts doesn't import any variant files.
|
|
113
|
+
* This enables proper tree-shaking: unused components are excluded from the bundle.
|
|
114
|
+
* @internal
|
|
115
|
+
*/
|
|
116
|
+
export function getComponentConfig(component, defaults) {
|
|
117
|
+
if (!(component in cachedConfigs)) {
|
|
118
|
+
const userConfig = globalConfig[component];
|
|
119
|
+
cachedConfigs[component] = userConfig
|
|
120
|
+
? deepMerge(defaults, userConfig)
|
|
121
|
+
: defaults;
|
|
122
|
+
}
|
|
123
|
+
return cachedConfigs[component];
|
|
124
|
+
}
|
package/dist/editor.d.ts
ADDED
package/dist/editor.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ชื่อฟิลด์สำหรับ form submission — ใส่ suffix `[]` เมื่อส่งหลายค่า
|
|
3
|
+
* เพื่อให้เข้ากับ SvelteKit `convert_formdata` และ HTML FormData
|
|
4
|
+
*/
|
|
5
|
+
export function resolveFormFieldName(name, multiple) {
|
|
6
|
+
if (!name)
|
|
7
|
+
return undefined;
|
|
8
|
+
if (!multiple)
|
|
9
|
+
return name;
|
|
10
|
+
return name.endsWith('[]') ? name : `${name}[]`;
|
|
11
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<script lang="ts">import { DragDropProvider } from "@dnd-kit/svelte";
|
|
2
|
+
import { getContext } from "svelte";
|
|
3
|
+
import { DRAG_DROP_CONTEXT_KEY } from "./drag-drop-context.js";
|
|
4
|
+
let { children } = $props();
|
|
5
|
+
const ctx = getContext(DRAG_DROP_CONTEXT_KEY);
|
|
6
|
+
function handleDragStart(event) {
|
|
7
|
+
const source = event.operation.source;
|
|
8
|
+
if (!source) return;
|
|
9
|
+
ctx.setDraggingId(String(source.id));
|
|
10
|
+
}
|
|
11
|
+
function handleDragEnd(event) {
|
|
12
|
+
const source = event.operation.source;
|
|
13
|
+
const target = event.operation.target;
|
|
14
|
+
ctx.setDraggingId(null);
|
|
15
|
+
if (!source || !target) return;
|
|
16
|
+
const zone = ctx.getDroppable(String(target.id));
|
|
17
|
+
if (!zone) return;
|
|
18
|
+
const payload = ctx.toPayload({
|
|
19
|
+
id: source.id,
|
|
20
|
+
data: source.data
|
|
21
|
+
});
|
|
22
|
+
if (zone.accept && !zone.accept(payload)) return;
|
|
23
|
+
zone.onDrop(payload);
|
|
24
|
+
}
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<DragDropProvider onDragStart={handleDragStart} onDragEnd={handleDragEnd}>
|
|
28
|
+
{@render children?.()}
|
|
29
|
+
</DragDropProvider>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
children?: Snippet;
|
|
4
|
+
}
|
|
5
|
+
declare const DragDropProviderScope: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type DragDropProviderScope = ReturnType<typeof DragDropProviderScope>;
|
|
7
|
+
export default DragDropProviderScope;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<script lang="ts" generics="T">import { DragDropProvider, DragOverlay } from "@dnd-kit/svelte";
|
|
2
|
+
import { RestrictToHorizontalAxis, RestrictToVerticalAxis } from "@dnd-kit/abstract/modifiers";
|
|
3
|
+
import { isSortableOperation } from "@dnd-kit/dom/sortable";
|
|
4
|
+
import { getContext } from "svelte";
|
|
5
|
+
import { moveArrayItem } from "../useSortable/sortable-utils.js";
|
|
6
|
+
import { SORTABLE_CONTEXT_KEY, SORTABLE_GROUP_CONTEXT_KEY } from "./sortable-context.js";
|
|
7
|
+
let { children, overlay } = $props();
|
|
8
|
+
const ctx = getContext(SORTABLE_CONTEXT_KEY);
|
|
9
|
+
const groupCtx = getContext(SORTABLE_GROUP_CONTEXT_KEY);
|
|
10
|
+
const isGrouped = !!groupCtx;
|
|
11
|
+
// Register/unregister overlay snippet with the parent SortableGroup
|
|
12
|
+
$effect(() => {
|
|
13
|
+
if (groupCtx && overlay) {
|
|
14
|
+
groupCtx.registerOverlay(ctx.groupId, overlay);
|
|
15
|
+
return () => {
|
|
16
|
+
groupCtx.unregisterOverlay(ctx.groupId);
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
const modifiers = $derived(ctx.getAxis() === "horizontal" ? [RestrictToHorizontalAxis] : ctx.getAxis() === "vertical" ? [RestrictToVerticalAxis] : []);
|
|
21
|
+
function handleDragStart(event) {
|
|
22
|
+
const source = event.operation.source;
|
|
23
|
+
if (!source) return;
|
|
24
|
+
const items = ctx.getItems();
|
|
25
|
+
const ownsItem = items.some((entry) => String(ctx.getId(entry)) === String(source.id));
|
|
26
|
+
if (!ownsItem) return;
|
|
27
|
+
ctx.setDraggingId(source.id);
|
|
28
|
+
groupCtx?.setDraggingGroupId(ctx.groupId);
|
|
29
|
+
}
|
|
30
|
+
function handleDragOver(event) {
|
|
31
|
+
// During drag, reorder items optimistically so Svelte re-renders them
|
|
32
|
+
// in the new order — dnd-kit then animates the transition via WAAPI.
|
|
33
|
+
// Without this, items only reorder on drop and there is no push animation.
|
|
34
|
+
if (ctx.isDisabled() || !isSortableOperation(event.operation)) return;
|
|
35
|
+
const { source, target } = event.operation;
|
|
36
|
+
if (!source || !target || source.index === target.index) return;
|
|
37
|
+
// Only handle items that belong to this list
|
|
38
|
+
const items = ctx.getItems();
|
|
39
|
+
const sourceInList = items.some((entry) => String(ctx.getId(entry)) === String(source.id));
|
|
40
|
+
if (!sourceInList) return;
|
|
41
|
+
ctx.onReorder(moveArrayItem(items, source.index, target.index));
|
|
42
|
+
}
|
|
43
|
+
function handleDragEnd(event) {
|
|
44
|
+
const { source } = event.operation;
|
|
45
|
+
// Let the drop animation play (250ms default) before clearing draggingId
|
|
46
|
+
// Items are already in correct order from handleDragOver — nothing to reorder here.
|
|
47
|
+
setTimeout(() => {
|
|
48
|
+
if (ctx.getDraggingId() === source?.id) {
|
|
49
|
+
ctx.setDraggingId(null);
|
|
50
|
+
}
|
|
51
|
+
}, 250);
|
|
52
|
+
}
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
{#if isGrouped}
|
|
56
|
+
{@render children?.()}
|
|
57
|
+
{:else}
|
|
58
|
+
<DragDropProvider {modifiers} onDragStart={handleDragStart} onDragOver={handleDragOver} onDragEnd={handleDragEnd}>
|
|
59
|
+
{@render children?.()}
|
|
60
|
+
{#if overlay}
|
|
61
|
+
<DragOverlay>
|
|
62
|
+
{#snippet children(draggable)}
|
|
63
|
+
{@render overlay({ item: draggable.data as T })}
|
|
64
|
+
{/snippet}
|
|
65
|
+
</DragOverlay>
|
|
66
|
+
{/if}
|
|
67
|
+
</DragDropProvider>
|
|
68
|
+
{/if}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Snippet } from 'svelte';
|
|
2
|
+
declare function $$render<T>(): {
|
|
3
|
+
props: {
|
|
4
|
+
children?: Snippet;
|
|
5
|
+
overlay?: Snippet<[{
|
|
6
|
+
item: T;
|
|
7
|
+
}]>;
|
|
8
|
+
};
|
|
9
|
+
exports: {};
|
|
10
|
+
bindings: "";
|
|
11
|
+
slots: {};
|
|
12
|
+
events: {};
|
|
13
|
+
};
|
|
14
|
+
declare class __sveltets_Render<T> {
|
|
15
|
+
props(): ReturnType<typeof $$render<T>>['props'];
|
|
16
|
+
events(): ReturnType<typeof $$render<T>>['events'];
|
|
17
|
+
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
18
|
+
bindings(): "";
|
|
19
|
+
exports(): {};
|
|
20
|
+
}
|
|
21
|
+
interface $$IsomorphicComponent {
|
|
22
|
+
new <T>(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']>> & {
|
|
23
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
24
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
25
|
+
<T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
26
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
27
|
+
}
|
|
28
|
+
declare const SortableProvider: $$IsomorphicComponent;
|
|
29
|
+
type SortableProvider<T> = InstanceType<typeof SortableProvider<T>>;
|
|
30
|
+
export default SortableProvider;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DragPayload, UseDroppableOptions } from '../useDragDrop/useDragDrop.svelte.js';
|
|
2
|
+
export declare const DRAG_DROP_CONTEXT_KEY: unique symbol;
|
|
3
|
+
export interface DragDropContextValue {
|
|
4
|
+
registerDroppable: <T>(id: string, options: UseDroppableOptions<T>) => void;
|
|
5
|
+
unregisterDroppable: (id: string) => void;
|
|
6
|
+
setDraggingId: (id: string | null) => void;
|
|
7
|
+
getDroppable: <T>(id: string) => UseDroppableOptions<T> | undefined;
|
|
8
|
+
toPayload: (source: {
|
|
9
|
+
id: string | number;
|
|
10
|
+
data?: unknown;
|
|
11
|
+
}) => DragPayload;
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const DRAG_DROP_CONTEXT_KEY = Symbol('sv5ui-plus-drag-drop');
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { UseSortableOptions } from '../useSortable/useSortable.svelte.js';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
export declare const SORTABLE_CONTEXT_KEY: unique symbol;
|
|
4
|
+
export declare const SORTABLE_GROUP_CONTEXT_KEY: unique symbol;
|
|
5
|
+
export interface SortableGroupContextValue {
|
|
6
|
+
draggingId: string | number | null;
|
|
7
|
+
registerOverlay: (groupId: string, snippet: Snippet<[{
|
|
8
|
+
item: unknown;
|
|
9
|
+
}]>) => void;
|
|
10
|
+
unregisterOverlay: (groupId: string) => void;
|
|
11
|
+
getOverlay: (groupId: string) => Snippet<[{
|
|
12
|
+
item: unknown;
|
|
13
|
+
}]> | undefined;
|
|
14
|
+
setDraggingGroupId: (groupId: string | null) => void;
|
|
15
|
+
}
|
|
16
|
+
export interface SortableContextValue<T> {
|
|
17
|
+
groupId: string;
|
|
18
|
+
getItems: UseSortableOptions<T>['getItems'];
|
|
19
|
+
getId: UseSortableOptions<T>['getId'];
|
|
20
|
+
onReorder: UseSortableOptions<T>['onReorder'];
|
|
21
|
+
isDisabled: () => boolean;
|
|
22
|
+
getAxis: () => 'vertical' | 'horizontal' | 'grid';
|
|
23
|
+
getHandle: () => string | undefined;
|
|
24
|
+
setDraggingId: (id: string | number | null) => void;
|
|
25
|
+
getDraggingId: () => string | number | null;
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useDragDrop.svelte.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useDragDrop.svelte.js';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Action } from 'svelte/action';
|
|
2
|
+
import type { Component } from 'svelte';
|
|
3
|
+
import { type Snippet } from 'svelte';
|
|
4
|
+
export interface DragPayload<T = unknown> {
|
|
5
|
+
id: string;
|
|
6
|
+
data?: T;
|
|
7
|
+
}
|
|
8
|
+
export interface UseDraggableOptions<T = unknown> {
|
|
9
|
+
/** Unique id for the draggable element. */
|
|
10
|
+
id: string;
|
|
11
|
+
/** Source drop zone id — used as the draggable type for cross-container matching. */
|
|
12
|
+
container: string;
|
|
13
|
+
data?: T;
|
|
14
|
+
disabled?: boolean | (() => boolean);
|
|
15
|
+
handle?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface UseDroppableOptions<T = unknown> {
|
|
18
|
+
id: string;
|
|
19
|
+
onDrop: (payload: DragPayload<T>) => void;
|
|
20
|
+
accept?: (payload: DragPayload<T>) => boolean;
|
|
21
|
+
disabled?: boolean | (() => boolean);
|
|
22
|
+
}
|
|
23
|
+
export interface UseDragDropReturn {
|
|
24
|
+
/**
|
|
25
|
+
* Wrap drag-and-drop markup with this provider.
|
|
26
|
+
* Required — [@dnd-kit/svelte](https://clauderic-dnd-kit.mintlify.app/frameworks/svelte) needs a DragDropProvider ancestor.
|
|
27
|
+
*/
|
|
28
|
+
readonly Provider: Component<{
|
|
29
|
+
children?: Snippet;
|
|
30
|
+
}>;
|
|
31
|
+
readonly draggingId: string | null;
|
|
32
|
+
readonly draggable: Action<HTMLElement, UseDraggableOptions>;
|
|
33
|
+
readonly droppable: Action<HTMLElement, UseDroppableOptions>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Cross-container drag and drop powered by [@dnd-kit/svelte](https://clauderic-dnd-kit.mintlify.app/frameworks/svelte).
|
|
37
|
+
*
|
|
38
|
+
* Wrap markup in `dragDrop.Provider`, then attach `draggable` and `droppable` actions.
|
|
39
|
+
*/
|
|
40
|
+
export declare function useDragDrop(): UseDragDropReturn;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { setContext } from 'svelte';
|
|
2
|
+
import { createDraggable, createDroppable } from '@dnd-kit/svelte';
|
|
3
|
+
import DragDropProviderScope from '../internal/DragDropProviderScope.svelte';
|
|
4
|
+
import { DRAG_DROP_CONTEXT_KEY } from '../internal/drag-drop-context.js';
|
|
5
|
+
/**
|
|
6
|
+
* Cross-container drag and drop powered by [@dnd-kit/svelte](https://clauderic-dnd-kit.mintlify.app/frameworks/svelte).
|
|
7
|
+
*
|
|
8
|
+
* Wrap markup in `dragDrop.Provider`, then attach `draggable` and `droppable` actions.
|
|
9
|
+
*/
|
|
10
|
+
export function useDragDrop() {
|
|
11
|
+
let draggingId = $state(null);
|
|
12
|
+
const droppables = new Map();
|
|
13
|
+
const context = {
|
|
14
|
+
registerDroppable(id, options) {
|
|
15
|
+
droppables.set(id, options);
|
|
16
|
+
},
|
|
17
|
+
unregisterDroppable(id) {
|
|
18
|
+
droppables.delete(id);
|
|
19
|
+
},
|
|
20
|
+
setDraggingId(id) {
|
|
21
|
+
draggingId = id;
|
|
22
|
+
},
|
|
23
|
+
getDroppable(id) {
|
|
24
|
+
return droppables.get(id);
|
|
25
|
+
},
|
|
26
|
+
toPayload(source) {
|
|
27
|
+
return {
|
|
28
|
+
id: String(source.id),
|
|
29
|
+
data: source.data
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
setContext(DRAG_DROP_CONTEXT_KEY, context);
|
|
34
|
+
const draggableAction = (node, initialOptions) => {
|
|
35
|
+
let currentOptions = initialOptions;
|
|
36
|
+
function isDisabled() {
|
|
37
|
+
return typeof currentOptions.disabled === 'function'
|
|
38
|
+
? currentOptions.disabled()
|
|
39
|
+
: (currentOptions.disabled ?? false);
|
|
40
|
+
}
|
|
41
|
+
const drag = createDraggable({
|
|
42
|
+
id: currentOptions.id,
|
|
43
|
+
type: currentOptions.container,
|
|
44
|
+
data: (currentOptions.data ?? {}),
|
|
45
|
+
disabled: isDisabled()
|
|
46
|
+
});
|
|
47
|
+
const detach = drag.attach(node);
|
|
48
|
+
let detachHandle;
|
|
49
|
+
function bindHandle() {
|
|
50
|
+
detachHandle?.();
|
|
51
|
+
const selector = currentOptions.handle;
|
|
52
|
+
if (!selector) {
|
|
53
|
+
drag.draggable.handle = undefined;
|
|
54
|
+
detachHandle = undefined;
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const handle = node.querySelector(selector);
|
|
58
|
+
if (!handle) {
|
|
59
|
+
drag.draggable.handle = undefined;
|
|
60
|
+
detachHandle = undefined;
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
detachHandle = drag.attachHandle(handle);
|
|
64
|
+
}
|
|
65
|
+
bindHandle();
|
|
66
|
+
return {
|
|
67
|
+
update(newOptions) {
|
|
68
|
+
currentOptions = newOptions;
|
|
69
|
+
drag.draggable.id = newOptions.id;
|
|
70
|
+
drag.draggable.type = newOptions.container;
|
|
71
|
+
drag.draggable.data = (newOptions.data ?? {});
|
|
72
|
+
drag.draggable.disabled = isDisabled();
|
|
73
|
+
bindHandle();
|
|
74
|
+
},
|
|
75
|
+
destroy() {
|
|
76
|
+
detach();
|
|
77
|
+
detachHandle?.();
|
|
78
|
+
node.removeAttribute('data-dragging');
|
|
79
|
+
if (draggingId === currentOptions.id) {
|
|
80
|
+
draggingId = null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
const droppableAction = (node, initialOptions) => {
|
|
86
|
+
let currentOptions = initialOptions;
|
|
87
|
+
function isDisabled() {
|
|
88
|
+
return typeof currentOptions.disabled === 'function'
|
|
89
|
+
? currentOptions.disabled()
|
|
90
|
+
: (currentOptions.disabled ?? false);
|
|
91
|
+
}
|
|
92
|
+
context.registerDroppable(currentOptions.id, currentOptions);
|
|
93
|
+
const drop = createDroppable({
|
|
94
|
+
id: currentOptions.id,
|
|
95
|
+
disabled: isDisabled(),
|
|
96
|
+
accept(source) {
|
|
97
|
+
const payload = context.toPayload({ id: source.id, data: source.data });
|
|
98
|
+
if (currentOptions.accept) {
|
|
99
|
+
return currentOptions.accept(payload);
|
|
100
|
+
}
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
const detach = drop.attach(node);
|
|
105
|
+
return {
|
|
106
|
+
update(newOptions) {
|
|
107
|
+
context.unregisterDroppable(currentOptions.id);
|
|
108
|
+
currentOptions = newOptions;
|
|
109
|
+
context.registerDroppable(currentOptions.id, currentOptions);
|
|
110
|
+
drop.droppable.id = newOptions.id;
|
|
111
|
+
drop.droppable.disabled = isDisabled();
|
|
112
|
+
},
|
|
113
|
+
destroy() {
|
|
114
|
+
detach();
|
|
115
|
+
context.unregisterDroppable(currentOptions.id);
|
|
116
|
+
node.removeAttribute('data-droppable-active');
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
return {
|
|
121
|
+
get draggingId() {
|
|
122
|
+
return draggingId;
|
|
123
|
+
},
|
|
124
|
+
Provider: DragDropProviderScope,
|
|
125
|
+
draggable: draggableAction,
|
|
126
|
+
droppable: droppableAction
|
|
127
|
+
};
|
|
128
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function moveArrayItem<T>(items: T[], fromIndex: number, toIndex: number): T[];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function moveArrayItem(items, fromIndex, toIndex) {
|
|
2
|
+
if (fromIndex === toIndex ||
|
|
3
|
+
fromIndex < 0 ||
|
|
4
|
+
toIndex < 0 ||
|
|
5
|
+
fromIndex >= items.length ||
|
|
6
|
+
toIndex >= items.length) {
|
|
7
|
+
return items;
|
|
8
|
+
}
|
|
9
|
+
const next = [...items];
|
|
10
|
+
const [removed] = next.splice(fromIndex, 1);
|
|
11
|
+
next.splice(toIndex, 0, removed);
|
|
12
|
+
return next;
|
|
13
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Action } from 'svelte/action';
|
|
2
|
+
import type { Component } from 'svelte';
|
|
3
|
+
import { type Snippet } from 'svelte';
|
|
4
|
+
export interface UseSortableItemParams<T> {
|
|
5
|
+
index: number;
|
|
6
|
+
item: T;
|
|
7
|
+
}
|
|
8
|
+
export interface UseSortableOptions<T> {
|
|
9
|
+
/** Reactive getter for the current item array. */
|
|
10
|
+
getItems: () => T[];
|
|
11
|
+
/** Stable id for each item — used for keys and reorder tracking. */
|
|
12
|
+
getId: (item: T) => string | number;
|
|
13
|
+
/** Called with the reordered array after a successful drop. */
|
|
14
|
+
onReorder: (items: T[]) => void;
|
|
15
|
+
/**
|
|
16
|
+
* Drag axis.
|
|
17
|
+
* @default 'vertical'
|
|
18
|
+
*/
|
|
19
|
+
axis?: 'vertical' | 'horizontal' | 'grid' | (() => 'vertical' | 'horizontal' | 'grid');
|
|
20
|
+
/**
|
|
21
|
+
* CSS selector for the drag handle, relative to each item.
|
|
22
|
+
* When omitted, the whole item is draggable.
|
|
23
|
+
* @example '[data-sortable-handle]'
|
|
24
|
+
*/
|
|
25
|
+
handle?: string | (() => string | undefined);
|
|
26
|
+
/**
|
|
27
|
+
* Disable sorting.
|
|
28
|
+
* @default false
|
|
29
|
+
*/
|
|
30
|
+
disabled?: boolean | (() => boolean);
|
|
31
|
+
/**
|
|
32
|
+
* Group ID for the sortable list. Used for cross-list drag and drop.
|
|
33
|
+
* If not provided, a unique ID is generated.
|
|
34
|
+
*/
|
|
35
|
+
group?: string | (() => string | undefined);
|
|
36
|
+
}
|
|
37
|
+
export interface UseSortableReturn<T> {
|
|
38
|
+
/**
|
|
39
|
+
* Wrap sortable markup with this provider.
|
|
40
|
+
* Required — [@dnd-kit/svelte](https://clauderic-dnd-kit.mintlify.app/frameworks/svelte) needs a DragDropProvider ancestor.
|
|
41
|
+
*/
|
|
42
|
+
readonly Provider: Component<{
|
|
43
|
+
children?: Snippet;
|
|
44
|
+
overlay?: Snippet<[{
|
|
45
|
+
item: T;
|
|
46
|
+
}]>;
|
|
47
|
+
}>;
|
|
48
|
+
/** Attach to the list container element (optional wrapper). */
|
|
49
|
+
readonly container: Action<HTMLElement>;
|
|
50
|
+
/** Attach to each sortable row with the current index and item. */
|
|
51
|
+
readonly item: Action<HTMLElement, UseSortableItemParams<T>>;
|
|
52
|
+
/** Id of the item currently being dragged, or null. */
|
|
53
|
+
readonly draggingId: string | number | null;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Sortable list hook powered by [@dnd-kit/svelte](https://clauderic-dnd-kit.mintlify.app/frameworks/svelte).
|
|
57
|
+
*
|
|
58
|
+
* Wrap markup in `sortable.Provider`, then attach `use:sortable.item` to each row.
|
|
59
|
+
*/
|
|
60
|
+
export declare function useSortable<T>(options: UseSortableOptions<T>): UseSortableReturn<T>;
|