@pelatform/starter.ui 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.
@@ -0,0 +1,1063 @@
1
+ import * as React from 'react';
2
+ import React__default, { DragEvent, ChangeEvent, InputHTMLAttributes, ComponentType, SVGProps, RefObject } from 'react';
3
+ import { META_THEME_COLORS } from '@pelatform/utils';
4
+
5
+ /**
6
+ * Body class management hook for React components
7
+ * Dynamically adds and removes CSS classes from the document body element
8
+ * Useful for global styling based on component state or route changes
9
+ */
10
+ /**
11
+ * Hook to dynamically add and remove CSS classes from the document body
12
+ *
13
+ * This hook automatically manages the lifecycle of body classes:
14
+ * - Adds classes when the component mounts
15
+ * - Removes classes when the component unmounts
16
+ * - Updates classes when the className prop changes
17
+ *
18
+ * @param className - Space-separated string of CSS class names to apply to body
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * // Single class
23
+ * useBodyClasses('dark-theme');
24
+ *
25
+ * // Multiple classes
26
+ * useBodyClasses('modal-open overflow-hidden');
27
+ *
28
+ * // Conditional classes
29
+ * useBodyClasses(isModalOpen ? 'modal-open' : '');
30
+ * ```
31
+ */
32
+ declare const useBodyClasses: (className: string) => void;
33
+
34
+ /**
35
+ * Clipboard copy functionality hook for React components
36
+ * Provides a simple interface for copying text to clipboard with feedback
37
+ * Includes automatic state management and timeout handling
38
+ */
39
+ /**
40
+ * Configuration options for the copy to clipboard hook
41
+ */
42
+ interface UseCopyToClipboardOptions {
43
+ /** Duration in milliseconds to show the copied state (default: 2000ms) */
44
+ timeout?: number;
45
+ /** Callback function executed after successful copy operation */
46
+ onCopy?: () => void;
47
+ }
48
+ /**
49
+ * Hook for copying text to clipboard with automatic state management
50
+ *
51
+ * Features:
52
+ * - Automatic copied state management with timeout
53
+ * - Browser compatibility checks
54
+ * - Error handling for failed copy operations
55
+ * - Optional callback for successful copies
56
+ *
57
+ * @param options - Configuration options for the hook
58
+ * @returns Object containing copied state and copy function
59
+ *
60
+ * @example
61
+ * ```tsx
62
+ * const { copied, copy } = useCopyToClipboard({
63
+ * timeout: 3000,
64
+ * onCopy: () => toast.success('Copied to clipboard!')
65
+ * });
66
+ *
67
+ * return (
68
+ * <button onClick={() => copy('Hello World')}>
69
+ * {copied ? 'Copied!' : 'Copy Text'}
70
+ * </button>
71
+ * );
72
+ * ```
73
+ */
74
+ declare function useCopyToClipboard({ timeout, onCopy }?: UseCopyToClipboardOptions): {
75
+ /** Whether text was recently copied (true for timeout duration) */
76
+ copied: boolean;
77
+ /** Function to copy text to clipboard */
78
+ copy: (value: string) => void;
79
+ };
80
+
81
+ /**
82
+ * File upload functionality hook for React components
83
+ * Provides comprehensive file upload capabilities with drag & drop support
84
+ * Includes validation, preview generation, and state management
85
+ */
86
+
87
+ /**
88
+ * Metadata structure for uploaded files
89
+ */
90
+ type FileMetadata = {
91
+ /** The name of the file */
92
+ name: string;
93
+ /** The size of the file in bytes */
94
+ size: number;
95
+ /** The MIME type of the file */
96
+ type: string;
97
+ /** The URL where the file can be accessed */
98
+ url: string;
99
+ /** Unique identifier for the file */
100
+ id: string;
101
+ };
102
+ /**
103
+ * File object with preview capabilities
104
+ */
105
+ type FileWithPreview = {
106
+ /** The actual file object or metadata */
107
+ file: File | FileMetadata;
108
+ /** Unique identifier for the file */
109
+ id: string;
110
+ /** Optional preview URL for the file (typically for images) */
111
+ preview?: string;
112
+ };
113
+ /**
114
+ * Configuration options for the file upload hook
115
+ */
116
+ type FileUploadOptions = {
117
+ /** Maximum number of files allowed (only used when multiple is true, defaults to Infinity) */
118
+ maxFiles?: number;
119
+ /** Maximum file size in bytes (defaults to Infinity) */
120
+ maxSize?: number;
121
+ /** Accepted file types (MIME types or extensions, defaults to '*') */
122
+ accept?: string;
123
+ /** Whether multiple files can be selected (defaults to false) */
124
+ multiple?: boolean;
125
+ /** Initial files to populate the upload state */
126
+ initialFiles?: FileMetadata[];
127
+ /** Callback function executed when files change */
128
+ onFilesChange?: (files: FileWithPreview[]) => void;
129
+ /** Callback function executed when new files are added */
130
+ onFilesAdded?: (addedFiles: FileWithPreview[]) => void;
131
+ onError?: (errors: string[]) => void;
132
+ };
133
+ /**
134
+ * Current state of the file upload component
135
+ */
136
+ type FileUploadState = {
137
+ /** Array of files currently selected/uploaded */
138
+ files: FileWithPreview[];
139
+ /** Whether the user is currently dragging files over the drop zone */
140
+ isDragging: boolean;
141
+ /** Array of validation error messages */
142
+ errors: string[];
143
+ };
144
+ /**
145
+ * Actions available for file upload management
146
+ */
147
+ type FileUploadActions = {
148
+ /** Add new files to the upload state */
149
+ addFiles: (files: FileList | File[]) => void;
150
+ /** Remove a specific file by its ID */
151
+ removeFile: (id: string) => void;
152
+ /** Clear all files from the upload state */
153
+ clearFiles: () => void;
154
+ /** Clear all error messages */
155
+ clearErrors: () => void;
156
+ /** Handle drag enter event for drop zone */
157
+ handleDragEnter: (e: DragEvent<HTMLElement>) => void;
158
+ /** Handle drag leave event for drop zone */
159
+ handleDragLeave: (e: DragEvent<HTMLElement>) => void;
160
+ /** Handle drag over event for drop zone */
161
+ handleDragOver: (e: DragEvent<HTMLElement>) => void;
162
+ /** Handle drop event for drop zone */
163
+ handleDrop: (e: DragEvent<HTMLElement>) => void;
164
+ /** Handle file input change event */
165
+ handleFileChange: (e: ChangeEvent<HTMLInputElement>) => void;
166
+ /** Programmatically open the file dialog */
167
+ openFileDialog: () => void;
168
+ /** Get props for the file input element */
169
+ getInputProps: (props?: InputHTMLAttributes<HTMLInputElement>) => InputHTMLAttributes<HTMLInputElement> & {
170
+ ref: React__default.Ref<HTMLInputElement>;
171
+ };
172
+ };
173
+ /**
174
+ * Hook for comprehensive file upload functionality with drag & drop support
175
+ *
176
+ * Features:
177
+ * - Single and multiple file upload support
178
+ * - Drag and drop functionality
179
+ * - File validation (size, type, count)
180
+ * - Preview generation for images
181
+ * - Error handling and state management
182
+ * - Duplicate file detection
183
+ * - Memory cleanup for object URLs
184
+ *
185
+ * @param options - Configuration options for the file upload hook
186
+ * @returns Tuple containing current state and available actions
187
+ *
188
+ * @example
189
+ * ```tsx
190
+ * const [state, actions] = useFileUpload({
191
+ * maxFiles: 5,
192
+ * maxSize: 10 * 1024 * 1024, // 10MB
193
+ * accept: 'image/*',
194
+ * multiple: true,
195
+ * onFilesChange: (files) => console.log('Files changed:', files),
196
+ * onFilesAdded: (newFiles) => console.log('New files added:', newFiles)
197
+ * });
198
+ *
199
+ * return (
200
+ * <div
201
+ * onDragEnter={actions.handleDragEnter}
202
+ * onDragLeave={actions.handleDragLeave}
203
+ * onDragOver={actions.handleDragOver}
204
+ * onDrop={actions.handleDrop}
205
+ * >
206
+ * <input {...actions.getInputProps()} />
207
+ * <button onClick={actions.openFileDialog}>
208
+ * Upload Files
209
+ * </button>
210
+ * {state.files.map(file => (
211
+ * <div key={file.id}>
212
+ * {file.file.name}
213
+ * <button onClick={() => actions.removeFile(file.id)}>
214
+ * Remove
215
+ * </button>
216
+ * </div>
217
+ * ))}
218
+ * </div>
219
+ * );
220
+ * ```
221
+ */
222
+ declare const useFileUpload: (options?: FileUploadOptions) => [FileUploadState, FileUploadActions];
223
+ /**
224
+ * Helper function to format bytes to human-readable format
225
+ *
226
+ * @param bytes - The number of bytes to format
227
+ * @param decimals - Number of decimal places to show (default: 2)
228
+ * @returns Formatted string with appropriate unit (e.g., "1.5 MB")
229
+ *
230
+ * @example
231
+ * ```tsx
232
+ * formatBytes(1024); // "1 KB"
233
+ * formatBytes(1536, 1); // "1.5 KB"
234
+ * formatBytes(1048576); // "1 MB"
235
+ * ```
236
+ */
237
+ declare const formatBytes: (bytes: number, decimals?: number) => string;
238
+
239
+ /**
240
+ * Hook that indicates whether code is executing on the client after hydration
241
+ *
242
+ * Features:
243
+ * - SSR-safe: returns `false` on the server to avoid hydration mismatches
244
+ * - Client-stable: returns `true` after hydration and remains stable
245
+ * - Minimal overhead: uses a no-op external store subscription
246
+ *
247
+ * @returns Boolean indicating hydration state (`true` on client, `false` on server)
248
+ *
249
+ * @example
250
+ * ```tsx
251
+ * // Conditionally render client-only components safely
252
+ * function ClientOnly() {
253
+ * const hydrated = useHydrated();
254
+ * if (!hydrated) return null;
255
+ * return <InteractiveChart />;
256
+ * }
257
+ * ```
258
+ *
259
+ * @since 1.0.0
260
+ */
261
+ declare function useHydrated(): boolean;
262
+
263
+ /**
264
+ * Intersection observer hook for React components
265
+ * Efficiently observes visibility of DOM elements using a shared IntersectionObserver instance.
266
+ * Ideal for lazy loading, infinite scrolling, and animating elements when they enter the viewport.
267
+ */
268
+
269
+ /**
270
+ * Configuration options for the `useIntersectionObserver` hook.
271
+ *
272
+ * Extends the native `IntersectionObserverInit` options with an additional
273
+ * convenience flag for freezing the observer state.
274
+ */
275
+ interface IntersectionObserverOptions extends IntersectionObserverInit {
276
+ /**
277
+ * When `true`, the hook stops observing once the element becomes visible
278
+ * and keeps returning `true` for subsequent renders.
279
+ *
280
+ * This is useful for one-time animations or lazy loading where you only
281
+ * care about the first time an element enters the viewport.
282
+ */
283
+ freezeOnceVisible?: boolean;
284
+ }
285
+ /**
286
+ * React hook that tracks whether a DOM element is currently intersecting the viewport.
287
+ *
288
+ * Features:
289
+ * - Uses a shared `IntersectionObserver` instance for better performance.
290
+ * - Supports custom `threshold`, `root`, and `rootMargin` options.
291
+ * - Optional `freezeOnceVisible` flag to stop observing after first intersection.
292
+ *
293
+ * @param elementRef - React ref pointing to the DOM element to observe.
294
+ * @param options - Optional observer configuration and behavior flags.
295
+ * @param options.threshold - Intersection threshold(s) for triggering visibility changes.
296
+ * @param options.root - Scrollable ancestor element to use as the viewport (defaults to browser viewport).
297
+ * @param options.rootMargin - Margin around the root, expressed in CSS units (e.g. `"0px 0px -20% 0px"`).
298
+ * @param options.freezeOnceVisible - When `true`, stops observing after the element first becomes visible.
299
+ *
300
+ * @returns `true` when the element is intersecting based on the given options, otherwise `false`.
301
+ *
302
+ * @example
303
+ * ```tsx
304
+ * const ref = React.useRef<HTMLDivElement | null>(null);
305
+ * const isVisible = useIntersectionObserver(ref, {
306
+ * threshold: 0.2,
307
+ * rootMargin: "0px 0px -10% 0px",
308
+ * freezeOnceVisible: true,
309
+ * });
310
+ *
311
+ * return (
312
+ * <div ref={ref} className={isVisible ? "animate-in" : "opacity-0"}>
313
+ * I will animate when I enter the viewport.
314
+ * </div>
315
+ * );
316
+ * ```
317
+ */
318
+ declare function useIntersectionObserver(elementRef: React.RefObject<Element | null>, { threshold, root, rootMargin, freezeOnceVisible, }?: IntersectionObserverOptions): boolean;
319
+
320
+ /**
321
+ * Platform detection hook for React components
322
+ * Determines whether the current user agent is running on a macOS device.
323
+ * Useful for rendering platform-specific keyboard shortcuts or UI variations.
324
+ */
325
+ /**
326
+ * React hook that returns whether the current platform is macOS.
327
+ *
328
+ * This hook:
329
+ * - Runs only on the client (browser) side.
330
+ * - Checks `navigator.platform` and normalizes the value to uppercase.
331
+ * - Returns a boolean indicating if the platform contains `"MAC"`.
332
+ *
333
+ * @returns `true` if the current platform is macOS, otherwise `false`.
334
+ *
335
+ * @example
336
+ * ```tsx
337
+ * const isMac = useIsMac();
338
+ *
339
+ * return (
340
+ * <kbd>
341
+ * {isMac ? "⌘" : "Ctrl"} + K
342
+ * </kbd>
343
+ * );
344
+ * ```
345
+ */
346
+ declare function useIsMac(): boolean;
347
+
348
+ /**
349
+ * Media query hook for responsive React components
350
+ * Provides real-time tracking of CSS media query matches
351
+ * with SSR-safe implementation and automatic cleanup
352
+ */
353
+ /**
354
+ * Hook for tracking CSS media query matches in React components
355
+ *
356
+ * Features:
357
+ * - Real-time updates when media query state changes
358
+ * - SSR-safe implementation
359
+ * - Automatic event listener cleanup
360
+ * - Supports all standard CSS media queries
361
+ *
362
+ * @param query - CSS media query string (e.g., '(min-width: 768px)')
363
+ * @returns Boolean indicating whether the media query currently matches
364
+ *
365
+ * @example
366
+ * ```tsx
367
+ * // Basic responsive behavior
368
+ * const isMobile = useMediaQuery('(max-width: 768px)');
369
+ * const isTablet = useMediaQuery('(min-width: 769px) and (max-width: 1024px)');
370
+ * const isDesktop = useMediaQuery('(min-width: 1025px)');
371
+ *
372
+ * // Dark mode preference
373
+ * const prefersDark = useMediaQuery('(prefers-color-scheme: dark)');
374
+ *
375
+ * // Reduced motion preference
376
+ * const prefersReducedMotion = useMediaQuery('(prefers-reduced-motion: reduce)');
377
+ *
378
+ * return (
379
+ * <div>
380
+ * {isMobile && <MobileLayout />}
381
+ * {isTablet && <TabletLayout />}
382
+ * {isDesktop && <DesktopLayout />}
383
+ * </div>
384
+ * );
385
+ * ```
386
+ */
387
+ declare const useMediaQuery: (query: string) => boolean;
388
+
389
+ /**
390
+ * Menu navigation utilities hook for dashboard layouts
391
+ * Provides comprehensive menu state management and navigation helpers
392
+ * Handles active states, breadcrumbs, and hierarchical menu structures
393
+ */
394
+
395
+ /**
396
+ * Menu item interface
397
+ */
398
+ interface MenuItem {
399
+ /** Heading text */
400
+ heading?: string;
401
+ /** Menu item title */
402
+ title?: string;
403
+ /** Navigation path */
404
+ path?: string;
405
+ /** Menu item icon component */
406
+ icon?: ComponentType<SVGProps<SVGSVGElement>>;
407
+ /** Whether to show separator */
408
+ separator?: boolean;
409
+ /** Root path for active state matching */
410
+ rootPath?: string;
411
+ /** Child menu items */
412
+ children?: MenuConfig;
413
+ /** Children index for nested items */
414
+ childrenIndex?: number;
415
+ /** Whether the item is external */
416
+ external?: boolean;
417
+ /** Whether the item is disabled */
418
+ disabled?: boolean;
419
+ /** Disable text */
420
+ disabledText?: string;
421
+ /** Badge text */
422
+ badge?: string;
423
+ /** Badge variant */
424
+ badgeVariant?: "primary" | "destructive" | "success" | "info" | "warning" | "secondary" | "outline";
425
+ /** Collapse configuration */
426
+ collapse?: boolean;
427
+ /** Title when collapsed */
428
+ collapseTitle?: string;
429
+ /** Title when expanded */
430
+ expandTitle?: string;
431
+ }
432
+ /**
433
+ * Type aliases for backward compatibility
434
+ */
435
+ type MenuConfig = MenuItem[];
436
+ /** Return type interface for useMenu hook */
437
+ interface UseMenuReturn {
438
+ /** Check if a specific path is currently active */
439
+ isActive: (path: string | undefined) => boolean;
440
+ /** Check if any child menu item is currently active */
441
+ hasActiveChild: (children: MenuItem[] | undefined) => boolean;
442
+ /** Check if a menu item (including its children) is currently active */
443
+ isItemActive: (item: MenuItem) => boolean;
444
+ /** Get the currently active menu item from the menu configuration */
445
+ getCurrentItem: (items: MenuConfig) => MenuItem | undefined;
446
+ /** Generate breadcrumb trail for the current active path */
447
+ getBreadcrumb: (items: MenuConfig) => MenuItem[];
448
+ /** Get child menu items at a specific level for the current active path */
449
+ getChildren: (items: MenuConfig, level: number) => MenuConfig | null;
450
+ }
451
+ /**
452
+ * Hook for managing menu navigation state and utilities
453
+ *
454
+ * This hook provides comprehensive menu management functionality including:
455
+ * - Active state detection for menu items and paths
456
+ * - Hierarchical menu navigation support
457
+ * - Breadcrumb generation for current navigation path
458
+ * - Child menu extraction at specific levels
459
+ * - Support for nested menu structures
460
+ *
461
+ * @param pathname - Current pathname from router or location
462
+ * @returns Object containing menu utility functions
463
+ *
464
+ * @example
465
+ * ```tsx
466
+ * const { isActive, getBreadcrumb, getCurrentItem } = useMenu(pathname);
467
+ *
468
+ * // Check if path is active
469
+ * const isHomeActive = isActive('/dashboard');
470
+ *
471
+ * // Get breadcrumb for current path
472
+ * const breadcrumb = getBreadcrumb(menuItems);
473
+ *
474
+ * // Get current active menu item
475
+ * const currentItem = getCurrentItem(menuItems);
476
+ * ```
477
+ */
478
+ declare const useMenu: (pathname: string) => UseMenuReturn;
479
+
480
+ /**
481
+ * Meta theme color management hook for React components
482
+ * Automatically manages HTML meta theme-color tag based on current theme
483
+ * Integrates with next-themes for seamless theme switching
484
+ */
485
+
486
+ /**
487
+ * Hook for managing HTML meta theme-color tag based on current theme
488
+ *
489
+ * This hook automatically calculates the appropriate meta theme color
490
+ * based on the current theme (light/dark) and provides utilities for
491
+ * manual meta color manipulation.
492
+ *
493
+ * Features:
494
+ * - Automatic theme color calculation based on resolved theme
495
+ * - Support for custom color configurations
496
+ * - Manual meta color setting capability
497
+ * - Integration with next-themes
498
+ *
499
+ * @param defaultColors - Optional custom color configuration (defaults to META_THEME_COLORS)
500
+ * @returns Object containing current meta color and setter function
501
+ *
502
+ * @example
503
+ * ```tsx
504
+ * // Basic usage with default colors (supports light, dark, and system)
505
+ * function App() {
506
+ * const { metaColor, setMetaColor } = useMetaColor();
507
+ *
508
+ * // metaColor automatically updates based on theme (light/dark/system)
509
+ * useEffect(() => {
510
+ * console.log('Current meta color:', metaColor);
511
+ * }, [metaColor]);
512
+ *
513
+ * return <div>App content</div>;
514
+ * }
515
+ *
516
+ * // Custom colors with system theme support
517
+ * function CustomThemeApp() {
518
+ * const customColors = {
519
+ * light: '#f0f0f0',
520
+ * dark: '#1a1a1a',
521
+ * system: 'auto' // Will resolve to light or dark based on OS preference
522
+ * };
523
+ * const { metaColor } = useMetaColor(customColors);
524
+ *
525
+ * return <div style={{ backgroundColor: metaColor }}>Custom themed app</div>;
526
+ * }
527
+ *
528
+ * // Manual meta color override for special pages
529
+ * function SpecialPage() {
530
+ * const { setMetaColor } = useMetaColor();
531
+ *
532
+ * useEffect(() => {
533
+ * // Override meta color for this page
534
+ * setMetaColor('#ff0000');
535
+ *
536
+ * // Cleanup: reset to theme color when leaving page
537
+ * return () => {
538
+ * setMetaColor(''); // This will revert to theme-based color
539
+ * };
540
+ * }, [setMetaColor]);
541
+ *
542
+ * return <div>Special page with red theme color</div>;
543
+ * }
544
+ *
545
+ * // Integration with theme switcher
546
+ * function ThemeAwareComponent() {
547
+ * const { theme, setTheme } = useTheme();
548
+ * const { metaColor } = useMetaColor();
549
+ *
550
+ * return (
551
+ * <div>
552
+ * <p>Current theme: {theme}</p>
553
+ * <p>Meta color: {metaColor}</p>
554
+ * <button onClick={() => setTheme('light')}>Light</button>
555
+ * <button onClick={() => setTheme('dark')}>Dark</button>
556
+ * <button onClick={() => setTheme('system')}>System</button>
557
+ * </div>
558
+ * );
559
+ * }
560
+ * ```
561
+ */
562
+ declare function useMetaColor(defaultColors?: typeof META_THEME_COLORS): {
563
+ /** Current meta theme color based on resolved theme */
564
+ metaColor: "#09090b" | "#ffffff";
565
+ /** Function to manually set meta theme color */
566
+ setMetaColor: (color: string) => void;
567
+ };
568
+
569
+ /**
570
+ * Mobile device detection hook for React components
571
+ * Provides real-time mobile/desktop state based on configurable viewport width breakpoint
572
+ * Uses customizable mobile breakpoint with proper SSR handling and hydration safety
573
+ */
574
+ /**
575
+ * Hook to detect if the current viewport is mobile-sized based on configurable breakpoint
576
+ *
577
+ * This hook provides real-time detection of mobile vs desktop viewports with a customizable
578
+ * breakpoint threshold. It handles SSR properly by starting with undefined state and updating
579
+ * on client-side hydration to prevent hydration mismatches.
580
+ *
581
+ * The hook uses both `matchMedia` API for efficient media query listening and `window.innerWidth`
582
+ * for consistent viewport width detection across different browsers and devices.
583
+ *
584
+ * Features:
585
+ * - Real-time viewport size tracking with media query listeners
586
+ * - SSR-safe implementation preventing hydration mismatches
587
+ * - Automatic event listener cleanup on unmount
588
+ * - Configurable mobile breakpoint with sensible default (1024px)
589
+ * - Performance optimized with proper dependency management
590
+ * - TypeScript support with proper type definitions
591
+ *
592
+ * @param breakpoint - Custom breakpoint in pixels. Viewports smaller than this value are considered mobile. Defaults to 1024px if not provided.
593
+ * @returns Boolean indicating if current viewport width is smaller than the specified breakpoint (mobile-sized)
594
+ *
595
+ * @example
596
+ * ```tsx
597
+ * // Basic usage with default breakpoint (1024px)
598
+ * function ResponsiveComponent() {
599
+ * const isMobile = useIsMobile();
600
+ *
601
+ * return (
602
+ * <div>
603
+ * {isMobile ? (
604
+ * <MobileNavigation />
605
+ * ) : (
606
+ * <DesktopNavigation />
607
+ * )}
608
+ * </div>
609
+ * );
610
+ * }
611
+ *
612
+ * // Custom breakpoint for tablet detection
613
+ * function TabletResponsiveComponent() {
614
+ * const isMobile = useIsMobile(768); // Use 768px breakpoint
615
+ * const isTablet = useIsMobile(1024); // Use 1024px for tablet detection
616
+ *
617
+ * return (
618
+ * <div className={isMobile ? 'mobile-layout' : isTablet ? 'tablet-layout' : 'desktop-layout'}>
619
+ * <Content />
620
+ * </div>
621
+ * );
622
+ * }
623
+ *
624
+ * // Conditional rendering with custom breakpoint
625
+ * function AdaptiveLayout() {
626
+ * const isSmallScreen = useIsMobile(640); // Custom small screen breakpoint
627
+ *
628
+ * return (
629
+ * <div className="container">
630
+ * {isSmallScreen ? (
631
+ * <div className="flex flex-col space-y-4">
632
+ * <MobileHeader />
633
+ * <MobileContent />
634
+ * </div>
635
+ * ) : (
636
+ * <div className="grid grid-cols-12 gap-6">
637
+ * <aside className="col-span-3">
638
+ * <Sidebar />
639
+ * </aside>
640
+ * <main className="col-span-9">
641
+ * <DesktopContent />
642
+ * </main>
643
+ * </div>
644
+ * )}
645
+ * </div>
646
+ * );
647
+ * }
648
+ *
649
+ * // Multiple breakpoints for different layouts
650
+ * function MultiBreakpointLayout() {
651
+ * const isMobile = useIsMobile(640); // Mobile: < 640px
652
+ * const isTablet = useIsMobile(1024); // Tablet: < 1024px
653
+ * const isDesktop = !isTablet; // Desktop: >= 1024px
654
+ *
655
+ * if (isMobile) {
656
+ * return <MobileLayout />;
657
+ * }
658
+ *
659
+ * if (isTablet) {
660
+ * return <TabletLayout />;
661
+ * }
662
+ *
663
+ * return <DesktopLayout />;
664
+ * }
665
+ * ```
666
+ *
667
+ * @since 1.0.0
668
+ */
669
+ declare function useIsMobile(breakpoint?: number): boolean;
670
+
671
+ /**
672
+ * Component mount state hook for React components
673
+ * Provides a reliable way to detect when a component has mounted on the client
674
+ * Essential for SSR applications to prevent hydration mismatches
675
+ */
676
+ /**
677
+ * Hook to detect when a React component has mounted on the client side
678
+ *
679
+ * This hook is essential for SSR applications where you need to conditionally
680
+ * render content only after the component has mounted on the client. It helps
681
+ * prevent hydration mismatches between server and client rendering.
682
+ *
683
+ * Features:
684
+ * - Starts with false during SSR
685
+ * - Updates to true after client-side mount
686
+ * - Prevents hydration mismatches
687
+ * - Simple boolean state management
688
+ *
689
+ * @returns Boolean indicating whether the component has mounted
690
+ *
691
+ * @example
692
+ * ```tsx
693
+ * function ClientOnlyComponent() {
694
+ * const mounted = useMounted();
695
+ *
696
+ * // Prevent rendering until mounted to avoid hydration issues
697
+ * if (!mounted) {
698
+ * return <div>Loading...</div>;
699
+ * }
700
+ *
701
+ * return (
702
+ * <div>
703
+ * <BrowserOnlyFeature />
704
+ * <LocalStorageComponent />
705
+ * </div>
706
+ * );
707
+ * }
708
+ *
709
+ * // Conditional rendering based on mount state
710
+ * function ThemeToggle() {
711
+ * const mounted = useMounted();
712
+ * const { theme, setTheme } = useTheme();
713
+ *
714
+ * // Avoid showing theme toggle until mounted
715
+ * if (!mounted) return null;
716
+ *
717
+ * return (
718
+ * <button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>
719
+ * Toggle Theme
720
+ * </button>
721
+ * );
722
+ * }
723
+ * ```
724
+ */
725
+ declare function useMounted(): boolean;
726
+
727
+ /**
728
+ * DOM Mutation Observer hook for React components
729
+ * Provides a React-friendly interface for observing DOM changes
730
+ * with automatic cleanup and ref integration
731
+ */
732
+
733
+ /**
734
+ * Hook to observe DOM mutations on a referenced element
735
+ *
736
+ * This hook provides a React-friendly way to use the MutationObserver API.
737
+ * It automatically handles observer creation, cleanup, and ref management.
738
+ * Useful for detecting DOM changes that occur outside of React's control.
739
+ *
740
+ * Features:
741
+ * - Automatic observer lifecycle management
742
+ * - Configurable observation options
743
+ * - Ref-based element targeting
744
+ * - Automatic cleanup on unmount
745
+ *
746
+ * @param ref - React ref pointing to the element to observe
747
+ * @param callback - Function called when mutations are detected
748
+ * @param options - MutationObserver configuration options
749
+ *
750
+ * @example
751
+ * ```tsx
752
+ * function DynamicContent() {
753
+ * const contentRef = useRef<HTMLDivElement>(null);
754
+ *
755
+ * // Watch for any changes to the content div
756
+ * useMutationObserver(
757
+ * contentRef,
758
+ * (mutations) => {
759
+ * mutations.forEach((mutation) => {
760
+ * console.log('DOM changed:', mutation.type);
761
+ * });
762
+ * }
763
+ * );
764
+ *
765
+ * return <div ref={contentRef}>Dynamic content here</div>;
766
+ * }
767
+ *
768
+ * // Watch only for attribute changes
769
+ * function AttributeWatcher() {
770
+ * const elementRef = useRef<HTMLElement>(null);
771
+ *
772
+ * useMutationObserver(
773
+ * elementRef,
774
+ * (mutations) => {
775
+ * mutations.forEach((mutation) => {
776
+ * if (mutation.type === 'attributes') {
777
+ * console.log('Attribute changed:', mutation.attributeName);
778
+ * }
779
+ * });
780
+ * },
781
+ * { attributes: true, childList: false, subtree: false }
782
+ * );
783
+ *
784
+ * return <div ref={elementRef}>Watched element</div>;
785
+ * }
786
+ * ```
787
+ */
788
+ declare const useMutationObserver: (ref: React.RefObject<HTMLElement | null>, callback: MutationCallback, options?: MutationObserverInit) => void;
789
+
790
+ /**
791
+ * Google Analytics linker parameter cleanup hook for React
792
+ * Safely removes the GA `_gl` query parameter from the URL after GA initialization.
793
+ */
794
+ /**
795
+ * Hook to remove the Google Analytics `_gl` query parameter from the current URL.
796
+ *
797
+ * GA's cross-domain linker temporarily appends `_gl` to URLs for attribution.
798
+ * Removing it *too early* can break attribution, so this hook waits briefly
799
+ * (≈2 seconds) to allow GA to read it, then strips the param using
800
+ * `history.replaceState` without causing a page reload or React re-render.
801
+ *
802
+ * Behavior:
803
+ * - Runs once on mount.
804
+ * - If `_gl` is present, schedules its removal after ~2000ms.
805
+ * - Uses `window.history.replaceState` to avoid navigation/re-render.
806
+ *
807
+ * @example
808
+ * ```tsx
809
+ * // app/layout.tsx or a top-level client component
810
+ * import { useRemoveGAParams } from '@/hooks/use-remove-ga-params';
811
+ *
812
+ * export default function RootLayout({ children }: { children: React.ReactNode }) {
813
+ * useRemoveGAParams();
814
+ * return <>{children}</>;
815
+ * }
816
+ * ```
817
+ */
818
+ declare function useRemoveGAParams(): void;
819
+
820
+ /**
821
+ * Scroll position tracking hook for React components
822
+ * Monitors scroll position of window or specific elements
823
+ * with real-time updates and automatic cleanup
824
+ */
825
+
826
+ /**
827
+ * Configuration options for the scroll position hook
828
+ */
829
+ interface UseScrollPositionProps {
830
+ /** Optional ref to a specific scrollable element (defaults to document) */
831
+ targetRef?: RefObject<HTMLElement | Document | undefined>;
832
+ }
833
+ /**
834
+ * Hook to track scroll position of window or specific elements
835
+ *
836
+ * This hook provides real-time tracking of scroll position with support
837
+ * for both window scrolling and element-specific scrolling. It automatically
838
+ * handles event listener management and cleanup.
839
+ *
840
+ * Features:
841
+ * - Real-time scroll position tracking
842
+ * - Support for window and element scrolling
843
+ * - Automatic event listener cleanup
844
+ * - SSR-safe implementation
845
+ * - Performance optimized
846
+ *
847
+ * @param options - Configuration options for the hook
848
+ * @returns Current scroll position in pixels
849
+ *
850
+ * @example
851
+ * ```tsx
852
+ * // Track window scroll position
853
+ * function ScrollIndicator() {
854
+ * const scrollPosition = useScrollPosition();
855
+ *
856
+ * return (
857
+ * <div className="scroll-indicator">
858
+ * Scrolled: {scrollPosition}px
859
+ * </div>
860
+ * );
861
+ * }
862
+ *
863
+ * // Track specific element scroll position
864
+ * function ScrollableContent() {
865
+ * const contentRef = useRef<HTMLDivElement>(null);
866
+ * const scrollPosition = useScrollPosition({ targetRef: contentRef });
867
+ *
868
+ * return (
869
+ * <div
870
+ * ref={contentRef}
871
+ * className="h-96 overflow-y-auto"
872
+ * >
873
+ * <div className="h-[1000px]">
874
+ * <p>Scroll position: {scrollPosition}px</p>
875
+ * <p>Long content here...</p>
876
+ * </div>
877
+ * </div>
878
+ * );
879
+ * }
880
+ *
881
+ * // Show/hide header based on scroll
882
+ * function StickyHeader() {
883
+ * const scrollPosition = useScrollPosition();
884
+ * const isVisible = scrollPosition < 100;
885
+ *
886
+ * return (
887
+ * <header className={`transition-transform ${
888
+ * isVisible ? 'translate-y-0' : '-translate-y-full'
889
+ * }`}>
890
+ * Header content
891
+ * </header>
892
+ * );
893
+ * }
894
+ * ```
895
+ */
896
+ declare const useScrollPosition: ({ targetRef }?: UseScrollPositionProps) => number;
897
+
898
+ /**
899
+ * Dual slider input management hook for React components
900
+ * Provides synchronized state management between range slider and number inputs
901
+ * with validation and boundary enforcement
902
+ */
903
+
904
+ /**
905
+ * Configuration options for the slider input hook
906
+ */
907
+ interface UseSliderInputProps {
908
+ /** Minimum allowed value for the range */
909
+ minValue: number;
910
+ /** Maximum allowed value for the range */
911
+ maxValue: number;
912
+ /** Initial values for the range [min, max] */
913
+ initialValue: [number, number];
914
+ }
915
+ /**
916
+ * Hook for managing dual slider input with synchronized state
917
+ *
918
+ * This hook provides state management for components that need both
919
+ * a range slider and corresponding number inputs. It handles synchronization
920
+ * between the two input types, validation, and boundary enforcement.
921
+ *
922
+ * Features:
923
+ * - Synchronized slider and input values
924
+ * - Automatic validation and boundary enforcement
925
+ * - Prevents invalid range configurations (min > max)
926
+ * - Optimized with useCallback for performance
927
+ *
928
+ * @param props - Configuration options for the hook
929
+ * @returns Object containing state and handlers for slider and inputs
930
+ *
931
+ * @example
932
+ * ```tsx
933
+ * function PriceRangeFilter() {
934
+ * const {
935
+ * sliderValues,
936
+ * inputValues,
937
+ * handleSliderChange,
938
+ * handleInputChange,
939
+ * validateAndUpdateValue
940
+ * } = useSliderInput({
941
+ * minValue: 0,
942
+ * maxValue: 1000,
943
+ * initialValue: [100, 500]
944
+ * });
945
+ *
946
+ * return (
947
+ * <div className="price-range">
948
+ * <div className="inputs">
949
+ * <input
950
+ * type="number"
951
+ * value={inputValues[0]}
952
+ * onChange={(e) => handleInputChange(e, 0)}
953
+ * onBlur={() => validateAndUpdateValue(inputValues[0], 0)}
954
+ * placeholder="Min price"
955
+ * />
956
+ * <input
957
+ * type="number"
958
+ * value={inputValues[1]}
959
+ * onChange={(e) => handleInputChange(e, 1)}
960
+ * onBlur={() => validateAndUpdateValue(inputValues[1], 1)}
961
+ * placeholder="Max price"
962
+ * />
963
+ * </div>
964
+ *
965
+ * <Slider
966
+ * value={sliderValues}
967
+ * onValueChange={handleSliderChange}
968
+ * min={0}
969
+ * max={1000}
970
+ * step={10}
971
+ * />
972
+ * </div>
973
+ * );
974
+ * }
975
+ * ```
976
+ */
977
+ declare function useSliderInput({ minValue, maxValue, initialValue }: UseSliderInputProps): {
978
+ /** Function to manually set slider values */
979
+ setSliderValues: React.Dispatch<React.SetStateAction<[number, number]>>;
980
+ /** Function to manually set input values */
981
+ setInputValues: React.Dispatch<React.SetStateAction<[number, number]>>;
982
+ /** Current slider values [min, max] */
983
+ sliderValues: [number, number];
984
+ /** Current input values [min, max] */
985
+ inputValues: [number, number];
986
+ /** Handler for slider value changes */
987
+ handleSliderChange: (values: [number, number]) => void;
988
+ /** Handler for input field changes */
989
+ handleInputChange: (e: React.ChangeEvent<HTMLInputElement>, index: 0 | 1) => void;
990
+ /** Function to validate and update values from inputs */
991
+ validateAndUpdateValue: (value: number, index: 0 | 1) => void;
992
+ };
993
+
994
+ /**
995
+ * Viewport dimensions tracking hook for React components
996
+ * Provides real-time viewport width and height with automatic updates
997
+ * on window resize events with SSR-safe implementation
998
+ */
999
+ /**
1000
+ * Type definition for viewport dimensions
1001
+ * Returns tuple of [height, width] in pixels
1002
+ */
1003
+ type ViewportDimensions = [number, number];
1004
+ /**
1005
+ * Hook to track viewport dimensions with real-time updates
1006
+ *
1007
+ * This hook provides the current viewport dimensions and automatically
1008
+ * updates when the window is resized. It's useful for responsive layouts,
1009
+ * conditional rendering based on screen size, and dynamic calculations.
1010
+ *
1011
+ * Features:
1012
+ * - Real-time viewport dimension tracking
1013
+ * - Automatic updates on window resize
1014
+ * - Performance optimized with passive event listeners
1015
+ * - SSR-safe implementation
1016
+ * - Returns both height and width
1017
+ *
1018
+ * @returns Tuple containing [height, width] in pixels
1019
+ *
1020
+ * @example
1021
+ * ```tsx
1022
+ * // Basic usage
1023
+ * function ResponsiveComponent() {
1024
+ * const [height, width] = useViewport();
1025
+ *
1026
+ * return (
1027
+ * <div>
1028
+ * <p>Viewport: {width}x{height}</p>
1029
+ * {width > 768 ? <DesktopLayout /> : <MobileLayout />}
1030
+ * </div>
1031
+ * );
1032
+ * }
1033
+ *
1034
+ * // Destructured usage
1035
+ * function ViewportInfo() {
1036
+ * const [height, width] = useViewport();
1037
+ * const aspectRatio = (width / height).toFixed(2);
1038
+ *
1039
+ * return (
1040
+ * <div className="viewport-info">
1041
+ * <p>Width: {width}px</p>
1042
+ * <p>Height: {height}px</p>
1043
+ * <p>Aspect Ratio: {aspectRatio}</p>
1044
+ * </div>
1045
+ * );
1046
+ * }
1047
+ *
1048
+ * // Conditional rendering based on viewport
1049
+ * function AdaptiveGrid() {
1050
+ * const [, width] = useViewport();
1051
+ * const columns = width > 1200 ? 4 : width > 768 ? 3 : width > 480 ? 2 : 1;
1052
+ *
1053
+ * return (
1054
+ * <div className={`grid grid-cols-${columns} gap-4`}>
1055
+ * {items.map(item => <GridItem key={item.id} {...item} />)}
1056
+ * </div>
1057
+ * );
1058
+ * }
1059
+ * ```
1060
+ */
1061
+ declare const useViewport: () => ViewportDimensions;
1062
+
1063
+ export { type FileMetadata, type FileUploadActions, type FileUploadOptions, type FileUploadState, type FileWithPreview, formatBytes, useBodyClasses, useCopyToClipboard, useFileUpload, useHydrated, useIntersectionObserver, useIsMac, useIsMobile, useMediaQuery, useMenu, useMetaColor, useMounted, useMutationObserver, useRemoveGAParams, useScrollPosition, useSliderInput, useViewport };