Outlook_Addin_LLM/node_modules/@fluentui/react-combobox/lib/utils/useTriggerSlot.js

142 lines
4.7 KiB
JavaScript
Raw Normal View History

import * as React from 'react';
import { useSetKeyboardNavigation } from '@fluentui/react-tabster';
import { mergeCallbacks, slot, useEventCallback, useMergedRefs } from '@fluentui/react-utilities';
import { getDropdownActionFromKey } from '../utils/dropdownKeyActions';
/**
* Shared trigger behaviour for combobox and dropdown
* @returns trigger slot with desired behaviour and props
*/ export function useTriggerSlot(triggerSlotFromProp, ref, options) {
const { state: { open, setOpen, setHasFocus }, defaultProps, elementType, activeDescendantController } = options;
const trigger = slot.always(triggerSlotFromProp, {
defaultProps: {
type: 'text',
'aria-expanded': open,
role: 'combobox',
...typeof defaultProps === 'object' && defaultProps
},
elementType
});
// handle trigger focus/blur
const triggerRef = React.useRef(null);
trigger.ref = useMergedRefs(triggerRef, trigger.ref, ref);
// the trigger should open/close the popup on click or blur
trigger.onBlur = mergeCallbacks((event)=>{
setOpen(event, false);
setHasFocus(false);
}, trigger.onBlur);
trigger.onFocus = mergeCallbacks((event)=>{
if (event.target === event.currentTarget) {
setHasFocus(true);
}
}, trigger.onFocus);
trigger.onClick = mergeCallbacks((event)=>{
setOpen(event, !open);
}, trigger.onClick);
// handle combobox keyboard interaction
trigger.onKeyDown = mergeCallbacks(useTriggerKeydown({
activeDescendantController,
...options.state
}), trigger.onKeyDown);
return trigger;
}
function useTriggerKeydown(options) {
const { activeDescendantController, getOptionById, setOpen, selectOption, multiselect, open } = options;
const getActiveOption = React.useCallback(()=>{
const activeOptionId = activeDescendantController.active();
return activeOptionId ? getOptionById(activeOptionId) : undefined;
}, [
activeDescendantController,
getOptionById
]);
const first = ()=>{
activeDescendantController.first();
};
const last = ()=>{
activeDescendantController.last();
};
const next = (activeOption)=>{
if (activeOption) {
activeDescendantController.next();
} else {
activeDescendantController.first();
}
};
const previous = (activeOption)=>{
if (activeOption) {
activeDescendantController.prev();
} else {
activeDescendantController.first();
}
};
const pageUp = ()=>{
for(let i = 0; i < 10; i++){
activeDescendantController.prev();
}
};
const pageDown = ()=>{
for(let i = 0; i < 10; i++){
activeDescendantController.next();
}
};
const setKeyboardNavigation = useSetKeyboardNavigation();
return useEventCallback((e)=>{
const action = getDropdownActionFromKey(e, {
open,
multiselect
});
const activeOption = getActiveOption();
switch(action){
case 'First':
case 'Last':
case 'Next':
case 'Previous':
case 'PageDown':
case 'PageUp':
case 'Open':
case 'Close':
case 'CloseSelect':
case 'Select':
e.preventDefault();
break;
}
setKeyboardNavigation(true);
switch(action){
case 'First':
first();
break;
case 'Last':
last();
break;
case 'Next':
next(activeOption);
break;
case 'Previous':
previous(activeOption);
break;
case 'PageDown':
pageDown();
break;
case 'PageUp':
pageUp();
break;
case 'Open':
setOpen(e, true);
break;
case 'Close':
// stop propagation for escape key to avoid dismissing any parent popups
e.stopPropagation();
setOpen(e, false);
break;
case 'CloseSelect':
!multiselect && !(activeOption === null || activeOption === void 0 ? void 0 : activeOption.disabled) && setOpen(e, false);
// fallthrough
case 'Select':
activeOption && selectOption(e, activeOption);
break;
case 'Tab':
!multiselect && activeOption && selectOption(e, activeOption);
break;
}
});
}