@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.
Files changed (78) hide show
  1. package/CHANGELOG.md +26 -5
  2. package/dist/index.d.ts +54 -11
  3. package/lib/components/Combobox/Combobox.types.js.map +1 -1
  4. package/lib/components/Combobox/renderCombobox.js +15 -11
  5. package/lib/components/Combobox/renderCombobox.js.map +1 -1
  6. package/lib/components/Combobox/useCombobox.js +12 -4
  7. package/lib/components/Combobox/useCombobox.js.map +1 -1
  8. package/lib/components/Combobox/useInputTriggerSlot.js +14 -12
  9. package/lib/components/Combobox/useInputTriggerSlot.js.map +1 -1
  10. package/lib/components/Dropdown/Dropdown.types.js.map +1 -1
  11. package/lib/components/Dropdown/renderDropdown.js +19 -15
  12. package/lib/components/Dropdown/renderDropdown.js.map +1 -1
  13. package/lib/components/Dropdown/useButtonTriggerSlot.js +51 -31
  14. package/lib/components/Dropdown/useButtonTriggerSlot.js.map +1 -1
  15. package/lib/components/Dropdown/useDropdown.js +14 -4
  16. package/lib/components/Dropdown/useDropdown.js.map +1 -1
  17. package/lib/components/Listbox/Listbox.types.js.map +1 -1
  18. package/lib/components/Listbox/renderListbox.js +7 -3
  19. package/lib/components/Listbox/renderListbox.js.map +1 -1
  20. package/lib/components/Listbox/useListbox.js +43 -35
  21. package/lib/components/Listbox/useListbox.js.map +1 -1
  22. package/lib/components/Option/Option.types.js.map +1 -1
  23. package/lib/components/Option/useOption.js +7 -11
  24. package/lib/components/Option/useOption.js.map +1 -1
  25. package/lib/components/Option/useOptionStyles.styles.js +27 -28
  26. package/lib/components/Option/useOptionStyles.styles.js.map +1 -1
  27. package/lib/contexts/useComboboxContextValues.js +14 -5
  28. package/lib/contexts/useComboboxContextValues.js.map +1 -1
  29. package/lib/contexts/useListboxContextValues.js +12 -5
  30. package/lib/contexts/useListboxContextValues.js.map +1 -1
  31. package/lib/utils/ComboboxBase.types.js.map +1 -1
  32. package/lib/utils/OptionCollection.types.js.map +1 -1
  33. package/lib/utils/Selection.types.js.map +1 -1
  34. package/lib/utils/dropdownKeyActions.js +0 -21
  35. package/lib/utils/dropdownKeyActions.js.map +1 -1
  36. package/lib/utils/useComboboxBaseState.js +52 -14
  37. package/lib/utils/useComboboxBaseState.js.map +1 -1
  38. package/lib/utils/useOptionCollection.js +18 -45
  39. package/lib/utils/useOptionCollection.js.map +1 -1
  40. package/lib/utils/useTriggerSlot.js +86 -33
  41. package/lib/utils/useTriggerSlot.js.map +1 -1
  42. package/lib-commonjs/components/Combobox/renderCombobox.js +15 -11
  43. package/lib-commonjs/components/Combobox/renderCombobox.js.map +1 -1
  44. package/lib-commonjs/components/Combobox/useCombobox.js +12 -4
  45. package/lib-commonjs/components/Combobox/useCombobox.js.map +1 -1
  46. package/lib-commonjs/components/Combobox/useInputTriggerSlot.js +14 -12
  47. package/lib-commonjs/components/Combobox/useInputTriggerSlot.js.map +1 -1
  48. package/lib-commonjs/components/Dropdown/renderDropdown.js +19 -15
  49. package/lib-commonjs/components/Dropdown/renderDropdown.js.map +1 -1
  50. package/lib-commonjs/components/Dropdown/useButtonTriggerSlot.js +51 -31
  51. package/lib-commonjs/components/Dropdown/useButtonTriggerSlot.js.map +1 -1
  52. package/lib-commonjs/components/Dropdown/useDropdown.js +14 -4
  53. package/lib-commonjs/components/Dropdown/useDropdown.js.map +1 -1
  54. package/lib-commonjs/components/Listbox/renderListbox.js +7 -3
  55. package/lib-commonjs/components/Listbox/renderListbox.js.map +1 -1
  56. package/lib-commonjs/components/Listbox/useListbox.js +42 -34
  57. package/lib-commonjs/components/Listbox/useListbox.js.map +1 -1
  58. package/lib-commonjs/components/Option/useOption.js +7 -11
  59. package/lib-commonjs/components/Option/useOption.js.map +1 -1
  60. package/lib-commonjs/components/Option/useOptionStyles.styles.js +85 -85
  61. package/lib-commonjs/components/Option/useOptionStyles.styles.js.map +1 -1
  62. package/lib-commonjs/contexts/useComboboxContextValues.js +13 -5
  63. package/lib-commonjs/contexts/useComboboxContextValues.js.map +1 -1
  64. package/lib-commonjs/contexts/useListboxContextValues.js +13 -5
  65. package/lib-commonjs/contexts/useListboxContextValues.js.map +1 -1
  66. package/lib-commonjs/utils/dropdownKeyActions.js +3 -30
  67. package/lib-commonjs/utils/dropdownKeyActions.js.map +1 -1
  68. package/lib-commonjs/utils/useComboboxBaseState.js +52 -14
  69. package/lib-commonjs/utils/useComboboxBaseState.js.map +1 -1
  70. package/lib-commonjs/utils/useOptionCollection.js +18 -45
  71. package/lib-commonjs/utils/useOptionCollection.js.map +1 -1
  72. package/lib-commonjs/utils/useTriggerSlot.js +84 -31
  73. package/lib-commonjs/utils/useTriggerSlot.js.map +1 -1
  74. package/package.json +9 -8
  75. package/lib/utils/useScrollOptionsIntoView.js +0 -29
  76. package/lib/utils/useScrollOptionsIntoView.js.map +0 -1
  77. package/lib-commonjs/utils/useScrollOptionsIntoView.js +0 -40
  78. 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, activeOption, setOpen, getOptionsMatchingText, getIndexOfId, setActiveOption, setFocusVisible }, defaultProps } = options;
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 getNextMatchingOption = ()=>{
15
- // first check for matches for the full searchString
16
- let matcher = (optionText)=>optionText.toLowerCase().indexOf(searchString.current) === 0;
17
- let matches = getOptionsMatchingText(matcher);
18
- let startIndex = activeOption ? getIndexOfId(activeOption.id) : 0;
19
- // if the dropdown is already open and the searchstring is a single character,
20
- // then look after the current activeOption for letters
21
- // this is so slowly typing the same letter will cycle through matches
22
- if (open && searchString.current.length === 1) {
23
- startIndex++;
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 (!matches.length) {
27
- const letters = searchString.current.split('');
28
- const allSameLetter = letters.length && letters.every((letter)=>letter === letters[0]);
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
- if (allSameLetter) {
31
- startIndex++;
32
- matcher = (optionText)=>optionText.toLowerCase().indexOf(letters[0]) === 0;
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
- var _matches_;
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
- const nextOption = getNextMatchingOption();
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 { useTriggerSlot, UseTriggerSlotState } from '../../utils/useTriggerSlot';\nimport { OptionValue } from '../../utils/OptionCollection.types';\nimport { getDropdownActionFromKey } from '../../utils/dropdownKeyActions';\nimport { DropdownState } from './Dropdown.types';\n\ntype UsedDropdownState = UseTriggerSlotState & Pick<DropdownState, 'getOptionsMatchingText'>;\ntype UseButtonTriggerSlotOptions = {\n state: UsedDropdownState;\n defaultProps: unknown;\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, activeOption, setOpen, getOptionsMatchingText, getIndexOfId, setActiveOption, setFocusVisible },\n defaultProps,\n } = options;\n\n // jump to matching option based on typing\n const searchString = React.useRef('');\n const [setKeyTimeout, clearKeyTimeout] = useTimeout();\n\n const getNextMatchingOption = (): OptionValue | undefined => {\n // first check for matches for the full searchString\n let matcher = (optionText: string) => optionText.toLowerCase().indexOf(searchString.current) === 0;\n let matches = getOptionsMatchingText(matcher);\n let startIndex = activeOption ? getIndexOfId(activeOption.id) : 0;\n\n // if the dropdown is already open and the searchstring is a single character,\n // then look after the current activeOption for letters\n // this is so slowly typing the same letter will cycle through matches\n if (open && searchString.current.length === 1) {\n startIndex++;\n }\n\n // if there are no direct matches, check if the search is all the same letter, e.g. \"aaa\"\n if (!matches.length) {\n const letters = searchString.current.split('');\n const allSameLetter = letters.length && letters.every(letter => letter === letters[0]);\n\n // if the search is all the same letter, cycle through options starting with that letter\n if (allSameLetter) {\n startIndex++;\n matcher = (optionText: string) => optionText.toLowerCase().indexOf(letters[0]) === 0;\n matches = getOptionsMatchingText(matcher);\n }\n }\n\n // if there is an active option and multiple matches,\n // return first matching option after the current active option, looping back to the top\n if (matches.length > 1 && activeOption) {\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 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\n const nextOption = getNextMatchingOption();\n setActiveOption(nextOption);\n setFocusVisible(true);\n }\n };\n\n const trigger = useTriggerSlot(triggerFromProps, ref, { state: options.state, defaultProps, elementType: 'button' });\n trigger.onKeyDown = mergeCallbacks(onTriggerKeyDown, trigger.onKeyDown);\n\n return trigger;\n}\n"],"names":["React","useTimeout","mergeCallbacks","useTriggerSlot","getDropdownActionFromKey","useButtonTriggerSlot","triggerFromProps","ref","options","state","open","activeOption","setOpen","getOptionsMatchingText","getIndexOfId","setActiveOption","setFocusVisible","defaultProps","searchString","useRef","setKeyTimeout","clearKeyTimeout","getNextMatchingOption","matcher","optionText","toLowerCase","indexOf","current","matches","startIndex","id","length","letters","split","allSameLetter","every","letter","nextMatch","find","option","undefined","onTriggerKeyDown","ev","key","nextOption","trigger","elementType","onKeyDown"],"mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,UAAU,EAAEC,cAAc,QAAQ,4BAA4B;AAEvE,SAASC,cAAc,QAA6B,6BAA6B;AAEjF,SAASC,wBAAwB,QAAQ,iCAAiC;AAS1E;;;;CAIC,GACD,OAAO,SAASC,qBACdC,gBAA6C,EAC7CC,GAAiC,EACjCC,OAAoC;IAEpC,MAAM,EACJC,OAAO,EAAEC,IAAI,EAAEC,YAAY,EAAEC,OAAO,EAAEC,sBAAsB,EAAEC,YAAY,EAAEC,eAAe,EAAEC,eAAe,EAAE,EAC9GC,YAAY,EACb,GAAGT;IAEJ,0CAA0C;IAC1C,MAAMU,eAAelB,MAAMmB,MAAM,CAAC;IAClC,MAAM,CAACC,eAAeC,gBAAgB,GAAGpB;IAEzC,MAAMqB,wBAAwB;QAC5B,oDAAoD;QACpD,IAAIC,UAAU,CAACC,aAAuBA,WAAWC,WAAW,GAAGC,OAAO,CAACR,aAAaS,OAAO,MAAM;QACjG,IAAIC,UAAUf,uBAAuBU;QACrC,IAAIM,aAAalB,eAAeG,aAAaH,aAAamB,EAAE,IAAI;QAEhE,8EAA8E;QAC9E,uDAAuD;QACvD,sEAAsE;QACtE,IAAIpB,QAAQQ,aAAaS,OAAO,CAACI,MAAM,KAAK,GAAG;YAC7CF;QACF;QAEA,yFAAyF;QACzF,IAAI,CAACD,QAAQG,MAAM,EAAE;YACnB,MAAMC,UAAUd,aAAaS,OAAO,CAACM,KAAK,CAAC;YAC3C,MAAMC,gBAAgBF,QAAQD,MAAM,IAAIC,QAAQG,KAAK,CAACC,CAAAA,SAAUA,WAAWJ,OAAO,CAAC,EAAE;YAErF,wFAAwF;YACxF,IAAIE,eAAe;gBACjBL;gBACAN,UAAU,CAACC,aAAuBA,WAAWC,WAAW,GAAGC,OAAO,CAACM,OAAO,CAAC,EAAE,MAAM;gBACnFJ,UAAUf,uBAAuBU;YACnC;QACF;QAEA,qDAAqD;QACrD,wFAAwF;QACxF,IAAIK,QAAQG,MAAM,GAAG,KAAKpB,cAAc;YACtC,MAAM0B,YAAYT,QAAQU,IAAI,CAACC,CAAAA,SAAUzB,aAAayB,OAAOT,EAAE,KAAKD;YACpE,OAAOQ,sBAAAA,uBAAAA,YAAaT,OAAO,CAAC,EAAE;QAChC;YAEOA;QAAP,OAAOA,CAAAA,YAAAA,OAAO,CAAC,EAAE,cAAVA,uBAAAA,YAAcY;IACvB;IAEA,MAAMC,mBAAmB,CAACC;QACxB,8BAA8B;QAC9BrB;QAEA,kDAAkD;QAClD,IAAIjB,yBAAyBsC,QAAQ,QAAQ;YAC3C,uBAAuB;YACvBxB,aAAaS,OAAO,IAAIe,GAAGC,GAAG,CAAClB,WAAW;YAC1CL,cAAc;gBACZF,aAAaS,OAAO,GAAG;YACzB,GAAG;YAEH,eAAe;YACf,CAACjB,QAAQE,QAAQ8B,IAAI;YAErB,MAAME,aAAatB;YACnBP,gBAAgB6B;YAChB5B,gBAAgB;QAClB;IACF;IAEA,MAAM6B,UAAU1C,eAAeG,kBAAkBC,KAAK;QAAEE,OAAOD,QAAQC,KAAK;QAAEQ;QAAc6B,aAAa;IAAS;IAClHD,QAAQE,SAAS,GAAG7C,eAAeuC,kBAAkBI,QAAQE,SAAS;IAEtE,OAAOF;AACT"}
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 baseState = useComboboxBaseState(props);
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","root","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
+ {"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 /* Option data for the currently highlighted option (not the selected option) */\n activeOption?: OptionValue;\n\n // Whether the keyboard focus outline style should be visible\n focusVisible: boolean;\n\n selectOption(event: SelectionEvents, option: OptionValue): void;\n\n setActiveOption(option?: OptionValue): void;\n };\n\nexport type ListboxContextValues = {\n listbox: ListboxContextValue;\n};\n"],"names":[],"mappings":"AAAA,WAmCE"}
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(ListboxContext.Provider, {
9
- value: contextValues.listbox,
10
- children: /*#__PURE__*/ _jsx(state.root, {})
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 <state.root />\n </ListboxContext.Provider>\n );\n};\n"],"names":["assertSlots","ListboxContext","renderListbox_unstable","state","contextValues","Provider","value","listbox","root"],"mappings":"AAAA,0BAA0B,GAC1B,iDAAiD;AAEjD,SAASA,WAAW,QAAQ,4BAA4B;AAExD,SAASC,cAAc,QAAQ,gCAAgC;AAE/D;;CAEC,GACD,OAAO,MAAMC,yBAAyB,CAACC,OAAqBC;IAC1DJ,YAA0BG;IAE1B,qBACE,KAACF,eAAeI,QAAQ;QAACC,OAAOF,cAAcG,OAAO;kBACnD,cAAA,KAACJ,MAAMK,IAAI;;AAGjB,EAAE"}
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 { getDropdownActionFromKey, getIndexFromAction } from '../../utils/dropdownKeyActions';
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 { getCount, getOptionAtIndex, getIndexOfId } = optionCollection;
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 maxIndex = getCount() - 1;
31
- const activeIndex = activeOption ? getIndexOfId(activeOption.id) : -1;
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
- setActiveOption: comboboxSetActiveOption
77
+ ...UNSAFE_noLongerUsed
65
78
  } : {
66
- activeOption,
67
- focusVisible,
68
79
  selectedOptions,
69
80
  selectOption,
70
- setActiveOption
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 { getDropdownActionFromKey, getIndexFromAction } from '../../utils/dropdownKeyActions';\nimport type { OptionValue } from '../../utils/OptionCollection.types';\nimport { useOptionCollection } from '../../utils/useOptionCollection';\nimport { useScrollOptionsIntoView } from '../../utils/useScrollOptionsIntoView';\nimport { useSelection } from '../../utils/useSelection';\nimport { ComboboxContext } from '../../contexts/ComboboxContext';\nimport type { ListboxProps, ListboxState } from './Listbox.types';\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 { getCount, getOptionAtIndex, getIndexOfId } = optionCollection;\n\n const { clearSelection, selectedOptions, selectOption } = useSelection(props);\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 const onKeyDown = (event: React.KeyboardEvent<HTMLElement>) => {\n const action = getDropdownActionFromKey(event, { open: true });\n const maxIndex = getCount() - 1;\n const activeIndex = activeOption ? getIndexOfId(activeOption.id) : -1;\n let newIndex = activeIndex;\n\n switch (action) {\n case 'Select':\n case 'CloseSelect':\n activeOption && selectOption(event, activeOption);\n break;\n default:\n newIndex = getIndexFromAction(action, activeIndex, maxIndex);\n }\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\n const onMouseOver = (event: React.MouseEvent<HTMLElement>) => {\n setFocusVisible(false);\n };\n\n // get state from parent combobox, if it exists\n const hasComboboxContext = useHasParentContext(ComboboxContext);\n const comboboxActiveOption = useContextSelector(ComboboxContext, ctx => ctx.activeOption);\n const comboboxFocusVisible = useContextSelector(ComboboxContext, ctx => ctx.focusVisible);\n const comboboxSelectedOptions = useContextSelector(ComboboxContext, ctx => ctx.selectedOptions);\n const comboboxSelectOption = useContextSelector(ComboboxContext, ctx => ctx.selectOption);\n const comboboxSetActiveOption = useContextSelector(ComboboxContext, ctx => ctx.setActiveOption);\n\n // without a parent combobox context, provide values directly from Listbox\n const optionContextValues = hasComboboxContext\n ? {\n activeOption: comboboxActiveOption,\n focusVisible: comboboxFocusVisible,\n selectedOptions: comboboxSelectedOptions,\n selectOption: comboboxSelectOption,\n setActiveOption: comboboxSetActiveOption,\n }\n : {\n activeOption,\n focusVisible,\n selectedOptions,\n selectOption,\n setActiveOption,\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: ref as React.Ref<HTMLDivElement>,\n role: multiselect ? 'menu' : 'listbox',\n 'aria-activedescendant': hasComboboxContext ? undefined : activeOption?.id,\n tabIndex: 0,\n ...props,\n }),\n { elementType: 'div' },\n ),\n multiselect,\n clearSelection,\n ...optionCollection,\n ...optionContextValues,\n };\n\n const scrollContainerRef = useScrollOptionsIntoView(state);\n state.root.ref = useMergedRefs(state.root.ref, scrollContainerRef);\n\n state.root.onKeyDown = useEventCallback(mergeCallbacks(state.root.onKeyDown, onKeyDown));\n state.root.onMouseOver = useEventCallback(mergeCallbacks(state.root.onMouseOver, onMouseOver));\n\n return state;\n};\n"],"names":["React","getIntrinsicElementProps","mergeCallbacks","useEventCallback","useMergedRefs","slot","useContextSelector","useHasParentContext","getDropdownActionFromKey","getIndexFromAction","useOptionCollection","useScrollOptionsIntoView","useSelection","ComboboxContext","useListbox_unstable","props","ref","multiselect","optionCollection","getCount","getOptionAtIndex","getIndexOfId","clearSelection","selectedOptions","selectOption","activeOption","setActiveOption","useState","focusVisible","setFocusVisible","onKeyDown","event","action","open","maxIndex","activeIndex","id","newIndex","preventDefault","onMouseOver","hasComboboxContext","comboboxActiveOption","ctx","comboboxFocusVisible","comboboxSelectedOptions","comboboxSelectOption","comboboxSetActiveOption","optionContextValues","state","components","root","always","role","undefined","tabIndex","elementType","scrollContainerRef"],"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,SAASC,wBAAwB,EAAEC,kBAAkB,QAAQ,iCAAiC;AAE9F,SAASC,mBAAmB,QAAQ,kCAAkC;AACtE,SAASC,wBAAwB,QAAQ,uCAAuC;AAChF,SAASC,YAAY,QAAQ,2BAA2B;AACxD,SAASC,eAAe,QAAQ,iCAAiC;AAGjE;;;;;;;;CAQC,GACD,OAAO,MAAMC,sBAAsB,CAACC,OAAqBC;IACvD,MAAM,EAAEC,WAAW,EAAE,GAAGF;IACxB,MAAMG,mBAAmBR;IACzB,MAAM,EAAES,QAAQ,EAAEC,gBAAgB,EAAEC,YAAY,EAAE,GAAGH;IAErD,MAAM,EAAEI,cAAc,EAAEC,eAAe,EAAEC,YAAY,EAAE,GAAGZ,aAAaG;IAEvE,MAAM,CAACU,cAAcC,gBAAgB,GAAG1B,MAAM2B,QAAQ;IAEtD,uDAAuD;IACvD,yFAAyF;IACzF,MAAM,CAACC,cAAcC,gBAAgB,GAAG7B,MAAM2B,QAAQ,CAAC;IAEvD,MAAMG,YAAY,CAACC;QACjB,MAAMC,SAASxB,yBAAyBuB,OAAO;YAAEE,MAAM;QAAK;QAC5D,MAAMC,WAAWf,aAAa;QAC9B,MAAMgB,cAAcV,eAAeJ,aAAaI,aAAaW,EAAE,IAAI,CAAC;QACpE,IAAIC,WAAWF;QAEf,OAAQH;YACN,KAAK;YACL,KAAK;gBACHP,gBAAgBD,aAAaO,OAAON;gBACpC;YACF;gBACEY,WAAW5B,mBAAmBuB,QAAQG,aAAaD;QACvD;QAEA,IAAIG,aAAaF,aAAa;YAC5B,mEAAmE;YACnEJ,MAAMO,cAAc;YACpBZ,gBAAgBN,iBAAiBiB;YACjCR,gBAAgB;QAClB;IACF;IAEA,MAAMU,cAAc,CAACR;QACnBF,gBAAgB;IAClB;IAEA,+CAA+C;IAC/C,MAAMW,qBAAqBjC,oBAAoBM;IAC/C,MAAM4B,uBAAuBnC,mBAAmBO,iBAAiB6B,CAAAA,MAAOA,IAAIjB,YAAY;IACxF,MAAMkB,uBAAuBrC,mBAAmBO,iBAAiB6B,CAAAA,MAAOA,IAAId,YAAY;IACxF,MAAMgB,0BAA0BtC,mBAAmBO,iBAAiB6B,CAAAA,MAAOA,IAAInB,eAAe;IAC9F,MAAMsB,uBAAuBvC,mBAAmBO,iBAAiB6B,CAAAA,MAAOA,IAAIlB,YAAY;IACxF,MAAMsB,0BAA0BxC,mBAAmBO,iBAAiB6B,CAAAA,MAAOA,IAAIhB,eAAe;IAE9F,0EAA0E;IAC1E,MAAMqB,sBAAsBP,qBACxB;QACEf,cAAcgB;QACdb,cAAce;QACdpB,iBAAiBqB;QACjBpB,cAAcqB;QACdnB,iBAAiBoB;IACnB,IACA;QACErB;QACAG;QACAL;QACAC;QACAE;IACF;IAEJ,MAAMsB,QAAsB;QAC1BC,YAAY;YACVC,MAAM;QACR;QACAA,MAAM7C,KAAK8C,MAAM,CACflD,yBAAyB,OAAO;YAC9B,SAAS;YACT,4EAA4E;YAC5E,4FAA4F;YAC5Fe,KAAKA;YACLoC,MAAMnC,cAAc,SAAS;YAC7B,yBAAyBuB,qBAAqBa,YAAY5B,yBAAAA,mCAAAA,aAAcW,EAAE;YAC1EkB,UAAU;YACV,GAAGvC,KAAK;QACV,IACA;YAAEwC,aAAa;QAAM;QAEvBtC;QACAK;QACA,GAAGJ,gBAAgB;QACnB,GAAG6B,mBAAmB;IACxB;IAEA,MAAMS,qBAAqB7C,yBAAyBqC;IACpDA,MAAME,IAAI,CAAClC,GAAG,GAAGZ,cAAc4C,MAAME,IAAI,CAAClC,GAAG,EAAEwC;IAE/CR,MAAME,IAAI,CAACpB,SAAS,GAAG3B,iBAAiBD,eAAe8C,MAAME,IAAI,CAACpB,SAAS,EAAEA;IAC7EkB,MAAME,IAAI,CAACX,WAAW,GAAGpC,iBAAiBD,eAAe8C,MAAME,IAAI,CAACX,WAAW,EAAEA;IAEjF,OAAOS;AACT,EAAE"}
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":"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"}
@@ -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 /* If true, this is the currently highlighted option */\n active: boolean;\n\n // Whether the keyboard focus outline style should be visible\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
+ {"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
- setActiveOption(optionData);
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
  };