shadcn-glass-ui 2.3.0 → 2.3.2
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/CHANGELOG.md +26 -0
- package/dist/cli/index.cjs +1 -1
- package/dist/components.cjs +4 -4
- package/dist/components.mjs +1 -1
- package/dist/hooks.cjs +2 -2
- package/dist/index.cjs +12 -5
- package/dist/index.mjs +8 -1
- package/dist/r/avatar-glass.json +1 -1
- package/dist/r/checkbox-glass.json +4 -5
- package/dist/r/circular-progress-glass.json +1 -1
- package/dist/r/dropdown-glass.json +1 -1
- package/dist/r/dropdown-menu-glass.json +1 -1
- package/dist/r/flag-alert-glass.json +1 -1
- package/dist/r/glass-card.json +3 -2
- package/dist/r/notification-glass.json +1 -1
- package/dist/r/popover-glass.json +1 -1
- package/dist/r/progress-glass.json +1 -1
- package/dist/r/registry.json +2 -2
- package/dist/r/skeleton-glass.json +1 -1
- package/dist/r/slider-glass.json +1 -1
- package/dist/r/stepper-glass.json +1 -1
- package/dist/r/tabs-glass.json +5 -4
- package/dist/r/toggle-glass.json +1 -1
- package/dist/shadcn-glass-ui.css +1 -1
- package/dist/{theme-context-DmTETrFi.cjs → theme-context-7NcW0KZL.cjs} +2 -2
- package/dist/themes.cjs +1 -1
- package/dist/{trust-score-card-glass-EfMB5l5J.mjs → trust-score-card-glass-BGqBcdyJ.mjs} +120 -177
- package/dist/{trust-score-card-glass-3VBi9soW.cjs → trust-score-card-glass-DtgFygh5.cjs} +124 -179
- package/dist/{use-focus-CswOSq71.cjs → use-focus-BFBcpBh1.cjs} +2 -2
- package/dist/{use-wallpaper-tint-WtRWtupA.cjs → use-wallpaper-tint-DTTStm5f.cjs} +2 -2
- package/dist/{utils-DX6rdBol.cjs → utils-CiuCe_Aq.cjs} +2 -2
- package/dist/utils.cjs +1 -1
- package/package.json +25 -3
- package/dist/components/blocks/avatar-gallery/index.d.ts +0 -2
- package/dist/components/blocks/avatar-gallery/index.d.ts.map +0 -1
- package/dist/components/blocks/avatar-gallery/page.d.ts +0 -7
- package/dist/components/blocks/avatar-gallery/page.d.ts.map +0 -1
- package/dist/components/blocks/badges/index.d.ts +0 -2
- package/dist/components/blocks/badges/index.d.ts.map +0 -1
- package/dist/components/blocks/badges/page.d.ts +0 -7
- package/dist/components/blocks/badges/page.d.ts.map +0 -1
- package/dist/components/blocks/buttons/index.d.ts +0 -2
- package/dist/components/blocks/buttons/index.d.ts.map +0 -1
- package/dist/components/blocks/buttons/page.d.ts +0 -7
- package/dist/components/blocks/buttons/page.d.ts.map +0 -1
- package/dist/components/blocks/form-elements/index.d.ts +0 -2
- package/dist/components/blocks/form-elements/index.d.ts.map +0 -1
- package/dist/components/blocks/form-elements/page.d.ts +0 -7
- package/dist/components/blocks/form-elements/page.d.ts.map +0 -1
- package/dist/components/blocks/index.d.ts +0 -14
- package/dist/components/blocks/index.d.ts.map +0 -1
- package/dist/components/blocks/notifications/index.d.ts +0 -2
- package/dist/components/blocks/notifications/index.d.ts.map +0 -1
- package/dist/components/blocks/notifications/page.d.ts +0 -7
- package/dist/components/blocks/notifications/page.d.ts.map +0 -1
- package/dist/components/blocks/progress/index.d.ts +0 -2
- package/dist/components/blocks/progress/index.d.ts.map +0 -1
- package/dist/components/blocks/progress/page.d.ts +0 -7
- package/dist/components/blocks/progress/page.d.ts.map +0 -1
- package/dist/components/blocks/registry.d.ts +0 -16
- package/dist/components/blocks/registry.d.ts.map +0 -1
- package/dist/components/demos/AnimatedBackground.d.ts +0 -5
- package/dist/components/demos/AnimatedBackground.d.ts.map +0 -1
- package/dist/components/demos/ComponentShowcase.d.ts +0 -6
- package/dist/components/demos/ComponentShowcase.d.ts.map +0 -1
- package/dist/components/demos/DesktopShowcase.d.ts +0 -3
- package/dist/components/demos/DesktopShowcase.d.ts.map +0 -1
- package/dist/components/demos/GlassFixesDemo.d.ts +0 -6
- package/dist/components/demos/GlassFixesDemo.d.ts.map +0 -1
- package/dist/components/demos/MobileShowcase.d.ts +0 -3
- package/dist/components/demos/MobileShowcase.d.ts.map +0 -1
- package/dist/components/glass/atomic/expandable-header-glass.d.ts +0 -16
- package/dist/components/glass/atomic/expandable-header-glass.d.ts.map +0 -1
- package/dist/components/glass/atomic/icon-button-glass.d.ts +0 -18
- package/dist/components/glass/atomic/icon-button-glass.d.ts.map +0 -1
- package/dist/components/glass/atomic/index.d.ts +0 -14
- package/dist/components/glass/atomic/index.d.ts.map +0 -1
- package/dist/components/glass/atomic/insight-card-glass.d.ts +0 -22
- package/dist/components/glass/atomic/insight-card-glass.d.ts.map +0 -1
- package/dist/components/glass/atomic/search-box-glass.d.ts +0 -17
- package/dist/components/glass/atomic/search-box-glass.d.ts.map +0 -1
- package/dist/components/glass/atomic/sort-dropdown-glass.d.ts +0 -38
- package/dist/components/glass/atomic/sort-dropdown-glass.d.ts.map +0 -1
- package/dist/components/glass/atomic/stat-item-glass.d.ts +0 -22
- package/dist/components/glass/atomic/stat-item-glass.d.ts.map +0 -1
- package/dist/components/glass/atomic/theme-toggle-glass.d.ts +0 -11
- package/dist/components/glass/atomic/theme-toggle-glass.d.ts.map +0 -1
- package/dist/components/glass/composite/ai-card-glass.d.ts +0 -7
- package/dist/components/glass/composite/ai-card-glass.d.ts.map +0 -1
- package/dist/components/glass/composite/career-stats-header-glass.d.ts +0 -15
- package/dist/components/glass/composite/career-stats-header-glass.d.ts.map +0 -1
- package/dist/components/glass/composite/circular-metric-glass.d.ts +0 -24
- package/dist/components/glass/composite/circular-metric-glass.d.ts.map +0 -1
- package/dist/components/glass/composite/contribution-metrics-glass.d.ts +0 -15
- package/dist/components/glass/composite/contribution-metrics-glass.d.ts.map +0 -1
- package/dist/components/glass/composite/index.d.ts +0 -22
- package/dist/components/glass/composite/index.d.ts.map +0 -1
- package/dist/components/glass/composite/metric-card-glass.d.ts +0 -96
- package/dist/components/glass/composite/metric-card-glass.d.ts.map +0 -1
- package/dist/components/glass/composite/metrics-grid-glass.d.ts +0 -17
- package/dist/components/glass/composite/metrics-grid-glass.d.ts.map +0 -1
- package/dist/components/glass/composite/repository-card-glass.d.ts +0 -16
- package/dist/components/glass/composite/repository-card-glass.d.ts.map +0 -1
- package/dist/components/glass/composite/repository-header-glass.d.ts +0 -16
- package/dist/components/glass/composite/repository-header-glass.d.ts.map +0 -1
- package/dist/components/glass/composite/repository-metadata-glass.d.ts +0 -13
- package/dist/components/glass/composite/repository-metadata-glass.d.ts.map +0 -1
- package/dist/components/glass/composite/split-layout-glass/index.d.ts +0 -16
- package/dist/components/glass/composite/split-layout-glass/index.d.ts.map +0 -1
- package/dist/components/glass/composite/split-layout-glass/split-layout-accordion.d.ts +0 -66
- package/dist/components/glass/composite/split-layout-glass/split-layout-accordion.d.ts.map +0 -1
- package/dist/components/glass/composite/split-layout-glass/split-layout-context.d.ts +0 -122
- package/dist/components/glass/composite/split-layout-glass/split-layout-context.d.ts.map +0 -1
- package/dist/components/glass/composite/split-layout-glass/split-layout-glass.d.ts +0 -177
- package/dist/components/glass/composite/split-layout-glass/split-layout-glass.d.ts.map +0 -1
- package/dist/components/glass/composite/trust-score-display-glass.d.ts +0 -15
- package/dist/components/glass/composite/trust-score-display-glass.d.ts.map +0 -1
- package/dist/components/glass/composite/user-info-glass.d.ts +0 -15
- package/dist/components/glass/composite/user-info-glass.d.ts.map +0 -1
- package/dist/components/glass/composite/user-stats-line-glass.d.ts +0 -15
- package/dist/components/glass/composite/user-stats-line-glass.d.ts.map +0 -1
- package/dist/components/glass/composite/year-card-glass.d.ts +0 -53
- package/dist/components/glass/composite/year-card-glass.d.ts.map +0 -1
- package/dist/components/glass/index.d.ts +0 -16
- package/dist/components/glass/index.d.ts.map +0 -1
- package/dist/components/glass/primitives/form-field-wrapper.d.ts +0 -69
- package/dist/components/glass/primitives/form-field-wrapper.d.ts.map +0 -1
- package/dist/components/glass/primitives/index.d.ts +0 -12
- package/dist/components/glass/primitives/index.d.ts.map +0 -1
- package/dist/components/glass/primitives/interactive-card.d.ts +0 -91
- package/dist/components/glass/primitives/interactive-card.d.ts.map +0 -1
- package/dist/components/glass/primitives/style-utils.d.ts +0 -147
- package/dist/components/glass/primitives/style-utils.d.ts.map +0 -1
- package/dist/components/glass/primitives/touch-target.d.ts +0 -46
- package/dist/components/glass/primitives/touch-target.d.ts.map +0 -1
- package/dist/components/glass/sections/career-stats-glass.d.ts +0 -17
- package/dist/components/glass/sections/career-stats-glass.d.ts.map +0 -1
- package/dist/components/glass/sections/flags-section-glass.d.ts +0 -13
- package/dist/components/glass/sections/flags-section-glass.d.ts.map +0 -1
- package/dist/components/glass/sections/header-branding-glass.d.ts +0 -16
- package/dist/components/glass/sections/header-branding-glass.d.ts.map +0 -1
- package/dist/components/glass/sections/header-nav-glass.d.ts +0 -7
- package/dist/components/glass/sections/header-nav-glass.d.ts.map +0 -1
- package/dist/components/glass/sections/index.d.ts +0 -13
- package/dist/components/glass/sections/index.d.ts.map +0 -1
- package/dist/components/glass/sections/profile-header-glass.d.ts +0 -16
- package/dist/components/glass/sections/profile-header-glass.d.ts.map +0 -1
- package/dist/components/glass/sections/projects-list-glass.d.ts +0 -42
- package/dist/components/glass/sections/projects-list-glass.d.ts.map +0 -1
- package/dist/components/glass/sections/trust-score-card-glass.d.ts +0 -12
- package/dist/components/glass/sections/trust-score-card-glass.d.ts.map +0 -1
- package/dist/components/glass/specialized/base-progress-glass.d.ts +0 -8
- package/dist/components/glass/specialized/base-progress-glass.d.ts.map +0 -1
- package/dist/components/glass/specialized/flag-alert-glass.d.ts +0 -8
- package/dist/components/glass/specialized/flag-alert-glass.d.ts.map +0 -1
- package/dist/components/glass/specialized/index.d.ts +0 -21
- package/dist/components/glass/specialized/index.d.ts.map +0 -1
- package/dist/components/glass/specialized/language-bar-glass.d.ts +0 -24
- package/dist/components/glass/specialized/language-bar-glass.d.ts.map +0 -1
- package/dist/components/glass/specialized/profile-avatar-glass.d.ts +0 -26
- package/dist/components/glass/specialized/profile-avatar-glass.d.ts.map +0 -1
- package/dist/components/glass/specialized/progress-glass.d.ts +0 -9
- package/dist/components/glass/specialized/progress-glass.d.ts.map +0 -1
- package/dist/components/glass/specialized/rainbow-progress-glass.d.ts +0 -8
- package/dist/components/glass/specialized/rainbow-progress-glass.d.ts.map +0 -1
- package/dist/components/glass/specialized/segmented-control-glass.d.ts +0 -11
- package/dist/components/glass/specialized/segmented-control-glass.d.ts.map +0 -1
- package/dist/components/glass/specialized/sparkline-glass.d.ts +0 -34
- package/dist/components/glass/specialized/sparkline-glass.d.ts.map +0 -1
- package/dist/components/glass/specialized/status-indicator-glass.d.ts +0 -8
- package/dist/components/glass/specialized/status-indicator-glass.d.ts.map +0 -1
- package/dist/components/glass/ui/alert-glass.d.ts +0 -13
- package/dist/components/glass/ui/alert-glass.d.ts.map +0 -1
- package/dist/components/glass/ui/avatar-glass.d.ts +0 -58
- package/dist/components/glass/ui/avatar-glass.d.ts.map +0 -1
- package/dist/components/glass/ui/badge-glass.d.ts +0 -74
- package/dist/components/glass/ui/badge-glass.d.ts.map +0 -1
- package/dist/components/glass/ui/button-glass.d.ts +0 -110
- package/dist/components/glass/ui/button-glass.d.ts.map +0 -1
- package/dist/components/glass/ui/card-glass.d.ts +0 -115
- package/dist/components/glass/ui/card-glass.d.ts.map +0 -1
- package/dist/components/glass/ui/checkbox-glass.d.ts +0 -113
- package/dist/components/glass/ui/checkbox-glass.d.ts.map +0 -1
- package/dist/components/glass/ui/circular-progress-glass.d.ts +0 -36
- package/dist/components/glass/ui/circular-progress-glass.d.ts.map +0 -1
- package/dist/components/glass/ui/combobox-glass.d.ts +0 -61
- package/dist/components/glass/ui/combobox-glass.d.ts.map +0 -1
- package/dist/components/glass/ui/dropdown-glass.d.ts +0 -83
- package/dist/components/glass/ui/dropdown-glass.d.ts.map +0 -1
- package/dist/components/glass/ui/dropdown-menu-glass.d.ts +0 -77
- package/dist/components/glass/ui/dropdown-menu-glass.d.ts.map +0 -1
- package/dist/components/glass/ui/glass-card.d.ts +0 -78
- package/dist/components/glass/ui/glass-card.d.ts.map +0 -1
- package/dist/components/glass/ui/index.d.ts +0 -44
- package/dist/components/glass/ui/index.d.ts.map +0 -1
- package/dist/components/glass/ui/input-glass.d.ts +0 -98
- package/dist/components/glass/ui/input-glass.d.ts.map +0 -1
- package/dist/components/glass/ui/modal-glass.d.ts +0 -180
- package/dist/components/glass/ui/modal-glass.d.ts.map +0 -1
- package/dist/components/glass/ui/notification-glass.d.ts +0 -13
- package/dist/components/glass/ui/notification-glass.d.ts.map +0 -1
- package/dist/components/glass/ui/popover-glass.d.ts +0 -71
- package/dist/components/glass/ui/popover-glass.d.ts.map +0 -1
- package/dist/components/glass/ui/sidebar-glass/index.d.ts +0 -100
- package/dist/components/glass/ui/sidebar-glass/index.d.ts.map +0 -1
- package/dist/components/glass/ui/sidebar-glass/sidebar-context.d.ts +0 -96
- package/dist/components/glass/ui/sidebar-glass/sidebar-context.d.ts.map +0 -1
- package/dist/components/glass/ui/sidebar-glass/sidebar-glass.d.ts +0 -88
- package/dist/components/glass/ui/sidebar-glass/sidebar-glass.d.ts.map +0 -1
- package/dist/components/glass/ui/sidebar-glass/sidebar-menu.d.ts +0 -121
- package/dist/components/glass/ui/sidebar-glass/sidebar-menu.d.ts.map +0 -1
- package/dist/components/glass/ui/skeleton-glass.d.ts +0 -8
- package/dist/components/glass/ui/skeleton-glass.d.ts.map +0 -1
- package/dist/components/glass/ui/slider-glass.d.ts +0 -38
- package/dist/components/glass/ui/slider-glass.d.ts.map +0 -1
- package/dist/components/glass/ui/stepper-glass.d.ts +0 -63
- package/dist/components/glass/ui/stepper-glass.d.ts.map +0 -1
- package/dist/components/glass/ui/tabs-glass.d.ts +0 -199
- package/dist/components/glass/ui/tabs-glass.d.ts.map +0 -1
- package/dist/components/glass/ui/toggle-glass.d.ts +0 -27
- package/dist/components/glass/ui/toggle-glass.d.ts.map +0 -1
- package/dist/components/glass/ui/tooltip-glass.d.ts +0 -65
- package/dist/components/glass/ui/tooltip-glass.d.ts.map +0 -1
- package/dist/components/ui/alert.d.ts +0 -8
- package/dist/components/ui/alert.d.ts.map +0 -1
- package/dist/components/ui/avatar.d.ts +0 -7
- package/dist/components/ui/avatar.d.ts.map +0 -1
- package/dist/components/ui/badge.d.ts +0 -8
- package/dist/components/ui/badge.d.ts.map +0 -1
- package/dist/components/ui/button.d.ts +0 -8
- package/dist/components/ui/button.d.ts.map +0 -1
- package/dist/components/ui/card.d.ts +0 -10
- package/dist/components/ui/card.d.ts.map +0 -1
- package/dist/components/ui/chart.d.ts +0 -69
- package/dist/components/ui/chart.d.ts.map +0 -1
- package/dist/components/ui/checkbox.d.ts +0 -5
- package/dist/components/ui/checkbox.d.ts.map +0 -1
- package/dist/components/ui/collapsible.d.ts +0 -6
- package/dist/components/ui/collapsible.d.ts.map +0 -1
- package/dist/components/ui/command.d.ts +0 -19
- package/dist/components/ui/command.d.ts.map +0 -1
- package/dist/components/ui/dialog.d.ts +0 -16
- package/dist/components/ui/dialog.d.ts.map +0 -1
- package/dist/components/ui/dropdown-menu.d.ts +0 -26
- package/dist/components/ui/dropdown-menu.d.ts.map +0 -1
- package/dist/components/ui/input.d.ts +0 -4
- package/dist/components/ui/input.d.ts.map +0 -1
- package/dist/components/ui/popover.d.ts +0 -8
- package/dist/components/ui/popover.d.ts.map +0 -1
- package/dist/components/ui/progress.d.ts +0 -5
- package/dist/components/ui/progress.d.ts.map +0 -1
- package/dist/components/ui/scroll-area.d.ts +0 -6
- package/dist/components/ui/scroll-area.d.ts.map +0 -1
- package/dist/components/ui/separator.d.ts +0 -5
- package/dist/components/ui/separator.d.ts.map +0 -1
- package/dist/components/ui/skeleton.d.ts +0 -3
- package/dist/components/ui/skeleton.d.ts.map +0 -1
- package/dist/components/ui/slider.d.ts +0 -5
- package/dist/components/ui/slider.d.ts.map +0 -1
- package/dist/components/ui/sonner.d.ts +0 -4
- package/dist/components/ui/sonner.d.ts.map +0 -1
- package/dist/components/ui/switch.d.ts +0 -5
- package/dist/components/ui/switch.d.ts.map +0 -1
- package/dist/components/ui/tabs.d.ts +0 -8
- package/dist/components/ui/tabs.d.ts.map +0 -1
- package/dist/components/ui/tooltip.d.ts +0 -8
- package/dist/components/ui/tooltip.d.ts.map +0 -1
- package/dist/components.d.ts.map +0 -1
- package/dist/demo-screenshot-aurora.png +0 -0
- package/dist/demo-screenshot.png +0 -0
- package/dist/demo-screenshot.png.zip +0 -0
- package/dist/hooks.d.ts.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/lib/config.d.ts +0 -28
- package/dist/lib/config.d.ts.map +0 -1
- package/dist/lib/hooks/index.d.ts +0 -11
- package/dist/lib/hooks/index.d.ts.map +0 -1
- package/dist/lib/hooks/use-focus.d.ts +0 -61
- package/dist/lib/hooks/use-focus.d.ts.map +0 -1
- package/dist/lib/hooks/use-hover.d.ts +0 -54
- package/dist/lib/hooks/use-hover.d.ts.map +0 -1
- package/dist/lib/hooks/use-responsive.d.ts +0 -44
- package/dist/lib/hooks/use-responsive.d.ts.map +0 -1
- package/dist/lib/hooks/use-wallpaper-tint.d.ts +0 -57
- package/dist/lib/hooks/use-wallpaper-tint.d.ts.map +0 -1
- package/dist/lib/hooks.d.ts +0 -92
- package/dist/lib/hooks.d.ts.map +0 -1
- package/dist/lib/theme/tokens.d.ts +0 -441
- package/dist/lib/theme/tokens.d.ts.map +0 -1
- package/dist/lib/theme-context.d.ts +0 -115
- package/dist/lib/theme-context.d.ts.map +0 -1
- package/dist/lib/types.d.ts +0 -24
- package/dist/lib/types.d.ts.map +0 -1
- package/dist/lib/utils.d.ts +0 -8
- package/dist/lib/utils.d.ts.map +0 -1
- package/dist/lib/variants/alert-glass-variants.d.ts +0 -10
- package/dist/lib/variants/alert-glass-variants.d.ts.map +0 -1
- package/dist/lib/variants/alert-variants.d.ts +0 -8
- package/dist/lib/variants/alert-variants.d.ts.map +0 -1
- package/dist/lib/variants/avatar-glass-variants.d.ts +0 -12
- package/dist/lib/variants/avatar-glass-variants.d.ts.map +0 -1
- package/dist/lib/variants/badge-glass-variants.d.ts +0 -10
- package/dist/lib/variants/badge-glass-variants.d.ts.map +0 -1
- package/dist/lib/variants/badge-variants.d.ts +0 -8
- package/dist/lib/variants/badge-variants.d.ts.map +0 -1
- package/dist/lib/variants/button-glass-variants.d.ts +0 -29
- package/dist/lib/variants/button-glass-variants.d.ts.map +0 -1
- package/dist/lib/variants/button-variants.d.ts +0 -9
- package/dist/lib/variants/button-variants.d.ts.map +0 -1
- package/dist/lib/variants/dropdown-content-styles.d.ts +0 -102
- package/dist/lib/variants/dropdown-content-styles.d.ts.map +0 -1
- package/dist/lib/variants/dropdown-glass-variants.d.ts +0 -9
- package/dist/lib/variants/dropdown-glass-variants.d.ts.map +0 -1
- package/dist/lib/variants/glass-card-variants.d.ts +0 -13
- package/dist/lib/variants/glass-card-variants.d.ts.map +0 -1
- package/dist/lib/variants/index.d.ts +0 -26
- package/dist/lib/variants/index.d.ts.map +0 -1
- package/dist/lib/variants/input-glass-variants.d.ts +0 -9
- package/dist/lib/variants/input-glass-variants.d.ts.map +0 -1
- package/dist/lib/variants/insight-card-glass-variants.d.ts +0 -11
- package/dist/lib/variants/insight-card-glass-variants.d.ts.map +0 -1
- package/dist/lib/variants/modal-glass-variants.d.ts +0 -9
- package/dist/lib/variants/modal-glass-variants.d.ts.map +0 -1
- package/dist/lib/variants/notification-glass-variants.d.ts +0 -9
- package/dist/lib/variants/notification-glass-variants.d.ts.map +0 -1
- package/dist/lib/variants/progress-glass-variants.d.ts +0 -10
- package/dist/lib/variants/progress-glass-variants.d.ts.map +0 -1
- package/dist/lib/variants/skeleton-glass-variants.d.ts +0 -9
- package/dist/lib/variants/skeleton-glass-variants.d.ts.map +0 -1
- package/dist/lib/variants/sparkline-glass-variants.d.ts +0 -10
- package/dist/lib/variants/sparkline-glass-variants.d.ts.map +0 -1
- package/dist/lib/variants/stepper-glass-variants.d.ts +0 -40
- package/dist/lib/variants/stepper-glass-variants.d.ts.map +0 -1
- package/dist/lib/variants/toggle-glass-variants.d.ts +0 -26
- package/dist/lib/variants/toggle-glass-variants.d.ts.map +0 -1
- package/dist/lib/variants/tooltip-glass-variants.d.ts +0 -9
- package/dist/lib/variants/tooltip-glass-variants.d.ts.map +0 -1
- package/dist/theme-context-DLS2uAgJ.mjs.map +0 -1
- package/dist/theme-context-DmTETrFi.cjs.map +0 -1
- package/dist/themes.d.ts.map +0 -1
- package/dist/trust-score-card-glass-3VBi9soW.cjs.map +0 -1
- package/dist/trust-score-card-glass-EfMB5l5J.mjs.map +0 -1
- package/dist/use-focus-C5kPAKr_.mjs.map +0 -1
- package/dist/use-focus-CswOSq71.cjs.map +0 -1
- package/dist/use-wallpaper-tint-C0kYXNiN.mjs.map +0 -1
- package/dist/use-wallpaper-tint-WtRWtupA.cjs.map +0 -1
- package/dist/utils-B792GPM_.mjs.map +0 -1
- package/dist/utils-DX6rdBol.cjs.map +0 -1
- package/dist/utils.d.ts.map +0 -1
- package/docs/AI_IMPROVEMENTS_COMPLETE.md +0 -574
- package/docs/API_PATTERNS_COMPARISON.md +0 -419
- package/docs/COMPLIANCE_CHECKLIST.md +0 -307
- package/docs/COMPLIANCE_TESTING.md +0 -436
- package/docs/CSS_VARIABLES_AUDIT.md +0 -306
- package/docs/CSS_VARIABLES_REFACTORING_PLAN.md +0 -330
- package/docs/DROPDOWN_ARCHITECTURE.md +0 -290
- package/docs/METRIC_CARD_API_REDESIGN.md +0 -354
- package/docs/PRIMITIVE_MAPPING.md +0 -404
- package/docs/PUBLISHING.md +0 -593
- package/docs/REGISTRY_SUMMARY.md +0 -96
- package/docs/SECURITY.md +0 -117
- package/docs/api/README.md +0 -723
- package/docs/api/functions/ThemeProvider.md +0 -21
- package/docs/api/functions/cn.md +0 -27
- package/docs/api/functions/getNextTheme.md +0 -21
- package/docs/api/functions/getThemeConfig.md +0 -21
- package/docs/api/functions/useFocus.md +0 -53
- package/docs/api/functions/useHover.md +0 -47
- package/docs/api/functions/useResponsive.md +0 -31
- package/docs/api/functions/useTheme.md +0 -15
- package/docs/api/functions/useWallpaperTint.md +0 -36
- package/docs/api/globals.md +0 -139
- package/docs/api/interfaces/AlertGlassProps.md +0 -131
- package/docs/api/interfaces/AvatarGlassProps.md +0 -114
- package/docs/api/interfaces/BadgeGlassProps.md +0 -125
- package/docs/api/interfaces/ButtonGlassProps.md +0 -186
- package/docs/api/interfaces/CheckboxGlassProps.md +0 -125
- package/docs/api/interfaces/DropdownGlassProps.md +0 -123
- package/docs/api/interfaces/DropdownItem.md +0 -53
- package/docs/api/interfaces/GlassCardProps.md +0 -151
- package/docs/api/interfaces/InputGlassProps.md +0 -169
- package/docs/api/interfaces/NotificationGlassProps.md +0 -67
- package/docs/api/interfaces/ProgressGlassProps.md +0 -49
- package/docs/api/interfaces/SkeletonGlassProps.md +0 -41
- package/docs/api/interfaces/SliderGlassProps.md +0 -107
- package/docs/api/interfaces/TabItem.md +0 -25
- package/docs/api/interfaces/ThemeConfig.md +0 -25
- package/docs/api/interfaces/ThemeContextValue.md +0 -47
- package/docs/api/interfaces/ToggleGlassProps.md +0 -59
- package/docs/api/interfaces/TooltipGlassProps.md +0 -119
- package/docs/api/type-aliases/AlertType.md +0 -11
- package/docs/api/type-aliases/AlertVariant.md +0 -11
- package/docs/api/type-aliases/AvatarSize.md +0 -11
- package/docs/api/type-aliases/AvatarStatus.md +0 -13
- package/docs/api/type-aliases/BadgeSize.md +0 -11
- package/docs/api/type-aliases/BadgeVariant.md +0 -11
- package/docs/api/type-aliases/ButtonGlassSize.md +0 -11
- package/docs/api/type-aliases/ButtonGlassVariant.md +0 -11
- package/docs/api/type-aliases/DropdownAlign.md +0 -11
- package/docs/api/type-aliases/GlowType.md +0 -11
- package/docs/api/type-aliases/InputGlassSize.md +0 -11
- package/docs/api/type-aliases/IntensityType.md +0 -11
- package/docs/api/type-aliases/ModalSize.md +0 -11
- package/docs/api/type-aliases/NotificationType.md +0 -11
- package/docs/api/type-aliases/PaddingType.md +0 -11
- package/docs/api/type-aliases/ProgressGradient.md +0 -11
- package/docs/api/type-aliases/ProgressSize.md +0 -11
- package/docs/api/type-aliases/SkeletonVariant.md +0 -11
- package/docs/api/type-aliases/Theme.md +0 -11
- package/docs/api/type-aliases/ToggleGlassSize.md +0 -11
- package/docs/api/type-aliases/TooltipPosition.md +0 -11
- package/docs/api/variables/AICardGlass.md +0 -11
- package/docs/api/variables/AlertGlass.md +0 -11
- package/docs/api/variables/AvatarGlass.md +0 -11
- package/docs/api/variables/BadgeGlass.md +0 -11
- package/docs/api/variables/BaseProgressGlass.md +0 -11
- package/docs/api/variables/ButtonGlass.md +0 -11
- package/docs/api/variables/CareerStatsGlass.md +0 -11
- package/docs/api/variables/CareerStatsHeaderGlass.md +0 -11
- package/docs/api/variables/CheckboxGlass.md +0 -11
- package/docs/api/variables/CircularMetricGlass.md +0 -22
- package/docs/api/variables/CircularProgressGlass.md +0 -11
- package/docs/api/variables/ComboBoxGlass.md +0 -27
- package/docs/api/variables/ContributionMetricsGlass.md +0 -11
- package/docs/api/variables/DropdownGlass.md +0 -11
- package/docs/api/variables/ExpandableHeaderGlass.md +0 -11
- package/docs/api/variables/FlagAlertGlass.md +0 -11
- package/docs/api/variables/FlagsSectionGlass.md +0 -11
- package/docs/api/variables/FormFieldWrapper.md +0 -44
- package/docs/api/variables/GlassCard.md +0 -11
- package/docs/api/variables/HeaderBrandingGlass.md +0 -11
- package/docs/api/variables/HeaderNavGlass.md +0 -11
- package/docs/api/variables/IconButtonGlass.md +0 -11
- package/docs/api/variables/InputGlass.md +0 -11
- package/docs/api/variables/InteractiveCard.md +0 -45
- package/docs/api/variables/LanguageBarGlass.md +0 -11
- package/docs/api/variables/MetricCardGlass.md +0 -11
- package/docs/api/variables/MetricsGridGlass.md +0 -11
- package/docs/api/variables/ModalGlass.md +0 -73
- package/docs/api/variables/NotificationGlass.md +0 -11
- package/docs/api/variables/PopoverGlass.md +0 -11
- package/docs/api/variables/ProfileAvatarGlass.md +0 -11
- package/docs/api/variables/ProfileHeaderGlass.md +0 -11
- package/docs/api/variables/ProgressGlass.md +0 -11
- package/docs/api/variables/ProjectsListGlass.md +0 -11
- package/docs/api/variables/RainbowProgressGlass.md +0 -11
- package/docs/api/variables/RepositoryCardGlass.md +0 -11
- package/docs/api/variables/RepositoryHeaderGlass.md +0 -11
- package/docs/api/variables/RepositoryMetadataGlass.md +0 -11
- package/docs/api/variables/SearchBoxGlass.md +0 -11
- package/docs/api/variables/SegmentedControlGlass.md +0 -11
- package/docs/api/variables/SkeletonGlass.md +0 -11
- package/docs/api/variables/SliderGlass.md +0 -11
- package/docs/api/variables/SortDropdownGlass.md +0 -11
- package/docs/api/variables/StatItemGlass.md +0 -11
- package/docs/api/variables/StatusIndicatorGlass.md +0 -11
- package/docs/api/variables/THEMES.md +0 -11
- package/docs/api/variables/THEME_CONFIG.md +0 -11
- package/docs/api/variables/TabsGlass.md +0 -52
- package/docs/api/variables/ThemeToggleGlass.md +0 -11
- package/docs/api/variables/ToggleGlass.md +0 -11
- package/docs/api/variables/TooltipGlass.md +0 -11
- package/docs/api/variables/TouchTarget.md +0 -35
- package/docs/api/variables/TrustScoreCardGlass.md +0 -11
- package/docs/api/variables/TrustScoreDisplayGlass.md +0 -11
- package/docs/api/variables/UserInfoGlass.md +0 -11
- package/docs/api/variables/UserStatsLineGlass.md +0 -11
- package/docs/api/variables/YearCardGlass.md +0 -11
- package/docs/api/variables/alertVariants.md +0 -21
- package/docs/api/variables/avatarSizes.md +0 -21
- package/docs/api/variables/badgeVariants.md +0 -21
- package/docs/api/variables/buttonGlassVariants.md +0 -21
- package/docs/api/variables/cardIntensity.md +0 -21
- package/docs/api/variables/dropdownAlign.md +0 -21
- package/docs/api/variables/inputVariants.md +0 -21
- package/docs/api/variables/modalSizes.md +0 -21
- package/docs/api/variables/notificationVariants.md +0 -21
- package/docs/api/variables/progressSizes.md +0 -21
- package/docs/api/variables/shadcnAlertVariants.md +0 -21
- package/docs/api/variables/shadcnBadgeVariants.md +0 -21
- package/docs/api/variables/shadcnButtonVariants.md +0 -21
- package/docs/api/variables/skeletonVariants.md +0 -21
- package/docs/api/variables/statusSizes.md +0 -21
- package/docs/api/variables/toggleSizes.md +0 -21
- package/docs/api/variables/tooltipPositions.md +0 -21
- package/docs/design-system/UI_DESIGN.md +0 -628
- package/docs/technical/DEPENDENCIES.md +0 -291
- package/docs/visual-testing-guide.md +0 -362
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
{
|
|
20
20
|
"path": "components/glass/ui/notification-glass.tsx",
|
|
21
21
|
"type": "registry:component",
|
|
22
|
-
"content": "/**\n * NotificationGlass Component\n *\n * Glass-themed toast notification with:\n * - Theme-aware styling (glass/light/aurora)\n * - Type variants (info/success/warning/error)\n * - Glow effect on hover\n * - Dismissible\n */\n\nimport { forwardRef, type CSSProperties } from 'react';\nimport { type VariantProps } from 'class-variance-authority';\nimport { Info, CheckCircle, AlertTriangle, AlertCircle, X } from 'lucide-react';\nimport { cn } from '@/lib/utils';\nimport { useHover } from '@/lib/hooks/use-hover';\nimport { notificationVariants } from '@/lib/variants/notification-glass-variants';\nimport { ICON_SIZES } from '@/components/glass/primitives';\nimport '@/glass-theme.css';\n\nimport type { NotificationType } from '@/lib/variants/notification-glass-variants';\n\n// ========================================\n// CONSTANTS\n// ========================================\n\nconst NOTIFICATION_ICONS = {\n info: Info,\n success: CheckCircle,\n warning: AlertTriangle,\n error: AlertCircle,\n} as const;\n\n// ========================================\n// PROPS INTERFACE\n// ========================================\n\nexport interface NotificationGlassProps\n extends
|
|
22
|
+
"content": "/**\n * NotificationGlass Component\n *\n * Glass-themed toast notification with:\n * - Theme-aware styling (glass/light/aurora)\n * - Type variants (info/success/warning/error)\n * - Glow effect on hover\n * - Dismissible\n */\n\nimport { forwardRef, type CSSProperties } from 'react';\nimport { type VariantProps } from 'class-variance-authority';\nimport { Info, CheckCircle, AlertTriangle, AlertCircle, X } from 'lucide-react';\nimport { cn } from '@/lib/utils';\nimport { useHover } from '@/lib/hooks/use-hover';\nimport { notificationVariants } from '@/lib/variants/notification-glass-variants';\nimport { ICON_SIZES } from '@/components/glass/primitives';\nimport '@/glass-theme.css';\n\nimport type { NotificationType } from '@/lib/variants/notification-glass-variants';\n\n// ========================================\n// CONSTANTS\n// ========================================\n\nconst NOTIFICATION_ICONS = {\n info: Info,\n success: CheckCircle,\n warning: AlertTriangle,\n error: AlertCircle,\n} as const;\n\n// ========================================\n// PROPS INTERFACE\n// ========================================\n\nexport interface NotificationGlassProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, 'title' | 'style'>,\n VariantProps<typeof notificationVariants> {\n readonly title: string;\n readonly message: string;\n /** Notification variant (shadcn/ui compatible) */\n readonly variant?: 'default' | 'destructive' | 'success' | 'warning';\n /** @deprecated Use variant prop instead. Will be removed in next major version. */\n readonly type?: NotificationType;\n readonly onClose: () => void;\n}\n\n// ========================================\n// COMPONENT\n// ========================================\n\n// Type-specific CSS variable mapping\nconst getTypeVars = (\n notifType: NotificationType\n): { color: string; glow: string; iconBg: string } => {\n const configs: Record<NotificationType, { color: string; glow: string; iconBg: string }> = {\n info: {\n color: 'var(--notification-info-color)',\n glow: 'var(--notification-info-glow)',\n iconBg: 'var(--notification-info-icon-bg)',\n },\n success: {\n color: 'var(--notification-success-color)',\n glow: 'var(--notification-success-glow)',\n iconBg: 'var(--notification-success-icon-bg)',\n },\n warning: {\n color: 'var(--notification-warning-color)',\n glow: 'var(--notification-warning-glow)',\n iconBg: 'var(--notification-warning-icon-bg)',\n },\n error: {\n color: 'var(--notification-error-color)',\n glow: 'var(--notification-error-glow)',\n iconBg: 'var(--notification-error-icon-bg)',\n },\n };\n return configs[notifType];\n};\n\nexport const NotificationGlass = forwardRef<HTMLDivElement, NotificationGlassProps>(\n ({ variant: variantProp, type: typeProp, title, message, onClose, className, ...props }, ref) => {\n // Backward compatibility: support deprecated 'type' prop\n const variant = variantProp ?? typeProp ?? 'default';\n\n // Show deprecation warning in development\n if (process.env.NODE_ENV === 'development' && typeProp) {\n console.warn(\n 'NotificationGlass: The \"type\" prop is deprecated. Use \"variant\" instead. Example: <NotificationGlass variant=\"destructive\" />'\n );\n }\n\n // Map variant to internal notification type\n const variantToType: Record<string, NotificationType> = {\n default: 'info',\n destructive: 'error',\n success: 'success',\n warning: 'warning',\n // Backward compatibility aliases\n info: 'info',\n error: 'error',\n };\n\n const effectiveType: NotificationType = variantToType[variant] || 'info';\n\n const { isHovered, hoverProps } = useHover();\n const Icon = NOTIFICATION_ICONS[effectiveType];\n const config = getTypeVars(effectiveType);\n\n const containerStyles: CSSProperties = {\n background: 'var(--notification-bg)',\n border: '1px solid var(--notification-border)',\n boxShadow: isHovered ? config.glow : 'var(--notification-shadow)',\n transform: isHovered ? 'translateY(-2px)' : 'translateY(0)',\n };\n\n const iconContainerStyles: CSSProperties = {\n background: config.iconBg,\n boxShadow: isHovered ? config.glow : 'none',\n };\n\n return (\n <div\n ref={ref}\n data-slot=\"notification\"\n className={cn(notificationVariants({ type: effectiveType }), className)}\n style={containerStyles}\n role=\"alert\"\n aria-live=\"polite\"\n onMouseEnter={hoverProps.onMouseEnter}\n onMouseLeave={hoverProps.onMouseLeave}\n {...props}\n >\n {/* Icon with glow */}\n <div\n className=\"w-8 h-8 md:w-10 md:h-10 rounded-xl flex items-center justify-center shrink-0\"\n style={iconContainerStyles}\n >\n <Icon className=\"w-4 h-4 md:w-5 md:h-5\" style={{ color: config.color }} />\n </div>\n\n {/* Content */}\n <div className=\"flex-1 min-w-0\">\n <p\n className=\"font-semibold text-xs md:text-sm mb-0.5 md:mb-1\"\n style={{ color: 'var(--text-primary)' }}\n >\n {title}\n </p>\n <p className=\"text-xs md:text-sm\" style={{ color: 'var(--text-secondary)' }}>\n {message}\n </p>\n </div>\n\n {/* Close button */}\n <button\n onClick={onClose}\n className=\"p-1 md:p-1.5 rounded-lg shrink-0\"\n style={{ color: 'var(--text-muted)' }}\n type=\"button\"\n aria-label=\"Close notification\"\n >\n <X className={ICON_SIZES.md} />\n </button>\n </div>\n );\n }\n);\n\nNotificationGlass.displayName = 'NotificationGlass';\n"
|
|
23
23
|
}
|
|
24
24
|
],
|
|
25
25
|
"categories": [
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
{
|
|
16
16
|
"path": "components/glass/ui/popover-glass.tsx",
|
|
17
17
|
"type": "registry:component",
|
|
18
|
-
"content": "/**\n * PopoverGlass Component\n *\n * Floating glass-themed container for tooltips, dropdowns, and overlays with:\n * - Theme-aware styling (glass/light/aurora)\n * - Smooth animations with fade-in effect\n * - Arrow pointer with glass styling\n * - ESC key and click-outside to close\n * - Focus trap for accessibility\n * - All position/alignment options (top/right/bottom/left × start/center/end)\n *\n * @example Compound API (recommended)\n * ```tsx\n * <PopoverGlass>\n * <PopoverGlassTrigger asChild>\n * <ButtonGlass>Open</ButtonGlass>\n * </PopoverGlassTrigger>\n * <PopoverGlassContent side=\"top\">\n * <div className=\"p-4\">\n * <h3 style={{ color: 'var(--text-primary)' }}>Title</h3>\n * <p style={{ color: 'var(--text-secondary)' }}>Content</p>\n * </div>\n * </PopoverGlassContent>\n * </PopoverGlass>\n * ```\n *\n * @example Legacy API (backward compatible)\n * ```tsx\n * <PopoverGlassLegacy\n * trigger={<ButtonGlass>Open</ButtonGlass>}\n * side=\"top\"\n * >\n * <div className=\"p-4\">Content</div>\n * </PopoverGlassLegacy>\n * ```\n */\n\n'use client';\n\nimport * as React from 'react';\nimport * as PopoverPrimitive from '@radix-ui/react-popover';\nimport { cn } from '@/lib/utils';\nimport '@/glass-theme.css';\n\n// ========================================\n// COMPOUND COMPONENT: ROOT\n// ========================================\n\nconst PopoverGlassRoot = PopoverPrimitive.Root;\n\n// ========================================\n// COMPOUND COMPONENT: TRIGGER\n// ========================================\n\nconst PopoverGlassTrigger = PopoverPrimitive.Trigger;\n\n// ========================================\n// COMPOUND COMPONENT: ANCHOR\n// ========================================\n\nconst PopoverGlassAnchor = PopoverPrimitive.Anchor;\n\n// ========================================\n// COMPOUND COMPONENT: CONTENT\n// ========================================\n\ninterface PopoverGlassContentProps extends React.ComponentPropsWithoutRef<\n typeof PopoverPrimitive.Content\n> {\n /** Whether to show the arrow pointer */\n showArrow?: boolean;\n}\n\nconst PopoverGlassContent = React.forwardRef<\n React.ElementRef<typeof PopoverPrimitive.Content>,\n PopoverGlassContentProps\n>(({ className, align = 'center', sideOffset = 8, showArrow = true, children, ...props }, ref) => {\n // Popover content styles with CSS variables\n const popoverStyles: React.CSSProperties = {\n background: 'var(--popover-bg)',\n border: '1px solid var(--popover-border)',\n boxShadow: 'var(--popover-shadow)',\n backdropFilter: 'blur(var(--blur-md))',\n WebkitBackdropFilter: 'blur(var(--blur-md))',\n };\n\n // Arrow styles\n const arrowStyles: React.CSSProperties = {\n fill: 'var(--popover-arrow-bg)',\n };\n\n return (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n ref={ref}\n align={align}\n sideOffset={sideOffset}\n className={cn(\n 'z-50003 rounded-2xl',\n 'animate-in fade-in-0 zoom-in-95 duration-200',\n 'data-[side=bottom]:slide-in-from-top-2',\n 'data-[side=top]:slide-in-from-bottom-2',\n 'data-[side=right]:slide-in-from-left-2',\n 'data-[side=left]:slide-in-from-right-2',\n 'outline-none',\n className\n )}\n style={popoverStyles}\n {...props}\n >\n {children}\n\n {showArrow && (\n <PopoverPrimitive.Arrow\n className=\"fill-current\"\n style={arrowStyles}\n width={16}\n height={8}\n />\n )}\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n );\n});\n\nPopoverGlassContent.displayName = 'PopoverGlassContent';\n\n// ========================================\n// LEGACY API (backward compatible)\n// ========================================\n\nexport interface PopoverGlassLegacyProps {\n /** The trigger element that opens the popover */\n readonly trigger: React.ReactNode;\n /** The content to display inside the popover */\n readonly children: React.ReactNode;\n /** The preferred side of the trigger to render against */\n readonly side?: 'top' | 'right' | 'bottom' | 'left';\n /** The preferred alignment against the trigger */\n readonly align?: 'start' | 'center' | 'end';\n /** The distance in pixels from the trigger */\n readonly sideOffset?: number;\n /** Controlled open state */\n readonly open?: boolean;\n /** Callback when open state changes */\n readonly onOpenChange?: (open: boolean) => void;\n /** Whether to show the arrow pointer */\n readonly showArrow?: boolean;\n /** Additional class name for the content wrapper */\n readonly className?: string;\n}\n\nconst PopoverGlassLegacy = React.forwardRef<HTMLDivElement, PopoverGlassLegacyProps>(\n (\n {\n trigger,\n children,\n side = 'bottom',\n align = 'center',\n sideOffset = 8,\n open,\n onOpenChange,\n showArrow = true,\n className,\n },\n ref\n ) => {\n return (\n <PopoverGlassRoot open={open} onOpenChange={onOpenChange}>\n <PopoverGlassTrigger asChild>{trigger}</PopoverGlassTrigger>\n <PopoverGlassContent\n ref={ref}\n side={side}\n align={align}\n sideOffset={sideOffset}\n showArrow={showArrow}\n className={className}\n >\n {children}\n </PopoverGlassContent>\n </PopoverGlassRoot>\n );\n }\n);\n\nPopoverGlassLegacy.displayName = 'PopoverGlassLegacy';\n\n// ========================================\n// EXPORTS\n// ========================================\n\n// Compound API (shadcn/ui pattern)\nexport const PopoverGlass = PopoverGlassRoot;\nexport { PopoverGlassTrigger, PopoverGlassContent, PopoverGlassAnchor };\n\n// Legacy API (backward compatible)\nexport { PopoverGlassLegacy };\n\n// For backward compatibility, also export as default\nexport { PopoverGlassLegacy as default };\n"
|
|
18
|
+
"content": "/**\n * PopoverGlass Component\n *\n * Floating glass-themed container for tooltips, dropdowns, and overlays with:\n * - Theme-aware styling (glass/light/aurora)\n * - Smooth animations with fade-in effect\n * - Arrow pointer with glass styling\n * - ESC key and click-outside to close\n * - Focus trap for accessibility\n * - All position/alignment options (top/right/bottom/left × start/center/end)\n *\n * @example Compound API (recommended)\n * ```tsx\n * <PopoverGlass>\n * <PopoverGlassTrigger asChild>\n * <ButtonGlass>Open</ButtonGlass>\n * </PopoverGlassTrigger>\n * <PopoverGlassContent side=\"top\">\n * <div className=\"p-4\">\n * <h3 style={{ color: 'var(--text-primary)' }}>Title</h3>\n * <p style={{ color: 'var(--text-secondary)' }}>Content</p>\n * </div>\n * </PopoverGlassContent>\n * </PopoverGlass>\n * ```\n *\n * @example Legacy API (backward compatible)\n * ```tsx\n * <PopoverGlassLegacy\n * trigger={<ButtonGlass>Open</ButtonGlass>}\n * side=\"top\"\n * >\n * <div className=\"p-4\">Content</div>\n * </PopoverGlassLegacy>\n * ```\n */\n\n'use client';\n\nimport * as React from 'react';\nimport * as PopoverPrimitive from '@radix-ui/react-popover';\nimport { cn } from '@/lib/utils';\nimport '@/glass-theme.css';\n\n// ========================================\n// COMPOUND COMPONENT: ROOT\n// ========================================\n\n// Note: PopoverPrimitive.Root is a context provider and doesn't render DOM,\n// so data-slot is applied to Content instead. This matches shadcn/ui pattern.\nconst PopoverGlassRoot = (props: React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Root>) => (\n <PopoverPrimitive.Root {...props} />\n);\nPopoverGlassRoot.displayName = 'PopoverGlass';\n\n// ========================================\n// COMPOUND COMPONENT: TRIGGER\n// ========================================\n\nconst PopoverGlassTrigger = React.forwardRef<\n React.ComponentRef<typeof PopoverPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Trigger>\n>((props, ref) => <PopoverPrimitive.Trigger data-slot=\"popover-trigger\" ref={ref} {...props} />);\nPopoverGlassTrigger.displayName = 'PopoverGlassTrigger';\n\n// ========================================\n// COMPOUND COMPONENT: ANCHOR\n// ========================================\n\nconst PopoverGlassAnchor = React.forwardRef<\n React.ComponentRef<typeof PopoverPrimitive.Anchor>,\n React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Anchor>\n>((props, ref) => <PopoverPrimitive.Anchor data-slot=\"popover-anchor\" ref={ref} {...props} />);\nPopoverGlassAnchor.displayName = 'PopoverGlassAnchor';\n\n// ========================================\n// COMPOUND COMPONENT: CONTENT\n// ========================================\n\ninterface PopoverGlassContentProps extends React.ComponentPropsWithoutRef<\n typeof PopoverPrimitive.Content\n> {\n /** Whether to show the arrow pointer */\n showArrow?: boolean;\n}\n\nconst PopoverGlassContent = React.forwardRef<\n React.ElementRef<typeof PopoverPrimitive.Content>,\n PopoverGlassContentProps\n>(({ className, align = 'center', sideOffset = 8, showArrow = true, children, ...props }, ref) => {\n // Popover content styles with CSS variables\n const popoverStyles: React.CSSProperties = {\n background: 'var(--popover-bg)',\n border: '1px solid var(--popover-border)',\n boxShadow: 'var(--popover-shadow)',\n backdropFilter: 'blur(var(--blur-md))',\n WebkitBackdropFilter: 'blur(var(--blur-md))',\n };\n\n // Arrow styles\n const arrowStyles: React.CSSProperties = {\n fill: 'var(--popover-arrow-bg)',\n };\n\n return (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n ref={ref}\n data-slot=\"popover-content\"\n align={align}\n sideOffset={sideOffset}\n className={cn(\n 'z-50003 rounded-2xl',\n 'animate-in fade-in-0 zoom-in-95 duration-200',\n 'data-[side=bottom]:slide-in-from-top-2',\n 'data-[side=top]:slide-in-from-bottom-2',\n 'data-[side=right]:slide-in-from-left-2',\n 'data-[side=left]:slide-in-from-right-2',\n 'outline-none',\n className\n )}\n style={popoverStyles}\n {...props}\n >\n {children}\n\n {showArrow && (\n <PopoverPrimitive.Arrow\n className=\"fill-current\"\n style={arrowStyles}\n width={16}\n height={8}\n />\n )}\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n );\n});\n\nPopoverGlassContent.displayName = 'PopoverGlassContent';\n\n// ========================================\n// LEGACY API (backward compatible)\n// ========================================\n\nexport interface PopoverGlassLegacyProps {\n /** The trigger element that opens the popover */\n readonly trigger: React.ReactNode;\n /** The content to display inside the popover */\n readonly children: React.ReactNode;\n /** The preferred side of the trigger to render against */\n readonly side?: 'top' | 'right' | 'bottom' | 'left';\n /** The preferred alignment against the trigger */\n readonly align?: 'start' | 'center' | 'end';\n /** The distance in pixels from the trigger */\n readonly sideOffset?: number;\n /** Controlled open state */\n readonly open?: boolean;\n /** Callback when open state changes */\n readonly onOpenChange?: (open: boolean) => void;\n /** Whether to show the arrow pointer */\n readonly showArrow?: boolean;\n /** Additional class name for the content wrapper */\n readonly className?: string;\n}\n\nconst PopoverGlassLegacy = React.forwardRef<HTMLDivElement, PopoverGlassLegacyProps>(\n (\n {\n trigger,\n children,\n side = 'bottom',\n align = 'center',\n sideOffset = 8,\n open,\n onOpenChange,\n showArrow = true,\n className,\n },\n ref\n ) => {\n return (\n <PopoverGlassRoot open={open} onOpenChange={onOpenChange}>\n <PopoverGlassTrigger asChild>{trigger}</PopoverGlassTrigger>\n <PopoverGlassContent\n ref={ref}\n side={side}\n align={align}\n sideOffset={sideOffset}\n showArrow={showArrow}\n className={className}\n >\n {children}\n </PopoverGlassContent>\n </PopoverGlassRoot>\n );\n }\n);\n\nPopoverGlassLegacy.displayName = 'PopoverGlassLegacy';\n\n// ========================================\n// EXPORTS\n// ========================================\n\n// Compound API (shadcn/ui pattern)\nexport const PopoverGlass = PopoverGlassRoot;\nexport { PopoverGlassTrigger, PopoverGlassContent, PopoverGlassAnchor };\n\n// Legacy API (backward compatible)\nexport { PopoverGlassLegacy };\n\n// For backward compatibility, also export as default\nexport { PopoverGlassLegacy as default };\n"
|
|
19
19
|
}
|
|
20
20
|
],
|
|
21
21
|
"categories": [
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
{
|
|
17
17
|
"path": "components/glass/specialized/progress-glass.tsx",
|
|
18
18
|
"type": "registry:component",
|
|
19
|
-
"content": "/**\n * ProgressGlass Component\n *\n * Glass-themed progress bar with:\n * - Theme-aware styling (glass/light/aurora)\n * - Gradient fill with glow\n * - Size variants\n * - Optional label\n */\n\nimport { forwardRef, type CSSProperties } from 'react';\nimport { type VariantProps } from 'class-variance-authority';\nimport { cn } from '@/lib/utils';\nimport { progressSizes, type ProgressGradient } from '@/lib/variants/progress-glass-variants';\nimport '@/glass-theme.css';\n\n// ========================================\n// PROPS INTERFACE\n// ========================================\n\nexport interface ProgressGlassProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'style'>, VariantProps<typeof progressSizes> {\n readonly value: number;\n readonly gradient?: ProgressGradient;\n readonly showLabel?: boolean;\n}\n\n// ========================================\n// COMPONENT\n// ========================================\n\n// Map gradient to existing metric color variables\nconst getGradientColor = (\n gradient: ProgressGradient = 'violet'\n): { colorVar: string; glowVar: string } => {\n const gradients: Record<ProgressGradient, { colorVar: string; glowVar: string }> = {\n violet: { colorVar: '--metric-default-text', glowVar: '--progress-glow-violet' }, // Uses blue metric color\n blue: { colorVar: '--metric-default-text', glowVar: '--progress-glow-blue' },\n cyan: { colorVar: '--metric-secondary-text', glowVar: '--progress-glow-cyan' },\n amber: { colorVar: '--metric-warning-text', glowVar: '--progress-glow-amber' },\n emerald: { colorVar: '--metric-success-text', glowVar: '--progress-glow-emerald' },\n rose: { colorVar: '--metric-destructive-text', glowVar: '--progress-glow-rose' },\n };\n return gradients[gradient] || gradients.violet;\n};\n\nexport const ProgressGlass = forwardRef<HTMLDivElement, ProgressGlassProps>(\n ({ className, size = 'md', value = 0, gradient = 'violet', showLabel, ...props }, ref) => {\n const clampedValue = Math.min(100, Math.max(0, value));\n const { colorVar, glowVar } = getGradientColor(gradient);\n\n const trackStyles: CSSProperties = {\n background: 'var(--progress-bg)',\n };\n\n const fillStyles: CSSProperties = {\n width: `${clampedValue}%`,\n background: `var(${colorVar})`,\n boxShadow: `var(${glowVar})`,\n };\n\n return (\n <div ref={ref} className={cn('w-full', className)} {...props}>\n {showLabel && (\n <div className=\"flex justify-between mb-1 md:mb-1.5\">\n <span className=\"text-(length:--font-size-2xs) md:text-xs text-(--text-muted)\">\n Progress\n </span>\n <span className=\"text-(length:--font-size-2xs) md:text-xs font-medium text-(--text-secondary)\">\n {clampedValue}%\n </span>\n </div>\n )}\n <div className={cn(progressSizes({ size }))} style={trackStyles}>\n <div\n className=\"h-full rounded-full transition-all duration-700 ease-out\"\n style={fillStyles}\n role=\"progressbar\"\n aria-valuenow={clampedValue}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={`Progress: ${clampedValue}%`}\n />\n </div>\n </div>\n );\n }\n);\n\nProgressGlass.displayName = 'ProgressGlass';\n"
|
|
19
|
+
"content": "/**\n * ProgressGlass Component\n *\n * Glass-themed progress bar with:\n * - Theme-aware styling (glass/light/aurora)\n * - Gradient fill with glow\n * - Size variants\n * - Optional label\n */\n\nimport { forwardRef, type CSSProperties } from 'react';\nimport { type VariantProps } from 'class-variance-authority';\nimport { cn } from '@/lib/utils';\nimport { progressSizes, type ProgressGradient } from '@/lib/variants/progress-glass-variants';\nimport '@/glass-theme.css';\n\n// ========================================\n// PROPS INTERFACE\n// ========================================\n\nexport interface ProgressGlassProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'style'>, VariantProps<typeof progressSizes> {\n readonly value: number;\n readonly gradient?: ProgressGradient;\n readonly showLabel?: boolean;\n}\n\n// ========================================\n// COMPONENT\n// ========================================\n\n// Map gradient to existing metric color variables\nconst getGradientColor = (\n gradient: ProgressGradient = 'violet'\n): { colorVar: string; glowVar: string } => {\n const gradients: Record<ProgressGradient, { colorVar: string; glowVar: string }> = {\n violet: { colorVar: '--metric-default-text', glowVar: '--progress-glow-violet' }, // Uses blue metric color\n blue: { colorVar: '--metric-default-text', glowVar: '--progress-glow-blue' },\n cyan: { colorVar: '--metric-secondary-text', glowVar: '--progress-glow-cyan' },\n amber: { colorVar: '--metric-warning-text', glowVar: '--progress-glow-amber' },\n emerald: { colorVar: '--metric-success-text', glowVar: '--progress-glow-emerald' },\n rose: { colorVar: '--metric-destructive-text', glowVar: '--progress-glow-rose' },\n };\n return gradients[gradient] || gradients.violet;\n};\n\nexport const ProgressGlass = forwardRef<HTMLDivElement, ProgressGlassProps>(\n ({ className, size = 'md', value = 0, gradient = 'violet', showLabel, ...props }, ref) => {\n const clampedValue = Math.min(100, Math.max(0, value));\n const { colorVar, glowVar } = getGradientColor(gradient);\n\n const trackStyles: CSSProperties = {\n background: 'var(--progress-bg)',\n };\n\n const fillStyles: CSSProperties = {\n width: `${clampedValue}%`,\n background: `var(${colorVar})`,\n boxShadow: `var(${glowVar})`,\n };\n\n return (\n <div ref={ref} data-slot=\"progress\" className={cn('w-full', className)} {...props}>\n {showLabel && (\n <div className=\"flex justify-between mb-1 md:mb-1.5\">\n <span className=\"text-(length:--font-size-2xs) md:text-xs text-(--text-muted)\">\n Progress\n </span>\n <span className=\"text-(length:--font-size-2xs) md:text-xs font-medium text-(--text-secondary)\">\n {clampedValue}%\n </span>\n </div>\n )}\n <div className={cn(progressSizes({ size }))} style={trackStyles}>\n <div\n data-slot=\"progress-indicator\"\n className=\"h-full rounded-full transition-all duration-700 ease-out\"\n style={fillStyles}\n role=\"progressbar\"\n aria-valuenow={clampedValue}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={`Progress: ${clampedValue}%`}\n />\n </div>\n </div>\n );\n }\n);\n\nProgressGlass.displayName = 'ProgressGlass';\n"
|
|
20
20
|
}
|
|
21
21
|
],
|
|
22
22
|
"categories": [
|
package/dist/r/registry.json
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"name": "tabs-glass",
|
|
20
20
|
"type": "registry:ui",
|
|
21
21
|
"title": "Tabs Glass",
|
|
22
|
-
"description": "TabsGlass Component (
|
|
22
|
+
"description": "TabsGlass Component (Radix UI based)"
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
25
|
"name": "stepper-glass",
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
"name": "checkbox-glass",
|
|
98
98
|
"type": "registry:ui",
|
|
99
99
|
"title": "Checkbox Glass",
|
|
100
|
-
"description": "Glass-themed checkbox with:"
|
|
100
|
+
"description": "Glass-themed checkbox built on Radix UI primitives with:"
|
|
101
101
|
},
|
|
102
102
|
{
|
|
103
103
|
"name": "card-glass",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
{
|
|
17
17
|
"path": "components/glass/ui/skeleton-glass.tsx",
|
|
18
18
|
"type": "registry:component",
|
|
19
|
-
"content": "/**\n * SkeletonGlass Component\n *\n * Glass-themed loading skeleton with:\n * - Theme-aware styling (glass/light/aurora)\n * - Shimmer animation\n * - Variant presets (text, title, avatar, thumbnail, card)\n */\n\nimport { forwardRef, type CSSProperties } from 'react';\nimport { type VariantProps } from 'class-variance-authority';\nimport { cn } from '@/lib/utils';\nimport { skeletonVariants } from '@/lib/variants/skeleton-glass-variants';\nimport '@/glass-theme.css';\n\n// ========================================\n// PROPS INTERFACE\n// ========================================\n\nexport interface SkeletonGlassProps\n extends React.HTMLAttributes<HTMLDivElement
|
|
19
|
+
"content": "/**\n * SkeletonGlass Component\n *\n * Glass-themed loading skeleton with:\n * - Theme-aware styling (glass/light/aurora)\n * - Shimmer animation\n * - Variant presets (text, title, avatar, thumbnail, card)\n */\n\nimport { forwardRef, type CSSProperties } from 'react';\nimport { type VariantProps } from 'class-variance-authority';\nimport { cn } from '@/lib/utils';\nimport { skeletonVariants } from '@/lib/variants/skeleton-glass-variants';\nimport '@/glass-theme.css';\n\n// ========================================\n// PROPS INTERFACE\n// ========================================\n\nexport interface SkeletonGlassProps\n extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof skeletonVariants> {\n readonly width?: string | number;\n readonly height?: string | number;\n}\n\n// ========================================\n// COMPONENT\n// ========================================\n\nexport const SkeletonGlass = forwardRef<HTMLDivElement, SkeletonGlassProps>(\n ({ className, variant = 'text', width, height, style, ...props }, ref) => {\n const skeletonStyles: CSSProperties = {\n width,\n height,\n background:\n 'linear-gradient(90deg, var(--skeleton-bg) 25%, var(--skeleton-shine) 50%, var(--skeleton-bg) 75%)',\n backgroundSize: '200% 100%',\n animation: 'skeleton-loading 1.5s infinite',\n ...style,\n };\n\n return (\n <div\n ref={ref}\n data-slot=\"skeleton\"\n className={cn(skeletonVariants({ variant }), className)}\n style={skeletonStyles}\n aria-hidden=\"true\"\n {...props}\n />\n );\n }\n);\n\nSkeletonGlass.displayName = 'SkeletonGlass';\n"
|
|
20
20
|
}
|
|
21
21
|
],
|
|
22
22
|
"categories": [
|
package/dist/r/slider-glass.json
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
{
|
|
17
17
|
"path": "components/glass/ui/slider-glass.tsx",
|
|
18
18
|
"type": "registry:component",
|
|
19
|
-
"content": "/**\n * SliderGlass Component\n *\n * Glass-themed range slider built on Radix UI with shadcn/ui compatible API:\n * - Theme-aware styling (glass/light/aurora)\n * - Glow effect on hover/drag\n * - Gradient fill (glass theme)\n * - Range slider support (multiple thumbs)\n * - Optional label and value display\n *\n * **shadcn/ui compatible props:**\n * - `value` / `defaultValue` - Array of values (supports range)\n * - `onValueChange` - Callback when values change\n * - `onValueCommit` - Callback when interaction ends\n *\n * @example\n * ```tsx\n * // Single value (controlled)\n * <SliderGlass value={[50]} onValueChange={setValue} />\n *\n * // Range slider\n * <SliderGlass defaultValue={[25, 75]} />\n *\n * // With label and value display\n * <SliderGlass value={[50]} onValueChange={setValue} label=\"Volume\" showValue />\n * ```\n */\n\nimport { forwardRef, type CSSProperties, type ComponentPropsWithoutRef } from 'react';\nimport * as SliderPrimitive from '@radix-ui/react-slider';\nimport { cn } from '@/lib/utils';\nimport { FormFieldWrapper } from '@/components/glass/primitives';\nimport '@/glass-theme.css';\n\n// ========================================\n// PROPS INTERFACE\n// ========================================\n\nexport interface SliderGlassProps extends Omit<\n ComponentPropsWithoutRef<typeof SliderPrimitive.Root>,\n 'value' | 'defaultValue' | 'onValueChange'\n> {\n /**\n * Controlled value (shadcn/ui compatible - array for range support)\n */\n readonly value?: number[];\n /**\n * Default value for uncontrolled usage (array for range support)\n */\n readonly defaultValue?: number[];\n /**\n * Callback when value changes (shadcn/ui compatible)\n */\n readonly onValueChange?: (value: number[]) => void;\n /**\n * Callback when interaction ends (mouse up / touch end)\n */\n readonly onValueCommit?: (value: number[]) => void;\n /**\n * Show current value(s) next to label\n */\n readonly showValue?: boolean;\n /**\n * Optional label text\n */\n readonly label?: string;\n /**\n * Error message to display\n */\n readonly error?: string;\n /**\n * Success message to display\n */\n readonly success?: string;\n}\n\n// ========================================\n// COMPONENT\n// ========================================\n\nexport const SliderGlass = forwardRef<\n React.ComponentRef<typeof SliderPrimitive.Root>,\n SliderGlassProps\n>(\n (\n {\n className,\n value,\n defaultValue,\n onValueChange,\n onValueCommit,\n min = 0,\n max = 100,\n step = 1,\n showValue,\n label,\n error,\n success,\n disabled,\n orientation = 'horizontal',\n ...props\n },\n ref\n ) => {\n // Determine current values for rendering thumbs and display\n const currentValue = value ?? defaultValue ?? [min];\n\n // Format value display\n const formatValueDisplay = (values: number[]) => {\n if (values.length === 1) {\n return `${values[0]}`;\n }\n return `${values[0]} - ${values[values.length - 1]}`;\n };\n\n // Track styles via CSS variables\n const trackStyles: CSSProperties = {\n background: 'var(--slider-track)',\n };\n\n // Range (fill) styles via CSS variables\n const rangeStyles: CSSProperties = {\n background: 'var(--slider-fill)',\n };\n\n // Thumb styles via CSS variables\n const thumbStyles: CSSProperties = {\n background: 'var(--slider-thumb)',\n border: '2px solid var(--slider-thumb-border)',\n };\n\n // Custom label with value display - only used when showValue is true\n const customLabel =\n (label && showValue) || (!label && showValue) ? (\n <div className=\"flex justify-between mb-1.5 md:mb-2\">\n {label && (\n <label\n className=\"text-xs md:text-sm font-medium\"\n style={{ color: 'var(--text-secondary)' }}\n >\n {label}\n </label>\n )}\n <span\n className=\"text-xs md:text-sm font-medium tabular-nums\"\n style={{ color: 'var(--text-secondary)' }}\n >\n {formatValueDisplay(currentValue)}\n </span>\n </div>\n ) : undefined;\n\n return (\n <FormFieldWrapper\n label={showValue ? undefined : label}\n error={error}\n success={success}\n className={cn('w-full', className)}\n >\n {customLabel}\n <SliderPrimitive.Root\n ref={ref}\n value={value}\n defaultValue={defaultValue}\n onValueChange={onValueChange}\n onValueCommit={onValueCommit}\n min={min}\n max={max}\n step={step}\n disabled={disabled}\n orientation={orientation}\n className={cn(\n 'relative flex touch-none select-none',\n orientation === 'horizontal'\n ? 'w-full h-8 md:h-6 items-center'\n : 'flex-col h-full w-8 md:w-6 justify-center',\n disabled && 'opacity-50 cursor-not-allowed',\n 'group'\n )}\n {...props}\n >\n <SliderPrimitive.Track\n className={cn(\n 'relative grow rounded-full',\n orientation === 'horizontal' ? 'h-2.5 md:h-2 w-full' : 'w-2.5 md:w-2 h-full'\n )}\n style={trackStyles}\n >\n <SliderPrimitive.Range\n className={cn(\n 'absolute rounded-full transition-shadow duration-150',\n orientation === 'horizontal' ? 'h-full' : 'w-full',\n 'group-hover:shadow-(--slider-fill-glow)',\n 'group-active:shadow-(--slider-fill-glow)'\n )}\n style={rangeStyles}\n />\n </SliderPrimitive.Track>\n {currentValue.map((_, index) => (\n <SliderPrimitive.Thumb\n key={index}\n className={cn(\n 'block rounded-full shadow-md transition-all duration-150',\n 'w-6 h-6 md:w-5 md:h-5',\n 'hover:scale-105',\n 'focus-visible:outline-none focus-visible:shadow-(--focus-glow)',\n 'active:scale-110',\n disabled && 'pointer-events-none'\n )}\n style={thumbStyles}\n aria-label={\n label\n ? currentValue.length > 1\n ? `${label} thumb ${index + 1}`\n : label\n : `Slider thumb ${index + 1}`\n }\n />\n ))}\n </SliderPrimitive.Root>\n </FormFieldWrapper>\n );\n }\n);\n\nSliderGlass.displayName = 'SliderGlass';\n"
|
|
19
|
+
"content": "/**\n * SliderGlass Component\n *\n * Glass-themed range slider built on Radix UI with shadcn/ui compatible API:\n * - Theme-aware styling (glass/light/aurora)\n * - Glow effect on hover/drag\n * - Gradient fill (glass theme)\n * - Range slider support (multiple thumbs)\n * - Optional label and value display\n *\n * **shadcn/ui compatible props:**\n * - `value` / `defaultValue` - Array of values (supports range)\n * - `onValueChange` - Callback when values change\n * - `onValueCommit` - Callback when interaction ends\n *\n * @example\n * ```tsx\n * // Single value (controlled)\n * <SliderGlass value={[50]} onValueChange={setValue} />\n *\n * // Range slider\n * <SliderGlass defaultValue={[25, 75]} />\n *\n * // With label and value display\n * <SliderGlass value={[50]} onValueChange={setValue} label=\"Volume\" showValue />\n * ```\n */\n\nimport { forwardRef, type CSSProperties, type ComponentPropsWithoutRef } from 'react';\nimport * as SliderPrimitive from '@radix-ui/react-slider';\nimport { cn } from '@/lib/utils';\nimport { FormFieldWrapper } from '@/components/glass/primitives';\nimport '@/glass-theme.css';\n\n// ========================================\n// PROPS INTERFACE\n// ========================================\n\nexport interface SliderGlassProps extends Omit<\n ComponentPropsWithoutRef<typeof SliderPrimitive.Root>,\n 'value' | 'defaultValue' | 'onValueChange'\n> {\n /**\n * Controlled value (shadcn/ui compatible - array for range support)\n */\n readonly value?: number[];\n /**\n * Default value for uncontrolled usage (array for range support)\n */\n readonly defaultValue?: number[];\n /**\n * Callback when value changes (shadcn/ui compatible)\n */\n readonly onValueChange?: (value: number[]) => void;\n /**\n * Callback when interaction ends (mouse up / touch end)\n */\n readonly onValueCommit?: (value: number[]) => void;\n /**\n * Show current value(s) next to label\n */\n readonly showValue?: boolean;\n /**\n * Optional label text\n */\n readonly label?: string;\n /**\n * Error message to display\n */\n readonly error?: string;\n /**\n * Success message to display\n */\n readonly success?: string;\n}\n\n// ========================================\n// COMPONENT\n// ========================================\n\nexport const SliderGlass = forwardRef<\n React.ComponentRef<typeof SliderPrimitive.Root>,\n SliderGlassProps\n>(\n (\n {\n className,\n value,\n defaultValue,\n onValueChange,\n onValueCommit,\n min = 0,\n max = 100,\n step = 1,\n showValue,\n label,\n error,\n success,\n disabled,\n orientation = 'horizontal',\n ...props\n },\n ref\n ) => {\n // Determine current values for rendering thumbs and display\n const currentValue = value ?? defaultValue ?? [min];\n\n // Format value display\n const formatValueDisplay = (values: number[]) => {\n if (values.length === 1) {\n return `${values[0]}`;\n }\n return `${values[0]} - ${values[values.length - 1]}`;\n };\n\n // Track styles via CSS variables\n const trackStyles: CSSProperties = {\n background: 'var(--slider-track)',\n };\n\n // Range (fill) styles via CSS variables\n const rangeStyles: CSSProperties = {\n background: 'var(--slider-fill)',\n };\n\n // Thumb styles via CSS variables\n const thumbStyles: CSSProperties = {\n background: 'var(--slider-thumb)',\n border: '2px solid var(--slider-thumb-border)',\n };\n\n // Custom label with value display - only used when showValue is true\n const customLabel =\n (label && showValue) || (!label && showValue) ? (\n <div className=\"flex justify-between mb-1.5 md:mb-2\">\n {label && (\n <label\n className=\"text-xs md:text-sm font-medium\"\n style={{ color: 'var(--text-secondary)' }}\n >\n {label}\n </label>\n )}\n <span\n className=\"text-xs md:text-sm font-medium tabular-nums\"\n style={{ color: 'var(--text-secondary)' }}\n >\n {formatValueDisplay(currentValue)}\n </span>\n </div>\n ) : undefined;\n\n return (\n <FormFieldWrapper\n label={showValue ? undefined : label}\n error={error}\n success={success}\n className={cn('w-full', className)}\n >\n {customLabel}\n <SliderPrimitive.Root\n ref={ref}\n data-slot=\"slider\"\n value={value}\n defaultValue={defaultValue}\n onValueChange={onValueChange}\n onValueCommit={onValueCommit}\n min={min}\n max={max}\n step={step}\n disabled={disabled}\n orientation={orientation}\n className={cn(\n 'relative flex touch-none select-none',\n orientation === 'horizontal'\n ? 'w-full h-8 md:h-6 items-center'\n : 'flex-col h-full w-8 md:w-6 justify-center',\n disabled && 'opacity-50 cursor-not-allowed',\n 'group'\n )}\n {...props}\n >\n <SliderPrimitive.Track\n data-slot=\"slider-track\"\n className={cn(\n 'relative grow rounded-full',\n orientation === 'horizontal' ? 'h-2.5 md:h-2 w-full' : 'w-2.5 md:w-2 h-full'\n )}\n style={trackStyles}\n >\n <SliderPrimitive.Range\n data-slot=\"slider-range\"\n className={cn(\n 'absolute rounded-full transition-shadow duration-150',\n orientation === 'horizontal' ? 'h-full' : 'w-full',\n 'group-hover:shadow-(--slider-fill-glow)',\n 'group-active:shadow-(--slider-fill-glow)'\n )}\n style={rangeStyles}\n />\n </SliderPrimitive.Track>\n {currentValue.map((_, index) => (\n <SliderPrimitive.Thumb\n key={index}\n data-slot=\"slider-thumb\"\n className={cn(\n 'block rounded-full shadow-md transition-all duration-150',\n 'w-6 h-6 md:w-5 md:h-5',\n 'hover:scale-105',\n 'focus-visible:outline-none focus-visible:shadow-(--focus-glow)',\n 'active:scale-110',\n disabled && 'pointer-events-none'\n )}\n style={thumbStyles}\n aria-label={\n label\n ? currentValue.length > 1\n ? `${label} thumb ${index + 1}`\n : label\n : `Slider thumb ${index + 1}`\n }\n />\n ))}\n </SliderPrimitive.Root>\n </FormFieldWrapper>\n );\n }\n);\n\nSliderGlass.displayName = 'SliderGlass';\n"
|
|
20
20
|
}
|
|
21
21
|
],
|
|
22
22
|
"categories": [
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
{
|
|
17
17
|
"path": "components/glass/ui/stepper-glass.tsx",
|
|
18
18
|
"type": "registry:component",
|
|
19
|
-
"content": "/* eslint-disable react-refresh/only-export-components */\n/**\n * StepperGlass Component (Compound API)\n *\n * Glass-themed step indicator with:\n * - Theme-aware styling (glass/light/aurora)\n * - Horizontal and vertical orientations\n * - Numbered, icon, and dots variants\n * - Linear mode (lock future steps)\n * - Animated connector lines\n * - Compound component API for advanced composition\n *\n * @example\n * ```tsx\n * <StepperGlass.Root value=\"step2\" onValueChange={setStep}>\n * <StepperGlass.List>\n * <StepperGlass.Step value=\"step1\" label=\"Account\" description=\"Create your account\" />\n * <StepperGlass.Step value=\"step2\" label=\"Profile\" description=\"Setup your profile\" />\n * <StepperGlass.Step value=\"step3\" label=\"Complete\" description=\"Finish setup\" />\n * </StepperGlass.List>\n * <StepperGlass.Content value=\"step1\">Step 1 content</StepperGlass.Content>\n * <StepperGlass.Content value=\"step2\">Step 2 content</StepperGlass.Content>\n * <StepperGlass.Content value=\"step3\">Step 3 content</StepperGlass.Content>\n * </StepperGlass.Root>\n * ```\n *\n * @accessibility\n * - **Keyboard Navigation:** Arrow keys navigate between steps (WCAG 2.1.1)\n * - **Focus Management:** Visible focus ring using `--focus-glow` (WCAG 2.4.7)\n * - **Screen Readers:** Uses `role=\"tablist\"`, `role=\"tab\"` (WCAG 4.1.3)\n * - **ARIA Attributes:** `aria-current=\"step\"`, `aria-disabled` for state\n * - **Touch Targets:** 44x44px minimum touch targets (WCAG 2.5.5)\n * - **Color Contrast:** All states meet WCAG AA 4.5:1 ratio\n * - **Motion:** Respects `prefers-reduced-motion`\n */\n\nimport {\n forwardRef,\n createContext,\n useContext,\n useMemo,\n useState,\n useCallback,\n useLayoutEffect,\n type CSSProperties,\n type FC,\n type ReactNode,\n} from 'react';\nimport { cn } from '@/lib/utils';\nimport { useFocus } from '@/lib/hooks/use-focus';\nimport { Check } from 'lucide-react';\nimport {\n stepperRootVariants,\n stepperListVariants,\n stepperStepContainerVariants,\n stepperIndicatorVariants,\n stepperConnectorVariants,\n stepperLabelVariants,\n stepperDescriptionVariants,\n stepperContentVariants,\n type StepperOrientation,\n type StepperVariant,\n type StepperSize,\n type StepStatus,\n} from '@/lib/variants/stepper-glass-variants';\nimport '@/glass-theme.css';\n\n// ========================================\n// CONTEXT\n// ========================================\n\ninterface StepperContextValue {\n value: string;\n onValueChange?: (value: string) => void;\n orientation: StepperOrientation;\n variant: StepperVariant;\n size: StepperSize;\n linear: boolean;\n steps: string[];\n registerStep: (value: string, index: number) => void;\n unregisterStep: (value: string) => void;\n}\n\nconst StepperContext = createContext<StepperContextValue | null>(null);\n\nconst useStepperContext = () => {\n const context = useContext(StepperContext);\n if (!context) {\n throw new Error('Stepper compound components must be used within StepperGlass.Root');\n }\n return context;\n};\n\n// ========================================\n// UTILITY: GET STEP STATUS\n// ========================================\n\nfunction getStepStatus(\n stepValue: string,\n currentValue: string,\n steps: string[],\n linear: boolean,\n disabled?: boolean\n): StepStatus {\n if (disabled) return 'disabled';\n\n const stepIndex = steps.indexOf(stepValue);\n const currentIndex = steps.indexOf(currentValue);\n\n if (stepIndex === -1 || currentIndex === -1) return 'pending';\n if (stepIndex === currentIndex) return 'active';\n if (stepIndex < currentIndex) return 'completed';\n if (linear && stepIndex > currentIndex) return 'disabled';\n return 'pending';\n}\n\n// ========================================\n// ROOT COMPONENT\n// ========================================\n\ninterface StepperRootProps {\n /** Current active step value */\n value: string;\n /** Callback when step value changes */\n onValueChange?: (value: string) => void;\n /** Orientation of the stepper */\n orientation?: StepperOrientation;\n /** Visual variant */\n variant?: StepperVariant;\n /** Size of step indicators */\n size?: StepperSize;\n /** Lock future steps (require sequential completion) */\n linear?: boolean;\n /** Child components */\n children: ReactNode;\n /** Optional className */\n className?: string;\n}\n\nconst StepperRoot: FC<StepperRootProps> = ({\n value,\n onValueChange,\n orientation = 'horizontal',\n variant = 'numbered',\n size = 'md',\n linear = false,\n children,\n className,\n}) => {\n const [steps, setSteps] = useState<string[]>([]);\n\n const registerStep = useCallback((stepValue: string, index: number) => {\n setSteps((prev) => {\n if (prev.includes(stepValue)) return prev;\n const newSteps = [...prev];\n // Insert at correct position to maintain order\n newSteps.splice(index, 0, stepValue);\n return newSteps;\n });\n }, []);\n\n const unregisterStep = useCallback((stepValue: string) => {\n setSteps((prev) => prev.filter((s) => s !== stepValue));\n }, []);\n\n const contextValue = useMemo(\n () => ({\n value,\n onValueChange,\n orientation,\n variant,\n size,\n linear,\n steps,\n registerStep,\n unregisterStep,\n }),\n [value, onValueChange, orientation, variant, size, linear, steps, registerStep, unregisterStep]\n );\n\n return (\n <StepperContext.Provider value={contextValue}>\n <div\n className={cn(stepperRootVariants({ orientation }), className)}\n aria-label=\"Progress steps\"\n >\n {children}\n </div>\n </StepperContext.Provider>\n );\n};\n\n// ========================================\n// LIST COMPONENT\n// ========================================\n\ninterface StepperListProps extends React.HTMLAttributes<HTMLDivElement> {\n children: ReactNode;\n className?: string;\n}\n\nconst StepperList = forwardRef<HTMLDivElement, StepperListProps>(\n ({ children, className, ...props }, ref) => {\n const { orientation } = useStepperContext();\n\n return (\n <div\n ref={ref}\n role=\"tablist\"\n aria-orientation={orientation}\n className={cn(stepperListVariants({ orientation }), className)}\n {...props}\n >\n {children}\n </div>\n );\n }\n);\n\nStepperList.displayName = 'StepperList';\n\n// ========================================\n// STEP COMPONENT\n// ========================================\n\ninterface StepperStepProps {\n /** Unique value for this step */\n value: string;\n /** Step label (required for accessibility) */\n label: string;\n /** Optional description */\n description?: string;\n /** Custom icon (for icon variant) */\n icon?: ReactNode;\n /** Completed icon override */\n completedIcon?: ReactNode;\n /** Force disabled state */\n disabled?: boolean;\n /** Optional className */\n className?: string;\n /** Step index for ordering (auto-detected) */\n index?: number;\n}\n\nconst StepperStep = forwardRef<HTMLButtonElement, StepperStepProps>(\n (\n {\n value: stepValue,\n label,\n description,\n icon,\n completedIcon,\n disabled: forcedDisabled,\n className,\n index: providedIndex,\n },\n ref\n ) => {\n const {\n value: currentValue,\n onValueChange,\n orientation,\n variant,\n size,\n linear,\n steps,\n registerStep,\n unregisterStep,\n } = useStepperContext();\n\n const { isFocusVisible, focusProps } = useFocus({ focusVisible: true });\n\n // Track mount order for step registration\n const [mountIndex] = useState(() => providedIndex ?? Date.now());\n\n // Register step on mount\n // Use useLayoutEffect to register before paint\n useLayoutEffect(() => {\n registerStep(stepValue, mountIndex);\n return () => unregisterStep(stepValue);\n }, [stepValue, mountIndex, registerStep, unregisterStep]);\n\n const status = getStepStatus(stepValue, currentValue, steps, linear, forcedDisabled);\n const stepIndex = steps.indexOf(stepValue);\n const isLast = stepIndex === steps.length - 1;\n const isClickable = status !== 'disabled';\n\n // Styles based on status\n const indicatorStyles: CSSProperties = {\n background:\n status === 'completed'\n ? 'var(--stepper-step-completed-bg)'\n : status === 'active'\n ? 'var(--stepper-step-active-bg)'\n : status === 'disabled'\n ? 'var(--stepper-step-disabled-bg)'\n : 'var(--stepper-step-bg)',\n border: `2px solid ${\n status === 'completed'\n ? 'var(--stepper-step-completed-border)'\n : status === 'active'\n ? 'var(--stepper-step-active-border)'\n : status === 'disabled'\n ? 'var(--stepper-step-disabled-border)'\n : 'var(--stepper-step-border)'\n }`,\n color:\n status === 'completed'\n ? 'var(--stepper-step-completed-text)'\n : status === 'active'\n ? 'var(--stepper-step-active-text)'\n : status === 'disabled'\n ? 'var(--stepper-step-disabled-text)'\n : 'var(--stepper-step-text)',\n boxShadow:\n status === 'active'\n ? 'var(--stepper-step-active-glow)'\n : status === 'completed'\n ? 'var(--stepper-step-glow)'\n : isFocusVisible\n ? 'var(--focus-glow)'\n : 'none',\n backdropFilter: 'blur(var(--blur-sm))',\n };\n\n const connectorStyles: CSSProperties = {\n background:\n stepIndex < steps.indexOf(currentValue)\n ? 'var(--stepper-connector-active-bg)'\n : 'var(--stepper-connector-bg)',\n };\n\n const labelStyles: CSSProperties = {\n color:\n status === 'active' || status === 'completed'\n ? 'var(--stepper-label-text)'\n : 'var(--stepper-description-text)',\n };\n\n const descriptionStyles: CSSProperties = {\n color: 'var(--stepper-description-text)',\n };\n\n // Render indicator content\n const renderIndicatorContent = () => {\n if (status === 'completed') {\n if (completedIcon) return completedIcon;\n return <Check className=\"w-4 h-4\" />;\n }\n if (variant === 'icon' && icon) return icon;\n if (variant === 'dots') return null;\n // Numbered variant\n return stepIndex >= 0 ? stepIndex + 1 : '';\n };\n\n const handleClick = () => {\n if (isClickable && onValueChange) {\n onValueChange(stepValue);\n }\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (!isClickable) return;\n\n const stepList = e.currentTarget.closest('[role=\"tablist\"]');\n if (!stepList) return;\n\n const allSteps = Array.from(\n stepList.querySelectorAll('[role=\"tab\"]:not([aria-disabled=\"true\"])')\n ) as HTMLButtonElement[];\n const currentIdx = allSteps.indexOf(e.currentTarget as HTMLButtonElement);\n\n let nextIdx = currentIdx;\n const isHorizontal = orientation === 'horizontal';\n\n switch (e.key) {\n case isHorizontal ? 'ArrowRight' : 'ArrowDown':\n e.preventDefault();\n nextIdx = (currentIdx + 1) % allSteps.length;\n break;\n case isHorizontal ? 'ArrowLeft' : 'ArrowUp':\n e.preventDefault();\n nextIdx = currentIdx - 1 < 0 ? allSteps.length - 1 : currentIdx - 1;\n break;\n case 'Home':\n e.preventDefault();\n nextIdx = 0;\n break;\n case 'End':\n e.preventDefault();\n nextIdx = allSteps.length - 1;\n break;\n default:\n return;\n }\n\n const nextStep = allSteps[nextIdx];\n if (nextStep) {\n nextStep.focus();\n const nextValue = nextStep.getAttribute('data-value');\n if (nextValue && onValueChange) {\n onValueChange(nextValue);\n }\n }\n };\n\n // For horizontal, we need step + connector inline\n // For vertical, step is a row with connector below\n if (orientation === 'horizontal') {\n return (\n <>\n <div className={cn(stepperStepContainerVariants({ orientation }), className)}>\n <button\n ref={ref}\n type=\"button\"\n role=\"tab\"\n aria-selected={status === 'active'}\n aria-disabled={!isClickable}\n aria-current={status === 'active' ? 'step' : undefined}\n data-value={stepValue}\n data-status={status}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n onFocus={focusProps.onFocus}\n onBlur={focusProps.onBlur}\n disabled={!isClickable}\n className={cn(\n stepperIndicatorVariants({ size, variant }),\n !isClickable && 'cursor-not-allowed opacity-60',\n isClickable && 'cursor-pointer hover:scale-105',\n // Ensure minimum touch target\n 'min-w-[44px] min-h-[44px]'\n )}\n style={indicatorStyles}\n >\n {renderIndicatorContent()}\n </button>\n\n {label && (\n <div className=\"flex flex-col items-center\">\n <span\n className={cn(stepperLabelVariants({ size, orientation }))}\n style={labelStyles}\n >\n {label}\n </span>\n {description && (\n <span\n className={cn(stepperDescriptionVariants({ size, orientation }))}\n style={descriptionStyles}\n >\n {description}\n </span>\n )}\n </div>\n )}\n </div>\n\n {/* Connector line between steps */}\n {!isLast && (\n <div\n className={cn(stepperConnectorVariants({ orientation }))}\n style={connectorStyles}\n aria-hidden=\"true\"\n />\n )}\n </>\n );\n }\n\n // Vertical orientation\n return (\n <div className=\"flex flex-col\">\n <div className={cn(stepperStepContainerVariants({ orientation }), className)}>\n <button\n ref={ref}\n type=\"button\"\n role=\"tab\"\n aria-selected={status === 'active'}\n aria-disabled={!isClickable}\n aria-current={status === 'active' ? 'step' : undefined}\n data-value={stepValue}\n data-status={status}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n onFocus={focusProps.onFocus}\n onBlur={focusProps.onBlur}\n disabled={!isClickable}\n className={cn(\n stepperIndicatorVariants({ size, variant }),\n !isClickable && 'cursor-not-allowed opacity-60',\n isClickable && 'cursor-pointer hover:scale-105',\n 'min-w-[44px] min-h-[44px]'\n )}\n style={indicatorStyles}\n >\n {renderIndicatorContent()}\n </button>\n\n {label && (\n <div className=\"flex flex-col justify-center\">\n <span className={cn(stepperLabelVariants({ size, orientation }))} style={labelStyles}>\n {label}\n </span>\n {description && (\n <span\n className={cn(stepperDescriptionVariants({ size, orientation }))}\n style={descriptionStyles}\n >\n {description}\n </span>\n )}\n </div>\n )}\n </div>\n\n {/* Vertical connector */}\n {!isLast && (\n <div\n className={cn(stepperConnectorVariants({ orientation }))}\n style={connectorStyles}\n aria-hidden=\"true\"\n />\n )}\n </div>\n );\n }\n);\n\nStepperStep.displayName = 'StepperStep';\n\n// ========================================\n// CONTENT COMPONENT\n// ========================================\n\ninterface StepperContentProps {\n /** Value of the step this content belongs to */\n value: string;\n /** Content to display when step is active */\n children: ReactNode;\n /** Optional className */\n className?: string;\n}\n\nconst StepperContent: FC<StepperContentProps> = ({ value, children, className }) => {\n const { value: currentValue, orientation } = useStepperContext();\n const isActive = currentValue === value;\n\n if (!isActive) return null;\n\n return (\n <div\n role=\"tabpanel\"\n aria-hidden={!isActive}\n className={cn(stepperContentVariants({ orientation }), className)}\n >\n {children}\n </div>\n );\n};\n\n// ========================================\n// EXPORT COMPOUND COMPONENT\n// ========================================\n\nexport const StepperGlass = {\n Root: StepperRoot,\n List: StepperList,\n Step: StepperStep,\n Content: StepperContent,\n};\n\n// Also export individual components for flexibility\nexport { StepperRoot, StepperList, StepperStep, StepperContent };\n\n// Re-export types\nexport type {\n StepperRootProps,\n StepperListProps,\n StepperStepProps,\n StepperContentProps,\n StepperOrientation,\n StepperVariant,\n StepperSize,\n StepStatus,\n};\n"
|
|
19
|
+
"content": "/* eslint-disable react-refresh/only-export-components */\n/**\n * StepperGlass Component (Compound API)\n *\n * Glass-themed step indicator with:\n * - Theme-aware styling (glass/light/aurora)\n * - Horizontal and vertical orientations\n * - Numbered, icon, and dots variants\n * - Linear mode (lock future steps)\n * - Animated connector lines\n * - Compound component API for advanced composition\n *\n * @example\n * ```tsx\n * <StepperGlass.Root value=\"step2\" onValueChange={setStep}>\n * <StepperGlass.List>\n * <StepperGlass.Step value=\"step1\" label=\"Account\" description=\"Create your account\" />\n * <StepperGlass.Step value=\"step2\" label=\"Profile\" description=\"Setup your profile\" />\n * <StepperGlass.Step value=\"step3\" label=\"Complete\" description=\"Finish setup\" />\n * </StepperGlass.List>\n * <StepperGlass.Content value=\"step1\">Step 1 content</StepperGlass.Content>\n * <StepperGlass.Content value=\"step2\">Step 2 content</StepperGlass.Content>\n * <StepperGlass.Content value=\"step3\">Step 3 content</StepperGlass.Content>\n * </StepperGlass.Root>\n * ```\n *\n * @accessibility\n * - **Keyboard Navigation:** Arrow keys navigate between steps (WCAG 2.1.1)\n * - **Focus Management:** Visible focus ring using `--focus-glow` (WCAG 2.4.7)\n * - **Screen Readers:** Uses `role=\"tablist\"`, `role=\"tab\"` (WCAG 4.1.3)\n * - **ARIA Attributes:** `aria-current=\"step\"`, `aria-disabled` for state\n * - **Touch Targets:** 44x44px minimum touch targets (WCAG 2.5.5)\n * - **Color Contrast:** All states meet WCAG AA 4.5:1 ratio\n * - **Motion:** Respects `prefers-reduced-motion`\n */\n\nimport {\n forwardRef,\n createContext,\n useContext,\n useMemo,\n useState,\n useCallback,\n useLayoutEffect,\n type CSSProperties,\n type FC,\n type ReactNode,\n} from 'react';\nimport { cn } from '@/lib/utils';\nimport { useFocus } from '@/lib/hooks/use-focus';\nimport { Check } from 'lucide-react';\nimport {\n stepperRootVariants,\n stepperListVariants,\n stepperStepContainerVariants,\n stepperIndicatorVariants,\n stepperConnectorVariants,\n stepperLabelVariants,\n stepperDescriptionVariants,\n stepperContentVariants,\n type StepperOrientation,\n type StepperVariant,\n type StepperSize,\n type StepStatus,\n} from '@/lib/variants/stepper-glass-variants';\nimport '@/glass-theme.css';\n\n// ========================================\n// CONTEXT\n// ========================================\n\ninterface StepperContextValue {\n value: string;\n onValueChange?: (value: string) => void;\n orientation: StepperOrientation;\n variant: StepperVariant;\n size: StepperSize;\n linear: boolean;\n steps: string[];\n registerStep: (value: string, index: number) => void;\n unregisterStep: (value: string) => void;\n}\n\nconst StepperContext = createContext<StepperContextValue | null>(null);\n\nconst useStepperContext = () => {\n const context = useContext(StepperContext);\n if (!context) {\n throw new Error('Stepper compound components must be used within StepperGlass.Root');\n }\n return context;\n};\n\n// ========================================\n// UTILITY: GET STEP STATUS\n// ========================================\n\nfunction getStepStatus(\n stepValue: string,\n currentValue: string,\n steps: string[],\n linear: boolean,\n disabled?: boolean\n): StepStatus {\n if (disabled) return 'disabled';\n\n const stepIndex = steps.indexOf(stepValue);\n const currentIndex = steps.indexOf(currentValue);\n\n if (stepIndex === -1 || currentIndex === -1) return 'pending';\n if (stepIndex === currentIndex) return 'active';\n if (stepIndex < currentIndex) return 'completed';\n if (linear && stepIndex > currentIndex) return 'disabled';\n return 'pending';\n}\n\n// ========================================\n// ROOT COMPONENT\n// ========================================\n\ninterface StepperRootProps {\n /** Current active step value */\n value: string;\n /** Callback when step value changes */\n onValueChange?: (value: string) => void;\n /** Orientation of the stepper */\n orientation?: StepperOrientation;\n /** Visual variant */\n variant?: StepperVariant;\n /** Size of step indicators */\n size?: StepperSize;\n /** Lock future steps (require sequential completion) */\n linear?: boolean;\n /** Child components */\n children: ReactNode;\n /** Optional className */\n className?: string;\n}\n\nconst StepperRoot: FC<StepperRootProps> = ({\n value,\n onValueChange,\n orientation = 'horizontal',\n variant = 'numbered',\n size = 'md',\n linear = false,\n children,\n className,\n}) => {\n const [steps, setSteps] = useState<string[]>([]);\n\n const registerStep = useCallback((stepValue: string, index: number) => {\n setSteps((prev) => {\n if (prev.includes(stepValue)) return prev;\n const newSteps = [...prev];\n // Insert at correct position to maintain order\n newSteps.splice(index, 0, stepValue);\n return newSteps;\n });\n }, []);\n\n const unregisterStep = useCallback((stepValue: string) => {\n setSteps((prev) => prev.filter((s) => s !== stepValue));\n }, []);\n\n const contextValue = useMemo(\n () => ({\n value,\n onValueChange,\n orientation,\n variant,\n size,\n linear,\n steps,\n registerStep,\n unregisterStep,\n }),\n [value, onValueChange, orientation, variant, size, linear, steps, registerStep, unregisterStep]\n );\n\n return (\n <StepperContext.Provider value={contextValue}>\n <div\n data-slot=\"stepper\"\n className={cn(stepperRootVariants({ orientation }), className)}\n aria-label=\"Progress steps\"\n >\n {children}\n </div>\n </StepperContext.Provider>\n );\n};\n\n// ========================================\n// LIST COMPONENT\n// ========================================\n\ninterface StepperListProps extends React.HTMLAttributes<HTMLDivElement> {\n children: ReactNode;\n className?: string;\n}\n\nconst StepperList = forwardRef<HTMLDivElement, StepperListProps>(\n ({ children, className, ...props }, ref) => {\n const { orientation } = useStepperContext();\n\n return (\n <div\n ref={ref}\n data-slot=\"stepper-list\"\n role=\"tablist\"\n aria-orientation={orientation}\n className={cn(stepperListVariants({ orientation }), className)}\n {...props}\n >\n {children}\n </div>\n );\n }\n);\n\nStepperList.displayName = 'StepperList';\n\n// ========================================\n// STEP COMPONENT\n// ========================================\n\ninterface StepperStepProps {\n /** Unique value for this step */\n value: string;\n /** Step label (required for accessibility) */\n label: string;\n /** Optional description */\n description?: string;\n /** Custom icon (for icon variant) */\n icon?: ReactNode;\n /** Completed icon override */\n completedIcon?: ReactNode;\n /** Force disabled state */\n disabled?: boolean;\n /** Optional className */\n className?: string;\n /** Step index for ordering (auto-detected) */\n index?: number;\n}\n\nconst StepperStep = forwardRef<HTMLButtonElement, StepperStepProps>(\n (\n {\n value: stepValue,\n label,\n description,\n icon,\n completedIcon,\n disabled: forcedDisabled,\n className,\n index: providedIndex,\n },\n ref\n ) => {\n const {\n value: currentValue,\n onValueChange,\n orientation,\n variant,\n size,\n linear,\n steps,\n registerStep,\n unregisterStep,\n } = useStepperContext();\n\n const { isFocusVisible, focusProps } = useFocus({ focusVisible: true });\n\n // Track mount order for step registration\n const [mountIndex] = useState(() => providedIndex ?? Date.now());\n\n // Register step on mount\n // Use useLayoutEffect to register before paint\n useLayoutEffect(() => {\n registerStep(stepValue, mountIndex);\n return () => unregisterStep(stepValue);\n }, [stepValue, mountIndex, registerStep, unregisterStep]);\n\n const status = getStepStatus(stepValue, currentValue, steps, linear, forcedDisabled);\n const stepIndex = steps.indexOf(stepValue);\n const isLast = stepIndex === steps.length - 1;\n const isClickable = status !== 'disabled';\n\n // Styles based on status\n const indicatorStyles: CSSProperties = {\n background:\n status === 'completed'\n ? 'var(--stepper-step-completed-bg)'\n : status === 'active'\n ? 'var(--stepper-step-active-bg)'\n : status === 'disabled'\n ? 'var(--stepper-step-disabled-bg)'\n : 'var(--stepper-step-bg)',\n border: `2px solid ${\n status === 'completed'\n ? 'var(--stepper-step-completed-border)'\n : status === 'active'\n ? 'var(--stepper-step-active-border)'\n : status === 'disabled'\n ? 'var(--stepper-step-disabled-border)'\n : 'var(--stepper-step-border)'\n }`,\n color:\n status === 'completed'\n ? 'var(--stepper-step-completed-text)'\n : status === 'active'\n ? 'var(--stepper-step-active-text)'\n : status === 'disabled'\n ? 'var(--stepper-step-disabled-text)'\n : 'var(--stepper-step-text)',\n boxShadow:\n status === 'active'\n ? 'var(--stepper-step-active-glow)'\n : status === 'completed'\n ? 'var(--stepper-step-glow)'\n : isFocusVisible\n ? 'var(--focus-glow)'\n : 'none',\n backdropFilter: 'blur(var(--blur-sm))',\n };\n\n const connectorStyles: CSSProperties = {\n background:\n stepIndex < steps.indexOf(currentValue)\n ? 'var(--stepper-connector-active-bg)'\n : 'var(--stepper-connector-bg)',\n };\n\n const labelStyles: CSSProperties = {\n color:\n status === 'active' || status === 'completed'\n ? 'var(--stepper-label-text)'\n : 'var(--stepper-description-text)',\n };\n\n const descriptionStyles: CSSProperties = {\n color: 'var(--stepper-description-text)',\n };\n\n // Render indicator content\n const renderIndicatorContent = () => {\n if (status === 'completed') {\n if (completedIcon) return completedIcon;\n return <Check className=\"w-4 h-4\" />;\n }\n if (variant === 'icon' && icon) return icon;\n if (variant === 'dots') return null;\n // Numbered variant\n return stepIndex >= 0 ? stepIndex + 1 : '';\n };\n\n const handleClick = () => {\n if (isClickable && onValueChange) {\n onValueChange(stepValue);\n }\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (!isClickable) return;\n\n const stepList = e.currentTarget.closest('[role=\"tablist\"]');\n if (!stepList) return;\n\n const allSteps = Array.from(\n stepList.querySelectorAll('[role=\"tab\"]:not([aria-disabled=\"true\"])')\n ) as HTMLButtonElement[];\n const currentIdx = allSteps.indexOf(e.currentTarget as HTMLButtonElement);\n\n let nextIdx = currentIdx;\n const isHorizontal = orientation === 'horizontal';\n\n switch (e.key) {\n case isHorizontal ? 'ArrowRight' : 'ArrowDown':\n e.preventDefault();\n nextIdx = (currentIdx + 1) % allSteps.length;\n break;\n case isHorizontal ? 'ArrowLeft' : 'ArrowUp':\n e.preventDefault();\n nextIdx = currentIdx - 1 < 0 ? allSteps.length - 1 : currentIdx - 1;\n break;\n case 'Home':\n e.preventDefault();\n nextIdx = 0;\n break;\n case 'End':\n e.preventDefault();\n nextIdx = allSteps.length - 1;\n break;\n default:\n return;\n }\n\n const nextStep = allSteps[nextIdx];\n if (nextStep) {\n nextStep.focus();\n const nextValue = nextStep.getAttribute('data-value');\n if (nextValue && onValueChange) {\n onValueChange(nextValue);\n }\n }\n };\n\n // For horizontal, we need step + connector inline\n // For vertical, step is a row with connector below\n if (orientation === 'horizontal') {\n return (\n <>\n <div\n data-slot=\"stepper-item\"\n className={cn(stepperStepContainerVariants({ orientation }), className)}\n >\n <button\n ref={ref}\n type=\"button\"\n role=\"tab\"\n aria-selected={status === 'active'}\n aria-disabled={!isClickable}\n aria-current={status === 'active' ? 'step' : undefined}\n data-value={stepValue}\n data-status={status}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n onFocus={focusProps.onFocus}\n onBlur={focusProps.onBlur}\n disabled={!isClickable}\n className={cn(\n stepperIndicatorVariants({ size, variant }),\n !isClickable && 'cursor-not-allowed opacity-60',\n isClickable && 'cursor-pointer hover:scale-105',\n // Ensure minimum touch target\n 'min-w-[44px] min-h-[44px]'\n )}\n style={indicatorStyles}\n >\n {renderIndicatorContent()}\n </button>\n\n {label && (\n <div className=\"flex flex-col items-center\">\n <span\n className={cn(stepperLabelVariants({ size, orientation }))}\n style={labelStyles}\n >\n {label}\n </span>\n {description && (\n <span\n className={cn(stepperDescriptionVariants({ size, orientation }))}\n style={descriptionStyles}\n >\n {description}\n </span>\n )}\n </div>\n )}\n </div>\n\n {/* Connector line between steps */}\n {!isLast && (\n <div\n data-slot=\"stepper-separator\"\n className={cn(stepperConnectorVariants({ orientation }))}\n style={connectorStyles}\n aria-hidden=\"true\"\n />\n )}\n </>\n );\n }\n\n // Vertical orientation\n return (\n <div className=\"flex flex-col\">\n <div\n data-slot=\"stepper-item\"\n className={cn(stepperStepContainerVariants({ orientation }), className)}\n >\n <button\n ref={ref}\n type=\"button\"\n role=\"tab\"\n aria-selected={status === 'active'}\n aria-disabled={!isClickable}\n aria-current={status === 'active' ? 'step' : undefined}\n data-value={stepValue}\n data-status={status}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n onFocus={focusProps.onFocus}\n onBlur={focusProps.onBlur}\n disabled={!isClickable}\n className={cn(\n stepperIndicatorVariants({ size, variant }),\n !isClickable && 'cursor-not-allowed opacity-60',\n isClickable && 'cursor-pointer hover:scale-105',\n 'min-w-[44px] min-h-[44px]'\n )}\n style={indicatorStyles}\n >\n {renderIndicatorContent()}\n </button>\n\n {label && (\n <div className=\"flex flex-col justify-center\">\n <span className={cn(stepperLabelVariants({ size, orientation }))} style={labelStyles}>\n {label}\n </span>\n {description && (\n <span\n className={cn(stepperDescriptionVariants({ size, orientation }))}\n style={descriptionStyles}\n >\n {description}\n </span>\n )}\n </div>\n )}\n </div>\n\n {/* Vertical connector */}\n {!isLast && (\n <div\n data-slot=\"stepper-separator\"\n className={cn(stepperConnectorVariants({ orientation }))}\n style={connectorStyles}\n aria-hidden=\"true\"\n />\n )}\n </div>\n );\n }\n);\n\nStepperStep.displayName = 'StepperStep';\n\n// ========================================\n// CONTENT COMPONENT\n// ========================================\n\ninterface StepperContentProps {\n /** Value of the step this content belongs to */\n value: string;\n /** Content to display when step is active */\n children: ReactNode;\n /** Optional className */\n className?: string;\n}\n\nconst StepperContent: FC<StepperContentProps> = ({ value, children, className }) => {\n const { value: currentValue, orientation } = useStepperContext();\n const isActive = currentValue === value;\n\n if (!isActive) return null;\n\n return (\n <div\n role=\"tabpanel\"\n data-slot=\"stepper-content\"\n aria-hidden={!isActive}\n className={cn(stepperContentVariants({ orientation }), className)}\n >\n {children}\n </div>\n );\n};\n\n// ========================================\n// EXPORT COMPOUND COMPONENT\n// ========================================\n\nexport const StepperGlass = {\n Root: StepperRoot,\n List: StepperList,\n Step: StepperStep,\n Content: StepperContent,\n};\n\n// Also export individual components for flexibility\nexport { StepperRoot, StepperList, StepperStep, StepperContent };\n\n// Re-export types\nexport type {\n StepperRootProps,\n StepperListProps,\n StepperStepProps,\n StepperContentProps,\n StepperOrientation,\n StepperVariant,\n StepperSize,\n StepStatus,\n};\n"
|
|
20
20
|
}
|
|
21
21
|
],
|
|
22
22
|
"categories": [
|
package/dist/r/tabs-glass.json
CHANGED
|
@@ -3,19 +3,20 @@
|
|
|
3
3
|
"name": "tabs-glass",
|
|
4
4
|
"type": "registry:ui",
|
|
5
5
|
"title": "Tabs Glass",
|
|
6
|
-
"description": "TabsGlass Component (
|
|
6
|
+
"description": "TabsGlass Component (Radix UI based)",
|
|
7
7
|
"dependencies": [
|
|
8
|
+
"@radix-ui/react-tabs",
|
|
9
|
+
"react",
|
|
8
10
|
"shadcn-glass-ui"
|
|
9
11
|
],
|
|
10
12
|
"registryDependencies": [
|
|
11
|
-
"cn"
|
|
12
|
-
"use-focus"
|
|
13
|
+
"cn"
|
|
13
14
|
],
|
|
14
15
|
"files": [
|
|
15
16
|
{
|
|
16
17
|
"path": "components/glass/ui/tabs-glass.tsx",
|
|
17
18
|
"type": "registry:component",
|
|
18
|
-
"content": "/* eslint-disable react-refresh/only-export-components */\n/**\n * TabsGlass Component (Compound API only)\n *\n * Glass-themed tab navigation with:\n * - Theme-aware styling (glass/light/aurora)\n * - Active tab indicator\n * - Smooth transitions\n * - Compound component API for advanced composition\n *\n * @example\n * ```tsx\n * <TabsGlass.Root value={activeTab} onValueChange={setActiveTab}>\n * <TabsGlass.List>\n * <TabsGlass.Trigger value=\"overview\">Overview</TabsGlass.Trigger>\n * <TabsGlass.Trigger value=\"analytics\">Analytics</TabsGlass.Trigger>\n * <TabsGlass.Trigger value=\"settings\">Settings</TabsGlass.Trigger>\n * </TabsGlass.List>\n * <TabsGlass.Content value=\"overview\">\n * Overview content\n * </TabsGlass.Content>\n * <TabsGlass.Content value=\"analytics\">\n * Analytics content\n * </TabsGlass.Content>\n * <TabsGlass.Content value=\"settings\">\n * Settings content\n * </TabsGlass.Content>\n * </TabsGlass.Root>\n * ```\n *\n * @since v1.0.0 - Legacy API removed (tabs/activeTab/onChange props)\n */\n\nimport {\n forwardRef,\n createContext,\n useContext,\n useState,\n type CSSProperties,\n type FC,\n type ReactNode,\n} from 'react';\nimport { cn } from '@/lib/utils';\nimport { useFocus } from '@/lib/hooks/use-focus';\nimport '@/glass-theme.css';\n\n// ========================================\n// TYPES\n// ========================================\n\nexport interface TabItem {\n readonly id: string;\n readonly label: string;\n}\n\n// ========================================\n// CONTEXT FOR COMPOUND COMPONENTS\n// ========================================\n\ninterface TabsContextValue {\n value: string;\n onValueChange?: (value: string) => void;\n}\n\nconst TabsContext = createContext<TabsContextValue | null>(null);\n\nconst useTabsContext = () => {\n const context = useContext(TabsContext);\n if (!context) {\n throw new Error('Tabs compound components must be used within TabsGlass.Root');\n }\n return context;\n};\n\n// ========================================\n// COMPOUND COMPONENT: ROOT\n// ========================================\n\n/**\n * Props for TabsGlass.Root component\n *\n * Root component that manages tab state and provides context for child components.\n * Features accessible keyboard navigation and ARIA attributes.\n *\n * @accessibility\n * - **Keyboard Navigation:** Arrow keys navigate between tabs, Tab moves to tab panel content (WCAG 2.1.1)\n * - **Focus Management:** Visible focus ring on active tab using `--focus-glow` CSS variable (WCAG 2.4.7)\n * - **Screen Readers:** Uses `role=\"tablist\"`, `role=\"tab\"`, `role=\"tabpanel\"` for proper tab semantics (WCAG 4.1.3)\n * - **ARIA Attributes:** Tabs marked with `aria-selected`, panels with `aria-hidden` for state announcement\n * - **Active State:** Visual indicator (underline) plus color change for multi-modal feedback\n * - **Touch Targets:** Tab triggers meet minimum 44x44px touch target (WCAG 2.5.5)\n * - **Color Contrast:** Active and inactive tab text meet WCAG AA contrast ratio 4.5:1\n * - **Motion:** Transitions and indicator animations respect `prefers-reduced-motion` settings\n *\n * @example\n * ```tsx\n * // Basic tabs\n * <TabsGlass.Root value={activeTab} onValueChange={setActiveTab}>\n * <TabsGlass.List>\n * <TabsGlass.Trigger value=\"overview\">Overview</TabsGlass.Trigger>\n * <TabsGlass.Trigger value=\"analytics\">Analytics</TabsGlass.Trigger>\n * <TabsGlass.Trigger value=\"settings\">Settings</TabsGlass.Trigger>\n * </TabsGlass.List>\n * <TabsGlass.Content value=\"overview\">\n * <h2>Overview</h2>\n * <p>Overview content here</p>\n * </TabsGlass.Content>\n * <TabsGlass.Content value=\"analytics\">\n * <h2>Analytics</h2>\n * <p>Analytics content here</p>\n * </TabsGlass.Content>\n * <TabsGlass.Content value=\"settings\">\n * <h2>Settings</h2>\n * <p>Settings content here</p>\n * </TabsGlass.Content>\n * </TabsGlass.Root>\n *\n * // Tabs with icons (ensure accessible labels)\n * <TabsGlass.Root value={activeTab} onValueChange={setActiveTab}>\n * <TabsGlass.List>\n * <TabsGlass.Trigger value=\"home\" aria-label=\"Home dashboard\">\n * <Home className=\"w-4 h-4\" />\n * </TabsGlass.Trigger>\n * <TabsGlass.Trigger value=\"search\" aria-label=\"Search\">\n * <Search className=\"w-4 h-4\" />\n * </TabsGlass.Trigger>\n * </TabsGlass.List>\n * <TabsGlass.Content value=\"home\">Dashboard content</TabsGlass.Content>\n * <TabsGlass.Content value=\"search\">Search content</TabsGlass.Content>\n * </TabsGlass.Root>\n *\n * // Disabled tab (announced to screen readers)\n * <TabsGlass.Root value={activeTab} onValueChange={setActiveTab}>\n * <TabsGlass.List>\n * <TabsGlass.Trigger value=\"tab1\">Available Tab</TabsGlass.Trigger>\n * <TabsGlass.Trigger value=\"tab2\" disabled>\n * Locked Tab\n * </TabsGlass.Trigger>\n * </TabsGlass.List>\n * <TabsGlass.Content value=\"tab1\">Content 1</TabsGlass.Content>\n * </TabsGlass.Root>\n *\n * // Form tabs with proper focus management\n * <TabsGlass.Root value={currentStep} onValueChange={setCurrentStep}>\n * <TabsGlass.List aria-label=\"Registration steps\">\n * <TabsGlass.Trigger value=\"account\">Account Info</TabsGlass.Trigger>\n * <TabsGlass.Trigger value=\"profile\">Profile Details</TabsGlass.Trigger>\n * <TabsGlass.Trigger value=\"confirm\">Confirmation</TabsGlass.Trigger>\n * </TabsGlass.List>\n * <TabsGlass.Content value=\"account\">\n * <InputGlass label=\"Email\" type=\"email\" />\n * </TabsGlass.Content>\n * <TabsGlass.Content value=\"profile\">\n * <InputGlass label=\"Name\" />\n * </TabsGlass.Content>\n * <TabsGlass.Content value=\"confirm\">\n * <p>Review your information</p>\n * </TabsGlass.Content>\n * </TabsGlass.Root>\n * ```\n */\n/**\n * Props for TabsGlass Root component (shadcn/ui compatible)\n */\nexport interface TabsRootProps {\n /** Current active tab value (controlled) */\n value?: string;\n /** Default active tab value (uncontrolled) */\n defaultValue?: string;\n /** Callback when tab value changes */\n onValueChange?: (value: string) => void;\n /** Child components */\n children: ReactNode;\n /** Optional className for container */\n className?: string;\n}\n\nconst TabsRoot: FC<TabsRootProps> = ({\n value: controlledValue,\n defaultValue,\n onValueChange,\n children,\n className,\n}) => {\n // Support both controlled and uncontrolled modes (shadcn/ui pattern)\n const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue ?? '');\n const isControlled = controlledValue !== undefined;\n const value = isControlled ? controlledValue : uncontrolledValue;\n\n const handleValueChange = (newValue: string) => {\n if (!isControlled) {\n setUncontrolledValue(newValue);\n }\n onValueChange?.(newValue);\n };\n\n return (\n <TabsContext.Provider value={{ value, onValueChange: handleValueChange }}>\n <div className={cn('tabs-glass-root', className)}>{children}</div>\n </TabsContext.Provider>\n );\n};\n\n// ========================================\n// COMPOUND COMPONENT: LIST\n// ========================================\n\nexport interface TabsListProps extends React.HTMLAttributes<HTMLDivElement> {\n children: ReactNode;\n className?: string;\n}\n\nconst TabsList = forwardRef<HTMLDivElement, TabsListProps>(\n ({ children, className, ...props }, ref) => {\n const containerStyles: CSSProperties = {\n background: 'var(--tab-container-bg)',\n border: '1px solid var(--tab-container-border)',\n };\n\n return (\n <div\n ref={ref}\n className={cn('inline-flex gap-0.5 md:gap-1 p-0.5 md:p-1 rounded-xl', className)}\n style={containerStyles}\n role=\"tablist\"\n {...props}\n >\n {children}\n </div>\n );\n }\n);\n\nTabsList.displayName = 'TabsList';\n\n// ========================================\n// COMPOUND COMPONENT: TRIGGER\n// ========================================\n\nexport interface TabsTriggerProps {\n /** Value of this tab */\n value: string;\n /** Tab label/content */\n children: ReactNode;\n /** Optional className */\n className?: string;\n /** Disabled state */\n disabled?: boolean;\n}\n\nconst TabsTrigger = forwardRef<HTMLButtonElement, TabsTriggerProps>(\n ({ value, children, className, disabled }, ref) => {\n const { value: activeValue, onValueChange } = useTabsContext();\n const { isFocusVisible, focusProps } = useFocus({ focusVisible: true });\n const isActive = activeValue === value;\n\n const tabStyles: CSSProperties = {\n background: isActive ? 'var(--tab-active-bg)' : 'var(--tab-bg)',\n color: isActive ? 'var(--tab-active-text)' : 'var(--text-secondary)',\n boxShadow: isFocusVisible && !disabled ? 'var(--focus-glow)' : 'none',\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLButtonElement>) => {\n if (disabled) return;\n\n const tablist = e.currentTarget.closest('[role=\"tablist\"]');\n if (!tablist) return;\n\n const tabs = Array.from(\n tablist.querySelectorAll('[role=\"tab\"]:not([disabled])')\n ) as HTMLButtonElement[];\n const currentIndex = tabs.indexOf(e.currentTarget);\n\n let nextIndex = currentIndex;\n\n switch (e.key) {\n case 'ArrowRight':\n e.preventDefault();\n nextIndex = currentIndex + 1 >= tabs.length ? 0 : currentIndex + 1;\n break;\n case 'ArrowLeft':\n e.preventDefault();\n nextIndex = currentIndex - 1 < 0 ? tabs.length - 1 : currentIndex - 1;\n break;\n case 'Home':\n e.preventDefault();\n nextIndex = 0;\n break;\n case 'End':\n e.preventDefault();\n nextIndex = tabs.length - 1;\n break;\n default:\n return;\n }\n\n const nextTab = tabs[nextIndex];\n if (nextTab) {\n nextTab.focus();\n // Get the value from the button's data attribute or find it in context\n const nextValue = nextTab.getAttribute('data-value');\n if (nextValue && onValueChange) {\n onValueChange(nextValue);\n }\n }\n };\n\n return (\n <button\n ref={ref}\n type=\"button\"\n role=\"tab\"\n aria-selected={isActive}\n disabled={disabled}\n data-value={value}\n className={cn(\n 'relative px-2.5 py-1.5 md:px-4 md:py-2 rounded-lg text-xs md:text-sm font-medium transition-[background-color,color,opacity] duration-300',\n disabled && 'opacity-50 cursor-not-allowed',\n className\n )}\n style={tabStyles}\n onClick={() => !disabled && onValueChange?.(value)}\n onKeyDown={handleKeyDown}\n onFocus={focusProps.onFocus}\n onBlur={focusProps.onBlur}\n >\n {children}\n {isActive && (\n <div\n className=\"absolute bottom-0 left-1/2 -translate-x-1/2 w-6 md:w-8 h-0.5 rounded-full\"\n style={{ background: 'var(--tab-indicator)' }}\n />\n )}\n </button>\n );\n }\n);\n\nTabsTrigger.displayName = 'TabsTrigger';\n\n// ========================================\n// COMPOUND COMPONENT: CONTENT\n// ========================================\n\nexport interface TabsContentProps {\n /** Value of the tab this content belongs to */\n value: string;\n /** Content to display when tab is active */\n children: ReactNode;\n /** Optional className */\n className?: string;\n}\n\nconst TabsContent: FC<TabsContentProps> = ({ value, children, className }) => {\n const { value: activeValue } = useTabsContext();\n const isActive = activeValue === value;\n\n if (!isActive) return null;\n\n return (\n <div\n role=\"tabpanel\"\n aria-hidden={!isActive}\n className={cn('animate-in fade-in-0 duration-200', className)}\n >\n {children}\n </div>\n );\n};\n\n// ========================================\n// EXPORT COMPOUND COMPONENT (v1.0.0+)\n// ========================================\n\n/**\n * TabsGlass - Compound Component API\n *\n * @example\n * ```tsx\n * // Compound API (TabsGlass.Root pattern)\n * <TabsGlass.Root value={activeTab} onValueChange={setActiveTab}>\n * <TabsGlass.List>\n * <TabsGlass.Trigger value=\"tab1\">Overview</TabsGlass.Trigger>\n * <TabsGlass.Trigger value=\"tab2\">Analytics</TabsGlass.Trigger>\n * </TabsGlass.List>\n * <TabsGlass.Content value=\"tab1\">\n * <p>Overview content</p>\n * </TabsGlass.Content>\n * <TabsGlass.Content value=\"tab2\">\n * <p>Analytics content</p>\n * </TabsGlass.Content>\n * </TabsGlass.Root>\n *\n * // shadcn/ui compatible API (separate imports)\n * import { Tabs, TabsList, TabsTrigger, TabsContent } from 'shadcn-glass-ui'\n * <Tabs defaultValue=\"tab1\">\n * <TabsList>\n * <TabsTrigger value=\"tab1\">Overview</TabsTrigger>\n * <TabsTrigger value=\"tab2\">Analytics</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"tab1\">Overview content</TabsContent>\n * <TabsContent value=\"tab2\">Analytics content</TabsContent>\n * </Tabs>\n * ```\n *\n * @since v1.0.0 - Legacy API removed (tabs/activeTab/onChange props)\n * @since v2.3.0 - Added shadcn/ui compatible separate exports\n */\nexport const TabsGlass = {\n Root: TabsRoot,\n List: TabsList,\n Trigger: TabsTrigger,\n Content: TabsContent,\n};\n\n// ========================================\n// SHADCN/UI COMPATIBLE EXPORTS (v2.3.0+)\n// ========================================\n\n/**\n * Tabs - shadcn/ui compatible alias for TabsGlass.Root\n *\n * @example\n * ```tsx\n * import { Tabs, TabsList, TabsTrigger, TabsContent } from 'shadcn-glass-ui'\n *\n * <Tabs defaultValue=\"account\">\n * <TabsList>\n * <TabsTrigger value=\"account\">Account</TabsTrigger>\n * <TabsTrigger value=\"password\">Password</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"account\">Account settings</TabsContent>\n * <TabsContent value=\"password\">Password settings</TabsContent>\n * </Tabs>\n * ```\n */\nexport const Tabs = TabsRoot;\n\n/**\n * TabsList - shadcn/ui compatible alias for TabsGlass.List\n */\nexport { TabsList };\n\n/**\n * TabsTrigger - shadcn/ui compatible alias for TabsGlass.Trigger\n */\nexport { TabsTrigger };\n\n/**\n * TabsContent - shadcn/ui compatible alias for TabsGlass.Content\n */\nexport { TabsContent };\n"
|
|
19
|
+
"content": "/* eslint-disable react-refresh/only-export-components */\n/**\n * TabsGlass Component (Radix UI based)\n *\n * Glass-themed tab navigation built on Radix UI primitives with:\n * - 100% shadcn/ui type compatibility\n * - Theme-aware styling (glass/light/aurora)\n * - Active tab indicator\n * - Full keyboard navigation (Arrow keys, Home, End)\n * - Support for orientation, dir, activationMode\n *\n * @since v2.2.6 - Migrated to Radix UI primitives for full type compatibility\n */\n\nimport * as React from 'react';\nimport * as TabsPrimitive from '@radix-ui/react-tabs';\nimport { cn } from '@/lib/utils';\nimport '@/glass-theme.css';\n\n// ========================================\n// TYPES\n// ========================================\n\n/**\n * Legacy TabItem interface for backwards compatibility\n */\nexport interface TabItem {\n readonly id: string;\n readonly label: string;\n}\n\n/**\n * Props for TabsGlass Root component\n *\n * Extends Radix UI Tabs.Root props for 100% shadcn/ui compatibility.\n * All Radix props are supported including: value, defaultValue, onValueChange,\n * orientation, dir, activationMode.\n *\n * **Type Compatibility (v2.3.1+):**\n * - Extends `React.ComponentPropsWithoutRef<typeof TabsPrimitive.Root>`\n * - No more `as unknown as` type assertions needed\n * - Full IntelliSense for all Radix props\n *\n * **New props from Radix:**\n * - `orientation`: 'horizontal' | 'vertical' - Tab layout direction\n * - `dir`: 'ltr' | 'rtl' - Text direction for RTL support\n * - `activationMode`: 'automatic' | 'manual' - Tab activation behavior\n *\n * @accessibility\n * - **Keyboard Navigation:** Arrow keys navigate between tabs (respects orientation)\n * - **Focus Management:** Visible focus ring using CSS variables\n * - **Screen Readers:** Radix UI handles all ARIA attributes automatically\n * - **RTL Support:** Full RTL support via `dir` prop\n *\n * @example\n * ```tsx\n * // Basic usage\n * <Tabs defaultValue=\"tab1\">\n * <TabsList>\n * <TabsTrigger value=\"tab1\">Tab 1</TabsTrigger>\n * <TabsTrigger value=\"tab2\">Tab 2</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"tab1\">Content 1</TabsContent>\n * <TabsContent value=\"tab2\">Content 2</TabsContent>\n * </Tabs>\n *\n * // Vertical tabs\n * <Tabs defaultValue=\"tab1\" orientation=\"vertical\">\n * <TabsList>\n * <TabsTrigger value=\"tab1\">Tab 1</TabsTrigger>\n * <TabsTrigger value=\"tab2\">Tab 2</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"tab1\">Content 1</TabsContent>\n * </Tabs>\n *\n * // Manual activation (click required, not focus)\n * <Tabs defaultValue=\"tab1\" activationMode=\"manual\">\n * ...\n * </Tabs>\n * ```\n *\n * @since v2.3.0 - Added shadcn/ui compatible separate exports\n * @since v2.2.6 - Migrated to Radix UI primitives\n */\nexport type TabsRootProps = React.ComponentPropsWithoutRef<typeof TabsPrimitive.Root>;\n\n/**\n * Props for TabsList component\n */\nexport type TabsListProps = React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>;\n\n/**\n * Props for TabsTrigger component\n */\nexport type TabsTriggerProps = React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>;\n\n/**\n * Props for TabsContent component\n */\nexport type TabsContentProps = React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>;\n\n// ========================================\n// COMPONENTS\n// ========================================\n\n/**\n * TabsRoot - Root container for tabs\n */\nfunction TabsRoot({ className, ...props }: TabsRootProps) {\n return (\n <TabsPrimitive.Root data-slot=\"tabs\" className={cn('tabs-glass-root', className)} {...props} />\n );\n}\n\n/**\n * TabsList - Container for tab triggers\n */\nconst TabsList = React.forwardRef<React.ElementRef<typeof TabsPrimitive.List>, TabsListProps>(\n ({ className, ...props }, ref) => (\n <TabsPrimitive.List\n ref={ref}\n data-slot=\"tabs-list\"\n className={cn(\n 'inline-flex gap-0.5 md:gap-1 p-0.5 md:p-1 rounded-xl',\n 'bg-(--tab-container-bg) border border-(--tab-container-border)',\n className\n )}\n {...props}\n />\n )\n);\n\nTabsList.displayName = 'TabsList';\n\n/**\n * TabsTrigger - Individual tab button\n */\nconst TabsTrigger = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Trigger>,\n TabsTriggerProps\n>(({ className, children, ...props }, ref) => (\n <TabsPrimitive.Trigger\n ref={ref}\n data-slot=\"tabs-trigger\"\n className={cn(\n 'relative px-2.5 py-1.5 md:px-4 md:py-2 rounded-lg',\n 'text-xs md:text-sm font-medium',\n 'transition-[background-color,color,opacity,box-shadow] duration-300',\n // Inactive state\n 'bg-(--tab-bg) text-(--text-secondary)',\n // Active state\n 'data-[state=active]:bg-(--tab-active-bg) data-[state=active]:text-(--tab-active-text)',\n // Focus state\n 'focus-visible:outline-none focus-visible:shadow-(--focus-glow)',\n // Disabled state\n 'disabled:opacity-50 disabled:cursor-not-allowed',\n // Indicator (using ::after pseudo-element)\n 'after:absolute after:bottom-0 after:left-1/2 after:-translate-x-1/2',\n 'after:w-6 md:after:w-8 after:h-0.5 after:rounded-full',\n 'after:bg-(--tab-indicator)',\n 'after:opacity-0 data-[state=active]:after:opacity-100',\n 'after:transition-opacity after:duration-300',\n className\n )}\n {...props}\n >\n {children}\n </TabsPrimitive.Trigger>\n));\n\nTabsTrigger.displayName = 'TabsTrigger';\n\n/**\n * TabsContent - Content panel for a tab\n */\nconst TabsContent = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Content>,\n TabsContentProps\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Content\n ref={ref}\n data-slot=\"tabs-content\"\n className={cn(\n 'animate-in fade-in-0 duration-200 outline-none',\n 'focus-visible:outline-none',\n className\n )}\n {...props}\n />\n));\n\nTabsContent.displayName = 'TabsContent';\n\n// ========================================\n// COMPOUND COMPONENT EXPORT\n// ========================================\n\n/**\n * TabsGlass - Compound Component API\n *\n * @example\n * ```tsx\n * // Compound API (TabsGlass.Root pattern)\n * <TabsGlass.Root value={activeTab} onValueChange={setActiveTab}>\n * <TabsGlass.List>\n * <TabsGlass.Trigger value=\"tab1\">Overview</TabsGlass.Trigger>\n * <TabsGlass.Trigger value=\"tab2\">Analytics</TabsGlass.Trigger>\n * </TabsGlass.List>\n * <TabsGlass.Content value=\"tab1\">\n * <p>Overview content</p>\n * </TabsGlass.Content>\n * <TabsGlass.Content value=\"tab2\">\n * <p>Analytics content</p>\n * </TabsGlass.Content>\n * </TabsGlass.Root>\n *\n * // shadcn/ui compatible API (separate imports)\n * import { Tabs, TabsList, TabsTrigger, TabsContent } from 'shadcn-glass-ui'\n * <Tabs defaultValue=\"tab1\">\n * <TabsList>\n * <TabsTrigger value=\"tab1\">Overview</TabsTrigger>\n * <TabsTrigger value=\"tab2\">Analytics</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"tab1\">Overview content</TabsContent>\n * <TabsContent value=\"tab2\">Analytics content</TabsContent>\n * </Tabs>\n * ```\n *\n * @since v1.0.0 - Legacy API removed (tabs/activeTab/onChange props)\n * @since v2.3.0 - Added shadcn/ui compatible separate exports\n * @since v2.2.6 - Migrated to Radix UI primitives\n */\nexport const TabsGlass = {\n Root: TabsRoot,\n List: TabsList,\n Trigger: TabsTrigger,\n Content: TabsContent,\n};\n\n// ========================================\n// SHADCN/UI COMPATIBLE EXPORTS\n// ========================================\n\n/**\n * Tabs - shadcn/ui compatible alias for TabsGlass.Root\n */\nexport const Tabs = TabsRoot;\n\nexport { TabsList, TabsTrigger, TabsContent };\n"
|
|
19
20
|
}
|
|
20
21
|
],
|
|
21
22
|
"categories": [
|
package/dist/r/toggle-glass.json
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
{
|
|
18
18
|
"path": "components/glass/ui/toggle-glass.tsx",
|
|
19
19
|
"type": "registry:component",
|
|
20
|
-
"content": "/**\n * ToggleGlass Component\n *\n * Glass-themed toggle switch with shadcn/ui compatible API:\n * - Theme-aware styling (glass/light/aurora)\n * - Glow effect when active\n * - Size variants (default, sm, lg)\n * - Variant styles (default, outline)\n * - Optional label\n *\n * **shadcn/ui compatible props:**\n * - `pressed` / `defaultPressed` - Control pressed state\n * - `onPressedChange` - Callback when state changes\n * - `variant` - 'default' | 'outline'\n * - `size` - 'default' | 'sm' | 'lg'\n *\n * @example\n * ```tsx\n * // Controlled\n * <ToggleGlass pressed={isOn} onPressedChange={setIsOn} />\n *\n * // Uncontrolled\n * <ToggleGlass defaultPressed={true} />\n *\n * // With variant\n * <ToggleGlass variant=\"outline\" pressed={isOn} onPressedChange={setIsOn} />\n * ```\n */\n\nimport { forwardRef, useState, type CSSProperties } from 'react';\nimport { type VariantProps } from 'class-variance-authority';\nimport { cn } from '@/lib/utils';\nimport { useFocus } from '@/lib/hooks/use-focus';\nimport { toggleSizes, type ToggleGlassVariant } from '@/lib/variants/toggle-glass-variants';\nimport '@/glass-theme.css';\n\n// ========================================\n// SIZE CONFIG\n// ========================================\n\nconst sizesConfig = {\n sm: { track: 'w-8 h-4', knob: 'w-3 h-3', translate: 'translate-x-4' },\n default: { track: 'w-11 h-6', knob: 'w-5 h-5', translate: 'translate-x-5' },\n lg: { track: 'w-14 h-7', knob: 'w-6 h-6', translate: 'translate-x-7' },\n} as const;\n\n// ========================================\n// PROPS INTERFACE\n// ========================================\n\nexport interface ToggleGlassProps\n extends\n Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onChange' | 'defaultValue'>,\n VariantProps<typeof toggleSizes> {\n /**\n * Controlled pressed state (shadcn/ui compatible)\n */\n readonly pressed?: boolean;\n /**\n * Default pressed state for uncontrolled usage\n */\n readonly defaultPressed?: boolean;\n /**\n * Callback when pressed state changes (shadcn/ui compatible)\n */\n readonly onPressedChange?: (pressed: boolean) => void;\n /**\n * Visual variant (shadcn/ui compatible)\n * @default \"default\"\n */\n readonly variant?: ToggleGlassVariant;\n /**\n * Optional label text\n */\n readonly label?: string;\n}\n\n// ========================================\n// COMPONENT\n// ========================================\n\nexport const ToggleGlass = forwardRef<HTMLButtonElement, ToggleGlassProps>(\n (\n {\n className,\n size = 'default',\n variant = 'default',\n pressed: controlledPressed,\n defaultPressed = false,\n onPressedChange,\n disabled,\n label,\n ...props\n },\n ref\n ) => {\n // Support both controlled and uncontrolled modes\n const [uncontrolledPressed, setUncontrolledPressed] = useState(defaultPressed);\n const isControlled = controlledPressed !== undefined;\n const isPressed = isControlled ? controlledPressed : uncontrolledPressed;\n\n const { isFocusVisible, focusProps } = useFocus({ focusVisible: true });\n const s = sizesConfig[size ?? 'default'];\n\n const handleToggle = () => {\n if (disabled) return;\n const newValue = !isPressed;\n if (!isControlled) {\n setUncontrolledPressed(newValue);\n }\n onPressedChange?.(newValue);\n };\n\n const getTrackStyles = (): CSSProperties => {\n if (variant === 'outline') {\n return {\n background: isPressed ? 'var(--toggle-outline-active-bg)' : 'transparent',\n borderColor: isPressed\n ? 'var(--toggle-outline-active-border)'\n : 'var(--toggle-outline-border)',\n boxShadow: isFocusVisible && !disabled ? 'var(--focus-glow)' : 'none',\n };\n }\n return {\n background: isPressed ? 'var(--toggle-active-bg)' : 'var(--toggle-bg)',\n boxShadow:\n isFocusVisible && !disabled\n ? 'var(--focus-glow)'\n : isPressed\n ? 'var(--toggle-glow)'\n : 'none',\n };\n };\n\n const knobStyles: CSSProperties = {\n background: 'var(--toggle-knob)',\n };\n\n // Touch area wrapper ensures 44px minimum touch target (Apple HIG)\n const toggle = (\n <span className=\"inline-flex items-center justify-center min-h-11\">\n <button\n ref={ref}\n type=\"button\"\n role=\"switch\"\n aria-pressed={isPressed}\n aria-label={label || 'Toggle switch'}\n disabled={disabled}\n className={cn(\n toggleSizes({ size, variant }),\n disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer',\n !label && className\n )}\n style={getTrackStyles()}\n onClick={handleToggle}\n onFocus={focusProps.onFocus}\n onBlur={focusProps.onBlur}\n {...props}\n >\n <div\n className={cn(\n 'absolute top-0.5 left-0.5 rounded-full shadow-md transition-all duration-300',\n s.knob,\n isPressed && s.translate\n )}\n style={knobStyles}\n />\n </button>\n </span>\n );\n\n if (label) {\n return (\n <label\n className={cn(\n 'inline-flex items-center gap-2 md:gap-2.5',\n disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer',\n className\n )}\n >\n {toggle}\n <span className=\"text-xs md:text-sm\" style={{ color: 'var(--text-secondary)' }}>\n {label}\n </span>\n </label>\n );\n }\n\n return toggle;\n }\n);\n\nToggleGlass.displayName = 'ToggleGlass';\n"
|
|
20
|
+
"content": "/**\n * ToggleGlass Component\n *\n * Glass-themed toggle switch with shadcn/ui compatible API:\n * - Theme-aware styling (glass/light/aurora)\n * - Glow effect when active\n * - Size variants (default, sm, lg)\n * - Variant styles (default, outline)\n * - Optional label\n *\n * **shadcn/ui compatible props:**\n * - `pressed` / `defaultPressed` - Control pressed state\n * - `onPressedChange` - Callback when state changes\n * - `variant` - 'default' | 'outline'\n * - `size` - 'default' | 'sm' | 'lg'\n *\n * @example\n * ```tsx\n * // Controlled\n * <ToggleGlass pressed={isOn} onPressedChange={setIsOn} />\n *\n * // Uncontrolled\n * <ToggleGlass defaultPressed={true} />\n *\n * // With variant\n * <ToggleGlass variant=\"outline\" pressed={isOn} onPressedChange={setIsOn} />\n * ```\n */\n\nimport { forwardRef, useState, type CSSProperties } from 'react';\nimport { type VariantProps } from 'class-variance-authority';\nimport { cn } from '@/lib/utils';\nimport { useFocus } from '@/lib/hooks/use-focus';\nimport { toggleSizes, type ToggleGlassVariant } from '@/lib/variants/toggle-glass-variants';\nimport '@/glass-theme.css';\n\n// ========================================\n// SIZE CONFIG\n// ========================================\n\nconst sizesConfig = {\n sm: { track: 'w-8 h-4', knob: 'w-3 h-3', translate: 'translate-x-4' },\n default: { track: 'w-11 h-6', knob: 'w-5 h-5', translate: 'translate-x-5' },\n lg: { track: 'w-14 h-7', knob: 'w-6 h-6', translate: 'translate-x-7' },\n} as const;\n\n// ========================================\n// PROPS INTERFACE\n// ========================================\n\nexport interface ToggleGlassProps\n extends\n Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onChange' | 'defaultValue'>,\n VariantProps<typeof toggleSizes> {\n /**\n * Controlled pressed state (shadcn/ui compatible)\n */\n readonly pressed?: boolean;\n /**\n * Default pressed state for uncontrolled usage\n */\n readonly defaultPressed?: boolean;\n /**\n * Callback when pressed state changes (shadcn/ui compatible)\n */\n readonly onPressedChange?: (pressed: boolean) => void;\n /**\n * Visual variant (shadcn/ui compatible)\n * @default \"default\"\n */\n readonly variant?: ToggleGlassVariant;\n /**\n * Optional label text\n */\n readonly label?: string;\n}\n\n// ========================================\n// COMPONENT\n// ========================================\n\nexport const ToggleGlass = forwardRef<HTMLButtonElement, ToggleGlassProps>(\n (\n {\n className,\n size = 'default',\n variant = 'default',\n pressed: controlledPressed,\n defaultPressed = false,\n onPressedChange,\n disabled,\n label,\n ...props\n },\n ref\n ) => {\n // Support both controlled and uncontrolled modes\n const [uncontrolledPressed, setUncontrolledPressed] = useState(defaultPressed);\n const isControlled = controlledPressed !== undefined;\n const isPressed = isControlled ? controlledPressed : uncontrolledPressed;\n\n const { isFocusVisible, focusProps } = useFocus({ focusVisible: true });\n const s = sizesConfig[size ?? 'default'];\n\n const handleToggle = () => {\n if (disabled) return;\n const newValue = !isPressed;\n if (!isControlled) {\n setUncontrolledPressed(newValue);\n }\n onPressedChange?.(newValue);\n };\n\n const getTrackStyles = (): CSSProperties => {\n if (variant === 'outline') {\n return {\n background: isPressed ? 'var(--toggle-outline-active-bg)' : 'transparent',\n borderColor: isPressed\n ? 'var(--toggle-outline-active-border)'\n : 'var(--toggle-outline-border)',\n boxShadow: isFocusVisible && !disabled ? 'var(--focus-glow)' : 'none',\n };\n }\n return {\n background: isPressed ? 'var(--toggle-active-bg)' : 'var(--toggle-bg)',\n boxShadow:\n isFocusVisible && !disabled\n ? 'var(--focus-glow)'\n : isPressed\n ? 'var(--toggle-glow)'\n : 'none',\n };\n };\n\n const knobStyles: CSSProperties = {\n background: 'var(--toggle-knob)',\n };\n\n // Touch area wrapper ensures 44px minimum touch target (Apple HIG)\n const toggle = (\n <span className=\"inline-flex items-center justify-center min-h-11\">\n <button\n ref={ref}\n data-slot=\"toggle\"\n type=\"button\"\n role=\"switch\"\n aria-pressed={isPressed}\n aria-label={label || 'Toggle switch'}\n disabled={disabled}\n className={cn(\n toggleSizes({ size, variant }),\n disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer',\n !label && className\n )}\n style={getTrackStyles()}\n onClick={handleToggle}\n onFocus={focusProps.onFocus}\n onBlur={focusProps.onBlur}\n {...props}\n >\n <div\n className={cn(\n 'absolute top-0.5 left-0.5 rounded-full shadow-md transition-all duration-300',\n s.knob,\n isPressed && s.translate\n )}\n style={knobStyles}\n />\n </button>\n </span>\n );\n\n if (label) {\n return (\n <label\n className={cn(\n 'inline-flex items-center gap-2 md:gap-2.5',\n disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer',\n className\n )}\n >\n {toggle}\n <span className=\"text-xs md:text-sm\" style={{ color: 'var(--text-secondary)' }}>\n {label}\n </span>\n </label>\n );\n }\n\n return toggle;\n }\n);\n\nToggleGlass.displayName = 'ToggleGlass';\n"
|
|
21
21
|
}
|
|
22
22
|
],
|
|
23
23
|
"categories": [
|