@catalystsoftware/ui 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +7 -0
  2. package/components/catalyst-ui/buttons/burger.tsx +207 -0
  3. package/components/catalyst-ui/core/data-display/timeline.tsx +210 -0
  4. package/components/catalyst-ui/core/feedback/alert.tsx +491 -0
  5. package/components/catalyst-ui/core/feedback/spinner-1.tsx +65 -0
  6. package/components/catalyst-ui/core/feedback/toast.tsx +1857 -0
  7. package/components/catalyst-ui/core/navigation/menu.tsx +164 -0
  8. package/components/catalyst-ui/forms/toggle-class.tsx +176 -0
  9. package/components/catalyst-ui/hooks/use-copy-to-clipboard.tsx +419 -0
  10. package/components/catalyst-ui/hooks/use-counter.tsx +13 -0
  11. package/components/catalyst-ui/hooks/use-event-listener.tsx +23 -0
  12. package/components/catalyst-ui/hooks/use-export-markdown.tsx +47 -0
  13. package/components/catalyst-ui/hooks/use-focus.tsx +17 -0
  14. package/components/catalyst-ui/hooks/use-interval.tsx +23 -0
  15. package/components/catalyst-ui/hooks/use-is-client.tsx +16 -0
  16. package/components/catalyst-ui/hooks/use-media-query.tsx +19 -0
  17. package/components/catalyst-ui/hooks/use-mobile.tsx +19 -0
  18. package/components/catalyst-ui/hooks/use-resize-observer.tsx +81 -0
  19. package/components/catalyst-ui/hooks/use-timeout.tsx +21 -0
  20. package/components/catalyst-ui/hooks/use-timer.tsx +209 -0
  21. package/components/catalyst-ui/hooks/use-toggle.tsx +12 -0
  22. package/components/catalyst-ui/media/image.tsx +13 -0
  23. package/components/catalyst-ui/overlays/dual-sidebar.tsx +4142 -0
  24. package/components/catalyst-ui/overlays/sidebar-original.tsx +726 -0
  25. package/components/catalyst-ui/primitives/accordion.tsx +250 -0
  26. package/components/catalyst-ui/primitives/alert-dialog.tsx +126 -0
  27. package/components/catalyst-ui/primitives/aspect-ratio.tsx +9 -0
  28. package/components/catalyst-ui/primitives/avatar.tsx +296 -0
  29. package/components/catalyst-ui/primitives/badge.tsx +57 -0
  30. package/components/catalyst-ui/primitives/breadcrumb.tsx +101 -0
  31. package/components/catalyst-ui/primitives/button.tsx +265 -0
  32. package/components/catalyst-ui/primitives/calendar-v4.tsx +208 -0
  33. package/components/catalyst-ui/primitives/calendar.tsx +295 -0
  34. package/components/catalyst-ui/primitives/card.tsx +618 -0
  35. package/components/catalyst-ui/primitives/carousel.tsx +238 -0
  36. package/components/catalyst-ui/primitives/chart.tsx +347 -0
  37. package/components/catalyst-ui/primitives/checkbox.tsx +225 -0
  38. package/components/catalyst-ui/primitives/collapsible.tsx +212 -0
  39. package/components/catalyst-ui/primitives/command.tsx +393 -0
  40. package/components/catalyst-ui/primitives/context-menu.tsx +236 -0
  41. package/components/catalyst-ui/primitives/dialog.tsx +471 -0
  42. package/components/catalyst-ui/primitives/drawer.tsx +761 -0
  43. package/components/catalyst-ui/primitives/dropdown-menu.tsx +290 -0
  44. package/components/catalyst-ui/primitives/empty.tsx +104 -0
  45. package/components/catalyst-ui/primitives/field.tsx +244 -0
  46. package/components/catalyst-ui/primitives/hover-card.tsx +124 -0
  47. package/components/catalyst-ui/primitives/input-otp.tsx +76 -0
  48. package/components/catalyst-ui/primitives/input.tsx +64 -0
  49. package/components/catalyst-ui/primitives/item.tsx +196 -0
  50. package/components/catalyst-ui/primitives/kbd.tsx +75 -0
  51. package/components/catalyst-ui/primitives/label.tsx +24 -0
  52. package/components/catalyst-ui/primitives/navigation-menu.tsx +150 -0
  53. package/components/catalyst-ui/primitives/pagination.tsx +198 -0
  54. package/components/catalyst-ui/primitives/popover.tsx +232 -0
  55. package/components/catalyst-ui/primitives/progress.tsx +34 -0
  56. package/components/catalyst-ui/primitives/radio-group.tsx +43 -0
  57. package/components/catalyst-ui/primitives/resizable.tsx +56 -0
  58. package/components/catalyst-ui/primitives/select.tsx +155 -0
  59. package/components/catalyst-ui/primitives/separator.tsx +74 -0
  60. package/components/catalyst-ui/primitives/sheet.tsx +126 -0
  61. package/components/catalyst-ui/primitives/skeleton.tsx +15 -0
  62. package/components/catalyst-ui/primitives/slider.tsx +27 -0
  63. package/components/catalyst-ui/primitives/switch.tsx +187 -0
  64. package/components/catalyst-ui/primitives/tabs.tsx +335 -0
  65. package/components/catalyst-ui/primitives/textarea.tsx +24 -0
  66. package/components/catalyst-ui/primitives/toggle-group.tsx +55 -0
  67. package/components/catalyst-ui/primitives/toggle.tsx +42 -0
  68. package/components/catalyst-ui/primitives/tooltip.tsx +116 -0
  69. package/components/catalyst-ui/utils/basic-auth.tsx +40 -0
  70. package/components/catalyst-ui/utils/context-storage.tsx +19 -0
  71. package/components/catalyst-ui/utils/cors-middleware.tsx +71 -0
  72. package/components/catalyst-ui/utils/deferred-content.tsx +595 -0
  73. package/components/catalyst-ui/utils/honeypot-middleware.tsx +38 -0
  74. package/components/catalyst-ui/utils/incId.tsx +75 -0
  75. package/components/catalyst-ui/utils/jwk-auth.tsx +36 -0
  76. package/components/catalyst-ui/utils/request-id.tsx +14 -0
  77. package/components/catalyst-ui/utils/secure-headers.tsx +37 -0
  78. package/components/catalyst-ui/utils/server-timing.tsx +23 -0
  79. package/components/catalyst-ui/utils/utils.ts +43 -0
  80. package/components/catalyst-ui/utils/with-cookie.tsx +43 -0
  81. package/components/catalyst-ui/x/accordian-x.tsx +428 -0
  82. package/components/catalyst-ui/x/alert-x.tsx +413 -0
  83. package/components/catalyst-ui/x/animated-text-x.tsx +2242 -0
  84. package/components/catalyst-ui/x/avatar-x.tsx +515 -0
  85. package/components/catalyst-ui/x/badge-x.tsx +670 -0
  86. package/components/catalyst-ui/x/button-X.tsx +2857 -0
  87. package/components/catalyst-ui/x/button-group-x.tsx +847 -0
  88. package/components/catalyst-ui/x/calendar-x.tsx +1910 -0
  89. package/components/catalyst-ui/x/card-x.tsx +2597 -0
  90. package/components/catalyst-ui/x/checkbox-x.tsx +656 -0
  91. package/components/catalyst-ui/x/collapsible-x.tsx +1360 -0
  92. package/components/catalyst-ui/x/combobox-x.tsx +911 -0
  93. package/components/catalyst-ui/x/data-table-x.tsx +1753 -0
  94. package/components/catalyst-ui/x/date-picker-x.tsx +648 -0
  95. package/components/catalyst-ui/x/dialog-x.tsx +659 -0
  96. package/components/catalyst-ui/x/dropdown-menu-x.tsx +612 -0
  97. package/components/catalyst-ui/x/hover-card-x.tsx +375 -0
  98. package/components/catalyst-ui/x/icon-x.tsx +840 -0
  99. package/components/catalyst-ui/x/input-mask-x.tsx +981 -0
  100. package/components/catalyst-ui/x/input-otp-x.tsx +659 -0
  101. package/components/catalyst-ui/x/loader-x.tsx +1757 -0
  102. package/components/catalyst-ui/x/pagination-x.tsx +622 -0
  103. package/components/catalyst-ui/x/popover-x.tsx +744 -0
  104. package/components/catalyst-ui/x/radio-group-x.tsx +499 -0
  105. package/components/catalyst-ui/x/select-x.tsx +1127 -0
  106. package/components/catalyst-ui/x/sheet-x.tsx +668 -0
  107. package/components/catalyst-ui/x/switch-x.tsx +681 -0
  108. package/components/catalyst-ui/x/table-x.tsx +574 -0
  109. package/components/catalyst-ui/x/tabs-x.tsx +839 -0
  110. package/components/catalyst-ui/x/textarea-x.tsx +1263 -0
  111. package/components/catalyst-ui/x/tooltip-x.tsx +396 -0
  112. package/components/catalyst-ui/x/tracker-x.tsx +560 -0
  113. package/data/bg-data.tsx +901 -0
  114. package/data/buttons-data.tsx +2327 -0
  115. package/data/charts-data.tsx +102 -0
  116. package/data/chat-data.tsx +83 -0
  117. package/data/code-data.tsx +1040 -0
  118. package/data/comboboxes-data.tsx +1843 -0
  119. package/data/command-data.tsx +1381 -0
  120. package/data/core-data.tsx +15953 -0
  121. package/data/crm-data.tsx +47 -0
  122. package/data/data.tsx +159 -0
  123. package/data/date-and-time-data.tsx +554 -0
  124. package/data/dependencies.tsx +7 -0
  125. package/data/ecommerce-data.tsx +1387 -0
  126. package/data/forms-data.tsx +7890 -0
  127. package/data/hooks-data.tsx +5487 -0
  128. package/data/index.ts +34 -0
  129. package/data/inputs-data.tsx +557 -0
  130. package/data/interactive-data.tsx +5394 -0
  131. package/data/lofi-data.tsx +18295 -0
  132. package/data/marketing-data.tsx +2546 -0
  133. package/data/media-data.tsx +1510 -0
  134. package/data/motion-data.tsx +5801 -0
  135. package/data/overlay-data.tsx +4136 -0
  136. package/data/pdf-data.tsx +124 -0
  137. package/data/pos-data.tsx +213 -0
  138. package/data/postcss.config.js +6 -0
  139. package/data/primitive-data.tsx +5170 -0
  140. package/data/prompt-data.tsx +1226 -0
  141. package/data/requiredLibs.ts +4 -0
  142. package/data/sandbox-data.tsx +1 -0
  143. package/data/sidebars-data.tsx +5421 -0
  144. package/data/stacks-data.tsx +32 -0
  145. package/data/table-data.tsx +706 -0
  146. package/data/tailwind.config.js +3830 -0
  147. package/data/tailwind.config.ngin.js +3830 -0
  148. package/data/tailwind.css +431 -0
  149. package/data/tools-data.tsx +6910 -0
  150. package/data/typography-data.tsx +2050 -0
  151. package/data/utils-data.tsx +6500 -0
  152. package/data/x-data.tsx +1171 -0
  153. package/dist/index.d.ts +3 -0
  154. package/dist/index.d.ts.map +1 -0
  155. package/dist/index.js +30245 -0
  156. package/dist/index.js.map +362 -0
  157. package/package.json +50 -0
