@regardio/react 0.5.7 → 0.7.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 (214) hide show
  1. package/dist/background-slideshow/index.d.mts +34 -0
  2. package/dist/background-slideshow/index.mjs +110 -0
  3. package/dist/blurry-gradient/index.d.mts +16 -0
  4. package/dist/blurry-gradient/index.mjs +93 -0
  5. package/dist/button/index.d.mts +2 -0
  6. package/dist/button/index.mjs +3 -0
  7. package/dist/button-BiSQpBbc.mjs +129 -0
  8. package/dist/carousel/index.d.mts +74 -0
  9. package/dist/carousel/index.mjs +136 -0
  10. package/dist/checkbox/index.d.mts +28 -0
  11. package/dist/checkbox/index.mjs +70 -0
  12. package/dist/checkbox-group/index.d.mts +16 -0
  13. package/dist/checkbox-group/index.mjs +29 -0
  14. package/dist/chunk-BTpB_u-K.mjs +18 -0
  15. package/dist/countdown/index.d.mts +4 -0
  16. package/dist/countdown/index.mjs +58 -0
  17. package/dist/field/index.d.mts +68 -0
  18. package/dist/field/index.mjs +115 -0
  19. package/dist/fieldset/index.d.mts +34 -0
  20. package/dist/fieldset/index.mjs +61 -0
  21. package/dist/form/index.d.mts +21 -0
  22. package/dist/form/index.mjs +31 -0
  23. package/dist/generic-error/index.d.mts +44 -0
  24. package/dist/generic-error/index.mjs +57 -0
  25. package/dist/grid/index.d.mts +101 -0
  26. package/dist/grid/index.mjs +219 -0
  27. package/dist/heading/index.d.mts +27 -0
  28. package/dist/heading/index.mjs +28 -0
  29. package/dist/highlight/index.d.mts +17 -0
  30. package/dist/highlight/index.mjs +35 -0
  31. package/dist/hooks/use-current-route-data.d.mts +8 -0
  32. package/dist/hooks/use-current-route-data.mjs +22 -0
  33. package/dist/hooks/{use-focus-search.d.ts → use-focus-search.d.mts} +4 -3
  34. package/dist/hooks/use-focus-search.mjs +23 -0
  35. package/dist/hooks/use-matches-data.d.mts +10 -0
  36. package/dist/hooks/use-matches-data.mjs +23 -0
  37. package/dist/hooks/use-media-query.d.mts +9 -0
  38. package/dist/hooks/use-media-query.mjs +28 -0
  39. package/dist/hooks/use-mobile.d.mts +4 -0
  40. package/dist/hooks/use-mobile.mjs +22 -0
  41. package/dist/hooks/use-nonce.d.mts +6 -0
  42. package/dist/hooks/use-nonce.mjs +13 -0
  43. package/dist/hooks/use-orientation.d.mts +12 -0
  44. package/dist/hooks/use-orientation.mjs +32 -0
  45. package/dist/hooks/use-user.d.mts +53 -0
  46. package/dist/hooks/use-user.mjs +39 -0
  47. package/dist/icon-button/index.d.mts +28 -0
  48. package/dist/icon-button/index.mjs +36 -0
  49. package/dist/if/index.d.mts +13 -0
  50. package/dist/if/index.mjs +21 -0
  51. package/dist/iframe/index.d.mts +11 -0
  52. package/dist/iframe/index.mjs +15 -0
  53. package/dist/index-Bj5_XfEC.d.mts +29 -0
  54. package/dist/index-C_evL5vG.d.mts +35 -0
  55. package/dist/input/index.d.mts +2 -0
  56. package/dist/input/index.mjs +3 -0
  57. package/dist/input-CtR6aRVi.mjs +73 -0
  58. package/dist/link/index.d.mts +71 -0
  59. package/dist/link/index.mjs +129 -0
  60. package/dist/list/index.d.mts +72 -0
  61. package/dist/list/index.mjs +54 -0
  62. package/dist/markdown-container/index.d.mts +23 -0
  63. package/dist/markdown-container/index.mjs +71 -0
  64. package/dist/password-input/index.d.mts +23 -0
  65. package/dist/password-input/index.mjs +92 -0
  66. package/dist/picture/index.d.mts +39 -0
  67. package/dist/picture/index.mjs +3 -0
  68. package/dist/picture-DkX3W5zl.mjs +69 -0
  69. package/dist/protected-email/index.d.mts +24 -0
  70. package/dist/protected-email/index.mjs +37 -0
  71. package/dist/radio/index.d.mts +28 -0
  72. package/dist/radio/index.mjs +72 -0
  73. package/dist/radio-group/index.d.mts +16 -0
  74. package/dist/radio-group/index.mjs +29 -0
  75. package/dist/slider/index.d.mts +63 -0
  76. package/dist/slider/index.mjs +133 -0
  77. package/dist/switch/index.d.mts +29 -0
  78. package/dist/switch/index.mjs +87 -0
  79. package/dist/text/index.d.mts +25 -0
  80. package/dist/text/index.mjs +32 -0
  81. package/dist/text-EQC4zJbE.mjs +52 -0
  82. package/dist/toggle/index.d.mts +25 -0
  83. package/dist/toggle/index.mjs +82 -0
  84. package/dist/utils/author/index.d.mts +4 -0
  85. package/dist/utils/author/index.mjs +26 -0
  86. package/dist/utils/text/{index.d.ts → index.d.mts} +9 -8
  87. package/dist/utils/text/index.mjs +3 -0
  88. package/package.json +131 -83
  89. package/src/background-slideshow/background-slideshow.tsx +1 -2
  90. package/src/blurry-gradient/blurry-gradient.tsx +1 -1
  91. package/src/button/button.stories.tsx +161 -0
  92. package/src/button/button.test.tsx +73 -0
  93. package/src/button/button.tsx +118 -0
  94. package/src/button/index.ts +2 -0
  95. package/src/carousel/carousel-content.tsx +17 -14
  96. package/src/carousel/carousel-item.tsx +18 -18
  97. package/src/carousel/carousel-next.tsx +22 -17
  98. package/src/carousel/carousel-previous.tsx +22 -17
  99. package/src/carousel/carousel-root.tsx +91 -86
  100. package/src/checkbox/checkbox.stories.tsx +118 -0
  101. package/src/checkbox/checkbox.tsx +102 -0
  102. package/src/checkbox/index.ts +2 -0
  103. package/src/checkbox-group/checkbox-group.tsx +40 -0
  104. package/src/checkbox-group/index.ts +2 -0
  105. package/src/countdown/countdown.tsx +1 -1
  106. package/src/field/field.stories.tsx +105 -0
  107. package/src/field/field.test.tsx +61 -0
  108. package/src/field/field.tsx +186 -0
  109. package/src/field/index.ts +12 -0
  110. package/src/fieldset/fieldset.stories.tsx +204 -0
  111. package/src/fieldset/fieldset.test.tsx +63 -0
  112. package/src/fieldset/fieldset.tsx +86 -0
  113. package/src/fieldset/index.ts +7 -0
  114. package/src/form/form.stories.tsx +230 -0
  115. package/src/form/form.test.tsx +68 -0
  116. package/src/form/form.tsx +38 -0
  117. package/src/form/index.ts +2 -0
  118. package/src/generic-error/generic-error.tsx +2 -3
  119. package/src/grid/grid-item.tsx +77 -36
  120. package/src/grid/grid-root.tsx +49 -22
  121. package/src/heading/heading.tsx +7 -3
  122. package/src/highlight/highlight.tsx +1 -1
  123. package/src/hooks/use-current-route-data.ts +4 -2
  124. package/src/hooks/use-focus-search.ts +3 -1
  125. package/src/hooks/use-matches-data.ts +2 -0
  126. package/src/hooks/use-media-query.ts +2 -0
  127. package/src/hooks/use-mobile.ts +3 -1
  128. package/src/hooks/use-nonce.ts +3 -3
  129. package/src/hooks/use-orientation.ts +2 -0
  130. package/src/hooks/use-user.tsx +3 -2
  131. package/src/icon-button/icon-button.stories.tsx +128 -7
  132. package/src/icon-button/icon-button.test.tsx +152 -0
  133. package/src/icon-button/icon-button.tsx +43 -9
  134. package/src/if/if.tsx +3 -1
  135. package/src/input/index.ts +2 -0
  136. package/src/input/input.stories.tsx +151 -0
  137. package/src/input/input.test.tsx +65 -0
  138. package/src/input/input.tsx +113 -0
  139. package/src/link/link.tsx +4 -3
  140. package/src/list/list-item.tsx +10 -13
  141. package/src/list/list-root-context.ts +3 -3
  142. package/src/list/list-root.tsx +10 -13
  143. package/src/password-input/index.ts +1 -1
  144. package/src/password-input/password-input.tsx +104 -27
  145. package/src/protected-email/protected-email.tsx +6 -1
  146. package/src/radio/index.ts +2 -0
  147. package/src/radio/radio.tsx +103 -0
  148. package/src/radio-group/index.ts +2 -0
  149. package/src/radio-group/radio-group.tsx +40 -0
  150. package/src/slider/index.ts +18 -0
  151. package/src/slider/slider.tsx +201 -0
  152. package/src/switch/index.ts +2 -0
  153. package/src/switch/switch.stories.tsx +118 -0
  154. package/src/switch/switch.tsx +112 -0
  155. package/src/text/text.tsx +6 -1
  156. package/src/toggle/index.ts +2 -0
  157. package/src/toggle/toggle.stories.tsx +232 -0
  158. package/src/toggle/toggle.test.tsx +149 -0
  159. package/src/toggle/toggle.tsx +88 -0
  160. package/src/utils/text/text.tsx +8 -16
  161. package/dist/background-slideshow/index.d.ts +0 -24
  162. package/dist/background-slideshow/index.js +0 -165
  163. package/dist/blurry-gradient/index.d.ts +0 -16
  164. package/dist/blurry-gradient/index.js +0 -128
  165. package/dist/carousel/index.d.ts +0 -36
  166. package/dist/carousel/index.js +0 -171
  167. package/dist/countdown/index.d.ts +0 -5
  168. package/dist/countdown/index.js +0 -73
  169. package/dist/generic-error/index.d.ts +0 -43
  170. package/dist/generic-error/index.js +0 -47
  171. package/dist/grid/index.d.ts +0 -1196
  172. package/dist/grid/index.js +0 -239
  173. package/dist/heading/index.d.ts +0 -24
  174. package/dist/heading/index.js +0 -99
  175. package/dist/highlight/index.d.ts +0 -13
  176. package/dist/highlight/index.js +0 -59
  177. package/dist/hooks/use-current-route-data.d.ts +0 -7
  178. package/dist/hooks/use-current-route-data.js +0 -16
  179. package/dist/hooks/use-focus-search.js +0 -19
  180. package/dist/hooks/use-matches-data.d.ts +0 -9
  181. package/dist/hooks/use-matches-data.js +0 -15
  182. package/dist/hooks/use-media-query.d.ts +0 -8
  183. package/dist/hooks/use-media-query.js +0 -20
  184. package/dist/hooks/use-mobile.d.ts +0 -3
  185. package/dist/hooks/use-mobile.js +0 -19
  186. package/dist/hooks/use-nonce.d.ts +0 -7
  187. package/dist/hooks/use-nonce.js +0 -8
  188. package/dist/hooks/use-orientation.d.ts +0 -11
  189. package/dist/hooks/use-orientation.js +0 -29
  190. package/dist/hooks/use-user.d.ts +0 -50
  191. package/dist/hooks/use-user.js +0 -25
  192. package/dist/icon-button/index.d.ts +0 -9
  193. package/dist/icon-button/index.js +0 -17
  194. package/dist/if/index.d.ts +0 -10
  195. package/dist/if/index.js +0 -24
  196. package/dist/iframe/index.d.ts +0 -10
  197. package/dist/iframe/index.js +0 -17
  198. package/dist/link/index.d.ts +0 -55
  199. package/dist/link/index.js +0 -195
  200. package/dist/list/index.d.ts +0 -69
  201. package/dist/list/index.js +0 -65
  202. package/dist/markdown-container/index.d.ts +0 -22
  203. package/dist/markdown-container/index.js +0 -128
  204. package/dist/password-input/index.d.ts +0 -11
  205. package/dist/password-input/index.js +0 -46
  206. package/dist/picture/index.d.ts +0 -38
  207. package/dist/picture/index.js +0 -68
  208. package/dist/protected-email/index.d.ts +0 -20
  209. package/dist/protected-email/index.js +0 -30
  210. package/dist/text/index.d.ts +0 -20
  211. package/dist/text/index.js +0 -38
  212. package/dist/utils/author/index.d.ts +0 -3
  213. package/dist/utils/author/index.js +0 -33
  214. package/dist/utils/text/index.js +0 -73
