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.
Files changed (214) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +62 -0
  3. package/dist/adapters/notify.d.ts +29 -0
  4. package/dist/adapters/notify.js +88 -0
  5. package/dist/compat.d.ts +6 -0
  6. package/dist/compat.js +6 -0
  7. package/dist/components/BentoGrid/BentoCard.svelte +45 -0
  8. package/dist/components/BentoGrid/BentoCard.svelte.d.ts +4 -0
  9. package/dist/components/BentoGrid/BentoGrid.svelte +9 -0
  10. package/dist/components/BentoGrid/BentoGrid.svelte.d.ts +4 -0
  11. package/dist/components/BentoGrid/bento-grid.types.d.ts +47 -0
  12. package/dist/components/BentoGrid/bento-grid.types.js +1 -0
  13. package/dist/components/BentoGrid/bento-grid.variants.d.ts +30 -0
  14. package/dist/components/BentoGrid/bento-grid.variants.js +16 -0
  15. package/dist/components/BentoGrid/index.d.ts +5 -0
  16. package/dist/components/BentoGrid/index.js +5 -0
  17. package/dist/components/Chart/Chart.svelte +62 -0
  18. package/dist/components/Chart/Chart.svelte.d.ts +4 -0
  19. package/dist/components/Chart/chart.types.d.ts +16 -0
  20. package/dist/components/Chart/chart.types.js +1 -0
  21. package/dist/components/Chart/index.d.ts +2 -0
  22. package/dist/components/Chart/index.js +2 -0
  23. package/dist/components/Chat/ChatBubble.svelte +30 -0
  24. package/dist/components/Chat/ChatBubble.svelte.d.ts +4 -0
  25. package/dist/components/Chat/ChatInput.svelte +50 -0
  26. package/dist/components/Chat/ChatInput.svelte.d.ts +4 -0
  27. package/dist/components/Chat/ChatMessage.svelte +15 -0
  28. package/dist/components/Chat/ChatMessage.svelte.d.ts +4 -0
  29. package/dist/components/Chat/chat.types.d.ts +63 -0
  30. package/dist/components/Chat/chat.types.js +1 -0
  31. package/dist/components/Chat/chat.variants.d.ts +117 -0
  32. package/dist/components/Chat/chat.variants.js +47 -0
  33. package/dist/components/Chat/index.d.ts +6 -0
  34. package/dist/components/Chat/index.js +6 -0
  35. package/dist/components/CodeBlock/CodeBlock.svelte +66 -0
  36. package/dist/components/CodeBlock/CodeBlock.svelte.d.ts +5 -0
  37. package/dist/components/CodeBlock/code-block.types.d.ts +15 -0
  38. package/dist/components/CodeBlock/code-block.types.js +1 -0
  39. package/dist/components/CodeBlock/code-block.variants.d.ts +288 -0
  40. package/dist/components/CodeBlock/code-block.variants.js +69 -0
  41. package/dist/components/CodeBlock/index.d.ts +2 -0
  42. package/dist/components/CodeBlock/index.js +1 -0
  43. package/dist/components/ColorPicker/ColorPicker.svelte +109 -0
  44. package/dist/components/ColorPicker/ColorPicker.svelte.d.ts +4 -0
  45. package/dist/components/ColorPicker/color-picker.types.d.ts +26 -0
  46. package/dist/components/ColorPicker/color-picker.types.js +1 -0
  47. package/dist/components/ColorPicker/color-picker.variants.d.ts +69 -0
  48. package/dist/components/ColorPicker/color-picker.variants.js +13 -0
  49. package/dist/components/ColorPicker/index.d.ts +4 -0
  50. package/dist/components/ColorPicker/index.js +4 -0
  51. package/dist/components/ConfirmDialog/ConfirmDialog.svelte +175 -0
  52. package/dist/components/ConfirmDialog/ConfirmDialog.svelte.d.ts +10 -0
  53. package/dist/components/ConfirmDialog/confirm.d.ts +9 -0
  54. package/dist/components/ConfirmDialog/confirm.js +24 -0
  55. package/dist/components/ConfirmDialog/confirm.types.d.ts +21 -0
  56. package/dist/components/ConfirmDialog/confirm.types.js +1 -0
  57. package/dist/components/ConfirmDialog/index.d.ts +4 -0
  58. package/dist/components/ConfirmDialog/index.js +2 -0
  59. package/dist/components/Fonts/Fonts.svelte +32 -0
  60. package/dist/components/Fonts/Fonts.svelte.d.ts +5 -0
  61. package/dist/components/Fonts/fonts.d.ts +12 -0
  62. package/dist/components/Fonts/fonts.js +126 -0
  63. package/dist/components/Fonts/fonts.types.d.ts +40 -0
  64. package/dist/components/Fonts/fonts.types.js +1 -0
  65. package/dist/components/Fonts/index.d.ts +3 -0
  66. package/dist/components/Fonts/index.js +2 -0
  67. package/dist/components/List/List.svelte +14 -0
  68. package/dist/components/List/List.svelte.d.ts +4 -0
  69. package/dist/components/List/ListItem.svelte +64 -0
  70. package/dist/components/List/ListItem.svelte.d.ts +4 -0
  71. package/dist/components/List/index.d.ts +5 -0
  72. package/dist/components/List/index.js +5 -0
  73. package/dist/components/List/list.types.d.ts +62 -0
  74. package/dist/components/List/list.types.js +1 -0
  75. package/dist/components/List/list.variants.d.ts +99 -0
  76. package/dist/components/List/list.variants.js +42 -0
  77. package/dist/components/LocaleButton/LocaleButton.svelte +181 -0
  78. package/dist/components/LocaleButton/LocaleButton.svelte.d.ts +5 -0
  79. package/dist/components/LocaleButton/index.d.ts +2 -0
  80. package/dist/components/LocaleButton/index.js +1 -0
  81. package/dist/components/LocaleButton/locale-button.types.d.ts +208 -0
  82. package/dist/components/LocaleButton/locale-button.types.js +1 -0
  83. package/dist/components/LocaleButton/locale-button.variants.d.ts +245 -0
  84. package/dist/components/LocaleButton/locale-button.variants.js +98 -0
  85. package/dist/components/Marquee/Marquee.svelte +50 -0
  86. package/dist/components/Marquee/Marquee.svelte.d.ts +4 -0
  87. package/dist/components/Marquee/index.d.ts +4 -0
  88. package/dist/components/Marquee/index.js +4 -0
  89. package/dist/components/Marquee/marquee.types.d.ts +38 -0
  90. package/dist/components/Marquee/marquee.types.js +1 -0
  91. package/dist/components/Marquee/marquee.variants.d.ts +78 -0
  92. package/dist/components/Marquee/marquee.variants.js +28 -0
  93. package/dist/components/NavigationMenu/NavigationMenu.svelte +623 -0
  94. package/dist/components/NavigationMenu/NavigationMenu.svelte.d.ts +5 -0
  95. package/dist/components/NavigationMenu/index.d.ts +2 -0
  96. package/dist/components/NavigationMenu/index.js +1 -0
  97. package/dist/components/NavigationMenu/navigation-menu.types.d.ts +245 -0
  98. package/dist/components/NavigationMenu/navigation-menu.types.js +1 -0
  99. package/dist/components/NavigationMenu/navigation-menu.variants.d.ts +543 -0
  100. package/dist/components/NavigationMenu/navigation-menu.variants.js +287 -0
  101. package/dist/components/NumberTicker/NumberTicker.svelte +59 -0
  102. package/dist/components/NumberTicker/NumberTicker.svelte.d.ts +4 -0
  103. package/dist/components/NumberTicker/index.d.ts +4 -0
  104. package/dist/components/NumberTicker/index.js +4 -0
  105. package/dist/components/NumberTicker/number-ticker.types.d.ts +26 -0
  106. package/dist/components/NumberTicker/number-ticker.types.js +1 -0
  107. package/dist/components/NumberTicker/number-ticker.variants.d.ts +27 -0
  108. package/dist/components/NumberTicker/number-ticker.variants.js +6 -0
  109. package/dist/components/PasswordInput/PasswordInput.svelte +182 -0
  110. package/dist/components/PasswordInput/PasswordInput.svelte.d.ts +5 -0
  111. package/dist/components/PasswordInput/index.d.ts +2 -0
  112. package/dist/components/PasswordInput/index.js +1 -0
  113. package/dist/components/PasswordInput/password-input.types.d.ts +111 -0
  114. package/dist/components/PasswordInput/password-input.types.js +1 -0
  115. package/dist/components/PasswordInput/password-input.variants.d.ts +273 -0
  116. package/dist/components/PasswordInput/password-input.variants.js +105 -0
  117. package/dist/components/Prose/Prose.svelte +13 -0
  118. package/dist/components/Prose/Prose.svelte.d.ts +4 -0
  119. package/dist/components/Prose/index.d.ts +4 -0
  120. package/dist/components/Prose/index.js +4 -0
  121. package/dist/components/Prose/prose.types.d.ts +22 -0
  122. package/dist/components/Prose/prose.types.js +1 -0
  123. package/dist/components/Prose/prose.variants.d.ts +45 -0
  124. package/dist/components/Prose/prose.variants.js +45 -0
  125. package/dist/components/Resizable/Resizable.svelte +9 -0
  126. package/dist/components/Resizable/Resizable.svelte.d.ts +4 -0
  127. package/dist/components/Resizable/index.d.ts +4 -0
  128. package/dist/components/Resizable/index.js +4 -0
  129. package/dist/components/Resizable/resizable.types.d.ts +18 -0
  130. package/dist/components/Resizable/resizable.types.js +1 -0
  131. package/dist/components/Resizable/resizable.variants.d.ts +48 -0
  132. package/dist/components/Resizable/resizable.variants.js +17 -0
  133. package/dist/components/ScrollArea/ScrollArea.svelte +54 -0
  134. package/dist/components/ScrollArea/ScrollArea.svelte.d.ts +4 -0
  135. package/dist/components/ScrollArea/index.d.ts +4 -0
  136. package/dist/components/ScrollArea/index.js +4 -0
  137. package/dist/components/ScrollArea/scroll-area.types.d.ts +27 -0
  138. package/dist/components/ScrollArea/scroll-area.types.js +1 -0
  139. package/dist/components/ScrollArea/scroll-area.variants.d.ts +45 -0
  140. package/dist/components/ScrollArea/scroll-area.variants.js +27 -0
  141. package/dist/components/Search/Search.svelte +94 -0
  142. package/dist/components/Search/Search.svelte.d.ts +4 -0
  143. package/dist/components/Search/index.d.ts +2 -0
  144. package/dist/components/Search/index.js +1 -0
  145. package/dist/components/Search/search.types.d.ts +40 -0
  146. package/dist/components/Search/search.types.js +1 -0
  147. package/dist/components/SortableGroup/SortableGroup.svelte +53 -0
  148. package/dist/components/SortableGroup/SortableGroup.svelte.d.ts +13 -0
  149. package/dist/components/SortableGroup/index.d.ts +1 -0
  150. package/dist/components/SortableGroup/index.js +1 -0
  151. package/dist/components/SortableList/SortableList.svelte +81 -0
  152. package/dist/components/SortableList/SortableList.svelte.d.ts +26 -0
  153. package/dist/components/SortableList/index.d.ts +2 -0
  154. package/dist/components/SortableList/index.js +1 -0
  155. package/dist/components/SortableList/sortable-list.types.d.ts +21 -0
  156. package/dist/components/SortableList/sortable-list.types.js +1 -0
  157. package/dist/components/Spotlight/Spotlight.svelte +31 -0
  158. package/dist/components/Spotlight/Spotlight.svelte.d.ts +4 -0
  159. package/dist/components/Spotlight/index.d.ts +4 -0
  160. package/dist/components/Spotlight/index.js +4 -0
  161. package/dist/components/Spotlight/spotlight.types.d.ts +22 -0
  162. package/dist/components/Spotlight/spotlight.types.js +1 -0
  163. package/dist/components/Spotlight/spotlight.variants.d.ts +39 -0
  164. package/dist/components/Spotlight/spotlight.variants.js +8 -0
  165. package/dist/components/TableBulkActionBar/TableBulkActionBar.svelte +38 -0
  166. package/dist/components/TableBulkActionBar/TableBulkActionBar.svelte.d.ts +5 -0
  167. package/dist/components/TableBulkActionBar/index.d.ts +2 -0
  168. package/dist/components/TableBulkActionBar/index.js +1 -0
  169. package/dist/components/TableBulkActionBar/table-bulk-action-bar.types.d.ts +31 -0
  170. package/dist/components/TableBulkActionBar/table-bulk-action-bar.types.js +1 -0
  171. package/dist/components/TableBulkActionBar/table-bulk-action-bar.variants.d.ts +52 -0
  172. package/dist/components/TableBulkActionBar/table-bulk-action-bar.variants.js +10 -0
  173. package/dist/components/TreeView/TreeView.svelte +95 -0
  174. package/dist/components/TreeView/TreeView.svelte.d.ts +4 -0
  175. package/dist/components/TreeView/index.d.ts +4 -0
  176. package/dist/components/TreeView/index.js +3 -0
  177. package/dist/components/TreeView/tree-view.types.d.ts +68 -0
  178. package/dist/components/TreeView/tree-view.types.js +1 -0
  179. package/dist/components/TreeView/tree-view.variants.d.ts +69 -0
  180. package/dist/components/TreeView/tree-view.variants.js +30 -0
  181. package/dist/config.d.ts +91 -0
  182. package/dist/config.js +124 -0
  183. package/dist/editor.d.ts +2 -0
  184. package/dist/editor.js +2 -0
  185. package/dist/form/resolve-form-field-name.d.ts +5 -0
  186. package/dist/form/resolve-form-field-name.js +11 -0
  187. package/dist/hooks/internal/DragDropProviderScope.svelte +29 -0
  188. package/dist/hooks/internal/DragDropProviderScope.svelte.d.ts +7 -0
  189. package/dist/hooks/internal/SortableProvider.svelte +68 -0
  190. package/dist/hooks/internal/SortableProvider.svelte.d.ts +30 -0
  191. package/dist/hooks/internal/drag-drop-context.d.ts +12 -0
  192. package/dist/hooks/internal/drag-drop-context.js +1 -0
  193. package/dist/hooks/internal/sortable-context.d.ts +26 -0
  194. package/dist/hooks/internal/sortable-context.js +2 -0
  195. package/dist/hooks/useDragDrop/index.d.ts +1 -0
  196. package/dist/hooks/useDragDrop/index.js +1 -0
  197. package/dist/hooks/useDragDrop/useDragDrop.svelte.d.ts +40 -0
  198. package/dist/hooks/useDragDrop/useDragDrop.svelte.js +128 -0
  199. package/dist/hooks/useSortable/index.d.ts +2 -0
  200. package/dist/hooks/useSortable/index.js +2 -0
  201. package/dist/hooks/useSortable/sortable-utils.d.ts +1 -0
  202. package/dist/hooks/useSortable/sortable-utils.js +13 -0
  203. package/dist/hooks/useSortable/useSortable.svelte.d.ts +60 -0
  204. package/dist/hooks/useSortable/useSortable.svelte.js +151 -0
  205. package/dist/hooks/utils.d.ts +1 -0
  206. package/dist/hooks/utils.js +3 -0
  207. package/dist/index.d.ts +27 -0
  208. package/dist/index.js +30 -0
  209. package/dist/mcp/cursor.mcp.json +12 -0
  210. package/dist/mcp/install-template.mjs +55 -0
  211. package/dist/mcp/server.mjs +338 -0
  212. package/dist/mcp/sv5ui-plus-docs.data.json +17 -0
  213. package/dist/theme.css +64 -0
  214. 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;
@@ -0,0 +1,3 @@
1
+ export function toGetter(value) {
2
+ return typeof value === 'function' ? value : () => value;
3
+ }
@@ -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,12 @@
1
+ {
2
+ "mcpServers": {
3
+ "sv5ui-plus-docs": {
4
+ "type": "stdio",
5
+ "command": "node",
6
+ "args": [
7
+ "./node_modules/sv5ui-plus/dist/mcp/server.mjs"
8
+ ],
9
+ "cwd": "${workspaceFolder}"
10
+ }
11
+ }
12
+ }
@@ -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('&amp;', '&')
139
+ .replaceAll('&times;', '×')
140
+ .replaceAll('&#39;', "'")
141
+ .replaceAll('&quot;', '"')
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)