react-aria-components 1.0.0-beta.0 → 1.0.0-beta.2
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/dist/import.mjs +1160 -855
- package/dist/main.js +1181 -852
- package/dist/main.js.map +1 -1
- package/dist/module.js +1160 -855
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +180 -226
- package/dist/types.d.ts.map +1 -1
- package/package.json +12 -12
- package/src/Breadcrumbs.tsx +2 -2
- package/src/Button.tsx +1 -1
- package/src/Calendar.tsx +15 -8
- package/src/Checkbox.tsx +5 -5
- package/src/Collection.tsx +14 -7
- package/src/ComboBox.tsx +19 -12
- package/src/DateField.tsx +95 -49
- package/src/DatePicker.tsx +34 -64
- package/src/Dialog.tsx +15 -15
- package/src/DropZone.tsx +6 -3
- package/src/FileTrigger.tsx +11 -10
- package/src/GridList.tsx +9 -13
- package/src/Group.tsx +36 -6
- package/src/Link.tsx +17 -24
- package/src/ListBox.tsx +31 -39
- package/src/Menu.tsx +17 -15
- package/src/Meter.tsx +1 -1
- package/src/Modal.tsx +14 -13
- package/src/NumberField.tsx +5 -3
- package/src/OverlayArrow.tsx +7 -10
- package/src/Popover.tsx +7 -11
- package/src/ProgressBar.tsx +1 -1
- package/src/RadioGroup.tsx +6 -6
- package/src/SearchField.tsx +3 -3
- package/src/Select.tsx +28 -23
- package/src/Separator.tsx +1 -1
- package/src/Slider.tsx +24 -23
- package/src/Switch.tsx +3 -3
- package/src/Table.tsx +30 -30
- package/src/Tabs.tsx +24 -31
- package/src/TagGroup.tsx +18 -21
- package/src/TextField.tsx +3 -3
- package/src/ToggleButton.tsx +1 -1
- package/src/Tooltip.tsx +33 -27
- package/src/index.ts +18 -18
- package/src/useDragAndDrop.tsx +8 -0
- package/src/utils.tsx +37 -10
package/src/DateField.tsx
CHANGED
|
@@ -10,12 +10,14 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
import {AriaDateFieldProps, AriaTimeFieldProps, DateValue, mergeProps, TimeValue, useDateField, useDateSegment, useFocusRing, useHover, useLocale, useTimeField} from 'react-aria';
|
|
13
|
-
import {ContextValue, forwardRefType, Provider, RenderProps, SlotProps, StyleRenderProps, useContextProps, useRenderProps, useSlot} from './utils';
|
|
13
|
+
import {ContextValue, forwardRefType, Provider, removeDataAttributes, RenderProps, SlotProps, StyleRenderProps, useContextProps, useRenderProps, useSlot} from './utils';
|
|
14
14
|
import {createCalendar} from '@internationalized/date';
|
|
15
|
-
import {DateFieldState, DateSegmentType, DateSegment as IDateSegment, useDateFieldState, useTimeFieldState} from 'react-stately';
|
|
15
|
+
import {DateFieldState, DateSegmentType, DateSegment as IDateSegment, TimeFieldState, useDateFieldState, useTimeFieldState} from 'react-stately';
|
|
16
16
|
import {filterDOMProps, useObjectRef} from '@react-aria/utils';
|
|
17
|
+
import {Group, GroupContext} from './Group';
|
|
18
|
+
import {Input, InputContext} from './Input';
|
|
17
19
|
import {LabelContext} from './Label';
|
|
18
|
-
import React, {cloneElement, createContext, ForwardedRef, forwardRef,
|
|
20
|
+
import React, {cloneElement, createContext, ForwardedRef, forwardRef, ReactElement, useContext, useRef} from 'react';
|
|
19
21
|
import {TextContext} from './Text';
|
|
20
22
|
|
|
21
23
|
export interface DateFieldRenderProps {
|
|
@@ -37,16 +39,10 @@ export interface DateFieldRenderProps {
|
|
|
37
39
|
export interface DateFieldProps<T extends DateValue> extends Omit<AriaDateFieldProps<T>, 'label' | 'description' | 'errorMessage' | 'validationState'>, RenderProps<DateFieldRenderProps>, SlotProps {}
|
|
38
40
|
export interface TimeFieldProps<T extends TimeValue> extends Omit<AriaTimeFieldProps<T>, 'label' | 'description' | 'errorMessage' | 'validationState'>, RenderProps<DateFieldRenderProps>, SlotProps {}
|
|
39
41
|
|
|
40
|
-
interface DateInputContextValue extends SlotProps {
|
|
41
|
-
state: DateFieldState,
|
|
42
|
-
fieldProps: HTMLAttributes<HTMLElement>,
|
|
43
|
-
inputProps: InputHTMLAttributes<HTMLInputElement>,
|
|
44
|
-
inputRef: RefObject<HTMLInputElement>
|
|
45
|
-
}
|
|
46
|
-
|
|
47
42
|
export const DateFieldContext = createContext<ContextValue<DateFieldProps<any>, HTMLDivElement>>(null);
|
|
48
43
|
export const TimeFieldContext = createContext<ContextValue<TimeFieldProps<any>, HTMLDivElement>>(null);
|
|
49
|
-
export const
|
|
44
|
+
export const DateFieldStateContext = createContext<DateFieldState | null>(null);
|
|
45
|
+
export const TimeFieldStateContext = createContext<TimeFieldState | null>(null);
|
|
50
46
|
|
|
51
47
|
function DateField<T extends DateValue>(props: DateFieldProps<T>, ref: ForwardedRef<HTMLDivElement>) {
|
|
52
48
|
[props, ref] = useContextProps(props, ref, DateFieldContext);
|
|
@@ -60,10 +56,10 @@ function DateField<T extends DateValue>(props: DateFieldProps<T>, ref: Forwarded
|
|
|
60
56
|
let fieldRef = useRef<HTMLDivElement>(null);
|
|
61
57
|
let [labelRef, label] = useSlot();
|
|
62
58
|
let inputRef = useRef<HTMLInputElement>(null);
|
|
63
|
-
let {labelProps, fieldProps, inputProps, descriptionProps, errorMessageProps} = useDateField({...props, label, inputRef}, state, fieldRef);
|
|
59
|
+
let {labelProps, fieldProps, inputProps, descriptionProps, errorMessageProps} = useDateField({...removeDataAttributes(props), label, inputRef}, state, fieldRef);
|
|
64
60
|
|
|
65
61
|
let renderProps = useRenderProps({
|
|
66
|
-
...props,
|
|
62
|
+
...removeDataAttributes(props),
|
|
67
63
|
values: {
|
|
68
64
|
state,
|
|
69
65
|
isInvalid: state.isInvalid,
|
|
@@ -78,7 +74,9 @@ function DateField<T extends DateValue>(props: DateFieldProps<T>, ref: Forwarded
|
|
|
78
74
|
return (
|
|
79
75
|
<Provider
|
|
80
76
|
values={[
|
|
81
|
-
[
|
|
77
|
+
[DateFieldStateContext, state],
|
|
78
|
+
[GroupContext, {...fieldProps, ref: fieldRef}],
|
|
79
|
+
[InputContext, {...inputProps, ref: inputRef}],
|
|
82
80
|
[LabelContext, {...labelProps, ref: labelRef, elementType: 'span'}],
|
|
83
81
|
[TextContext, {
|
|
84
82
|
slots: {
|
|
@@ -91,7 +89,7 @@ function DateField<T extends DateValue>(props: DateFieldProps<T>, ref: Forwarded
|
|
|
91
89
|
{...DOMProps}
|
|
92
90
|
{...renderProps}
|
|
93
91
|
ref={ref}
|
|
94
|
-
slot={props.slot}
|
|
92
|
+
slot={props.slot || undefined}
|
|
95
93
|
data-invalid={state.isInvalid || undefined} />
|
|
96
94
|
</Provider>
|
|
97
95
|
);
|
|
@@ -115,7 +113,7 @@ function TimeField<T extends TimeValue>(props: TimeFieldProps<T>, ref: Forwarded
|
|
|
115
113
|
let fieldRef = useRef<HTMLDivElement>(null);
|
|
116
114
|
let [labelRef, label] = useSlot();
|
|
117
115
|
let inputRef = useRef<HTMLInputElement>(null);
|
|
118
|
-
let {labelProps, fieldProps, inputProps, descriptionProps, errorMessageProps} = useTimeField({...props, label, inputRef}, state, fieldRef);
|
|
116
|
+
let {labelProps, fieldProps, inputProps, descriptionProps, errorMessageProps} = useTimeField({...removeDataAttributes(props), label, inputRef}, state, fieldRef);
|
|
119
117
|
|
|
120
118
|
let renderProps = useRenderProps({
|
|
121
119
|
...props,
|
|
@@ -133,7 +131,9 @@ function TimeField<T extends TimeValue>(props: TimeFieldProps<T>, ref: Forwarded
|
|
|
133
131
|
return (
|
|
134
132
|
<Provider
|
|
135
133
|
values={[
|
|
136
|
-
[
|
|
134
|
+
[TimeFieldStateContext, state],
|
|
135
|
+
[GroupContext, {...fieldProps, ref: fieldRef}],
|
|
136
|
+
[InputContext, {...inputProps, ref: inputRef}],
|
|
137
137
|
[LabelContext, {...labelProps, ref: labelRef, elementType: 'span'}],
|
|
138
138
|
[TextContext, {
|
|
139
139
|
slots: {
|
|
@@ -146,7 +146,7 @@ function TimeField<T extends TimeValue>(props: TimeFieldProps<T>, ref: Forwarded
|
|
|
146
146
|
{...DOMProps}
|
|
147
147
|
{...renderProps}
|
|
148
148
|
ref={ref}
|
|
149
|
-
slot={props.slot}
|
|
149
|
+
slot={props.slot || undefined}
|
|
150
150
|
data-invalid={state.isInvalid || undefined} />
|
|
151
151
|
</Provider>
|
|
152
152
|
);
|
|
@@ -159,8 +159,6 @@ function TimeField<T extends TimeValue>(props: TimeFieldProps<T>, ref: Forwarded
|
|
|
159
159
|
const _TimeField = /*#__PURE__*/ (forwardRef as forwardRefType)(TimeField);
|
|
160
160
|
export {_TimeField as TimeField};
|
|
161
161
|
|
|
162
|
-
const InternalDateInputContext = createContext<DateFieldState| null>(null);
|
|
163
|
-
|
|
164
162
|
export interface DateInputRenderProps {
|
|
165
163
|
/**
|
|
166
164
|
* Whether the date input is currently hovered with a mouse.
|
|
@@ -188,38 +186,60 @@ export interface DateInputProps extends SlotProps, StyleRenderProps<DateInputRen
|
|
|
188
186
|
children: (segment: IDateSegment) => ReactElement
|
|
189
187
|
}
|
|
190
188
|
|
|
191
|
-
function DateInput(
|
|
192
|
-
|
|
189
|
+
function DateInput(props: DateInputProps, ref: ForwardedRef<HTMLDivElement>): JSX.Element {
|
|
190
|
+
// If state is provided by DateField/TimeField, just render.
|
|
191
|
+
// Otherwise (e.g. in DatePicker), we need to call hooks and create state ourselves.
|
|
192
|
+
let dateFieldState = useContext(DateFieldStateContext);
|
|
193
|
+
let timeFieldState = useContext(TimeFieldStateContext);
|
|
194
|
+
return dateFieldState || timeFieldState
|
|
195
|
+
? <DateInputInner {...props} ref={ref} />
|
|
196
|
+
: <DateInputStandalone {...props} ref={ref} />;
|
|
197
|
+
}
|
|
193
198
|
|
|
194
|
-
|
|
195
|
-
let
|
|
196
|
-
|
|
197
|
-
|
|
199
|
+
const DateInputStandalone = forwardRef((props: DateInputProps, ref: ForwardedRef<HTMLDivElement>) => {
|
|
200
|
+
let [dateFieldProps, fieldRef] = useContextProps({slot: props.slot} as DateFieldProps<any>, ref, DateFieldContext);
|
|
201
|
+
let {locale} = useLocale();
|
|
202
|
+
let state = useDateFieldState({
|
|
203
|
+
...dateFieldProps,
|
|
204
|
+
locale,
|
|
205
|
+
createCalendar
|
|
198
206
|
});
|
|
199
207
|
|
|
200
|
-
let
|
|
201
|
-
|
|
202
|
-
values: {isHovered, isFocusWithin: isFocused, isFocusVisible, isDisabled: state.isDisabled},
|
|
203
|
-
defaultClassName: 'react-aria-DateInput'
|
|
204
|
-
});
|
|
208
|
+
let inputRef = useRef<HTMLInputElement>(null);
|
|
209
|
+
let {fieldProps, inputProps} = useDateField({...dateFieldProps, inputRef}, state, fieldRef);
|
|
205
210
|
|
|
206
211
|
return (
|
|
207
|
-
<
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
{...
|
|
211
|
-
ref
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
212
|
+
<Provider
|
|
213
|
+
values={[
|
|
214
|
+
[DateFieldStateContext, state],
|
|
215
|
+
[InputContext, {...inputProps, ref: inputRef}],
|
|
216
|
+
[GroupContext, {...fieldProps, ref: fieldRef}]
|
|
217
|
+
]}>
|
|
218
|
+
<DateInputInner {...props} />
|
|
219
|
+
</Provider>
|
|
220
|
+
);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
const DateInputInner = forwardRef((props: DateInputProps, ref: ForwardedRef<HTMLDivElement>) => {
|
|
224
|
+
let {className, children} = props;
|
|
225
|
+
let dateFieldState = useContext(DateFieldStateContext);
|
|
226
|
+
let timeFieldState = useContext(TimeFieldStateContext);
|
|
227
|
+
let state = dateFieldState ?? timeFieldState!;
|
|
228
|
+
|
|
229
|
+
return (
|
|
230
|
+
<>
|
|
231
|
+
<Group
|
|
232
|
+
{...props}
|
|
233
|
+
ref={ref}
|
|
234
|
+
slot={props.slot || undefined}
|
|
235
|
+
className={className ?? 'react-aria-DateInput'}
|
|
236
|
+
isInvalid={state.isInvalid}>
|
|
217
237
|
{state.segments.map((segment, i) => cloneElement(children(segment), {key: i}))}
|
|
218
|
-
</
|
|
219
|
-
<
|
|
220
|
-
|
|
238
|
+
</Group>
|
|
239
|
+
<Input />
|
|
240
|
+
</>
|
|
221
241
|
);
|
|
222
|
-
}
|
|
242
|
+
});
|
|
223
243
|
|
|
224
244
|
/**
|
|
225
245
|
* A date input groups the editable date segments within a date field.
|
|
@@ -228,6 +248,21 @@ const _DateInput = /*#__PURE__*/ (forwardRef as forwardRefType)(DateInput);
|
|
|
228
248
|
export {_DateInput as DateInput};
|
|
229
249
|
|
|
230
250
|
export interface DateSegmentRenderProps extends Omit<IDateSegment, 'isEditable'> {
|
|
251
|
+
/**
|
|
252
|
+
* Whether the segment is currently hovered with a mouse.
|
|
253
|
+
* @selector [data-hovered]
|
|
254
|
+
*/
|
|
255
|
+
isHovered: boolean,
|
|
256
|
+
/**
|
|
257
|
+
* Whether the segment is focused, either via a mouse or keyboard.
|
|
258
|
+
* @selector [data-focused]
|
|
259
|
+
*/
|
|
260
|
+
isFocused: boolean,
|
|
261
|
+
/**
|
|
262
|
+
* Whether the segment is keyboard focused.
|
|
263
|
+
* @selector [data-focus-visible]
|
|
264
|
+
*/
|
|
265
|
+
isFocusVisible: boolean,
|
|
231
266
|
/**
|
|
232
267
|
* Whether the value is a placeholder.
|
|
233
268
|
* @selector [data-placeholder]
|
|
@@ -255,29 +290,40 @@ export interface DateSegmentProps extends RenderProps<DateSegmentRenderProps> {
|
|
|
255
290
|
}
|
|
256
291
|
|
|
257
292
|
function DateSegment({segment, ...otherProps}: DateSegmentProps, ref: ForwardedRef<HTMLDivElement>) {
|
|
258
|
-
let
|
|
293
|
+
let dateFieldState = useContext(DateFieldStateContext);
|
|
294
|
+
let timeFieldState = useContext(TimeFieldStateContext);
|
|
295
|
+
let state = dateFieldState ?? timeFieldState!;
|
|
259
296
|
let domRef = useObjectRef(ref);
|
|
260
297
|
let {segmentProps} = useDateSegment(segment, state, domRef);
|
|
298
|
+
let {focusProps, isFocused, isFocusVisible} = useFocusRing();
|
|
299
|
+
let {hoverProps, isHovered} = useHover({isDisabled: state.isDisabled || segment.type === 'literal'});
|
|
261
300
|
let renderProps = useRenderProps({
|
|
262
301
|
...otherProps,
|
|
263
302
|
values: {
|
|
264
303
|
...segment,
|
|
265
304
|
isReadOnly: !segment.isEditable,
|
|
266
|
-
isInvalid: state.isInvalid
|
|
305
|
+
isInvalid: state.isInvalid,
|
|
306
|
+
isHovered,
|
|
307
|
+
isFocused,
|
|
308
|
+
isFocusVisible
|
|
267
309
|
},
|
|
268
310
|
defaultChildren: segment.text,
|
|
269
311
|
defaultClassName: 'react-aria-DateSegment'
|
|
270
312
|
});
|
|
271
313
|
|
|
314
|
+
|
|
272
315
|
return (
|
|
273
316
|
<div
|
|
274
|
-
{...mergeProps(filterDOMProps(otherProps as any), segmentProps)}
|
|
317
|
+
{...mergeProps(filterDOMProps(otherProps as any), segmentProps, focusProps, hoverProps)}
|
|
275
318
|
{...renderProps}
|
|
276
319
|
ref={domRef}
|
|
277
320
|
data-placeholder={segment.isPlaceholder || undefined}
|
|
278
321
|
data-invalid={state.isInvalid || undefined}
|
|
279
322
|
data-readonly={!segment.isEditable || undefined}
|
|
280
|
-
data-type={segment.type}
|
|
323
|
+
data-type={segment.type}
|
|
324
|
+
data-hovered={isHovered || undefined}
|
|
325
|
+
data-focused={isFocused || undefined}
|
|
326
|
+
data-focus-visible={isFocusVisible || undefined} />
|
|
281
327
|
);
|
|
282
328
|
}
|
|
283
329
|
|
package/src/DatePicker.tsx
CHANGED
|
@@ -9,14 +9,13 @@
|
|
|
9
9
|
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
|
-
import {AriaDatePickerProps, AriaDateRangePickerProps, DateValue,
|
|
12
|
+
import {AriaDatePickerProps, AriaDateRangePickerProps, DateValue, useDatePicker, useDateRangePicker, useFocusRing} from 'react-aria';
|
|
13
13
|
import {ButtonContext} from './Button';
|
|
14
14
|
import {CalendarContext, RangeCalendarContext} from './Calendar';
|
|
15
|
-
import {ContextValue, forwardRefType, Provider, RenderProps, SlotProps, useContextProps, useRenderProps, useSlot} from './utils';
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {DialogContext} from './Dialog';
|
|
15
|
+
import {ContextValue, forwardRefType, Provider, removeDataAttributes, RenderProps, SlotProps, useContextProps, useRenderProps, useSlot} from './utils';
|
|
16
|
+
import {DateFieldContext} from './DateField';
|
|
17
|
+
import {DatePickerState, DateRangePickerState, useDatePickerState, useDateRangePickerState} from 'react-stately';
|
|
18
|
+
import {DialogContext, OverlayTriggerStateContext} from './Dialog';
|
|
20
19
|
import {filterDOMProps} from '@react-aria/utils';
|
|
21
20
|
import {GroupContext} from './Group';
|
|
22
21
|
import {LabelContext} from './Label';
|
|
@@ -45,6 +44,11 @@ export interface DatePickerRenderProps {
|
|
|
45
44
|
* @selector [data-disabled]
|
|
46
45
|
*/
|
|
47
46
|
isInvalid: boolean,
|
|
47
|
+
/**
|
|
48
|
+
* Whether the date picker's popover is currently open.
|
|
49
|
+
* @selector [data-open]
|
|
50
|
+
*/
|
|
51
|
+
isOpen: boolean,
|
|
48
52
|
/**
|
|
49
53
|
* State of the date picker.
|
|
50
54
|
*/
|
|
@@ -62,6 +66,8 @@ export interface DateRangePickerProps<T extends DateValue> extends Omit<AriaDate
|
|
|
62
66
|
|
|
63
67
|
export const DatePickerContext = createContext<ContextValue<DatePickerProps<any>, HTMLDivElement>>(null);
|
|
64
68
|
export const DateRangePickerContext = createContext<ContextValue<DateRangePickerProps<any>, HTMLDivElement>>(null);
|
|
69
|
+
export const DatePickerStateContext = createContext<DatePickerState | null>(null);
|
|
70
|
+
export const DateRangePickerStateContext = createContext<DateRangePickerState | null>(null);
|
|
65
71
|
|
|
66
72
|
function DatePicker<T extends DateValue>(props: DatePickerProps<T>, ref: ForwardedRef<HTMLDivElement>) {
|
|
67
73
|
[props, ref] = useContextProps(props, ref, DatePickerContext);
|
|
@@ -77,20 +83,9 @@ function DatePicker<T extends DateValue>(props: DatePickerProps<T>, ref: Forward
|
|
|
77
83
|
calendarProps,
|
|
78
84
|
descriptionProps,
|
|
79
85
|
errorMessageProps
|
|
80
|
-
} = useDatePicker({...props, label}, state, groupRef);
|
|
81
|
-
|
|
82
|
-
let {locale} = useLocale();
|
|
83
|
-
let fieldState = useDateFieldState({
|
|
84
|
-
...fieldProps,
|
|
85
|
-
locale,
|
|
86
|
-
createCalendar
|
|
87
|
-
});
|
|
86
|
+
} = useDatePicker({...removeDataAttributes(props), label}, state, groupRef);
|
|
88
87
|
|
|
89
|
-
let fieldRef = useRef<HTMLDivElement>(null);
|
|
90
|
-
let inputRef = useRef<HTMLInputElement>(null);
|
|
91
88
|
let {focusProps, isFocused, isFocusVisible} = useFocusRing({within: true});
|
|
92
|
-
let {fieldProps: dateFieldProps, inputProps} = useDateField({...fieldProps, label, inputRef}, fieldState, fieldRef);
|
|
93
|
-
|
|
94
89
|
let renderProps = useRenderProps({
|
|
95
90
|
...props,
|
|
96
91
|
values: {
|
|
@@ -98,7 +93,8 @@ function DatePicker<T extends DateValue>(props: DatePickerProps<T>, ref: Forward
|
|
|
98
93
|
isFocusWithin: isFocused,
|
|
99
94
|
isFocusVisible,
|
|
100
95
|
isDisabled: props.isDisabled || false,
|
|
101
|
-
isInvalid: state.isInvalid
|
|
96
|
+
isInvalid: state.isInvalid,
|
|
97
|
+
isOpen: state.isOpen
|
|
102
98
|
},
|
|
103
99
|
defaultClassName: 'react-aria-DatePicker'
|
|
104
100
|
});
|
|
@@ -109,12 +105,14 @@ function DatePicker<T extends DateValue>(props: DatePickerProps<T>, ref: Forward
|
|
|
109
105
|
return (
|
|
110
106
|
<Provider
|
|
111
107
|
values={[
|
|
108
|
+
[DatePickerStateContext, state],
|
|
112
109
|
[GroupContext, {...groupProps, ref: groupRef}],
|
|
113
|
-
[
|
|
110
|
+
[DateFieldContext, fieldProps],
|
|
114
111
|
[ButtonContext, {...buttonProps, isPressed: state.isOpen}],
|
|
115
112
|
[LabelContext, {...labelProps, ref: labelRef, elementType: 'span'}],
|
|
116
113
|
[CalendarContext, calendarProps],
|
|
117
|
-
[
|
|
114
|
+
[OverlayTriggerStateContext, state],
|
|
115
|
+
[PopoverContext, {triggerRef: groupRef, placement: 'bottom start'}],
|
|
118
116
|
[DialogContext, dialogProps],
|
|
119
117
|
[TextContext, {
|
|
120
118
|
slots: {
|
|
@@ -128,11 +126,12 @@ function DatePicker<T extends DateValue>(props: DatePickerProps<T>, ref: Forward
|
|
|
128
126
|
{...DOMProps}
|
|
129
127
|
{...renderProps}
|
|
130
128
|
ref={ref}
|
|
131
|
-
slot={props.slot}
|
|
129
|
+
slot={props.slot || undefined}
|
|
132
130
|
data-focus-within={isFocused || undefined}
|
|
133
131
|
data-invalid={state.isInvalid || undefined}
|
|
134
132
|
data-focus-visible={isFocusVisible || undefined}
|
|
135
|
-
data-disabled={props.isDisabled || undefined}
|
|
133
|
+
data-disabled={props.isDisabled || undefined}
|
|
134
|
+
data-open={state.isOpen || undefined} />
|
|
136
135
|
</Provider>
|
|
137
136
|
);
|
|
138
137
|
}
|
|
@@ -158,30 +157,9 @@ function DateRangePicker<T extends DateValue>(props: DateRangePickerProps<T>, re
|
|
|
158
157
|
calendarProps,
|
|
159
158
|
descriptionProps,
|
|
160
159
|
errorMessageProps
|
|
161
|
-
} = useDateRangePicker({...props, label}, state, groupRef);
|
|
160
|
+
} = useDateRangePicker({...removeDataAttributes(props), label}, state, groupRef);
|
|
162
161
|
|
|
163
|
-
let {locale} = useLocale();
|
|
164
|
-
let startFieldState = useDateFieldState({
|
|
165
|
-
...startFieldProps,
|
|
166
|
-
locale,
|
|
167
|
-
createCalendar
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
let startFieldRef = useRef<HTMLDivElement>(null);
|
|
171
|
-
let startInputRef = useRef<HTMLInputElement>(null);
|
|
172
162
|
let {focusProps, isFocused, isFocusVisible} = useFocusRing({within: true});
|
|
173
|
-
let {fieldProps: startDateFieldProps, inputProps: startInputProps} = useDateField({...startFieldProps, label, inputRef: startInputRef}, startFieldState, startFieldRef);
|
|
174
|
-
|
|
175
|
-
let endFieldState = useDateFieldState({
|
|
176
|
-
...endFieldProps,
|
|
177
|
-
locale,
|
|
178
|
-
createCalendar
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
let endFieldRef = useRef<HTMLDivElement>(null);
|
|
182
|
-
let endInputRef = useRef<HTMLInputElement>(null);
|
|
183
|
-
let {fieldProps: endDateFieldProps, inputProps: endInputProps} = useDateField({...endFieldProps, label, inputRef: endInputRef}, endFieldState, endFieldRef);
|
|
184
|
-
|
|
185
163
|
let renderProps = useRenderProps({
|
|
186
164
|
...props,
|
|
187
165
|
values: {
|
|
@@ -189,7 +167,8 @@ function DateRangePicker<T extends DateValue>(props: DateRangePickerProps<T>, re
|
|
|
189
167
|
isFocusWithin: isFocused,
|
|
190
168
|
isFocusVisible,
|
|
191
169
|
isDisabled: props.isDisabled || false,
|
|
192
|
-
isInvalid: state.isInvalid
|
|
170
|
+
isInvalid: state.isInvalid,
|
|
171
|
+
isOpen: state.isOpen
|
|
193
172
|
},
|
|
194
173
|
defaultClassName: 'react-aria-DateRangePicker'
|
|
195
174
|
});
|
|
@@ -200,28 +179,18 @@ function DateRangePicker<T extends DateValue>(props: DateRangePickerProps<T>, re
|
|
|
200
179
|
return (
|
|
201
180
|
<Provider
|
|
202
181
|
values={[
|
|
182
|
+
[DateRangePickerStateContext, state],
|
|
203
183
|
[GroupContext, {...groupProps, ref: groupRef}],
|
|
204
184
|
[ButtonContext, {...buttonProps, isPressed: state.isOpen}],
|
|
205
185
|
[LabelContext, {...labelProps, ref: labelRef, elementType: 'span'}],
|
|
206
186
|
[RangeCalendarContext, calendarProps],
|
|
207
|
-
[
|
|
187
|
+
[OverlayTriggerStateContext, state],
|
|
188
|
+
[PopoverContext, {triggerRef: groupRef, placement: 'bottom start'}],
|
|
208
189
|
[DialogContext, dialogProps],
|
|
209
|
-
[
|
|
190
|
+
[DateFieldContext, {
|
|
210
191
|
slots: {
|
|
211
|
-
start:
|
|
212
|
-
|
|
213
|
-
fieldProps: startDateFieldProps,
|
|
214
|
-
ref: startFieldRef,
|
|
215
|
-
inputRef: startInputRef,
|
|
216
|
-
inputProps: startInputProps
|
|
217
|
-
},
|
|
218
|
-
end: {
|
|
219
|
-
state: endFieldState,
|
|
220
|
-
fieldProps: endDateFieldProps,
|
|
221
|
-
ref: endFieldRef,
|
|
222
|
-
inputRef: endInputRef,
|
|
223
|
-
inputProps: endInputProps
|
|
224
|
-
}
|
|
192
|
+
start: startFieldProps,
|
|
193
|
+
end: endFieldProps
|
|
225
194
|
}
|
|
226
195
|
}],
|
|
227
196
|
[TextContext, {
|
|
@@ -236,11 +205,12 @@ function DateRangePicker<T extends DateValue>(props: DateRangePickerProps<T>, re
|
|
|
236
205
|
{...DOMProps}
|
|
237
206
|
{...renderProps}
|
|
238
207
|
ref={ref}
|
|
239
|
-
slot={props.slot}
|
|
208
|
+
slot={props.slot || undefined}
|
|
240
209
|
data-focus-within={isFocused || undefined}
|
|
241
210
|
data-invalid={state.isInvalid || undefined}
|
|
242
211
|
data-focus-visible={isFocusVisible || undefined}
|
|
243
|
-
data-disabled={props.isDisabled || undefined}
|
|
212
|
+
data-disabled={props.isDisabled || undefined}
|
|
213
|
+
data-open={state.isOpen || undefined} />
|
|
244
214
|
</Provider>
|
|
245
215
|
);
|
|
246
216
|
}
|
package/src/Dialog.tsx
CHANGED
|
@@ -10,14 +10,13 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
import {AriaDialogProps, useDialog, useOverlayTrigger} from 'react-aria';
|
|
13
|
-
import {ButtonContext} from './Button';
|
|
14
13
|
import {ContextValue, forwardRefType, Provider, SlotProps, StyleProps, useContextProps} from './utils';
|
|
15
14
|
import {filterDOMProps} from '@react-aria/utils';
|
|
16
15
|
import {HeadingContext} from './Heading';
|
|
17
|
-
import {
|
|
18
|
-
import {OverlayTriggerProps, useOverlayTriggerState} from 'react-stately';
|
|
16
|
+
import {OverlayTriggerProps, OverlayTriggerState, useOverlayTriggerState} from 'react-stately';
|
|
19
17
|
import {PopoverContext} from './Popover';
|
|
20
|
-
import
|
|
18
|
+
import {PressResponder} from '@react-aria/interactions';
|
|
19
|
+
import React, {createContext, ForwardedRef, forwardRef, ReactNode, useContext, useRef} from 'react';
|
|
21
20
|
|
|
22
21
|
export interface DialogTriggerProps extends OverlayTriggerProps {
|
|
23
22
|
children: ReactNode
|
|
@@ -28,11 +27,12 @@ interface DialogRenderProps {
|
|
|
28
27
|
}
|
|
29
28
|
|
|
30
29
|
export interface DialogProps extends AriaDialogProps, StyleProps, SlotProps {
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
/** Children of the dialog. A function may be provided to access a function to close the dialog. */
|
|
31
|
+
children?: ReactNode | ((opts: DialogRenderProps) => ReactNode)
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
export const DialogContext = createContext<ContextValue<DialogProps, HTMLElement>>(null);
|
|
35
|
+
export const OverlayTriggerStateContext = createContext<OverlayTriggerState | null>(null);
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* A DialogTrigger opens a dialog when a trigger element is pressed.
|
|
@@ -46,25 +46,26 @@ export function DialogTrigger(props: DialogTriggerProps) {
|
|
|
46
46
|
return (
|
|
47
47
|
<Provider
|
|
48
48
|
values={[
|
|
49
|
-
[
|
|
50
|
-
[DialogContext,
|
|
51
|
-
[
|
|
52
|
-
[PopoverContext, {state, triggerRef: buttonRef}]
|
|
49
|
+
[OverlayTriggerStateContext, state],
|
|
50
|
+
[DialogContext, overlayProps],
|
|
51
|
+
[PopoverContext, {triggerRef: buttonRef}]
|
|
53
52
|
]}>
|
|
54
|
-
{
|
|
53
|
+
<PressResponder {...triggerProps} ref={buttonRef} isPressed={state.isOpen}>
|
|
54
|
+
{props.children}
|
|
55
|
+
</PressResponder>
|
|
55
56
|
</Provider>
|
|
56
57
|
);
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
|
|
60
60
|
function Dialog(props: DialogProps, ref: ForwardedRef<HTMLElement>) {
|
|
61
61
|
[props, ref] = useContextProps(props, ref, DialogContext);
|
|
62
62
|
let {dialogProps, titleProps} = useDialog(props, ref);
|
|
63
|
+
let state = useContext(OverlayTriggerStateContext);
|
|
63
64
|
|
|
64
65
|
let children = props.children;
|
|
65
66
|
if (typeof children === 'function') {
|
|
66
67
|
children = children({
|
|
67
|
-
close:
|
|
68
|
+
close: state?.close || (() => {})
|
|
68
69
|
});
|
|
69
70
|
}
|
|
70
71
|
|
|
@@ -73,12 +74,11 @@ function Dialog(props: DialogProps, ref: ForwardedRef<HTMLElement>) {
|
|
|
73
74
|
{...filterDOMProps(props)}
|
|
74
75
|
{...dialogProps}
|
|
75
76
|
ref={ref}
|
|
76
|
-
slot={props.slot}
|
|
77
|
+
slot={props.slot || undefined}
|
|
77
78
|
style={props.style}
|
|
78
79
|
className={props.className ?? 'react-aria-Dialog'}>
|
|
79
80
|
<Provider
|
|
80
81
|
values={[
|
|
81
|
-
[ButtonContext, undefined],
|
|
82
82
|
// TODO: clear context within dialog content?
|
|
83
83
|
[HeadingContext, {...titleProps, level: 2}]
|
|
84
84
|
]}>
|
package/src/DropZone.tsx
CHANGED
|
@@ -12,8 +12,10 @@
|
|
|
12
12
|
|
|
13
13
|
import {AriaLabelingProps} from '@react-types/shared';
|
|
14
14
|
import {ContextValue, Provider, RenderProps, SlotProps, useContextProps, useRenderProps} from './utils';
|
|
15
|
-
import {DropOptions, mergeProps, useClipboard, useDrop, useFocusRing, useHover, VisuallyHidden} from 'react-aria';
|
|
15
|
+
import {DropOptions, mergeProps, useClipboard, useDrop, useFocusRing, useHover, useLocalizedStringFormatter, VisuallyHidden} from 'react-aria';
|
|
16
16
|
import {filterDOMProps, useLabels, useSlotId} from '@react-aria/utils';
|
|
17
|
+
// @ts-ignore
|
|
18
|
+
import intlMessages from '../intl/*.json';
|
|
17
19
|
import React, {createContext, ForwardedRef, forwardRef, useRef} from 'react';
|
|
18
20
|
import {TextContext} from './Text';
|
|
19
21
|
|
|
@@ -50,9 +52,10 @@ function DropZone(props: DropZoneProps, ref: ForwardedRef<HTMLDivElement>) {
|
|
|
50
52
|
let {dropProps, dropButtonProps, isDropTarget} = useDrop({...props, ref: buttonRef, hasDropButton: true});
|
|
51
53
|
let {hoverProps, isHovered} = useHover({});
|
|
52
54
|
let {focusProps, isFocused, isFocusVisible} = useFocusRing();
|
|
55
|
+
let stringFormatter = useLocalizedStringFormatter(intlMessages);
|
|
53
56
|
|
|
54
57
|
let textId = useSlotId();
|
|
55
|
-
let ariaLabel = props['aria-label'] || '
|
|
58
|
+
let ariaLabel = props['aria-label'] || stringFormatter.format('dropzoneLabel');
|
|
56
59
|
let messageId = (isDropTarget && props['aria-labelledby']) ? props['aria-labelledby'] : null;
|
|
57
60
|
let ariaLabelledby = [textId, messageId].filter(Boolean).join(' ');
|
|
58
61
|
let labelProps = useLabels({'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby});
|
|
@@ -84,7 +87,7 @@ function DropZone(props: DropZoneProps, ref: ForwardedRef<HTMLDivElement>) {
|
|
|
84
87
|
<div
|
|
85
88
|
{...mergeProps(dropProps, hoverProps, DOMProps)}
|
|
86
89
|
{...renderProps}
|
|
87
|
-
slot={props.slot}
|
|
90
|
+
slot={props.slot || undefined}
|
|
88
91
|
ref={ref}
|
|
89
92
|
onClick={() => buttonRef.current?.focus()}
|
|
90
93
|
data-hovered={isHovered || undefined}
|
package/src/FileTrigger.tsx
CHANGED
|
@@ -31,11 +31,7 @@ export interface FileTriggerProps {
|
|
|
31
31
|
/**
|
|
32
32
|
* Handler when a user selects a file.
|
|
33
33
|
*/
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* The name of the input element, used when submitting an HTML form. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefname).
|
|
37
|
-
*/
|
|
38
|
-
name?: string,
|
|
34
|
+
onSelect?: (files: FileList | null) => void,
|
|
39
35
|
/**
|
|
40
36
|
* The children of the component.
|
|
41
37
|
*/
|
|
@@ -43,13 +39,19 @@ export interface FileTriggerProps {
|
|
|
43
39
|
}
|
|
44
40
|
|
|
45
41
|
function FileTrigger(props: FileTriggerProps, ref: ForwardedRef<HTMLInputElement>) {
|
|
46
|
-
let {
|
|
42
|
+
let {onSelect, acceptedFileTypes, allowsMultiple, defaultCamera, children, ...rest} = props;
|
|
47
43
|
let inputRef = useObjectRef(ref);
|
|
48
44
|
let domProps = filterDOMProps(rest);
|
|
49
45
|
|
|
50
46
|
return (
|
|
51
47
|
<>
|
|
52
|
-
<PressResponder
|
|
48
|
+
<PressResponder
|
|
49
|
+
onPress={() => {
|
|
50
|
+
if (inputRef.current.value) {
|
|
51
|
+
inputRef.current.value = '';
|
|
52
|
+
}
|
|
53
|
+
inputRef.current?.click();
|
|
54
|
+
}}>
|
|
53
55
|
{children}
|
|
54
56
|
</PressResponder>
|
|
55
57
|
<Input
|
|
@@ -58,10 +60,9 @@ function FileTrigger(props: FileTriggerProps, ref: ForwardedRef<HTMLInputElement
|
|
|
58
60
|
ref={inputRef}
|
|
59
61
|
style={{display: 'none'}}
|
|
60
62
|
accept={acceptedFileTypes?.toString()}
|
|
61
|
-
onChange={(e) =>
|
|
63
|
+
onChange={(e) => onSelect?.(e.target.files)}
|
|
62
64
|
capture={defaultCamera}
|
|
63
|
-
multiple={allowsMultiple}
|
|
64
|
-
name={name} />
|
|
65
|
+
multiple={allowsMultiple} />
|
|
65
66
|
</>
|
|
66
67
|
);
|
|
67
68
|
}
|