@cl-light-ds/ui 0.2.0 → 0.4.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 (293) hide show
  1. package/README.md +45 -45
  2. package/package.json +2 -2
  3. package/src/components/accordion/Accordion.astro +248 -248
  4. package/src/components/accordion/AccordionContent.astro +26 -26
  5. package/src/components/accordion/AccordionItem.astro +36 -36
  6. package/src/components/accordion/AccordionTrigger.astro +118 -118
  7. package/src/components/accordion/CHANGELOG.md +41 -41
  8. package/src/components/accordion/index.ts +4 -4
  9. package/src/components/alert/Alert.astro +167 -167
  10. package/src/components/alert/AlertDescription.astro +24 -24
  11. package/src/components/alert/AlertTitle.astro +24 -24
  12. package/src/components/alert/CHANGELOG.md +5 -5
  13. package/src/components/alert/index.ts +4 -4
  14. package/src/components/avatar/Avatar.astro +197 -197
  15. package/src/components/avatar/AvatarBadge.astro +44 -44
  16. package/src/components/avatar/AvatarFallback.astro +26 -26
  17. package/src/components/avatar/AvatarGroup.astro +26 -26
  18. package/src/components/avatar/AvatarGroupCount.astro +30 -30
  19. package/src/components/avatar/AvatarImage.astro +46 -46
  20. package/src/components/avatar/CHANGELOG.md +44 -44
  21. package/src/components/avatar/index.ts +6 -6
  22. package/src/components/badge/Badge.astro +167 -167
  23. package/src/components/badge/CHANGELOG.md +49 -49
  24. package/src/components/badge/index.ts +2 -2
  25. package/src/components/breadcrumb/Breadcrumb.astro +76 -76
  26. package/src/components/breadcrumb/BreadcrumbItem.astro +32 -32
  27. package/src/components/breadcrumb/BreadcrumbList.astro +26 -26
  28. package/src/components/breadcrumb/BreadcrumbSeparator.astro +26 -26
  29. package/src/components/breadcrumb/CHANGELOG.md +24 -24
  30. package/src/components/breadcrumb/index.ts +5 -5
  31. package/src/components/button/Button.astro +233 -233
  32. package/src/components/button/CHANGELOG.md +41 -41
  33. package/src/components/button/index.ts +2 -2
  34. package/src/components/button-group/ButtonGroup.astro +130 -130
  35. package/src/components/button-group/ButtonGroupSeparator.astro +30 -30
  36. package/src/components/button-group/ButtonGroupText.astro +21 -21
  37. package/src/components/button-group/CHANGELOG.md +34 -34
  38. package/src/components/button-group/index.ts +3 -3
  39. package/src/components/callout/CHANGELOG.md +32 -0
  40. package/src/components/callout/Callout.astro +147 -0
  41. package/src/components/callout/CalloutDescription.astro +16 -0
  42. package/src/components/callout/CalloutTitle.astro +16 -0
  43. package/src/components/callout/index.ts +3 -0
  44. package/src/components/card/CHANGELOG.md +162 -119
  45. package/src/components/card/Card.astro +197 -182
  46. package/src/components/card/CardAction.astro +26 -26
  47. package/src/components/card/CardContent.astro +28 -28
  48. package/src/components/card/CardDescription.astro +28 -28
  49. package/src/components/card/CardFooter.astro +24 -24
  50. package/src/components/card/CardHeader.astro +30 -30
  51. package/src/components/card/CardMedia.astro +27 -27
  52. package/src/components/card/CardMediaActions.astro +21 -0
  53. package/src/components/card/CardMediaSelect.astro +21 -0
  54. package/src/components/card/CardOverlay.astro +32 -32
  55. package/src/components/card/CardTitle.astro +21 -21
  56. package/src/components/card/index.ts +12 -10
  57. package/src/components/carousel/CHANGELOG.md +5 -5
  58. package/src/components/carousel/Carousel.astro +106 -106
  59. package/src/components/carousel/CarouselSlide.astro +22 -22
  60. package/src/components/carousel/index.ts +3 -3
  61. package/src/components/checkbox/CHANGELOG.md +58 -58
  62. package/src/components/checkbox/Checkbox.astro +159 -159
  63. package/src/components/checkbox/index.ts +1 -1
  64. package/src/components/collapsible/CHANGELOG.md +5 -5
  65. package/src/components/collapsible/Collapsible.astro +202 -202
  66. package/src/components/collapsible/CollapsibleContent.astro +36 -36
  67. package/src/components/collapsible/CollapsibleTrigger.astro +34 -34
  68. package/src/components/collapsible/index.ts +4 -4
  69. package/src/components/combobox/CHANGELOG.md +27 -27
  70. package/src/components/combobox/Combobox.astro +365 -365
  71. package/src/components/combobox/ComboboxContent.astro +37 -37
  72. package/src/components/combobox/ComboboxEmpty.astro +18 -18
  73. package/src/components/combobox/ComboboxGroup.astro +19 -19
  74. package/src/components/combobox/ComboboxInput.astro +74 -74
  75. package/src/components/combobox/ComboboxItem.astro +39 -39
  76. package/src/components/combobox/ComboboxLabel.astro +18 -18
  77. package/src/components/combobox/ComboboxList.astro +21 -21
  78. package/src/components/combobox/ComboboxSeparator.astro +17 -17
  79. package/src/components/combobox/ComboboxTrigger.astro +30 -30
  80. package/src/components/combobox/ComboboxValue.astro +22 -22
  81. package/src/components/combobox/index.ts +11 -11
  82. package/src/components/date/CHANGELOG.md +18 -18
  83. package/src/components/date/Date.astro +137 -137
  84. package/src/components/date/index.ts +2 -2
  85. package/src/components/dialog/CHANGELOG.md +39 -39
  86. package/src/components/dialog/Dialog.astro +196 -196
  87. package/src/components/dialog/DialogClose.astro +23 -23
  88. package/src/components/dialog/DialogContent.astro +42 -42
  89. package/src/components/dialog/DialogDescription.astro +18 -18
  90. package/src/components/dialog/DialogFooter.astro +18 -18
  91. package/src/components/dialog/DialogHeader.astro +18 -18
  92. package/src/components/dialog/DialogOverlay.astro +19 -19
  93. package/src/components/dialog/DialogTitle.astro +18 -18
  94. package/src/components/dialog/DialogTrigger.astro +37 -37
  95. package/src/components/dialog/index.ts +9 -9
  96. package/src/components/dropdown-menu/CHANGELOG.md +194 -194
  97. package/src/components/dropdown-menu/DropdownMenu.astro +226 -226
  98. package/src/components/dropdown-menu/DropdownMenuCheckboxItem.astro +114 -114
  99. package/src/components/dropdown-menu/DropdownMenuContent.astro +42 -42
  100. package/src/components/dropdown-menu/DropdownMenuGroup.astro +19 -19
  101. package/src/components/dropdown-menu/DropdownMenuItem.astro +220 -220
  102. package/src/components/dropdown-menu/DropdownMenuItemContent.astro +79 -79
  103. package/src/components/dropdown-menu/DropdownMenuLabel.astro +20 -20
  104. package/src/components/dropdown-menu/DropdownMenuPortal.astro +13 -13
  105. package/src/components/dropdown-menu/DropdownMenuRadioGroup.astro +13 -13
  106. package/src/components/dropdown-menu/DropdownMenuRadioItem.astro +101 -101
  107. package/src/components/dropdown-menu/DropdownMenuSeparator.astro +18 -18
  108. package/src/components/dropdown-menu/DropdownMenuShortcut.astro +18 -18
  109. package/src/components/dropdown-menu/DropdownMenuTrigger.astro +49 -49
  110. package/src/components/dropdown-menu/dropdown-menu-item-variants.ts +24 -24
  111. package/src/components/dropdown-menu/index.ts +12 -12
  112. package/src/components/field/CHANGELOG.md +33 -33
  113. package/src/components/field/Field.astro +664 -664
  114. package/src/components/field/FieldContent.astro +20 -20
  115. package/src/components/field/FieldDescription.astro +22 -22
  116. package/src/components/field/FieldError.astro +51 -51
  117. package/src/components/field/FieldGroup.astro +20 -20
  118. package/src/components/field/FieldLabel.astro +22 -22
  119. package/src/components/field/FieldLegend.astro +23 -23
  120. package/src/components/field/FieldSeparator.astro +30 -30
  121. package/src/components/field/FieldSet.astro +20 -20
  122. package/src/components/field/FieldTitle.astro +20 -20
  123. package/src/components/field/index.ts +10 -10
  124. package/src/components/hover-card/CHANGELOG.md +20 -20
  125. package/src/components/hover-card/HoverCard.astro +235 -235
  126. package/src/components/hover-card/HoverCardContent.astro +54 -54
  127. package/src/components/hover-card/HoverCardTrigger.astro +38 -38
  128. package/src/components/hover-card/index.ts +3 -3
  129. package/src/components/input/CHANGELOG.md +44 -29
  130. package/src/components/input/Input.astro +130 -130
  131. package/src/components/input/InputOTP.astro +211 -0
  132. package/src/components/input/index.ts +2 -2
  133. package/src/components/input-group/CHANGELOG.md +49 -49
  134. package/src/components/input-group/InputGroup.astro +135 -135
  135. package/src/components/input-group/InputGroupAddon.astro +49 -49
  136. package/src/components/input-group/InputGroupButton.astro +58 -58
  137. package/src/components/input-group/InputGroupInput.astro +18 -18
  138. package/src/components/input-group/InputGroupText.astro +21 -21
  139. package/src/components/input-group/InputGroupTextarea.astro +17 -17
  140. package/src/components/input-group/controlClasses.ts +2 -2
  141. package/src/components/input-group/index.ts +6 -6
  142. package/src/components/item/CHANGELOG.md +27 -27
  143. package/src/components/item/Item.astro +122 -122
  144. package/src/components/item/ItemActions.astro +21 -21
  145. package/src/components/item/ItemContent.astro +25 -25
  146. package/src/components/item/ItemDescription.astro +25 -25
  147. package/src/components/item/ItemFooter.astro +24 -24
  148. package/src/components/item/ItemGroup.astro +24 -24
  149. package/src/components/item/ItemHeader.astro +24 -24
  150. package/src/components/item/ItemMedia.astro +47 -47
  151. package/src/components/item/ItemSeparator.astro +21 -21
  152. package/src/components/item/ItemTitle.astro +25 -25
  153. package/src/components/item/index.ts +10 -10
  154. package/src/components/kbd/CHANGELOG.md +5 -5
  155. package/src/components/kbd/Kbd.astro +145 -145
  156. package/src/components/kbd/KbdGroup.astro +55 -55
  157. package/src/components/kbd/index.ts +2 -2
  158. package/src/components/label/CHANGELOG.md +28 -28
  159. package/src/components/label/Label.astro +97 -97
  160. package/src/components/label/index.ts +2 -2
  161. package/src/components/link-group/CHANGELOG.md +75 -75
  162. package/src/components/link-group/LinkGroup.astro +67 -67
  163. package/src/components/link-group/LinkGroupItem.astro +32 -32
  164. package/src/components/link-group/LinkGroupList.astro +25 -25
  165. package/src/components/link-group/LinkGroupTitle.astro +22 -22
  166. package/src/components/link-group/index.ts +5 -5
  167. package/src/components/link-group/link-group-list-variants.ts +15 -15
  168. package/src/components/logo/CHANGELOG.md +17 -0
  169. package/src/components/logo/Logo.astro +90 -0
  170. package/src/components/logo/index.ts +3 -0
  171. package/src/components/logo/logo-paths.ts +57 -0
  172. package/src/components/marquee/CHANGELOG.md +5 -5
  173. package/src/components/marquee/Marquee.astro +119 -119
  174. package/src/components/marquee/index.ts +2 -2
  175. package/src/components/native-select/CHANGELOG.md +5 -5
  176. package/src/components/native-select/NativeSelect.astro +125 -125
  177. package/src/components/native-select/NativeSelectOptGroup.astro +14 -14
  178. package/src/components/native-select/NativeSelectOption.astro +9 -9
  179. package/src/components/native-select/index.ts +3 -3
  180. package/src/components/navigation-menu/CHANGELOG.md +63 -63
  181. package/src/components/navigation-menu/NavigationMenu.astro +414 -414
  182. package/src/components/navigation-menu/NavigationMenuContent.astro +37 -37
  183. package/src/components/navigation-menu/NavigationMenuIndicator.astro +24 -24
  184. package/src/components/navigation-menu/NavigationMenuItem.astro +22 -22
  185. package/src/components/navigation-menu/NavigationMenuLink.astro +18 -18
  186. package/src/components/navigation-menu/NavigationMenuList.astro +21 -21
  187. package/src/components/navigation-menu/NavigationMenuPositioner.astro +44 -44
  188. package/src/components/navigation-menu/NavigationMenuTrigger.astro +30 -30
  189. package/src/components/navigation-menu/NavigationMenuViewport.astro +19 -19
  190. package/src/components/navigation-menu/index.ts +10 -10
  191. package/src/components/organisms/lightning-sidebar-nav/CHANGELOG.md +50 -0
  192. package/src/components/organisms/lightning-sidebar-nav/LightningSidebarNav.astro +176 -0
  193. package/src/components/organisms/lightning-sidebar-nav/SidebarNav.astro +50 -0
  194. package/src/components/organisms/lightning-sidebar-nav/SidebarNavGroup.astro +74 -0
  195. package/src/components/organisms/lightning-sidebar-nav/SidebarNavItem.astro +94 -0
  196. package/src/components/organisms/lightning-sidebar-nav/SidebarNavProBadge.astro +26 -0
  197. package/src/components/organisms/lightning-sidebar-nav/SidebarNavSection.astro +71 -0
  198. package/src/components/organisms/lightning-sidebar-nav/SidebarNavSkeleton.astro +67 -0
  199. package/src/components/organisms/lightning-sidebar-nav/SidebarNavSubItem.astro +69 -0
  200. package/src/components/organisms/lightning-sidebar-nav/SidebarNavUsage.astro +78 -0
  201. package/src/components/organisms/lightning-sidebar-nav/SidebarNavWorkspaceAvatar.astro +46 -0
  202. package/src/components/organisms/lightning-sidebar-nav/SidebarNavWorkspaceSwitcher.astro +130 -0
  203. package/src/components/organisms/lightning-sidebar-nav/icons.ts +46 -0
  204. package/src/components/organisms/lightning-sidebar-nav/index.ts +18 -0
  205. package/src/components/organisms/lightning-sidebar-nav/types.ts +77 -0
  206. package/src/components/popover/CHANGELOG.md +20 -20
  207. package/src/components/popover/Popover.astro +211 -211
  208. package/src/components/popover/PopoverClose.astro +18 -18
  209. package/src/components/popover/PopoverContent.astro +50 -50
  210. package/src/components/popover/PopoverDescription.astro +18 -18
  211. package/src/components/popover/PopoverHeader.astro +18 -18
  212. package/src/components/popover/PopoverTitle.astro +18 -18
  213. package/src/components/popover/PopoverTrigger.astro +35 -35
  214. package/src/components/popover/index.ts +7 -7
  215. package/src/components/radio-group/CHANGELOG.md +31 -31
  216. package/src/components/radio-group/RadioGroup.astro +81 -81
  217. package/src/components/radio-group/RadioGroupItem.astro +51 -51
  218. package/src/components/radio-group/index.ts +3 -3
  219. package/src/components/select/CHANGELOG.md +39 -39
  220. package/src/components/select/Select.astro +373 -373
  221. package/src/components/select/SelectContent.astro +91 -91
  222. package/src/components/select/SelectGroup.astro +19 -19
  223. package/src/components/select/SelectItem.astro +48 -48
  224. package/src/components/select/SelectLabel.astro +18 -18
  225. package/src/components/select/SelectSeparator.astro +17 -17
  226. package/src/components/select/SelectTrigger.astro +34 -34
  227. package/src/components/select/SelectValue.astro +22 -22
  228. package/src/components/select/index.ts +8 -8
  229. package/src/components/separator/CHANGELOG.md +5 -5
  230. package/src/components/separator/Separator.astro +60 -60
  231. package/src/components/separator/index.ts +2 -2
  232. package/src/components/skeleton/CHANGELOG.md +5 -5
  233. package/src/components/skeleton/Skeleton.astro +121 -121
  234. package/src/components/skeleton/index.ts +1 -1
  235. package/src/components/slider/CHANGELOG.md +5 -5
  236. package/src/components/slider/Slider.astro +198 -198
  237. package/src/components/slider/index.ts +1 -1
  238. package/src/components/spinner/CHANGELOG.md +18 -18
  239. package/src/components/spinner/Spinner.astro +135 -135
  240. package/src/components/spinner/index.ts +1 -1
  241. package/src/components/sticky-surface/CHANGELOG.md +5 -5
  242. package/src/components/sticky-surface/StickySurface.astro +152 -152
  243. package/src/components/sticky-surface/index.ts +2 -2
  244. package/src/components/switch/CHANGELOG.md +29 -29
  245. package/src/components/switch/Switch.astro +106 -106
  246. package/src/components/switch/index.ts +1 -1
  247. package/src/components/table/CHANGELOG.md +24 -24
  248. package/src/components/table/Table.astro +358 -251
  249. package/src/components/table/TableBody.astro +17 -18
  250. package/src/components/table/TableBulkToolbar.astro +37 -0
  251. package/src/components/table/TableCaption.astro +17 -17
  252. package/src/components/table/TableCell.astro +45 -21
  253. package/src/components/table/TableCellText.astro +17 -0
  254. package/src/components/table/TableColumnMenu.astro +50 -0
  255. package/src/components/table/TableEditableCell.astro +287 -0
  256. package/src/components/table/TableEmpty.astro +17 -0
  257. package/src/components/table/TableFolderCell.astro +38 -0
  258. package/src/components/table/TableFooter.astro +21 -21
  259. package/src/components/table/TableHead.astro +90 -21
  260. package/src/components/table/TableHeader.astro +17 -17
  261. package/src/components/table/TablePagination.astro +57 -0
  262. package/src/components/table/TableRow.astro +52 -21
  263. package/src/components/table/TableSelectAllBanner.astro +34 -0
  264. package/src/components/table/TableSelectCell.astro +50 -0
  265. package/src/components/table/TableSkeletonRow.astro +21 -0
  266. package/src/components/table/index.ts +19 -9
  267. package/src/components/table/table-cell-variants.ts +29 -0
  268. package/src/components/tabs/CHANGELOG.md +5 -5
  269. package/src/components/tabs/Tabs.astro +306 -306
  270. package/src/components/tabs/TabsContent.astro +47 -47
  271. package/src/components/tabs/TabsList.astro +69 -69
  272. package/src/components/tabs/TabsTrigger.astro +40 -40
  273. package/src/components/tabs/index.ts +6 -6
  274. package/src/components/textarea/CHANGELOG.md +22 -22
  275. package/src/components/textarea/Textarea.astro +58 -58
  276. package/src/components/textarea/index.ts +2 -2
  277. package/src/components/toggle/CHANGELOG.md +23 -23
  278. package/src/components/toggle/Toggle.astro +150 -150
  279. package/src/components/toggle/index.ts +1 -1
  280. package/src/components/toggle-group/CHANGELOG.md +18 -18
  281. package/src/components/toggle-group/ToggleGroup.astro +236 -236
  282. package/src/components/toggle-group/ToggleGroupItem.astro +48 -48
  283. package/src/components/toggle-group/index.ts +2 -2
  284. package/src/components/tooltip/CHANGELOG.md +22 -22
  285. package/src/components/tooltip/Tooltip.astro +357 -357
  286. package/src/components/tooltip/TooltipContent.astro +85 -85
  287. package/src/components/tooltip/TooltipTrigger.astro +34 -34
  288. package/src/components/tooltip/index.ts +3 -3
  289. package/src/lib/table-controller.ts +1090 -0
  290. package/src/lib/toggle-group-controller.ts +113 -113
  291. package/src/lib/toggle-shared.ts +27 -27
  292. package/src/lib/utils.ts +6 -6
  293. package/src/styles/globals.css +209 -177
