@react-spectrum/list 3.0.0-alpha.10 → 3.0.0-alpha.11
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/main.css +1 -1
- package/dist/main.js +530 -338
- package/dist/main.js.map +1 -1
- package/dist/module.js +532 -340
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +3 -31
- package/dist/types.d.ts.map +1 -1
- package/package.json +39 -37
- package/src/DragPreview.tsx +28 -40
- package/src/InsertionIndicator.tsx +42 -0
- package/src/ListView.tsx +170 -120
- package/src/ListViewItem.tsx +129 -65
- package/src/RootDropIndicator.tsx +25 -0
- package/src/{listview.css → styles.css} +264 -33
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import {classNames} from '@react-spectrum/utils';
|
|
2
|
+
import {ItemDropTarget} from '@react-types/shared';
|
|
3
|
+
import listStyles from './styles.css';
|
|
4
|
+
import {ListViewContext} from './ListView';
|
|
5
|
+
import React, {useContext, useRef} from 'react';
|
|
6
|
+
import {useVisuallyHidden} from '@react-aria/visually-hidden';
|
|
7
|
+
|
|
8
|
+
interface InsertionIndicatorProps {
|
|
9
|
+
target: ItemDropTarget,
|
|
10
|
+
isPresentationOnly?: boolean
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default function InsertionIndicator(props: InsertionIndicatorProps) {
|
|
14
|
+
let {dropState, dropHooks} = useContext(ListViewContext);
|
|
15
|
+
const {target, isPresentationOnly} = props;
|
|
16
|
+
|
|
17
|
+
let ref = useRef();
|
|
18
|
+
let {dropIndicatorProps} = dropHooks.useDropIndicator(props, dropState, ref);
|
|
19
|
+
let {visuallyHiddenProps} = useVisuallyHidden();
|
|
20
|
+
|
|
21
|
+
let isDropTarget = dropState.isDropTarget(target);
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div role="row" aria-hidden={dropIndicatorProps['aria-hidden']}>
|
|
25
|
+
<div
|
|
26
|
+
role="gridcell"
|
|
27
|
+
aria-selected="false"
|
|
28
|
+
className={
|
|
29
|
+
classNames(
|
|
30
|
+
listStyles,
|
|
31
|
+
'react-spectrum-ListViewInsertionIndicator',
|
|
32
|
+
{
|
|
33
|
+
'react-spectrum-ListViewInsertionIndicator--dropTarget': isDropTarget
|
|
34
|
+
}
|
|
35
|
+
)}>
|
|
36
|
+
{!isPresentationOnly &&
|
|
37
|
+
<div {...visuallyHiddenProps} role="button" {...dropIndicatorProps} ref={ref} />
|
|
38
|
+
}
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
);
|
|
42
|
+
}
|
package/src/ListView.tsx
CHANGED
|
@@ -9,42 +9,42 @@
|
|
|
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 {
|
|
13
|
-
AriaLabelingProps,
|
|
14
|
-
AsyncLoadable,
|
|
15
|
-
CollectionBase,
|
|
16
|
-
DOMProps,
|
|
17
|
-
DOMRef,
|
|
18
|
-
LoadingState,
|
|
19
|
-
MultipleSelection,
|
|
20
|
-
SpectrumSelectionProps,
|
|
21
|
-
StyleProps
|
|
22
|
-
} from '@react-types/shared';
|
|
23
12
|
import {classNames, useDOMRef, useStyleProps} from '@react-spectrum/utils';
|
|
24
|
-
import
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
13
|
+
import {DOMRef, LoadingState} from '@react-types/shared';
|
|
14
|
+
import type {DraggableCollectionState, DroppableCollectionState} from '@react-stately/dnd';
|
|
15
|
+
import {DragHooks, DropHooks} from '@react-spectrum/dnd';
|
|
16
|
+
import type {DroppableCollectionResult} from '@react-aria/dnd';
|
|
17
|
+
import {filterDOMProps, useLayoutEffect} from '@react-aria/utils';
|
|
18
|
+
import InsertionIndicator from './InsertionIndicator';
|
|
29
19
|
// @ts-ignore
|
|
30
20
|
import intlMessages from '../intl/*.json';
|
|
31
21
|
import {ListLayout} from '@react-stately/layout';
|
|
32
22
|
import {ListState, useListState} from '@react-stately/list';
|
|
33
|
-
import listStyles from './
|
|
23
|
+
import listStyles from './styles.css';
|
|
34
24
|
import {ListViewItem} from './ListViewItem';
|
|
25
|
+
import {mergeProps} from '@react-aria/utils';
|
|
35
26
|
import {ProgressCircle} from '@react-spectrum/progress';
|
|
36
|
-
import React, {ReactElement, useContext, useMemo, useRef} from 'react';
|
|
37
|
-
import {
|
|
27
|
+
import React, {Key, ReactElement, useContext, useMemo, useRef, useState} from 'react';
|
|
28
|
+
import {Rect} from '@react-stately/virtualizer';
|
|
29
|
+
import RootDropIndicator from './RootDropIndicator';
|
|
30
|
+
import {DragPreview as SpectrumDragPreview} from './DragPreview';
|
|
31
|
+
import {SpectrumListProps} from '@react-types/list';
|
|
32
|
+
import {useCollator, useMessageFormatter} from '@react-aria/i18n';
|
|
33
|
+
import {useList} from '@react-aria/list';
|
|
38
34
|
import {useProvider} from '@react-spectrum/provider';
|
|
39
35
|
import {Virtualizer} from '@react-aria/virtualizer';
|
|
40
36
|
|
|
41
37
|
interface ListViewContextValue<T> {
|
|
42
|
-
state:
|
|
43
|
-
keyboardDelegate: GridKeyboardDelegate<T, GridCollection<any>>,
|
|
38
|
+
state: ListState<T>,
|
|
44
39
|
dragState: DraggableCollectionState,
|
|
45
|
-
|
|
40
|
+
dropState: DroppableCollectionState,
|
|
41
|
+
dragHooks: DragHooks,
|
|
42
|
+
dropHooks: DropHooks,
|
|
43
|
+
onAction:(key: Key) => void,
|
|
46
44
|
isListDraggable: boolean,
|
|
47
|
-
|
|
45
|
+
isListDroppable: boolean,
|
|
46
|
+
layout: ListLayout<T>,
|
|
47
|
+
loadingState: LoadingState
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
export const ListViewContext = React.createContext<ListViewContextValue<unknown>>(null);
|
|
@@ -64,7 +64,7 @@ const ROW_HEIGHTS = {
|
|
|
64
64
|
}
|
|
65
65
|
};
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
function useListLayout<T>(state: ListState<T>, density: SpectrumListProps<T>['density'], allowDisabledKeyFocus: boolean) {
|
|
68
68
|
let {scale} = useProvider();
|
|
69
69
|
let collator = useCollator({usage: 'search', sensitivity: 'base'});
|
|
70
70
|
let isEmpty = state.collection.size === 0;
|
|
@@ -73,136 +73,155 @@ export function useListLayout<T>(state: ListState<T>, density: ListViewProps<T>[
|
|
|
73
73
|
estimatedRowHeight: ROW_HEIGHTS[density][scale],
|
|
74
74
|
padding: 0,
|
|
75
75
|
collator,
|
|
76
|
-
loaderHeight: isEmpty ? null : ROW_HEIGHTS[density][scale]
|
|
76
|
+
loaderHeight: isEmpty ? null : ROW_HEIGHTS[density][scale],
|
|
77
|
+
allowDisabledKeyFocus
|
|
77
78
|
})
|
|
78
|
-
, [collator, scale, density, isEmpty]);
|
|
79
|
+
, [collator, scale, density, isEmpty, allowDisabledKeyFocus]);
|
|
79
80
|
|
|
80
81
|
layout.collection = state.collection;
|
|
81
82
|
layout.disabledKeys = state.disabledKeys;
|
|
82
83
|
return layout;
|
|
83
84
|
}
|
|
84
85
|
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Sets the amount of vertical padding within each cell.
|
|
88
|
-
* @default 'regular'
|
|
89
|
-
*/
|
|
90
|
-
density?: 'compact' | 'regular' | 'spacious',
|
|
91
|
-
/** Whether the ListView should be displayed with a quiet style. */
|
|
92
|
-
isQuiet?: boolean,
|
|
93
|
-
/** The current loading state of the ListView. Determines whether or not the progress circle should be shown. */
|
|
94
|
-
loadingState?: LoadingState,
|
|
95
|
-
/** Sets what the ListView should render when there is no content to display. */
|
|
96
|
-
renderEmptyState?: () => JSX.Element,
|
|
97
|
-
/**
|
|
98
|
-
* The duration of animated layout changes, in milliseconds. Used by the Virtualizer.
|
|
99
|
-
* @default 0
|
|
100
|
-
*/
|
|
101
|
-
transitionDuration?: number,
|
|
102
|
-
/**
|
|
103
|
-
* Handler that is called when a user performs an action on an item. The exact user event depends on
|
|
104
|
-
* the collection's `selectionBehavior` prop and the interaction modality.
|
|
105
|
-
*/
|
|
106
|
-
onAction?: (key: string) => void,
|
|
107
|
-
/**
|
|
108
|
-
* The drag hooks returned by `useDragHooks` used to enable drag and drop behavior for the ListView. See the
|
|
109
|
-
* [docs](https://react-spectrum.adobe.com/react-spectrum/useDragHooks.html) for more info.
|
|
110
|
-
*/
|
|
111
|
-
dragHooks?: DragHooks
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function ListView<T extends object>(props: ListViewProps<T>, ref: DOMRef<HTMLDivElement>) {
|
|
86
|
+
function ListView<T extends object>(props: SpectrumListProps<T>, ref: DOMRef<HTMLDivElement>) {
|
|
115
87
|
let {
|
|
116
88
|
density = 'regular',
|
|
117
89
|
onLoadMore,
|
|
118
90
|
loadingState,
|
|
119
91
|
isQuiet,
|
|
120
|
-
|
|
92
|
+
overflowMode = 'truncate',
|
|
121
93
|
onAction,
|
|
122
|
-
dragHooks
|
|
94
|
+
dragHooks,
|
|
95
|
+
dropHooks,
|
|
96
|
+
...otherProps
|
|
123
97
|
} = props;
|
|
124
98
|
let isListDraggable = !!dragHooks;
|
|
99
|
+
let isListDroppable = !!dropHooks;
|
|
125
100
|
let dragHooksProvided = useRef(isListDraggable);
|
|
101
|
+
let dropHooksProvided = useRef(isListDroppable);
|
|
126
102
|
if (dragHooksProvided.current !== isListDraggable) {
|
|
127
103
|
console.warn('Drag hooks were provided during one render, but not another. This should be avoided as it may produce unexpected behavior.');
|
|
128
104
|
}
|
|
105
|
+
if (dropHooksProvided.current !== isListDroppable) {
|
|
106
|
+
console.warn('Drop hooks were provided during one render, but not another. This should be avoided as it may produce unexpected behavior.');
|
|
107
|
+
}
|
|
129
108
|
let domRef = useDOMRef(ref);
|
|
130
|
-
let
|
|
131
|
-
let formatMessage = useMessageFormatter(intlMessages);
|
|
132
|
-
let isLoading = loadingState === 'loading' || loadingState === 'loadingMore';
|
|
133
|
-
|
|
134
|
-
let {styleProps} = useStyleProps(props);
|
|
135
|
-
let {direction, locale} = useLocale();
|
|
136
|
-
let collator = useCollator({usage: 'search', sensitivity: 'base'});
|
|
137
|
-
let gridCollection = useMemo(() => new GridCollection({
|
|
138
|
-
columnCount: 1,
|
|
139
|
-
items: [...collection].map(item => ({
|
|
140
|
-
...item,
|
|
141
|
-
hasChildNodes: true,
|
|
142
|
-
childNodes: [{
|
|
143
|
-
key: `cell-${item.key}`,
|
|
144
|
-
type: 'cell',
|
|
145
|
-
index: 0,
|
|
146
|
-
value: null,
|
|
147
|
-
level: 0,
|
|
148
|
-
rendered: null,
|
|
149
|
-
textValue: item.textValue,
|
|
150
|
-
hasChildNodes: false,
|
|
151
|
-
childNodes: []
|
|
152
|
-
}]
|
|
153
|
-
}))
|
|
154
|
-
}), [collection]);
|
|
155
|
-
let state = useGridState({
|
|
109
|
+
let state = useListState({
|
|
156
110
|
...props,
|
|
157
|
-
collection: gridCollection,
|
|
158
|
-
focusMode: 'cell',
|
|
159
111
|
selectionBehavior: props.selectionStyle === 'highlight' ? 'replace' : 'toggle'
|
|
160
112
|
});
|
|
161
|
-
let
|
|
162
|
-
let
|
|
163
|
-
|
|
164
|
-
disabledKeys: state.disabledKeys,
|
|
165
|
-
ref: domRef,
|
|
166
|
-
direction,
|
|
167
|
-
collator,
|
|
168
|
-
// Focus the ListView cell instead of the row so that focus doesn't change with left/right arrow keys when there aren't any
|
|
169
|
-
// focusable children in the cell.
|
|
170
|
-
focusMode: 'cell'
|
|
171
|
-
}), [state, domRef, direction, collator]);
|
|
113
|
+
let {collection, selectionManager} = state;
|
|
114
|
+
let formatMessage = useMessageFormatter(intlMessages);
|
|
115
|
+
let isLoading = loadingState === 'loading' || loadingState === 'loadingMore';
|
|
172
116
|
|
|
173
|
-
let
|
|
117
|
+
let {styleProps} = useStyleProps(props);
|
|
118
|
+
let layout = useListLayout(state, props.density || 'regular', state.selectionManager.disabledBehavior === 'selection');
|
|
174
119
|
let dragState: DraggableCollectionState;
|
|
120
|
+
let preview = useRef(null);
|
|
175
121
|
if (isListDraggable) {
|
|
176
122
|
dragState = dragHooks.useDraggableCollectionState({
|
|
177
|
-
collection
|
|
178
|
-
selectionManager
|
|
179
|
-
|
|
180
|
-
let item = state.collection.getItem(draggedKey);
|
|
181
|
-
let itemCount = draggingKeys.size;
|
|
182
|
-
let itemHeight = layout.getLayoutInfo(draggedKey).rect.height;
|
|
183
|
-
return <DragPreview item={item} itemCount={itemCount} itemHeight={itemHeight} provider={provider} locale={locale} />;
|
|
184
|
-
}
|
|
123
|
+
collection,
|
|
124
|
+
selectionManager,
|
|
125
|
+
preview
|
|
185
126
|
});
|
|
186
127
|
}
|
|
187
128
|
|
|
188
|
-
let
|
|
129
|
+
let DragPreview = dragHooks?.DragPreview;
|
|
130
|
+
let dropState: DroppableCollectionState;
|
|
131
|
+
let droppableCollection: DroppableCollectionResult;
|
|
132
|
+
let isRootDropTarget: boolean;
|
|
133
|
+
if (isListDroppable) {
|
|
134
|
+
dropState = dropHooks.useDroppableCollectionState({
|
|
135
|
+
collection,
|
|
136
|
+
selectionManager
|
|
137
|
+
});
|
|
138
|
+
droppableCollection = dropHooks.useDroppableCollection({
|
|
139
|
+
keyboardDelegate: layout,
|
|
140
|
+
getDropTargetFromPoint(x, y) {
|
|
141
|
+
let closest = null;
|
|
142
|
+
let closestDistance = Infinity;
|
|
143
|
+
let closestDir = null;
|
|
144
|
+
|
|
145
|
+
x += domRef.current.scrollLeft;
|
|
146
|
+
y += domRef.current.scrollTop;
|
|
147
|
+
|
|
148
|
+
let visible = layout.getVisibleLayoutInfos(new Rect(x - 50, y - 50, x + 50, y + 50));
|
|
149
|
+
|
|
150
|
+
for (let layoutInfo of visible) {
|
|
151
|
+
let r = layoutInfo.rect;
|
|
152
|
+
let points: [number, number, string][] = [
|
|
153
|
+
[r.x, r.y + 4, 'before'],
|
|
154
|
+
[r.maxX, r.y + 4, 'before'],
|
|
155
|
+
[r.x, r.maxY - 8, 'after'],
|
|
156
|
+
[r.maxX, r.maxY - 8, 'after']
|
|
157
|
+
];
|
|
158
|
+
|
|
159
|
+
for (let [px, py, dir] of points) {
|
|
160
|
+
let dx = px - x;
|
|
161
|
+
let dy = py - y;
|
|
162
|
+
let d = dx * dx + dy * dy;
|
|
163
|
+
if (d < closestDistance) {
|
|
164
|
+
closestDistance = d;
|
|
165
|
+
closest = layoutInfo;
|
|
166
|
+
closestDir = dir;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// TODO: Best way to implement only for when closest can be dropped on
|
|
171
|
+
// TODO: Figure out the typescript for this
|
|
172
|
+
// @ts-ignore
|
|
173
|
+
if (y >= r.y + 10 && y <= r.maxY - 10 && collection.getItem(closest.key).value.type === 'folder') {
|
|
174
|
+
closestDir = 'on';
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
let key = closest?.key;
|
|
179
|
+
if (key) {
|
|
180
|
+
return {
|
|
181
|
+
type: 'item',
|
|
182
|
+
key,
|
|
183
|
+
dropPosition: closestDir
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}, dropState, domRef);
|
|
188
|
+
|
|
189
|
+
isRootDropTarget = dropState.isDropTarget({type: 'root'});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
let {gridProps} = useList({
|
|
189
193
|
...props,
|
|
190
194
|
isVirtualized: true,
|
|
191
|
-
keyboardDelegate
|
|
195
|
+
keyboardDelegate: layout,
|
|
196
|
+
onAction
|
|
192
197
|
}, state, domRef);
|
|
193
198
|
|
|
194
199
|
// Sync loading state into the layout.
|
|
195
200
|
layout.isLoading = isLoading;
|
|
196
201
|
|
|
197
|
-
let focusedKey =
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
focusedKey = focusedItem.parentKey;
|
|
202
|
+
let focusedKey = selectionManager.focusedKey;
|
|
203
|
+
if (dropState?.target?.type === 'item') {
|
|
204
|
+
focusedKey = dropState.target.key;
|
|
201
205
|
}
|
|
202
206
|
|
|
207
|
+
// wait for layout to get accurate measurements
|
|
208
|
+
let [isVerticalScrollbarVisible, setVerticalScollbarVisible] = useState(false);
|
|
209
|
+
let [isHorizontalScrollbarVisible, setHorizontalScollbarVisible] = useState(false);
|
|
210
|
+
useLayoutEffect(() => {
|
|
211
|
+
if (domRef.current) {
|
|
212
|
+
// 2 is the width of the border which is not part of the box size
|
|
213
|
+
setVerticalScollbarVisible(domRef.current.clientWidth + 2 < domRef.current.offsetWidth);
|
|
214
|
+
setHorizontalScollbarVisible(domRef.current.clientHeight + 2 < domRef.current.offsetHeight);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
let hasAnyChildren = useMemo(() => [...collection].some(item => item.hasChildNodes), [collection]);
|
|
219
|
+
|
|
203
220
|
return (
|
|
204
|
-
<ListViewContext.Provider value={{state,
|
|
221
|
+
<ListViewContext.Provider value={{state, dragState, dropState, dragHooks, dropHooks, onAction, isListDraggable, isListDroppable, layout, loadingState}}>
|
|
205
222
|
<Virtualizer
|
|
223
|
+
{...mergeProps(isListDroppable && droppableCollection?.collectionProps, gridProps)}
|
|
224
|
+
{...filterDOMProps(otherProps)}
|
|
206
225
|
{...gridProps}
|
|
207
226
|
{...styleProps}
|
|
208
227
|
isLoading={isLoading}
|
|
@@ -218,26 +237,47 @@ function ListView<T extends object>(props: ListViewProps<T>, ref: DOMRef<HTMLDiv
|
|
|
218
237
|
'react-spectrum-ListView--emphasized',
|
|
219
238
|
{
|
|
220
239
|
'react-spectrum-ListView--quiet': isQuiet,
|
|
221
|
-
'react-spectrum-ListView--
|
|
222
|
-
'react-spectrum-ListView--
|
|
240
|
+
'react-spectrum-ListView--loadingMore': loadingState === 'loadingMore',
|
|
241
|
+
'react-spectrum-ListView--draggable': !!isListDraggable,
|
|
242
|
+
'react-spectrum-ListView--dropTarget': !!isRootDropTarget,
|
|
243
|
+
'react-spectrum-ListView--isVerticalScrollbarVisible': isVerticalScrollbarVisible,
|
|
244
|
+
'react-spectrum-ListView--isHorizontalScrollbarVisible': isHorizontalScrollbarVisible,
|
|
245
|
+
'react-spectrum-ListView--hasAnyChildren': hasAnyChildren,
|
|
246
|
+
'react-spectrum-ListView--wrap': overflowMode === 'wrap'
|
|
223
247
|
},
|
|
224
248
|
styleProps.className
|
|
225
249
|
)
|
|
226
250
|
}
|
|
227
251
|
layout={layout}
|
|
228
|
-
collection={
|
|
229
|
-
transitionDuration={
|
|
252
|
+
collection={collection}
|
|
253
|
+
transitionDuration={isLoading ? 160 : 220}>
|
|
230
254
|
{(type, item) => {
|
|
231
255
|
if (type === 'item') {
|
|
232
256
|
return (
|
|
233
|
-
|
|
257
|
+
<>
|
|
258
|
+
{isListDroppable && collection.getKeyBefore(item.key) == null &&
|
|
259
|
+
<RootDropIndicator key="root" />
|
|
260
|
+
}
|
|
261
|
+
{isListDroppable &&
|
|
262
|
+
<InsertionIndicator
|
|
263
|
+
key={`${item.key}-before`}
|
|
264
|
+
target={{key: item.key, type: 'item', dropPosition: 'before'}} />
|
|
265
|
+
}
|
|
266
|
+
<ListViewItem item={item} isEmphasized hasActions={!!onAction} />
|
|
267
|
+
{isListDroppable &&
|
|
268
|
+
<InsertionIndicator
|
|
269
|
+
key={`${item.key}-after`}
|
|
270
|
+
target={{key: item.key, type: 'item', dropPosition: 'after'}}
|
|
271
|
+
isPresentationOnly={collection.getKeyAfter(item.key) !== null} />
|
|
272
|
+
}
|
|
273
|
+
</>
|
|
234
274
|
);
|
|
235
275
|
} else if (type === 'loader') {
|
|
236
276
|
return (
|
|
237
277
|
<CenteredWrapper>
|
|
238
278
|
<ProgressCircle
|
|
239
279
|
isIndeterminate
|
|
240
|
-
aria-label={
|
|
280
|
+
aria-label={collection.size > 0 ? formatMessage('loadingMore') : formatMessage('loading')} />
|
|
241
281
|
</CenteredWrapper>
|
|
242
282
|
);
|
|
243
283
|
} else if (type === 'placeholder') {
|
|
@@ -255,6 +295,16 @@ function ListView<T extends object>(props: ListViewProps<T>, ref: DOMRef<HTMLDiv
|
|
|
255
295
|
|
|
256
296
|
}}
|
|
257
297
|
</Virtualizer>
|
|
298
|
+
{DragPreview && isListDraggable &&
|
|
299
|
+
<DragPreview ref={preview}>
|
|
300
|
+
{() => {
|
|
301
|
+
let item = state.collection.getItem(dragState.draggedKey);
|
|
302
|
+
let itemCount = dragState.draggingKeys.size;
|
|
303
|
+
let itemHeight = layout.getLayoutInfo(dragState.draggedKey).rect.height;
|
|
304
|
+
return <SpectrumDragPreview item={item} itemCount={itemCount} itemHeight={itemHeight} />;
|
|
305
|
+
}}
|
|
306
|
+
</DragPreview>
|
|
307
|
+
}
|
|
258
308
|
</ListViewContext.Provider>
|
|
259
309
|
);
|
|
260
310
|
}
|
|
@@ -283,5 +333,5 @@ function CenteredWrapper({children}) {
|
|
|
283
333
|
/**
|
|
284
334
|
* Lists display a linear collection of data. They allow users to quickly scan, sort, compare, and take action on large amounts of data.
|
|
285
335
|
*/
|
|
286
|
-
const _ListView = React.forwardRef(ListView) as <T>(props:
|
|
336
|
+
const _ListView = React.forwardRef(ListView) as <T>(props: SpectrumListProps<T> & {ref?: DOMRef<HTMLDivElement>}) => ReactElement;
|
|
287
337
|
export {_ListView as ListView};
|