@mutt/widgets-vue
Version:
Mutt forms - VueJS integration
223 lines (191 loc) • 5.7 kB
JavaScript
/**
* Mutt Forms Vue
* Wrapper for Mutt Forms for Vue.js
**/
import Mutt from '@mutt/forms'
// Widgets
import MuttVue from './Form.vue'
import MuttWatcher from './Watcher.vue'
import MuttText from './widgets/Text.vue'
import MuttTel from './widgets/Tel.vue'
import MuttTextarea from './widgets/Textarea.vue'
import MuttNumber from './widgets/Number.vue'
import MuttCheckbox from './widgets/Checkbox.vue'
import MuttRadio from './widgets/Radio.vue'
import MuttChoice from './widgets/Select.vue'
import MuttObject from './widgets/Object.vue'
import MuttArray from './widgets/Array.vue'
import MuttHidden from './widgets/Hidden.vue'
import MuttPassword from './widgets/Password.vue'
import MuttLabel from './widgets/helpers/Label.vue'
import WidgetMixin from './mixins/WidgetMixin'
import ValueSubstituteMixin from './mixins/ValueSubstitute'
import {
PropsProxy,
DataProxy,
ComputedProxy,
MethodProxy,
MuttWidgetProxy,
} from './utils'
// Proxy used to mock Widget interface to Mutt.
// NOTE: This is never used in practice as Vue components
// overwrite this value and masqurade as Mutt Widgets
/* eslint-disable */
class VueWidget extends Mutt.widgets.Widget {
constructor(field, type, id, name, label,
attribs = {}, options = {}, initial = null) {
super(field, type, id, name, label, attribs,
options, initial)
}
render() {
return null
}
}
/* eslint-enable */
export default {
install(Vue, options) {
// Get the default component list
let components = {
MuttText,
MuttTel,
MuttTextarea,
MuttNumber,
MuttCheckbox,
MuttChoice,
MuttObject,
MuttArray,
MuttRadio,
MuttHidden,
MuttPassword,
}
// We may in future want to extend the component list
if (options && options.hasOwnProperty('plugins')) {
// Ensure that plugins allow for overriding core components
components = {
...components,
...options.plugins,
}
}
// Setup a new instance of the config, this will later
// be used to map field types back to widgets
for (let component of Object.values(components)) {
let name = component.name
let type = name.replace('mutt-', '')
if (component.hasOwnProperty('for')) {
type = component.for
}
let VueWidgetProxy = function(
field, type, id, name, label,
attribs = {}, options = {}, initial = null
) {
return new VueWidget(
field, type, id, name, label,
attribs, options, initial
)
}
VueWidgetProxy.getWidgetName = () => {
return name
}
Mutt.config.registerWidget(type, VueWidgetProxy)
if (component.hasOwnProperty('alternative')) {
Mutt.config.registerWidget(
component.alternative,
VueWidgetProxy
)
}
}
// Register the binding widget
Vue.component('mutt-widget', {
render(h) {
const component = this.resolveWidget()
if (component) {
return h(component, {
on: this.$listeners,
props: {
field: this.field,
readonly: this.readonly,
fieldIndex: this.fieldIndex,
},
})
}
throw new Error(
`No Vue component could be found registered for Mutt widget type "${
this.getWidget()
}".`
)
},
props: [
'field',
'widget',
'readonly',
'fieldIndex',
],
components,
methods: {
/**
* Get the name of the Mutt-internal widget the field should render as.
*
* @return {string} The name of the Mutt widget to try to use for this field.
*/
getWidget() {
// If a widget is specified directly, we always use this
if (this.widget) {
return this.widget
}
// Option overrides take next priority
if (this.field.options.hasOwnProperty('widget')) {
return this.field.options.widget
}
// Hidden is a special case, as this can be specified using
// a non-widget key
if (this.field.options.hasOwnProperty('hidden')) {
if (this.field.options.hidden) {
return 'hidden'
}
}
// By default we fallback to the field type
return this.field.type
},
/**
* Resolve the Vue component to render based on this field's type and
* options.
*
* @return {string} The kebab-cased Vue component to render (by name).
*/
resolveWidget() {
// As we use a proxy to integrate Mutt Vue widgets into
// Vue, we need to 'resolve' this proxy here. Mutt Vue
// components are registered globally within Vue, we just
// need to resolve the name
const widget = Mutt.config.getWidget(this.getWidget())
if (typeof widget === 'function') {
if (widget.name === 'VueWidgetProxy') {
return widget.getWidgetName()
}
}
return widget
},
},
})
/**
* Special Mutt Watcher Component
*/
Vue.component('mutt-watcher', MuttWatcher)
/**
* Register root vue on global scope to be usable anywhere
* outside of mutt-widget
*/
Vue.component('mutt-vue', MuttVue)
Vue.prototype.$mutt = Mutt
},
mixin: WidgetMixin,
utils: {
PropsProxy,
DataProxy,
ComputedProxy,
MethodProxy,
MuttWidgetProxy,
},
}
export { ValueSubstituteMixin, MuttLabel }