@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
@@ -1,38 +1,208 @@
1
1
  /**
2
2
  * Sidebar Store - Svelte 5 runes-based state management for sidebar
3
3
  */
4
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
5
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
6
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
7
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
8
+ };
9
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
10
+ if (kind === "m") throw new TypeError("Private method is not writable");
11
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
12
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
13
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
14
+ };
15
+ var _SidebarStore_instances, _SidebarStore_initialized, _SidebarStore_loadedFromStorage, _SidebarStore_loadedExpansionFromStorage, _SidebarStore_persist, _SidebarStore_persistExpansion;
16
+ const STORAGE_KEY = 'classic-theme-sidebar-open';
17
+ const SECTIONS_STORAGE_KEY = 'classic-theme-sidebar-sections';
18
+ const ITEMS_STORAGE_KEY = 'classic-theme-sidebar-items';
4
19
  class SidebarStore {
5
20
  constructor() {
21
+ _SidebarStore_instances.add(this);
6
22
  this.isOpen = $state(true);
7
23
  this.isMobile = $state(false);
24
+ this.expandedSections = $state(new Set());
25
+ this.expandedItems = $state(new Set());
26
+ _SidebarStore_initialized.set(this, false);
27
+ _SidebarStore_loadedFromStorage.set(this, false);
28
+ _SidebarStore_loadedExpansionFromStorage.set(this, false);
29
+ }
30
+ /**
31
+ * Whether the store has been initialized
32
+ */
33
+ get initialized() {
34
+ return __classPrivateFieldGet(this, _SidebarStore_initialized, "f");
35
+ }
36
+ /**
37
+ * Whether the sidebar open state was loaded from localStorage
38
+ */
39
+ get hasPersistedState() {
40
+ return __classPrivateFieldGet(this, _SidebarStore_loadedFromStorage, "f");
41
+ }
42
+ /**
43
+ * Whether expansion state was loaded from localStorage
44
+ */
45
+ get hasPersistedExpansionState() {
46
+ return __classPrivateFieldGet(this, _SidebarStore_loadedExpansionFromStorage, "f");
47
+ }
48
+ /**
49
+ * Initialize store with persisted state.
50
+ * Call this from a component's $effect to load saved state.
51
+ */
52
+ initialize() {
53
+ if (__classPrivateFieldGet(this, _SidebarStore_initialized, "f") || typeof window === 'undefined')
54
+ return;
55
+ __classPrivateFieldSet(this, _SidebarStore_initialized, true, "f");
56
+ try {
57
+ // Load sidebar open state
58
+ const stored = localStorage.getItem(STORAGE_KEY);
59
+ if (stored !== null) {
60
+ this.isOpen = stored === 'true';
61
+ __classPrivateFieldSet(this, _SidebarStore_loadedFromStorage, true, "f");
62
+ }
63
+ // Load expanded sections
64
+ const sections = localStorage.getItem(SECTIONS_STORAGE_KEY);
65
+ if (sections) {
66
+ this.expandedSections = new Set(JSON.parse(sections));
67
+ __classPrivateFieldSet(this, _SidebarStore_loadedExpansionFromStorage, true, "f");
68
+ }
69
+ // Load expanded items
70
+ const items = localStorage.getItem(ITEMS_STORAGE_KEY);
71
+ if (items) {
72
+ this.expandedItems = new Set(JSON.parse(items));
73
+ __classPrivateFieldSet(this, _SidebarStore_loadedExpansionFromStorage, true, "f");
74
+ }
75
+ }
76
+ catch {
77
+ // localStorage not available
78
+ }
8
79
  }
9
80
  /**
10
81
  * Toggle the sidebar open/closed state
11
82
  */
12
83
  toggle() {
13
84
  this.isOpen = !this.isOpen;
85
+ __classPrivateFieldGet(this, _SidebarStore_instances, "m", _SidebarStore_persist).call(this);
14
86
  }
15
87
  /**
16
88
  * Open the sidebar
17
89
  */
18
90
  open() {
19
91
  this.isOpen = true;
92
+ __classPrivateFieldGet(this, _SidebarStore_instances, "m", _SidebarStore_persist).call(this);
20
93
  }
21
94
  /**
22
95
  * Close the sidebar
23
96
  */
24
97
  close() {
25
98
  this.isOpen = false;
99
+ __classPrivateFieldGet(this, _SidebarStore_instances, "m", _SidebarStore_persist).call(this);
26
100
  }
27
101
  /**
28
102
  * Set mobile mode
29
103
  */
30
104
  setMobile(isMobile) {
31
105
  this.isMobile = isMobile;
32
- // Auto-close sidebar on mobile
106
+ // Auto-close sidebar on mobile (don't persist mobile state)
33
107
  if (isMobile) {
34
108
  this.isOpen = false;
35
109
  }
36
110
  }
111
+ /**
112
+ * Toggle section expansion state
113
+ */
114
+ toggleSection(sectionId) {
115
+ const newSet = new Set(this.expandedSections);
116
+ if (newSet.has(sectionId)) {
117
+ newSet.delete(sectionId);
118
+ }
119
+ else {
120
+ newSet.add(sectionId);
121
+ }
122
+ this.expandedSections = newSet;
123
+ __classPrivateFieldGet(this, _SidebarStore_instances, "m", _SidebarStore_persistExpansion).call(this);
124
+ }
125
+ /**
126
+ * Toggle item expansion state
127
+ */
128
+ toggleItem(itemId) {
129
+ const newSet = new Set(this.expandedItems);
130
+ if (newSet.has(itemId)) {
131
+ newSet.delete(itemId);
132
+ }
133
+ else {
134
+ newSet.add(itemId);
135
+ }
136
+ this.expandedItems = newSet;
137
+ __classPrivateFieldGet(this, _SidebarStore_instances, "m", _SidebarStore_persistExpansion).call(this);
138
+ }
139
+ /**
140
+ * Check if a section is expanded
141
+ */
142
+ isSectionExpanded(sectionId) {
143
+ return this.expandedSections.has(sectionId);
144
+ }
145
+ /**
146
+ * Check if an item is expanded
147
+ */
148
+ isItemExpanded(itemId) {
149
+ return this.expandedItems.has(itemId);
150
+ }
151
+ /**
152
+ * Set default expansion for sections (called during initialization)
153
+ */
154
+ setDefaultSections(sectionIds) {
155
+ if (__classPrivateFieldGet(this, _SidebarStore_loadedExpansionFromStorage, "f"))
156
+ return;
157
+ this.expandedSections = new Set(sectionIds);
158
+ }
159
+ /**
160
+ * Set default expansion for items (called during initialization)
161
+ */
162
+ setDefaultItems(itemIds) {
163
+ if (__classPrivateFieldGet(this, _SidebarStore_loadedExpansionFromStorage, "f"))
164
+ return;
165
+ this.expandedItems = new Set(itemIds);
166
+ }
167
+ /**
168
+ * Force expand specific items (used during search to show matching children)
169
+ * This bypasses the persisted state check but doesn't persist the changes
170
+ */
171
+ forceExpandItems(itemIds) {
172
+ const newSet = new Set(this.expandedItems);
173
+ itemIds.forEach((id) => newSet.add(id));
174
+ this.expandedItems = newSet;
175
+ // Don't persist - this is temporary for search
176
+ }
177
+ /**
178
+ * Force expand specific sections (used during search)
179
+ * This bypasses the persisted state check but doesn't persist the changes
180
+ */
181
+ forceExpandSections(sectionIds) {
182
+ const newSet = new Set(this.expandedSections);
183
+ sectionIds.forEach((id) => newSet.add(id));
184
+ this.expandedSections = newSet;
185
+ // Don't persist - this is temporary for search
186
+ }
37
187
  }