@@ -0,0 +1,118 @@
1
+ import { Button as BaseUIButton } from '@base-ui/react/button';
2
+ import { tv } from '@regardio/tailwind/utils';
3
+ import type { ComponentProps } from 'react';
4
+
5
+ const buttonVariants = {
6
+ destructive: [
7
+ 'bg-red-600',
8
+ 'text-white',
9
+ 'border-red-600',
10
+ 'hover:bg-red-700',
11
+ 'hover:border-red-700',
12
+ 'focus-visible:ring-2',
13
+ 'focus-visible:ring-red-500',
14
+ 'focus-visible:ring-offset-2',
15
+ ],
16
+ ghost: [
17
+ 'bg-transparent',
18
+ 'text-gray-900',
19
+ 'border-transparent',
20
+ 'hover:bg-gray-100',
21
+ 'hover:border-transparent',
22
+ 'focus-visible:ring-2',
23
+ 'focus-visible:ring-gray-500',
24
+ 'focus-visible:ring-offset-2',
25
+ ],
26
+ outline: [
27
+ 'bg-transparent',
28
+ 'text-gray-900',
29
+ 'border-gray-300',
30
+ 'hover:bg-gray-50',
31
+ 'hover:border-gray-400',
32
+ 'focus-visible:ring-2',
33
+ 'focus-visible:ring-gray-500',
34
+ 'focus-visible:ring-offset-2',
35
+ ],
36
+ primary: [
37
+ 'bg-blue-600',
38
+ 'text-white',
39
+ 'border-blue-600',
40
+ 'hover:bg-blue-700',
41
+ 'hover:border-blue-700',
42
+ 'focus-visible:ring-2',
43
+ 'focus-visible:ring-blue-500',
44
+ 'focus-visible:ring-offset-2',
45
+ ],
46
+ secondary: [
47
+ 'bg-gray-100',
48
+ 'text-gray-900',
49
+ 'border-gray-300',
50
+ 'hover:bg-gray-200',
51
+ 'hover:border-gray-400',
52
+ 'focus-visible:ring-2',
53
+ 'focus-visible:ring-gray-500',
54
+ 'focus-visible:ring-offset-2',
55
+ ],
56
+ } as const;
57
+
58
+ const buttonSizes = {
59
+ '2xl': ['px-10', 'py-5', 'text-2xl', 'font-medium', 'rounded-lg'],
60
+ lg: ['px-6', 'py-3', 'text-lg', 'font-medium', 'rounded-lg'],
61
+ md: ['px-4', 'py-2', 'text-base', 'font-medium', 'rounded-md'],
62
+ sm: ['px-3', 'py-1.5', 'text-sm', 'font-medium', 'rounded-md'],
63
+ xl: ['px-8', 'py-4', 'text-xl', 'font-medium', 'rounded-lg'],
64
+ } as const;
65
+
66
+ const button = tv({
67
+ base: [
68
+ 'inline-flex',
69
+ 'items-center',
70
+ 'justify-center',
71
+ 'border',
72
+ 'transition-colors',
73
+ 'duration-200',
74
+ 'ease-in-out',
75
+ 'disabled:opacity-50',
76
+ 'disabled:cursor-not-allowed',
77
+ 'disabled:pointer-events-none',
78
+ ],
79
+ defaultVariants: {
80
+ size: 'md',
81
+ variant: 'primary',
82
+ },
83
+ variants: {
84
+ size: buttonSizes,
85
+ variant: buttonVariants,
86
+ },
87
+ });
88
+
89
+ export type ButtonVariant = keyof typeof buttonVariants;
90
+ export type ButtonSize = keyof typeof buttonSizes;
91
+
92
+ export interface ButtonProps extends Omit<ComponentProps<typeof BaseUIButton>, 'className'> {
93
+ variant?: ButtonVariant;
94
+ size?: ButtonSize;
95
+ className?: string;
96
+ type?: 'button' | 'submit' | 'reset';
97
+ }
98
+
99
+ export const Button = ({
100
+ children,
101
+ className,
102
+ variant,
103
+ size,
104
+ ...props
105
+ }: ButtonProps): React.JSX.Element => {
106
+ return (
107
+ <BaseUIButton
108
+ className={button({
109
+ className,
110
+ size,
111
+ variant,
112
+ })}
113
+ {...props}
114
+ >
115
+ {children}
116
+ </BaseUIButton>
117
+ );
118
+ };
@@ -0,0 +1,2 @@
1
+ export type { ButtonProps, ButtonSize, ButtonVariant } from './button';
2
+ export { Button } from './button';
@@ -1,16 +1,19 @@
1
- 'use client';
1
+ import type { HTMLAttributes } from 'react';
2
2
 
