@classic-homes/theme-svelte 0.1.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.
- package/README.md +305 -0
- package/dist/lib/components/Alert.svelte +51 -0
- package/dist/lib/components/Alert.svelte.d.ts +9 -0
- package/dist/lib/components/AlertDescription.svelte +16 -0
- package/dist/lib/components/AlertDescription.svelte.d.ts +9 -0
- package/dist/lib/components/AlertDialog.svelte +136 -0
- package/dist/lib/components/AlertDialog.svelte.d.ts +79 -0
- package/dist/lib/components/AlertTitle.svelte +16 -0
- package/dist/lib/components/AlertTitle.svelte.d.ts +9 -0
- package/dist/lib/components/Avatar.svelte +56 -0
- package/dist/lib/components/Avatar.svelte.d.ts +26 -0
- package/dist/lib/components/AvatarFallback.svelte +31 -0
- package/dist/lib/components/AvatarFallback.svelte.d.ts +17 -0
- package/dist/lib/components/AvatarImage.svelte +29 -0
- package/dist/lib/components/AvatarImage.svelte.d.ts +12 -0
- package/dist/lib/components/Badge.svelte +73 -0
- package/dist/lib/components/Badge.svelte.d.ts +11 -0
- package/dist/lib/components/Button.svelte +130 -0
- package/dist/lib/components/Button.svelte.d.ts +17 -0
- package/dist/lib/components/Card.svelte +58 -0
- package/dist/lib/components/Card.svelte.d.ts +26 -0
- package/dist/lib/components/CardContent.svelte +16 -0
- package/dist/lib/components/CardContent.svelte.d.ts +9 -0
- package/dist/lib/components/CardDescription.svelte +16 -0
- package/dist/lib/components/CardDescription.svelte.d.ts +9 -0
- package/dist/lib/components/CardFooter.svelte +16 -0
- package/dist/lib/components/CardFooter.svelte.d.ts +9 -0
- package/dist/lib/components/CardHeader.svelte +16 -0
- package/dist/lib/components/CardHeader.svelte.d.ts +9 -0
- package/dist/lib/components/CardTitle.svelte +16 -0
- package/dist/lib/components/CardTitle.svelte.d.ts +9 -0
- package/dist/lib/components/Checkbox.svelte +65 -0
- package/dist/lib/components/Checkbox.svelte.d.ts +14 -0
- package/dist/lib/components/DataTable.svelte +334 -0
- package/dist/lib/components/DataTable.svelte.d.ts +103 -0
- package/dist/lib/components/Dialog.svelte +111 -0
- package/dist/lib/components/Dialog.svelte.d.ts +22 -0
- package/dist/lib/components/DropdownMenu.svelte +135 -0
- package/dist/lib/components/DropdownMenu.svelte.d.ts +33 -0
- package/dist/lib/components/FileUpload.svelte +448 -0
- package/dist/lib/components/FileUpload.svelte.d.ts +42 -0
- package/dist/lib/components/FormField.svelte +134 -0
- package/dist/lib/components/FormField.svelte.d.ts +37 -0
- package/dist/lib/components/Input.svelte +61 -0
- package/dist/lib/components/Input.svelte.d.ts +19 -0
- package/dist/lib/components/Label.svelte +33 -0
- package/dist/lib/components/Label.svelte.d.ts +11 -0
- package/dist/lib/components/LoadingLogo.svelte +124 -0
- package/dist/lib/components/LoadingLogo.svelte.d.ts +16 -0
- package/dist/lib/components/LogoMain.svelte +237 -0
- package/dist/lib/components/LogoMain.svelte.d.ts +20 -0
- package/dist/lib/components/PageHeader.svelte +90 -0
- package/dist/lib/components/PageHeader.svelte.d.ts +28 -0
- package/dist/lib/components/Section.svelte +44 -0
- package/dist/lib/components/Section.svelte.d.ts +28 -0
- package/dist/lib/components/Select.svelte +174 -0
- package/dist/lib/components/Select.svelte.d.ts +32 -0
- package/dist/lib/components/Separator.svelte +29 -0
- package/dist/lib/components/Separator.svelte.d.ts +9 -0
- package/dist/lib/components/Skeleton.svelte +35 -0
- package/dist/lib/components/Skeleton.svelte.d.ts +7 -0
- package/dist/lib/components/Spinner.svelte +50 -0
- package/dist/lib/components/Spinner.svelte.d.ts +8 -0
- package/dist/lib/components/Switch.svelte +56 -0
- package/dist/lib/components/Switch.svelte.d.ts +14 -0
- package/dist/lib/components/TabPanel.svelte +44 -0
- package/dist/lib/components/TabPanel.svelte.d.ts +12 -0
- package/dist/lib/components/Tabs.svelte +125 -0
- package/dist/lib/components/Tabs.svelte.d.ts +19 -0
- package/dist/lib/components/Textarea.svelte +54 -0
- package/dist/lib/components/Textarea.svelte.d.ts +16 -0
- package/dist/lib/components/Toast.svelte +116 -0
- package/dist/lib/components/Toast.svelte.d.ts +12 -0
- package/dist/lib/components/ToastContainer.svelte +56 -0
- package/dist/lib/components/ToastContainer.svelte.d.ts +8 -0
- package/dist/lib/components/Tooltip.svelte +55 -0
- package/dist/lib/components/Tooltip.svelte.d.ts +18 -0
- package/dist/lib/components/layout/AppShell.svelte +82 -0
- package/dist/lib/components/layout/AppShell.svelte.d.ts +44 -0
- package/dist/lib/components/layout/DashboardLayout.svelte +248 -0
- package/dist/lib/components/layout/DashboardLayout.svelte.d.ts +62 -0
- package/dist/lib/components/layout/Footer.svelte +130 -0
- package/dist/lib/components/layout/Footer.svelte.d.ts +32 -0
- package/dist/lib/components/layout/FormPageLayout.svelte +92 -0
- package/dist/lib/components/layout/FormPageLayout.svelte.d.ts +33 -0
- package/dist/lib/components/layout/Header.svelte +94 -0
- package/dist/lib/components/layout/Header.svelte.d.ts +30 -0
- package/dist/lib/components/layout/PublicLayout.svelte +180 -0
- package/dist/lib/components/layout/PublicLayout.svelte.d.ts +39 -0
- package/dist/lib/components/layout/QuickLinks.svelte +112 -0
- package/dist/lib/components/layout/QuickLinks.svelte.d.ts +27 -0
- package/dist/lib/components/layout/Sidebar.svelte +243 -0
- package/dist/lib/components/layout/Sidebar.svelte.d.ts +48 -0
- package/dist/lib/composables/index.d.ts +8 -0
- package/dist/lib/composables/index.js +10 -0
- package/dist/lib/composables/useAsync.svelte.d.ts +102 -0
- package/dist/lib/composables/useAsync.svelte.js +210 -0
- package/dist/lib/composables/useForm.svelte.d.ts +123 -0
- package/dist/lib/composables/useForm.svelte.js +245 -0
- package/dist/lib/index.d.ts +65 -0
- package/dist/lib/index.js +83 -0
- package/dist/lib/performance.d.ts +79 -0
- package/dist/lib/performance.js +170 -0
- package/dist/lib/schemas/auth.d.ts +410 -0
- package/dist/lib/schemas/auth.js +216 -0
- package/dist/lib/schemas/common.d.ts +267 -0
- package/dist/lib/schemas/common.js +268 -0
- package/dist/lib/schemas/index.d.ts +24 -0
- package/dist/lib/schemas/index.js +32 -0
- package/dist/lib/stores/sidebar.svelte.d.ts +25 -0
- package/dist/lib/stores/sidebar.svelte.js +38 -0
- package/dist/lib/stores/theme.svelte.d.ts +72 -0
- package/dist/lib/stores/theme.svelte.js +150 -0
- package/dist/lib/stores/toast.svelte.d.ts +62 -0
- package/dist/lib/stores/toast.svelte.js +93 -0
- package/dist/lib/types/components.d.ts +85 -0
- package/dist/lib/types/components.js +7 -0
- package/dist/lib/types/layout.d.ts +258 -0
- package/dist/lib/types/layout.js +7 -0
- package/dist/lib/utils.d.ts +6 -0
- package/dist/lib/utils.js +9 -0
- package/dist/lib/validation.d.ts +101 -0
- package/dist/lib/validation.js +170 -0
- package/package.json +56 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classic Theme Svelte Components
|
|
3
|
+
*
|
|
4
|
+
* A collection of accessible, composable Svelte 5 components built on Bits UI
|
|
5
|
+
* and styled with Tailwind CSS using the Classic theme design tokens.
|
|
6
|
+
*
|
|
7
|
+
* All components use Svelte 5 runes syntax ($props, $state, $derived, etc.)
|
|
8
|
+
*/
|
|
9
|
+
export { default as Button } from './components/Button.svelte';
|
|
10
|
+
export { default as Input } from './components/Input.svelte';
|
|
11
|
+
export { default as Label } from './components/Label.svelte';
|
|
12
|
+
export { default as Textarea } from './components/Textarea.svelte';
|
|
13
|
+
export { default as Checkbox } from './components/Checkbox.svelte';
|
|
14
|
+
export { default as Switch } from './components/Switch.svelte';
|
|
15
|
+
export { default as Separator } from './components/Separator.svelte';
|
|
16
|
+
export { default as Card } from './components/Card.svelte';
|
|
17
|
+
export { default as CardHeader } from './components/CardHeader.svelte';
|
|
18
|
+
export { default as CardTitle } from './components/CardTitle.svelte';
|
|
19
|
+
export { default as CardDescription } from './components/CardDescription.svelte';
|
|
20
|
+
export { default as CardContent } from './components/CardContent.svelte';
|
|
21
|
+
export { default as CardFooter } from './components/CardFooter.svelte';
|
|
22
|
+
export { default as Alert } from './components/Alert.svelte';
|
|
23
|
+
export { default as AlertTitle } from './components/AlertTitle.svelte';
|
|
24
|
+
export { default as AlertDescription } from './components/AlertDescription.svelte';
|
|
25
|
+
export { default as Badge } from './components/Badge.svelte';
|
|
26
|
+
export { default as Spinner } from './components/Spinner.svelte';
|
|
27
|
+
export { default as Skeleton } from './components/Skeleton.svelte';
|
|
28
|
+
export { default as Toast } from './components/Toast.svelte';
|
|
29
|
+
export { default as ToastContainer } from './components/ToastContainer.svelte';
|
|
30
|
+
export { default as Dialog } from './components/Dialog.svelte';
|
|
31
|
+
export { default as AlertDialog } from './components/AlertDialog.svelte';
|
|
32
|
+
export { default as Tooltip } from './components/Tooltip.svelte';
|
|
33
|
+
export { default as DropdownMenu } from './components/DropdownMenu.svelte';
|
|
34
|
+
export { default as Select } from './components/Select.svelte';
|
|
35
|
+
export { default as FormField } from './components/FormField.svelte';
|
|
36
|
+
export { default as FileUpload } from './components/FileUpload.svelte';
|
|
37
|
+
export { default as DataTable } from './components/DataTable.svelte';
|
|
38
|
+
export { default as Tabs } from './components/Tabs.svelte';
|
|
39
|
+
export { default as TabPanel } from './components/TabPanel.svelte';
|
|
40
|
+
export type { DropdownMenuItem, DropdownMenuGroup, SelectOption, SelectGroup, Tab, FileMetadata, DataTableColumn, } from './types/components.js';
|
|
41
|
+
export { default as LogoMain } from './components/LogoMain.svelte';
|
|
42
|
+
export { default as LoadingLogo } from './components/LoadingLogo.svelte';
|
|
43
|
+
export { default as Avatar } from './components/Avatar.svelte';
|
|
44
|
+
export { default as AvatarImage } from './components/AvatarImage.svelte';
|
|
45
|
+
export { default as AvatarFallback } from './components/AvatarFallback.svelte';
|
|
46
|
+
export { default as Section } from './components/Section.svelte';
|
|
47
|
+
export { default as PageHeader } from './components/PageHeader.svelte';
|
|
48
|
+
export { default as AppShell } from './components/layout/AppShell.svelte';
|
|
49
|
+
export { default as DashboardLayout } from './components/layout/DashboardLayout.svelte';
|
|
50
|
+
export { default as PublicLayout } from './components/layout/PublicLayout.svelte';
|
|
51
|
+
export { default as FormPageLayout } from './components/layout/FormPageLayout.svelte';
|
|
52
|
+
export { default as Sidebar } from './components/layout/Sidebar.svelte';
|
|
53
|
+
export { default as Header } from './components/layout/Header.svelte';
|
|
54
|
+
export { default as Footer } from './components/layout/Footer.svelte';
|
|
55
|
+
export { default as QuickLinks } from './components/layout/QuickLinks.svelte';
|
|
56
|
+
export type { NavItem, NavSection, User, BackLink, QuickLink, QuickLinksProps, DashboardLayoutProps, PublicLayoutProps, FormPageLayoutProps, SidebarProps, HeaderProps, FooterProps, AppShellProps, } from './types/layout.js';
|
|
57
|
+
export { toastStore, type Toast as ToastType, type ToastInput } from './stores/toast.svelte.js';
|
|
58
|
+
export { sidebarStore } from './stores/sidebar.svelte.js';
|
|
59
|
+
export { themeStore, type ThemeMode } from './stores/theme.svelte.js';
|
|
60
|
+
export { cn } from './utils.js';
|
|
61
|
+
export { tv, type VariantProps } from 'tailwind-variants';
|
|
62
|
+
export { validateNonEmptyArray, validateRequired, validateOneOf, validateRange, validateProps, createValidator, type ValidationResult, } from './validation.js';
|
|
63
|
+
export { perfStart, perfEnd, measure, measureAsync, getPerformanceEntries, clearPerformanceEntries, createPerfMonitor, type PerformanceMark, } from './performance.js';
|
|
64
|
+
export { useForm, useAsync, runAsync, type UseFormOptions, type UseFormReturn, type FieldError, type FormState, type InferFormData, type UseAsyncOptions, type UseAsyncReturn, } from './composables/index.js';
|
|
65
|
+
export * from './schemas/index.js';
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classic Theme Svelte Components
|
|
3
|
+
*
|
|
4
|
+
* A collection of accessible, composable Svelte 5 components built on Bits UI
|
|
5
|
+
* and styled with Tailwind CSS using the Classic theme design tokens.
|
|
6
|
+
*
|
|
7
|
+
* All components use Svelte 5 runes syntax ($props, $state, $derived, etc.)
|
|
8
|
+
*/
|
|
9
|
+
// Core UI Components
|
|
10
|
+
export { default as Button } from './components/Button.svelte';
|
|
11
|
+
export { default as Input } from './components/Input.svelte';
|
|
12
|
+
export { default as Label } from './components/Label.svelte';
|
|
13
|
+
export { default as Textarea } from './components/Textarea.svelte';
|
|
14
|
+
export { default as Checkbox } from './components/Checkbox.svelte';
|
|
15
|
+
export { default as Switch } from './components/Switch.svelte';
|
|
16
|
+
export { default as Separator } from './components/Separator.svelte';
|
|
17
|
+
// Card Components
|
|
18
|
+
export { default as Card } from './components/Card.svelte';
|
|
19
|
+
export { default as CardHeader } from './components/CardHeader.svelte';
|
|
20
|
+
export { default as CardTitle } from './components/CardTitle.svelte';
|
|
21
|
+
export { default as CardDescription } from './components/CardDescription.svelte';
|
|
22
|
+
export { default as CardContent } from './components/CardContent.svelte';
|
|
23
|
+
export { default as CardFooter } from './components/CardFooter.svelte';
|
|
24
|
+
// Alert Components
|
|
25
|
+
export { default as Alert } from './components/Alert.svelte';
|
|
26
|
+
export { default as AlertTitle } from './components/AlertTitle.svelte';
|
|
27
|
+
export { default as AlertDescription } from './components/AlertDescription.svelte';
|
|
28
|
+
// Badge
|
|
29
|
+
export { default as Badge } from './components/Badge.svelte';
|
|
30
|
+
// Feedback Components
|
|
31
|
+
export { default as Spinner } from './components/Spinner.svelte';
|
|
32
|
+
export { default as Skeleton } from './components/Skeleton.svelte';
|
|
33
|
+
export { default as Toast } from './components/Toast.svelte';
|
|
34
|
+
export { default as ToastContainer } from './components/ToastContainer.svelte';
|
|
35
|
+
// Overlay Components (using Bits UI)
|
|
36
|
+
export { default as Dialog } from './components/Dialog.svelte';
|
|
37
|
+
export { default as AlertDialog } from './components/AlertDialog.svelte';
|
|
38
|
+
export { default as Tooltip } from './components/Tooltip.svelte';
|
|
39
|
+
export { default as DropdownMenu } from './components/DropdownMenu.svelte';
|
|
40
|
+
// Form Components (using Bits UI)
|
|
41
|
+
export { default as Select } from './components/Select.svelte';
|
|
42
|
+
export { default as FormField } from './components/FormField.svelte';
|
|
43
|
+
export { default as FileUpload } from './components/FileUpload.svelte';
|
|
44
|
+
// Data Display
|
|
45
|
+
export { default as DataTable } from './components/DataTable.svelte';
|
|
46
|
+
// Tabs
|
|
47
|
+
export { default as Tabs } from './components/Tabs.svelte';
|
|
48
|
+
export { default as TabPanel } from './components/TabPanel.svelte';
|
|
49
|
+
// Branding
|
|
50
|
+
export { default as LogoMain } from './components/LogoMain.svelte';
|
|
51
|
+
export { default as LoadingLogo } from './components/LoadingLogo.svelte';
|
|
52
|
+
// Avatar Components
|
|
53
|
+
export { default as Avatar } from './components/Avatar.svelte';
|
|
54
|
+
export { default as AvatarImage } from './components/AvatarImage.svelte';
|
|
55
|
+
export { default as AvatarFallback } from './components/AvatarFallback.svelte';
|
|
56
|
+
// Page Components
|
|
57
|
+
export { default as Section } from './components/Section.svelte';
|
|
58
|
+
export { default as PageHeader } from './components/PageHeader.svelte';
|
|
59
|
+
// Layout Components
|
|
60
|
+
export { default as AppShell } from './components/layout/AppShell.svelte';
|
|
61
|
+
export { default as DashboardLayout } from './components/layout/DashboardLayout.svelte';
|
|
62
|
+
export { default as PublicLayout } from './components/layout/PublicLayout.svelte';
|
|
63
|
+
export { default as FormPageLayout } from './components/layout/FormPageLayout.svelte';
|
|
64
|
+
export { default as Sidebar } from './components/layout/Sidebar.svelte';
|
|
65
|
+
export { default as Header } from './components/layout/Header.svelte';
|
|
66
|
+
export { default as Footer } from './components/layout/Footer.svelte';
|
|
67
|
+
export { default as QuickLinks } from './components/layout/QuickLinks.svelte';
|
|
68
|
+
// Stores
|
|
69
|
+
export { toastStore } from './stores/toast.svelte.js';
|
|
70
|
+
export { sidebarStore } from './stores/sidebar.svelte.js';
|
|
71
|
+
export { themeStore } from './stores/theme.svelte.js';
|
|
72
|
+
// Utilities
|
|
73
|
+
export { cn } from './utils.js';
|
|
74
|
+
// Re-export tailwind-variants types for consumer convenience
|
|
75
|
+
export { tv } from 'tailwind-variants';
|
|
76
|
+
// Validation utilities (dev-only, tree-shaken in production)
|
|
77
|
+
export { validateNonEmptyArray, validateRequired, validateOneOf, validateRange, validateProps, createValidator, } from './validation.js';
|
|
78
|
+
// Performance monitoring utilities (dev-only, tree-shaken in production)
|
|
79
|
+
export { perfStart, perfEnd, measure, measureAsync, getPerformanceEntries, clearPerformanceEntries, createPerfMonitor, } from './performance.js';
|
|
80
|
+
// Composables - reusable Svelte 5 state management patterns
|
|
81
|
+
export { useForm, useAsync, runAsync, } from './composables/index.js';
|
|
82
|
+
// Validation schemas - Zod schemas for forms and data validation
|
|
83
|
+
export * from './schemas/index.js';
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Performance monitoring utilities for development
|
|
3
|
+
*
|
|
4
|
+
* All functions are no-ops in production builds for zero runtime cost.
|
|
5
|
+
* These utilities help identify slow operations during development.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { measure, measureAsync } from '@classic-homes/theme-svelte';
|
|
10
|
+
*
|
|
11
|
+
* // Sync measurement
|
|
12
|
+
* const result = measure('sort-data', () => {
|
|
13
|
+
* return data.sort((a, b) => a.name.localeCompare(b.name));
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* // Async measurement
|
|
17
|
+
* const data = await measureAsync('fetch-users', async () => {
|
|
18
|
+
* return await fetch('/api/users').then(r => r.json());
|
|
19
|
+
* });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export interface PerformanceMark {
|
|
23
|
+
name: string;
|
|
24
|
+
startTime: number;
|
|
25
|
+
duration?: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Start a performance measurement
|
|
29
|
+
* @param name - Unique name for this measurement
|
|
30
|
+
*/
|
|
31
|
+
export declare function perfStart(name: string): void;
|
|
32
|
+
/**
|
|
33
|
+
* End a performance measurement and log results
|
|
34
|
+
* @param name - Name of the measurement to end
|
|
35
|
+
* @returns Duration in milliseconds, or undefined if not in dev mode
|
|
36
|
+
*/
|
|
37
|
+
export declare function perfEnd(name: string): number | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Measure a synchronous function's execution time
|
|
40
|
+
* @param name - Name for the measurement
|
|
41
|
+
* @param fn - Function to measure
|
|
42
|
+
* @returns The function's return value
|
|
43
|
+
*/
|
|
44
|
+
export declare function measure<T>(name: string, fn: () => T): T;
|
|
45
|
+
/**
|
|
46
|
+
* Measure an async function's execution time
|
|
47
|
+
* @param name - Name for the measurement
|
|
48
|
+
* @param fn - Async function to measure
|
|
49
|
+
* @returns Promise resolving to the function's return value
|
|
50
|
+
*/
|
|
51
|
+
export declare function measureAsync<T>(name: string, fn: () => Promise<T>): Promise<T>;
|
|
52
|
+
/**
|
|
53
|
+
* Get all recorded performance measurements
|
|
54
|
+
* Useful for testing or building custom performance dashboards
|
|
55
|
+
* @returns Array of performance entries
|
|
56
|
+
*/
|
|
57
|
+
export declare function getPerformanceEntries(): PerformanceEntryList;
|
|
58
|
+
/**
|
|
59
|
+
* Clear all recorded performance measurements
|
|
60
|
+
*/
|
|
61
|
+
export declare function clearPerformanceEntries(): void;
|
|
62
|
+
/**
|
|
63
|
+
* Create a performance monitor for a specific component or module
|
|
64
|
+
* @param prefix - Prefix for all measurements (e.g., 'DataTable')
|
|
65
|
+
* @returns Object with prefixed measurement functions
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* const perf = createPerfMonitor('DataTable');
|
|
70
|
+
* perf.measure('sort', () => sortData());
|
|
71
|
+
* await perf.measureAsync('fetch', () => fetchData());
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export declare function createPerfMonitor(prefix: string): {
|
|
75
|
+
start: (name: string) => void;
|
|
76
|
+
end: (name: string) => number | undefined;
|
|
77
|
+
measure: <T>(name: string, fn: () => T) => T;
|
|
78
|
+
measureAsync: <T>(name: string, fn: () => Promise<T>) => Promise<T>;
|
|
79
|
+
};
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Performance monitoring utilities for development
|
|
3
|
+
*
|
|
4
|
+
* All functions are no-ops in production builds for zero runtime cost.
|
|
5
|
+
* These utilities help identify slow operations during development.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { measure, measureAsync } from '@classic-homes/theme-svelte';
|
|
10
|
+
*
|
|
11
|
+
* // Sync measurement
|
|
12
|
+
* const result = measure('sort-data', () => {
|
|
13
|
+
* return data.sort((a, b) => a.name.localeCompare(b.name));
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* // Async measurement
|
|
17
|
+
* const data = await measureAsync('fetch-users', async () => {
|
|
18
|
+
* return await fetch('/api/users').then(r => r.json());
|
|
19
|
+
* });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
// Detect development mode
|
|
23
|
+
const getIsDev = () => {
|
|
24
|
+
try {
|
|
25
|
+
// @ts-expect-error - import.meta.env may not exist
|
|
26
|
+
if (typeof import.meta !== 'undefined' && import.meta.env?.DEV !== undefined) {
|
|
27
|
+
// @ts-expect-error - accessing env.DEV
|
|
28
|
+
return import.meta.env.DEV === true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// Ignore
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
// @ts-expect-error - process may not exist
|
|
36
|
+
if (typeof process !== 'undefined' && process.env?.NODE_ENV !== undefined) {
|
|
37
|
+
// @ts-expect-error - accessing process.env
|
|
38
|
+
return process.env.NODE_ENV !== 'production';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Ignore
|
|
43
|
+
}
|
|
44
|
+
return false;
|
|
45
|
+
};
|
|
46
|
+
const isDev = getIsDev();
|
|
47
|
+
const marks = new Map();
|
|
48
|
+
/** Threshold in ms for logging slow operations (1 frame at 60fps) */
|
|
49
|
+
const SLOW_THRESHOLD = 16;
|
|
50
|
+
/**
|
|
51
|
+
* Start a performance measurement
|
|
52
|
+
* @param name - Unique name for this measurement
|
|
53
|
+
*/
|
|
54
|
+
export function perfStart(name) {
|
|
55
|
+
if (!isDev)
|
|
56
|
+
return;
|
|
57
|
+
marks.set(name, {
|
|
58
|
+
name,
|
|
59
|
+
startTime: performance.now(),
|
|
60
|
+
});
|
|
61
|
+
if (typeof performance !== 'undefined' && performance.mark) {
|
|
62
|
+
performance.mark(`${name}-start`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* End a performance measurement and log results
|
|
67
|
+
* @param name - Name of the measurement to end
|
|
68
|
+
* @returns Duration in milliseconds, or undefined if not in dev mode
|
|
69
|
+
*/
|
|
70
|
+
export function perfEnd(name) {
|
|
71
|
+
if (!isDev)
|
|
72
|
+
return undefined;
|
|
73
|
+
const mark = marks.get(name);
|
|
74
|
+
if (!mark) {
|
|
75
|
+
console.warn(`[perf] No start mark found for "${name}"`);
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
const duration = performance.now() - mark.startTime;
|
|
79
|
+
mark.duration = duration;
|
|
80
|
+
if (typeof performance !== 'undefined' && performance.mark && performance.measure) {
|
|
81
|
+
performance.mark(`${name}-end`);
|
|
82
|
+
performance.measure(name, `${name}-start`, `${name}-end`);
|
|
83
|
+
}
|
|
84
|
+
// Log slow operations
|
|
85
|
+
if (duration > SLOW_THRESHOLD) {
|
|
86
|
+
console.warn(`[perf] Slow operation "${name}": ${duration.toFixed(2)}ms`);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
console.debug(`[perf] "${name}": ${duration.toFixed(2)}ms`);
|
|
90
|
+
}
|
|
91
|
+
marks.delete(name);
|
|
92
|
+
return duration;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Measure a synchronous function's execution time
|
|
96
|
+
* @param name - Name for the measurement
|
|
97
|
+
* @param fn - Function to measure
|
|
98
|
+
* @returns The function's return value
|
|
99
|
+
*/
|
|
100
|
+
export function measure(name, fn) {
|
|
101
|
+
if (!isDev)
|
|
102
|
+
return fn();
|
|
103
|
+
perfStart(name);
|
|
104
|
+
try {
|
|
105
|
+
return fn();
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
perfEnd(name);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Measure an async function's execution time
|
|
113
|
+
* @param name - Name for the measurement
|
|
114
|
+
* @param fn - Async function to measure
|
|
115
|
+
* @returns Promise resolving to the function's return value
|
|
116
|
+
*/
|
|
117
|
+
export async function measureAsync(name, fn) {
|
|
118
|
+
if (!isDev)
|
|
119
|
+
return fn();
|
|
120
|
+
perfStart(name);
|
|
121
|
+
try {
|
|
122
|
+
return await fn();
|
|
123
|
+
}
|
|
124
|
+
finally {
|
|
125
|
+
perfEnd(name);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Get all recorded performance measurements
|
|
130
|
+
* Useful for testing or building custom performance dashboards
|
|
131
|
+
* @returns Array of performance entries
|
|
132
|
+
*/
|
|
133
|
+
export function getPerformanceEntries() {
|
|
134
|
+
if (typeof performance === 'undefined' || !performance.getEntriesByType) {
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
return performance.getEntriesByType('measure');
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Clear all recorded performance measurements
|
|
141
|
+
*/
|
|
142
|
+
export function clearPerformanceEntries() {
|
|
143
|
+
if (typeof performance === 'undefined')
|
|
144
|
+
return;
|
|
145
|
+
if (performance.clearMarks)
|
|
146
|
+
performance.clearMarks();
|
|
147
|
+
if (performance.clearMeasures)
|
|
148
|
+
performance.clearMeasures();
|
|
149
|
+
marks.clear();
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Create a performance monitor for a specific component or module
|
|
153
|
+
* @param prefix - Prefix for all measurements (e.g., 'DataTable')
|
|
154
|
+
* @returns Object with prefixed measurement functions
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* ```ts
|
|
158
|
+
* const perf = createPerfMonitor('DataTable');
|
|
159
|
+
* perf.measure('sort', () => sortData());
|
|
160
|
+
* await perf.measureAsync('fetch', () => fetchData());
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
export function createPerfMonitor(prefix) {
|
|
164
|
+
return {
|
|
165
|
+
start: (name) => perfStart(`${prefix}:${name}`),
|
|
166
|
+
end: (name) => perfEnd(`${prefix}:${name}`),
|
|
167
|
+
measure: (name, fn) => measure(`${prefix}:${name}`, fn),
|
|
168
|
+
measureAsync: (name, fn) => measureAsync(`${prefix}:${name}`, fn),
|
|
169
|
+
};
|
|
170
|
+
}
|