UNPKG

vui-design

Version:

A high quality UI Toolkit based on Vue.js

352 lines (305 loc) 8.78 kB
import VuiResizeObserver from "../resize-observer"; import VuiIcon from "../icon"; import Locale from "../../mixins/locale"; import PropTypes from "../../utils/prop-types"; import is from "../../utils/is"; import getClassNamePrefix from "../../utils/getClassNamePrefix"; export const createProps = () => { return { classNamePrefix: PropTypes.string, placeholder: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), value: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), backfillOptionProp: PropTypes.string.def("children"), multiple: PropTypes.bool.def(false), maxTagCount: PropTypes.number, maxTagPlaceholder: PropTypes.func.def(count => "+" + count), searchable: PropTypes.bool.def(false), keyword: PropTypes.string, clearable: PropTypes.bool.def(false), hovered: PropTypes.bool.def(false), focused: PropTypes.bool.def(false), disabled: PropTypes.bool.def(false) }; }; export default { name: "vui-select-selection", inject: { vuiSelect: { default: undefined } }, componetns: { VuiResizeObserver, VuiIcon }, mixins: [ Locale ], props: createProps(), methods: { focus() { this.$refs.input.focus(); }, blur() { this.$refs.input.blur(); }, handleMouseenter(e) { const { $props: props } = this; if (props.disabled) { return; } this.$emit("mouseenter", e); }, handleMouseleave(e) { const { $props: props } = this; if (props.disabled) { return; } this.$emit("mouseleave", e); }, handleMousedown(e) { const { $refs: references, $props: props } = this; if (props.disabled || e.target === references.input) { return; } this.focus(); e.preventDefault(); }, handleClick(e) { const { $props: props } = this; if (props.disabled) { return; } this.$emit("click", e); }, handleFocus(e) { const { $props: props } = this; if (props.disabled) { return; } this.$emit("focus", e); }, handleBlur(e) { const { $props: props } = this; if (props.disabled) { return; } this.$emit("blur", e); }, handleKeydown(e) { const { $props: props } = this; if (props.disabled) { return; } this.$emit("keydown", e); }, handleInput(e) { const { $props: props } = this; if (props.disabled) { return; } this.$emit("input", e); }, handleDeselect(e, item) { const { $props: props } = this; if (props.disabled) { return; } this.$emit("deselect", item); e.stopPropagation(); }, handleClear(e) { const { $props: props } = this; if (props.disabled) { return; } this.$emit("clear", e); e.stopPropagation(); }, handleResize() { this.$emit("resize"); } }, render() { const { vuiSelect, $props: props, t: translate } = this; const { handleMouseenter, handleMouseleave, handleMousedown, handleClick, handleFocus, handleBlur, handleKeydown, handleInput, handleDeselect, handleClear, handleResize } = this; // value const valueLength = props.multiple ? props.value.length : 0; let value = props.value; // placeholder const placeholder = props.placeholder || translate("vui.select.placeholder"); // showItemBtnDeselect const showItemBtnDeselect = props.multiple && !props.disabled; // showBtnClear const showBtnClear = props.clearable && props.hovered && !props.disabled && (props.keyword || (props.multiple ? valueLength > 0 : !is.undefined(value))); // showArrow const showArrow = !props.multiple; // class const classNamePrefix = getClassNamePrefix(props.classNamePrefix, "selection"); let classes = {}; classes.el = `${classNamePrefix}`; classes.elItemList = `${classNamePrefix}-item-list`; classes.elItem = `${classNamePrefix}-item`; classes.elItemContent = `${classNamePrefix}-item-content`; classes.elItemBtnDeselect = `${classNamePrefix}-item-btn-deselect`; classes.elPlaceholder = `${classNamePrefix}-placeholder`; classes.elInput = `${classNamePrefix}-input`; classes.elBtnClear = `${classNamePrefix}-btn-clear`; classes.elArraw = `${classNamePrefix}-arrow`; // style let styles = {}; styles.el = {}; styles.elItem = {}; styles.elPlaceholder = {}; styles.elInput = {}; if (props.disabled) { styles.el.cursor = "not-allowed"; } else if (props.focused) { styles.el.cursor = "text"; } else { styles.el.cursor = "pointer"; } if (!props.multiple) { if (props.keyword) { styles.elItem.opacity = 0; } else if (props.focused) { styles.elItem.opacity = 0.4; } else { styles.elItem.opacity = 1; } } if (props.multiple) { if (valueLength === 0) { styles.elPlaceholder.display = "block"; styles.elPlaceholder.opacity = props.keyword ? 0 : 1; } else { styles.elPlaceholder.display = "none"; styles.elPlaceholder.opacity = 0; } } else { if (is.undefined(value)) { styles.elPlaceholder.display = "block"; styles.elPlaceholder.opacity = props.keyword ? 0 : 1; } else { styles.elPlaceholder.display = "none"; styles.elPlaceholder.opacity = 0; } } if (props.focused) { styles.elInput.opacity = 1; } else { styles.elInput.opacity = 0; } // render const elInput = ( <div key="input" class={classes.elInput} style={styles.elInput}> { props.multiple && props.searchable && ( <pre>{props.keyword}</pre> ) } <input ref="input" type="text" autocomplete="off" value={props.keyword} readonly={!props.searchable} disabled={props.disabled} onFocus={handleFocus} onBlur={handleBlur} onKeydown={handleKeydown} onCompositionstart={handleInput} onCompositionupdate={handleInput} onCompositionend={handleInput} onInput={handleInput} /> </div> ); let children = []; if (props.multiple) { let maxTagPlaceholder; if (props.maxTagCount >= 0 && valueLength > props.maxTagCount) { value = value.slice(0, props.maxTagCount); maxTagPlaceholder = ( <div key="maxTagPlaceholder" class={classes.elItem}> <div class={classes.elItemContent}> {props.maxTagPlaceholder(valueLength - props.maxTagCount)} </div> </div> ); } let itemList = value.map(item => { return ( <div key={item.value} class={classes.elItem}> <div class={classes.elItemContent}>{item[props.backfillOptionProp]}</div> { showItemBtnDeselect && !item.disabled && ( <div class={classes.elItemBtnDeselect} onClick={e => handleDeselect(e, item)}> <VuiIcon type="crossmark" /> </div> ) } </div> ); }); if (maxTagPlaceholder) { itemList.push(maxTagPlaceholder); } itemList.push(elInput); children.push( <div key="item-list" class={classes.elItemList}> {itemList} </div> ); } else if (!is.undefined(value)) { children.push( <div key="item" class={classes.elItem} style={styles.elItem}> <div class={classes.elItemContent}>{value[props.backfillOptionProp]}</div> </div> ); } children.push( <div key="placeholder" class={classes.elPlaceholder} style={styles.elPlaceholder}> {placeholder} </div> ); if (!props.multiple) { children.push(elInput); } if (showBtnClear) { children.push( <div key="btn-clear" class={classes.elBtnClear} onClick={handleClear}> <VuiIcon type="crossmark-circle-filled" /> </div> ); } else if (showArrow) { children.push( <div key="arrow" class={classes.elArraw}></div> ); } return ( <VuiResizeObserver onResize={handleResize}> <div class={classes.el} style={styles.el} onMouseenter={handleMouseenter} onMouseleave={handleMouseleave} onMousedown={handleMousedown} onClick={handleClick} > {children} </div> </VuiResizeObserver> ); } };