3
- import { forwardRef, type HTMLAttributes } from 'react';
3
+ export interface CarouselContentProps extends HTMLAttributes<HTMLDivElement> {
4
+ ref?: React.Ref<HTMLDivElement>;
5
+ }
4
6
 
5
- export const CarouselContent = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
6
- ({ className, ...props }, ref) => {
7
- return (
8
- <div
9
- className={className}
10
- ref={ref}
11
- {...props}
12
- />
13
- );
14
- },
15
- );
16
- CarouselContent.displayName = 'CarouselContent';
7
+ export const CarouselContent = function CarouselContent({
8
+ className,
9
+ ref,
10
+ ...props
11
+ }: CarouselContentProps): React.JSX.Element {
12
+ return (
13
+ <div
14
+ className={className}
15
+ ref={ref}
16
+ {...props}
17
+ />
18
+ );
19
+ };
@@ -1,23 +1,23 @@
1
- 'use client';
2
-
3
- import { forwardRef, type HTMLAttributes } from 'react';
1
+ import type { HTMLAttributes } from 'react';
4
2
 
5
3
  export interface CarouselItemProps extends HTMLAttributes<HTMLDivElement> {
6
4
  'aria-label'?: string;
5
+ ref?: React.Ref<HTMLDivElement>;
7
6
  }