188
+ _SidebarStore_initialized = new WeakMap(), _SidebarStore_loadedFromStorage = new WeakMap(), _SidebarStore_loadedExpansionFromStorage = new WeakMap(), _SidebarStore_instances = new WeakSet(), _SidebarStore_persist = function _SidebarStore_persist() {
189
+ if (typeof window === 'undefined')
190
+ return;
191
+ try {
192
+ localStorage.setItem(STORAGE_KEY, String(this.isOpen));
193
+ }
194
+ catch {
195
+ // localStorage not available
196
+ }
197
+ }, _SidebarStore_persistExpansion = function _SidebarStore_persistExpansion() {
198
+ if (typeof window === 'undefined')
199
+ return;
200
+ try {
201
+ localStorage.setItem(SECTIONS_STORAGE_KEY, JSON.stringify([...this.expandedSections]));
202
+ localStorage.setItem(ITEMS_STORAGE_KEY, JSON.stringify([...this.expandedItems]));
203
+ }
204
+ catch {
205
+ // localStorage not available
206
+ }
207
+ };
38
208
  export const sidebarStore = new SidebarStore();
@@ -80,3 +80,108 @@ export interface DataTableColumn<T = object> {
80
80
  /** Custom cell render function returning string */
81
81
  format?: (value: unknown, row: T) => string;
82
82
  }
