@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,329 @@
1
+ import { splitProps, useMemo } from "@shadow-js/core";
2
+ import {
3
+ createOneTimePasswordPattern,
4
+ createPartContext,
5
+ type Direction,
6
+ OneTimePasswordField,
7
+ type OneTimePasswordType,
8
+ } from "@shadow-js/primitives";
9
+ import type { ComponentProps, JSX } from "@shadow-js/web";
10
+ import { useUiStrings } from "@/lib/ui-strings";
11
+ import { cn } from "@/lib/utils";
12
+
13
+ /** What a code field shares with its slots, to name them. @internal */
14
+ interface InputOtpContextValue {
15
+ readonly length: () => number;
16
+ /** Whether the slots take digits (numeric, no pattern) rather than characters. */
17
+ readonly digits: () => boolean;
18
+ }
19
+
20
+ const inputOtpContext = createPartContext<InputOtpContextValue>("InputOTP");
21
+
22
+ /**
23
+ * A per-character digit pattern; Arabic-Indic and Persian digits normalize before matching.
24
+ * @example
25
+ * import { REGEXP_ONLY_DIGITS } from "@/components/ui/input-otp";
26
+ * export const acceptsDigit = new RegExp(REGEXP_ONLY_DIGITS).test("7");
27
+ * @since 1.0.0
28
+ */
29
+ const REGEXP_ONLY_DIGITS: string = "^[0-9]+$";
30
+ /**
31
+ * A per-character ASCII letter pattern, accepting uppercase and lowercase letters.
32
+ * @example
33
+ * import { REGEXP_ONLY_CHARS } from "@/components/ui/input-otp";
34
+ * export const acceptsLetter = new RegExp(REGEXP_ONLY_CHARS).test("A");
35
+ * @since 1.0.0
36
+ */
37
+ const REGEXP_ONLY_CHARS: string = "^[a-zA-Z]+$";
38
+ /**
39
+ * A per-character ASCII letter and digit pattern.
40
+ * @example
41
+ * import { REGEXP_ONLY_DIGITS_AND_CHARS } from "@/components/ui/input-otp";
42
+ * export const acceptsCode = new RegExp(REGEXP_ONLY_DIGITS_AND_CHARS).test("A7");
43
+ * @since 1.0.0
44
+ */
45
+ const REGEXP_ONLY_DIGITS_AND_CHARS: string = "^[a-zA-Z0-9]+$";
46
+
47
+ /**
48
+ * Props of {@link InputOTP}. The slots and separators are its children; the code is `value`
49
+ * (controlled) or `defaultValue` (uncontrolled).
50
+ * @since 1.0.0
51
+ * @see {@link InputOTP}
52
+ */
53
+ export interface InputOTPProps {
54
+ /** Explicit reading direction for layout and arrow keys. @default undefined (inherited direction) */
55
+ readonly dir?: Direction | undefined;
56
+ /**
57
+ * The number of slots, an integer from 1 to 64, fixed when the component mounts.
58
+ * @default 6
59
+ */
60
+ readonly maxLength?: number | undefined;
61
+ /**
62
+ * Which characters a slot accepts: `"numeric"` for digits, `"alphanumeric"` for letters and digits.
63
+ * @default "numeric"
64
+ */
65
+ readonly type?: OneTimePasswordType | undefined;
66
+ /**
67
+ * A regular expression source of at most 256 characters, matched against each normalized
68
+ * character. Overrides `type` filtering; use the exported REGEXP constants for common codes.
69
+ * This filters characters rather than validating the whole code. Custom patterns use text input mode.
70
+ * @default undefined (use `type`)
71
+ */
72
+ readonly pattern?: string | undefined;
73
+ /**
74
+ * The code when controlled. Pair it with `onChange` to keep it up to date.
75
+ * @default none (uncontrolled)
76
+ */
77
+ readonly value?: string | undefined;
78
+ /**
79
+ * The starting code when uncontrolled.
80
+ * @default "" (empty)
81
+ */
82
+ readonly defaultValue?: string | undefined;
83
+ /**
84
+ * Called with the whole code after every change: typing, deleting or pasting.
85
+ * @default none
86
+ */
87
+ readonly onChange?: ((value: string) => void) | undefined;
88
+ /**
89
+ * Called once when every slot is filled, with the full code.
90
+ * @default none
91
+ */
92
+ readonly onComplete?: ((value: string) => void) | undefined;
93
+ /**
94
+ * Disables every slot.
95
+ * @default false
96
+ */
97
+ readonly disabled?: boolean | undefined;
98
+ /**
99
+ * Submits the code with a surrounding form under this name.
100
+ * @default none
101
+ */
102
+ readonly name?: string | undefined;
103
+ /**
104
+ * The slots ({@link InputOTPSlot}) and separators ({@link InputOTPSeparator}), in order.
105
+ * @default none
106
+ */
107
+ readonly children?: unknown;
108
+ /**
109
+ * Classes of the wrapper that holds the slots. It is the same element as `class`.
110
+ * @default none
111
+ */
112
+ readonly containerClassName?: string | undefined;
113
+ /**
114
+ * Classes of the wrapper that holds the slots. It is the same element as `containerClassName`.
115
+ * @default none
116
+ */
117
+ readonly class?: string | undefined;
118
+ /**
119
+ * The name of the code field, for example "Verification code". The wrapper is named with it.
120
+ * @default none
121
+ */
122
+ readonly "aria-label"?: string | undefined;
123
+ }
124
+
125
+ /**
126
+ * A one-time code, one character per slot. Typing fills the slot and moves on; Backspace steps
127
+ * back; the arrow keys, Home and End move between slots; a paste or an OS autofill fills them all.
128
+ * Only the characters `type` or `pattern` accepts are kept. Arabic-Indic and Persian digits
129
+ * normalize before matching. An edit scans at most its first 4,096 UTF-16 units; surrogate pairs
130
+ * are refused instead of being split between slots.
131
+ *
132
+ * Keyboard and ARIA: the wrapper is a `role="group"`. Name it with `aria-label`, for example
133
+ * "Verification code", because the slots on their own are only named "Digit 1 of 6". Each slot is
134
+ * an `input` named "Digit n of N" (or "Character n of N" for alphanumeric) unless it has its own
135
+ * `aria-label`. The first slot has `autocomplete="one-time-code"`, so the operating system can
136
+ * offer to fill in a code it has received. Backspace clears the slot and steps back from an empty one; Delete clears
137
+ * the slot; ArrowLeft and ArrowRight (swapped in right-to-left text) and Home and End move between
138
+ * slots. `aria-invalid="true"` on a slot, which you pass, turns its border destructive.
139
+ *
140
+ * shadcn/ui differences: slots compose through JSX children and are native inputs. `type` is a
141
+ * convenience when no `pattern` is supplied. `class` and `containerClassName` style the same root.
142
+ *
143
+ * @param props See {@link InputOTPProps}.
144
+ * @returns The wrapper `div` with the slots and separators inside.
145
+ * @example
146
+ * import {
147
+ * InputOTP,
148
+ * InputOTPGroup,
149
+ * InputOTPSeparator,
150
+ * InputOTPSlot,
151
+ * } from "@/components/ui/input-otp";
152
+ *
153
+ * const submit = (code: string): void => console.info("submit", code);
154
+ *
155
+ * <InputOTP maxLength={6} onComplete={submit} aria-label="Verification code">
156
+ * <InputOTPGroup>
157
+ * <InputOTPSlot index={0} />
158
+ * <InputOTPSlot index={1} />
159
+ * <InputOTPSlot index={2} />
160
+ * </InputOTPGroup>
161
+ * <InputOTPSeparator />
162
+ * <InputOTPGroup>
163
+ * <InputOTPSlot index={3} />
164
+ * <InputOTPSlot index={4} />
165
+ * <InputOTPSlot index={5} />
166
+ * </InputOTPGroup>
167
+ * </InputOTP>
168
+ * @since 1.0.0
169
+ * @see {@link InputOTPSlot}
170
+ */
171
+ function InputOTP(props: InputOTPProps): JSX.Element {
172
+ const [local, rest] = splitProps(props as InputOTPProps & Record<string, unknown>, [
173
+ "maxLength",
174
+ "type",
175
+ "pattern",
176
+ "value",
177
+ "defaultValue",
178
+ "onChange",
179
+ "onComplete",
180
+ "disabled",
181
+ "name",
182
+ "children",
183
+ "containerClassName",
184
+ "class",
185
+ ]);
186
+ const filter = useMemo(() =>
187
+ local.pattern === undefined ? undefined : createOneTimePasswordPattern(local.pattern as string),
188
+ );
189
+ const length = (): number => (local.maxLength as number | undefined) ?? 6;
190
+ const digits = (): boolean =>
191
+ ((local.type as OneTimePasswordType | undefined) ?? "numeric") === "numeric" &&
192
+ local.pattern === undefined;
193
+ return (
194
+ <inputOtpContext.Provider value={{ length, digits }}>
195
+ <OneTimePasswordField
196
+ data-slot="input-otp"
197
+ length={(local.maxLength as number | undefined) ?? 6}
198
+ type={(local.type as OneTimePasswordType | undefined) ?? "numeric"}
199
+ filter={filter()}
200
+ value={local.value as string | undefined}
201
+ defaultValue={local.defaultValue as string | undefined}
202
+ onValueChange={local.onChange as ((value: string) => void) | undefined}
203
+ onComplete={local.onComplete as ((value: string) => void) | undefined}
204
+ disabled={local.disabled as boolean | undefined}
205
+ name={local.name as string | undefined}
206
+ class={cn(
207
+ "flex items-center gap-2 has-disabled:opacity-50",
208
+ local.containerClassName as string | undefined,
209
+ local.class as string | undefined,
210
+ )}
211
+ {...rest}
212
+ >
213
+ {local.children as JSX.Element}
214
+ </OneTimePasswordField>
215
+ </inputOtpContext.Provider>
216
+ );
217
+ }
218
+
219
+ /**
220
+ * A row of slots, drawn with the kit's border, focus ring and radius on each one.
221
+ *
222
+ * Keyboard and ARIA: no keys and no role of its own; the slots inside keep theirs.
223
+ *
224
+ * @param props The `div` attributes; `class` adds to the classes.
225
+ * @returns The group `div`.
226
+ * @example
227
+ * import { InputOTPGroup, InputOTPSlot } from "@/components/ui/input-otp";
228
+ *
229
+ * <InputOTPGroup>
230
+ * <InputOTPSlot index={0} />
231
+ * </InputOTPGroup>
232
+ * @since 1.0.0
233
+ * @see {@link InputOTPSlot}
234
+ */
235
+ function InputOTPGroup(props: ComponentProps<"div">): JSX.Element {
236
+ const [local, rest] = splitProps(props, ["class"]);
237
+ return <div data-slot="input-otp-group" class={cn("flex items-center", local.class)} {...rest} />;
238
+ }
239
+
240
+ /**
241
+ * One character of an {@link InputOTP}, at `index` (counted from 0). It is a text `input` of its
242
+ * own: its border and ring turn destructive while you pass `aria-invalid="true"`.
243
+ *
244
+ * Keyboard and ARIA: the keys are those of {@link InputOTP}. The slot is named "Digit n of N" (or
245
+ * "Character n of N") unless you pass an `aria-label`.
246
+ *
247
+ * @param props The `input` attributes plus `index`, the position of the slot from 0. `class` adds to
248
+ * the classes.
249
+ * @returns The slot `input`.
250
+ * @throws Error when rendered outside an {@link InputOTP}.
251
+ * @example
252
+ * import { InputOTP, InputOTPSlot } from "@/components/ui/input-otp";
253
+ *
254
+ * <InputOTP maxLength={1} aria-label="PIN">
255
+ * <InputOTPSlot index={0} aria-invalid="true" />
256
+ * </InputOTP>
257
+ * @since 1.0.0
258
+ * @see {@link InputOTP}
259
+ */
260
+ function InputOTPSlot(props: ComponentProps<"input"> & { readonly index: number }): JSX.Element {
261
+ const [local, rest] = splitProps(
262
+ props as ComponentProps<"input"> & { readonly index: number; readonly class?: unknown },
263
+ ["class", "index"],
264
+ );
265
+ const field = inputOtpContext.useOptional();
266
+ const t = useUiStrings();
267
+ // The name is "Digit n of N" or "Character n of N", in the language of the UI strings.
268
+ const name = (): string | undefined => {
269
+ if (field === undefined) return undefined;
270
+ const values = { position: local.index + 1, total: field.length() };
271
+ return field.digits()
272
+ ? t("inputOtp.digit", "Digit {position} of {total}", values)
273
+ : t("inputOtp.character", "Character {position} of {total}", values);
274
+ };
275
+ return (
276
+ <OneTimePasswordField.Input
277
+ data-slot="input-otp-slot"
278
+ aria-label={name()}
279
+ index={local.index}
280
+ class={cn(
281
+ "relative flex size-9 items-center justify-center border-y border-e border-input bg-transparent text-center text-sm shadow-xs transition-all outline-none first:rounded-s-md first:border-s last:rounded-e-md dark:bg-input/30",
282
+ "focus:z-10 focus:border-ring focus:ring-[3px] focus:ring-ring/50 focus:outline-solid focus:outline-2 focus:outline-offset-2 focus:outline-transparent aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
283
+ "disabled:pointer-events-none disabled:opacity-50 motion-reduce:transition-none forced-colors:focus:outline-[Highlight]",
284
+ local.class as string | undefined,
285
+ )}
286
+ {...rest}
287
+ />
288
+ );
289
+ }
290
+
291
+ /**
292
+ * A dot between two groups of slots.
293
+ *
294
+ * Keyboard and ARIA: a horizontal `role="separator"` with `aria-orientation="horizontal"`. It is not
295
+ * focusable. The dot inside it is decorative and hidden from assistive technology.
296
+ *
297
+ * @param props The `div` attributes; `class` adds to the classes.
298
+ * @returns The separator `div`.
299
+ * @example
300
+ * import { InputOTPSeparator } from "@/components/ui/input-otp";
301
+ *
302
+ * <InputOTPSeparator />
303
+ * @since 1.0.0
304
+ * @see {@link InputOTP}
305
+ */
306
+ function InputOTPSeparator(props: ComponentProps<"div">): JSX.Element {
307
+ const [local, rest] = splitProps(props, ["class"]);
308
+ return (
309
+ <div
310
+ role="separator"
311
+ aria-orientation="horizontal"
312
+ data-slot="input-otp-separator"
313
+ class={cn("mx-1 flex w-4 items-center justify-center", local.class)}
314
+ {...rest}
315
+ >
316
+ <span aria-hidden="true" class="size-1.5 rounded-full bg-muted-foreground" />
317
+ </div>
318
+ );
319
+ }
320
+
321
+ export {
322
+ InputOTP,
323
+ InputOTPGroup,
324
+ InputOTPSeparator,
325
+ InputOTPSlot,
326
+ REGEXP_ONLY_CHARS,
327
+ REGEXP_ONLY_DIGITS,
328
+ REGEXP_ONLY_DIGITS_AND_CHARS,
329
+ };
@@ -0,0 +1,4 @@
1
+ {
2
+ "title": "Input OTP",
3
+ "description": "A one-time code with custom character patterns, digit normalization, paste, autofill and RTL keyboard navigation."
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "title": "Item",
3
+ "description": "A row of media, content and actions, in a group, that can be a link."
4
+ }