Initial commit

This commit is contained in:
2025-03-07 19:22:02 +01:00
commit 4a98255d83
55743 changed files with 5280367 additions and 0 deletions
@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/OptionCollection.types.ts"],"sourcesContent":["export type OptionValue = {\n /** The disabled state of the option. */\n disabled?: boolean;\n\n /** The `id` attribute of the option. */\n id: string;\n\n /** The `text` string for the option. */\n text: string;\n\n /** The value string of the option. */\n value: string;\n};\n\nexport type OptionCollectionState = {\n /**\n * @deprecated - no longer used internally\n */\n getIndexOfId(id: string): number;\n\n /**\n * @deprecated - no longer used internally\n */\n getOptionAtIndex(index: number): OptionValue | undefined;\n\n /**\n * @deprecated - no longer used internally\n */\n getOptionsMatchingText(matcher: (text: string) => boolean): OptionValue[];\n\n /** The total number of options in the collection. */\n getCount: () => number;\n\n /** Returns the option data by key. */\n getOptionById(id: string): OptionValue | undefined;\n\n /** Returns an array of options filtered by a value matching function against the option's value string. */\n getOptionsMatchingValue(matcher: (value: string) => boolean): OptionValue[];\n\n /** The unordered option data. */\n options: OptionValue[];\n\n /** A function that child options call to register their values. Returns a function to unregister the option. */\n registerOption: (option: OptionValue, element: HTMLElement) => () => void;\n};\n"],"names":[],"rangeMappings":"","mappings":""}
@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/Selection.types.ts"],"sourcesContent":["import * as React from 'react';\nimport { OptionValue } from './OptionCollection.types';\n\nexport type SelectionProps = {\n /**\n * For an uncontrolled component, sets the initial selection.\n * If this is set, the `defaultValue` prop MUST also be set.\n */\n defaultSelectedOptions?: string[];\n\n /**\n * Sets the selection type to multiselect.\n * Set this to true for multiselect, even if fully controlling selection state.\n * This enables styles and accessibility properties to be set.\n * @default false\n */\n multiselect?: boolean;\n\n /** Callback when an option is selected */\n // eslint-disable-next-line @nx/workspace-consistent-callback-type -- can't change type of existing callback\n onOptionSelect?: (event: SelectionEvents, data: OptionOnSelectData) => void;\n\n /**\n * An array of selected option keys.\n * Use this with `onOptionSelect` to directly control the selected option(s)\n * If this is set, the `value` prop MUST also be controlled.\n */\n selectedOptions?: string[];\n};\n\n/** Values returned by the useSelection hook */\nexport type SelectionState = {\n clearSelection: (event: SelectionEvents) => void;\n selectedOptions: string[];\n selectOption: (event: SelectionEvents, option: OptionValue) => void;\n};\n\n/**\n * Data for the onOptionSelect callback.\n * `optionValue` and `optionText` will be undefined if multiple options are modified at once.\n */\nexport type OptionOnSelectData = {\n optionValue: string | undefined;\n optionText: string | undefined;\n selectedOptions: string[];\n};\n\n/** Possible event types for onOptionSelect */\nexport type SelectionEvents =\n | React.ChangeEvent<HTMLElement>\n | React.KeyboardEvent<HTMLElement>\n | React.MouseEvent<HTMLElement>;\n"],"names":[],"rangeMappings":";;;;;","mappings":";;;;;iEAAuB"}
@@ -0,0 +1,64 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "getDropdownActionFromKey", {
enumerable: true,
get: function() {
return getDropdownActionFromKey;
}
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _keyboardkeys = /*#__PURE__*/ _interop_require_wildcard._(require("@fluentui/keyboard-keys"));
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
function getDropdownActionFromKey(e, options = {}) {
const { open = true, multiselect = false } = options;
const code = e.key;
const { altKey, ctrlKey, key, metaKey } = e;
// typing action occurs whether open or closed
if (key.length === 1 && code !== _keyboardkeys.Space && !altKey && !ctrlKey && !metaKey) {
return 'Type';
}
// handle opening the dropdown if closed
if (!open) {
if (code === _keyboardkeys.ArrowDown || code === _keyboardkeys.ArrowUp || code === _keyboardkeys.Enter || code === _keyboardkeys.Space) {
return 'Open';
}
// if the dropdown is closed and an action did not match the above, do nothing
return 'None';
}
// select or close actions
if (code === _keyboardkeys.ArrowUp && altKey || code === _keyboardkeys.Enter || !multiselect && code === _keyboardkeys.Space) {
return 'CloseSelect';
}
if (multiselect && code === _keyboardkeys.Space) {
return 'Select';
}
if (code === _keyboardkeys.Escape) {
return 'Close';
}
// navigation interactions
if (code === _keyboardkeys.ArrowDown) {
return 'Next';
}
if (code === _keyboardkeys.ArrowUp) {
return 'Previous';
}
if (code === _keyboardkeys.Home) {
return 'First';
}
if (code === _keyboardkeys.End) {
return 'Last';
}
if (code === _keyboardkeys.PageUp) {
return 'PageUp';
}
if (code === _keyboardkeys.PageDown) {
return 'PageDown';
}
if (code === _keyboardkeys.Tab) {
return 'Tab';
}
// if nothing matched, return none
return 'None';
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/dropdownKeyActions.ts"],"sourcesContent":["import * as keys from '@fluentui/keyboard-keys';\nimport * as React from 'react';\n\n/**\n * enum of actions available in any type of managed dropdown control\n * e.g. combobox, select, datepicker, menu\n */\nexport type DropdownActions =\n | 'Close'\n | 'CloseSelect'\n | 'First'\n | 'Last'\n | 'Next'\n | 'None'\n | 'Open'\n | 'PageDown'\n | 'PageUp'\n | 'Previous'\n | 'Select'\n | 'Tab'\n | 'Type';\n\nexport interface DropdownActionOptions {\n open?: boolean;\n multiselect?: boolean;\n}\n\n/**\n * Converts a keyboard interaction into a defined action\n */\nexport function getDropdownActionFromKey(\n e: KeyboardEvent | React.KeyboardEvent,\n options: DropdownActionOptions = {},\n): DropdownActions {\n const { open = true, multiselect = false } = options;\n const code = e.key;\n const { altKey, ctrlKey, key, metaKey } = e;\n\n // typing action occurs whether open or closed\n if (key.length === 1 && code !== keys.Space && !altKey && !ctrlKey && !metaKey) {\n return 'Type';\n }\n\n // handle opening the dropdown if closed\n if (!open) {\n if (code === keys.ArrowDown || code === keys.ArrowUp || code === keys.Enter || code === keys.Space) {\n return 'Open';\n }\n\n // if the dropdown is closed and an action did not match the above, do nothing\n return 'None';\n }\n\n // select or close actions\n if ((code === keys.ArrowUp && altKey) || code === keys.Enter || (!multiselect && code === keys.Space)) {\n return 'CloseSelect';\n }\n if (multiselect && code === keys.Space) {\n return 'Select';\n }\n if (code === keys.Escape) {\n return 'Close';\n }\n\n // navigation interactions\n if (code === keys.ArrowDown) {\n return 'Next';\n }\n if (code === keys.ArrowUp) {\n return 'Previous';\n }\n if (code === keys.Home) {\n return 'First';\n }\n if (code === keys.End) {\n return 'Last';\n }\n if (code === keys.PageUp) {\n return 'PageUp';\n }\n if (code === keys.PageDown) {\n return 'PageDown';\n }\n if (code === keys.Tab) {\n return 'Tab';\n }\n\n // if nothing matched, return none\n return 'None';\n}\n"],"names":["getDropdownActionFromKey","e","options","open","multiselect","code","key","altKey","ctrlKey","metaKey","length","keys","Space","ArrowDown","ArrowUp","Enter","Escape","Home","End","PageUp","PageDown","Tab"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;+BA8BgBA;;;eAAAA;;;;wEA9BM;iEACC;AA6BhB,SAASA,yBACdC,CAAsC,EACtCC,UAAiC,CAAC,CAAC;IAEnC,MAAM,EAAEC,OAAO,IAAI,EAAEC,cAAc,KAAK,EAAE,GAAGF;IAC7C,MAAMG,OAAOJ,EAAEK,GAAG;IAClB,MAAM,EAAEC,MAAM,EAAEC,OAAO,EAAEF,GAAG,EAAEG,OAAO,EAAE,GAAGR;IAE1C,8CAA8C;IAC9C,IAAIK,IAAII,MAAM,KAAK,KAAKL,SAASM,cAAKC,KAAK,IAAI,CAACL,UAAU,CAACC,WAAW,CAACC,SAAS;QAC9E,OAAO;IACT;IAEA,wCAAwC;IACxC,IAAI,CAACN,MAAM;QACT,IAAIE,SAASM,cAAKE,SAAS,IAAIR,SAASM,cAAKG,OAAO,IAAIT,SAASM,cAAKI,KAAK,IAAIV,SAASM,cAAKC,KAAK,EAAE;YAClG,OAAO;QACT;QAEA,8EAA8E;QAC9E,OAAO;IACT;IAEA,0BAA0B;IAC1B,IAAIP,SAAUM,cAAKG,OAAO,IAAIP,UAAWF,SAASM,cAAKI,KAAK,IAAK,CAACX,eAAeC,SAASM,cAAKC,KAAK,EAAG;QACrG,OAAO;IACT;IACA,IAAIR,eAAeC,SAASM,cAAKC,KAAK,EAAE;QACtC,OAAO;IACT;IACA,IAAIP,SAASM,cAAKK,MAAM,EAAE;QACxB,OAAO;IACT;IAEA,0BAA0B;IAC1B,IAAIX,SAASM,cAAKE,SAAS,EAAE;QAC3B,OAAO;IACT;IACA,IAAIR,SAASM,cAAKG,OAAO,EAAE;QACzB,OAAO;IACT;IACA,IAAIT,SAASM,cAAKM,IAAI,EAAE;QACtB,OAAO;IACT;IACA,IAAIZ,SAASM,cAAKO,GAAG,EAAE;QACrB,OAAO;IACT;IACA,IAAIb,SAASM,cAAKQ,MAAM,EAAE;QACxB,OAAO;IACT;IACA,IAAId,SAASM,cAAKS,QAAQ,EAAE;QAC1B,OAAO;IACT;IACA,IAAIf,SAASM,cAAKU,GAAG,EAAE;QACrB,OAAO;IACT;IAEA,kCAAkC;IAClC,OAAO;AACT"}
@@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "iconSizes", {
enumerable: true,
get: function() {
return iconSizes;
}
});
const iconSizes = {
small: '16px',
medium: '20px',
large: '24px'
};
@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/internalTokens.ts"],"sourcesContent":["export const iconSizes = {\n small: '16px',\n medium: '20px',\n large: '24px',\n};\n"],"names":["iconSizes","small","medium","large"],"rangeMappings":";;;;;;;;;;;;;;","mappings":";;;;+BAAaA;;;eAAAA;;;AAAN,MAAMA,YAAY;IACvBC,OAAO;IACPC,QAAQ;IACRC,OAAO;AACT"}
@@ -0,0 +1,200 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "useComboboxBaseState", {
enumerable: true,
get: function() {
return useComboboxBaseState;
}
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
const _reactdom = /*#__PURE__*/ _interop_require_wildcard._(require("react-dom"));
const _reactutilities = require("@fluentui/react-utilities");
const _useOptionCollection = require("../utils/useOptionCollection");
const _useSelection = require("../utils/useSelection");
const useComboboxBaseState = (props)=>{
'use no memo';
const { appearance = 'outline', disableAutoFocus, children, clearable = false, editable = false, inlinePopup = false, mountNode = undefined, multiselect, onOpenChange, size = 'medium', activeDescendantController, freeform = false, disabled = false, onActiveOptionChange = null } = props;
const optionCollection = (0, _useOptionCollection.useOptionCollection)();
const { getOptionsMatchingValue } = optionCollection;
const { getOptionById } = optionCollection;
const getActiveOption = _react.useCallback(()=>{
const activeOptionId = activeDescendantController.active();
return activeOptionId ? getOptionById(activeOptionId) : undefined;
}, [
activeDescendantController,
getOptionById
]);
// Keeping some kind of backwards compatible functionality here
// eslint-disable-next-line @typescript-eslint/naming-convention
const UNSAFE_activeOption = getActiveOption();
// eslint-disable-next-line @typescript-eslint/naming-convention
const UNSAFE_setActiveOption = _react.useCallback((option)=>{
let nextOption = undefined;
if (typeof option === 'function') {
const activeOption = getActiveOption();
nextOption = option(activeOption);
}
if (nextOption) {
activeDescendantController.focus(nextOption.id);
} else {
activeDescendantController.blur();
}
}, [
activeDescendantController,
getActiveOption
]);
// track whether keyboard focus outline should be shown
// tabster/keyborg doesn't work here, since the actual keyboard focus target doesn't move
const [focusVisible, setFocusVisible] = _react.useState(false);
// track focused state to conditionally render collapsed listbox
// when the trigger is focused - the listbox should but hidden until the open state is changed
const [hasFocus, setHasFocus] = _react.useState(false);
const ignoreNextBlur = _react.useRef(false);
// calculate value based on props, internal value changes, and selected options
const isFirstMount = (0, _reactutilities.useFirstMount)();
const [controllableValue, setValue] = (0, _reactutilities.useControllableState)({
state: props.value,
initialState: undefined
});
const { selectedOptions, selectOption: baseSelectOption, clearSelection } = (0, _useSelection.useSelection)(props);
// reset any typed value when an option is selected
const selectOption = _react.useCallback((ev, option)=>{
_reactdom.unstable_batchedUpdates(()=>{
setValue(undefined);
baseSelectOption(ev, option);
});
}, [
setValue,
baseSelectOption
]);
const value = _react.useMemo(()=>{
// don't compute the value if it is defined through props or setValue,
if (controllableValue !== undefined) {
return controllableValue;
}
// handle defaultValue here, so it is overridden by selection
if (isFirstMount && props.defaultValue !== undefined) {
return props.defaultValue;
}
const selectedOptionsText = getOptionsMatchingValue((optionValue)=>{
return selectedOptions.includes(optionValue);
}).map((option)=>option.text);
if (multiselect) {
// editable inputs should not display multiple selected options in the input as text
return editable ? '' : selectedOptionsText.join(', ');
}
return selectedOptionsText[0];
// do not change value after isFirstMount changes,
// we do not want to accidentally override defaultValue on a second render
// unless another value is intentionally set
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
controllableValue,
editable,
getOptionsMatchingValue,
multiselect,
selectedOptions
]);
// Handle open state, which is shared with options in context
const [open, setOpenState] = (0, _reactutilities.useControllableState)({
state: props.open,
defaultState: props.defaultOpen,
initialState: false
});
const setOpen = _react.useCallback((event, newState)=>{
if (disabled) {
return;
}
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(event, {
open: newState
});
_reactdom.unstable_batchedUpdates(()=>{
if (!newState && !freeform) {
setValue(undefined);
}
setOpenState(newState);
});
}, [
onOpenChange,
setOpenState,
setValue,
freeform,
disabled
]);
// update active option based on change in open state
_react.useEffect(()=>{
if (open) {
// if it is single-select and there is a selected option, start at the selected option
if (!multiselect && selectedOptions.length > 0) {
const selectedOption = getOptionsMatchingValue((v)=>v === selectedOptions[0]).pop();
if (selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.id) {
activeDescendantController.focus(selectedOption.id);
}
}
} else {
activeDescendantController.blur();
}
// this should only be run in response to changes in the open state
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
open,
activeDescendantController
]);
// Fallback focus when children are updated in an open popover results in no item being focused
_react.useEffect(()=>{
if (open && !disableAutoFocus && !activeDescendantController.active()) {
activeDescendantController.first();
}
// this should only be run in response to changes in the open state or children
}, [
open,
children,
disableAutoFocus,
activeDescendantController,
getOptionById
]);
const onActiveDescendantChange = (0, _reactutilities.useEventCallback)((event)=>{
const previousOption = event.detail.previousId ? optionCollection.getOptionById(event.detail.previousId) : null;
const nextOption = optionCollection.getOptionById(event.detail.id);
onActiveOptionChange === null || onActiveOptionChange === void 0 ? void 0 : onActiveOptionChange(event, {
event,
type: 'change',
previousOption,
nextOption
});
});
return {
...optionCollection,
freeform,
disabled,
selectOption,
clearSelection,
selectedOptions,
activeOption: UNSAFE_activeOption,
appearance,
clearable,
focusVisible,
ignoreNextBlur,
inlinePopup,
mountNode,
open,
hasFocus,
setActiveOption: UNSAFE_setActiveOption,
setFocusVisible,
setHasFocus,
setOpen,
setValue,
size,
value,
multiselect,
onOptionClick: (0, _reactutilities.useEventCallback)((e)=>{
if (!multiselect) {
setOpen(e, false);
}
}),
onActiveDescendantChange
};
};
File diff suppressed because one or more lines are too long
@@ -0,0 +1,42 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "useComboboxPositioning", {
enumerable: true,
get: function() {
return useComboboxPositioning;
}
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _reactpositioning = require("@fluentui/react-positioning");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
function useComboboxPositioning(props) {
const { positioning } = props;
// Set a default set of fallback positions to try if the dropdown does not fit on screen
const fallbackPositions = [
'above',
'after',
'after-top',
'before',
'before-top'
];
// popper options
const popperOptions = {
position: 'below',
align: 'start',
offset: {
crossAxis: 0,
mainAxis: 2
},
fallbackPositions,
matchTargetSize: 'width',
autoSize: true,
...(0, _reactpositioning.resolvePositioningShorthand)(positioning)
};
const { targetRef, containerRef } = (0, _reactpositioning.usePositioning)(popperOptions);
return [
containerRef,
targetRef
];
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/useComboboxPositioning.ts"],"sourcesContent":["import { PositioningShorthandValue, resolvePositioningShorthand, usePositioning } from '@fluentui/react-positioning';\nimport type { ComboboxBaseProps } from './ComboboxBase.types';\nimport * as React from 'react';\n\nexport function useComboboxPositioning(props: ComboboxBaseProps): [\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n listboxRef: React.MutableRefObject<any>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n triggerRef: React.MutableRefObject<any>,\n] {\n const { positioning } = props;\n\n // Set a default set of fallback positions to try if the dropdown does not fit on screen\n const fallbackPositions: PositioningShorthandValue[] = ['above', 'after', 'after-top', 'before', 'before-top'];\n\n // popper options\n const popperOptions = {\n position: 'below' as const,\n align: 'start' as const,\n offset: { crossAxis: 0, mainAxis: 2 },\n fallbackPositions,\n matchTargetSize: 'width' as const,\n autoSize: true,\n ...resolvePositioningShorthand(positioning),\n };\n\n const { targetRef, containerRef } = usePositioning(popperOptions);\n\n return [containerRef, targetRef];\n}\n"],"names":["useComboboxPositioning","props","positioning","fallbackPositions","popperOptions","position","align","offset","crossAxis","mainAxis","matchTargetSize","autoSize","resolvePositioningShorthand","targetRef","containerRef","usePositioning"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;+BAIgBA;;;eAAAA;;;;kCAJuE;iEAEhE;AAEhB,SAASA,uBAAuBC,KAAwB;IAM7D,MAAM,EAAEC,WAAW,EAAE,GAAGD;IAExB,wFAAwF;IACxF,MAAME,oBAAiD;QAAC;QAAS;QAAS;QAAa;QAAU;KAAa;IAE9G,iBAAiB;IACjB,MAAMC,gBAAgB;QACpBC,UAAU;QACVC,OAAO;QACPC,QAAQ;YAAEC,WAAW;YAAGC,UAAU;QAAE;QACpCN;QACAO,iBAAiB;QACjBC,UAAU;QACV,GAAGC,IAAAA,6CAAAA,EAA4BV,YAAY;IAC7C;IAEA,MAAM,EAAEW,SAAS,EAAEC,YAAY,EAAE,GAAGC,IAAAA,gCAAAA,EAAeX;IAEnD,OAAO;QAACU;QAAcD;KAAU;AAClC"}
@@ -0,0 +1,46 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "useListboxSlot", {
enumerable: true,
get: function() {
return useListboxSlot;
}
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
const _reactutilities = require("@fluentui/react-utilities");
const _Listbox = require("../Listbox");
function useListboxSlot(listboxSlotFromProp, ref, options) {
const { state: { multiselect }, triggerRef, defaultProps } = options;
const listboxId = (0, _reactutilities.useId)('fluent-listbox', (0, _reactutilities.isResolvedShorthand)(listboxSlotFromProp) ? listboxSlotFromProp.id : undefined);
const listboxSlot = _reactutilities.slot.optional(listboxSlotFromProp, {
renderByDefault: true,
elementType: _Listbox.Listbox,
defaultProps: {
id: listboxId,
multiselect,
tabIndex: undefined,
...defaultProps
}
});
/**
* Clicking on the listbox should never blur the trigger
* in a combobox
*/ const onMouseDown = (0, _reactutilities.useEventCallback)((0, _reactutilities.mergeCallbacks)((event)=>{
event.preventDefault();
}, listboxSlot === null || listboxSlot === void 0 ? void 0 : listboxSlot.onMouseDown));
const onClick = (0, _reactutilities.useEventCallback)((0, _reactutilities.mergeCallbacks)((event)=>{
var _triggerRef_current;
event.preventDefault();
(_triggerRef_current = triggerRef.current) === null || _triggerRef_current === void 0 ? void 0 : _triggerRef_current.focus();
}, listboxSlot === null || listboxSlot === void 0 ? void 0 : listboxSlot.onClick));
const listboxRef = (0, _reactutilities.useMergedRefs)(listboxSlot === null || listboxSlot === void 0 ? void 0 : listboxSlot.ref, ref);
if (listboxSlot) {
listboxSlot.ref = listboxRef;
listboxSlot.onMouseDown = onMouseDown;
listboxSlot.onClick = onClick;
}
return listboxSlot;
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/useListboxSlot.ts"],"sourcesContent":["import * as React from 'react';\nimport {\n mergeCallbacks,\n useId,\n useEventCallback,\n slot,\n isResolvedShorthand,\n useMergedRefs,\n} from '@fluentui/react-utilities';\nimport type { ExtractSlotProps, Slot, SlotComponentType } from '@fluentui/react-utilities';\nimport type { ComboboxBaseState } from './ComboboxBase.types';\nimport { Listbox } from '../Listbox';\nimport { ListboxProps } from '../Listbox';\n\nexport type UseListboxSlotState = Pick<ComboboxBaseState, 'multiselect'>;\n\ntype UseListboxSlotOptions = {\n state: UseListboxSlotState;\n triggerRef:\n | React.RefObject<HTMLInputElement>\n | React.RefObject<HTMLButtonElement>\n | React.RefObject<HTMLButtonElement | HTMLInputElement>;\n defaultProps?: Partial<ListboxProps>;\n};\n\n/**\n * @internal\n * @returns listbox slot with desired behaviour and props\n */\nexport function useListboxSlot(\n listboxSlotFromProp: Slot<typeof Listbox> | undefined,\n ref: React.Ref<HTMLDivElement>,\n options: UseListboxSlotOptions,\n): SlotComponentType<ExtractSlotProps<Slot<typeof Listbox>>> | undefined {\n const {\n state: { multiselect },\n triggerRef,\n defaultProps,\n } = options;\n\n const listboxId = useId(\n 'fluent-listbox',\n isResolvedShorthand(listboxSlotFromProp) ? listboxSlotFromProp.id : undefined,\n );\n\n const listboxSlot = slot.optional(listboxSlotFromProp, {\n renderByDefault: true,\n elementType: Listbox,\n defaultProps: {\n id: listboxId,\n multiselect,\n tabIndex: undefined,\n ...defaultProps,\n },\n });\n\n /**\n * Clicking on the listbox should never blur the trigger\n * in a combobox\n */\n const onMouseDown = useEventCallback(\n mergeCallbacks((event: React.MouseEvent<HTMLDivElement>) => {\n event.preventDefault();\n }, listboxSlot?.onMouseDown),\n );\n\n const onClick = useEventCallback(\n mergeCallbacks((event: React.MouseEvent<HTMLDivElement>) => {\n event.preventDefault();\n triggerRef.current?.focus();\n }, listboxSlot?.onClick),\n );\n\n const listboxRef = useMergedRefs(listboxSlot?.ref, ref);\n if (listboxSlot) {\n listboxSlot.ref = listboxRef;\n listboxSlot.onMouseDown = onMouseDown;\n listboxSlot.onClick = onClick;\n }\n\n return listboxSlot;\n}\n"],"names":["useListboxSlot","listboxSlotFromProp","ref","options","state","multiselect","triggerRef","defaultProps","listboxId","useId","isResolvedShorthand","id","undefined","listboxSlot","slot","optional","renderByDefault","elementType","Listbox","tabIndex","onMouseDown","useEventCallback","mergeCallbacks","event","preventDefault","onClick","current","focus","listboxRef","useMergedRefs"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;+BA6BgBA;;;eAAAA;;;;iEA7BO;gCAQhB;yBAGiB;AAkBjB,SAASA,eACdC,mBAAqD,EACrDC,GAA8B,EAC9BC,OAA8B;IAE9B,MAAM,EACJC,OAAO,EAAEC,WAAW,EAAE,EACtBC,UAAU,EACVC,YAAY,EACb,GAAGJ;IAEJ,MAAMK,YAAYC,IAAAA,qBAAAA,EAChB,kBACAC,IAAAA,mCAAAA,EAAoBT,uBAAuBA,oBAAoBU,EAAE,GAAGC;IAGtE,MAAMC,cAAcC,oBAAAA,CAAKC,QAAQ,CAACd,qBAAqB;QACrDe,iBAAiB;QACjBC,aAAaC,gBAAAA;QACbX,cAAc;YACZI,IAAIH;YACJH;YACAc,UAAUP;YACV,GAAGL,YAAY;QACjB;IACF;IAEA;;;GAGC,GACD,MAAMa,cAAcC,IAAAA,gCAAAA,EAClBC,IAAAA,8BAAAA,EAAe,CAACC;QACdA,MAAMC,cAAc;IACtB,GAAGX,gBAAAA,QAAAA,gBAAAA,KAAAA,IAAAA,KAAAA,IAAAA,YAAaO,WAAW;IAG7B,MAAMK,UAAUJ,IAAAA,gCAAAA,EACdC,IAAAA,8BAAAA,EAAe,CAACC;YAEdjB;QADAiB,MAAMC,cAAc;QACpBlB,CAAAA,sBAAAA,WAAWoB,OAAO,AAAPA,MAAO,QAAlBpB,wBAAAA,KAAAA,IAAAA,KAAAA,IAAAA,oBAAoBqB,KAAK;IAC3B,GAAGd,gBAAAA,QAAAA,gBAAAA,KAAAA,IAAAA,KAAAA,IAAAA,YAAaY,OAAO;IAGzB,MAAMG,aAAaC,IAAAA,6BAAAA,EAAchB,gBAAAA,QAAAA,gBAAAA,KAAAA,IAAAA,KAAAA,IAAAA,YAAaX,GAAG,EAAEA;IACnD,IAAIW,aAAa;QACfA,YAAYX,GAAG,GAAG0B;QAClBf,YAAYO,WAAW,GAAGA;QAC1BP,YAAYY,OAAO,GAAGA;IACxB;IAEA,OAAOZ;AACT"}
@@ -0,0 +1,53 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "useOptionCollection", {
enumerable: true,
get: function() {
return useOptionCollection;
}
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
const useOptionCollection = ()=>{
const optionsById = _react.useRef(new Map());
const collectionAPI = _react.useMemo(()=>{
const getCount = ()=>optionsById.current.size;
// index searches are no longer used
const getOptionAtIndex = ()=>undefined;
const getIndexOfId = ()=>-1;
const getOptionById = (id)=>{
return optionsById.current.get(id);
};
const getOptionsMatchingText = (matcher)=>{
return Array.from(optionsById.current.values()).filter(({ text })=>matcher(text));
};
const getOptionsMatchingValue = (matcher)=>{
const matches = [];
for (const option of optionsById.current.values()){
if (matcher(option.value)) {
matches.push(option);
}
}
return matches;
};
return {
getCount,
getOptionAtIndex,
getIndexOfId,
getOptionById,
getOptionsMatchingText,
getOptionsMatchingValue
};
}, []);
const registerOption = _react.useCallback((option)=>{
optionsById.current.set(option.id, option);
return ()=>optionsById.current.delete(option.id);
}, []);
return {
...collectionAPI,
options: Array.from(optionsById.current.values()),
registerOption
};
};
@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/useOptionCollection.ts"],"sourcesContent":["import * as React from 'react';\nimport type { OptionCollectionState, OptionValue } from './OptionCollection.types';\n\n/**\n * A hook for managing a collection of child Options\n */\nexport const useOptionCollection = (): OptionCollectionState => {\n const optionsById = React.useRef(new Map<string, OptionValue>());\n\n const collectionAPI = React.useMemo(() => {\n const getCount = () => optionsById.current.size;\n\n // index searches are no longer used\n const getOptionAtIndex = () => undefined;\n const getIndexOfId = () => -1;\n\n const getOptionById = (id: string) => {\n return optionsById.current.get(id);\n };\n const getOptionsMatchingText = (matcher: (text: string) => boolean) => {\n return Array.from(optionsById.current.values()).filter(({ text }) => matcher(text));\n };\n\n const getOptionsMatchingValue = (matcher: (value: string) => boolean) => {\n const matches: OptionValue[] = [];\n for (const option of optionsById.current.values()) {\n if (matcher(option.value)) {\n matches.push(option);\n }\n }\n\n return matches;\n };\n\n return {\n getCount,\n getOptionAtIndex,\n getIndexOfId,\n getOptionById,\n getOptionsMatchingText,\n getOptionsMatchingValue,\n };\n }, []);\n\n const registerOption = React.useCallback((option: OptionValue) => {\n optionsById.current.set(option.id, option);\n\n return () => optionsById.current.delete(option.id);\n }, []);\n\n return {\n ...collectionAPI,\n options: Array.from(optionsById.current.values()),\n registerOption,\n };\n};\n"],"names":["useOptionCollection","optionsById","React","useRef","Map","collectionAPI","useMemo","getCount","current","size","getOptionAtIndex","undefined","getIndexOfId","getOptionById","id","get","getOptionsMatchingText","matcher","Array","from","values","filter","text","getOptionsMatchingValue","matches","option","value","push","registerOption","useCallback","set","delete","options"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;+BAMaA;;;eAAAA;;;;iEANU;AAMhB,MAAMA,sBAAsB;IACjC,MAAMC,cAAcC,OAAMC,MAAM,CAAC,IAAIC;IAErC,MAAMC,gBAAgBH,OAAMI,OAAO,CAAC;QAClC,MAAMC,WAAW,IAAMN,YAAYO,OAAO,CAACC,IAAI;QAE/C,oCAAoC;QACpC,MAAMC,mBAAmB,IAAMC;QAC/B,MAAMC,eAAe,IAAM,CAAC;QAE5B,MAAMC,gBAAgB,CAACC;YACrB,OAAOb,YAAYO,OAAO,CAACO,GAAG,CAACD;QACjC;QACA,MAAME,yBAAyB,CAACC;YAC9B,OAAOC,MAAMC,IAAI,CAAClB,YAAYO,OAAO,CAACY,MAAM,IAAIC,MAAM,CAAC,CAAC,EAAEC,IAAI,EAAE,GAAKL,QAAQK;QAC/E;QAEA,MAAMC,0BAA0B,CAACN;YAC/B,MAAMO,UAAyB,EAAE;YACjC,KAAK,MAAMC,UAAUxB,YAAYO,OAAO,CAACY,MAAM,GAAI;gBACjD,IAAIH,QAAQQ,OAAOC,KAAK,GAAG;oBACzBF,QAAQG,IAAI,CAACF;gBACf;YACF;YAEA,OAAOD;QACT;QAEA,OAAO;YACLjB;YACAG;YACAE;YACAC;YACAG;YACAO;QACF;IACF,GAAG,EAAE;IAEL,MAAMK,iBAAiB1B,OAAM2B,WAAW,CAAC,CAACJ;QACxCxB,YAAYO,OAAO,CAACsB,GAAG,CAACL,OAAOX,EAAE,EAAEW;QAEnC,OAAO,IAAMxB,YAAYO,OAAO,CAACuB,MAAM,CAACN,OAAOX,EAAE;IACnD,GAAG,EAAE;IAEL,OAAO;QACL,GAAGT,aAAa;QAChB2B,SAASd,MAAMC,IAAI,CAAClB,YAAYO,OAAO,CAACY,MAAM;QAC9CQ;IACF;AACF"}
@@ -0,0 +1,72 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "useSelection", {
enumerable: true,
get: function() {
return useSelection;
}
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
const _reactutilities = require("@fluentui/react-utilities");
const useSelection = (props)=>{
const { defaultSelectedOptions, multiselect, onOptionSelect } = props;
const [selectedOptions, setSelectedOptions] = (0, _reactutilities.useControllableState)({
state: props.selectedOptions,
defaultState: defaultSelectedOptions,
initialState: []
});
const selectOption = _react.useCallback((event, option)=>{
// if the option is disabled, do nothing
if (option.disabled) {
return;
}
// for single-select, always return the selected option
let newSelection = [
option.value
];
// toggle selected state of the option for multiselect
if (multiselect) {
const selectedIndex = selectedOptions.findIndex((o)=>o === option.value);
if (selectedIndex > -1) {
// deselect option
newSelection = [
...selectedOptions.slice(0, selectedIndex),
...selectedOptions.slice(selectedIndex + 1)
];
} else {
// select option
newSelection = [
...selectedOptions,
option.value
];
}
}
setSelectedOptions(newSelection);
onOptionSelect === null || onOptionSelect === void 0 ? void 0 : onOptionSelect(event, {
optionValue: option.value,
optionText: option.text,
selectedOptions: newSelection
});
}, [
onOptionSelect,
multiselect,
selectedOptions,
setSelectedOptions
]);
const clearSelection = (event)=>{
setSelectedOptions([]);
onOptionSelect === null || onOptionSelect === void 0 ? void 0 : onOptionSelect(event, {
optionValue: undefined,
optionText: undefined,
selectedOptions: []
});
};
return {
clearSelection,
selectOption,
selectedOptions
};
};
@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/useSelection.ts"],"sourcesContent":["import * as React from 'react';\nimport { useControllableState } from '@fluentui/react-utilities';\nimport { OptionValue } from './OptionCollection.types';\nimport { SelectionEvents, SelectionProps, SelectionState } from './Selection.types';\n\nexport const useSelection = (props: SelectionProps): SelectionState => {\n const { defaultSelectedOptions, multiselect, onOptionSelect } = props;\n\n const [selectedOptions, setSelectedOptions] = useControllableState({\n state: props.selectedOptions,\n defaultState: defaultSelectedOptions,\n initialState: [],\n });\n\n const selectOption = React.useCallback(\n (event: SelectionEvents, option: OptionValue) => {\n // if the option is disabled, do nothing\n if (option.disabled) {\n return;\n }\n\n // for single-select, always return the selected option\n let newSelection = [option.value];\n\n // toggle selected state of the option for multiselect\n if (multiselect) {\n const selectedIndex = selectedOptions.findIndex(o => o === option.value);\n if (selectedIndex > -1) {\n // deselect option\n newSelection = [...selectedOptions.slice(0, selectedIndex), ...selectedOptions.slice(selectedIndex + 1)];\n } else {\n // select option\n newSelection = [...selectedOptions, option.value];\n }\n }\n\n setSelectedOptions(newSelection);\n onOptionSelect?.(event, { optionValue: option.value, optionText: option.text, selectedOptions: newSelection });\n },\n [onOptionSelect, multiselect, selectedOptions, setSelectedOptions],\n );\n\n const clearSelection = (event: SelectionEvents) => {\n setSelectedOptions([]);\n onOptionSelect?.(event, { optionValue: undefined, optionText: undefined, selectedOptions: [] });\n };\n\n return { clearSelection, selectOption, selectedOptions };\n};\n"],"names":["useSelection","props","defaultSelectedOptions","multiselect","onOptionSelect","selectedOptions","setSelectedOptions","useControllableState","state","defaultState","initialState","selectOption","React","useCallback","event","option","disabled","newSelection","value","selectedIndex","findIndex","o","slice","optionValue","optionText","text","clearSelection","undefined"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;+BAKaA;;;eAAAA;;;;iEALU;gCACc;AAI9B,MAAMA,eAAe,CAACC;IAC3B,MAAM,EAAEC,sBAAsB,EAAEC,WAAW,EAAEC,cAAc,EAAE,GAAGH;IAEhE,MAAM,CAACI,iBAAiBC,mBAAmB,GAAGC,IAAAA,oCAAAA,EAAqB;QACjEC,OAAOP,MAAMI,eAAe;QAC5BI,cAAcP;QACdQ,cAAc,EAAE;IAClB;IAEA,MAAMC,eAAeC,OAAMC,WAAW,CACpC,CAACC,OAAwBC;QACvB,wCAAwC;QACxC,IAAIA,OAAOC,QAAQ,EAAE;YACnB;QACF;QAEA,uDAAuD;QACvD,IAAIC,eAAe;YAACF,OAAOG,KAAK;SAAC;QAEjC,sDAAsD;QACtD,IAAIf,aAAa;YACf,MAAMgB,gBAAgBd,gBAAgBe,SAAS,CAACC,CAAAA,IAAKA,MAAMN,OAAOG,KAAK;YACvE,IAAIC,gBAAgB,CAAC,GAAG;gBACtB,kBAAkB;gBAClBF,eAAe;uBAAIZ,gBAAgBiB,KAAK,CAAC,GAAGH;uBAAmBd,gBAAgBiB,KAAK,CAACH,gBAAgB;iBAAG;YAC1G,OAAO;gBACL,gBAAgB;gBAChBF,eAAe;uBAAIZ;oBAAiBU,OAAOG,KAAK;iBAAC;YACnD;QACF;QAEAZ,mBAAmBW;QACnBb,mBAAAA,QAAAA,mBAAAA,KAAAA,IAAAA,KAAAA,IAAAA,eAAiBU,OAAO;YAAES,aAAaR,OAAOG,KAAK;YAAEM,YAAYT,OAAOU,IAAI;YAAEpB,iBAAiBY;QAAa;IAC9G,GACA;QAACb;QAAgBD;QAAaE;QAAiBC;KAAmB;IAGpE,MAAMoB,iBAAiB,CAACZ;QACtBR,mBAAmB,EAAE;QACrBF,mBAAAA,QAAAA,mBAAAA,KAAAA,IAAAA,KAAAA,IAAAA,eAAiBU,OAAO;YAAES,aAAaI;YAAWH,YAAYG;YAAWtB,iBAAiB,EAAE;QAAC;IAC/F;IAEA,OAAO;QAAEqB;QAAgBf;QAAcN;IAAgB;AACzD"}
@@ -0,0 +1,149 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "useTriggerSlot", {
enumerable: true,
get: function() {
return useTriggerSlot;
}
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
const _reacttabster = require("@fluentui/react-tabster");
const _reactutilities = require("@fluentui/react-utilities");
const _dropdownKeyActions = require("../utils/dropdownKeyActions");
function useTriggerSlot(triggerSlotFromProp, ref, options) {
const { state: { open, setOpen, setHasFocus }, defaultProps, elementType, activeDescendantController } = options;
const trigger = _reactutilities.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 = (0, _reactutilities.useMergedRefs)(triggerRef, trigger.ref, ref);
// the trigger should open/close the popup on click or blur
trigger.onBlur = (0, _reactutilities.mergeCallbacks)((event)=>{
setOpen(event, false);
setHasFocus(false);
}, trigger.onBlur);
trigger.onFocus = (0, _reactutilities.mergeCallbacks)((event)=>{
if (event.target === event.currentTarget) {
setHasFocus(true);
}
}, trigger.onFocus);
trigger.onClick = (0, _reactutilities.mergeCallbacks)((event)=>{
setOpen(event, !open);
}, trigger.onClick);
// handle combobox keyboard interaction
trigger.onKeyDown = (0, _reactutilities.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 = (0, _reacttabster.useSetKeyboardNavigation)();
return (0, _reactutilities.useEventCallback)((e)=>{
const action = (0, _dropdownKeyActions.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;
}
});
}
File diff suppressed because one or more lines are too long