@@ -1,29 +1,44 @@
1
- # Changelog
2
-
3
- All notable changes to the `Input` component will be documented in this file.
4
-
5
- ## 2026-09-09 — Figma alignment (ClickLearn Lightning Design Library, node `145-3`)
6
-
7
- Figma documents Input across four pages: Variants (Default, Lead, Tail, Complex, Wide), Sizes (Default 32px, Large 40px), States (Default, Hover, Pressed, Focus, Disabled, Error), and Contents (Default, Lead Icon, Tail Icon, Label, Counter, Helper, Error text, All Details).
8
-
9
- ### Fixed
10
-
11
- - Updated `@figmaUrl` from the old Bejamas file to the ClickLearn Lightning Design Library link.
12
- - Background: `bg-transparent dark:bg-input/30` → `bg-card` — Figma's surface token is `card` (`#ffffff`), which genuinely differs from `--background`/transparent in dark mode, same category of fix already made to `DialogContent`/`HoverCardContent`.
13
- - Disabled: replaced the blanket `disabled:opacity-50` fade with an explicit `disabled:bg-muted disabled:text-muted-foreground`, matching Figma's actual flat muted-gray disabled treatment (same category of fix as Checkbox's disabled state).
14
- - Large size: `data-[size=lg]:md:text-base` (16px) → `data-[size=lg]:md:text-sm` (14px) — Figma's Large instance binds the identical 14px font token as Default; only padding/height grow, not font size. **Reverted in the follow-up below** — the three sizes read as visually indistinct with matching font sizes, so the user asked to keep them differentiated.
15
- - Added a Pressed (`:active`) state: `active:border-ring`, matching Figma's Pressed state (same border-color token as Focus, without Focus's outer glow).
16
- - Removed dead, redundant unconditional legacy classes (`h-9`, `rounded-md`, `px-2.5 py-1`, `text-base`, `md:text-sm`) that were fully superseded by the newer `data-[size=*]:...` gated system already present in the same class string — same class of cleanup already done on Dialog/HoverCard/TooltipContent.
17
-
18
- ### Notes (not changed)
19
-
20
- - Border color (`border-input`), radius (`rounded-lg`), Focus (`focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50`), and Error/`aria-invalid` styling already matched Figma's tokens exactly — no changes needed.
21
- - Figma's Hover state isn't implemented, per the standing project direction to skip hover states ("ignore hover states, they are not necessary... I will delete from figma").
22
- - Figma's two documented sizes — Default (32px) and Large (40px) — correspond exactly to the existing `sm` (`h-8`) and `lg` (`h-10`) tiers. The code's own literal `"default"` tier (`h-9`, 36px) isn't represented in Figma at all — flagging in case you want to rename in Figma, same as was done for Accordion/Checkbox.
23
- - Lead/Tail/Complex/Wide (icon and toolbar compositions) are already fully covered by the existing `InputGroup` family — no new props added to `Input`. Added storybook examples for all four so they're visibly demonstrated on the Input docs page.
24
- - Label/Helper/Error-text content variants are already covered by the existing `Field`/`FieldLabel`/`FieldDescription`/`FieldError` primitives (shared across the whole design system, not Input-specific) — no new props added. Added a storybook example combining `Field` + `Input` to demonstrate Helper text, a character counter, and an Error state, since none of these Figma-documented compositions had a visible Input demo before. The small icon Figma shows before Helper/Error text is left as consumer-supplied slot content rather than hardcoded, since `Field` is used well beyond Input.
25
- - Counter (e.g. "10/100") has no dedicated primitive — it's a plain flex row + a counter `<span>` next to `FieldLabel`, demonstrated in the new storybook example above.
26
-
27
- ### Fixed (follow-up)
28
-
29
- - User correction: the three sizes weren't visually distinct enough with matching font sizes (per Figma's literal token match above). Restored a differentiated type scale across the existing Tailwind tokens: `sm` → `text-xs` (12px, unchanged), `default` → `text-sm` (14px, unchanged), `lg` → `text-base` (16px, reverted from the Figma-matched 14px).
1
+ # Changelog
2
+
3
+ All notable changes to the `Input` component will be documented in this file.
4
+
5
+ ## 2026-10-06 — OTP Input (ClickLearn Lightning Design Library, node `7650-4177`)
6
+
7
+ Figma adds an "OTP Input" component set to the Input page with states Default, Focused, Filled, Disabled and Error: six joined 56×40 slots (outer corners `rounded-lg`, shared inner borders, 14px medium centered text), a label above and hint text below.
8
+
9
+ ### Added
10
+
11
+ - `InputOTP` (exported from `components/input`). Props: `length` (default 6), `name`, `value`, `size` (`sm` | `default` | `lg`; `default` is Figma's 56×40), `mode` (`numeric` | `alphanumeric`), `id` (applied to the first slot so `FieldLabel for` works), `disabled`, `required`, `autofocus`, `aria-invalid`.
12
+ - Joined value is submitted through a hidden input named by `name`.
13
+ - Inline script: auto-advance on type, Backspace to previous slot, arrow-key navigation, paste/OS autofill distributes characters across slots. Emits `input-otp:change` and `input-otp:complete` (`detail.value`).
14
+
15
+ ### Notes
16
+
17
+ - States reuse Input's tokens exactly: `border-input`, `bg-card`, `shadow-xs`; Focus `border-ring ring-3 ring-ring/50`; Error `aria-invalid:border-destructive` (no outer ring, matching Figma); Disabled `bg-muted text-muted-foreground`. Hover not implemented (standing direction).
18
+ - Label and hint are composed with `Field` / `FieldLabel` / `FieldDescription` / `FieldError`, same as Input, rather than new props.
19
+
20
+ ## 2026-09-09 — Figma alignment (ClickLearn Lightning Design Library, node `145-3`)
21
+
22
+ Figma documents Input across four pages: Variants (Default, Lead, Tail, Complex, Wide), Sizes (Default 32px, Large 40px), States (Default, Hover, Pressed, Focus, Disabled, Error), and Contents (Default, Lead Icon, Tail Icon, Label, Counter, Helper, Error text, All Details).
23
+
24
+ ### Fixed
25
+
26
+ - Updated `@figmaUrl` from the old Bejamas file to the ClickLearn Lightning Design Library link.
27
+ - Background: `bg-transparent dark:bg-input/30` → `bg-card` — Figma's surface token is `card` (`#ffffff`), which genuinely differs from `--background`/transparent in dark mode, same category of fix already made to `DialogContent`/`HoverCardContent`.
28
+ - Disabled: replaced the blanket `disabled:opacity-50` fade with an explicit `disabled:bg-muted disabled:text-muted-foreground`, matching Figma's actual flat muted-gray disabled treatment (same category of fix as Checkbox's disabled state).
29
+ - Large size: `data-[size=lg]:md:text-base` (16px) → `data-[size=lg]:md:text-sm` (14px) — Figma's Large instance binds the identical 14px font token as Default; only padding/height grow, not font size. **Reverted in the follow-up below** — the three sizes read as visually indistinct with matching font sizes, so the user asked to keep them differentiated.
30
+ - Added a Pressed (`:active`) state: `active:border-ring`, matching Figma's Pressed state (same border-color token as Focus, without Focus's outer glow).
31
+ - Removed dead, redundant unconditional legacy classes (`h-9`, `rounded-md`, `px-2.5 py-1`, `text-base`, `md:text-sm`) that were fully superseded by the newer `data-[size=*]:...` gated system already present in the same class string — same class of cleanup already done on Dialog/HoverCard/TooltipContent.
32
+
33
+ ### Notes (not changed)
34
+
35
+ - Border color (`border-input`), radius (`rounded-lg`), Focus (`focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50`), and Error/`aria-invalid` styling already matched Figma's tokens exactly — no changes needed.
36
+ - Figma's Hover state isn't implemented, per the standing project direction to skip hover states ("ignore hover states, they are not necessary... I will delete from figma").
37
+ - Figma's two documented sizes — Default (32px) and Large (40px) — correspond exactly to the existing `sm` (`h-8`) and `lg` (`h-10`) tiers. The code's own literal `"default"` tier (`h-9`, 36px) isn't represented in Figma at all — flagging in case you want to rename in Figma, same as was done for Accordion/Checkbox.
38
+ - Lead/Tail/Complex/Wide (icon and toolbar compositions) are already fully covered by the existing `InputGroup` family — no new props added to `Input`. Added storybook examples for all four so they're visibly demonstrated on the Input docs page.
39
+ - Label/Helper/Error-text content variants are already covered by the existing `Field`/`FieldLabel`/`FieldDescription`/`FieldError` primitives (shared across the whole design system, not Input-specific) — no new props added. Added a storybook example combining `Field` + `Input` to demonstrate Helper text, a character counter, and an Error state, since none of these Figma-documented compositions had a visible Input demo before. The small icon Figma shows before Helper/Error text is left as consumer-supplied slot content rather than hardcoded, since `Field` is used well beyond Input.
40
+ - Counter (e.g. "10/100") has no dedicated primitive — it's a plain flex row + a counter `<span>` next to `FieldLabel`, demonstrated in the new storybook example above.
41
+
42
+ ### Fixed (follow-up)
43
+
44
+ - User correction: the three sizes weren't visually distinct enough with matching font sizes (per Figma's literal token match above). Restored a differentiated type scale across the existing Tailwind tokens: `sm` → `text-xs` (12px, unchanged), `default` → `text-sm` (14px, unchanged), `lg` → `text-base` (16px, reverted from the Figma-matched 14px).
@@ -1,130 +1,130 @@
1
- ---
2
- /**
3
- * @component Input
4
- * @title Input
5
- * @description Base input field used in forms.
6
- * @description A field for collecting user input.
7
- * @figmaUrl https://www.figma.com/design/qXkzdqZ3QPQqgckU3AwIAH/ClickLearn-Lightning-Design-Library?node-id=145-3
8
- * @status stable
9
- * @since 0.1.0
10
- *
11
- * @preview
12
- *
13
- * <Input type="text" placeholder="Enter your name" />
14
- *
15
- * @usage
16
- *
17
- * ```astro nocollapse
18
- * ---
19
- * import { Input } from '@bejamas/ui/components/input';
20
- * ---
21
- * <Input type="email" placeholder="Enter your email" />
22
- * ```
23
- *
24
- * @examples
25
- *
26
- * ### Default
27
- *
28
- * <Input type="email" placeholder="Enter your email" />
29
- *
30
- * ### Disabled
31
- *
32
- * <Input type="email" placeholder="Enter your email" disabled />
33
- *
34
- * ### Sizes
35
- *
36
- * <div class="grid w-full max-w-sm gap-3">
37
- * <div class="flex items-center gap-2">
38
- * <Input size="sm" placeholder="Small input (h-8)" />
39
- * <Button size="sm" variant="outline">
40
- * Small
41
- * </Button>
42
- * </div>
43
- * <div class="flex items-center gap-2">
44
- * <Input placeholder="Default input (h-9)" />
45
- * <Button variant="outline">Default</Button>
46
- * </div>
47
- * <div class="flex items-center gap-2">
48
- * <Input size="lg" placeholder="Large input (h-10)" />
49
- * <Button size="lg" variant="outline">
50
- * Large
51
- * </Button>
52
- * </div>
53
- * </div>
54
- *
55
- * ### File
56
- *
57
- * <div class="grid w-full max-w-sm items-center gap-3">
58
- * <Label htmlFor="picture">Picture</Label>
59
- * <Input id="picture" type="file" />
60
- * </div>
61
- *
62
- * ### With Label
63
- *
64
- * <div class="grid w-full max-w-sm items-center gap-3">
65
- * <Label htmlFor="email">Email</Label>
66
- * <Input id="email" type="email" placeholder="Enter your email" />
67
- * </div>
68
- *
69
- * ### With Button
70
- *
71
- * <div class="flex w-full max-w-sm items-center gap-2">
72
- * <Input type="email" placeholder="Email" />
73
- * <Button type="submit" variant="outline">
74
- * Subscribe
75
- * </Button>
76
- * </div>
77
- */
78
-
79
- import { cn } from "@cl-light-ds/ui/lib/utils";
80
- import { cva, type VariantProps } from "class-variance-authority";
81
- import type { HTMLAttributes } from "astro/types";
82
-
83
- const inputVariants = cva(
84
- "w-full min-w-0 outline-none file:inline-flex file:border-0 file:bg-transparent disabled:pointer-events-none disabled:cursor-not-allowed",
85
- {
86
- variants: {
87
- size: {
88
- sm: "data-[size=sm]",
89
- default: "data-[size=default]",
90
- lg: "data-[size=lg]",
91
- },
92
- },
93
- defaultVariants: {
94
- size: "default",
95
- },
96
- },
97
- );
98
-
99
- type InputUiSize = NonNullable<VariantProps<typeof inputVariants>["size"]>;
100
- type NativeInputSize = HTMLAttributes<"input">["size"];
101
-
102
- interface Props extends Omit<HTMLAttributes<"input">, "size"> {
103
- size?: InputUiSize | NativeInputSize;
104
- nativeSize?: NativeInputSize;
105
- }
106
-
107
- const {
108
- class: className = "",
109
- type = "text",
110
- size: sizeProp,
111
- nativeSize,
112
- ...props
113
- } = Astro.props as Props;
114
-
115
- const isUiSize = (value: unknown): value is InputUiSize =>
116
- value === "sm" || value === "default" || value === "lg";
117
-
118
- const resolvedUiSize = isUiSize(sizeProp) ? sizeProp : "default";
119
- const resolvedNativeSize =
120
- nativeSize ?? (!isUiSize(sizeProp) ? sizeProp : undefined);
121
- ---
122
-
123
- <input
124
- type={type}
125
- size={resolvedNativeSize}
126
- data-slot={props["data-slot"] ?? "input"}
127
- data-size={resolvedUiSize}
128
- class={cn("border-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 active:border-ring rounded-lg border bg-card shadow-xs transition-[color,box-shadow] file:h-7 file:text-sm file:font-medium focus-visible:ring-3 aria-invalid:ring-3 disabled:bg-muted disabled:text-muted-foreground data-[size=sm]:h-8 data-[size=sm]:px-2.5 data-[size=sm]:py-1 data-[size=sm]:md:text-xs data-[size=default]:h-9 data-[size=default]:px-2.5 data-[size=default]:py-1 data-[size=default]:md:text-sm data-[size=lg]:h-10 data-[size=lg]:px-3.5 data-[size=lg]:py-1.5 data-[size=lg]:md:text-base", inputVariants({ size: resolvedUiSize }), className)}
129
- {...props}
130
- />
1
+ ---
2
+ /**
3
+ * @component Input
4
+ * @title Input
5
+ * @description Base input field used in forms.
6
+ * @description A field for collecting user input.
7
+ * @figmaUrl https://www.figma.com/design/qXkzdqZ3QPQqgckU3AwIAH/ClickLearn-Lightning-Design-Library?node-id=145-3
8
+ * @status stable
9
+ * @since 0.1.0
10
+ *
11
+ * @preview
12
+ *
13
+ * <Input type="text" placeholder="Enter your name" />
14
+ *
15
+ * @usage
16
+ *
17
+ * ```astro nocollapse
18
+ * ---
19
+ * import { Input } from '@bejamas/ui/components/input';
20
+ * ---
21
+ * <Input type="email" placeholder="Enter your email" />
22
+ * ```
23
+ *
24
+ * @examples
25
+ *
26
+ * ### Default
27
+ *
28
+ * <Input type="email" placeholder="Enter your email" />
29
+ *
30
+ * ### Disabled
31
+ *
32
+ * <Input type="email" placeholder="Enter your email" disabled />
33
+ *
34
+ * ### Sizes
35
+ *
36
+ * <div class="grid w-full max-w-sm gap-3">
37
+ * <div class="flex items-center gap-2">
38
+ * <Input size="sm" placeholder="Small input (h-8)" />
39
+ * <Button size="sm" variant="outline">
40
+ * Small
41
+ * </Button>
42
+ * </div>
43
+ * <div class="flex items-center gap-2">
44
+ * <Input placeholder="Default input (h-9)" />
45
+ * <Button variant="outline">Default</Button>
46
+ * </div>
47
+ * <div class="flex items-center gap-2">
48
+ * <Input size="lg" placeholder="Large input (h-10)" />
49
+ * <Button size="lg" variant="outline">
50
+ * Large
51
+ * </Button>
52
+ * </div>
53
+ * </div>
54
+ *
55
+ * ### File
56
+ *
57
+ * <div class="grid w-full max-w-sm items-center gap-3">
58
+ * <Label htmlFor="picture">Picture</Label>
59
+ * <Input id="picture" type="file" />
60
+ * </div>
61
+ *
62
+ * ### With Label
63
+ *
64
+ * <div class="grid w-full max-w-sm items-center gap-3">
65
+ * <Label htmlFor="email">Email</Label>
66
+ * <Input id="email" type="email" placeholder="Enter your email" />
67
+ * </div>
68
+ *
69
+ * ### With Button
70
+ *
71
+ * <div class="flex w-full max-w-sm items-center gap-2">
72
+ * <Input type="email" placeholder="Email" />
73
+ * <Button type="submit" variant="outline">
74
+ * Subscribe
75
+ * </Button>
76
+ * </div>
77
+ */
78
+
79
+ import { cn } from "@cl-light-ds/ui/lib/utils";
80
+ import { cva, type VariantProps } from "class-variance-authority";
81
+ import type { HTMLAttributes } from "astro/types";
82
+
83
+ const inputVariants = cva(
84
+ "w-full min-w-0 outline-none file:inline-flex file:border-0 file:bg-transparent disabled:pointer-events-none disabled:cursor-not-allowed",
85
+ {
86
+ variants: {
87
+ size: {
88
+ sm: "data-[size=sm]",
89
+ default: "data-[size=default]",
90
+ lg: "data-[size=lg]",
91
+ },
92
+ },
93
+ defaultVariants: {
94
+ size: "default",
95
+ },
96
+ },
97
+ );
98
+
99
+ type InputUiSize = NonNullable<VariantProps<typeof inputVariants>["size"]>;
100
+ type NativeInputSize = HTMLAttributes<"input">["size"];
101
+
102
+ interface Props extends Omit<HTMLAttributes<"input">, "size"> {
103
+ size?: InputUiSize | NativeInputSize;
104
+ nativeSize?: NativeInputSize;
105
+ }
106
+
107
+ const {
108
+ class: className = "",
109
+ type = "text",
110
+ size: sizeProp,
111
+ nativeSize,
112
+ ...props
113
+ } = Astro.props as Props;
114
+
115
+ const isUiSize = (value: unknown): value is InputUiSize =>
116
+ value === "sm" || value === "default" || value === "lg";
117
+
118
+ const resolvedUiSize = isUiSize(sizeProp) ? sizeProp : "default";
119
+ const resolvedNativeSize =
120
+ nativeSize ?? (!isUiSize(sizeProp) ? sizeProp : undefined);
121
+ ---
122
+
123
+ <input
124
+ type={type}
125
+ size={resolvedNativeSize}
126
+ data-slot={props["data-slot"] ?? "input"}
127
+ data-size={resolvedUiSize}
128
+ class={cn("border-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 active:border-ring rounded-lg border bg-card shadow-xs transition-[color,box-shadow] file:h-7 file:text-sm file:font-medium focus-visible:ring-3 aria-invalid:ring-3 disabled:bg-muted disabled:text-muted-foreground data-[size=sm]:h-8 data-[size=sm]:px-2.5 data-[size=sm]:py-1 data-[size=sm]:md:text-xs data-[size=default]:h-9 data-[size=default]:px-2.5 data-[size=default]:py-1 data-[size=default]:md:text-sm data-[size=lg]:h-10 data-[size=lg]:px-3.5 data-[size=lg]:py-1.5 data-[size=lg]:md:text-base", inputVariants({ size: resolvedUiSize }), className)}
129
+ {...props}
130
+ />
@@ -0,0 +1,211 @@
1
+ ---
2
+ /**
3
+ * @component InputOTP
4
+ * @title OTP Input
5
+ * @description A row of single-character slots for entering one-time codes, with auto-advance, backspace and paste support.
6
+ * @figmaUrl https://www.figma.com/design/qXkzdqZ3QPQqgckU3AwIAH/ClickLearn-Lightning-Design-Library?node-id=7650-4177
7
+ * @status stable
8
+ * @since 0.4.0
9
+ *
10
+ * @preview
11
+ *
12
+ * <Field class="w-fit">
13
+ * <FieldLabel for="otp">Verification code</FieldLabel>
14
+ * <InputOTP id="otp" name="code" />
15
+ * <FieldDescription>Enter the 6-digit code we sent to your email.</FieldDescription>
16
+ * </Field>
17
+ *
18
+ * @usage
19
+ *
20
+ * ```astro nocollapse
21
+ * ---
22
+ * import { InputOTP } from '@cl-light-ds/ui/components/input';
23
+ * ---
24
+ * <InputOTP id="otp" name="code" length={6} />
25
+ * ```
26
+ *
27
+ * @api
28
+ *
29
+ * ### Events
30
+ *
31
+ * | Event | Detail | Description |
32
+ * |-------|--------|-------------|
33
+ * | `input-otp:change` | `{ value: string }` | Fired whenever the code changes |
34
+ * | `input-otp:complete` | `{ value: string }` | Fired when every slot is filled |
35
+ */
36
+
37
+ import { cn } from "@cl-light-ds/ui/lib/utils";
38
+ import type { HTMLAttributes } from "astro/types";
39
+
40
+ type InputOTPSize = "sm" | "default" | "lg";
41
+ type InputOTPMode = "numeric" | "alphanumeric";
42
+
43
+ interface Props extends Omit<HTMLAttributes<"div">, "id"> {
44
+ /** Number of slots. */
45
+ length?: number;
46
+ /** Name of the hidden input that carries the joined code on form submit. */
47
+ name?: string;
48
+ /** Initial value; characters fill slots from the left. */
49
+ value?: string;
50
+ size?: InputOTPSize;
51
+ /** `numeric` accepts digits only; `alphanumeric` accepts letters and digits. */
52
+ mode?: InputOTPMode;
53
+ /** Applied to the first slot so a `<label for>` / `FieldLabel` focuses it. */
54
+ id?: string;
55
+ disabled?: boolean;
56
+ required?: boolean;
57
+ autofocus?: boolean;
58
+ "aria-invalid"?: boolean | "true" | "false";
59
+ class?: string;
60
+ }
61
+
62
+ const {
63
+ class: className = "",
64
+ length = 6,
65
+ name,
66
+ value = "",
67
+ size = "default",
68
+ mode = "numeric",
69
+ id,
70
+ disabled = false,
71
+ required = false,
72
+ autofocus = false,
73
+ "aria-invalid": ariaInvalid,
74
+ ...rest
75
+ } = Astro.props as Props;
76
+
77
+ const allowed = mode === "alphanumeric" ? /[a-z0-9]/i : /\d/;
78
+ const chars = [...value].filter((char) => allowed.test(char)).slice(0, length);
79
+ const slots = Array.from({ length }, (_, index) => chars[index] ?? "");
80
+ const invalid = ariaInvalid === true || ariaInvalid === "true";
81
+ ---
82
+
83
+ <div
84
+ {...rest}
85
+ role="group"
86
+ data-slot="input-otp"
87
+ data-size={size}
88
+ data-mode={mode}
89
+ data-length={length}
90
+ data-disabled={disabled ? "" : undefined}
91
+ data-invalid={invalid ? "" : undefined}
92
+ class={cn("flex w-fit items-center", className)}
93
+ >
94
+ {
95
+ slots.map((char, index) => (
96
+ <input
97
+ type="text"
98
+ id={index === 0 ? id : undefined}
99
+ data-slot="input-otp-slot"
100
+ data-size={size}
101
+ value={char}
102
+ inputmode={mode === "numeric" ? "numeric" : "text"}
103
+ autocomplete={index === 0 ? "one-time-code" : "off"}
104
+ autocapitalize="off"
105
+ spellcheck="false"
106
+ aria-label={`Character ${index + 1} of ${length}`}
107
+ aria-invalid={invalid ? "true" : undefined}
108
+ disabled={disabled}
109
+ autofocus={index === 0 && autofocus}
110
+ class={cn(
111
+ "relative -ml-px min-w-0 border border-input bg-card text-center font-medium text-foreground shadow-xs outline-none transition-[color,box-shadow] first:ml-0 first:rounded-l-lg last:rounded-r-lg",
112
+ "focus-visible:z-10 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:border-ring",
113
+ "aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 aria-invalid:focus-visible:ring-destructive/20",
114
+ "disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-muted disabled:text-muted-foreground",
115
+ "data-[size=sm]:h-8 data-[size=sm]:w-10 data-[size=sm]:text-xs",
116
+ "data-[size=default]:h-10 data-[size=default]:w-14 data-[size=default]:text-sm",
117
+ "data-[size=lg]:h-12 data-[size=lg]:w-16 data-[size=lg]:text-base",
118
+ )}
119
+ />
120
+ ))
121
+ }
122
+ <input
123
+ type="hidden"
124
+ data-slot="input-otp-value"
125
+ name={name}
126
+ value={chars.join("")}
127
+ required={required}
128
+ disabled={disabled}
129
+ />
130
+ </div>
131
+
132
+ <script>
133
+ function initInputOTP(root: HTMLElement) {
134
+ if (root.dataset.initialized !== undefined) return;
135
+ root.dataset.initialized = "";
136
+
137
+ const slots = Array.from(root.querySelectorAll<HTMLInputElement>('[data-slot="input-otp-slot"]'));
138
+ const hidden = root.querySelector<HTMLInputElement>('[data-slot="input-otp-value"]');
139
+ const allowed = root.dataset.mode === "alphanumeric" ? /[a-z0-9]/i : /\d/;
140
+ const accept = (text: string) => [...text].filter((char) => allowed.test(char));
141
+
142
+ function sync() {
143
+ const value = slots.map((slot) => slot.value).join("");
144
+ if (hidden) hidden.value = value;
145
+ root.dispatchEvent(new CustomEvent("input-otp:change", { bubbles: true, detail: { value } }));
146
+ if (slots.every((slot) => slot.value)) {
147
+ root.dispatchEvent(new CustomEvent("input-otp:complete", { bubbles: true, detail: { value } }));
148
+ }
149
+ }
150
+
151
+ // Writes characters into consecutive slots starting at `start`, then focuses the next empty one.
152
+ function fill(start: number, chars: string[]) {
153
+ let index = start;
154
+ for (const char of chars) {
155
+ const slot = slots[index];
156
+ if (!slot) break;
157
+ slot.value = char;
158
+ index++;
159
+ }
160
+ slots[Math.min(index, slots.length - 1)]?.focus();
161
+ sync();
162
+ }
163
+
164
+ slots.forEach((slot, index) => {
165
+ slot.addEventListener("focus", () => slot.select());
166
+
167
+ let previousValue = slot.value;
168
+ slot.addEventListener("beforeinput", () => (previousValue = slot.value));
169
+
170
+ slot.addEventListener("input", (event) => {
171
+ const { data: typed, inputType } = event as InputEvent;
172
+ // Single keystroke: use only the typed character, so typing into a filled slot replaces it.
173
+ // Anything else (OS autofill, IME) carries the whole string in the value.
174
+ const chars = accept(typed && typed.length === 1 ? typed : slot.value);
175
+ if (chars.length) {
176
+ slot.value = "";
177
+ fill(index, chars);
178
+ } else {
179
+ // Rejected characters leave the slot as it was; deletions clear it.
180
+ slot.value = inputType.startsWith("insert") ? previousValue : "";
181
+ sync();
182
+ }
183
+ });
184
+
185
+ slot.addEventListener("paste", (event) => {
186
+ event.preventDefault();
187
+ const chars = accept(event.clipboardData?.getData("text") ?? "");
188
+ if (chars.length) fill(index, chars);
189
+ });
190
+
191
+ slot.addEventListener("keydown", (event) => {
192
+ const previous = slots[index - 1];
193
+ const next = slots[index + 1];
194
+ if (event.key === "Backspace" && !slot.value && previous) {
195
+ event.preventDefault();
196
+ previous.value = "";
197
+ previous.focus();
198
+ sync();
199
+ } else if (event.key === "ArrowLeft" && previous) {
200
+ event.preventDefault();
201
+ previous.focus();
202
+ } else if (event.key === "ArrowRight" && next) {
203
+ event.preventDefault();
204
+ next.focus();
205
+ }
206
+ });
207
+ });
208
+ }
209
+
210
+ document.querySelectorAll<HTMLElement>('[data-slot="input-otp"]').forEach(initInputOTP);
211
+ </script>
@@ -1,2 +1,2 @@
1
- export { default as Input } from "./Input.astro";
2
-
1
+ export { default as Input } from "./Input.astro";
2
+ export { default as InputOTP } from "./InputOTP.astro";