1
0
mirror of synced 2024-11-22 13:26:06 +03:00

Adds initial work on groupings

This commit is contained in:
Justin Schroeder 2020-04-16 09:22:58 -04:00
parent 3d79733cba
commit 1e52dcc213
17 changed files with 175 additions and 38 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,16 +1,19 @@
<template> <template>
<div id="app"> <div id="app">
<SpecimenGroup />
<SpecimenText /> <SpecimenText />
</div> </div>
</template> </template>
<script> <script>
import SpecimenText from './specimens/SpecimenText' import SpecimenText from './specimens/SpecimenText'
import SpecimenGroup from './specimens/SpecimenGroup'
export default { export default {
name: 'App', name: 'App',
components: { components: {
SpecimenText SpecimenText,
SpecimenGroup
}, },
data () { data () {
return { return {
@ -24,4 +27,13 @@ export default {
body { body {
font-family: $formulate-font-stack; font-family: $formulate-font-stack;
} }
.specimens {
margin-bottom: 2em;
padding-bottom: 2em;
border-bottom: 1px solid gray;
&:last-child {
border-bottom: 0;
}
}
</style> </style>

View File

@ -0,0 +1,22 @@
<template>
<div class="specimens specimens--group">
<FormulateInput
label="Invite some new users"
type="group"
placeholder="users"
help="Fields can be grouped"
>
<FormulateInput
name="Name"
type="text"
placeholder="Users name"
/>
<FormulateInput
name="Email"
type="email"
placeholder="Users email"
validation="required|email"
/>
</FormulateInput>
</div>
</template>

View File

@ -6,15 +6,11 @@
placeholder="Username" placeholder="Username"
help="Select a username" help="Select a username"
/> />
<FormulateInput
label="How old are you?"
type="number"
placeholder="25"
help="Select your age"
/>
</div> </div>
</template> </template>
<script>
export default {
}
</script>
<style>
</style>

View File

@ -6,15 +6,18 @@ import { arrayify, parseLocale } from './libs/utils'
import isPlainObject from 'is-plain-object' import isPlainObject from 'is-plain-object'
import { en } from '@braid/vue-formulate-i18n' import { en } from '@braid/vue-formulate-i18n'
import fauxUploader from './libs/faux-uploader' import fauxUploader from './libs/faux-uploader'
import FormulateSlot from './FormulateSlot'
import FormulateInput from './FormulateInput.vue' import FormulateInput from './FormulateInput.vue'
import FormulateForm from './FormulateForm.vue' import FormulateForm from './FormulateForm.vue'
import FormulateErrors from './FormulateErrors.vue' import FormulateErrors from './FormulateErrors.vue'
import FormulateHelp from './slots/FormulateHelp.vue' import FormulateHelp from './slots/FormulateHelp.vue'
import FormulateGrouping from './FormulateGrouping.vue'
import FormulateLabel from './slots/FormulateLabel.vue' import FormulateLabel from './slots/FormulateLabel.vue'
import FormulateInputGroup from './FormulateInputGroup.vue'
import FormulateInputBox from './inputs/FormulateInputBox.vue' import FormulateInputBox from './inputs/FormulateInputBox.vue'
import FormulateInputText from './inputs/FormulateInputText.vue' import FormulateInputText from './inputs/FormulateInputText.vue'
import FormulateInputFile from './inputs/FormulateInputFile.vue' import FormulateInputFile from './inputs/FormulateInputFile.vue'
import FormulateRepeatable from './slots/FormulateRepeatable.vue'
import FormulateInputGroup from './inputs/FormulateInputGroup.vue'
import FormulateInputButton from './inputs/FormulateInputButton.vue' import FormulateInputButton from './inputs/FormulateInputButton.vue'
import FormulateInputSelect from './inputs/FormulateInputSelect.vue' import FormulateInputSelect from './inputs/FormulateInputSelect.vue'
import FormulateInputSlider from './inputs/FormulateInputSlider.vue' import FormulateInputSlider from './inputs/FormulateInputSlider.vue'
@ -31,14 +34,17 @@ class Formulate {
this.options = {} this.options = {}
this.defaults = { this.defaults = {
components: { components: {
FormulateSlot,
FormulateForm, FormulateForm,
FormulateHelp, FormulateHelp,
FormulateLabel, FormulateLabel,
FormulateInput, FormulateInput,
FormulateErrors, FormulateErrors,
FormulateGrouping,
FormulateInputBox, FormulateInputBox,
FormulateInputText, FormulateInputText,
FormulateInputFile, FormulateInputFile,
FormulateRepeatable,
FormulateInputGroup, FormulateInputGroup,
FormulateInputButton, FormulateInputButton,
FormulateInputSelect, FormulateInputSelect,

32
src/FormulateGrouping.vue Normal file
View File

@ -0,0 +1,32 @@
<template>
<FormulateSlot
name="repeatable"
>
<FormulateRepeatable
v-for="item in items"
:key="item.id"
>
<slot />
</FormulateRepeatable>
</FormulateSlot>
</template>
<script>
export default {
props: {
context: {
type: Object,
required: true
}
},
computed: {
items () {
return [{ id: 1 }, { id: 2 }]
}
}
}
</script>
<style>
</style>

View File

@ -46,16 +46,22 @@
v-bind="context" v-bind="context"
> >
<component <component
:is="slotComponents.help" :is="context.slotComponents.help"
v-if="context.help" v-if="context.help"
:context="context" :context="context"
/> />
</slot> </slot>
<FormulateErrors <slot
v-if="!disableErrors" name="errors"
:type="`input`" v-bind="context"
:context="context" >
/> <component
:is="context.slotComponents.errors"
v-if="!context.disableErrors"
:type="context.slotComponents.errors === 'FormulateErrors' ? 'input' : false"
:context="context"
/>
</slot>
</div> </div>
</template> </template>

14
src/FormulateSlot.js Normal file
View File

@ -0,0 +1,14 @@
export default {
inheritAttrs: false,
functional: true,
render (h, { props, data, parent, children }) {
var p = parent
while (p && p.$options.name !== 'FormulateInput') {
p = p.$parent
}
if (p.$scopedSlots && p.$scopedSlots[props.name]) {
return p.$scopedSlots[props.name](props)
}
return h('div', data, children)
}
}

View File

@ -1,15 +1,27 @@
<template> <template>
<div class="formulate-input-group"> <div class="formulate-input-group">
<component <template
:is="subComponent" v-if="subType !== 'grouping'"
v-for="optionContext in optionsWithContext" >
:key="optionContext.id" <FormulateInput
v-model="context.model" v-for="optionContext in optionsWithContext"
v-bind="optionContext" :key="optionContext.id"
:disable-errors="true" v-model="context.model"
class="formulate-input-group-item" v-bind="optionContext"
@blur="context.blurHandler" :disable-errors="true"
/> class="formulate-input-group-item"
@blur="context.blurHandler"
/>
</template>
<template
v-else
>
<FormulateGrouping
:context="context"
>
<slot />
</FormulateGrouping>
</template>
</div> </div>
</template> </template>
@ -26,9 +38,8 @@ export default {
options () { options () {
return this.context.options || [] return this.context.options || []
}, },
subComponent () { subType () {
// @todo - rough-in for future flexible input-groups return (this.context.type === 'group') ? 'grouping' : 'inputs'
return 'FormulateInput'
}, },
optionsWithContext () { optionsWithContext () {
const { const {

View File

@ -13,6 +13,7 @@ export default {
blurHandler: blurHandler.bind(this), blurHandler: blurHandler.bind(this),
classification: this.classification, classification: this.classification,
component: this.component, component: this.component,
disableErrors: this.disableErrors,
errors: this.explicitErrors, errors: this.explicitErrors,
getValidationErrors: this.getValidationErrors.bind(this), getValidationErrors: this.getValidationErrors.bind(this),
hasLabel: (this.label && this.classification !== 'button'), hasLabel: (this.label && this.classification !== 'button'),
@ -238,7 +239,8 @@ function hasVisibleErrors () {
function slotComponents () { function slotComponents () {
return { return {
label: this.$formulate.slotComponent(this.type, 'label'), label: this.$formulate.slotComponent(this.type, 'label'),
help: this.$formulate.slotComponent(this.type, 'help') help: this.$formulate.slotComponent(this.type, 'help'),
errors: this.$formulate.slotComponent(this.type, 'errors')
} }
} }

View File

@ -47,5 +47,8 @@ export default {
// === FILE TYPE // === FILE TYPE
file: add('file'), file: add('file'),
image: add('file') image: add('file'),
// === GROUP TYPE
group: add('group')
} }

View File

@ -0,0 +1,19 @@
<template>
<div
class="formulate-group-row"
>
<FormulateSlot
name="default"
/>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>

View File

@ -62,14 +62,17 @@ describe('Formulate', () => {
it('installs on vue instance', () => { it('installs on vue instance', () => {
const components = [ const components = [
'FormulateSlot',
'FormulateForm', 'FormulateForm',
'FormulateHelp', 'FormulateHelp',
'FormulateLabel', 'FormulateLabel',
'FormulateInput', 'FormulateInput',
'FormulateErrors', 'FormulateErrors',
'FormulateGrouping',
'FormulateInputBox', 'FormulateInputBox',
'FormulateInputText', 'FormulateInputText',
'FormulateInputFile', 'FormulateInputFile',
'FormulateRepeatable',
'FormulateInputGroup', 'FormulateInputGroup',
'FormulateInputButton', 'FormulateInputButton',
'FormulateInputSelect', 'FormulateInputSelect',

View File

@ -4,7 +4,7 @@ import { mount } from '@vue/test-utils'
import Formulate from '../../src/Formulate.js' import Formulate from '../../src/Formulate.js'
import FormulateInput from '@/FormulateInput.vue' import FormulateInput from '@/FormulateInput.vue'
import FormulateInputBox from '@/inputs/FormulateInputBox.vue' import FormulateInputBox from '@/inputs/FormulateInputBox.vue'
import FormulateInputGroup from '@/FormulateInputGroup.vue' import FormulateInputGroup from '@/inputs/FormulateInputGroup.vue'
Vue.use(Formulate) Vue.use(Formulate)

View File

@ -272,4 +272,15 @@ describe('FormulateInputText', () => {
}) })
expect(wrapper.find('small').text()).toBe('Do you want some soda?') expect(wrapper.find('small').text()).toBe('Do you want some soda?')
}) })
it('Allow errors override with scoped slot', async () => {
const wrapper = mount(FormulateInput, {
propsData: { type: 'text', name: 'soda', validation: 'required|in:foo,bar', errorBehavior: 'live' },
scopedSlots: {
errors: '<ul class="my-errors"><li v-for="error in props.visibleValidationErrors">{{ error }}</li></ul>'
}
})
await flushPromises();
expect(wrapper.findAll('.my-errors li').length).toBe(2)
})
}) })