react-aria-components 0.0.4 → 1.0.0-alpha.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/LICENSE +201 -0
- package/README.md +12 -29
- package/dist/import.mjs +5223 -0
- package/dist/main.js +5345 -0
- package/dist/main.js.map +1 -0
- package/dist/module.js +5223 -0
- package/dist/module.js.map +1 -0
- package/dist/types.d.ts +1481 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +36 -44
- package/src/Breadcrumbs.tsx +90 -0
- package/src/Button.tsx +79 -0
- package/src/Calendar.tsx +471 -0
- package/src/Checkbox.tsx +240 -0
- package/src/Collection.tsx +787 -0
- package/src/ComboBox.tsx +129 -0
- package/src/DateField.tsx +244 -0
- package/src/DatePicker.tsx +178 -0
- package/src/Dialog.tsx +95 -0
- package/src/GridList.tsx +411 -0
- package/src/Group.tsx +69 -0
- package/src/Header.tsx +34 -0
- package/src/Heading.tsx +35 -0
- package/src/Input.tsx +73 -0
- package/src/Keyboard.tsx +24 -0
- package/src/Label.tsx +30 -0
- package/src/Link.tsx +98 -0
- package/src/ListBox.tsx +406 -0
- package/src/Menu.tsx +227 -0
- package/src/Meter.tsx +73 -0
- package/src/Modal.tsx +192 -0
- package/src/NumberField.tsx +79 -0
- package/src/OverlayArrow.tsx +70 -0
- package/src/Popover.tsx +125 -0
- package/src/ProgressBar.tsx +81 -0
- package/src/RadioGroup.tsx +219 -0
- package/src/SearchField.tsx +78 -0
- package/src/Select.tsx +180 -0
- package/src/Separator.tsx +53 -0
- package/src/Slider.tsx +217 -0
- package/src/Switch.tsx +127 -0
- package/src/Table.tsx +917 -0
- package/src/Tabs.tsx +282 -0
- package/src/Text.tsx +30 -0
- package/src/TextField.tsx +62 -0
- package/src/ToggleButton.tsx +59 -0
- package/src/Tooltip.tsx +135 -0
- package/src/index.ts +94 -0
- package/src/useDragAndDrop.tsx +172 -0
- package/src/utils.tsx +235 -0
- package/.babelrc +0 -17
- package/.eslintrc +0 -12
- package/src/accordion/accordion.css +0 -4
- package/src/accordion/accordion.js +0 -20
- package/src/accordion/index.js +0 -2
- package/src/accordion/section.css +0 -21
- package/src/accordion/section.js +0 -85
- package/src/examples/accordion-example.js +0 -73
- package/src/examples/example.js +0 -21
- package/src/examples/grid-cells/fancy-input-grid-cell.js +0 -206
- package/src/examples/grid-cells/input-grid-cell.js +0 -44
- package/src/examples/grid-example.css +0 -23
- package/src/examples/grid-example.js +0 -231
- package/src/examples/index.html +0 -10
- package/src/examples/index.js +0 -53
- package/src/examples/tabs-example.js +0 -52
- package/src/grid/column-header.css +0 -4
- package/src/grid/column-header.js +0 -29
- package/src/grid/grid-cell.css +0 -16
- package/src/grid/grid-cell.js +0 -104
- package/src/grid/grid-context.js +0 -3
- package/src/grid/grid.css +0 -4
- package/src/grid/grid.js +0 -110
- package/src/grid/index.js +0 -6
- package/src/grid/interactive-grid-cell.js +0 -96
- package/src/grid/row-headers.css +0 -6
- package/src/grid/row-headers.js +0 -22
- package/src/grid/row.css +0 -5
- package/src/grid/row.js +0 -21
- package/src/prop-types/ref.js +0 -3
- package/src/tabs/index.js +0 -4
- package/src/tabs/tab-list.css +0 -6
- package/src/tabs/tab-list.js +0 -103
- package/src/tabs/tab-panels.js +0 -35
- package/src/tabs/tab.css +0 -10
- package/src/tabs/tab.js +0 -45
- package/src/tabs/tabs.js +0 -52
- package/src/utils/debounce.js +0 -12
- package/src/utils/event-handlers-factory.js +0 -42
- package/src/utils/unique-id.js +0 -6
- package/webpack.config.js +0 -43
package/src/GridList.tsx
ADDED
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
import {AriaGridListProps, DraggableItemResult, DragPreviewRenderer, DropIndicatorAria, DroppableCollectionResult, FocusScope, ListKeyboardDelegate, mergeProps, useFocusRing, useGridList, useGridListItem, useGridListSelectionCheckbox, useHover, useVisuallyHidden, VisuallyHidden} from 'react-aria';
|
|
13
|
+
import {ButtonContext} from './Button';
|
|
14
|
+
import {CheckboxContext} from './Checkbox';
|
|
15
|
+
import {CollectionProps, ItemProps, useCachedChildren, useCollection} from './Collection';
|
|
16
|
+
import {ContextValue, defaultSlot, forwardRefType, Provider, SlotProps, StyleRenderProps, useContextProps, useRenderProps} from './utils';
|
|
17
|
+
import {DragAndDropHooks, DropIndicator, DropIndicatorContext, DropIndicatorProps} from './useDragAndDrop';
|
|
18
|
+
import {DraggableCollectionState, DroppableCollectionState, ListState, Node, SelectionBehavior, useListState} from 'react-stately';
|
|
19
|
+
import {filterDOMProps, isIOS, isWebKit, useObjectRef} from '@react-aria/utils';
|
|
20
|
+
import React, {createContext, ForwardedRef, forwardRef, HTMLAttributes, ReactNode, RefObject, useContext, useEffect, useRef} from 'react';
|
|
21
|
+
import {TextContext} from './Text';
|
|
22
|
+
|
|
23
|
+
export interface GridListRenderProps {
|
|
24
|
+
/**
|
|
25
|
+
* Whether the list has no items and should display its empty state.
|
|
26
|
+
* @selector [data-empty]
|
|
27
|
+
*/
|
|
28
|
+
isEmpty: boolean,
|
|
29
|
+
/**
|
|
30
|
+
* Whether the grid list is currently focused.
|
|
31
|
+
* @selector [data-focused]
|
|
32
|
+
*/
|
|
33
|
+
isFocused: boolean,
|
|
34
|
+
/**
|
|
35
|
+
* Whether the grid list is currently keyboard focused.
|
|
36
|
+
* @selector [data-focus-visible]
|
|
37
|
+
*/
|
|
38
|
+
isFocusVisible: boolean,
|
|
39
|
+
/**
|
|
40
|
+
* Whether the grid list is currently the active drop target.
|
|
41
|
+
* @selector [data-drop-target]
|
|
42
|
+
*/
|
|
43
|
+
isDropTarget: boolean
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface GridListProps<T> extends Omit<AriaGridListProps<T>, 'children'>, CollectionProps<T>, StyleRenderProps<GridListRenderProps>, SlotProps {
|
|
47
|
+
/** How multiple selection should behave in the collection. */
|
|
48
|
+
selectionBehavior?: SelectionBehavior,
|
|
49
|
+
/** The drag and drop hooks returned by `useDragAndDrop` used to enable drag and drop behavior for the GridList. */
|
|
50
|
+
dragAndDropHooks?: DragAndDropHooks,
|
|
51
|
+
/** Provides content to display when there are no items in the list. */
|
|
52
|
+
renderEmptyState?: () => ReactNode
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
interface InternalGridListContextValue {
|
|
56
|
+
state: ListState<unknown>,
|
|
57
|
+
dragAndDropHooks?: DragAndDropHooks,
|
|
58
|
+
dragState?: DraggableCollectionState,
|
|
59
|
+
dropState?: DroppableCollectionState
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const GridListContext = createContext<ContextValue<GridListProps<any>, HTMLDivElement>>(null);
|
|
63
|
+
const InternalGridListContext = createContext<InternalGridListContextValue | null>(null);
|
|
64
|
+
|
|
65
|
+
function GridList<T extends object>(props: GridListProps<T>, ref: ForwardedRef<HTMLDivElement>) {
|
|
66
|
+
[props, ref] = useContextProps(props, ref, GridListContext);
|
|
67
|
+
let {dragAndDropHooks} = props;
|
|
68
|
+
let {portal, collection} = useCollection(props);
|
|
69
|
+
let state = useListState({
|
|
70
|
+
...props,
|
|
71
|
+
collection,
|
|
72
|
+
children: undefined
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
let {gridProps} = useGridList(props, state, ref);
|
|
76
|
+
|
|
77
|
+
let children = useCachedChildren({
|
|
78
|
+
items: collection,
|
|
79
|
+
children: (item: Node<T>) => {
|
|
80
|
+
switch (item.type) {
|
|
81
|
+
case 'item':
|
|
82
|
+
return <GridListItem item={item} />;
|
|
83
|
+
default:
|
|
84
|
+
throw new Error('Unsupported node type in GridList: ' + item.type);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
let selectionManager = state.selectionManager;
|
|
90
|
+
let isListDraggable = !!dragAndDropHooks?.useDraggableCollectionState;
|
|
91
|
+
let isListDroppable = !!dragAndDropHooks?.useDroppableCollectionState;
|
|
92
|
+
let dragHooksProvided = useRef(isListDraggable);
|
|
93
|
+
let dropHooksProvided = useRef(isListDroppable);
|
|
94
|
+
if (dragHooksProvided.current !== isListDraggable) {
|
|
95
|
+
console.warn('Drag hooks were provided during one render, but not another. This should be avoided as it may produce unexpected behavior.');
|
|
96
|
+
}
|
|
97
|
+
if (dropHooksProvided.current !== isListDroppable) {
|
|
98
|
+
console.warn('Drop hooks were provided during one render, but not another. This should be avoided as it may produce unexpected behavior.');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let dragState: DraggableCollectionState | undefined = undefined;
|
|
102
|
+
let dropState: DroppableCollectionState | undefined = undefined;
|
|
103
|
+
let droppableCollection: DroppableCollectionResult | undefined = undefined;
|
|
104
|
+
let isRootDropTarget = false;
|
|
105
|
+
let dragPreview: JSX.Element | null = null;
|
|
106
|
+
let preview = useRef<DragPreviewRenderer>(null);
|
|
107
|
+
|
|
108
|
+
if (isListDraggable && dragAndDropHooks) {
|
|
109
|
+
dragState = dragAndDropHooks.useDraggableCollectionState!({
|
|
110
|
+
collection,
|
|
111
|
+
selectionManager,
|
|
112
|
+
preview: dragAndDropHooks.renderDragPreview ? preview : undefined
|
|
113
|
+
});
|
|
114
|
+
dragAndDropHooks.useDraggableCollection!({}, dragState, ref);
|
|
115
|
+
|
|
116
|
+
let DragPreview = dragAndDropHooks.DragPreview!;
|
|
117
|
+
dragPreview = dragAndDropHooks.renderDragPreview
|
|
118
|
+
? <DragPreview ref={preview}>{dragAndDropHooks.renderDragPreview}</DragPreview>
|
|
119
|
+
: null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (isListDroppable && dragAndDropHooks) {
|
|
123
|
+
dropState = dragAndDropHooks.useDroppableCollectionState!({
|
|
124
|
+
collection,
|
|
125
|
+
selectionManager
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
let keyboardDelegate = new ListKeyboardDelegate(
|
|
129
|
+
collection,
|
|
130
|
+
selectionManager.disabledBehavior === 'selection' ? new Set() : selectionManager.disabledKeys,
|
|
131
|
+
ref
|
|
132
|
+
);
|
|
133
|
+
let dropTargetDelegate = dragAndDropHooks.dropTargetDelegate || new dragAndDropHooks.ListDropTargetDelegate(collection, ref);
|
|
134
|
+
droppableCollection = dragAndDropHooks.useDroppableCollection!({
|
|
135
|
+
keyboardDelegate,
|
|
136
|
+
dropTargetDelegate
|
|
137
|
+
}, dropState, ref);
|
|
138
|
+
|
|
139
|
+
isRootDropTarget = dropState.isDropTarget({type: 'root'});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
let {focusProps, isFocused, isFocusVisible} = useFocusRing();
|
|
143
|
+
let renderProps = useRenderProps({
|
|
144
|
+
className: props.className,
|
|
145
|
+
style: props.style,
|
|
146
|
+
defaultClassName: 'react-aria-GridList',
|
|
147
|
+
values: {
|
|
148
|
+
isDropTarget: isRootDropTarget,
|
|
149
|
+
isEmpty: state.collection.size === 0,
|
|
150
|
+
isFocused,
|
|
151
|
+
isFocusVisible
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
let emptyState: ReactNode = null;
|
|
156
|
+
let emptyStatePropOverrides: HTMLAttributes<HTMLElement> | null = null;
|
|
157
|
+
if (state.collection.size === 0 && props.renderEmptyState) {
|
|
158
|
+
// Ideally we'd use `display: contents` on the row and cell elements so that
|
|
159
|
+
// they don't affect the layout of the children. However, WebKit currently has
|
|
160
|
+
// a bug that makes grid elements with display: contents hidden to screen readers.
|
|
161
|
+
// https://bugs.webkit.org/show_bug.cgi?id=239479
|
|
162
|
+
let content = props.renderEmptyState();
|
|
163
|
+
if (isWebKit()) {
|
|
164
|
+
// For now, when in an empty state, swap the role to group in webkit.
|
|
165
|
+
emptyStatePropOverrides = {
|
|
166
|
+
role: 'group',
|
|
167
|
+
'aria-multiselectable': undefined
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
if (isIOS()) {
|
|
171
|
+
// iOS VoiceOver also doesn't announce the aria-label of group elements
|
|
172
|
+
// so try to add a visually hidden label element as well.
|
|
173
|
+
emptyState = (
|
|
174
|
+
<>
|
|
175
|
+
<VisuallyHidden>{gridProps['aria-label']}</VisuallyHidden>
|
|
176
|
+
{content}
|
|
177
|
+
</>
|
|
178
|
+
);
|
|
179
|
+
} else {
|
|
180
|
+
emptyState = content;
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
emptyState = (
|
|
184
|
+
<div role="row" style={{display: 'contents'}}>
|
|
185
|
+
<div role="gridcell" style={{display: 'contents'}}>
|
|
186
|
+
{content}
|
|
187
|
+
</div>
|
|
188
|
+
</div>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<FocusScope>
|
|
195
|
+
<div
|
|
196
|
+
{...filterDOMProps(props)}
|
|
197
|
+
{...renderProps}
|
|
198
|
+
{...mergeProps(gridProps, focusProps, droppableCollection?.collectionProps, emptyStatePropOverrides)}
|
|
199
|
+
ref={ref}
|
|
200
|
+
slot={props.slot}
|
|
201
|
+
data-drop-target={isRootDropTarget || undefined}
|
|
202
|
+
data-empty={state.collection.size === 0 || undefined}
|
|
203
|
+
data-focused={isFocused || undefined}
|
|
204
|
+
data-focus-visible={isFocusVisible || undefined}>
|
|
205
|
+
<Provider
|
|
206
|
+
values={[
|
|
207
|
+
[InternalGridListContext, {state, dragAndDropHooks, dragState, dropState}],
|
|
208
|
+
[DropIndicatorContext, {render: GridListDropIndicator}]
|
|
209
|
+
]}>
|
|
210
|
+
{isListDroppable && <RootDropIndicator />}
|
|
211
|
+
{children}
|
|
212
|
+
</Provider>
|
|
213
|
+
{emptyState}
|
|
214
|
+
{dragPreview}
|
|
215
|
+
{portal}
|
|
216
|
+
</div>
|
|
217
|
+
</FocusScope>
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* A grid list displays a list of interactive items, with support for keyboard navigation,
|
|
223
|
+
* single or multiple selection, and row actions.
|
|
224
|
+
*/
|
|
225
|
+
const _GridList = (forwardRef as forwardRefType)(GridList);
|
|
226
|
+
export {_GridList as GridList};
|
|
227
|
+
|
|
228
|
+
function GridListItem({item}) {
|
|
229
|
+
let {state, dragAndDropHooks, dragState, dropState} = useContext(InternalGridListContext)!;
|
|
230
|
+
let ref = React.useRef<HTMLDivElement>(null);
|
|
231
|
+
let {rowProps, gridCellProps, descriptionProps, ...states} = useGridListItem(
|
|
232
|
+
{
|
|
233
|
+
node: item,
|
|
234
|
+
shouldSelectOnPressUp: !!dragState
|
|
235
|
+
},
|
|
236
|
+
state,
|
|
237
|
+
ref
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
let {hoverProps, isHovered} = useHover({
|
|
241
|
+
isDisabled: !states.allowsSelection && !states.hasAction
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
let {isFocusVisible, focusProps} = useFocusRing();
|
|
245
|
+
let {checkboxProps} = useGridListSelectionCheckbox(
|
|
246
|
+
{key: item.key},
|
|
247
|
+
state
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
let draggableItem: DraggableItemResult | null = null;
|
|
251
|
+
if (dragState && dragAndDropHooks) {
|
|
252
|
+
draggableItem = dragAndDropHooks.useDraggableItem!({key: item.key, hasDragButton: true}, dragState);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
let dropIndicator: DropIndicatorAria | null = null;
|
|
256
|
+
let dropIndicatorRef = useRef<HTMLDivElement>(null);
|
|
257
|
+
let {visuallyHiddenProps} = useVisuallyHidden();
|
|
258
|
+
if (dropState && dragAndDropHooks) {
|
|
259
|
+
dropIndicator = dragAndDropHooks.useDropIndicator!({
|
|
260
|
+
target: {type: 'item', key: item.key, dropPosition: 'on'}
|
|
261
|
+
}, dropState, dropIndicatorRef);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
let props: ItemProps<unknown> = item.props;
|
|
265
|
+
let isDragging = dragState && dragState.isDragging(item.key);
|
|
266
|
+
let renderProps = useRenderProps({
|
|
267
|
+
...props,
|
|
268
|
+
id: undefined,
|
|
269
|
+
children: item.rendered,
|
|
270
|
+
defaultClassName: 'react-aria-Item',
|
|
271
|
+
values: {
|
|
272
|
+
...states,
|
|
273
|
+
isHovered,
|
|
274
|
+
isFocusVisible,
|
|
275
|
+
selectionMode: state.selectionManager.selectionMode,
|
|
276
|
+
selectionBehavior: state.selectionManager.selectionBehavior,
|
|
277
|
+
allowsDragging: !!dragState,
|
|
278
|
+
isDragging,
|
|
279
|
+
isDropTarget: dropIndicator?.isDropTarget
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
let renderDropIndicator = dragAndDropHooks?.renderDropIndicator || (target => <DropIndicator target={target} />);
|
|
284
|
+
let dragButtonRef = useRef<HTMLButtonElement>(null);
|
|
285
|
+
useEffect(() => {
|
|
286
|
+
if (dragState && !dragButtonRef.current) {
|
|
287
|
+
console.warn('Draggable items in a GridList must contain a <Button slot="drag"> element so that keyboard and screen reader users can drag them.');
|
|
288
|
+
}
|
|
289
|
+
// eslint-disable-next-line
|
|
290
|
+
}, []);
|
|
291
|
+
|
|
292
|
+
useEffect(() => {
|
|
293
|
+
if (!item.textValue) {
|
|
294
|
+
console.warn('A `textValue` prop is required for <Item> elements with non-plain text children in order to support accessibility features such as type to select.');
|
|
295
|
+
}
|
|
296
|
+
}, [item.textValue]);
|
|
297
|
+
|
|
298
|
+
return (
|
|
299
|
+
<>
|
|
300
|
+
{dragAndDropHooks?.useDropIndicator &&
|
|
301
|
+
renderDropIndicator({type: 'item', key: item.key, dropPosition: 'before'})
|
|
302
|
+
}
|
|
303
|
+
{dropIndicator && !dropIndicator.isHidden &&
|
|
304
|
+
<div role="row" style={{position: 'absolute'}}>
|
|
305
|
+
<div role="gridcell">
|
|
306
|
+
<div role="button" {...visuallyHiddenProps} {...dropIndicator?.dropIndicatorProps} ref={dropIndicatorRef} />
|
|
307
|
+
</div>
|
|
308
|
+
</div>
|
|
309
|
+
}
|
|
310
|
+
<div
|
|
311
|
+
{...mergeProps(rowProps, focusProps, hoverProps, draggableItem?.dragProps)}
|
|
312
|
+
{...renderProps}
|
|
313
|
+
ref={ref}
|
|
314
|
+
data-hovered={isHovered || undefined}
|
|
315
|
+
data-focused={states.isFocused || undefined}
|
|
316
|
+
data-focus-visible={isFocusVisible || undefined}
|
|
317
|
+
data-pressed={states.isPressed || undefined}
|
|
318
|
+
data-dragging={isDragging || undefined}
|
|
319
|
+
data-drop-target={dropIndicator?.isDropTarget || undefined}>
|
|
320
|
+
<div {...gridCellProps}>
|
|
321
|
+
<Provider
|
|
322
|
+
values={[
|
|
323
|
+
[CheckboxContext, checkboxProps],
|
|
324
|
+
[ButtonContext, {
|
|
325
|
+
slots: {
|
|
326
|
+
[defaultSlot]: {},
|
|
327
|
+
drag: {
|
|
328
|
+
...draggableItem?.dragButtonProps,
|
|
329
|
+
ref: dragButtonRef,
|
|
330
|
+
style: {
|
|
331
|
+
pointerEvents: 'none'
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}],
|
|
336
|
+
[TextContext, {
|
|
337
|
+
slots: {
|
|
338
|
+
description: descriptionProps
|
|
339
|
+
}
|
|
340
|
+
}]
|
|
341
|
+
]}>
|
|
342
|
+
{renderProps.children}
|
|
343
|
+
</Provider>
|
|
344
|
+
</div>
|
|
345
|
+
</div>
|
|
346
|
+
{dragAndDropHooks?.useDropIndicator && state.collection.getKeyAfter(item.key) == null &&
|
|
347
|
+
renderDropIndicator({type: 'item', key: item.key, dropPosition: 'after'})
|
|
348
|
+
}
|
|
349
|
+
</>
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function GridListDropIndicator(props: DropIndicatorProps, ref: ForwardedRef<HTMLElement>) {
|
|
354
|
+
ref = useObjectRef(ref);
|
|
355
|
+
let {dragAndDropHooks, dropState} = useContext(InternalGridListContext)!;
|
|
356
|
+
let buttonRef = useRef<HTMLDivElement>(null);
|
|
357
|
+
let {dropIndicatorProps, isHidden, isDropTarget} = dragAndDropHooks!.useDropIndicator!(
|
|
358
|
+
props,
|
|
359
|
+
dropState!,
|
|
360
|
+
buttonRef
|
|
361
|
+
);
|
|
362
|
+
|
|
363
|
+
let {visuallyHiddenProps} = useVisuallyHidden();
|
|
364
|
+
|
|
365
|
+
if (isHidden) {
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
370
|
+
let renderProps = useRenderProps({
|
|
371
|
+
...props,
|
|
372
|
+
defaultClassName: 'react-aria-DropIndicator',
|
|
373
|
+
values: {
|
|
374
|
+
isDropTarget
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
return (
|
|
379
|
+
<div
|
|
380
|
+
{...renderProps}
|
|
381
|
+
role="row"
|
|
382
|
+
ref={ref as RefObject<HTMLDivElement>}
|
|
383
|
+
data-drop-target={isDropTarget || undefined}>
|
|
384
|
+
<div role="gridcell">
|
|
385
|
+
<div {...visuallyHiddenProps} role="button" {...dropIndicatorProps} ref={buttonRef} />
|
|
386
|
+
</div>
|
|
387
|
+
</div>
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function RootDropIndicator() {
|
|
392
|
+
let {dragAndDropHooks, dropState} = useContext(InternalGridListContext)!;
|
|
393
|
+
let ref = useRef<HTMLDivElement>(null);
|
|
394
|
+
let {dropIndicatorProps} = dragAndDropHooks!.useDropIndicator!({
|
|
395
|
+
target: {type: 'root'}
|
|
396
|
+
}, dropState!, ref);
|
|
397
|
+
let isDropTarget = dropState!.isDropTarget({type: 'root'});
|
|
398
|
+
let {visuallyHiddenProps} = useVisuallyHidden();
|
|
399
|
+
|
|
400
|
+
if (!isDropTarget && dropIndicatorProps['aria-hidden']) {
|
|
401
|
+
return null;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return (
|
|
405
|
+
<div role="row" aria-hidden={dropIndicatorProps['aria-hidden']} style={{position: 'absolute'}}>
|
|
406
|
+
<div role="gridcell">
|
|
407
|
+
<div role="button" {...visuallyHiddenProps} {...dropIndicatorProps} ref={ref} />
|
|
408
|
+
</div>
|
|
409
|
+
</div>
|
|
410
|
+
);
|
|
411
|
+
}
|
package/src/Group.tsx
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {ContextValue, StyleRenderProps, useContextProps, useRenderProps} from './utils';
|
|
14
|
+
import {mergeProps, useFocusRing, useHover} from 'react-aria';
|
|
15
|
+
import React, {createContext, ForwardedRef, forwardRef, HTMLAttributes} from 'react';
|
|
16
|
+
|
|
17
|
+
export interface GroupRenderProps {
|
|
18
|
+
/**
|
|
19
|
+
* Whether the group is currently hovered with a mouse.
|
|
20
|
+
* @selector [data-hovered]
|
|
21
|
+
*/
|
|
22
|
+
isHovered: boolean,
|
|
23
|
+
/**
|
|
24
|
+
* Whether an element within the group is focused, either via a mouse or keyboard.
|
|
25
|
+
* @selector :focus-within
|
|
26
|
+
*/
|
|
27
|
+
isFocusWithin: boolean,
|
|
28
|
+
/**
|
|
29
|
+
* Whether an element within the group is keyboard focused.
|
|
30
|
+
* @selector [data-focus-visible]
|
|
31
|
+
*/
|
|
32
|
+
isFocusVisible: boolean
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface GroupProps extends Omit<HTMLAttributes<HTMLElement>, 'className' | 'style'>, StyleRenderProps<GroupRenderProps> {}
|
|
36
|
+
|
|
37
|
+
export const GroupContext = createContext<ContextValue<GroupProps, HTMLDivElement>>({});
|
|
38
|
+
|
|
39
|
+
function Group(props: GroupProps, ref: ForwardedRef<HTMLDivElement>) {
|
|
40
|
+
[props, ref] = useContextProps(props, ref, GroupContext);
|
|
41
|
+
|
|
42
|
+
let {hoverProps, isHovered} = useHover({});
|
|
43
|
+
let {isFocused, isFocusVisible, focusProps} = useFocusRing({
|
|
44
|
+
within: true
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
let renderProps = useRenderProps({
|
|
48
|
+
...props,
|
|
49
|
+
values: {isHovered, isFocusWithin: isFocused, isFocusVisible},
|
|
50
|
+
defaultClassName: 'react-aria-Group'
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<div
|
|
55
|
+
{...mergeProps(props, focusProps, hoverProps)}
|
|
56
|
+
{...renderProps}
|
|
57
|
+
ref={ref}
|
|
58
|
+
data-hovered={isHovered || undefined}
|
|
59
|
+
data-focus-visible={isFocusVisible || undefined}>
|
|
60
|
+
{props.children}
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* An group represents a set of related UI controls.
|
|
67
|
+
*/
|
|
68
|
+
const _Group = forwardRef(Group);
|
|
69
|
+
export {_Group as Group};
|
package/src/Header.tsx
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {ContextValue, useContextProps} from './utils';
|
|
14
|
+
import React, {createContext, ForwardedRef, forwardRef, HTMLAttributes} from 'react';
|
|
15
|
+
import {useShallowRender} from './Collection';
|
|
16
|
+
|
|
17
|
+
export const HeaderContext = createContext<ContextValue<HTMLAttributes<HTMLElement>, HTMLElement>>({});
|
|
18
|
+
|
|
19
|
+
function Header(props: HTMLAttributes<HTMLElement>, ref: ForwardedRef<HTMLElement>) {
|
|
20
|
+
[props, ref] = useContextProps(props, ref, HeaderContext);
|
|
21
|
+
let shallow = useShallowRender('header', props, ref);
|
|
22
|
+
if (shallow) {
|
|
23
|
+
return shallow;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<header className="react-aria-Header" {...props} ref={ref}>
|
|
28
|
+
{props.children}
|
|
29
|
+
</header>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const _Header = forwardRef(Header);
|
|
34
|
+
export {_Header as Header};
|
package/src/Heading.tsx
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {ContextValue, useContextProps} from './utils';
|
|
14
|
+
import React, {createContext, ElementType, ForwardedRef, forwardRef, HTMLAttributes} from 'react';
|
|
15
|
+
|
|
16
|
+
export interface HeadingProps extends HTMLAttributes<HTMLElement> {
|
|
17
|
+
level?: number
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const HeadingContext = createContext<ContextValue<HeadingProps, HTMLHeadingElement>>({});
|
|
21
|
+
|
|
22
|
+
function Heading(props: HeadingProps, ref: ForwardedRef<HTMLHeadingElement>) {
|
|
23
|
+
[props, ref] = useContextProps(props, ref, HeadingContext);
|
|
24
|
+
let {children, level = 3, className, ...domProps} = props;
|
|
25
|
+
let Element = `h${level}` as ElementType;
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<Element {...domProps} className={className ?? 'react-aria-Heading'}>
|
|
29
|
+
{children}
|
|
30
|
+
</Element>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const _Heading = forwardRef(Heading);
|
|
35
|
+
export {_Heading as Heading};
|
package/src/Input.tsx
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {ContextValue, StyleRenderProps, useContextProps, useRenderProps} from './utils';
|
|
14
|
+
import {mergeProps, useFocusRing, useHover} from 'react-aria';
|
|
15
|
+
import React, {createContext, ForwardedRef, forwardRef, InputHTMLAttributes} from 'react';
|
|
16
|
+
|
|
17
|
+
export interface InputRenderProps {
|
|
18
|
+
/**
|
|
19
|
+
* Whether the input is currently hovered with a mouse.
|
|
20
|
+
* @selector [data-hovered]
|
|
21
|
+
*/
|
|
22
|
+
isHovered: boolean,
|
|
23
|
+
/**
|
|
24
|
+
* Whether the input is focused, either via a mouse or keyboard.
|
|
25
|
+
* @selector :focus
|
|
26
|
+
*/
|
|
27
|
+
isFocused: boolean,
|
|
28
|
+
/**
|
|
29
|
+
* Whether the input is keyboard focused.
|
|
30
|
+
* @selector [data-focus-visible]
|
|
31
|
+
*/
|
|
32
|
+
isFocusVisible: boolean,
|
|
33
|
+
/**
|
|
34
|
+
* Whether the input is disabled.
|
|
35
|
+
* @selector :disabled
|
|
36
|
+
*/
|
|
37
|
+
isDisabled: boolean
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'className' | 'style'>, StyleRenderProps<InputRenderProps> {}
|
|
41
|
+
|
|
42
|
+
export const InputContext = createContext<ContextValue<InputProps, HTMLInputElement>>({});
|
|
43
|
+
|
|
44
|
+
function Input(props: InputProps, ref: ForwardedRef<HTMLInputElement>) {
|
|
45
|
+
[props, ref] = useContextProps(props, ref, InputContext);
|
|
46
|
+
|
|
47
|
+
let {hoverProps, isHovered} = useHover({});
|
|
48
|
+
let {isFocused, isFocusVisible, focusProps} = useFocusRing({
|
|
49
|
+
isTextInput: true,
|
|
50
|
+
autoFocus: props.autoFocus
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
let renderProps = useRenderProps({
|
|
54
|
+
...props,
|
|
55
|
+
values: {isHovered, isFocused, isFocusVisible, isDisabled: props.disabled || false},
|
|
56
|
+
defaultClassName: 'react-aria-Input'
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<input
|
|
61
|
+
{...mergeProps(props, focusProps, hoverProps)}
|
|
62
|
+
{...renderProps}
|
|
63
|
+
ref={ref}
|
|
64
|
+
data-hovered={isHovered || undefined}
|
|
65
|
+
data-focus-visible={isFocusVisible || undefined} />
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* An input allows a user to input text.
|
|
71
|
+
*/
|
|
72
|
+
const _Input = forwardRef(Input);
|
|
73
|
+
export {_Input as Input};
|
package/src/Keyboard.tsx
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {ContextValue, useContextProps} from './utils';
|
|
14
|
+
import React, {createContext, ForwardedRef, forwardRef, HTMLAttributes} from 'react';
|
|
15
|
+
|
|
16
|
+
export const KeyboardContext = createContext<ContextValue<HTMLAttributes<HTMLElement>, HTMLElement>>({});
|
|
17
|
+
|
|
18
|
+
function Keyboard(props: HTMLAttributes<HTMLElement>, ref: ForwardedRef<HTMLElement>) {
|
|
19
|
+
[props, ref] = useContextProps(props, ref, KeyboardContext);
|
|
20
|
+
return <kbd dir="ltr" {...props} ref={ref} />;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const _Keyboard = forwardRef(Keyboard);
|
|
24
|
+
export {_Keyboard as Keyboard};
|
package/src/Label.tsx
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {ContextValue, useContextProps} from './utils';
|
|
14
|
+
import React, {createContext, ForwardedRef, forwardRef, LabelHTMLAttributes} from 'react';
|
|
15
|
+
|
|
16
|
+
export interface LabelProps extends LabelHTMLAttributes<HTMLLabelElement> {
|
|
17
|
+
elementType?: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const LabelContext = createContext<ContextValue<LabelProps, HTMLLabelElement>>({});
|
|
21
|
+
|
|
22
|
+
function Label(props: LabelProps, ref: ForwardedRef<HTMLLabelElement>) {
|
|
23
|
+
[props, ref] = useContextProps(props, ref, LabelContext);
|
|
24
|
+
let {elementType: ElementType = 'label', ...labelProps} = props;
|
|
25
|
+
// @ts-ignore
|
|
26
|
+
return <ElementType className="react-aria-Label" {...labelProps} ref={ref} />;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const _Label = forwardRef(Label);
|
|
30
|
+
export {_Label as Label};
|