@engie-group/fluid-design-system-react
Version:
Fluid Design System React
76 lines (73 loc) • 4.82 kB
JavaScript
import { jsx, jsxs } from 'react/jsx-runtime';
import React__default, { useId, useMemo, useRef, useCallback } from 'react';
import { useStateControl, useInert } from '../../../utils/hook.js';
import { labelFromChildren } from '../../../utils/label-from-children.js';
import { Utils } from '../../../utils/util.js';
import { NJFormItem } from '../../form-item/NJFormItem.js';
import { NJMenuAnchor } from '../../menu/anchor/NJMenuAnchor.js';
import { NJMenuDropdown } from '../../menu/dropdown/NJMenuDropdown.js';
import { NJMenuGroup } from '../../menu/group/NJMenuGroup.js';
import '../../menu/item/NJMenuItem.js';
import { NJMenuRoot } from '../../menu/root/NJMenuRoot.js';
import { NJMenuSelection } from '../../menu/selection/NJMenuSelection.js';
import '../../menu/NJMenuContext.js';
import '../../menu/NJMenuItemContext.js';
import '../../menu/NJMenuSelectionContext.js';
const NJSelectRoot = React__default.forwardRef((props, forwardedRef) => {
const { id: baseId, name, placeholder, form, isRequired, isDisabled, readOnly, iconName, value: controlledValue, initialValue, onChange, children, label, buttonDefaultValueLabel, listNavigationLabel, className, ...htmlProps } = props;
const id = baseId ?? useId();
const items = React__default.Children.map(children, (child, index) => {
if (React__default.isValidElement(child)) {
return {
label: child.props.label ?? labelFromChildren(child),
value: child.props.value,
index
};
}
return {
label: labelFromChildren(child),
value: undefined,
index
};
});
const optionsByIndex = new Map(items?.map((item) => [item.index, item]));
const [value, setValue] = useStateControl(initialValue, controlledValue);
const [isOpen, setIsOpen] = React__default.useState(false);
const selectedOption = useMemo(() => Array.from(optionsByIndex.values()).find((option) => option.value === undefined ? option.label === value : option.value === value), [value, optionsByIndex]);
const rootEl = useRef(null);
const buttonEl = useRef(null);
useInert(rootEl, isDisabled || readOnly);
const inputClass = Utils.classNames(props.labelKind === 'static' ? 'nj-form-item--static' : null, 'nj-form-item--select', 'nj-form-item--custom-list', { ['nj-form-item--open']: isOpen }, className);
const handleChange = useCallback((selectedIndexes) => {
if (selectedIndexes.length === 0) {
setValue(undefined);
onChange?.(undefined);
return;
}
const option = optionsByIndex.get(selectedIndexes[0]);
if (!option) {
setValue(undefined);
onChange?.(undefined);
return;
}
if (option.value === null) {
setValue(null);
onChange?.(null);
return;
}
if (option.value === undefined) {
const labelValue = option.label || '';
setValue(labelValue);
onChange?.(labelValue);
return;
}
setValue(option.value);
onChange?.(option.value);
}, [onChange, optionsByIndex]);
if (initialValue && controlledValue) {
throw new Error('NJSelect: initialValue and value cannot be used together, the component is either controlled or uncontrolled');
}
return (jsx(NJMenuRoot, { floatingRole: "select", onOpen: (isOpen) => setIsOpen(isOpen), children: jsx(NJMenuSelection, { selectedIndexes: selectedOption ? [selectedOption.index] : [], onSelection: handleChange, children: jsxs(NJFormItem, { isMultiline: false, label: label, id: id, onChange: undefined, isSelect: true, className: inputClass, iconName: iconName ?? 'keyboard_arrow_down', iconClassName: "nj-form-item__icon", labelClassName: "nj-form-item__label", ref: rootEl, children: [jsx("input", { "data-child-name": "inputField", type: "text", id: id, ref: forwardedRef, name: name, value: selectedOption?.label || '', disabled: isDisabled, required: isRequired, "aria-hidden": true, placeholder: placeholder || ' ', form: form, tabIndex: -1, className: "nj-form-item__field", readOnly: true }), jsxs("div", { "data-child-name": "additionalContent", children: [jsx("p", { id: `${id}-instructions`, hidden: true, children: listNavigationLabel }), jsx(NJMenuAnchor, { children: jsx("button", { ...htmlProps, type: "button", "aria-label": `${label} - ${value || buttonDefaultValueLabel}`, className: "nj-form-item__custom-list-button", ref: buttonEl, "aria-haspopup": "listbox", "aria-describedby": `${id}-subscript ${id}-instructions` }) }), jsx(NJMenuDropdown, { scrollable: true, children: jsx(NJMenuGroup, { children: children }) })] })] }) }) }));
});
NJSelectRoot.displayName = 'NJSelectRoot';
export { NJSelectRoot };