UNPKG

@limetech/lime-elements

Version:
193 lines (192 loc) • 7.35 kB
import { h } from '@stencil/core'; import { isMultiple } from '../../util/multiple'; import { getIconColor, getIconName } from '../icon/get-icon-props'; export const SelectTemplate = (props) => { const value = props.value; let hasValue = !!props.value; let hasEmptyText = true; if (isMultiple(value)) { hasValue = value.length > 0; } else if (hasValue) { hasValue = !!value.value; hasEmptyText = value.text === ''; } let isValid = !props.invalid; if (props.checkValid && props.required && !hasValue) { isValid = false; } const classList = { 'limel-select': true, 'mdc-select': true, 'mdc-select--disabled': props.disabled, 'limel-select--readonly': props.readonly, 'limel-select--invalid': !isValid, 'limel-select--with-helper-text': typeof props.helperText === 'string', }; return [ h("limel-notched-outline", { class: classList, labelId: "s-label", label: props.label, required: props.required, invalid: !isValid, disabled: props.disabled, readonly: props.readonly, hasValue: hasValue, hasFloatingLabel: floatLabelAbove(props) }, h(SelectValue, Object.assign({}, props, { hasValue: hasValue, isValid: isValid, hasEmptyText: hasEmptyText }))), h(HelperText, { text: props.helperText, isValid: !props.invalid }), h(SelectDropdown, Object.assign({}, props)), ]; }; const floatLabelAbove = (props) => { if (props.isOpen) { return true; } const value = props.value; if (value) { if (isMultiple(value)) { return value.length > 0; } else { return value.text !== ''; } } return false; }; const SelectValue = (props) => { const anchorClassList = { 'mdc-select__anchor': true, 'limel-select-trigger': true, 'limel-select--focused': props.isOpen, }; return (h("button", { slot: "content", class: anchorClassList, onClick: props.open, onKeyPress: props.onTriggerPress, "aria-haspopup": "listbox", "aria-expanded": props.isOpen, "aria-controls": props.id, "aria-labelledby": "s-label s-selected-text", "aria-required": props.required, disabled: props.disabled || props.readonly }, h("span", { class: "mdc-select__selected-text-container limel-select__selected-option" }, getSelectedIcon(props.value), h("span", { id: "s-selected-text", class: "mdc-select__selected-text limel-select__selected-option__text" }, getSelectedText(props.value))), h(ShowIcon, Object.assign({}, props, { isValid: props.isValid })), h("span", { class: "mdc-select__dropdown-icon" }, h("svg", { class: "mdc-select__dropdown-icon-graphic", viewBox: "7 10 10 5", focusable: "false" }, h("polygon", { stroke: "none", "fill-rule": "evenodd", points: "7 10 12 15 17 10" }))))); }; const ShowIcon = (props) => { if (props.isValid) { return; } return (h("limel-icon", { name: "high_importance", size: "medium", class: "invalid-icon" })); }; const HelperText = (props) => { if (typeof props.text !== 'string') { return; } return (h("limel-helper-line", { helperText: props.text.trim(), invalid: !props.isValid })); }; const SelectDropdown = (props) => { if (props.native) { return h(NativeDropdown, Object.assign({}, props)); } return h(MenuDropdown, Object.assign({}, props)); }; const MenuDropdown = (props) => { const items = createMenuItems(props.options, props.value, props.required); return (h("limel-portal", { containerId: props.id, visible: props.isOpen, inheritParentWidth: true, containerStyle: { 'z-index': props.dropdownZIndex } }, h("limel-menu-surface", { open: props.isOpen, onDismiss: props.close, style: { '--menu-surface-width': '100%', 'max-height': 'inherit', display: 'flex', 'min-width': '100%', width: 'fit-content', } }, h("limel-list", { items: items, type: props.multiple ? 'checkbox' : 'selectable', onChange: props.onMenuChange })))); }; const NativeDropdown = (props) => { const options = props.options .filter((option) => !('separator' in option)) .map(renderOption(props.value)); return (h("select", { required: props.required, "aria-disabled": props.disabled, "aria-required": props.required, onChange: props.onNativeChange, onFocus: props.open, onBlur: props.close, class: "limel-select__native-control", disabled: props.disabled, multiple: props.multiple }, options)); }; const renderOption = (selectedOption) => { return (option) => { const { value, disabled, text } = option; return (h("option", { key: value, value: value, selected: isSelected(option, selectedOption), disabled: disabled }, text)); }; }; function isSelected(option, value) { if (!value) { return false; } if (isMultiple(value)) { return value.some((o) => option.value === o.value); } return option.value === value.value; } function createMenuItems(options, value, selectIsRequired = false) { const menuOptionFilter = getMenuOptionFilter(selectIsRequired); return options.filter(menuOptionFilter).map((option) => { if ('separator' in option) { return { text: option.text, separator: true, }; } const selected = isSelected(option, value); const { text, secondaryText, disabled } = option; const name = getIconName(option.icon); const color = getIconColor(option.icon, option.iconColor); if (!name) { return { text: text, secondaryText: secondaryText, selected: selected, disabled: disabled, value: option, }; } return { text: text, secondaryText: secondaryText, selected: selected, disabled: disabled, value: option, icon: { name: name, color: color, }, }; }); } function getMenuOptionFilter(selectIsRequired) { return (option) => { if (!selectIsRequired) { // If the select component is NOT required, we keep all options. return true; } if (option.text) { // If the select component IS required, we keep only options // that are not "empty". We only check the text property, because // some systems use an "empty option" that will have a value for // the `value` property, to signify "no option selected". Such // an option should be treated as "empty". return true; } if ('separator' in option) { return true; } }; } function getSelectedText(value) { const isEmptyValue = !value || (isMultiple(value) && value.length === 0); if (isEmptyValue) { return ''; } if (isMultiple(value)) { return value.map((option) => option.text).join(', '); } return value.text; } function getSelectedIcon(value) { if (!(value === null || value === void 0 ? void 0 : value.icon)) { return ''; } const name = getIconName(value.icon); const color = getIconColor(value.icon, value.iconColor); const style = {}; if (color) { style.color = color; } return (h("limel-icon", { class: "limel-select__selected-option__icon", name: name, size: "medium", style: style })); } /** * * @param options */ export function triggerIconColorWarning(options) { for (const option of options) { if (option.iconColor) { console.warn("The `iconColor` prop is deprecated now! Use the new `Icon` interface and instead of `iconColor: 'color-name'` write `icon {name: 'icon-name', color: 'color-name'}`."); } } } //# sourceMappingURL=select.template.js.map