@shadow-js/ui 0.0.0-stage → 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 (190) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/LICENSE +21 -0
  3. package/README.md +598 -2
  4. package/dist/cli.mjs +2293 -0
  5. package/dist/dev/cli/schema.d.ts +73 -0
  6. package/dist/dev/index.d.ts +6 -0
  7. package/dist/dev/index.js +5 -0
  8. package/dist/dev/locales/ar.d.ts +141 -0
  9. package/dist/dev/locales/ar.js +128 -0
  10. package/dist/dev/locales/ar.js.map +1 -0
  11. package/dist/dev/locales/en.d.ts +141 -0
  12. package/dist/dev/locales/en.js +128 -0
  13. package/dist/dev/locales/en.js.map +1 -0
  14. package/dist/dev/registry/utils/utils.d.ts +29 -0
  15. package/dist/dev/registry/utils/utils.js +27 -0
  16. package/dist/dev/registry/utils/utils.js.map +1 -0
  17. package/dist/dev/theme/theme-logic.d.ts +187 -0
  18. package/dist/dev/theme/theme-logic.js +184 -0
  19. package/dist/dev/theme/theme-logic.js.map +1 -0
  20. package/dist/dev/theme/theme-provider.d.ts +90 -0
  21. package/dist/dev/theme/theme-provider.js +150 -0
  22. package/dist/dev/theme/theme-provider.js.map +1 -0
  23. package/dist/prod/index.js +1 -0
  24. package/dist/prod/locales/ar.js +2 -0
  25. package/dist/prod/locales/ar.js.map +1 -0
  26. package/dist/prod/locales/en.js +2 -0
  27. package/dist/prod/locales/en.js.map +1 -0
  28. package/dist/prod/registry/utils/utils.js +2 -0
  29. package/dist/prod/registry/utils/utils.js.map +1 -0
  30. package/dist/prod/theme/theme-logic.js +2 -0
  31. package/dist/prod/theme/theme-logic.js.map +1 -0
  32. package/dist/prod/theme/theme-provider.js +2 -0
  33. package/dist/prod/theme/theme-provider.js.map +1 -0
  34. package/package.json +102 -4
  35. package/registry/accordion/accordion.tsx +210 -0
  36. package/registry/accordion/item.json +4 -0
  37. package/registry/alert/alert.tsx +200 -0
  38. package/registry/alert/item.json +4 -0
  39. package/registry/alert-dialog/alert-dialog.tsx +530 -0
  40. package/registry/alert-dialog/item.json +4 -0
  41. package/registry/aspect-ratio/aspect-ratio.tsx +71 -0
  42. package/registry/aspect-ratio/item.json +4 -0
  43. package/registry/attachment/attachment.tsx +459 -0
  44. package/registry/attachment/item.json +4 -0
  45. package/registry/avatar/avatar.tsx +385 -0
  46. package/registry/avatar/item.json +4 -0
  47. package/registry/badge/badge.tsx +108 -0
  48. package/registry/badge/item.json +4 -0
  49. package/registry/breadcrumb/breadcrumb.tsx +354 -0
  50. package/registry/breadcrumb/item.json +4 -0
  51. package/registry/bubble/bubble.tsx +260 -0
  52. package/registry/bubble/item.json +4 -0
  53. package/registry/button/button.tsx +125 -0
  54. package/registry/button/item.json +4 -0
  55. package/registry/button-group/button-group.tsx +189 -0
  56. package/registry/button-group/item.json +4 -0
  57. package/registry/calendar/calendar.tsx +348 -0
  58. package/registry/calendar/item.json +4 -0
  59. package/registry/card/card.tsx +311 -0
  60. package/registry/card/item.json +4 -0
  61. package/registry/carousel/carousel.tsx +851 -0
  62. package/registry/carousel/item.json +4 -0
  63. package/registry/chart/chart.tsx +1956 -0
  64. package/registry/chart/item.json +4 -0
  65. package/registry/chart-scale/chart-scale.ts +670 -0
  66. package/registry/chart-scale/item.json +5 -0
  67. package/registry/checkbox/checkbox.tsx +79 -0
  68. package/registry/checkbox/item.json +4 -0
  69. package/registry/code-block/code-block.tsx +470 -0
  70. package/registry/code-block/item.json +4 -0
  71. package/registry/collapsible/collapsible.tsx +117 -0
  72. package/registry/collapsible/item.json +4 -0
  73. package/registry/combobox/combobox.tsx +977 -0
  74. package/registry/combobox/item.json +4 -0
  75. package/registry/command/command.tsx +757 -0
  76. package/registry/command/item.json +4 -0
  77. package/registry/context-menu/context-menu.tsx +697 -0
  78. package/registry/context-menu/item.json +4 -0
  79. package/registry/data-table/data-table.tsx +437 -0
  80. package/registry/data-table/item.json +4 -0
  81. package/registry/date-picker/date-picker.tsx +349 -0
  82. package/registry/date-picker/item.json +4 -0
  83. package/registry/dialog/dialog.tsx +412 -0
  84. package/registry/dialog/item.json +4 -0
  85. package/registry/direction/direction.tsx +88 -0
  86. package/registry/direction/item.json +4 -0
  87. package/registry/drawer/drawer.tsx +787 -0
  88. package/registry/drawer/item.json +4 -0
  89. package/registry/dropdown-menu/dropdown-menu.tsx +692 -0
  90. package/registry/dropdown-menu/item.json +4 -0
  91. package/registry/empty/empty.tsx +240 -0
  92. package/registry/empty/item.json +4 -0
  93. package/registry/field/field.tsx +624 -0
  94. package/registry/field/item.json +4 -0
  95. package/registry/form/form.tsx +1112 -0
  96. package/registry/form/item.json +4 -0
  97. package/registry/hover-card/hover-card.tsx +144 -0
  98. package/registry/hover-card/item.json +4 -0
  99. package/registry/icons/icons.tsx +1691 -0
  100. package/registry/icons/item.json +4 -0
  101. package/registry/input/input.tsx +43 -0
  102. package/registry/input/item.json +4 -0
  103. package/registry/input-group/input-group.tsx +315 -0
  104. package/registry/input-group/item.json +4 -0
  105. package/registry/input-otp/input-otp.tsx +329 -0
  106. package/registry/input-otp/item.json +4 -0
  107. package/registry/item/item.json +4 -0
  108. package/registry/item/item.tsx +439 -0
  109. package/registry/kbd/item.json +4 -0
  110. package/registry/kbd/kbd.tsx +65 -0
  111. package/registry/label/item.json +4 -0
  112. package/registry/label/label.tsx +60 -0
  113. package/registry/marker/item.json +4 -0
  114. package/registry/marker/marker.tsx +175 -0
  115. package/registry/menubar/item.json +4 -0
  116. package/registry/menubar/menubar.tsx +694 -0
  117. package/registry/message/item.json +4 -0
  118. package/registry/message/message.tsx +280 -0
  119. package/registry/message-scroller/item.json +4 -0
  120. package/registry/message-scroller/message-scroller.tsx +262 -0
  121. package/registry/native-select/item.json +4 -0
  122. package/registry/native-select/native-select.tsx +113 -0
  123. package/registry/navigation-menu/item.json +4 -0
  124. package/registry/navigation-menu/navigation-menu.tsx +362 -0
  125. package/registry/pagination/item.json +4 -0
  126. package/registry/pagination/pagination.tsx +460 -0
  127. package/registry/password-input/item.json +5 -0
  128. package/registry/password-input/password-input.tsx +494 -0
  129. package/registry/popover/item.json +4 -0
  130. package/registry/popover/popover.tsx +284 -0
  131. package/registry/progress/item.json +4 -0
  132. package/registry/progress/progress.tsx +190 -0
  133. package/registry/questionnaire/item.json +4 -0
  134. package/registry/questionnaire/questionnaire.tsx +569 -0
  135. package/registry/radio-group/item.json +4 -0
  136. package/registry/radio-group/radio-group.tsx +101 -0
  137. package/registry/resizable/item.json +4 -0
  138. package/registry/resizable/resizable.tsx +455 -0
  139. package/registry/scroll-area/item.json +4 -0
  140. package/registry/scroll-area/scroll-area.tsx +149 -0
  141. package/registry/select/item.json +4 -0
  142. package/registry/select/select.tsx +571 -0
  143. package/registry/separator/item.json +4 -0
  144. package/registry/separator/separator.tsx +52 -0
  145. package/registry/sheet/item.json +4 -0
  146. package/registry/sheet/sheet.tsx +476 -0
  147. package/registry/sidebar/item.json +4 -0
  148. package/registry/sidebar/sidebar.tsx +1870 -0
  149. package/registry/skeleton/item.json +4 -0
  150. package/registry/skeleton/skeleton.tsx +47 -0
  151. package/registry/slider/item.json +4 -0
  152. package/registry/slider/slider.tsx +149 -0
  153. package/registry/spinner/item.json +4 -0
  154. package/registry/spinner/spinner.tsx +51 -0
  155. package/registry/switch/item.json +4 -0
  156. package/registry/switch/switch.tsx +93 -0
  157. package/registry/table/item.json +4 -0
  158. package/registry/table/table.tsx +373 -0
  159. package/registry/tabs/item.json +4 -0
  160. package/registry/tabs/tabs.tsx +209 -0
  161. package/registry/textarea/item.json +4 -0
  162. package/registry/textarea/textarea.tsx +51 -0
  163. package/registry/toast/item.json +4 -0
  164. package/registry/toast/toast.tsx +949 -0
  165. package/registry/toggle/item.json +4 -0
  166. package/registry/toggle/toggle.tsx +110 -0
  167. package/registry/toggle-group/item.json +4 -0
  168. package/registry/toggle-group/toggle-group.tsx +189 -0
  169. package/registry/tooltip/item.json +4 -0
  170. package/registry/tooltip/tooltip.tsx +169 -0
  171. package/registry/trace/item.json +4 -0
  172. package/registry/trace/trace.tsx +356 -0
  173. package/registry/ui-strings/item.json +5 -0
  174. package/registry/ui-strings/ui-strings.tsx +454 -0
  175. package/registry/use-highlighted-code/item.json +5 -0
  176. package/registry/use-highlighted-code/use-highlighted-code.tsx +145 -0
  177. package/registry/use-mobile/item.json +5 -0
  178. package/registry/use-mobile/use-mobile.ts +46 -0
  179. package/registry/utils/item.json +5 -0
  180. package/registry/utils/utils.ts +38 -0
  181. package/registry.json +3274 -0
  182. package/styles/animations.css +321 -0
  183. package/styles/theme-core.css +55 -0
  184. package/styles/theme.css +12 -0
  185. package/styles/themes/gray.css +69 -0
  186. package/styles/themes/neutral.css +69 -0
  187. package/styles/themes/slate.css +69 -0
  188. package/styles/themes/stone.css +69 -0
  189. package/styles/themes/zinc.css +69 -0
  190. package/styles/typeset.css +251 -0
