@fluentui/react-combobox 9.0.0-beta.20 → 9.0.0-beta.21
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/CHANGELOG.json +52 -1
- package/CHANGELOG.md +17 -2
- package/lib/components/Combobox/useCombobox.js +14 -7
- package/lib/components/Combobox/useCombobox.js.map +1 -1
- package/lib/utils/useComboboxBaseState.js +6 -6
- package/lib/utils/useComboboxBaseState.js.map +1 -1
- package/lib/utils/useSelection.js +3 -2
- package/lib/utils/useSelection.js.map +1 -1
- package/lib/utils/useTriggerListboxSlots.js +19 -16
- package/lib/utils/useTriggerListboxSlots.js.map +1 -1
- package/lib-commonjs/components/Combobox/useCombobox.js +14 -7
- package/lib-commonjs/components/Combobox/useCombobox.js.map +1 -1
- package/lib-commonjs/utils/useComboboxBaseState.js +6 -6
- package/lib-commonjs/utils/useComboboxBaseState.js.map +1 -1
- package/lib-commonjs/utils/useSelection.js +3 -2
- package/lib-commonjs/utils/useSelection.js.map +1 -1
- package/lib-commonjs/utils/useTriggerListboxSlots.js +18 -15
- package/lib-commonjs/utils/useTriggerListboxSlots.js.map +1 -1
- package/package.json +6 -6
package/CHANGELOG.json
CHANGED
|
@@ -2,7 +2,58 @@
|
|
|
2
2
|
"name": "@fluentui/react-combobox",
|
|
3
3
|
"entries": [
|
|
4
4
|
{
|
|
5
|
-
"date": "
|
|
5
|
+
"date": "Mon, 09 Jan 2023 14:31:42 GMT",
|
|
6
|
+
"tag": "@fluentui/react-combobox_v9.0.0-beta.21",
|
|
7
|
+
"version": "9.0.0-beta.21",
|
|
8
|
+
"comments": {
|
|
9
|
+
"prerelease": [
|
|
10
|
+
{
|
|
11
|
+
"author": "sarah.higley@microsoft.com",
|
|
12
|
+
"package": "@fluentui/react-combobox",
|
|
13
|
+
"commit": "d7a98c92818f5ad8c80548dc288cc2cc55731c93",
|
|
14
|
+
"comment": "fix: perf improvements with useEventCallback"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"author": "sarah.higley@microsoft.com",
|
|
18
|
+
"package": "@fluentui/react-combobox",
|
|
19
|
+
"commit": "54b6220d442231ffa0c3df88359f53373690da6f",
|
|
20
|
+
"comment": "fix: Combobox always starts at the first option if multiselect, and correctly sets focus visible\""
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"author": "beachball",
|
|
24
|
+
"package": "@fluentui/react-combobox",
|
|
25
|
+
"comment": "Bump @fluentui/react-context-selector to v9.1.5",
|
|
26
|
+
"commit": "26f0364b3837056ee8e0df42a7932c298c68290e"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"author": "beachball",
|
|
30
|
+
"package": "@fluentui/react-combobox",
|
|
31
|
+
"comment": "Bump @fluentui/react-field to v9.0.0-alpha.14",
|
|
32
|
+
"commit": "26f0364b3837056ee8e0df42a7932c298c68290e"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"author": "beachball",
|
|
36
|
+
"package": "@fluentui/react-combobox",
|
|
37
|
+
"comment": "Bump @fluentui/react-portal to v9.1.0",
|
|
38
|
+
"commit": "26f0364b3837056ee8e0df42a7932c298c68290e"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"author": "beachball",
|
|
42
|
+
"package": "@fluentui/react-combobox",
|
|
43
|
+
"comment": "Bump @fluentui/react-positioning to v9.3.7",
|
|
44
|
+
"commit": "26f0364b3837056ee8e0df42a7932c298c68290e"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"author": "beachball",
|
|
48
|
+
"package": "@fluentui/react-combobox",
|
|
49
|
+
"comment": "Bump @fluentui/react-utilities to v9.4.0",
|
|
50
|
+
"commit": "26f0364b3837056ee8e0df42a7932c298c68290e"
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"date": "Wed, 04 Jan 2023 01:40:56 GMT",
|
|
6
57
|
"tag": "@fluentui/react-combobox_v9.0.0-beta.20",
|
|
7
58
|
"version": "9.0.0-beta.20",
|
|
8
59
|
"comments": {
|
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
# Change Log - @fluentui/react-combobox
|
|
2
2
|
|
|
3
|
-
This log was last generated on
|
|
3
|
+
This log was last generated on Mon, 09 Jan 2023 14:31:42 GMT and should not be manually modified.
|
|
4
4
|
|
|
5
5
|
<!-- Start content -->
|
|
6
6
|
|
|
7
|
+
## [9.0.0-beta.21](https://github.com/microsoft/fluentui/tree/@fluentui/react-combobox_v9.0.0-beta.21)
|
|
8
|
+
|
|
9
|
+
Mon, 09 Jan 2023 14:31:42 GMT
|
|
10
|
+
[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-combobox_v9.0.0-beta.20..@fluentui/react-combobox_v9.0.0-beta.21)
|
|
11
|
+
|
|
12
|
+
### Changes
|
|
13
|
+
|
|
14
|
+
- fix: perf improvements with useEventCallback ([PR #26191](https://github.com/microsoft/fluentui/pull/26191) by sarah.higley@microsoft.com)
|
|
15
|
+
- fix: Combobox always starts at the first option if multiselect, and correctly sets focus visible" ([PR #26173](https://github.com/microsoft/fluentui/pull/26173) by sarah.higley@microsoft.com)
|
|
16
|
+
- Bump @fluentui/react-context-selector to v9.1.5 ([PR #26257](https://github.com/microsoft/fluentui/pull/26257) by beachball)
|
|
17
|
+
- Bump @fluentui/react-field to v9.0.0-alpha.14 ([PR #26257](https://github.com/microsoft/fluentui/pull/26257) by beachball)
|
|
18
|
+
- Bump @fluentui/react-portal to v9.1.0 ([PR #26257](https://github.com/microsoft/fluentui/pull/26257) by beachball)
|
|
19
|
+
- Bump @fluentui/react-positioning to v9.3.7 ([PR #26257](https://github.com/microsoft/fluentui/pull/26257) by beachball)
|
|
20
|
+
- Bump @fluentui/react-utilities to v9.4.0 ([PR #26257](https://github.com/microsoft/fluentui/pull/26257) by beachball)
|
|
21
|
+
|
|
7
22
|
## [9.0.0-beta.20](https://github.com/microsoft/fluentui/tree/@fluentui/react-combobox_v9.0.0-beta.20)
|
|
8
23
|
|
|
9
|
-
Wed, 04 Jan 2023 01:
|
|
24
|
+
Wed, 04 Jan 2023 01:40:56 GMT
|
|
10
25
|
[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-combobox_v9.0.0-beta.19..@fluentui/react-combobox_v9.0.0-beta.20)
|
|
11
26
|
|
|
12
27
|
### Changes
|
|
@@ -51,12 +51,19 @@ export const useCombobox_unstable = (props, ref) => {
|
|
|
51
51
|
const rootRef = React.useRef(null);
|
|
52
52
|
const triggerRef = React.useRef(null);
|
|
53
53
|
// calculate listbox width style based on trigger width
|
|
54
|
-
const [
|
|
54
|
+
const [popupDimensions, setPopupDimensions] = React.useState();
|
|
55
55
|
React.useEffect(() => {
|
|
56
56
|
var _a;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
// only recalculate width when opening
|
|
58
|
+
if (open) {
|
|
59
|
+
const width = `${(_a = rootRef.current) === null || _a === void 0 ? void 0 : _a.clientWidth}px`;
|
|
60
|
+
if (width !== (popupDimensions === null || popupDimensions === void 0 ? void 0 : popupDimensions.width)) {
|
|
61
|
+
setPopupDimensions({
|
|
62
|
+
width
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}, [open, popupDimensions]);
|
|
60
67
|
// set active option and selection based on typing
|
|
61
68
|
const getOptionFromInput = inputValue => {
|
|
62
69
|
var _a;
|
|
@@ -137,9 +144,7 @@ export const useCombobox_unstable = (props, ref) => {
|
|
|
137
144
|
required: true,
|
|
138
145
|
defaultProps: {
|
|
139
146
|
children: props.children,
|
|
140
|
-
style:
|
|
141
|
-
width: popupWidth
|
|
142
|
-
}
|
|
147
|
+
style: popupDimensions
|
|
143
148
|
}
|
|
144
149
|
}) : undefined;
|
|
145
150
|
[triggerSlot, listboxSlot] = useComboboxPopup(props, triggerSlot, listboxSlot);
|
|
@@ -185,6 +190,8 @@ export const useCombobox_unstable = (props, ref) => {
|
|
|
185
190
|
// open and set focus
|
|
186
191
|
state.setOpen(event, !state.open);
|
|
187
192
|
(_a = triggerRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
193
|
+
// set focus visible=false, since this can only be done with the mouse/pointer
|
|
194
|
+
setFocusVisible(false);
|
|
188
195
|
}));
|
|
189
196
|
if (state.expandIcon) {
|
|
190
197
|
state.expandIcon.onMouseDown = onExpandIconMouseDown;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"mappings":"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","names":["React","ChevronDownRegular","ChevronDownIcon","getPartitionedNativeProps","resolveShorthand","mergeCallbacks","useEventCallback","useMergedRefs","getDropdownActionFromKey","useComboboxBaseState","useComboboxPopup","useTriggerListboxSlots","Listbox","useCombobox_unstable","props","ref","baseState","editable","activeOption","clearSelection","getIndexOfId","getOptionsMatchingText","hasFocus","open","selectOption","selectedOptions","setActiveOption","setFocusVisible","setOpen","setValue","value","freeform","multiselect","primary","triggerNativeProps","root","rootNativeProps","primarySlotTagName","excludedPropNames","rootRef","useRef","triggerRef","popupWidth","setPopupWidth","useState","useEffect","width","current","clientWidth","undefined","getOptionFromInput","inputValue","searchString","trim","toLowerCase","length","matcher","optionText","indexOf","matches","startIndex","id","nextMatch","find","option","ev","onTriggerBlur","newState","onTriggerChange","target","matchingOption","onTriggerKeyDown","triggerSlot","listboxSlot","input","required","defaultProps","type","onChange","onBlur","onKeyDown","listbox","children","style","state","components","expandIcon","onMouseDown","onIconMouseDown","onClick","onIconClick","onExpandIconMouseDown","ignoreNextBlur","onExpandIconClick","event","focus"],"sourceRoot":"../src/","sources":["packages/react-components/react-combobox/src/components/Combobox/useCombobox.tsx"],"sourcesContent":["import * as React from 'react';\nimport { ChevronDownRegular as ChevronDownIcon } from '@fluentui/react-icons';\nimport {\n getPartitionedNativeProps,\n resolveShorthand,\n mergeCallbacks,\n useEventCallback,\n useMergedRefs,\n} from '@fluentui/react-utilities';\nimport { getDropdownActionFromKey } from '../../utils/dropdownKeyActions';\nimport { useComboboxBaseState } from '../../utils/useComboboxBaseState';\nimport { useComboboxPopup } from '../../utils/useComboboxPopup';\nimport { useTriggerListboxSlots } from '../../utils/useTriggerListboxSlots';\nimport { Listbox } from '../Listbox/Listbox';\nimport type { Slot } from '@fluentui/react-utilities';\nimport type { SelectionEvents } from '../../utils/Selection.types';\nimport type { OptionValue } from '../../utils/OptionCollection.types';\nimport type { ComboboxProps, ComboboxState } from './Combobox.types';\n\n/**\n * Create the state required to render Combobox.\n *\n * The returned state can be modified with hooks such as useComboboxStyles_unstable,\n * before being passed to renderCombobox_unstable.\n *\n * @param props - props from this instance of Combobox\n * @param ref - reference to root HTMLElement of Combobox\n */\nexport const useCombobox_unstable = (props: ComboboxProps, ref: React.Ref<HTMLInputElement>): ComboboxState => {\n const baseState = useComboboxBaseState({ ...props, editable: true });\n const {\n activeOption,\n clearSelection,\n getIndexOfId,\n getOptionsMatchingText,\n hasFocus,\n open,\n selectOption,\n selectedOptions,\n setActiveOption,\n setFocusVisible,\n setOpen,\n setValue,\n value,\n } = baseState;\n const { freeform, multiselect } = props;\n\n const { primary: triggerNativeProps, root: rootNativeProps } = getPartitionedNativeProps({\n props,\n primarySlotTagName: 'input',\n excludedPropNames: ['children', 'size'],\n });\n\n const rootRef = React.useRef<HTMLDivElement>(null);\n const triggerRef = React.useRef<HTMLInputElement>(null);\n\n // calculate listbox width style based on trigger width\n const [popupWidth, setPopupWidth] = React.useState<string>();\n React.useEffect(() => {\n const width = open ? `${rootRef.current?.clientWidth}px` : undefined;\n setPopupWidth(width);\n }, [open]);\n\n // set active option and selection based on typing\n const getOptionFromInput = (inputValue: string): OptionValue | undefined => {\n const searchString = inputValue?.trim().toLowerCase();\n\n if (!searchString || searchString.length === 0) {\n return;\n }\n\n const matcher = (optionText: string) => optionText.toLowerCase().indexOf(searchString) === 0;\n const matches = getOptionsMatchingText(matcher);\n\n // return first matching option after the current active option, looping back to the top\n if (matches.length > 1 && activeOption) {\n const startIndex = getIndexOfId(activeOption.id);\n const nextMatch = matches.find(option => getIndexOfId(option.id) >= startIndex);\n return nextMatch ?? matches[0];\n }\n\n return matches[0] ?? undefined;\n };\n\n /* Handle typed input */\n\n // reset any typed value when an option is selected\n baseState.selectOption = (ev: SelectionEvents, option: OptionValue) => {\n setValue(undefined);\n selectOption(ev, option);\n };\n\n const onTriggerBlur = (ev: React.FocusEvent<HTMLInputElement>) => {\n // handle selection and updating value if freeform is false\n if (!baseState.open && !freeform) {\n // select matching option, if the value fully matches\n if (value && activeOption && value.trim().toLowerCase() === activeOption?.value.toLowerCase()) {\n baseState.selectOption(ev, activeOption);\n }\n\n // reset typed value when the input loses focus while collapsed, unless freeform is true\n setValue(undefined);\n }\n };\n\n baseState.setOpen = (ev, newState: boolean) => {\n if (!newState && !freeform) {\n setValue(undefined);\n }\n\n setOpen(ev, newState);\n };\n\n // update value and active option based on input\n const onTriggerChange = (ev: React.ChangeEvent<HTMLInputElement>) => {\n const inputValue = ev.target.value;\n // update uncontrolled value\n baseState.setValue(inputValue);\n\n // handle updating active option based on input\n const matchingOption = getOptionFromInput(inputValue);\n setActiveOption(matchingOption);\n\n setFocusVisible(true);\n\n // clear selection for single-select if the input value no longer matches the selection\n if (\n !multiselect &&\n selectedOptions.length === 1 &&\n (inputValue.length < 1 || selectedOptions[0].indexOf(inputValue) !== 0)\n ) {\n clearSelection(ev);\n }\n };\n\n // open Combobox when typing\n const onTriggerKeyDown = (ev: React.KeyboardEvent<HTMLInputElement>) => {\n if (!open && getDropdownActionFromKey(ev) === 'Type') {\n setOpen(ev, true);\n }\n };\n\n // resolve input and listbox slot props\n let triggerSlot: Slot<'input'>;\n let listboxSlot: Slot<typeof Listbox> | undefined;\n\n triggerSlot = resolveShorthand(props.input, {\n required: true,\n defaultProps: {\n ref: useMergedRefs(props.input?.ref, triggerRef),\n type: 'text',\n value: value ?? '',\n ...triggerNativeProps,\n },\n });\n\n triggerSlot.onChange = mergeCallbacks(triggerSlot.onChange, onTriggerChange);\n triggerSlot.onBlur = mergeCallbacks(triggerSlot.onBlur, onTriggerBlur);\n triggerSlot.onKeyDown = mergeCallbacks(triggerSlot.onKeyDown, onTriggerKeyDown);\n\n // only resolve listbox slot if needed\n listboxSlot =\n open || hasFocus\n ? resolveShorthand(props.listbox, {\n required: true,\n defaultProps: {\n children: props.children,\n style: { width: popupWidth },\n },\n })\n : undefined;\n\n [triggerSlot, listboxSlot] = useComboboxPopup(props, triggerSlot, listboxSlot);\n [triggerSlot, listboxSlot] = useTriggerListboxSlots(props, baseState, ref, triggerSlot, listboxSlot);\n\n const state: ComboboxState = {\n components: {\n root: 'div',\n input: 'input',\n expandIcon: 'span',\n listbox: Listbox,\n },\n root: resolveShorthand(props.root, {\n required: true,\n defaultProps: {\n ...rootNativeProps,\n },\n }),\n input: triggerSlot,\n listbox: listboxSlot,\n expandIcon: resolveShorthand(props.expandIcon, {\n required: true,\n defaultProps: {\n children: <ChevronDownIcon />,\n },\n }),\n ...baseState,\n setOpen,\n };\n\n state.root.ref = useMergedRefs(state.root.ref, rootRef);\n\n /* handle open/close + focus change when clicking expandIcon */\n const { onMouseDown: onIconMouseDown, onClick: onIconClick } = state.expandIcon || {};\n const onExpandIconMouseDown = useEventCallback(\n mergeCallbacks(onIconMouseDown, () => {\n // do not dismiss on blur when closing via clicking the icon\n if (open) {\n baseState.ignoreNextBlur.current = true;\n }\n }),\n );\n\n const onExpandIconClick = useEventCallback(\n mergeCallbacks(onIconClick, (event: React.MouseEvent<HTMLSpanElement>) => {\n // open and set focus\n state.setOpen(event, !state.open);\n triggerRef.current?.focus();\n }),\n );\n\n if (state.expandIcon) {\n state.expandIcon.onMouseDown = onExpandIconMouseDown;\n state.expandIcon.onClick = onExpandIconClick;\n }\n\n return state;\n};\n"]}
|
|
1
|
+
{"version":3,"mappings":"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","names":["React","ChevronDownRegular","ChevronDownIcon","getPartitionedNativeProps","resolveShorthand","mergeCallbacks","useEventCallback","useMergedRefs","getDropdownActionFromKey","useComboboxBaseState","useComboboxPopup","useTriggerListboxSlots","Listbox","useCombobox_unstable","props","ref","baseState","editable","activeOption","clearSelection","getIndexOfId","getOptionsMatchingText","hasFocus","open","selectOption","selectedOptions","setActiveOption","setFocusVisible","setOpen","setValue","value","freeform","multiselect","primary","triggerNativeProps","root","rootNativeProps","primarySlotTagName","excludedPropNames","rootRef","useRef","triggerRef","popupDimensions","setPopupDimensions","useState","useEffect","width","current","clientWidth","getOptionFromInput","inputValue","searchString","trim","toLowerCase","length","matcher","optionText","indexOf","matches","startIndex","id","nextMatch","find","option","undefined","ev","onTriggerBlur","newState","onTriggerChange","target","matchingOption","onTriggerKeyDown","triggerSlot","listboxSlot","input","required","defaultProps","type","onChange","onBlur","onKeyDown","listbox","children","style","state","components","expandIcon","onMouseDown","onIconMouseDown","onClick","onIconClick","onExpandIconMouseDown","ignoreNextBlur","onExpandIconClick","event","focus"],"sourceRoot":"../src/","sources":["packages/react-components/react-combobox/src/components/Combobox/useCombobox.tsx"],"sourcesContent":["import * as React from 'react';\nimport { ChevronDownRegular as ChevronDownIcon } from '@fluentui/react-icons';\nimport {\n getPartitionedNativeProps,\n resolveShorthand,\n mergeCallbacks,\n useEventCallback,\n useMergedRefs,\n} from '@fluentui/react-utilities';\nimport { getDropdownActionFromKey } from '../../utils/dropdownKeyActions';\nimport { useComboboxBaseState } from '../../utils/useComboboxBaseState';\nimport { useComboboxPopup } from '../../utils/useComboboxPopup';\nimport { useTriggerListboxSlots } from '../../utils/useTriggerListboxSlots';\nimport { Listbox } from '../Listbox/Listbox';\nimport type { Slot } from '@fluentui/react-utilities';\nimport type { SelectionEvents } from '../../utils/Selection.types';\nimport type { OptionValue } from '../../utils/OptionCollection.types';\nimport type { ComboboxProps, ComboboxState } from './Combobox.types';\n\n/**\n * Create the state required to render Combobox.\n *\n * The returned state can be modified with hooks such as useComboboxStyles_unstable,\n * before being passed to renderCombobox_unstable.\n *\n * @param props - props from this instance of Combobox\n * @param ref - reference to root HTMLElement of Combobox\n */\nexport const useCombobox_unstable = (props: ComboboxProps, ref: React.Ref<HTMLInputElement>): ComboboxState => {\n const baseState = useComboboxBaseState({ ...props, editable: true });\n const {\n activeOption,\n clearSelection,\n getIndexOfId,\n getOptionsMatchingText,\n hasFocus,\n open,\n selectOption,\n selectedOptions,\n setActiveOption,\n setFocusVisible,\n setOpen,\n setValue,\n value,\n } = baseState;\n const { freeform, multiselect } = props;\n\n const { primary: triggerNativeProps, root: rootNativeProps } = getPartitionedNativeProps({\n props,\n primarySlotTagName: 'input',\n excludedPropNames: ['children', 'size'],\n });\n\n const rootRef = React.useRef<HTMLDivElement>(null);\n const triggerRef = React.useRef<HTMLInputElement>(null);\n\n // calculate listbox width style based on trigger width\n const [popupDimensions, setPopupDimensions] = React.useState<{ width: string }>();\n React.useEffect(() => {\n // only recalculate width when opening\n if (open) {\n const width = `${rootRef.current?.clientWidth}px`;\n if (width !== popupDimensions?.width) {\n setPopupDimensions({ width });\n }\n }\n }, [open, popupDimensions]);\n\n // set active option and selection based on typing\n const getOptionFromInput = (inputValue: string): OptionValue | undefined => {\n const searchString = inputValue?.trim().toLowerCase();\n\n if (!searchString || searchString.length === 0) {\n return;\n }\n\n const matcher = (optionText: string) => optionText.toLowerCase().indexOf(searchString) === 0;\n const matches = getOptionsMatchingText(matcher);\n\n // return first matching option after the current active option, looping back to the top\n if (matches.length > 1 && activeOption) {\n const startIndex = getIndexOfId(activeOption.id);\n const nextMatch = matches.find(option => getIndexOfId(option.id) >= startIndex);\n return nextMatch ?? matches[0];\n }\n\n return matches[0] ?? undefined;\n };\n\n /* Handle typed input */\n\n // reset any typed value when an option is selected\n baseState.selectOption = (ev: SelectionEvents, option: OptionValue) => {\n setValue(undefined);\n selectOption(ev, option);\n };\n\n const onTriggerBlur = (ev: React.FocusEvent<HTMLInputElement>) => {\n // handle selection and updating value if freeform is false\n if (!baseState.open && !freeform) {\n // select matching option, if the value fully matches\n if (value && activeOption && value.trim().toLowerCase() === activeOption?.value.toLowerCase()) {\n baseState.selectOption(ev, activeOption);\n }\n\n // reset typed value when the input loses focus while collapsed, unless freeform is true\n setValue(undefined);\n }\n };\n\n baseState.setOpen = (ev, newState: boolean) => {\n if (!newState && !freeform) {\n setValue(undefined);\n }\n\n setOpen(ev, newState);\n };\n\n // update value and active option based on input\n const onTriggerChange = (ev: React.ChangeEvent<HTMLInputElement>) => {\n const inputValue = ev.target.value;\n // update uncontrolled value\n baseState.setValue(inputValue);\n\n // handle updating active option based on input\n const matchingOption = getOptionFromInput(inputValue);\n setActiveOption(matchingOption);\n\n setFocusVisible(true);\n\n // clear selection for single-select if the input value no longer matches the selection\n if (\n !multiselect &&\n selectedOptions.length === 1 &&\n (inputValue.length < 1 || selectedOptions[0].indexOf(inputValue) !== 0)\n ) {\n clearSelection(ev);\n }\n };\n\n // open Combobox when typing\n const onTriggerKeyDown = (ev: React.KeyboardEvent<HTMLInputElement>) => {\n if (!open && getDropdownActionFromKey(ev) === 'Type') {\n setOpen(ev, true);\n }\n };\n\n // resolve input and listbox slot props\n let triggerSlot: Slot<'input'>;\n let listboxSlot: Slot<typeof Listbox> | undefined;\n\n triggerSlot = resolveShorthand(props.input, {\n required: true,\n defaultProps: {\n ref: useMergedRefs(props.input?.ref, triggerRef),\n type: 'text',\n value: value ?? '',\n ...triggerNativeProps,\n },\n });\n\n triggerSlot.onChange = mergeCallbacks(triggerSlot.onChange, onTriggerChange);\n triggerSlot.onBlur = mergeCallbacks(triggerSlot.onBlur, onTriggerBlur);\n triggerSlot.onKeyDown = mergeCallbacks(triggerSlot.onKeyDown, onTriggerKeyDown);\n\n // only resolve listbox slot if needed\n listboxSlot =\n open || hasFocus\n ? resolveShorthand(props.listbox, {\n required: true,\n defaultProps: {\n children: props.children,\n style: popupDimensions,\n },\n })\n : undefined;\n\n [triggerSlot, listboxSlot] = useComboboxPopup(props, triggerSlot, listboxSlot);\n [triggerSlot, listboxSlot] = useTriggerListboxSlots(props, baseState, ref, triggerSlot, listboxSlot);\n\n const state: ComboboxState = {\n components: {\n root: 'div',\n input: 'input',\n expandIcon: 'span',\n listbox: Listbox,\n },\n root: resolveShorthand(props.root, {\n required: true,\n defaultProps: {\n ...rootNativeProps,\n },\n }),\n input: triggerSlot,\n listbox: listboxSlot,\n expandIcon: resolveShorthand(props.expandIcon, {\n required: true,\n defaultProps: {\n children: <ChevronDownIcon />,\n },\n }),\n ...baseState,\n setOpen,\n };\n\n state.root.ref = useMergedRefs(state.root.ref, rootRef);\n\n /* handle open/close + focus change when clicking expandIcon */\n const { onMouseDown: onIconMouseDown, onClick: onIconClick } = state.expandIcon || {};\n const onExpandIconMouseDown = useEventCallback(\n mergeCallbacks(onIconMouseDown, () => {\n // do not dismiss on blur when closing via clicking the icon\n if (open) {\n baseState.ignoreNextBlur.current = true;\n }\n }),\n );\n\n const onExpandIconClick = useEventCallback(\n mergeCallbacks(onIconClick, (event: React.MouseEvent<HTMLSpanElement>) => {\n // open and set focus\n state.setOpen(event, !state.open);\n triggerRef.current?.focus();\n\n // set focus visible=false, since this can only be done with the mouse/pointer\n setFocusVisible(false);\n }),\n );\n\n if (state.expandIcon) {\n state.expandIcon.onMouseDown = onExpandIconMouseDown;\n state.expandIcon.onClick = onExpandIconClick;\n }\n\n return state;\n};\n"]}
|
|
@@ -57,19 +57,19 @@ export const useComboboxBaseState = props => {
|
|
|
57
57
|
defaultState: props.defaultOpen,
|
|
58
58
|
initialState: false
|
|
59
59
|
});
|
|
60
|
-
const setOpen = (event, newState) => {
|
|
60
|
+
const setOpen = React.useCallback((event, newState) => {
|
|
61
61
|
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(event, {
|
|
62
62
|
open: newState
|
|
63
63
|
});
|
|
64
64
|
setOpenState(newState);
|
|
65
|
-
};
|
|
65
|
+
}, [onOpenChange, setOpenState]);
|
|
66
66
|
// update active option based on change in open state
|
|
67
67
|
React.useEffect(() => {
|
|
68
68
|
if (open && !activeOption) {
|
|
69
|
-
// if there is a
|
|
70
|
-
if (selectedOptions.length > 0) {
|
|
71
|
-
const
|
|
72
|
-
|
|
69
|
+
// if it is single-select and there is a selected option, start at the selected option
|
|
70
|
+
if (!multiselect && selectedOptions.length > 0) {
|
|
71
|
+
const selectedOption = getOptionsMatchingText(v => v === selectedOptions[0]).pop();
|
|
72
|
+
selectedOption && setActiveOption(selectedOption);
|
|
73
73
|
}
|
|
74
74
|
// default to starting at the first option
|
|
75
75
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"mappings":"AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAC9B,SAASC,oBAAoB,EAAEC,aAAa,QAAQ,2BAA2B;AAC/E,SAASC,mBAAmB,QAAQ,8BAA8B;AAElE,SAASC,YAAY,QAAQ,uBAAuB;AAGpD;;;AAGA,OAAO,MAAMC,oBAAoB,GAAIC,KAAiD,IAAuB;EAC3G,MAAM;IACJC,UAAU,GAAG,SAAS;IACtBC,QAAQ,GAAG,KAAK;IAChBC,WAAW,GAAG,KAAK;IACnBC,WAAW;IACXC,YAAY;IACZC,IAAI,GAAG;EAAQ,CAChB,GAAGN,KAAK;EAET,MAAMO,gBAAgB,GAAGV,mBAAmB,EAAE;EAC9C,MAAM;IAAEW,gBAAgB;IAAEC;EAAsB,CAAE,GAAGF,gBAAgB;EAErE,MAAM,CAACG,YAAY,EAAEC,eAAe,CAAC,GAAGjB,KAAK,CAACkB,QAAQ,EAA2B;EAEjF;EACA;EACA,MAAM,CAACC,YAAY,EAAEC,eAAe,CAAC,GAAGpB,KAAK,CAACkB,QAAQ,CAAC,KAAK,CAAC;EAE7D;EACA,MAAM,CAACG,QAAQ,EAAEC,WAAW,CAAC,GAAGtB,KAAK,CAACkB,QAAQ,CAAC,KAAK,CAAC;EAErD,MAAMK,cAAc,GAAGvB,KAAK,CAACwB,MAAM,CAAC,KAAK,CAAC;EAE1C,MAAMC,cAAc,GAAGrB,YAAY,CAACE,KAAK,CAAC;EAC1C,MAAM;IAAEoB;EAAe,CAAE,GAAGD,cAAc;EAE1C;EACA,MAAME,YAAY,GAAGzB,aAAa,EAAE;EACpC,MAAM,CAAC0B,iBAAiB,EAAEC,QAAQ,CAAC,GAAG5B,oBAAoB,CAAC;IACzD6B,KAAK,EAAExB,KAAK,CAACyB,KAAK;IAClBC,YAAY,EAAEC;GACf,CAAC;EAEF,MAAMF,KAAK,GAAG/B,KAAK,CAACkC,OAAO,CAAC,MAAK;IAC/B;IACA,IAAIN,iBAAiB,KAAKK,SAAS,EAAE;MACnC,OAAOL,iBAAiB;;IAG1B;IACA,IAAID,YAAY,IAAIrB,KAAK,CAAC6B,YAAY,KAAKF,SAAS,EAAE;MACpD,OAAO3B,KAAK,CAAC6B,YAAY;;IAG3B,IAAIzB,WAAW,EAAE;MACf;MACA,OAAOF,QAAQ,GAAG,EAAE,GAAGkB,eAAe,CAACU,IAAI,CAAC,IAAI,CAAC;;IAGnD,OAAOV,eAAe,CAAC,CAAC,CAAC;EAC3B,CAAC,EAAE,CAACE,iBAAiB,EAAEpB,QAAQ,EAAEmB,YAAY,EAAEjB,WAAW,EAAEJ,KAAK,CAAC6B,YAAY,EAAET,eAAe,CAAC,CAAC;EAEjG;EACA,MAAM,CAACW,IAAI,EAAEC,YAAY,CAAC,GAAGrC,oBAAoB,CAAC;IAChD6B,KAAK,EAAExB,KAAK,CAAC+B,IAAI;IACjBE,YAAY,EAAEjC,KAAK,CAACkC,WAAW;IAC/BR,YAAY,EAAE;GACf,CAAC;EAEF,MAAMS,OAAO,
|
|
1
|
+
{"version":3,"mappings":"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","names":["React","useControllableState","useFirstMount","useOptionCollection","useSelection","useComboboxBaseState","props","appearance","editable","inlinePopup","multiselect","onOpenChange","size","optionCollection","getOptionAtIndex","getOptionsMatchingText","activeOption","setActiveOption","useState","focusVisible","setFocusVisible","hasFocus","setHasFocus","ignoreNextBlur","useRef","selectionState","selectedOptions","isFirstMount","controllableValue","setValue","state","value","initialState","undefined","useMemo","defaultValue","join","open","setOpenState","defaultState","defaultOpen","setOpen","useCallback","event","newState","useEffect","length","selectedOption","v","pop"],"sourceRoot":"../src/","sources":["packages/react-components/react-combobox/src/utils/useComboboxBaseState.ts"],"sourcesContent":["import * as React from 'react';\nimport { useControllableState, useFirstMount } from '@fluentui/react-utilities';\nimport { useOptionCollection } from '../utils/useOptionCollection';\nimport { OptionValue } from '../utils/OptionCollection.types';\nimport { useSelection } from '../utils/useSelection';\nimport type { ComboboxBaseProps, ComboboxBaseOpenEvents, ComboboxBaseState } from './ComboboxBase.types';\n\n/**\n * State shared between Combobox and Dropdown components\n */\nexport const useComboboxBaseState = (props: ComboboxBaseProps & { editable?: boolean }): ComboboxBaseState => {\n const {\n appearance = 'outline',\n editable = false,\n inlinePopup = false,\n multiselect,\n onOpenChange,\n size = 'medium',\n } = props;\n\n const optionCollection = useOptionCollection();\n const { getOptionAtIndex, getOptionsMatchingText } = optionCollection;\n\n const [activeOption, setActiveOption] = React.useState<OptionValue | undefined>();\n\n // track whether keyboard focus outline should be shown\n // tabster/keyborg doesn't work here, since the actual keyboard focus target doesn't move\n const [focusVisible, setFocusVisible] = React.useState(false);\n\n // track focused state to conditionally render collapsed listbox\n const [hasFocus, setHasFocus] = React.useState(false);\n\n const ignoreNextBlur = React.useRef(false);\n\n const selectionState = useSelection(props);\n const { selectedOptions } = selectionState;\n\n // calculate value based on props, internal value changes, and selected options\n const isFirstMount = useFirstMount();\n const [controllableValue, setValue] = useControllableState({\n state: props.value,\n initialState: undefined,\n });\n\n const value = React.useMemo(() => {\n // don't compute the value if it is defined through props or setValue,\n if (controllableValue !== undefined) {\n return controllableValue;\n }\n\n // handle defaultValue here, so it is overridden by selection\n if (isFirstMount && props.defaultValue !== undefined) {\n return props.defaultValue;\n }\n\n if (multiselect) {\n // editable inputs should not display multiple selected options in the input as text\n return editable ? '' : selectedOptions.join(', ');\n }\n\n return selectedOptions[0];\n }, [controllableValue, editable, isFirstMount, multiselect, props.defaultValue, selectedOptions]);\n\n // Handle open state, which is shared with options in context\n const [open, setOpenState] = useControllableState({\n state: props.open,\n defaultState: props.defaultOpen,\n initialState: false,\n });\n\n const setOpen = React.useCallback(\n (event: ComboboxBaseOpenEvents, newState: boolean) => {\n onOpenChange?.(event, { open: newState });\n setOpenState(newState);\n },\n [onOpenChange, setOpenState],\n );\n\n // update active option based on change in open state\n React.useEffect(() => {\n if (open && !activeOption) {\n // if it is single-select and there is a selected option, start at the selected option\n if (!multiselect && selectedOptions.length > 0) {\n const selectedOption = getOptionsMatchingText(v => v === selectedOptions[0]).pop();\n selectedOption && setActiveOption(selectedOption);\n }\n // default to starting at the first option\n else {\n setActiveOption(getOptionAtIndex(0));\n }\n } else if (!open) {\n // reset the active option when closing\n setActiveOption(undefined);\n }\n // this should only be run in response to changes in the open state\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open]);\n\n return {\n ...optionCollection,\n ...selectionState,\n activeOption,\n appearance,\n focusVisible,\n hasFocus,\n ignoreNextBlur,\n inlinePopup,\n open,\n setActiveOption,\n setFocusVisible,\n setHasFocus,\n setOpen,\n setValue,\n size,\n value,\n };\n};\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
1
2
|
import { useControllableState } from '@fluentui/react-utilities';
|
|
2
3
|
export const useSelection = props => {
|
|
3
4
|
const {
|
|
@@ -10,7 +11,7 @@ export const useSelection = props => {
|
|
|
10
11
|
defaultState: defaultSelectedOptions,
|
|
11
12
|
initialState: []
|
|
12
13
|
});
|
|
13
|
-
const selectOption = (event, option) => {
|
|
14
|
+
const selectOption = useCallback((event, option) => {
|
|
14
15
|
// if the option is disabled, do nothing
|
|
15
16
|
if (option.disabled) {
|
|
16
17
|
return;
|
|
@@ -34,7 +35,7 @@ export const useSelection = props => {
|
|
|
34
35
|
optionText: option.text,
|
|
35
36
|
selectedOptions: newSelection
|
|
36
37
|
});
|
|
37
|
-
};
|
|
38
|
+
}, [onOptionSelect, multiselect, selectedOptions, setSelectedOptions]);
|
|
38
39
|
const clearSelection = event => {
|
|
39
40
|
setSelectedOptions([]);
|
|
40
41
|
onOptionSelect === null || onOptionSelect === void 0 ? void 0 : onOptionSelect(event, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"mappings":"AAAA,SAASA,oBAAoB,QAAQ,2BAA2B;AAIhE,OAAO,MAAMC,YAAY,GAAIC,KAAqB,IAAoB;EACpE,MAAM;IAAEC,sBAAsB;IAAEC,WAAW;IAAEC;EAAc,CAAE,GAAGH,KAAK;EAErE,MAAM,CAACI,eAAe,EAAEC,kBAAkB,CAAC,GAAGP,oBAAoB,CAAC;IACjEQ,KAAK,EAAEN,KAAK,CAACI,eAAe;IAC5BG,YAAY,EAAEN,sBAAsB;IACpCO,YAAY,EAAE;GACf,CAAC;EAEF,MAAMC,YAAY,
|
|
1
|
+
{"version":3,"mappings":"AAAA,SAASA,WAAW,QAAQ,OAAO;AACnC,SAASC,oBAAoB,QAAQ,2BAA2B;AAIhE,OAAO,MAAMC,YAAY,GAAIC,KAAqB,IAAoB;EACpE,MAAM;IAAEC,sBAAsB;IAAEC,WAAW;IAAEC;EAAc,CAAE,GAAGH,KAAK;EAErE,MAAM,CAACI,eAAe,EAAEC,kBAAkB,CAAC,GAAGP,oBAAoB,CAAC;IACjEQ,KAAK,EAAEN,KAAK,CAACI,eAAe;IAC5BG,YAAY,EAAEN,sBAAsB;IACpCO,YAAY,EAAE;GACf,CAAC;EAEF,MAAMC,YAAY,GAAGZ,WAAW,CAC9B,CAACa,KAAsB,EAAEC,MAAmB,KAAI;IAC9C;IACA,IAAIA,MAAM,CAACC,QAAQ,EAAE;MACnB;;IAGF;IACA,IAAIC,YAAY,GAAG,CAACF,MAAM,CAACG,KAAK,CAAC;IAEjC;IACA,IAAIZ,WAAW,EAAE;MACf,MAAMa,aAAa,GAAGX,eAAe,CAACY,SAAS,CAACC,CAAC,IAAIA,CAAC,KAAKN,MAAM,CAACG,KAAK,CAAC;MACxE,IAAIC,aAAa,GAAG,CAAC,CAAC,EAAE;QACtB;QACAF,YAAY,GAAG,CAAC,GAAGT,eAAe,CAACc,KAAK,CAAC,CAAC,EAAEH,aAAa,CAAC,EAAE,GAAGX,eAAe,CAACc,KAAK,CAACH,aAAa,GAAG,CAAC,CAAC,CAAC;OACzG,MAAM;QACL;QACAF,YAAY,GAAG,CAAC,GAAGT,eAAe,EAAEO,MAAM,CAACG,KAAK,CAAC;;;IAIrDT,kBAAkB,CAACQ,YAAY,CAAC;IAChCV,cAAc,aAAdA,cAAc,uBAAdA,cAAc,CAAGO,KAAK,EAAE;MAAES,WAAW,EAAER,MAAM,CAACG,KAAK;MAAEM,UAAU,EAAET,MAAM,CAACU,IAAI;MAAEjB,eAAe,EAAES;IAAY,CAAE,CAAC;EAChH,CAAC,EACD,CAACV,cAAc,EAAED,WAAW,EAAEE,eAAe,EAAEC,kBAAkB,CAAC,CACnE;EAED,MAAMiB,cAAc,GAAIZ,KAAsB,IAAI;IAChDL,kBAAkB,CAAC,EAAE,CAAC;IACtBF,cAAc,aAAdA,cAAc,uBAAdA,cAAc,CAAGO,KAAK,EAAE;MAAES,WAAW,EAAEI,SAAS;MAAEH,UAAU,EAAEG,SAAS;MAAEnB,eAAe,EAAE;IAAE,CAAE,CAAC;EACjG,CAAC;EAED,OAAO;IAAEkB,cAAc;IAAEb,YAAY;IAAEL;EAAe,CAAE;AAC1D,CAAC","names":["useCallback","useControllableState","useSelection","props","defaultSelectedOptions","multiselect","onOptionSelect","selectedOptions","setSelectedOptions","state","defaultState","initialState","selectOption","event","option","disabled","newSelection","value","selectedIndex","findIndex","o","slice","optionValue","optionText","text","clearSelection","undefined"],"sourceRoot":"../src/","sources":["packages/react-components/react-combobox/src/utils/useSelection.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useControllableState } from '@fluentui/react-utilities';\nimport { OptionValue } from './OptionCollection.types';\nimport { SelectionEvents, SelectionProps, SelectionState } from './Selection.types';\n\nexport const useSelection = (props: SelectionProps): SelectionState => {\n const { defaultSelectedOptions, multiselect, onOptionSelect } = props;\n\n const [selectedOptions, setSelectedOptions] = useControllableState({\n state: props.selectedOptions,\n defaultState: defaultSelectedOptions,\n initialState: [],\n });\n\n const selectOption = useCallback(\n (event: SelectionEvents, option: OptionValue) => {\n // if the option is disabled, do nothing\n if (option.disabled) {\n return;\n }\n\n // for single-select, always return the selected option\n let newSelection = [option.value];\n\n // toggle selected state of the option for multiselect\n if (multiselect) {\n const selectedIndex = selectedOptions.findIndex(o => o === option.value);\n if (selectedIndex > -1) {\n // deselect option\n newSelection = [...selectedOptions.slice(0, selectedIndex), ...selectedOptions.slice(selectedIndex + 1)];\n } else {\n // select option\n newSelection = [...selectedOptions, option.value];\n }\n }\n\n setSelectedOptions(newSelection);\n onOptionSelect?.(event, { optionValue: option.value, optionText: option.text, selectedOptions: newSelection });\n },\n [onOptionSelect, multiselect, selectedOptions, setSelectedOptions],\n );\n\n const clearSelection = (event: SelectionEvents) => {\n setSelectedOptions([]);\n onOptionSelect?.(event, { optionValue: undefined, optionText: undefined, selectedOptions: [] });\n };\n\n return { clearSelection, selectOption, selectedOptions };\n};\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { mergeCallbacks, useMergedRefs } from '@fluentui/react-utilities';
|
|
2
|
+
import { mergeCallbacks, useEventCallback, useMergedRefs } from '@fluentui/react-utilities';
|
|
3
3
|
import { getDropdownActionFromKey, getIndexFromAction } from '../utils/dropdownKeyActions';
|
|
4
4
|
/*
|
|
5
5
|
* useTriggerListboxSlots returns a tuple of trigger/listbox shorthand,
|
|
@@ -42,23 +42,26 @@ export function useTriggerListboxSlots(props, state, ref, triggerSlot, listboxSl
|
|
|
42
42
|
// functionally both ref and triggerRef will always be the same element type
|
|
43
43
|
ref: useMergedRefs(ref, triggerSlot === null || triggerSlot === void 0 ? void 0 : triggerSlot.ref, triggerRef)
|
|
44
44
|
};
|
|
45
|
+
/*
|
|
46
|
+
* Handle focus when clicking the listbox popup:
|
|
47
|
+
* 1. Move focus back to the button/input when the listbox is clicked (otherwise it goes to body)
|
|
48
|
+
* 2. Do not close the listbox on button/input blur when clicking into the listbox
|
|
49
|
+
*/
|
|
50
|
+
const listboxOnClick = useEventCallback(mergeCallbacks(event => {
|
|
51
|
+
var _a;
|
|
52
|
+
(_a = triggerRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
53
|
+
}, listbox === null || listbox === void 0 ? void 0 : listbox.onClick));
|
|
54
|
+
const listboxOnMouseOver = useEventCallback(mergeCallbacks(event => {
|
|
55
|
+
setFocusVisible(false);
|
|
56
|
+
}, listbox === null || listbox === void 0 ? void 0 : listbox.onMouseOver));
|
|
57
|
+
const listboxOnMouseDown = useEventCallback(mergeCallbacks(event => {
|
|
58
|
+
ignoreNextBlur.current = true;
|
|
59
|
+
}, listbox === null || listbox === void 0 ? void 0 : listbox.onMouseDown));
|
|
45
60
|
// listbox is nullable, only add event handlers if it exists
|
|
46
61
|
if (listbox) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
* 2. Do not close the listbox on button/input blur when clicking into the listbox
|
|
51
|
-
*/
|
|
52
|
-
listbox.onClick = mergeCallbacks(event => {
|
|
53
|
-
var _a;
|
|
54
|
-
(_a = triggerRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
55
|
-
}, listbox.onClick);
|
|
56
|
-
listbox.onMouseOver = mergeCallbacks(event => {
|
|
57
|
-
setFocusVisible(false);
|
|
58
|
-
}, listbox.onMouseOver);
|
|
59
|
-
listbox.onMouseDown = mergeCallbacks(event => {
|
|
60
|
-
ignoreNextBlur.current = true;
|
|
61
|
-
}, listbox.onMouseDown);
|
|
62
|
+
listbox.onClick = listboxOnClick;
|
|
63
|
+
listbox.onMouseOver = listboxOnMouseOver;
|
|
64
|
+
listbox.onMouseDown = listboxOnMouseDown;
|
|
62
65
|
}
|
|
63
66
|
// the trigger should open/close the popup on click or blur
|
|
64
67
|
trigger.onBlur = mergeCallbacks(event => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"mappings":"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","names":["React","mergeCallbacks","useMergedRefs","getDropdownActionFromKey","getIndexFromAction","useTriggerListboxSlots","props","state","ref","triggerSlot","listboxSlot","multiselect","activeOption","getCount","getIndexOfId","getOptionAtIndex","ignoreNextBlur","open","selectOption","setActiveOption","setFocusVisible","setHasFocus","setOpen","triggerRef","useRef","listbox","tabIndex","undefined","trigger","id","role","onClick","event","current","focus","onMouseOver","onMouseDown","onBlur","onFocus","onKeyDown","action","maxIndex","activeIndex","newIndex","preventDefault","stopPropagation","disabled"],"sourceRoot":"../src/","sources":["packages/react-components/react-combobox/src/utils/useTriggerListboxSlots.ts"],"sourcesContent":["import * as React from 'react';\nimport { mergeCallbacks, useMergedRefs } from '@fluentui/react-utilities';\nimport type { ExtractSlotProps, Slot } from '@fluentui/react-utilities';\nimport { getDropdownActionFromKey, getIndexFromAction } from '../utils/dropdownKeyActions';\nimport { Listbox } from '../components/Listbox/Listbox';\nimport type { ComboboxBaseProps, ComboboxBaseState } from './ComboboxBase.types';\n\nexport function useTriggerListboxSlots(\n props: ComboboxBaseProps,\n state: ComboboxBaseState,\n ref: React.Ref<HTMLButtonElement>,\n triggerSlot?: ExtractSlotProps<Slot<'button'>>,\n listboxSlot?: ExtractSlotProps<Slot<typeof Listbox>>,\n): [trigger: ExtractSlotProps<Slot<'button'>>, listbox?: ExtractSlotProps<Slot<typeof Listbox>>];\nexport function useTriggerListboxSlots(\n props: ComboboxBaseProps,\n state: ComboboxBaseState,\n ref: React.Ref<HTMLInputElement>,\n triggerSlot?: ExtractSlotProps<Slot<'input'>>,\n listboxSlot?: ExtractSlotProps<Slot<typeof Listbox>>,\n): [trigger: ExtractSlotProps<Slot<'input'>>, listbox?: ExtractSlotProps<Slot<typeof Listbox>>];\n\n/*\n * useTriggerListboxSlots returns a tuple of trigger/listbox shorthand,\n * with the semantics and event handlers needed for the Combobox and Dropdown components.\n * The element type of the ref should always match the element type used in the trigger shorthand.\n */\nexport function useTriggerListboxSlots(\n props: ComboboxBaseProps,\n state: ComboboxBaseState,\n ref: React.Ref<HTMLButtonElement | HTMLInputElement>,\n triggerSlot?: ExtractSlotProps<Slot<'input'>> | ExtractSlotProps<Slot<'button'>>,\n listboxSlot?: ExtractSlotProps<Slot<typeof Listbox>>,\n): [\n trigger: ExtractSlotProps<Slot<'input'>> | ExtractSlotProps<Slot<'button'>>,\n listbox?: ExtractSlotProps<Slot<typeof Listbox>>,\n] {\n const { multiselect } = props;\n const {\n activeOption,\n getCount,\n getIndexOfId,\n getOptionAtIndex,\n ignoreNextBlur,\n open,\n selectOption,\n setActiveOption,\n setFocusVisible,\n setHasFocus,\n setOpen,\n } = state;\n\n // handle trigger focus/blur\n const triggerRef: typeof ref = React.useRef(null);\n\n // resolve listbox shorthand props\n const listbox: typeof listboxSlot = listboxSlot && {\n multiselect,\n tabIndex: undefined,\n ...listboxSlot,\n };\n\n // resolve trigger shorthand props\n const trigger: typeof triggerSlot = {\n 'aria-expanded': open,\n 'aria-activedescendant': open ? activeOption?.id : undefined,\n role: 'combobox',\n ...triggerSlot,\n // explicitly type the ref as an intersection here to prevent type errors\n // since the `children` prop has mutually incompatible types between input/button\n // functionally both ref and triggerRef will always be the same element type\n ref: useMergedRefs(ref, triggerSlot?.ref, triggerRef) as React.Ref<HTMLButtonElement & HTMLInputElement>,\n };\n\n // listbox is nullable, only add event handlers if it exists\n if (listbox) {\n /*\n * Handle focus when clicking the listbox popup:\n * 1. Move focus back to the button/input when the listbox is clicked (otherwise it goes to body)\n * 2. Do not close the listbox on button/input blur when clicking into the listbox\n */\n listbox.onClick = mergeCallbacks((event: React.MouseEvent<HTMLDivElement>) => {\n triggerRef.current?.focus();\n }, listbox.onClick);\n\n listbox.onMouseOver = mergeCallbacks((event: React.MouseEvent<HTMLDivElement>) => {\n setFocusVisible(false);\n }, listbox.onMouseOver);\n\n listbox.onMouseDown = mergeCallbacks((event: React.MouseEvent<HTMLDivElement>) => {\n ignoreNextBlur.current = true;\n }, listbox.onMouseDown);\n }\n\n // the trigger should open/close the popup on click or blur\n trigger.onBlur = mergeCallbacks((event: React.FocusEvent<HTMLButtonElement> & React.FocusEvent<HTMLInputElement>) => {\n if (!ignoreNextBlur.current) {\n setOpen(event, false);\n }\n\n ignoreNextBlur.current = false;\n\n setHasFocus(false);\n }, trigger.onBlur);\n\n trigger.onClick = mergeCallbacks(\n (event: React.MouseEvent<HTMLButtonElement> & React.MouseEvent<HTMLInputElement>) => {\n setOpen(event, !open);\n },\n trigger.onClick,\n );\n\n trigger.onFocus = mergeCallbacks(\n (event: React.FocusEvent<HTMLButtonElement> & React.FocusEvent<HTMLInputElement>) => {\n setHasFocus(true);\n },\n trigger.onFocus,\n );\n\n // handle combobox keyboard interaction\n trigger.onKeyDown = mergeCallbacks(\n (event: React.KeyboardEvent<HTMLButtonElement> & React.KeyboardEvent<HTMLInputElement>) => {\n const action = getDropdownActionFromKey(event, { open, multiselect });\n const maxIndex = getCount() - 1;\n const activeIndex = activeOption ? getIndexOfId(activeOption.id) : -1;\n let newIndex = activeIndex;\n\n switch (action) {\n case 'Open':\n event.preventDefault();\n setFocusVisible(true);\n setOpen(event, true);\n break;\n case 'Close':\n // stop propagation for escape key to avoid dismissing any parent popups\n event.stopPropagation();\n event.preventDefault();\n setOpen(event, false);\n break;\n case 'CloseSelect':\n !multiselect && !activeOption?.disabled && setOpen(event, false);\n // fallthrough\n case 'Select':\n activeOption && selectOption(event, activeOption);\n event.preventDefault();\n break;\n case 'Tab':\n !multiselect && activeOption && selectOption(event, activeOption);\n break;\n default:\n newIndex = getIndexFromAction(action, activeIndex, maxIndex);\n }\n if (newIndex !== activeIndex) {\n // prevent default page scroll/keyboard action if the index changed\n event.preventDefault();\n setActiveOption(getOptionAtIndex(newIndex));\n setFocusVisible(true);\n }\n },\n trigger.onKeyDown,\n );\n\n trigger.onMouseOver = mergeCallbacks(\n (event: React.MouseEvent<HTMLButtonElement> & React.MouseEvent<HTMLInputElement>) => {\n setFocusVisible(false);\n },\n trigger.onMouseOver,\n );\n\n return [trigger, listbox];\n}\n"]}
|
|
1
|
+
{"version":3,"mappings":"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","names":["React","mergeCallbacks","useEventCallback","useMergedRefs","getDropdownActionFromKey","getIndexFromAction","useTriggerListboxSlots","props","state","ref","triggerSlot","listboxSlot","multiselect","activeOption","getCount","getIndexOfId","getOptionAtIndex","ignoreNextBlur","open","selectOption","setActiveOption","setFocusVisible","setHasFocus","setOpen","triggerRef","useRef","listbox","tabIndex","undefined","trigger","id","role","listboxOnClick","event","current","focus","onClick","listboxOnMouseOver","onMouseOver","listboxOnMouseDown","onMouseDown","onBlur","onFocus","onKeyDown","action","maxIndex","activeIndex","newIndex","preventDefault","stopPropagation","disabled"],"sourceRoot":"../src/","sources":["packages/react-components/react-combobox/src/utils/useTriggerListboxSlots.ts"],"sourcesContent":["import * as React from 'react';\nimport { mergeCallbacks, useEventCallback, useMergedRefs } from '@fluentui/react-utilities';\nimport type { ExtractSlotProps, Slot } from '@fluentui/react-utilities';\nimport { getDropdownActionFromKey, getIndexFromAction } from '../utils/dropdownKeyActions';\nimport { Listbox } from '../components/Listbox/Listbox';\nimport type { ComboboxBaseProps, ComboboxBaseState } from './ComboboxBase.types';\n\nexport function useTriggerListboxSlots(\n props: ComboboxBaseProps,\n state: ComboboxBaseState,\n ref: React.Ref<HTMLButtonElement>,\n triggerSlot?: ExtractSlotProps<Slot<'button'>>,\n listboxSlot?: ExtractSlotProps<Slot<typeof Listbox>>,\n): [trigger: ExtractSlotProps<Slot<'button'>>, listbox?: ExtractSlotProps<Slot<typeof Listbox>>];\nexport function useTriggerListboxSlots(\n props: ComboboxBaseProps,\n state: ComboboxBaseState,\n ref: React.Ref<HTMLInputElement>,\n triggerSlot?: ExtractSlotProps<Slot<'input'>>,\n listboxSlot?: ExtractSlotProps<Slot<typeof Listbox>>,\n): [trigger: ExtractSlotProps<Slot<'input'>>, listbox?: ExtractSlotProps<Slot<typeof Listbox>>];\n\n/*\n * useTriggerListboxSlots returns a tuple of trigger/listbox shorthand,\n * with the semantics and event handlers needed for the Combobox and Dropdown components.\n * The element type of the ref should always match the element type used in the trigger shorthand.\n */\nexport function useTriggerListboxSlots(\n props: ComboboxBaseProps,\n state: ComboboxBaseState,\n ref: React.Ref<HTMLButtonElement | HTMLInputElement>,\n triggerSlot?: ExtractSlotProps<Slot<'input'>> | ExtractSlotProps<Slot<'button'>>,\n listboxSlot?: ExtractSlotProps<Slot<typeof Listbox>>,\n): [\n trigger: ExtractSlotProps<Slot<'input'>> | ExtractSlotProps<Slot<'button'>>,\n listbox?: ExtractSlotProps<Slot<typeof Listbox>>,\n] {\n const { multiselect } = props;\n const {\n activeOption,\n getCount,\n getIndexOfId,\n getOptionAtIndex,\n ignoreNextBlur,\n open,\n selectOption,\n setActiveOption,\n setFocusVisible,\n setHasFocus,\n setOpen,\n } = state;\n\n // handle trigger focus/blur\n const triggerRef: typeof ref = React.useRef(null);\n\n // resolve listbox shorthand props\n const listbox: typeof listboxSlot = listboxSlot && {\n multiselect,\n tabIndex: undefined,\n ...listboxSlot,\n };\n\n // resolve trigger shorthand props\n const trigger: typeof triggerSlot = {\n 'aria-expanded': open,\n 'aria-activedescendant': open ? activeOption?.id : undefined,\n role: 'combobox',\n ...triggerSlot,\n // explicitly type the ref as an intersection here to prevent type errors\n // since the `children` prop has mutually incompatible types between input/button\n // functionally both ref and triggerRef will always be the same element type\n ref: useMergedRefs(ref, triggerSlot?.ref, triggerRef) as React.Ref<HTMLButtonElement & HTMLInputElement>,\n };\n\n /*\n * Handle focus when clicking the listbox popup:\n * 1. Move focus back to the button/input when the listbox is clicked (otherwise it goes to body)\n * 2. Do not close the listbox on button/input blur when clicking into the listbox\n */\n const listboxOnClick = useEventCallback(\n mergeCallbacks((event: React.MouseEvent<HTMLDivElement>) => {\n triggerRef.current?.focus();\n }, listbox?.onClick),\n );\n\n const listboxOnMouseOver = useEventCallback(\n mergeCallbacks((event: React.MouseEvent<HTMLDivElement>) => {\n setFocusVisible(false);\n }, listbox?.onMouseOver),\n );\n\n const listboxOnMouseDown = useEventCallback(\n mergeCallbacks((event: React.MouseEvent<HTMLDivElement>) => {\n ignoreNextBlur.current = true;\n }, listbox?.onMouseDown),\n );\n\n // listbox is nullable, only add event handlers if it exists\n if (listbox) {\n listbox.onClick = listboxOnClick;\n listbox.onMouseOver = listboxOnMouseOver;\n listbox.onMouseDown = listboxOnMouseDown;\n }\n\n // the trigger should open/close the popup on click or blur\n trigger.onBlur = mergeCallbacks((event: React.FocusEvent<HTMLButtonElement> & React.FocusEvent<HTMLInputElement>) => {\n if (!ignoreNextBlur.current) {\n setOpen(event, false);\n }\n\n ignoreNextBlur.current = false;\n\n setHasFocus(false);\n }, trigger.onBlur);\n\n trigger.onClick = mergeCallbacks(\n (event: React.MouseEvent<HTMLButtonElement> & React.MouseEvent<HTMLInputElement>) => {\n setOpen(event, !open);\n },\n trigger.onClick,\n );\n\n trigger.onFocus = mergeCallbacks(\n (event: React.FocusEvent<HTMLButtonElement> & React.FocusEvent<HTMLInputElement>) => {\n setHasFocus(true);\n },\n trigger.onFocus,\n );\n\n // handle combobox keyboard interaction\n trigger.onKeyDown = mergeCallbacks(\n (event: React.KeyboardEvent<HTMLButtonElement> & React.KeyboardEvent<HTMLInputElement>) => {\n const action = getDropdownActionFromKey(event, { open, multiselect });\n const maxIndex = getCount() - 1;\n const activeIndex = activeOption ? getIndexOfId(activeOption.id) : -1;\n let newIndex = activeIndex;\n\n switch (action) {\n case 'Open':\n event.preventDefault();\n setFocusVisible(true);\n setOpen(event, true);\n break;\n case 'Close':\n // stop propagation for escape key to avoid dismissing any parent popups\n event.stopPropagation();\n event.preventDefault();\n setOpen(event, false);\n break;\n case 'CloseSelect':\n !multiselect && !activeOption?.disabled && setOpen(event, false);\n // fallthrough\n case 'Select':\n activeOption && selectOption(event, activeOption);\n event.preventDefault();\n break;\n case 'Tab':\n !multiselect && activeOption && selectOption(event, activeOption);\n break;\n default:\n newIndex = getIndexFromAction(action, activeIndex, maxIndex);\n }\n if (newIndex !== activeIndex) {\n // prevent default page scroll/keyboard action if the index changed\n event.preventDefault();\n setActiveOption(getOptionAtIndex(newIndex));\n setFocusVisible(true);\n }\n },\n trigger.onKeyDown,\n );\n\n trigger.onMouseOver = mergeCallbacks(\n (event: React.MouseEvent<HTMLButtonElement> & React.MouseEvent<HTMLInputElement>) => {\n setFocusVisible(false);\n },\n trigger.onMouseOver,\n );\n\n return [trigger, listbox];\n}\n"]}
|
|
@@ -57,12 +57,19 @@ const useCombobox_unstable = (props, ref) => {
|
|
|
57
57
|
const rootRef = React.useRef(null);
|
|
58
58
|
const triggerRef = React.useRef(null);
|
|
59
59
|
// calculate listbox width style based on trigger width
|
|
60
|
-
const [
|
|
60
|
+
const [popupDimensions, setPopupDimensions] = React.useState();
|
|
61
61
|
React.useEffect(() => {
|
|
62
62
|
var _a;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
// only recalculate width when opening
|
|
64
|
+
if (open) {
|
|
65
|
+
const width = `${(_a = rootRef.current) === null || _a === void 0 ? void 0 : _a.clientWidth}px`;
|
|
66
|
+
if (width !== (popupDimensions === null || popupDimensions === void 0 ? void 0 : popupDimensions.width)) {
|
|
67
|
+
setPopupDimensions({
|
|
68
|
+
width
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}, [open, popupDimensions]);
|
|
66
73
|
// set active option and selection based on typing
|
|
67
74
|
const getOptionFromInput = inputValue => {
|
|
68
75
|
var _a;
|
|
@@ -143,9 +150,7 @@ const useCombobox_unstable = (props, ref) => {
|
|
|
143
150
|
required: true,
|
|
144
151
|
defaultProps: {
|
|
145
152
|
children: props.children,
|
|
146
|
-
style:
|
|
147
|
-
width: popupWidth
|
|
148
|
-
}
|
|
153
|
+
style: popupDimensions
|
|
149
154
|
}
|
|
150
155
|
}) : undefined;
|
|
151
156
|
[triggerSlot, listboxSlot] = useComboboxPopup_1.useComboboxPopup(props, triggerSlot, listboxSlot);
|
|
@@ -191,6 +196,8 @@ const useCombobox_unstable = (props, ref) => {
|
|
|
191
196
|
// open and set focus
|
|
192
197
|
state.setOpen(event, !state.open);
|
|
193
198
|
(_a = triggerRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
199
|
+
// set focus visible=false, since this can only be done with the mouse/pointer
|
|
200
|
+
setFocusVisible(false);
|
|
194
201
|
}));
|
|
195
202
|
if (state.expandIcon) {
|
|
196
203
|
state.expandIcon.onMouseDown = onExpandIconMouseDown;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"mappings":"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","names":["useCombobox_unstable","props","ref","baseState","useComboboxBaseState_1","editable","activeOption","clearSelection","getIndexOfId","getOptionsMatchingText","hasFocus","open","selectOption","selectedOptions","setActiveOption","setFocusVisible","setOpen","setValue","value","freeform","multiselect","primary","triggerNativeProps","root","rootNativeProps","react_utilities_1","primarySlotTagName","excludedPropNames","rootRef","React","useRef","triggerRef","popupWidth","setPopupWidth","useState","useEffect","width","current","clientWidth","undefined","getOptionFromInput","inputValue","searchString","trim","toLowerCase","length","matcher","optionText","indexOf","matches","startIndex","id","nextMatch","find","option","ev","onTriggerBlur","newState","onTriggerChange","target","matchingOption","onTriggerKeyDown","dropdownKeyActions_1","triggerSlot","listboxSlot","input","required","defaultProps","type","onChange","onBlur","onKeyDown","listbox","children","style","useComboboxPopup_1","useTriggerListboxSlots_1","state","components","expandIcon","Listbox_1","react_icons_1","onMouseDown","onIconMouseDown","onClick","onIconClick","onExpandIconMouseDown","ignoreNextBlur","onExpandIconClick","event","focus","exports"],"sourceRoot":"../src/","sources":["packages/react-components/react-combobox/src/components/Combobox/useCombobox.tsx"],"sourcesContent":["import * as React from 'react';\nimport { ChevronDownRegular as ChevronDownIcon } from '@fluentui/react-icons';\nimport {\n getPartitionedNativeProps,\n resolveShorthand,\n mergeCallbacks,\n useEventCallback,\n useMergedRefs,\n} from '@fluentui/react-utilities';\nimport { getDropdownActionFromKey } from '../../utils/dropdownKeyActions';\nimport { useComboboxBaseState } from '../../utils/useComboboxBaseState';\nimport { useComboboxPopup } from '../../utils/useComboboxPopup';\nimport { useTriggerListboxSlots } from '../../utils/useTriggerListboxSlots';\nimport { Listbox } from '../Listbox/Listbox';\nimport type { Slot } from '@fluentui/react-utilities';\nimport type { SelectionEvents } from '../../utils/Selection.types';\nimport type { OptionValue } from '../../utils/OptionCollection.types';\nimport type { ComboboxProps, ComboboxState } from './Combobox.types';\n\n/**\n * Create the state required to render Combobox.\n *\n * The returned state can be modified with hooks such as useComboboxStyles_unstable,\n * before being passed to renderCombobox_unstable.\n *\n * @param props - props from this instance of Combobox\n * @param ref - reference to root HTMLElement of Combobox\n */\nexport const useCombobox_unstable = (props: ComboboxProps, ref: React.Ref<HTMLInputElement>): ComboboxState => {\n const baseState = useComboboxBaseState({ ...props, editable: true });\n const {\n activeOption,\n clearSelection,\n getIndexOfId,\n getOptionsMatchingText,\n hasFocus,\n open,\n selectOption,\n selectedOptions,\n setActiveOption,\n setFocusVisible,\n setOpen,\n setValue,\n value,\n } = baseState;\n const { freeform, multiselect } = props;\n\n const { primary: triggerNativeProps, root: rootNativeProps } = getPartitionedNativeProps({\n props,\n primarySlotTagName: 'input',\n excludedPropNames: ['children', 'size'],\n });\n\n const rootRef = React.useRef<HTMLDivElement>(null);\n const triggerRef = React.useRef<HTMLInputElement>(null);\n\n // calculate listbox width style based on trigger width\n const [popupWidth, setPopupWidth] = React.useState<string>();\n React.useEffect(() => {\n const width = open ? `${rootRef.current?.clientWidth}px` : undefined;\n setPopupWidth(width);\n }, [open]);\n\n // set active option and selection based on typing\n const getOptionFromInput = (inputValue: string): OptionValue | undefined => {\n const searchString = inputValue?.trim().toLowerCase();\n\n if (!searchString || searchString.length === 0) {\n return;\n }\n\n const matcher = (optionText: string) => optionText.toLowerCase().indexOf(searchString) === 0;\n const matches = getOptionsMatchingText(matcher);\n\n // return first matching option after the current active option, looping back to the top\n if (matches.length > 1 && activeOption) {\n const startIndex = getIndexOfId(activeOption.id);\n const nextMatch = matches.find(option => getIndexOfId(option.id) >= startIndex);\n return nextMatch ?? matches[0];\n }\n\n return matches[0] ?? undefined;\n };\n\n /* Handle typed input */\n\n // reset any typed value when an option is selected\n baseState.selectOption = (ev: SelectionEvents, option: OptionValue) => {\n setValue(undefined);\n selectOption(ev, option);\n };\n\n const onTriggerBlur = (ev: React.FocusEvent<HTMLInputElement>) => {\n // handle selection and updating value if freeform is false\n if (!baseState.open && !freeform) {\n // select matching option, if the value fully matches\n if (value && activeOption && value.trim().toLowerCase() === activeOption?.value.toLowerCase()) {\n baseState.selectOption(ev, activeOption);\n }\n\n // reset typed value when the input loses focus while collapsed, unless freeform is true\n setValue(undefined);\n }\n };\n\n baseState.setOpen = (ev, newState: boolean) => {\n if (!newState && !freeform) {\n setValue(undefined);\n }\n\n setOpen(ev, newState);\n };\n\n // update value and active option based on input\n const onTriggerChange = (ev: React.ChangeEvent<HTMLInputElement>) => {\n const inputValue = ev.target.value;\n // update uncontrolled value\n baseState.setValue(inputValue);\n\n // handle updating active option based on input\n const matchingOption = getOptionFromInput(inputValue);\n setActiveOption(matchingOption);\n\n setFocusVisible(true);\n\n // clear selection for single-select if the input value no longer matches the selection\n if (\n !multiselect &&\n selectedOptions.length === 1 &&\n (inputValue.length < 1 || selectedOptions[0].indexOf(inputValue) !== 0)\n ) {\n clearSelection(ev);\n }\n };\n\n // open Combobox when typing\n const onTriggerKeyDown = (ev: React.KeyboardEvent<HTMLInputElement>) => {\n if (!open && getDropdownActionFromKey(ev) === 'Type') {\n setOpen(ev, true);\n }\n };\n\n // resolve input and listbox slot props\n let triggerSlot: Slot<'input'>;\n let listboxSlot: Slot<typeof Listbox> | undefined;\n\n triggerSlot = resolveShorthand(props.input, {\n required: true,\n defaultProps: {\n ref: useMergedRefs(props.input?.ref, triggerRef),\n type: 'text',\n value: value ?? '',\n ...triggerNativeProps,\n },\n });\n\n triggerSlot.onChange = mergeCallbacks(triggerSlot.onChange, onTriggerChange);\n triggerSlot.onBlur = mergeCallbacks(triggerSlot.onBlur, onTriggerBlur);\n triggerSlot.onKeyDown = mergeCallbacks(triggerSlot.onKeyDown, onTriggerKeyDown);\n\n // only resolve listbox slot if needed\n listboxSlot =\n open || hasFocus\n ? resolveShorthand(props.listbox, {\n required: true,\n defaultProps: {\n children: props.children,\n style: { width: popupWidth },\n },\n })\n : undefined;\n\n [triggerSlot, listboxSlot] = useComboboxPopup(props, triggerSlot, listboxSlot);\n [triggerSlot, listboxSlot] = useTriggerListboxSlots(props, baseState, ref, triggerSlot, listboxSlot);\n\n const state: ComboboxState = {\n components: {\n root: 'div',\n input: 'input',\n expandIcon: 'span',\n listbox: Listbox,\n },\n root: resolveShorthand(props.root, {\n required: true,\n defaultProps: {\n ...rootNativeProps,\n },\n }),\n input: triggerSlot,\n listbox: listboxSlot,\n expandIcon: resolveShorthand(props.expandIcon, {\n required: true,\n defaultProps: {\n children: <ChevronDownIcon />,\n },\n }),\n ...baseState,\n setOpen,\n };\n\n state.root.ref = useMergedRefs(state.root.ref, rootRef);\n\n /* handle open/close + focus change when clicking expandIcon */\n const { onMouseDown: onIconMouseDown, onClick: onIconClick } = state.expandIcon || {};\n const onExpandIconMouseDown = useEventCallback(\n mergeCallbacks(onIconMouseDown, () => {\n // do not dismiss on blur when closing via clicking the icon\n if (open) {\n baseState.ignoreNextBlur.current = true;\n }\n }),\n );\n\n const onExpandIconClick = useEventCallback(\n mergeCallbacks(onIconClick, (event: React.MouseEvent<HTMLSpanElement>) => {\n // open and set focus\n state.setOpen(event, !state.open);\n triggerRef.current?.focus();\n }),\n );\n\n if (state.expandIcon) {\n state.expandIcon.onMouseDown = onExpandIconMouseDown;\n state.expandIcon.onClick = onExpandIconClick;\n }\n\n return state;\n};\n"]}
|
|
1
|
+
{"version":3,"mappings":"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","names":["useCombobox_unstable","props","ref","baseState","useComboboxBaseState_1","editable","activeOption","clearSelection","getIndexOfId","getOptionsMatchingText","hasFocus","open","selectOption","selectedOptions","setActiveOption","setFocusVisible","setOpen","setValue","value","freeform","multiselect","primary","triggerNativeProps","root","rootNativeProps","react_utilities_1","primarySlotTagName","excludedPropNames","rootRef","React","useRef","triggerRef","popupDimensions","setPopupDimensions","useState","useEffect","width","current","clientWidth","getOptionFromInput","inputValue","searchString","trim","toLowerCase","length","matcher","optionText","indexOf","matches","startIndex","id","nextMatch","find","option","undefined","ev","onTriggerBlur","newState","onTriggerChange","target","matchingOption","onTriggerKeyDown","dropdownKeyActions_1","triggerSlot","listboxSlot","input","required","defaultProps","type","onChange","onBlur","onKeyDown","listbox","children","style","useComboboxPopup_1","useTriggerListboxSlots_1","state","components","expandIcon","Listbox_1","react_icons_1","onMouseDown","onIconMouseDown","onClick","onIconClick","onExpandIconMouseDown","ignoreNextBlur","onExpandIconClick","event","focus","exports"],"sourceRoot":"../src/","sources":["packages/react-components/react-combobox/src/components/Combobox/useCombobox.tsx"],"sourcesContent":["import * as React from 'react';\nimport { ChevronDownRegular as ChevronDownIcon } from '@fluentui/react-icons';\nimport {\n getPartitionedNativeProps,\n resolveShorthand,\n mergeCallbacks,\n useEventCallback,\n useMergedRefs,\n} from '@fluentui/react-utilities';\nimport { getDropdownActionFromKey } from '../../utils/dropdownKeyActions';\nimport { useComboboxBaseState } from '../../utils/useComboboxBaseState';\nimport { useComboboxPopup } from '../../utils/useComboboxPopup';\nimport { useTriggerListboxSlots } from '../../utils/useTriggerListboxSlots';\nimport { Listbox } from '../Listbox/Listbox';\nimport type { Slot } from '@fluentui/react-utilities';\nimport type { SelectionEvents } from '../../utils/Selection.types';\nimport type { OptionValue } from '../../utils/OptionCollection.types';\nimport type { ComboboxProps, ComboboxState } from './Combobox.types';\n\n/**\n * Create the state required to render Combobox.\n *\n * The returned state can be modified with hooks such as useComboboxStyles_unstable,\n * before being passed to renderCombobox_unstable.\n *\n * @param props - props from this instance of Combobox\n * @param ref - reference to root HTMLElement of Combobox\n */\nexport const useCombobox_unstable = (props: ComboboxProps, ref: React.Ref<HTMLInputElement>): ComboboxState => {\n const baseState = useComboboxBaseState({ ...props, editable: true });\n const {\n activeOption,\n clearSelection,\n getIndexOfId,\n getOptionsMatchingText,\n hasFocus,\n open,\n selectOption,\n selectedOptions,\n setActiveOption,\n setFocusVisible,\n setOpen,\n setValue,\n value,\n } = baseState;\n const { freeform, multiselect } = props;\n\n const { primary: triggerNativeProps, root: rootNativeProps } = getPartitionedNativeProps({\n props,\n primarySlotTagName: 'input',\n excludedPropNames: ['children', 'size'],\n });\n\n const rootRef = React.useRef<HTMLDivElement>(null);\n const triggerRef = React.useRef<HTMLInputElement>(null);\n\n // calculate listbox width style based on trigger width\n const [popupDimensions, setPopupDimensions] = React.useState<{ width: string }>();\n React.useEffect(() => {\n // only recalculate width when opening\n if (open) {\n const width = `${rootRef.current?.clientWidth}px`;\n if (width !== popupDimensions?.width) {\n setPopupDimensions({ width });\n }\n }\n }, [open, popupDimensions]);\n\n // set active option and selection based on typing\n const getOptionFromInput = (inputValue: string): OptionValue | undefined => {\n const searchString = inputValue?.trim().toLowerCase();\n\n if (!searchString || searchString.length === 0) {\n return;\n }\n\n const matcher = (optionText: string) => optionText.toLowerCase().indexOf(searchString) === 0;\n const matches = getOptionsMatchingText(matcher);\n\n // return first matching option after the current active option, looping back to the top\n if (matches.length > 1 && activeOption) {\n const startIndex = getIndexOfId(activeOption.id);\n const nextMatch = matches.find(option => getIndexOfId(option.id) >= startIndex);\n return nextMatch ?? matches[0];\n }\n\n return matches[0] ?? undefined;\n };\n\n /* Handle typed input */\n\n // reset any typed value when an option is selected\n baseState.selectOption = (ev: SelectionEvents, option: OptionValue) => {\n setValue(undefined);\n selectOption(ev, option);\n };\n\n const onTriggerBlur = (ev: React.FocusEvent<HTMLInputElement>) => {\n // handle selection and updating value if freeform is false\n if (!baseState.open && !freeform) {\n // select matching option, if the value fully matches\n if (value && activeOption && value.trim().toLowerCase() === activeOption?.value.toLowerCase()) {\n baseState.selectOption(ev, activeOption);\n }\n\n // reset typed value when the input loses focus while collapsed, unless freeform is true\n setValue(undefined);\n }\n };\n\n baseState.setOpen = (ev, newState: boolean) => {\n if (!newState && !freeform) {\n setValue(undefined);\n }\n\n setOpen(ev, newState);\n };\n\n // update value and active option based on input\n const onTriggerChange = (ev: React.ChangeEvent<HTMLInputElement>) => {\n const inputValue = ev.target.value;\n // update uncontrolled value\n baseState.setValue(inputValue);\n\n // handle updating active option based on input\n const matchingOption = getOptionFromInput(inputValue);\n setActiveOption(matchingOption);\n\n setFocusVisible(true);\n\n // clear selection for single-select if the input value no longer matches the selection\n if (\n !multiselect &&\n selectedOptions.length === 1 &&\n (inputValue.length < 1 || selectedOptions[0].indexOf(inputValue) !== 0)\n ) {\n clearSelection(ev);\n }\n };\n\n // open Combobox when typing\n const onTriggerKeyDown = (ev: React.KeyboardEvent<HTMLInputElement>) => {\n if (!open && getDropdownActionFromKey(ev) === 'Type') {\n setOpen(ev, true);\n }\n };\n\n // resolve input and listbox slot props\n let triggerSlot: Slot<'input'>;\n let listboxSlot: Slot<typeof Listbox> | undefined;\n\n triggerSlot = resolveShorthand(props.input, {\n required: true,\n defaultProps: {\n ref: useMergedRefs(props.input?.ref, triggerRef),\n type: 'text',\n value: value ?? '',\n ...triggerNativeProps,\n },\n });\n\n triggerSlot.onChange = mergeCallbacks(triggerSlot.onChange, onTriggerChange);\n triggerSlot.onBlur = mergeCallbacks(triggerSlot.onBlur, onTriggerBlur);\n triggerSlot.onKeyDown = mergeCallbacks(triggerSlot.onKeyDown, onTriggerKeyDown);\n\n // only resolve listbox slot if needed\n listboxSlot =\n open || hasFocus\n ? resolveShorthand(props.listbox, {\n required: true,\n defaultProps: {\n children: props.children,\n style: popupDimensions,\n },\n })\n : undefined;\n\n [triggerSlot, listboxSlot] = useComboboxPopup(props, triggerSlot, listboxSlot);\n [triggerSlot, listboxSlot] = useTriggerListboxSlots(props, baseState, ref, triggerSlot, listboxSlot);\n\n const state: ComboboxState = {\n components: {\n root: 'div',\n input: 'input',\n expandIcon: 'span',\n listbox: Listbox,\n },\n root: resolveShorthand(props.root, {\n required: true,\n defaultProps: {\n ...rootNativeProps,\n },\n }),\n input: triggerSlot,\n listbox: listboxSlot,\n expandIcon: resolveShorthand(props.expandIcon, {\n required: true,\n defaultProps: {\n children: <ChevronDownIcon />,\n },\n }),\n ...baseState,\n setOpen,\n };\n\n state.root.ref = useMergedRefs(state.root.ref, rootRef);\n\n /* handle open/close + focus change when clicking expandIcon */\n const { onMouseDown: onIconMouseDown, onClick: onIconClick } = state.expandIcon || {};\n const onExpandIconMouseDown = useEventCallback(\n mergeCallbacks(onIconMouseDown, () => {\n // do not dismiss on blur when closing via clicking the icon\n if (open) {\n baseState.ignoreNextBlur.current = true;\n }\n }),\n );\n\n const onExpandIconClick = useEventCallback(\n mergeCallbacks(onIconClick, (event: React.MouseEvent<HTMLSpanElement>) => {\n // open and set focus\n state.setOpen(event, !state.open);\n triggerRef.current?.focus();\n\n // set focus visible=false, since this can only be done with the mouse/pointer\n setFocusVisible(false);\n }),\n );\n\n if (state.expandIcon) {\n state.expandIcon.onMouseDown = onExpandIconMouseDown;\n state.expandIcon.onClick = onExpandIconClick;\n }\n\n return state;\n};\n"]}
|
|
@@ -63,19 +63,19 @@ const useComboboxBaseState = props => {
|
|
|
63
63
|
defaultState: props.defaultOpen,
|
|
64
64
|
initialState: false
|
|
65
65
|
});
|
|
66
|
-
const setOpen = (event, newState) => {
|
|
66
|
+
const setOpen = React.useCallback((event, newState) => {
|
|
67
67
|
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(event, {
|
|
68
68
|
open: newState
|
|
69
69
|
});
|
|
70
70
|
setOpenState(newState);
|
|
71
|
-
};
|
|
71
|
+
}, [onOpenChange, setOpenState]);
|
|
72
72
|
// update active option based on change in open state
|
|
73
73
|
React.useEffect(() => {
|
|
74
74
|
if (open && !activeOption) {
|
|
75
|
-
// if there is a
|
|
76
|
-
if (selectedOptions.length > 0) {
|
|
77
|
-
const
|
|
78
|
-
|
|
75
|
+
// if it is single-select and there is a selected option, start at the selected option
|
|
76
|
+
if (!multiselect && selectedOptions.length > 0) {
|
|
77
|
+
const selectedOption = getOptionsMatchingText(v => v === selectedOptions[0]).pop();
|
|
78
|
+
selectedOption && setActiveOption(selectedOption);
|
|
79
79
|
}
|
|
80
80
|
// default to starting at the first option
|
|
81
81
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"mappings":";;;;;;AAAA;AACA;AACA;AAEA;AAGA;;;AAGO,MAAMA,oBAAoB,GAAIC,KAAiD,IAAuB;EAC3G,MAAM;IACJC,UAAU,GAAG,SAAS;IACtBC,QAAQ,GAAG,KAAK;IAChBC,WAAW,GAAG,KAAK;IACnBC,WAAW;IACXC,YAAY;IACZC,IAAI,GAAG;EAAQ,CAChB,GAAGN,KAAK;EAET,MAAMO,gBAAgB,GAAGC,yCAAmB,EAAE;EAC9C,MAAM;IAAEC,gBAAgB;IAAEC;EAAsB,CAAE,GAAGH,gBAAgB;EAErE,MAAM,CAACI,YAAY,EAAEC,eAAe,CAAC,GAAGC,KAAK,CAACC,QAAQ,EAA2B;EAEjF;EACA;EACA,MAAM,CAACC,YAAY,EAAEC,eAAe,CAAC,GAAGH,KAAK,CAACC,QAAQ,CAAC,KAAK,CAAC;EAE7D;EACA,MAAM,CAACG,QAAQ,EAAEC,WAAW,CAAC,GAAGL,KAAK,CAACC,QAAQ,CAAC,KAAK,CAAC;EAErD,MAAMK,cAAc,GAAGN,KAAK,CAACO,MAAM,CAAC,KAAK,CAAC;EAE1C,MAAMC,cAAc,GAAGC,2BAAY,CAACtB,KAAK,CAAC;EAC1C,MAAM;IAAEuB;EAAe,CAAE,GAAGF,cAAc;EAE1C;EACA,MAAMG,YAAY,GAAGC,+BAAa,EAAE;EACpC,MAAM,CAACC,iBAAiB,EAAEC,QAAQ,CAAC,GAAGF,sCAAoB,CAAC;IACzDG,KAAK,EAAE5B,KAAK,CAAC6B,KAAK;IAClBC,YAAY,EAAEC;GACf,CAAC;EAEF,MAAMF,KAAK,GAAGhB,KAAK,CAACmB,OAAO,CAAC,MAAK;IAC/B;IACA,IAAIN,iBAAiB,KAAKK,SAAS,EAAE;MACnC,OAAOL,iBAAiB;;IAG1B;IACA,IAAIF,YAAY,IAAIxB,KAAK,CAACiC,YAAY,KAAKF,SAAS,EAAE;MACpD,OAAO/B,KAAK,CAACiC,YAAY;;IAG3B,IAAI7B,WAAW,EAAE;MACf;MACA,OAAOF,QAAQ,GAAG,EAAE,GAAGqB,eAAe,CAACW,IAAI,CAAC,IAAI,CAAC;;IAGnD,OAAOX,eAAe,CAAC,CAAC,CAAC;EAC3B,CAAC,EAAE,CAACG,iBAAiB,EAAExB,QAAQ,EAAEsB,YAAY,EAAEpB,WAAW,EAAEJ,KAAK,CAACiC,YAAY,EAAEV,eAAe,CAAC,CAAC;EAEjG;EACA,MAAM,CAACY,IAAI,EAAEC,YAAY,CAAC,GAAGX,sCAAoB,CAAC;IAChDG,KAAK,EAAE5B,KAAK,CAACmC,IAAI;IACjBE,YAAY,EAAErC,KAAK,CAACsC,WAAW;IAC/BR,YAAY,EAAE;GACf,CAAC;EAEF,MAAMS,OAAO,
|
|
1
|
+
{"version":3,"mappings":"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","names":["useComboboxBaseState","props","appearance","editable","inlinePopup","multiselect","onOpenChange","size","optionCollection","useOptionCollection_1","getOptionAtIndex","getOptionsMatchingText","activeOption","setActiveOption","React","useState","focusVisible","setFocusVisible","hasFocus","setHasFocus","ignoreNextBlur","useRef","selectionState","useSelection_1","selectedOptions","isFirstMount","react_utilities_1","controllableValue","setValue","state","value","initialState","undefined","useMemo","defaultValue","join","open","setOpenState","defaultState","defaultOpen","setOpen","useCallback","event","newState","useEffect","length","selectedOption","v","pop","exports"],"sourceRoot":"../src/","sources":["packages/react-components/react-combobox/src/utils/useComboboxBaseState.ts"],"sourcesContent":["import * as React from 'react';\nimport { useControllableState, useFirstMount } from '@fluentui/react-utilities';\nimport { useOptionCollection } from '../utils/useOptionCollection';\nimport { OptionValue } from '../utils/OptionCollection.types';\nimport { useSelection } from '../utils/useSelection';\nimport type { ComboboxBaseProps, ComboboxBaseOpenEvents, ComboboxBaseState } from './ComboboxBase.types';\n\n/**\n * State shared between Combobox and Dropdown components\n */\nexport const useComboboxBaseState = (props: ComboboxBaseProps & { editable?: boolean }): ComboboxBaseState => {\n const {\n appearance = 'outline',\n editable = false,\n inlinePopup = false,\n multiselect,\n onOpenChange,\n size = 'medium',\n } = props;\n\n const optionCollection = useOptionCollection();\n const { getOptionAtIndex, getOptionsMatchingText } = optionCollection;\n\n const [activeOption, setActiveOption] = React.useState<OptionValue | undefined>();\n\n // track whether keyboard focus outline should be shown\n // tabster/keyborg doesn't work here, since the actual keyboard focus target doesn't move\n const [focusVisible, setFocusVisible] = React.useState(false);\n\n // track focused state to conditionally render collapsed listbox\n const [hasFocus, setHasFocus] = React.useState(false);\n\n const ignoreNextBlur = React.useRef(false);\n\n const selectionState = useSelection(props);\n const { selectedOptions } = selectionState;\n\n // calculate value based on props, internal value changes, and selected options\n const isFirstMount = useFirstMount();\n const [controllableValue, setValue] = useControllableState({\n state: props.value,\n initialState: undefined,\n });\n\n const value = React.useMemo(() => {\n // don't compute the value if it is defined through props or setValue,\n if (controllableValue !== undefined) {\n return controllableValue;\n }\n\n // handle defaultValue here, so it is overridden by selection\n if (isFirstMount && props.defaultValue !== undefined) {\n return props.defaultValue;\n }\n\n if (multiselect) {\n // editable inputs should not display multiple selected options in the input as text\n return editable ? '' : selectedOptions.join(', ');\n }\n\n return selectedOptions[0];\n }, [controllableValue, editable, isFirstMount, multiselect, props.defaultValue, selectedOptions]);\n\n // Handle open state, which is shared with options in context\n const [open, setOpenState] = useControllableState({\n state: props.open,\n defaultState: props.defaultOpen,\n initialState: false,\n });\n\n const setOpen = React.useCallback(\n (event: ComboboxBaseOpenEvents, newState: boolean) => {\n onOpenChange?.(event, { open: newState });\n setOpenState(newState);\n },\n [onOpenChange, setOpenState],\n );\n\n // update active option based on change in open state\n React.useEffect(() => {\n if (open && !activeOption) {\n // if it is single-select and there is a selected option, start at the selected option\n if (!multiselect && selectedOptions.length > 0) {\n const selectedOption = getOptionsMatchingText(v => v === selectedOptions[0]).pop();\n selectedOption && setActiveOption(selectedOption);\n }\n // default to starting at the first option\n else {\n setActiveOption(getOptionAtIndex(0));\n }\n } else if (!open) {\n // reset the active option when closing\n setActiveOption(undefined);\n }\n // this should only be run in response to changes in the open state\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open]);\n\n return {\n ...optionCollection,\n ...selectionState,\n activeOption,\n appearance,\n focusVisible,\n hasFocus,\n ignoreNextBlur,\n inlinePopup,\n open,\n setActiveOption,\n setFocusVisible,\n setHasFocus,\n setOpen,\n setValue,\n size,\n value,\n };\n};\n"]}
|
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.useSelection = void 0;
|
|
7
|
+
const react_1 = /*#__PURE__*/require("react");
|
|
7
8
|
const react_utilities_1 = /*#__PURE__*/require("@fluentui/react-utilities");
|
|
8
9
|
const useSelection = props => {
|
|
9
10
|
const {
|
|
@@ -16,7 +17,7 @@ const useSelection = props => {
|
|
|
16
17
|
defaultState: defaultSelectedOptions,
|
|
17
18
|
initialState: []
|
|
18
19
|
});
|
|
19
|
-
const selectOption = (event, option) => {
|
|
20
|
+
const selectOption = react_1.useCallback((event, option) => {
|
|
20
21
|
// if the option is disabled, do nothing
|
|
21
22
|
if (option.disabled) {
|
|
22
23
|
return;
|
|
@@ -40,7 +41,7 @@ const useSelection = props => {
|
|
|
40
41
|
optionText: option.text,
|
|
41
42
|
selectedOptions: newSelection
|
|
42
43
|
});
|
|
43
|
-
};
|
|
44
|
+
}, [onOptionSelect, multiselect, selectedOptions, setSelectedOptions]);
|
|
44
45
|
const clearSelection = event => {
|
|
45
46
|
setSelectedOptions([]);
|
|
46
47
|
onOptionSelect === null || onOptionSelect === void 0 ? void 0 : onOptionSelect(event, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"mappings":";;;;;;AAAA;AAIO,MAAMA,YAAY,GAAIC,KAAqB,IAAoB;EACpE,MAAM;IAAEC,sBAAsB;IAAEC,WAAW;IAAEC;EAAc,CAAE,GAAGH,KAAK;EAErE,MAAM,CAACI,eAAe,EAAEC,kBAAkB,CAAC,GAAGC,sCAAoB,CAAC;IACjEC,KAAK,EAAEP,KAAK,CAACI,eAAe;IAC5BI,YAAY,EAAEP,sBAAsB;IACpCQ,YAAY,EAAE;GACf,CAAC;EAEF,MAAMC,YAAY,
|
|
1
|
+
{"version":3,"mappings":";;;;;;AAAA;AACA;AAIO,MAAMA,YAAY,GAAIC,KAAqB,IAAoB;EACpE,MAAM;IAAEC,sBAAsB;IAAEC,WAAW;IAAEC;EAAc,CAAE,GAAGH,KAAK;EAErE,MAAM,CAACI,eAAe,EAAEC,kBAAkB,CAAC,GAAGC,sCAAoB,CAAC;IACjEC,KAAK,EAAEP,KAAK,CAACI,eAAe;IAC5BI,YAAY,EAAEP,sBAAsB;IACpCQ,YAAY,EAAE;GACf,CAAC;EAEF,MAAMC,YAAY,GAAGC,mBAAW,CAC9B,CAACC,KAAsB,EAAEC,MAAmB,KAAI;IAC9C;IACA,IAAIA,MAAM,CAACC,QAAQ,EAAE;MACnB;;IAGF;IACA,IAAIC,YAAY,GAAG,CAACF,MAAM,CAACG,KAAK,CAAC;IAEjC;IACA,IAAId,WAAW,EAAE;MACf,MAAMe,aAAa,GAAGb,eAAe,CAACc,SAAS,CAACC,CAAC,IAAIA,CAAC,KAAKN,MAAM,CAACG,KAAK,CAAC;MACxE,IAAIC,aAAa,GAAG,CAAC,CAAC,EAAE;QACtB;QACAF,YAAY,GAAG,CAAC,GAAGX,eAAe,CAACgB,KAAK,CAAC,CAAC,EAAEH,aAAa,CAAC,EAAE,GAAGb,eAAe,CAACgB,KAAK,CAACH,aAAa,GAAG,CAAC,CAAC,CAAC;OACzG,MAAM;QACL;QACAF,YAAY,GAAG,CAAC,GAAGX,eAAe,EAAES,MAAM,CAACG,KAAK,CAAC;;;IAIrDX,kBAAkB,CAACU,YAAY,CAAC;IAChCZ,cAAc,aAAdA,cAAc,uBAAdA,cAAc,CAAGS,KAAK,EAAE;MAAES,WAAW,EAAER,MAAM,CAACG,KAAK;MAAEM,UAAU,EAAET,MAAM,CAACU,IAAI;MAAEnB,eAAe,EAAEW;IAAY,CAAE,CAAC;EAChH,CAAC,EACD,CAACZ,cAAc,EAAED,WAAW,EAAEE,eAAe,EAAEC,kBAAkB,CAAC,CACnE;EAED,MAAMmB,cAAc,GAAIZ,KAAsB,IAAI;IAChDP,kBAAkB,CAAC,EAAE,CAAC;IACtBF,cAAc,aAAdA,cAAc,uBAAdA,cAAc,CAAGS,KAAK,EAAE;MAAES,WAAW,EAAEI,SAAS;MAAEH,UAAU,EAAEG,SAAS;MAAErB,eAAe,EAAE;IAAE,CAAE,CAAC;EACjG,CAAC;EAED,OAAO;IAAEoB,cAAc;IAAEd,YAAY;IAAEN;EAAe,CAAE;AAC1D,CAAC;AA3CYsB,oBAAY","names":["useSelection","props","defaultSelectedOptions","multiselect","onOptionSelect","selectedOptions","setSelectedOptions","react_utilities_1","state","defaultState","initialState","selectOption","react_1","event","option","disabled","newSelection","value","selectedIndex","findIndex","o","slice","optionValue","optionText","text","clearSelection","undefined","exports"],"sourceRoot":"../src/","sources":["packages/react-components/react-combobox/src/utils/useSelection.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useControllableState } from '@fluentui/react-utilities';\nimport { OptionValue } from './OptionCollection.types';\nimport { SelectionEvents, SelectionProps, SelectionState } from './Selection.types';\n\nexport const useSelection = (props: SelectionProps): SelectionState => {\n const { defaultSelectedOptions, multiselect, onOptionSelect } = props;\n\n const [selectedOptions, setSelectedOptions] = useControllableState({\n state: props.selectedOptions,\n defaultState: defaultSelectedOptions,\n initialState: [],\n });\n\n const selectOption = useCallback(\n (event: SelectionEvents, option: OptionValue) => {\n // if the option is disabled, do nothing\n if (option.disabled) {\n return;\n }\n\n // for single-select, always return the selected option\n let newSelection = [option.value];\n\n // toggle selected state of the option for multiselect\n if (multiselect) {\n const selectedIndex = selectedOptions.findIndex(o => o === option.value);\n if (selectedIndex > -1) {\n // deselect option\n newSelection = [...selectedOptions.slice(0, selectedIndex), ...selectedOptions.slice(selectedIndex + 1)];\n } else {\n // select option\n newSelection = [...selectedOptions, option.value];\n }\n }\n\n setSelectedOptions(newSelection);\n onOptionSelect?.(event, { optionValue: option.value, optionText: option.text, selectedOptions: newSelection });\n },\n [onOptionSelect, multiselect, selectedOptions, setSelectedOptions],\n );\n\n const clearSelection = (event: SelectionEvents) => {\n setSelectedOptions([]);\n onOptionSelect?.(event, { optionValue: undefined, optionText: undefined, selectedOptions: [] });\n };\n\n return { clearSelection, selectOption, selectedOptions };\n};\n"]}
|
|
@@ -48,23 +48,26 @@ function useTriggerListboxSlots(props, state, ref, triggerSlot, listboxSlot) {
|
|
|
48
48
|
// functionally both ref and triggerRef will always be the same element type
|
|
49
49
|
ref: react_utilities_1.useMergedRefs(ref, triggerSlot === null || triggerSlot === void 0 ? void 0 : triggerSlot.ref, triggerRef)
|
|
50
50
|
};
|
|
51
|
+
/*
|
|
52
|
+
* Handle focus when clicking the listbox popup:
|
|
53
|
+
* 1. Move focus back to the button/input when the listbox is clicked (otherwise it goes to body)
|
|
54
|
+
* 2. Do not close the listbox on button/input blur when clicking into the listbox
|
|
55
|
+
*/
|
|
56
|
+
const listboxOnClick = react_utilities_1.useEventCallback(react_utilities_1.mergeCallbacks(event => {
|
|
57
|
+
var _a;
|
|
58
|
+
(_a = triggerRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
59
|
+
}, listbox === null || listbox === void 0 ? void 0 : listbox.onClick));
|
|
60
|
+
const listboxOnMouseOver = react_utilities_1.useEventCallback(react_utilities_1.mergeCallbacks(event => {
|
|
61
|
+
setFocusVisible(false);
|
|
62
|
+
}, listbox === null || listbox === void 0 ? void 0 : listbox.onMouseOver));
|
|
63
|
+
const listboxOnMouseDown = react_utilities_1.useEventCallback(react_utilities_1.mergeCallbacks(event => {
|
|
64
|
+
ignoreNextBlur.current = true;
|
|
65
|
+
}, listbox === null || listbox === void 0 ? void 0 : listbox.onMouseDown));
|
|
51
66
|
// listbox is nullable, only add event handlers if it exists
|
|
52
67
|
if (listbox) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
* 2. Do not close the listbox on button/input blur when clicking into the listbox
|
|
57
|
-
*/
|
|
58
|
-
listbox.onClick = react_utilities_1.mergeCallbacks(event => {
|
|
59
|
-
var _a;
|
|
60
|
-
(_a = triggerRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
61
|
-
}, listbox.onClick);
|
|
62
|
-
listbox.onMouseOver = react_utilities_1.mergeCallbacks(event => {
|
|
63
|
-
setFocusVisible(false);
|
|
64
|
-
}, listbox.onMouseOver);
|
|
65
|
-
listbox.onMouseDown = react_utilities_1.mergeCallbacks(event => {
|
|
66
|
-
ignoreNextBlur.current = true;
|
|
67
|
-
}, listbox.onMouseDown);
|
|
68
|
+
listbox.onClick = listboxOnClick;
|
|
69
|
+
listbox.onMouseOver = listboxOnMouseOver;
|
|
70
|
+
listbox.onMouseDown = listboxOnMouseDown;
|
|
68
71
|
}
|
|
69
72
|
// the trigger should open/close the popup on click or blur
|
|
70
73
|
trigger.onBlur = react_utilities_1.mergeCallbacks(event => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"mappings":"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","names":["useTriggerListboxSlots","props","state","ref","triggerSlot","listboxSlot","multiselect","activeOption","getCount","getIndexOfId","getOptionAtIndex","ignoreNextBlur","open","selectOption","setActiveOption","setFocusVisible","setHasFocus","setOpen","triggerRef","React","useRef","listbox","tabIndex","undefined","trigger","id","role","react_utilities_1","onClick","event","current","focus","onMouseOver","onMouseDown","onBlur","onFocus","onKeyDown","action","dropdownKeyActions_1","maxIndex","activeIndex","newIndex","preventDefault","stopPropagation","disabled","exports"],"sourceRoot":"../src/","sources":["packages/react-components/react-combobox/src/utils/useTriggerListboxSlots.ts"],"sourcesContent":["import * as React from 'react';\nimport { mergeCallbacks, useMergedRefs } from '@fluentui/react-utilities';\nimport type { ExtractSlotProps, Slot } from '@fluentui/react-utilities';\nimport { getDropdownActionFromKey, getIndexFromAction } from '../utils/dropdownKeyActions';\nimport { Listbox } from '../components/Listbox/Listbox';\nimport type { ComboboxBaseProps, ComboboxBaseState } from './ComboboxBase.types';\n\nexport function useTriggerListboxSlots(\n props: ComboboxBaseProps,\n state: ComboboxBaseState,\n ref: React.Ref<HTMLButtonElement>,\n triggerSlot?: ExtractSlotProps<Slot<'button'>>,\n listboxSlot?: ExtractSlotProps<Slot<typeof Listbox>>,\n): [trigger: ExtractSlotProps<Slot<'button'>>, listbox?: ExtractSlotProps<Slot<typeof Listbox>>];\nexport function useTriggerListboxSlots(\n props: ComboboxBaseProps,\n state: ComboboxBaseState,\n ref: React.Ref<HTMLInputElement>,\n triggerSlot?: ExtractSlotProps<Slot<'input'>>,\n listboxSlot?: ExtractSlotProps<Slot<typeof Listbox>>,\n): [trigger: ExtractSlotProps<Slot<'input'>>, listbox?: ExtractSlotProps<Slot<typeof Listbox>>];\n\n/*\n * useTriggerListboxSlots returns a tuple of trigger/listbox shorthand,\n * with the semantics and event handlers needed for the Combobox and Dropdown components.\n * The element type of the ref should always match the element type used in the trigger shorthand.\n */\nexport function useTriggerListboxSlots(\n props: ComboboxBaseProps,\n state: ComboboxBaseState,\n ref: React.Ref<HTMLButtonElement | HTMLInputElement>,\n triggerSlot?: ExtractSlotProps<Slot<'input'>> | ExtractSlotProps<Slot<'button'>>,\n listboxSlot?: ExtractSlotProps<Slot<typeof Listbox>>,\n): [\n trigger: ExtractSlotProps<Slot<'input'>> | ExtractSlotProps<Slot<'button'>>,\n listbox?: ExtractSlotProps<Slot<typeof Listbox>>,\n] {\n const { multiselect } = props;\n const {\n activeOption,\n getCount,\n getIndexOfId,\n getOptionAtIndex,\n ignoreNextBlur,\n open,\n selectOption,\n setActiveOption,\n setFocusVisible,\n setHasFocus,\n setOpen,\n } = state;\n\n // handle trigger focus/blur\n const triggerRef: typeof ref = React.useRef(null);\n\n // resolve listbox shorthand props\n const listbox: typeof listboxSlot = listboxSlot && {\n multiselect,\n tabIndex: undefined,\n ...listboxSlot,\n };\n\n // resolve trigger shorthand props\n const trigger: typeof triggerSlot = {\n 'aria-expanded': open,\n 'aria-activedescendant': open ? activeOption?.id : undefined,\n role: 'combobox',\n ...triggerSlot,\n // explicitly type the ref as an intersection here to prevent type errors\n // since the `children` prop has mutually incompatible types between input/button\n // functionally both ref and triggerRef will always be the same element type\n ref: useMergedRefs(ref, triggerSlot?.ref, triggerRef) as React.Ref<HTMLButtonElement & HTMLInputElement>,\n };\n\n // listbox is nullable, only add event handlers if it exists\n if (listbox) {\n /*\n * Handle focus when clicking the listbox popup:\n * 1. Move focus back to the button/input when the listbox is clicked (otherwise it goes to body)\n * 2. Do not close the listbox on button/input blur when clicking into the listbox\n */\n listbox.onClick = mergeCallbacks((event: React.MouseEvent<HTMLDivElement>) => {\n triggerRef.current?.focus();\n }, listbox.onClick);\n\n listbox.onMouseOver = mergeCallbacks((event: React.MouseEvent<HTMLDivElement>) => {\n setFocusVisible(false);\n }, listbox.onMouseOver);\n\n listbox.onMouseDown = mergeCallbacks((event: React.MouseEvent<HTMLDivElement>) => {\n ignoreNextBlur.current = true;\n }, listbox.onMouseDown);\n }\n\n // the trigger should open/close the popup on click or blur\n trigger.onBlur = mergeCallbacks((event: React.FocusEvent<HTMLButtonElement> & React.FocusEvent<HTMLInputElement>) => {\n if (!ignoreNextBlur.current) {\n setOpen(event, false);\n }\n\n ignoreNextBlur.current = false;\n\n setHasFocus(false);\n }, trigger.onBlur);\n\n trigger.onClick = mergeCallbacks(\n (event: React.MouseEvent<HTMLButtonElement> & React.MouseEvent<HTMLInputElement>) => {\n setOpen(event, !open);\n },\n trigger.onClick,\n );\n\n trigger.onFocus = mergeCallbacks(\n (event: React.FocusEvent<HTMLButtonElement> & React.FocusEvent<HTMLInputElement>) => {\n setHasFocus(true);\n },\n trigger.onFocus,\n );\n\n // handle combobox keyboard interaction\n trigger.onKeyDown = mergeCallbacks(\n (event: React.KeyboardEvent<HTMLButtonElement> & React.KeyboardEvent<HTMLInputElement>) => {\n const action = getDropdownActionFromKey(event, { open, multiselect });\n const maxIndex = getCount() - 1;\n const activeIndex = activeOption ? getIndexOfId(activeOption.id) : -1;\n let newIndex = activeIndex;\n\n switch (action) {\n case 'Open':\n event.preventDefault();\n setFocusVisible(true);\n setOpen(event, true);\n break;\n case 'Close':\n // stop propagation for escape key to avoid dismissing any parent popups\n event.stopPropagation();\n event.preventDefault();\n setOpen(event, false);\n break;\n case 'CloseSelect':\n !multiselect && !activeOption?.disabled && setOpen(event, false);\n // fallthrough\n case 'Select':\n activeOption && selectOption(event, activeOption);\n event.preventDefault();\n break;\n case 'Tab':\n !multiselect && activeOption && selectOption(event, activeOption);\n break;\n default:\n newIndex = getIndexFromAction(action, activeIndex, maxIndex);\n }\n if (newIndex !== activeIndex) {\n // prevent default page scroll/keyboard action if the index changed\n event.preventDefault();\n setActiveOption(getOptionAtIndex(newIndex));\n setFocusVisible(true);\n }\n },\n trigger.onKeyDown,\n );\n\n trigger.onMouseOver = mergeCallbacks(\n (event: React.MouseEvent<HTMLButtonElement> & React.MouseEvent<HTMLInputElement>) => {\n setFocusVisible(false);\n },\n trigger.onMouseOver,\n );\n\n return [trigger, listbox];\n}\n"]}
|
|
1
|
+
{"version":3,"mappings":"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","names":["useTriggerListboxSlots","props","state","ref","triggerSlot","listboxSlot","multiselect","activeOption","getCount","getIndexOfId","getOptionAtIndex","ignoreNextBlur","open","selectOption","setActiveOption","setFocusVisible","setHasFocus","setOpen","triggerRef","React","useRef","listbox","tabIndex","undefined","trigger","id","role","react_utilities_1","listboxOnClick","event","current","focus","onClick","listboxOnMouseOver","onMouseOver","listboxOnMouseDown","onMouseDown","onBlur","onFocus","onKeyDown","action","dropdownKeyActions_1","maxIndex","activeIndex","newIndex","preventDefault","stopPropagation","disabled","exports"],"sourceRoot":"../src/","sources":["packages/react-components/react-combobox/src/utils/useTriggerListboxSlots.ts"],"sourcesContent":["import * as React from 'react';\nimport { mergeCallbacks, useEventCallback, useMergedRefs } from '@fluentui/react-utilities';\nimport type { ExtractSlotProps, Slot } from '@fluentui/react-utilities';\nimport { getDropdownActionFromKey, getIndexFromAction } from '../utils/dropdownKeyActions';\nimport { Listbox } from '../components/Listbox/Listbox';\nimport type { ComboboxBaseProps, ComboboxBaseState } from './ComboboxBase.types';\n\nexport function useTriggerListboxSlots(\n props: ComboboxBaseProps,\n state: ComboboxBaseState,\n ref: React.Ref<HTMLButtonElement>,\n triggerSlot?: ExtractSlotProps<Slot<'button'>>,\n listboxSlot?: ExtractSlotProps<Slot<typeof Listbox>>,\n): [trigger: ExtractSlotProps<Slot<'button'>>, listbox?: ExtractSlotProps<Slot<typeof Listbox>>];\nexport function useTriggerListboxSlots(\n props: ComboboxBaseProps,\n state: ComboboxBaseState,\n ref: React.Ref<HTMLInputElement>,\n triggerSlot?: ExtractSlotProps<Slot<'input'>>,\n listboxSlot?: ExtractSlotProps<Slot<typeof Listbox>>,\n): [trigger: ExtractSlotProps<Slot<'input'>>, listbox?: ExtractSlotProps<Slot<typeof Listbox>>];\n\n/*\n * useTriggerListboxSlots returns a tuple of trigger/listbox shorthand,\n * with the semantics and event handlers needed for the Combobox and Dropdown components.\n * The element type of the ref should always match the element type used in the trigger shorthand.\n */\nexport function useTriggerListboxSlots(\n props: ComboboxBaseProps,\n state: ComboboxBaseState,\n ref: React.Ref<HTMLButtonElement | HTMLInputElement>,\n triggerSlot?: ExtractSlotProps<Slot<'input'>> | ExtractSlotProps<Slot<'button'>>,\n listboxSlot?: ExtractSlotProps<Slot<typeof Listbox>>,\n): [\n trigger: ExtractSlotProps<Slot<'input'>> | ExtractSlotProps<Slot<'button'>>,\n listbox?: ExtractSlotProps<Slot<typeof Listbox>>,\n] {\n const { multiselect } = props;\n const {\n activeOption,\n getCount,\n getIndexOfId,\n getOptionAtIndex,\n ignoreNextBlur,\n open,\n selectOption,\n setActiveOption,\n setFocusVisible,\n setHasFocus,\n setOpen,\n } = state;\n\n // handle trigger focus/blur\n const triggerRef: typeof ref = React.useRef(null);\n\n // resolve listbox shorthand props\n const listbox: typeof listboxSlot = listboxSlot && {\n multiselect,\n tabIndex: undefined,\n ...listboxSlot,\n };\n\n // resolve trigger shorthand props\n const trigger: typeof triggerSlot = {\n 'aria-expanded': open,\n 'aria-activedescendant': open ? activeOption?.id : undefined,\n role: 'combobox',\n ...triggerSlot,\n // explicitly type the ref as an intersection here to prevent type errors\n // since the `children` prop has mutually incompatible types between input/button\n // functionally both ref and triggerRef will always be the same element type\n ref: useMergedRefs(ref, triggerSlot?.ref, triggerRef) as React.Ref<HTMLButtonElement & HTMLInputElement>,\n };\n\n /*\n * Handle focus when clicking the listbox popup:\n * 1. Move focus back to the button/input when the listbox is clicked (otherwise it goes to body)\n * 2. Do not close the listbox on button/input blur when clicking into the listbox\n */\n const listboxOnClick = useEventCallback(\n mergeCallbacks((event: React.MouseEvent<HTMLDivElement>) => {\n triggerRef.current?.focus();\n }, listbox?.onClick),\n );\n\n const listboxOnMouseOver = useEventCallback(\n mergeCallbacks((event: React.MouseEvent<HTMLDivElement>) => {\n setFocusVisible(false);\n }, listbox?.onMouseOver),\n );\n\n const listboxOnMouseDown = useEventCallback(\n mergeCallbacks((event: React.MouseEvent<HTMLDivElement>) => {\n ignoreNextBlur.current = true;\n }, listbox?.onMouseDown),\n );\n\n // listbox is nullable, only add event handlers if it exists\n if (listbox) {\n listbox.onClick = listboxOnClick;\n listbox.onMouseOver = listboxOnMouseOver;\n listbox.onMouseDown = listboxOnMouseDown;\n }\n\n // the trigger should open/close the popup on click or blur\n trigger.onBlur = mergeCallbacks((event: React.FocusEvent<HTMLButtonElement> & React.FocusEvent<HTMLInputElement>) => {\n if (!ignoreNextBlur.current) {\n setOpen(event, false);\n }\n\n ignoreNextBlur.current = false;\n\n setHasFocus(false);\n }, trigger.onBlur);\n\n trigger.onClick = mergeCallbacks(\n (event: React.MouseEvent<HTMLButtonElement> & React.MouseEvent<HTMLInputElement>) => {\n setOpen(event, !open);\n },\n trigger.onClick,\n );\n\n trigger.onFocus = mergeCallbacks(\n (event: React.FocusEvent<HTMLButtonElement> & React.FocusEvent<HTMLInputElement>) => {\n setHasFocus(true);\n },\n trigger.onFocus,\n );\n\n // handle combobox keyboard interaction\n trigger.onKeyDown = mergeCallbacks(\n (event: React.KeyboardEvent<HTMLButtonElement> & React.KeyboardEvent<HTMLInputElement>) => {\n const action = getDropdownActionFromKey(event, { open, multiselect });\n const maxIndex = getCount() - 1;\n const activeIndex = activeOption ? getIndexOfId(activeOption.id) : -1;\n let newIndex = activeIndex;\n\n switch (action) {\n case 'Open':\n event.preventDefault();\n setFocusVisible(true);\n setOpen(event, true);\n break;\n case 'Close':\n // stop propagation for escape key to avoid dismissing any parent popups\n event.stopPropagation();\n event.preventDefault();\n setOpen(event, false);\n break;\n case 'CloseSelect':\n !multiselect && !activeOption?.disabled && setOpen(event, false);\n // fallthrough\n case 'Select':\n activeOption && selectOption(event, activeOption);\n event.preventDefault();\n break;\n case 'Tab':\n !multiselect && activeOption && selectOption(event, activeOption);\n break;\n default:\n newIndex = getIndexFromAction(action, activeIndex, maxIndex);\n }\n if (newIndex !== activeIndex) {\n // prevent default page scroll/keyboard action if the index changed\n event.preventDefault();\n setActiveOption(getOptionAtIndex(newIndex));\n setFocusVisible(true);\n }\n },\n trigger.onKeyDown,\n );\n\n trigger.onMouseOver = mergeCallbacks(\n (event: React.MouseEvent<HTMLButtonElement> & React.MouseEvent<HTMLInputElement>) => {\n setFocusVisible(false);\n },\n trigger.onMouseOver,\n );\n\n return [trigger, listbox];\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluentui/react-combobox",
|
|
3
|
-
"version": "9.0.0-beta.
|
|
3
|
+
"version": "9.0.0-beta.21",
|
|
4
4
|
"description": "Fluent UI React Combobox component",
|
|
5
5
|
"main": "lib-commonjs/index.js",
|
|
6
6
|
"module": "lib/index.js",
|
|
@@ -32,13 +32,13 @@
|
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@fluentui/keyboard-keys": "^9.0.1",
|
|
35
|
-
"@fluentui/react-context-selector": "^9.1.
|
|
36
|
-
"@fluentui/react-field": "9.0.0-alpha.
|
|
35
|
+
"@fluentui/react-context-selector": "^9.1.5",
|
|
36
|
+
"@fluentui/react-field": "9.0.0-alpha.14",
|
|
37
37
|
"@fluentui/react-icons": "^2.0.175",
|
|
38
|
-
"@fluentui/react-portal": "^9.0
|
|
39
|
-
"@fluentui/react-positioning": "^9.3.
|
|
38
|
+
"@fluentui/react-portal": "^9.1.0",
|
|
39
|
+
"@fluentui/react-positioning": "^9.3.7",
|
|
40
40
|
"@fluentui/react-theme": "^9.1.5",
|
|
41
|
-
"@fluentui/react-utilities": "^9.
|
|
41
|
+
"@fluentui/react-utilities": "^9.4.0",
|
|
42
42
|
"@griffel/react": "^1.5.2",
|
|
43
43
|
"tslib": "^2.1.0"
|
|
44
44
|
},
|