@react-aria/gridlist 3.12.0 → 3.13.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/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/useGridList.main.js +3 -2
- package/dist/useGridList.main.js.map +1 -1
- package/dist/useGridList.mjs +3 -2
- package/dist/useGridList.module.js +3 -2
- package/dist/useGridList.module.js.map +1 -1
- package/dist/useGridListItem.main.js +22 -16
- package/dist/useGridListItem.main.js.map +1 -1
- package/dist/useGridListItem.mjs +22 -16
- package/dist/useGridListItem.module.js +22 -16
- package/dist/useGridListItem.module.js.map +1 -1
- package/dist/utils.main.js.map +1 -1
- package/dist/utils.module.js.map +1 -1
- package/package.json +12 -12
- package/src/useGridList.ts +6 -3
- package/src/useGridListItem.ts +28 -18
- package/src/utils.ts +2 -1
package/dist/types.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export interface GridListProps<T> extends CollectionBase<T>, MultipleSelection {
|
|
|
13
13
|
onAction?: (key: Key) => void;
|
|
14
14
|
/** Whether `disabledKeys` applies to all interactions, or only selection. */
|
|
15
15
|
disabledBehavior?: DisabledBehavior;
|
|
16
|
+
/** Whether selection should occur on press up instead of press down. */
|
|
17
|
+
shouldSelectOnPressUp?: boolean;
|
|
16
18
|
}
|
|
17
19
|
export interface AriaGridListProps<T> extends GridListProps<T>, DOMProps, AriaLabelingProps {
|
|
18
20
|
/**
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;;;;ACgCA,+BAA+B,CAAC,CAAE,SAAQ,eAAe,CAAC,CAAC,EAAE,iBAAiB;IAC5E,uDAAuD;IACvD,SAAS,CAAC,EAAE,OAAO,GAAG,aAAa,CAAC;IACpC;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;IAC9B,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;
|
|
1
|
+
{"mappings":";;;;;ACgCA,+BAA+B,CAAC,CAAE,SAAQ,eAAe,CAAC,CAAC,EAAE,iBAAiB;IAC5E,uDAAuD;IACvD,SAAS,CAAC,EAAE,OAAO,GAAG,aAAa,CAAC;IACpC;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;IAC9B,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,wEAAwE;IACxE,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAChC;AAED,mCAAmC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,EAAE,QAAQ,EAAE,iBAAiB;IACzF;;;;OAIG;IACH,0BAA0B,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;IAC7C;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAAA;CAC9C;AAED,qCAAqC,CAAC,CAAE,SAAQ,IAAI,CAAC,kBAAkB,CAAC,CAAC,EAAE,UAAU,CAAC;IACpF,+CAA+C;IAC/C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC;;;;OAIG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,QAAQ,GAAG,WAAW,GAAG,UAAU,CAAA;CACnD;AAED;IACE,kCAAkC;IAClC,SAAS,EAAE,aAAa,CAAA;CACzB;AAED;;;;;;GAMG;AACH,4BAA4B,CAAC,EAAE,KAAK,EAAE,oBAAoB,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,EAAE,GAAG,EAAE,UAAU,WAAW,GAAG,IAAI,CAAC,GAAG,YAAY,CAoEnI;AC1JD;IACE,8GAA8G;IAC9G,IAAI,EAAE,KAAO,OAAO,CAAC,CAAC;IACtB,+DAA+D;IAC/D,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,wEAAwE;IACxE,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,8DAA8D;IAC9D,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED,iCAAkC,SAAQ,oBAAoB;IAC5D,sCAAsC;IACtC,QAAQ,EAAE,aAAa,CAAC;IACxB,2DAA2D;IAC3D,aAAa,EAAE,aAAa,CAAC;IAC7B,2DAA2D;IAC3D,gBAAgB,EAAE,aAAa,CAAA;CAChC;AAaD;;;;;GAKG;AACH,gCAAgC,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,EAAE,GAAG,EAAE,UAAU,gBAAgB,GAAG,IAAI,CAAC,GAAG,gBAAgB,CAyPhK;ACtSD;;;;GAIG;AACH,6CAA6C,CAAC,EAAE,KAAK,EAAE,8BAA8B,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,GAAG,yBAAyB,CAUrI;ACbD,YAAY,EAAC,8BAA8B,EAAE,yBAAyB,EAAC,MAAM,kBAAkB,CAAC","sources":["packages/@react-aria/gridlist/src/packages/@react-aria/gridlist/src/utils.ts","packages/@react-aria/gridlist/src/packages/@react-aria/gridlist/src/useGridList.ts","packages/@react-aria/gridlist/src/packages/@react-aria/gridlist/src/useGridListItem.ts","packages/@react-aria/gridlist/src/packages/@react-aria/gridlist/src/useGridListSelectionCheckbox.ts","packages/@react-aria/gridlist/src/packages/@react-aria/gridlist/src/index.ts","packages/@react-aria/gridlist/src/index.ts"],"sourcesContent":[null,null,null,null,null,"/*\n * Copyright 2022 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nexport {useGridList} from './useGridList';\nexport {useGridListItem} from './useGridListItem';\nexport {useGridListSelectionCheckbox} from './useGridListSelectionCheckbox';\n\nexport type {AriaGridListOptions, AriaGridListProps, GridListAria, GridListProps} from './useGridList';\nexport type {AriaGridListItemOptions, GridListItemAria} from './useGridListItem';\nexport type {AriaGridSelectionCheckboxProps, GridSelectionCheckboxAria} from '@react-aria/grid';\n"],"names":[],"version":3,"file":"types.d.ts.map"}
|
package/dist/useGridList.main.js
CHANGED
|
@@ -26,7 +26,7 @@ $parcel$export(module.exports, "useGridList", () => $acf209ae814f1c93$export$664
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
function $acf209ae814f1c93$export$664f9155035607eb(props, state, ref) {
|
|
29
|
-
let { isVirtualized: isVirtualized, keyboardDelegate: keyboardDelegate, layoutDelegate: layoutDelegate, onAction: onAction, disallowTypeAhead: disallowTypeAhead, linkBehavior: linkBehavior = 'action', keyboardNavigationBehavior: keyboardNavigationBehavior = 'arrow', escapeKeyBehavior: escapeKeyBehavior = 'clearSelection' } = props;
|
|
29
|
+
let { isVirtualized: isVirtualized, keyboardDelegate: keyboardDelegate, layoutDelegate: layoutDelegate, onAction: onAction, disallowTypeAhead: disallowTypeAhead, linkBehavior: linkBehavior = 'action', keyboardNavigationBehavior: keyboardNavigationBehavior = 'arrow', escapeKeyBehavior: escapeKeyBehavior = 'clearSelection', shouldSelectOnPressUp: shouldSelectOnPressUp } = props;
|
|
30
30
|
if (!props['aria-label'] && !props['aria-labelledby']) console.warn('An aria-label or aria-labelledby prop is required for accessibility.');
|
|
31
31
|
let { listProps: listProps } = (0, $i2dnl$reactariaselection.useSelectableList)({
|
|
32
32
|
selectionManager: state.selectionManager,
|
|
@@ -48,7 +48,8 @@ function $acf209ae814f1c93$export$664f9155035607eb(props, state, ref) {
|
|
|
48
48
|
id: id,
|
|
49
49
|
onAction: onAction,
|
|
50
50
|
linkBehavior: linkBehavior,
|
|
51
|
-
keyboardNavigationBehavior: keyboardNavigationBehavior
|
|
51
|
+
keyboardNavigationBehavior: keyboardNavigationBehavior,
|
|
52
|
+
shouldSelectOnPressUp: shouldSelectOnPressUp
|
|
52
53
|
});
|
|
53
54
|
let descriptionProps = (0, $i2dnl$reactariagrid.useHighlightSelectionDescription)({
|
|
54
55
|
selectionManager: state.selectionManager,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;;;;;;;;;;;AAAA;;;;;;;;;;CAUC;;;;;
|
|
1
|
+
{"mappings":";;;;;;;;;;;;AAAA;;;;;;;;;;CAUC;;;;;AAoGM,SAAS,0CAAe,KAA6B,EAAE,KAAmB,EAAE,GAAkC;IACnH,IAAI,iBACF,aAAa,oBACb,gBAAgB,kBAChB,cAAc,YACd,QAAQ,qBACR,iBAAiB,gBACjB,eAAe,sCACf,6BAA6B,4BAC7B,oBAAoB,yCACpB,qBAAqB,EACtB,GAAG;IAEJ,IAAI,CAAC,KAAK,CAAC,aAAa,IAAI,CAAC,KAAK,CAAC,kBAAkB,EACnD,QAAQ,IAAI,CAAC;IAGf,IAAI,aAAC,SAAS,EAAC,GAAG,CAAA,GAAA,2CAAgB,EAAE;QAClC,kBAAkB,MAAM,gBAAgB;QACxC,YAAY,MAAM,UAAU;QAC5B,cAAc,MAAM,YAAY;aAChC;0BACA;wBACA;uBACA;QACA,eAAe,MAAM,gBAAgB,CAAC,iBAAiB,KAAK;QAC5D,iBAAiB,MAAM,eAAe;sBACtC;2BACA;QACA,WAAW,MAAM,SAAS;2BAC1B;IACF;IAEA,IAAI,KAAK,CAAA,GAAA,2BAAI,EAAE,MAAM,EAAE;IACvB,CAAA,GAAA,iCAAM,EAAE,GAAG,CAAC,OAAO;YAAC;kBAAI;sBAAU;oCAAc;+BAA4B;IAAqB;IAEjG,IAAI,mBAAmB,CAAA,GAAA,qDAA+B,EAAE;QACtD,kBAAkB,MAAM,gBAAgB;QACxC,gBAAgB,CAAC,CAAC;IACpB;IAEA,IAAI,mBAAmB,CAAA,GAAA,yCAAkB,EAAE,KAAK;QAC9C,YAAY,MAAM,UAAU,CAAC,IAAI,KAAK;IACxC;IAEA,IAAI,WAAW,CAAA,GAAA,oCAAa,EAAE,OAAO;QAAC,WAAW;IAAI;IACrD,IAAI,YAA2B,CAAA,GAAA,gCAAS,EACtC,UACA;QACE,MAAM;YACN;QACA,wBAAwB,MAAM,gBAAgB,CAAC,aAAa,KAAK,aAAa,SAAS;IACzF,GACA,mGAAmG;IACnG,MAAM,UAAU,CAAC,IAAI,KAAK,IAAI;QAAC,UAAU,mBAAmB,KAAK;IAAC,IAAI,WACtE;IAGF,IAAI,eAAe;QACjB,SAAS,CAAC,gBAAgB,GAAG,MAAM,UAAU,CAAC,IAAI;QAClD,SAAS,CAAC,gBAAgB,GAAG;IAC/B;IAEA,CAAA,GAAA,iDAA2B,EAAE,CAAC,GAAG;IAEjC,OAAO;mBACL;IACF;AACF","sources":["packages/@react-aria/gridlist/src/useGridList.ts"],"sourcesContent":["/*\n * Copyright 2022 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {\n AriaLabelingProps,\n CollectionBase,\n DisabledBehavior,\n DOMAttributes,\n DOMProps,\n FocusStrategy,\n Key,\n KeyboardDelegate,\n LayoutDelegate,\n MultipleSelection,\n RefObject\n} from '@react-types/shared';\nimport {filterDOMProps, mergeProps, useId} from '@react-aria/utils';\nimport {listMap} from './utils';\nimport {ListState} from '@react-stately/list';\nimport {useGridSelectionAnnouncement, useHighlightSelectionDescription} from '@react-aria/grid';\nimport {useHasTabbableChild} from '@react-aria/focus';\nimport {useSelectableList} from '@react-aria/selection';\n\nexport interface GridListProps<T> extends CollectionBase<T>, MultipleSelection {\n /** Whether to auto focus the gridlist or an option. */\n autoFocus?: boolean | FocusStrategy,\n /**\n * Handler that is called when a user performs an action on an item. The exact user event depends on\n * the collection's `selectionBehavior` prop and the interaction modality.\n */\n onAction?: (key: Key) => void,\n /** Whether `disabledKeys` applies to all interactions, or only selection. */\n disabledBehavior?: DisabledBehavior,\n /** Whether selection should occur on press up instead of press down. */\n shouldSelectOnPressUp?: boolean\n}\n\nexport interface AriaGridListProps<T> extends GridListProps<T>, DOMProps, AriaLabelingProps {\n /**\n * Whether keyboard navigation to focusable elements within grid list items is\n * via the left/right arrow keys or the tab key.\n * @default 'arrow'\n */\n keyboardNavigationBehavior?: 'arrow' | 'tab',\n /**\n * Whether pressing the escape key should clear selection in the grid list or not.\n *\n * Most experiences should not modify this option as it eliminates a keyboard user's ability to\n * easily clear selection. Only use if the escape key is being handled externally or should not\n * trigger selection clearing contextually.\n * @default 'clearSelection'\n */\n escapeKeyBehavior?: 'clearSelection' | 'none'\n}\n\nexport interface AriaGridListOptions<T> extends Omit<AriaGridListProps<T>, 'children'> {\n /** Whether the list uses virtual scrolling. */\n isVirtualized?: boolean,\n /**\n * Whether typeahead navigation is disabled.\n * @default false\n */\n disallowTypeAhead?: boolean,\n /**\n * An optional keyboard delegate implementation for type to select,\n * to override the default.\n */\n keyboardDelegate?: KeyboardDelegate,\n /**\n * A delegate object that provides layout information for items in the collection.\n * By default this uses the DOM, but this can be overridden to implement things like\n * virtualized scrolling.\n */\n layoutDelegate?: LayoutDelegate,\n /**\n * Whether focus should wrap around when the end/start is reached.\n * @default false\n */\n shouldFocusWrap?: boolean,\n /**\n * The behavior of links in the collection.\n * - 'action': link behaves like onAction.\n * - 'selection': link follows selection interactions (e.g. if URL drives selection).\n * - 'override': links override all other interactions (link items are not selectable).\n * @default 'action'\n */\n linkBehavior?: 'action' | 'selection' | 'override'\n}\n\nexport interface GridListAria {\n /** Props for the grid element. */\n gridProps: DOMAttributes\n}\n\n/**\n * Provides the behavior and accessibility implementation for a list component with interactive children.\n * A grid list displays data in a single column and enables a user to navigate its contents via directional navigation keys.\n * @param props - Props for the list.\n * @param state - State for the list, as returned by `useListState`.\n * @param ref - The ref attached to the list element.\n */\nexport function useGridList<T>(props: AriaGridListOptions<T>, state: ListState<T>, ref: RefObject<HTMLElement | null>): GridListAria {\n let {\n isVirtualized,\n keyboardDelegate,\n layoutDelegate,\n onAction,\n disallowTypeAhead,\n linkBehavior = 'action',\n keyboardNavigationBehavior = 'arrow',\n escapeKeyBehavior = 'clearSelection',\n shouldSelectOnPressUp\n } = props;\n\n if (!props['aria-label'] && !props['aria-labelledby']) {\n console.warn('An aria-label or aria-labelledby prop is required for accessibility.');\n }\n\n let {listProps} = useSelectableList({\n selectionManager: state.selectionManager,\n collection: state.collection,\n disabledKeys: state.disabledKeys,\n ref,\n keyboardDelegate,\n layoutDelegate,\n isVirtualized,\n selectOnFocus: state.selectionManager.selectionBehavior === 'replace',\n shouldFocusWrap: props.shouldFocusWrap,\n linkBehavior,\n disallowTypeAhead,\n autoFocus: props.autoFocus,\n escapeKeyBehavior\n });\n\n let id = useId(props.id);\n listMap.set(state, {id, onAction, linkBehavior, keyboardNavigationBehavior, shouldSelectOnPressUp});\n\n let descriptionProps = useHighlightSelectionDescription({\n selectionManager: state.selectionManager,\n hasItemActions: !!onAction\n });\n\n let hasTabbableChild = useHasTabbableChild(ref, {\n isDisabled: state.collection.size !== 0\n });\n\n let domProps = filterDOMProps(props, {labelable: true});\n let gridProps: DOMAttributes = mergeProps(\n domProps,\n {\n role: 'grid',\n id,\n 'aria-multiselectable': state.selectionManager.selectionMode === 'multiple' ? 'true' : undefined\n },\n // If collection is empty, make sure the grid is tabbable unless there is a child tabbable element.\n state.collection.size === 0 ? {tabIndex: hasTabbableChild ? -1 : 0} : listProps,\n descriptionProps\n );\n\n if (isVirtualized) {\n gridProps['aria-rowcount'] = state.collection.size;\n gridProps['aria-colcount'] = 1;\n }\n\n useGridSelectionAnnouncement({}, state);\n\n return {\n gridProps\n };\n}\n"],"names":[],"version":3,"file":"useGridList.main.js.map"}
|
package/dist/useGridList.mjs
CHANGED
|
@@ -20,7 +20,7 @@ import {useSelectableList as $lnALe$useSelectableList} from "@react-aria/selecti
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
function $f47efb0c3a859cf2$export$664f9155035607eb(props, state, ref) {
|
|
23
|
-
let { isVirtualized: isVirtualized, keyboardDelegate: keyboardDelegate, layoutDelegate: layoutDelegate, onAction: onAction, disallowTypeAhead: disallowTypeAhead, linkBehavior: linkBehavior = 'action', keyboardNavigationBehavior: keyboardNavigationBehavior = 'arrow', escapeKeyBehavior: escapeKeyBehavior = 'clearSelection' } = props;
|
|
23
|
+
let { isVirtualized: isVirtualized, keyboardDelegate: keyboardDelegate, layoutDelegate: layoutDelegate, onAction: onAction, disallowTypeAhead: disallowTypeAhead, linkBehavior: linkBehavior = 'action', keyboardNavigationBehavior: keyboardNavigationBehavior = 'arrow', escapeKeyBehavior: escapeKeyBehavior = 'clearSelection', shouldSelectOnPressUp: shouldSelectOnPressUp } = props;
|
|
24
24
|
if (!props['aria-label'] && !props['aria-labelledby']) console.warn('An aria-label or aria-labelledby prop is required for accessibility.');
|
|
25
25
|
let { listProps: listProps } = (0, $lnALe$useSelectableList)({
|
|
26
26
|
selectionManager: state.selectionManager,
|
|
@@ -42,7 +42,8 @@ function $f47efb0c3a859cf2$export$664f9155035607eb(props, state, ref) {
|
|
|
42
42
|
id: id,
|
|
43
43
|
onAction: onAction,
|
|
44
44
|
linkBehavior: linkBehavior,
|
|
45
|
-
keyboardNavigationBehavior: keyboardNavigationBehavior
|
|
45
|
+
keyboardNavigationBehavior: keyboardNavigationBehavior,
|
|
46
|
+
shouldSelectOnPressUp: shouldSelectOnPressUp
|
|
46
47
|
});
|
|
47
48
|
let descriptionProps = (0, $lnALe$useHighlightSelectionDescription)({
|
|
48
49
|
selectionManager: state.selectionManager,
|
|
@@ -20,7 +20,7 @@ import {useSelectableList as $lnALe$useSelectableList} from "@react-aria/selecti
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
function $f47efb0c3a859cf2$export$664f9155035607eb(props, state, ref) {
|
|
23
|
-
let { isVirtualized: isVirtualized, keyboardDelegate: keyboardDelegate, layoutDelegate: layoutDelegate, onAction: onAction, disallowTypeAhead: disallowTypeAhead, linkBehavior: linkBehavior = 'action', keyboardNavigationBehavior: keyboardNavigationBehavior = 'arrow', escapeKeyBehavior: escapeKeyBehavior = 'clearSelection' } = props;
|
|
23
|
+
let { isVirtualized: isVirtualized, keyboardDelegate: keyboardDelegate, layoutDelegate: layoutDelegate, onAction: onAction, disallowTypeAhead: disallowTypeAhead, linkBehavior: linkBehavior = 'action', keyboardNavigationBehavior: keyboardNavigationBehavior = 'arrow', escapeKeyBehavior: escapeKeyBehavior = 'clearSelection', shouldSelectOnPressUp: shouldSelectOnPressUp } = props;
|
|
24
24
|
if (!props['aria-label'] && !props['aria-labelledby']) console.warn('An aria-label or aria-labelledby prop is required for accessibility.');
|
|
25
25
|
let { listProps: listProps } = (0, $lnALe$useSelectableList)({
|
|
26
26
|
selectionManager: state.selectionManager,
|
|
@@ -42,7 +42,8 @@ function $f47efb0c3a859cf2$export$664f9155035607eb(props, state, ref) {
|
|
|
42
42
|
id: id,
|
|
43
43
|
onAction: onAction,
|
|
44
44
|
linkBehavior: linkBehavior,
|
|
45
|
-
keyboardNavigationBehavior: keyboardNavigationBehavior
|
|
45
|
+
keyboardNavigationBehavior: keyboardNavigationBehavior,
|
|
46
|
+
shouldSelectOnPressUp: shouldSelectOnPressUp
|
|
46
47
|
});
|
|
47
48
|
let descriptionProps = (0, $lnALe$useHighlightSelectionDescription)({
|
|
48
49
|
selectionManager: state.selectionManager,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;;;;;AAAA;;;;;;;;;;CAUC;;;;;
|
|
1
|
+
{"mappings":";;;;;;AAAA;;;;;;;;;;CAUC;;;;;AAoGM,SAAS,0CAAe,KAA6B,EAAE,KAAmB,EAAE,GAAkC;IACnH,IAAI,iBACF,aAAa,oBACb,gBAAgB,kBAChB,cAAc,YACd,QAAQ,qBACR,iBAAiB,gBACjB,eAAe,sCACf,6BAA6B,4BAC7B,oBAAoB,yCACpB,qBAAqB,EACtB,GAAG;IAEJ,IAAI,CAAC,KAAK,CAAC,aAAa,IAAI,CAAC,KAAK,CAAC,kBAAkB,EACnD,QAAQ,IAAI,CAAC;IAGf,IAAI,aAAC,SAAS,EAAC,GAAG,CAAA,GAAA,wBAAgB,EAAE;QAClC,kBAAkB,MAAM,gBAAgB;QACxC,YAAY,MAAM,UAAU;QAC5B,cAAc,MAAM,YAAY;aAChC;0BACA;wBACA;uBACA;QACA,eAAe,MAAM,gBAAgB,CAAC,iBAAiB,KAAK;QAC5D,iBAAiB,MAAM,eAAe;sBACtC;2BACA;QACA,WAAW,MAAM,SAAS;2BAC1B;IACF;IAEA,IAAI,KAAK,CAAA,GAAA,YAAI,EAAE,MAAM,EAAE;IACvB,CAAA,GAAA,yCAAM,EAAE,GAAG,CAAC,OAAO;YAAC;kBAAI;sBAAU;oCAAc;+BAA4B;IAAqB;IAEjG,IAAI,mBAAmB,CAAA,GAAA,uCAA+B,EAAE;QACtD,kBAAkB,MAAM,gBAAgB;QACxC,gBAAgB,CAAC,CAAC;IACpB;IAEA,IAAI,mBAAmB,CAAA,GAAA,0BAAkB,EAAE,KAAK;QAC9C,YAAY,MAAM,UAAU,CAAC,IAAI,KAAK;IACxC;IAEA,IAAI,WAAW,CAAA,GAAA,qBAAa,EAAE,OAAO;QAAC,WAAW;IAAI;IACrD,IAAI,YAA2B,CAAA,GAAA,iBAAS,EACtC,UACA;QACE,MAAM;YACN;QACA,wBAAwB,MAAM,gBAAgB,CAAC,aAAa,KAAK,aAAa,SAAS;IACzF,GACA,mGAAmG;IACnG,MAAM,UAAU,CAAC,IAAI,KAAK,IAAI;QAAC,UAAU,mBAAmB,KAAK;IAAC,IAAI,WACtE;IAGF,IAAI,eAAe;QACjB,SAAS,CAAC,gBAAgB,GAAG,MAAM,UAAU,CAAC,IAAI;QAClD,SAAS,CAAC,gBAAgB,GAAG;IAC/B;IAEA,CAAA,GAAA,mCAA2B,EAAE,CAAC,GAAG;IAEjC,OAAO;mBACL;IACF;AACF","sources":["packages/@react-aria/gridlist/src/useGridList.ts"],"sourcesContent":["/*\n * Copyright 2022 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {\n AriaLabelingProps,\n CollectionBase,\n DisabledBehavior,\n DOMAttributes,\n DOMProps,\n FocusStrategy,\n Key,\n KeyboardDelegate,\n LayoutDelegate,\n MultipleSelection,\n RefObject\n} from '@react-types/shared';\nimport {filterDOMProps, mergeProps, useId} from '@react-aria/utils';\nimport {listMap} from './utils';\nimport {ListState} from '@react-stately/list';\nimport {useGridSelectionAnnouncement, useHighlightSelectionDescription} from '@react-aria/grid';\nimport {useHasTabbableChild} from '@react-aria/focus';\nimport {useSelectableList} from '@react-aria/selection';\n\nexport interface GridListProps<T> extends CollectionBase<T>, MultipleSelection {\n /** Whether to auto focus the gridlist or an option. */\n autoFocus?: boolean | FocusStrategy,\n /**\n * Handler that is called when a user performs an action on an item. The exact user event depends on\n * the collection's `selectionBehavior` prop and the interaction modality.\n */\n onAction?: (key: Key) => void,\n /** Whether `disabledKeys` applies to all interactions, or only selection. */\n disabledBehavior?: DisabledBehavior,\n /** Whether selection should occur on press up instead of press down. */\n shouldSelectOnPressUp?: boolean\n}\n\nexport interface AriaGridListProps<T> extends GridListProps<T>, DOMProps, AriaLabelingProps {\n /**\n * Whether keyboard navigation to focusable elements within grid list items is\n * via the left/right arrow keys or the tab key.\n * @default 'arrow'\n */\n keyboardNavigationBehavior?: 'arrow' | 'tab',\n /**\n * Whether pressing the escape key should clear selection in the grid list or not.\n *\n * Most experiences should not modify this option as it eliminates a keyboard user's ability to\n * easily clear selection. Only use if the escape key is being handled externally or should not\n * trigger selection clearing contextually.\n * @default 'clearSelection'\n */\n escapeKeyBehavior?: 'clearSelection' | 'none'\n}\n\nexport interface AriaGridListOptions<T> extends Omit<AriaGridListProps<T>, 'children'> {\n /** Whether the list uses virtual scrolling. */\n isVirtualized?: boolean,\n /**\n * Whether typeahead navigation is disabled.\n * @default false\n */\n disallowTypeAhead?: boolean,\n /**\n * An optional keyboard delegate implementation for type to select,\n * to override the default.\n */\n keyboardDelegate?: KeyboardDelegate,\n /**\n * A delegate object that provides layout information for items in the collection.\n * By default this uses the DOM, but this can be overridden to implement things like\n * virtualized scrolling.\n */\n layoutDelegate?: LayoutDelegate,\n /**\n * Whether focus should wrap around when the end/start is reached.\n * @default false\n */\n shouldFocusWrap?: boolean,\n /**\n * The behavior of links in the collection.\n * - 'action': link behaves like onAction.\n * - 'selection': link follows selection interactions (e.g. if URL drives selection).\n * - 'override': links override all other interactions (link items are not selectable).\n * @default 'action'\n */\n linkBehavior?: 'action' | 'selection' | 'override'\n}\n\nexport interface GridListAria {\n /** Props for the grid element. */\n gridProps: DOMAttributes\n}\n\n/**\n * Provides the behavior and accessibility implementation for a list component with interactive children.\n * A grid list displays data in a single column and enables a user to navigate its contents via directional navigation keys.\n * @param props - Props for the list.\n * @param state - State for the list, as returned by `useListState`.\n * @param ref - The ref attached to the list element.\n */\nexport function useGridList<T>(props: AriaGridListOptions<T>, state: ListState<T>, ref: RefObject<HTMLElement | null>): GridListAria {\n let {\n isVirtualized,\n keyboardDelegate,\n layoutDelegate,\n onAction,\n disallowTypeAhead,\n linkBehavior = 'action',\n keyboardNavigationBehavior = 'arrow',\n escapeKeyBehavior = 'clearSelection',\n shouldSelectOnPressUp\n } = props;\n\n if (!props['aria-label'] && !props['aria-labelledby']) {\n console.warn('An aria-label or aria-labelledby prop is required for accessibility.');\n }\n\n let {listProps} = useSelectableList({\n selectionManager: state.selectionManager,\n collection: state.collection,\n disabledKeys: state.disabledKeys,\n ref,\n keyboardDelegate,\n layoutDelegate,\n isVirtualized,\n selectOnFocus: state.selectionManager.selectionBehavior === 'replace',\n shouldFocusWrap: props.shouldFocusWrap,\n linkBehavior,\n disallowTypeAhead,\n autoFocus: props.autoFocus,\n escapeKeyBehavior\n });\n\n let id = useId(props.id);\n listMap.set(state, {id, onAction, linkBehavior, keyboardNavigationBehavior, shouldSelectOnPressUp});\n\n let descriptionProps = useHighlightSelectionDescription({\n selectionManager: state.selectionManager,\n hasItemActions: !!onAction\n });\n\n let hasTabbableChild = useHasTabbableChild(ref, {\n isDisabled: state.collection.size !== 0\n });\n\n let domProps = filterDOMProps(props, {labelable: true});\n let gridProps: DOMAttributes = mergeProps(\n domProps,\n {\n role: 'grid',\n id,\n 'aria-multiselectable': state.selectionManager.selectionMode === 'multiple' ? 'true' : undefined\n },\n // If collection is empty, make sure the grid is tabbable unless there is a child tabbable element.\n state.collection.size === 0 ? {tabIndex: hasTabbableChild ? -1 : 0} : listProps,\n descriptionProps\n );\n\n if (isVirtualized) {\n gridProps['aria-rowcount'] = state.collection.size;\n gridProps['aria-colcount'] = 1;\n }\n\n useGridSelectionAnnouncement({}, state);\n\n return {\n gridProps\n };\n}\n"],"names":[],"version":3,"file":"useGridList.module.js.map"}
|
|
@@ -44,10 +44,10 @@ const $f7116f5928c03f32$var$EXPANSION_KEYS = {
|
|
|
44
44
|
function $f7116f5928c03f32$export$9610e69494fadfd2(props, state, ref) {
|
|
45
45
|
var _node_props, _node_props1;
|
|
46
46
|
// Copied from useGridCell + some modifications to make it not so grid specific
|
|
47
|
-
let { node: node, isVirtualized: isVirtualized
|
|
47
|
+
let { node: node, isVirtualized: isVirtualized } = props;
|
|
48
48
|
// let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/gridlist');
|
|
49
49
|
let { direction: direction } = (0, $911qM$reactariai18n.useLocale)();
|
|
50
|
-
let { onAction: onAction, linkBehavior: linkBehavior, keyboardNavigationBehavior: keyboardNavigationBehavior } = (0, $7db02799adae605d$exports.listMap).get(state);
|
|
50
|
+
let { onAction: onAction, linkBehavior: linkBehavior, keyboardNavigationBehavior: keyboardNavigationBehavior, shouldSelectOnPressUp: shouldSelectOnPressUp } = (0, $7db02799adae605d$exports.listMap).get(state);
|
|
51
51
|
let descriptionId = (0, $911qM$reactariautils.useSlotId)();
|
|
52
52
|
// We need to track the key of the item at the time it was last focused so that we force
|
|
53
53
|
// focus to go to the item when the DOM node is reused for a different item in a virtualizer.
|
|
@@ -96,12 +96,12 @@ function $f7116f5928c03f32$export$9610e69494fadfd2(props, state, ref) {
|
|
|
96
96
|
key: node.key,
|
|
97
97
|
ref: ref,
|
|
98
98
|
isVirtualized: isVirtualized,
|
|
99
|
-
shouldSelectOnPressUp: shouldSelectOnPressUp,
|
|
99
|
+
shouldSelectOnPressUp: props.shouldSelectOnPressUp || shouldSelectOnPressUp,
|
|
100
100
|
onAction: onAction || ((_node_props = node.props) === null || _node_props === void 0 ? void 0 : _node_props.onAction) ? (0, $911qM$reactariautils.chain)((_node_props1 = node.props) === null || _node_props1 === void 0 ? void 0 : _node_props1.onAction, onAction ? ()=>onAction(node.key) : undefined) : undefined,
|
|
101
101
|
focus: focus,
|
|
102
102
|
linkBehavior: linkBehavior
|
|
103
103
|
});
|
|
104
|
-
let
|
|
104
|
+
let onKeyDownCapture = (e)=>{
|
|
105
105
|
if (!e.currentTarget.contains(e.target) || !ref.current || !document.activeElement) return;
|
|
106
106
|
let walker = (0, $911qM$reactariafocus.getFocusableTreeWalker)(ref.current);
|
|
107
107
|
walker.currentNode = document.activeElement;
|
|
@@ -193,17 +193,6 @@ function $f7116f5928c03f32$export$9610e69494fadfd2(props, state, ref) {
|
|
|
193
193
|
(_ref_current_parentElement = ref.current.parentElement) === null || _ref_current_parentElement === void 0 ? void 0 : _ref_current_parentElement.dispatchEvent(new KeyboardEvent(e.nativeEvent.type, e.nativeEvent));
|
|
194
194
|
}
|
|
195
195
|
break;
|
|
196
|
-
case 'Tab':
|
|
197
|
-
if (keyboardNavigationBehavior === 'tab') {
|
|
198
|
-
// If there is another focusable element within this item, stop propagation so the tab key
|
|
199
|
-
// is handled by the browser and not by useSelectableCollection (which would take us out of the list).
|
|
200
|
-
let walker = (0, $911qM$reactariafocus.getFocusableTreeWalker)(ref.current, {
|
|
201
|
-
tabbable: true
|
|
202
|
-
});
|
|
203
|
-
walker.currentNode = document.activeElement;
|
|
204
|
-
let next = e.shiftKey ? walker.previousNode() : walker.nextNode();
|
|
205
|
-
if (next) e.stopPropagation();
|
|
206
|
-
}
|
|
207
196
|
}
|
|
208
197
|
};
|
|
209
198
|
let onFocus = (e)=>{
|
|
@@ -219,6 +208,22 @@ function $f7116f5928c03f32$export$9610e69494fadfd2(props, state, ref) {
|
|
|
219
208
|
return;
|
|
220
209
|
}
|
|
221
210
|
};
|
|
211
|
+
let onKeyDown = (e)=>{
|
|
212
|
+
if (!e.currentTarget.contains(e.target) || !ref.current || !document.activeElement) return;
|
|
213
|
+
switch(e.key){
|
|
214
|
+
case 'Tab':
|
|
215
|
+
if (keyboardNavigationBehavior === 'tab') {
|
|
216
|
+
// If there is another focusable element within this item, stop propagation so the tab key
|
|
217
|
+
// is handled by the browser and not by useSelectableCollection (which would take us out of the list).
|
|
218
|
+
let walker = (0, $911qM$reactariafocus.getFocusableTreeWalker)(ref.current, {
|
|
219
|
+
tabbable: true
|
|
220
|
+
});
|
|
221
|
+
walker.currentNode = document.activeElement;
|
|
222
|
+
let next = e.shiftKey ? walker.previousNode() : walker.nextNode();
|
|
223
|
+
if (next) e.stopPropagation();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
};
|
|
222
227
|
let syntheticLinkProps = (0, $911qM$reactariautils.useSyntheticLinkProps)(node.props);
|
|
223
228
|
let linkProps = itemStates.hasAction ? syntheticLinkProps : {};
|
|
224
229
|
// TODO: re-add when we get translations and fix this for iOS VO
|
|
@@ -232,7 +237,8 @@ function $f7116f5928c03f32$export$9610e69494fadfd2(props, state, ref) {
|
|
|
232
237
|
// }
|
|
233
238
|
let rowProps = (0, $911qM$reactariautils.mergeProps)(itemProps, linkProps, {
|
|
234
239
|
role: 'row',
|
|
235
|
-
onKeyDownCapture:
|
|
240
|
+
onKeyDownCapture: onKeyDownCapture,
|
|
241
|
+
onKeyDown: onKeyDown,
|
|
236
242
|
onFocus: onFocus,
|
|
237
243
|
// 'aria-label': [(node.textValue || undefined), rowAnnouncement].filter(Boolean).join(', '),
|
|
238
244
|
'aria-label': node.textValue || undefined,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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","sources":["packages/@react-aria/gridlist/src/useGridListItem.ts"],"sourcesContent":["/*\n * Copyright 2022 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {chain, getScrollParent, mergeProps, scrollIntoViewport, useSlotId, useSyntheticLinkProps} from '@react-aria/utils';\nimport {DOMAttributes, FocusableElement, Key, RefObject, Node as RSNode} from '@react-types/shared';\nimport {focusSafely, getFocusableTreeWalker} from '@react-aria/focus';\nimport {getLastItem} from '@react-stately/collections';\nimport {getRowId, listMap} from './utils';\nimport {HTMLAttributes, KeyboardEvent as ReactKeyboardEvent, useRef} from 'react';\nimport {isFocusVisible} from '@react-aria/interactions';\nimport type {ListState} from '@react-stately/list';\nimport {SelectableItemStates, useSelectableItem} from '@react-aria/selection';\nimport type {TreeState} from '@react-stately/tree';\nimport {useLocale} from '@react-aria/i18n';\n\nexport interface AriaGridListItemOptions {\n /** An object representing the list item. Contains all the relevant information that makes up the list row. */\n node: RSNode<unknown>,\n /** Whether the list row is contained in a virtual scroller. */\n isVirtualized?: boolean,\n /** Whether selection should occur on press up instead of press down. */\n shouldSelectOnPressUp?: boolean,\n /** Whether this item has children, even if not loaded yet. */\n hasChildItems?: boolean\n}\n\nexport interface GridListItemAria extends SelectableItemStates {\n /** Props for the list row element. */\n rowProps: DOMAttributes,\n /** Props for the grid cell element within the list row. */\n gridCellProps: DOMAttributes,\n /** Props for the list item description element, if any. */\n descriptionProps: DOMAttributes\n}\n\nconst EXPANSION_KEYS = {\n 'expand': {\n ltr: 'ArrowRight',\n rtl: 'ArrowLeft'\n },\n 'collapse': {\n ltr: 'ArrowLeft',\n rtl: 'ArrowRight'\n }\n};\n\n/**\n * Provides the behavior and accessibility implementation for a row in a grid list.\n * @param props - Props for the row.\n * @param state - State of the parent list, as returned by `useListState`.\n * @param ref - The ref attached to the row element.\n */\nexport function useGridListItem<T>(props: AriaGridListItemOptions, state: ListState<T> | TreeState<T>, ref: RefObject<FocusableElement | null>): GridListItemAria {\n // Copied from useGridCell + some modifications to make it not so grid specific\n let {\n node,\n isVirtualized,\n shouldSelectOnPressUp\n } = props;\n\n // let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/gridlist');\n let {direction} = useLocale();\n let {onAction, linkBehavior, keyboardNavigationBehavior} = listMap.get(state)!;\n let descriptionId = useSlotId();\n\n // We need to track the key of the item at the time it was last focused so that we force\n // focus to go to the item when the DOM node is reused for a different item in a virtualizer.\n let keyWhenFocused = useRef<Key | null>(null);\n let focus = () => {\n // Don't shift focus to the row if the active element is a element within the row already\n // (e.g. clicking on a row button)\n if (\n ref.current !== null &&\n ((keyWhenFocused.current != null && node.key !== keyWhenFocused.current) ||\n !ref.current?.contains(document.activeElement))\n ) {\n focusSafely(ref.current);\n }\n };\n\n let treeGridRowProps: HTMLAttributes<HTMLElement> = {};\n let hasChildRows = props.hasChildItems;\n let hasLink = state.selectionManager.isLink(node.key);\n if (node != null && 'expandedKeys' in state) {\n // TODO: ideally node.hasChildNodes would be a way to tell if a row has child nodes, but the row's contents make it so that value is always\n // true...\n let children = state.collection.getChildren?.(node.key);\n hasChildRows = hasChildRows || [...(children ?? [])].length > 1;\n\n if (onAction == null && !hasLink && state.selectionManager.selectionMode === 'none' && hasChildRows) {\n onAction = () => state.toggleKey(node.key);\n }\n\n let isExpanded = hasChildRows ? state.expandedKeys.has(node.key) : undefined;\n let setSize = 1;\n if (node.level > 0 && node?.parentKey != null) {\n let parent = state.collection.getItem(node.parentKey);\n if (parent) {\n // siblings must exist because our original node exists, same with lastItem\n let siblings = state.collection.getChildren?.(parent.key)!;\n setSize = getLastItem(siblings)!.index + 1;\n }\n } else {\n setSize = ([...state.collection].filter(row => row.level === 0).at(-1)?.index ?? 0) + 1;\n }\n treeGridRowProps = {\n 'aria-expanded': isExpanded,\n 'aria-level': node.level + 1,\n 'aria-posinset': node?.index + 1,\n 'aria-setsize': setSize\n };\n }\n\n let {itemProps, ...itemStates} = useSelectableItem({\n selectionManager: state.selectionManager,\n key: node.key,\n ref,\n isVirtualized,\n shouldSelectOnPressUp,\n onAction: onAction || node.props?.onAction ? chain(node.props?.onAction, onAction ? () => onAction(node.key) : undefined) : undefined,\n focus,\n linkBehavior\n });\n\n let onKeyDown = (e: ReactKeyboardEvent) => {\n if (!e.currentTarget.contains(e.target as Element) || !ref.current || !document.activeElement) {\n return;\n }\n\n let walker = getFocusableTreeWalker(ref.current);\n walker.currentNode = document.activeElement;\n\n if ('expandedKeys' in state && document.activeElement === ref.current) {\n if ((e.key === EXPANSION_KEYS['expand'][direction]) && state.selectionManager.focusedKey === node.key && hasChildRows && !state.expandedKeys.has(node.key)) {\n state.toggleKey(node.key);\n e.stopPropagation();\n return;\n } else if ((e.key === EXPANSION_KEYS['collapse'][direction]) && state.selectionManager.focusedKey === node.key && hasChildRows && state.expandedKeys.has(node.key)) {\n state.toggleKey(node.key);\n e.stopPropagation();\n return;\n }\n }\n\n switch (e.key) {\n case 'ArrowLeft': {\n if (keyboardNavigationBehavior === 'arrow') {\n // Find the next focusable element within the row.\n let focusable = direction === 'rtl'\n ? walker.nextNode() as FocusableElement\n : walker.previousNode() as FocusableElement;\n\n if (focusable) {\n e.preventDefault();\n e.stopPropagation();\n focusSafely(focusable);\n scrollIntoViewport(focusable, {containingElement: getScrollParent(ref.current)});\n } else {\n // If there is no next focusable child, then return focus back to the row\n e.preventDefault();\n e.stopPropagation();\n if (direction === 'rtl') {\n focusSafely(ref.current);\n scrollIntoViewport(ref.current, {containingElement: getScrollParent(ref.current)});\n } else {\n walker.currentNode = ref.current;\n let lastElement = last(walker);\n if (lastElement) {\n focusSafely(lastElement);\n scrollIntoViewport(lastElement, {containingElement: getScrollParent(ref.current)});\n }\n }\n }\n }\n break;\n }\n case 'ArrowRight': {\n if (keyboardNavigationBehavior === 'arrow') {\n let focusable = direction === 'rtl'\n ? walker.previousNode() as FocusableElement\n : walker.nextNode() as FocusableElement;\n\n if (focusable) {\n e.preventDefault();\n e.stopPropagation();\n focusSafely(focusable);\n scrollIntoViewport(focusable, {containingElement: getScrollParent(ref.current)});\n } else {\n e.preventDefault();\n e.stopPropagation();\n if (direction === 'ltr') {\n focusSafely(ref.current);\n scrollIntoViewport(ref.current, {containingElement: getScrollParent(ref.current)});\n } else {\n walker.currentNode = ref.current;\n let lastElement = last(walker);\n if (lastElement) {\n focusSafely(lastElement);\n scrollIntoViewport(lastElement, {containingElement: getScrollParent(ref.current)});\n }\n }\n }\n }\n break;\n }\n case 'ArrowUp':\n case 'ArrowDown':\n // Prevent this event from reaching row children, e.g. menu buttons. We want arrow keys to navigate\n // to the row above/below instead. We need to re-dispatch the event from a higher parent so it still\n // bubbles and gets handled by useSelectableCollection.\n if (!e.altKey && ref.current.contains(e.target as Element)) {\n e.stopPropagation();\n e.preventDefault();\n ref.current.parentElement?.dispatchEvent(\n new KeyboardEvent(e.nativeEvent.type, e.nativeEvent)\n );\n }\n break;\n case 'Tab': {\n if (keyboardNavigationBehavior === 'tab') {\n // If there is another focusable element within this item, stop propagation so the tab key\n // is handled by the browser and not by useSelectableCollection (which would take us out of the list).\n let walker = getFocusableTreeWalker(ref.current, {tabbable: true});\n walker.currentNode = document.activeElement;\n let next = e.shiftKey ? walker.previousNode() : walker.nextNode();\n if (next) {\n e.stopPropagation();\n }\n }\n }\n }\n };\n\n let onFocus = (e) => {\n keyWhenFocused.current = node.key;\n if (e.target !== ref.current) {\n // useSelectableItem only handles setting the focused key when\n // the focused element is the row itself. We also want to\n // set the focused key when a child element receives focus.\n // If focus is currently visible (e.g. the user is navigating with the keyboard),\n // then skip this. We want to restore focus to the previously focused row\n // in that case since the list should act like a single tab stop.\n if (!isFocusVisible()) {\n state.selectionManager.setFocusedKey(node.key);\n }\n return;\n }\n };\n\n let syntheticLinkProps = useSyntheticLinkProps(node.props);\n let linkProps = itemStates.hasAction ? syntheticLinkProps : {};\n // TODO: re-add when we get translations and fix this for iOS VO\n // let rowAnnouncement;\n // if (onAction) {\n // rowAnnouncement = stringFormatter.format('hasActionAnnouncement');\n // } else if (hasLink) {\n // rowAnnouncement = stringFormatter.format('hasLinkAnnouncement', {\n // link: node.props.href\n // });\n // }\n\n let rowProps: DOMAttributes = mergeProps(itemProps, linkProps, {\n role: 'row',\n onKeyDownCapture: onKeyDown,\n onFocus,\n // 'aria-label': [(node.textValue || undefined), rowAnnouncement].filter(Boolean).join(', '),\n 'aria-label': node.textValue || undefined,\n 'aria-selected': state.selectionManager.canSelectItem(node.key) ? state.selectionManager.isSelected(node.key) : undefined,\n 'aria-disabled': state.selectionManager.isDisabled(node.key) || undefined,\n 'aria-labelledby': descriptionId && node.textValue ? `${getRowId(state, node.key)} ${descriptionId}` : undefined,\n id: getRowId(state, node.key)\n });\n\n if (isVirtualized) {\n rowProps['aria-rowindex'] = node.index + 1;\n }\n\n let gridCellProps = {\n role: 'gridcell',\n 'aria-colindex': 1\n };\n\n // TODO: should isExpanded and hasChildRows be a item state that gets returned by the hook?\n return {\n rowProps: {...mergeProps(rowProps, treeGridRowProps)},\n gridCellProps,\n descriptionProps: {\n id: descriptionId\n },\n ...itemStates\n };\n}\n\nfunction last(walker: TreeWalker) {\n let next: FocusableElement | null = null;\n let last: FocusableElement | null = null;\n do {\n last = walker.lastChild() as FocusableElement | null;\n if (last) {\n next = last;\n }\n } while (last);\n return next;\n}\n"],"names":[],"version":3,"file":"useGridListItem.main.js.map"}
|
|
1
|
+
{"mappings":"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","sources":["packages/@react-aria/gridlist/src/useGridListItem.ts"],"sourcesContent":["/*\n * Copyright 2022 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {chain, getScrollParent, mergeProps, scrollIntoViewport, useSlotId, useSyntheticLinkProps} from '@react-aria/utils';\nimport {DOMAttributes, FocusableElement, Key, RefObject, Node as RSNode} from '@react-types/shared';\nimport {focusSafely, getFocusableTreeWalker} from '@react-aria/focus';\nimport {getLastItem} from '@react-stately/collections';\nimport {getRowId, listMap} from './utils';\nimport {HTMLAttributes, KeyboardEvent as ReactKeyboardEvent, useRef} from 'react';\nimport {isFocusVisible} from '@react-aria/interactions';\nimport type {ListState} from '@react-stately/list';\nimport {SelectableItemStates, useSelectableItem} from '@react-aria/selection';\nimport type {TreeState} from '@react-stately/tree';\nimport {useLocale} from '@react-aria/i18n';\n\nexport interface AriaGridListItemOptions {\n /** An object representing the list item. Contains all the relevant information that makes up the list row. */\n node: RSNode<unknown>,\n /** Whether the list row is contained in a virtual scroller. */\n isVirtualized?: boolean,\n /** Whether selection should occur on press up instead of press down. */\n shouldSelectOnPressUp?: boolean,\n /** Whether this item has children, even if not loaded yet. */\n hasChildItems?: boolean\n}\n\nexport interface GridListItemAria extends SelectableItemStates {\n /** Props for the list row element. */\n rowProps: DOMAttributes,\n /** Props for the grid cell element within the list row. */\n gridCellProps: DOMAttributes,\n /** Props for the list item description element, if any. */\n descriptionProps: DOMAttributes\n}\n\nconst EXPANSION_KEYS = {\n 'expand': {\n ltr: 'ArrowRight',\n rtl: 'ArrowLeft'\n },\n 'collapse': {\n ltr: 'ArrowLeft',\n rtl: 'ArrowRight'\n }\n};\n\n/**\n * Provides the behavior and accessibility implementation for a row in a grid list.\n * @param props - Props for the row.\n * @param state - State of the parent list, as returned by `useListState`.\n * @param ref - The ref attached to the row element.\n */\nexport function useGridListItem<T>(props: AriaGridListItemOptions, state: ListState<T> | TreeState<T>, ref: RefObject<FocusableElement | null>): GridListItemAria {\n // Copied from useGridCell + some modifications to make it not so grid specific\n let {\n node,\n isVirtualized\n } = props;\n\n // let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/gridlist');\n let {direction} = useLocale();\n let {onAction, linkBehavior, keyboardNavigationBehavior, shouldSelectOnPressUp} = listMap.get(state)!;\n let descriptionId = useSlotId();\n\n // We need to track the key of the item at the time it was last focused so that we force\n // focus to go to the item when the DOM node is reused for a different item in a virtualizer.\n let keyWhenFocused = useRef<Key | null>(null);\n let focus = () => {\n // Don't shift focus to the row if the active element is a element within the row already\n // (e.g. clicking on a row button)\n if (\n ref.current !== null &&\n ((keyWhenFocused.current != null && node.key !== keyWhenFocused.current) ||\n !ref.current?.contains(document.activeElement))\n ) {\n focusSafely(ref.current);\n }\n };\n\n let treeGridRowProps: HTMLAttributes<HTMLElement> = {};\n let hasChildRows = props.hasChildItems;\n let hasLink = state.selectionManager.isLink(node.key);\n if (node != null && 'expandedKeys' in state) {\n // TODO: ideally node.hasChildNodes would be a way to tell if a row has child nodes, but the row's contents make it so that value is always\n // true...\n let children = state.collection.getChildren?.(node.key);\n hasChildRows = hasChildRows || [...(children ?? [])].length > 1;\n\n if (onAction == null && !hasLink && state.selectionManager.selectionMode === 'none' && hasChildRows) {\n onAction = () => state.toggleKey(node.key);\n }\n\n let isExpanded = hasChildRows ? state.expandedKeys.has(node.key) : undefined;\n let setSize = 1;\n if (node.level > 0 && node?.parentKey != null) {\n let parent = state.collection.getItem(node.parentKey);\n if (parent) {\n // siblings must exist because our original node exists, same with lastItem\n let siblings = state.collection.getChildren?.(parent.key)!;\n setSize = getLastItem(siblings)!.index + 1;\n }\n } else {\n setSize = ([...state.collection].filter(row => row.level === 0).at(-1)?.index ?? 0) + 1;\n }\n treeGridRowProps = {\n 'aria-expanded': isExpanded,\n 'aria-level': node.level + 1,\n 'aria-posinset': node?.index + 1,\n 'aria-setsize': setSize\n };\n }\n\n let {itemProps, ...itemStates} = useSelectableItem({\n selectionManager: state.selectionManager,\n key: node.key,\n ref,\n isVirtualized,\n shouldSelectOnPressUp: props.shouldSelectOnPressUp || shouldSelectOnPressUp,\n onAction: onAction || node.props?.onAction ? chain(node.props?.onAction, onAction ? () => onAction(node.key) : undefined) : undefined,\n focus,\n linkBehavior\n });\n\n let onKeyDownCapture = (e: ReactKeyboardEvent) => {\n if (!e.currentTarget.contains(e.target as Element) || !ref.current || !document.activeElement) {\n return;\n }\n\n let walker = getFocusableTreeWalker(ref.current);\n walker.currentNode = document.activeElement;\n\n if ('expandedKeys' in state && document.activeElement === ref.current) {\n if ((e.key === EXPANSION_KEYS['expand'][direction]) && state.selectionManager.focusedKey === node.key && hasChildRows && !state.expandedKeys.has(node.key)) {\n state.toggleKey(node.key);\n e.stopPropagation();\n return;\n } else if ((e.key === EXPANSION_KEYS['collapse'][direction]) && state.selectionManager.focusedKey === node.key && hasChildRows && state.expandedKeys.has(node.key)) {\n state.toggleKey(node.key);\n e.stopPropagation();\n return;\n }\n }\n\n switch (e.key) {\n case 'ArrowLeft': {\n if (keyboardNavigationBehavior === 'arrow') {\n // Find the next focusable element within the row.\n let focusable = direction === 'rtl'\n ? walker.nextNode() as FocusableElement\n : walker.previousNode() as FocusableElement;\n\n if (focusable) {\n e.preventDefault();\n e.stopPropagation();\n focusSafely(focusable);\n scrollIntoViewport(focusable, {containingElement: getScrollParent(ref.current)});\n } else {\n // If there is no next focusable child, then return focus back to the row\n e.preventDefault();\n e.stopPropagation();\n if (direction === 'rtl') {\n focusSafely(ref.current);\n scrollIntoViewport(ref.current, {containingElement: getScrollParent(ref.current)});\n } else {\n walker.currentNode = ref.current;\n let lastElement = last(walker);\n if (lastElement) {\n focusSafely(lastElement);\n scrollIntoViewport(lastElement, {containingElement: getScrollParent(ref.current)});\n }\n }\n }\n }\n break;\n }\n case 'ArrowRight': {\n if (keyboardNavigationBehavior === 'arrow') {\n let focusable = direction === 'rtl'\n ? walker.previousNode() as FocusableElement\n : walker.nextNode() as FocusableElement;\n\n if (focusable) {\n e.preventDefault();\n e.stopPropagation();\n focusSafely(focusable);\n scrollIntoViewport(focusable, {containingElement: getScrollParent(ref.current)});\n } else {\n e.preventDefault();\n e.stopPropagation();\n if (direction === 'ltr') {\n focusSafely(ref.current);\n scrollIntoViewport(ref.current, {containingElement: getScrollParent(ref.current)});\n } else {\n walker.currentNode = ref.current;\n let lastElement = last(walker);\n if (lastElement) {\n focusSafely(lastElement);\n scrollIntoViewport(lastElement, {containingElement: getScrollParent(ref.current)});\n }\n }\n }\n }\n break;\n }\n case 'ArrowUp':\n case 'ArrowDown':\n // Prevent this event from reaching row children, e.g. menu buttons. We want arrow keys to navigate\n // to the row above/below instead. We need to re-dispatch the event from a higher parent so it still\n // bubbles and gets handled by useSelectableCollection.\n if (!e.altKey && ref.current.contains(e.target as Element)) {\n e.stopPropagation();\n e.preventDefault();\n ref.current.parentElement?.dispatchEvent(\n new KeyboardEvent(e.nativeEvent.type, e.nativeEvent)\n );\n }\n break;\n }\n };\n\n let onFocus = (e) => {\n keyWhenFocused.current = node.key;\n if (e.target !== ref.current) {\n // useSelectableItem only handles setting the focused key when\n // the focused element is the row itself. We also want to\n // set the focused key when a child element receives focus.\n // If focus is currently visible (e.g. the user is navigating with the keyboard),\n // then skip this. We want to restore focus to the previously focused row\n // in that case since the list should act like a single tab stop.\n if (!isFocusVisible()) {\n state.selectionManager.setFocusedKey(node.key);\n }\n return;\n }\n };\n\n let onKeyDown = (e) => {\n if (!e.currentTarget.contains(e.target as Element) || !ref.current || !document.activeElement) {\n return;\n }\n\n switch (e.key) {\n case 'Tab': {\n if (keyboardNavigationBehavior === 'tab') {\n // If there is another focusable element within this item, stop propagation so the tab key\n // is handled by the browser and not by useSelectableCollection (which would take us out of the list).\n let walker = getFocusableTreeWalker(ref.current, {tabbable: true});\n walker.currentNode = document.activeElement;\n let next = e.shiftKey ? walker.previousNode() : walker.nextNode();\n\n if (next) {\n e.stopPropagation();\n }\n }\n }\n }\n };\n\n let syntheticLinkProps = useSyntheticLinkProps(node.props);\n let linkProps = itemStates.hasAction ? syntheticLinkProps : {};\n // TODO: re-add when we get translations and fix this for iOS VO\n // let rowAnnouncement;\n // if (onAction) {\n // rowAnnouncement = stringFormatter.format('hasActionAnnouncement');\n // } else if (hasLink) {\n // rowAnnouncement = stringFormatter.format('hasLinkAnnouncement', {\n // link: node.props.href\n // });\n // }\n\n let rowProps: DOMAttributes = mergeProps(itemProps, linkProps, {\n role: 'row',\n onKeyDownCapture,\n onKeyDown,\n onFocus,\n // 'aria-label': [(node.textValue || undefined), rowAnnouncement].filter(Boolean).join(', '),\n 'aria-label': node.textValue || undefined,\n 'aria-selected': state.selectionManager.canSelectItem(node.key) ? state.selectionManager.isSelected(node.key) : undefined,\n 'aria-disabled': state.selectionManager.isDisabled(node.key) || undefined,\n 'aria-labelledby': descriptionId && node.textValue ? `${getRowId(state, node.key)} ${descriptionId}` : undefined,\n id: getRowId(state, node.key)\n });\n\n if (isVirtualized) {\n rowProps['aria-rowindex'] = node.index + 1;\n }\n\n let gridCellProps = {\n role: 'gridcell',\n 'aria-colindex': 1\n };\n\n // TODO: should isExpanded and hasChildRows be a item state that gets returned by the hook?\n return {\n rowProps: {...mergeProps(rowProps, treeGridRowProps)},\n gridCellProps,\n descriptionProps: {\n id: descriptionId\n },\n ...itemStates\n };\n}\n\nfunction last(walker: TreeWalker) {\n let next: FocusableElement | null = null;\n let last: FocusableElement | null = null;\n do {\n last = walker.lastChild() as FocusableElement | null;\n if (last) {\n next = last;\n }\n } while (last);\n return next;\n}\n"],"names":[],"version":3,"file":"useGridListItem.main.js.map"}
|
package/dist/useGridListItem.mjs
CHANGED
|
@@ -38,10 +38,10 @@ const $4e8b0456ef72939f$var$EXPANSION_KEYS = {
|
|
|
38
38
|
function $4e8b0456ef72939f$export$9610e69494fadfd2(props, state, ref) {
|
|
39
39
|
var _node_props, _node_props1;
|
|
40
40
|
// Copied from useGridCell + some modifications to make it not so grid specific
|
|
41
|
-
let { node: node, isVirtualized: isVirtualized
|
|
41
|
+
let { node: node, isVirtualized: isVirtualized } = props;
|
|
42
42
|
// let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/gridlist');
|
|
43
43
|
let { direction: direction } = (0, $lxFUG$useLocale)();
|
|
44
|
-
let { onAction: onAction, linkBehavior: linkBehavior, keyboardNavigationBehavior: keyboardNavigationBehavior } = (0, $ce9b18daab526bbd$export$5b9bb410392e3991).get(state);
|
|
44
|
+
let { onAction: onAction, linkBehavior: linkBehavior, keyboardNavigationBehavior: keyboardNavigationBehavior, shouldSelectOnPressUp: shouldSelectOnPressUp } = (0, $ce9b18daab526bbd$export$5b9bb410392e3991).get(state);
|
|
45
45
|
let descriptionId = (0, $lxFUG$useSlotId)();
|
|
46
46
|
// We need to track the key of the item at the time it was last focused so that we force
|
|
47
47
|
// focus to go to the item when the DOM node is reused for a different item in a virtualizer.
|
|
@@ -90,12 +90,12 @@ function $4e8b0456ef72939f$export$9610e69494fadfd2(props, state, ref) {
|
|
|
90
90
|
key: node.key,
|
|
91
91
|
ref: ref,
|
|
92
92
|
isVirtualized: isVirtualized,
|
|
93
|
-
shouldSelectOnPressUp: shouldSelectOnPressUp,
|
|
93
|
+
shouldSelectOnPressUp: props.shouldSelectOnPressUp || shouldSelectOnPressUp,
|
|
94
94
|
onAction: onAction || ((_node_props = node.props) === null || _node_props === void 0 ? void 0 : _node_props.onAction) ? (0, $lxFUG$chain)((_node_props1 = node.props) === null || _node_props1 === void 0 ? void 0 : _node_props1.onAction, onAction ? ()=>onAction(node.key) : undefined) : undefined,
|
|
95
95
|
focus: focus,
|
|
96
96
|
linkBehavior: linkBehavior
|
|
97
97
|
});
|
|
98
|
-
let
|
|
98
|
+
let onKeyDownCapture = (e)=>{
|
|
99
99
|
if (!e.currentTarget.contains(e.target) || !ref.current || !document.activeElement) return;
|
|
100
100
|
let walker = (0, $lxFUG$getFocusableTreeWalker)(ref.current);
|
|
101
101
|
walker.currentNode = document.activeElement;
|
|
@@ -187,17 +187,6 @@ function $4e8b0456ef72939f$export$9610e69494fadfd2(props, state, ref) {
|
|
|
187
187
|
(_ref_current_parentElement = ref.current.parentElement) === null || _ref_current_parentElement === void 0 ? void 0 : _ref_current_parentElement.dispatchEvent(new KeyboardEvent(e.nativeEvent.type, e.nativeEvent));
|
|
188
188
|
}
|
|
189
189
|
break;
|
|
190
|
-
case 'Tab':
|
|
191
|
-
if (keyboardNavigationBehavior === 'tab') {
|
|
192
|
-
// If there is another focusable element within this item, stop propagation so the tab key
|
|
193
|
-
// is handled by the browser and not by useSelectableCollection (which would take us out of the list).
|
|
194
|
-
let walker = (0, $lxFUG$getFocusableTreeWalker)(ref.current, {
|
|
195
|
-
tabbable: true
|
|
196
|
-
});
|
|
197
|
-
walker.currentNode = document.activeElement;
|
|
198
|
-
let next = e.shiftKey ? walker.previousNode() : walker.nextNode();
|
|
199
|
-
if (next) e.stopPropagation();
|
|
200
|
-
}
|
|
201
190
|
}
|
|
202
191
|
};
|
|
203
192
|
let onFocus = (e)=>{
|
|
@@ -213,6 +202,22 @@ function $4e8b0456ef72939f$export$9610e69494fadfd2(props, state, ref) {
|
|
|
213
202
|
return;
|
|
214
203
|
}
|
|
215
204
|
};
|
|
205
|
+
let onKeyDown = (e)=>{
|
|
206
|
+
if (!e.currentTarget.contains(e.target) || !ref.current || !document.activeElement) return;
|
|
207
|
+
switch(e.key){
|
|
208
|
+
case 'Tab':
|
|
209
|
+
if (keyboardNavigationBehavior === 'tab') {
|
|
210
|
+
// If there is another focusable element within this item, stop propagation so the tab key
|
|
211
|
+
// is handled by the browser and not by useSelectableCollection (which would take us out of the list).
|
|
212
|
+
let walker = (0, $lxFUG$getFocusableTreeWalker)(ref.current, {
|
|
213
|
+
tabbable: true
|
|
214
|
+
});
|
|
215
|
+
walker.currentNode = document.activeElement;
|
|
216
|
+
let next = e.shiftKey ? walker.previousNode() : walker.nextNode();
|
|
217
|
+
if (next) e.stopPropagation();
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
};
|
|
216
221
|
let syntheticLinkProps = (0, $lxFUG$useSyntheticLinkProps)(node.props);
|
|
217
222
|
let linkProps = itemStates.hasAction ? syntheticLinkProps : {};
|
|
218
223
|
// TODO: re-add when we get translations and fix this for iOS VO
|
|
@@ -226,7 +231,8 @@ function $4e8b0456ef72939f$export$9610e69494fadfd2(props, state, ref) {
|
|
|
226
231
|
// }
|
|
227
232
|
let rowProps = (0, $lxFUG$mergeProps)(itemProps, linkProps, {
|
|
228
233
|
role: 'row',
|
|
229
|
-
onKeyDownCapture:
|
|
234
|
+
onKeyDownCapture: onKeyDownCapture,
|
|
235
|
+
onKeyDown: onKeyDown,
|
|
230
236
|
onFocus: onFocus,
|
|
231
237
|
// 'aria-label': [(node.textValue || undefined), rowAnnouncement].filter(Boolean).join(', '),
|
|
232
238
|
'aria-label': node.textValue || undefined,
|
|
@@ -38,10 +38,10 @@ const $4e8b0456ef72939f$var$EXPANSION_KEYS = {
|
|
|
38
38
|
function $4e8b0456ef72939f$export$9610e69494fadfd2(props, state, ref) {
|
|
39
39
|
var _node_props, _node_props1;
|
|
40
40
|
// Copied from useGridCell + some modifications to make it not so grid specific
|
|
41
|
-
let { node: node, isVirtualized: isVirtualized
|
|
41
|
+
let { node: node, isVirtualized: isVirtualized } = props;
|
|
42
42
|
// let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/gridlist');
|
|
43
43
|
let { direction: direction } = (0, $lxFUG$useLocale)();
|
|
44
|
-
let { onAction: onAction, linkBehavior: linkBehavior, keyboardNavigationBehavior: keyboardNavigationBehavior } = (0, $ce9b18daab526bbd$export$5b9bb410392e3991).get(state);
|
|
44
|
+
let { onAction: onAction, linkBehavior: linkBehavior, keyboardNavigationBehavior: keyboardNavigationBehavior, shouldSelectOnPressUp: shouldSelectOnPressUp } = (0, $ce9b18daab526bbd$export$5b9bb410392e3991).get(state);
|
|
45
45
|
let descriptionId = (0, $lxFUG$useSlotId)();
|
|
46
46
|
// We need to track the key of the item at the time it was last focused so that we force
|
|
47
47
|
// focus to go to the item when the DOM node is reused for a different item in a virtualizer.
|
|
@@ -90,12 +90,12 @@ function $4e8b0456ef72939f$export$9610e69494fadfd2(props, state, ref) {
|
|
|
90
90
|
key: node.key,
|
|
91
91
|
ref: ref,
|
|
92
92
|
isVirtualized: isVirtualized,
|
|
93
|
-
shouldSelectOnPressUp: shouldSelectOnPressUp,
|
|
93
|
+
shouldSelectOnPressUp: props.shouldSelectOnPressUp || shouldSelectOnPressUp,
|
|
94
94
|
onAction: onAction || ((_node_props = node.props) === null || _node_props === void 0 ? void 0 : _node_props.onAction) ? (0, $lxFUG$chain)((_node_props1 = node.props) === null || _node_props1 === void 0 ? void 0 : _node_props1.onAction, onAction ? ()=>onAction(node.key) : undefined) : undefined,
|
|
95
95
|
focus: focus,
|
|
96
96
|
linkBehavior: linkBehavior
|
|
97
97
|
});
|
|
98
|
-
let
|
|
98
|
+
let onKeyDownCapture = (e)=>{
|
|
99
99
|
if (!e.currentTarget.contains(e.target) || !ref.current || !document.activeElement) return;
|
|
100
100
|
let walker = (0, $lxFUG$getFocusableTreeWalker)(ref.current);
|
|
101
101
|
walker.currentNode = document.activeElement;
|
|
@@ -187,17 +187,6 @@ function $4e8b0456ef72939f$export$9610e69494fadfd2(props, state, ref) {
|
|
|
187
187
|
(_ref_current_parentElement = ref.current.parentElement) === null || _ref_current_parentElement === void 0 ? void 0 : _ref_current_parentElement.dispatchEvent(new KeyboardEvent(e.nativeEvent.type, e.nativeEvent));
|
|
188
188
|
}
|
|
189
189
|
break;
|
|
190
|
-
case 'Tab':
|
|
191
|
-
if (keyboardNavigationBehavior === 'tab') {
|
|
192
|
-
// If there is another focusable element within this item, stop propagation so the tab key
|
|
193
|
-
// is handled by the browser and not by useSelectableCollection (which would take us out of the list).
|
|
194
|
-
let walker = (0, $lxFUG$getFocusableTreeWalker)(ref.current, {
|
|
195
|
-
tabbable: true
|
|
196
|
-
});
|
|
197
|
-
walker.currentNode = document.activeElement;
|
|
198
|
-
let next = e.shiftKey ? walker.previousNode() : walker.nextNode();
|
|
199
|
-
if (next) e.stopPropagation();
|
|
200
|
-
}
|
|
201
190
|
}
|
|
202
191
|
};
|
|
203
192
|
let onFocus = (e)=>{
|
|
@@ -213,6 +202,22 @@ function $4e8b0456ef72939f$export$9610e69494fadfd2(props, state, ref) {
|
|
|
213
202
|
return;
|
|
214
203
|
}
|
|
215
204
|
};
|
|
205
|
+
let onKeyDown = (e)=>{
|
|
206
|
+
if (!e.currentTarget.contains(e.target) || !ref.current || !document.activeElement) return;
|
|
207
|
+
switch(e.key){
|
|
208
|
+
case 'Tab':
|
|
209
|
+
if (keyboardNavigationBehavior === 'tab') {
|
|
210
|
+
// If there is another focusable element within this item, stop propagation so the tab key
|
|
211
|
+
// is handled by the browser and not by useSelectableCollection (which would take us out of the list).
|
|
212
|
+
let walker = (0, $lxFUG$getFocusableTreeWalker)(ref.current, {
|
|
213
|
+
tabbable: true
|
|
214
|
+
});
|
|
215
|
+
walker.currentNode = document.activeElement;
|
|
216
|
+
let next = e.shiftKey ? walker.previousNode() : walker.nextNode();
|
|
217
|
+
if (next) e.stopPropagation();
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
};
|
|
216
221
|
let syntheticLinkProps = (0, $lxFUG$useSyntheticLinkProps)(node.props);
|
|
217
222
|
let linkProps = itemStates.hasAction ? syntheticLinkProps : {};
|
|
218
223
|
// TODO: re-add when we get translations and fix this for iOS VO
|
|
@@ -226,7 +231,8 @@ function $4e8b0456ef72939f$export$9610e69494fadfd2(props, state, ref) {
|
|
|
226
231
|
// }
|
|
227
232
|
let rowProps = (0, $lxFUG$mergeProps)(itemProps, linkProps, {
|
|
228
233
|
role: 'row',
|
|
229
|
-
onKeyDownCapture:
|
|
234
|
+
onKeyDownCapture: onKeyDownCapture,
|
|
235
|
+
onKeyDown: onKeyDown,
|
|
230
236
|
onFocus: onFocus,
|
|
231
237
|
// 'aria-label': [(node.textValue || undefined), rowAnnouncement].filter(Boolean).join(', '),
|
|
232
238
|
'aria-label': node.textValue || undefined,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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","sources":["packages/@react-aria/gridlist/src/useGridListItem.ts"],"sourcesContent":["/*\n * Copyright 2022 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {chain, getScrollParent, mergeProps, scrollIntoViewport, useSlotId, useSyntheticLinkProps} from '@react-aria/utils';\nimport {DOMAttributes, FocusableElement, Key, RefObject, Node as RSNode} from '@react-types/shared';\nimport {focusSafely, getFocusableTreeWalker} from '@react-aria/focus';\nimport {getLastItem} from '@react-stately/collections';\nimport {getRowId, listMap} from './utils';\nimport {HTMLAttributes, KeyboardEvent as ReactKeyboardEvent, useRef} from 'react';\nimport {isFocusVisible} from '@react-aria/interactions';\nimport type {ListState} from '@react-stately/list';\nimport {SelectableItemStates, useSelectableItem} from '@react-aria/selection';\nimport type {TreeState} from '@react-stately/tree';\nimport {useLocale} from '@react-aria/i18n';\n\nexport interface AriaGridListItemOptions {\n /** An object representing the list item. Contains all the relevant information that makes up the list row. */\n node: RSNode<unknown>,\n /** Whether the list row is contained in a virtual scroller. */\n isVirtualized?: boolean,\n /** Whether selection should occur on press up instead of press down. */\n shouldSelectOnPressUp?: boolean,\n /** Whether this item has children, even if not loaded yet. */\n hasChildItems?: boolean\n}\n\nexport interface GridListItemAria extends SelectableItemStates {\n /** Props for the list row element. */\n rowProps: DOMAttributes,\n /** Props for the grid cell element within the list row. */\n gridCellProps: DOMAttributes,\n /** Props for the list item description element, if any. */\n descriptionProps: DOMAttributes\n}\n\nconst EXPANSION_KEYS = {\n 'expand': {\n ltr: 'ArrowRight',\n rtl: 'ArrowLeft'\n },\n 'collapse': {\n ltr: 'ArrowLeft',\n rtl: 'ArrowRight'\n }\n};\n\n/**\n * Provides the behavior and accessibility implementation for a row in a grid list.\n * @param props - Props for the row.\n * @param state - State of the parent list, as returned by `useListState`.\n * @param ref - The ref attached to the row element.\n */\nexport function useGridListItem<T>(props: AriaGridListItemOptions, state: ListState<T> | TreeState<T>, ref: RefObject<FocusableElement | null>): GridListItemAria {\n // Copied from useGridCell + some modifications to make it not so grid specific\n let {\n node,\n isVirtualized,\n shouldSelectOnPressUp\n } = props;\n\n // let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/gridlist');\n let {direction} = useLocale();\n let {onAction, linkBehavior, keyboardNavigationBehavior} = listMap.get(state)!;\n let descriptionId = useSlotId();\n\n // We need to track the key of the item at the time it was last focused so that we force\n // focus to go to the item when the DOM node is reused for a different item in a virtualizer.\n let keyWhenFocused = useRef<Key | null>(null);\n let focus = () => {\n // Don't shift focus to the row if the active element is a element within the row already\n // (e.g. clicking on a row button)\n if (\n ref.current !== null &&\n ((keyWhenFocused.current != null && node.key !== keyWhenFocused.current) ||\n !ref.current?.contains(document.activeElement))\n ) {\n focusSafely(ref.current);\n }\n };\n\n let treeGridRowProps: HTMLAttributes<HTMLElement> = {};\n let hasChildRows = props.hasChildItems;\n let hasLink = state.selectionManager.isLink(node.key);\n if (node != null && 'expandedKeys' in state) {\n // TODO: ideally node.hasChildNodes would be a way to tell if a row has child nodes, but the row's contents make it so that value is always\n // true...\n let children = state.collection.getChildren?.(node.key);\n hasChildRows = hasChildRows || [...(children ?? [])].length > 1;\n\n if (onAction == null && !hasLink && state.selectionManager.selectionMode === 'none' && hasChildRows) {\n onAction = () => state.toggleKey(node.key);\n }\n\n let isExpanded = hasChildRows ? state.expandedKeys.has(node.key) : undefined;\n let setSize = 1;\n if (node.level > 0 && node?.parentKey != null) {\n let parent = state.collection.getItem(node.parentKey);\n if (parent) {\n // siblings must exist because our original node exists, same with lastItem\n let siblings = state.collection.getChildren?.(parent.key)!;\n setSize = getLastItem(siblings)!.index + 1;\n }\n } else {\n setSize = ([...state.collection].filter(row => row.level === 0).at(-1)?.index ?? 0) + 1;\n }\n treeGridRowProps = {\n 'aria-expanded': isExpanded,\n 'aria-level': node.level + 1,\n 'aria-posinset': node?.index + 1,\n 'aria-setsize': setSize\n };\n }\n\n let {itemProps, ...itemStates} = useSelectableItem({\n selectionManager: state.selectionManager,\n key: node.key,\n ref,\n isVirtualized,\n shouldSelectOnPressUp,\n onAction: onAction || node.props?.onAction ? chain(node.props?.onAction, onAction ? () => onAction(node.key) : undefined) : undefined,\n focus,\n linkBehavior\n });\n\n let onKeyDown = (e: ReactKeyboardEvent) => {\n if (!e.currentTarget.contains(e.target as Element) || !ref.current || !document.activeElement) {\n return;\n }\n\n let walker = getFocusableTreeWalker(ref.current);\n walker.currentNode = document.activeElement;\n\n if ('expandedKeys' in state && document.activeElement === ref.current) {\n if ((e.key === EXPANSION_KEYS['expand'][direction]) && state.selectionManager.focusedKey === node.key && hasChildRows && !state.expandedKeys.has(node.key)) {\n state.toggleKey(node.key);\n e.stopPropagation();\n return;\n } else if ((e.key === EXPANSION_KEYS['collapse'][direction]) && state.selectionManager.focusedKey === node.key && hasChildRows && state.expandedKeys.has(node.key)) {\n state.toggleKey(node.key);\n e.stopPropagation();\n return;\n }\n }\n\n switch (e.key) {\n case 'ArrowLeft': {\n if (keyboardNavigationBehavior === 'arrow') {\n // Find the next focusable element within the row.\n let focusable = direction === 'rtl'\n ? walker.nextNode() as FocusableElement\n : walker.previousNode() as FocusableElement;\n\n if (focusable) {\n e.preventDefault();\n e.stopPropagation();\n focusSafely(focusable);\n scrollIntoViewport(focusable, {containingElement: getScrollParent(ref.current)});\n } else {\n // If there is no next focusable child, then return focus back to the row\n e.preventDefault();\n e.stopPropagation();\n if (direction === 'rtl') {\n focusSafely(ref.current);\n scrollIntoViewport(ref.current, {containingElement: getScrollParent(ref.current)});\n } else {\n walker.currentNode = ref.current;\n let lastElement = last(walker);\n if (lastElement) {\n focusSafely(lastElement);\n scrollIntoViewport(lastElement, {containingElement: getScrollParent(ref.current)});\n }\n }\n }\n }\n break;\n }\n case 'ArrowRight': {\n if (keyboardNavigationBehavior === 'arrow') {\n let focusable = direction === 'rtl'\n ? walker.previousNode() as FocusableElement\n : walker.nextNode() as FocusableElement;\n\n if (focusable) {\n e.preventDefault();\n e.stopPropagation();\n focusSafely(focusable);\n scrollIntoViewport(focusable, {containingElement: getScrollParent(ref.current)});\n } else {\n e.preventDefault();\n e.stopPropagation();\n if (direction === 'ltr') {\n focusSafely(ref.current);\n scrollIntoViewport(ref.current, {containingElement: getScrollParent(ref.current)});\n } else {\n walker.currentNode = ref.current;\n let lastElement = last(walker);\n if (lastElement) {\n focusSafely(lastElement);\n scrollIntoViewport(lastElement, {containingElement: getScrollParent(ref.current)});\n }\n }\n }\n }\n break;\n }\n case 'ArrowUp':\n case 'ArrowDown':\n // Prevent this event from reaching row children, e.g. menu buttons. We want arrow keys to navigate\n // to the row above/below instead. We need to re-dispatch the event from a higher parent so it still\n // bubbles and gets handled by useSelectableCollection.\n if (!e.altKey && ref.current.contains(e.target as Element)) {\n e.stopPropagation();\n e.preventDefault();\n ref.current.parentElement?.dispatchEvent(\n new KeyboardEvent(e.nativeEvent.type, e.nativeEvent)\n );\n }\n break;\n case 'Tab': {\n if (keyboardNavigationBehavior === 'tab') {\n // If there is another focusable element within this item, stop propagation so the tab key\n // is handled by the browser and not by useSelectableCollection (which would take us out of the list).\n let walker = getFocusableTreeWalker(ref.current, {tabbable: true});\n walker.currentNode = document.activeElement;\n let next = e.shiftKey ? walker.previousNode() : walker.nextNode();\n if (next) {\n e.stopPropagation();\n }\n }\n }\n }\n };\n\n let onFocus = (e) => {\n keyWhenFocused.current = node.key;\n if (e.target !== ref.current) {\n // useSelectableItem only handles setting the focused key when\n // the focused element is the row itself. We also want to\n // set the focused key when a child element receives focus.\n // If focus is currently visible (e.g. the user is navigating with the keyboard),\n // then skip this. We want to restore focus to the previously focused row\n // in that case since the list should act like a single tab stop.\n if (!isFocusVisible()) {\n state.selectionManager.setFocusedKey(node.key);\n }\n return;\n }\n };\n\n let syntheticLinkProps = useSyntheticLinkProps(node.props);\n let linkProps = itemStates.hasAction ? syntheticLinkProps : {};\n // TODO: re-add when we get translations and fix this for iOS VO\n // let rowAnnouncement;\n // if (onAction) {\n // rowAnnouncement = stringFormatter.format('hasActionAnnouncement');\n // } else if (hasLink) {\n // rowAnnouncement = stringFormatter.format('hasLinkAnnouncement', {\n // link: node.props.href\n // });\n // }\n\n let rowProps: DOMAttributes = mergeProps(itemProps, linkProps, {\n role: 'row',\n onKeyDownCapture: onKeyDown,\n onFocus,\n // 'aria-label': [(node.textValue || undefined), rowAnnouncement].filter(Boolean).join(', '),\n 'aria-label': node.textValue || undefined,\n 'aria-selected': state.selectionManager.canSelectItem(node.key) ? state.selectionManager.isSelected(node.key) : undefined,\n 'aria-disabled': state.selectionManager.isDisabled(node.key) || undefined,\n 'aria-labelledby': descriptionId && node.textValue ? `${getRowId(state, node.key)} ${descriptionId}` : undefined,\n id: getRowId(state, node.key)\n });\n\n if (isVirtualized) {\n rowProps['aria-rowindex'] = node.index + 1;\n }\n\n let gridCellProps = {\n role: 'gridcell',\n 'aria-colindex': 1\n };\n\n // TODO: should isExpanded and hasChildRows be a item state that gets returned by the hook?\n return {\n rowProps: {...mergeProps(rowProps, treeGridRowProps)},\n gridCellProps,\n descriptionProps: {\n id: descriptionId\n },\n ...itemStates\n };\n}\n\nfunction last(walker: TreeWalker) {\n let next: FocusableElement | null = null;\n let last: FocusableElement | null = null;\n do {\n last = walker.lastChild() as FocusableElement | null;\n if (last) {\n next = last;\n }\n } while (last);\n return next;\n}\n"],"names":[],"version":3,"file":"useGridListItem.module.js.map"}
|
|
1
|
+
{"mappings":";;;;;;;;;AAAA;;;;;;;;;;CAUC;;;;;;;;AAkCD,MAAM,uCAAiB;IACrB,UAAU;QACR,KAAK;QACL,KAAK;IACP;IACA,YAAY;QACV,KAAK;QACL,KAAK;IACP;AACF;AAQO,SAAS,0CAAmB,KAA8B,EAAE,KAAkC,EAAE,GAAuC;QAkEpH,aAA6B;IAjErD,+EAA+E;IAC/E,IAAI,QACF,IAAI,iBACJ,aAAa,EACd,GAAG;IAEJ,2FAA2F;IAC3F,IAAI,aAAC,SAAS,EAAC,GAAG,CAAA,GAAA,gBAAQ;IAC1B,IAAI,YAAC,QAAQ,gBAAE,YAAY,8BAAE,0BAA0B,yBAAE,qBAAqB,EAAC,GAAG,CAAA,GAAA,yCAAM,EAAE,GAAG,CAAC;IAC9F,IAAI,gBAAgB,CAAA,GAAA,gBAAQ;IAE5B,wFAAwF;IACxF,6FAA6F;IAC7F,IAAI,iBAAiB,CAAA,GAAA,aAAK,EAAc;IACxC,IAAI,QAAQ;YAMP;QALH,yFAAyF;QACzF,kCAAkC;QAClC,IACE,IAAI,OAAO,KAAK,QACf,CAAA,AAAC,eAAe,OAAO,IAAI,QAAQ,KAAK,GAAG,KAAK,eAAe,OAAO,IACvE,GAAC,eAAA,IAAI,OAAO,cAAX,mCAAA,aAAa,QAAQ,CAAC,SAAS,aAAa,EAAA,GAE7C,CAAA,GAAA,kBAAU,EAAE,IAAI,OAAO;IAE3B;IAEA,IAAI,mBAAgD,CAAC;IACrD,IAAI,eAAe,MAAM,aAAa;IACtC,IAAI,UAAU,MAAM,gBAAgB,CAAC,MAAM,CAAC,KAAK,GAAG;IACpD,IAAI,QAAQ,QAAQ,kBAAkB,OAAO;YAG5B,+BAAA,mBAiBF;QAnBb,2IAA2I;QAC3I,UAAU;QACV,IAAI,YAAW,gCAAA,CAAA,oBAAA,MAAM,UAAU,EAAC,WAAW,cAA5B,oDAAA,mCAAA,mBAA+B,KAAK,GAAG;QACtD,eAAe,gBAAgB;eAAK,qBAAA,sBAAA,WAAY,EAAE;SAAE,CAAC,MAAM,GAAG;QAE9D,IAAI,YAAY,QAAQ,CAAC,WAAW,MAAM,gBAAgB,CAAC,aAAa,KAAK,UAAU,cACrF,WAAW,IAAM,MAAM,SAAS,CAAC,KAAK,GAAG;QAG3C,IAAI,aAAa,eAAe,MAAM,YAAY,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI;QACnE,IAAI,UAAU;YASD;QARb,IAAI,KAAK,KAAK,GAAG,KAAK,CAAA,iBAAA,2BAAA,KAAM,SAAS,KAAI,MAAM;YAC7C,IAAI,SAAS,MAAM,UAAU,CAAC,OAAO,CAAC,KAAK,SAAS;YACpD,IAAI,QAAQ;oBAEK,gCAAA;gBADf,2EAA2E;gBAC3E,IAAI,YAAW,iCAAA,CAAA,qBAAA,MAAM,UAAU,EAAC,WAAW,cAA5B,qDAAA,oCAAA,oBAA+B,OAAO,GAAG;gBACxD,UAAU,CAAA,GAAA,kBAAU,EAAE,UAAW,KAAK,GAAG;YAC3C;QACF,OACE,UAAU,AAAC,CAAA,CAAA,oBAAA,aAAA;eAAI,MAAM,UAAU;SAAC,CAAC,MAAM,CAAC,CAAA,MAAO,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC,CAAC,gBAAzD,iCAAA,WAA6D,KAAK,cAAlE,8BAAA,mBAAsE,CAAA,IAAK;QAExF,mBAAmB;YACjB,iBAAiB;YACjB,cAAc,KAAK,KAAK,GAAG;YAC3B,iBAAiB,CAAA,iBAAA,2BAAA,KAAM,KAAK,IAAG;YAC/B,gBAAgB;QAClB;IACF;IAEA,IAAI,aAAC,SAAS,EAAE,GAAG,YAAW,GAAG,CAAA,GAAA,wBAAgB,EAAE;QACjD,kBAAkB,MAAM,gBAAgB;QACxC,KAAK,KAAK,GAAG;aACb;uBACA;QACA,uBAAuB,MAAM,qBAAqB,IAAI;QACtD,UAAU,cAAY,cAAA,KAAK,KAAK,cAAV,kCAAA,YAAY,QAAQ,IAAG,CAAA,GAAA,YAAI,GAAE,eAAA,KAAK,KAAK,cAAV,mCAAA,aAAY,QAAQ,EAAE,WAAW,IAAM,SAAS,KAAK,GAAG,IAAI,aAAa;eAC5H;sBACA;IACF;IAEA,IAAI,mBAAmB,CAAC;QACtB,IAAI,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,EAAE,MAAM,KAAgB,CAAC,IAAI,OAAO,IAAI,CAAC,SAAS,aAAa,EAC3F;QAGF,IAAI,SAAS,CAAA,GAAA,6BAAqB,EAAE,IAAI,OAAO;QAC/C,OAAO,WAAW,GAAG,SAAS,aAAa;QAE3C,IAAI,kBAAkB,SAAS,SAAS,aAAa,KAAK,IAAI,OAAO,EAAE;YACrE,IAAI,AAAC,EAAE,GAAG,KAAK,oCAAc,CAAC,SAAS,CAAC,UAAU,IAAK,MAAM,gBAAgB,CAAC,UAAU,KAAK,KAAK,GAAG,IAAI,gBAAgB,CAAC,MAAM,YAAY,CAAC,GAAG,CAAC,KAAK,GAAG,GAAG;gBAC1J,MAAM,SAAS,CAAC,KAAK,GAAG;gBACxB,EAAE,eAAe;gBACjB;YACF,OAAO,IAAI,AAAC,EAAE,GAAG,KAAK,oCAAc,CAAC,WAAW,CAAC,UAAU,IAAK,MAAM,gBAAgB,CAAC,UAAU,KAAK,KAAK,GAAG,IAAI,gBAAgB,MAAM,YAAY,CAAC,GAAG,CAAC,KAAK,GAAG,GAAG;gBAClK,MAAM,SAAS,CAAC,KAAK,GAAG;gBACxB,EAAE,eAAe;gBACjB;YACF;QACF;QAEA,OAAQ,EAAE,GAAG;YACX,KAAK;gBACH,IAAI,+BAA+B,SAAS;oBAC1C,kDAAkD;oBAClD,IAAI,YAAY,cAAc,QAC1B,OAAO,QAAQ,KACf,OAAO,YAAY;oBAEvB,IAAI,WAAW;wBACb,EAAE,cAAc;wBAChB,EAAE,eAAe;wBACjB,CAAA,GAAA,kBAAU,EAAE;wBACZ,CAAA,GAAA,yBAAiB,EAAE,WAAW;4BAAC,mBAAmB,CAAA,GAAA,sBAAc,EAAE,IAAI,OAAO;wBAAC;oBAChF,OAAO;wBACL,yEAAyE;wBACzE,EAAE,cAAc;wBAChB,EAAE,eAAe;wBACjB,IAAI,cAAc,OAAO;4BACvB,CAAA,GAAA,kBAAU,EAAE,IAAI,OAAO;4BACvB,CAAA,GAAA,yBAAiB,EAAE,IAAI,OAAO,EAAE;gCAAC,mBAAmB,CAAA,GAAA,sBAAc,EAAE,IAAI,OAAO;4BAAC;wBAClF,OAAO;4BACL,OAAO,WAAW,GAAG,IAAI,OAAO;4BAChC,IAAI,cAAc,2BAAK;4BACvB,IAAI,aAAa;gCACf,CAAA,GAAA,kBAAU,EAAE;gCACZ,CAAA,GAAA,yBAAiB,EAAE,aAAa;oCAAC,mBAAmB,CAAA,GAAA,sBAAc,EAAE,IAAI,OAAO;gCAAC;4BAClF;wBACF;oBACF;gBACF;gBACA;YAEF,KAAK;gBACH,IAAI,+BAA+B,SAAS;oBAC1C,IAAI,YAAY,cAAc,QAC1B,OAAO,YAAY,KACnB,OAAO,QAAQ;oBAEnB,IAAI,WAAW;wBACb,EAAE,cAAc;wBAChB,EAAE,eAAe;wBACjB,CAAA,GAAA,kBAAU,EAAE;wBACZ,CAAA,GAAA,yBAAiB,EAAE,WAAW;4BAAC,mBAAmB,CAAA,GAAA,sBAAc,EAAE,IAAI,OAAO;wBAAC;oBAChF,OAAO;wBACL,EAAE,cAAc;wBAChB,EAAE,eAAe;wBACjB,IAAI,cAAc,OAAO;4BACvB,CAAA,GAAA,kBAAU,EAAE,IAAI,OAAO;4BACvB,CAAA,GAAA,yBAAiB,EAAE,IAAI,OAAO,EAAE;gCAAC,mBAAmB,CAAA,GAAA,sBAAc,EAAE,IAAI,OAAO;4BAAC;wBAClF,OAAO;4BACL,OAAO,WAAW,GAAG,IAAI,OAAO;4BAChC,IAAI,cAAc,2BAAK;4BACvB,IAAI,aAAa;gCACf,CAAA,GAAA,kBAAU,EAAE;gCACZ,CAAA,GAAA,yBAAiB,EAAE,aAAa;oCAAC,mBAAmB,CAAA,GAAA,sBAAc,EAAE,IAAI,OAAO;gCAAC;4BAClF;wBACF;oBACF;gBACF;gBACA;YAEF,KAAK;YACL,KAAK;gBACH,mGAAmG;gBACnG,oGAAoG;gBACpG,uDAAuD;gBACvD,IAAI,CAAC,EAAE,MAAM,IAAI,IAAI,OAAO,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAc;wBAG1D;oBAFA,EAAE,eAAe;oBACjB,EAAE,cAAc;qBAChB,6BAAA,IAAI,OAAO,CAAC,aAAa,cAAzB,iDAAA,2BAA2B,aAAa,CACtC,IAAI,cAAc,EAAE,WAAW,CAAC,IAAI,EAAE,EAAE,WAAW;gBAEvD;gBACA;QACJ;IACF;IAEA,IAAI,UAAU,CAAC;QACb,eAAe,OAAO,GAAG,KAAK,GAAG;QACjC,IAAI,EAAE,MAAM,KAAK,IAAI,OAAO,EAAE;YAC5B,8DAA8D;YAC9D,yDAAyD;YACzD,2DAA2D;YAC3D,iFAAiF;YACjF,yEAAyE;YACzE,iEAAiE;YACjE,IAAI,CAAC,CAAA,GAAA,qBAAa,KAChB,MAAM,gBAAgB,CAAC,aAAa,CAAC,KAAK,GAAG;YAE/C;QACF;IACF;IAEA,IAAI,YAAY,CAAC;QACf,IAAI,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,EAAE,MAAM,KAAgB,CAAC,IAAI,OAAO,IAAI,CAAC,SAAS,aAAa,EAC3F;QAGF,OAAQ,EAAE,GAAG;YACX,KAAK;gBACH,IAAI,+BAA+B,OAAO;oBACxC,0FAA0F;oBAC1F,sGAAsG;oBACtG,IAAI,SAAS,CAAA,GAAA,6BAAqB,EAAE,IAAI,OAAO,EAAE;wBAAC,UAAU;oBAAI;oBAChE,OAAO,WAAW,GAAG,SAAS,aAAa;oBAC3C,IAAI,OAAO,EAAE,QAAQ,GAAG,OAAO,YAAY,KAAK,OAAO,QAAQ;oBAE/D,IAAI,MACF,EAAE,eAAe;gBAErB;QAEJ;IACF;IAEA,IAAI,qBAAqB,CAAA,GAAA,4BAAoB,EAAE,KAAK,KAAK;IACzD,IAAI,YAAY,WAAW,SAAS,GAAG,qBAAqB,CAAC;IAC7D,gEAAgE;IAChE,uBAAuB;IACvB,kBAAkB;IAClB,uEAAuE;IACvE,wBAAwB;IACxB,sEAAsE;IACtE,4BAA4B;IAC5B,QAAQ;IACR,IAAI;IAEJ,IAAI,WAA0B,CAAA,GAAA,iBAAS,EAAE,WAAW,WAAW;QAC7D,MAAM;0BACN;mBACA;iBACA;QACA,6FAA6F;QAC7F,cAAc,KAAK,SAAS,IAAI;QAChC,iBAAiB,MAAM,gBAAgB,CAAC,aAAa,CAAC,KAAK,GAAG,IAAI,MAAM,gBAAgB,CAAC,UAAU,CAAC,KAAK,GAAG,IAAI;QAChH,iBAAiB,MAAM,gBAAgB,CAAC,UAAU,CAAC,KAAK,GAAG,KAAK;QAChE,mBAAmB,iBAAiB,KAAK,SAAS,GAAG,GAAG,CAAA,GAAA,yCAAO,EAAE,OAAO,KAAK,GAAG,EAAE,CAAC,EAAE,eAAe,GAAG;QACvG,IAAI,CAAA,GAAA,yCAAO,EAAE,OAAO,KAAK,GAAG;IAC9B;IAEA,IAAI,eACF,QAAQ,CAAC,gBAAgB,GAAG,KAAK,KAAK,GAAG;IAG3C,IAAI,gBAAgB;QAClB,MAAM;QACN,iBAAiB;IACnB;IAEA,2FAA2F;IAC3F,OAAO;QACL,UAAU;YAAC,GAAG,CAAA,GAAA,iBAAS,EAAE,UAAU,iBAAiB;QAAA;uBACpD;QACA,kBAAkB;YAChB,IAAI;QACN;QACA,GAAG,UAAU;IACf;AACF;AAEA,SAAS,2BAAK,MAAkB;IAC9B,IAAI,OAAgC;IACpC,IAAI,OAAgC;IACpC,GAAG;QACD,OAAO,OAAO,SAAS;QACvB,IAAI,MACF,OAAO;IAEX,QAAS,MAAM;IACf,OAAO;AACT","sources":["packages/@react-aria/gridlist/src/useGridListItem.ts"],"sourcesContent":["/*\n * Copyright 2022 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {chain, getScrollParent, mergeProps, scrollIntoViewport, useSlotId, useSyntheticLinkProps} from '@react-aria/utils';\nimport {DOMAttributes, FocusableElement, Key, RefObject, Node as RSNode} from '@react-types/shared';\nimport {focusSafely, getFocusableTreeWalker} from '@react-aria/focus';\nimport {getLastItem} from '@react-stately/collections';\nimport {getRowId, listMap} from './utils';\nimport {HTMLAttributes, KeyboardEvent as ReactKeyboardEvent, useRef} from 'react';\nimport {isFocusVisible} from '@react-aria/interactions';\nimport type {ListState} from '@react-stately/list';\nimport {SelectableItemStates, useSelectableItem} from '@react-aria/selection';\nimport type {TreeState} from '@react-stately/tree';\nimport {useLocale} from '@react-aria/i18n';\n\nexport interface AriaGridListItemOptions {\n /** An object representing the list item. Contains all the relevant information that makes up the list row. */\n node: RSNode<unknown>,\n /** Whether the list row is contained in a virtual scroller. */\n isVirtualized?: boolean,\n /** Whether selection should occur on press up instead of press down. */\n shouldSelectOnPressUp?: boolean,\n /** Whether this item has children, even if not loaded yet. */\n hasChildItems?: boolean\n}\n\nexport interface GridListItemAria extends SelectableItemStates {\n /** Props for the list row element. */\n rowProps: DOMAttributes,\n /** Props for the grid cell element within the list row. */\n gridCellProps: DOMAttributes,\n /** Props for the list item description element, if any. */\n descriptionProps: DOMAttributes\n}\n\nconst EXPANSION_KEYS = {\n 'expand': {\n ltr: 'ArrowRight',\n rtl: 'ArrowLeft'\n },\n 'collapse': {\n ltr: 'ArrowLeft',\n rtl: 'ArrowRight'\n }\n};\n\n/**\n * Provides the behavior and accessibility implementation for a row in a grid list.\n * @param props - Props for the row.\n * @param state - State of the parent list, as returned by `useListState`.\n * @param ref - The ref attached to the row element.\n */\nexport function useGridListItem<T>(props: AriaGridListItemOptions, state: ListState<T> | TreeState<T>, ref: RefObject<FocusableElement | null>): GridListItemAria {\n // Copied from useGridCell + some modifications to make it not so grid specific\n let {\n node,\n isVirtualized\n } = props;\n\n // let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/gridlist');\n let {direction} = useLocale();\n let {onAction, linkBehavior, keyboardNavigationBehavior, shouldSelectOnPressUp} = listMap.get(state)!;\n let descriptionId = useSlotId();\n\n // We need to track the key of the item at the time it was last focused so that we force\n // focus to go to the item when the DOM node is reused for a different item in a virtualizer.\n let keyWhenFocused = useRef<Key | null>(null);\n let focus = () => {\n // Don't shift focus to the row if the active element is a element within the row already\n // (e.g. clicking on a row button)\n if (\n ref.current !== null &&\n ((keyWhenFocused.current != null && node.key !== keyWhenFocused.current) ||\n !ref.current?.contains(document.activeElement))\n ) {\n focusSafely(ref.current);\n }\n };\n\n let treeGridRowProps: HTMLAttributes<HTMLElement> = {};\n let hasChildRows = props.hasChildItems;\n let hasLink = state.selectionManager.isLink(node.key);\n if (node != null && 'expandedKeys' in state) {\n // TODO: ideally node.hasChildNodes would be a way to tell if a row has child nodes, but the row's contents make it so that value is always\n // true...\n let children = state.collection.getChildren?.(node.key);\n hasChildRows = hasChildRows || [...(children ?? [])].length > 1;\n\n if (onAction == null && !hasLink && state.selectionManager.selectionMode === 'none' && hasChildRows) {\n onAction = () => state.toggleKey(node.key);\n }\n\n let isExpanded = hasChildRows ? state.expandedKeys.has(node.key) : undefined;\n let setSize = 1;\n if (node.level > 0 && node?.parentKey != null) {\n let parent = state.collection.getItem(node.parentKey);\n if (parent) {\n // siblings must exist because our original node exists, same with lastItem\n let siblings = state.collection.getChildren?.(parent.key)!;\n setSize = getLastItem(siblings)!.index + 1;\n }\n } else {\n setSize = ([...state.collection].filter(row => row.level === 0).at(-1)?.index ?? 0) + 1;\n }\n treeGridRowProps = {\n 'aria-expanded': isExpanded,\n 'aria-level': node.level + 1,\n 'aria-posinset': node?.index + 1,\n 'aria-setsize': setSize\n };\n }\n\n let {itemProps, ...itemStates} = useSelectableItem({\n selectionManager: state.selectionManager,\n key: node.key,\n ref,\n isVirtualized,\n shouldSelectOnPressUp: props.shouldSelectOnPressUp || shouldSelectOnPressUp,\n onAction: onAction || node.props?.onAction ? chain(node.props?.onAction, onAction ? () => onAction(node.key) : undefined) : undefined,\n focus,\n linkBehavior\n });\n\n let onKeyDownCapture = (e: ReactKeyboardEvent) => {\n if (!e.currentTarget.contains(e.target as Element) || !ref.current || !document.activeElement) {\n return;\n }\n\n let walker = getFocusableTreeWalker(ref.current);\n walker.currentNode = document.activeElement;\n\n if ('expandedKeys' in state && document.activeElement === ref.current) {\n if ((e.key === EXPANSION_KEYS['expand'][direction]) && state.selectionManager.focusedKey === node.key && hasChildRows && !state.expandedKeys.has(node.key)) {\n state.toggleKey(node.key);\n e.stopPropagation();\n return;\n } else if ((e.key === EXPANSION_KEYS['collapse'][direction]) && state.selectionManager.focusedKey === node.key && hasChildRows && state.expandedKeys.has(node.key)) {\n state.toggleKey(node.key);\n e.stopPropagation();\n return;\n }\n }\n\n switch (e.key) {\n case 'ArrowLeft': {\n if (keyboardNavigationBehavior === 'arrow') {\n // Find the next focusable element within the row.\n let focusable = direction === 'rtl'\n ? walker.nextNode() as FocusableElement\n : walker.previousNode() as FocusableElement;\n\n if (focusable) {\n e.preventDefault();\n e.stopPropagation();\n focusSafely(focusable);\n scrollIntoViewport(focusable, {containingElement: getScrollParent(ref.current)});\n } else {\n // If there is no next focusable child, then return focus back to the row\n e.preventDefault();\n e.stopPropagation();\n if (direction === 'rtl') {\n focusSafely(ref.current);\n scrollIntoViewport(ref.current, {containingElement: getScrollParent(ref.current)});\n } else {\n walker.currentNode = ref.current;\n let lastElement = last(walker);\n if (lastElement) {\n focusSafely(lastElement);\n scrollIntoViewport(lastElement, {containingElement: getScrollParent(ref.current)});\n }\n }\n }\n }\n break;\n }\n case 'ArrowRight': {\n if (keyboardNavigationBehavior === 'arrow') {\n let focusable = direction === 'rtl'\n ? walker.previousNode() as FocusableElement\n : walker.nextNode() as FocusableElement;\n\n if (focusable) {\n e.preventDefault();\n e.stopPropagation();\n focusSafely(focusable);\n scrollIntoViewport(focusable, {containingElement: getScrollParent(ref.current)});\n } else {\n e.preventDefault();\n e.stopPropagation();\n if (direction === 'ltr') {\n focusSafely(ref.current);\n scrollIntoViewport(ref.current, {containingElement: getScrollParent(ref.current)});\n } else {\n walker.currentNode = ref.current;\n let lastElement = last(walker);\n if (lastElement) {\n focusSafely(lastElement);\n scrollIntoViewport(lastElement, {containingElement: getScrollParent(ref.current)});\n }\n }\n }\n }\n break;\n }\n case 'ArrowUp':\n case 'ArrowDown':\n // Prevent this event from reaching row children, e.g. menu buttons. We want arrow keys to navigate\n // to the row above/below instead. We need to re-dispatch the event from a higher parent so it still\n // bubbles and gets handled by useSelectableCollection.\n if (!e.altKey && ref.current.contains(e.target as Element)) {\n e.stopPropagation();\n e.preventDefault();\n ref.current.parentElement?.dispatchEvent(\n new KeyboardEvent(e.nativeEvent.type, e.nativeEvent)\n );\n }\n break;\n }\n };\n\n let onFocus = (e) => {\n keyWhenFocused.current = node.key;\n if (e.target !== ref.current) {\n // useSelectableItem only handles setting the focused key when\n // the focused element is the row itself. We also want to\n // set the focused key when a child element receives focus.\n // If focus is currently visible (e.g. the user is navigating with the keyboard),\n // then skip this. We want to restore focus to the previously focused row\n // in that case since the list should act like a single tab stop.\n if (!isFocusVisible()) {\n state.selectionManager.setFocusedKey(node.key);\n }\n return;\n }\n };\n\n let onKeyDown = (e) => {\n if (!e.currentTarget.contains(e.target as Element) || !ref.current || !document.activeElement) {\n return;\n }\n\n switch (e.key) {\n case 'Tab': {\n if (keyboardNavigationBehavior === 'tab') {\n // If there is another focusable element within this item, stop propagation so the tab key\n // is handled by the browser and not by useSelectableCollection (which would take us out of the list).\n let walker = getFocusableTreeWalker(ref.current, {tabbable: true});\n walker.currentNode = document.activeElement;\n let next = e.shiftKey ? walker.previousNode() : walker.nextNode();\n\n if (next) {\n e.stopPropagation();\n }\n }\n }\n }\n };\n\n let syntheticLinkProps = useSyntheticLinkProps(node.props);\n let linkProps = itemStates.hasAction ? syntheticLinkProps : {};\n // TODO: re-add when we get translations and fix this for iOS VO\n // let rowAnnouncement;\n // if (onAction) {\n // rowAnnouncement = stringFormatter.format('hasActionAnnouncement');\n // } else if (hasLink) {\n // rowAnnouncement = stringFormatter.format('hasLinkAnnouncement', {\n // link: node.props.href\n // });\n // }\n\n let rowProps: DOMAttributes = mergeProps(itemProps, linkProps, {\n role: 'row',\n onKeyDownCapture,\n onKeyDown,\n onFocus,\n // 'aria-label': [(node.textValue || undefined), rowAnnouncement].filter(Boolean).join(', '),\n 'aria-label': node.textValue || undefined,\n 'aria-selected': state.selectionManager.canSelectItem(node.key) ? state.selectionManager.isSelected(node.key) : undefined,\n 'aria-disabled': state.selectionManager.isDisabled(node.key) || undefined,\n 'aria-labelledby': descriptionId && node.textValue ? `${getRowId(state, node.key)} ${descriptionId}` : undefined,\n id: getRowId(state, node.key)\n });\n\n if (isVirtualized) {\n rowProps['aria-rowindex'] = node.index + 1;\n }\n\n let gridCellProps = {\n role: 'gridcell',\n 'aria-colindex': 1\n };\n\n // TODO: should isExpanded and hasChildRows be a item state that gets returned by the hook?\n return {\n rowProps: {...mergeProps(rowProps, treeGridRowProps)},\n gridCellProps,\n descriptionProps: {\n id: descriptionId\n },\n ...itemStates\n };\n}\n\nfunction last(walker: TreeWalker) {\n let next: FocusableElement | null = null;\n let last: FocusableElement | null = null;\n do {\n last = walker.lastChild() as FocusableElement | null;\n if (last) {\n next = last;\n }\n } while (last);\n return next;\n}\n"],"names":[],"version":3,"file":"useGridListItem.module.js.map"}
|
package/dist/utils.main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;;;;;;AAAA;;;;;;;;;;CAUC,
|
|
1
|
+
{"mappings":";;;;;;;AAAA;;;;;;;;;;CAUC,GAeM,MAAM,4CAAU,IAAI;AAEpB,SAAS,0CAAY,KAAmB,EAAE,GAAQ;QAC5C;IAAX,IAAI,MAAC,EAAE,EAAC,GAAG,CAAA,eAAA,0CAAQ,GAAG,CAAC,oBAAZ,0BAAA,eAAsB,CAAC;IAClC,IAAI,CAAC,IACH,MAAM,IAAI,MAAM;IAGlB,OAAO,GAAG,GAAG,CAAC,EAAE,0CAAa,MAAM;AACrC;AAEO,SAAS,0CAAa,GAAQ;IACnC,IAAI,OAAO,QAAQ,UACjB,OAAO,IAAI,OAAO,CAAC,QAAQ;IAG7B,OAAO,KAAK;AACd","sources":["packages/@react-aria/gridlist/src/utils.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {Key} from '@react-types/shared';\nimport type {ListState} from '@react-stately/list';\n\ninterface ListMapShared {\n id: string,\n onAction?: (key: Key) => void,\n linkBehavior?: 'action' | 'selection' | 'override',\n keyboardNavigationBehavior: 'arrow' | 'tab',\n shouldSelectOnPressUp?: boolean\n}\n\n// Used to share:\n// id of the list and onAction between useList, useListItem, and useListSelectionCheckbox\nexport const listMap = new WeakMap<ListState<unknown>, ListMapShared>();\n\nexport function getRowId<T>(state: ListState<T>, key: Key): string {\n let {id} = listMap.get(state) ?? {};\n if (!id) {\n throw new Error('Unknown list');\n }\n\n return `${id}-${normalizeKey(key)}`;\n}\n\nexport function normalizeKey(key: Key): string {\n if (typeof key === 'string') {\n return key.replace(/\\s*/g, '');\n }\n\n return '' + key;\n}\n"],"names":[],"version":3,"file":"utils.main.js.map"}
|
package/dist/utils.module.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"AAAA;;;;;;;;;;CAUC,
|
|
1
|
+
{"mappings":"AAAA;;;;;;;;;;CAUC,GAeM,MAAM,4CAAU,IAAI;AAEpB,SAAS,0CAAY,KAAmB,EAAE,GAAQ;QAC5C;IAAX,IAAI,MAAC,EAAE,EAAC,GAAG,CAAA,eAAA,0CAAQ,GAAG,CAAC,oBAAZ,0BAAA,eAAsB,CAAC;IAClC,IAAI,CAAC,IACH,MAAM,IAAI,MAAM;IAGlB,OAAO,GAAG,GAAG,CAAC,EAAE,0CAAa,MAAM;AACrC;AAEO,SAAS,0CAAa,GAAQ;IACnC,IAAI,OAAO,QAAQ,UACjB,OAAO,IAAI,OAAO,CAAC,QAAQ;IAG7B,OAAO,KAAK;AACd","sources":["packages/@react-aria/gridlist/src/utils.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {Key} from '@react-types/shared';\nimport type {ListState} from '@react-stately/list';\n\ninterface ListMapShared {\n id: string,\n onAction?: (key: Key) => void,\n linkBehavior?: 'action' | 'selection' | 'override',\n keyboardNavigationBehavior: 'arrow' | 'tab',\n shouldSelectOnPressUp?: boolean\n}\n\n// Used to share:\n// id of the list and onAction between useList, useListItem, and useListSelectionCheckbox\nexport const listMap = new WeakMap<ListState<unknown>, ListMapShared>();\n\nexport function getRowId<T>(state: ListState<T>, key: Key): string {\n let {id} = listMap.get(state) ?? {};\n if (!id) {\n throw new Error('Unknown list');\n }\n\n return `${id}-${normalizeKey(key)}`;\n}\n\nexport function normalizeKey(key: Key): string {\n if (typeof key === 'string') {\n return key.replace(/\\s*/g, '');\n }\n\n return '' + key;\n}\n"],"names":[],"version":3,"file":"utils.module.js.map"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-aria/gridlist",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.13.0",
|
|
4
4
|
"description": "Spectrum UI components in React",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -22,16 +22,16 @@
|
|
|
22
22
|
"url": "https://github.com/adobe/react-spectrum"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@react-aria/focus": "^3.20.
|
|
26
|
-
"@react-aria/grid": "^3.
|
|
27
|
-
"@react-aria/i18n": "^3.12.
|
|
28
|
-
"@react-aria/interactions": "^3.25.
|
|
29
|
-
"@react-aria/selection": "^3.24.
|
|
30
|
-
"@react-aria/utils": "^3.
|
|
31
|
-
"@react-stately/collections": "^3.12.
|
|
32
|
-
"@react-stately/list": "^3.12.
|
|
33
|
-
"@react-stately/tree": "^3.8.
|
|
34
|
-
"@react-types/shared": "^3.29.
|
|
25
|
+
"@react-aria/focus": "^3.20.3",
|
|
26
|
+
"@react-aria/grid": "^3.14.0",
|
|
27
|
+
"@react-aria/i18n": "^3.12.9",
|
|
28
|
+
"@react-aria/interactions": "^3.25.1",
|
|
29
|
+
"@react-aria/selection": "^3.24.1",
|
|
30
|
+
"@react-aria/utils": "^3.29.0",
|
|
31
|
+
"@react-stately/collections": "^3.12.4",
|
|
32
|
+
"@react-stately/list": "^3.12.2",
|
|
33
|
+
"@react-stately/tree": "^3.8.10",
|
|
34
|
+
"@react-types/shared": "^3.29.1",
|
|
35
35
|
"@swc/helpers": "^0.5.0"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
@@ -41,5 +41,5 @@
|
|
|
41
41
|
"publishConfig": {
|
|
42
42
|
"access": "public"
|
|
43
43
|
},
|
|
44
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "9c77d4e8267ed39469c65f65da94ece7be509874"
|
|
45
45
|
}
|
package/src/useGridList.ts
CHANGED
|
@@ -39,7 +39,9 @@ export interface GridListProps<T> extends CollectionBase<T>, MultipleSelection {
|
|
|
39
39
|
*/
|
|
40
40
|
onAction?: (key: Key) => void,
|
|
41
41
|
/** Whether `disabledKeys` applies to all interactions, or only selection. */
|
|
42
|
-
disabledBehavior?: DisabledBehavior
|
|
42
|
+
disabledBehavior?: DisabledBehavior,
|
|
43
|
+
/** Whether selection should occur on press up instead of press down. */
|
|
44
|
+
shouldSelectOnPressUp?: boolean
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
export interface AriaGridListProps<T> extends GridListProps<T>, DOMProps, AriaLabelingProps {
|
|
@@ -115,7 +117,8 @@ export function useGridList<T>(props: AriaGridListOptions<T>, state: ListState<T
|
|
|
115
117
|
disallowTypeAhead,
|
|
116
118
|
linkBehavior = 'action',
|
|
117
119
|
keyboardNavigationBehavior = 'arrow',
|
|
118
|
-
escapeKeyBehavior = 'clearSelection'
|
|
120
|
+
escapeKeyBehavior = 'clearSelection',
|
|
121
|
+
shouldSelectOnPressUp
|
|
119
122
|
} = props;
|
|
120
123
|
|
|
121
124
|
if (!props['aria-label'] && !props['aria-labelledby']) {
|
|
@@ -139,7 +142,7 @@ export function useGridList<T>(props: AriaGridListOptions<T>, state: ListState<T
|
|
|
139
142
|
});
|
|
140
143
|
|
|
141
144
|
let id = useId(props.id);
|
|
142
|
-
listMap.set(state, {id, onAction, linkBehavior, keyboardNavigationBehavior});
|
|
145
|
+
listMap.set(state, {id, onAction, linkBehavior, keyboardNavigationBehavior, shouldSelectOnPressUp});
|
|
143
146
|
|
|
144
147
|
let descriptionProps = useHighlightSelectionDescription({
|
|
145
148
|
selectionManager: state.selectionManager,
|
package/src/useGridListItem.ts
CHANGED
|
@@ -63,13 +63,12 @@ export function useGridListItem<T>(props: AriaGridListItemOptions, state: ListSt
|
|
|
63
63
|
// Copied from useGridCell + some modifications to make it not so grid specific
|
|
64
64
|
let {
|
|
65
65
|
node,
|
|
66
|
-
isVirtualized
|
|
67
|
-
shouldSelectOnPressUp
|
|
66
|
+
isVirtualized
|
|
68
67
|
} = props;
|
|
69
68
|
|
|
70
69
|
// let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/gridlist');
|
|
71
70
|
let {direction} = useLocale();
|
|
72
|
-
let {onAction, linkBehavior, keyboardNavigationBehavior} = listMap.get(state)!;
|
|
71
|
+
let {onAction, linkBehavior, keyboardNavigationBehavior, shouldSelectOnPressUp} = listMap.get(state)!;
|
|
73
72
|
let descriptionId = useSlotId();
|
|
74
73
|
|
|
75
74
|
// We need to track the key of the item at the time it was last focused so that we force
|
|
@@ -125,13 +124,13 @@ export function useGridListItem<T>(props: AriaGridListItemOptions, state: ListSt
|
|
|
125
124
|
key: node.key,
|
|
126
125
|
ref,
|
|
127
126
|
isVirtualized,
|
|
128
|
-
shouldSelectOnPressUp,
|
|
127
|
+
shouldSelectOnPressUp: props.shouldSelectOnPressUp || shouldSelectOnPressUp,
|
|
129
128
|
onAction: onAction || node.props?.onAction ? chain(node.props?.onAction, onAction ? () => onAction(node.key) : undefined) : undefined,
|
|
130
129
|
focus,
|
|
131
130
|
linkBehavior
|
|
132
131
|
});
|
|
133
132
|
|
|
134
|
-
let
|
|
133
|
+
let onKeyDownCapture = (e: ReactKeyboardEvent) => {
|
|
135
134
|
if (!e.currentTarget.contains(e.target as Element) || !ref.current || !document.activeElement) {
|
|
136
135
|
return;
|
|
137
136
|
}
|
|
@@ -225,18 +224,6 @@ export function useGridListItem<T>(props: AriaGridListItemOptions, state: ListSt
|
|
|
225
224
|
);
|
|
226
225
|
}
|
|
227
226
|
break;
|
|
228
|
-
case 'Tab': {
|
|
229
|
-
if (keyboardNavigationBehavior === 'tab') {
|
|
230
|
-
// If there is another focusable element within this item, stop propagation so the tab key
|
|
231
|
-
// is handled by the browser and not by useSelectableCollection (which would take us out of the list).
|
|
232
|
-
let walker = getFocusableTreeWalker(ref.current, {tabbable: true});
|
|
233
|
-
walker.currentNode = document.activeElement;
|
|
234
|
-
let next = e.shiftKey ? walker.previousNode() : walker.nextNode();
|
|
235
|
-
if (next) {
|
|
236
|
-
e.stopPropagation();
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
227
|
}
|
|
241
228
|
};
|
|
242
229
|
|
|
@@ -256,6 +243,28 @@ export function useGridListItem<T>(props: AriaGridListItemOptions, state: ListSt
|
|
|
256
243
|
}
|
|
257
244
|
};
|
|
258
245
|
|
|
246
|
+
let onKeyDown = (e) => {
|
|
247
|
+
if (!e.currentTarget.contains(e.target as Element) || !ref.current || !document.activeElement) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
switch (e.key) {
|
|
252
|
+
case 'Tab': {
|
|
253
|
+
if (keyboardNavigationBehavior === 'tab') {
|
|
254
|
+
// If there is another focusable element within this item, stop propagation so the tab key
|
|
255
|
+
// is handled by the browser and not by useSelectableCollection (which would take us out of the list).
|
|
256
|
+
let walker = getFocusableTreeWalker(ref.current, {tabbable: true});
|
|
257
|
+
walker.currentNode = document.activeElement;
|
|
258
|
+
let next = e.shiftKey ? walker.previousNode() : walker.nextNode();
|
|
259
|
+
|
|
260
|
+
if (next) {
|
|
261
|
+
e.stopPropagation();
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
|
|
259
268
|
let syntheticLinkProps = useSyntheticLinkProps(node.props);
|
|
260
269
|
let linkProps = itemStates.hasAction ? syntheticLinkProps : {};
|
|
261
270
|
// TODO: re-add when we get translations and fix this for iOS VO
|
|
@@ -270,7 +279,8 @@ export function useGridListItem<T>(props: AriaGridListItemOptions, state: ListSt
|
|
|
270
279
|
|
|
271
280
|
let rowProps: DOMAttributes = mergeProps(itemProps, linkProps, {
|
|
272
281
|
role: 'row',
|
|
273
|
-
onKeyDownCapture
|
|
282
|
+
onKeyDownCapture,
|
|
283
|
+
onKeyDown,
|
|
274
284
|
onFocus,
|
|
275
285
|
// 'aria-label': [(node.textValue || undefined), rowAnnouncement].filter(Boolean).join(', '),
|
|
276
286
|
'aria-label': node.textValue || undefined,
|
package/src/utils.ts
CHANGED
|
@@ -17,7 +17,8 @@ interface ListMapShared {
|
|
|
17
17
|
id: string,
|
|
18
18
|
onAction?: (key: Key) => void,
|
|
19
19
|
linkBehavior?: 'action' | 'selection' | 'override',
|
|
20
|
-
keyboardNavigationBehavior: 'arrow' | 'tab'
|
|
20
|
+
keyboardNavigationBehavior: 'arrow' | 'tab',
|
|
21
|
+
shouldSelectOnPressUp?: boolean
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
// Used to share:
|