@react-aria/selection 3.27.0 → 3.27.1
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.map +1 -1
- package/dist/useSelectableCollection.main.js +9 -10
- package/dist/useSelectableCollection.main.js.map +1 -1
- package/dist/useSelectableCollection.mjs +10 -11
- package/dist/useSelectableCollection.module.js +10 -11
- package/dist/useSelectableCollection.module.js.map +1 -1
- package/dist/useSelectableItem.main.js +15 -10
- package/dist/useSelectableItem.main.js.map +1 -1
- package/dist/useSelectableItem.mjs +15 -10
- package/dist/useSelectableItem.module.js +15 -10
- package/dist/useSelectableItem.module.js.map +1 -1
- package/dist/useTypeSelect.main.js +3 -1
- package/dist/useTypeSelect.main.js.map +1 -1
- package/dist/useTypeSelect.mjs +3 -1
- package/dist/useTypeSelect.module.js +3 -1
- package/dist/useTypeSelect.module.js.map +1 -1
- package/package.json +8 -8
- package/src/useSelectableCollection.ts +9 -10
- package/src/useSelectableItem.ts +14 -10
- package/src/useTypeSelect.ts +2 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
var $3XJlT$react = require("react");
|
|
2
|
+
var $3XJlT$reactariautils = require("@react-aria/utils");
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
function $parcel$export(e, n, v, s) {
|
|
@@ -17,6 +18,7 @@ $parcel$export(module.exports, "useTypeSelect", () => $a1189052f36475e8$export$e
|
|
|
17
18
|
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
18
19
|
* governing permissions and limitations under the License.
|
|
19
20
|
*/
|
|
21
|
+
|
|
20
22
|
/**
|
|
21
23
|
* Controls how long to wait before clearing the typeahead buffer.
|
|
22
24
|
*/ const $a1189052f36475e8$var$TYPEAHEAD_DEBOUNCE_WAIT_MS = 1000; // 1 second
|
|
@@ -28,7 +30,7 @@ function $a1189052f36475e8$export$e32c88dfddc6e1d8(options) {
|
|
|
28
30
|
}).current;
|
|
29
31
|
let onKeyDown = (e)=>{
|
|
30
32
|
let character = $a1189052f36475e8$var$getStringForKey(e.key);
|
|
31
|
-
if (!character || e.ctrlKey || e.metaKey || !e.currentTarget
|
|
33
|
+
if (!character || e.ctrlKey || e.metaKey || !(0, $3XJlT$reactariautils.nodeContains)(e.currentTarget, e.target) || state.search.length === 0 && character === ' ') return;
|
|
32
34
|
// Do not propagate the Spacebar event if it's meant to be part of the search.
|
|
33
35
|
// When we time out, the search term becomes empty, hence the check on length.
|
|
34
36
|
// Trimming is to account for the case of pressing the Spacebar more than once,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"
|
|
1
|
+
{"mappings":";;;;;;;;;AAAA;;;;;;;;;;CAUC;;AAOD;;CAEC,GACD,MAAM,mDAA6B,MAAM,WAAW;AA2B7C,SAAS,0CAAc,OAA8B;IAC1D,IAAI,oBAAC,gBAAgB,oBAAE,gBAAgB,gBAAE,YAAY,EAAC,GAAG;IACzD,IAAI,QAAQ,CAAA,GAAA,mBAAK,EAAwE;QACvF,QAAQ;QACR,SAAS;IACX,GAAG,OAAO;IAEV,IAAI,YAAY,CAAC;QACf,IAAI,YAAY,sCAAgB,EAAE,GAAG;QACrC,IAAI,CAAC,aAAa,EAAE,OAAO,IAAI,EAAE,OAAO,IAAI,CAAC,CAAA,GAAA,kCAAW,EAAE,EAAE,aAAa,EAAE,EAAE,MAAM,KAAqB,MAAM,MAAM,CAAC,MAAM,KAAK,KAAK,cAAc,KACjJ;QAGF,8EAA8E;QAC9E,8EAA8E;QAC9E,+EAA+E;QAC/E,4EAA4E;QAC5E,IAAI,cAAc,OAAO,MAAM,MAAM,CAAC,IAAI,GAAG,MAAM,GAAG,GAAG;YACvD,EAAE,cAAc;YAChB,IAAI,CAAE,CAAA,yBAAyB,CAAA,GAC7B,EAAE,eAAe;QAErB;QAEA,MAAM,MAAM,IAAI;QAEhB,IAAI,iBAAiB,eAAe,IAAI,MAAM;YAC5C,2CAA2C;YAC3C,+FAA+F;YAC/F,IAAI,MAAM,iBAAiB,eAAe,CAAC,MAAM,MAAM,EAAE,iBAAiB,UAAU;YAEpF,wCAAwC;YACxC,IAAI,OAAO,MACT,MAAM,iBAAiB,eAAe,CAAC,MAAM,MAAM;YAGrD,IAAI,OAAO,MAAM;gBACf,iBAAiB,aAAa,CAAC;gBAC/B,IAAI,cACF,aAAa;YAEjB;QACF;QAEA,aAAa,MAAM,OAAO;QAC1B,MAAM,OAAO,GAAG,WAAW;YACzB,MAAM,MAAM,GAAG;QACjB,GAAG;IACL;IAEA,OAAO;QACL,iBAAiB;YACf,+DAA+D;YAC/D,qDAAqD;YACrD,kBAAkB,iBAAiB,eAAe,GAAG,YAAY;QACnE;IACF;AACF;AAEA,SAAS,sCAAgB,GAAW;IAClC,mDAAmD;IACnD,+DAA+D;IAC/D,6BAA6B;IAC7B,0CAA0C;IAC1C,IAAI,IAAI,MAAM,KAAK,KAAK,CAAC,UAAU,IAAI,CAAC,MACtC,OAAO;IAGT,OAAO;AACT","sources":["packages/@react-aria/selection/src/useTypeSelect.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 {DOMAttributes, Key, KeyboardDelegate} from '@react-types/shared';\nimport {KeyboardEvent, useRef} from 'react';\nimport {MultipleSelectionManager} from '@react-stately/selection';\nimport {nodeContains} from '@react-aria/utils';\n\n/**\n * Controls how long to wait before clearing the typeahead buffer.\n */\nconst TYPEAHEAD_DEBOUNCE_WAIT_MS = 1000; // 1 second\n\nexport interface AriaTypeSelectOptions {\n /**\n * A delegate that returns collection item keys with respect to visual layout.\n */\n keyboardDelegate: KeyboardDelegate,\n /**\n * An interface for reading and updating multiple selection state.\n */\n selectionManager: MultipleSelectionManager,\n /**\n * Called when an item is focused by typing.\n */\n onTypeSelect?: (key: Key) => void\n}\n\nexport interface TypeSelectAria {\n /**\n * Props to be spread on the owner of the options.\n */\n typeSelectProps: DOMAttributes\n}\n\n/**\n * Handles typeahead interactions with collections.\n */\nexport function useTypeSelect(options: AriaTypeSelectOptions): TypeSelectAria {\n let {keyboardDelegate, selectionManager, onTypeSelect} = options;\n let state = useRef<{search: string, timeout: ReturnType<typeof setTimeout> | undefined}>({\n search: '',\n timeout: undefined\n }).current;\n\n let onKeyDown = (e: KeyboardEvent) => {\n let character = getStringForKey(e.key);\n if (!character || e.ctrlKey || e.metaKey || !nodeContains(e.currentTarget, e.target as HTMLElement) || (state.search.length === 0 && character === ' ')) {\n return;\n }\n\n // Do not propagate the Spacebar event if it's meant to be part of the search.\n // When we time out, the search term becomes empty, hence the check on length.\n // Trimming is to account for the case of pressing the Spacebar more than once,\n // which should cycle through the selection/deselection of the focused item.\n if (character === ' ' && state.search.trim().length > 0) {\n e.preventDefault();\n if (!('continuePropagation' in e)) {\n e.stopPropagation();\n }\n }\n\n state.search += character;\n\n if (keyboardDelegate.getKeyForSearch != null) {\n // Use the delegate to find a key to focus.\n // Prioritize items after the currently focused item, falling back to searching the whole list.\n let key = keyboardDelegate.getKeyForSearch(state.search, selectionManager.focusedKey);\n\n // If no key found, search from the top.\n if (key == null) {\n key = keyboardDelegate.getKeyForSearch(state.search);\n }\n\n if (key != null) {\n selectionManager.setFocusedKey(key);\n if (onTypeSelect) {\n onTypeSelect(key);\n }\n }\n }\n\n clearTimeout(state.timeout);\n state.timeout = setTimeout(() => {\n state.search = '';\n }, TYPEAHEAD_DEBOUNCE_WAIT_MS);\n };\n\n return {\n typeSelectProps: {\n // Using a capturing listener to catch the keydown event before\n // other hooks in order to handle the Spacebar event.\n onKeyDownCapture: keyboardDelegate.getKeyForSearch ? onKeyDown : undefined\n }\n };\n}\n\nfunction getStringForKey(key: string) {\n // If the key is of length 1, it is an ASCII value.\n // Otherwise, if there are no ASCII characters in the key name,\n // it is a Unicode character.\n // See https://www.w3.org/TR/uievents-key/\n if (key.length === 1 || !/^[A-Z]/i.test(key)) {\n return key;\n }\n\n return '';\n}\n"],"names":[],"version":3,"file":"useTypeSelect.main.js.map"}
|
package/dist/useTypeSelect.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {useRef as $dAE4Y$useRef} from "react";
|
|
2
|
+
import {nodeContains as $dAE4Y$nodeContains} from "@react-aria/utils";
|
|
2
3
|
|
|
3
4
|
/*
|
|
4
5
|
* Copyright 2020 Adobe. All rights reserved.
|
|
@@ -11,6 +12,7 @@ import {useRef as $dAE4Y$useRef} from "react";
|
|
|
11
12
|
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
12
13
|
* governing permissions and limitations under the License.
|
|
13
14
|
*/
|
|
15
|
+
|
|
14
16
|
/**
|
|
15
17
|
* Controls how long to wait before clearing the typeahead buffer.
|
|
16
18
|
*/ const $fb3050f43d946246$var$TYPEAHEAD_DEBOUNCE_WAIT_MS = 1000; // 1 second
|
|
@@ -22,7 +24,7 @@ function $fb3050f43d946246$export$e32c88dfddc6e1d8(options) {
|
|
|
22
24
|
}).current;
|
|
23
25
|
let onKeyDown = (e)=>{
|
|
24
26
|
let character = $fb3050f43d946246$var$getStringForKey(e.key);
|
|
25
|
-
if (!character || e.ctrlKey || e.metaKey || !e.currentTarget
|
|
27
|
+
if (!character || e.ctrlKey || e.metaKey || !(0, $dAE4Y$nodeContains)(e.currentTarget, e.target) || state.search.length === 0 && character === ' ') return;
|
|
26
28
|
// Do not propagate the Spacebar event if it's meant to be part of the search.
|
|
27
29
|
// When we time out, the search term becomes empty, hence the check on length.
|
|
28
30
|
// Trimming is to account for the case of pressing the Spacebar more than once,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {useRef as $dAE4Y$useRef} from "react";
|
|
2
|
+
import {nodeContains as $dAE4Y$nodeContains} from "@react-aria/utils";
|
|
2
3
|
|
|
3
4
|
/*
|
|
4
5
|
* Copyright 2020 Adobe. All rights reserved.
|
|
@@ -11,6 +12,7 @@ import {useRef as $dAE4Y$useRef} from "react";
|
|
|
11
12
|
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
12
13
|
* governing permissions and limitations under the License.
|
|
13
14
|
*/
|
|
15
|
+
|
|
14
16
|
/**
|
|
15
17
|
* Controls how long to wait before clearing the typeahead buffer.
|
|
16
18
|
*/ const $fb3050f43d946246$var$TYPEAHEAD_DEBOUNCE_WAIT_MS = 1000; // 1 second
|
|
@@ -22,7 +24,7 @@ function $fb3050f43d946246$export$e32c88dfddc6e1d8(options) {
|
|
|
22
24
|
}).current;
|
|
23
25
|
let onKeyDown = (e)=>{
|
|
24
26
|
let character = $fb3050f43d946246$var$getStringForKey(e.key);
|
|
25
|
-
if (!character || e.ctrlKey || e.metaKey || !e.currentTarget
|
|
27
|
+
if (!character || e.ctrlKey || e.metaKey || !(0, $dAE4Y$nodeContains)(e.currentTarget, e.target) || state.search.length === 0 && character === ' ') return;
|
|
26
28
|
// Do not propagate the Spacebar event if it's meant to be part of the search.
|
|
27
29
|
// When we time out, the search term becomes empty, hence the check on length.
|
|
28
30
|
// Trimming is to account for the case of pressing the Spacebar more than once,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"
|
|
1
|
+
{"mappings":";;;AAAA;;;;;;;;;;CAUC;;AAOD;;CAEC,GACD,MAAM,mDAA6B,MAAM,WAAW;AA2B7C,SAAS,0CAAc,OAA8B;IAC1D,IAAI,oBAAC,gBAAgB,oBAAE,gBAAgB,gBAAE,YAAY,EAAC,GAAG;IACzD,IAAI,QAAQ,CAAA,GAAA,aAAK,EAAwE;QACvF,QAAQ;QACR,SAAS;IACX,GAAG,OAAO;IAEV,IAAI,YAAY,CAAC;QACf,IAAI,YAAY,sCAAgB,EAAE,GAAG;QACrC,IAAI,CAAC,aAAa,EAAE,OAAO,IAAI,EAAE,OAAO,IAAI,CAAC,CAAA,GAAA,mBAAW,EAAE,EAAE,aAAa,EAAE,EAAE,MAAM,KAAqB,MAAM,MAAM,CAAC,MAAM,KAAK,KAAK,cAAc,KACjJ;QAGF,8EAA8E;QAC9E,8EAA8E;QAC9E,+EAA+E;QAC/E,4EAA4E;QAC5E,IAAI,cAAc,OAAO,MAAM,MAAM,CAAC,IAAI,GAAG,MAAM,GAAG,GAAG;YACvD,EAAE,cAAc;YAChB,IAAI,CAAE,CAAA,yBAAyB,CAAA,GAC7B,EAAE,eAAe;QAErB;QAEA,MAAM,MAAM,IAAI;QAEhB,IAAI,iBAAiB,eAAe,IAAI,MAAM;YAC5C,2CAA2C;YAC3C,+FAA+F;YAC/F,IAAI,MAAM,iBAAiB,eAAe,CAAC,MAAM,MAAM,EAAE,iBAAiB,UAAU;YAEpF,wCAAwC;YACxC,IAAI,OAAO,MACT,MAAM,iBAAiB,eAAe,CAAC,MAAM,MAAM;YAGrD,IAAI,OAAO,MAAM;gBACf,iBAAiB,aAAa,CAAC;gBAC/B,IAAI,cACF,aAAa;YAEjB;QACF;QAEA,aAAa,MAAM,OAAO;QAC1B,MAAM,OAAO,GAAG,WAAW;YACzB,MAAM,MAAM,GAAG;QACjB,GAAG;IACL;IAEA,OAAO;QACL,iBAAiB;YACf,+DAA+D;YAC/D,qDAAqD;YACrD,kBAAkB,iBAAiB,eAAe,GAAG,YAAY;QACnE;IACF;AACF;AAEA,SAAS,sCAAgB,GAAW;IAClC,mDAAmD;IACnD,+DAA+D;IAC/D,6BAA6B;IAC7B,0CAA0C;IAC1C,IAAI,IAAI,MAAM,KAAK,KAAK,CAAC,UAAU,IAAI,CAAC,MACtC,OAAO;IAGT,OAAO;AACT","sources":["packages/@react-aria/selection/src/useTypeSelect.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 {DOMAttributes, Key, KeyboardDelegate} from '@react-types/shared';\nimport {KeyboardEvent, useRef} from 'react';\nimport {MultipleSelectionManager} from '@react-stately/selection';\nimport {nodeContains} from '@react-aria/utils';\n\n/**\n * Controls how long to wait before clearing the typeahead buffer.\n */\nconst TYPEAHEAD_DEBOUNCE_WAIT_MS = 1000; // 1 second\n\nexport interface AriaTypeSelectOptions {\n /**\n * A delegate that returns collection item keys with respect to visual layout.\n */\n keyboardDelegate: KeyboardDelegate,\n /**\n * An interface for reading and updating multiple selection state.\n */\n selectionManager: MultipleSelectionManager,\n /**\n * Called when an item is focused by typing.\n */\n onTypeSelect?: (key: Key) => void\n}\n\nexport interface TypeSelectAria {\n /**\n * Props to be spread on the owner of the options.\n */\n typeSelectProps: DOMAttributes\n}\n\n/**\n * Handles typeahead interactions with collections.\n */\nexport function useTypeSelect(options: AriaTypeSelectOptions): TypeSelectAria {\n let {keyboardDelegate, selectionManager, onTypeSelect} = options;\n let state = useRef<{search: string, timeout: ReturnType<typeof setTimeout> | undefined}>({\n search: '',\n timeout: undefined\n }).current;\n\n let onKeyDown = (e: KeyboardEvent) => {\n let character = getStringForKey(e.key);\n if (!character || e.ctrlKey || e.metaKey || !nodeContains(e.currentTarget, e.target as HTMLElement) || (state.search.length === 0 && character === ' ')) {\n return;\n }\n\n // Do not propagate the Spacebar event if it's meant to be part of the search.\n // When we time out, the search term becomes empty, hence the check on length.\n // Trimming is to account for the case of pressing the Spacebar more than once,\n // which should cycle through the selection/deselection of the focused item.\n if (character === ' ' && state.search.trim().length > 0) {\n e.preventDefault();\n if (!('continuePropagation' in e)) {\n e.stopPropagation();\n }\n }\n\n state.search += character;\n\n if (keyboardDelegate.getKeyForSearch != null) {\n // Use the delegate to find a key to focus.\n // Prioritize items after the currently focused item, falling back to searching the whole list.\n let key = keyboardDelegate.getKeyForSearch(state.search, selectionManager.focusedKey);\n\n // If no key found, search from the top.\n if (key == null) {\n key = keyboardDelegate.getKeyForSearch(state.search);\n }\n\n if (key != null) {\n selectionManager.setFocusedKey(key);\n if (onTypeSelect) {\n onTypeSelect(key);\n }\n }\n }\n\n clearTimeout(state.timeout);\n state.timeout = setTimeout(() => {\n state.search = '';\n }, TYPEAHEAD_DEBOUNCE_WAIT_MS);\n };\n\n return {\n typeSelectProps: {\n // Using a capturing listener to catch the keydown event before\n // other hooks in order to handle the Spacebar event.\n onKeyDownCapture: keyboardDelegate.getKeyForSearch ? onKeyDown : undefined\n }\n };\n}\n\nfunction getStringForKey(key: string) {\n // If the key is of length 1, it is an ASCII value.\n // Otherwise, if there are no ASCII characters in the key name,\n // it is a Unicode character.\n // See https://www.w3.org/TR/uievents-key/\n if (key.length === 1 || !/^[A-Z]/i.test(key)) {\n return key;\n }\n\n return '';\n}\n"],"names":[],"version":3,"file":"useTypeSelect.module.js.map"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-aria/selection",
|
|
3
|
-
"version": "3.27.
|
|
3
|
+
"version": "3.27.1",
|
|
4
4
|
"description": "Spectrum UI components in React",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -26,12 +26,12 @@
|
|
|
26
26
|
"url": "https://github.com/adobe/react-spectrum"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@react-aria/focus": "^3.21.
|
|
30
|
-
"@react-aria/i18n": "^3.12.
|
|
31
|
-
"@react-aria/interactions": "^3.
|
|
32
|
-
"@react-aria/utils": "^3.
|
|
33
|
-
"@react-stately/selection": "^3.20.
|
|
34
|
-
"@react-types/shared": "^3.
|
|
29
|
+
"@react-aria/focus": "^3.21.4",
|
|
30
|
+
"@react-aria/i18n": "^3.12.15",
|
|
31
|
+
"@react-aria/interactions": "^3.27.0",
|
|
32
|
+
"@react-aria/utils": "^3.33.0",
|
|
33
|
+
"@react-stately/selection": "^3.20.8",
|
|
34
|
+
"@react-types/shared": "^3.33.0",
|
|
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": "66e51757606b43a89ed02c574ca24517323a2ab9"
|
|
45
45
|
}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {CLEAR_FOCUS_EVENT, FOCUS_EVENT, focusWithoutScrolling, getActiveElement, isCtrlKeyPressed, isTabbable, mergeProps, scrollIntoView, scrollIntoViewport, useEvent, useRouter, useUpdateLayoutEffect} from '@react-aria/utils';
|
|
13
|
+
import {CLEAR_FOCUS_EVENT, FOCUS_EVENT, focusWithoutScrolling, getActiveElement, isCtrlKeyPressed, isTabbable, mergeProps, nodeContains, scrollIntoView, scrollIntoViewport, useEvent, useRouter, useUpdateLayoutEffect} from '@react-aria/utils';
|
|
14
14
|
import {dispatchVirtualFocus, getFocusableTreeWalker, moveVirtualFocus} from '@react-aria/focus';
|
|
15
15
|
import {DOMAttributes, FocusableElement, FocusStrategy, Key, KeyboardDelegate, RefObject} from '@react-types/shared';
|
|
16
16
|
import {flushSync} from 'react-dom';
|
|
@@ -118,7 +118,6 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
|
|
|
118
118
|
disallowTypeAhead = false,
|
|
119
119
|
shouldUseVirtualFocus,
|
|
120
120
|
allowsTabNavigation = false,
|
|
121
|
-
isVirtualized,
|
|
122
121
|
// If no scrollRef is provided, assume the collection ref is the scrollable region
|
|
123
122
|
scrollRef = ref,
|
|
124
123
|
linkBehavior = 'action'
|
|
@@ -134,7 +133,7 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
|
|
|
134
133
|
|
|
135
134
|
// Keyboard events bubble through portals. Don't handle keyboard events
|
|
136
135
|
// for elements outside the collection (e.g. menus).
|
|
137
|
-
if (!ref.current
|
|
136
|
+
if (!ref.current || !nodeContains(ref.current, e.target as Element)) {
|
|
138
137
|
return;
|
|
139
138
|
}
|
|
140
139
|
|
|
@@ -315,7 +314,7 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
|
|
|
315
314
|
// If the active element is NOT tabbable but is contained by an element that IS tabbable (aka the cell), the browser will actually move focus to
|
|
316
315
|
// the containing element. We need to special case this so that tab will move focus out of the grid instead of looping between
|
|
317
316
|
// focusing the containing cell and back to the non-tabbable child element
|
|
318
|
-
if (next && (!next
|
|
317
|
+
if (next && (!nodeContains(next, document.activeElement) || (document.activeElement && !isTabbable(document.activeElement)))) {
|
|
319
318
|
focusWithoutScrolling(next);
|
|
320
319
|
}
|
|
321
320
|
}
|
|
@@ -328,7 +327,7 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
|
|
|
328
327
|
// Store the scroll position so we can restore it later.
|
|
329
328
|
/// TODO: should this happen all the time??
|
|
330
329
|
let scrollPos = useRef({top: 0, left: 0});
|
|
331
|
-
useEvent(scrollRef, 'scroll',
|
|
330
|
+
useEvent(scrollRef, 'scroll', () => {
|
|
332
331
|
scrollPos.current = {
|
|
333
332
|
top: scrollRef.current?.scrollTop ?? 0,
|
|
334
333
|
left: scrollRef.current?.scrollLeft ?? 0
|
|
@@ -338,7 +337,7 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
|
|
|
338
337
|
let onFocus = (e: FocusEvent) => {
|
|
339
338
|
if (manager.isFocused) {
|
|
340
339
|
// If a focus event bubbled through a portal, reset focus state.
|
|
341
|
-
if (!e.currentTarget
|
|
340
|
+
if (!nodeContains(e.currentTarget, e.target)) {
|
|
342
341
|
manager.setFocused(false);
|
|
343
342
|
}
|
|
344
343
|
|
|
@@ -346,7 +345,7 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
|
|
|
346
345
|
}
|
|
347
346
|
|
|
348
347
|
// Focus events can bubble through portals. Ignore these events.
|
|
349
|
-
if (!e.currentTarget
|
|
348
|
+
if (!nodeContains(e.currentTarget, e.target)) {
|
|
350
349
|
return;
|
|
351
350
|
}
|
|
352
351
|
|
|
@@ -369,7 +368,7 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
|
|
|
369
368
|
} else {
|
|
370
369
|
navigateToKey(manager.firstSelectedKey ?? delegate.getFirstKey?.());
|
|
371
370
|
}
|
|
372
|
-
} else if (
|
|
371
|
+
} else if (scrollRef.current) {
|
|
373
372
|
// Restore the scroll position to what it was before.
|
|
374
373
|
scrollRef.current.scrollTop = scrollPos.current.top;
|
|
375
374
|
scrollRef.current.scrollLeft = scrollPos.current.left;
|
|
@@ -380,7 +379,7 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
|
|
|
380
379
|
let element = getItemElement(ref, manager.focusedKey);
|
|
381
380
|
if (element instanceof HTMLElement) {
|
|
382
381
|
// This prevents a flash of focus on the first/last element in the collection, or the collection itself.
|
|
383
|
-
if (!element
|
|
382
|
+
if (!nodeContains(element, document.activeElement) && !shouldUseVirtualFocus) {
|
|
384
383
|
focusWithoutScrolling(element);
|
|
385
384
|
}
|
|
386
385
|
|
|
@@ -394,7 +393,7 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
|
|
|
394
393
|
|
|
395
394
|
let onBlur = (e) => {
|
|
396
395
|
// Don't set blurred and then focused again if moving focus within the collection.
|
|
397
|
-
if (!e.currentTarget
|
|
396
|
+
if (!nodeContains(e.currentTarget, e.relatedTarget as HTMLElement)) {
|
|
398
397
|
manager.setFocused(false);
|
|
399
398
|
}
|
|
400
399
|
};
|
package/src/useSelectableItem.ts
CHANGED
|
@@ -200,6 +200,12 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
|
|
|
200
200
|
};
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
+
useEffect(() => {
|
|
204
|
+
if (isDisabled && manager.focusedKey === key) {
|
|
205
|
+
manager.setFocusedKey(null);
|
|
206
|
+
}
|
|
207
|
+
}, [manager, isDisabled, key]);
|
|
208
|
+
|
|
203
209
|
// With checkbox selection, onAction (i.e. navigation) becomes primary, and occurs on a single click of the row.
|
|
204
210
|
// Clicking the checkbox enters selection mode, after which clicking anywhere on any row toggles selection for that row.
|
|
205
211
|
// With highlight selection, onAction is secondary, and occurs on double click. Single click selects the row.
|
|
@@ -246,7 +252,7 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
|
|
|
246
252
|
itemPressProps.onPressStart = (e) => {
|
|
247
253
|
modality.current = e.pointerType;
|
|
248
254
|
longPressEnabledOnPressStart.current = longPressEnabled;
|
|
249
|
-
if (e.pointerType === 'keyboard' && (!hasAction || isSelectionKey())) {
|
|
255
|
+
if (e.pointerType === 'keyboard' && (!hasAction || isSelectionKey(e.key))) {
|
|
250
256
|
onSelect(e);
|
|
251
257
|
}
|
|
252
258
|
};
|
|
@@ -256,7 +262,7 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
|
|
|
256
262
|
if (!allowsDifferentPressOrigin) {
|
|
257
263
|
itemPressProps.onPress = (e) => {
|
|
258
264
|
if (hasPrimaryAction || (hasSecondaryAction && e.pointerType !== 'mouse')) {
|
|
259
|
-
if (e.pointerType === 'keyboard' && !isActionKey()) {
|
|
265
|
+
if (e.pointerType === 'keyboard' && !isActionKey(e.key)) {
|
|
260
266
|
return;
|
|
261
267
|
}
|
|
262
268
|
|
|
@@ -290,7 +296,7 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
|
|
|
290
296
|
if (
|
|
291
297
|
allowsSelection && (
|
|
292
298
|
(e.pointerType === 'mouse' && !hasPrimaryAction) ||
|
|
293
|
-
(e.pointerType === 'keyboard' && (!allowsActions || isSelectionKey()))
|
|
299
|
+
(e.pointerType === 'keyboard' && (!allowsActions || isSelectionKey(e.key)))
|
|
294
300
|
)
|
|
295
301
|
) {
|
|
296
302
|
onSelect(e);
|
|
@@ -305,7 +311,7 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
|
|
|
305
311
|
e.pointerType === 'touch' ||
|
|
306
312
|
e.pointerType === 'pen' ||
|
|
307
313
|
e.pointerType === 'virtual' ||
|
|
308
|
-
(e.pointerType === 'keyboard' && hasAction && isActionKey()) ||
|
|
314
|
+
(e.pointerType === 'keyboard' && hasAction && isActionKey(e.key)) ||
|
|
309
315
|
(e.pointerType === 'mouse' && hadPrimaryActionOnPressStart.current)
|
|
310
316
|
) {
|
|
311
317
|
if (hasAction) {
|
|
@@ -407,12 +413,10 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
|
|
|
407
413
|
};
|
|
408
414
|
}
|
|
409
415
|
|
|
410
|
-
function isActionKey() {
|
|
411
|
-
|
|
412
|
-
return event?.key === 'Enter';
|
|
416
|
+
function isActionKey(key: string | undefined) {
|
|
417
|
+
return key === 'Enter';
|
|
413
418
|
}
|
|
414
419
|
|
|
415
|
-
function isSelectionKey() {
|
|
416
|
-
|
|
417
|
-
return event?.key === ' ' || event?.code === 'Space';
|
|
420
|
+
function isSelectionKey(key: string | undefined) {
|
|
421
|
+
return key === ' ';
|
|
418
422
|
}
|
package/src/useTypeSelect.ts
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import {DOMAttributes, Key, KeyboardDelegate} from '@react-types/shared';
|
|
14
14
|
import {KeyboardEvent, useRef} from 'react';
|
|
15
15
|
import {MultipleSelectionManager} from '@react-stately/selection';
|
|
16
|
+
import {nodeContains} from '@react-aria/utils';
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* Controls how long to wait before clearing the typeahead buffer.
|
|
@@ -53,7 +54,7 @@ export function useTypeSelect(options: AriaTypeSelectOptions): TypeSelectAria {
|
|
|
53
54
|
|
|
54
55
|
let onKeyDown = (e: KeyboardEvent) => {
|
|
55
56
|
let character = getStringForKey(e.key);
|
|
56
|
-
if (!character || e.ctrlKey || e.metaKey || !e.currentTarget
|
|
57
|
+
if (!character || e.ctrlKey || e.metaKey || !nodeContains(e.currentTarget, e.target as HTMLElement) || (state.search.length === 0 && character === ' ')) {
|
|
57
58
|
return;
|
|
58
59
|
}
|
|
59
60
|
|