@fluentui/react-combobox 9.7.5 → 9.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -5
- package/dist/index.d.ts +54 -11
- package/lib/components/Combobox/Combobox.types.js.map +1 -1
- package/lib/components/Combobox/renderCombobox.js +15 -11
- package/lib/components/Combobox/renderCombobox.js.map +1 -1
- package/lib/components/Combobox/useCombobox.js +12 -4
- package/lib/components/Combobox/useCombobox.js.map +1 -1
- package/lib/components/Combobox/useInputTriggerSlot.js +14 -12
- package/lib/components/Combobox/useInputTriggerSlot.js.map +1 -1
- package/lib/components/Dropdown/Dropdown.types.js.map +1 -1
- package/lib/components/Dropdown/renderDropdown.js +19 -15
- package/lib/components/Dropdown/renderDropdown.js.map +1 -1
- package/lib/components/Dropdown/useButtonTriggerSlot.js +51 -31
- package/lib/components/Dropdown/useButtonTriggerSlot.js.map +1 -1
- package/lib/components/Dropdown/useDropdown.js +14 -4
- package/lib/components/Dropdown/useDropdown.js.map +1 -1
- package/lib/components/Listbox/Listbox.types.js.map +1 -1
- package/lib/components/Listbox/renderListbox.js +7 -3
- package/lib/components/Listbox/renderListbox.js.map +1 -1
- package/lib/components/Listbox/useListbox.js +43 -35
- package/lib/components/Listbox/useListbox.js.map +1 -1
- package/lib/components/Option/Option.types.js.map +1 -1
- package/lib/components/Option/useOption.js +7 -11
- package/lib/components/Option/useOption.js.map +1 -1
- package/lib/components/Option/useOptionStyles.styles.js +27 -28
- package/lib/components/Option/useOptionStyles.styles.js.map +1 -1
- package/lib/contexts/useComboboxContextValues.js +14 -5
- package/lib/contexts/useComboboxContextValues.js.map +1 -1
- package/lib/contexts/useListboxContextValues.js +12 -5
- package/lib/contexts/useListboxContextValues.js.map +1 -1
- package/lib/utils/ComboboxBase.types.js.map +1 -1
- package/lib/utils/OptionCollection.types.js.map +1 -1
- package/lib/utils/Selection.types.js.map +1 -1
- package/lib/utils/dropdownKeyActions.js +0 -21
- package/lib/utils/dropdownKeyActions.js.map +1 -1
- package/lib/utils/useComboboxBaseState.js +52 -14
- package/lib/utils/useComboboxBaseState.js.map +1 -1
- package/lib/utils/useOptionCollection.js +18 -45
- package/lib/utils/useOptionCollection.js.map +1 -1
- package/lib/utils/useTriggerSlot.js +86 -33
- package/lib/utils/useTriggerSlot.js.map +1 -1
- package/lib-commonjs/components/Combobox/renderCombobox.js +15 -11
- package/lib-commonjs/components/Combobox/renderCombobox.js.map +1 -1
- package/lib-commonjs/components/Combobox/useCombobox.js +12 -4
- package/lib-commonjs/components/Combobox/useCombobox.js.map +1 -1
- package/lib-commonjs/components/Combobox/useInputTriggerSlot.js +14 -12
- package/lib-commonjs/components/Combobox/useInputTriggerSlot.js.map +1 -1
- package/lib-commonjs/components/Dropdown/renderDropdown.js +19 -15
- package/lib-commonjs/components/Dropdown/renderDropdown.js.map +1 -1
- package/lib-commonjs/components/Dropdown/useButtonTriggerSlot.js +51 -31
- package/lib-commonjs/components/Dropdown/useButtonTriggerSlot.js.map +1 -1
- package/lib-commonjs/components/Dropdown/useDropdown.js +14 -4
- package/lib-commonjs/components/Dropdown/useDropdown.js.map +1 -1
- package/lib-commonjs/components/Listbox/renderListbox.js +7 -3
- package/lib-commonjs/components/Listbox/renderListbox.js.map +1 -1
- package/lib-commonjs/components/Listbox/useListbox.js +42 -34
- package/lib-commonjs/components/Listbox/useListbox.js.map +1 -1
- package/lib-commonjs/components/Option/useOption.js +7 -11
- package/lib-commonjs/components/Option/useOption.js.map +1 -1
- package/lib-commonjs/components/Option/useOptionStyles.styles.js +85 -85
- package/lib-commonjs/components/Option/useOptionStyles.styles.js.map +1 -1
- package/lib-commonjs/contexts/useComboboxContextValues.js +13 -5
- package/lib-commonjs/contexts/useComboboxContextValues.js.map +1 -1
- package/lib-commonjs/contexts/useListboxContextValues.js +13 -5
- package/lib-commonjs/contexts/useListboxContextValues.js.map +1 -1
- package/lib-commonjs/utils/dropdownKeyActions.js +3 -30
- package/lib-commonjs/utils/dropdownKeyActions.js.map +1 -1
- package/lib-commonjs/utils/useComboboxBaseState.js +52 -14
- package/lib-commonjs/utils/useComboboxBaseState.js.map +1 -1
- package/lib-commonjs/utils/useOptionCollection.js +18 -45
- package/lib-commonjs/utils/useOptionCollection.js.map +1 -1
- package/lib-commonjs/utils/useTriggerSlot.js +84 -31
- package/lib-commonjs/utils/useTriggerSlot.js.map +1 -1
- package/package.json +9 -8
- package/lib/utils/useScrollOptionsIntoView.js +0 -29
- package/lib/utils/useScrollOptionsIntoView.js.map +0 -1
- package/lib-commonjs/utils/useScrollOptionsIntoView.js +0 -40
- package/lib-commonjs/utils/useScrollOptionsIntoView.js.map +0 -1
|
@@ -7,40 +7,51 @@ import { getDropdownActionFromKey } from '../../utils/dropdownKeyActions';
|
|
|
7
7
|
* with the semantics and event handlers needed for the Combobox and Dropdown components.
|
|
8
8
|
* The element type of the ref should always match the element type used in the trigger shorthand.
|
|
9
9
|
*/ export function useButtonTriggerSlot(triggerFromProps, ref, options) {
|
|
10
|
-
const { state: { open,
|
|
10
|
+
const { state: { open, setOpen, getOptionById }, defaultProps, activeDescendantController } = options;
|
|
11
11
|
// jump to matching option based on typing
|
|
12
12
|
const searchString = React.useRef('');
|
|
13
13
|
const [setKeyTimeout, clearKeyTimeout] = useTimeout();
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
14
|
+
const moveToNextMatchingOption = (matcher, opt = {
|
|
15
|
+
startFromNext: false
|
|
16
|
+
})=>{
|
|
17
|
+
const { startFromNext } = opt;
|
|
18
|
+
const activeOptionId = activeDescendantController.active();
|
|
19
|
+
const nextInOrder = activeDescendantController.find((id)=>{
|
|
20
|
+
const option = getOptionById(id);
|
|
21
|
+
return !!option && matcher(option.text);
|
|
22
|
+
}, {
|
|
23
|
+
startFrom: startFromNext ? activeDescendantController.next({
|
|
24
|
+
passive: true
|
|
25
|
+
}) : activeOptionId
|
|
26
|
+
});
|
|
27
|
+
if (nextInOrder) {
|
|
28
|
+
return nextInOrder;
|
|
29
|
+
}
|
|
30
|
+
// Cycle back to first match
|
|
31
|
+
return activeDescendantController.find((id)=>{
|
|
32
|
+
const option = getOptionById(id);
|
|
33
|
+
return !!option && matcher(option.text);
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
const moveToNextMatchingOptionWithSameCharacterHandling = ()=>{
|
|
37
|
+
if (moveToNextMatchingOption((optionText)=>{
|
|
38
|
+
return optionText.toLocaleLowerCase().indexOf(searchString.current) === 0;
|
|
39
|
+
}, {
|
|
40
|
+
// Slowly pressing the same key will cycle through options
|
|
41
|
+
startFromNext: searchString.current.length === 1
|
|
42
|
+
})) {
|
|
43
|
+
return;
|
|
24
44
|
}
|
|
25
45
|
// if there are no direct matches, check if the search is all the same letter, e.g. "aaa"
|
|
26
|
-
if (
|
|
27
|
-
|
|
28
|
-
|
|
46
|
+
if (allCharactersSame(searchString.current) && moveToNextMatchingOption((optionText)=>{
|
|
47
|
+
return optionText.toLocaleLowerCase().indexOf(searchString.current[0]) === 0;
|
|
48
|
+
}, {
|
|
29
49
|
// if the search is all the same letter, cycle through options starting with that letter
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
matches = getOptionsMatchingText(matcher);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
// if there is an active option and multiple matches,
|
|
37
|
-
// return first matching option after the current active option, looping back to the top
|
|
38
|
-
if (matches.length > 1 && activeOption) {
|
|
39
|
-
const nextMatch = matches.find((option)=>getIndexOfId(option.id) >= startIndex);
|
|
40
|
-
return nextMatch !== null && nextMatch !== void 0 ? nextMatch : matches[0];
|
|
50
|
+
startFromNext: true
|
|
51
|
+
})) {
|
|
52
|
+
return;
|
|
41
53
|
}
|
|
42
|
-
|
|
43
|
-
return (_matches_ = matches[0]) !== null && _matches_ !== void 0 ? _matches_ : undefined;
|
|
54
|
+
activeDescendantController.blur();
|
|
44
55
|
};
|
|
45
56
|
const onTriggerKeyDown = (ev)=>{
|
|
46
57
|
// clear timeout, if it exists
|
|
@@ -54,16 +65,25 @@ import { getDropdownActionFromKey } from '../../utils/dropdownKeyActions';
|
|
|
54
65
|
}, 500);
|
|
55
66
|
// update state
|
|
56
67
|
!open && setOpen(ev, true);
|
|
57
|
-
|
|
58
|
-
setActiveOption(nextOption);
|
|
59
|
-
setFocusVisible(true);
|
|
68
|
+
moveToNextMatchingOptionWithSameCharacterHandling();
|
|
60
69
|
}
|
|
61
70
|
};
|
|
62
71
|
const trigger = useTriggerSlot(triggerFromProps, ref, {
|
|
63
72
|
state: options.state,
|
|
64
73
|
defaultProps,
|
|
65
|
-
elementType: 'button'
|
|
74
|
+
elementType: 'button',
|
|
75
|
+
activeDescendantController
|
|
66
76
|
});
|
|
67
77
|
trigger.onKeyDown = mergeCallbacks(onTriggerKeyDown, trigger.onKeyDown);
|
|
68
78
|
return trigger;
|
|
69
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* @returns - whether every character in the string is the same
|
|
82
|
+
*/ function allCharactersSame(str) {
|
|
83
|
+
for(let i = 1; i < str.length; i++){
|
|
84
|
+
if (str[i] !== str[i - 1]) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["useButtonTriggerSlot.ts"],"sourcesContent":["import * as React from 'react';\nimport { useTimeout, mergeCallbacks } from '@fluentui/react-utilities';\nimport type { Slot, ExtractSlotProps, SlotComponentType } from '@fluentui/react-utilities';\nimport {
|
|
1
|
+
{"version":3,"sources":["useButtonTriggerSlot.ts"],"sourcesContent":["import * as React from 'react';\nimport { useTimeout, mergeCallbacks } from '@fluentui/react-utilities';\nimport type { Slot, ExtractSlotProps, SlotComponentType } from '@fluentui/react-utilities';\nimport type { ActiveDescendantImperativeRef } from '@fluentui/react-aria';\nimport { useTriggerSlot, UseTriggerSlotState } from '../../utils/useTriggerSlot';\nimport { getDropdownActionFromKey } from '../../utils/dropdownKeyActions';\n\ntype UseButtonTriggerSlotOptions = {\n state: UseTriggerSlotState;\n defaultProps: unknown;\n activeDescendantController: ActiveDescendantImperativeRef;\n};\n\n/*\n * useButtonTriggerSlot 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 useButtonTriggerSlot(\n triggerFromProps: NonNullable<Slot<'button'>>,\n ref: React.Ref<HTMLButtonElement>,\n options: UseButtonTriggerSlotOptions,\n): SlotComponentType<ExtractSlotProps<Slot<'button'>>> {\n const {\n state: { open, setOpen, getOptionById },\n defaultProps,\n activeDescendantController,\n } = options;\n\n // jump to matching option based on typing\n const searchString = React.useRef('');\n const [setKeyTimeout, clearKeyTimeout] = useTimeout();\n\n const moveToNextMatchingOption = (\n matcher: (optionText: string) => boolean,\n opt: { startFromNext: boolean } = { startFromNext: false },\n ) => {\n const { startFromNext } = opt;\n const activeOptionId = activeDescendantController.active();\n\n const nextInOrder = activeDescendantController.find(\n id => {\n const option = getOptionById(id);\n return !!option && matcher(option.text);\n },\n { startFrom: startFromNext ? activeDescendantController.next({ passive: true }) : activeOptionId },\n );\n\n if (nextInOrder) {\n return nextInOrder;\n }\n\n // Cycle back to first match\n return activeDescendantController.find(id => {\n const option = getOptionById(id);\n return !!option && matcher(option.text);\n });\n };\n\n const moveToNextMatchingOptionWithSameCharacterHandling = () => {\n if (\n moveToNextMatchingOption(\n optionText => {\n return optionText.toLocaleLowerCase().indexOf(searchString.current) === 0;\n },\n {\n // Slowly pressing the same key will cycle through options\n startFromNext: searchString.current.length === 1,\n },\n )\n ) {\n return;\n }\n\n // if there are no direct matches, check if the search is all the same letter, e.g. \"aaa\"\n if (\n allCharactersSame(searchString.current) &&\n moveToNextMatchingOption(\n optionText => {\n return optionText.toLocaleLowerCase().indexOf(searchString.current[0]) === 0;\n },\n {\n // if the search is all the same letter, cycle through options starting with that letter\n startFromNext: true,\n },\n )\n ) {\n return;\n }\n\n activeDescendantController.blur();\n };\n\n const onTriggerKeyDown = (ev: React.KeyboardEvent<HTMLButtonElement>) => {\n // clear timeout, if it exists\n clearKeyTimeout();\n\n // if the key was a char key, update search string\n if (getDropdownActionFromKey(ev) === 'Type') {\n // update search string\n searchString.current += ev.key.toLowerCase();\n setKeyTimeout(() => {\n searchString.current = '';\n }, 500);\n\n // update state\n !open && setOpen(ev, true);\n moveToNextMatchingOptionWithSameCharacterHandling();\n }\n };\n\n const trigger = useTriggerSlot(triggerFromProps, ref, {\n state: options.state,\n defaultProps,\n elementType: 'button',\n activeDescendantController,\n });\n trigger.onKeyDown = mergeCallbacks(onTriggerKeyDown, trigger.onKeyDown);\n\n return trigger;\n}\n\n/**\n * @returns - whether every character in the string is the same\n */\nfunction allCharactersSame(str: string) {\n for (let i = 1; i < str.length; i++) {\n if (str[i] !== str[i - 1]) {\n return false;\n }\n }\n\n return true;\n}\n"],"names":["React","useTimeout","mergeCallbacks","useTriggerSlot","getDropdownActionFromKey","useButtonTriggerSlot","triggerFromProps","ref","options","state","open","setOpen","getOptionById","defaultProps","activeDescendantController","searchString","useRef","setKeyTimeout","clearKeyTimeout","moveToNextMatchingOption","matcher","opt","startFromNext","activeOptionId","active","nextInOrder","find","id","option","text","startFrom","next","passive","moveToNextMatchingOptionWithSameCharacterHandling","optionText","toLocaleLowerCase","indexOf","current","length","allCharactersSame","blur","onTriggerKeyDown","ev","key","toLowerCase","trigger","elementType","onKeyDown","str","i"],"mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,UAAU,EAAEC,cAAc,QAAQ,4BAA4B;AAGvE,SAASC,cAAc,QAA6B,6BAA6B;AACjF,SAASC,wBAAwB,QAAQ,iCAAiC;AAQ1E;;;;CAIC,GACD,OAAO,SAASC,qBACdC,gBAA6C,EAC7CC,GAAiC,EACjCC,OAAoC;IAEpC,MAAM,EACJC,OAAO,EAAEC,IAAI,EAAEC,OAAO,EAAEC,aAAa,EAAE,EACvCC,YAAY,EACZC,0BAA0B,EAC3B,GAAGN;IAEJ,0CAA0C;IAC1C,MAAMO,eAAef,MAAMgB,MAAM,CAAC;IAClC,MAAM,CAACC,eAAeC,gBAAgB,GAAGjB;IAEzC,MAAMkB,2BAA2B,CAC/BC,SACAC,MAAkC;QAAEC,eAAe;IAAM,CAAC;QAE1D,MAAM,EAAEA,aAAa,EAAE,GAAGD;QAC1B,MAAME,iBAAiBT,2BAA2BU,MAAM;QAExD,MAAMC,cAAcX,2BAA2BY,IAAI,CACjDC,CAAAA;YACE,MAAMC,SAAShB,cAAce;YAC7B,OAAO,CAAC,CAACC,UAAUR,QAAQQ,OAAOC,IAAI;QACxC,GACA;YAAEC,WAAWR,gBAAgBR,2BAA2BiB,IAAI,CAAC;gBAAEC,SAAS;YAAK,KAAKT;QAAe;QAGnG,IAAIE,aAAa;YACf,OAAOA;QACT;QAEA,4BAA4B;QAC5B,OAAOX,2BAA2BY,IAAI,CAACC,CAAAA;YACrC,MAAMC,SAAShB,cAAce;YAC7B,OAAO,CAAC,CAACC,UAAUR,QAAQQ,OAAOC,IAAI;QACxC;IACF;IAEA,MAAMI,oDAAoD;QACxD,IACEd,yBACEe,CAAAA;YACE,OAAOA,WAAWC,iBAAiB,GAAGC,OAAO,CAACrB,aAAasB,OAAO,MAAM;QAC1E,GACA;YACE,0DAA0D;YAC1Df,eAAeP,aAAasB,OAAO,CAACC,MAAM,KAAK;QACjD,IAEF;YACA;QACF;QAEA,yFAAyF;QACzF,IACEC,kBAAkBxB,aAAasB,OAAO,KACtClB,yBACEe,CAAAA;YACE,OAAOA,WAAWC,iBAAiB,GAAGC,OAAO,CAACrB,aAAasB,OAAO,CAAC,EAAE,MAAM;QAC7E,GACA;YACE,wFAAwF;YACxFf,eAAe;QACjB,IAEF;YACA;QACF;QAEAR,2BAA2B0B,IAAI;IACjC;IAEA,MAAMC,mBAAmB,CAACC;QACxB,8BAA8B;QAC9BxB;QAEA,kDAAkD;QAClD,IAAId,yBAAyBsC,QAAQ,QAAQ;YAC3C,uBAAuB;YACvB3B,aAAasB,OAAO,IAAIK,GAAGC,GAAG,CAACC,WAAW;YAC1C3B,cAAc;gBACZF,aAAasB,OAAO,GAAG;YACzB,GAAG;YAEH,eAAe;YACf,CAAC3B,QAAQC,QAAQ+B,IAAI;YACrBT;QACF;IACF;IAEA,MAAMY,UAAU1C,eAAeG,kBAAkBC,KAAK;QACpDE,OAAOD,QAAQC,KAAK;QACpBI;QACAiC,aAAa;QACbhC;IACF;IACA+B,QAAQE,SAAS,GAAG7C,eAAeuC,kBAAkBI,QAAQE,SAAS;IAEtE,OAAOF;AACT;AAEA;;CAEC,GACD,SAASN,kBAAkBS,GAAW;IACpC,IAAK,IAAIC,IAAI,GAAGA,IAAID,IAAIV,MAAM,EAAEW,IAAK;QACnC,IAAID,GAAG,CAACC,EAAE,KAAKD,GAAG,CAACC,IAAI,EAAE,EAAE;YACzB,OAAO;QACT;IACF;IAEA,OAAO;AACT"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { useFieldControlProps_unstable } from '@fluentui/react-field';
|
|
3
|
+
import { useActiveDescendant } from '@fluentui/react-aria';
|
|
3
4
|
import { ChevronDownRegular as ChevronDownIcon, DismissRegular as DismissIcon } from '@fluentui/react-icons';
|
|
4
5
|
import { getPartitionedNativeProps, mergeCallbacks, useMergedRefs, slot, useEventCallback } from '@fluentui/react-utilities';
|
|
5
6
|
import { useComboboxBaseState } from '../../utils/useComboboxBaseState';
|
|
@@ -7,6 +8,7 @@ import { useComboboxPositioning } from '../../utils/useComboboxPositioning';
|
|
|
7
8
|
import { Listbox } from '../Listbox/Listbox';
|
|
8
9
|
import { useListboxSlot } from '../../utils/useListboxSlot';
|
|
9
10
|
import { useButtonTriggerSlot } from './useButtonTriggerSlot';
|
|
11
|
+
import { optionClassNames } from '../Option/useOptionStyles.styles';
|
|
10
12
|
/**
|
|
11
13
|
* Create the state required to render Dropdown.
|
|
12
14
|
*
|
|
@@ -22,7 +24,13 @@ import { useButtonTriggerSlot } from './useButtonTriggerSlot';
|
|
|
22
24
|
supportsLabelFor: true,
|
|
23
25
|
supportsSize: true
|
|
24
26
|
});
|
|
25
|
-
const
|
|
27
|
+
const { listboxRef: activeDescendantListboxRef, activeParentRef, controller: activeDescendantController } = useActiveDescendant({
|
|
28
|
+
matchOption: (el)=>el.classList.contains(optionClassNames.root)
|
|
29
|
+
});
|
|
30
|
+
const baseState = useComboboxBaseState({
|
|
31
|
+
...props,
|
|
32
|
+
activeDescendantController
|
|
33
|
+
});
|
|
26
34
|
const { clearable, clearSelection, hasFocus, multiselect, open, selectedOptions } = baseState;
|
|
27
35
|
const { primary: triggerNativeProps, root: rootNativeProps } = getPartitionedNativeProps({
|
|
28
36
|
props,
|
|
@@ -33,7 +41,7 @@ import { useButtonTriggerSlot } from './useButtonTriggerSlot';
|
|
|
33
41
|
});
|
|
34
42
|
const [comboboxPopupRef, comboboxTargetRef] = useComboboxPositioning(props);
|
|
35
43
|
const triggerRef = React.useRef(null);
|
|
36
|
-
const listbox = useListboxSlot(props.listbox, comboboxPopupRef, {
|
|
44
|
+
const listbox = useListboxSlot(props.listbox, useMergedRefs(comboboxPopupRef, activeDescendantListboxRef), {
|
|
37
45
|
state: baseState,
|
|
38
46
|
triggerRef,
|
|
39
47
|
defaultProps: {
|
|
@@ -41,7 +49,7 @@ import { useButtonTriggerSlot } from './useButtonTriggerSlot';
|
|
|
41
49
|
}
|
|
42
50
|
});
|
|
43
51
|
var _props_button;
|
|
44
|
-
const trigger = useButtonTriggerSlot((_props_button = props.button) !== null && _props_button !== void 0 ? _props_button : {}, useMergedRefs(triggerRef, ref), {
|
|
52
|
+
const trigger = useButtonTriggerSlot((_props_button = props.button) !== null && _props_button !== void 0 ? _props_button : {}, useMergedRefs(triggerRef, activeParentRef, ref), {
|
|
45
53
|
state: baseState,
|
|
46
54
|
defaultProps: {
|
|
47
55
|
type: 'button',
|
|
@@ -49,7 +57,8 @@ import { useButtonTriggerSlot } from './useButtonTriggerSlot';
|
|
|
49
57
|
children: baseState.value || props.placeholder,
|
|
50
58
|
'aria-controls': open ? listbox === null || listbox === void 0 ? void 0 : listbox.id : undefined,
|
|
51
59
|
...triggerNativeProps
|
|
52
|
-
}
|
|
60
|
+
},
|
|
61
|
+
activeDescendantController
|
|
53
62
|
});
|
|
54
63
|
const rootSlot = slot.always(props.root, {
|
|
55
64
|
defaultProps: {
|
|
@@ -92,6 +101,7 @@ import { useButtonTriggerSlot } from './useButtonTriggerSlot';
|
|
|
92
101
|
}),
|
|
93
102
|
placeholderVisible: !baseState.value && !!props.placeholder,
|
|
94
103
|
showClearButton,
|
|
104
|
+
activeDescendantController,
|
|
95
105
|
...baseState
|
|
96
106
|
};
|
|
97
107
|
const onClearButtonClick = useEventCallback(mergeCallbacks((_state_clearButton = state.clearButton) === null || _state_clearButton === void 0 ? void 0 : _state_clearButton.onClick, (ev)=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["useDropdown.tsx"],"sourcesContent":["import * as React from 'react';\nimport { useFieldControlProps_unstable } from '@fluentui/react-field';\nimport { ChevronDownRegular as ChevronDownIcon, DismissRegular as DismissIcon } from '@fluentui/react-icons';\nimport {\n getPartitionedNativeProps,\n mergeCallbacks,\n useMergedRefs,\n slot,\n useEventCallback,\n} from '@fluentui/react-utilities';\nimport { useComboboxBaseState } from '../../utils/useComboboxBaseState';\nimport { useComboboxPositioning } from '../../utils/useComboboxPositioning';\nimport { Listbox } from '../Listbox/Listbox';\nimport type { DropdownProps, DropdownState } from './Dropdown.types';\nimport { useListboxSlot } from '../../utils/useListboxSlot';\nimport { useButtonTriggerSlot } from './useButtonTriggerSlot';\n\n/**\n * Create the state required to render Dropdown.\n *\n * The returned state can be modified with hooks such as useDropdownStyles_unstable,\n * before being passed to renderDropdown_unstable.\n *\n * @param props - props from this instance of Dropdown\n * @param ref - reference to root HTMLElement of Dropdown\n */\nexport const useDropdown_unstable = (props: DropdownProps, ref: React.Ref<HTMLButtonElement>): DropdownState => {\n // Merge props from surrounding <Field>, if any\n props = useFieldControlProps_unstable(props, { supportsLabelFor: true, supportsSize: true });\n\n const baseState = useComboboxBaseState(props);\n const { clearable, clearSelection, hasFocus, multiselect, open, selectedOptions } = baseState;\n\n const { primary: triggerNativeProps, root: rootNativeProps } = getPartitionedNativeProps({\n props,\n primarySlotTagName: 'button',\n excludedPropNames: ['children'],\n });\n\n const [comboboxPopupRef, comboboxTargetRef] = useComboboxPositioning(props);\n\n const triggerRef = React.useRef<HTMLButtonElement>(null);\n const listbox = useListboxSlot(props.listbox, comboboxPopupRef, {\n state: baseState,\n triggerRef,\n defaultProps: {\n children: props.children,\n },\n });\n\n const trigger = useButtonTriggerSlot(props.button ?? {}, useMergedRefs(triggerRef, ref), {\n state: baseState,\n defaultProps: {\n type: 'button',\n tabIndex: 0,\n children: baseState.value || props.placeholder,\n 'aria-controls': open ? listbox?.id : undefined,\n ...triggerNativeProps,\n },\n });\n\n const rootSlot = slot.always(props.root, {\n defaultProps: {\n 'aria-owns': !props.inlinePopup && open ? listbox?.id : undefined,\n children: props.children,\n ...rootNativeProps,\n },\n elementType: 'div',\n });\n rootSlot.ref = useMergedRefs(rootSlot.ref, comboboxTargetRef);\n\n const showClearButton = selectedOptions.length > 0 && clearable && !multiselect;\n const state: DropdownState = {\n components: { root: 'div', button: 'button', clearButton: 'button', expandIcon: 'span', listbox: Listbox },\n root: rootSlot,\n button: trigger,\n listbox: open || hasFocus ? listbox : undefined,\n clearButton: slot.optional(props.clearButton, {\n defaultProps: {\n 'aria-label': 'Clear selection',\n children: <DismissIcon />,\n // Safari doesn't allow to focus an element with this\n tabIndex: 0,\n type: 'button',\n },\n elementType: 'button',\n renderByDefault: true,\n }),\n expandIcon: slot.optional(props.expandIcon, {\n renderByDefault: true,\n defaultProps: {\n children: <ChevronDownIcon />,\n },\n elementType: 'span',\n }),\n placeholderVisible: !baseState.value && !!props.placeholder,\n showClearButton,\n ...baseState,\n };\n\n const onClearButtonClick = useEventCallback(\n mergeCallbacks(state.clearButton?.onClick, (ev: React.MouseEvent<HTMLButtonElement>) => {\n clearSelection(ev);\n triggerRef.current?.focus();\n }),\n );\n\n if (state.clearButton) {\n state.clearButton.onClick = onClearButtonClick;\n }\n\n // Heads up! We don't support \"clearable\" in multiselect mode, so we should never display a slot\n if (multiselect) {\n state.clearButton = undefined;\n }\n\n if (process.env.NODE_ENV !== 'production') {\n // eslint-disable-next-line react-hooks/rules-of-hooks -- \"process.env\" does not change in runtime\n React.useEffect(() => {\n if (clearable && multiselect) {\n // eslint-disable-next-line no-console\n console.error(`[@fluentui/react-combobox] \"clearable\" prop is not supported in multiselect mode.`);\n }\n }, [clearable, multiselect]);\n }\n\n return state;\n};\n"],"names":["React","useFieldControlProps_unstable","ChevronDownRegular","ChevronDownIcon","DismissRegular","DismissIcon","getPartitionedNativeProps","mergeCallbacks","useMergedRefs","slot","useEventCallback","useComboboxBaseState","useComboboxPositioning","Listbox","useListboxSlot","useButtonTriggerSlot","useDropdown_unstable","props","ref","state","supportsLabelFor","supportsSize","baseState","clearable","clearSelection","hasFocus","multiselect","open","selectedOptions","primary","triggerNativeProps","
|
|
1
|
+
{"version":3,"sources":["useDropdown.tsx"],"sourcesContent":["import * as React from 'react';\nimport { useFieldControlProps_unstable } from '@fluentui/react-field';\nimport { useActiveDescendant } from '@fluentui/react-aria';\nimport { ChevronDownRegular as ChevronDownIcon, DismissRegular as DismissIcon } from '@fluentui/react-icons';\nimport {\n getPartitionedNativeProps,\n mergeCallbacks,\n useMergedRefs,\n slot,\n useEventCallback,\n} from '@fluentui/react-utilities';\nimport { useComboboxBaseState } from '../../utils/useComboboxBaseState';\nimport { useComboboxPositioning } from '../../utils/useComboboxPositioning';\nimport { Listbox } from '../Listbox/Listbox';\nimport type { DropdownProps, DropdownState } from './Dropdown.types';\nimport { useListboxSlot } from '../../utils/useListboxSlot';\nimport { useButtonTriggerSlot } from './useButtonTriggerSlot';\nimport { optionClassNames } from '../Option/useOptionStyles.styles';\n\n/**\n * Create the state required to render Dropdown.\n *\n * The returned state can be modified with hooks such as useDropdownStyles_unstable,\n * before being passed to renderDropdown_unstable.\n *\n * @param props - props from this instance of Dropdown\n * @param ref - reference to root HTMLElement of Dropdown\n */\nexport const useDropdown_unstable = (props: DropdownProps, ref: React.Ref<HTMLButtonElement>): DropdownState => {\n // Merge props from surrounding <Field>, if any\n props = useFieldControlProps_unstable(props, { supportsLabelFor: true, supportsSize: true });\n const {\n listboxRef: activeDescendantListboxRef,\n activeParentRef,\n controller: activeDescendantController,\n } = useActiveDescendant<HTMLButtonElement, HTMLDivElement>({\n matchOption: el => el.classList.contains(optionClassNames.root),\n });\n\n const baseState = useComboboxBaseState({ ...props, activeDescendantController });\n const { clearable, clearSelection, hasFocus, multiselect, open, selectedOptions } = baseState;\n\n const { primary: triggerNativeProps, root: rootNativeProps } = getPartitionedNativeProps({\n props,\n primarySlotTagName: 'button',\n excludedPropNames: ['children'],\n });\n\n const [comboboxPopupRef, comboboxTargetRef] = useComboboxPositioning(props);\n\n const triggerRef = React.useRef<HTMLButtonElement>(null);\n const listbox = useListboxSlot(props.listbox, useMergedRefs(comboboxPopupRef, activeDescendantListboxRef), {\n state: baseState,\n triggerRef,\n defaultProps: {\n children: props.children,\n },\n });\n\n const trigger = useButtonTriggerSlot(props.button ?? {}, useMergedRefs(triggerRef, activeParentRef, ref), {\n state: baseState,\n defaultProps: {\n type: 'button',\n tabIndex: 0,\n children: baseState.value || props.placeholder,\n 'aria-controls': open ? listbox?.id : undefined,\n ...triggerNativeProps,\n },\n activeDescendantController,\n });\n\n const rootSlot = slot.always(props.root, {\n defaultProps: {\n 'aria-owns': !props.inlinePopup && open ? listbox?.id : undefined,\n children: props.children,\n ...rootNativeProps,\n },\n elementType: 'div',\n });\n rootSlot.ref = useMergedRefs(rootSlot.ref, comboboxTargetRef);\n\n const showClearButton = selectedOptions.length > 0 && clearable && !multiselect;\n const state: DropdownState = {\n components: { root: 'div', button: 'button', clearButton: 'button', expandIcon: 'span', listbox: Listbox },\n root: rootSlot,\n button: trigger,\n listbox: open || hasFocus ? listbox : undefined,\n clearButton: slot.optional(props.clearButton, {\n defaultProps: {\n 'aria-label': 'Clear selection',\n children: <DismissIcon />,\n // Safari doesn't allow to focus an element with this\n tabIndex: 0,\n type: 'button',\n },\n elementType: 'button',\n renderByDefault: true,\n }),\n expandIcon: slot.optional(props.expandIcon, {\n renderByDefault: true,\n defaultProps: {\n children: <ChevronDownIcon />,\n },\n elementType: 'span',\n }),\n placeholderVisible: !baseState.value && !!props.placeholder,\n showClearButton,\n activeDescendantController,\n ...baseState,\n };\n\n const onClearButtonClick = useEventCallback(\n mergeCallbacks(state.clearButton?.onClick, (ev: React.MouseEvent<HTMLButtonElement>) => {\n clearSelection(ev);\n triggerRef.current?.focus();\n }),\n );\n\n if (state.clearButton) {\n state.clearButton.onClick = onClearButtonClick;\n }\n\n // Heads up! We don't support \"clearable\" in multiselect mode, so we should never display a slot\n if (multiselect) {\n state.clearButton = undefined;\n }\n\n if (process.env.NODE_ENV !== 'production') {\n // eslint-disable-next-line react-hooks/rules-of-hooks -- \"process.env\" does not change in runtime\n React.useEffect(() => {\n if (clearable && multiselect) {\n // eslint-disable-next-line no-console\n console.error(`[@fluentui/react-combobox] \"clearable\" prop is not supported in multiselect mode.`);\n }\n }, [clearable, multiselect]);\n }\n\n return state;\n};\n"],"names":["React","useFieldControlProps_unstable","useActiveDescendant","ChevronDownRegular","ChevronDownIcon","DismissRegular","DismissIcon","getPartitionedNativeProps","mergeCallbacks","useMergedRefs","slot","useEventCallback","useComboboxBaseState","useComboboxPositioning","Listbox","useListboxSlot","useButtonTriggerSlot","optionClassNames","useDropdown_unstable","props","ref","state","supportsLabelFor","supportsSize","listboxRef","activeDescendantListboxRef","activeParentRef","controller","activeDescendantController","matchOption","el","classList","contains","root","baseState","clearable","clearSelection","hasFocus","multiselect","open","selectedOptions","primary","triggerNativeProps","rootNativeProps","primarySlotTagName","excludedPropNames","comboboxPopupRef","comboboxTargetRef","triggerRef","useRef","listbox","defaultProps","children","trigger","button","type","tabIndex","value","placeholder","id","undefined","rootSlot","always","inlinePopup","elementType","showClearButton","length","components","clearButton","expandIcon","optional","renderByDefault","placeholderVisible","onClearButtonClick","onClick","ev","current","focus","process","env","NODE_ENV","useEffect","console","error"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["Listbox.types.ts"],"sourcesContent":["import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';\nimport { OptionValue, OptionCollectionState } from '../../utils/OptionCollection.types';\nimport { SelectionEvents, SelectionProps, SelectionState } from '../../utils/Selection.types';\nimport type { ListboxContextValue } from '../../contexts/ListboxContext';\n\nexport type ListboxSlots = {\n /* The root slot, a `<div>` with `role=\"listbox\"` */\n root: Slot<'div'>;\n};\n\n/**\n * Listbox Props\n */\nexport type ListboxProps = ComponentProps<ListboxSlots> & SelectionProps;\n\n/**\n * State used in rendering Listbox\n */\nexport type ListboxState = ComponentState<ListboxSlots> &\n OptionCollectionState &\n Pick<SelectionProps, 'multiselect'> &\n SelectionState & {\n
|
|
1
|
+
{"version":3,"sources":["Listbox.types.ts"],"sourcesContent":["import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';\nimport type { ActiveDescendantContextValue, ActiveDescendantImperativeRef } from '@fluentui/react-aria';\nimport { OptionValue, OptionCollectionState } from '../../utils/OptionCollection.types';\nimport { SelectionEvents, SelectionProps, SelectionState } from '../../utils/Selection.types';\nimport type { ListboxContextValue } from '../../contexts/ListboxContext';\n\nexport type ListboxSlots = {\n /* The root slot, a `<div>` with `role=\"listbox\"` */\n root: Slot<'div'>;\n};\n\n/**\n * Listbox Props\n */\nexport type ListboxProps = ComponentProps<ListboxSlots> & SelectionProps;\n\n/**\n * State used in rendering Listbox\n */\nexport type ListboxState = ComponentState<ListboxSlots> &\n OptionCollectionState &\n Pick<SelectionProps, 'multiselect'> &\n SelectionState & {\n /**\n * @deprecated - no longer used internally\n * @see activeDescendantController.active()\n */\n activeOption?: OptionValue;\n\n /**\n * @deprecated - no longer used internally\n */\n focusVisible: boolean;\n\n /**\n * @deprecated - no longer used internally\n * @see activeDescendantController.focus(id)\n */\n setActiveOption(option?: OptionValue): void;\n\n selectOption(event: SelectionEvents, option: OptionValue): void;\n\n activeDescendantController: ActiveDescendantImperativeRef;\n };\n\nexport type ListboxContextValues = {\n listbox: ListboxContextValue;\n activeDescendant: ActiveDescendantContextValue;\n};\n"],"names":[],"mappings":"AAAA,WAgDE"}
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx } from "@fluentui/react-jsx-runtime/jsx-runtime";
|
|
2
2
|
import { assertSlots } from '@fluentui/react-utilities';
|
|
3
|
+
import { ActiveDescendantContextProvider } from '@fluentui/react-aria';
|
|
3
4
|
import { ListboxContext } from '../../contexts/ListboxContext';
|
|
4
5
|
/**
|
|
5
6
|
* Render the final JSX of Listbox
|
|
6
7
|
*/ export const renderListbox_unstable = (state, contextValues)=>{
|
|
7
8
|
assertSlots(state);
|
|
8
|
-
return /*#__PURE__*/ _jsx(
|
|
9
|
-
value: contextValues.
|
|
10
|
-
children: /*#__PURE__*/ _jsx(
|
|
9
|
+
return /*#__PURE__*/ _jsx(ActiveDescendantContextProvider, {
|
|
10
|
+
value: contextValues.activeDescendant,
|
|
11
|
+
children: /*#__PURE__*/ _jsx(ListboxContext.Provider, {
|
|
12
|
+
value: contextValues.listbox,
|
|
13
|
+
children: /*#__PURE__*/ _jsx(state.root, {})
|
|
14
|
+
})
|
|
11
15
|
});
|
|
12
16
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["renderListbox.tsx"],"sourcesContent":["/** @jsxRuntime automatic */\n/** @jsxImportSource @fluentui/react-jsx-runtime */\n\nimport { assertSlots } from '@fluentui/react-utilities';\nimport type { ListboxContextValues, ListboxState, ListboxSlots } from './Listbox.types';\nimport { ListboxContext } from '../../contexts/ListboxContext';\n\n/**\n * Render the final JSX of Listbox\n */\nexport const renderListbox_unstable = (state: ListboxState, contextValues: ListboxContextValues) => {\n assertSlots<ListboxSlots>(state);\n\n return (\n <ListboxContext.Provider value={contextValues.listbox}>\n
|
|
1
|
+
{"version":3,"sources":["renderListbox.tsx"],"sourcesContent":["/** @jsxRuntime automatic */\n/** @jsxImportSource @fluentui/react-jsx-runtime */\n\nimport { assertSlots } from '@fluentui/react-utilities';\nimport { ActiveDescendantContextProvider } from '@fluentui/react-aria';\nimport type { ListboxContextValues, ListboxState, ListboxSlots } from './Listbox.types';\nimport { ListboxContext } from '../../contexts/ListboxContext';\n\n/**\n * Render the final JSX of Listbox\n */\nexport const renderListbox_unstable = (state: ListboxState, contextValues: ListboxContextValues) => {\n assertSlots<ListboxSlots>(state);\n\n return (\n <ActiveDescendantContextProvider value={contextValues.activeDescendant}>\n <ListboxContext.Provider value={contextValues.listbox}>\n <state.root />\n </ListboxContext.Provider>\n </ActiveDescendantContextProvider>\n );\n};\n"],"names":["assertSlots","ActiveDescendantContextProvider","ListboxContext","renderListbox_unstable","state","contextValues","value","activeDescendant","Provider","listbox","root"],"mappings":"AAAA,0BAA0B,GAC1B,iDAAiD;AAEjD,SAASA,WAAW,QAAQ,4BAA4B;AACxD,SAASC,+BAA+B,QAAQ,uBAAuB;AAEvE,SAASC,cAAc,QAAQ,gCAAgC;AAE/D;;CAEC,GACD,OAAO,MAAMC,yBAAyB,CAACC,OAAqBC;IAC1DL,YAA0BI;IAE1B,qBACE,KAACH;QAAgCK,OAAOD,cAAcE,gBAAgB;kBACpE,cAAA,KAACL,eAAeM,QAAQ;YAACF,OAAOD,cAAcI,OAAO;sBACnD,cAAA,KAACL,MAAMM,IAAI;;;AAInB,EAAE"}
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { getIntrinsicElementProps, mergeCallbacks, useEventCallback, useMergedRefs, slot } from '@fluentui/react-utilities';
|
|
3
3
|
import { useContextSelector, useHasParentContext } from '@fluentui/react-context-selector';
|
|
4
|
-
import {
|
|
4
|
+
import { useActiveDescendant, useActiveDescendantContext, useHasParentActiveDescendantContext } from '@fluentui/react-aria';
|
|
5
|
+
import { getDropdownActionFromKey } from '../../utils/dropdownKeyActions';
|
|
5
6
|
import { useOptionCollection } from '../../utils/useOptionCollection';
|
|
6
|
-
import { useScrollOptionsIntoView } from '../../utils/useScrollOptionsIntoView';
|
|
7
7
|
import { useSelection } from '../../utils/useSelection';
|
|
8
8
|
import { ComboboxContext } from '../../contexts/ComboboxContext';
|
|
9
|
+
import { optionClassNames } from '../Option/useOptionStyles.styles';
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
11
|
+
const UNSAFE_noLongerUsed = {
|
|
12
|
+
activeOption: undefined,
|
|
13
|
+
focusVisible: false,
|
|
14
|
+
setActiveOption: ()=>null
|
|
15
|
+
};
|
|
9
16
|
/**
|
|
10
17
|
* Create the state required to render Listbox.
|
|
11
18
|
*
|
|
@@ -17,57 +24,61 @@ import { ComboboxContext } from '../../contexts/ComboboxContext';
|
|
|
17
24
|
*/ export const useListbox_unstable = (props, ref)=>{
|
|
18
25
|
const { multiselect } = props;
|
|
19
26
|
const optionCollection = useOptionCollection();
|
|
20
|
-
const {
|
|
27
|
+
const { getOptionById } = optionCollection;
|
|
28
|
+
const { listboxRef: activeDescendantListboxRef, activeParentRef, controller } = useActiveDescendant({
|
|
29
|
+
matchOption: (el)=>el.classList.contains(optionClassNames.root)
|
|
30
|
+
});
|
|
31
|
+
const activeDescendantContext = useActiveDescendantContext();
|
|
32
|
+
const activeDescendantController = useHasParentActiveDescendantContext() ? activeDescendantContext.controller : controller;
|
|
21
33
|
const { clearSelection, selectedOptions, selectOption } = useSelection(props);
|
|
22
|
-
const [activeOption, setActiveOption] = React.useState();
|
|
23
|
-
// track whether keyboard focus outline should be shown
|
|
24
|
-
// tabster/keyborg doesn't work here, since the actual keyboard focus target doesn't move
|
|
25
|
-
const [focusVisible, setFocusVisible] = React.useState(false);
|
|
26
34
|
const onKeyDown = (event)=>{
|
|
27
35
|
const action = getDropdownActionFromKey(event, {
|
|
28
36
|
open: true
|
|
29
37
|
});
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
let newIndex = activeIndex;
|
|
38
|
+
const activeOptionId = activeDescendantController.active();
|
|
39
|
+
const activeOption = activeOptionId ? getOptionById(activeOptionId) : null;
|
|
33
40
|
switch(action){
|
|
41
|
+
case 'Next':
|
|
42
|
+
if (activeOption) {
|
|
43
|
+
activeDescendantController.next();
|
|
44
|
+
} else {
|
|
45
|
+
activeDescendantController.first();
|
|
46
|
+
}
|
|
47
|
+
break;
|
|
48
|
+
case 'Previous':
|
|
49
|
+
if (activeOption) {
|
|
50
|
+
activeDescendantController.prev();
|
|
51
|
+
} else {
|
|
52
|
+
activeDescendantController.first();
|
|
53
|
+
}
|
|
54
|
+
break;
|
|
55
|
+
case 'PageUp':
|
|
56
|
+
case 'First':
|
|
57
|
+
activeDescendantController.first();
|
|
58
|
+
break;
|
|
59
|
+
case 'PageDown':
|
|
60
|
+
case 'Last':
|
|
61
|
+
activeDescendantController.last();
|
|
62
|
+
break;
|
|
34
63
|
case 'Select':
|
|
35
64
|
case 'CloseSelect':
|
|
36
65
|
activeOption && selectOption(event, activeOption);
|
|
37
66
|
break;
|
|
38
|
-
default:
|
|
39
|
-
newIndex = getIndexFromAction(action, activeIndex, maxIndex);
|
|
40
|
-
}
|
|
41
|
-
if (newIndex !== activeIndex) {
|
|
42
|
-
// prevent default page scroll/keyboard action if the index changed
|
|
43
|
-
event.preventDefault();
|
|
44
|
-
setActiveOption(getOptionAtIndex(newIndex));
|
|
45
|
-
setFocusVisible(true);
|
|
46
67
|
}
|
|
47
68
|
};
|
|
48
|
-
const onMouseOver = (event)=>{
|
|
49
|
-
setFocusVisible(false);
|
|
50
|
-
};
|
|
51
69
|
// get state from parent combobox, if it exists
|
|
52
70
|
const hasComboboxContext = useHasParentContext(ComboboxContext);
|
|
53
|
-
const comboboxActiveOption = useContextSelector(ComboboxContext, (ctx)=>ctx.activeOption);
|
|
54
|
-
const comboboxFocusVisible = useContextSelector(ComboboxContext, (ctx)=>ctx.focusVisible);
|
|
55
71
|
const comboboxSelectedOptions = useContextSelector(ComboboxContext, (ctx)=>ctx.selectedOptions);
|
|
56
72
|
const comboboxSelectOption = useContextSelector(ComboboxContext, (ctx)=>ctx.selectOption);
|
|
57
|
-
const comboboxSetActiveOption = useContextSelector(ComboboxContext, (ctx)=>ctx.setActiveOption);
|
|
58
73
|
// without a parent combobox context, provide values directly from Listbox
|
|
59
74
|
const optionContextValues = hasComboboxContext ? {
|
|
60
|
-
activeOption: comboboxActiveOption,
|
|
61
|
-
focusVisible: comboboxFocusVisible,
|
|
62
75
|
selectedOptions: comboboxSelectedOptions,
|
|
63
76
|
selectOption: comboboxSelectOption,
|
|
64
|
-
|
|
77
|
+
...UNSAFE_noLongerUsed
|
|
65
78
|
} : {
|
|
66
|
-
activeOption,
|
|
67
|
-
focusVisible,
|
|
68
79
|
selectedOptions,
|
|
69
80
|
selectOption,
|
|
70
|
-
|
|
81
|
+
...UNSAFE_noLongerUsed
|
|
71
82
|
};
|
|
72
83
|
const state = {
|
|
73
84
|
components: {
|
|
@@ -77,9 +88,8 @@ import { ComboboxContext } from '../../contexts/ComboboxContext';
|
|
|
77
88
|
// FIXME:
|
|
78
89
|
// `ref` is wrongly assigned to be `HTMLElement` instead of `HTMLDivElement`
|
|
79
90
|
// but since it would be a breaking change to fix it, we are casting ref to it's proper type
|
|
80
|
-
ref: ref,
|
|
91
|
+
ref: useMergedRefs(ref, activeParentRef, activeDescendantListboxRef),
|
|
81
92
|
role: multiselect ? 'menu' : 'listbox',
|
|
82
|
-
'aria-activedescendant': hasComboboxContext ? undefined : activeOption === null || activeOption === void 0 ? void 0 : activeOption.id,
|
|
83
93
|
tabIndex: 0,
|
|
84
94
|
...props
|
|
85
95
|
}), {
|
|
@@ -87,12 +97,10 @@ import { ComboboxContext } from '../../contexts/ComboboxContext';
|
|
|
87
97
|
}),
|
|
88
98
|
multiselect,
|
|
89
99
|
clearSelection,
|
|
100
|
+
activeDescendantController,
|
|
90
101
|
...optionCollection,
|
|
91
102
|
...optionContextValues
|
|
92
103
|
};
|
|
93
|
-
const scrollContainerRef = useScrollOptionsIntoView(state);
|
|
94
|
-
state.root.ref = useMergedRefs(state.root.ref, scrollContainerRef);
|
|
95
104
|
state.root.onKeyDown = useEventCallback(mergeCallbacks(state.root.onKeyDown, onKeyDown));
|
|
96
|
-
state.root.onMouseOver = useEventCallback(mergeCallbacks(state.root.onMouseOver, onMouseOver));
|
|
97
105
|
return state;
|
|
98
106
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["useListbox.ts"],"sourcesContent":["import * as React from 'react';\nimport {\n getIntrinsicElementProps,\n mergeCallbacks,\n useEventCallback,\n useMergedRefs,\n slot,\n} from '@fluentui/react-utilities';\nimport { useContextSelector, useHasParentContext } from '@fluentui/react-context-selector';\nimport {
|
|
1
|
+
{"version":3,"sources":["useListbox.ts"],"sourcesContent":["import * as React from 'react';\nimport {\n getIntrinsicElementProps,\n mergeCallbacks,\n useEventCallback,\n useMergedRefs,\n slot,\n} from '@fluentui/react-utilities';\nimport { useContextSelector, useHasParentContext } from '@fluentui/react-context-selector';\nimport {\n useActiveDescendant,\n useActiveDescendantContext,\n useHasParentActiveDescendantContext,\n} from '@fluentui/react-aria';\nimport { getDropdownActionFromKey } from '../../utils/dropdownKeyActions';\nimport { useOptionCollection } from '../../utils/useOptionCollection';\nimport { useSelection } from '../../utils/useSelection';\nimport { ComboboxContext } from '../../contexts/ComboboxContext';\nimport { optionClassNames } from '../Option/useOptionStyles.styles';\nimport type { ListboxProps, ListboxState } from './Listbox.types';\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst UNSAFE_noLongerUsed = {\n activeOption: undefined,\n focusVisible: false,\n setActiveOption: () => null,\n};\n\n/**\n * Create the state required to render Listbox.\n *\n * The returned state can be modified with hooks such as useListboxStyles_unstable,\n * before being passed to renderListbox_unstable.\n *\n * @param props - props from this instance of Listbox\n * @param ref - reference to root HTMLElement of Listbox\n */\nexport const useListbox_unstable = (props: ListboxProps, ref: React.Ref<HTMLElement>): ListboxState => {\n const { multiselect } = props;\n const optionCollection = useOptionCollection();\n const { getOptionById } = optionCollection;\n\n const {\n listboxRef: activeDescendantListboxRef,\n activeParentRef,\n controller,\n } = useActiveDescendant<HTMLInputElement, HTMLDivElement>({\n matchOption: el => el.classList.contains(optionClassNames.root),\n });\n\n const activeDescendantContext = useActiveDescendantContext();\n const activeDescendantController = useHasParentActiveDescendantContext()\n ? activeDescendantContext.controller\n : controller;\n\n const { clearSelection, selectedOptions, selectOption } = useSelection(props);\n\n const onKeyDown = (event: React.KeyboardEvent<HTMLElement>) => {\n const action = getDropdownActionFromKey(event, { open: true });\n const activeOptionId = activeDescendantController.active();\n const activeOption = activeOptionId ? getOptionById(activeOptionId) : null;\n\n switch (action) {\n case 'Next':\n if (activeOption) {\n activeDescendantController.next();\n } else {\n activeDescendantController.first();\n }\n break;\n case 'Previous':\n if (activeOption) {\n activeDescendantController.prev();\n } else {\n activeDescendantController.first();\n }\n break;\n case 'PageUp':\n case 'First':\n activeDescendantController.first();\n break;\n case 'PageDown':\n case 'Last':\n activeDescendantController.last();\n break;\n case 'Select':\n case 'CloseSelect':\n activeOption && selectOption(event, activeOption);\n break;\n }\n };\n\n // get state from parent combobox, if it exists\n const hasComboboxContext = useHasParentContext(ComboboxContext);\n const comboboxSelectedOptions = useContextSelector(ComboboxContext, ctx => ctx.selectedOptions);\n const comboboxSelectOption = useContextSelector(ComboboxContext, ctx => ctx.selectOption);\n\n // without a parent combobox context, provide values directly from Listbox\n const optionContextValues = hasComboboxContext\n ? {\n selectedOptions: comboboxSelectedOptions,\n selectOption: comboboxSelectOption,\n ...UNSAFE_noLongerUsed,\n }\n : {\n selectedOptions,\n selectOption,\n ...UNSAFE_noLongerUsed,\n };\n\n const state: ListboxState = {\n components: {\n root: 'div',\n },\n root: slot.always(\n getIntrinsicElementProps('div', {\n // FIXME:\n // `ref` is wrongly assigned to be `HTMLElement` instead of `HTMLDivElement`\n // but since it would be a breaking change to fix it, we are casting ref to it's proper type\n ref: useMergedRefs(ref as React.Ref<HTMLDivElement>, activeParentRef, activeDescendantListboxRef),\n role: multiselect ? 'menu' : 'listbox',\n tabIndex: 0,\n ...props,\n }),\n { elementType: 'div' },\n ),\n multiselect,\n clearSelection,\n activeDescendantController,\n ...optionCollection,\n ...optionContextValues,\n };\n\n state.root.onKeyDown = useEventCallback(mergeCallbacks(state.root.onKeyDown, onKeyDown));\n\n return state;\n};\n"],"names":["React","getIntrinsicElementProps","mergeCallbacks","useEventCallback","useMergedRefs","slot","useContextSelector","useHasParentContext","useActiveDescendant","useActiveDescendantContext","useHasParentActiveDescendantContext","getDropdownActionFromKey","useOptionCollection","useSelection","ComboboxContext","optionClassNames","UNSAFE_noLongerUsed","activeOption","undefined","focusVisible","setActiveOption","useListbox_unstable","props","ref","multiselect","optionCollection","getOptionById","listboxRef","activeDescendantListboxRef","activeParentRef","controller","matchOption","el","classList","contains","root","activeDescendantContext","activeDescendantController","clearSelection","selectedOptions","selectOption","onKeyDown","event","action","open","activeOptionId","active","next","first","prev","last","hasComboboxContext","comboboxSelectedOptions","ctx","comboboxSelectOption","optionContextValues","state","components","always","role","tabIndex","elementType"],"mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SACEC,wBAAwB,EACxBC,cAAc,EACdC,gBAAgB,EAChBC,aAAa,EACbC,IAAI,QACC,4BAA4B;AACnC,SAASC,kBAAkB,EAAEC,mBAAmB,QAAQ,mCAAmC;AAC3F,SACEC,mBAAmB,EACnBC,0BAA0B,EAC1BC,mCAAmC,QAC9B,uBAAuB;AAC9B,SAASC,wBAAwB,QAAQ,iCAAiC;AAC1E,SAASC,mBAAmB,QAAQ,kCAAkC;AACtE,SAASC,YAAY,QAAQ,2BAA2B;AACxD,SAASC,eAAe,QAAQ,iCAAiC;AACjE,SAASC,gBAAgB,QAAQ,mCAAmC;AAGpE,gEAAgE;AAChE,MAAMC,sBAAsB;IAC1BC,cAAcC;IACdC,cAAc;IACdC,iBAAiB,IAAM;AACzB;AAEA;;;;;;;;CAQC,GACD,OAAO,MAAMC,sBAAsB,CAACC,OAAqBC;IACvD,MAAM,EAAEC,WAAW,EAAE,GAAGF;IACxB,MAAMG,mBAAmBb;IACzB,MAAM,EAAEc,aAAa,EAAE,GAAGD;IAE1B,MAAM,EACJE,YAAYC,0BAA0B,EACtCC,eAAe,EACfC,UAAU,EACX,GAAGtB,oBAAsD;QACxDuB,aAAaC,CAAAA,KAAMA,GAAGC,SAAS,CAACC,QAAQ,CAACnB,iBAAiBoB,IAAI;IAChE;IAEA,MAAMC,0BAA0B3B;IAChC,MAAM4B,6BAA6B3B,wCAC/B0B,wBAAwBN,UAAU,GAClCA;IAEJ,MAAM,EAAEQ,cAAc,EAAEC,eAAe,EAAEC,YAAY,EAAE,GAAG3B,aAAaS;IAEvE,MAAMmB,YAAY,CAACC;QACjB,MAAMC,SAAShC,yBAAyB+B,OAAO;YAAEE,MAAM;QAAK;QAC5D,MAAMC,iBAAiBR,2BAA2BS,MAAM;QACxD,MAAM7B,eAAe4B,iBAAiBnB,cAAcmB,kBAAkB;QAEtE,OAAQF;YACN,KAAK;gBACH,IAAI1B,cAAc;oBAChBoB,2BAA2BU,IAAI;gBACjC,OAAO;oBACLV,2BAA2BW,KAAK;gBAClC;gBACA;YACF,KAAK;gBACH,IAAI/B,cAAc;oBAChBoB,2BAA2BY,IAAI;gBACjC,OAAO;oBACLZ,2BAA2BW,KAAK;gBAClC;gBACA;YACF,KAAK;YACL,KAAK;gBACHX,2BAA2BW,KAAK;gBAChC;YACF,KAAK;YACL,KAAK;gBACHX,2BAA2Ba,IAAI;gBAC/B;YACF,KAAK;YACL,KAAK;gBACHjC,gBAAgBuB,aAAaE,OAAOzB;gBACpC;QACJ;IACF;IAEA,+CAA+C;IAC/C,MAAMkC,qBAAqB5C,oBAAoBO;IAC/C,MAAMsC,0BAA0B9C,mBAAmBQ,iBAAiBuC,CAAAA,MAAOA,IAAId,eAAe;IAC9F,MAAMe,uBAAuBhD,mBAAmBQ,iBAAiBuC,CAAAA,MAAOA,IAAIb,YAAY;IAExF,0EAA0E;IAC1E,MAAMe,sBAAsBJ,qBACxB;QACEZ,iBAAiBa;QACjBZ,cAAcc;QACd,GAAGtC,mBAAmB;IACxB,IACA;QACEuB;QACAC;QACA,GAAGxB,mBAAmB;IACxB;IAEJ,MAAMwC,QAAsB;QAC1BC,YAAY;YACVtB,MAAM;QACR;QACAA,MAAM9B,KAAKqD,MAAM,CACfzD,yBAAyB,OAAO;YAC9B,SAAS;YACT,4EAA4E;YAC5E,4FAA4F;YAC5FsB,KAAKnB,cAAcmB,KAAkCM,iBAAiBD;YACtE+B,MAAMnC,cAAc,SAAS;YAC7BoC,UAAU;YACV,GAAGtC,KAAK;QACV,IACA;YAAEuC,aAAa;QAAM;QAEvBrC;QACAc;QACAD;QACA,GAAGZ,gBAAgB;QACnB,GAAG8B,mBAAmB;IACxB;IAEAC,MAAMrB,IAAI,CAACM,SAAS,GAAGtC,iBAAiBD,eAAesD,MAAMrB,IAAI,CAACM,SAAS,EAAEA;IAE7E,OAAOe;AACT,EAAE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["Option.types.ts"],"sourcesContent":["import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nexport type OptionSlots = {\n /* The root option slot, with role=\"option\" */\n root: NonNullable<Slot<'div'>>;\n\n /* The check icon that is visible for selected options */\n checkIcon: Slot<'span'>;\n};\n\n/**\n * Option Props\n */\nexport type OptionProps = ComponentProps<Partial<OptionSlots>> & {\n /**\n * Sets an option to the `disabled` state.\n * Disabled options cannot be selected, but are still keyboard navigable\n */\n disabled?: boolean;\n\n /*\n * Defines a unique identifier for the option.\n * Use this to control selectedOptions, or to get the option value in the onOptionSelect callback.\n * Defaults to `text` if not provided.\n */\n value?: string;\n} & (\n | {\n /**\n * An optional override the string value of the Option's display text,\n * defaulting to the Option's child content.\n * This is used as the Dropdown button's or Combobox input's value when the option is selected,\n * and as the comparison for type-to-find keyboard functionality.\n */\n text?: string;\n children: string;\n }\n | {\n /**\n * The string value of the Option's display text when the Option's children are not a string.\n * This is used as the Dropdown button's or Combobox input's value when the option is selected,\n * and as the comparison for type-to-find keyboard functionality.\n */\n text: string;\n children?: React.ReactNode;\n }\n );\n\n/**\n * State used in rendering Option\n */\nexport type OptionState = ComponentState<OptionSlots> &\n Pick<OptionProps, 'disabled'> & {\n
|
|
1
|
+
{"version":3,"sources":["Option.types.ts"],"sourcesContent":["import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nexport type OptionSlots = {\n /* The root option slot, with role=\"option\" */\n root: NonNullable<Slot<'div'>>;\n\n /* The check icon that is visible for selected options */\n checkIcon: Slot<'span'>;\n};\n\n/**\n * Option Props\n */\nexport type OptionProps = ComponentProps<Partial<OptionSlots>> & {\n /**\n * Sets an option to the `disabled` state.\n * Disabled options cannot be selected, but are still keyboard navigable\n */\n disabled?: boolean;\n\n /*\n * Defines a unique identifier for the option.\n * Use this to control selectedOptions, or to get the option value in the onOptionSelect callback.\n * Defaults to `text` if not provided.\n */\n value?: string;\n} & (\n | {\n /**\n * An optional override the string value of the Option's display text,\n * defaulting to the Option's child content.\n * This is used as the Dropdown button's or Combobox input's value when the option is selected,\n * and as the comparison for type-to-find keyboard functionality.\n */\n text?: string;\n children: string;\n }\n | {\n /**\n * The string value of the Option's display text when the Option's children are not a string.\n * This is used as the Dropdown button's or Combobox input's value when the option is selected,\n * and as the comparison for type-to-find keyboard functionality.\n */\n text: string;\n children?: React.ReactNode;\n }\n );\n\n/**\n * State used in rendering Option\n */\nexport type OptionState = ComponentState<OptionSlots> &\n Pick<OptionProps, 'disabled'> & {\n /**\n * @deprecated - no longer used internally\n */\n active: boolean;\n\n /**\n * @deprecated - no longer used internally\n */\n focusVisible: boolean;\n\n /* If true, the option is part of a multiselect combobox or listbox */\n multiselect?: boolean;\n\n /* If true, the option is selected */\n selected: boolean;\n };\n"],"names":["React"],"mappings":"AACA,YAAYA,WAAW,QAAQ"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { getIntrinsicElementProps, useId, useMergedRefs, slot } from '@fluentui/react-utilities';
|
|
3
3
|
import { useContextSelector } from '@fluentui/react-context-selector';
|
|
4
|
+
import { useActiveDescendantContext } from '@fluentui/react-aria';
|
|
4
5
|
import { CheckmarkFilled, Checkmark12Filled } from '@fluentui/react-icons';
|
|
5
6
|
import { ComboboxContext } from '../../contexts/ComboboxContext';
|
|
6
7
|
import { ListboxContext } from '../../contexts/ListboxContext';
|
|
@@ -51,8 +52,8 @@ function getTextString(text, children) {
|
|
|
51
52
|
optionText,
|
|
52
53
|
optionValue
|
|
53
54
|
]);
|
|
55
|
+
const { controller: activeDescendantController } = useActiveDescendantContext();
|
|
54
56
|
// context values
|
|
55
|
-
const focusVisible = useContextSelector(ListboxContext, (ctx)=>ctx.focusVisible);
|
|
56
57
|
const multiselect = useContextSelector(ListboxContext, (ctx)=>ctx.multiselect);
|
|
57
58
|
const registerOption = useContextSelector(ListboxContext, (ctx)=>ctx.registerOption);
|
|
58
59
|
const selected = useContextSelector(ListboxContext, (ctx)=>{
|
|
@@ -60,13 +61,7 @@ function getTextString(text, children) {
|
|
|
60
61
|
return !!optionValue && !!selectedOptions.find((o)=>o === optionValue);
|
|
61
62
|
});
|
|
62
63
|
const selectOption = useContextSelector(ListboxContext, (ctx)=>ctx.selectOption);
|
|
63
|
-
const setActiveOption = useContextSelector(ListboxContext, (ctx)=>ctx.setActiveOption);
|
|
64
64
|
const setOpen = useContextSelector(ComboboxContext, (ctx)=>ctx.setOpen);
|
|
65
|
-
// current active option?
|
|
66
|
-
const active = useContextSelector(ListboxContext, (ctx)=>{
|
|
67
|
-
var _ctx_activeOption, _ctx_activeOption1;
|
|
68
|
-
return ((_ctx_activeOption = ctx.activeOption) === null || _ctx_activeOption === void 0 ? void 0 : _ctx_activeOption.id) !== undefined && ((_ctx_activeOption1 = ctx.activeOption) === null || _ctx_activeOption1 === void 0 ? void 0 : _ctx_activeOption1.id) === id;
|
|
69
|
-
});
|
|
70
65
|
// check icon
|
|
71
66
|
let CheckIcon = /*#__PURE__*/ React.createElement(CheckmarkFilled, null);
|
|
72
67
|
if (multiselect) {
|
|
@@ -79,7 +74,7 @@ function getTextString(text, children) {
|
|
|
79
74
|
return;
|
|
80
75
|
}
|
|
81
76
|
// clicked option should always become active option
|
|
82
|
-
|
|
77
|
+
activeDescendantController.focus(id);
|
|
83
78
|
// close on option click for single-select options in a combobox
|
|
84
79
|
if (!multiselect) {
|
|
85
80
|
setOpen === null || setOpen === void 0 ? void 0 : setOpen(event, false);
|
|
@@ -131,10 +126,11 @@ function getTextString(text, children) {
|
|
|
131
126
|
},
|
|
132
127
|
elementType: 'span'
|
|
133
128
|
}),
|
|
134
|
-
active,
|
|
135
129
|
disabled,
|
|
136
|
-
focusVisible,
|
|
137
130
|
multiselect,
|
|
138
|
-
selected
|
|
131
|
+
selected,
|
|
132
|
+
// no longer used
|
|
133
|
+
focusVisible: false,
|
|
134
|
+
active: false
|
|
139
135
|
};
|
|
140
136
|
};
|