99 * OF ANY KIND, either express or implied. See the License for the specific language
1010 * governing permissions and limitations under the License.
1111 */
12- import { AriaGridListProps , DraggableItemResult , DragPreviewRenderer , DropIndicatorAria , DroppableCollectionResult , FocusScope , ListKeyboardDelegate , mergeProps , useFocusRing , useGridList , useGridListItem , useGridListSelectionCheckbox , useHover , useVisuallyHidden } from 'react-aria' ;
12+ import { AriaGridListProps , DraggableItemResult , DragPreviewRenderer , DropIndicatorAria , DroppableCollectionResult , FocusScope , ListKeyboardDelegate , mergeProps , useCollator , useFocusRing , useGridList , useGridListItem , useGridListSelectionCheckbox , useHover , useLocale , useVisuallyHidden } from 'react-aria' ;
1313import { ButtonContext } from './Button' ;
1414import { CheckboxContext } from './RSPContexts' ;
1515import { Collection , DraggableCollectionState , DroppableCollectionState , ListState , Node , SelectionBehavior , useListState } from 'react-stately' ;
@@ -19,7 +19,7 @@ import {DragAndDropContext, DragAndDropHooks, DropIndicator, DropIndicatorContex
1919import { filterDOMProps , useObjectRef } from '@react-aria/utils' ;
2020import { HoverEvents , Key , LinkDOMProps } from '@react-types/shared' ;
2121import { ListStateContext } from './ListBox' ;
22- import React , { createContext , ForwardedRef , forwardRef , HTMLAttributes , JSX , ReactNode , RefObject , useContext , useEffect , useRef } from 'react' ;
22+ import React , { createContext , ForwardedRef , forwardRef , HTMLAttributes , JSX , ReactNode , RefObject , useContext , useEffect , useMemo , useRef } from 'react' ;
2323import { TextContext } from './Text' ;
2424
2525export interface GridListRenderProps {
@@ -43,6 +43,11 @@ export interface GridListRenderProps {
4343 * @selector [data-drop-target]
4444 */
4545 isDropTarget : boolean ,
46+ /**
47+ * Whether the items are arranged in a stack or grid.
48+ * @selector [data-layout="stack | grid"]
49+ */
50+ layout : 'stack' | 'grid' ,
4651 /**
4752 * State of the grid list.
4853 */
@@ -55,7 +60,12 @@ export interface GridListProps<T> extends Omit<AriaGridListProps<T>, 'children'>
5560 /** The drag and drop hooks returned by `useDragAndDrop` used to enable drag and drop behavior for the GridList. */
5661 dragAndDropHooks ?: DragAndDropHooks ,
5762 /** Provides content to display when there are no items in the list. */
58- renderEmptyState ?: ( props : GridListRenderProps ) => ReactNode
63+ renderEmptyState ?: ( props : GridListRenderProps ) => ReactNode ,
64+ /**
65+ * Whether the items are arranged in a stack or grid.
66+ * @default 'stack'
67+ */
68+ layout ?: 'stack' | 'grid'
5969}
6070
6171
@@ -80,14 +90,34 @@ interface GridListInnerProps<T extends object> {
8090}
8191
8292function GridListInner < T extends object > ( { props, collection, gridListRef : ref } : GridListInnerProps < T > ) {
83- let { dragAndDropHooks} = props ;
93+ let { dragAndDropHooks, keyboardNavigationBehavior = 'arrow' , layout = 'stack' } = props ;
8494 let state = useListState ( {
8595 ...props ,
8696 collection,
8797 children : undefined
8898 } ) ;
8999
90- let { gridProps} = useGridList ( props , state , ref ) ;
100+ let collator = useCollator ( { usage : 'search' , sensitivity : 'base' } ) ;
101+ let { disabledBehavior, disabledKeys} = state . selectionManager ;
102+ let { direction} = useLocale ( ) ;
103+ let keyboardDelegate = useMemo ( ( ) => (
104+ new ListKeyboardDelegate ( {
105+ collection,
106+ collator,
107+ ref,
108+ disabledKeys,
109+ disabledBehavior,
110+ layout,
111+ direction
112+ } )
113+ ) , [ collection , ref , layout , disabledKeys , disabledBehavior , collator , direction ] ) ;
114+
115+ let { gridProps} = useGridList ( {
116+ ...props ,
117+ keyboardDelegate,
118+ // Only tab navigation is supported in grid layout.
119+ keyboardNavigationBehavior : layout === 'grid' ? 'tab' : keyboardNavigationBehavior
120+ } , state , ref ) ;
91121
92122 let selectionManager = state . selectionManager ;
93123 let isListDraggable = ! ! dragAndDropHooks ?. useDraggableCollectionState ;
@@ -136,7 +166,7 @@ function GridListInner<T extends object>({props, collection, gridListRef: ref}:
136166 disabledBehavior : selectionManager . disabledBehavior ,
137167 ref
138168 } ) ;
139- let dropTargetDelegate = dragAndDropHooks . dropTargetDelegate || new dragAndDropHooks . ListDropTargetDelegate ( collection , ref ) ;
169+ let dropTargetDelegate = dragAndDropHooks . dropTargetDelegate || new dragAndDropHooks . ListDropTargetDelegate ( collection , ref , { layout , direction } ) ;
140170 droppableCollection = dragAndDropHooks . useDroppableCollection ! ( {
141171 keyboardDelegate,
142172 dropTargetDelegate
@@ -151,6 +181,7 @@ function GridListInner<T extends object>({props, collection, gridListRef: ref}:
151181 isEmpty : state . collection . size === 0 ,
152182 isFocused,
153183 isFocusVisible,
184+ layout,
154185 state
155186 } ;
156187 let renderProps = useRenderProps ( {
@@ -185,7 +216,8 @@ function GridListInner<T extends object>({props, collection, gridListRef: ref}:
185216 data-drop-target = { isRootDropTarget || undefined }
186217 data-empty = { state . collection . size === 0 || undefined }
187218 data-focused = { isFocused || undefined }
188- data-focus-visible = { isFocusVisible || undefined } >
219+ data-focus-visible = { isFocusVisible || undefined }
220+ data-layout = { layout } >
189221 < Provider
190222 values = { [
191223 [ ListStateContext , state ] ,
0 commit comments