@svadmin/ui 0.63.0 → 0.64.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 (34) hide show
  1. package/dist/components/AutoTable.svelte +8 -0
  2. package/dist/components/AutoTable.svelte.d.ts +7 -1
  3. package/dist/components/Cascader.svelte +205 -0
  4. package/dist/components/Cascader.svelte.d.ts +21 -0
  5. package/dist/components/DynamicFormList.svelte +214 -0
  6. package/dist/components/DynamicFormList.svelte.d.ts +62 -0
  7. package/dist/components/FieldRenderer.svelte +32 -0
  8. package/dist/components/FilterBuilder.svelte +310 -0
  9. package/dist/components/FilterBuilder.svelte.d.ts +23 -0
  10. package/dist/components/Transfer.svelte +352 -0
  11. package/dist/components/Transfer.svelte.d.ts +28 -0
  12. package/dist/components/TreeSelect.svelte +307 -0
  13. package/dist/components/TreeSelect.svelte.d.ts +22 -0
  14. package/dist/components/ui/navigation-menu/index.d.ts +11 -0
  15. package/dist/components/ui/navigation-menu/index.js +13 -0
  16. package/dist/components/ui/navigation-menu/navigation-menu-content.svelte +21 -0
  17. package/dist/components/ui/navigation-menu/navigation-menu-content.svelte.d.ts +4 -0
  18. package/dist/components/ui/navigation-menu/navigation-menu-indicator.svelte +22 -0
  19. package/dist/components/ui/navigation-menu/navigation-menu-indicator.svelte.d.ts +4 -0
  20. package/dist/components/ui/navigation-menu/navigation-menu-item.svelte +17 -0
  21. package/dist/components/ui/navigation-menu/navigation-menu-item.svelte.d.ts +4 -0
  22. package/dist/components/ui/navigation-menu/navigation-menu-link.svelte +20 -0
  23. package/dist/components/ui/navigation-menu/navigation-menu-link.svelte.d.ts +4 -0
  24. package/dist/components/ui/navigation-menu/navigation-menu-list.svelte +17 -0
  25. package/dist/components/ui/navigation-menu/navigation-menu-list.svelte.d.ts +4 -0
  26. package/dist/components/ui/navigation-menu/navigation-menu-trigger.svelte +28 -0
  27. package/dist/components/ui/navigation-menu/navigation-menu-trigger.svelte.d.ts +4 -0
  28. package/dist/components/ui/navigation-menu/navigation-menu-viewport.svelte +22 -0
  29. package/dist/components/ui/navigation-menu/navigation-menu-viewport.svelte.d.ts +4 -0
  30. package/dist/components/ui/navigation-menu/navigation-menu.svelte +24 -0
  31. package/dist/components/ui/navigation-menu/navigation-menu.svelte.d.ts +4 -0
  32. package/dist/index.d.ts +10 -0
  33. package/dist/index.js +7 -0
  34. package/package.json +2 -2
