svelora 3.0.7 → 3.0.10

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 (36) hide show
  1. package/dist/Chart/Chart.svelte +45 -44
  2. package/dist/Chart/chart.types.d.ts +9 -13
  3. package/dist/Chart/index.d.ts +1 -3
  4. package/dist/Chart/index.js +1 -3
  5. package/dist/NavigationMenu/NavigationMenu.svelte +255 -0
  6. package/dist/NavigationMenu/NavigationMenu.svelte.d.ts +4 -0
  7. package/dist/NavigationMenu/index.d.ts +3 -0
  8. package/dist/NavigationMenu/index.js +3 -0
  9. package/dist/NavigationMenu/navigation-menu.types.d.ts +104 -0
  10. package/dist/NavigationMenu/navigation-menu.variants.d.ts +142 -0
  11. package/dist/NavigationMenu/navigation-menu.variants.js +71 -0
  12. package/dist/Search/Search.svelte +94 -0
  13. package/dist/Search/Search.svelte.d.ts +4 -0
  14. package/dist/Search/index.d.ts +2 -0
  15. package/dist/Search/index.js +1 -0
  16. package/dist/Search/search.types.d.ts +40 -0
  17. package/dist/Search/search.types.js +1 -0
  18. package/dist/Sidebar/Sidebar.svelte +5 -5
  19. package/dist/Sidebar/sidebar.types.d.ts +10 -4
  20. package/dist/Sidebar/sidebar.variants.d.ts +18 -0
  21. package/dist/Sidebar/sidebar.variants.js +16 -6
  22. package/dist/docs/navigation.js +20 -9
  23. package/dist/index.d.ts +2 -3
  24. package/dist/index.js +2 -2
  25. package/dist/mcp/svelora-docs.data.json +11 -9
  26. package/package.json +4 -5
  27. package/dist/Chart/chart.variants.d.ts +0 -3
  28. package/dist/Chart/chart.variants.js +0 -4
  29. package/dist/Menu/Menu.svelte +0 -134
  30. package/dist/Menu/Menu.svelte.d.ts +0 -4
  31. package/dist/Menu/index.d.ts +0 -4
  32. package/dist/Menu/index.js +0 -4
  33. package/dist/Menu/menu.types.d.ts +0 -82
  34. package/dist/Menu/menu.variants.d.ts +0 -46
  35. package/dist/Menu/menu.variants.js +0 -32
  36. /package/dist/{Menu/menu.types.js → NavigationMenu/navigation-menu.types.js} +0 -0