83
+ /**
84
+ * RadioGroup Types
85
+ */
86
+ export interface RadioOption {
87
+ value: string;
88
+ label: string;
89
+ disabled?: boolean;
90
+ description?: string;
91
+ }
92
+ /**
93
+ * Combobox Types
94
+ */
95
+ export interface ComboboxOption {
96
+ value: string;
97
+ label: string;
98
+ disabled?: boolean;
99
+ }
100
+ /**
101
+ * MultiSelect Types
102
+ */
103
+ export interface MultiSelectOption {
104
+ value: string;
105
+ label: string;
106
+ disabled?: boolean;
107
+ }
108
+ /**
109
+ * Signature Types
110
+ */
111
+ /** Signature output data */
112
+ export interface SignatureData {
113
+ /** Unique identifier for this signature instance */
114
+ id: string;
115
+ /** The signature mode used */
116
+ mode: 'draw' | 'type';
117
+ /** Data URL of the signature image (PNG base64) */
118
+ dataUrl: string;
119
+ /** PNG blob (if requested) */
120
+ png?: Blob;
121
+ /** SVG string (if requested or mode is draw) */
122
+ svg?: string;
123
+ /** Typed name (if mode is type) */
124
+ typedName?: string;
125
+ /** Font used for typed signature */
126
+ font?: string;
127
+ /** Stroke data for reconstruction (draw mode) */
128
+ strokes?: SignatureStroke[];
129
+ /** Metadata for legal/audit purposes */
130
+ metadata: SignatureMetadata;
131
+ }
132
+ /** Individual stroke in draw mode */
133
+ export interface SignatureStroke {
134
+ /** Stroke points */
135
+ points: SignaturePoint[];
136
+ /** Stroke color */
137
+ color: string;
138
+ /** Stroke width */
139
+ width: number;
140
+ /** Timestamp when stroke started */
141
+ startTime: number;
142
+ /** Timestamp when stroke ended */
143
+ endTime: number;
144
+ }
145
+ /** Point in a stroke */
146
+ export interface SignaturePoint {
147
+ x: number;
148
+ y: number;
149
+ /** Pressure (0-1) if available */
150
+ pressure?: number;
151
+ /** Timestamp */
152
+ time: number;
153
+ }
154
+ /** Metadata captured with signature */
155
+ export interface SignatureMetadata {
156
+ /** ISO timestamp when signature was created */
157
+ timestamp: string;
158
+ /** User agent string */
159
+ userAgent: string;
160
+ /** Canvas dimensions used */
161
+ dimensions: {
162
+ width: number;
163
+ height: number;
164
+ };
165
+ /** Whether consent was given */
166
+ consented: boolean;
167
+ /** Consent text shown (for audit trail) */
168
+ consentText?: string;
169
+ /** Hash of signature data for tamper detection */
170
+ hash?: string;
171
+ }
172
+ /** Font configuration for typed signatures */
173
+ export interface SignatureFont {
174
+ /** Font family name */
175
+ family: string;
176
+ /** Display name for font picker */
177
+ label: string;
178
+ /** CSS src URL or Google Fonts name */
179
+ src?: string;
180
+ /** Whether font is loaded from Google Fonts */
181
+ googleFont?: boolean;
182
+ }
183
+ /** Validation result */
184
+ export interface SignatureValidationResult {
185
+ valid: boolean;
186
+ error?: string;
187
+ }
@@ -13,8 +13,8 @@ export interface NavItem {
13
13
  id: string;
14
14
  /** Display name */
15
15
  name: string;
16
- /** URL to navigate to */
17
- href: string;
16
+ /** URL to navigate to (optional if item has children) */
17
+ href?: string;
18
18
  /** Icon name (app renders via snippet) */
19
19
  icon?: string;
20
20
  /** Optional badge (notification count, etc.) */
@@ -25,6 +25,14 @@ export interface NavItem {
25
25
  external?: boolean;
26
26
  /** Whether this item is currently active */
27
27
  active?: boolean;
28
+ /** Nested child items for submenus */
29
+ children?: NavItem[];
30
+ /** Whether submenu is expanded (for items with children) */
31
+ expanded?: boolean;
32
+ /** Whether the item is disabled */
33
+ disabled?: boolean;
34
+ /** Whether the item is in a loading state */
35
+ loading?: boolean;
28
36
  }
29
37
  /**
30
38
  * Navigation section for grouping nav items
@@ -85,6 +93,8 @@ export interface QuickLink {
85
93
  external?: boolean;
86
94
  /** Accessible label for screen readers (used in icon-only mode) */
87
95
  ariaLabel?: string;
96
+ /** Optional badge (notification count, etc.) */
97
+ badge?: string | number;
88
98
  }
