@fluentui/react
Version:
Reusable React components for building web experiences.
108 lines • 6.2 kB
JavaScript
import { __assign } from "tslib";
import * as React from 'react';
import { Label } from '../../Label';
import { classNamesFunction, find, FocusRectsContext, getNativeProps, divProperties, setFocusVisibility, useFocusRects, } from '../../Utilities';
import { ChoiceGroupOption } from './ChoiceGroupOption/index';
import { useId, useControllableValue, useMergedRefs, useWarnings } from '@fluentui/react-hooks';
import { useDocumentEx } from '../../utilities/dom';
var getClassNames = classNamesFunction();
var getOptionId = function (option, id) {
return "".concat(id, "-").concat(option.key);
};
var findOption = function (options, key) {
return key === undefined ? undefined : find(options, function (value) { return value.key === key; });
};
var focusSelectedOption = function (options, keyChecked, id, focusProviders, doc) {
var optionToFocus = findOption(options, keyChecked) || options.filter(function (option) { return !option.disabled; })[0];
var elementToFocus = optionToFocus && (doc === null || doc === void 0 ? void 0 : doc.getElementById(getOptionId(optionToFocus, id)));
if (elementToFocus) {
elementToFocus.focus();
setFocusVisibility(true, elementToFocus, focusProviders);
}
};
var focusFromFocusTrapZone = function (evt) {
return evt.relatedTarget instanceof HTMLElement && evt.relatedTarget.dataset.isFocusTrapZoneBumper === 'true';
};
var useComponentRef = function (options, keyChecked, id, componentRef, focusProviders) {
var doc = useDocumentEx();
React.useImperativeHandle(componentRef, function () { return ({
get checkedOption() {
return findOption(options, keyChecked);
},
focus: function () {
focusSelectedOption(options, keyChecked, id, focusProviders, doc);
},
}); }, [options, keyChecked, id, focusProviders, doc]);
};
var COMPONENT_NAME = 'ChoiceGroup';
export var ChoiceGroupBase = React.forwardRef(function (props, forwardedRef) {
var className = props.className, theme = props.theme, styles = props.styles, _a = props.options, options = _a === void 0 ? [] : _a, label = props.label, required = props.required, disabled = props.disabled, name = props.name, defaultSelectedKey = props.defaultSelectedKey, componentRef = props.componentRef, onChange = props.onChange;
var id = useId('ChoiceGroup');
var labelId = useId('ChoiceGroupLabel');
var divProps = getNativeProps(props, divProperties, [
'onChange',
'className',
'required',
]);
var classNames = getClassNames(styles, {
theme: theme,
className: className,
optionsContainIconOrImage: options.some(function (option) { return !!(option.iconProps || option.imageSrc); }),
});
var ariaLabelledBy = props.ariaLabelledBy || (label ? labelId : props['aria-labelledby']);
var _b = useControllableValue(props.selectedKey, defaultSelectedKey), keyChecked = _b[0], setKeyChecked = _b[1];
var _c = React.useState(), keyFocused = _c[0], setKeyFocused = _c[1];
var rootRef = React.useRef(null);
var mergedRootRefs = useMergedRefs(rootRef, forwardedRef);
var focusContext = React.useContext(FocusRectsContext);
useDebugWarnings(props);
useComponentRef(options, keyChecked, id, componentRef, focusContext === null || focusContext === void 0 ? void 0 : focusContext.registeredProviders);
useFocusRects(rootRef);
var onFocus = React.useCallback(function (ev, option) {
var _a;
if (option) {
setKeyFocused(option.itemKey);
(_a = option.onFocus) === null || _a === void 0 ? void 0 : _a.call(option, ev);
}
}, []);
var onBlur = React.useCallback(function (ev, option) {
var _a;
setKeyFocused(undefined);
(_a = option === null || option === void 0 ? void 0 : option.onBlur) === null || _a === void 0 ? void 0 : _a.call(option, ev);
}, []);
var onOptionChange = React.useCallback(function (evt, option) {
var _a;
if (!option) {
return;
}
setKeyChecked(option.itemKey);
(_a = option.onChange) === null || _a === void 0 ? void 0 : _a.call(option, evt);
onChange === null || onChange === void 0 ? void 0 : onChange(evt, findOption(options, option.itemKey));
}, [onChange, options, setKeyChecked]);
var onRadioFocus = React.useCallback(function (evt) {
// Handles scenarios like this bug: https://github.com/microsoft/fluentui/issues/20173
if (focusFromFocusTrapZone(evt)) {
focusSelectedOption(options, keyChecked, id, focusContext === null || focusContext === void 0 ? void 0 : focusContext.registeredProviders);
}
}, [options, keyChecked, id, focusContext]);
return (React.createElement("div", __assign({ className: classNames.root }, divProps, { ref: mergedRootRefs }),
React.createElement("div", __assign({ role: "radiogroup" }, (ariaLabelledBy && { 'aria-labelledby': ariaLabelledBy }), { onFocus: onRadioFocus }),
label && (React.createElement(Label, { className: classNames.label, required: required, id: labelId, disabled: disabled }, label)),
React.createElement("div", { className: classNames.flexContainer }, options.map(function (option) {
return (React.createElement(ChoiceGroupOption, __assign({ itemKey: option.key }, option, { key: option.key, onBlur: onBlur, onFocus: onFocus, onChange: onOptionChange, focused: option.key === keyFocused, checked: option.key === keyChecked, disabled: option.disabled || disabled, id: getOptionId(option, id), labelId: option.labelId || "".concat(labelId, "-").concat(option.key), name: name || id, required: required })));
})))));
});
ChoiceGroupBase.displayName = COMPONENT_NAME;
function useDebugWarnings(props) {
if (process.env.NODE_ENV !== 'production') {
// eslint-disable-next-line react-hooks/rules-of-hooks -- build-time conditional
useWarnings({
name: COMPONENT_NAME,
props: props,
mutuallyExclusive: {
selectedKey: 'defaultSelectedKey',
},
});
}
}
//# sourceMappingURL=ChoiceGroup.base.js.map