@@ -0,0 +1,71 @@
1
+ import { tv } from 'tailwind-variants';
2
+ export const navigationMenuVariants = tv({
3
+ slots: {
4
+ base: 'flex',
5
+ group: 'flex',
6
+ item: [
7
+ 'group relative flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium transition-colors',
8
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2',
9
+ 'disabled:pointer-events-none disabled:opacity-50'
10
+ ],
11
+ icon: 'text-lg shrink-0 transition-colors',
12
+ chevron: 'text-base opacity-50 shrink-0 transition-transform group-data-[state=open]:rotate-180',
13
+ accordionGroupContent: 'flex flex-col gap-1 pl-4 mt-1',
14
+ accordionTrigger: [
15
+ 'flex items-center justify-between w-full px-3 py-2 text-sm font-medium rounded-md',
16
+ 'transition-colors duration-200 outline-none focus-visible:ring-2 focus-visible:ring-outline',
17
+ 'text-on-surface hover:bg-surface-container-highest',
18
+ 'disabled:opacity-50 disabled:cursor-not-allowed'
19
+ ]
20
+ },
21
+ variants: {
22
+ orientation: {
23
+ horizontal: {
24
+ base: 'flex-row items-center justify-between w-full gap-4',
25
+ group: 'flex-row items-center gap-1',
26
+ item: ''
27
+ },
28
+ vertical: {
29
+ base: 'flex-col w-full gap-4',
30
+ group: 'flex-col gap-1 w-full',
31
+ item: 'w-full justify-start'
32
+ }
33
+ },
34
+ variant: {
35
+ default: {
36
+ item: [
37
+ 'text-on-surface-variant hover:bg-surface-container hover:text-on-surface',
38
+ 'data-[state=open]:bg-surface-container data-[state=open]:text-on-surface'
39
+ ],
40
+ icon: 'text-on-surface-variant group-hover:text-on-surface group-data-[state=open]:text-on-surface'
41
+ },
42
+ ghost: {
43
+ item: [
44
+ 'text-on-surface hover:bg-primary/10 hover:text-primary',
45
+ 'data-[state=open]:bg-primary/10 data-[state=open]:text-primary'
46
+ ],
47
+ icon: 'text-on-surface-variant group-hover:text-primary group-data-[state=open]:text-primary'
48
+ }
49
+ },
50
+ active: {
51
+ true: {
52
+ item: 'bg-primary/10 text-primary font-semibold',
53
+ icon: 'text-primary',
54
+ accordionTrigger: 'bg-primary-container text-on-primary-container'
55
+ },
56
+ false: {}
57
+ },
58
+ collapsed: {
59
+ true: {
60
+ item: 'w-10 h-10 justify-center p-0 aspect-square shrink-0',
61
+ icon: 'text-[1.25rem] m-0'
62
+ },
63
+ false: {}
64
+ }
65
+ },
66
+ defaultVariants: {
67
+ variant: 'default',
68
+ active: false,
69
+ orientation: 'horizontal'
70
+ }
71
+ });
@@ -0,0 +1,94 @@
1
+ <script lang="ts">import { twMerge } from "tailwind-merge";
2
+ import Input from "../Input/Input.svelte";
3
+ import Button from "../Button/Button.svelte";
4
+ import Modal from "../Modal/Modal.svelte";
5
+ import Command from "../Command/Command.svelte";
6
+ import Kbd from "../Kbd/Kbd.svelte";
7
+ import { onMount } from "svelte";
8
+ let { variant = "input", value = $bindable(""), kbd = [], groups = [], onSelect, placeholder = "Search...", class: className, ...rest } = $props();
9
+ let open = $state(false);
10
+ onMount(() => {
11
+ if (kbd.length > 0 && (variant === "modal" || variant === "button")) {
12
+ const handleKeydown = (e) => {
13
+ const isMac = navigator.userAgent.toLowerCase().includes("mac");
14
+ const isMeta = kbd.includes("meta") || kbd.includes("ctrl");
15
+ const key = kbd.find((k) => k.length === 1)?.toLowerCase();
16
+ if (isMeta && key) {
17
+ if ((isMac ? e.metaKey : e.ctrlKey) && e.key.toLowerCase() === key) {
18
+ e.preventDefault();
19
+ open = true;
20
+ }
21
+ }
22
+ };
23
+ window.addEventListener("keydown", handleKeydown);
24
+ return () => window.removeEventListener("keydown", handleKeydown);
25
+ }
26
+ });
27
+ </script>
28
+
29
+ {#if variant === 'input'}
30
+ <Input
31
+ type="search"
32
+ {placeholder}
33
+ bind:value
34
+ leadingIcon="lucide:search"
35
+ class={className}
36
+ {...(rest as any)}
37
+ >
38
+ {#snippet trailingSlot()}
39
+ {#if kbd.length > 0}
40
+ <div class="pointer-events-none flex items-center gap-1">
41
+ {#each kbd as key}
42
+ <Kbd value={key} size="sm" />
43
+ {/each}
44
+ </div>
45
+ {/if}
46
+ {/snippet}
47
+ </Input>
48
+ {:else if variant === 'modal'}
49
+ <button
50
+ type="button"
51
+ class={twMerge(
52
+ 'flex h-10 w-full items-center justify-between rounded-md border border-outline-variant bg-surface px-3 py-2 text-sm text-on-surface-variant shadow-sm transition-colors hover:bg-surface-container hover:text-on-surface focus:outline-none focus:ring-2 focus:ring-primary',
53
+ className
54
+ )}
55
+ onclick={() => (open = true)}
56
+ {...(rest as any)}
57
+ >
58
+ <span class="flex items-center gap-2">
59
+ <span class="iconify lucide--search text-lg"></span>
60
+ <span>{placeholder}</span>
61
+ </span>
62
+ {#if kbd.length > 0}
63
+ <span class="flex items-center gap-1">
64
+ {#each kbd as key}
65
+ <Kbd value={key} size="sm" />
66
+ {/each}
67
+ </span>
68
+ {/if}
69
+ </button>
70
+ {:else if variant === 'button'}
71
+ <Button
72
+ variant="ghost"
73
+ color="surface"
74
+ leadingIcon="lucide:search"
75
+ class={className}
76
+ onclick={() => (open = true)}
77
+ {...(rest as any)}
78
+ />
79
+ {/if}
80
+
81
+ {#if variant === 'modal' || variant === 'button'}
82
+ <Modal bind:open size="lg">
83
+ {#snippet content()}
84
+ <Command
85
+ {groups}
86
+ bind:search={value}
87
+ placeholder="Type a command or search..."
88
+ ui={{
89
+ root: 'border-0 shadow-none'
90
+ }}
91
+ />
92
+ {/snippet}
93
+ </Modal>
94
+ {/if}
@@ -0,0 +1,4 @@
1
+ import type { SearchProps } from './search.types.js';
2
+ declare const Search: import("svelte").Component<SearchProps, {}, "value">;
3
+ type Search = ReturnType<typeof Search>;
4
+ export default Search;
@@ -0,0 +1,2 @@
1
+ export { default as Search } from './Search.svelte';
2
+ export type * from './search.types.js';
@@ -0,0 +1 @@
1
+ export { default as Search } from './Search.svelte';
@@ -0,0 +1,40 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ import type { ClassNameValue } from 'tailwind-merge';
3
+ import type { CommandGroup } from '../Command/command.types.js';
4
+ export type SearchVariant = 'input' | 'modal' | 'button';
5
+ export interface SearchProps extends Omit<HTMLAttributes<HTMLInputElement | HTMLButtonElement>, 'class'> {
6
+ /**
7
+ * Determines the visual style and behavior of the search component.
8
+ * - `input`: A standard input box.
9
+ * - `modal`: A fake input that opens a modal containing a Command palette when clicked.
10
+ * - `button`: A simple icon button that opens a modal containing a Command palette.
11
+ * @default 'input'
12
+ */
13
+ variant?: SearchVariant;
14
+ /**
15
+ * The value of the search input (when variant is 'input' or internal modal search).
16
+ */
17
+ value?: string;
18
+ /**
19
+ * Keyboard shortcut to display (and listen to) for opening the modal.
20
+ * E.g. `['meta', 'K']` or `['ctrl', '/']`
21
+ */
22
+ kbd?: string[];
23
+ /**
24
+ * Data groups to display in the Command palette (used when variant is 'modal' or 'button').
25
+ */
26
+ groups?: CommandGroup[];
27
+ /**
28
+ * Callback fired when an item is selected from the Command palette.
29
+ */
30
+ onSelect?: (value: string) => void;
31
+ /**
32
+ * Placeholder text for the input or fake input.
33
+ * @default 'Search...'
34
+ */
35
+ placeholder?: string;
36
+ /**
37
+ * Additional CSS classes for the root element.
38
+ */
39
+ class?: ClassNameValue;
40
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -6,25 +6,25 @@ let styles = $derived(sidebarVariants({
6
6
  collapsed,
7
7
  position
8
8
  }));
9
- // Provide context to children (like Menu) so they know if sidebar is collapsed
10
- // Useful if we want the Menu to hide labels when collapsed
9
+ // Provide context to children (like Menu) so they know if sidebar is collapsed or right-aligned
11
10
  setContext("sidebar-collapsed", () => collapsed);
11
+ setContext("sidebar-position", () => position);
12
12
  </script>
13
13
 
14
14
  <aside class={twMerge(styles.base(), className)} {...restProps}>
15
15
  {#if header}
16
16
  <div class={styles.header()}>
17
- {@render header()}
17
+ {@render header({ collapsed })}
18
18
  </div>
19
19
  {/if}
20
20
 
21
21
  <div class={styles.content()}>
22
- {@render children?.()}
22
+ {@render children?.({ collapsed })}
23
23
  </div>
24
24
 
25
25
  {#if footer}
26
26
  <div class={styles.footer()}>
27
- {@render footer()}
27
+ {@render footer({ collapsed })}
28
28
  </div>
29
29
  {/if}
30
30
  </aside>
@@ -1,7 +1,7 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
3
  import type { SidebarVariantProps } from './sidebar.variants.js';
4
- export interface SidebarProps extends HTMLAttributes<HTMLElement> {
4
+ export interface SidebarProps extends Omit<HTMLAttributes<HTMLElement>, 'children'> {
5
5
  /**
6
6
  * Whether the sidebar is collapsed (icons only).
7
7
  * @default false
@@ -19,13 +19,19 @@ export interface SidebarProps extends HTMLAttributes<HTMLElement> {
19
19
  /**
20
20
  * Snippet for the top header section (e.g. Logo).
21
21
  */
22
- header?: Snippet;
22
+ header?: Snippet<[{
23
+ collapsed: boolean;
24
+ }]>;
23
25
  /**
24
26
  * Snippet for the main content (e.g. Navigation Menu).
25
27
  */
26
- children?: Snippet;
28
+ children?: Snippet<[{
29
+ collapsed: boolean;
30
+ }]>;
27
31
  /**
28
32
  * Snippet for the bottom footer section (e.g. User Profile).
29
33
  */
30
- footer?: Snippet;
34
+ footer?: Snippet<[{
35
+ collapsed: boolean;
36
+ }]>;
31
37
  }
@@ -11,9 +11,15 @@ export declare const sidebarVariants: import("tailwind-variants").TVReturnType<{
11
11
  collapsed: {
12
12
  true: {
13
13
  base: string;
14
+ header: string;
15
+ content: string;
16
+ footer: string;
14
17
  };
15
18
  false: {
16
19
  base: string;
20
+ header: string;
21
+ content: string;
22
+ footer: string;
17
23
  };
18
24
  };
19
25
  }, {
@@ -33,9 +39,15 @@ export declare const sidebarVariants: import("tailwind-variants").TVReturnType<{
33
39
  collapsed: {
34
40
  true: {
35
41
  base: string;
42
+ header: string;
43
+ content: string;
44
+ footer: string;
36
45
  };
37
46
  false: {
38
47
  base: string;
48
+ header: string;
49
+ content: string;
50
+ footer: string;
39
51
  };
40
52
  };
41
53
  }, {
@@ -55,9 +67,15 @@ export declare const sidebarVariants: import("tailwind-variants").TVReturnType<{
55
67
  collapsed: {
56
68
  true: {
57
69
  base: string;
70
+ header: string;
71
+ content: string;
72
+ footer: string;
58
73
  };
59
74
  false: {
60
75
  base: string;
76
+ header: string;
77
+ content: string;
78
+ footer: string;
61
79
  };
62
80
  };
63
81
  }, {
@@ -1,10 +1,10 @@
1
1
  import { tv } from 'tailwind-variants';
2
2
  export const sidebarVariants = tv({
3
3
  slots: {
4
- base: 'flex flex-col h-full bg-surface-50 dark:bg-surface-900 border-outline-variant text-surface-900 dark:text-surface-50 transition-all duration-300',
5
- header: 'flex items-center px-4 h-16 shrink-0 border-b border-outline-variant',
6
- content: 'flex-1 overflow-y-auto px-3 py-4',
7
- footer: 'p-4 mt-auto border-t border-outline-variant shrink-0'
4
+ base: 'flex flex-col h-full bg-surface-container-low border-outline-variant/60 text-on-surface transition-[width] duration-300 ease-in-out',
5
+ header: 'flex items-center shrink-0 border-b border-outline-variant/60 transition-[padding] duration-300 h-16',
6
+ content: 'flex-1 overflow-y-auto py-4 transition-[padding] duration-300',
7
+ footer: 'mt-auto border-t border-outline-variant/60 shrink-0 transition-[padding] duration-300'
8
8
  },
9
9
  variants: {
10
10
  position: {
@@ -12,8 +12,18 @@ export const sidebarVariants = tv({
12
12
  right: { base: 'border-l' }
13
13
  },
14
14
  collapsed: {
15
- true: { base: 'w-16' },
16
- false: { base: 'w-64' }
15
+ true: {
16
+ base: 'w-[64px]',
17
+ header: 'px-3 justify-center',
18
+ content: 'px-3 flex flex-col items-center',
19
+ footer: 'p-3 flex flex-col items-center justify-center gap-4'
20
+ },
21
+ false: {
22
+ base: 'w-64',
23
+ header: 'px-4',
24
+ content: 'px-3',
25
+ footer: 'p-4'
26
+ }
17
27
  }
18
28
  },
19
29
  defaultVariants: {
@@ -146,10 +146,27 @@ export const docsComponentGroups = [
146
146
  icon: 'lucide:layout-panel-left-right'
147
147
  },
148
148
  {
149
- title: 'ScrollArea',
149
+ title: 'Modal',
150
+ href: '/docs/components/modal',
151
+ icon: 'lucide:layout-panel-left-right'
152
+ },
153
+ {
154
+ title: 'Navigation Menu',
155
+ href: '/docs/components/navigation-menu',
156
+ icon: 'lucide:compass',
157
+ description: 'A horizontal list of links with optional nested dropdowns.'
158
+ },
159
+ {
160
+ title: 'Scroll Area',
150
161
  href: '/docs/components/scroll-area',
151
- legacyHref: '/scroll-area',
152
- icon: 'lucide:mouse-pointer-square-dashed'
162
+ icon: 'lucide:scroll-text',
163
+ description: 'A customizable scrollable area with custom scrollbars.'
164
+ },
165
+ {
166
+ title: 'Search',
167
+ href: '/docs/components/search',
168
+ icon: 'lucide:search',
169
+ description: 'A flexible search input or command palette modal.'
153
170
  },
154
171
  {
155
172
  title: 'Separator',
@@ -435,12 +452,6 @@ export const docsComponentGroups = [
435
452
  legacyHref: '/pagination',
436
453
  icon: 'lucide:ellipsis'
437
454
  },
438
- {
439
- title: 'Menu',
440
- href: '/docs/components/menu',
441
- legacyHref: '/menu',
442
- icon: 'lucide:menu-square'
443
- },
444
455
  {
445
456
  title: 'Sidebar',
446
457
  href: '/docs/components/sidebar',
package/dist/index.d.ts CHANGED
@@ -1,5 +1,3 @@
1
- export { ModeWatcher, createInitialModeExpression, generateSetInitialModeExpression, mode, resetMode, setMode, setTheme, systemPrefersMode, theme, themeStorageKey, toggleMode, userPrefersMode, modeStorageKey } from 'mode-watcher';
2
- export type { SystemModeValue, SystemPrefersMode, UserPrefersMode } from 'mode-watcher';
3
1
  export * from './Accordion/index.js';
4
2
  export * from './Alert/index.js';
5
3
  export * from './Avatar/index.js';
@@ -40,8 +38,8 @@ export * from './Link/index.js';
40
38
  export * from './List/index.js';
41
39
  export * from './LocaleButton/index.js';
42
40
  export * from './Marquee/index.js';
43
- export * from './Menu/index.js';
44
41
  export * from './Modal/index.js';
42
+ export * from './NavigationMenu/index.js';
45
43
  export * from './NumberTicker/index.js';
46
44
  export * from './Pagination/index.js';
47
45
  export * from './PasswordInput/index.js';
@@ -53,6 +51,7 @@ export * from './RadioGroup/index.js';
53
51
  export * from './Rating/index.js';
54
52
  export * from './Resizable/index.js';
55
53
  export * from './ScrollArea/index.js';
54
+ export * from './Search/index.js';
56
55
  export * from './Select/index.js';
57
56
  export * from './SelectMenu/index.js';
58
57
  export * from './Separator/index.js';
package/dist/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  // Components
2
- export { ModeWatcher, createInitialModeExpression, generateSetInitialModeExpression, mode, resetMode, setMode, setTheme, systemPrefersMode, theme, themeStorageKey, toggleMode, userPrefersMode, modeStorageKey } from 'mode-watcher';
3
2
  export * from './Accordion/index.js';
4
3
  export * from './Alert/index.js';
5
4
  export * from './Avatar/index.js';
@@ -41,8 +40,8 @@ export * from './Link/index.js';
41
40
  export * from './List/index.js';
42
41
  export * from './LocaleButton/index.js';
43
42
  export * from './Marquee/index.js';
44
- export * from './Menu/index.js';
45
43
  export * from './Modal/index.js';
44
+ export * from './NavigationMenu/index.js';
46
45
  export * from './NumberTicker/index.js';
47
46
  export * from './Pagination/index.js';
48
47
  export * from './PasswordInput/index.js';
@@ -54,6 +53,7 @@ export * from './RadioGroup/index.js';
54
53
  export * from './Rating/index.js';
55
54
  export * from './Resizable/index.js';
56
55
  export * from './ScrollArea/index.js';
56
+ export * from './Search/index.js';
57
57
  export * from './Select/index.js';
58
58
  export * from './SelectMenu/index.js';
59
59
  export * from './Separator/index.js';