@@ -0,0 +1,4 @@
1
+ {
2
+ "title": "Skeleton",
3
+ "description": "Use to show a placeholder while content is loading."
4
+ }
@@ -0,0 +1,47 @@
1
+ import { splitProps } from "@shadow-js/core";
2
+ import type { ComponentProps, JSX } from "@shadow-js/web";
3
+ import { cn } from "@/lib/utils";
4
+
5
+ /**
6
+ * A placeholder shaped like the content that is loading: a pulsing block that you size with
7
+ * `class`. The placeholder is decorative, so it is hidden from assistive technology
8
+ * (`aria-hidden="true"`). Mark the region that loads with `aria-busy="true"`, or announce the
9
+ * loading state with a status (see {@link Spinner}). Under reduced motion the pulse stops.
10
+ *
11
+ * Keyboard and ARIA: no keys and no role. The element is `aria-hidden="true"`, so the loading
12
+ * state must be announced by the region around it, not by the placeholder.
13
+ *
14
+ * shadcn/ui differences: `class` replaces `className`. Unlike shadcn/ui, the placeholder is
15
+ * `aria-hidden="true"` by default.
16
+ *
17
+ * @param props - The props: the attributes of the `div`. `class` is merged with the base classes.
18
+ * @returns The placeholder `div`.
19
+ * @example
20
+ * ```tsx
21
+ * import { Skeleton } from "@/components/ui/skeleton";
22
+ *
23
+ * export function CardSkeleton() {
24
+ * return (
25
+ * <div aria-busy="true" class="flex items-center gap-4">
26
+ * <Skeleton class="size-12 rounded-full" />
27
+ * <Skeleton class="h-4 w-[250px]" />
28
+ * </div>
29
+ * );
30
+ * }
31
+ * ```
32
+ * @since 1.0.0
33
+ * @see {@link Spinner}
34
+ */
35
+ function Skeleton(props: ComponentProps<"div">): JSX.Element {
36
+ const [local, rest] = splitProps(props, ["class"]);
37
+ return (
38
+ <div
39
+ data-slot="skeleton"
40
+ aria-hidden="true"
41
+ class={cn("animate-pulse rounded-md bg-accent motion-reduce:animate-none", local.class)}
42
+ {...rest}
43
+ />
44
+ );
45
+ }
46
+
47
+ export { Skeleton };
@@ -0,0 +1,4 @@
1
+ {
2
+ "title": "Slider",
3
+ "description": "An input where the user selects a value, or a range, from within a given range."
4
+ }
@@ -0,0 +1,149 @@
1
+ import { splitProps } from "@shadow-js/core";
2
+ import {
3
+ type PolymorphicTarget,
4
+ Slider as SliderPrimitive,
5
+ type SliderProps as SliderPrimitiveProps,
6
+ } from "@shadow-js/primitives";
7
+ import { For, type JSX } from "@shadow-js/web";
8
+ import { type ClassValue, cn } from "@/lib/utils";
9
+
10
+ /**
11
+ * Props that {@link Slider} adds to the primitive's props. Use them to name the thumbs and to
12
+ * give a value text.
13
+ * @since 1.0.0
14
+ * @see {@link Slider}
15
+ */
16
+ export interface SliderExtraProps {
17
+ /**
18
+ * The accessible name of each thumb of a range slider, by thumb index (for example
19
+ * `["Minimum price", "Maximum price"]`). Without it a range of two thumbs is named "Minimum" and
20
+ * "Maximum". A single-thumb slider is named by `aria-label` or `aria-labelledby` instead.
21
+ * @default none (a range of two thumbs is named "Minimum" and "Maximum")
22
+ */
23
+ readonly thumbLabels?: readonly string[] | undefined;
24
+ /**
25
+ * The `aria-valuetext` of each thumb of a range, by thumb index (for example
26
+ * `["40 events per second"]`). It is set on the thumb, the element with `role="slider"`, and
27
+ * never on the group that wraps a range.
28
+ * @default none
29
+ */
30
+ readonly thumbValueTexts?: readonly string[] | undefined;
31
+ /**
32
+ * The value text of a single-thumb slider, for example `"30 percent"`. It is set on the thumb.
33
+ * @default none
34
+ */
35
+ readonly "aria-valuetext"?: string | undefined;
36
+ }
37
+
38
+ /** The props as the implementation sees them. */
39
+ type Loose = {
40
+ readonly class?: ClassValue;
41
+ readonly value?: readonly number[] | undefined;
42
+ readonly defaultValue?: readonly number[] | undefined;
43
+ readonly min?: number | undefined;
44
+ readonly thumbLabels?: readonly string[] | undefined;
45
+ readonly thumbValueTexts?: readonly string[] | undefined;
46
+ readonly "aria-label"?: string | undefined;
47
+ readonly "aria-labelledby"?: string | undefined;
48
+ readonly "aria-valuetext"?: string | undefined;
49
+ readonly [prop: string]: unknown;
50
+ };
51
+
52
+ /**
53
+ * Props of {@link Slider}: the primitive's props (`value`, `defaultValue`, `onValueChange`,
54
+ * `onValueCommit`, `min`, `max`, `step`, `orientation`, `dir`, `inverted`, `disabled`, `name` and
55
+ * others), plus the {@link SliderExtraProps}. The remaining props are the attributes of the root
56
+ * element.
57
+ * @since 1.0.0
58
+ * @see {@link Slider}
59
+ */
60
+ export type SliderProps<T extends PolymorphicTarget = "span"> = SliderPrimitiveProps<T> &
61
+ SliderExtraProps;
62
+
63
+ /**
64
+ * Selects a number, or a range of several numbers, by dragging a thumb along a track or with the
65
+ * keyboard. The number of thumbs is the length of `value` or `defaultValue` (one thumb at `min` when
66
+ * neither is given). Use `value` and `onValueChange` to control it, or `defaultValue` to start it.
67
+ *
68
+ * Keyboard and ARIA: each thumb is a focusable element with `role="slider"`. Arrow keys move one
69
+ * step (the arrow that raises the value follows the direction, `inverted` and the orientation).
70
+ * Shift+Arrow and PageUp or PageDown move ten steps, and Home and End jump to the ends. The
71
+ * thumb sets `aria-valuemin`, `aria-valuenow`, `aria-valuemax` and `aria-orientation`. While
72
+ * disabled it leaves the tab order and has `aria-disabled="true"`. A single slider is named by
73
+ * `aria-label` or `aria-labelledby`, which the component puts on its thumb. A range is a
74
+ * `role="group"` named by `aria-label` or `aria-labelledby`, and each of its thumbs is named by
75
+ * `thumbLabels` (default "Minimum" and "Maximum"). A press on the track moves the nearest thumb to
76
+ * the pointer, and the drag continues outside the slider.
77
+ *
78
+ * shadcn/ui differences: `class` replaces `className`. Each thumb gets its own accessible name
79
+ * here (`thumbLabels`, or `aria-label` for a single thumb). shadcn/ui does not name the thumbs.
80
+ *
81
+ * @param props - The props, see {@link SliderProps}.
82
+ * @returns The slider root, with the track, the range and one thumb per value.
83
+ * @example
84
+ * ```tsx
85
+ * import { Slider } from "@/components/ui/slider";
86
+ *
87
+ * export function VolumeControl() {
88
+ * return <Slider defaultValue={[50]} max={100} step={1} aria-label="Volume" class="w-64" />;
89
+ * }
90
+ * ```
91
+ * @since 1.0.0
92
+ * @see {@link SliderProps}
93
+ */
94
+ function Slider<T extends PolymorphicTarget = "span">(props: SliderProps<T>): JSX.Element {
95
+ const [local, rest] = splitProps(props as unknown as Loose, [
96
+ "class",
97
+ "value",
98
+ "defaultValue",
99
+ "min",
100
+ "thumbLabels",
101
+ "thumbValueTexts",
102
+ "aria-label",
103
+ "aria-labelledby",
104
+ "aria-valuetext",
105
+ ]);
106
+ const values = (): readonly number[] => local.value ?? local.defaultValue ?? [local.min ?? 0];
107
+ const single = (): boolean => values().length === 1;
108
+ return (
109
+ <SliderPrimitive
110
+ data-slot="slider"
111
+ value={local.value}
112
+ defaultValue={local.defaultValue}
113
+ min={local.min}
114
+ role={single() ? undefined : "group"}
115
+ aria-label={single() ? undefined : local["aria-label"]}
116
+ aria-labelledby={single() ? undefined : local["aria-labelledby"]}
117
+ class={cn(
118
+ "relative flex w-full touch-none items-center select-none data-[disabled]:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col",
119
+ local.class,
120
+ )}
121
+ {...rest}
122
+ >
123
+ <SliderPrimitive.Track
124
+ data-slot="slider-track"
125
+ class="relative grow overflow-hidden rounded-full bg-muted data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5 forced-colors:border forced-colors:border-[ButtonText] forced-colors:bg-[Canvas]"
126
+ >
127
+ <SliderPrimitive.Range
128
+ data-slot="slider-range"
129
+ class="absolute bg-primary data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full forced-colors:bg-[Highlight]"
130
+ />
131
+ </SliderPrimitive.Track>
132
+ <For each={values().map((_, index) => index)}>
133
+ {(index: number) => (
134
+ <SliderPrimitive.Thumb
135
+ data-slot="slider-thumb"
136
+ aria-label={single() ? local["aria-label"] : local.thumbLabels?.[index]}
137
+ aria-labelledby={single() ? local["aria-labelledby"] : undefined}
138
+ aria-valuetext={
139
+ local.thumbValueTexts?.[index] ?? (single() ? local["aria-valuetext"] : undefined)
140
+ }
141
+ class="block size-4 shrink-0 rounded-full border border-primary bg-white shadow-sm ring-ring/50 transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden motion-reduce:transition-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 forced-colors:border-[ButtonText] forced-colors:bg-[ButtonFace]"
142
+ />
143
+ )}
144
+ </For>
145
+ </SliderPrimitive>
146
+ );
147
+ }
148
+
149
+ export { Slider };
@@ -0,0 +1,4 @@
1
+ {
2
+ "title": "Spinner",
3
+ "description": "An indicator that can be used to show a loading state."
4
+ }
@@ -0,0 +1,51 @@
1
+ import { splitProps } from "@shadow-js/core";
2
+ import type { JSX } from "@shadow-js/web";
3
+ import { type IconProps, LoaderIcon } from "@/components/ui/icons";
4
+ import { useUiStrings } from "@/lib/ui-strings";
5
+ import { cn } from "@/lib/utils";
6
+
7
+ /**
8
+ * A loading indicator: a spinning arc that assistive technology announces as "Loading". It is an
9
+ * `svg` with `role="status"`. It is sized with `class` (the default is `size-4`, the icon size).
10
+ * Under reduced motion it turns slowly instead of stopping, so it still reads as busy.
11
+ *
12
+ * Keyboard and ARIA: no keys. The element is `role="status"` with `aria-label="Loading"` by
13
+ * default; pass your own `aria-label` (for example "Saving") to name what is loading.
14
+ *
15
+ * shadcn/ui differences: `class` replaces `className`. The spinner also keeps turning slowly under
16
+ * reduced motion, which shadcn/ui does not do.
17
+ *
18
+ * @param props - The props: the attributes of the `svg`, such as `class` and `aria-label`.
19
+ * @returns The spinner `svg`.
20
+ * @example
21
+ * ```tsx
22
+ * import { Button } from "@/components/ui/button";
23
+ * import { Spinner } from "@/components/ui/spinner";
24
+ *
25
+ * export function SaveButton() {
26
+ * return (
27
+ * <Button disabled>
28
+ * <Spinner />
29
+ * Saving
30
+ * </Button>
31
+ * );
32
+ * }
33
+ * ```
34
+ * @since 1.0.0
35
+ */
36
+ function Spinner(props: IconProps): JSX.Element {
37
+ const [local, rest] = splitProps(props, ["class"]);
38
+ const t = useUiStrings();
39
+ return (
40
+ <LoaderIcon
41
+ role="status"
42
+ aria-label={t("spinner.loading", "Loading")}
43
+ aria-hidden="false"
44
+ data-slot="spinner"
45
+ class={cn("size-4 animate-spin motion-reduce:animate-[spin_3s_linear_infinite]", local.class)}
46
+ {...rest}
47
+ />
48
+ );
49
+ }
50
+
51
+ export { Spinner };
@@ -0,0 +1,4 @@
1
+ {
2
+ "title": "Switch",
3
+ "description": "A control that allows the user to toggle between checked and not checked."
4
+ }
@@ -0,0 +1,93 @@
1
+ import { splitProps } from "@shadow-js/core";
2
+ import {
3
+ type PolymorphicTarget,
4
+ Switch as SwitchPrimitive,
5
+ type SwitchProps as SwitchPrimitiveProps,
6
+ } from "@shadow-js/primitives";
7
+ import type { JSX } from "@shadow-js/web";
8
+ import { type ClassValue, cn } from "@/lib/utils";
9
+
10
+ /**
11
+ * Props of {@link Switch}: the primitive's props (`checked`, `defaultChecked`, `onCheckedChange`,
12
+ * `name`, `value`, `required`, `disabled`, `form`), `size` (`"default"` or `"sm"`), `as` to render
13
+ * another element, and the attributes of the rendered element.
14
+ * @since 1.0.0
15
+ * @see {@link Switch}
16
+ */
17
+ export type SwitchProps<T extends PolymorphicTarget = "button"> = SwitchPrimitiveProps<T> &
18
+ SwitchExtraProps;
19
+
20
+ /**
21
+ * The switch's own props: its size.
22
+ * @since 1.0.0
23
+ * @see {@link Switch}
24
+ */
25
+ export interface SwitchExtraProps {
26
+ /**
27
+ * The size of the switch: `default` is 20px high and 32px wide, `sm` is 14px high and 24px wide.
28
+ * @default "default"
29
+ */
30
+ readonly size?: "sm" | "default" | undefined;
31
+ }
32
+
33
+ /** The props as the implementation sees them. */
34
+ type Loose = {
35
+ readonly class?: ClassValue;
36
+ readonly size?: "sm" | "default" | undefined;
37
+ readonly [prop: string]: unknown;
38
+ };
39
+
40
+ /**
41
+ * A control that switches one setting on or off. Controlled with `checked` and `onCheckedChange`,
42
+ * or uncontrolled with `defaultChecked`. With a `name` it takes part in native forms. The thumb
43
+ * moves the right way in right-to-left layouts.
44
+ *
45
+ * Keyboard and ARIA: Tab moves focus to the switch. Space or Enter toggles it. It has
46
+ * `role="switch"` and `aria-checked` (`"true"` or `"false"`), and `data-state` (`"checked"` or
47
+ * `"unchecked"`). A disabled switch is a disabled button. `required` sets `aria-required`. Name it
48
+ * with a {@link Label} (`id` on the switch, `htmlFor` on the label) or with `aria-label`. Clicking
49
+ * the label toggles the switch.
50
+ *
51
+ * shadcn/ui differences: `as` replaces `asChild` for choosing the rendered element, and `class`
52
+ * replaces `className`. Each part has its `data-slot` (`switch` and `switch-thumb`).
53
+ *
54
+ * @param props - The props, see {@link SwitchProps}.
55
+ * @returns The switch element with its thumb inside.
56
+ * @example
57
+ * ```tsx
58
+ * import { Label } from "@/components/ui/label";
59
+ * import { Switch } from "@/components/ui/switch";
60
+ *
61
+ * export function AirplaneMode() {
62
+ * return (
63
+ * <div class="flex items-center gap-2">
64
+ * <Switch id="airplane" onCheckedChange={(on: boolean) => console.log(on)} />
65
+ * <Label htmlFor="airplane">Airplane mode</Label>
66
+ * </div>
67
+ * );
68
+ * }
69
+ * ```
70
+ * @since 1.0.0
71
+ * @see {@link SwitchProps}
72
+ */
73
+ function Switch<T extends PolymorphicTarget = "button">(props: SwitchProps<T>): JSX.Element {
74
+ const [local, rest] = splitProps(props as unknown as Loose, ["class", "size"]);
75
+ return (
76
+ <SwitchPrimitive
77
+ data-slot="switch"
78
+ data-size={local.size ?? "default"}
79
+ class={cn(
80
+ "peer group/switch inline-flex h-[1.15rem] w-8 data-[size=sm]:h-3.5 data-[size=sm]:w-6 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 motion-reduce:transition-none data-[state=checked]:bg-primary data-[state=unchecked]:bg-input dark:data-[state=unchecked]:bg-input/80 forced-colors:border-[ButtonText] forced-colors:data-[state=checked]:bg-[Highlight] forced-colors:data-[state=unchecked]:bg-[Canvas] focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-transparent",
81
+ local.class,
82
+ )}
83
+ {...rest}
84
+ >
85
+ <SwitchPrimitive.Thumb
86
+ data-slot="switch-thumb"
87
+ class="pointer-events-none block size-4 group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 rounded-full bg-background ring-0 transition-transform motion-reduce:transition-none data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0 rtl:data-[state=checked]:-translate-x-[calc(100%-2px)] dark:data-[state=checked]:bg-primary-foreground dark:data-[state=unchecked]:bg-foreground forced-colors:bg-[ButtonText] forced-colors:data-[state=checked]:bg-[HighlightText]"
88
+ />
89
+ </SwitchPrimitive>
90
+ );
91
+ }
92
+
93
+ export { Switch };
@@ -0,0 +1,4 @@
1
+ {
2
+ "title": "Table",
3
+ "description": "A responsive table component."
4
+ }