@react-spectrum/list 3.0.0-alpha.6 → 3.0.0-alpha.9

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.
@@ -14,24 +14,28 @@ import ChevronLeftMedium from '@spectrum-icons/ui/ChevronLeftMedium';
14
14
  import ChevronRightMedium from '@spectrum-icons/ui/ChevronRightMedium';
15
15
  import {classNames, ClearSlots, SlotProvider} from '@react-spectrum/utils';
16
16
  import {Content} from '@react-spectrum/view';
17
+ import type {DraggableItemResult} from '@react-aria/dnd';
18
+ import {FocusRing, useFocusRing} from '@react-aria/focus';
17
19
  import {Grid} from '@react-spectrum/layout';
20
+ import ListGripper from '@spectrum-icons/ui/ListGripper';
18
21
  import listStyles from './listview.css';
19
22
  import {ListViewContext} from './ListView';
20
23
  import {mergeProps} from '@react-aria/utils';
21
24
  import React, {useContext, useRef} from 'react';
22
- import {useFocusRing} from '@react-aria/focus';
25
+ import {useButton} from '@react-aria/button';
23
26
  import {useGridCell, useGridRow, useGridSelectionCheckbox} from '@react-aria/grid';
24
27
  import {useHover, usePress} from '@react-aria/interactions';
25
28
  import {useLocale} from '@react-aria/i18n';
29
+ import {useVisuallyHidden} from '@react-aria/visually-hidden';
26
30
 
