@react-stately/combobox 3.8.1-nightly.4321 → 3.8.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/import.mjs +22 -11
- package/dist/main.js +22 -11
- package/dist/main.js.map +1 -1
- package/dist/module.js +22 -11
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +10 -10
- package/src/useComboBoxState.ts +21 -11
package/dist/import.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import {getChildNodes as $k6Ppu$getChildNodes} from "@react-stately/collections"
|
|
|
3
3
|
import {useSingleSelectListState as $k6Ppu$useSingleSelectListState, ListCollection as $k6Ppu$ListCollection} from "@react-stately/list";
|
|
4
4
|
import {useState as $k6Ppu$useState, useMemo as $k6Ppu$useMemo, useRef as $k6Ppu$useRef, useCallback as $k6Ppu$useCallback, useEffect as $k6Ppu$useEffect} from "react";
|
|
5
5
|
import {useControlledState as $k6Ppu$useControlledState} from "@react-stately/utils";
|
|
6
|
-
import {
|
|
6
|
+
import {useOverlayTriggerState as $k6Ppu$useOverlayTriggerState} from "@react-stately/overlays";
|
|
7
7
|
|
|
8
8
|
/*
|
|
9
9
|
* Copyright 2020 Adobe. All rights reserved.
|
|
@@ -36,6 +36,7 @@ function $a9e7382a7d111cb5$export$b453a3bfd4a5fa9e(props) {
|
|
|
36
36
|
let { defaultFilter: defaultFilter, menuTrigger: menuTrigger = "input", allowsEmptyCollection: allowsEmptyCollection = false, allowsCustomValue: allowsCustomValue, shouldCloseOnBlur: shouldCloseOnBlur = true } = props;
|
|
37
37
|
let [showAllItems, setShowAllItems] = (0, $k6Ppu$useState)(false);
|
|
38
38
|
let [isFocused, setFocusedState] = (0, $k6Ppu$useState)(false);
|
|
39
|
+
let [focusStrategy, setFocusStrategy] = (0, $k6Ppu$useState)(null);
|
|
39
40
|
let onSelectionChange = (key)=>{
|
|
40
41
|
if (props.onSelectionChange) props.onSelectionChange(key);
|
|
41
42
|
// If key is the same, reset the inputValue and close the menu
|
|
@@ -70,13 +71,13 @@ function $a9e7382a7d111cb5$export$b453a3bfd4a5fa9e(props) {
|
|
|
70
71
|
selectionManager.setFocused(open);
|
|
71
72
|
if (!open) selectionManager.setFocusedKey(null);
|
|
72
73
|
};
|
|
73
|
-
let triggerState = (0, $k6Ppu$
|
|
74
|
+
let triggerState = (0, $k6Ppu$useOverlayTriggerState)({
|
|
74
75
|
...props,
|
|
75
76
|
onOpenChange: onOpenChange,
|
|
76
77
|
isOpen: undefined,
|
|
77
78
|
defaultOpen: undefined
|
|
78
79
|
});
|
|
79
|
-
let open = (focusStrategy, trigger)=>{
|
|
80
|
+
let open = (focusStrategy = null, trigger)=>{
|
|
80
81
|
let displayAllItems = trigger === "manual" || trigger === "focus" && menuTrigger === "focus";
|
|
81
82
|
// Prevent open operations from triggering if there is nothing to display
|
|
82
83
|
// Also prevent open operations from triggering if items are uncontrolled but defaultItems is empty, even if displayAllItems is true.
|
|
@@ -85,10 +86,11 @@ function $a9e7382a7d111cb5$export$b453a3bfd4a5fa9e(props) {
|
|
|
85
86
|
if (displayAllItems && !triggerState.isOpen && props.items === undefined) // Show all items if menu is manually opened. Only care about this if items are undefined
|
|
86
87
|
setShowAllItems(true);
|
|
87
88
|
menuOpenTrigger.current = trigger;
|
|
88
|
-
|
|
89
|
+
setFocusStrategy(focusStrategy);
|
|
90
|
+
triggerState.open();
|
|
89
91
|
}
|
|
90
92
|
};
|
|
91
|
-
let toggle = (focusStrategy, trigger)=>{
|
|
93
|
+
let toggle = (focusStrategy = null, trigger)=>{
|
|
92
94
|
let displayAllItems = trigger === "manual" || trigger === "focus" && menuTrigger === "focus";
|
|
93
95
|
// If the menu is closed and there is nothing to display, early return so toggle isn't called to prevent extraneous onOpenChange
|
|
94
96
|
if (!(allowsEmptyCollection || filteredCollection.size > 0 || displayAllItems && originalCollection.size > 0 || props.items) && !triggerState.isOpen) return;
|
|
@@ -98,23 +100,31 @@ function $a9e7382a7d111cb5$export$b453a3bfd4a5fa9e(props) {
|
|
|
98
100
|
if (!triggerState.isOpen) menuOpenTrigger.current = trigger;
|
|
99
101
|
toggleMenu(focusStrategy);
|
|
100
102
|
};
|
|
103
|
+
let updateLastCollection = (0, $k6Ppu$useCallback)(()=>{
|
|
104
|
+
setLastCollection(showAllItems ? originalCollection : filteredCollection);
|
|
105
|
+
}, [
|
|
106
|
+
showAllItems,
|
|
107
|
+
originalCollection,
|
|
108
|
+
filteredCollection
|
|
109
|
+
]);
|
|
101
110
|
// If menu is going to close, save the current collection so we can freeze the displayed collection when the
|
|
102
111
|
// user clicks outside the popover to close the menu. Prevents the menu contents from updating as the menu closes.
|
|
103
|
-
let toggleMenu = (0, $k6Ppu$useCallback)((focusStrategy)=>{
|
|
104
|
-
if (triggerState.isOpen)
|
|
105
|
-
|
|
112
|
+
let toggleMenu = (0, $k6Ppu$useCallback)((focusStrategy = null)=>{
|
|
113
|
+
if (triggerState.isOpen) updateLastCollection();
|
|
114
|
+
setFocusStrategy(focusStrategy);
|
|
115
|
+
triggerState.toggle();
|
|
106
116
|
}, [
|
|
107
117
|
triggerState,
|
|
108
|
-
|
|
118
|
+
updateLastCollection
|
|
109
119
|
]);
|
|
110
120
|
let closeMenu = (0, $k6Ppu$useCallback)(()=>{
|
|
111
121
|
if (triggerState.isOpen) {
|
|
112
|
-
|
|
122
|
+
updateLastCollection();
|
|
113
123
|
triggerState.close();
|
|
114
124
|
}
|
|
115
125
|
}, [
|
|
116
126
|
triggerState,
|
|
117
|
-
|
|
127
|
+
updateLastCollection
|
|
118
128
|
]);
|
|
119
129
|
let [lastValue, setLastValue] = (0, $k6Ppu$useState)(inputValue);
|
|
120
130
|
let resetInputValue = ()=>{
|
|
@@ -247,6 +257,7 @@ function $a9e7382a7d111cb5$export$b453a3bfd4a5fa9e(props) {
|
|
|
247
257
|
return {
|
|
248
258
|
...validation,
|
|
249
259
|
...triggerState,
|
|
260
|
+
focusStrategy: focusStrategy,
|
|
250
261
|
toggle: toggle,
|
|
251
262
|
open: open,
|
|
252
263
|
close: commitValue,
|
package/dist/main.js
CHANGED
|
@@ -3,7 +3,7 @@ var $5XAuq$reactstatelycollections = require("@react-stately/collections");
|
|
|
3
3
|
var $5XAuq$reactstatelylist = require("@react-stately/list");
|
|
4
4
|
var $5XAuq$react = require("react");
|
|
5
5
|
var $5XAuq$reactstatelyutils = require("@react-stately/utils");
|
|
6
|
-
var $5XAuq$
|
|
6
|
+
var $5XAuq$reactstatelyoverlays = require("@react-stately/overlays");
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
function $parcel$export(e, n, v, s) {
|
|
@@ -42,6 +42,7 @@ function $e563f9c9469ad14c$export$b453a3bfd4a5fa9e(props) {
|
|
|
42
42
|
let { defaultFilter: defaultFilter, menuTrigger: menuTrigger = "input", allowsEmptyCollection: allowsEmptyCollection = false, allowsCustomValue: allowsCustomValue, shouldCloseOnBlur: shouldCloseOnBlur = true } = props;
|
|
43
43
|
let [showAllItems, setShowAllItems] = (0, $5XAuq$react.useState)(false);
|
|
44
44
|
let [isFocused, setFocusedState] = (0, $5XAuq$react.useState)(false);
|
|
45
|
+
let [focusStrategy, setFocusStrategy] = (0, $5XAuq$react.useState)(null);
|
|
45
46
|
let onSelectionChange = (key)=>{
|
|
46
47
|
if (props.onSelectionChange) props.onSelectionChange(key);
|
|
47
48
|
// If key is the same, reset the inputValue and close the menu
|
|
@@ -76,13 +77,13 @@ function $e563f9c9469ad14c$export$b453a3bfd4a5fa9e(props) {
|
|
|
76
77
|
selectionManager.setFocused(open);
|
|
77
78
|
if (!open) selectionManager.setFocusedKey(null);
|
|
78
79
|
};
|
|
79
|
-
let triggerState = (0, $5XAuq$
|
|
80
|
+
let triggerState = (0, $5XAuq$reactstatelyoverlays.useOverlayTriggerState)({
|
|
80
81
|
...props,
|
|
81
82
|
onOpenChange: onOpenChange,
|
|
82
83
|
isOpen: undefined,
|
|
83
84
|
defaultOpen: undefined
|
|
84
85
|
});
|
|
85
|
-
let open = (focusStrategy, trigger)=>{
|
|
86
|
+
let open = (focusStrategy = null, trigger)=>{
|
|
86
87
|
let displayAllItems = trigger === "manual" || trigger === "focus" && menuTrigger === "focus";
|
|
87
88
|
// Prevent open operations from triggering if there is nothing to display
|
|
88
89
|
// Also prevent open operations from triggering if items are uncontrolled but defaultItems is empty, even if displayAllItems is true.
|
|
@@ -91,10 +92,11 @@ function $e563f9c9469ad14c$export$b453a3bfd4a5fa9e(props) {
|
|
|
91
92
|
if (displayAllItems && !triggerState.isOpen && props.items === undefined) // Show all items if menu is manually opened. Only care about this if items are undefined
|
|
92
93
|
setShowAllItems(true);
|
|
93
94
|
menuOpenTrigger.current = trigger;
|
|
94
|
-
|
|
95
|
+
setFocusStrategy(focusStrategy);
|
|
96
|
+
triggerState.open();
|
|
95
97
|
}
|
|
96
98
|
};
|
|
97
|
-
let toggle = (focusStrategy, trigger)=>{
|
|
99
|
+
let toggle = (focusStrategy = null, trigger)=>{
|
|
98
100
|
let displayAllItems = trigger === "manual" || trigger === "focus" && menuTrigger === "focus";
|
|
99
101
|
// If the menu is closed and there is nothing to display, early return so toggle isn't called to prevent extraneous onOpenChange
|
|
100
102
|
if (!(allowsEmptyCollection || filteredCollection.size > 0 || displayAllItems && originalCollection.size > 0 || props.items) && !triggerState.isOpen) return;
|
|
@@ -104,23 +106,31 @@ function $e563f9c9469ad14c$export$b453a3bfd4a5fa9e(props) {
|
|
|
104
106
|
if (!triggerState.isOpen) menuOpenTrigger.current = trigger;
|
|
105
107
|
toggleMenu(focusStrategy);
|
|
106
108
|
};
|
|
109
|
+
let updateLastCollection = (0, $5XAuq$react.useCallback)(()=>{
|
|
110
|
+
setLastCollection(showAllItems ? originalCollection : filteredCollection);
|
|
111
|
+
}, [
|
|
112
|
+
showAllItems,
|
|
113
|
+
originalCollection,
|
|
114
|
+
filteredCollection
|
|
115
|
+
]);
|
|
107
116
|
// If menu is going to close, save the current collection so we can freeze the displayed collection when the
|
|
108
117
|
// user clicks outside the popover to close the menu. Prevents the menu contents from updating as the menu closes.
|
|
109
|
-
let toggleMenu = (0, $5XAuq$react.useCallback)((focusStrategy)=>{
|
|
110
|
-
if (triggerState.isOpen)
|
|
111
|
-
|
|
118
|
+
let toggleMenu = (0, $5XAuq$react.useCallback)((focusStrategy = null)=>{
|
|
119
|
+
if (triggerState.isOpen) updateLastCollection();
|
|
120
|
+
setFocusStrategy(focusStrategy);
|
|
121
|
+
triggerState.toggle();
|
|
112
122
|
}, [
|
|
113
123
|
triggerState,
|
|
114
|
-
|
|
124
|
+
updateLastCollection
|
|
115
125
|
]);
|
|
116
126
|
let closeMenu = (0, $5XAuq$react.useCallback)(()=>{
|
|
117
127
|
if (triggerState.isOpen) {
|
|
118
|
-
|
|
128
|
+
updateLastCollection();
|
|
119
129
|
triggerState.close();
|
|
120
130
|
}
|
|
121
131
|
}, [
|
|
122
132
|
triggerState,
|
|
123
|
-
|
|
133
|
+
updateLastCollection
|
|
124
134
|
]);
|
|
125
135
|
let [lastValue, setLastValue] = (0, $5XAuq$react.useState)(inputValue);
|
|
126
136
|
let resetInputValue = ()=>{
|
|
@@ -253,6 +263,7 @@ function $e563f9c9469ad14c$export$b453a3bfd4a5fa9e(props) {
|
|
|
253
263
|
return {
|
|
254
264
|
...validation,
|
|
255
265
|
...triggerState,
|
|
266
|
+
focusStrategy: focusStrategy,
|
|
256
267
|
toggle: toggle,
|
|
257
268
|
open: open,
|
|
258
269
|
close: commitValue,
|
package/dist/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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","sources":["packages/@react-stately/combobox/src/index.ts","packages/@react-stately/combobox/src/useComboBoxState.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\nexport {useComboBoxState} from './useComboBoxState';\n\nexport type {ComboBoxStateOptions, ComboBoxState} from './useComboBoxState';\n","/*\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 {Collection, CollectionStateBase, FocusStrategy, Node} from '@react-types/shared';\nimport {ComboBoxProps, MenuTriggerAction} from '@react-types/combobox';\nimport {FormValidationState, useFormValidationState} from '@react-stately/form';\nimport {getChildNodes} from '@react-stately/collections';\nimport {ListCollection, useSingleSelectListState} from '@react-stately/list';\nimport {SelectState} from '@react-stately/select';\nimport {useCallback, useEffect, useMemo, useRef, useState} from 'react';\nimport {useControlledState} from '@react-stately/utils';\nimport {useMenuTriggerState} from '@react-stately/menu';\n\nexport interface ComboBoxState<T> extends SelectState<T>, FormValidationState{\n /** The current value of the combo box input. */\n inputValue: string,\n /** Sets the value of the combo box input. */\n setInputValue(value: string): void,\n /** Selects the currently focused item and updates the input value. */\n commit(): void,\n /** Opens the menu. */\n open(focusStrategy?: FocusStrategy | null, trigger?: MenuTriggerAction): void,\n /** Toggles the menu. */\n toggle(focusStrategy?: FocusStrategy | null, trigger?: MenuTriggerAction): void,\n /** Resets the input value to the previously selected item's text if any and closes the menu. */\n revert(): void\n}\n\ntype FilterFn = (textValue: string, inputValue: string) => boolean;\n\nexport interface ComboBoxStateOptions<T> extends Omit<ComboBoxProps<T>, 'children'>, CollectionStateBase<T> {\n /** The filter function used to determine if a option should be included in the combo box list. */\n defaultFilter?: FilterFn,\n /** Whether the combo box allows the menu to be open when the collection is empty. */\n allowsEmptyCollection?: boolean,\n /** Whether the combo box menu should close on blur. */\n shouldCloseOnBlur?: boolean\n}\n\n/**\n * Provides state management for a combo box component. Handles building a collection\n * of items from props and manages the option selection state of the combo box. In addition, it tracks the input value,\n * focus state, and other properties of the combo box.\n */\nexport function useComboBoxState<T extends object>(props: ComboBoxStateOptions<T>): ComboBoxState<T> {\n let {\n defaultFilter,\n menuTrigger = 'input',\n allowsEmptyCollection = false,\n allowsCustomValue,\n shouldCloseOnBlur = true\n } = props;\n\n let [showAllItems, setShowAllItems] = useState(false);\n let [isFocused, setFocusedState] = useState(false);\n\n let onSelectionChange = (key) => {\n if (props.onSelectionChange) {\n props.onSelectionChange(key);\n }\n\n // If key is the same, reset the inputValue and close the menu\n // (scenario: user clicks on already selected option)\n if (key === selectedKey) {\n resetInputValue();\n closeMenu();\n }\n };\n\n let {collection, selectionManager, selectedKey, setSelectedKey, selectedItem, disabledKeys} = useSingleSelectListState({\n ...props,\n onSelectionChange,\n items: props.items ?? props.defaultItems\n });\n\n let [inputValue, setInputValue] = useControlledState(\n props.inputValue,\n props.defaultInputValue ?? collection.getItem(selectedKey)?.textValue ?? '',\n props.onInputChange\n );\n\n // Preserve original collection so we can show all items on demand\n let originalCollection = collection;\n let filteredCollection = useMemo(() => (\n // No default filter if items are controlled.\n props.items != null || !defaultFilter\n ? collection\n : filterCollection(collection, inputValue, defaultFilter)\n ), [collection, inputValue, defaultFilter, props.items]);\n let [lastCollection, setLastCollection] = useState(filteredCollection);\n\n // Track what action is attempting to open the menu\n let menuOpenTrigger = useRef('focus' as MenuTriggerAction);\n let onOpenChange = (open: boolean) => {\n if (props.onOpenChange) {\n props.onOpenChange(open, open ? menuOpenTrigger.current : undefined);\n }\n\n selectionManager.setFocused(open);\n if (!open) {\n selectionManager.setFocusedKey(null);\n }\n };\n\n let triggerState = useMenuTriggerState({...props, onOpenChange, isOpen: undefined, defaultOpen: undefined});\n let open = (focusStrategy?: FocusStrategy, trigger?: MenuTriggerAction) => {\n let displayAllItems = (trigger === 'manual' || (trigger === 'focus' && menuTrigger === 'focus'));\n // Prevent open operations from triggering if there is nothing to display\n // Also prevent open operations from triggering if items are uncontrolled but defaultItems is empty, even if displayAllItems is true.\n // This is to prevent comboboxes with empty defaultItems from opening but allow controlled items comboboxes to open even if the inital list is empty (assumption is user will provide swap the empty list with a base list via onOpenChange returning `menuTrigger` manual)\n if (allowsEmptyCollection || filteredCollection.size > 0 || (displayAllItems && originalCollection.size > 0) || props.items) {\n if (displayAllItems && !triggerState.isOpen && props.items === undefined) {\n // Show all items if menu is manually opened. Only care about this if items are undefined\n setShowAllItems(true);\n }\n\n menuOpenTrigger.current = trigger;\n triggerState.open(focusStrategy);\n }\n };\n\n let toggle = (focusStrategy?: FocusStrategy, trigger?: MenuTriggerAction) => {\n let displayAllItems = (trigger === 'manual' || (trigger === 'focus' && menuTrigger === 'focus'));\n // If the menu is closed and there is nothing to display, early return so toggle isn't called to prevent extraneous onOpenChange\n if (!(allowsEmptyCollection || filteredCollection.size > 0 || (displayAllItems && originalCollection.size > 0) || props.items) && !triggerState.isOpen) {\n return;\n }\n\n if (displayAllItems && !triggerState.isOpen && props.items === undefined) {\n // Show all items if menu is toggled open. Only care about this if items are undefined\n setShowAllItems(true);\n }\n\n // Only update the menuOpenTrigger if menu is currently closed\n if (!triggerState.isOpen) {\n menuOpenTrigger.current = trigger;\n }\n\n toggleMenu(focusStrategy);\n };\n\n // If menu is going to close, save the current collection so we can freeze the displayed collection when the\n // user clicks outside the popover to close the menu. Prevents the menu contents from updating as the menu closes.\n let toggleMenu = useCallback((focusStrategy) => {\n if (triggerState.isOpen) {\n setLastCollection(filteredCollection);\n }\n\n triggerState.toggle(focusStrategy);\n }, [triggerState, filteredCollection]);\n\n let closeMenu = useCallback(() => {\n if (triggerState.isOpen) {\n setLastCollection(filteredCollection);\n triggerState.close();\n }\n }, [triggerState, filteredCollection]);\n\n let [lastValue, setLastValue] = useState(inputValue);\n let resetInputValue = () => {\n let itemText = collection.getItem(selectedKey)?.textValue ?? '';\n setLastValue(itemText);\n setInputValue(itemText);\n };\n\n let lastSelectedKey = useRef(props.selectedKey ?? props.defaultSelectedKey ?? null);\n let lastSelectedKeyText = useRef(collection.getItem(selectedKey)?.textValue ?? '');\n // intentional omit dependency array, want this to happen on every render\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(() => {\n // Open and close menu automatically when the input value changes if the input is focused,\n // and there are items in the collection or allowEmptyCollection is true.\n if (\n isFocused &&\n (filteredCollection.size > 0 || allowsEmptyCollection) &&\n !triggerState.isOpen &&\n inputValue !== lastValue &&\n menuTrigger !== 'manual'\n ) {\n open(null, 'input');\n }\n\n // Close the menu if the collection is empty. Don't close menu if filtered collection size is 0\n // but we are currently showing all items via button press\n if (\n !showAllItems &&\n !allowsEmptyCollection &&\n triggerState.isOpen &&\n filteredCollection.size === 0\n ) {\n closeMenu();\n }\n\n // Close when an item is selected.\n if (\n selectedKey != null &&\n selectedKey !== lastSelectedKey.current\n ) {\n closeMenu();\n }\n\n // Clear focused key when input value changes and display filtered collection again.\n if (inputValue !== lastValue) {\n selectionManager.setFocusedKey(null);\n setShowAllItems(false);\n\n // Set selectedKey to null when the user clears the input.\n // If controlled, this is the application developer's responsibility.\n if (inputValue === '' && (props.inputValue === undefined || props.selectedKey === undefined)) {\n setSelectedKey(null);\n }\n }\n\n // If the selectedKey changed, update the input value.\n // Do nothing if both inputValue and selectedKey are controlled.\n // In this case, it's the user's responsibility to update inputValue in onSelectionChange.\n if (\n selectedKey !== lastSelectedKey.current &&\n (props.inputValue === undefined || props.selectedKey === undefined)\n ) {\n resetInputValue();\n } else if (lastValue !== inputValue) {\n setLastValue(inputValue);\n }\n\n // Update the inputValue if the selected item's text changes from its last tracked value.\n // This is to handle cases where a selectedKey is specified but the items aren't available (async loading) or the selected item's text value updates.\n // Only reset if the user isn't currently within the field so we don't erroneously modify user input.\n // If inputValue is controlled, it is the user's responsibility to update the inputValue when items change.\n let selectedItemText = collection.getItem(selectedKey)?.textValue ?? '';\n if (!isFocused && selectedKey != null && props.inputValue === undefined && selectedKey === lastSelectedKey.current) {\n if (lastSelectedKeyText.current !== selectedItemText) {\n setLastValue(selectedItemText);\n setInputValue(selectedItemText);\n }\n }\n\n lastSelectedKey.current = selectedKey;\n lastSelectedKeyText.current = selectedItemText;\n });\n\n let validation = useFormValidationState({\n ...props,\n value: useMemo(() => ({inputValue, selectedKey}), [inputValue, selectedKey])\n });\n\n // Revert input value and close menu\n let revert = () => {\n if (allowsCustomValue && selectedKey == null) {\n commitCustomValue();\n } else {\n commitSelection();\n }\n };\n\n let commitCustomValue = () => {\n lastSelectedKey.current = null;\n setSelectedKey(null);\n closeMenu();\n };\n\n let commitSelection = () => {\n // If multiple things are controlled, call onSelectionChange\n if (props.selectedKey !== undefined && props.inputValue !== undefined) {\n props.onSelectionChange(selectedKey);\n\n // Stop menu from reopening from useEffect\n let itemText = collection.getItem(selectedKey)?.textValue ?? '';\n setLastValue(itemText);\n closeMenu();\n } else {\n // If only a single aspect of combobox is controlled, reset input value and close menu for the user\n resetInputValue();\n closeMenu();\n }\n };\n\n const commitValue = () => {\n if (allowsCustomValue) {\n const itemText = collection.getItem(selectedKey)?.textValue ?? '';\n (inputValue === itemText) ? commitSelection() : commitCustomValue();\n } else {\n // Reset inputValue and close menu\n commitSelection();\n }\n };\n\n let commit = () => {\n if (triggerState.isOpen && selectionManager.focusedKey != null) {\n // Reset inputValue and close menu here if the selected key is already the focused key. Otherwise\n // fire onSelectionChange to allow the application to control the closing.\n if (selectedKey === selectionManager.focusedKey) {\n commitSelection();\n } else {\n setSelectedKey(selectionManager.focusedKey);\n }\n } else {\n commitValue();\n }\n };\n\n let valueOnFocus = useRef(inputValue);\n let setFocused = (isFocused: boolean) => {\n if (isFocused) {\n valueOnFocus.current = inputValue;\n if (menuTrigger === 'focus') {\n open(null, 'focus');\n }\n } else {\n if (shouldCloseOnBlur) {\n commitValue();\n }\n\n if (inputValue !== valueOnFocus.current) {\n validation.commitValidation();\n }\n }\n\n setFocusedState(isFocused);\n };\n\n let displayedCollection = useMemo(() => {\n if (triggerState.isOpen) {\n if (showAllItems) {\n return originalCollection;\n } else {\n return filteredCollection;\n }\n } else {\n return lastCollection;\n }\n }, [triggerState.isOpen, originalCollection, filteredCollection, showAllItems, lastCollection]);\n\n return {\n ...validation,\n ...triggerState,\n toggle,\n open,\n close: commitValue,\n selectionManager,\n selectedKey,\n setSelectedKey,\n disabledKeys,\n isFocused,\n setFocused,\n selectedItem,\n collection: displayedCollection,\n inputValue,\n setInputValue,\n commit,\n revert\n };\n}\n\nfunction filterCollection<T extends object>(collection: Collection<Node<T>>, inputValue: string, filter: FilterFn): Collection<Node<T>> {\n return new ListCollection(filterNodes(collection, collection, inputValue, filter));\n}\n\nfunction filterNodes<T>(collection: Collection<Node<T>>, nodes: Iterable<Node<T>>, inputValue: string, filter: FilterFn): Iterable<Node<T>> {\n let filteredNode = [];\n for (let node of nodes) {\n if (node.type === 'section' && node.hasChildNodes) {\n let filtered = filterNodes(collection, getChildNodes(node, collection), inputValue, filter);\n if ([...filtered].some(node => node.type === 'item')) {\n filteredNode.push({...node, childNodes: filtered});\n }\n } else if (node.type === 'item' && filter(node.textValue, inputValue)) {\n filteredNode.push({...node});\n } else if (node.type !== 'item') {\n filteredNode.push({...node});\n }\n }\n return filteredNode;\n}\n"],"names":[],"version":3,"file":"main.js.map"}
|
|
1
|
+
{"mappings":"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","sources":["packages/@react-stately/combobox/src/index.ts","packages/@react-stately/combobox/src/useComboBoxState.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\nexport {useComboBoxState} from './useComboBoxState';\n\nexport type {ComboBoxStateOptions, ComboBoxState} from './useComboBoxState';\n","/*\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 {Collection, CollectionStateBase, FocusStrategy, Node} from '@react-types/shared';\nimport {ComboBoxProps, MenuTriggerAction} from '@react-types/combobox';\nimport {FormValidationState, useFormValidationState} from '@react-stately/form';\nimport {getChildNodes} from '@react-stately/collections';\nimport {ListCollection, useSingleSelectListState} from '@react-stately/list';\nimport {SelectState} from '@react-stately/select';\nimport {useCallback, useEffect, useMemo, useRef, useState} from 'react';\nimport {useControlledState} from '@react-stately/utils';\nimport {useOverlayTriggerState} from '@react-stately/overlays';\n\nexport interface ComboBoxState<T> extends SelectState<T>, FormValidationState{\n /** The current value of the combo box input. */\n inputValue: string,\n /** Sets the value of the combo box input. */\n setInputValue(value: string): void,\n /** Selects the currently focused item and updates the input value. */\n commit(): void,\n /** Controls which item will be auto focused when the menu opens. */\n readonly focusStrategy: FocusStrategy,\n /** Opens the menu. */\n open(focusStrategy?: FocusStrategy | null, trigger?: MenuTriggerAction): void,\n /** Toggles the menu. */\n toggle(focusStrategy?: FocusStrategy | null, trigger?: MenuTriggerAction): void,\n /** Resets the input value to the previously selected item's text if any and closes the menu. */\n revert(): void\n}\n\ntype FilterFn = (textValue: string, inputValue: string) => boolean;\n\nexport interface ComboBoxStateOptions<T> extends Omit<ComboBoxProps<T>, 'children'>, CollectionStateBase<T> {\n /** The filter function used to determine if a option should be included in the combo box list. */\n defaultFilter?: FilterFn,\n /** Whether the combo box allows the menu to be open when the collection is empty. */\n allowsEmptyCollection?: boolean,\n /** Whether the combo box menu should close on blur. */\n shouldCloseOnBlur?: boolean\n}\n\n/**\n * Provides state management for a combo box component. Handles building a collection\n * of items from props and manages the option selection state of the combo box. In addition, it tracks the input value,\n * focus state, and other properties of the combo box.\n */\nexport function useComboBoxState<T extends object>(props: ComboBoxStateOptions<T>): ComboBoxState<T> {\n let {\n defaultFilter,\n menuTrigger = 'input',\n allowsEmptyCollection = false,\n allowsCustomValue,\n shouldCloseOnBlur = true\n } = props;\n\n let [showAllItems, setShowAllItems] = useState(false);\n let [isFocused, setFocusedState] = useState(false);\n let [focusStrategy, setFocusStrategy] = useState<FocusStrategy>(null);\n\n let onSelectionChange = (key) => {\n if (props.onSelectionChange) {\n props.onSelectionChange(key);\n }\n\n // If key is the same, reset the inputValue and close the menu\n // (scenario: user clicks on already selected option)\n if (key === selectedKey) {\n resetInputValue();\n closeMenu();\n }\n };\n\n let {collection, selectionManager, selectedKey, setSelectedKey, selectedItem, disabledKeys} = useSingleSelectListState({\n ...props,\n onSelectionChange,\n items: props.items ?? props.defaultItems\n });\n\n let [inputValue, setInputValue] = useControlledState(\n props.inputValue,\n props.defaultInputValue ?? collection.getItem(selectedKey)?.textValue ?? '',\n props.onInputChange\n );\n\n // Preserve original collection so we can show all items on demand\n let originalCollection = collection;\n let filteredCollection = useMemo(() => (\n // No default filter if items are controlled.\n props.items != null || !defaultFilter\n ? collection\n : filterCollection(collection, inputValue, defaultFilter)\n ), [collection, inputValue, defaultFilter, props.items]);\n let [lastCollection, setLastCollection] = useState(filteredCollection);\n\n // Track what action is attempting to open the menu\n let menuOpenTrigger = useRef('focus' as MenuTriggerAction);\n let onOpenChange = (open: boolean) => {\n if (props.onOpenChange) {\n props.onOpenChange(open, open ? menuOpenTrigger.current : undefined);\n }\n\n selectionManager.setFocused(open);\n if (!open) {\n selectionManager.setFocusedKey(null);\n }\n };\n\n let triggerState = useOverlayTriggerState({...props, onOpenChange, isOpen: undefined, defaultOpen: undefined});\n let open = (focusStrategy: FocusStrategy = null, trigger?: MenuTriggerAction) => {\n let displayAllItems = (trigger === 'manual' || (trigger === 'focus' && menuTrigger === 'focus'));\n // Prevent open operations from triggering if there is nothing to display\n // Also prevent open operations from triggering if items are uncontrolled but defaultItems is empty, even if displayAllItems is true.\n // This is to prevent comboboxes with empty defaultItems from opening but allow controlled items comboboxes to open even if the inital list is empty (assumption is user will provide swap the empty list with a base list via onOpenChange returning `menuTrigger` manual)\n if (allowsEmptyCollection || filteredCollection.size > 0 || (displayAllItems && originalCollection.size > 0) || props.items) {\n if (displayAllItems && !triggerState.isOpen && props.items === undefined) {\n // Show all items if menu is manually opened. Only care about this if items are undefined\n setShowAllItems(true);\n }\n\n menuOpenTrigger.current = trigger;\n setFocusStrategy(focusStrategy);\n triggerState.open();\n }\n };\n\n let toggle = (focusStrategy: FocusStrategy = null, trigger?: MenuTriggerAction) => {\n let displayAllItems = (trigger === 'manual' || (trigger === 'focus' && menuTrigger === 'focus'));\n // If the menu is closed and there is nothing to display, early return so toggle isn't called to prevent extraneous onOpenChange\n if (!(allowsEmptyCollection || filteredCollection.size > 0 || (displayAllItems && originalCollection.size > 0) || props.items) && !triggerState.isOpen) {\n return;\n }\n\n if (displayAllItems && !triggerState.isOpen && props.items === undefined) {\n // Show all items if menu is toggled open. Only care about this if items are undefined\n setShowAllItems(true);\n }\n\n // Only update the menuOpenTrigger if menu is currently closed\n if (!triggerState.isOpen) {\n menuOpenTrigger.current = trigger;\n }\n\n toggleMenu(focusStrategy);\n };\n\n let updateLastCollection = useCallback(() => {\n setLastCollection(showAllItems ? originalCollection : filteredCollection);\n }, [showAllItems, originalCollection, filteredCollection]);\n\n // If menu is going to close, save the current collection so we can freeze the displayed collection when the\n // user clicks outside the popover to close the menu. Prevents the menu contents from updating as the menu closes.\n let toggleMenu = useCallback((focusStrategy: FocusStrategy = null) => {\n if (triggerState.isOpen) {\n updateLastCollection();\n }\n\n setFocusStrategy(focusStrategy);\n triggerState.toggle();\n }, [triggerState, updateLastCollection]);\n\n let closeMenu = useCallback(() => {\n if (triggerState.isOpen) {\n updateLastCollection();\n triggerState.close();\n }\n }, [triggerState, updateLastCollection]);\n\n let [lastValue, setLastValue] = useState(inputValue);\n let resetInputValue = () => {\n let itemText = collection.getItem(selectedKey)?.textValue ?? '';\n setLastValue(itemText);\n setInputValue(itemText);\n };\n\n let lastSelectedKey = useRef(props.selectedKey ?? props.defaultSelectedKey ?? null);\n let lastSelectedKeyText = useRef(collection.getItem(selectedKey)?.textValue ?? '');\n // intentional omit dependency array, want this to happen on every render\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(() => {\n // Open and close menu automatically when the input value changes if the input is focused,\n // and there are items in the collection or allowEmptyCollection is true.\n if (\n isFocused &&\n (filteredCollection.size > 0 || allowsEmptyCollection) &&\n !triggerState.isOpen &&\n inputValue !== lastValue &&\n menuTrigger !== 'manual'\n ) {\n open(null, 'input');\n }\n\n // Close the menu if the collection is empty. Don't close menu if filtered collection size is 0\n // but we are currently showing all items via button press\n if (\n !showAllItems &&\n !allowsEmptyCollection &&\n triggerState.isOpen &&\n filteredCollection.size === 0\n ) {\n closeMenu();\n }\n\n // Close when an item is selected.\n if (\n selectedKey != null &&\n selectedKey !== lastSelectedKey.current\n ) {\n closeMenu();\n }\n\n // Clear focused key when input value changes and display filtered collection again.\n if (inputValue !== lastValue) {\n selectionManager.setFocusedKey(null);\n setShowAllItems(false);\n\n // Set selectedKey to null when the user clears the input.\n // If controlled, this is the application developer's responsibility.\n if (inputValue === '' && (props.inputValue === undefined || props.selectedKey === undefined)) {\n setSelectedKey(null);\n }\n }\n\n // If the selectedKey changed, update the input value.\n // Do nothing if both inputValue and selectedKey are controlled.\n // In this case, it's the user's responsibility to update inputValue in onSelectionChange.\n if (\n selectedKey !== lastSelectedKey.current &&\n (props.inputValue === undefined || props.selectedKey === undefined)\n ) {\n resetInputValue();\n } else if (lastValue !== inputValue) {\n setLastValue(inputValue);\n }\n\n // Update the inputValue if the selected item's text changes from its last tracked value.\n // This is to handle cases where a selectedKey is specified but the items aren't available (async loading) or the selected item's text value updates.\n // Only reset if the user isn't currently within the field so we don't erroneously modify user input.\n // If inputValue is controlled, it is the user's responsibility to update the inputValue when items change.\n let selectedItemText = collection.getItem(selectedKey)?.textValue ?? '';\n if (!isFocused && selectedKey != null && props.inputValue === undefined && selectedKey === lastSelectedKey.current) {\n if (lastSelectedKeyText.current !== selectedItemText) {\n setLastValue(selectedItemText);\n setInputValue(selectedItemText);\n }\n }\n\n lastSelectedKey.current = selectedKey;\n lastSelectedKeyText.current = selectedItemText;\n });\n\n let validation = useFormValidationState({\n ...props,\n value: useMemo(() => ({inputValue, selectedKey}), [inputValue, selectedKey])\n });\n\n // Revert input value and close menu\n let revert = () => {\n if (allowsCustomValue && selectedKey == null) {\n commitCustomValue();\n } else {\n commitSelection();\n }\n };\n\n let commitCustomValue = () => {\n lastSelectedKey.current = null;\n setSelectedKey(null);\n closeMenu();\n };\n\n let commitSelection = () => {\n // If multiple things are controlled, call onSelectionChange\n if (props.selectedKey !== undefined && props.inputValue !== undefined) {\n props.onSelectionChange(selectedKey);\n\n // Stop menu from reopening from useEffect\n let itemText = collection.getItem(selectedKey)?.textValue ?? '';\n setLastValue(itemText);\n closeMenu();\n } else {\n // If only a single aspect of combobox is controlled, reset input value and close menu for the user\n resetInputValue();\n closeMenu();\n }\n };\n\n const commitValue = () => {\n if (allowsCustomValue) {\n const itemText = collection.getItem(selectedKey)?.textValue ?? '';\n (inputValue === itemText) ? commitSelection() : commitCustomValue();\n } else {\n // Reset inputValue and close menu\n commitSelection();\n }\n };\n\n let commit = () => {\n if (triggerState.isOpen && selectionManager.focusedKey != null) {\n // Reset inputValue and close menu here if the selected key is already the focused key. Otherwise\n // fire onSelectionChange to allow the application to control the closing.\n if (selectedKey === selectionManager.focusedKey) {\n commitSelection();\n } else {\n setSelectedKey(selectionManager.focusedKey);\n }\n } else {\n commitValue();\n }\n };\n\n let valueOnFocus = useRef(inputValue);\n let setFocused = (isFocused: boolean) => {\n if (isFocused) {\n valueOnFocus.current = inputValue;\n if (menuTrigger === 'focus') {\n open(null, 'focus');\n }\n } else {\n if (shouldCloseOnBlur) {\n commitValue();\n }\n\n if (inputValue !== valueOnFocus.current) {\n validation.commitValidation();\n }\n }\n\n setFocusedState(isFocused);\n };\n\n let displayedCollection = useMemo(() => {\n if (triggerState.isOpen) {\n if (showAllItems) {\n return originalCollection;\n } else {\n return filteredCollection;\n }\n } else {\n return lastCollection;\n }\n }, [triggerState.isOpen, originalCollection, filteredCollection, showAllItems, lastCollection]);\n\n return {\n ...validation,\n ...triggerState,\n focusStrategy,\n toggle,\n open,\n close: commitValue,\n selectionManager,\n selectedKey,\n setSelectedKey,\n disabledKeys,\n isFocused,\n setFocused,\n selectedItem,\n collection: displayedCollection,\n inputValue,\n setInputValue,\n commit,\n revert\n };\n}\n\nfunction filterCollection<T extends object>(collection: Collection<Node<T>>, inputValue: string, filter: FilterFn): Collection<Node<T>> {\n return new ListCollection(filterNodes(collection, collection, inputValue, filter));\n}\n\nfunction filterNodes<T>(collection: Collection<Node<T>>, nodes: Iterable<Node<T>>, inputValue: string, filter: FilterFn): Iterable<Node<T>> {\n let filteredNode = [];\n for (let node of nodes) {\n if (node.type === 'section' && node.hasChildNodes) {\n let filtered = filterNodes(collection, getChildNodes(node, collection), inputValue, filter);\n if ([...filtered].some(node => node.type === 'item')) {\n filteredNode.push({...node, childNodes: filtered});\n }\n } else if (node.type === 'item' && filter(node.textValue, inputValue)) {\n filteredNode.push({...node});\n } else if (node.type !== 'item') {\n filteredNode.push({...node});\n }\n }\n return filteredNode;\n}\n"],"names":[],"version":3,"file":"main.js.map"}
|
package/dist/module.js
CHANGED
|
@@ -3,7 +3,7 @@ import {getChildNodes as $k6Ppu$getChildNodes} from "@react-stately/collections"
|
|
|
3
3
|
import {useSingleSelectListState as $k6Ppu$useSingleSelectListState, ListCollection as $k6Ppu$ListCollection} from "@react-stately/list";
|
|
4
4
|
import {useState as $k6Ppu$useState, useMemo as $k6Ppu$useMemo, useRef as $k6Ppu$useRef, useCallback as $k6Ppu$useCallback, useEffect as $k6Ppu$useEffect} from "react";
|
|
5
5
|
import {useControlledState as $k6Ppu$useControlledState} from "@react-stately/utils";
|
|
6
|
-
import {
|
|
6
|
+
import {useOverlayTriggerState as $k6Ppu$useOverlayTriggerState} from "@react-stately/overlays";
|
|
7
7
|
|
|
8
8
|
/*
|
|
9
9
|
* Copyright 2020 Adobe. All rights reserved.
|
|
@@ -36,6 +36,7 @@ function $a9e7382a7d111cb5$export$b453a3bfd4a5fa9e(props) {
|
|
|
36
36
|
let { defaultFilter: defaultFilter, menuTrigger: menuTrigger = "input", allowsEmptyCollection: allowsEmptyCollection = false, allowsCustomValue: allowsCustomValue, shouldCloseOnBlur: shouldCloseOnBlur = true } = props;
|
|
37
37
|
let [showAllItems, setShowAllItems] = (0, $k6Ppu$useState)(false);
|
|
38
38
|
let [isFocused, setFocusedState] = (0, $k6Ppu$useState)(false);
|
|
39
|
+
let [focusStrategy, setFocusStrategy] = (0, $k6Ppu$useState)(null);
|
|
39
40
|
let onSelectionChange = (key)=>{
|
|
40
41
|
if (props.onSelectionChange) props.onSelectionChange(key);
|
|
41
42
|
// If key is the same, reset the inputValue and close the menu
|
|
@@ -70,13 +71,13 @@ function $a9e7382a7d111cb5$export$b453a3bfd4a5fa9e(props) {
|
|
|
70
71
|
selectionManager.setFocused(open);
|
|
71
72
|
if (!open) selectionManager.setFocusedKey(null);
|
|
72
73
|
};
|
|
73
|
-
let triggerState = (0, $k6Ppu$
|
|
74
|
+
let triggerState = (0, $k6Ppu$useOverlayTriggerState)({
|
|
74
75
|
...props,
|
|
75
76
|
onOpenChange: onOpenChange,
|
|
76
77
|
isOpen: undefined,
|
|
77
78
|
defaultOpen: undefined
|
|
78
79
|
});
|
|
79
|
-
let open = (focusStrategy, trigger)=>{
|
|
80
|
+
let open = (focusStrategy = null, trigger)=>{
|
|
80
81
|
let displayAllItems = trigger === "manual" || trigger === "focus" && menuTrigger === "focus";
|
|
81
82
|
// Prevent open operations from triggering if there is nothing to display
|
|
82
83
|
// Also prevent open operations from triggering if items are uncontrolled but defaultItems is empty, even if displayAllItems is true.
|
|
@@ -85,10 +86,11 @@ function $a9e7382a7d111cb5$export$b453a3bfd4a5fa9e(props) {
|
|
|
85
86
|
if (displayAllItems && !triggerState.isOpen && props.items === undefined) // Show all items if menu is manually opened. Only care about this if items are undefined
|
|
86
87
|
setShowAllItems(true);
|
|
87
88
|
menuOpenTrigger.current = trigger;
|
|
88
|
-
|
|
89
|
+
setFocusStrategy(focusStrategy);
|
|
90
|
+
triggerState.open();
|
|
89
91
|
}
|
|
90
92
|
};
|
|
91
|
-
let toggle = (focusStrategy, trigger)=>{
|
|
93
|
+
let toggle = (focusStrategy = null, trigger)=>{
|
|
92
94
|
let displayAllItems = trigger === "manual" || trigger === "focus" && menuTrigger === "focus";
|
|
93
95
|
// If the menu is closed and there is nothing to display, early return so toggle isn't called to prevent extraneous onOpenChange
|
|
94
96
|
if (!(allowsEmptyCollection || filteredCollection.size > 0 || displayAllItems && originalCollection.size > 0 || props.items) && !triggerState.isOpen) return;
|
|
@@ -98,23 +100,31 @@ function $a9e7382a7d111cb5$export$b453a3bfd4a5fa9e(props) {
|
|
|
98
100
|
if (!triggerState.isOpen) menuOpenTrigger.current = trigger;
|
|
99
101
|
toggleMenu(focusStrategy);
|
|
100
102
|
};
|
|
103
|
+
let updateLastCollection = (0, $k6Ppu$useCallback)(()=>{
|
|
104
|
+
setLastCollection(showAllItems ? originalCollection : filteredCollection);
|
|
105
|
+
}, [
|
|
106
|
+
showAllItems,
|
|
107
|
+
originalCollection,
|
|
108
|
+
filteredCollection
|
|
109
|
+
]);
|
|
101
110
|
// If menu is going to close, save the current collection so we can freeze the displayed collection when the
|
|
102
111
|
// user clicks outside the popover to close the menu. Prevents the menu contents from updating as the menu closes.
|
|
103
|
-
let toggleMenu = (0, $k6Ppu$useCallback)((focusStrategy)=>{
|
|
104
|
-
if (triggerState.isOpen)
|
|
105
|
-
|
|
112
|
+
let toggleMenu = (0, $k6Ppu$useCallback)((focusStrategy = null)=>{
|
|
113
|
+
if (triggerState.isOpen) updateLastCollection();
|
|
114
|
+
setFocusStrategy(focusStrategy);
|
|
115
|
+
triggerState.toggle();
|
|
106
116
|
}, [
|
|
107
117
|
triggerState,
|
|
108
|
-
|
|
118
|
+
updateLastCollection
|
|
109
119
|
]);
|
|
110
120
|
let closeMenu = (0, $k6Ppu$useCallback)(()=>{
|
|
111
121
|
if (triggerState.isOpen) {
|
|
112
|
-
|
|
122
|
+
updateLastCollection();
|
|
113
123
|
triggerState.close();
|
|
114
124
|
}
|
|
115
125
|
}, [
|
|
116
126
|
triggerState,
|
|
117
|
-
|
|
127
|
+
updateLastCollection
|
|
118
128
|
]);
|
|
119
129
|
let [lastValue, setLastValue] = (0, $k6Ppu$useState)(inputValue);
|
|
120
130
|
let resetInputValue = ()=>{
|
|
@@ -247,6 +257,7 @@ function $a9e7382a7d111cb5$export$b453a3bfd4a5fa9e(props) {
|
|
|
247
257
|
return {
|
|
248
258
|
...validation,
|
|
249
259
|
...triggerState,
|
|
260
|
+
focusStrategy: focusStrategy,
|
|
250
261
|
toggle: toggle,
|
|
251
262
|
open: open,
|
|
252
263
|
close: commitValue,
|
package/dist/module.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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","sources":["packages/@react-stately/combobox/src/index.ts","packages/@react-stately/combobox/src/useComboBoxState.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\nexport {useComboBoxState} from './useComboBoxState';\n\nexport type {ComboBoxStateOptions, ComboBoxState} from './useComboBoxState';\n","/*\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 {Collection, CollectionStateBase, FocusStrategy, Node} from '@react-types/shared';\nimport {ComboBoxProps, MenuTriggerAction} from '@react-types/combobox';\nimport {FormValidationState, useFormValidationState} from '@react-stately/form';\nimport {getChildNodes} from '@react-stately/collections';\nimport {ListCollection, useSingleSelectListState} from '@react-stately/list';\nimport {SelectState} from '@react-stately/select';\nimport {useCallback, useEffect, useMemo, useRef, useState} from 'react';\nimport {useControlledState} from '@react-stately/utils';\nimport {useMenuTriggerState} from '@react-stately/menu';\n\nexport interface ComboBoxState<T> extends SelectState<T>, FormValidationState{\n /** The current value of the combo box input. */\n inputValue: string,\n /** Sets the value of the combo box input. */\n setInputValue(value: string): void,\n /** Selects the currently focused item and updates the input value. */\n commit(): void,\n /** Opens the menu. */\n open(focusStrategy?: FocusStrategy | null, trigger?: MenuTriggerAction): void,\n /** Toggles the menu. */\n toggle(focusStrategy?: FocusStrategy | null, trigger?: MenuTriggerAction): void,\n /** Resets the input value to the previously selected item's text if any and closes the menu. */\n revert(): void\n}\n\ntype FilterFn = (textValue: string, inputValue: string) => boolean;\n\nexport interface ComboBoxStateOptions<T> extends Omit<ComboBoxProps<T>, 'children'>, CollectionStateBase<T> {\n /** The filter function used to determine if a option should be included in the combo box list. */\n defaultFilter?: FilterFn,\n /** Whether the combo box allows the menu to be open when the collection is empty. */\n allowsEmptyCollection?: boolean,\n /** Whether the combo box menu should close on blur. */\n shouldCloseOnBlur?: boolean\n}\n\n/**\n * Provides state management for a combo box component. Handles building a collection\n * of items from props and manages the option selection state of the combo box. In addition, it tracks the input value,\n * focus state, and other properties of the combo box.\n */\nexport function useComboBoxState<T extends object>(props: ComboBoxStateOptions<T>): ComboBoxState<T> {\n let {\n defaultFilter,\n menuTrigger = 'input',\n allowsEmptyCollection = false,\n allowsCustomValue,\n shouldCloseOnBlur = true\n } = props;\n\n let [showAllItems, setShowAllItems] = useState(false);\n let [isFocused, setFocusedState] = useState(false);\n\n let onSelectionChange = (key) => {\n if (props.onSelectionChange) {\n props.onSelectionChange(key);\n }\n\n // If key is the same, reset the inputValue and close the menu\n // (scenario: user clicks on already selected option)\n if (key === selectedKey) {\n resetInputValue();\n closeMenu();\n }\n };\n\n let {collection, selectionManager, selectedKey, setSelectedKey, selectedItem, disabledKeys} = useSingleSelectListState({\n ...props,\n onSelectionChange,\n items: props.items ?? props.defaultItems\n });\n\n let [inputValue, setInputValue] = useControlledState(\n props.inputValue,\n props.defaultInputValue ?? collection.getItem(selectedKey)?.textValue ?? '',\n props.onInputChange\n );\n\n // Preserve original collection so we can show all items on demand\n let originalCollection = collection;\n let filteredCollection = useMemo(() => (\n // No default filter if items are controlled.\n props.items != null || !defaultFilter\n ? collection\n : filterCollection(collection, inputValue, defaultFilter)\n ), [collection, inputValue, defaultFilter, props.items]);\n let [lastCollection, setLastCollection] = useState(filteredCollection);\n\n // Track what action is attempting to open the menu\n let menuOpenTrigger = useRef('focus' as MenuTriggerAction);\n let onOpenChange = (open: boolean) => {\n if (props.onOpenChange) {\n props.onOpenChange(open, open ? menuOpenTrigger.current : undefined);\n }\n\n selectionManager.setFocused(open);\n if (!open) {\n selectionManager.setFocusedKey(null);\n }\n };\n\n let triggerState = useMenuTriggerState({...props, onOpenChange, isOpen: undefined, defaultOpen: undefined});\n let open = (focusStrategy?: FocusStrategy, trigger?: MenuTriggerAction) => {\n let displayAllItems = (trigger === 'manual' || (trigger === 'focus' && menuTrigger === 'focus'));\n // Prevent open operations from triggering if there is nothing to display\n // Also prevent open operations from triggering if items are uncontrolled but defaultItems is empty, even if displayAllItems is true.\n // This is to prevent comboboxes with empty defaultItems from opening but allow controlled items comboboxes to open even if the inital list is empty (assumption is user will provide swap the empty list with a base list via onOpenChange returning `menuTrigger` manual)\n if (allowsEmptyCollection || filteredCollection.size > 0 || (displayAllItems && originalCollection.size > 0) || props.items) {\n if (displayAllItems && !triggerState.isOpen && props.items === undefined) {\n // Show all items if menu is manually opened. Only care about this if items are undefined\n setShowAllItems(true);\n }\n\n menuOpenTrigger.current = trigger;\n triggerState.open(focusStrategy);\n }\n };\n\n let toggle = (focusStrategy?: FocusStrategy, trigger?: MenuTriggerAction) => {\n let displayAllItems = (trigger === 'manual' || (trigger === 'focus' && menuTrigger === 'focus'));\n // If the menu is closed and there is nothing to display, early return so toggle isn't called to prevent extraneous onOpenChange\n if (!(allowsEmptyCollection || filteredCollection.size > 0 || (displayAllItems && originalCollection.size > 0) || props.items) && !triggerState.isOpen) {\n return;\n }\n\n if (displayAllItems && !triggerState.isOpen && props.items === undefined) {\n // Show all items if menu is toggled open. Only care about this if items are undefined\n setShowAllItems(true);\n }\n\n // Only update the menuOpenTrigger if menu is currently closed\n if (!triggerState.isOpen) {\n menuOpenTrigger.current = trigger;\n }\n\n toggleMenu(focusStrategy);\n };\n\n // If menu is going to close, save the current collection so we can freeze the displayed collection when the\n // user clicks outside the popover to close the menu. Prevents the menu contents from updating as the menu closes.\n let toggleMenu = useCallback((focusStrategy) => {\n if (triggerState.isOpen) {\n setLastCollection(filteredCollection);\n }\n\n triggerState.toggle(focusStrategy);\n }, [triggerState, filteredCollection]);\n\n let closeMenu = useCallback(() => {\n if (triggerState.isOpen) {\n setLastCollection(filteredCollection);\n triggerState.close();\n }\n }, [triggerState, filteredCollection]);\n\n let [lastValue, setLastValue] = useState(inputValue);\n let resetInputValue = () => {\n let itemText = collection.getItem(selectedKey)?.textValue ?? '';\n setLastValue(itemText);\n setInputValue(itemText);\n };\n\n let lastSelectedKey = useRef(props.selectedKey ?? props.defaultSelectedKey ?? null);\n let lastSelectedKeyText = useRef(collection.getItem(selectedKey)?.textValue ?? '');\n // intentional omit dependency array, want this to happen on every render\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(() => {\n // Open and close menu automatically when the input value changes if the input is focused,\n // and there are items in the collection or allowEmptyCollection is true.\n if (\n isFocused &&\n (filteredCollection.size > 0 || allowsEmptyCollection) &&\n !triggerState.isOpen &&\n inputValue !== lastValue &&\n menuTrigger !== 'manual'\n ) {\n open(null, 'input');\n }\n\n // Close the menu if the collection is empty. Don't close menu if filtered collection size is 0\n // but we are currently showing all items via button press\n if (\n !showAllItems &&\n !allowsEmptyCollection &&\n triggerState.isOpen &&\n filteredCollection.size === 0\n ) {\n closeMenu();\n }\n\n // Close when an item is selected.\n if (\n selectedKey != null &&\n selectedKey !== lastSelectedKey.current\n ) {\n closeMenu();\n }\n\n // Clear focused key when input value changes and display filtered collection again.\n if (inputValue !== lastValue) {\n selectionManager.setFocusedKey(null);\n setShowAllItems(false);\n\n // Set selectedKey to null when the user clears the input.\n // If controlled, this is the application developer's responsibility.\n if (inputValue === '' && (props.inputValue === undefined || props.selectedKey === undefined)) {\n setSelectedKey(null);\n }\n }\n\n // If the selectedKey changed, update the input value.\n // Do nothing if both inputValue and selectedKey are controlled.\n // In this case, it's the user's responsibility to update inputValue in onSelectionChange.\n if (\n selectedKey !== lastSelectedKey.current &&\n (props.inputValue === undefined || props.selectedKey === undefined)\n ) {\n resetInputValue();\n } else if (lastValue !== inputValue) {\n setLastValue(inputValue);\n }\n\n // Update the inputValue if the selected item's text changes from its last tracked value.\n // This is to handle cases where a selectedKey is specified but the items aren't available (async loading) or the selected item's text value updates.\n // Only reset if the user isn't currently within the field so we don't erroneously modify user input.\n // If inputValue is controlled, it is the user's responsibility to update the inputValue when items change.\n let selectedItemText = collection.getItem(selectedKey)?.textValue ?? '';\n if (!isFocused && selectedKey != null && props.inputValue === undefined && selectedKey === lastSelectedKey.current) {\n if (lastSelectedKeyText.current !== selectedItemText) {\n setLastValue(selectedItemText);\n setInputValue(selectedItemText);\n }\n }\n\n lastSelectedKey.current = selectedKey;\n lastSelectedKeyText.current = selectedItemText;\n });\n\n let validation = useFormValidationState({\n ...props,\n value: useMemo(() => ({inputValue, selectedKey}), [inputValue, selectedKey])\n });\n\n // Revert input value and close menu\n let revert = () => {\n if (allowsCustomValue && selectedKey == null) {\n commitCustomValue();\n } else {\n commitSelection();\n }\n };\n\n let commitCustomValue = () => {\n lastSelectedKey.current = null;\n setSelectedKey(null);\n closeMenu();\n };\n\n let commitSelection = () => {\n // If multiple things are controlled, call onSelectionChange\n if (props.selectedKey !== undefined && props.inputValue !== undefined) {\n props.onSelectionChange(selectedKey);\n\n // Stop menu from reopening from useEffect\n let itemText = collection.getItem(selectedKey)?.textValue ?? '';\n setLastValue(itemText);\n closeMenu();\n } else {\n // If only a single aspect of combobox is controlled, reset input value and close menu for the user\n resetInputValue();\n closeMenu();\n }\n };\n\n const commitValue = () => {\n if (allowsCustomValue) {\n const itemText = collection.getItem(selectedKey)?.textValue ?? '';\n (inputValue === itemText) ? commitSelection() : commitCustomValue();\n } else {\n // Reset inputValue and close menu\n commitSelection();\n }\n };\n\n let commit = () => {\n if (triggerState.isOpen && selectionManager.focusedKey != null) {\n // Reset inputValue and close menu here if the selected key is already the focused key. Otherwise\n // fire onSelectionChange to allow the application to control the closing.\n if (selectedKey === selectionManager.focusedKey) {\n commitSelection();\n } else {\n setSelectedKey(selectionManager.focusedKey);\n }\n } else {\n commitValue();\n }\n };\n\n let valueOnFocus = useRef(inputValue);\n let setFocused = (isFocused: boolean) => {\n if (isFocused) {\n valueOnFocus.current = inputValue;\n if (menuTrigger === 'focus') {\n open(null, 'focus');\n }\n } else {\n if (shouldCloseOnBlur) {\n commitValue();\n }\n\n if (inputValue !== valueOnFocus.current) {\n validation.commitValidation();\n }\n }\n\n setFocusedState(isFocused);\n };\n\n let displayedCollection = useMemo(() => {\n if (triggerState.isOpen) {\n if (showAllItems) {\n return originalCollection;\n } else {\n return filteredCollection;\n }\n } else {\n return lastCollection;\n }\n }, [triggerState.isOpen, originalCollection, filteredCollection, showAllItems, lastCollection]);\n\n return {\n ...validation,\n ...triggerState,\n toggle,\n open,\n close: commitValue,\n selectionManager,\n selectedKey,\n setSelectedKey,\n disabledKeys,\n isFocused,\n setFocused,\n selectedItem,\n collection: displayedCollection,\n inputValue,\n setInputValue,\n commit,\n revert\n };\n}\n\nfunction filterCollection<T extends object>(collection: Collection<Node<T>>, inputValue: string, filter: FilterFn): Collection<Node<T>> {\n return new ListCollection(filterNodes(collection, collection, inputValue, filter));\n}\n\nfunction filterNodes<T>(collection: Collection<Node<T>>, nodes: Iterable<Node<T>>, inputValue: string, filter: FilterFn): Iterable<Node<T>> {\n let filteredNode = [];\n for (let node of nodes) {\n if (node.type === 'section' && node.hasChildNodes) {\n let filtered = filterNodes(collection, getChildNodes(node, collection), inputValue, filter);\n if ([...filtered].some(node => node.type === 'item')) {\n filteredNode.push({...node, childNodes: filtered});\n }\n } else if (node.type === 'item' && filter(node.textValue, inputValue)) {\n filteredNode.push({...node});\n } else if (node.type !== 'item') {\n filteredNode.push({...node});\n }\n }\n return filteredNode;\n}\n"],"names":[],"version":3,"file":"module.js.map"}
|
|
1
|
+
{"mappings":"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","sources":["packages/@react-stately/combobox/src/index.ts","packages/@react-stately/combobox/src/useComboBoxState.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\nexport {useComboBoxState} from './useComboBoxState';\n\nexport type {ComboBoxStateOptions, ComboBoxState} from './useComboBoxState';\n","/*\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 {Collection, CollectionStateBase, FocusStrategy, Node} from '@react-types/shared';\nimport {ComboBoxProps, MenuTriggerAction} from '@react-types/combobox';\nimport {FormValidationState, useFormValidationState} from '@react-stately/form';\nimport {getChildNodes} from '@react-stately/collections';\nimport {ListCollection, useSingleSelectListState} from '@react-stately/list';\nimport {SelectState} from '@react-stately/select';\nimport {useCallback, useEffect, useMemo, useRef, useState} from 'react';\nimport {useControlledState} from '@react-stately/utils';\nimport {useOverlayTriggerState} from '@react-stately/overlays';\n\nexport interface ComboBoxState<T> extends SelectState<T>, FormValidationState{\n /** The current value of the combo box input. */\n inputValue: string,\n /** Sets the value of the combo box input. */\n setInputValue(value: string): void,\n /** Selects the currently focused item and updates the input value. */\n commit(): void,\n /** Controls which item will be auto focused when the menu opens. */\n readonly focusStrategy: FocusStrategy,\n /** Opens the menu. */\n open(focusStrategy?: FocusStrategy | null, trigger?: MenuTriggerAction): void,\n /** Toggles the menu. */\n toggle(focusStrategy?: FocusStrategy | null, trigger?: MenuTriggerAction): void,\n /** Resets the input value to the previously selected item's text if any and closes the menu. */\n revert(): void\n}\n\ntype FilterFn = (textValue: string, inputValue: string) => boolean;\n\nexport interface ComboBoxStateOptions<T> extends Omit<ComboBoxProps<T>, 'children'>, CollectionStateBase<T> {\n /** The filter function used to determine if a option should be included in the combo box list. */\n defaultFilter?: FilterFn,\n /** Whether the combo box allows the menu to be open when the collection is empty. */\n allowsEmptyCollection?: boolean,\n /** Whether the combo box menu should close on blur. */\n shouldCloseOnBlur?: boolean\n}\n\n/**\n * Provides state management for a combo box component. Handles building a collection\n * of items from props and manages the option selection state of the combo box. In addition, it tracks the input value,\n * focus state, and other properties of the combo box.\n */\nexport function useComboBoxState<T extends object>(props: ComboBoxStateOptions<T>): ComboBoxState<T> {\n let {\n defaultFilter,\n menuTrigger = 'input',\n allowsEmptyCollection = false,\n allowsCustomValue,\n shouldCloseOnBlur = true\n } = props;\n\n let [showAllItems, setShowAllItems] = useState(false);\n let [isFocused, setFocusedState] = useState(false);\n let [focusStrategy, setFocusStrategy] = useState<FocusStrategy>(null);\n\n let onSelectionChange = (key) => {\n if (props.onSelectionChange) {\n props.onSelectionChange(key);\n }\n\n // If key is the same, reset the inputValue and close the menu\n // (scenario: user clicks on already selected option)\n if (key === selectedKey) {\n resetInputValue();\n closeMenu();\n }\n };\n\n let {collection, selectionManager, selectedKey, setSelectedKey, selectedItem, disabledKeys} = useSingleSelectListState({\n ...props,\n onSelectionChange,\n items: props.items ?? props.defaultItems\n });\n\n let [inputValue, setInputValue] = useControlledState(\n props.inputValue,\n props.defaultInputValue ?? collection.getItem(selectedKey)?.textValue ?? '',\n props.onInputChange\n );\n\n // Preserve original collection so we can show all items on demand\n let originalCollection = collection;\n let filteredCollection = useMemo(() => (\n // No default filter if items are controlled.\n props.items != null || !defaultFilter\n ? collection\n : filterCollection(collection, inputValue, defaultFilter)\n ), [collection, inputValue, defaultFilter, props.items]);\n let [lastCollection, setLastCollection] = useState(filteredCollection);\n\n // Track what action is attempting to open the menu\n let menuOpenTrigger = useRef('focus' as MenuTriggerAction);\n let onOpenChange = (open: boolean) => {\n if (props.onOpenChange) {\n props.onOpenChange(open, open ? menuOpenTrigger.current : undefined);\n }\n\n selectionManager.setFocused(open);\n if (!open) {\n selectionManager.setFocusedKey(null);\n }\n };\n\n let triggerState = useOverlayTriggerState({...props, onOpenChange, isOpen: undefined, defaultOpen: undefined});\n let open = (focusStrategy: FocusStrategy = null, trigger?: MenuTriggerAction) => {\n let displayAllItems = (trigger === 'manual' || (trigger === 'focus' && menuTrigger === 'focus'));\n // Prevent open operations from triggering if there is nothing to display\n // Also prevent open operations from triggering if items are uncontrolled but defaultItems is empty, even if displayAllItems is true.\n // This is to prevent comboboxes with empty defaultItems from opening but allow controlled items comboboxes to open even if the inital list is empty (assumption is user will provide swap the empty list with a base list via onOpenChange returning `menuTrigger` manual)\n if (allowsEmptyCollection || filteredCollection.size > 0 || (displayAllItems && originalCollection.size > 0) || props.items) {\n if (displayAllItems && !triggerState.isOpen && props.items === undefined) {\n // Show all items if menu is manually opened. Only care about this if items are undefined\n setShowAllItems(true);\n }\n\n menuOpenTrigger.current = trigger;\n setFocusStrategy(focusStrategy);\n triggerState.open();\n }\n };\n\n let toggle = (focusStrategy: FocusStrategy = null, trigger?: MenuTriggerAction) => {\n let displayAllItems = (trigger === 'manual' || (trigger === 'focus' && menuTrigger === 'focus'));\n // If the menu is closed and there is nothing to display, early return so toggle isn't called to prevent extraneous onOpenChange\n if (!(allowsEmptyCollection || filteredCollection.size > 0 || (displayAllItems && originalCollection.size > 0) || props.items) && !triggerState.isOpen) {\n return;\n }\n\n if (displayAllItems && !triggerState.isOpen && props.items === undefined) {\n // Show all items if menu is toggled open. Only care about this if items are undefined\n setShowAllItems(true);\n }\n\n // Only update the menuOpenTrigger if menu is currently closed\n if (!triggerState.isOpen) {\n menuOpenTrigger.current = trigger;\n }\n\n toggleMenu(focusStrategy);\n };\n\n let updateLastCollection = useCallback(() => {\n setLastCollection(showAllItems ? originalCollection : filteredCollection);\n }, [showAllItems, originalCollection, filteredCollection]);\n\n // If menu is going to close, save the current collection so we can freeze the displayed collection when the\n // user clicks outside the popover to close the menu. Prevents the menu contents from updating as the menu closes.\n let toggleMenu = useCallback((focusStrategy: FocusStrategy = null) => {\n if (triggerState.isOpen) {\n updateLastCollection();\n }\n\n setFocusStrategy(focusStrategy);\n triggerState.toggle();\n }, [triggerState, updateLastCollection]);\n\n let closeMenu = useCallback(() => {\n if (triggerState.isOpen) {\n updateLastCollection();\n triggerState.close();\n }\n }, [triggerState, updateLastCollection]);\n\n let [lastValue, setLastValue] = useState(inputValue);\n let resetInputValue = () => {\n let itemText = collection.getItem(selectedKey)?.textValue ?? '';\n setLastValue(itemText);\n setInputValue(itemText);\n };\n\n let lastSelectedKey = useRef(props.selectedKey ?? props.defaultSelectedKey ?? null);\n let lastSelectedKeyText = useRef(collection.getItem(selectedKey)?.textValue ?? '');\n // intentional omit dependency array, want this to happen on every render\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(() => {\n // Open and close menu automatically when the input value changes if the input is focused,\n // and there are items in the collection or allowEmptyCollection is true.\n if (\n isFocused &&\n (filteredCollection.size > 0 || allowsEmptyCollection) &&\n !triggerState.isOpen &&\n inputValue !== lastValue &&\n menuTrigger !== 'manual'\n ) {\n open(null, 'input');\n }\n\n // Close the menu if the collection is empty. Don't close menu if filtered collection size is 0\n // but we are currently showing all items via button press\n if (\n !showAllItems &&\n !allowsEmptyCollection &&\n triggerState.isOpen &&\n filteredCollection.size === 0\n ) {\n closeMenu();\n }\n\n // Close when an item is selected.\n if (\n selectedKey != null &&\n selectedKey !== lastSelectedKey.current\n ) {\n closeMenu();\n }\n\n // Clear focused key when input value changes and display filtered collection again.\n if (inputValue !== lastValue) {\n selectionManager.setFocusedKey(null);\n setShowAllItems(false);\n\n // Set selectedKey to null when the user clears the input.\n // If controlled, this is the application developer's responsibility.\n if (inputValue === '' && (props.inputValue === undefined || props.selectedKey === undefined)) {\n setSelectedKey(null);\n }\n }\n\n // If the selectedKey changed, update the input value.\n // Do nothing if both inputValue and selectedKey are controlled.\n // In this case, it's the user's responsibility to update inputValue in onSelectionChange.\n if (\n selectedKey !== lastSelectedKey.current &&\n (props.inputValue === undefined || props.selectedKey === undefined)\n ) {\n resetInputValue();\n } else if (lastValue !== inputValue) {\n setLastValue(inputValue);\n }\n\n // Update the inputValue if the selected item's text changes from its last tracked value.\n // This is to handle cases where a selectedKey is specified but the items aren't available (async loading) or the selected item's text value updates.\n // Only reset if the user isn't currently within the field so we don't erroneously modify user input.\n // If inputValue is controlled, it is the user's responsibility to update the inputValue when items change.\n let selectedItemText = collection.getItem(selectedKey)?.textValue ?? '';\n if (!isFocused && selectedKey != null && props.inputValue === undefined && selectedKey === lastSelectedKey.current) {\n if (lastSelectedKeyText.current !== selectedItemText) {\n setLastValue(selectedItemText);\n setInputValue(selectedItemText);\n }\n }\n\n lastSelectedKey.current = selectedKey;\n lastSelectedKeyText.current = selectedItemText;\n });\n\n let validation = useFormValidationState({\n ...props,\n value: useMemo(() => ({inputValue, selectedKey}), [inputValue, selectedKey])\n });\n\n // Revert input value and close menu\n let revert = () => {\n if (allowsCustomValue && selectedKey == null) {\n commitCustomValue();\n } else {\n commitSelection();\n }\n };\n\n let commitCustomValue = () => {\n lastSelectedKey.current = null;\n setSelectedKey(null);\n closeMenu();\n };\n\n let commitSelection = () => {\n // If multiple things are controlled, call onSelectionChange\n if (props.selectedKey !== undefined && props.inputValue !== undefined) {\n props.onSelectionChange(selectedKey);\n\n // Stop menu from reopening from useEffect\n let itemText = collection.getItem(selectedKey)?.textValue ?? '';\n setLastValue(itemText);\n closeMenu();\n } else {\n // If only a single aspect of combobox is controlled, reset input value and close menu for the user\n resetInputValue();\n closeMenu();\n }\n };\n\n const commitValue = () => {\n if (allowsCustomValue) {\n const itemText = collection.getItem(selectedKey)?.textValue ?? '';\n (inputValue === itemText) ? commitSelection() : commitCustomValue();\n } else {\n // Reset inputValue and close menu\n commitSelection();\n }\n };\n\n let commit = () => {\n if (triggerState.isOpen && selectionManager.focusedKey != null) {\n // Reset inputValue and close menu here if the selected key is already the focused key. Otherwise\n // fire onSelectionChange to allow the application to control the closing.\n if (selectedKey === selectionManager.focusedKey) {\n commitSelection();\n } else {\n setSelectedKey(selectionManager.focusedKey);\n }\n } else {\n commitValue();\n }\n };\n\n let valueOnFocus = useRef(inputValue);\n let setFocused = (isFocused: boolean) => {\n if (isFocused) {\n valueOnFocus.current = inputValue;\n if (menuTrigger === 'focus') {\n open(null, 'focus');\n }\n } else {\n if (shouldCloseOnBlur) {\n commitValue();\n }\n\n if (inputValue !== valueOnFocus.current) {\n validation.commitValidation();\n }\n }\n\n setFocusedState(isFocused);\n };\n\n let displayedCollection = useMemo(() => {\n if (triggerState.isOpen) {\n if (showAllItems) {\n return originalCollection;\n } else {\n return filteredCollection;\n }\n } else {\n return lastCollection;\n }\n }, [triggerState.isOpen, originalCollection, filteredCollection, showAllItems, lastCollection]);\n\n return {\n ...validation,\n ...triggerState,\n focusStrategy,\n toggle,\n open,\n close: commitValue,\n selectionManager,\n selectedKey,\n setSelectedKey,\n disabledKeys,\n isFocused,\n setFocused,\n selectedItem,\n collection: displayedCollection,\n inputValue,\n setInputValue,\n commit,\n revert\n };\n}\n\nfunction filterCollection<T extends object>(collection: Collection<Node<T>>, inputValue: string, filter: FilterFn): Collection<Node<T>> {\n return new ListCollection(filterNodes(collection, collection, inputValue, filter));\n}\n\nfunction filterNodes<T>(collection: Collection<Node<T>>, nodes: Iterable<Node<T>>, inputValue: string, filter: FilterFn): Iterable<Node<T>> {\n let filteredNode = [];\n for (let node of nodes) {\n if (node.type === 'section' && node.hasChildNodes) {\n let filtered = filterNodes(collection, getChildNodes(node, collection), inputValue, filter);\n if ([...filtered].some(node => node.type === 'item')) {\n filteredNode.push({...node, childNodes: filtered});\n }\n } else if (node.type === 'item' && filter(node.textValue, inputValue)) {\n filteredNode.push({...node});\n } else if (node.type !== 'item') {\n filteredNode.push({...node});\n }\n }\n return filteredNode;\n}\n"],"names":[],"version":3,"file":"module.js.map"}
|
package/dist/types.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ export interface ComboBoxState<T> extends SelectState<T>, FormValidationState {
|
|
|
9
9
|
setInputValue(value: string): void;
|
|
10
10
|
/** Selects the currently focused item and updates the input value. */
|
|
11
11
|
commit(): void;
|
|
12
|
+
/** Controls which item will be auto focused when the menu opens. */
|
|
13
|
+
readonly focusStrategy: FocusStrategy;
|
|
12
14
|
/** Opens the menu. */
|
|
13
15
|
open(focusStrategy?: FocusStrategy | null, trigger?: MenuTriggerAction): void;
|
|
14
16
|
/** Toggles the menu. */
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;;;AAsBA,+BAA+B,CAAC,CAAE,SAAQ,YAAY,CAAC,CAAC,EAAE,mBAAmB;IAC3E,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,sEAAsE;IACtE,MAAM,IAAI,IAAI,CAAC;IACf,sBAAsB;IACtB,IAAI,CAAC,aAAa,CAAC,EAAE,aAAa,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC9E,wBAAwB;IACxB,MAAM,CAAC,aAAa,CAAC,EAAE,aAAa,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAChF,iGAAiG;IACjG,MAAM,IAAI,IAAI,CAAA;CACf;AAED,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;AAEnE,sCAAsC,CAAC,CAAE,SAAQ,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,oBAAoB,CAAC,CAAC;IACzG,kGAAkG;IAClG,aAAa,CAAC,EAAE,QAAQ,CAAC;IACzB,qFAAqF;IACrF,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,uDAAuD;IACvD,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED;;;;GAIG;AACH,iCAAiC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,qBAAqB,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,
|
|
1
|
+
{"mappings":";;;;AAsBA,+BAA+B,CAAC,CAAE,SAAQ,YAAY,CAAC,CAAC,EAAE,mBAAmB;IAC3E,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,sEAAsE;IACtE,MAAM,IAAI,IAAI,CAAC;IACf,oEAAoE;IACpE,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,sBAAsB;IACtB,IAAI,CAAC,aAAa,CAAC,EAAE,aAAa,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC9E,wBAAwB;IACxB,MAAM,CAAC,aAAa,CAAC,EAAE,aAAa,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAChF,iGAAiG;IACjG,MAAM,IAAI,IAAI,CAAA;CACf;AAED,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;AAEnE,sCAAsC,CAAC,CAAE,SAAQ,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,oBAAoB,CAAC,CAAC;IACzG,kGAAkG;IAClG,aAAa,CAAC,EAAE,QAAQ,CAAC;IACzB,qFAAqF;IACrF,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,uDAAuD;IACvD,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED;;;;GAIG;AACH,iCAAiC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,qBAAqB,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CA4TnG","sources":["packages/@react-stately/combobox/src/packages/@react-stately/combobox/src/useComboBoxState.ts","packages/@react-stately/combobox/src/packages/@react-stately/combobox/src/index.ts","packages/@react-stately/combobox/src/index.ts"],"sourcesContent":[null,null,"/*\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\nexport {useComboBoxState} from './useComboBoxState';\n\nexport type {ComboBoxStateOptions, ComboBoxState} from './useComboBoxState';\n"],"names":[],"version":3,"file":"types.d.ts.map"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-stately/combobox",
|
|
3
|
-
"version": "3.8.1
|
|
3
|
+
"version": "3.8.1",
|
|
4
4
|
"description": "Spectrum UI components in React",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -22,14 +22,14 @@
|
|
|
22
22
|
"url": "https://github.com/adobe/react-spectrum"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@react-stately/collections": "3.
|
|
26
|
-
"@react-stately/form": "3.0.
|
|
27
|
-
"@react-stately/list": "3.10.2
|
|
28
|
-
"@react-stately/
|
|
29
|
-
"@react-stately/select": "3.6.1
|
|
30
|
-
"@react-stately/utils": "3.
|
|
31
|
-
"@react-types/combobox": "3.
|
|
32
|
-
"@react-types/shared": "3.
|
|
25
|
+
"@react-stately/collections": "^3.10.4",
|
|
26
|
+
"@react-stately/form": "^3.0.0",
|
|
27
|
+
"@react-stately/list": "^3.10.2",
|
|
28
|
+
"@react-stately/overlays": "^3.6.4",
|
|
29
|
+
"@react-stately/select": "^3.6.1",
|
|
30
|
+
"@react-stately/utils": "^3.9.0",
|
|
31
|
+
"@react-types/combobox": "^3.10.0",
|
|
32
|
+
"@react-types/shared": "^3.22.0",
|
|
33
33
|
"@swc/helpers": "^0.5.0"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
@@ -38,5 +38,5 @@
|
|
|
38
38
|
"publishConfig": {
|
|
39
39
|
"access": "public"
|
|
40
40
|
},
|
|
41
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "86b38c87868ce7f262e0df905e5ac4eb2653791d"
|
|
42
42
|
}
|
package/src/useComboBoxState.ts
CHANGED
|
@@ -18,7 +18,7 @@ import {ListCollection, useSingleSelectListState} from '@react-stately/list';
|
|
|
18
18
|
import {SelectState} from '@react-stately/select';
|
|
19
19
|
import {useCallback, useEffect, useMemo, useRef, useState} from 'react';
|
|
20
20
|
import {useControlledState} from '@react-stately/utils';
|
|
21
|
-
import {
|
|
21
|
+
import {useOverlayTriggerState} from '@react-stately/overlays';
|
|
22
22
|
|
|
23
23
|
export interface ComboBoxState<T> extends SelectState<T>, FormValidationState{
|
|
24
24
|
/** The current value of the combo box input. */
|
|
@@ -27,6 +27,8 @@ export interface ComboBoxState<T> extends SelectState<T>, FormValidationState{
|
|
|
27
27
|
setInputValue(value: string): void,
|
|
28
28
|
/** Selects the currently focused item and updates the input value. */
|
|
29
29
|
commit(): void,
|
|
30
|
+
/** Controls which item will be auto focused when the menu opens. */
|
|
31
|
+
readonly focusStrategy: FocusStrategy,
|
|
30
32
|
/** Opens the menu. */
|
|
31
33
|
open(focusStrategy?: FocusStrategy | null, trigger?: MenuTriggerAction): void,
|
|
32
34
|
/** Toggles the menu. */
|
|
@@ -62,6 +64,7 @@ export function useComboBoxState<T extends object>(props: ComboBoxStateOptions<T
|
|
|
62
64
|
|
|
63
65
|
let [showAllItems, setShowAllItems] = useState(false);
|
|
64
66
|
let [isFocused, setFocusedState] = useState(false);
|
|
67
|
+
let [focusStrategy, setFocusStrategy] = useState<FocusStrategy>(null);
|
|
65
68
|
|
|
66
69
|
let onSelectionChange = (key) => {
|
|
67
70
|
if (props.onSelectionChange) {
|
|
@@ -111,8 +114,8 @@ export function useComboBoxState<T extends object>(props: ComboBoxStateOptions<T
|
|
|
111
114
|
}
|
|
112
115
|
};
|
|
113
116
|
|
|
114
|
-
let triggerState =
|
|
115
|
-
let open = (focusStrategy
|
|
117
|
+
let triggerState = useOverlayTriggerState({...props, onOpenChange, isOpen: undefined, defaultOpen: undefined});
|
|
118
|
+
let open = (focusStrategy: FocusStrategy = null, trigger?: MenuTriggerAction) => {
|
|
116
119
|
let displayAllItems = (trigger === 'manual' || (trigger === 'focus' && menuTrigger === 'focus'));
|
|
117
120
|
// Prevent open operations from triggering if there is nothing to display
|
|
118
121
|
// Also prevent open operations from triggering if items are uncontrolled but defaultItems is empty, even if displayAllItems is true.
|
|
@@ -124,11 +127,12 @@ export function useComboBoxState<T extends object>(props: ComboBoxStateOptions<T
|
|
|
124
127
|
}
|
|
125
128
|
|
|
126
129
|
menuOpenTrigger.current = trigger;
|
|
127
|
-
|
|
130
|
+
setFocusStrategy(focusStrategy);
|
|
131
|
+
triggerState.open();
|
|
128
132
|
}
|
|
129
133
|
};
|
|
130
134
|
|
|
131
|
-
let toggle = (focusStrategy
|
|
135
|
+
let toggle = (focusStrategy: FocusStrategy = null, trigger?: MenuTriggerAction) => {
|
|
132
136
|
let displayAllItems = (trigger === 'manual' || (trigger === 'focus' && menuTrigger === 'focus'));
|
|
133
137
|
// If the menu is closed and there is nothing to display, early return so toggle isn't called to prevent extraneous onOpenChange
|
|
134
138
|
if (!(allowsEmptyCollection || filteredCollection.size > 0 || (displayAllItems && originalCollection.size > 0) || props.items) && !triggerState.isOpen) {
|
|
@@ -148,22 +152,27 @@ export function useComboBoxState<T extends object>(props: ComboBoxStateOptions<T
|
|
|
148
152
|
toggleMenu(focusStrategy);
|
|
149
153
|
};
|
|
150
154
|
|
|
155
|
+
let updateLastCollection = useCallback(() => {
|
|
156
|
+
setLastCollection(showAllItems ? originalCollection : filteredCollection);
|
|
157
|
+
}, [showAllItems, originalCollection, filteredCollection]);
|
|
158
|
+
|
|
151
159
|
// If menu is going to close, save the current collection so we can freeze the displayed collection when the
|
|
152
160
|
// user clicks outside the popover to close the menu. Prevents the menu contents from updating as the menu closes.
|
|
153
|
-
let toggleMenu = useCallback((focusStrategy) => {
|
|
161
|
+
let toggleMenu = useCallback((focusStrategy: FocusStrategy = null) => {
|
|
154
162
|
if (triggerState.isOpen) {
|
|
155
|
-
|
|
163
|
+
updateLastCollection();
|
|
156
164
|
}
|
|
157
165
|
|
|
158
|
-
|
|
159
|
-
|
|
166
|
+
setFocusStrategy(focusStrategy);
|
|
167
|
+
triggerState.toggle();
|
|
168
|
+
}, [triggerState, updateLastCollection]);
|
|
160
169
|
|
|
161
170
|
let closeMenu = useCallback(() => {
|
|
162
171
|
if (triggerState.isOpen) {
|
|
163
|
-
|
|
172
|
+
updateLastCollection();
|
|
164
173
|
triggerState.close();
|
|
165
174
|
}
|
|
166
|
-
}, [triggerState,
|
|
175
|
+
}, [triggerState, updateLastCollection]);
|
|
167
176
|
|
|
168
177
|
let [lastValue, setLastValue] = useState(inputValue);
|
|
169
178
|
let resetInputValue = () => {
|
|
@@ -343,6 +352,7 @@ export function useComboBoxState<T extends object>(props: ComboBoxStateOptions<T
|
|
|
343
352
|
return {
|
|
344
353
|
...validation,
|
|
345
354
|
...triggerState,
|
|
355
|
+
focusStrategy,
|
|
346
356
|
toggle,
|
|
347
357
|
open,
|
|
348
358
|
close: commitValue,
|