@react-spectrum/list 3.0.0-alpha.9 → 3.0.0-beta.0
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 +572 -304
- package/dist/main.js.map +1 -1
- package/dist/module.js +574 -306
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +6 -16
- package/dist/types.d.ts.map +1 -1
- package/package.json +39 -35
- package/src/DragPreview.tsx +60 -0
- package/src/InsertionIndicator.tsx +46 -0
- package/src/ListView.tsx +184 -150
- package/src/ListViewItem.tsx +158 -62
- package/src/RootDropIndicator.tsx +28 -0
- package/src/styles.css +593 -0
- package/src/listview.css +0 -236
package/src/ListView.tsx
CHANGED
|
@@ -9,46 +9,45 @@
|
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
MultipleSelection,
|
|
20
|
-
SpectrumSelectionProps,
|
|
21
|
-
StyleProps
|
|
22
|
-
} from '@react-types/shared';
|
|
23
|
-
import {Checkbox} from '@react-spectrum/checkbox';
|
|
24
|
-
import {classNames, SlotProvider, useDOMRef, useStyleProps} from '@react-spectrum/utils';
|
|
25
|
-
import {Content} from '@react-spectrum/view';
|
|
26
|
-
import type {DraggableCollectionState} from '@react-stately/dnd';
|
|
27
|
-
import {DragHooks} from '@react-spectrum/dnd';
|
|
28
|
-
import {GridCollection, GridState, useGridState} from '@react-stately/grid';
|
|
29
|
-
import {GridKeyboardDelegate, useGrid, useGridSelectionCheckbox} from '@react-aria/grid';
|
|
12
|
+
import {classNames, useDOMRef, useStyleProps} from '@react-spectrum/utils';
|
|
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';
|
|
30
19
|
// @ts-ignore
|
|
31
20
|
import intlMessages from '../intl/*.json';
|
|
32
|
-
import ListGripper from '@spectrum-icons/ui/ListGripper';
|
|
33
21
|
import {ListLayout} from '@react-stately/layout';
|
|
34
22
|
import {ListState, useListState} from '@react-stately/list';
|
|
35
|
-
import listStyles from './
|
|
23
|
+
import listStyles from './styles.css';
|
|
36
24
|
import {ListViewItem} from './ListViewItem';
|
|
25
|
+
import {mergeProps} from '@react-aria/utils';
|
|
37
26
|
import {ProgressCircle} from '@react-spectrum/progress';
|
|
38
|
-
import {
|
|
39
|
-
import
|
|
40
|
-
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';
|
|
34
|
+
import {useProvider} from '@react-spectrum/provider';
|
|
41
35
|
import {Virtualizer} from '@react-aria/virtualizer';
|
|
42
36
|
|
|
43
|
-
interface ListViewContextValue {
|
|
44
|
-
state:
|
|
45
|
-
keyboardDelegate: GridKeyboardDelegate<unknown, GridCollection<any>>,
|
|
37
|
+
interface ListViewContextValue<T> {
|
|
38
|
+
state: ListState<T>,
|
|
46
39
|
dragState: DraggableCollectionState,
|
|
47
|
-
|
|
48
|
-
|
|
40
|
+
dropState: DroppableCollectionState,
|
|
41
|
+
dragHooks: DragHooks,
|
|
42
|
+
dropHooks: DropHooks,
|
|
43
|
+
onAction:(key: Key) => void,
|
|
44
|
+
isListDraggable: boolean,
|
|
45
|
+
isListDroppable: boolean,
|
|
46
|
+
layout: ListLayout<T>,
|
|
47
|
+
loadingState: LoadingState
|
|
49
48
|
}
|
|
50
49
|
|
|
51
|
-
export const ListViewContext = React.createContext<ListViewContextValue
|
|
50
|
+
export const ListViewContext = React.createContext<ListViewContextValue<unknown>>(null);
|
|
52
51
|
|
|
53
52
|
const ROW_HEIGHTS = {
|
|
54
53
|
compact: {
|
|
@@ -65,7 +64,7 @@ const ROW_HEIGHTS = {
|
|
|
65
64
|
}
|
|
66
65
|
};
|
|
67
66
|
|
|
68
|
-
|
|
67
|
+
function useListLayout<T>(state: ListState<T>, density: SpectrumListProps<T>['density'], overflowMode: SpectrumListProps<T>['overflowMode']) {
|
|
69
68
|
let {scale} = useProvider();
|
|
70
69
|
let collator = useCollator({usage: 'search', sensitivity: 'base'});
|
|
71
70
|
let isEmpty = state.collection.size === 0;
|
|
@@ -76,159 +75,160 @@ export function useListLayout<T>(state: ListState<T>, density: ListViewProps<T>[
|
|
|
76
75
|
collator,
|
|
77
76
|
loaderHeight: isEmpty ? null : ROW_HEIGHTS[density][scale]
|
|
78
77
|
})
|
|
79
|
-
|
|
78
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
79
|
+
, [collator, scale, density, isEmpty, overflowMode]);
|
|
80
80
|
|
|
81
81
|
layout.collection = state.collection;
|
|
82
82
|
layout.disabledKeys = state.disabledKeys;
|
|
83
83
|
return layout;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Sets the amount of vertical padding within each cell.
|
|
89
|
-
* @default 'regular'
|
|
90
|
-
*/
|
|
91
|
-
density?: 'compact' | 'regular' | 'spacious',
|
|
92
|
-
isQuiet?: boolean,
|
|
93
|
-
loadingState?: LoadingState,
|
|
94
|
-
renderEmptyState?: () => JSX.Element,
|
|
95
|
-
transitionDuration?: number,
|
|
96
|
-
onAction?: (key: string) => void,
|
|
97
|
-
dragHooks?: DragHooks
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function ListView<T extends object>(props: ListViewProps<T>, ref: DOMRef<HTMLDivElement>) {
|
|
86
|
+
function ListView<T extends object>(props: SpectrumListProps<T>, ref: DOMRef<HTMLDivElement>) {
|
|
101
87
|
let {
|
|
102
88
|
density = 'regular',
|
|
103
89
|
onLoadMore,
|
|
104
90
|
loadingState,
|
|
105
91
|
isQuiet,
|
|
106
|
-
|
|
92
|
+
overflowMode = 'truncate',
|
|
107
93
|
onAction,
|
|
108
|
-
dragHooks
|
|
94
|
+
dragHooks,
|
|
95
|
+
dropHooks,
|
|
96
|
+
...otherProps
|
|
109
97
|
} = props;
|
|
110
98
|
let isListDraggable = !!dragHooks;
|
|
99
|
+
let isListDroppable = !!dropHooks;
|
|
111
100
|
let dragHooksProvided = useRef(isListDraggable);
|
|
101
|
+
let dropHooksProvided = useRef(isListDroppable);
|
|
112
102
|
if (dragHooksProvided.current !== isListDraggable) {
|
|
113
103
|
console.warn('Drag hooks were provided during one render, but not another. This should be avoided as it may produce unexpected behavior.');
|
|
114
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
|
+
}
|
|
115
108
|
let domRef = useDOMRef(ref);
|
|
116
|
-
let
|
|
117
|
-
let formatMessage = useMessageFormatter(intlMessages);
|
|
118
|
-
let isLoading = loadingState === 'loading' || loadingState === 'loadingMore';
|
|
119
|
-
|
|
120
|
-
let {styleProps} = useStyleProps(props);
|
|
121
|
-
let {direction} = useLocale();
|
|
122
|
-
let collator = useCollator({usage: 'search', sensitivity: 'base'});
|
|
123
|
-
let gridCollection = useMemo(() => new GridCollection({
|
|
124
|
-
columnCount: 1,
|
|
125
|
-
items: [...collection].map(item => ({
|
|
126
|
-
...item,
|
|
127
|
-
hasChildNodes: true,
|
|
128
|
-
childNodes: [{
|
|
129
|
-
key: `cell-${item.key}`,
|
|
130
|
-
type: 'cell',
|
|
131
|
-
index: 0,
|
|
132
|
-
value: null,
|
|
133
|
-
level: 0,
|
|
134
|
-
rendered: null,
|
|
135
|
-
textValue: item.textValue,
|
|
136
|
-
hasChildNodes: false,
|
|
137
|
-
childNodes: []
|
|
138
|
-
}]
|
|
139
|
-
}))
|
|
140
|
-
}), [collection]);
|
|
141
|
-
let state = useGridState({
|
|
109
|
+
let state = useListState({
|
|
142
110
|
...props,
|
|
143
|
-
collection: gridCollection,
|
|
144
|
-
focusMode: 'cell',
|
|
145
111
|
selectionBehavior: props.selectionStyle === 'highlight' ? 'replace' : 'toggle'
|
|
146
112
|
});
|
|
147
|
-
let
|
|
148
|
-
let
|
|
149
|
-
|
|
150
|
-
disabledKeys: state.disabledKeys,
|
|
151
|
-
ref: domRef,
|
|
152
|
-
direction,
|
|
153
|
-
collator,
|
|
154
|
-
// Focus the ListView cell instead of the row so that focus doesn't change with left/right arrow keys when there aren't any
|
|
155
|
-
// focusable children in the cell.
|
|
156
|
-
focusMode: 'cell'
|
|
157
|
-
}), [state, domRef, direction, collator]);
|
|
113
|
+
let {collection, selectionManager} = state;
|
|
114
|
+
let formatMessage = useMessageFormatter(intlMessages);
|
|
115
|
+
let isLoading = loadingState === 'loading' || loadingState === 'loadingMore';
|
|
158
116
|
|
|
159
|
-
let
|
|
160
|
-
let {checkboxProps} = useGridSelectionCheckbox({key: null}, state);
|
|
117
|
+
let {styleProps} = useStyleProps(props);
|
|
161
118
|
let dragState: DraggableCollectionState;
|
|
119
|
+
let preview = useRef(null);
|
|
162
120
|
if (isListDraggable) {
|
|
163
121
|
dragState = dragHooks.useDraggableCollectionState({
|
|
164
|
-
collection
|
|
165
|
-
selectionManager
|
|
166
|
-
|
|
167
|
-
let item = state.collection.getItem(draggedKey);
|
|
168
|
-
let itemWidth = domRef.current.offsetWidth;
|
|
169
|
-
let showCheckbox = state.selectionManager.selectionMode !== 'none' && state.selectionManager.selectionBehavior === 'toggle';
|
|
170
|
-
let isSelected = state.selectionManager.isSelected(item.key);
|
|
171
|
-
return (
|
|
172
|
-
<Provider
|
|
173
|
-
{...provider}
|
|
174
|
-
UNSAFE_className={classNames(listStyles, 'react-spectrum-ListViewItem', 'is-dragging')}
|
|
175
|
-
UNSAFE_style={{width: itemWidth, paddingInlineStart: 0}}>
|
|
176
|
-
<div className={listStyles['react-spectrum-ListViewItem-grid']}>
|
|
177
|
-
<div className={listStyles['react-spectrum-ListViewItem-draghandle-container']}>
|
|
178
|
-
<div className={listStyles['react-spectrum-ListViewItem-draghandle-button']}>
|
|
179
|
-
<ListGripper />
|
|
180
|
-
</div>
|
|
181
|
-
</div>
|
|
182
|
-
{showCheckbox &&
|
|
183
|
-
<Checkbox
|
|
184
|
-
isSelected={isSelected}
|
|
185
|
-
UNSAFE_className={listStyles['react-spectrum-ListViewItem-checkbox']}
|
|
186
|
-
isEmphasized
|
|
187
|
-
aria-label={checkboxProps['aria-label']} />
|
|
188
|
-
}
|
|
189
|
-
<SlotProvider
|
|
190
|
-
slots={{
|
|
191
|
-
content: {UNSAFE_className: listStyles['react-spectrum-ListViewItem-content']},
|
|
192
|
-
text: {UNSAFE_className: listStyles['react-spectrum-ListViewItem-content']},
|
|
193
|
-
description: {UNSAFE_className: listStyles['react-spectrum-ListViewItem-description']},
|
|
194
|
-
icon: {UNSAFE_className: listStyles['react-spectrum-ListViewItem-icon'], size: 'M'},
|
|
195
|
-
image: {UNSAFE_className: listStyles['react-spectrum-ListViewItem-image']},
|
|
196
|
-
link: {UNSAFE_className: listStyles['react-spectrum-ListViewItem-content'], isQuiet: true},
|
|
197
|
-
actionButton: {UNSAFE_className: listStyles['react-spectrum-ListViewItem-actions'], isQuiet: true},
|
|
198
|
-
actionGroup: {
|
|
199
|
-
UNSAFE_className: listStyles['react-spectrum-ListViewItem-actions'],
|
|
200
|
-
isQuiet: true,
|
|
201
|
-
density: 'compact'
|
|
202
|
-
},
|
|
203
|
-
actionMenu: {UNSAFE_className: listStyles['react-spectrum-ListViewItem-actionmenu'], isQuiet: true}
|
|
204
|
-
}}>
|
|
205
|
-
{typeof item.rendered === 'string' ? <Content>{item.rendered}</Content> : item.rendered}
|
|
206
|
-
</SlotProvider>
|
|
207
|
-
</div>
|
|
208
|
-
</Provider>
|
|
209
|
-
);
|
|
210
|
-
}
|
|
122
|
+
collection,
|
|
123
|
+
selectionManager,
|
|
124
|
+
preview
|
|
211
125
|
});
|
|
212
126
|
}
|
|
127
|
+
let layout = useListLayout(
|
|
128
|
+
state,
|
|
129
|
+
props.density || 'regular',
|
|
130
|
+
overflowMode
|
|
131
|
+
);
|
|
132
|
+
// !!0 is false, so we can cast size or undefined and they'll be falsy
|
|
133
|
+
layout.allowDisabledKeyFocus = state.selectionManager.disabledBehavior === 'selection' || !!dragState?.draggingKeys.size;
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
let DragPreview = dragHooks?.DragPreview;
|
|
137
|
+
let dropState: DroppableCollectionState;
|
|
138
|
+
let droppableCollection: DroppableCollectionResult;
|
|
139
|
+
let isRootDropTarget: boolean;
|
|
140
|
+
if (isListDroppable) {
|
|
141
|
+
dropState = dropHooks.useDroppableCollectionState({
|
|
142
|
+
collection,
|
|
143
|
+
selectionManager
|
|
144
|
+
});
|
|
145
|
+
droppableCollection = dropHooks.useDroppableCollection({
|
|
146
|
+
keyboardDelegate: layout,
|
|
147
|
+
getDropTargetFromPoint(x, y) {
|
|
148
|
+
let closest = null;
|
|
149
|
+
let closestDistance = Infinity;
|
|
150
|
+
let closestDir = null;
|
|
151
|
+
|
|
152
|
+
x += domRef.current.scrollLeft;
|
|
153
|
+
y += domRef.current.scrollTop;
|
|
154
|
+
|
|
155
|
+
let visible = layout.getVisibleLayoutInfos(new Rect(x - 50, y - 50, x + 50, y + 50));
|
|
156
|
+
|
|
157
|
+
for (let layoutInfo of visible) {
|
|
158
|
+
let r = layoutInfo.rect;
|
|
159
|
+
let points: [number, number, string][] = [
|
|
160
|
+
[r.x, r.y + 4, 'before'],
|
|
161
|
+
[r.maxX, r.y + 4, 'before'],
|
|
162
|
+
[r.x, r.maxY - 8, 'after'],
|
|
163
|
+
[r.maxX, r.maxY - 8, 'after']
|
|
164
|
+
];
|
|
165
|
+
|
|
166
|
+
for (let [px, py, dir] of points) {
|
|
167
|
+
let dx = px - x;
|
|
168
|
+
let dy = py - y;
|
|
169
|
+
let d = dx * dx + dy * dy;
|
|
170
|
+
if (d < closestDistance) {
|
|
171
|
+
closestDistance = d;
|
|
172
|
+
closest = layoutInfo;
|
|
173
|
+
closestDir = dir;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// TODO: Best way to implement only for when closest can be dropped on
|
|
178
|
+
// TODO: Figure out the typescript for this
|
|
179
|
+
// @ts-ignore
|
|
180
|
+
if (y >= r.y + 10 && y <= r.maxY - 10 && collection.getItem(closest.key).value.type === 'folder') {
|
|
181
|
+
closestDir = 'on';
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
let key = closest?.key;
|
|
186
|
+
if (key) {
|
|
187
|
+
return {
|
|
188
|
+
type: 'item',
|
|
189
|
+
key,
|
|
190
|
+
dropPosition: closestDir
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}, dropState, domRef);
|
|
195
|
+
|
|
196
|
+
isRootDropTarget = dropState.isDropTarget({type: 'root'});
|
|
197
|
+
}
|
|
213
198
|
|
|
214
|
-
let {gridProps} =
|
|
199
|
+
let {gridProps} = useList({
|
|
215
200
|
...props,
|
|
216
201
|
isVirtualized: true,
|
|
217
|
-
keyboardDelegate
|
|
202
|
+
keyboardDelegate: layout,
|
|
203
|
+
onAction
|
|
218
204
|
}, state, domRef);
|
|
219
205
|
|
|
220
206
|
// Sync loading state into the layout.
|
|
221
207
|
layout.isLoading = isLoading;
|
|
222
208
|
|
|
223
|
-
let focusedKey =
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
focusedKey = focusedItem.parentKey;
|
|
209
|
+
let focusedKey = selectionManager.focusedKey;
|
|
210
|
+
if (dropState?.target?.type === 'item') {
|
|
211
|
+
focusedKey = dropState.target.key;
|
|
227
212
|
}
|
|
228
213
|
|
|
214
|
+
// wait for layout to get accurate measurements
|
|
215
|
+
let [isVerticalScrollbarVisible, setVerticalScollbarVisible] = useState(false);
|
|
216
|
+
let [isHorizontalScrollbarVisible, setHorizontalScollbarVisible] = useState(false);
|
|
217
|
+
useLayoutEffect(() => {
|
|
218
|
+
if (domRef.current) {
|
|
219
|
+
// 2 is the width of the border which is not part of the box size
|
|
220
|
+
setVerticalScollbarVisible(domRef.current.clientWidth + 2 < domRef.current.offsetWidth);
|
|
221
|
+
setHorizontalScollbarVisible(domRef.current.clientHeight + 2 < domRef.current.offsetHeight);
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
let hasAnyChildren = useMemo(() => [...collection].some(item => item.hasChildNodes), [collection]);
|
|
226
|
+
|
|
229
227
|
return (
|
|
230
|
-
<ListViewContext.Provider value={{state,
|
|
228
|
+
<ListViewContext.Provider value={{state, dragState, dropState, dragHooks, dropHooks, onAction, isListDraggable, isListDroppable, layout, loadingState}}>
|
|
231
229
|
<Virtualizer
|
|
230
|
+
{...mergeProps(isListDroppable && droppableCollection?.collectionProps, gridProps)}
|
|
231
|
+
{...filterDOMProps(otherProps)}
|
|
232
232
|
{...gridProps}
|
|
233
233
|
{...styleProps}
|
|
234
234
|
isLoading={isLoading}
|
|
@@ -244,25 +244,47 @@ function ListView<T extends object>(props: ListViewProps<T>, ref: DOMRef<HTMLDiv
|
|
|
244
244
|
'react-spectrum-ListView--emphasized',
|
|
245
245
|
{
|
|
246
246
|
'react-spectrum-ListView--quiet': isQuiet,
|
|
247
|
-
'react-spectrum-ListView--
|
|
247
|
+
'react-spectrum-ListView--loadingMore': loadingState === 'loadingMore',
|
|
248
|
+
'react-spectrum-ListView--draggable': !!isListDraggable,
|
|
249
|
+
'react-spectrum-ListView--dropTarget': !!isRootDropTarget,
|
|
250
|
+
'react-spectrum-ListView--isVerticalScrollbarVisible': isVerticalScrollbarVisible,
|
|
251
|
+
'react-spectrum-ListView--isHorizontalScrollbarVisible': isHorizontalScrollbarVisible,
|
|
252
|
+
'react-spectrum-ListView--hasAnyChildren': hasAnyChildren,
|
|
253
|
+
'react-spectrum-ListView--wrap': overflowMode === 'wrap'
|
|
248
254
|
},
|
|
249
255
|
styleProps.className
|
|
250
256
|
)
|
|
251
257
|
}
|
|
252
258
|
layout={layout}
|
|
253
|
-
collection={
|
|
254
|
-
transitionDuration={
|
|
259
|
+
collection={collection}
|
|
260
|
+
transitionDuration={isLoading ? 160 : 220}>
|
|
255
261
|
{(type, item) => {
|
|
256
262
|
if (type === 'item') {
|
|
257
263
|
return (
|
|
258
|
-
|
|
264
|
+
<>
|
|
265
|
+
{isListDroppable && collection.getKeyBefore(item.key) == null &&
|
|
266
|
+
<RootDropIndicator key="root" />
|
|
267
|
+
}
|
|
268
|
+
{isListDroppable &&
|
|
269
|
+
<InsertionIndicator
|
|
270
|
+
key={`${item.key}-before`}
|
|
271
|
+
target={{key: item.key, type: 'item', dropPosition: 'before'}} />
|
|
272
|
+
}
|
|
273
|
+
<ListViewItem item={item} isEmphasized hasActions={!!onAction} />
|
|
274
|
+
{isListDroppable &&
|
|
275
|
+
<InsertionIndicator
|
|
276
|
+
key={`${item.key}-after`}
|
|
277
|
+
target={{key: item.key, type: 'item', dropPosition: 'after'}}
|
|
278
|
+
isPresentationOnly={collection.getKeyAfter(item.key) != null} />
|
|
279
|
+
}
|
|
280
|
+
</>
|
|
259
281
|
);
|
|
260
282
|
} else if (type === 'loader') {
|
|
261
283
|
return (
|
|
262
284
|
<CenteredWrapper>
|
|
263
285
|
<ProgressCircle
|
|
264
286
|
isIndeterminate
|
|
265
|
-
aria-label={
|
|
287
|
+
aria-label={collection.size > 0 ? formatMessage('loadingMore') : formatMessage('loading')} />
|
|
266
288
|
</CenteredWrapper>
|
|
267
289
|
);
|
|
268
290
|
} else if (type === 'placeholder') {
|
|
@@ -280,11 +302,20 @@ function ListView<T extends object>(props: ListViewProps<T>, ref: DOMRef<HTMLDiv
|
|
|
280
302
|
|
|
281
303
|
}}
|
|
282
304
|
</Virtualizer>
|
|
305
|
+
{DragPreview && isListDraggable &&
|
|
306
|
+
<DragPreview ref={preview}>
|
|
307
|
+
{() => {
|
|
308
|
+
let item = state.collection.getItem(dragState.draggedKey);
|
|
309
|
+
let itemCount = dragState.draggingKeys.size;
|
|
310
|
+
let itemHeight = layout.getLayoutInfo(dragState.draggedKey).rect.height;
|
|
311
|
+
return <SpectrumDragPreview item={item} itemCount={itemCount} itemHeight={itemHeight} />;
|
|
312
|
+
}}
|
|
313
|
+
</DragPreview>
|
|
314
|
+
}
|
|
283
315
|
</ListViewContext.Provider>
|
|
284
316
|
);
|
|
285
317
|
}
|
|
286
318
|
|
|
287
|
-
|
|
288
319
|
function CenteredWrapper({children}) {
|
|
289
320
|
let {state} = useContext(ListViewContext);
|
|
290
321
|
return (
|
|
@@ -306,5 +337,8 @@ function CenteredWrapper({children}) {
|
|
|
306
337
|
);
|
|
307
338
|
}
|
|
308
339
|
|
|
309
|
-
|
|
340
|
+
/**
|
|
341
|
+
* Lists display a linear collection of data. They allow users to quickly scan, sort, compare, and take action on large amounts of data.
|
|
342
|
+
*/
|
|
343
|
+
const _ListView = React.forwardRef(ListView) as <T>(props: SpectrumListProps<T> & {ref?: DOMRef<HTMLDivElement>}) => ReactElement;
|
|
310
344
|
export {_ListView as ListView};
|