@classic-homes/theme-svelte 0.1.3 → 0.1.5

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 (41) hide show
  1. package/dist/lib/components/Combobox.svelte +187 -0
  2. package/dist/lib/components/Combobox.svelte.d.ts +38 -0
  3. package/dist/lib/components/DateTimePicker.svelte +415 -0
  4. package/dist/lib/components/DateTimePicker.svelte.d.ts +31 -0
  5. package/dist/lib/components/MultiSelect.svelte +244 -0
  6. package/dist/lib/components/MultiSelect.svelte.d.ts +40 -0
  7. package/dist/lib/components/NumberInput.svelte +205 -0
  8. package/dist/lib/components/NumberInput.svelte.d.ts +33 -0
  9. package/dist/lib/components/OTPInput.svelte +213 -0
  10. package/dist/lib/components/OTPInput.svelte.d.ts +23 -0
  11. package/dist/lib/components/RadioGroup.svelte +124 -0
  12. package/dist/lib/components/RadioGroup.svelte.d.ts +31 -0
  13. package/dist/lib/components/Signature.svelte +1070 -0
  14. package/dist/lib/components/Signature.svelte.d.ts +74 -0
  15. package/dist/lib/components/Slider.svelte +136 -0
  16. package/dist/lib/components/Slider.svelte.d.ts +30 -0
  17. package/dist/lib/components/layout/AppShell.svelte +1 -1
  18. package/dist/lib/components/layout/DashboardLayout.svelte +63 -16
  19. package/dist/lib/components/layout/DashboardLayout.svelte.d.ts +12 -10
  20. package/dist/lib/components/layout/QuickLinks.svelte +49 -29
  21. package/dist/lib/components/layout/QuickLinks.svelte.d.ts +4 -2
  22. package/dist/lib/components/layout/Sidebar.svelte +345 -86
  23. package/dist/lib/components/layout/Sidebar.svelte.d.ts +12 -0
  24. package/dist/lib/components/layout/sidebar/SidebarFlyout.svelte +182 -0
  25. package/dist/lib/components/layout/sidebar/SidebarFlyout.svelte.d.ts +18 -0
  26. package/dist/lib/components/layout/sidebar/SidebarNavItem.svelte +369 -0
  27. package/dist/lib/components/layout/sidebar/SidebarNavItem.svelte.d.ts +25 -0
  28. package/dist/lib/components/layout/sidebar/SidebarSearch.svelte +121 -0
  29. package/dist/lib/components/layout/sidebar/SidebarSearch.svelte.d.ts +17 -0
  30. package/dist/lib/components/layout/sidebar/SidebarSection.svelte +144 -0
  31. package/dist/lib/components/layout/sidebar/SidebarSection.svelte.d.ts +25 -0
  32. package/dist/lib/components/layout/sidebar/index.d.ts +10 -0
  33. package/dist/lib/components/layout/sidebar/index.js +10 -0
  34. package/dist/lib/index.d.ts +9 -1
  35. package/dist/lib/index.js +8 -0
  36. package/dist/lib/schemas/auth.d.ts +6 -6
  37. package/dist/lib/stores/sidebar.svelte.d.ts +54 -0
  38. package/dist/lib/stores/sidebar.svelte.js +171 -1
  39. package/dist/lib/types/components.d.ts +105 -0
  40. package/dist/lib/types/layout.d.ts +32 -2
  41. package/package.json +1 -1