8
7
 
9
- export const CarouselItem = forwardRef<HTMLDivElement, CarouselItemProps>(
10
- ({ className, ...props }, ref) => {
11
- return (
12
- // biome-ignore lint/a11y/useSemanticElements: False positive
13
- <div
14
- aria-roledescription="slide"
15
- className={className}
16
- ref={ref}
17
- role="group"
18
- {...props}
19
- />
20
- );
21
- },
22
- );
23
- CarouselItem.displayName = 'CarouselItem';
8
+ export const CarouselItem = function CarouselItem({
9
+ className,
10
+ ref,
11
+ ...props
12
+ }: CarouselItemProps): React.JSX.Element {
13
+ return (
14
+ // biome-ignore lint/a11y/useSemanticElements: False positive
15
+ <div
16
+ aria-roledescription="slide"
17
+ className={className}
18
+ ref={ref}
19
+ role="group"
20
+ {...props}
21
+ />
22
+ );
23
+ };
@@ -1,22 +1,27 @@
1
1
  'use client';
2
2
 
3
- import { forwardRef, type HTMLAttributes } from 'react';
3
+ import type { HTMLAttributes } from 'react';
4
+ import { Button } from '../button';
4
5
  import { useCarousel } from './carousel-root';
5
6
 
6
- export const CarouselNext = forwardRef<HTMLButtonElement, HTMLAttributes<HTMLButtonElement>>(
7
- ({ className, ...props }, ref) => {
8
- const { canScrollNext, scrollNext } = useCarousel();
7
+ export interface CarouselNextProps extends HTMLAttributes<HTMLButtonElement> {
8
+ ref?: React.Ref<HTMLButtonElement>;
9
+ }
9
10
 
10
- return (
11
- <button
12
- className={className}
13
- disabled={!canScrollNext}
14
- onClick={scrollNext}
15
- ref={ref}
16
- type="button"
17
- {...props}
18
- />
19
- );
20
- },
21
- );
22
- CarouselNext.displayName = 'CarouselNext';
11
+ export const CarouselNext = function CarouselNext({
12
+ className,
13
+ ref,
14
+ ...props
15
+ }: CarouselNextProps): React.JSX.Element {
16
+ const { canScrollNext, scrollNext } = useCarousel();
17
+
18
+ return (
19
+ <Button
20
+ className={className}
21
+ disabled={!canScrollNext}
22
+ onClick={scrollNext}
23
+ ref={ref}
24
+ {...props}
25
+ />
26
+ );
27
+ };
@@ -1,22 +1,27 @@
1
1
  'use client';
