react-aria-components 1.6.0 → 1.7.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 +1 -1
- package/dist/Autocomplete.main.js +23 -12
- package/dist/Autocomplete.main.js.map +1 -1
- package/dist/Autocomplete.mjs +23 -12
- package/dist/Autocomplete.module.js +23 -12
- package/dist/Autocomplete.module.js.map +1 -1
- package/dist/Checkbox.main.js +1 -1
- package/dist/Checkbox.main.js.map +1 -1
- package/dist/Checkbox.mjs +1 -1
- package/dist/Checkbox.module.js +1 -1
- package/dist/Checkbox.module.js.map +1 -1
- package/dist/Collection.main.js.map +1 -1
- package/dist/Collection.module.js.map +1 -1
- package/dist/ColorArea.main.js +4 -4
- package/dist/ColorArea.main.js.map +1 -1
- package/dist/ColorArea.mjs +2 -2
- package/dist/ColorArea.module.js +2 -2
- package/dist/ColorArea.module.js.map +1 -1
- package/dist/ColorField.main.js +8 -10
- package/dist/ColorField.main.js.map +1 -1
- package/dist/ColorField.mjs +4 -6
- package/dist/ColorField.module.js +4 -6
- package/dist/ColorField.module.js.map +1 -1
- package/dist/ColorPicker.main.js +2 -2
- package/dist/ColorPicker.main.js.map +1 -1
- package/dist/ColorPicker.mjs +1 -1
- package/dist/ColorPicker.module.js +1 -1
- package/dist/ColorPicker.module.js.map +1 -1
- package/dist/ColorSlider.main.js +5 -7
- package/dist/ColorSlider.main.js.map +1 -1
- package/dist/ColorSlider.mjs +3 -5
- package/dist/ColorSlider.module.js +3 -5
- package/dist/ColorSlider.module.js.map +1 -1
- package/dist/ColorSwatch.main.js +2 -2
- package/dist/ColorSwatch.main.js.map +1 -1
- package/dist/ColorSwatch.mjs +1 -1
- package/dist/ColorSwatch.module.js +1 -1
- package/dist/ColorSwatch.module.js.map +1 -1
- package/dist/ColorSwatchPicker.main.js +3 -3
- package/dist/ColorSwatchPicker.main.js.map +1 -1
- package/dist/ColorSwatchPicker.mjs +1 -1
- package/dist/ColorSwatchPicker.module.js +1 -1
- package/dist/ColorSwatchPicker.module.js.map +1 -1
- package/dist/ColorThumb.main.js +2 -6
- package/dist/ColorThumb.main.js.map +1 -1
- package/dist/ColorThumb.mjs +1 -5
- package/dist/ColorThumb.module.js +1 -5
- package/dist/ColorThumb.module.js.map +1 -1
- package/dist/ColorWheel.main.js +4 -4
- package/dist/ColorWheel.main.js.map +1 -1
- package/dist/ColorWheel.mjs +2 -2
- package/dist/ColorWheel.module.js +2 -2
- package/dist/ColorWheel.module.js.map +1 -1
- package/dist/ComboBox.main.js +1 -1
- package/dist/ComboBox.main.js.map +1 -1
- package/dist/ComboBox.mjs +1 -1
- package/dist/ComboBox.module.js +1 -1
- package/dist/ComboBox.module.js.map +1 -1
- package/dist/DateField.main.js +4 -3
- package/dist/DateField.main.js.map +1 -1
- package/dist/DateField.mjs +4 -3
- package/dist/DateField.module.js +4 -3
- package/dist/DateField.module.js.map +1 -1
- package/dist/DatePicker.main.js +2 -2
- package/dist/DatePicker.main.js.map +1 -1
- package/dist/DatePicker.mjs +2 -2
- package/dist/DatePicker.module.js +2 -2
- package/dist/DatePicker.module.js.map +1 -1
- package/dist/Dialog.main.js +2 -1
- package/dist/Dialog.main.js.map +1 -1
- package/dist/Dialog.mjs +2 -1
- package/dist/Dialog.module.js +2 -1
- package/dist/Dialog.module.js.map +1 -1
- package/dist/Disclosure.main.js +5 -7
- package/dist/Disclosure.main.js.map +1 -1
- package/dist/Disclosure.mjs +2 -4
- package/dist/Disclosure.module.js +2 -4
- package/dist/Disclosure.module.js.map +1 -1
- package/dist/DropZone.main.js +1 -3
- package/dist/DropZone.main.js.map +1 -1
- package/dist/DropZone.mjs +1 -3
- package/dist/DropZone.module.js +1 -3
- package/dist/DropZone.module.js.map +1 -1
- package/dist/GridList.main.js.map +1 -1
- package/dist/GridList.module.js.map +1 -1
- package/dist/Group.main.js.map +1 -1
- package/dist/Group.module.js.map +1 -1
- package/dist/ListBox.main.js +17 -16
- package/dist/ListBox.main.js.map +1 -1
- package/dist/ListBox.mjs +19 -18
- package/dist/ListBox.module.js +19 -18
- package/dist/ListBox.module.js.map +1 -1
- package/dist/Menu.main.js +39 -24
- package/dist/Menu.main.js.map +1 -1
- package/dist/Menu.mjs +40 -25
- package/dist/Menu.module.js +40 -25
- package/dist/Menu.module.js.map +1 -1
- package/dist/Meter.main.js +1 -1
- package/dist/Meter.main.js.map +1 -1
- package/dist/Meter.mjs +1 -1
- package/dist/Meter.module.js +1 -1
- package/dist/Meter.module.js.map +1 -1
- package/dist/NumberField.main.js +4 -2
- package/dist/NumberField.main.js.map +1 -1
- package/dist/NumberField.mjs +4 -2
- package/dist/NumberField.module.js +4 -2
- package/dist/NumberField.module.js.map +1 -1
- package/dist/Popover.main.js +67 -15
- package/dist/Popover.main.js.map +1 -1
- package/dist/Popover.mjs +69 -17
- package/dist/Popover.module.js +69 -17
- package/dist/Popover.module.js.map +1 -1
- package/dist/ProgressBar.main.js +1 -1
- package/dist/ProgressBar.main.js.map +1 -1
- package/dist/ProgressBar.mjs +1 -1
- package/dist/ProgressBar.module.js +1 -1
- package/dist/ProgressBar.module.js.map +1 -1
- package/dist/RadioGroup.main.js +1 -1
- package/dist/RadioGroup.main.js.map +1 -1
- package/dist/RadioGroup.mjs +1 -1
- package/dist/RadioGroup.module.js +1 -1
- package/dist/RadioGroup.module.js.map +1 -1
- package/dist/SearchField.main.js +4 -2
- package/dist/SearchField.main.js.map +1 -1
- package/dist/SearchField.mjs +5 -3
- package/dist/SearchField.module.js +5 -3
- package/dist/SearchField.module.js.map +1 -1
- package/dist/Select.main.js +3 -2
- package/dist/Select.main.js.map +1 -1
- package/dist/Select.mjs +3 -2
- package/dist/Select.module.js +3 -2
- package/dist/Select.module.js.map +1 -1
- package/dist/Slider.main.js +2 -2
- package/dist/Slider.main.js.map +1 -1
- package/dist/Slider.mjs +2 -2
- package/dist/Slider.module.js +2 -2
- package/dist/Slider.module.js.map +1 -1
- package/dist/Table.main.js +15 -6
- package/dist/Table.main.js.map +1 -1
- package/dist/Table.mjs +15 -6
- package/dist/Table.module.js +15 -6
- package/dist/Table.module.js.map +1 -1
- package/dist/TableLayout.main.js.map +1 -1
- package/dist/TableLayout.module.js.map +1 -1
- package/dist/Tabs.main.js +3 -2
- package/dist/Tabs.main.js.map +1 -1
- package/dist/Tabs.mjs +4 -3
- package/dist/Tabs.module.js +4 -3
- package/dist/Tabs.module.js.map +1 -1
- package/dist/TagGroup.main.js +1 -1
- package/dist/TagGroup.main.js.map +1 -1
- package/dist/TagGroup.mjs +1 -1
- package/dist/TagGroup.module.js +1 -1
- package/dist/TagGroup.module.js.map +1 -1
- package/dist/TextField.main.js +4 -2
- package/dist/TextField.main.js.map +1 -1
- package/dist/TextField.mjs +5 -3
- package/dist/TextField.module.js +5 -3
- package/dist/TextField.module.js.map +1 -1
- package/dist/Toast.main.js +148 -0
- package/dist/Toast.main.js.map +1 -0
- package/dist/Toast.mjs +137 -0
- package/dist/Toast.module.js +137 -0
- package/dist/Toast.module.js.map +1 -0
- package/dist/Tree.main.js +38 -34
- package/dist/Tree.main.js.map +1 -1
- package/dist/Tree.mjs +34 -30
- package/dist/Tree.module.js +34 -30
- package/dist/Tree.module.js.map +1 -1
- package/dist/Virtualizer.main.js +4 -1
- package/dist/Virtualizer.main.js.map +1 -1
- package/dist/Virtualizer.mjs +4 -1
- package/dist/Virtualizer.module.js +4 -1
- package/dist/Virtualizer.module.js.map +1 -1
- package/dist/import.mjs +9 -7
- package/dist/main.js +31 -17
- package/dist/main.js.map +1 -1
- package/dist/module.js +9 -7
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +159 -59
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.main.js +9 -7
- package/dist/utils.main.js.map +1 -1
- package/dist/utils.mjs +9 -7
- package/dist/utils.module.js +9 -7
- package/dist/utils.module.js.map +1 -1
- package/i18n/index.js +1 -1
- package/i18n/index.mjs +1 -1
- package/package.json +25 -30
- package/src/Autocomplete.tsx +19 -15
- package/src/Checkbox.tsx +3 -1
- package/src/Collection.tsx +2 -2
- package/src/ColorArea.tsx +2 -3
- package/src/ColorField.tsx +8 -6
- package/src/ColorPicker.tsx +1 -2
- package/src/ColorSlider.tsx +5 -5
- package/src/ColorSwatch.tsx +2 -2
- package/src/ColorSwatchPicker.tsx +1 -1
- package/src/ColorThumb.tsx +2 -4
- package/src/ColorWheel.tsx +2 -2
- package/src/ComboBox.tsx +3 -1
- package/src/DateField.tsx +8 -3
- package/src/DatePicker.tsx +6 -2
- package/src/Dialog.tsx +6 -2
- package/src/Disclosure.tsx +2 -3
- package/src/DropZone.tsx +1 -2
- package/src/GridList.tsx +5 -0
- package/src/Group.tsx +1 -0
- package/src/ListBox.tsx +11 -9
- package/src/Menu.tsx +53 -25
- package/src/Meter.tsx +3 -1
- package/src/NumberField.tsx +11 -2
- package/src/Popover.tsx +77 -25
- package/src/ProgressBar.tsx +3 -1
- package/src/RadioGroup.tsx +3 -1
- package/src/SearchField.tsx +6 -4
- package/src/Select.tsx +5 -2
- package/src/Slider.tsx +6 -2
- package/src/Table.tsx +35 -15
- package/src/TableLayout.ts +1 -1
- package/src/Tabs.tsx +6 -3
- package/src/TagGroup.tsx +3 -1
- package/src/TextField.tsx +6 -4
- package/src/Toast.tsx +184 -0
- package/src/Tree.tsx +67 -49
- package/src/Virtualizer.tsx +18 -3
- package/src/index.ts +16 -16
- package/src/utils.tsx +8 -10
package/src/Menu.tsx
CHANGED
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {AriaMenuProps, FocusScope, mergeProps,
|
|
13
|
+
import {AriaMenuProps, FocusScope, mergeProps, useHover, useMenu, useMenuItem, useMenuSection, useMenuTrigger, useSubmenuTrigger} from 'react-aria';
|
|
14
14
|
import {BaseCollection, Collection, CollectionBuilder, createBranchComponent, createLeafComponent} from '@react-aria/collections';
|
|
15
|
-
import {MenuTriggerProps as BaseMenuTriggerProps, Collection as ICollection, Node, TreeState, useMenuTriggerState, useTreeState} from 'react-stately';
|
|
15
|
+
import {MenuTriggerProps as BaseMenuTriggerProps, Collection as ICollection, Node, RootMenuTriggerState, TreeState, useMenuTriggerState, useSubmenuTriggerState, useTreeState} from 'react-stately';
|
|
16
16
|
import {CollectionProps, CollectionRendererContext, ItemRenderProps, SectionContext, SectionProps, usePersistedKeys} from './Collection';
|
|
17
|
-
import {ContextValue, Provider, RenderProps, ScrollableProps, SlotProps,
|
|
17
|
+
import {ContextValue, DEFAULT_SLOT, Provider, RenderProps, ScrollableProps, SlotProps, StyleRenderProps, useContextProps, useRenderProps, useSlot, useSlottedContext} from './utils';
|
|
18
18
|
import {filterDOMProps, mergeRefs, useObjectRef, useResizeObserver} from '@react-aria/utils';
|
|
19
19
|
import {FocusStrategy, forwardRefType, HoverEvents, Key, LinkDOMProps, MultipleSelection} from '@react-types/shared';
|
|
20
20
|
import {HeaderContext} from './Header';
|
|
@@ -22,7 +22,7 @@ import {KeyboardContext} from './Keyboard';
|
|
|
22
22
|
import {MultipleSelectionState, SelectionManager, useMultipleSelectionState} from '@react-stately/selection';
|
|
23
23
|
import {OverlayTriggerStateContext} from './Dialog';
|
|
24
24
|
import {PopoverContext} from './Popover';
|
|
25
|
-
import {PressResponder
|
|
25
|
+
import {PressResponder} from '@react-aria/interactions';
|
|
26
26
|
import React, {
|
|
27
27
|
createContext,
|
|
28
28
|
ForwardedRef,
|
|
@@ -36,11 +36,9 @@ import React, {
|
|
|
36
36
|
useRef,
|
|
37
37
|
useState
|
|
38
38
|
} from 'react';
|
|
39
|
-
import {RootMenuTriggerState, useSubmenuTriggerState} from '@react-stately/menu';
|
|
40
39
|
import {SeparatorContext} from './Separator';
|
|
41
40
|
import {TextContext} from './Text';
|
|
42
41
|
import {UNSTABLE_InternalAutocompleteContext} from './Autocomplete';
|
|
43
|
-
import {useSubmenuTrigger} from '@react-aria/menu';
|
|
44
42
|
|
|
45
43
|
export const MenuContext = createContext<ContextValue<MenuProps<any>, HTMLDivElement>>(null);
|
|
46
44
|
export const MenuStateContext = createContext<TreeState<any> | null>(null);
|
|
@@ -70,7 +68,6 @@ export function MenuTrigger(props: MenuTriggerProps) {
|
|
|
70
68
|
ref: ref,
|
|
71
69
|
onResize: onResize
|
|
72
70
|
});
|
|
73
|
-
|
|
74
71
|
let scrollRef = useRef(null);
|
|
75
72
|
|
|
76
73
|
return (
|
|
@@ -84,7 +81,8 @@ export function MenuTrigger(props: MenuTriggerProps) {
|
|
|
84
81
|
triggerRef: ref,
|
|
85
82
|
scrollRef,
|
|
86
83
|
placement: 'bottom start',
|
|
87
|
-
style: {'--trigger-width': buttonWidth} as React.CSSProperties
|
|
84
|
+
style: {'--trigger-width': buttonWidth} as React.CSSProperties,
|
|
85
|
+
'aria-labelledby': menuProps['aria-labelledby']
|
|
88
86
|
}]
|
|
89
87
|
]}>
|
|
90
88
|
<PressResponder {...menuTriggerProps} ref={ref} isPressed={state.isOpen}>
|
|
@@ -106,7 +104,7 @@ export interface SubmenuTriggerProps {
|
|
|
106
104
|
delay?: number
|
|
107
105
|
}
|
|
108
106
|
|
|
109
|
-
const SubmenuTriggerContext = createContext<{parentMenuRef: RefObject<HTMLElement | null
|
|
107
|
+
const SubmenuTriggerContext = createContext<{parentMenuRef: RefObject<HTMLElement | null>, shouldUseVirtualFocus?: boolean} | null>(null);
|
|
110
108
|
|
|
111
109
|
/**
|
|
112
110
|
* A submenu trigger is used to wrap a submenu's trigger item and the submenu itself.
|
|
@@ -120,11 +118,12 @@ export const SubmenuTrigger = /*#__PURE__*/ createBranchComponent('submenutrigg
|
|
|
120
118
|
let submenuTriggerState = useSubmenuTriggerState({triggerKey: item.key}, rootMenuTriggerState);
|
|
121
119
|
let submenuRef = useRef<HTMLDivElement>(null);
|
|
122
120
|
let itemRef = useObjectRef(ref);
|
|
123
|
-
let {parentMenuRef} = useContext(SubmenuTriggerContext)!;
|
|
121
|
+
let {parentMenuRef, shouldUseVirtualFocus} = useContext(SubmenuTriggerContext)!;
|
|
124
122
|
let {submenuTriggerProps, submenuProps, popoverProps} = useSubmenuTrigger({
|
|
125
123
|
parentMenuRef,
|
|
126
124
|
submenuRef,
|
|
127
|
-
delay: props.delay
|
|
125
|
+
delay: props.delay,
|
|
126
|
+
shouldUseVirtualFocus
|
|
128
127
|
}, submenuTriggerState, itemRef);
|
|
129
128
|
|
|
130
129
|
return (
|
|
@@ -138,9 +137,7 @@ export const SubmenuTrigger = /*#__PURE__*/ createBranchComponent('submenutrigg
|
|
|
138
137
|
trigger: 'SubmenuTrigger',
|
|
139
138
|
triggerRef: itemRef,
|
|
140
139
|
placement: 'end top',
|
|
141
|
-
|
|
142
|
-
// @ts-ignore
|
|
143
|
-
'data-react-aria-top-layer': true,
|
|
140
|
+
'aria-labelledby': submenuProps['aria-labelledby'],
|
|
144
141
|
...popoverProps
|
|
145
142
|
}]
|
|
146
143
|
]}>
|
|
@@ -150,7 +147,18 @@ export const SubmenuTrigger = /*#__PURE__*/ createBranchComponent('submenutrigg
|
|
|
150
147
|
);
|
|
151
148
|
}, props => props.children[0]);
|
|
152
149
|
|
|
153
|
-
export interface
|
|
150
|
+
export interface MenuRenderProps {
|
|
151
|
+
/**
|
|
152
|
+
* Whether the menu has no items and should display its empty state.
|
|
153
|
+
* @selector [data-empty]
|
|
154
|
+
*/
|
|
155
|
+
isEmpty: boolean
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface MenuProps<T> extends Omit<AriaMenuProps<T>, 'children'>, CollectionProps<T>, StyleRenderProps<MenuRenderProps>, SlotProps, ScrollableProps<HTMLDivElement> {
|
|
159
|
+
/** Provides content to display when there are no items in the list. */
|
|
160
|
+
renderEmptyState?: () => ReactNode
|
|
161
|
+
}
|
|
154
162
|
|
|
155
163
|
/**
|
|
156
164
|
* A menu displays a list of actions or options that a user can choose.
|
|
@@ -161,7 +169,7 @@ export const Menu = /*#__PURE__*/ (forwardRef as forwardRefType)(function Menu<T
|
|
|
161
169
|
// Delay rendering the actual menu until we have the collection so that auto focus works properly.
|
|
162
170
|
return (
|
|
163
171
|
<CollectionBuilder content={<Collection {...props} />}>
|
|
164
|
-
{collection =>
|
|
172
|
+
{collection => <MenuInner props={props} collection={collection} menuRef={ref} />}
|
|
165
173
|
</CollectionBuilder>
|
|
166
174
|
);
|
|
167
175
|
});
|
|
@@ -173,10 +181,10 @@ interface MenuInnerProps<T> {
|
|
|
173
181
|
}
|
|
174
182
|
|
|
175
183
|
function MenuInner<T extends object>({props, collection, menuRef: ref}: MenuInnerProps<T>) {
|
|
176
|
-
let {
|
|
184
|
+
let {filter, collectionProps: autocompleteMenuProps, collectionRef} = useContext(UNSTABLE_InternalAutocompleteContext) || {};
|
|
177
185
|
// Memoed so that useAutocomplete callback ref is properly only called once on mount and not everytime a rerender happens
|
|
178
186
|
ref = useObjectRef(useMemo(() => mergeRefs(ref, collectionRef !== undefined ? collectionRef as RefObject<HTMLDivElement> : null), [collectionRef, ref]));
|
|
179
|
-
let filteredCollection = useMemo(() =>
|
|
187
|
+
let filteredCollection = useMemo(() => filter ? collection.UNSTABLE_filter(filter) : collection, [collection, filter]);
|
|
180
188
|
let state = useTreeState({
|
|
181
189
|
...props,
|
|
182
190
|
collection: filteredCollection as ICollection<Node<object>>,
|
|
@@ -189,9 +197,22 @@ function MenuInner<T extends object>({props, collection, menuRef: ref}: MenuInne
|
|
|
189
197
|
defaultClassName: 'react-aria-Menu',
|
|
190
198
|
className: props.className,
|
|
191
199
|
style: props.style,
|
|
192
|
-
values: {
|
|
200
|
+
values: {
|
|
201
|
+
isEmpty: state.collection.size === 0
|
|
202
|
+
}
|
|
193
203
|
});
|
|
194
204
|
|
|
205
|
+
let emptyState: ReactElement | null = null;
|
|
206
|
+
if (state.collection.size === 0 && props.renderEmptyState) {
|
|
207
|
+
emptyState = (
|
|
208
|
+
<div
|
|
209
|
+
role="menuitem"
|
|
210
|
+
style={{display: 'contents'}}>
|
|
211
|
+
{props.renderEmptyState()}
|
|
212
|
+
</div>
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
195
216
|
return (
|
|
196
217
|
<FocusScope>
|
|
197
218
|
<div
|
|
@@ -200,21 +221,28 @@ function MenuInner<T extends object>({props, collection, menuRef: ref}: MenuInne
|
|
|
200
221
|
{...renderProps}
|
|
201
222
|
ref={ref}
|
|
202
223
|
slot={props.slot || undefined}
|
|
224
|
+
data-empty={state.collection.size === 0 || undefined}
|
|
203
225
|
onScroll={props.onScroll}>
|
|
204
226
|
<Provider
|
|
205
227
|
values={[
|
|
206
228
|
[MenuStateContext, state],
|
|
207
229
|
[SeparatorContext, {elementType: 'div'}],
|
|
208
230
|
[SectionContext, {name: 'MenuSection', render: MenuSectionInner}],
|
|
209
|
-
[SubmenuTriggerContext, {parentMenuRef: ref}],
|
|
231
|
+
[SubmenuTriggerContext, {parentMenuRef: ref, shouldUseVirtualFocus: autocompleteMenuProps?.shouldUseVirtualFocus}],
|
|
210
232
|
[MenuItemContext, null],
|
|
211
|
-
[
|
|
233
|
+
[UNSTABLE_InternalAutocompleteContext, null],
|
|
234
|
+
[SelectionManagerContext, state.selectionManager],
|
|
235
|
+
/* Ensure root MenuTriggerState is defined, in case Menu is rendered outside a MenuTrigger. */
|
|
236
|
+
/* We assume the context can never change between defined and undefined. */
|
|
237
|
+
/* eslint-disable-next-line react-hooks/rules-of-hooks */
|
|
238
|
+
[RootMenuTriggerStateContext, triggerState ?? useMenuTriggerState({})]
|
|
212
239
|
]}>
|
|
213
240
|
<CollectionRoot
|
|
214
241
|
collection={state.collection}
|
|
215
242
|
persistedKeys={usePersistedKeys(state.selectionManager.focusedKey)}
|
|
216
243
|
scrollRef={ref} />
|
|
217
244
|
</Provider>
|
|
245
|
+
{emptyState}
|
|
218
246
|
</div>
|
|
219
247
|
</FocusScope>
|
|
220
248
|
);
|
|
@@ -343,7 +371,6 @@ export const MenuItem = /*#__PURE__*/ createLeafComponent('item', function MenuI
|
|
|
343
371
|
selectionManager
|
|
344
372
|
}, state, ref);
|
|
345
373
|
|
|
346
|
-
let {isFocusVisible, focusProps} = useFocusRing();
|
|
347
374
|
let {hoverProps, isHovered} = useHover({
|
|
348
375
|
isDisabled: states.isDisabled
|
|
349
376
|
});
|
|
@@ -355,7 +382,7 @@ export const MenuItem = /*#__PURE__*/ createLeafComponent('item', function MenuI
|
|
|
355
382
|
values: {
|
|
356
383
|
...states,
|
|
357
384
|
isHovered,
|
|
358
|
-
isFocusVisible,
|
|
385
|
+
isFocusVisible: states.isFocusVisible,
|
|
359
386
|
selectionMode: selectionManager.selectionMode,
|
|
360
387
|
selectionBehavior: selectionManager.selectionBehavior,
|
|
361
388
|
hasSubmenu: !!props['aria-haspopup'],
|
|
@@ -367,13 +394,13 @@ export const MenuItem = /*#__PURE__*/ createLeafComponent('item', function MenuI
|
|
|
367
394
|
|
|
368
395
|
return (
|
|
369
396
|
<ElementType
|
|
370
|
-
{...mergeProps(menuItemProps,
|
|
397
|
+
{...mergeProps(menuItemProps, hoverProps)}
|
|
371
398
|
{...renderProps}
|
|
372
399
|
ref={ref}
|
|
373
400
|
data-disabled={states.isDisabled || undefined}
|
|
374
401
|
data-hovered={isHovered || undefined}
|
|
375
402
|
data-focused={states.isFocused || undefined}
|
|
376
|
-
data-focus-visible={isFocusVisible || undefined}
|
|
403
|
+
data-focus-visible={states.isFocusVisible || undefined}
|
|
377
404
|
data-pressed={states.isPressed || undefined}
|
|
378
405
|
data-selected={states.isSelected || undefined}
|
|
379
406
|
data-selection-mode={selectionManager.selectionMode === 'none' ? undefined : selectionManager.selectionMode}
|
|
@@ -383,6 +410,7 @@ export const MenuItem = /*#__PURE__*/ createLeafComponent('item', function MenuI
|
|
|
383
410
|
values={[
|
|
384
411
|
[TextContext, {
|
|
385
412
|
slots: {
|
|
413
|
+
[DEFAULT_SLOT]: labelProps,
|
|
386
414
|
label: labelProps,
|
|
387
415
|
description: descriptionProps
|
|
388
416
|
}
|
package/src/Meter.tsx
CHANGED
|
@@ -45,7 +45,9 @@ export const Meter = /*#__PURE__*/ (forwardRef as forwardRefType)(function Meter
|
|
|
45
45
|
} = props;
|
|
46
46
|
value = clamp(value, minValue, maxValue);
|
|
47
47
|
|
|
48
|
-
let [labelRef, label] = useSlot(
|
|
48
|
+
let [labelRef, label] = useSlot(
|
|
49
|
+
!props['aria-label'] && !props['aria-labelledby']
|
|
50
|
+
);
|
|
49
51
|
let {
|
|
50
52
|
meterProps,
|
|
51
53
|
labelProps
|
package/src/NumberField.tsx
CHANGED
|
@@ -35,6 +35,11 @@ export interface NumberFieldRenderProps {
|
|
|
35
35
|
* @selector [data-invalid]
|
|
36
36
|
*/
|
|
37
37
|
isInvalid: boolean,
|
|
38
|
+
/**
|
|
39
|
+
* Whether the number field is required.
|
|
40
|
+
* @selector [data-required]
|
|
41
|
+
*/
|
|
42
|
+
isRequired: boolean,
|
|
38
43
|
/**
|
|
39
44
|
* State of the number field.
|
|
40
45
|
*/
|
|
@@ -61,7 +66,9 @@ export const NumberField = /*#__PURE__*/ (forwardRef as forwardRefType)(function
|
|
|
61
66
|
});
|
|
62
67
|
|
|
63
68
|
let inputRef = useRef<HTMLInputElement>(null);
|
|
64
|
-
let [labelRef, label] = useSlot(
|
|
69
|
+
let [labelRef, label] = useSlot(
|
|
70
|
+
!props['aria-label'] && !props['aria-labelledby']
|
|
71
|
+
);
|
|
65
72
|
let {
|
|
66
73
|
labelProps,
|
|
67
74
|
groupProps,
|
|
@@ -82,7 +89,8 @@ export const NumberField = /*#__PURE__*/ (forwardRef as forwardRefType)(function
|
|
|
82
89
|
values: {
|
|
83
90
|
state,
|
|
84
91
|
isDisabled: props.isDisabled || false,
|
|
85
|
-
isInvalid: validation.isInvalid || false
|
|
92
|
+
isInvalid: validation.isInvalid || false,
|
|
93
|
+
isRequired: props.isRequired || false
|
|
86
94
|
},
|
|
87
95
|
defaultClassName: 'react-aria-NumberField'
|
|
88
96
|
});
|
|
@@ -117,6 +125,7 @@ export const NumberField = /*#__PURE__*/ (forwardRef as forwardRefType)(function
|
|
|
117
125
|
ref={ref}
|
|
118
126
|
slot={props.slot || undefined}
|
|
119
127
|
data-disabled={props.isDisabled || undefined}
|
|
128
|
+
data-required={props.isRequired || undefined}
|
|
120
129
|
data-invalid={validation.isInvalid || undefined} />
|
|
121
130
|
{props.name && <input type="hidden" name={props.name} value={isNaN(state.numberValue) ? '' : state.numberValue} />}
|
|
122
131
|
</Provider>
|
package/src/Popover.tsx
CHANGED
|
@@ -10,17 +10,18 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {
|
|
13
|
+
import {AriaLabelingProps, forwardRefType, RefObject} from '@react-types/shared';
|
|
14
|
+
import {AriaPopoverProps, DismissButton, Overlay, PlacementAxis, PositionProps, useLocale, usePopover} from 'react-aria';
|
|
14
15
|
import {ContextValue, RenderProps, SlotProps, useContextProps, useRenderProps} from './utils';
|
|
15
16
|
import {filterDOMProps, mergeProps, useEnterAnimation, useExitAnimation, useLayoutEffect} from '@react-aria/utils';
|
|
16
|
-
import {
|
|
17
|
+
import {focusSafely} from '@react-aria/interactions';
|
|
17
18
|
import {OverlayArrowContext} from './OverlayArrow';
|
|
18
19
|
import {OverlayTriggerProps, OverlayTriggerState, useOverlayTriggerState} from 'react-stately';
|
|
19
20
|
import {OverlayTriggerStateContext} from './Dialog';
|
|
20
|
-
import React, {createContext, ForwardedRef, forwardRef, useContext, useRef, useState} from 'react';
|
|
21
|
+
import React, {createContext, ForwardedRef, forwardRef, useContext, useEffect, useRef, useState} from 'react';
|
|
21
22
|
import {useIsHidden} from '@react-aria/collections';
|
|
22
23
|
|
|
23
|
-
export interface PopoverProps extends Omit<PositionProps, 'isOpen'>, Omit<AriaPopoverProps, 'popoverRef' | 'triggerRef' | 'offset' | 'arrowSize'>, OverlayTriggerProps, RenderProps<PopoverRenderProps>, SlotProps {
|
|
24
|
+
export interface PopoverProps extends Omit<PositionProps, 'isOpen'>, Omit<AriaPopoverProps, 'popoverRef' | 'triggerRef' | 'groupRef' | 'offset' | 'arrowSize'>, OverlayTriggerProps, RenderProps<PopoverRenderProps>, SlotProps, AriaLabelingProps {
|
|
24
25
|
/**
|
|
25
26
|
* The name of the component that triggered the popover. This is reflected on the element
|
|
26
27
|
* as the `data-trigger` attribute, and can be used to provide specific
|
|
@@ -80,6 +81,9 @@ export interface PopoverRenderProps {
|
|
|
80
81
|
|
|
81
82
|
export const PopoverContext = createContext<ContextValue<PopoverProps, HTMLElement>>(null);
|
|
82
83
|
|
|
84
|
+
// Stores a ref for the portal container for a group of popovers (e.g. submenus).
|
|
85
|
+
const PopoverGroupContext = createContext<RefObject<Element | null> | null>(null);
|
|
86
|
+
|
|
83
87
|
/**
|
|
84
88
|
* A popover is an overlay element positioned relative to a trigger.
|
|
85
89
|
*/
|
|
@@ -90,6 +94,7 @@ export const Popover = /*#__PURE__*/ (forwardRef as forwardRefType)(function Pop
|
|
|
90
94
|
let state = props.isOpen != null || props.defaultOpen != null || !contextState ? localState : contextState;
|
|
91
95
|
let isExiting = useExitAnimation(ref, state.isOpen) || props.isExiting || false;
|
|
92
96
|
let isHidden = useIsHidden();
|
|
97
|
+
let {direction} = useLocale();
|
|
93
98
|
|
|
94
99
|
// If we are in a hidden tree, we still need to preserve our children.
|
|
95
100
|
if (isHidden) {
|
|
@@ -117,7 +122,8 @@ export const Popover = /*#__PURE__*/ (forwardRef as forwardRefType)(function Pop
|
|
|
117
122
|
triggerRef={props.triggerRef!}
|
|
118
123
|
state={state}
|
|
119
124
|
popoverRef={ref}
|
|
120
|
-
isExiting={isExiting}
|
|
125
|
+
isExiting={isExiting}
|
|
126
|
+
dir={direction} />
|
|
121
127
|
);
|
|
122
128
|
});
|
|
123
129
|
|
|
@@ -126,7 +132,8 @@ interface PopoverInnerProps extends AriaPopoverProps, RenderProps<PopoverRenderP
|
|
|
126
132
|
isEntering?: boolean,
|
|
127
133
|
isExiting: boolean,
|
|
128
134
|
UNSTABLE_portalContainer?: Element,
|
|
129
|
-
trigger?: string
|
|
135
|
+
trigger?: string,
|
|
136
|
+
dir?: 'ltr' | 'rtl'
|
|
130
137
|
}
|
|
131
138
|
|
|
132
139
|
function PopoverInner({state, isExiting, UNSTABLE_portalContainer, ...props}: PopoverInnerProps) {
|
|
@@ -134,6 +141,9 @@ function PopoverInner({state, isExiting, UNSTABLE_portalContainer, ...props}: Po
|
|
|
134
141
|
// Referenced from: packages/@react-spectrum/tooltip/src/TooltipTrigger.tsx
|
|
135
142
|
let arrowRef = useRef<HTMLDivElement>(null);
|
|
136
143
|
let [arrowWidth, setArrowWidth] = useState(0);
|
|
144
|
+
let containerRef = useRef<HTMLDivElement | null>(null);
|
|
145
|
+
let groupCtx = useContext(PopoverGroupContext);
|
|
146
|
+
let isSubPopover = groupCtx && props.trigger === 'SubmenuTrigger';
|
|
137
147
|
useLayoutEffect(() => {
|
|
138
148
|
if (arrowRef.current && state.isOpen) {
|
|
139
149
|
setArrowWidth(arrowRef.current.getBoundingClientRect().width);
|
|
@@ -143,7 +153,10 @@ function PopoverInner({state, isExiting, UNSTABLE_portalContainer, ...props}: Po
|
|
|
143
153
|
let {popoverProps, underlayProps, arrowProps, placement} = usePopover({
|
|
144
154
|
...props,
|
|
145
155
|
offset: props.offset ?? 8,
|
|
146
|
-
arrowSize: arrowWidth
|
|
156
|
+
arrowSize: arrowWidth,
|
|
157
|
+
// If this is a submenu/subdialog, use the root popover's container
|
|
158
|
+
// to detect outside interaction and add aria-hidden.
|
|
159
|
+
groupRef: isSubPopover ? groupCtx! : containerRef
|
|
147
160
|
}, state);
|
|
148
161
|
|
|
149
162
|
let ref = props.popoverRef as RefObject<HTMLDivElement | null>;
|
|
@@ -159,27 +172,66 @@ function PopoverInner({state, isExiting, UNSTABLE_portalContainer, ...props}: Po
|
|
|
159
172
|
}
|
|
160
173
|
});
|
|
161
174
|
|
|
175
|
+
// Automatically render Popover with role=dialog except when isNonModal is true,
|
|
176
|
+
// or a dialog is already nested inside the popover.
|
|
177
|
+
let shouldBeDialog = !props.isNonModal || props.trigger === 'SubmenuTrigger';
|
|
178
|
+
let [isDialog, setDialog] = useState(false);
|
|
179
|
+
useLayoutEffect(() => {
|
|
180
|
+
if (ref.current) {
|
|
181
|
+
setDialog(shouldBeDialog && !ref.current.querySelector('[role=dialog]'));
|
|
182
|
+
}
|
|
183
|
+
}, [ref, shouldBeDialog]);
|
|
184
|
+
|
|
185
|
+
// Focus the popover itself on mount, unless a child element is already focused.
|
|
186
|
+
useEffect(() => {
|
|
187
|
+
if (isDialog && ref.current && !ref.current.contains(document.activeElement)) {
|
|
188
|
+
focusSafely(ref.current);
|
|
189
|
+
}
|
|
190
|
+
}, [isDialog, ref]);
|
|
191
|
+
|
|
162
192
|
let style = {...popoverProps.style, ...renderProps.style};
|
|
193
|
+
let overlay = (
|
|
194
|
+
<div
|
|
195
|
+
{...mergeProps(filterDOMProps(props as any), popoverProps)}
|
|
196
|
+
{...renderProps}
|
|
197
|
+
role={isDialog ? 'dialog' : undefined}
|
|
198
|
+
tabIndex={isDialog ? -1 : undefined}
|
|
199
|
+
aria-label={props['aria-label']}
|
|
200
|
+
aria-labelledby={props['aria-labelledby']}
|
|
201
|
+
ref={ref}
|
|
202
|
+
slot={props.slot || undefined}
|
|
203
|
+
style={style}
|
|
204
|
+
dir={props.dir}
|
|
205
|
+
data-trigger={props.trigger}
|
|
206
|
+
data-placement={placement}
|
|
207
|
+
data-entering={isEntering || undefined}
|
|
208
|
+
data-exiting={isExiting || undefined}>
|
|
209
|
+
{!props.isNonModal && <DismissButton onDismiss={state.close} />}
|
|
210
|
+
<OverlayArrowContext.Provider value={{...arrowProps, placement, ref: arrowRef}}>
|
|
211
|
+
{renderProps.children}
|
|
212
|
+
</OverlayArrowContext.Provider>
|
|
213
|
+
<DismissButton onDismiss={state.close} />
|
|
214
|
+
</div>
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
// If this is a root popover, render an extra div to act as the portal container for submenus/subdialogs.
|
|
218
|
+
if (!isSubPopover) {
|
|
219
|
+
return (
|
|
220
|
+
<Overlay {...props} shouldContainFocus={isDialog} isExiting={isExiting} portalContainer={UNSTABLE_portalContainer}>
|
|
221
|
+
{!props.isNonModal && state.isOpen && <div data-testid="underlay" {...underlayProps} style={{position: 'fixed', inset: 0}} />}
|
|
222
|
+
<div ref={containerRef} style={{display: 'contents'}}>
|
|
223
|
+
<PopoverGroupContext.Provider value={containerRef}>
|
|
224
|
+
{overlay}
|
|
225
|
+
</PopoverGroupContext.Provider>
|
|
226
|
+
</div>
|
|
227
|
+
</Overlay>
|
|
228
|
+
);
|
|
229
|
+
}
|
|
163
230
|
|
|
231
|
+
// Submenus/subdialogs are mounted into the root popover's container.
|
|
164
232
|
return (
|
|
165
|
-
<Overlay {...props} isExiting={isExiting} portalContainer={UNSTABLE_portalContainer}>
|
|
166
|
-
{
|
|
167
|
-
<div
|
|
168
|
-
{...mergeProps(filterDOMProps(props as any), popoverProps)}
|
|
169
|
-
{...renderProps}
|
|
170
|
-
ref={ref}
|
|
171
|
-
slot={props.slot || undefined}
|
|
172
|
-
style={style}
|
|
173
|
-
data-trigger={props.trigger}
|
|
174
|
-
data-placement={placement}
|
|
175
|
-
data-entering={isEntering || undefined}
|
|
176
|
-
data-exiting={isExiting || undefined}>
|
|
177
|
-
{!props.isNonModal && <DismissButton onDismiss={state.close} />}
|
|
178
|
-
<OverlayArrowContext.Provider value={{...arrowProps, placement, ref: arrowRef}}>
|
|
179
|
-
{renderProps.children}
|
|
180
|
-
</OverlayArrowContext.Provider>
|
|
181
|
-
<DismissButton onDismiss={state.close} />
|
|
182
|
-
</div>
|
|
233
|
+
<Overlay {...props} shouldContainFocus={isDialog} isExiting={isExiting} portalContainer={UNSTABLE_portalContainer ?? groupCtx?.current ?? undefined}>
|
|
234
|
+
{overlay}
|
|
183
235
|
</Overlay>
|
|
184
236
|
);
|
|
185
237
|
}
|
package/src/ProgressBar.tsx
CHANGED
|
@@ -51,7 +51,9 @@ export const ProgressBar = forwardRef(function ProgressBar(props: ProgressBarPro
|
|
|
51
51
|
} = props;
|
|
52
52
|
value = clamp(value, minValue, maxValue);
|
|
53
53
|
|
|
54
|
-
let [labelRef, label] = useSlot(
|
|
54
|
+
let [labelRef, label] = useSlot(
|
|
55
|
+
!props['aria-label'] && !props['aria-labelledby']
|
|
56
|
+
);
|
|
55
57
|
let {
|
|
56
58
|
progressBarProps,
|
|
57
59
|
labelProps
|
package/src/RadioGroup.tsx
CHANGED
|
@@ -125,7 +125,9 @@ export const RadioGroup = /*#__PURE__*/ (forwardRef as forwardRefType)(function
|
|
|
125
125
|
validationBehavior
|
|
126
126
|
});
|
|
127
127
|
|
|
128
|
-
let [labelRef, label] = useSlot(
|
|
128
|
+
let [labelRef, label] = useSlot(
|
|
129
|
+
!props['aria-label'] && !props['aria-labelledby']
|
|
130
|
+
);
|
|
129
131
|
let {radioGroupProps, labelProps, descriptionProps, errorMessageProps, ...validation} = useRadioGroup({
|
|
130
132
|
...props,
|
|
131
133
|
label,
|
package/src/SearchField.tsx
CHANGED
|
@@ -13,14 +13,14 @@
|
|
|
13
13
|
import {AriaSearchFieldProps, useSearchField} from 'react-aria';
|
|
14
14
|
import {ButtonContext} from './Button';
|
|
15
15
|
import {ContextValue, Provider, RACValidation, removeDataAttributes, RenderProps, SlotProps, useContextProps, useRenderProps, useSlot, useSlottedContext} from './utils';
|
|
16
|
+
import {createHideableComponent} from '@react-aria/collections';
|
|
16
17
|
import {FieldErrorContext} from './FieldError';
|
|
17
18
|
import {filterDOMProps, mergeProps} from '@react-aria/utils';
|
|
18
19
|
import {FormContext} from './Form';
|
|
19
|
-
import {forwardRefType} from '@react-types/shared';
|
|
20
20
|
import {GroupContext} from './Group';
|
|
21
21
|
import {InputContext} from './Input';
|
|
22
22
|
import {LabelContext} from './Label';
|
|
23
|
-
import React, {createContext, ForwardedRef,
|
|
23
|
+
import React, {createContext, ForwardedRef, useRef} from 'react';
|
|
24
24
|
import {SearchFieldState, useSearchFieldState} from 'react-stately';
|
|
25
25
|
import {TextContext} from './Text';
|
|
26
26
|
|
|
@@ -53,13 +53,15 @@ export const SearchFieldContext = createContext<ContextValue<SearchFieldProps, H
|
|
|
53
53
|
/**
|
|
54
54
|
* A search field allows a user to enter and clear a search query.
|
|
55
55
|
*/
|
|
56
|
-
export const SearchField = /*#__PURE__*/ (
|
|
56
|
+
export const SearchField = /*#__PURE__*/ createHideableComponent(function SearchField(props: SearchFieldProps, ref: ForwardedRef<HTMLDivElement>) {
|
|
57
57
|
[props, ref] = useContextProps(props, ref, SearchFieldContext);
|
|
58
58
|
let {validationBehavior: formValidationBehavior} = useSlottedContext(FormContext) || {};
|
|
59
59
|
let validationBehavior = props.validationBehavior ?? formValidationBehavior ?? 'native';
|
|
60
60
|
let inputRef = useRef<HTMLInputElement>(null);
|
|
61
61
|
let [inputContextProps, mergedInputRef] = useContextProps({}, inputRef, InputContext);
|
|
62
|
-
let [labelRef, label] = useSlot(
|
|
62
|
+
let [labelRef, label] = useSlot(
|
|
63
|
+
!props['aria-label'] && !props['aria-labelledby']
|
|
64
|
+
);
|
|
63
65
|
let state = useSearchFieldState({
|
|
64
66
|
...props,
|
|
65
67
|
validationBehavior
|
package/src/Select.tsx
CHANGED
|
@@ -114,7 +114,9 @@ function SelectInner<T extends object>({props, selectRef: ref, collection}: Sele
|
|
|
114
114
|
|
|
115
115
|
// Get props for child elements from useSelect
|
|
116
116
|
let buttonRef = useRef<HTMLButtonElement>(null);
|
|
117
|
-
let [labelRef, label] = useSlot(
|
|
117
|
+
let [labelRef, label] = useSlot(
|
|
118
|
+
!props['aria-label'] && !props['aria-labelledby']
|
|
119
|
+
);
|
|
118
120
|
let {
|
|
119
121
|
labelProps,
|
|
120
122
|
triggerProps,
|
|
@@ -177,7 +179,8 @@ function SelectInner<T extends object>({props, selectRef: ref, collection}: Sele
|
|
|
177
179
|
triggerRef: buttonRef,
|
|
178
180
|
scrollRef,
|
|
179
181
|
placement: 'bottom start',
|
|
180
|
-
style: {'--trigger-width': buttonWidth} as React.CSSProperties
|
|
182
|
+
style: {'--trigger-width': buttonWidth} as React.CSSProperties,
|
|
183
|
+
'aria-labelledby': menuProps['aria-labelledby']
|
|
181
184
|
}],
|
|
182
185
|
[ListBoxContext, {...menuProps, ref: scrollRef}],
|
|
183
186
|
[ListStateContext, state],
|
package/src/Slider.tsx
CHANGED
|
@@ -55,7 +55,9 @@ export const Slider = /*#__PURE__*/ (forwardRef as forwardRefType)(function Slid
|
|
|
55
55
|
let trackRef = useRef<HTMLDivElement>(null);
|
|
56
56
|
let numberFormatter = useNumberFormatter(props.formatOptions);
|
|
57
57
|
let state = useSliderState({...props, numberFormatter});
|
|
58
|
-
let [labelRef, label] = useSlot(
|
|
58
|
+
let [labelRef, label] = useSlot(
|
|
59
|
+
!props['aria-label'] && !props['aria-labelledby']
|
|
60
|
+
);
|
|
59
61
|
let {
|
|
60
62
|
groupProps,
|
|
61
63
|
trackProps,
|
|
@@ -221,7 +223,9 @@ export const SliderThumb = /*#__PURE__*/ (forwardRef as forwardRefType)(function
|
|
|
221
223
|
let {index = 0} = props;
|
|
222
224
|
let defaultInputRef = useRef<HTMLInputElement>(null);
|
|
223
225
|
let inputRef = userInputRef || defaultInputRef;
|
|
224
|
-
let [labelRef, label] = useSlot(
|
|
226
|
+
let [labelRef, label] = useSlot(
|
|
227
|
+
!props['aria-label'] && !props['aria-labelledby']
|
|
228
|
+
);
|
|
225
229
|
let {thumbProps, inputProps, labelProps, isDragging, isFocused, isDisabled} = useSliderThumb({
|
|
226
230
|
...props,
|
|
227
231
|
index,
|
package/src/Table.tsx
CHANGED
|
@@ -41,8 +41,21 @@ class TableCollection<T> extends BaseCollection<T> implements ITableCollection<T
|
|
|
41
41
|
|
|
42
42
|
commit(firstKey: Key, lastKey: Key, isSSR = false) {
|
|
43
43
|
this.updateColumns(isSSR);
|
|
44
|
+
|
|
45
|
+
this.rows = [];
|
|
46
|
+
for (let row of this.getChildren(this.body.key)) {
|
|
47
|
+
let lastChildKey = (row as CollectionNode<T>).lastChildKey;
|
|
48
|
+
if (lastChildKey != null) {
|
|
49
|
+
let lastCell = this.getItem(lastChildKey) as GridNode<T>;
|
|
50
|
+
let numberOfCellsInRow = (lastCell.colIndex ?? lastCell.index) + (lastCell.colSpan ?? 1);
|
|
51
|
+
if (numberOfCellsInRow !== this.columns.length && !isSSR) {
|
|
52
|
+
throw new Error(`Cell count must match column count. Found ${numberOfCellsInRow} cells and ${this.columns.length} columns.`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
this.rows.push(row);
|
|
56
|
+
}
|
|
57
|
+
|
|
44
58
|
super.commit(firstKey, lastKey, isSSR);
|
|
45
|
-
this.rows = [...this.getChildren(this.body.key)];
|
|
46
59
|
}
|
|
47
60
|
|
|
48
61
|
private updateColumns(isSSR: boolean) {
|
|
@@ -526,11 +539,11 @@ export interface TableHeaderRenderProps {
|
|
|
526
539
|
|
|
527
540
|
export interface TableHeaderProps<T> extends StyleRenderProps<TableHeaderRenderProps>, HoverEvents {
|
|
528
541
|
/** A list of table columns. */
|
|
529
|
-
columns?: T
|
|
542
|
+
columns?: Iterable<T>,
|
|
530
543
|
/** A list of `Column(s)` or a function. If the latter, a list of columns must be provided using the `columns` prop. */
|
|
531
544
|
children?: ReactNode | ((item: T) => ReactElement),
|
|
532
545
|
/** Values that should invalidate the column cache when using dynamic collections. */
|
|
533
|
-
dependencies?: any
|
|
546
|
+
dependencies?: ReadonlyArray<any>
|
|
534
547
|
}
|
|
535
548
|
|
|
536
549
|
/**
|
|
@@ -737,7 +750,6 @@ export const Column = /*#__PURE__*/ createLeafComponent('column', (props: Column
|
|
|
737
750
|
{...mergeProps(filterDOMProps(props as any), columnHeaderProps, focusProps, hoverProps)}
|
|
738
751
|
{...renderProps}
|
|
739
752
|
style={style}
|
|
740
|
-
colSpan={column.colspan}
|
|
741
753
|
ref={ref}
|
|
742
754
|
data-hovered={isHovered || undefined}
|
|
743
755
|
data-focused={isFocused || undefined}
|
|
@@ -976,12 +988,12 @@ export const TableBody = /*#__PURE__*/ createBranchComponent('tablebody', <T ext
|
|
|
976
988
|
|
|
977
989
|
export interface RowRenderProps extends ItemRenderProps {
|
|
978
990
|
/** Whether the row's children have keyboard focus. */
|
|
979
|
-
isFocusVisibleWithin: boolean
|
|
991
|
+
isFocusVisibleWithin: boolean,
|
|
992
|
+
/** The unique id of the row. */
|
|
993
|
+
id?: Key
|
|
980
994
|
}
|
|
981
995
|
|
|
982
996
|
export interface RowProps<T> extends StyleRenderProps<RowRenderProps>, LinkDOMProps, HoverEvents {
|
|
983
|
-
/** The unique id of the row. */
|
|
984
|
-
id?: Key,
|
|
985
997
|
/** A list of columns used when dynamically rendering cells. */
|
|
986
998
|
columns?: Iterable<T>,
|
|
987
999
|
/** The cells within the row. Supports static items or a function for dynamic rendering. */
|
|
@@ -989,7 +1001,7 @@ export interface RowProps<T> extends StyleRenderProps<RowRenderProps>, LinkDOMPr
|
|
|
989
1001
|
/** The object value that this row represents. When using dynamic collections, this is set automatically. */
|
|
990
1002
|
value?: T,
|
|
991
1003
|
/** Values that should invalidate the cell cache when using dynamic collections. */
|
|
992
|
-
dependencies?: any
|
|
1004
|
+
dependencies?: ReadonlyArray<any>,
|
|
993
1005
|
/** A string representation of the row's contents, used for features like typeahead. */
|
|
994
1006
|
textValue?: string,
|
|
995
1007
|
/** Whether the row is disabled. */
|
|
@@ -998,7 +1010,9 @@ export interface RowProps<T> extends StyleRenderProps<RowRenderProps>, LinkDOMPr
|
|
|
998
1010
|
* Handler that is called when a user performs an action on the row. The exact user event depends on
|
|
999
1011
|
* the collection's `selectionBehavior` prop and the interaction modality.
|
|
1000
1012
|
*/
|
|
1001
|
-
onAction?: () => void
|
|
1013
|
+
onAction?: () => void,
|
|
1014
|
+
/** The unique id of the row. */
|
|
1015
|
+
id?: Key
|
|
1002
1016
|
}
|
|
1003
1017
|
|
|
1004
1018
|
/**
|
|
@@ -1075,7 +1089,8 @@ export const Row = /*#__PURE__*/ createBranchComponent(
|
|
|
1075
1089
|
selectionBehavior: state.selectionManager.selectionBehavior,
|
|
1076
1090
|
isDragging,
|
|
1077
1091
|
isDropTarget: dropIndicator?.isDropTarget,
|
|
1078
|
-
isFocusVisibleWithin
|
|
1092
|
+
isFocusVisibleWithin,
|
|
1093
|
+
id: item.key
|
|
1079
1094
|
}
|
|
1080
1095
|
});
|
|
1081
1096
|
|
|
@@ -1166,14 +1181,18 @@ export interface CellRenderProps {
|
|
|
1166
1181
|
* Whether the cell is currently hovered with a mouse.
|
|
1167
1182
|
* @selector [data-hovered]
|
|
1168
1183
|
*/
|
|
1169
|
-
isHovered: boolean
|
|
1184
|
+
isHovered: boolean,
|
|
1185
|
+
/**
|
|
1186
|
+
* The unique id of the cell.
|
|
1187
|
+
**/
|
|
1188
|
+
id?: Key
|
|
1170
1189
|
}
|
|
1171
1190
|
|
|
1172
1191
|
export interface CellProps extends RenderProps<CellRenderProps> {
|
|
1173
|
-
/** The unique id of the cell. */
|
|
1174
|
-
id?: Key,
|
|
1175
1192
|
/** A string representation of the cell's contents, used for features like typeahead. */
|
|
1176
|
-
textValue?: string
|
|
1193
|
+
textValue?: string,
|
|
1194
|
+
/** Indicates how many columns the data cell spans. */
|
|
1195
|
+
colSpan?: number
|
|
1177
1196
|
}
|
|
1178
1197
|
|
|
1179
1198
|
/**
|
|
@@ -1203,7 +1222,8 @@ export const Cell = /*#__PURE__*/ createLeafComponent('cell', (props: CellProps,
|
|
|
1203
1222
|
isFocused,
|
|
1204
1223
|
isFocusVisible,
|
|
1205
1224
|
isPressed,
|
|
1206
|
-
isHovered
|
|
1225
|
+
isHovered,
|
|
1226
|
+
id: cell.key
|
|
1207
1227
|
}
|
|
1208
1228
|
});
|
|
1209
1229
|
|