@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,98 @@
1
+ import React, { RefObject, useRef } from 'react'
2
+ import classNames from 'classnames'
3
+ import { AriaListBoxOptions, useListBox, useOption } from 'react-aria'
4
+ import { ComboBoxState, Node } from 'react-stately'
5
+
6
+ import { getVirtualFocusStyle } from '../../utils/virtualFocusStyle'
7
+ import { ComboboxEntry, ComboboxSelectionMode } from '../../utils/comboboxCollection'
8
+ import { Icon } from '../icon/Icon'
9
+
10
+ interface ComboboxListBoxProps<M extends ComboboxSelectionMode = 'single'> {
11
+ listBoxProps: AriaListBoxOptions<ComboboxEntry>
12
+ listBoxRef: RefObject<HTMLElement | null>
13
+ state: ComboBoxState<ComboboxEntry, M>
14
+ }
15
+
16
+ // Generic over `M` (single- vs multi-select) purely so both `Combobox` (always single) and
17
+ // `Autocomplete` (either) can pass their own `ComboBoxState` here without a cast — nothing in
18
+ // this file's rendering logic actually depends on which mode is active.
19
+ export const ComboboxListBox = <M extends ComboboxSelectionMode = 'single'>({
20
+ listBoxProps,
21
+ listBoxRef,
22
+ state
23
+ }: ComboboxListBoxProps<M>) => {
24
+ const { listBoxProps: domListBoxProps } = useListBox(listBoxProps, state, listBoxRef)
25
+
26
+ return (
27
+ <div {...domListBoxProps} ref={listBoxRef as RefObject<HTMLDivElement>}>
28
+ {[...state.collection].map((node) =>
29
+ node.type === 'section' ? (
30
+ <ComboboxSection key={node.key} node={node} state={state} />
31
+ ) : (
32
+ <ComboboxOption key={node.key} item={node} state={state} />
33
+ )
34
+ )}
35
+ </div>
36
+ )
37
+ }
38
+
39
+ interface ComboboxSectionProps<M extends ComboboxSelectionMode = 'single'> {
40
+ node: Node<ComboboxEntry>
41
+ state: ComboBoxState<ComboboxEntry, M>
42
+ }
43
+
44
+ // Chassis-css groups are `.menu-header` siblings interleaved with `.menu-item`s, no wrapping
45
+ // element — plain, static markup, so there's no need for react-aria's `useListBoxSection`.
46
+ // `useComboBoxState`'s filtering hides child items whose text doesn't match, but doesn't drop an
47
+ // emptied-out section node itself, so a fully-filtered-out group's header is skipped by hand here
48
+ // rather than left to render on its own.
49
+ const ComboboxSection = <M extends ComboboxSelectionMode = 'single'>({
50
+ node,
51
+ state
52
+ }: ComboboxSectionProps<M>) => {
53
+ const childNodes = [...state.collection.getChildren!(node.key)]
54
+ if (childNodes.length === 0) return null
55
+
56
+ return (
57
+ <>
58
+ <div className="menu-header" role="presentation">
59
+ {node.rendered}
60
+ </div>
61
+ {childNodes.map((child) => (
62
+ <ComboboxOption key={child.key} item={child} state={state} />
63
+ ))}
64
+ </>
65
+ )
66
+ }
67
+
68
+ interface ComboboxOptionProps<M extends ComboboxSelectionMode = 'single'> {
69
+ item: Node<ComboboxEntry>
70
+ state: ComboBoxState<ComboboxEntry, M>
71
+ }
72
+
73
+ const ComboboxOption = <M extends ComboboxSelectionMode = 'single'>({
74
+ item,
75
+ state
76
+ }: ComboboxOptionProps<M>) => {
77
+ const ref = useRef<HTMLDivElement>(null)
78
+ const { optionProps, isSelected, isDisabled, isFocused } = useOption(
79
+ { key: item.key },
80
+ state,
81
+ ref
82
+ )
83
+
84
+ return (
85
+ <div
86
+ className={classNames('menu-item', {
87
+ selected: isSelected,
88
+ disabled: isDisabled
89
+ })}
90
+ style={getVirtualFocusStyle(isFocused)}
91
+ {...optionProps}
92
+ ref={ref}
93
+ >
94
+ {item.rendered}
95
+ {isSelected && <Icon name="check-solid" className="menu-item-check" />}
96
+ </div>
97
+ )
98
+ }
@@ -0,0 +1,6 @@
1
+ export { Combobox } from './Combobox'
2
+ export type { ComboboxProps } from './Combobox'
3
+ export { ComboboxGroup } from './ComboboxGroup'
4
+ export type { ComboboxGroupProps } from './ComboboxGroup'
5
+ export { ComboboxItem } from './ComboboxItem'
6
+ export type { ComboboxItemProps } from './ComboboxItem'
@@ -0,0 +1,58 @@
1
+ import React, { forwardRef, useRef } from 'react'
2
+ import { AriaButtonProps, useButton } from 'react-aria'
3
+ import { OverlayTriggerState } from 'react-stately'
4
+
5
+ import { useForkedRef } from '../../hooks'
6
+
7
+ interface CalendarToggleButtonProps {
8
+ buttonProps: AriaButtonProps
9
+ state: OverlayTriggerState
10
+ }
11
+
12
+ // Shared by `DatePicker` and `DateRangePicker` — both trigger their calendar overlay with an
13
+ // identical calendar-icon button. `buttonProps.onPress` (from that caller's own `useDatePicker`/
14
+ // `useDateRangePicker`) only ever opens the overlay (matches upstream react-aria), so re-clicking
15
+ // the button while it's already open would otherwise do nothing — overridden here to actually
16
+ // toggle. Forwards its ref so callers can move focus onto it explicitly — e.g. `ClearButton` sits
17
+ // immediately before it and unmounts itself on press, so focus needs somewhere to land.
18
+ export const CalendarToggleButton = forwardRef<HTMLButtonElement, CalendarToggleButtonProps>(
19
+ ({ buttonProps, state }, forwardedRef) => {
20
+ const internalRef = useRef<HTMLButtonElement>(null)
21
+ const ref = useForkedRef(internalRef, forwardedRef)
22
+ const { buttonProps: toggleProps } = useButton(
23
+ { ...buttonProps, onPress: () => state.toggle() },
24
+ internalRef
25
+ )
26
+
27
+ return (
28
+ <button {...toggleProps} className="input-adorn" ref={ref} type="button">
29
+ <svg
30
+ fill="none"
31
+ height="16"
32
+ viewBox="0 0 16 16"
33
+ width="16"
34
+ xmlns="http://www.w3.org/2000/svg"
35
+ >
36
+ <rect
37
+ height="12"
38
+ rx="1.5"
39
+ stroke="currentColor"
40
+ strokeWidth="1.25"
41
+ width="13"
42
+ x="1.5"
43
+ y="3"
44
+ />
45
+ <path d="M1.5 6.5h13" stroke="currentColor" strokeWidth="1.25" />
46
+ <path
47
+ d="M4.5 1.5v3M11.5 1.5v3"
48
+ stroke="currentColor"
49
+ strokeLinecap="round"
50
+ strokeWidth="1.25"
51
+ />
52
+ </svg>
53
+ </button>
54
+ )
55
+ }
56
+ )
57
+
58
+ CalendarToggleButton.displayName = 'CalendarToggleButton'
@@ -0,0 +1,35 @@
1
+ import React, { useRef } from 'react'
2
+ import { useButton } from 'react-aria'
3
+
4
+ interface ClearButtonProps {
5
+ isDisabled?: boolean
6
+ onPress: () => void
7
+ }
8
+
9
+ // Shared by `DatePicker` and `DateRangePicker` — a trailing "×" adornment that resets the
10
+ // current selection to empty. Rendered only while there's something to clear (see each caller's
11
+ // own conditional). `useButton` for the same reason `CalendarToggleButton` uses it: proper
12
+ // press/keyboard semantics consistent with the rest of this library, rather than a raw `onClick`.
13
+ export const ClearButton = ({ isDisabled, onPress }: ClearButtonProps) => {
14
+ const ref = useRef<HTMLButtonElement>(null)
15
+ const { buttonProps } = useButton({ 'aria-label': 'Clear', isDisabled, onPress }, ref)
16
+
17
+ return (
18
+ <button {...buttonProps} className="input-adorn" ref={ref} type="button">
19
+ <svg
20
+ fill="none"
21
+ height="16"
22
+ viewBox="0 0 16 16"
23
+ width="16"
24
+ xmlns="http://www.w3.org/2000/svg"
25
+ >
26
+ <path
27
+ d="M4 4l8 8M12 4l-8 8"
28
+ stroke="currentColor"
29
+ strokeLinecap="round"
30
+ strokeWidth="1.25"
31
+ />
32
+ </svg>
33
+ </button>
34
+ )
35
+ }
@@ -0,0 +1,54 @@
1
+ import React, { useRef } from 'react'
2
+ import classNames from 'classnames'
3
+ import { AriaDateFieldProps, DateValue, useDateField, useDateSegment, useLocale } from 'react-aria'
4
+ import { DateFieldState, DateSegment as DateSegmentType, useDateFieldState } from 'react-stately'
5
+ import { createCalendar } from '@internationalized/date'
6
+
7
+ interface DateFieldProps {
8
+ fieldProps: AriaDateFieldProps<DateValue>
9
+ }
10
+
11
+ // Builds its own segment state from the `fieldProps` `DatePicker` hands down — mirrors react
12
+ // aria's own documented composition (the top-level `useDatePickerState`/`useDatePicker` pair
13
+ // manages the *selected value*; the field's individually-editable segments are a separate piece
14
+ // of state derived from `locale`/`createCalendar`, owned here).
15
+ export const DateField = ({ fieldProps }: DateFieldProps) => {
16
+ const { locale } = useLocale()
17
+ const state = useDateFieldState({
18
+ ...fieldProps,
19
+ createCalendar,
20
+ locale
21
+ })
22
+
23
+ const ref = useRef<HTMLDivElement>(null)
24
+ const { fieldProps: domFieldProps } = useDateField(fieldProps, state, ref)
25
+
26
+ return (
27
+ <div {...domFieldProps} className="datepicker-field" ref={ref}>
28
+ {state.segments.map((segment, index) => (
29
+ // eslint-disable-next-line react/no-array-index-key
30
+ <DateSegment key={index} segment={segment} state={state} />
31
+ ))}
32
+ </div>
33
+ )
34
+ }
35
+
36
+ interface DateSegmentProps {
37
+ segment: DateSegmentType
38
+ state: DateFieldState
39
+ }
40
+
41
+ const DateSegment = ({ segment, state }: DateSegmentProps) => {
42
+ const ref = useRef<HTMLDivElement>(null)
43
+ const { segmentProps } = useDateSegment(segment, state, ref)
44
+
45
+ return (
46
+ <span
47
+ {...segmentProps}
48
+ className={classNames('datepicker-segment', { placeholder: segment.isPlaceholder })}
49
+ ref={ref}
50
+ >
51
+ {segment.text}
52
+ </span>
53
+ )
54
+ }
@@ -0,0 +1,51 @@
1
+ /*
2
+ * DatePicker's segmented field reuses chassis-css's existing `.form-input`/`.input-adorn`/
3
+ * `.ghost-input` classes as-is (input chrome, trailing-button layout, sizing modifiers all come
4
+ * for free). The popover shell is chassis-css's real `.datepicker` class too now (not the custom
5
+ * `.datepicker-calendar` this used to be) — rendered *without* `data-cx-inline`, so it gets
6
+ * chassis-css's native popover treatment (position, z-index, padding, border, box-shadow)
7
+ * directly, while `Calendar` nested inside it stays `data-cx-inline` (no border/shadow of its
8
+ * own — see `Calendar.scss`'s comment) so there's only one bordered/shadowed box, not two. Only
9
+ * the segments themselves are genuinely new visual territory with no chassis-css equivalent.
10
+ * Built on chassis-css's globally-defined `--cx-*` tokens so it stays on the same design language
11
+ * (and adapts to light/dark) — except `--cx-form-idle-fg-inactive`, which is only ever defined
12
+ * inside chassis-css's own `.form-input` block, not `:root`; see `Calendar.scss`'s comment on why
13
+ * that one internal-token exception was kept anyway.
14
+ */
15
+
16
+ @use "@chassis-ui/css/scss/mixins" as *;
17
+
18
+ /*
19
+ * chassis-css's own `.datepicker` rule sets `display: flex` unconditionally, which — same-
20
+ * specificity, later-declared-layer concerns aside — otherwise wins over the browser's default
21
+ * `[hidden] { display: none }` UA rule (author styles always beat UA styles). Layered here to
22
+ * land in the same cascade layer as chassis-css's own rule (see `Calendar.scss`'s comment on
23
+ * why), with the `[hidden]` attribute bumping specificity enough to reliably win within it.
24
+ */
25
+ @layer components {
26
+ .datepicker[hidden] {
27
+ display: none;
28
+ }
29
+ }
30
+
31
+ .datepicker-field {
32
+ display: flex;
33
+ align-items: center;
34
+ width: fit-content;
35
+ }
36
+
37
+ .datepicker-segment {
38
+ padding-inline: var(--cx-space-3xsmall);
39
+ @include border-radius(var(--cx-border-radius-small));
40
+ outline: 0;
41
+ }
42
+
43
+ .datepicker-segment.placeholder {
44
+ color: var(--cx-form-idle-fg-inactive);
45
+ }
46
+
47
+ .datepicker-segment:focus {
48
+ color: var(--cx-primary-contrast);
49
+ background-color: var(--cx-primary);
50
+ }
51
+