UNPKG

vui-design

Version:

A high quality UI Toolkit based on Vue.js

238 lines (214 loc) 6.24 kB
import Emitter from "../../mixins/emitter"; import PropTypes from "../../utils/prop-types"; import is from "../../utils/is"; import getClassNamePrefix from "../../utils/getClassNamePrefix"; export const createProps = () => { return { classNamePrefix: PropTypes.string, name: PropTypes.string, type: PropTypes.string, size: PropTypes.oneOf(["small", "medium", "large"]), minWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]), checked: PropTypes.oneOfType([PropTypes.bool, PropTypes.string, PropTypes.number]).def(false), disabled: PropTypes.bool.def(false), checkedValue: PropTypes.oneOfType([PropTypes.bool, PropTypes.string, PropTypes.number]).def(true), uncheckedValue: PropTypes.oneOfType([PropTypes.bool, PropTypes.string, PropTypes.number]).def(false), validator: PropTypes.bool.def(true) }; }; export default { name: "vui-radio", inject: { vuiForm: { default: undefined }, vuiRadioGroup: { default: undefined }, vuiChoiceGroup: { default: undefined } }, mixins: [ Emitter ], inheritAttrs: false, model: { prop: "checked", event: "input" }, props: createProps(), data() { const { $props: props } = this; const state = { focused: false, checked: props.checked }; return { state }; }, watch: { checked(value) { if (this.state.checked === value) { return; } this.state.checked = value; } }, methods: { handleFocus(e) { this.state.focused = true; this.$emit("focus"); }, handleBlur(e) { this.state.focused = false; this.$emit("blur"); }, handleChange(e) { const { vuiRadioGroup, vuiChoiceGroup, $refs: references, $props: props } = this; const checked = e.target.checked; if (props.disabled) { return; } if (vuiRadioGroup) { const beforeCheck = vuiRadioGroup.beforeSelect || vuiRadioGroup.beforeCheck; const callback = () => vuiRadioGroup.handleChange(checked, props.value); let hook = true; if (is.function(beforeCheck)) { hook = beforeCheck(props.value); } if (is.boolean(hook) && hook === false) { references.radio.checked = ""; } else if (is.promise(hook)) { hook.then(() => callback()).catch(() => references.radio.checked = ""); } else { callback(); } } else if (vuiChoiceGroup) { vuiChoiceGroup.handleChange("radio", checked, props.value); } else { const value = checked ? props.checkedValue : props.uncheckedValue; this.state.checked = value; this.$emit("input", value); this.$emit('change', value); if (props.validator) { this.dispatch("vui-form-item", "change", value); } } } }, render() { const { vuiForm, vuiRadioGroup, vuiChoiceGroup, $slots: slots, $attrs: attrs, $props: props, state } = this; const { handleFocus, handleBlur, handleChange } = this; // props & state let type, name, label, value, size, minWidth, focused, checked, disabled; if (vuiRadioGroup) { type = vuiRadioGroup.type; name = vuiRadioGroup.name; } else if (vuiChoiceGroup) { type = vuiChoiceGroup.type; name = vuiChoiceGroup.name; } else { type = props.type; name = props.name; } label = slots.default || props.label; value = props.value; if (props.size) { size = props.size; } else if (vuiRadioGroup && vuiRadioGroup.size) { size = vuiRadioGroup.size; } else if (vuiChoiceGroup && vuiChoiceGroup.size) { size = vuiChoiceGroup.size; } else if (vuiForm && vuiForm.size) { size = vuiForm.size; } else { size = "medium"; } if (props.minWidth) { minWidth = props.minWidth; } else if (vuiRadioGroup && vuiRadioGroup.minWidth) { minWidth = vuiRadioGroup.minWidth; } else if (vuiChoiceGroup && vuiChoiceGroup.minWidth) { minWidth = vuiChoiceGroup.minWidth; } focused = state.focused; if (vuiRadioGroup) { checked = value === vuiRadioGroup.state.value; } else if (vuiChoiceGroup) { checked = !is.array(vuiChoiceGroup.state.value) && value === vuiChoiceGroup.state.value; } else { checked = state.checked === props.checkedValue; } if (vuiForm && vuiForm.disabled) { disabled = vuiForm.disabled; } else if (vuiRadioGroup && vuiRadioGroup.disabled) { disabled = vuiRadioGroup.disabled; } else if (vuiChoiceGroup && vuiChoiceGroup.disabled) { disabled = vuiChoiceGroup.disabled; } else { disabled = props.disabled; } // class const classNamePrefix = getClassNamePrefix(props.classNamePrefix, type === "button" ? "radio-button" : "radio"); let classes = {}; classes.el = { [`${classNamePrefix}`]: true, [`${classNamePrefix}-${size}`]: size, [`${classNamePrefix}-focused`]: focused, [`${classNamePrefix}-checked`]: checked, [`${classNamePrefix}-disabled`]: disabled }; classes.elInput = `${classNamePrefix}-input`; classes.elLabel = `${classNamePrefix}-label`; // style let styles = {}; if (type === "button" && minWidth) { styles.el = { minWidth: is.string(minWidth) ? minWidth : `${minWidth}px` }; } // render const attributes = { ref: "radio", attrs: attrs, on: { focus: handleFocus, blur: handleBlur, change: handleChange } }; return ( <label class={classes.el} style={styles.el}> <div class={classes.elInput}> <input type="radio" name={name} value={value} checked={checked} disabled={disabled} {...attributes} /> </div> { label ? ( <div class={classes.elLabel}>{label}</div> ) : null } </label> ); } };