UNPKG

@amaui/ui-react

Version:
414 lines (413 loc) 25.1 kB
"use strict"; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = __importDefault(require("react")); const utils_1 = require("@amaui/utils"); const style_react_1 = require("@amaui/style-react"); const IconMaterialCloseW100_1 = __importDefault(require("@amaui/icons-material-rounded-react/IconMaterialCloseW100")); const IconMaterialArrowDropDownW100_1 = __importDefault(require("@amaui/icons-material-rounded-react/IconMaterialArrowDropDownW100")); const ListItem_1 = __importDefault(require("../ListItem")); const Type_1 = __importDefault(require("../Type")); const Menu_1 = __importDefault(require("../Menu")); const Chip_1 = __importDefault(require("../Chip")); const Chips_1 = __importDefault(require("../Chips")); const TextField_1 = __importDefault(require("../TextField")); const IconButton_1 = __importDefault(require("../IconButton")); const Line_1 = __importDefault(require("../Line")); const utils_2 = require("../utils"); const useStyle = (0, style_react_1.style)(theme => { const overflow = { width: '100%', overflow: 'hidden', whiteSpace: 'pre', textOverflow: 'ellipsis' }; return { root: { flex: 'unset', minWidth: '184px', '& .amaui-TextField-input': { position: 'absolute', left: '0', bottom: '0', pointerEvents: 'none', opacity: '0' }, '& .amaui-TextField-input-wrapper': { cursor: 'pointer' } }, wrapper: { position: 'relative' }, inputWrapper: { cursor: 'pointer', '&.amaui-TextField-input-wrapper': { cursor: 'pointer' } }, inputWrapper_chip_size_small: { minHeight: '48px' }, inputWrapper_chip_size_regular: { minHeight: '56px' }, inputWrapper_chip_size_large: { minHeight: '64px' }, input: Object.assign(Object.assign({ display: 'flex', alignItems: 'center', width: '100%', minHeight: 20, margin: '0', border: '0', color: theme.palette.text.default.primary, background: 'transparent', '-webkit-tap-highlight-color': 'transparent', textAlign: 'start', borderRadius: `${theme.shape.radius.unit / 2}px ${theme.shape.radius.unit / 2}px 0 0`, cursor: 'pointer', pointerEvents: 'none' }, theme.typography.values.b2), overflow), chip: { '&.amaui-TextField-input-wrapper': { height: 'unset' } }, chipGroup: { pointerEvents: 'auto' }, chipGroup_padding: { paddingTop: theme.methods.space.value(0.5, 'px') }, arrow: { transition: theme.methods.transitions.make('transform') }, arrow_open: { transform: 'rotate(-180deg)' }, open: { '&.amaui-TextField-root': { cursor: 'default' } }, fullWidth: { width: '100%' }, readOnly: { '&.amaui-TextField-root': { cursor: 'default' } }, disabled: { '&.amaui-TextField-root': { cursor: 'default' } } }; }, { name: 'amaui-Select' }); const getValue = (value) => (value === null || value === void 0 ? void 0 : value.value) !== undefined ? value.value : value; const Select = react_1.default.forwardRef((props_, ref) => { var _a; const theme = (0, style_react_1.useAmauiTheme)(); const props = react_1.default.useMemo(() => { var _a, _b, _c, _d, _e, _f, _g, _h; return (Object.assign(Object.assign(Object.assign({}, (_d = (_c = (_b = (_a = theme === null || theme === void 0 ? void 0 : theme.ui) === null || _a === void 0 ? void 0 : _a.elements) === null || _b === void 0 ? void 0 : _b.all) === null || _c === void 0 ? void 0 : _c.props) === null || _d === void 0 ? void 0 : _d.default), (_h = (_g = (_f = (_e = theme === null || theme === void 0 ? void 0 : theme.ui) === null || _e === void 0 ? void 0 : _e.elements) === null || _f === void 0 ? void 0 : _f.amauiSelect) === null || _g === void 0 ? void 0 : _g.props) === null || _h === void 0 ? void 0 : _h.default), props_)); }, [props_]); const Line = react_1.default.useMemo(() => { var _a; return ((_a = theme === null || theme === void 0 ? void 0 : theme.elements) === null || _a === void 0 ? void 0 : _a.Line) || Line_1.default; }, [theme]); const ListItem = react_1.default.useMemo(() => { var _a; return ((_a = theme === null || theme === void 0 ? void 0 : theme.elements) === null || _a === void 0 ? void 0 : _a.ListItem) || ListItem_1.default; }, [theme]); const Type = react_1.default.useMemo(() => { var _a; return ((_a = theme === null || theme === void 0 ? void 0 : theme.elements) === null || _a === void 0 ? void 0 : _a.Type) || Type_1.default; }, [theme]); const Menu = react_1.default.useMemo(() => { var _a; return ((_a = theme === null || theme === void 0 ? void 0 : theme.elements) === null || _a === void 0 ? void 0 : _a.Menu) || Menu_1.default; }, [theme]); const Chip = react_1.default.useMemo(() => { var _a; return ((_a = theme === null || theme === void 0 ? void 0 : theme.elements) === null || _a === void 0 ? void 0 : _a.Chip) || Chip_1.default; }, [theme]); const Chips = react_1.default.useMemo(() => { var _a; return ((_a = theme === null || theme === void 0 ? void 0 : theme.elements) === null || _a === void 0 ? void 0 : _a.Chips) || Chips_1.default; }, [theme]); const TextField = react_1.default.useMemo(() => { var _a; return ((_a = theme === null || theme === void 0 ? void 0 : theme.elements) === null || _a === void 0 ? void 0 : _a.TextField) || TextField_1.default; }, [theme]); const IconButton = react_1.default.useMemo(() => { var _a; return ((_a = theme === null || theme === void 0 ? void 0 : theme.elements) === null || _a === void 0 ? void 0 : _a.IconButton) || IconButton_1.default; }, [theme]); const { tonal = true, color = 'primary', size = 'regular', version = 'filled', value: value_, valueDefault, onChange: onChange_, options, name, multiple, prefix, sufix, start, end, autoWidth = true, getLabel: getLabel_, fullWidth, chip, clear, readOnly, noSelectText, disabled, renderValues: renderValues_, renderChip, IconClear = IconMaterialCloseW100_1.default, IconDropdown = IconMaterialArrowDropDownW100_1.default, WrapperProps, ChipProps, ChiProps, ListProps = { style: { maxHeight: 250, overflowY: 'auto', overflowX: 'hidden' } }, MenuProps = { portal: true }, IconButtonProps, IconProps, className, style, children: children_ } = props, other = __rest(props, ["tonal", "color", "size", "version", "value", "valueDefault", "onChange", "options", "name", "multiple", "prefix", "sufix", "start", "end", "autoWidth", "getLabel", "fullWidth", "chip", "clear", "readOnly", "noSelectText", "disabled", "renderValues", "renderChip", "IconClear", "IconDropdown", "WrapperProps", "ChipProps", "ChiProps", "ListProps", "MenuProps", "IconButtonProps", "IconProps", "className", "style", "children"]); const children = react_1.default.Children.toArray(children_); const [value, setValue] = react_1.default.useState(() => { const values = valueDefault !== undefined ? valueDefault : value_; return multiple ? ((0, utils_1.is)('array', values) ? values : [values]).filter(Boolean) : values; }); const [open, setOpen] = react_1.default.useState(false); const [mouseDown, setMouseDown] = react_1.default.useState(false); const [focus, setFocus] = react_1.default.useState(false); const { classes } = useStyle(); const refs = { root: react_1.default.useRef(undefined), wrapper: react_1.default.useRef(undefined), menu: react_1.default.useRef(undefined), input: react_1.default.useRef(undefined), ids: { list: react_1.default.useId() } }; const styles = { root: {}, menu: {} }; if ((MenuProps === null || MenuProps === void 0 ? void 0 : MenuProps.portal) && autoWidth) { styles.menu.width = (_a = refs.wrapper.current) === null || _a === void 0 ? void 0 : _a.clientWidth; } react_1.default.useEffect(() => { var _a; const method = (event) => { if (event.key === 'Escape') onClose(); }; const rootDocument = (0, utils_1.isEnvironment)('browser') ? (((_a = refs.root.current) === null || _a === void 0 ? void 0 : _a.ownerDocument) || window.document) : undefined; rootDocument.addEventListener('keydown', method); return () => { // Clean up rootDocument.removeEventListener('keydown', method); }; }, []); react_1.default.useEffect(() => { if (value_ !== undefined && value_ !== value) setValue(value_); }, [value_]); const onMouseDown = react_1.default.useCallback((event) => { if (!disabled && !readOnly) setMouseDown(true); }, []); const onMouseUp = react_1.default.useCallback((event) => { if (!disabled && !readOnly) setMouseDown(false); }, []); const onFocus = react_1.default.useCallback((event) => { if (!disabled && !readOnly) setFocus(true); }, []); const onBlur = react_1.default.useCallback((event) => { if (!disabled && !readOnly) setFocus(false); }, []); const onClick = react_1.default.useCallback((event) => { if (!disabled && !readOnly) setOpen(open_ => { if (open_) setFocus(false); return !open_; }); }, []); const onClickArrowDown = react_1.default.useCallback((event) => { if (!disabled && !readOnly) setOpen(open_ => !open_); }, []); const onEnterKeyDown = react_1.default.useCallback((event) => { if (event.key === 'Enter' && !disabled && !readOnly) setOpen(open_ => { if (open_) refs.input.current.focus(); return !open_; }); }, []); const onClose = react_1.default.useCallback((refocus = true) => { if (!disabled && !readOnly) { setOpen(open_ => { if (open_ && refocus) refs.input.current.focus(); return false; }); } }, []); const onChange = (valueNew) => { // Inner controlled value if (!props.hasOwnProperty('value')) setValue(valueNew); if ((0, utils_1.is)('function', onChange_)) onChange_(valueNew); }; const onSelect = (newValue) => { let values = multiple ? (0, utils_1.is)('array', value) ? value : [value] : value; values = multiple ? (0, utils_1.unique)([...values, newValue]) : newValue; onChange(values); }; const onUnselect = (itemValue) => { if (multiple) { let values = (0, utils_1.is)('array', value) ? value : [value]; values = values.filter(item => item !== itemValue); onChange(values); } }; const onClear = react_1.default.useCallback((refocus = false) => { if (!disabled && !readOnly) { onChange(multiple ? [] : null); if (refocus) refs.input.current.focus(); } }, [multiple, readOnly, disabled]); const items = react_1.default.useMemo(() => { return (options || []).map((item) => (Object.assign(Object.assign({}, item), { name: String((item === null || item === void 0 ? void 0 : item.name) !== undefined ? item === null || item === void 0 ? void 0 : item.name : (item === null || item === void 0 ? void 0 : item.value) !== undefined ? item.value : item), value: (item === null || item === void 0 ? void 0 : item.value) !== undefined ? item === null || item === void 0 ? void 0 : item.value : item }))); }, [options]); const getLabel = (item, propsOther) => { if ((0, utils_1.is)('function', getLabel_)) return getLabel_(item, propsOther); const properties = ['name', 'label', 'primary', 'secondary', 'tertiary', 'value', 'children']; const objects = [item, item === null || item === void 0 ? void 0 : item.props].filter(Boolean); for (const itemObject of objects) { if ((0, utils_1.is)('simple', itemObject)) return itemObject; const valueItem = (0, utils_1.getObjectValue)(itemObject, ...properties); if (valueItem !== undefined) return valueItem; } return noSelectText || 'Select an option'; }; const renderValue = (itemValue = value) => { const item = !!(items === null || items === void 0 ? void 0 : items.length) ? items.find((item_) => getValue(item_) === getValue(itemValue)) : children.find((item_) => { var _a; return getValue((_a = item_.props) === null || _a === void 0 ? void 0 : _a.value) === getValue(itemValue); }); return item ? getLabel(item, props) : getLabel(itemValue, props) || ''; }; const renderValues = renderValues_ || ((value__ = value) => { if (multiple) { if (chip) { return ((0, jsx_runtime_1.jsx)(Chips, Object.assign({ wrap: 'wrap', size: size, className: (0, style_react_1.classNames)([ classes.chipGroup, version !== 'outlined' && classes.chipGroup_padding ]) }, ChiProps, { children: value__.map(item => { const other_ = { onClick: (event) => { event.preventDefault(); event.stopPropagation(); }, onRemove: (event) => { event.preventDefault(); event.stopPropagation(); onUnselect(item); }, input: true }; if ((0, utils_1.is)('function', renderChip)) return renderChip(item, renderValue(item), other_); return ((0, jsx_runtime_1.jsx)(Chip, Object.assign({ size: 'small' }, other_, ChipProps, { children: renderValue(item) }), item)); }) }))); } const valuesAll = value.map(item => renderValue(item)); if (valuesAll.every(item => (0, utils_1.is)('simple', item))) return valuesAll.join(', '); return (value === null || value === void 0 ? void 0 : value.length) ? valuesAll : noSelectText || name; } return renderValue(value); }); const endIcons = [ end, clear && !!(multiple ? value.length : ![undefined, null].includes(value)) && ((0, jsx_runtime_1.jsx)(IconButton, Object.assign({ onClick: onClear, size: 'small', "aria-label": 'Input clear' }, IconButtonProps, { children: (0, jsx_runtime_1.jsx)(IconClear, Object.assign({}, IconProps)) }))), ...(!readOnly ? [ (0, jsx_runtime_1.jsx)(IconButton, Object.assign({ size: 'regular', onClick: onClickArrowDown, "aria-expanded": open, "aria-controls": refs.ids.list }, IconButtonProps, { children: (0, jsx_runtime_1.jsx)(IconDropdown, Object.assign({ size: 'large' }, IconProps, { className: (0, style_react_1.classNames)([ IconProps === null || IconProps === void 0 ? void 0 : IconProps.className, classes.arrow, open && classes.arrow_open ]) })) }), 1) ] : []) ]; const sizeListItem = (MenuProps === null || MenuProps === void 0 ? void 0 : MenuProps.size) || size; return ((0, jsx_runtime_1.jsxs)(Line, Object.assign({ gap: 0, direction: 'column', fullWidth: fullWidth }, WrapperProps, { ref: item => { if (WrapperProps === null || WrapperProps === void 0 ? void 0 : WrapperProps.ref) { if ((0, utils_1.is)('function', WrapperProps.ref)) WrapperProps.ref(item); else WrapperProps.ref.current = item; } refs.wrapper.current = item; }, className: (0, style_react_1.classNames)([ (0, utils_2.staticClassName)('Select', theme) && [ 'amaui-Select-wrapper', fullWidth && 'amaui-full-width' ], WrapperProps === null || WrapperProps === void 0 ? void 0 : WrapperProps.className, classes.wrapper ]) }, { children: [(0, jsx_runtime_1.jsx)(TextField, Object.assign({ ref: refs.input, rootRef: (item => { if (ref) { if ((0, utils_1.is)('function', ref)) ref(item); else ref.current = item; } refs.root.current = item; }), onBlur: onBlur, onFocus: onFocus, enabled: open || focus || mouseDown || !!((0, utils_1.is)('array', value) ? value.length : ![undefined, null].includes(value)), focus: open || focus || mouseDown, className: (0, style_react_1.classNames)([ (0, utils_2.staticClassName)('Select', theme) && [ 'amaui-Select-root', `amaui-Select-version-${version}`, `amaui-Select-size-${size}`, open && `amaui-Select-open`, mouseDown && `amaui-Select-mouse-down`, focus && `amaui-Select-focus` ], className, classes.root, open && classes.open, disabled && classes.disabled ]), tonal: tonal, color: color, size: size, version: version, name: name, prefix: prefix, sufix: sufix, start: start, end: endIcons, readOnly: readOnly, endVerticalAlign: 'center', role: 'combobox', "aria-multiselectable": multiple, "aria-controls": refs.ids.list, "aria-expanded": open, "aria-haspopup": 'listbox', "aria-labelledby": name, "aria-disabled": disabled, fullWidth: fullWidth, disabled: disabled, InputWrapperProps: { className: (0, style_react_1.classNames)([ (0, utils_2.staticClassName)('Select', theme) && [ 'amaui-Select-input-wrapper' ], classes.inputWrapper, chip && [ classes.chip, classes[`inputWrapper_chip_size_${size}`] ], open && classes.open, readOnly && classes.readOnly ]), onMouseDown, onMouseUp, onClick, onKeyDown: onEnterKeyDown }, inputProps: { disabled: true, readOnly: true }, style: Object.assign(Object.assign({}, style), styles.root) }, other, { children: (0, jsx_runtime_1.jsx)(Line, Object.assign({ gap: 0, direction: 'row', className: (0, style_react_1.classNames)([ (0, utils_2.staticClassName)('Select', theme) && [ 'amaui-Select-input' ], classes.input, chip && classes.chip, open && classes.open, readOnly && classes.readOnly ]), justify: other.align }, { children: renderValues(value) })) })), (!!items.length || children) && ((0, jsx_runtime_1.jsx)(Menu, Object.assign({ ref: refs.menu, open: open, portal: false, onClose: () => onClose(false), anchorElement: refs.root.current, transformOrigin: 'center top', transformOriginSwitch: 'center bottom', maxWidth: 'unset', size: size, menuItems: !!items.length ? (items.map((item, index) => ((0, jsx_runtime_1.jsx)(ListItem, Object.assign({ role: 'option', selected: item.selected !== undefined ? item.selected : multiple ? value.includes(item === null || item === void 0 ? void 0 : item.value) : value === (item === null || item === void 0 ? void 0 : item.value), preselected: item.preselected !== undefined ? item.preselected : !(multiple ? value.includes(item === null || item === void 0 ? void 0 : item.value) : value === (item === null || item === void 0 ? void 0 : item.value)), onMouseUp: onMouseUp, onMouseDown: onMouseDown, primary: ((0, jsx_runtime_1.jsx)(Type, Object.assign({ version: sizeListItem === 'large' ? 'b1' : sizeListItem === 'regular' ? 'b2' : 'b3' }, { children: item.name }))), value: item.value, size: (MenuProps === null || MenuProps === void 0 ? void 0 : MenuProps.size) || size, button: true }, item.props, { onClick: (event) => { var _a, _b; if (multiple && value.includes(item === null || item === void 0 ? void 0 : item.value)) onUnselect(item === null || item === void 0 ? void 0 : item.value); else onSelect(item === null || item === void 0 ? void 0 : item.value); if ((0, utils_1.is)('function', (_a = item.props) === null || _a === void 0 ? void 0 : _a.onClick)) (_b = item.props) === null || _b === void 0 ? void 0 : _b.onClick(event); if (!multiple) setOpen(false); } }), index)))) : children.map((item, index) => { var _a, _b, _c, _d; return (react_1.default.cloneElement(item, { key: index, role: 'option', selected: item.props.selected !== undefined ? item.props.selected : multiple ? value.includes((_a = item.props) === null || _a === void 0 ? void 0 : _a.value) : value === ((_b = item.props) === null || _b === void 0 ? void 0 : _b.value), preselected: item.props.preselected !== undefined ? item.props.preselected : !(multiple ? value.includes((_c = item.props) === null || _c === void 0 ? void 0 : _c.value) : value === ((_d = item.props) === null || _d === void 0 ? void 0 : _d.value)), onMouseUp, onMouseDown, onClick: (event) => { var _a, _b, _c, _d, _e; if (multiple && value.includes((_a = item.props) === null || _a === void 0 ? void 0 : _a.value)) onUnselect((_b = item.props) === null || _b === void 0 ? void 0 : _b.value); else onSelect((_c = item.props) === null || _c === void 0 ? void 0 : _c.value); if ((0, utils_1.is)('function', (_d = item.props) === null || _d === void 0 ? void 0 : _d.onClick)) (_e = item.props) === null || _e === void 0 ? void 0 : _e.onClick(event); if (!multiple) setOpen(false); } })); }), AppendProps: { alignment: 'start' }, ModalProps: { // focus: !MenuProps.portal }, ListProps: Object.assign({ menu: true, size: (ListProps === null || ListProps === void 0 ? void 0 : ListProps.size) || (MenuProps === null || MenuProps === void 0 ? void 0 : MenuProps.size) || size, role: 'listbox', id: refs.ids.list, 'aria-label': name }, ListProps) }, MenuProps, { style: Object.assign(Object.assign({}, styles.menu), MenuProps === null || MenuProps === void 0 ? void 0 : MenuProps.style), className: (0, style_react_1.classNames)([ MenuProps === null || MenuProps === void 0 ? void 0 : MenuProps.className ]) })))] }))); }); Select.displayName = 'amaui-Select'; exports.default = Select;