@chassis-ui/react 0.0.0-20260831090525

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 (275) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +65 -0
  3. package/dist/index.d.ts +5909 -0
  4. package/dist/index.js +2 -0
  5. package/dist/style.css +1 -0
  6. package/package.json +114 -0
  7. package/src/components/accordion/Accordion.tsx +190 -0
  8. package/src/components/accordion/AccordionBody.tsx +46 -0
  9. package/src/components/accordion/AccordionHeader.tsx +21 -0
  10. package/src/components/accordion/AccordionItem.tsx +59 -0
  11. package/src/components/accordion/context.ts +8 -0
  12. package/src/components/accordion/index.ts +8 -0
  13. package/src/components/autocomplete/Autocomplete.tsx +464 -0
  14. package/src/components/autocomplete/AutocompleteGroup.tsx +20 -0
  15. package/src/components/autocomplete/AutocompleteItem.tsx +18 -0
  16. package/src/components/autocomplete/index.ts +6 -0
  17. package/src/components/avatar/Avatar.tsx +134 -0
  18. package/src/components/avatar/AvatarImage.tsx +19 -0
  19. package/src/components/avatar/AvatarStack.tsx +98 -0
  20. package/src/components/avatar/index.ts +6 -0
  21. package/src/components/badge/Badge.tsx +94 -0
  22. package/src/components/badge/index.ts +2 -0
  23. package/src/components/breadcrumb/Breadcrumb.tsx +59 -0
  24. package/src/components/breadcrumb/BreadcrumbItem.tsx +38 -0
  25. package/src/components/breadcrumb/index.ts +4 -0
  26. package/src/components/button/Button.tsx +229 -0
  27. package/src/components/button/index.ts +2 -0
  28. package/src/components/button-group/ButtonGroup.tsx +55 -0
  29. package/src/components/button-group/ButtonToolbar.tsx +47 -0
  30. package/src/components/button-group/index.ts +4 -0
  31. package/src/components/calendar/Calendar.scss +57 -0
  32. package/src/components/calendar/Calendar.tsx +324 -0
  33. package/src/components/calendar/CalendarMonthBlock.tsx +57 -0
  34. package/src/components/calendar/CalendarMonthGrid.tsx +92 -0
  35. package/src/components/calendar/CalendarMonthYearPicker.tsx +162 -0
  36. package/src/components/calendar/CalendarNavButton.tsx +24 -0
  37. package/src/components/calendar/CalendarWeekGrid.tsx +58 -0
  38. package/src/components/calendar/CalendarYearGrid.tsx +126 -0
  39. package/src/components/calendar/RangeCalendar.scss +95 -0
  40. package/src/components/calendar/RangeCalendar.tsx +361 -0
  41. package/src/components/calendar/index.ts +5 -0
  42. package/src/components/card/Card.tsx +173 -0
  43. package/src/components/card/CardBody.tsx +75 -0
  44. package/src/components/card/CardFooter.tsx +47 -0
  45. package/src/components/card/CardGroup.tsx +51 -0
  46. package/src/components/card/CardHeader.tsx +47 -0
  47. package/src/components/card/CardImage.tsx +70 -0
  48. package/src/components/card/CardImageOverlay.tsx +47 -0
  49. package/src/components/card/CardLink.tsx +40 -0
  50. package/src/components/card/CardSubtitle.tsx +47 -0
  51. package/src/components/card/CardText.tsx +47 -0
  52. package/src/components/card/CardTitle.tsx +47 -0
  53. package/src/components/card/index.ts +22 -0
  54. package/src/components/carousel/Carousel.tsx +742 -0
  55. package/src/components/carousel/CarouselControlButton.tsx +74 -0
  56. package/src/components/carousel/CarouselControlNext.tsx +22 -0
  57. package/src/components/carousel/CarouselControlPrev.tsx +22 -0
  58. package/src/components/carousel/CarouselIndicators.tsx +44 -0
  59. package/src/components/carousel/CarouselInner.tsx +56 -0
  60. package/src/components/carousel/CarouselItem.tsx +51 -0
  61. package/src/components/carousel/CarouselOverlay.tsx +51 -0
  62. package/src/components/carousel/CarouselPlayPause.tsx +61 -0
  63. package/src/components/carousel/carouselEngine.ts +170 -0
  64. package/src/components/carousel/context.ts +29 -0
  65. package/src/components/carousel/index.ts +21 -0
  66. package/src/components/checkbox/Checkbox.tsx +236 -0
  67. package/src/components/checkbox/CheckboxGroup.tsx +145 -0
  68. package/src/components/checkbox/context.ts +14 -0
  69. package/src/components/checkbox/index.ts +4 -0
  70. package/src/components/chip/Chip.tsx +183 -0
  71. package/src/components/chip/index.ts +2 -0
  72. package/src/components/chip-input/ChipInput.tsx +363 -0
  73. package/src/components/chip-input/ChipList.tsx +95 -0
  74. package/src/components/chip-input/index.ts +2 -0
  75. package/src/components/close-button/CloseButton.tsx +205 -0
  76. package/src/components/close-button/index.ts +2 -0
  77. package/src/components/collapse/Collapse.tsx +128 -0
  78. package/src/components/collapse/index.ts +2 -0
  79. package/src/components/color-input/ColorInput.tsx +106 -0
  80. package/src/components/color-input/index.ts +2 -0
  81. package/src/components/combobox/Combobox.tsx +320 -0
  82. package/src/components/combobox/ComboboxGroup.tsx +27 -0
  83. package/src/components/combobox/ComboboxItem.tsx +44 -0
  84. package/src/components/combobox/ComboboxListBox.tsx +98 -0
  85. package/src/components/combobox/index.ts +6 -0
  86. package/src/components/datepicker/CalendarToggleButton.tsx +58 -0
  87. package/src/components/datepicker/ClearButton.tsx +35 -0
  88. package/src/components/datepicker/DateField.tsx +54 -0
  89. package/src/components/datepicker/DatePicker.scss +51 -0
  90. package/src/components/datepicker/DatePicker.tsx +574 -0
  91. package/src/components/datepicker/DateRangePicker.scss +11 -0
  92. package/src/components/datepicker/DateRangePicker.tsx +343 -0
  93. package/src/components/datepicker/index.ts +4 -0
  94. package/src/components/datepicker/renderDatePickerShell.tsx +104 -0
  95. package/src/components/drawer/Drawer.tsx +211 -0
  96. package/src/components/drawer/DrawerBody.tsx +47 -0
  97. package/src/components/drawer/DrawerFooter.tsx +51 -0
  98. package/src/components/drawer/DrawerHeader.tsx +60 -0
  99. package/src/components/drawer/DrawerTitle.tsx +49 -0
  100. package/src/components/drawer/index.ts +10 -0
  101. package/src/components/file-input/FileInput.tsx +100 -0
  102. package/src/components/file-input/index.ts +2 -0
  103. package/src/components/flex/Flex.tsx +134 -0
  104. package/src/components/flex/index.ts +2 -0
  105. package/src/components/floating-input/FloatingInput.tsx +94 -0
  106. package/src/components/floating-input/index.ts +2 -0
  107. package/src/components/form/Form.tsx +26 -0
  108. package/src/components/form/FormFeedback.tsx +64 -0
  109. package/src/components/form/FormHelp.tsx +46 -0
  110. package/src/components/form/FormLabel.tsx +26 -0
  111. package/src/components/form/index.ts +8 -0
  112. package/src/components/form/renderFormCheck.tsx +86 -0
  113. package/src/components/form-field/FormField.tsx +84 -0
  114. package/src/components/form-field/index.ts +2 -0
  115. package/src/components/form-field/renderFormField.tsx +74 -0
  116. package/src/components/grid/Col.tsx +69 -0
  117. package/src/components/grid/Container.tsx +59 -0
  118. package/src/components/grid/Grid.tsx +86 -0
  119. package/src/components/grid/GridItem.tsx +123 -0
  120. package/src/components/grid/Row.tsx +71 -0
  121. package/src/components/grid/gap.ts +8 -0
  122. package/src/components/grid/index.ts +10 -0
  123. package/src/components/icon/Icon.tsx +74 -0
  124. package/src/components/icon/index.ts +2 -0
  125. package/src/components/input-adorn/InputAdorn.tsx +55 -0
  126. package/src/components/input-adorn/index.ts +2 -0
  127. package/src/components/input-group/InputGroup.tsx +50 -0
  128. package/src/components/input-group/InputGroupAddon.tsx +50 -0
  129. package/src/components/input-group/index.ts +4 -0
  130. package/src/components/link/Link.tsx +148 -0
  131. package/src/components/link/index.ts +2 -0
  132. package/src/components/list/List.tsx +193 -0
  133. package/src/components/list/ListItem.tsx +91 -0
  134. package/src/components/list/index.ts +4 -0
  135. package/src/components/menu/Menu.tsx +398 -0
  136. package/src/components/menu/MenuDivider.tsx +19 -0
  137. package/src/components/menu/MenuHeader.tsx +55 -0
  138. package/src/components/menu/MenuItem.tsx +85 -0
  139. package/src/components/menu/MenuItemDef.ts +83 -0
  140. package/src/components/menu/MenuList.tsx +142 -0
  141. package/src/components/menu/MenuSubmenu.tsx +284 -0
  142. package/src/components/menu/MenuSubmenuBack.tsx +39 -0
  143. package/src/components/menu/MenuText.tsx +47 -0
  144. package/src/components/menu/MenuToggle.tsx +148 -0
  145. package/src/components/menu/index.ts +19 -0
  146. package/src/components/menu/menuNavigation.ts +106 -0
  147. package/src/components/menu/submenuGroup.ts +43 -0
  148. package/src/components/modal/Modal.tsx +162 -0
  149. package/src/components/modal/ModalBody.tsx +47 -0
  150. package/src/components/modal/ModalFooter.tsx +51 -0
  151. package/src/components/modal/ModalHeader.tsx +60 -0
  152. package/src/components/modal/ModalTitle.tsx +49 -0
  153. package/src/components/modal/index.ts +10 -0
  154. package/src/components/nav/Nav.tsx +97 -0
  155. package/src/components/nav/NavItem.tsx +42 -0
  156. package/src/components/nav/NavLink.tsx +48 -0
  157. package/src/components/nav/NavTitle.tsx +22 -0
  158. package/src/components/nav/index.ts +7 -0
  159. package/src/components/navbar/Navbar.tsx +112 -0
  160. package/src/components/navbar/NavbarBrand.tsx +55 -0
  161. package/src/components/navbar/NavbarNav.tsx +47 -0
  162. package/src/components/navbar/NavbarText.tsx +47 -0
  163. package/src/components/navbar/NavbarToggler.tsx +34 -0
  164. package/src/components/navbar/index.ts +10 -0
  165. package/src/components/notification/Notification.scss +15 -0
  166. package/src/components/notification/Notification.tsx +187 -0
  167. package/src/components/notification/NotificationIcon.tsx +21 -0
  168. package/src/components/notification/NotificationStack.tsx +66 -0
  169. package/src/components/notification/NotificationText.tsx +47 -0
  170. package/src/components/notification/NotificationTitle.tsx +47 -0
  171. package/src/components/notification/context.ts +14 -0
  172. package/src/components/notification/index.ts +17 -0
  173. package/src/components/notification/notificationQueue.ts +48 -0
  174. package/src/components/otp-input/OtpBox.tsx +68 -0
  175. package/src/components/otp-input/OtpInput.tsx +341 -0
  176. package/src/components/otp-input/index.ts +2 -0
  177. package/src/components/pagination/Pagination.tsx +199 -0
  178. package/src/components/pagination/PaginationItem.tsx +133 -0
  179. package/src/components/pagination/index.ts +4 -0
  180. package/src/components/password-strength/PasswordStrength.tsx +155 -0
  181. package/src/components/password-strength/index.ts +2 -0
  182. package/src/components/password-strength/strengthScore.ts +79 -0
  183. package/src/components/placeholder/Placeholder.tsx +178 -0
  184. package/src/components/placeholder/index.ts +2 -0
  185. package/src/components/popover/Popover.tsx +243 -0
  186. package/src/components/popover/index.ts +2 -0
  187. package/src/components/progress/Progress.tsx +154 -0
  188. package/src/components/progress/ProgressBar.tsx +88 -0
  189. package/src/components/progress/index.ts +4 -0
  190. package/src/components/radio/Radio.tsx +88 -0
  191. package/src/components/radio/RadioGroup.tsx +142 -0
  192. package/src/components/radio/context.ts +14 -0
  193. package/src/components/radio/index.ts +4 -0
  194. package/src/components/range-input/RangeInput.tsx +109 -0
  195. package/src/components/range-input/index.ts +2 -0
  196. package/src/components/select/Select.tsx +277 -0
  197. package/src/components/select/index.ts +2 -0
  198. package/src/components/skeleton/Skeleton.tsx +89 -0
  199. package/src/components/skeleton/SkeletonLoader.tsx +91 -0
  200. package/src/components/skeleton/index.ts +4 -0
  201. package/src/components/spinner/Spinner.tsx +77 -0
  202. package/src/components/spinner/index.ts +2 -0
  203. package/src/components/stack/Stack.tsx +81 -0
  204. package/src/components/stack/index.ts +2 -0
  205. package/src/components/stepper/Stepper.tsx +172 -0
  206. package/src/components/stepper/StepperItem.tsx +66 -0
  207. package/src/components/stepper/index.ts +4 -0
  208. package/src/components/switch/Switch.tsx +246 -0
  209. package/src/components/switch/index.ts +2 -0
  210. package/src/components/table/Table.css +39 -0
  211. package/src/components/table/Table.tsx +390 -0
  212. package/src/components/table/TableBody.tsx +25 -0
  213. package/src/components/table/TableCell.tsx +27 -0
  214. package/src/components/table/TableColumn.tsx +31 -0
  215. package/src/components/table/TableHeader.tsx +26 -0
  216. package/src/components/table/TableRow.tsx +24 -0
  217. package/src/components/table/index.ts +12 -0
  218. package/src/components/tabs/Tab.tsx +36 -0
  219. package/src/components/tabs/TabList.tsx +76 -0
  220. package/src/components/tabs/TabPanel.tsx +68 -0
  221. package/src/components/tabs/Tabs.tsx +136 -0
  222. package/src/components/tabs/context.ts +24 -0
  223. package/src/components/tabs/index.ts +8 -0
  224. package/src/components/text-input/TextInput.tsx +188 -0
  225. package/src/components/text-input/index.ts +2 -0
  226. package/src/components/textarea/Textarea.tsx +145 -0
  227. package/src/components/textarea/index.ts +2 -0
  228. package/src/components/toast/Toast.tsx +219 -0
  229. package/src/components/toast/ToastBody.tsx +64 -0
  230. package/src/components/toast/ToastFooter.tsx +47 -0
  231. package/src/components/toast/ToastHeader.tsx +104 -0
  232. package/src/components/toast/ToastIcon.tsx +21 -0
  233. package/src/components/toast/Toaster.tsx +87 -0
  234. package/src/components/toast/context.ts +14 -0
  235. package/src/components/toast/index.ts +18 -0
  236. package/src/components/toast/toastQueue.ts +56 -0
  237. package/src/components/tooltip/Tooltip.tsx +155 -0
  238. package/src/components/tooltip/index.ts +2 -0
  239. package/src/global.d.ts +2 -0
  240. package/src/hooks/index.ts +57 -0
  241. package/src/hooks/useAutoDismiss.ts +88 -0
  242. package/src/hooks/useButtonSemantics.ts +33 -0
  243. package/src/hooks/useControllableState.ts +24 -0
  244. package/src/hooks/useDialogElement.ts +216 -0
  245. package/src/hooks/useDisabledAnchorGuard.ts +22 -0
  246. package/src/hooks/useDismissibleTransition.ts +126 -0
  247. package/src/hooks/useDrawer.ts +9 -0
  248. package/src/hooks/useFloatingOverlay.ts +115 -0
  249. package/src/hooks/useForkedRef.ts +50 -0
  250. package/src/hooks/useFormField.ts +89 -0
  251. package/src/hooks/useIsomorphicLayoutEffect.ts +9 -0
  252. package/src/hooks/useModal.ts +9 -0
  253. package/src/hooks/useNotification.ts +10 -0
  254. package/src/hooks/useOverlayPlacement.ts +93 -0
  255. package/src/hooks/usePagination.ts +85 -0
  256. package/src/hooks/useToast.ts +9 -0
  257. package/src/hooks/useToastRegionQueue.ts +27 -0
  258. package/src/index.ts +276 -0
  259. package/src/types.ts +133 -0
  260. package/src/utils/breakpoints.ts +43 -0
  261. package/src/utils/comboboxCollection.tsx +152 -0
  262. package/src/utils/dateRangePresets.ts +6 -0
  263. package/src/utils/dialogTransition.ts +39 -0
  264. package/src/utils/focusRedirect.ts +29 -0
  265. package/src/utils/isWholeUnitDisabled.ts +17 -0
  266. package/src/utils/mergeIsDateUnavailable.ts +15 -0
  267. package/src/utils/overlayPlacement.ts +93 -0
  268. package/src/utils/pointerInteraction.ts +21 -0
  269. package/src/utils/polymorphic.ts +36 -0
  270. package/src/utils/renderMenuItemContent.tsx +62 -0
  271. package/src/utils/setVisibleRangeStart.ts +64 -0
  272. package/src/utils/spacingClassName.ts +14 -0
  273. package/src/utils/suppressFocusRingGlobally.ts +69 -0
  274. package/src/utils/validationClassName.ts +8 -0
  275. package/src/utils/virtualFocusStyle.ts +16 -0
