@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.
- package/LICENSE +21 -0
- package/README.md +65 -0
- package/dist/index.d.ts +5909 -0
- package/dist/index.js +2 -0
- package/dist/style.css +1 -0
- package/package.json +114 -0
- package/src/components/accordion/Accordion.tsx +190 -0
- package/src/components/accordion/AccordionBody.tsx +46 -0
- package/src/components/accordion/AccordionHeader.tsx +21 -0
- package/src/components/accordion/AccordionItem.tsx +59 -0
- package/src/components/accordion/context.ts +8 -0
- package/src/components/accordion/index.ts +8 -0
- package/src/components/autocomplete/Autocomplete.tsx +464 -0
- package/src/components/autocomplete/AutocompleteGroup.tsx +20 -0
- package/src/components/autocomplete/AutocompleteItem.tsx +18 -0
- package/src/components/autocomplete/index.ts +6 -0
- package/src/components/avatar/Avatar.tsx +134 -0
- package/src/components/avatar/AvatarImage.tsx +19 -0
- package/src/components/avatar/AvatarStack.tsx +98 -0
- package/src/components/avatar/index.ts +6 -0
- package/src/components/badge/Badge.tsx +94 -0
- package/src/components/badge/index.ts +2 -0
- package/src/components/breadcrumb/Breadcrumb.tsx +59 -0
- package/src/components/breadcrumb/BreadcrumbItem.tsx +38 -0
- package/src/components/breadcrumb/index.ts +4 -0
- package/src/components/button/Button.tsx +229 -0
- package/src/components/button/index.ts +2 -0
- package/src/components/button-group/ButtonGroup.tsx +55 -0
- package/src/components/button-group/ButtonToolbar.tsx +47 -0
- package/src/components/button-group/index.ts +4 -0
- package/src/components/calendar/Calendar.scss +57 -0
- package/src/components/calendar/Calendar.tsx +324 -0
- package/src/components/calendar/CalendarMonthBlock.tsx +57 -0
- package/src/components/calendar/CalendarMonthGrid.tsx +92 -0
- package/src/components/calendar/CalendarMonthYearPicker.tsx +162 -0
- package/src/components/calendar/CalendarNavButton.tsx +24 -0
- package/src/components/calendar/CalendarWeekGrid.tsx +58 -0
- package/src/components/calendar/CalendarYearGrid.tsx +126 -0
- package/src/components/calendar/RangeCalendar.scss +95 -0
- package/src/components/calendar/RangeCalendar.tsx +361 -0
- package/src/components/calendar/index.ts +5 -0
- package/src/components/card/Card.tsx +173 -0
- package/src/components/card/CardBody.tsx +75 -0
- package/src/components/card/CardFooter.tsx +47 -0
- package/src/components/card/CardGroup.tsx +51 -0
- package/src/components/card/CardHeader.tsx +47 -0
- package/src/components/card/CardImage.tsx +70 -0
- package/src/components/card/CardImageOverlay.tsx +47 -0
- package/src/components/card/CardLink.tsx +40 -0
- package/src/components/card/CardSubtitle.tsx +47 -0
- package/src/components/card/CardText.tsx +47 -0
- package/src/components/card/CardTitle.tsx +47 -0
- package/src/components/card/index.ts +22 -0
- package/src/components/carousel/Carousel.tsx +742 -0
- package/src/components/carousel/CarouselControlButton.tsx +74 -0
- package/src/components/carousel/CarouselControlNext.tsx +22 -0
- package/src/components/carousel/CarouselControlPrev.tsx +22 -0
- package/src/components/carousel/CarouselIndicators.tsx +44 -0
- package/src/components/carousel/CarouselInner.tsx +56 -0
- package/src/components/carousel/CarouselItem.tsx +51 -0
- package/src/components/carousel/CarouselOverlay.tsx +51 -0
- package/src/components/carousel/CarouselPlayPause.tsx +61 -0
- package/src/components/carousel/carouselEngine.ts +170 -0
- package/src/components/carousel/context.ts +29 -0
- package/src/components/carousel/index.ts +21 -0
- package/src/components/checkbox/Checkbox.tsx +236 -0
- package/src/components/checkbox/CheckboxGroup.tsx +145 -0
- package/src/components/checkbox/context.ts +14 -0
- package/src/components/checkbox/index.ts +4 -0
- package/src/components/chip/Chip.tsx +183 -0
- package/src/components/chip/index.ts +2 -0
- package/src/components/chip-input/ChipInput.tsx +363 -0
- package/src/components/chip-input/ChipList.tsx +95 -0
- package/src/components/chip-input/index.ts +2 -0
- package/src/components/close-button/CloseButton.tsx +205 -0
- package/src/components/close-button/index.ts +2 -0
- package/src/components/collapse/Collapse.tsx +128 -0
- package/src/components/collapse/index.ts +2 -0
- package/src/components/color-input/ColorInput.tsx +106 -0
- package/src/components/color-input/index.ts +2 -0
- package/src/components/combobox/Combobox.tsx +320 -0
- package/src/components/combobox/ComboboxGroup.tsx +27 -0
- package/src/components/combobox/ComboboxItem.tsx +44 -0
- package/src/components/combobox/ComboboxListBox.tsx +98 -0
- package/src/components/combobox/index.ts +6 -0
- package/src/components/datepicker/CalendarToggleButton.tsx +58 -0
- package/src/components/datepicker/ClearButton.tsx +35 -0
- package/src/components/datepicker/DateField.tsx +54 -0
- package/src/components/datepicker/DatePicker.scss +51 -0
- package/src/components/datepicker/DatePicker.tsx +574 -0
- package/src/components/datepicker/DateRangePicker.scss +11 -0
- package/src/components/datepicker/DateRangePicker.tsx +343 -0
- package/src/components/datepicker/index.ts +4 -0
- package/src/components/datepicker/renderDatePickerShell.tsx +104 -0
- package/src/components/drawer/Drawer.tsx +211 -0
- package/src/components/drawer/DrawerBody.tsx +47 -0
- package/src/components/drawer/DrawerFooter.tsx +51 -0
- package/src/components/drawer/DrawerHeader.tsx +60 -0
- package/src/components/drawer/DrawerTitle.tsx +49 -0
- package/src/components/drawer/index.ts +10 -0
- package/src/components/file-input/FileInput.tsx +100 -0
- package/src/components/file-input/index.ts +2 -0
- package/src/components/flex/Flex.tsx +134 -0
- package/src/components/flex/index.ts +2 -0
- package/src/components/floating-input/FloatingInput.tsx +94 -0
- package/src/components/floating-input/index.ts +2 -0
- package/src/components/form/Form.tsx +26 -0
- package/src/components/form/FormFeedback.tsx +64 -0
- package/src/components/form/FormHelp.tsx +46 -0
- package/src/components/form/FormLabel.tsx +26 -0
- package/src/components/form/index.ts +8 -0
- package/src/components/form/renderFormCheck.tsx +86 -0
- package/src/components/form-field/FormField.tsx +84 -0
- package/src/components/form-field/index.ts +2 -0
- package/src/components/form-field/renderFormField.tsx +74 -0
- package/src/components/grid/Col.tsx +69 -0
- package/src/components/grid/Container.tsx +59 -0
- package/src/components/grid/Grid.tsx +86 -0
- package/src/components/grid/GridItem.tsx +123 -0
- package/src/components/grid/Row.tsx +71 -0
- package/src/components/grid/gap.ts +8 -0
- package/src/components/grid/index.ts +10 -0
- package/src/components/icon/Icon.tsx +74 -0
- package/src/components/icon/index.ts +2 -0
- package/src/components/input-adorn/InputAdorn.tsx +55 -0
- package/src/components/input-adorn/index.ts +2 -0
- package/src/components/input-group/InputGroup.tsx +50 -0
- package/src/components/input-group/InputGroupAddon.tsx +50 -0
- package/src/components/input-group/index.ts +4 -0
- package/src/components/link/Link.tsx +148 -0
- package/src/components/link/index.ts +2 -0
- package/src/components/list/List.tsx +193 -0
- package/src/components/list/ListItem.tsx +91 -0
- package/src/components/list/index.ts +4 -0
- package/src/components/menu/Menu.tsx +398 -0
- package/src/components/menu/MenuDivider.tsx +19 -0
- package/src/components/menu/MenuHeader.tsx +55 -0
- package/src/components/menu/MenuItem.tsx +85 -0
- package/src/components/menu/MenuItemDef.ts +83 -0
- package/src/components/menu/MenuList.tsx +142 -0
- package/src/components/menu/MenuSubmenu.tsx +284 -0
- package/src/components/menu/MenuSubmenuBack.tsx +39 -0
- package/src/components/menu/MenuText.tsx +47 -0
- package/src/components/menu/MenuToggle.tsx +148 -0
- package/src/components/menu/index.ts +19 -0
- package/src/components/menu/menuNavigation.ts +106 -0
- package/src/components/menu/submenuGroup.ts +43 -0
- package/src/components/modal/Modal.tsx +162 -0
- package/src/components/modal/ModalBody.tsx +47 -0
- package/src/components/modal/ModalFooter.tsx +51 -0
- package/src/components/modal/ModalHeader.tsx +60 -0
- package/src/components/modal/ModalTitle.tsx +49 -0
- package/src/components/modal/index.ts +10 -0
- package/src/components/nav/Nav.tsx +97 -0
- package/src/components/nav/NavItem.tsx +42 -0
- package/src/components/nav/NavLink.tsx +48 -0
- package/src/components/nav/NavTitle.tsx +22 -0
- package/src/components/nav/index.ts +7 -0
- package/src/components/navbar/Navbar.tsx +112 -0
- package/src/components/navbar/NavbarBrand.tsx +55 -0
- package/src/components/navbar/NavbarNav.tsx +47 -0
- package/src/components/navbar/NavbarText.tsx +47 -0
- package/src/components/navbar/NavbarToggler.tsx +34 -0
- package/src/components/navbar/index.ts +10 -0
- package/src/components/notification/Notification.scss +15 -0
- package/src/components/notification/Notification.tsx +187 -0
- package/src/components/notification/NotificationIcon.tsx +21 -0
- package/src/components/notification/NotificationStack.tsx +66 -0
- package/src/components/notification/NotificationText.tsx +47 -0
- package/src/components/notification/NotificationTitle.tsx +47 -0
- package/src/components/notification/context.ts +14 -0
- package/src/components/notification/index.ts +17 -0
- package/src/components/notification/notificationQueue.ts +48 -0
- package/src/components/otp-input/OtpBox.tsx +68 -0
- package/src/components/otp-input/OtpInput.tsx +341 -0
- package/src/components/otp-input/index.ts +2 -0
- package/src/components/pagination/Pagination.tsx +199 -0
- package/src/components/pagination/PaginationItem.tsx +133 -0
- package/src/components/pagination/index.ts +4 -0
- package/src/components/password-strength/PasswordStrength.tsx +155 -0
- package/src/components/password-strength/index.ts +2 -0
- package/src/components/password-strength/strengthScore.ts +79 -0
- package/src/components/placeholder/Placeholder.tsx +178 -0
- package/src/components/placeholder/index.ts +2 -0
- package/src/components/popover/Popover.tsx +243 -0
- package/src/components/popover/index.ts +2 -0
- package/src/components/progress/Progress.tsx +154 -0
- package/src/components/progress/ProgressBar.tsx +88 -0
- package/src/components/progress/index.ts +4 -0
- package/src/components/radio/Radio.tsx +88 -0
- package/src/components/radio/RadioGroup.tsx +142 -0
- package/src/components/radio/context.ts +14 -0
- package/src/components/radio/index.ts +4 -0
- package/src/components/range-input/RangeInput.tsx +109 -0
- package/src/components/range-input/index.ts +2 -0
- package/src/components/select/Select.tsx +277 -0
- package/src/components/select/index.ts +2 -0
- package/src/components/skeleton/Skeleton.tsx +89 -0
- package/src/components/skeleton/SkeletonLoader.tsx +91 -0
- package/src/components/skeleton/index.ts +4 -0
- package/src/components/spinner/Spinner.tsx +77 -0
- package/src/components/spinner/index.ts +2 -0
- package/src/components/stack/Stack.tsx +81 -0
- package/src/components/stack/index.ts +2 -0
- package/src/components/stepper/Stepper.tsx +172 -0
- package/src/components/stepper/StepperItem.tsx +66 -0
- package/src/components/stepper/index.ts +4 -0
- package/src/components/switch/Switch.tsx +246 -0
- package/src/components/switch/index.ts +2 -0
- package/src/components/table/Table.css +39 -0
- package/src/components/table/Table.tsx +390 -0
- package/src/components/table/TableBody.tsx +25 -0
- package/src/components/table/TableCell.tsx +27 -0
- package/src/components/table/TableColumn.tsx +31 -0
- package/src/components/table/TableHeader.tsx +26 -0
- package/src/components/table/TableRow.tsx +24 -0
- package/src/components/table/index.ts +12 -0
- package/src/components/tabs/Tab.tsx +36 -0
- package/src/components/tabs/TabList.tsx +76 -0
- package/src/components/tabs/TabPanel.tsx +68 -0
- package/src/components/tabs/Tabs.tsx +136 -0
- package/src/components/tabs/context.ts +24 -0
- package/src/components/tabs/index.ts +8 -0
- package/src/components/text-input/TextInput.tsx +188 -0
- package/src/components/text-input/index.ts +2 -0
- package/src/components/textarea/Textarea.tsx +145 -0
- package/src/components/textarea/index.ts +2 -0
- package/src/components/toast/Toast.tsx +219 -0
- package/src/components/toast/ToastBody.tsx +64 -0
- package/src/components/toast/ToastFooter.tsx +47 -0
- package/src/components/toast/ToastHeader.tsx +104 -0
- package/src/components/toast/ToastIcon.tsx +21 -0
- package/src/components/toast/Toaster.tsx +87 -0
- package/src/components/toast/context.ts +14 -0
- package/src/components/toast/index.ts +18 -0
- package/src/components/toast/toastQueue.ts +56 -0
- package/src/components/tooltip/Tooltip.tsx +155 -0
- package/src/components/tooltip/index.ts +2 -0
- package/src/global.d.ts +2 -0
- package/src/hooks/index.ts +57 -0
- package/src/hooks/useAutoDismiss.ts +88 -0
- package/src/hooks/useButtonSemantics.ts +33 -0
- package/src/hooks/useControllableState.ts +24 -0
- package/src/hooks/useDialogElement.ts +216 -0
- package/src/hooks/useDisabledAnchorGuard.ts +22 -0
- package/src/hooks/useDismissibleTransition.ts +126 -0
- package/src/hooks/useDrawer.ts +9 -0
- package/src/hooks/useFloatingOverlay.ts +115 -0
- package/src/hooks/useForkedRef.ts +50 -0
- package/src/hooks/useFormField.ts +89 -0
- package/src/hooks/useIsomorphicLayoutEffect.ts +9 -0
- package/src/hooks/useModal.ts +9 -0
- package/src/hooks/useNotification.ts +10 -0
- package/src/hooks/useOverlayPlacement.ts +93 -0
- package/src/hooks/usePagination.ts +85 -0
- package/src/hooks/useToast.ts +9 -0
- package/src/hooks/useToastRegionQueue.ts +27 -0
- package/src/index.ts +276 -0
- package/src/types.ts +133 -0
- package/src/utils/breakpoints.ts +43 -0
- package/src/utils/comboboxCollection.tsx +152 -0
- package/src/utils/dateRangePresets.ts +6 -0
- package/src/utils/dialogTransition.ts +39 -0
- package/src/utils/focusRedirect.ts +29 -0
- package/src/utils/isWholeUnitDisabled.ts +17 -0
- package/src/utils/mergeIsDateUnavailable.ts +15 -0
- package/src/utils/overlayPlacement.ts +93 -0
- package/src/utils/pointerInteraction.ts +21 -0
- package/src/utils/polymorphic.ts +36 -0
- package/src/utils/renderMenuItemContent.tsx +62 -0
- package/src/utils/setVisibleRangeStart.ts +64 -0
- package/src/utils/spacingClassName.ts +14 -0
- package/src/utils/suppressFocusRingGlobally.ts +69 -0
- package/src/utils/validationClassName.ts +8 -0
- 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
|
+
|