89
99
  /**
90
100
  * Props for QuickLinks component
@@ -98,6 +108,8 @@ export interface QuickLinksProps {
98
108
  variant?: 'light' | 'dark';
99
109
  /** Custom icon renderer */
100
110
  icon?: Snippet<[QuickLink]>;
111
+ /** Accessible label for the navigation region */
112
+ ariaLabel?: string;
101
113
  /** Additional classes */
102
114
  class?: string;
103
115
  }
@@ -131,6 +143,8 @@ export interface DashboardLayoutProps {
131
143
  quickLinksDisplay?: 'list' | 'icons';
132
144
  /** Custom icon renderer for quick links */
133
145
  quickLinkIcon?: Snippet<[QuickLink]>;
146
+ /** Callback when a navigation item is clicked */
147
+ onNavigate?: (item: NavItem) => void;
134
148
  /** Custom content at start of header */
135
149
  headerStart?: Snippet;
136
150
  /** Custom content at end of header */
@@ -139,6 +153,10 @@ export interface DashboardLayoutProps {
139
153
  userMenu?: Snippet<[User]>;
140
154
  /** Sidebar footer content */
141
155
  sidebarFooter?: Snippet;
156
+ /** Sidebar width when expanded in pixels (default: 256) */
157
+ expandedWidth?: number;
158
+ /** Sidebar width when collapsed in pixels (default: 64) */
159
+ collapsedWidth?: number;
142
160
  /** Main content */
143
161
  children: Snippet;
144
162
  }
@@ -167,6 +185,8 @@ export interface PublicLayoutProps {
167
185
  export interface SidebarProps {
168
186
  /** Navigation sections */
169
187
  navigation: NavSection[];
188
+ /** User roles for filtering navigation items */
189
+ userRoles?: string[];
170
190
  /** Visual variant - light (default) or dark */
171
191
  variant?: 'light' | 'dark';
172
192
  /** Whether sidebar is collapsed */
@@ -177,6 +197,8 @@ export interface SidebarProps {
177
197
  mobileOpen?: boolean;
178
198
  /** Callback when mobile sidebar should close */
179
199
  onClose?: () => void;
200
+ /** Callback when a navigation item is clicked */
201
+ onNavigate?: (item: NavItem) => void;
180
202
  /** Custom logo snippet */
181
203
  logo?: Snippet;
182
204
  /** Custom icon renderer for nav items */
@@ -191,6 +213,14 @@ export interface SidebarProps {
191
213
  footer?: Snippet;
192
214
  /** Use stronger/thicker border */
193
215
  strongBorder?: boolean;
216
+ /** Sidebar width when expanded in pixels (default: 256) */
217
+ expandedWidth?: number;
218
+ /** Sidebar width when collapsed in pixels (default: 64) */
219
+ collapsedWidth?: number;
220
+ /** Enable search/filter input for navigation */
221
+ searchable?: boolean;
222
+ /** Placeholder text for search input */
223
+ searchPlaceholder?: string;
194
224
  /** Additional classes */
195
225
  class?: string;
196
226
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classic-homes/theme-svelte",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Svelte components for the Classic theme system",
5
5
  "type": "module",
6
6
  "svelte": "./dist/lib/index.js",