UNPKG

quasar-framework

Version:

Simultaneously build desktop/mobile SPA websites & phone/tablet apps with VueJS

284 lines (271 loc) 7.51 kB
import FrameMixin from '../../mixins/input-frame' import DisplayModeMixin from '../../mixins/display-mode' import extend from '../../utils/extend' import { QInputFrame } from '../input-frame' import { QPopover } from '../popover' import QColorPicker from './QColorPicker' import { QBtn } from '../btn' import { QModal } from '../modal' import clone from '../../utils/clone' import { getEventKey, stopAndPrevent } from '../../utils/event' const contentCss = __THEME__ === 'ios' ? { maxHeight: '80vh', height: 'auto', boxShadow: 'none', backgroundColor: '#e4e4e4' } : { maxWidth: '95vw', maxHeight: '98vh' } export default { name: 'q-color', mixins: [FrameMixin, DisplayModeMixin], props: { value: { required: true }, color: { type: String, default: 'primary' }, defaultValue: { type: [String, Object], default: null }, formatModel: { type: String, default: 'auto', validator: v => ['auto', 'hex', 'rgb', 'hexa', 'rgba'].includes(v) }, displayValue: String, placeholder: String, okLabel: String, cancelLabel: String }, data () { let data = this.isPopover ? {} : { transition: __THEME__ === 'ios' ? 'q-modal-bottom' : 'q-modal' } data.focused = false data.model = clone(this.value || this.defaultValue) return data }, computed: { actualValue () { if (this.displayValue) { return this.displayValue } if (this.value) { return typeof this.value === 'string' ? this.value : `rgb${this.value.a !== void 0 ? 'a' : ''}(${this.value.r},${this.value.g},${this.value.b}${this.value.a !== void 0 ? `,${this.value.a / 100}` : ''})` } return '' }, modalBtnColor () { return this.$q.theme === 'mat' ? this.color : (this.dark ? 'light' : 'dark') } }, methods: { toggle () { this[this.$refs.popup.showing ? 'hide' : 'show']() }, show () { if (!this.disable) { if (!this.focused) { this.__setModel(this.value || this.defaultValue) } return this.$refs.popup.show() } }, hide () { this.focused = false return this.$refs.popup.hide() }, __handleKeyDown (e) { switch (getEventKey(e)) { case 13: // ENTER key case 32: // SPACE key stopAndPrevent(e) return this.show() case 8: // BACKSPACE key if (this.editable && this.clearable && this.actualValue.length) { this.clear() } } }, __onFocus () { if (this.disable || this.focused) { return } this.__setModel(this.value || this.defaultValue) this.focused = true this.$emit('focus') }, __onBlur (e) { this.__onHide() setTimeout(() => { const el = document.activeElement if (el !== document.body && !this.$refs.popup.$el.contains(el)) { this.hide() } }, 1) }, __onHide (forceUpdate) { this.focused = false this.$emit('blur') if (forceUpdate || (this.isPopover && this.$refs.popup.showing)) { this.__update(true) } }, __setModel (val, forceUpdate) { this.model = clone(val) if (forceUpdate || (this.isPopover && this.$refs.popup.showing)) { this.__update(forceUpdate) } }, __update (change) { this.$nextTick(() => { this.$emit('input', this.model) this.$nextTick(() => { if (change && JSON.stringify(this.model) !== JSON.stringify(this.value)) { this.$emit('change', this.model) } }) }) }, __getPicker (h, modal) { const child = [ h(QColorPicker, { staticClass: `no-border${modal ? ' full-width' : ''}`, props: extend({ value: this.model || '#000', disable: this.disable, readonly: this.readonly, formatModel: this.formatModel, dark: this.dark, noParentField: true }, this.$attrs), on: { input: v => this.$nextTick(() => this.__setModel(v)) } }) ] if (modal) { child[__THEME__ === 'mat' ? 'push' : 'unshift'](h('div', { staticClass: 'modal-buttons modal-buttons-top row full-width', 'class': this.dark ? 'bg-black' : null }, [ h('div', { staticClass: 'col' }), h(QBtn, { props: { color: this.modalBtnColor, flat: true, label: this.cancelLabel || this.$q.i18n.label.cancel, waitForRipple: true }, on: { click: this.hide } }), this.editable ? h(QBtn, { props: { color: this.modalBtnColor, flat: true, label: this.okLabel || this.$q.i18n.label.set, waitForRipple: true }, on: { click: () => { this.hide() this.__update(true) } } }) : null ])) } return child } }, render (h) { return h(QInputFrame, { props: { prefix: this.prefix, suffix: this.suffix, stackLabel: this.stackLabel, floatLabel: this.floatLabel, error: this.error, warning: this.warning, disable: this.disable, inverted: this.inverted, invertedLight: this.invertedLight, dark: this.dark, hideUnderline: this.hideUnderline, before: this.before, after: this.after, color: this.color, noParentField: this.noParentField, focused: this.focused, focusable: true, length: this.actualValue.length }, nativeOn: { click: this.toggle, focus: this.__onFocus, blur: this.__onBlur, keydown: this.__handleKeyDown } }, [ h('div', { staticClass: 'col q-input-target ellipsis', 'class': this.fakeInputClasses }, [ this.fakeInputValue ]), this.isPopover ? h(QPopover, { ref: 'popup', props: { disable: this.disable, anchorClick: false, maxHeight: '100vh' }, on: { show: this.__onFocus, hide: val => this.__onHide(true) } }, this.__getPicker(h)) : h(QModal, { ref: 'popup', staticClass: 'with-backdrop', props: { contentCss, minimized: __THEME__ === 'mat', position: __THEME__ === 'ios' ? 'bottom' : null, transition: this.transition }, on: { show: this.__onFocus, hide: val => this.__onHide(true) } }, this.__getPicker(h, true)), this.editable && this.clearable && this.actualValue.length ? h('q-icon', { slot: 'after', props: { name: this.$q.icon.input[`clear${this.isInverted ? 'Inverted' : ''}`] }, nativeOn: { click: this.clear }, staticClass: 'q-if-control' }) : null, h('q-icon', { slot: 'after', props: { name: this.$q.icon.input.dropdown }, staticClass: 'q-if-control' }) ]) } }