@@ -0,0 +1,121 @@
1
+ <script lang="ts">
2
+ /**
3
+ * SidebarSearch - Search input component for sidebar navigation
4
+ *
5
+ * Features debounced input to prevent excessive filtering on large navigation trees
6
+ */
7
+ import { cn } from '../../../utils.js';
8
+
9
+ interface Props {
10
+ /** Current search value */
11
+ value: string;
12
+ /** Placeholder text */
13
+ placeholder?: string;
14
+ /** Whether using light variant */
15
+ isLight?: boolean;
16
+ /** Debounce delay in milliseconds (default: 150) */
17
+ debounceMs?: number;
18
+ /** Callback when value changes (debounced) */
19
+ onInput: (value: string) => void;
20
+ /** Callback when search is cleared */
21
+ onClear: () => void;
22
+ }
23
+
24
+ let {
25
+ value,
26
+ placeholder = 'Search...',
27
+ isLight = true,
28
+ debounceMs = 150,
29
+ onInput,
30
+ onClear,
31
+ }: Props = $props();
32
+
33
+ // Local input value for immediate feedback
34
+ let localValue = $state('');
35
+ let debounceTimer: ReturnType<typeof setTimeout> | null = null;
36
+
37
+ // Sync local value when external value changes (including initial value)
38
+ $effect(() => {
39
+ localValue = value;
40
+ });
41
+
42
+ function handleInput(newValue: string) {
43
+ localValue = newValue;
44
+
45
+ // Clear any existing timer
46
+ if (debounceTimer) {
47
+ clearTimeout(debounceTimer);
48
+ }
49
+
50
+ // Debounce the callback
51
+ debounceTimer = setTimeout(() => {
52
+ onInput(newValue);
53
+ debounceTimer = null;
54
+ }, debounceMs);
55
+ }
56
+
57
+ function handleClear() {
58
+ // Clear immediately without debounce
59
+ if (debounceTimer) {
60
+ clearTimeout(debounceTimer);
61
+ debounceTimer = null;
62
+ }
63
+ localValue = '';
64
+ onClear();
65
+ }
66
+ </script>
67
+
68
+ <div class="px-3 py-2 border-b border-black">
69
+ <div class="relative">
70
+ <!-- Search icon - always rendered, no conditional blocks to avoid transition issues -->
71
+ <svg
72
+ class="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground pointer-events-none"
73
+ fill="none"
74
+ viewBox="0 0 24 24"
75
+ stroke="currentColor"
76
+ >
77
+ <path
78
+ stroke-linecap="round"
79
+ stroke-linejoin="round"
80
+ stroke-width="2"
81
+ d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
82
+ />
83
+ </svg>
84
+ <input
85
+ type="search"
86
+ data-sidebar-search
87
+ value={localValue}
88
+ {placeholder}
89
+ class={cn(
90
+ 'w-full pl-9 pr-8 py-1.5 text-sm rounded-md border transition-colors',
91
+ 'focus:outline-none focus:ring-2 focus:ring-primary/50',
92
+ '[&::-webkit-search-cancel-button]:hidden [&::-webkit-search-decoration]:hidden',
93
+ isLight
94
+ ? 'bg-background border-border text-foreground placeholder:text-muted-foreground'
95
+ : 'bg-sidebar-accent/50 border-sidebar-foreground/20 text-sidebar-foreground placeholder:text-sidebar-foreground/50'
96
+ )}
97
+ oninput={(e) => handleInput(e.currentTarget.value)}
98
+ />
99
+ {#if localValue}
100
+ <button
101
+ type="button"
102
+ class={cn(
103
+ 'absolute right-2 top-1/2 -translate-y-1/2 p-1 rounded',
104
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1',
105
+ isLight ? 'hover:bg-accent' : 'hover:bg-sidebar-accent'
106
+ )}
107
+ onclick={handleClear}
108
+ aria-label="Clear search"
109
+ >
110
+ <svg class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
111
+ <path
112
+ stroke-linecap="round"
113
+ stroke-linejoin="round"
114
+ stroke-width="2"
115
+ d="M6 18L18 6M6 6l12 12"
116
+ />
117
+ </svg>
118
+ </button>
119
+ {/if}
120
+ </div>
121
+ </div>
@@ -0,0 +1,17 @@
1
+ interface Props {
2
+ /** Current search value */
3
+ value: string;
4
+ /** Placeholder text */
5
+ placeholder?: string;
6
+ /** Whether using light variant */
7
+ isLight?: boolean;
8
+ /** Debounce delay in milliseconds (default: 150) */
9
+ debounceMs?: number;
10
+ /** Callback when value changes (debounced) */
11
+ onInput: (value: string) => void;
12
+ /** Callback when search is cleared */
13
+ onClear: () => void;
14
+ }
15
+ declare const SidebarSearch: import("svelte").Component<Props, {}, "">;
16
+ type SidebarSearch = ReturnType<typeof SidebarSearch>;
17
+ export default SidebarSearch;
@@ -0,0 +1,144 @@
1
+ <script lang="ts">
2
+ /**
3
+ * SidebarSection - Navigation section component with optional collapsible header
4
+ *
5
+ * Features animated collapse/expand transitions
6
+ */
7
+ import { slide } from 'svelte/transition';
8
+ import type { Snippet } from 'svelte';
9
+ import type { NavSection, NavItem } from '../../../types/layout.js';
10
+ import { cn } from '../../../utils.js';
11
+ import { sidebarStore } from '../../../stores/sidebar.svelte.js';
12
+ import SidebarNavItem from './SidebarNavItem.svelte';
13
+
14
+ interface Props {
15
+ /** The navigation section to render */
16
+ section: NavSection;
17
+ /** Whether using light variant */
18
+ isLight?: boolean;
19
+ /** Whether sidebar is collapsed */
20
+ collapsed?: boolean;
21
+ /** Whether currently on mobile */
22
+ isMobile?: boolean;
23
+ /** Custom icon renderer for nav items */
24
+ icon?: Snippet<[NavItem]>;
25
+ /** Search query for text highlighting */
26
+ searchQuery?: string;
27
+ /** Callback when a navigation item is clicked */
28
+ onNavigate?: (item: NavItem) => void;
29
+ /** Callback when mouse enters an item (for flyout) */
30
+ onItemMouseEnter?: (item: NavItem, event: MouseEvent) => void;
31
+ /** Callback when mouse leaves an item (for flyout) */
32
+ onItemMouseLeave?: () => void;
33
+ }
34
+
35
+ let {
36
+ section,
37
+ isLight = true,
38
+ collapsed = false,
39
+ isMobile = false,
40
+ icon,
41
+ searchQuery = '',
42
+ onNavigate,
43
+ onItemMouseEnter,
44
+ onItemMouseLeave,
45
+ }: Props = $props();
46
+
47
+ const isExpanded = $derived(sidebarStore.isSectionExpanded(section.id));
48
+
49
+ function toggleSection() {
50
+ sidebarStore.toggleSection(section.id);
51
+ }
52
+ </script>
53
+
54
+ <div class="mb-4">
55
+ {#if section.title}
56
+ {#if section.collapsible && !collapsed && !isMobile}
57
+ <!-- Collapsible section header -->
58
+ <button
59
+ onclick={toggleSection}
60
+ class={cn(
61
+ 'flex w-full items-center justify-between mb-2 px-4 text-xs font-semibold uppercase tracking-wider transition-colors rounded-md',
62
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1',
63
+ isLight
64
+ ? 'text-muted-foreground hover:text-foreground'
65
+ : 'text-sidebar-foreground/60 hover:text-sidebar-foreground'
66
+ )}
67
+ aria-expanded={isExpanded}
68
+ aria-controls={`sidebar-section-${section.id}`}
69
+ >
70
+ <span class="whitespace-nowrap">{section.title}</span>
71
+ <svg
72
+ class={cn(
73
+ 'h-4 w-4 transition-transform duration-200',
74
+ isExpanded ? 'rotate-0' : '-rotate-90'
75
+ )}
76
+ fill="none"
77
+ viewBox="0 0 24 24"
78
+ stroke="currentColor"
79
+ >
80
+ <path
81
+ stroke-linecap="round"
82
+ stroke-linejoin="round"
83
+ stroke-width="2"
84
+ d="M19 9l-7 7-7-7"
85
+ />
86
+ </svg>
87
+ </button>
88
+ {:else if !collapsed}
89
+ <!-- Non-collapsible section header -->
90
+ <h2
91
+ class={cn(
92
+ 'mb-2 px-4 text-xs font-semibold uppercase tracking-wider',
93
+ isLight ? 'text-muted-foreground' : 'text-sidebar-foreground/60'
94
+ )}
95
+ >
96
+ {section.title}
97
+ </h2>
98
+ {/if}
99
+ {/if}
100
+
101
+ {#if !section.collapsible || collapsed || isMobile}
102
+ <!-- Non-collapsible or mobile/collapsed: show without animation -->
103
+ <ul class="space-y-1 px-2" id={`sidebar-section-${section.id}`}>
104
+ {#each section.items as item}
105
+ <li>
106
+ <SidebarNavItem
107
+ {item}
108
+ {isLight}
109
+ {collapsed}
110
+ {isMobile}
111
+ {icon}
112
+ {searchQuery}
113
+ {onNavigate}
114
+ onMouseEnter={onItemMouseEnter}
115
+ onMouseLeave={onItemMouseLeave}
116
+ />
117
+ </li>
118
+ {/each}
119
+ </ul>
120
+ {:else if isExpanded}
121
+ <!-- Collapsible and expanded: animate -->
122
+ <ul
123
+ class="space-y-1 px-2 motion-reduce:transition-none overflow-hidden"
124
+ id={`sidebar-section-${section.id}`}
125
+ transition:slide={{ duration: 200 }}
126
+ >
127
+ {#each section.items as item}
128
+ <li>
129
+ <SidebarNavItem
130
+ {item}
131
+ {isLight}
132
+ {collapsed}
133
+ {isMobile}
134
+ {icon}
135
+ {searchQuery}
136
+ {onNavigate}
137
+ onMouseEnter={onItemMouseEnter}
138
+ onMouseLeave={onItemMouseLeave}
139
+ />
140
+ </li>
141
+ {/each}
142
+ </ul>
143
+ {/if}
144
+ </div>
@@ -0,0 +1,25 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { NavSection, NavItem } from '../../../types/layout.js';
3
+ interface Props {
4
+ /** The navigation section to render */
5
+ section: NavSection;
6
+ /** Whether using light variant */
7
+ isLight?: boolean;
8
+ /** Whether sidebar is collapsed */
9
+ collapsed?: boolean;
10
+ /** Whether currently on mobile */
11
+ isMobile?: boolean;
12
+ /** Custom icon renderer for nav items */
13
+ icon?: Snippet<[NavItem]>;
14
+ /** Search query for text highlighting */
15
+ searchQuery?: string;
16
+ /** Callback when a navigation item is clicked */
17
+ onNavigate?: (item: NavItem) => void;
18
+ /** Callback when mouse enters an item (for flyout) */
19
+ onItemMouseEnter?: (item: NavItem, event: MouseEvent) => void;
20
+ /** Callback when mouse leaves an item (for flyout) */
21
+ onItemMouseLeave?: () => void;
22
+ }
23
+ declare const SidebarSection: import("svelte").Component<Props, {}, "">;
24
+ type SidebarSection = ReturnType<typeof SidebarSection>;
25
+ export default SidebarSection;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Sidebar subcomponents
3
+ *
4
+ * These are internal components used by the main Sidebar component.
5
+ * They can be used independently for custom sidebar implementations.
6
+ */
7
+ export { default as SidebarSearch } from './SidebarSearch.svelte';
8
+ export { default as SidebarNavItem } from './SidebarNavItem.svelte';
9
+ export { default as SidebarSection } from './SidebarSection.svelte';
10
+ export { default as SidebarFlyout } from './SidebarFlyout.svelte';
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Sidebar subcomponents
3
+ *
4
+ * These are internal components used by the main Sidebar component.
5
+ * They can be used independently for custom sidebar implementations.
6
+ */
7
+ export { default as SidebarSearch } from './SidebarSearch.svelte';
8
+ export { default as SidebarNavItem } from './SidebarNavItem.svelte';
9
+ export { default as SidebarSection } from './SidebarSection.svelte';
10
+ export { default as SidebarFlyout } from './SidebarFlyout.svelte';
@@ -34,10 +34,18 @@ export { default as DropdownMenu } from './components/DropdownMenu.svelte';
34
34
  export { default as Select } from './components/Select.svelte';
35
35
  export { default as FormField } from './components/FormField.svelte';
36
36
  export { default as FileUpload } from './components/FileUpload.svelte';
37
+ export { default as RadioGroup } from './components/RadioGroup.svelte';
38
+ export { default as Slider } from './components/Slider.svelte';
39
+ export { default as NumberInput } from './components/NumberInput.svelte';
40
+ export { default as Combobox } from './components/Combobox.svelte';
41
+ export { default as MultiSelect } from './components/MultiSelect.svelte';
42
+ export { default as DateTimePicker } from './components/DateTimePicker.svelte';
43
+ export { default as OTPInput } from './components/OTPInput.svelte';
44
+ export { default as Signature } from './components/Signature.svelte';
37
45
  export { default as DataTable } from './components/DataTable.svelte';
38
46
  export { default as Tabs } from './components/Tabs.svelte';
39
47
  export { default as TabPanel } from './components/TabPanel.svelte';
40
- export type { DropdownMenuItem, DropdownMenuGroup, SelectOption, SelectGroup, Tab, FileMetadata, DataTableColumn, } from './types/components.js';
48
+ export type { DropdownMenuItem, DropdownMenuGroup, SelectOption, SelectGroup, Tab, FileMetadata, DataTableColumn, RadioOption, ComboboxOption, MultiSelectOption, SignatureData, SignatureStroke, SignaturePoint, SignatureMetadata, SignatureFont, SignatureValidationResult, } from './types/components.js';
41
49
  export { default as LogoMain } from './components/LogoMain.svelte';
42
50
  export { default as LoadingLogo } from './components/LoadingLogo.svelte';
43
51
  export { default as Avatar } from './components/Avatar.svelte';
package/dist/lib/index.js CHANGED
@@ -41,6 +41,14 @@ export { default as DropdownMenu } from './components/DropdownMenu.svelte';
41
41
  export { default as Select } from './components/Select.svelte';
42
42
  export { default as FormField } from './components/FormField.svelte';
43
43
  export { default as FileUpload } from './components/FileUpload.svelte';
44
+ export { default as RadioGroup } from './components/RadioGroup.svelte';
45
+ export { default as Slider } from './components/Slider.svelte';
46
+ export { default as NumberInput } from './components/NumberInput.svelte';
47
+ export { default as Combobox } from './components/Combobox.svelte';
48
+ export { default as MultiSelect } from './components/MultiSelect.svelte';
49
+ export { default as DateTimePicker } from './components/DateTimePicker.svelte';
50
+ export { default as OTPInput } from './components/OTPInput.svelte';
51
+ export { default as Signature } from './components/Signature.svelte';
44
52
  // Data Display
45
53
  export { default as DataTable } from './components/DataTable.svelte';
46
54
  // Tabs
@@ -261,9 +261,9 @@ export declare const userSchema: z.ZodObject<{
261
261
  id: string;
262
262
  email: string;
263
263
  username?: string | undefined;
264
+ roles?: string[] | undefined;
264
265
  fullName?: string | undefined;
265
266
  avatarUrl?: string | null | undefined;
266
- roles?: string[] | undefined;
267
267
  permissions?: string[] | undefined;
268
268
  mfaEnabled?: boolean | undefined;
269
269
  emailVerified?: boolean | undefined;
@@ -273,9 +273,9 @@ export declare const userSchema: z.ZodObject<{
273
273
  id: string;
274
274
  email: string;
275
275
  username?: string | undefined;
276
+ roles?: string[] | undefined;
276
277
  fullName?: string | undefined;
277
278
  avatarUrl?: string | null | undefined;
278
- roles?: string[] | undefined;
279
279
  permissions?: string[] | undefined;
280
280
  mfaEnabled?: boolean | undefined;
281
281
  emailVerified?: boolean | undefined;
@@ -323,9 +323,9 @@ export declare const loginResponseSchema: z.ZodObject<{
323
323
  id: string;
324
324
  email: string;
325
325
  username?: string | undefined;
326
+ roles?: string[] | undefined;
326
327
  fullName?: string | undefined;
327
328
  avatarUrl?: string | null | undefined;
328
- roles?: string[] | undefined;
329
329
  permissions?: string[] | undefined;
330
330
  mfaEnabled?: boolean | undefined;
331
331
  emailVerified?: boolean | undefined;
@@ -335,9 +335,9 @@ export declare const loginResponseSchema: z.ZodObject<{
335
335
  id: string;
336
336
  email: string;
337
337
  username?: string | undefined;
338
+ roles?: string[] | undefined;
338
339
  fullName?: string | undefined;
339
340
  avatarUrl?: string | null | undefined;
340
- roles?: string[] | undefined;
341
341
  permissions?: string[] | undefined;
342
342
  mfaEnabled?: boolean | undefined;
343
343
  emailVerified?: boolean | undefined;
@@ -367,9 +367,9 @@ export declare const loginResponseSchema: z.ZodObject<{
367
367
  id: string;
368
368
  email: string;
369
369
  username?: string | undefined;
370
+ roles?: string[] | undefined;
370
371
  fullName?: string | undefined;
371
372
  avatarUrl?: string | null | undefined;
372
- roles?: string[] | undefined;
373
373
  permissions?: string[] | undefined;
374
374
  mfaEnabled?: boolean | undefined;
375
375
  emailVerified?: boolean | undefined;
@@ -389,9 +389,9 @@ export declare const loginResponseSchema: z.ZodObject<{
389
389
  id: string;
390
390
  email: string;
391
391
  username?: string | undefined;
392
+ roles?: string[] | undefined;
392
393
  fullName?: string | undefined;
393
394
  avatarUrl?: string | null | undefined;
394
- roles?: string[] | undefined;
395
395
  permissions?: string[] | undefined;
396
396
  mfaEnabled?: boolean | undefined;
397
397
  emailVerified?: boolean | undefined;
@@ -2,8 +2,28 @@
2
2
  * Sidebar Store - Svelte 5 runes-based state management for sidebar
3
3
  */
4
4
  declare class SidebarStore {
5
+ #private;
5
6
  isOpen: boolean;
6
7
  isMobile: boolean;
8
+ expandedSections: Set<string>;
9
+ expandedItems: Set<string>;
10
+ /**
11
+ * Whether the store has been initialized
12
+ */
13
+ get initialized(): boolean;
14
+ /**
15
+ * Whether the sidebar open state was loaded from localStorage
16
+ */
17
+ get hasPersistedState(): boolean;
18
+ /**
19
+ * Whether expansion state was loaded from localStorage
20
+ */
21
+ get hasPersistedExpansionState(): boolean;
22
+ /**
23
+ * Initialize store with persisted state.
24
+ * Call this from a component's $effect to load saved state.
25
+ */
26
+ initialize(): void;
7
27
  /**
8
28
  * Toggle the sidebar open/closed state
9
29
  */
@@ -20,6 +40,40 @@ declare class SidebarStore {
20
40
  * Set mobile mode
21
41
  */
22
42
  setMobile(isMobile: boolean): void;
43
+ /**
44
+ * Toggle section expansion state
45
+ */
46
+ toggleSection(sectionId: string): void;
47
+ /**
48
+ * Toggle item expansion state
49
+ */
50
+ toggleItem(itemId: string): void;
51
+ /**
52
+ * Check if a section is expanded
53
+ */
54
+ isSectionExpanded(sectionId: string): boolean;
55
+ /**
56
+ * Check if an item is expanded
57
+ */
58
+ isItemExpanded(itemId: string): boolean;
59
+ /**
60
+ * Set default expansion for sections (called during initialization)
61
+ */
62
+ setDefaultSections(sectionIds: string[]): void;
63
+ /**
64
+ * Set default expansion for items (called during initialization)
65
+ */
66
+ setDefaultItems(itemIds: string[]): void;
67
+ /**
68
+ * Force expand specific items (used during search to show matching children)
69
+ * This bypasses the persisted state check but doesn't persist the changes
70
+ */
71
+ forceExpandItems(itemIds: string[]): void;
72
+ /**
73
+ * Force expand specific sections (used during search)
74
+ * This bypasses the persisted state check but doesn't persist the changes
75
+ */
76
+ forceExpandSections(sectionIds: string[]): void;
23
77
  }
24
78
  export declare const sidebarStore: SidebarStore;
25
79
  export {};