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
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { setContext } from 'svelte';
|
|
2
|
+
import { CollisionPriority } from '@dnd-kit/abstract';
|
|
3
|
+
import { createDroppable } from '@dnd-kit/svelte';
|
|
4
|
+
import { createSortable } from '@dnd-kit/svelte/sortable';
|
|
5
|
+
import SortableProvider from '../internal/SortableProvider.svelte';
|
|
6
|
+
import { SORTABLE_CONTEXT_KEY, SORTABLE_GROUP_CONTEXT_KEY } from '../internal/sortable-context.js';
|
|
7
|
+
import { getContext } from 'svelte';
|
|
8
|
+
let sortableGroupCounter = 0;
|
|
9
|
+
/**
|
|
10
|
+
* Sortable list hook powered by [@dnd-kit/svelte](https://clauderic-dnd-kit.mintlify.app/frameworks/svelte).
|
|
11
|
+
*
|
|
12
|
+
* Wrap markup in `sortable.Provider`, then attach `use:sortable.item` to each row.
|
|
13
|
+
*/
|
|
14
|
+
export function useSortable(options) {
|
|
15
|
+
const { getItems, getId, onReorder } = options;
|
|
16
|
+
function getGroup() {
|
|
17
|
+
const group = options.group;
|
|
18
|
+
return ((typeof group === 'function' ? group() : group) ??
|
|
19
|
+
`sv5ui-plus-sortable-${++sortableGroupCounter}`);
|
|
20
|
+
}
|
|
21
|
+
const groupId = getGroup();
|
|
22
|
+
let localDraggingId = $state(null);
|
|
23
|
+
let listNode = $state(null);
|
|
24
|
+
// Optional group context tracking draggingId globally
|
|
25
|
+
const groupCtx = getContext(SORTABLE_GROUP_CONTEXT_KEY);
|
|
26
|
+
const draggingId = $derived(groupCtx ? groupCtx.draggingId : localDraggingId);
|
|
27
|
+
function getAxis() {
|
|
28
|
+
const axis = options.axis;
|
|
29
|
+
return typeof axis === 'function' ? axis() : (axis ?? 'vertical');
|
|
30
|
+
}
|
|
31
|
+
function getHandle() {
|
|
32
|
+
const handle = options.handle;
|
|
33
|
+
return typeof handle === 'function' ? handle() : handle;
|
|
34
|
+
}
|
|
35
|
+
function isDisabled() {
|
|
36
|
+
return typeof options.disabled === 'function'
|
|
37
|
+
? options.disabled()
|
|
38
|
+
: (options.disabled ?? false);
|
|
39
|
+
}
|
|
40
|
+
const context = {
|
|
41
|
+
groupId,
|
|
42
|
+
getItems,
|
|
43
|
+
getId,
|
|
44
|
+
onReorder,
|
|
45
|
+
isDisabled,
|
|
46
|
+
getAxis,
|
|
47
|
+
getHandle,
|
|
48
|
+
setDraggingId(id) {
|
|
49
|
+
localDraggingId = id;
|
|
50
|
+
},
|
|
51
|
+
getDraggingId: () => localDraggingId
|
|
52
|
+
};
|
|
53
|
+
setContext(SORTABLE_CONTEXT_KEY, context);
|
|
54
|
+
$effect(() => {
|
|
55
|
+
const node = listNode;
|
|
56
|
+
if (!node)
|
|
57
|
+
return;
|
|
58
|
+
if (draggingId != null) {
|
|
59
|
+
node.setAttribute('data-sortable-active', 'true');
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
node.removeAttribute('data-sortable-active');
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
const container = (node) => {
|
|
66
|
+
listNode = node;
|
|
67
|
+
const droppable = createDroppable({
|
|
68
|
+
get id() {
|
|
69
|
+
return getGroup();
|
|
70
|
+
},
|
|
71
|
+
type: 'sortable-group',
|
|
72
|
+
collisionPriority: CollisionPriority.Low
|
|
73
|
+
});
|
|
74
|
+
const detach = droppable.attach(node);
|
|
75
|
+
return {
|
|
76
|
+
destroy() {
|
|
77
|
+
detach();
|
|
78
|
+
if (listNode === node) {
|
|
79
|
+
listNode = null;
|
|
80
|
+
}
|
|
81
|
+
node.removeAttribute('data-sortable-active');
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
const item = (node, params) => {
|
|
86
|
+
let current = params;
|
|
87
|
+
const sortable = createSortable({
|
|
88
|
+
get id() {
|
|
89
|
+
return String(getId(current.item));
|
|
90
|
+
},
|
|
91
|
+
get index() {
|
|
92
|
+
return current.index;
|
|
93
|
+
},
|
|
94
|
+
get group() {
|
|
95
|
+
return getGroup();
|
|
96
|
+
},
|
|
97
|
+
get data() {
|
|
98
|
+
return current.item;
|
|
99
|
+
},
|
|
100
|
+
get disabled() {
|
|
101
|
+
return isDisabled();
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
const detach = sortable.attach(node);
|
|
105
|
+
let detachHandle;
|
|
106
|
+
function bindHandle() {
|
|
107
|
+
detachHandle?.();
|
|
108
|
+
const selector = getHandle();
|
|
109
|
+
if (!selector) {
|
|
110
|
+
sortable.sortable.handle = undefined;
|
|
111
|
+
detachHandle = undefined;
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const handle = node.querySelector(selector);
|
|
115
|
+
if (!handle) {
|
|
116
|
+
sortable.sortable.handle = undefined;
|
|
117
|
+
detachHandle = undefined;
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
detachHandle = sortable.attachHandle(handle);
|
|
121
|
+
}
|
|
122
|
+
bindHandle();
|
|
123
|
+
node.setAttribute('data-sortable-item', '');
|
|
124
|
+
node.dataset.sortableId = String(getId(current.item));
|
|
125
|
+
return {
|
|
126
|
+
update(nextParams) {
|
|
127
|
+
current = nextParams;
|
|
128
|
+
sortable.sortable.id = String(getId(nextParams.item));
|
|
129
|
+
sortable.sortable.index = nextParams.index;
|
|
130
|
+
sortable.sortable.data = nextParams.item;
|
|
131
|
+
sortable.sortable.disabled = isDisabled();
|
|
132
|
+
node.dataset.sortableId = String(getId(nextParams.item));
|
|
133
|
+
bindHandle();
|
|
134
|
+
},
|
|
135
|
+
destroy() {
|
|
136
|
+
detach();
|
|
137
|
+
detachHandle?.();
|
|
138
|
+
node.removeAttribute('data-sortable-item');
|
|
139
|
+
delete node.dataset.sortableId;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
return {
|
|
144
|
+
Provider: SortableProvider,
|
|
145
|
+
container,
|
|
146
|
+
item,
|
|
147
|
+
get draggingId() {
|
|
148
|
+
return draggingId;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function toGetter<T>(value: T | (() => T)): () => T;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export * from './components/BentoGrid/index.js';
|
|
2
|
+
export * from './components/Chart/index.js';
|
|
3
|
+
export * from './components/Chat/index.js';
|
|
4
|
+
export * from './components/CodeBlock/index.js';
|
|
5
|
+
export * from './components/ColorPicker/index.js';
|
|
6
|
+
export * from './components/ConfirmDialog/index.js';
|
|
7
|
+
export * from './components/Fonts/index.js';
|
|
8
|
+
export * from './components/List/index.js';
|
|
9
|
+
export * from './components/LocaleButton/index.js';
|
|
10
|
+
export * from './components/Marquee/index.js';
|
|
11
|
+
export * from './components/NavigationMenu/index.js';
|
|
12
|
+
export * from './components/NumberTicker/index.js';
|
|
13
|
+
export * from './components/PasswordInput/index.js';
|
|
14
|
+
export * from './components/Prose/index.js';
|
|
15
|
+
export * from './components/Resizable/index.js';
|
|
16
|
+
export * from './components/ScrollArea/index.js';
|
|
17
|
+
export * from './components/Search/index.js';
|
|
18
|
+
export * from './components/SortableGroup/index.js';
|
|
19
|
+
export * from './components/SortableList/index.js';
|
|
20
|
+
export * from './components/Spotlight/index.js';
|
|
21
|
+
export * from './components/TableBulkActionBar/index.js';
|
|
22
|
+
export * from './components/TreeView/index.js';
|
|
23
|
+
export * from './hooks/useSortable/index.js';
|
|
24
|
+
export * from './hooks/useDragDrop/index.js';
|
|
25
|
+
export * from './adapters/notify.js';
|
|
26
|
+
export { defineConfig as defineSV5UIPlusConfig, getConfig as getSV5UIPlusConfig, resetConfig as resetSV5UIPlusConfig } from './config.js';
|
|
27
|
+
export type { UIConfig as SV5UIPlusConfig } from './config.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// SV5UI Plus-exclusive components
|
|
2
|
+
export * from './components/BentoGrid/index.js';
|
|
3
|
+
export * from './components/Chart/index.js';
|
|
4
|
+
export * from './components/Chat/index.js';
|
|
5
|
+
export * from './components/CodeBlock/index.js';
|
|
6
|
+
export * from './components/ColorPicker/index.js';
|
|
7
|
+
export * from './components/ConfirmDialog/index.js';
|
|
8
|
+
export * from './components/Fonts/index.js';
|
|
9
|
+
export * from './components/List/index.js';
|
|
10
|
+
export * from './components/LocaleButton/index.js';
|
|
11
|
+
export * from './components/Marquee/index.js';
|
|
12
|
+
export * from './components/NavigationMenu/index.js';
|
|
13
|
+
export * from './components/NumberTicker/index.js';
|
|
14
|
+
export * from './components/PasswordInput/index.js';
|
|
15
|
+
export * from './components/Prose/index.js';
|
|
16
|
+
export * from './components/Resizable/index.js';
|
|
17
|
+
export * from './components/ScrollArea/index.js';
|
|
18
|
+
export * from './components/Search/index.js';
|
|
19
|
+
export * from './components/SortableGroup/index.js';
|
|
20
|
+
export * from './components/SortableList/index.js';
|
|
21
|
+
export * from './components/Spotlight/index.js';
|
|
22
|
+
export * from './components/TableBulkActionBar/index.js';
|
|
23
|
+
export * from './components/TreeView/index.js';
|
|
24
|
+
// SV5UI Plus-exclusive hooks
|
|
25
|
+
export * from './hooks/useSortable/index.js';
|
|
26
|
+
export * from './hooks/useDragDrop/index.js';
|
|
27
|
+
// Adapters
|
|
28
|
+
export * from './adapters/notify.js';
|
|
29
|
+
// Addon configuration. Core SV5UI configuration remains `defineConfig` from `sv5ui`.
|
|
30
|
+
export { defineConfig as defineSV5UIPlusConfig, getConfig as getSV5UIPlusConfig, resetConfig as resetSV5UIPlusConfig } from './config.js';
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { access, copyFile, mkdir } from 'node:fs/promises'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import { fileURLToPath } from 'node:url'
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
8
|
+
const __dirname = path.dirname(__filename)
|
|
9
|
+
|
|
10
|
+
const args = new Set(process.argv.slice(2))
|
|
11
|
+
const force = args.has('--force')
|
|
12
|
+
const cwd = process.cwd()
|
|
13
|
+
const targetDir = path.join(cwd, '.cursor')
|
|
14
|
+
const targetPath = path.join(targetDir, 'mcp.json')
|
|
15
|
+
|
|
16
|
+
async function resolveTemplatePath() {
|
|
17
|
+
const candidates = [
|
|
18
|
+
path.join(__dirname, 'cursor.mcp.json'),
|
|
19
|
+
path.resolve(__dirname, '../../dist/mcp/cursor.mcp.json')
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
for (const candidate of candidates) {
|
|
23
|
+
try {
|
|
24
|
+
await access(candidate)
|
|
25
|
+
return candidate
|
|
26
|
+
} catch {
|
|
27
|
+
// Try next candidate.
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
throw new Error('Could not find cursor.mcp.json template for SV5UI Plus MCP.')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function main() {
|
|
35
|
+
const templatePath = await resolveTemplatePath()
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
await access(targetPath)
|
|
39
|
+
if (!force) {
|
|
40
|
+
console.error(`Refusing to overwrite existing file: ${targetPath}`)
|
|
41
|
+
console.error('Run again with --force if you want to replace it.')
|
|
42
|
+
process.exitCode = 1
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
} catch {
|
|
46
|
+
// Continue and attempt to create the file.
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
await mkdir(targetDir, { recursive: true })
|
|
50
|
+
await copyFile(templatePath, targetPath)
|
|
51
|
+
|
|
52
|
+
console.log(`Installed SV5UI Plus MCP template at ${targetPath}`)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
await main()
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { readFile } from 'node:fs/promises'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import { fileURLToPath } from 'node:url'
|
|
6
|
+
|
|
7
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
8
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
9
|
+
import { codeToHtml } from 'shiki'
|
|
10
|
+
import { z } from 'zod'
|
|
11
|
+
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
13
|
+
const __dirname = path.dirname(__filename)
|
|
14
|
+
const repoRoot = path.resolve(__dirname, '../../')
|
|
15
|
+
const packagedDataPath = path.resolve(__dirname, './sv5ui-plus-docs.data.json')
|
|
16
|
+
|
|
17
|
+
let packagedDataPromise
|
|
18
|
+
|
|
19
|
+
function resolveRepoPath(relativePath) {
|
|
20
|
+
const fullPath = path.resolve(repoRoot, relativePath)
|
|
21
|
+
if (!fullPath.startsWith(repoRoot)) {
|
|
22
|
+
throw new Error('Invalid path')
|
|
23
|
+
}
|
|
24
|
+
return fullPath
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function readJsonIfExists(filePath) {
|
|
28
|
+
try {
|
|
29
|
+
const source = await readFile(filePath, 'utf8')
|
|
30
|
+
return JSON.parse(source)
|
|
31
|
+
} catch (error) {
|
|
32
|
+
if (error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT') {
|
|
33
|
+
return null
|
|
34
|
+
}
|
|
35
|
+
throw error
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function getPackagedData() {
|
|
40
|
+
packagedDataPromise ??= readJsonIfExists(packagedDataPath)
|
|
41
|
+
return await packagedDataPromise
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function normalizeCode(code) {
|
|
45
|
+
const lines = code.replaceAll('\r\n', '\n').split('\n')
|
|
46
|
+
const firstNonEmpty = lines.findIndex((line) => line.trim().length > 0)
|
|
47
|
+
if (firstNonEmpty === -1) return ''
|
|
48
|
+
|
|
49
|
+
let lastNonEmptyFromEnd = 0
|
|
50
|
+
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
51
|
+
if (lines[index].trim().length > 0) break
|
|
52
|
+
lastNonEmptyFromEnd += 1
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const trimmed = lines.slice(firstNonEmpty, lines.length - lastNonEmptyFromEnd)
|
|
56
|
+
const indents = trimmed
|
|
57
|
+
.filter((line) => line.trim().length > 0)
|
|
58
|
+
.map((line) => line.match(/^(\s*)/)?.[1].length ?? 0)
|
|
59
|
+
|
|
60
|
+
const minIndent = indents.length > 0 ? Math.min(...indents) : 0
|
|
61
|
+
return trimmed
|
|
62
|
+
.map((line) => line.slice(minIndent))
|
|
63
|
+
.join('\n')
|
|
64
|
+
.trim()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function unwrapPreviewWrappers(source) {
|
|
68
|
+
let current = source.trim()
|
|
69
|
+
|
|
70
|
+
const stripPrefix = (token) => token.split(':').at(-1) ?? token
|
|
71
|
+
const isPresentationToken = (token) => {
|
|
72
|
+
const t = stripPrefix(token)
|
|
73
|
+
if (t.length === 0) return false
|
|
74
|
+
|
|
75
|
+
if (t.startsWith('max-w-') || t.startsWith('min-w-') || t.startsWith('w-')) return true
|
|
76
|
+
if (t.startsWith('max-h-') || t.startsWith('min-h-') || t.startsWith('h-')) return true
|
|
77
|
+
if (/^(m|p)[trblxyse]?-\d+$/.test(t)) return true
|
|
78
|
+
if (t.startsWith('gap-') || t.startsWith('space-')) return true
|
|
79
|
+
if (t.startsWith('overflow-')) return true
|
|
80
|
+
if (t === 'grid' || t.startsWith('grid-')) return true
|
|
81
|
+
if (t === 'flex' || t === 'inline-flex' || t.startsWith('flex-')) return true
|
|
82
|
+
if (t.startsWith('items-') || t.startsWith('justify-') || t.startsWith('content-'))
|
|
83
|
+
return true
|
|
84
|
+
if (t.startsWith('self-') || t.startsWith('place-')) return true
|
|
85
|
+
if (t.startsWith('rounded')) return true
|
|
86
|
+
if (t.startsWith('border') || t.startsWith('ring') || t.startsWith('shadow')) return true
|
|
87
|
+
if (t === 'bg-transparent') return true
|
|
88
|
+
if (t.startsWith('bg-surface')) return true
|
|
89
|
+
if (t.startsWith('bg-[')) return true
|
|
90
|
+
if (t.startsWith('text-') || t.startsWith('font-') || t.startsWith('leading-')) return true
|
|
91
|
+
if (t.startsWith('tracking-')) return true
|
|
92
|
+
if (t === 'uppercase' || t === 'lowercase' || t === 'capitalize') return true
|
|
93
|
+
if (t.startsWith('opacity-')) return true
|
|
94
|
+
if (t.startsWith('backdrop-blur') || t.startsWith('blur')) return true
|
|
95
|
+
if (t.startsWith('aspect-') || t.startsWith('object-')) return true
|
|
96
|
+
if (t.startsWith('size-')) return true
|
|
97
|
+
if (t.startsWith('[') && t.includes(']:')) return true
|
|
98
|
+
|
|
99
|
+
return false
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
for (let pass = 0; pass < 3; pass += 1) {
|
|
103
|
+
const match = current.match(/^<div\b([^>]*)>([\s\S]*)<\/div>$/)
|
|
104
|
+
if (!match) break
|
|
105
|
+
|
|
106
|
+
const attrs = match[1]
|
|
107
|
+
const attrsWithoutClass = attrs
|
|
108
|
+
.replace(/\s*\bclass=(?:"[^"]*"|'[^']*')/, '')
|
|
109
|
+
.replace(/\s+/g, ' ')
|
|
110
|
+
.trim()
|
|
111
|
+
if (attrsWithoutClass.length > 0) break
|
|
112
|
+
|
|
113
|
+
const classMatch = attrs.match(/\bclass=(?:"([^"]*)"|'([^']*)')/)
|
|
114
|
+
const classValue = (classMatch?.[1] ?? classMatch?.[2] ?? '').trim()
|
|
115
|
+
const tokens = classValue.length > 0 ? classValue.split(/\s+/) : []
|
|
116
|
+
|
|
117
|
+
const isPreviewBg = tokens.some((token) => token.startsWith('bg-surface-container'))
|
|
118
|
+
const isBordered = tokens.some((token) => token.startsWith('border-outline-variant'))
|
|
119
|
+
const isRounded = tokens.some((token) => token.startsWith('rounded'))
|
|
120
|
+
const hasPadding = tokens.some((token) => /^p[trblxy]?-\d+$/.test(token))
|
|
121
|
+
const isMaxWidth = tokens.some((token) => token.startsWith('max-w-'))
|
|
122
|
+
const isOverflow = tokens.some((token) => token.startsWith('overflow-'))
|
|
123
|
+
const isPresentationOnly = tokens.length > 0 && tokens.every(isPresentationToken)
|
|
124
|
+
|
|
125
|
+
const shouldUnwrap = ((isPreviewBg || isBordered || isRounded) && hasPadding) || isOverflow
|
|
126
|
+
const shouldUnwrapMaxWidth = isMaxWidth && isPresentationOnly
|
|
127
|
+
|
|
128
|
+
if (!shouldUnwrap && !shouldUnwrapMaxWidth) break
|
|
129
|
+
|
|
130
|
+
current = match[2].trim()
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return current
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function decodeHeading(value) {
|
|
137
|
+
return value
|
|
138
|
+
.replaceAll('&', '&')
|
|
139
|
+
.replaceAll('×', '×')
|
|
140
|
+
.replaceAll(''', "'")
|
|
141
|
+
.replaceAll('"', '"')
|
|
142
|
+
.trim()
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function extractSectionHeading(sectionSource) {
|
|
146
|
+
const match = sectionSource.match(/<h2\b[^>]*>([\s\S]*?)<\/h2>/)
|
|
147
|
+
if (!match) return ''
|
|
148
|
+
return decodeHeading(match[1].replace(/<[^>]+>/g, ' '))
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function extractSectionSnippet(sectionSource) {
|
|
152
|
+
const openTagEnd = sectionSource.indexOf('>')
|
|
153
|
+
const closeTagStart = sectionSource.lastIndexOf('</section>')
|
|
154
|
+
|
|
155
|
+
if (openTagEnd < 0 || closeTagStart < 0) {
|
|
156
|
+
return normalizeCode(sectionSource)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
let inner = sectionSource.slice(openTagEnd + 1, closeTagStart)
|
|
160
|
+
inner = inner.replace(/^\s*<h2\b[\s\S]*?<\/h2>\s*/, '')
|
|
161
|
+
inner = inner.replace(/^\s*<!--[\s\S]*?-->\s*/g, '')
|
|
162
|
+
|
|
163
|
+
while (/^\s*<p\b[\s\S]*?<\/p>\s*/.test(inner)) {
|
|
164
|
+
inner = inner.replace(/^\s*<p\b[\s\S]*?<\/p>\s*/, '')
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
inner = inner.replace(/\s*<!--[\s\S]*?-->\s*$/g, '')
|
|
168
|
+
inner = unwrapPreviewWrappers(inner)
|
|
169
|
+
return normalizeCode(inner)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function getSectionSnippets(source) {
|
|
173
|
+
return [...source.matchAll(/<section\b[\s\S]*?<\/section>/g)].map((match) => {
|
|
174
|
+
const sectionSource = match[0]
|
|
175
|
+
return {
|
|
176
|
+
heading: extractSectionHeading(sectionSource),
|
|
177
|
+
snippet: extractSectionSnippet(sectionSource)
|
|
178
|
+
}
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function detectLanguage(code) {
|
|
183
|
+
const source = code.trim()
|
|
184
|
+
|
|
185
|
+
if (
|
|
186
|
+
source.includes('<script lang="ts">') ||
|
|
187
|
+
source.includes('$state(') ||
|
|
188
|
+
source.includes('{#each') ||
|
|
189
|
+
source.includes('<Button') ||
|
|
190
|
+
source.includes('<FormField')
|
|
191
|
+
) {
|
|
192
|
+
return 'svelte'
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (source.startsWith('{') || source.startsWith('[')) {
|
|
196
|
+
return 'json'
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (
|
|
200
|
+
source.startsWith('@import') ||
|
|
201
|
+
(source.includes('{') && source.includes(':') && source.includes(';'))
|
|
202
|
+
) {
|
|
203
|
+
return 'css'
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (source.startsWith('#') || source.startsWith('bun ') || source.startsWith('npm ')) {
|
|
207
|
+
return 'bash'
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (source.includes('export ') || source.includes('import ') || source.includes('interface ')) {
|
|
211
|
+
return 'ts'
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return 'html'
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function decorateHighlightedHtml(html) {
|
|
218
|
+
return html.replace(/<pre class="shiki[\s\S]*?"[^>]*>/, '<pre class="shiki">')
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async function renderHighlightedCode(code, isDarkMode = true) {
|
|
222
|
+
const html = await codeToHtml(code, {
|
|
223
|
+
lang: detectLanguage(code),
|
|
224
|
+
theme: isDarkMode ? 'github-dark' : 'github-light'
|
|
225
|
+
})
|
|
226
|
+
return decorateHighlightedHtml(html)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function getPagePathFromSlug(slug) {
|
|
230
|
+
return `src/routes/${slug}/+page.svelte`
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async function readRouteSource(slug) {
|
|
234
|
+
const packagedData = await getPackagedData()
|
|
235
|
+
if (packagedData?.pages?.[slug]) {
|
|
236
|
+
return packagedData.pages[slug]
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const filePath = resolveRepoPath(getPagePathFromSlug(slug))
|
|
240
|
+
return await readFile(filePath, 'utf8')
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async function readDocsNavigationSource() {
|
|
244
|
+
const filePath = resolveRepoPath('src/internal/docs/navigation.ts')
|
|
245
|
+
return await readFile(filePath, 'utf8')
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
async function listDocSlugs() {
|
|
249
|
+
const packagedData = await getPackagedData()
|
|
250
|
+
if (packagedData?.slugs) {
|
|
251
|
+
return packagedData.slugs
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const navigationSource = await readDocsNavigationSource()
|
|
255
|
+
return extractDocSlugs(navigationSource)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function extractDocSlugs(navigationSource) {
|
|
259
|
+
const componentSlugs = []
|
|
260
|
+
const hookSlugs = []
|
|
261
|
+
|
|
262
|
+
for (const match of navigationSource.matchAll(/href:\s*'\/docs\/components\/([^']+)'/g)) {
|
|
263
|
+
componentSlugs.push(match[1])
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
for (const match of navigationSource.matchAll(/href:\s*'\/docs\/hooks\/([^']+)'/g)) {
|
|
267
|
+
hookSlugs.push(match[1])
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return {
|
|
271
|
+
components: Array.from(new Set(componentSlugs)),
|
|
272
|
+
hooks: Array.from(new Set(hookSlugs))
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const server = new McpServer({
|
|
277
|
+
name: 'sv5ui-plus-docs',
|
|
278
|
+
version: '0.1.0'
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
server.tool(
|
|
282
|
+
'sv5ui_plus_docs_list_slugs',
|
|
283
|
+
'List docs slugs from src/internal/docs/navigation.ts (components + hooks)',
|
|
284
|
+
{},
|
|
285
|
+
async () => {
|
|
286
|
+
const slugs = await listDocSlugs()
|
|
287
|
+
|
|
288
|
+
return {
|
|
289
|
+
content: [
|
|
290
|
+
{
|
|
291
|
+
type: 'text',
|
|
292
|
+
text: JSON.stringify(slugs, null, 2)
|
|
293
|
+
}
|
|
294
|
+
]
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
server.tool(
|
|
300
|
+
'sv5ui_plus_docs_get_page_source',
|
|
301
|
+
'Read src/routes/[slug]/+page.svelte and return as text',
|
|
302
|
+
{
|
|
303
|
+
slug: z.string().min(1).describe('Route slug, e.g. button, select-menu, use-form-field')
|
|
304
|
+
},
|
|
305
|
+
async ({ slug }) => {
|
|
306
|
+
const source = await readRouteSource(slug)
|
|
307
|
+
return { content: [{ type: 'text', text: source }] }
|
|
308
|
+
}
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
server.tool(
|
|
312
|
+
'sv5ui_plus_docs_get_section_snippets',
|
|
313
|
+
'Extract all <section> headings and code snippets from a route page source',
|
|
314
|
+
{
|
|
315
|
+
slug: z.string().min(1).describe('Route slug, e.g. button, select-menu, use-form-field')
|
|
316
|
+
},
|
|
317
|
+
async ({ slug }) => {
|
|
318
|
+
const source = await readRouteSource(slug)
|
|
319
|
+
const sections = getSectionSnippets(source)
|
|
320
|
+
return { content: [{ type: 'text', text: JSON.stringify(sections, null, 2) }] }
|
|
321
|
+
}
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
server.tool(
|
|
325
|
+
'sv5ui_plus_docs_render_shiki',
|
|
326
|
+
'Render highlighted HTML (Shiki) for a code snippet. Returns <pre class="shiki">...</pre> HTML',
|
|
327
|
+
{
|
|
328
|
+
code: z.string().min(1).describe('Code string'),
|
|
329
|
+
isDarkMode: z.boolean().optional().describe('Use dark theme when true')
|
|
330
|
+
},
|
|
331
|
+
async ({ code, isDarkMode }) => {
|
|
332
|
+
const html = await renderHighlightedCode(code, isDarkMode ?? true)
|
|
333
|
+
return { content: [{ type: 'text', text: html }] }
|
|
334
|
+
}
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
const transport = new StdioServerTransport()
|
|
338
|
+
await server.connect(transport)
|