2
2
 
3
- import { forwardRef, type HTMLAttributes } from 'react';
3
+ import type { HTMLAttributes } from 'react';
4
+ import { Button } from '../button';
4
5
  import { useCarousel } from './carousel-root';
5
6
 
6
- export const CarouselPrevious = forwardRef<HTMLButtonElement, HTMLAttributes<HTMLButtonElement>>(
7
- ({ className, ...props }, ref) => {
8
- const { canScrollPrev, scrollPrev } = useCarousel();
7
+ export interface CarouselPreviousProps extends HTMLAttributes<HTMLButtonElement> {
8
+ ref?: React.Ref<HTMLButtonElement>;
9
+ }
9
10
 
10
- return (
11
- <button
12
- className={className}
13
- disabled={!canScrollPrev}
14
- onClick={scrollPrev}
15
- ref={ref}
16
- type="button"
17
- {...props}
18
- />
19
- );
20
- },
21
- );
22
- CarouselPrevious.displayName = 'CarouselPrevious';
11
+ export const CarouselPrevious = function CarouselPrevious({
12
+ className,
13
+ ref,
14
+ ...props
15
+ }: CarouselPreviousProps): React.JSX.Element {
16
+ const { canScrollPrev, scrollPrev } = useCarousel();
17
+
18
+ return (
19
+ <Button
20
+ className={className}
21
+ disabled={!canScrollPrev}
22
+ onClick={scrollPrev}
23
+ ref={ref}
24
+ {...props}
25
+ />
26
+ );
27
+ };
@@ -4,7 +4,6 @@ import type { EmblaCarouselType, EmblaOptionsType } from 'embla-carousel';
4
4
  import useEmblaCarousel from 'embla-carousel-react';