@@ -0,0 +1,51 @@
1
+ import React, { ElementType, ForwardRefRenderFunction, ReactElement } from 'react'
2
+ import classNames from 'classnames'
3
+
4
+ import {
5
+ createPolymorphicComponent,
6
+ PolymorphicComponentProps,
7
+ PolymorphicRef
8
+ } from '../../utils/polymorphic'
9
+
10
+ type DrawerFooterOwnProps<C extends ElementType> = {
11
+ /**
12
+ * A string of all className you want applied to the base component.
13
+ */
14
+ className?: string
15
+ /**
16
+ * Component used for the root node. Either a string to use a HTML element or a component.
17
+ */
18
+ component?: C
19
+ /**
20
+ * Stack the footer actions as full-width columns instead of a right-aligned row.
21
+ */
22
+ stacked?: boolean
23
+ }
24
+
25
+ export type DrawerFooterProps<C extends ElementType = 'div'> = PolymorphicComponentProps<
26
+ C,
27
+ DrawerFooterOwnProps<C>
28
+ >
29
+
30
+ type DrawerFooterComponent = (<C extends ElementType = 'div'>(
31
+ props: DrawerFooterProps<C> & { ref?: PolymorphicRef<C> }
32
+ ) => ReactElement | null) & { displayName?: string }
33
+
34
+ function DrawerFooterRender<C extends ElementType = 'div'>(
35
+ { children, className, component, stacked, ...rest }: DrawerFooterProps<C>,
36
+ ref: PolymorphicRef<C>
37
+ ) {
38
+ const Component = component ?? 'div'
39
+ const _className = classNames('drawer-footer', { stacked }, className)
40
+
41
+ return (
42
+ <Component className={_className} {...rest} ref={ref}>
43
+ {children}
44
+ </Component>
45
+ )
46
+ }
47
+
48
+ export const DrawerFooter = createPolymorphicComponent<DrawerFooterComponent>(
49
+ DrawerFooterRender as ForwardRefRenderFunction<Element, DrawerFooterProps<ElementType>>,
50
+ 'DrawerFooter'
51
+ )
@@ -0,0 +1,60 @@
1
+ import React, { ElementType, ForwardRefRenderFunction, ReactElement } from 'react'
2
+ import classNames from 'classnames'
3
+
4
+ import { useDrawer } from '../../hooks'
5
+ import {
6
+ createPolymorphicComponent,
7
+ PolymorphicComponentProps,
8
+ PolymorphicRef
9
+ } from '../../utils/polymorphic'
10
+ import { CloseButton } from '../close-button/CloseButton'
11
+
12
+ type DrawerHeaderOwnProps<C extends ElementType> = {
13
+ /**
14
+ * A string of all className you want applied to the base component.
15
+ */
16
+ className?: string
17
+ /**
18
+ * Add a close button component to the header.
19
+ */
20
+ closeButton?: boolean
21
+ /**
22
+ * Overrides the close button's accessible name (defaults to `'Close'`). Set this for
23
+ * non-English UIs.
24
+ */
25
+ closeLabel?: string
26
+ /**
27
+ * Component used for the root node. Either a string to use a HTML element or a component.
28
+ */
29
+ component?: C
30
+ }
31
+
32
+ export type DrawerHeaderProps<C extends ElementType = 'div'> = PolymorphicComponentProps<
33
+ C,
34
+ DrawerHeaderOwnProps<C>
35
+ >
36
+
37
+ type DrawerHeaderComponent = (<C extends ElementType = 'div'>(
38
+ props: DrawerHeaderProps<C> & { ref?: PolymorphicRef<C> }
39
+ ) => ReactElement | null) & { displayName?: string }
40
+
41
+ function DrawerHeaderRender<C extends ElementType = 'div'>(
42
+ { children, className, closeButton = true, closeLabel, component, ...rest }: DrawerHeaderProps<C>,
43
+ ref: PolymorphicRef<C>
44
+ ) {
45
+ const Component = component ?? 'div'
46
+ const { close } = useDrawer()
47
+ const _className = classNames('drawer-header', className)
48
+
49
+ return (
50
+ <Component className={_className} {...rest} ref={ref}>
51
+ {children}
52
+ {closeButton && <CloseButton label={closeLabel} onClick={close} />}
53
+ </Component>
54
+ )
55
+ }
56
+
57
+ export const DrawerHeader = createPolymorphicComponent<DrawerHeaderComponent>(
58
+ DrawerHeaderRender as ForwardRefRenderFunction<Element, DrawerHeaderProps<ElementType>>,
59
+ 'DrawerHeader'
60
+ )
@@ -0,0 +1,49 @@
1
+ import React, { ElementType, ForwardRefRenderFunction, ReactElement } from 'react'
2
+ import classNames from 'classnames'
3
+
4
+ import { useDrawer } from '../../hooks'
5
+ import {
6
+ createPolymorphicComponent,
7
+ PolymorphicComponentProps,
8
+ PolymorphicRef
9
+ } from '../../utils/polymorphic'
10
+
11
+ type DrawerTitleOwnProps<C extends ElementType> = {
12
+ /**
13
+ * A string of all className you want applied to the base component.
14
+ */
15
+ className?: string
16
+ /**
17
+ * Component used for the root node. Either a string to use a HTML element or a component.
18
+ */
19
+ component?: C
20
+ }
21
+
22
+ export type DrawerTitleProps<C extends ElementType = 'h2'> = PolymorphicComponentProps<
23
+ C,
24
+ DrawerTitleOwnProps<C>
25
+ >
26
+
27
+ type DrawerTitleComponent = (<C extends ElementType = 'h2'>(
28
+ props: DrawerTitleProps<C> & { ref?: PolymorphicRef<C> }
29
+ ) => ReactElement | null) & { displayName?: string }
30
+
31
+ function DrawerTitleRender<C extends ElementType = 'h2'>(
32
+ { children, component, className, id, ...rest }: DrawerTitleProps<C>,
33
+ ref: PolymorphicRef<C>
34
+ ) {
35
+ const { titleId } = useDrawer()
36
+ const Component = component ?? 'h2'
37
+ const _className = classNames('drawer-title', className)
38
+
39
+ return (
40
+ <Component className={_className} id={id ?? titleId} {...rest} ref={ref}>
41
+ {children}
42
+ </Component>
43
+ )
44
+ }
45
+
46
+ export const DrawerTitle = createPolymorphicComponent<DrawerTitleComponent>(
47
+ DrawerTitleRender as ForwardRefRenderFunction<Element, DrawerTitleProps<ElementType>>,
48
+ 'DrawerTitle'
49
+ )
@@ -0,0 +1,10 @@
1
+ export { Drawer } from './Drawer'
2
+ export type { DrawerProps } from './Drawer'
3
+ export { DrawerBody } from './DrawerBody'
4
+ export type { DrawerBodyProps } from './DrawerBody'
5
+ export { DrawerFooter } from './DrawerFooter'
6
+ export type { DrawerFooterProps } from './DrawerFooter'
7
+ export { DrawerHeader } from './DrawerHeader'
8
+ export type { DrawerHeaderProps } from './DrawerHeader'
9
+ export { DrawerTitle } from './DrawerTitle'
10
+ export type { DrawerTitleProps } from './DrawerTitle'
@@ -0,0 +1,100 @@
1
+ import React, { ChangeEventHandler, forwardRef, InputHTMLAttributes, ReactNode } from 'react'
2
+ import classNames from 'classnames'
3
+
4
+ import { useFormField } from '../../hooks'
5
+ import { validationClassName } from '../../utils/validationClassName'
6
+ import { renderFormField } from '../form-field/renderFormField'
7
+
8
+ export interface FileInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size'> {
9
+ /**
10
+ * A string of all className you want applied to the component.
11
+ */
12
+ className?: string
13
+ /**
14
+ * Toggle the disabled state for the component.
15
+ */
16
+ disabled?: boolean
17
+ /**
18
+ * A description for the field, rendered below the input.
19
+ */
20
+ help?: ReactNode
21
+ /**
22
+ * Set component validation state to invalid.
23
+ */
24
+ invalid?: boolean
25
+ /**
26
+ * An error message for the field, rendered below the input when `invalid` is set.
27
+ */
28
+ invalidFeedback?: ReactNode
29
+ /**
30
+ * The field's caption, rendered as a `FormLabel` associated with this input.
31
+ */
32
+ label?: ReactNode
33
+ /**
34
+ * Allows selecting more than one file.
35
+ */
36
+ multiple?: boolean
37
+ /**
38
+ * Method called when the selected file(s) change.
39
+ */
40
+ onChange?: ChangeEventHandler<HTMLInputElement>
41
+ /**
42
+ * Size the component small or large.
43
+ */
44
+ size?: 'small' | 'large'
45
+ /**
46
+ * Set component validation state to valid.
47
+ */
48
+ valid?: boolean
49
+ /**
50
+ * A success message for the field, rendered below the input when `valid` is set.
51
+ */
52
+ validFeedback?: ReactNode
53
+ }
54
+
55
+ export const FileInput = forwardRef<HTMLInputElement, FileInputProps>(
56
+ (
57
+ { className, help, id, invalid, invalidFeedback, label, size, valid, validFeedback, ...rest },
58
+ ref
59
+ ) => {
60
+ const { describedBy, feedbackId, helpId, inputId } = useFormField({
61
+ ariaDescribedBy: rest['aria-describedby'],
62
+ help,
63
+ id,
64
+ invalid,
65
+ invalidFeedback,
66
+ valid,
67
+ validFeedback
68
+ })
69
+
70
+ const _className = classNames(
71
+ 'form-input',
72
+ size,
73
+ validationClassName(invalid, valid),
74
+ className
75
+ )
76
+
77
+ return renderFormField({
78
+ children: (
79
+ <input
80
+ {...rest}
81
+ aria-describedby={describedBy}
82
+ aria-invalid={invalid || undefined}
83
+ className={_className}
84
+ id={inputId}
85
+ ref={ref}
86
+ type="file"
87
+ />
88
+ ),
89
+ help,
90
+ ids: { feedback: feedbackId, help: helpId, input: inputId },
91
+ invalid,
92
+ invalidFeedback,
93
+ label,
94
+ valid,
95
+ validFeedback
96
+ })
97
+ }
98
+ )
99
+
100
+ FileInput.displayName = 'FileInput'
@@ -0,0 +1,2 @@
1
+ export { FileInput } from './FileInput'
2
+ export type { FileInputProps } from './FileInput'
@@ -0,0 +1,134 @@
1
+ import React, { ElementType, ForwardRefRenderFunction, ReactElement } from 'react'
2
+ import classNames from 'classnames'
3
+
4
+ import {
5
+ createPolymorphicComponent,
6
+ PolymorphicComponentProps,
7
+ PolymorphicRef
8
+ } from '../../utils/polymorphic'
9
+ import { buildResponsiveClassNames } from '../../utils/breakpoints'
10
+ import { spacingClassName } from '../../utils/spacingClassName'
11
+ import { Breakpoint, Spacing } from '../../types'
12
+
13
+ export interface FlexLayout {
14
+ /**
15
+ * Sets `flex-direction`. Omit for the browser default (`row`).
16
+ */
17
+ direction?: 'row' | 'column' | 'row-reverse' | 'column-reverse'
18
+ /**
19
+ * Sets `flex-wrap`. Omit for the browser default (`nowrap`).
20
+ */
21
+ wrap?: 'wrap' | 'nowrap' | 'wrap-reverse'
22
+ /**
23
+ * Sets `justify-content`, aligning items along the main axis.
24
+ */
25
+ justify?: 'start' | 'end' | 'center' | 'between' | 'around' | 'evenly'
26
+ /**
27
+ * Sets `align-items`, aligning items along the cross axis.
28
+ */
29
+ align?: 'start' | 'end' | 'center' | 'baseline' | 'stretch'
30
+ /**
31
+ * Sets `align-content`, distributing wrapped lines along the cross axis. Has no effect on
32
+ * single-line (non-wrapping) containers.
33
+ */
34
+ alignContent?: 'start' | 'end' | 'center' | 'between' | 'around' | 'stretch'
35
+ /**
36
+ * Spacing between children on both axes, mapped to the `gap-*` utility classes. Overridden per
37
+ * axis by `rowGap`/`columnGap` where set.
38
+ */
39
+ gap?: Spacing | 0
40
+ /**
41
+ * Spacing between rows (the cross axis when wrapped), mapped to the `row-gap-*` utility
42
+ * classes. Independent of `gap`/`columnGap`.
43
+ */
44
+ rowGap?: Spacing | 0
45
+ /**
46
+ * Spacing between columns (the main axis), mapped to the `column-gap-*` utility classes.
47
+ * Independent of `gap`/`rowGap`.
48
+ */
49
+ columnGap?: Spacing | 0
50
+ }
51
+
52
+ type FlexOwnProps<C extends ElementType> = FlexLayout & {
53
+ /**
54
+ * A string of all className you want applied to the component.
55
+ */
56
+ className?: string
57
+ /**
58
+ * Component used for the root node. Either a string to use a HTML element or a component.
59
+ */
60
+ component?: C
61
+ /**
62
+ * Renders an inline flex container (`.d-inline-flex`) instead of a block-level one (`.d-flex`,
63
+ * the default).
64
+ */
65
+ inline?: boolean
66
+ /**
67
+ * Overrides any of `direction`/`wrap`/`justify`/`align`/`alignContent`/`gap`/`rowGap`/
68
+ * `columnGap` at one or more breakpoints, via regular viewport media queries (unlike `Stack`'s
69
+ * `responsive` prop, this doesn't require a `.contains-inline` ancestor).
70
+ */
71
+ responsive?: Partial<Record<Breakpoint, FlexLayout>>
72
+ }
73
+
74
+ export type FlexProps<C extends ElementType = 'div'> = PolymorphicComponentProps<C, FlexOwnProps<C>>
75
+
76
+ type FlexComponent = (<C extends ElementType = 'div'>(
77
+ props: FlexProps<C> & { ref?: PolymorphicRef<C> }
78
+ ) => ReactElement | null) & { displayName?: string }
79
+
80
+ const layoutClassNames = (
81
+ { direction, wrap, justify, align, alignContent, gap, rowGap, columnGap }: FlexLayout,
82
+ prefix: string
83
+ ) => [
84
+ direction && `${prefix}flex-${direction}`,
85
+ wrap && `${prefix}flex-${wrap}`,
86
+ justify && `${prefix}justify-content-${justify}`,
87
+ align && `${prefix}align-items-${align}`,
88
+ alignContent && `${prefix}align-content-${alignContent}`,
89
+ spacingClassName('gap', gap, prefix),
90
+ spacingClassName('row-gap', rowGap, prefix),
91
+ spacingClassName('column-gap', columnGap, prefix)
92
+ ]
93
+
94
+ function FlexRender<C extends ElementType = 'div'>(
95
+ {
96
+ children,
97
+ className,
98
+ component,
99
+ inline,
100
+ direction,
101
+ wrap,
102
+ justify,
103
+ align,
104
+ alignContent,
105
+ gap,
106
+ rowGap,
107
+ columnGap,
108
+ responsive,
109
+ ...rest
110
+ }: FlexProps<C>,
111
+ ref: PolymorphicRef<C>
112
+ ) {
113
+ const Component = component ?? 'div'
114
+ const _className = classNames(
115
+ inline ? 'd-inline-flex' : 'd-flex',
116
+ buildResponsiveClassNames(
117
+ layoutClassNames,
118
+ { direction, wrap, justify, align, alignContent, gap, rowGap, columnGap },
119
+ responsive
120
+ ),
121
+ className
122
+ )
123
+
124
+ return (
125
+ <Component className={_className} {...rest} ref={ref}>
126
+ {children}
127
+ </Component>
128
+ )
129
+ }
130
+
131
+ export const Flex = createPolymorphicComponent<FlexComponent>(
132
+ FlexRender as ForwardRefRenderFunction<Element, FlexProps<ElementType>>,
133
+ 'Flex'
134
+ )
@@ -0,0 +1,2 @@
1
+ export { Flex } from './Flex'
2
+ export type { FlexProps } from './Flex'
@@ -0,0 +1,94 @@
1
+ import React, { forwardRef, HTMLAttributes, ReactNode } from 'react'
2
+ import classNames from 'classnames'
3
+
4
+ import { FormLabel } from '../form/FormLabel'
5
+ import { FormFieldIds, renderFormField } from '../form-field/renderFormField'
6
+
7
+ export interface FloatingInputProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
8
+ /**
9
+ * The form control (e.g. a `TextInput`, `Select`, or `Textarea`) the floating label attaches
10
+ * to. Chassis-css's floating-label CSS relies on a `label:has(~ .form-input)` selector, so this
11
+ * must render an element carrying the `form-input` class as a direct child.
12
+ */
13
+ children: ReactNode
14
+ /**
15
+ * A string of all className you want applied to the `.form-floating` element.
16
+ */
17
+ className?: string
18
+ /**
19
+ * A description for the field, rendered below the control. Setting this (or `invalidFeedback`/
20
+ * `validFeedback`) wraps the floating input in a `.form-field`.
21
+ */
22
+ help?: ReactNode
23
+ /**
24
+ * The DOM ids of the wrapped control, used to associate the label (`htmlFor`) and point your
25
+ * control's own `aria-describedby` at the rendered help/feedback text.
26
+ */
27
+ ids?: FormFieldIds
28
+ /**
29
+ * Set field validation state to invalid.
30
+ */
31
+ invalid?: boolean
32
+ /**
33
+ * An error message for the field, rendered below the control when `invalid` is set.
34
+ */
35
+ invalidFeedback?: ReactNode
36
+ /**
37
+ * The field's caption, rendered as a floating `FormLabel` associated with `ids.input`.
38
+ */
39
+ label: ReactNode
40
+ /**
41
+ * Set field validation state to valid.
42
+ */
43
+ valid?: boolean
44
+ /**
45
+ * A success message for the field, rendered below the control when `valid` is set.
46
+ */
47
+ validFeedback?: ReactNode
48
+ }
49
+
50
+ export const FloatingInput = forwardRef<HTMLDivElement, FloatingInputProps>(
51
+ (
52
+ {
53
+ children,
54
+ className,
55
+ help,
56
+ ids,
57
+ invalid,
58
+ invalidFeedback,
59
+ label,
60
+ valid,
61
+ validFeedback,
62
+ ...rest
63
+ },
64
+ ref
65
+ ) => {
66
+ if (!ids?.input && !ids?.label) {
67
+ console.warn(
68
+ 'FloatingInput: `ids.input`/`ids.label` are not set — the rendered label ' +
69
+ "won't be associated with your control (no `htmlFor`, no `aria-labelledby` target). " +
70
+ 'Pass `ids={{ input: yourControlId }}` (or `ids.label` for a group with no single ' +
71
+ 'input) so the label has something to point at.'
72
+ )
73
+ }
74
+
75
+ return renderFormField({
76
+ children: (
77
+ <div className={classNames('form-floating', className)} {...rest} ref={ref}>
78
+ <FormLabel htmlFor={ids?.input} id={ids?.label}>
79
+ {label}
80
+ </FormLabel>
81
+ {children}
82
+ </div>
83
+ ),
84
+ help,
85
+ ids: { feedback: ids?.feedback, help: ids?.help },
86
+ invalid,
87
+ invalidFeedback,
88
+ valid,
89
+ validFeedback
90
+ })
91
+ }
92
+ )
93
+
94
+ FloatingInput.displayName = 'FloatingInput'
@@ -0,0 +1,2 @@
1
+ export { FloatingInput } from './FloatingInput'
2
+ export type { FloatingInputProps } from './FloatingInput'
@@ -0,0 +1,26 @@
1
+ import React, { forwardRef, FormHTMLAttributes } from 'react'
2
+ import classNames from 'classnames'
3
+
4
+ export interface FormProps extends FormHTMLAttributes<HTMLFormElement> {
5
+ /**
6
+ * A string of all className you want applied to the component.
7
+ */
8
+ className?: string
9
+ /**
10
+ * Mark a form as validated. If you set it `true`, all validation styles will be applied to the forms component.
11
+ */
12
+ validated?: boolean
13
+ }
14
+
15
+ export const Form = forwardRef<HTMLFormElement, FormProps>(
16
+ ({ children, className, validated, ...rest }, ref) => {
17
+ const _className = classNames({ 'was-validated': validated }, className)
18
+ return (
19
+ <form className={_className} {...rest} ref={ref}>
20
+ {children}
21
+ </form>
22
+ )
23
+ }
24
+ )
25
+
26
+ Form.displayName = 'Form'
@@ -0,0 +1,64 @@
1
+ import React, { ElementType, ForwardRefRenderFunction, ReactElement } from 'react'
2
+ import classNames from 'classnames'
3
+
4
+ import {
5
+ createPolymorphicComponent,
6
+ PolymorphicComponentProps,
7
+ PolymorphicRef
8
+ } from '../../utils/polymorphic'
9
+
10
+ type FormFeedbackOwnProps<C extends ElementType> = {
11
+ /**
12
+ * A string of all className you want applied to the component.
13
+ */
14
+ className?: string
15
+ /**
16
+ * Component used for the root node. Either a string to use a HTML element or a component.
17
+ */
18
+ component?: C
19
+ /**
20
+ * Set component validation state to invalid.
21
+ */
22
+ invalid?: boolean
23
+ /**
24
+ * If your form layout allows it, you can display validation feedback in a styled tooltip.
25
+ */
26
+ tooltip?: boolean
27
+ /**
28
+ * Set component validation state to valid.
29
+ */
30
+ valid?: boolean
31
+ }
32
+
33
+ export type FormFeedbackProps<C extends ElementType = 'div'> = PolymorphicComponentProps<
34
+ C,
35
+ FormFeedbackOwnProps<C>
36
+ >
37
+
38
+ type FormFeedbackComponent = (<C extends ElementType = 'div'>(
39
+ props: FormFeedbackProps<C> & { ref?: PolymorphicRef<C> }
40
+ ) => ReactElement | null) & { displayName?: string }
41
+
42
+ function FormFeedbackRender<C extends ElementType = 'div'>(
43
+ { children, className, component, invalid, tooltip, valid, ...rest }: FormFeedbackProps<C>,
44
+ ref: PolymorphicRef<C>
45
+ ) {
46
+ const Component = component ?? 'div'
47
+ const _className = classNames(
48
+ {
49
+ [`invalid-${tooltip ? 'tooltip' : 'feedback'}`]: invalid,
50
+ [`valid-${tooltip ? 'tooltip' : 'feedback'}`]: valid
51
+ },
52
+ className
53
+ )
54
+ return (
55
+ <Component className={_className} {...rest} ref={ref}>
56
+ {children}
57
+ </Component>
58
+ )
59
+ }
60
+
61
+ export const FormFeedback = createPolymorphicComponent<FormFeedbackComponent>(
62
+ FormFeedbackRender as ForwardRefRenderFunction<Element, FormFeedbackProps<ElementType>>,
63
+ 'FormFeedback'
64
+ )
@@ -0,0 +1,46 @@
1
+ import React, { ElementType, ForwardRefRenderFunction, ReactElement } from 'react'
2
+ import classNames from 'classnames'
3
+
4
+ import {
5
+ createPolymorphicComponent,
6
+ PolymorphicComponentProps,
7
+ PolymorphicRef
8
+ } from '../../utils/polymorphic'
9
+
10
+ type FormHelpOwnProps<C extends ElementType> = {
11
+ /**
12
+ * A string of all className you want applied to the component.
13
+ */
14
+ className?: string
15
+ /**
16
+ * Component used for the root node. Either a string to use a HTML element or a component.
17
+ */
18
+ component?: C
19
+ }
20
+
21
+ export type FormHelpProps<C extends ElementType = 'div'> = PolymorphicComponentProps<
22
+ C,
23
+ FormHelpOwnProps<C>
24
+ >
25
+
26
+ type FormHelpComponent = (<C extends ElementType = 'div'>(
27
+ props: FormHelpProps<C> & { ref?: PolymorphicRef<C> }
28
+ ) => ReactElement | null) & { displayName?: string }
29
+
30
+ function FormHelpRender<C extends ElementType = 'div'>(
31
+ { children, className, component, ...rest }: FormHelpProps<C>,
32
+ ref: PolymorphicRef<C>
33
+ ) {
34
+ const Component = component ?? 'div'
35
+ const _className = classNames('form-help', className)
36
+ return (
37
+ <Component className={_className} {...rest} ref={ref}>
38
+ {children}
39
+ </Component>
40
+ )
41
+ }
42
+
43
+ export const FormHelp = createPolymorphicComponent<FormHelpComponent>(
44
+ FormHelpRender as ForwardRefRenderFunction<Element, FormHelpProps<ElementType>>,
45
+ 'FormHelp'
46
+ )
@@ -0,0 +1,26 @@
1
+ import React, { forwardRef, LabelHTMLAttributes } from 'react'
2
+ import classNames from 'classnames'
3
+
4
+ export interface FormLabelProps extends LabelHTMLAttributes<HTMLLabelElement> {
5
+ /**
6
+ * A string of all className you want applied to the component.
7
+ */
8
+ className?: string
9
+ /**
10
+ * A string of all className you want to be applied to the component, and override standard className value.
11
+ */
12
+ customClassName?: string
13
+ }
14
+
15
+ export const FormLabel = forwardRef<HTMLLabelElement, FormLabelProps>(
16
+ ({ children, className, customClassName, ...rest }, ref) => {
17
+ const _className = customClassName ? customClassName : classNames('form-label', className)
18
+ return (
19
+ <label className={_className} {...rest} ref={ref}>
20
+ {children}
21
+ </label>
22
+ )
23
+ }
24
+ )
25
+
26
+ FormLabel.displayName = 'FormLabel'
@@ -0,0 +1,8 @@
1
+ export { Form } from './Form'
2
+ export type { FormProps } from './Form'
3
+ export { FormLabel } from './FormLabel'
4
+ export type { FormLabelProps } from './FormLabel'
5
+ export { FormHelp } from './FormHelp'
6
+ export type { FormHelpProps } from './FormHelp'
7
+ export { FormFeedback } from './FormFeedback'
8
+ export type { FormFeedbackProps } from './FormFeedback'