@@ -0,0 +1,681 @@
1
+ import React, { useId, useState } from 'react'
2
+ import { Switch, switchRootVariants, switchThumbVariants, Label } from '~/components/catalyst-ui'
3
+ import { MoonIcon, SunIcon, CheckIcon, XIcon, DatabaseIcon, CodeIcon, PaletteIcon, ShieldIcon } from 'lucide-react'
4
+ import { cn } from '~/components/catalyst-ui'
5
+
6
+ export function SwitchXGroup({ variant, className, children }: any) {
7
+ switch (variant) {
8
+ case 'vertical':
9
+ return (
10
+ <div className={cn('flex flex-col *:rounded-none *:shadow-none *:not-last:border-b-0 *:first:rounded-t-xl *:last:rounded-b-xl', className)}>
11
+ {children}
12
+ </div>
13
+ )
14
+ default:
15
+ return (
16
+ <div className={cn('flex *:rounded-none *:shadow-none max-xl:flex-col max-xl:*:not-last:border-b-0 max-xl:*:first:rounded-t-xl max-xl:*:last:rounded-b-xl xl:*:not-last:border-r-0 xl:*:first:rounded-l-xl xl:*:last:rounded-r-xl', className)}>
17
+ {children}
18
+ </div>
19
+ )
20
+ }
21
+ }
22
+
23
+
24
+ export function SwitchX({ switch: switchType = 'default', ...props }: any) {
25
+ switch (switchType) {
26
+ case 'toggleLabel':
27
+ return <ToggleLabel {...props} />
28
+ case 'dualToggleLabel':
29
+ return <DualToggleLabel {...props} />
30
+ case 'iconLabel':
31
+ return <IconLabel {...props} />
32
+ case 'dualIconLabel':
33
+ return <DualIconLabel {...props} />
34
+ case 'iconIndicator':
35
+ return <IconIndicator {...props} />
36
+ case 'permanentIndicator':
37
+ return <PermanentIndicator {...props} />
38
+ case 'squarePermanentIndicator':
39
+ return <SquarePermanentIndicator {...props} />
40
+ case 'animated':
41
+ return <Animated {...props} />
42
+ case 'animatedGradient':
43
+ return <AnimatedGradient {...props} />
44
+ case 'card':
45
+ return <Card {...props} />
46
+ case 'gradient':
47
+ return <Gradient {...props} />
48
+ case 'colors':
49
+ return <Colors {...props} />
50
+ case 'sizes':
51
+ return <Sizes {...props} />
52
+ case 'square':
53
+ return <Square {...props} />
54
+ case 'mini':
55
+ return <Mini {...props} />
56
+ case 'outline':
57
+ return <Outline {...props} />
58
+ default:
59
+ return <DefaultSwitch {...props} />
60
+ }
61
+ }
62
+
63
+ const DefaultSwitch = ({ label, className, size, variant, shape, style, mini, ...props }) => {
64
+ const id = useId()
65
+
66
+ return (
67
+ <div className='flex items-center space-x-2'>
68
+ <Switch id={id} size={size} variant={variant} shape={shape} style={style} mini={mini} className={className} {...props} />
69
+ {label && <Label htmlFor={id}>{label}</Label>}
70
+ </div>
71
+ )
72
+ }
73
+
74
+ const ToggleLabel = ({ checked: controlledChecked, onCheckedChange, label, yesLabel = 'Yes', noLabel = 'No', className, size, variant, shape, style, mini, ...props }) => {
75
+ const id = useId()
76
+ const [internalChecked, setInternalChecked] = useState(false)
77
+ const checked = controlledChecked !== undefined ? controlledChecked : internalChecked
78
+ const handleChange = (value: boolean) => {
79
+ if (onCheckedChange) {
80
+ onCheckedChange(value)
81
+ } else {
82
+ setInternalChecked(value)
83
+ }
84
+ }
85
+
86
+ return (
87
+ <div className='inline-flex items-center gap-2'>
88
+ <Switch id={id} checked={checked} onCheckedChange={handleChange} size={size} variant={variant} shape={shape} style={style} mini={mini} className={className} {...props} />
89
+ <Label htmlFor={id} className='text-sm font-medium'>
90
+ {checked ? yesLabel : noLabel}
91
+ </Label>
92
+ </div>
93
+ )
94
+ }
95
+
96
+ const DualToggleLabel = ({ checked: controlledChecked, onCheckedChange, yesLabel = 'Yes', noLabel = 'No', className, size, variant, shape, style, mini, ...props }) => {
97
+ const id = useId()
98
+ const [internalChecked, setInternalChecked] = useState(false)
99
+ const checked = controlledChecked !== undefined ? controlledChecked : internalChecked
100
+ const handleChange = (value: boolean) => {
101
+ if (onCheckedChange) {
102
+ onCheckedChange(value)
103
+ } else {
104
+ setInternalChecked(value)
105
+ }
106
+ }
107
+
108
+ return (
109
+ <div className='group inline-flex items-center gap-2' data-state={checked ? 'checked' : 'unchecked'}>
110
+ <span
111
+ id={`${id}-yes`}
112
+ className='group-data-[state=checked]:text-muted-foreground/70 cursor-pointer text-right text-sm font-medium'
113
+ aria-controls={id}
114
+ onClick={() => handleChange(false)}
115
+ >
116
+ {yesLabel}
117
+ </span>
118
+ <Switch id={id} checked={checked} onCheckedChange={handleChange} size={size} variant={variant} shape={shape} style={style} mini={mini} className={className} {...props} />
119
+ <span
120
+ id={`${id}-no`}
121
+ className='group-data-[state=unchecked]:text-muted-foreground/70 cursor-pointer text-left text-sm font-medium'
122
+ aria-controls={id}
123
+ onClick={() => handleChange(true)}
124
+ >
125
+ {noLabel}
126
+ </span>
127
+ </div>
128
+ )
129
+ }
130
+
131
+ const IconLabel = ({ checked: controlledChecked, onCheckedChange, checkedIcon: CheckedIcon = MoonIcon, uncheckedIcon: UncheckedIcon = SunIcon, className, size, variant, shape, style, mini, ...props }) => {
132
+ const id = useId()
133
+ const [internalChecked, setInternalChecked] = useState(true)
134
+ const checked = controlledChecked !== undefined ? controlledChecked : internalChecked
135
+ const handleChange = (value: boolean) => {
136
+ if (onCheckedChange) {
137
+ onCheckedChange(value)
138
+ } else {
139
+ setInternalChecked(value)
140
+ }
141
+ }
142
+
143
+ return (
144
+ <div className='inline-flex items-center gap-2'>
145
+ <Switch id={id} checked={checked} onCheckedChange={handleChange} size={size} variant={variant} shape={shape} style={style} mini={mini} className={className} {...props} />
146
+ <Label htmlFor={id}>
147
+ <span className='sr-only'>Toggle switch</span>
148
+ {checked ? (
149
+ <CheckedIcon className='size-4' aria-hidden='true' />
150
+ ) : (
151
+ <UncheckedIcon className='size-4' aria-hidden='true' />
152
+ )}
153
+ </Label>
154
+ </div>
155
+ )
156
+ }
157
+
158
+ const DualIconLabel = ({ checked: controlledChecked, onCheckedChange, checkedIcon: CheckedIcon = MoonIcon, uncheckedIcon: UncheckedIcon = SunIcon, className, size, variant, shape, style, mini, ...props }) => {
159
+ const id = useId()
160
+ const [internalChecked, setInternalChecked] = useState(true)
161
+ const checked = controlledChecked !== undefined ? controlledChecked : internalChecked
162
+ const handleChange = (value: boolean) => {
163
+ if (onCheckedChange) {
164
+ onCheckedChange(value)
165
+ } else {
166
+ setInternalChecked(value)
167
+ }
168
+ }
169
+
170
+ return (
171
+ <div className='group inline-flex items-center gap-2' data-state={checked ? 'checked' : 'unchecked'}>
172
+ <span
173
+ id={`${id}-light`}
174
+ className='group-data-[state=checked]:text-muted-foreground/70 cursor-pointer text-left text-sm font-medium'
175
+ aria-controls={id}
176
+ onClick={() => handleChange(false)}
177
+ >
178
+ <UncheckedIcon className='size-4' aria-hidden='true' />
179
+ </span>
180
+ <Switch
181
+ id={id}
182
+ checked={checked}
183
+ onCheckedChange={handleChange}
184
+ size={size}
185
+ variant={variant}
186
+ shape={shape}
187
+ style={style}
188
+ mini={mini}
189
+ className={className}
190
+ {...props}
191
+ />
192
+ <span
193
+ id={`${id}-dark`}
194
+ className='group-data-[state=unchecked]:text-muted-foreground/70 cursor-pointer text-right text-sm font-medium'
195
+ aria-controls={id}
196
+ onClick={() => handleChange(true)}
197
+ >
198
+ <CheckedIcon className='size-4' aria-hidden='true' />
199
+ </span>
200
+ </div>
201
+ )
202
+ }
203
+
204
+ const IconIndicator = ({ checked: controlledChecked, onCheckedChange, checkedIcon: CheckedIcon = CheckIcon, uncheckedIcon: UncheckedIcon = XIcon, className, size, variant, shape, style, mini, ...props }) => {
205
+ const [internalChecked, setInternalChecked] = useState(true)
206
+ const checked = controlledChecked !== undefined ? controlledChecked : internalChecked
207
+ const handleChange = (value: boolean) => {
208
+ if (onCheckedChange) {
209
+ onCheckedChange(value)
210
+ } else {
211
+ setInternalChecked(value)
212
+ }
213
+ }
214
+
215
+ return (
216
+ <div>
217
+ <div className='relative inline-grid h-7 grid-cols-[1fr_1fr] items-center text-sm font-medium'>
218
+ <Switch
219
+ checked={checked}
220
+ onCheckedChange={handleChange}
221
+ className={cn(
222
+ switchRootVariants({ size, variant, shape, style, mini }),
223
+ 'peer data-[state=checked]:bg-input/50 data-[state=unchecked]:bg-input/50 [&_span]:!bg-background absolute inset-0 h-[inherit] w-14 [&_span]:size-6.5 [&_span]:transition-transform [&_span]:duration-300 [&_span]:ease-[cubic-bezier(0.16,1,0.3,1)] [&_span]:data-[state=checked]:translate-x-7 [&_span]:data-[state=checked]:rtl:-translate-x-7',
224
+ className
225
+ )}
226
+ {...props}
227
+ />
228
+ <span className='peer-data-[state=checked]:text-muted-foreground/70 pointer-events-none relative ml-1.75 flex min-w-7 items-center text-center'>
229
+ <CheckedIcon className='size-4' aria-hidden='true' />
230
+ </span>
231
+ <span className='peer-data-[state=unchecked]:text-muted-foreground/70 pointer-events-none relative -ms-0.25 flex min-w-7 items-center text-center'>
232
+ <UncheckedIcon className='size-4' aria-hidden='true' />
233
+ </span>
234
+ </div>
235
+ </div>
236
+ )
237
+ }
238
+
239
+ const PermanentIndicator = ({ checked: controlledChecked, onCheckedChange, checkedIcon: CheckedIcon = CheckIcon, uncheckedIcon: UncheckedIcon = XIcon, className, size, variant, shape, style, mini, ...props }) => {
240
+ const [internalChecked, setInternalChecked] = useState(true)
241
+ const checked = controlledChecked !== undefined ? controlledChecked : internalChecked
242
+ const handleChange = (value: boolean) => {
243
+ if (onCheckedChange) {
244
+ onCheckedChange(value)
245
+ } else {
246
+ setInternalChecked(value)
247
+ }
248
+ }
249
+
250
+ return (
251
+ <div>
252
+ <div className='relative inline-grid h-7 grid-cols-[1fr_1fr] items-center text-sm font-medium'>
253
+ <Switch
254
+ checked={checked}
255
+ onCheckedChange={handleChange}
256
+ className={cn(
257
+ switchRootVariants({ size, variant, shape, style, mini }),
258
+ 'peer data-[state=unchecked]:bg-input/50 absolute inset-0 h-[inherit] w-14 [&_span]:z-10 [&_span]:size-6.5 [&_span]:transition-transform [&_span]:duration-300 [&_span]:ease-[cubic-bezier(0.16,1,0.3,1)] [&_span]:data-[state=checked]:translate-x-7 [&_span]:data-[state=checked]:rtl:-translate-x-7',
259
+ className
260
+ )}
261
+ {...props}
262
+ />
263
+ <span className='pointer-events-none relative ml-0.5 flex min-w-8 items-center justify-center text-center transition-transform duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] peer-data-[state=checked]:invisible peer-data-[state=unchecked]:translate-x-6 peer-data-[state=unchecked]:rtl:-translate-x-6'>
264
+ <UncheckedIcon className='size-4' aria-hidden='true' />
265
+ </span>
266
+ <span className='peer-data-[state=checked]:text-background pointer-events-none relative flex min-w-8 items-center justify-center text-center transition-transform duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] peer-data-[state=checked]:-translate-x-full peer-data-[state=unchecked]:invisible peer-data-[state=checked]:rtl:translate-x-full'>
267
+ <CheckedIcon className='size-4' aria-hidden='true' />
268
+ </span>
269
+ </div>
270
+ </div>
271
+ )
272
+ }
273
+
274
+ const SquarePermanentIndicator = ({ checked: controlledChecked, onCheckedChange, yesLabel = 'Yes', noLabel = 'No', className, size, variant, shape, style, mini, ...props }) => {
275
+ const [internalChecked, setInternalChecked] = useState(true)
276
+ const checked = controlledChecked !== undefined ? controlledChecked : internalChecked
277
+ const handleChange = (value: boolean) => {
278
+ if (onCheckedChange) {
279
+ onCheckedChange(value)
280
+ } else {
281
+ setInternalChecked(value)
282
+ }
283
+ }
284
+
285
+ return (
286
+ <div>
287
+ <div className='relative inline-grid h-8 grid-cols-[1fr_1fr] items-center text-sm font-medium'>
288
+ <Switch
289
+ checked={checked}
290
+ onCheckedChange={handleChange}
291
+ className={cn(
292
+ switchRootVariants({ size, variant, shape, style, mini }),
293
+ 'peer data-[state=unchecked]:bg-input/50 absolute inset-0 h-[inherit] w-auto rounded-md [&_span]:z-10 [&_span]:h-full [&_span]:w-1/2 [&_span]:rounded-sm [&_span]:transition-transform [&_span]:duration-300 [&_span]:ease-[cubic-bezier(0.16,1,0.3,1)] [&_span]:data-[state=checked]:translate-x-8.75 [&_span]:data-[state=checked]:rtl:-translate-x-8.75',
294
+ className
295
+ )}
296
+ {...props}
297
+ />
298
+ <span className='pointer-events-none relative ml-0.5 flex items-center justify-center px-2 text-center transition-transform duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] peer-data-[state=checked]:invisible peer-data-[state=unchecked]:translate-x-full peer-data-[state=unchecked]:rtl:-translate-x-full'>
299
+ <span className='text-[10px] font-medium uppercase'>{noLabel}</span>
300
+ </span>
301
+ <span className='peer-data-[state=checked]:text-background pointer-events-none relative mr-0.5 flex items-center justify-center px-2 text-center transition-transform duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] peer-data-[state=checked]:-translate-x-full peer-data-[state=unchecked]:invisible peer-data-[state=checked]:rtl:translate-x-full'>
302
+ <span className='text-[10px] font-medium uppercase'>{yesLabel}</span>
303
+ </span>
304
+ </div>
305
+ </div>
306
+ )
307
+ }
308
+
309
+ const Animated = ({ label, className, size, variant, shape, style, mini, ...props }) => {
310
+ const id = useId()
311
+
312
+ return (
313
+ <div className='flex items-center space-x-2'>
314
+ <Switch id={id} size={size} variant={variant} shape={shape} style={style} mini={mini} className={className} {...props} />
315
+ {label && <Label htmlFor={id}>{label}</Label>}
316
+ </div>
317
+ )
318
+ }
319
+
320
+ const AnimatedGradient = ({ label, className, size, variant, shape, style, mini, ...props }) => {
321
+ const id = useId()
322
+
323
+ return (
324
+ <div className='flex items-center space-x-2'>
325
+ <Switch
326
+ id={id}
327
+ size={size}
328
+ variant={variant}
329
+ shape={shape}
330
+ style={style}
331
+ mini={mini}
332
+ className={cn(
333
+ 'focus-visible:border-destructive to-destructive/60 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 border-none bg-gradient-to-r from-amber-500 data-[state=checked]:from-sky-400 data-[state=checked]:to-indigo-700 [&_span]:size-5 [&_span]:!translate-x-0.25',
334
+ className
335
+ )}
336
+ {...props}
337
+ />
338
+ {label && <Label htmlFor={id}>{label}</Label>}
339
+ </div>
340
+ )
341
+ }
342
+
343
+ const Card = ({ icon: Icon = DatabaseIcon, title, description, className, size, variant, shape, style, mini, ...props }) => {
344
+ const id = useId()
345
+
346
+ return (
347
+ <div className='border-input has-data-[state=checked]:border-primary/50 relative flex w-full items-start gap-2 rounded-md border p-4 shadow-xs outline-none'>
348
+ <Switch
349
+ id={id}
350
+ size={size}
351
+ variant={variant}
352
+ shape={shape}
353
+ style={style}
354
+ mini={mini}
355
+ className={cn(
356
+ 'order-1 h-4 w-6 after:absolute after:inset-0 [&_span]:size-3 data-[state=checked]:[&_span]:translate-x-2.5 data-[state=checked]:[&_span]:rtl:-translate-x-2.5',
357
+ className
358
+ )}
359
+ {...props}
360
+ />
361
+ <div className='flex grow items-center gap-3'>
362
+ {Icon && <Icon className='size-5' />}
363
+ <div className='grid grow gap-2'>
364
+ {title && <Label htmlFor={id}>{title}</Label>}
365
+ {description && (
366
+ <p id={`${id}-description`} className='text-muted-foreground text-xs'>
367
+ {description}
368
+ </p>
369
+ )}
370
+ </div>
371
+ </div>
372
+ </div>
373
+ )
374
+ }
375
+
376
+
377
+ const Gradient = ({ label, className, size, variant, shape, style, mini, ...props }) => {
378
+ const id = useId()
379
+
380
+ return (
381
+ <div className='flex items-center space-x-2'>
382
+ <Switch
383
+ id={id}
384
+ size={size}
385
+ variant={variant}
386
+ shape={shape}
387
+ style={style}
388
+ mini={mini}
389
+ className={cn(
390
+ 'focus-visible:border-destructive to-destructive/60 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 h-6 w-10 border-none bg-gradient-to-r from-amber-500 data-[state=checked]:from-sky-400 data-[state=checked]:to-indigo-700 [&_span]:size-5 [&_span]:!translate-x-0.25 data-[state=checked]:[&_span]:!translate-x-4.75 data-[state=checked]:[&_span]:rtl:!-translate-x-4.75',
391
+ className
392
+ )}
393
+ {...props}
394
+ />
395
+ {label && <Label htmlFor={id}>{label}</Label>}
396
+ </div>
397
+ )
398
+ }
399
+
400
+ const Colors = ({ colorVariant = 'destructive', label, className, size, variant, shape, style, mini, ...props }) => {
401
+ const id = useId()
402
+
403
+ return (
404
+ <div className='flex items-center gap-3'>
405
+ <Switch
406
+ id={id}
407
+ size={size}
408
+ variant={colorVariant}
409
+ shape={shape}
410
+ style={style}
411
+ mini={mini}
412
+ className={className}
413
+ defaultChecked
414
+ {...props}
415
+ />
416
+ {label && <Label htmlFor={id}>{label}</Label>}
417
+ </div>
418
+ )
419
+ }
420
+
421
+ const Sizes = ({ sizeVariant = 'sm', label, className, variant, shape, style, mini, ...props }) => {
422
+ const id = useId()
423
+
424
+ return (
425
+ <div className='flex items-center gap-3'>
426
+ <Switch
427
+ id={id}
428
+ size={sizeVariant}
429
+ variant={variant}
430
+ shape={shape}
431
+ style={style}
432
+ mini={mini}
433
+ className={className}
434
+ {...props}
435
+ />
436
+ {label && <Label htmlFor={id}>{label}</Label>}
437
+ </div>
438
+ )
439
+ }
440
+
441
+ const Square = ({ label, className, size, variant, shape, style, mini, ...props }) => {
442
+ const id = useId()
443
+
444
+ return (
445
+ <div className='flex items-center space-x-2'>
446
+ <Switch
447
+ id={id}
448
+ size={size}
449
+ variant={variant}
450
+ shape='square'
451
+ style={style}
452
+ mini={mini}
453
+ className={className}
454
+ {...props}
455
+ />
456
+ {label && <Label htmlFor={id}>{label}</Label>}
457
+ </div>
458
+ )
459
+ }
460
+
461
+ const Mini = ({ label, className, size, variant, shape, style, ...props }) => {
462
+ const id = useId()
463
+
464
+ return (
465
+ <div className='flex items-center space-x-2'>
466
+ <Switch
467
+ id={id}
468
+ size={size}
469
+ variant={variant}
470
+ shape={shape}
471
+ style={style}
472
+ mini={true}
473
+ className={className}
474
+ {...props}
475
+ />
476
+ {label && <Label htmlFor={id}>{label}</Label>}
477
+ </div>
478
+ )
479
+ }
480
+
481
+ const Outline = ({ colorVariant = 'default', label, className, size, variant, shape, mini, ...props }) => {
482
+ const id = useId()
483
+
484
+ return (
485
+ <div className='flex items-center gap-3'>
486
+ <Switch
487
+ id={id}
488
+ size={size}
489
+ variant={colorVariant}
490
+ shape={shape}
491
+ style='outline'
492
+ mini={mini}
493
+ className={className}
494
+ defaultChecked
495
+ {...props}
496
+ />
497
+ {label && <Label htmlFor={id}>{label}</Label>}
498
+ </div>
499
+ )
500
+ }
501
+
502
+ export function SwitchXDemo() {
503
+ const [checked1, setChecked1] = useState(false)
504
+ const [checked2, setChecked2] = useState(true)
505
+ const [checked3, setChecked3] = useState(false)
506
+ const [checked4, setChecked4] = useState(true)
507
+ const [checked5, setChecked5] = useState(true)
508
+ const [checked6, setChecked6] = useState(true)
509
+ const [checked7, setChecked7] = useState(true)
510
+ const [checked8, setChecked8] = useState(true)
511
+ const [checked9, setChecked9] = useState(false)
512
+ const [checked10, setChecked10] = useState(false)
513
+ const [checked11, setChecked11] = useState(false)
514
+ const [checked12, setChecked12] = useState(false)
515
+ const [checked13, setChecked13] = useState(false)
516
+ const [checked14, setChecked14] = useState(false)
517
+ const [checked15, setChecked15] = useState(false)
518
+ const [checked16, setChecked16] = useState(false)
519
+ const [checked17, setChecked17] = useState(false)
520
+
521
+ const [listItems, setListItems] = useState([
522
+ { label: 'React', icon: CodeIcon, checked: false },
523
+ { label: 'Design', icon: PaletteIcon, checked: false },
524
+ { label: 'Security', icon: ShieldIcon, checked: false },
525
+ ])
526
+
527
+ const handleListItemChange = (index: number, checked: boolean) => {
528
+ const newItems = [...listItems]
529
+ newItems[index].checked = checked
530
+ setListItems(newItems)
531
+ }
532
+
533
+ return (
534
+ <div className='space-y-12 p-6 max-w-3xl mx-auto'>
535
+ <div>
536
+ <h3 className='text-lg font-semibold mb-4'>Default</h3>
537
+ <SwitchX label='Airplane Mode' checked={checked1} onCheckedChange={setChecked1} />
538
+ </div>
539
+
540
+ <div>
541
+ <h3 className='text-lg font-semibold mb-4'>Square</h3>
542
+ <SwitchX switch='square' label='Square Switch' checked={checked15} onCheckedChange={setChecked15} />
543
+ </div>
544
+
545
+ <div>
546
+ <h3 className='text-lg font-semibold mb-4'>Mini</h3>
547
+ <SwitchX switch='mini' label='Mini Switch' checked={checked16} onCheckedChange={setChecked16} />
548
+ </div>
549
+
550
+ <div>
551
+ <h3 className='text-lg font-semibold mb-4'>Colors</h3>
552
+ <div className='flex items-center gap-3'>
553
+ <SwitchX switch='colors' colorVariant='destructive' />
554
+ <SwitchX switch='colors' colorVariant='success' />
555
+ <SwitchX switch='colors' colorVariant='info' />
556
+ <SwitchX switch='colors' colorVariant='warning' />
557
+ </div>
558
+ </div>
559
+
560
+ <div>
561
+ <h3 className='text-lg font-semibold mb-4'>Sizes</h3>
562
+ <div className='flex items-center gap-3'>
563
+ <SwitchX switch='sizes' sizeVariant='sm' />
564
+ <SwitchX switch='sizes' sizeVariant='md' />
565
+ <SwitchX switch='sizes' sizeVariant='lg' />
566
+ </div>
567
+ </div>
568
+
569
+ <div>
570
+ <h3 className='text-lg font-semibold mb-4'>Outline</h3>
571
+ <div className='flex items-center gap-3'>
572
+ <SwitchX switch='outline' colorVariant='default' />
573
+ <SwitchX switch='outline' colorVariant='destructive' />
574
+ <SwitchX switch='outline' colorVariant='success' />
575
+ <SwitchX switch='outline' colorVariant='info' />
576
+ <SwitchX switch='outline' colorVariant='warning' />
577
+ </div>
578
+ </div>
579
+
580
+ <div>
581
+ <h3 className='text-lg font-semibold mb-4'>Gradient</h3>
582
+ <SwitchX switch='gradient' label='Gradient Switch' checked={checked17} onCheckedChange={setChecked17} />
583
+ </div>
584
+
585
+ <div>
586
+ <h3 className='text-lg font-semibold mb-4'>Toggle Label</h3>
587
+ <SwitchX switch='toggleLabel' checked={checked2} onCheckedChange={setChecked2} />
588
+ </div>
589
+
590
+ <div>
591
+ <h3 className='text-lg font-semibold mb-4'>Dual Toggle Label</h3>
592
+ <SwitchX switch='dualToggleLabel' checked={checked3} onCheckedChange={setChecked3} />
593
+ </div>
594
+
595
+ <div>
596
+ <h3 className='text-lg font-semibold mb-4'>Icon Label</h3>
597
+ <SwitchX switch='iconLabel' checked={checked4} onCheckedChange={setChecked4} />
598
+ </div>
599
+
600
+ <div>
601
+ <h3 className='text-lg font-semibold mb-4'>Dual Icon Label</h3>
602
+ <SwitchX switch='dualIconLabel' checked={checked5} onCheckedChange={setChecked5} />
603
+ </div>
604
+
605
+ <div>
606
+ <h3 className='text-lg font-semibold mb-4'>Icon Indicator</h3>
607
+ <SwitchX switch='iconIndicator' checked={checked6} onCheckedChange={setChecked6} />
608
+ </div>
609
+
610
+ <div>
611
+ <h3 className='text-lg font-semibold mb-4'>Permanent Indicator</h3>
612
+ <SwitchX switch='permanentIndicator' checked={checked7} onCheckedChange={setChecked7} />
613
+ </div>
614
+
615
+ <div>
616
+ <h3 className='text-lg font-semibold mb-4'>Square Permanent Indicator</h3>
617
+ <SwitchX switch='squarePermanentIndicator' checked={checked8} onCheckedChange={setChecked8} />
618
+ </div>
619
+
620
+ <div>
621
+ <h3 className='text-lg font-semibold mb-4'>Card 1</h3>
622
+ <SwitchX
623
+ switch='card'
624
+ icon={DatabaseIcon}
625
+ title='Backup'
626
+ description='Backup every file from your project.'
627
+ checked={checked9}
628
+ onCheckedChange={setChecked9}
629
+ />
630
+ </div>
631
+
632
+ <div>
633
+ <h3 className='text-lg font-semibold mb-4'>Card 2</h3>
634
+ <SwitchX
635
+ switch='card'
636
+ icon={() => (
637
+ <img
638
+ src='https://cdn.shadcnstudio.com/ss-assets/brand-logo/google-icon.png?width=20&height=20&format=auto'
639
+ alt='Google Icon'
640
+ className='size-5'
641
+ />
642
+ )}
643
+ title='Google Cloud Backup'
644
+ description='Backup every picture, video and PDFs.'
645
+ checked={checked10}
646
+ onCheckedChange={setChecked10}
647
+ />
648
+ </div>
649
+
650
+ <div>
651
+ <h3 className='text-lg font-semibold mb-4'>Card 3</h3>
652
+ <SwitchX
653
+ switch='card'
654
+ icon={() => (
655
+ <img
656
+ src='https://cdn.shadcnstudio.com/ss-assets/brand-logo/github-icon.png?width=20&height=20&format=auto'
657
+ alt='GitHub Icon'
658
+ className='size-5'
659
+ />
660
+ )}
661
+ title='Connect with GitHub'
662
+ description='Access your projects direct from GitHub.'
663
+ checked={checked11}
664
+ onCheckedChange={setChecked11}
665
+ />
666
+ </div>
667
+
668
+ <div>
669
+ <h3 className='text-lg font-semibold mb-4'>List Group</h3>
670
+ <SwitchX
671
+ switch='listGroup'
672
+ items={listItems.map((item, index) => ({
673
+ ...item,
674
+ onCheckedChange: (checked: boolean) => handleListItemChange(index, checked),
675
+ }))}
676
+ />
677
+ </div>
678
+
679
+ </div>
680
+ )
681
+ }