@chassis-ui/react 0.0.0-20260831090525 → 0.1.1
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/README.md +11 -0
- package/dist/index.d.ts +682 -237
- package/dist/index.js +2 -2
- package/dist/style.css +1 -1
- package/package.json +53 -46
- package/src/components/accordion/Accordion.tsx +2 -2
- package/src/components/accordion/AccordionItem.tsx +6 -6
- package/src/components/autocomplete/Autocomplete.tsx +4 -4
- package/src/components/avatar/Avatar.tsx +5 -2
- package/src/components/breadcrumb/Breadcrumb.tsx +11 -2
- package/src/components/button/Button.tsx +7 -4
- package/src/components/button-group/ButtonGroup.tsx +2 -2
- package/src/components/calendar/Calendar.tsx +56 -42
- package/src/components/calendar/CalendarMonthGrid.tsx +3 -1
- package/src/components/calendar/CalendarMonthYearPicker.tsx +4 -2
- package/src/components/calendar/CalendarYearGrid.tsx +5 -3
- package/src/components/calendar/RangeCalendar.scss +8 -8
- package/src/components/calendar/RangeCalendar.tsx +56 -44
- package/src/components/calendar/index.ts +1 -0
- package/src/components/calendar/labels.tsx +71 -0
- package/src/components/card/Card.tsx +4 -4
- package/src/components/card/CardGroup.tsx +1 -1
- package/src/components/card/CardImage.tsx +1 -1
- package/src/components/carousel/Carousel.tsx +20 -9
- package/src/components/carousel/CarouselControlButton.tsx +1 -1
- package/src/components/carousel/CarouselPlayPause.tsx +1 -1
- package/src/components/carousel/carouselEngine.ts +3 -3
- package/src/components/checkbox/Checkbox.tsx +12 -11
- package/src/components/checkbox/CheckboxGroup.tsx +1 -1
- package/src/components/chip/Chip.tsx +5 -4
- package/src/components/chip-input/ChipInput.tsx +12 -4
- package/src/components/chip-input/ChipList.tsx +2 -2
- package/src/components/close-button/CloseButton.tsx +2 -2
- package/src/components/color-input/ColorInput.tsx +2 -2
- package/src/components/combobox/Combobox.tsx +2 -2
- package/src/components/datagrid/DataGrid.scss +203 -0
- package/src/components/datagrid/DataGrid.tsx +259 -0
- package/src/components/datagrid/DataGridBody.tsx +162 -0
- package/src/components/datagrid/DataGridCell.tsx +47 -0
- package/src/components/datagrid/DataGridColumn.tsx +109 -0
- package/src/components/datagrid/DataGridHeader.tsx +47 -0
- package/src/components/datagrid/DataGridPinBehavior.tsx +225 -0
- package/src/components/datagrid/DataGridRow.tsx +48 -0
- package/src/components/datagrid/DataGridSelectionCell.tsx +74 -0
- package/src/components/datagrid/DataGridTableLayout.ts +30 -0
- package/src/components/datagrid/index.ts +14 -0
- package/src/components/datagrid/useColumnGeometry.ts +161 -0
- package/src/components/datepicker/ClearButton.tsx +4 -1
- package/src/components/datepicker/DatePicker.scss +2 -2
- package/src/components/datepicker/DatePicker.tsx +179 -147
- package/src/components/datepicker/DateRangePicker.tsx +107 -89
- package/src/components/datepicker/renderDatePickerShell.tsx +1 -1
- package/src/components/drawer/Drawer.tsx +3 -1
- package/src/components/file-input/FileInput.tsx +2 -2
- package/src/components/floating-input/FloatingInput.tsx +8 -8
- package/src/components/form/renderFormCheck.tsx +3 -3
- package/src/components/form-field/FormField.tsx +8 -8
- package/src/components/form-field/renderFormField.tsx +14 -3
- package/src/components/grid/Col.tsx +1 -1
- package/src/components/grid/GridItem.tsx +1 -1
- package/src/components/grid/Row.tsx +1 -1
- package/src/components/input-group/InputGroup.tsx +2 -2
- package/src/components/list/List.tsx +5 -5
- package/src/components/menu/Menu.tsx +10 -0
- package/src/components/menu/MenuSubmenu.tsx +3 -3
- package/src/components/menu/MenuSubmenuBack.tsx +1 -1
- package/src/components/menu/MenuToggle.tsx +2 -2
- package/src/components/modal/Modal.tsx +5 -3
- package/src/components/navbar/Navbar.tsx +1 -1
- package/src/components/navbar/NavbarBrand.tsx +5 -2
- package/src/components/notification/NotificationStack.tsx +1 -1
- package/src/components/otp-input/OtpBox.tsx +1 -1
- package/src/components/otp-input/OtpInput.tsx +12 -11
- package/src/components/pagination/Pagination.tsx +2 -2
- package/src/components/pagination/PaginationItem.tsx +23 -4
- package/src/components/popover/Popover.tsx +40 -14
- package/src/components/progress/Progress.tsx +1 -1
- package/src/components/progress/ProgressBar.tsx +1 -1
- package/src/components/radio/Radio.tsx +2 -2
- package/src/components/radio/RadioGroup.tsx +1 -1
- package/src/components/select/Select.tsx +8 -8
- package/src/components/skeleton/Skeleton.tsx +1 -1
- package/src/components/spinner/Spinner.tsx +2 -2
- package/src/components/stepper/Stepper.tsx +5 -5
- package/src/components/switch/Switch.tsx +3 -3
- package/src/components/table/Table.css +2 -2
- package/src/components/table/Table.tsx +12 -6
- package/src/components/text-input/TextInput.tsx +2 -2
- package/src/components/textarea/Textarea.tsx +2 -2
- package/src/components/toast/ToastBody.tsx +1 -1
- package/src/components/toast/ToastHeader.tsx +2 -2
- package/src/components/toast/Toaster.tsx +1 -1
- package/src/components/tooltip/Tooltip.tsx +23 -7
- package/src/hooks/useAutoDismiss.ts +4 -1
- package/src/hooks/useDialogElement.ts +10 -0
- package/src/hooks/useFloatingOverlay.ts +12 -2
- package/src/hooks/usePagination.ts +6 -2
- package/src/index.ts +226 -0
- package/src/types.ts +26 -26
- package/src/utils/breakpoints.ts +1 -1
- package/src/utils/devWarning.ts +58 -0
- package/src/utils/direction.ts +14 -0
- package/src/utils/focusRedirect.ts +10 -16
- package/src/utils/polymorphic.ts +18 -1
- package/src/utils/suppressFocusRingGlobally.ts +22 -7
- package/src/utils/triggerElement.ts +25 -0
|
@@ -26,6 +26,7 @@ import { mergeIsDateUnavailable } from '../../utils/mergeIsDateUnavailable'
|
|
|
26
26
|
import { suppressFocusRing } from '../../utils/suppressFocusRingGlobally'
|
|
27
27
|
import './Calendar.scss'
|
|
28
28
|
import './RangeCalendar.scss'
|
|
29
|
+
import { CalendarLabels, CalendarLabelsProvider } from './labels'
|
|
29
30
|
|
|
30
31
|
export interface RangeCalendarProps extends Omit<
|
|
31
32
|
HTMLAttributes<HTMLDivElement>,
|
|
@@ -67,6 +68,14 @@ export interface RangeCalendarProps extends Omit<
|
|
|
67
68
|
* shown but cannot be selected.
|
|
68
69
|
*/
|
|
69
70
|
isDateUnavailable?: (date: DateValue) => boolean
|
|
71
|
+
/**
|
|
72
|
+
* Overrides for the handful of strings this component renders itself rather than getting from
|
|
73
|
+
* the active locale (the year view's paging arrows, its live-region announcements, and the
|
|
74
|
+
* month/year header buttons). Everything else — month and weekday names, the calendar system —
|
|
75
|
+
* follows `I18nProvider`'s locale via react-aria and needs no override. Merged over the English
|
|
76
|
+
* defaults, so passing one key leaves the rest alone.
|
|
77
|
+
*/
|
|
78
|
+
labels?: Partial<CalendarLabels>
|
|
70
79
|
/**
|
|
71
80
|
* The maximum allowed date that a user may select.
|
|
72
81
|
*/
|
|
@@ -97,7 +106,7 @@ export interface RangeCalendarProps extends Omit<
|
|
|
97
106
|
value?: RangeValue<DateValue> | null
|
|
98
107
|
/**
|
|
99
108
|
* Number of months to display side by side, sharing one selection. Wraps to multiple rows in
|
|
100
|
-
* a narrow container (e.g. a popover on a
|
|
109
|
+
* a narrow container (e.g. a popover on a sm screen) rather than overflowing — the wrap is
|
|
101
110
|
* driven by the calendar's own width, not the viewport, so it adapts correctly regardless of
|
|
102
111
|
* where the calendar is embedded.
|
|
103
112
|
*
|
|
@@ -122,6 +131,7 @@ export const RangeCalendar = forwardRef<HTMLDivElement, RangeCalendarProps>(
|
|
|
122
131
|
disabled,
|
|
123
132
|
firstDayOfWeek = 'mon',
|
|
124
133
|
isDateUnavailable,
|
|
134
|
+
labels,
|
|
125
135
|
maxValue,
|
|
126
136
|
minValue,
|
|
127
137
|
onChange,
|
|
@@ -205,53 +215,55 @@ export const RangeCalendar = forwardRef<HTMLDivElement, RangeCalendarProps>(
|
|
|
205
215
|
}
|
|
206
216
|
|
|
207
217
|
return (
|
|
208
|
-
<
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
<div className="datepicker-body">
|
|
223
|
-
{visibleMonths > 1 && !hasPickerView && (
|
|
224
|
-
<div className="datepicker-controls">
|
|
225
|
-
{prevButton}
|
|
226
|
-
{nextButton}
|
|
227
|
-
</div>
|
|
218
|
+
<CalendarLabelsProvider labels={labels}>
|
|
219
|
+
<div
|
|
220
|
+
{...mergeProps(calendarProps, rest)}
|
|
221
|
+
className={classNames('datepicker', className)}
|
|
222
|
+
data-cx-inline="true"
|
|
223
|
+
ref={ref}
|
|
224
|
+
>
|
|
225
|
+
<div className="datepicker-grid">
|
|
226
|
+
{resolvedPresets && (
|
|
227
|
+
<DateRangePresets
|
|
228
|
+
onSelect={handlePresetSelect}
|
|
229
|
+
presets={resolvedPresets}
|
|
230
|
+
value={state.value}
|
|
231
|
+
/>
|
|
228
232
|
)}
|
|
229
|
-
<div className="datepicker-
|
|
230
|
-
{
|
|
231
|
-
<
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
233
|
+
<div className="datepicker-body">
|
|
234
|
+
{visibleMonths > 1 && !hasPickerView && (
|
|
235
|
+
<div className="datepicker-controls">
|
|
236
|
+
{prevButton}
|
|
237
|
+
{nextButton}
|
|
238
|
+
</div>
|
|
239
|
+
)}
|
|
240
|
+
<div className="datepicker-grid">
|
|
241
|
+
{[...new Array(visibleMonths).keys()].map((monthIndex) => (
|
|
242
|
+
<CalendarMonthBlock
|
|
243
|
+
arrows={monthIndex === 0 ? singleMonthArrows : null}
|
|
244
|
+
firstDayOfWeek={firstDayOfWeek}
|
|
245
|
+
key={monthIndex}
|
|
246
|
+
monthIndex={monthIndex}
|
|
247
|
+
onViewChange={(view) =>
|
|
248
|
+
setMonthViews((prev) => ({ ...prev, [monthIndex]: view }))
|
|
249
|
+
}
|
|
250
|
+
renderCell={(date, i, week) => (
|
|
251
|
+
<CalendarCell
|
|
252
|
+
date={date}
|
|
253
|
+
isFirstInRow={i === 0}
|
|
254
|
+
isLastInRow={i === week.length - 1}
|
|
255
|
+
locale={locale}
|
|
256
|
+
state={state}
|
|
257
|
+
/>
|
|
258
|
+
)}
|
|
259
|
+
state={state}
|
|
260
|
+
/>
|
|
261
|
+
))}
|
|
262
|
+
</div>
|
|
251
263
|
</div>
|
|
252
264
|
</div>
|
|
253
265
|
</div>
|
|
254
|
-
</
|
|
266
|
+
</CalendarLabelsProvider>
|
|
255
267
|
)
|
|
256
268
|
}
|
|
257
269
|
)
|
|
@@ -2,4 +2,5 @@ export { Calendar } from './Calendar'
|
|
|
2
2
|
export type { CalendarProps, CalendarSingleProps, CalendarMultipleProps } from './Calendar'
|
|
3
3
|
export { RangeCalendar } from './RangeCalendar'
|
|
4
4
|
export type { RangeCalendarProps } from './RangeCalendar'
|
|
5
|
+
export type { CalendarLabels } from './labels'
|
|
5
6
|
export type { DateRangePreset } from '../../utils/dateRangePresets'
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import React, { createContext, ReactNode, useContext, useMemo } from 'react'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The user-facing strings the calendar/datepicker family renders itself, rather than getting from
|
|
5
|
+
* the active locale.
|
|
6
|
+
*
|
|
7
|
+
* Everything else these components say — weekday names, month names, the calendar system, segment
|
|
8
|
+
* order — comes from `I18nProvider`'s locale via react-aria, which ships its own translations. The
|
|
9
|
+
* strings below have no equivalent in react-aria's dictionaries, so they were hardcoded English
|
|
10
|
+
* with no way to override them: under `<I18nProvider locale="ar-SA">` a user got Arabic month
|
|
11
|
+
* names interleaved with an English "Previous years". Pass `labels` to translate them, the same
|
|
12
|
+
* way `Pagination`'s `previousLabel`/`nextLabel` are translated (see the Internationalization
|
|
13
|
+
* docs page).
|
|
14
|
+
*/
|
|
15
|
+
export interface CalendarLabels {
|
|
16
|
+
/** Accessible name of the year view's "page back" arrow. */
|
|
17
|
+
previousYears: string
|
|
18
|
+
/** Accessible name of the year view's "page forward" arrow. */
|
|
19
|
+
nextYears: string
|
|
20
|
+
/** Prefix of the year view's live-region announcement, rendered as `${selectYear}, 2020 – 2034`. */
|
|
21
|
+
selectYear: string
|
|
22
|
+
/** Prefix of the month view's live-region announcement, rendered as `${selectMonth}, 2024`. */
|
|
23
|
+
selectMonth: string
|
|
24
|
+
/** Prefix of the header month button's accessible name, rendered as `${month}: March`. */
|
|
25
|
+
month: string
|
|
26
|
+
/** Prefix of the header year button's accessible name, rendered as `${year}: 2024`. */
|
|
27
|
+
year: string
|
|
28
|
+
/** Accessible name of the trigger that opens the calendar overlay. */
|
|
29
|
+
calendar: string
|
|
30
|
+
/** Accessible name of the adornment that resets the current selection. */
|
|
31
|
+
clear: string
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const DEFAULT_CALENDAR_LABELS: CalendarLabels = {
|
|
35
|
+
previousYears: 'Previous years',
|
|
36
|
+
nextYears: 'Next years',
|
|
37
|
+
selectYear: 'Select year',
|
|
38
|
+
selectMonth: 'Select month',
|
|
39
|
+
month: 'Month',
|
|
40
|
+
year: 'Year',
|
|
41
|
+
calendar: 'Calendar',
|
|
42
|
+
clear: 'Clear'
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const CalendarLabelsContext = createContext<CalendarLabels>(DEFAULT_CALENDAR_LABELS)
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Reads the merged labels. Internal — every component in this family that renders one of these
|
|
49
|
+
* strings goes through here rather than taking its own prop, because most of them
|
|
50
|
+
* (`CalendarYearGrid`, `CalendarMonthGrid`, `CalendarMonthYearPicker`) sit three or four levels
|
|
51
|
+
* below the public component a consumer actually passes `labels` to.
|
|
52
|
+
*/
|
|
53
|
+
export const useCalendarLabels = (): CalendarLabels => useContext(CalendarLabelsContext)
|
|
54
|
+
|
|
55
|
+
interface CalendarLabelsProviderProps {
|
|
56
|
+
children: ReactNode
|
|
57
|
+
labels?: Partial<CalendarLabels>
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Merges `labels` over whatever is already in context, rather than replacing it. `DatePicker`
|
|
62
|
+
* renders a `Calendar` internally, so both provide — without merging, the inner `Calendar`
|
|
63
|
+
* (which usually has no `labels` of its own) would reset the outer `DatePicker`'s overrides back
|
|
64
|
+
* to English.
|
|
65
|
+
*/
|
|
66
|
+
export const CalendarLabelsProvider = ({ children, labels }: CalendarLabelsProviderProps) => {
|
|
67
|
+
const parent = useContext(CalendarLabelsContext)
|
|
68
|
+
const value = useMemo(() => (labels ? { ...parent, ...labels } : parent), [parent, labels])
|
|
69
|
+
|
|
70
|
+
return <CalendarLabelsContext.Provider value={value}>{children}</CalendarLabelsContext.Provider>
|
|
71
|
+
}
|
|
@@ -59,8 +59,8 @@ type CardOwnProps<C extends ElementType> = {
|
|
|
59
59
|
*/
|
|
60
60
|
imageOrientation?: 'top' | 'bottom'
|
|
61
61
|
/**
|
|
62
|
-
* Overrides `direction` at one or more breakpoints — e.g. `{
|
|
63
|
-
* out horizontally from `
|
|
62
|
+
* Overrides `direction` at one or more breakpoints — e.g. `{ lg: 'row' }` to lay the card
|
|
63
|
+
* out horizontally from `lg` up while stacking below it.
|
|
64
64
|
*/
|
|
65
65
|
responsive?: Partial<Record<Breakpoint, FlexDirection>>
|
|
66
66
|
/**
|
|
@@ -127,8 +127,8 @@ function CardRender<C extends ElementType = 'div'>(
|
|
|
127
127
|
solid: variant === 'solid',
|
|
128
128
|
smooth: variant === 'smooth',
|
|
129
129
|
outline: variant === 'outline',
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
sm: size === 'sm',
|
|
131
|
+
lg: size === 'lg'
|
|
132
132
|
},
|
|
133
133
|
buildResponsiveClassNames(flexDirectionClassNames, direction, responsive),
|
|
134
134
|
className
|
|
@@ -28,7 +28,7 @@ type CardGroupComponent = (<C extends ElementType = 'div'>(
|
|
|
28
28
|
) => ReactElement | null) & { displayName?: string }
|
|
29
29
|
|
|
30
30
|
// Arranges direct-child Cards as an equal-width row, joined edge-to-edge, once its container
|
|
31
|
-
// reaches the
|
|
31
|
+
// reaches the sm container breakpoint — below that, cards stack vertically. Requires a
|
|
32
32
|
// `.contains-inline` ancestor (not applied by CardGroup itself, e.g. a wrapping
|
|
33
33
|
// `<div className="contains-inline">`) to establish the container query context.
|
|
34
34
|
function CardGroupRender<C extends ElementType = 'div'>(
|
|
@@ -28,7 +28,7 @@ type CardImageOwnProps<C extends ElementType> = {
|
|
|
28
28
|
*/
|
|
29
29
|
orientation?: CardImageOrientation
|
|
30
30
|
/**
|
|
31
|
-
* Overrides `orientation` at one or more breakpoints — e.g. `{
|
|
31
|
+
* Overrides `orientation` at one or more breakpoints — e.g. `{ lg: 'start' }` to switch an
|
|
32
32
|
* image cap from `top` to `start` once the card lays out horizontally.
|
|
33
33
|
*/
|
|
34
34
|
responsive?: Partial<Record<Breakpoint, CardImageOrientation>>
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
prefersReducedMotion,
|
|
27
27
|
scrollDeltaFor
|
|
28
28
|
} from './carouselEngine'
|
|
29
|
+
import { devWarning } from '../../utils/devWarning'
|
|
29
30
|
|
|
30
31
|
export type { CarouselEnds }
|
|
31
32
|
export type CarouselTransition = 'scroll' | 'fade'
|
|
@@ -131,6 +132,9 @@ export const Carousel = forwardRef<HTMLDivElement, CarouselProps>(
|
|
|
131
132
|
itemsGap,
|
|
132
133
|
itemsPeek,
|
|
133
134
|
keyboard = true,
|
|
135
|
+
onKeyDown,
|
|
136
|
+
onMouseEnter,
|
|
137
|
+
onMouseLeave,
|
|
134
138
|
onSlid,
|
|
135
139
|
onSlide,
|
|
136
140
|
pause = 'hover',
|
|
@@ -145,13 +149,12 @@ export const Carousel = forwardRef<HTMLDivElement, CarouselProps>(
|
|
|
145
149
|
// "Controlled usage" section). Missing both means every click/swipe/autoplay advance updates
|
|
146
150
|
// internal state that `useControllableState` immediately discards (controlled mode always
|
|
147
151
|
// mirrors the prop), so the carousel silently freezes instead of erroring.
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
152
|
+
devWarning(
|
|
153
|
+
activeIndexProp !== undefined && !onSlide && !onSlid,
|
|
154
|
+
'Carousel: `activeIndex` is set (controlled) but neither `onSlide` nor `onSlid` is — ' +
|
|
155
|
+
'nothing feeds the new index back to your state, so the carousel will visually freeze ' +
|
|
156
|
+
'on click/swipe/autoplay. Pass `onSlide` or `onSlid` and update `activeIndex` from it.'
|
|
157
|
+
)
|
|
155
158
|
|
|
156
159
|
const carouselRef = useRef<HTMLDivElement>(null)
|
|
157
160
|
const forkedRef = useForkedRef(ref, carouselRef)
|
|
@@ -655,7 +658,13 @@ export const Carousel = forwardRef<HTMLDivElement, CarouselProps>(
|
|
|
655
658
|
}
|
|
656
659
|
}, [])
|
|
657
660
|
|
|
661
|
+
// Compose rather than let a caller's handler silently replace the carousel's own — same rule
|
|
662
|
+
// `CarouselControlButton`/`CarouselPlayPause` follow for `onClick`. These three sit on the
|
|
663
|
+
// root element, so before this they were simply overwritten by the `{...rest}` spread below:
|
|
664
|
+
// passing `onKeyDown` turned off arrow-key navigation and passing `onMouseEnter`/
|
|
665
|
+
// `onMouseLeave` turned off pause-on-hover, both silently.
|
|
658
666
|
const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
|
|
667
|
+
onKeyDown?.(event)
|
|
659
668
|
if (!keyboard) return
|
|
660
669
|
const target = event.target as HTMLElement
|
|
661
670
|
if (target.closest('input, textarea, select, [contenteditable="true"]')) return
|
|
@@ -667,11 +676,13 @@ export const Carousel = forwardRef<HTMLDivElement, CarouselProps>(
|
|
|
667
676
|
else goNext()
|
|
668
677
|
}
|
|
669
678
|
|
|
670
|
-
const handleMouseEnter = () => {
|
|
679
|
+
const handleMouseEnter = (event: React.MouseEvent<HTMLDivElement>) => {
|
|
680
|
+
onMouseEnter?.(event)
|
|
671
681
|
if (pause === 'hover') pauseCycle()
|
|
672
682
|
}
|
|
673
683
|
|
|
674
|
-
const handleMouseLeave = () => {
|
|
684
|
+
const handleMouseLeave = (event: React.MouseEvent<HTMLDivElement>) => {
|
|
685
|
+
onMouseLeave?.(event)
|
|
675
686
|
if (pause === 'hover' && playing) startCycle()
|
|
676
687
|
}
|
|
677
688
|
|
|
@@ -51,7 +51,7 @@ export const CarouselControlButton = forwardRef<HTMLButtonElement, CarouselContr
|
|
|
51
51
|
return (
|
|
52
52
|
<button
|
|
53
53
|
type="button"
|
|
54
|
-
className={classNames('button
|
|
54
|
+
className={classNames('button sm icon-only', className)}
|
|
55
55
|
disabled={isDisabled}
|
|
56
56
|
onClick={handleClick}
|
|
57
57
|
{...rest}
|
|
@@ -28,7 +28,7 @@ export const CarouselPlayPause = forwardRef<HTMLButtonElement, CarouselPlayPause
|
|
|
28
28
|
({ children, className, onClick, pauseLabel = 'Pause', playLabel = 'Play', ...rest }, ref) => {
|
|
29
29
|
const { playing, togglePlayPause } = useCarouselContext()
|
|
30
30
|
const _className = classNames(
|
|
31
|
-
'carousel-control-play-pause button
|
|
31
|
+
'carousel-control-play-pause button sm icon-only',
|
|
32
32
|
{ paused: !playing },
|
|
33
33
|
className
|
|
34
34
|
)
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
// Internal helpers shared by the carousel family. Not exported from the component's public
|
|
2
2
|
// barrel (see CONVENTIONS.md's helper-module carve-out).
|
|
3
3
|
|
|
4
|
+
import { isRTL } from '../../utils/direction'
|
|
5
|
+
|
|
4
6
|
export const ITEM_SELECTOR = '.carousel-item:not(.carousel-item-clone)'
|
|
5
7
|
|
|
6
8
|
export function getCarouselItems(viewport: HTMLElement): HTMLElement[] {
|
|
7
9
|
return Array.from(viewport.querySelectorAll<HTMLElement>(`:scope > ${ITEM_SELECTOR}`))
|
|
8
10
|
}
|
|
9
11
|
|
|
10
|
-
export
|
|
11
|
-
return getComputedStyle(element).direction === 'rtl'
|
|
12
|
-
}
|
|
12
|
+
export { isRTL }
|
|
13
13
|
|
|
14
14
|
export function prefersReducedMotion(): boolean {
|
|
15
15
|
return (
|
|
@@ -21,6 +21,7 @@ import { validationClassName } from '../../utils/validationClassName'
|
|
|
21
21
|
|
|
22
22
|
import { CheckboxGroupContext } from './context'
|
|
23
23
|
import { ButtonObject, renderFormCheck } from '../form/renderFormCheck'
|
|
24
|
+
import { devError, devWarning } from '../../utils/devWarning'
|
|
24
25
|
|
|
25
26
|
export type { ButtonObject } from '../form/renderFormCheck'
|
|
26
27
|
|
|
@@ -72,9 +73,9 @@ export interface CheckboxProps extends Omit<
|
|
|
72
73
|
*/
|
|
73
74
|
onChange?: (isSelected: boolean) => void
|
|
74
75
|
/**
|
|
75
|
-
* Size the component
|
|
76
|
+
* Size the component sm or lg.
|
|
76
77
|
*/
|
|
77
|
-
size?: '
|
|
78
|
+
size?: 'sm' | 'lg'
|
|
78
79
|
/**
|
|
79
80
|
* Set component validation state to valid.
|
|
80
81
|
*/
|
|
@@ -183,15 +184,15 @@ const CheckboxGroupItem = forwardRef<HTMLInputElement, CheckboxGroupItemProps>(
|
|
|
183
184
|
// Once per mount, not on every render — these are dev-time misuse warnings, not something
|
|
184
185
|
// that needs to re-fire for every keystroke a parent's re-render happens to cause.
|
|
185
186
|
useEffect(() => {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
187
|
+
devError(
|
|
188
|
+
!rest.value,
|
|
189
|
+
'Checkbox: a `value` prop is required when rendered inside a CheckboxGroup.'
|
|
190
|
+
)
|
|
191
|
+
devWarning(
|
|
192
|
+
_defaultSelected !== undefined || _isSelected !== undefined || _onChange !== undefined,
|
|
193
|
+
'Checkbox: `defaultSelected`, `isSelected`, and `onChange` are ignored inside a ' +
|
|
194
|
+
"CheckboxGroup — selection is owned by the group's `value`/`defaultValue`/`onChange`."
|
|
195
|
+
)
|
|
195
196
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
196
197
|
}, [])
|
|
197
198
|
|
|
@@ -130,7 +130,7 @@ export const CheckboxGroup = forwardRef<HTMLFieldSetElement, CheckboxGroupProps>
|
|
|
130
130
|
{label}
|
|
131
131
|
</legend>
|
|
132
132
|
)}
|
|
133
|
-
{orientation === 'horizontal' ? <Flex gap="
|
|
133
|
+
{orientation === 'horizontal' ? <Flex gap="md">{items}</Flex> : items}
|
|
134
134
|
{description && <FormHelp {...descriptionProps}>{description}</FormHelp>}
|
|
135
135
|
{invalid && errorMessage && (
|
|
136
136
|
<FormFeedback invalid {...errorMessageProps}>
|
|
@@ -13,7 +13,8 @@ import { useButtonSemantics, useDisabledAnchorGuard } from '../../hooks'
|
|
|
13
13
|
import {
|
|
14
14
|
createPolymorphicComponent,
|
|
15
15
|
PolymorphicComponentProps,
|
|
16
|
-
PolymorphicRef
|
|
16
|
+
PolymorphicRef,
|
|
17
|
+
PolymorphicRefWithFallback
|
|
17
18
|
} from '../../utils/polymorphic'
|
|
18
19
|
|
|
19
20
|
type ChipOwnProps<C extends ElementType> = {
|
|
@@ -51,9 +52,9 @@ type ChipOwnProps<C extends ElementType> = {
|
|
|
51
52
|
*/
|
|
52
53
|
pressed?: boolean
|
|
53
54
|
/**
|
|
54
|
-
* Size the component
|
|
55
|
+
* Size the component sm or lg.
|
|
55
56
|
*/
|
|
56
|
-
size?: '
|
|
57
|
+
size?: 'sm' | 'lg'
|
|
57
58
|
/**
|
|
58
59
|
* Specifies the type of button. Only applies when `component` is `button`. Different browsers
|
|
59
60
|
* may use different default types for the `<button>` element, so always specify it explicitly.
|
|
@@ -71,7 +72,7 @@ export type ChipProps<C extends ElementType = 'span'> = PolymorphicComponentProp
|
|
|
71
72
|
>
|
|
72
73
|
|
|
73
74
|
type ChipComponent = (<C extends ElementType = 'span'>(
|
|
74
|
-
props: ChipProps<C> & { ref?:
|
|
75
|
+
props: ChipProps<C> & { ref?: PolymorphicRefWithFallback<C, HTMLSpanElement | HTMLAnchorElement> }
|
|
75
76
|
) => ReactElement | null) & { displayName?: string }
|
|
76
77
|
|
|
77
78
|
function ChipRender<C extends ElementType = 'span'>(
|
|
@@ -15,6 +15,7 @@ import { useControllableState, useForkedRef, useFormField } from '../../hooks'
|
|
|
15
15
|
import { validationClassName } from '../../utils/validationClassName'
|
|
16
16
|
import { renderFormField } from '../form-field/renderFormField'
|
|
17
17
|
import { ChipList, ChipItem } from './ChipList'
|
|
18
|
+
import { isRTL } from '../../utils/direction'
|
|
18
19
|
|
|
19
20
|
// `allowDuplicates` means two tags can share a value, but react-stately's collection needs a
|
|
20
21
|
// unique key per item — keying on the value alone collapses duplicates into the same node, so
|
|
@@ -106,9 +107,9 @@ export interface ChipInputProps extends Omit<
|
|
|
106
107
|
*/
|
|
107
108
|
separator?: string | null
|
|
108
109
|
/**
|
|
109
|
-
* Size the component
|
|
110
|
+
* Size the component sm or lg.
|
|
110
111
|
*/
|
|
111
|
-
size?: '
|
|
112
|
+
size?: 'sm' | 'lg'
|
|
112
113
|
/**
|
|
113
114
|
* Set component validation state to valid.
|
|
114
115
|
*/
|
|
@@ -237,9 +238,16 @@ export const ChipInput = forwardRef<HTMLDivElement, ChipInputProps>(
|
|
|
237
238
|
}
|
|
238
239
|
break
|
|
239
240
|
}
|
|
240
|
-
|
|
241
|
+
// Stepping backwards out of the text field and into the chips is a *visual* movement, so
|
|
242
|
+
// the key that does it mirrors under RTL — ArrowLeft in an LTR field, ArrowRight in an RTL
|
|
243
|
+
// one, matching where the chips actually sit relative to the caret. The caret check is
|
|
244
|
+
// unchanged: `selectionStart === 0` is the start of the text in either direction.
|
|
245
|
+
case 'ArrowLeft':
|
|
246
|
+
case 'ArrowRight': {
|
|
241
247
|
const input = inputRef.current
|
|
242
|
-
if (input
|
|
248
|
+
if (!input) break
|
|
249
|
+
const movesBackward = (event.key === 'ArrowLeft') !== isRTL(input)
|
|
250
|
+
if (movesBackward && input.selectionStart === 0 && input.selectionEnd === 0) {
|
|
243
251
|
event.preventDefault()
|
|
244
252
|
focusLastChip(event.shiftKey)
|
|
245
253
|
}
|
|
@@ -18,7 +18,7 @@ interface ChipListProps {
|
|
|
18
18
|
disabled?: boolean
|
|
19
19
|
groupRef: RefObject<HTMLDivElement | null>
|
|
20
20
|
props: AriaTagGroupOptions<ChipItem>
|
|
21
|
-
size?: '
|
|
21
|
+
size?: 'sm' | 'lg'
|
|
22
22
|
state: ListState<ChipItem>
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -52,7 +52,7 @@ interface ChipRowProps {
|
|
|
52
52
|
chipVariant?: string
|
|
53
53
|
disabled?: boolean
|
|
54
54
|
item: Node<ChipItem>
|
|
55
|
-
size?: '
|
|
55
|
+
size?: 'sm' | 'lg'
|
|
56
56
|
state: ListState<ChipItem>
|
|
57
57
|
}
|
|
58
58
|
|
|
@@ -55,9 +55,9 @@ type CloseButtonOwnProps<C extends ElementType> = {
|
|
|
55
55
|
*/
|
|
56
56
|
onClick?: MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>
|
|
57
57
|
/**
|
|
58
|
-
* Size the component
|
|
58
|
+
* Size the component sm or lg.
|
|
59
59
|
*/
|
|
60
|
-
size?: '
|
|
60
|
+
size?: 'sm' | 'lg'
|
|
61
61
|
/**
|
|
62
62
|
* Specifies the type of button. Always specify the type attribute for the `<button>` element.
|
|
63
63
|
* Different browsers may use different default types for the `<button>` element.
|
|
@@ -39,9 +39,9 @@ export interface ColorInputProps extends Omit<InputHTMLAttributes<HTMLInputEleme
|
|
|
39
39
|
*/
|
|
40
40
|
onChange?: ChangeEventHandler<HTMLInputElement>
|
|
41
41
|
/**
|
|
42
|
-
* Size the component
|
|
42
|
+
* Size the component sm or lg.
|
|
43
43
|
*/
|
|
44
|
-
size?: '
|
|
44
|
+
size?: 'sm' | 'lg'
|
|
45
45
|
/**
|
|
46
46
|
* Set component validation state to valid.
|
|
47
47
|
*/
|
|
@@ -108,9 +108,9 @@ export interface ComboboxProps extends Omit<
|
|
|
108
108
|
*/
|
|
109
109
|
placeholder?: string
|
|
110
110
|
/**
|
|
111
|
-
* Size the component
|
|
111
|
+
* Size the component sm or lg.
|
|
112
112
|
*/
|
|
113
|
-
size?: '
|
|
113
|
+
size?: 'sm' | 'lg'
|
|
114
114
|
/**
|
|
115
115
|
* Set component validation state to valid.
|
|
116
116
|
*/
|