27
31
  export function ListViewItem(props) {
28
32
  let {
29
33
  item,
30
- onAction,
31
- isEmphasized
34
+ isEmphasized,
35
+ dragHooks
32
36
  } = props;
33
37
  let cellNode = [...item.childNodes][0];
34
- let {state} = useContext(ListViewContext);
38
+ let {state, dragState, onAction, isListDraggable} = useContext(ListViewContext);
35
39
  let {direction} = useLocale();
36
40
  let rowRef = useRef<HTMLDivElement>();
37
41
  let cellRef = useRef<HTMLDivElement>();
@@ -42,17 +46,24 @@ export function ListViewItem(props) {
42
46
  let {isFocusVisible, focusProps} = useFocusRing();
43
47
  let allowsInteraction = state.selectionManager.selectionMode !== 'none' || onAction;
44
48
  let isDisabled = !allowsInteraction || state.disabledKeys.has(item.key);
49
+ let isDraggable = dragState?.isDraggable(item.key) && !isDisabled;
45
50
  let {hoverProps, isHovered} = useHover({isDisabled});
46
51
  let {pressProps, isPressed} = usePress({isDisabled});
47
52
  let {rowProps} = useGridRow({
48
53
  node: item,
49
54
  isVirtualized: true,
50
- onAction: onAction ? () => onAction(item.key) : undefined
55
+ onAction: onAction ? () => onAction(item.key) : undefined,
56
+ shouldSelectOnPressUp: isListDraggable
51
57
  }, state, rowRef);
52
58
  let {gridCellProps} = useGridCell({
53
59
  node: cellNode,
54
60
  focusMode: 'cell'
55
61
  }, state, cellRef);
62
+ let draggableItem: DraggableItemResult;
63
+ if (isListDraggable) {
64
+ // eslint-disable-next-line react-hooks/rules-of-hooks
65
+ draggableItem = dragHooks.useDraggableItem({key: item.key}, dragState);
66
+ }
56
67
  const mergedProps = mergeProps(
57
68
  gridCellProps,
58
69
  hoverProps,
@@ -61,6 +72,12 @@ export function ListViewItem(props) {
61
72
  );
62
73
  let {checkboxProps} = useGridSelectionCheckbox({...props, key: item.key}, state);
63
74
 
75
+ let dragButtonRef = React.useRef();
76
+ let {buttonProps} = useButton({
77
+ ...draggableItem?.dragButtonProps,
78
+ elementType: 'div'
79
+ }, dragButtonRef);
80
+
64
81
  let chevron = null;
65
82
  if (item.props.hasChildItems) {
66
83
  chevron = direction === 'ltr'
@@ -78,9 +95,11 @@ export function ListViewItem(props) {
78
95
 
79
96
  let showCheckbox = state.selectionManager.selectionMode !== 'none' && state.selectionManager.selectionBehavior === 'toggle';
80
97
  let isSelected = state.selectionManager.isSelected(item.key);
98
+ let showDragHandle = isDraggable && (isFocusVisibleWithin || isHovered || isPressed);
99
+ let {visuallyHiddenProps} = useVisuallyHidden();
81
100
  return (
82
101
  <div
83
- {...mergeProps(rowProps, pressProps)}
102
+ {...mergeProps(rowProps, pressProps, isDraggable && draggableItem?.dragProps)}
84
103
  ref={rowRef}>
85
104
  <div
86
105
  className={
@@ -94,19 +113,41 @@ export function ListViewItem(props) {
94
113
  'is-hovered': isHovered,
95
114
  'is-selected': isSelected,
96
115
  'is-previous-selected': state.selectionManager.isSelected(item.prevKey),
97
- 'react-spectrum-ListViewItem--highlightSelection': state.selectionManager.selectionBehavior === 'replace' && (isSelected || state.selectionManager.isSelected(item.nextKey))
116
+ 'react-spectrum-ListViewItem--highlightSelection': state.selectionManager.selectionBehavior === 'replace' && (isSelected || state.selectionManager.isSelected(item.nextKey)),
117
+ 'react-spectrum-ListViewItem--draggable': isDraggable
98
118
  }
99
119
  )
100
120
  }
101
121
  ref={cellRef}
102
122
  {...mergedProps}>
103
123
  <Grid UNSAFE_className={listStyles['react-spectrum-ListViewItem-grid']}>
104
- {showCheckbox && (
124
+ {isListDraggable &&
125
+ <div className={listStyles['react-spectrum-ListViewItem-draghandle-container']}>
126
+ {isDraggable &&
127
+ <FocusRing focusRingClass={classNames(listStyles, 'focus-ring')}>
128
+ <div
129
+ {...buttonProps as React.HTMLAttributes<HTMLElement>}
130
+ className={
131
+ classNames(
132
+ listStyles,
133
+ 'react-spectrum-ListViewItem-draghandle-button'
134
+ )
135
+ }
136
+ style={!showDragHandle ? {...visuallyHiddenProps.style} : {}}
137
+ ref={dragButtonRef}
138
+ draggable="true">
139
+ <ListGripper />
140
+ </div>
141
+ </FocusRing>
142
+ }
143
+ </div>
144
+ }
145
+ {showCheckbox &&
105
146
  <Checkbox
106
147
  UNSAFE_className={listStyles['react-spectrum-ListViewItem-checkbox']}
107
148
  {...checkboxProps}
108
149
  isEmphasized={isEmphasized} />
109
- )}
150
+ }
110
151
  <SlotProvider
111
152
  slots={{
112
153
  content: {UNSAFE_className: listStyles['react-spectrum-ListViewItem-content']},
package/src/listview.css CHANGED
@@ -98,17 +98,46 @@
98
98
  padding-bottom: 0px;
99
99
  }
100
100
 
101
+ &.is-dragging {
102
+ border: 1px solid var(--spectrum-global-color-blue-500);
103
+ border-radius: var(--spectrum-global-dimension-size-50);
104
+ }
105
+
101
106
  .react-spectrum-ListViewItem-grid {
102
107
  display: grid;
103
- grid-template-columns: auto auto auto 1fr auto auto;
108
+ grid-template-columns: auto auto auto auto 1fr auto auto;
104
109
  grid-template-rows: 1fr auto;
105
110
  grid-template-areas:
106
- "checkbox icon image content actions actionmenu chevron"
107
- "checkbox icon image description actions actionmenu chevron"
111
+ "draghandle checkbox icon image content actions actionmenu chevron"
112
+ "draghandle checkbox icon image description actions actionmenu chevron"
108
113
  ;
109
114
  align-items: center;
110
115
  }
111
116
 
117
+ .react-spectrum-ListViewItem-draghandle-container {
118
+ grid-area: draghandle;
119
+ width: var(--spectrum-global-dimension-size-250);
120
+ display: flex;
121
+ align-self: stretch;
122
+ justify-self: stretch;
123
+ justify-content: center;
124
+ padding: var(--spectrum-global-dimension-size-25);
125
+
126
+
127
+ .react-spectrum-ListViewItem-draghandle-button {
128
+ width: var(--spectrum-global-dimension-size-200);
129
+ display: flex;
130
+ align-items: center;
131
+ justify-content: center;
132
+ border-radius: var(--spectrum-alias-border-radius-regular);
133
+
134
+ &:focus-ring {
135
+ box-shadow: inset 0 0 0 2px var(--spectrum-table-cell-border-color-key-focus);
136
+ outline: none;
137
+ }
138
+ }
139
+ }
140
+
112
141
  .react-spectrum-ListViewItem-checkbox {
113
142
  grid-area: checkbox;
114
143
  align-items: center;
@@ -185,6 +214,16 @@
185
214
  min-height: var(--spectrum-global-dimension-size-600);
186
215
  }
187
216
 
217
+ .react-spectrum-ListView--draggable .react-spectrum-ListViewItem {
218
+ padding-inline-start: 0;
219
+ }
220
+
221
+ .react-spectrum-ListViewItem--draggable {
222
+ .react-spectrum-ListViewItem-checkbox input {
223
+ inset-inline-start: 0;
224
+ }
225
+ }
226
+
188
227
  .react-spectrum-ListView-centeredWrapper {
189
228
  display: flex;
190
229
  align-items: center;