5
5
  import {
6
6
  createContext,
7
- forwardRef,
8
7
  type HTMLAttributes,
9
8
  type KeyboardEvent,
10
9
  useCallback,
@@ -25,7 +24,7 @@ interface CarouselContextValue {
25
24
 
26
25
  const CarouselContext = createContext<CarouselContextValue | null>(null);
27
26
 
28
- export function useCarousel() {
27
+ export function useCarousel(): CarouselContextValue {
29
28
  const context = useContext(CarouselContext);
30
29
  if (!context) {
31
30
  throw new Error('useCarousel must be used within a <Carousel.Root />');
@@ -37,91 +36,97 @@ export interface CarouselRootProps extends HTMLAttributes<HTMLDivElement> {
37
36
  opts?: EmblaOptionsType;
38
37
  setApi?: (api: CarouselApi) => void;
39
38
  orientation?: 'horizontal' | 'vertical';
39
+ ref?: React.Ref<HTMLDivElement>;
40
40
  }
41
41
 
42
- export const CarouselRoot = forwardRef<HTMLDivElement, CarouselRootProps>(
43
- ({ children, className, opts, orientation = 'horizontal', setApi, ...props }, ref) => {
44
- const [emblaRef, emblaApi] = useEmblaCarousel({
45
- ...opts,
46
- axis: orientation === 'horizontal' ? 'x' : 'y',
47
- });
48
- const [canScrollPrev, setCanScrollPrev] = useState(false);
49
- const [canScrollNext, setCanScrollNext] = useState(false);
50
-
51
- const onSelect = useCallback((api: CarouselApi) => {
52
- if (!api) {
53
- return;
42
+ export const CarouselRoot = function CarouselRoot({
43
+ children,
44
+ className,
45
+ opts,
46
+ orientation = 'horizontal',
47
+ setApi,
48
+ ref,
49
+ ...props
50
+ }: CarouselRootProps): React.JSX.Element {
51
+ const [emblaRef, emblaApi] = useEmblaCarousel({
52
+ ...opts,
53
+ axis: orientation === 'horizontal' ? 'x' : 'y',
54
+ });
55
+ const [canScrollPrev, setCanScrollPrev] = useState(false);
56
+ const [canScrollNext, setCanScrollNext] = useState(false);
57
+
58
+ const onSelect = useCallback((api: CarouselApi) => {
59
+ if (!api) {
60
+ return;
61
+ }
62
+ setCanScrollPrev(api.canScrollPrev());
63
+ setCanScrollNext(api.canScrollNext());
64
+ }, []);
65
+
66
+ const scrollPrev = useCallback(() => {
67
+ emblaApi?.scrollPrev();
68
+ }, [emblaApi]);
69
+
70
+ const scrollNext = useCallback(() => {
71
+ emblaApi?.scrollNext();
72
+ }, [emblaApi]);
73
+
74
+ const handleKeyDown = useCallback(
75
+ (event: KeyboardEvent<HTMLDivElement>) => {
76
+ if (event.key === 'ArrowLeft') {
77
+ event.preventDefault();
78
+ scrollPrev();
79
+ } else if (event.key === 'ArrowRight') {
80
+ event.preventDefault();
81
+ scrollNext();
54
82
  }
55
- setCanScrollPrev(api.canScrollPrev());
56
- setCanScrollNext(api.canScrollNext());
57
- }, []);
58
-
59
- const scrollPrev = useCallback(() => {
60
- emblaApi?.scrollPrev();
61
- }, [emblaApi]);
62
-
63
- const scrollNext = useCallback(() => {
64
- emblaApi?.scrollNext();
65
- }, [emblaApi]);
66
-
67
- const handleKeyDown = useCallback(
68
- (event: KeyboardEvent<HTMLDivElement>) => {
69
- if (event.key === 'ArrowLeft') {
70
- event.preventDefault();
71
- scrollPrev();
72
- } else if (event.key === 'ArrowRight') {
73
- event.preventDefault();
74
- scrollNext();
75
- }
76
- },
77
- [scrollPrev, scrollNext],
78
- );
79
-
80
- useEffect(() => {
81
- if (!emblaApi || !setApi) {
82
- return;
83
- }
84
- setApi(emblaApi);
85
- }, [emblaApi, setApi]);
86
-
87
- useEffect(() => {
88
- if (!emblaApi) {
89
- return;
90
- }
91
-
92
- onSelect(emblaApi);
93
- emblaApi.on('reInit', onSelect);
94
- emblaApi.on('select', onSelect);
95
-
96
- return () => {
97
- emblaApi?.off('select', onSelect);
98
- };
99
- }, [emblaApi, onSelect]);
100
-
101
- return (
102
- <CarouselContext.Provider
103
- value={{
104
- api: emblaApi,
105
- canScrollNext,
106
- canScrollPrev,
107
- scrollNext,
108
- scrollPrev,
109
- }}
83
+ },
84
+ [scrollPrev, scrollNext],
85
+ );
86
+
87
+ useEffect(() => {
88
+ if (!emblaApi || !setApi) {
89
+ return;
90
+ }
91
+ setApi(emblaApi);
92
+ }, [emblaApi, setApi]);
93
+
94
+ useEffect(() => {
95
+ if (!emblaApi) {
96
+ return;
97
+ }
98
+
99
+ onSelect(emblaApi);
100
+ emblaApi.on('reInit', onSelect);
101
+ emblaApi.on('select', onSelect);
102
+
103
+ return () => {
104
+ emblaApi?.off('select', onSelect);
105
+ };
106
+ }, [emblaApi, onSelect]);
107
+
108
+ return (
109
+ <CarouselContext.Provider
110
+ value={{
111
+ api: emblaApi,
112
+ canScrollNext,
113
+ canScrollPrev,
114
+ scrollNext,
115
+ scrollPrev,
116
+ }}
117
+ >
118
+ <section
119
+ aria-label="Carousel"
120
+ aria-roledescription="carousel"
121
+ className={className}
122
+ onKeyDownCapture={handleKeyDown}
123
+ ref={ref}
124
+ {...props}
110
125
  >
111
- <section
112
- aria-label="Carousel"
113
- aria-roledescription="carousel"
114
- className={className}
115
- onKeyDownCapture={handleKeyDown}
116
- ref={ref}
117
- {...props}
118
- >
119
- <div ref={emblaRef}>
120
- <div>{children}</div>
121
- </div>
122
- </section>
123
- </CarouselContext.Provider>
124
- );
125
- },
126
- );
127
- CarouselRoot.displayName = 'CarouselRoot';
126
+ <div ref={emblaRef}>
127
+ <div>{children}</div>
128
+ </div>
129
+ </section>
130
+ </CarouselContext.Provider>
131
+ );
132
+ };
@@ -0,0 +1,118 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { useState } from 'react';
3
+ import { Field } from '../field';
4
+ import { Checkbox } from './checkbox';
5
+
6
+ const meta: Meta<typeof Checkbox.Root> = {
7
+ argTypes: {
8
+ disabled: {
9
+ control: 'boolean',
10
+ description: 'Disable the checkbox',
11
+ },
12
+ size: {
13
+ control: 'select',
14
+ description: 'Checkbox size',
15
+ options: ['sm', 'md', 'lg'],
16
+ },
17
+ },
18
+ component: Checkbox.Root,
19
+ parameters: {
20
+ layout: 'centered',
21
+ },
22
+ tags: ['autodocs'],
23
+ title: 'Components/Checkbox',
24
+ };
25
+
26
+ export default meta;
27
+ type Story = StoryObj<typeof meta>;
28
+
29
+ export const Default: Story = {
30
+ render: () => (
31
+ <Checkbox.Root>
32
+ <Checkbox.Indicator />
33
+ </Checkbox.Root>
34
+ ),
35
+ };
36
+
37
+ export const Checked: Story = {
38
+ render: () => (
39
+ <Checkbox.Root defaultChecked>
40
+ <Checkbox.Indicator />
41
+ </Checkbox.Root>
42
+ ),
43
+ };
44
+
45
+ export const Small: Story = {
46
+ render: () => (
47
+ <Checkbox.Root size="sm">
48
+ <Checkbox.Indicator />
49
+ </Checkbox.Root>
50
+ ),
51
+ };
52
+
53
+ export const Large: Story = {
54
+ render: () => (
55
+ <Checkbox.Root size="lg">
56
+ <Checkbox.Indicator />
57
+ </Checkbox.Root>
58
+ ),
59
+ };
60
+
61
+ export const Disabled: Story = {
62
+ render: () => (
63
+ <Checkbox.Root disabled>
64
+ <Checkbox.Indicator />
65
+ </Checkbox.Root>
66
+ ),
67
+ };
68
+
69
+ export const WithLabel: Story = {
70
+ render: () => (
71
+ <Field.Root>
72
+ <Field.Label>
73
+ <Checkbox.Root>
74
+ <Checkbox.Indicator />
75
+ </Checkbox.Root>
76
+ Accept terms and conditions
77
+ </Field.Label>
78
+ </Field.Root>
79
+ ),
80
+ };
81
+
82
+ export const Controlled: Story = {
83
+ render: () => {
84
+ const [checked, setChecked] = useState(false);
85
+ return (
86
+ <div className="space-y-4">
87
+ <Field.Root>
88
+ <Field.Label>
89
+ <Checkbox.Root
90
+ checked={checked}
91
+ onCheckedChange={setChecked}
92
+ >
93
+ <Checkbox.Indicator />
94
+ </Checkbox.Root>
95
+ Subscribe to newsletter
96
+ </Field.Label>
97
+ </Field.Root>
98
+ <p className="text-sm text-gray-600">Status: {checked ? 'Subscribed' : 'Not subscribed'}</p>
99
+ </div>
100
+ );
101
+ },
102
+ };
103
+
104
+ export const AllSizes: Story = {
105
+ render: () => (
106
+ <div className="flex items-center gap-4">
107
+ <Checkbox.Root size="sm">
108
+ <Checkbox.Indicator />
109
+ </Checkbox.Root>
110
+ <Checkbox.Root size="md">
111
+ <Checkbox.Indicator />
112
+ </Checkbox.Root>
113
+ <Checkbox.Root size="lg">
114
+ <Checkbox.Indicator />
115
+ </Checkbox.Root>
116
+ </div>
117
+ ),
118
+ };