@@ -0,0 +1,28 @@
1
+ import type { Snippet } from 'svelte';
2
+ export interface TransferItem {
3
+ key: string | number;
4
+ title: string;
5
+ description?: string;
6
+ disabled?: boolean;
7
+ }
8
+ interface Props {
9
+ dataSource?: TransferItem[];
10
+ targetKeys?: (string | number)[];
11
+ titles?: [string, string];
12
+ searchable?: boolean;
13
+ disabled?: boolean;
14
+ class?: string;
15
+ onchange?: (nextTargetKeys: (string | number)[], direction: 'left' | 'right', moveKeys: (string | number)[]) => void;
16
+ renderItem?: Snippet<[{
17
+ item: TransferItem;
18
+ direction: 'left' | 'right';
19
+ }]>;
20
+ }
21
+ declare const Transfer: import("svelte").Component<Props, {
22
+ moveToRight: () => void;
23
+ moveToLeft: () => void;
24
+ moveAllToRight: () => void;
25
+ moveAllToLeft: () => void;
26
+ }, "targetKeys">;
27
+ type Transfer = ReturnType<typeof Transfer>;
28
+ export default Transfer;
@@ -0,0 +1,307 @@
1
+ <script lang="ts">
2
+ import { SvelteSet } from 'svelte/reactivity';
3
+ import { ChevronRight, ChevronDown, Check, X, Search, ChevronsUpDown } from '@lucide/svelte';
4
+ import { cn } from '../utils.js';
5
+ import * as Popover from './ui/popover/index.js';
6
+ import { Input } from './ui/input/index.js';
7
+ import { Badge } from './ui/badge/index.js';
8
+ import { useTranslation } from '@svadmin/core/i18n';
9
+
10
+ export interface TreeSelectOption {
11
+ value: string | number;
12
+ label: string;
13
+ children?: TreeSelectOption[];
14
+ disabled?: boolean;
15
+ expanded?: boolean;
16
+ }
17
+
18
+ const i18n = useTranslation();
19
+
20
+ interface Props {
21
+ options?: TreeSelectOption[];
22
+ value?: string | number | (string | number)[];
23
+ multiple?: boolean;
24
+ placeholder?: string;
25
+ searchable?: boolean;
26
+ onlyLeafSelectable?: boolean;
27
+ disabled?: boolean;
28
+ allowClear?: boolean;
29
+ class?: string;
30
+ onchange?: (value: string | number | (string | number)[] | undefined) => void;
31
+ }
32
+
33
+ let {
34
+ options = [],
35
+ value = $bindable(undefined),
36
+ multiple = false,
37
+ placeholder,
38
+ searchable = true,
39
+ onlyLeafSelectable = false,
40
+ disabled = false,
41
+ allowClear = true,
42
+ class: className,
43
+ onchange,
44
+ }: Props = $props();
45
+
46
+ let open = $state(false);
47
+ let searchQuery = $state('');
48
+ let expandedNodes = new SvelteSet<string | number>();
49
+
50
+ // Map to quickly look up option info by value
51
+ const optionMap = $derived.by(() => {
52
+ const map = new Map<string | number, TreeSelectOption>();
53
+ function traverse(nodes: TreeSelectOption[]) {
54
+ for (const node of nodes) {
55
+ map.set(node.value, node);
56
+ if (node.children) traverse(node.children);
57
+ }
58
+ }
59
+ traverse(options);
60
+ return map;
61
+ });
62
+
63
+ // Selected values array normalized
64
+ const selectedValues = $derived.by< (string | number)[]>(() => {
65
+ if (value === undefined || value === null || value === '') return [];
66
+ return Array.isArray(value) ? value : [value];
67
+ });
68
+
69
+ const selectedLabels = $derived.by(() => {
70
+ return selectedValues.map((v) => optionMap.get(v)?.label ?? String(v));
71
+ });
72
+
73
+ function toggleExpand(nodeValue: string | number, event?: MouseEvent) {
74
+ event?.stopPropagation();
75
+ if (expandedNodes.has(nodeValue)) {
76
+ expandedNodes.delete(nodeValue);
77
+ } else {
78
+ expandedNodes.add(nodeValue);
79
+ }
80
+ }
81
+
82
+ function isNodeExpanded(node: TreeSelectOption): boolean {
83
+ if (searchQuery.trim()) return true; // Auto expand all on search
84
+ return expandedNodes.has(node.value) || !!node.expanded;
85
+ }
86
+
87
+ function isSelected(val: string | number): boolean {
88
+ return selectedValues.includes(val);
89
+ }
90
+
91
+ function handleSelect(node: TreeSelectOption) {
92
+ if (node.disabled) return;
93
+ const hasChildren = node.children && node.children.length > 0;
94
+ if (onlyLeafSelectable && hasChildren) {
95
+ toggleExpand(node.value);
96
+ return;
97
+ }
98
+
99
+ if (multiple) {
100
+ let next: (string | number)[];
101
+ if (isSelected(node.value)) {
102
+ next = selectedValues.filter((v) => v !== node.value);
103
+ } else {
104
+ next = [...selectedValues, node.value];
105
+ }
106
+ value = next;
107
+ onchange?.(next);
108
+ } else {
109
+ const next = node.value;
110
+ value = next;
111
+ onchange?.(next);
112
+ open = false;
113
+ }
114
+ }
115
+
116
+ function clearAll(event?: MouseEvent) {
117
+ event?.stopPropagation();
118
+ const next = multiple ? [] : undefined;
119
+ value = next;
120
+ onchange?.(next);
121
+ }
122
+
123
+ function removeSingle(val: string | number, event?: MouseEvent) {
124
+ event?.stopPropagation();
125
+ if (multiple) {
126
+ const next = selectedValues.filter((v) => v !== val);
127
+ value = next;
128
+ onchange?.(next);
129
+ }
130
+ }
131
+
132
+ function filterTree(nodes: TreeSelectOption[], query: string): TreeSelectOption[] {
133
+ const q = query.trim().toLowerCase();
134
+ if (!q) return nodes;
135
+
136
+ const filtered: TreeSelectOption[] = [];
137
+ for (const node of nodes) {
138
+ const matchSelf = node.label.toLowerCase().includes(q);
139
+ const filteredChildren = node.children ? filterTree(node.children, q) : undefined;
140
+ const matchChildren = filteredChildren && filteredChildren.length > 0;
141
+
142
+ if (matchSelf || matchChildren) {
143
+ filtered.push({
144
+ ...node,
145
+ children: filteredChildren ?? node.children,
146
+ });
147
+ }
148
+ }
149
+ return filtered;
150
+ }
151
+
152
+ const visibleOptions = $derived(filterTree(options, searchQuery));
153
+ </script>
154
+
155
+ {#snippet treeNode(node: TreeSelectOption, level: number)}
156
+ {@const hasChildren = Boolean(node.children && node.children.length > 0)}
157
+ {@const expanded = isNodeExpanded(node)}
158
+ {@const selected = isSelected(node.value)}
159
+ {@const selectable = !node.disabled && (!onlyLeafSelectable || !hasChildren)}
160
+
161
+ <div class="flex flex-col">
162
+ <div
163
+ role="treeitem"
164
+ tabindex="0"
165
+ aria-selected={selected}
166
+ aria-expanded={hasChildren ? expanded : undefined}
167
+ class={cn(
168
+ 'group flex items-center justify-between gap-1.5 rounded-md px-2 py-1.5 text-xs transition-colors cursor-pointer select-none',
169
+ selected ? 'bg-primary/10 text-primary font-medium' : 'hover:bg-muted/60 text-foreground',
170
+ node.disabled && 'opacity-50 cursor-not-allowed pointer-events-none'
171
+ )}
172
+ style="padding-left: {level * 16 + 8}px;"
173
+ onclick={() => {
174
+ if (selectable) handleSelect(node);
175
+ }}
176
+ onkeydown={(e) => {
177
+ if (e.key === 'Enter' || e.key === ' ') {
178
+ e.preventDefault();
179
+ if (selectable) handleSelect(node);
180
+ }
181
+ }}
182
+ >
183
+ <div class="flex min-w-0 items-center gap-1.5">
184
+ {#if hasChildren}
185
+ <button
186
+ type="button"
187
+ class="flex h-4 w-4 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-muted"
188
+ onclick={(e) => toggleExpand(node.value, e)}
189
+ >
190
+ {#if expanded}
191
+ <ChevronDown class="h-3.5 w-3.5" />
192
+ {:else}
193
+ <ChevronRight class="h-3.5 w-3.5" />
194
+ {/if}
195
+ </button>
196
+ {:else}
197
+ <span class="inline-block h-4 w-4 shrink-0"></span>
198
+ {/if}
199
+
200
+ <span class="truncate">{node.label}</span>
201
+ </div>
202
+
203
+ {#if selected}
204
+ <Check class="h-3.5 w-3.5 shrink-0 text-primary" />
205
+ {/if}
206
+ </div>
207
+
208
+ {#if hasChildren && expanded && node.children}
209
+ <div role="group" class="flex flex-col">
210
+ {#each node.children as child (child.value)}
211
+ {@render treeNode(child, level + 1)}
212
+ {/each}
213
+ </div>
214
+ {/if}
215
+ </div>
216
+ {/snippet}
217
+
218
+ <div class={cn('relative w-full', className)} data-testid="tree-select">
219
+ <Popover.Root bind:open>
220
+ <Popover.Trigger class="w-full">
221
+ {#snippet child({ props })}
222
+ <button
223
+ type="button"
224
+ {...props}
225
+ {disabled}
226
+ class={cn(
227
+ 'flex min-h-9 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-1.5 text-xs ring-offset-background placeholder:text-muted-foreground focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 text-left',
228
+ open && 'ring-2 ring-ring ring-offset-2'
229
+ )}
230
+ >
231
+ <div class="flex flex-wrap items-center gap-1 min-w-0 flex-1">
232
+ {#if selectedValues.length === 0}
233
+ <span class="text-muted-foreground">
234
+ {placeholder ?? (i18n.t('field.selectPlaceholder', undefined) ?? '请选择...')}
235
+ </span>
236
+ {:else if multiple}
237
+ {#each selectedValues as val (val)}
238
+ {@const opt = optionMap.get(val)}
239
+ <Badge variant="secondary" class="h-5 px-1.5 py-0 text-[11px] gap-1 shrink-0">
240
+ <span>{opt?.label ?? val}</span>
241
+ {#if !disabled}
242
+ <span
243
+ role="button"
244
+ tabindex="0"
245
+ class="hover:text-destructive cursor-pointer"
246
+ onclick={(e) => removeSingle(val, e)}
247
+ onkeydown={(e) => {
248
+ if (e.key === 'Enter') removeSingle(val, e as never);
249
+ }}
250
+ >
251
+ <X class="h-3 w-3" />
252
+ </span>
253
+ {/if}
254
+ </Badge>
255
+ {/each}
256
+ {:else}
257
+ <span class="truncate text-foreground font-normal">
258
+ {selectedLabels[0] ?? ''}
259
+ </span>
260
+ {/if}
261
+ </div>
262
+
263
+ <div class="flex items-center gap-1 shrink-0 ml-1 text-muted-foreground">
264
+ {#if allowClear && selectedValues.length > 0 && !disabled}
265
+ <span
266
+ role="button"
267
+ tabindex="0"
268
+ class="hover:text-foreground cursor-pointer p-0.5"
269
+ onclick={clearAll}
270
+ onkeydown={(e) => {
271
+ if (e.key === 'Enter') clearAll(e as never);
272
+ }}
273
+ >
274
+ <X class="h-3.5 w-3.5" />
275
+ </span>
276
+ {/if}
277
+ <ChevronsUpDown class="h-3.5 w-3.5 opacity-50" />
278
+ </div>
279
+ </button>
280
+ {/snippet}
281
+ </Popover.Trigger>
282
+
283
+ <Popover.Content class="w-(--bits-popover-anchor-width) min-w-[220px] max-w-[400px] p-2" align="start">
284
+ {#if searchable}
285
+ <div class="relative mb-2">
286
+ <Search class="absolute left-2.5 top-2.5 h-3.5 w-3.5 text-muted-foreground" />
287
+ <Input
288
+ type="text"
289
+ bind:value={searchQuery}
290
+ placeholder={i18n.t('common.search', undefined) ?? '搜索...'}
291
+ class="h-8 pl-8 pr-2 text-xs"
292
+ />
293
+ </div>
294
+ {/if}
295
+
296
+ <div role="tree" class="max-h-60 overflow-y-auto space-y-0.5 pr-1">
297
+ {#each visibleOptions as rootNode (rootNode.value)}
298
+ {@render treeNode(rootNode, 0)}
299
+ {:else}
300
+ <div class="py-6 text-center text-xs text-muted-foreground">
301
+ {i18n.t('common.noData', undefined) ?? '无匹配选项'}
302
+ </div>
303
+ {/each}
304
+ </div>
305
+ </Popover.Content>
306
+ </Popover.Root>
307
+ </div>
@@ -0,0 +1,22 @@
1
+ export interface TreeSelectOption {
2
+ value: string | number;
3
+ label: string;
4
+ children?: TreeSelectOption[];
5
+ disabled?: boolean;
6
+ expanded?: boolean;
7
+ }
8
+ interface Props {
9
+ options?: TreeSelectOption[];
10
+ value?: string | number | (string | number)[];
11
+ multiple?: boolean;
12
+ placeholder?: string;
13
+ searchable?: boolean;
14
+ onlyLeafSelectable?: boolean;
15
+ disabled?: boolean;
16
+ allowClear?: boolean;
17
+ class?: string;
18
+ onchange?: (value: string | number | (string | number)[] | undefined) => void;
19
+ }
20
+ declare const TreeSelect: import("svelte").Component<Props, {}, "value">;
21
+ type TreeSelect = ReturnType<typeof TreeSelect>;
22
+ export default TreeSelect;
@@ -0,0 +1,11 @@
1
+ import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
2
+ import Root from "./navigation-menu.svelte";
3
+ import List from "./navigation-menu-list.svelte";
4
+ import Item from "./navigation-menu-item.svelte";
5
+ import Trigger from "./navigation-menu-trigger.svelte";
6
+ import Content from "./navigation-menu-content.svelte";
7
+ import Link from "./navigation-menu-link.svelte";
8
+ import Viewport from "./navigation-menu-viewport.svelte";
9
+ import Indicator from "./navigation-menu-indicator.svelte";
10
+ declare const Sub: import("svelte").Component<NavigationMenuPrimitive.SubProps, {}, "value" | "ref">;
11
+ export { Root, List, Item, Trigger, Content, Link, Viewport, Indicator, Sub, Root as NavigationMenu, List as NavigationMenuList, Item as NavigationMenuItem, Trigger as NavigationMenuTrigger, Content as NavigationMenuContent, Link as NavigationMenuLink, Viewport as NavigationMenuViewport, Indicator as NavigationMenuIndicator, Sub as NavigationMenuSub, };
@@ -0,0 +1,13 @@
1
+ import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
2
+ import Root from "./navigation-menu.svelte";
3
+ import List from "./navigation-menu-list.svelte";
4
+ import Item from "./navigation-menu-item.svelte";
5
+ import Trigger from "./navigation-menu-trigger.svelte";
6
+ import Content from "./navigation-menu-content.svelte";
7
+ import Link from "./navigation-menu-link.svelte";
8
+ import Viewport from "./navigation-menu-viewport.svelte";
9
+ import Indicator from "./navigation-menu-indicator.svelte";
10
+ const Sub = NavigationMenuPrimitive.Sub;
11
+ export { Root, List, Item, Trigger, Content, Link, Viewport, Indicator, Sub,
12
+ //
13
+ Root as NavigationMenu, List as NavigationMenuList, Item as NavigationMenuItem, Trigger as NavigationMenuTrigger, Content as NavigationMenuContent, Link as NavigationMenuLink, Viewport as NavigationMenuViewport, Indicator as NavigationMenuIndicator, Sub as NavigationMenuSub, };
@@ -0,0 +1,21 @@
1
+ <script lang="ts">
2
+ import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
3
+ import { cn } from "../../../utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ ...restProps
9
+ }: NavigationMenuPrimitive.ContentProps = $props();
10
+ </script>
11
+
12
+ <NavigationMenuPrimitive.Content
13
+ bind:ref
14
+ data-slot="navigation-menu-content"
15
+ class={cn(
16
+ "top-0 left-0 w-full md:absolute md:w-auto",
17
+ "data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52",
18
+ className
19
+ )}
20
+ {...restProps}
21
+ />
@@ -0,0 +1,4 @@
1
+ import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
2
+ declare const NavigationMenuContent: import("svelte").Component<NavigationMenuPrimitive.ContentProps, {}, "ref">;
3
+ type NavigationMenuContent = ReturnType<typeof NavigationMenuContent>;
4
+ export default NavigationMenuContent;
@@ -0,0 +1,22 @@
1
+ <script lang="ts">
2
+ import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
3
+ import { cn } from "../../../utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ ...restProps
9
+ }: NavigationMenuPrimitive.IndicatorProps = $props();
10
+ </script>
11
+
12
+ <NavigationMenuPrimitive.Indicator
13
+ bind:ref
14
+ data-slot="navigation-menu-indicator"
15
+ class={cn(
16
+ "top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in",
17
+ className
18
+ )}
19
+ {...restProps}
20
+ >
21
+ <div class="relative top-[60%] size-2 rotate-45 rounded-tl-sm bg-border shadow-md"></div>
22
+ </NavigationMenuPrimitive.Indicator>
@@ -0,0 +1,4 @@
1
+ import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
2
+ declare const NavigationMenuIndicator: import("svelte").Component<NavigationMenuPrimitive.IndicatorProps, {}, "ref">;
3
+ type NavigationMenuIndicator = ReturnType<typeof NavigationMenuIndicator>;
4
+ export default NavigationMenuIndicator;
@@ -0,0 +1,17 @@
1
+ <script lang="ts">
2
+ import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
3
+ import { cn } from "../../../utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ ...restProps
9
+ }: NavigationMenuPrimitive.ItemProps = $props();
10
+ </script>
11
+
12
+ <NavigationMenuPrimitive.Item
13
+ bind:ref
14
+ data-slot="navigation-menu-item"
15
+ class={cn("relative", className)}
16
+ {...restProps}
17
+ />
@@ -0,0 +1,4 @@
1
+ import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
2
+ declare const NavigationMenuItem: import("svelte").Component<NavigationMenuPrimitive.ItemProps, {}, "ref">;
3
+ type NavigationMenuItem = ReturnType<typeof NavigationMenuItem>;
4
+ export default NavigationMenuItem;
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
3
+ import { cn } from "../../../utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ ...restProps
9
+ }: NavigationMenuPrimitive.LinkProps = $props();
10
+ </script>
11
+
12
+ <NavigationMenuPrimitive.Link
13
+ bind:ref
14
+ data-slot="navigation-menu-link"
15
+ class={cn(
16
+ "inline-flex h-9 w-max items-center justify-center rounded-md px-4 py-2 text-sm font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus:bg-muted focus:text-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50",
17
+ className
18
+ )}
19
+ {...restProps}
20
+ />
@@ -0,0 +1,4 @@
1
+ import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
2
+ declare const NavigationMenuLink: import("svelte").Component<NavigationMenuPrimitive.LinkProps, {}, "ref">;
3
+ type NavigationMenuLink = ReturnType<typeof NavigationMenuLink>;
4
+ export default NavigationMenuLink;
@@ -0,0 +1,17 @@
1
+ <script lang="ts">
2
+ import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
3
+ import { cn } from "../../../utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ ...restProps
9
+ }: NavigationMenuPrimitive.ListProps = $props();
10
+ </script>
11
+
12
+ <NavigationMenuPrimitive.List
13
+ bind:ref
14
+ data-slot="navigation-menu-list"
15
+ class={cn("group flex flex-1 list-none items-center justify-center gap-1", className)}
16
+ {...restProps}
17
+ />
@@ -0,0 +1,4 @@
1
+ import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
2
+ declare const NavigationMenuList: import("svelte").Component<NavigationMenuPrimitive.ListProps, {}, "ref">;
3
+ type NavigationMenuList = ReturnType<typeof NavigationMenuList>;
4
+ export default NavigationMenuList;
@@ -0,0 +1,28 @@
1
+ <script lang="ts">
2
+ import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
3
+ import { cn } from "../../../utils.js";
4
+ import ChevronDownIcon from "@lucide/svelte/icons/chevron-down";
5
+
6
+ let {
7
+ ref = $bindable(null),
8
+ class: className,
9
+ children,
10
+ ...restProps
11
+ }: NavigationMenuPrimitive.TriggerProps = $props();
12
+ </script>
13
+
14
+ <NavigationMenuPrimitive.Trigger
15
+ bind:ref
16
+ data-slot="navigation-menu-trigger"
17
+ class={cn(
18
+ "group/trigger inline-flex h-9 w-max items-center justify-center rounded-md px-4 py-2 text-sm font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus:bg-muted focus:text-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[state=open]:bg-muted/50 data-[state=open]:text-foreground",
19
+ className
20
+ )}
21
+ {...restProps}
22
+ >
23
+ {@render children?.()}
24
+ <ChevronDownIcon
25
+ class="relative top-[1px] ml-1 size-3 transition duration-200 group-data-[state=open]/trigger:rotate-180"
26
+ aria-hidden="true"
27
+ />
28
+ </NavigationMenuPrimitive.Trigger>
@@ -0,0 +1,4 @@
1
+ import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
2
+ declare const NavigationMenuTrigger: import("svelte").Component<NavigationMenuPrimitive.TriggerProps, {}, "ref">;
3
+ type NavigationMenuTrigger = ReturnType<typeof NavigationMenuTrigger>;
4
+ export default NavigationMenuTrigger;
@@ -0,0 +1,22 @@
1
+ <script lang="ts">
2
+ import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
3
+ import { cn } from "../../../utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ ...restProps
9
+ }: NavigationMenuPrimitive.ViewportProps = $props();
10
+ </script>
11
+
12
+ <div class="absolute top-full left-0 flex justify-center">
13
+ <NavigationMenuPrimitive.Viewport
14
+ bind:ref
15
+ data-slot="navigation-menu-viewport"
16
+ class={cn(
17
+ "origin-top-center relative mt-1.5 h-[var(--bits-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-[0_18px_48px_rgba(15,23,42,0.14),0_4px_12px_rgba(15,23,42,0.08)] backdrop-blur-md transition-[width,height] duration-300 md:w-[var(--bits-navigation-menu-viewport-width)]",
18
+ className
19
+ )}
20
+ {...restProps}
21
+ />
22
+ </div>
@@ -0,0 +1,4 @@
1
+ import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
2
+ declare const NavigationMenuViewport: import("svelte").Component<NavigationMenuPrimitive.ViewportProps, {}, "ref">;
3
+ type NavigationMenuViewport = ReturnType<typeof NavigationMenuViewport>;
4
+ export default NavigationMenuViewport;
@@ -0,0 +1,24 @@
1
+ <script lang="ts">
2
+ import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
3
+ import { cn } from "../../../utils.js";
4
+ import NavigationMenuViewport from "./navigation-menu-viewport.svelte";
5
+
6
+ let {
7
+ ref = $bindable(null),
8
+ value = $bindable(""),
9
+ class: className,
10
+ children,
11
+ ...restProps
12
+ }: NavigationMenuPrimitive.RootProps = $props();
13
+ </script>
14
+
15
+ <NavigationMenuPrimitive.Root
16
+ bind:ref
17
+ bind:value
18
+ data-slot="navigation-menu"
19
+ class={cn("relative z-10 flex max-w-max flex-1 items-center justify-center", className)}
20
+ {...restProps}
21
+ >
22
+ {@render children?.()}
23
+ <NavigationMenuViewport />
24
+ </NavigationMenuPrimitive.Root>
@@ -0,0 +1,4 @@
1
+ import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
2
+ declare const NavigationMenu: import("svelte").Component<NavigationMenuPrimitive.RootProps, {}, "value" | "ref">;
3
+ type NavigationMenu = ReturnType<typeof NavigationMenu>;
4
+ export default NavigationMenu;
package/dist/index.d.ts CHANGED
@@ -49,6 +49,15 @@ export { default as CatchAllNavigate } from './components/CatchAllNavigate.svelt
49
49
  export { default as ThemedTitle } from './components/ThemedTitle.svelte';
50
50
  export { default as CommandPalette } from './components/CommandPalette.svelte';
51
51
  export { default as StepsForm } from './components/StepsForm.svelte';
52
+ export { default as DynamicFormList } from './components/DynamicFormList.svelte';
53
+ export { default as TreeSelect } from './components/TreeSelect.svelte';
54
+ export type { TreeSelectOption } from './components/TreeSelect.svelte';
55
+ export { default as Cascader } from './components/Cascader.svelte';
56
+ export type { CascaderOption } from './components/Cascader.svelte';
57
+ export { default as Transfer } from './components/Transfer.svelte';
58
+ export type { TransferItem } from './components/Transfer.svelte';
59
+ export { default as FilterBuilder } from './components/FilterBuilder.svelte';
60
+ export type { FilterRuleItem } from './components/FilterBuilder.svelte';
52
61
  export { default as InfiniteList } from './components/InfiniteList.svelte';
53
62
  export { default as ComboboxField } from './components/ComboboxField.svelte';
54
63
  export { default as PasswordInput } from './components/PasswordInput.svelte';
@@ -137,6 +146,7 @@ export * as DropdownMenu from './components/ui/dropdown-menu/index.js';
137
146
  export * as Breadcrumb from './components/ui/breadcrumb/index.js';
138
147
  export * as Pagination from './components/ui/pagination/index.js';
139
148
  export * as ContextMenu from './components/ui/context-menu/index.js';
149
+ export * as NavigationMenu from './components/ui/navigation-menu/index.js';
140
150
  export * as Collapsible from './components/ui/collapsible/index.js';
141
151
  export { Label } from './components/ui/label/index.js';
142
152
  export { Command } from './components/ui/command/index.js';
package/dist/index.js CHANGED
@@ -52,6 +52,12 @@ export { default as CatchAllNavigate } from './components/CatchAllNavigate.svelt
52
52
  export { default as ThemedTitle } from './components/ThemedTitle.svelte';
53
53
  export { default as CommandPalette } from './components/CommandPalette.svelte';
54
54
  export { default as StepsForm } from './components/StepsForm.svelte';
55
+ // Advanced Form & Data Controls (Refine/Antd Parity)
56
+ export { default as DynamicFormList } from './components/DynamicFormList.svelte';
57
+ export { default as TreeSelect } from './components/TreeSelect.svelte';
58
+ export { default as Cascader } from './components/Cascader.svelte';
59
+ export { default as Transfer } from './components/Transfer.svelte';
60
+ export { default as FilterBuilder } from './components/FilterBuilder.svelte';
55
61
  export { default as InfiniteList } from './components/InfiniteList.svelte';
56
62
  export { default as ComboboxField } from './components/ComboboxField.svelte';
57
63
  export { default as PasswordInput } from './components/PasswordInput.svelte';
@@ -144,6 +150,7 @@ export * as DropdownMenu from './components/ui/dropdown-menu/index.js';
144
150
  export * as Breadcrumb from './components/ui/breadcrumb/index.js';
145
151
  export * as Pagination from './components/ui/pagination/index.js';
146
152
  export * as ContextMenu from './components/ui/context-menu/index.js';
153
+ export * as NavigationMenu from './components/ui/navigation-menu/index.js';
147
154
  export * as Collapsible from './components/ui/collapsible/index.js';
148
155
  export { Label } from './components/ui/label/index.js';
149
156
  export { Command } from './components/ui/command/index.js';