1
0
mirror of synced 2024-11-25 23:06:02 +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>
<div id="app">
<SpecimenGroup />
<SpecimenText />
</div>
</template>
<script>
import SpecimenText from './specimens/SpecimenText'
import SpecimenGroup from './specimens/SpecimenGroup'
export default {
name: 'App',
components: {
SpecimenText
SpecimenText,
SpecimenGroup
},
data () {
return {
@ -24,4 +27,13 @@ export default {
body {
font-family: $formulate-font-stack;
}
.specimens {
margin-bottom: 2em;
padding-bottom: 2em;
border-bottom: 1px solid gray;
&:last-child {
border-bottom: 0;
}
}
</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"
help="Select a username"
/>
<FormulateInput
label="How old are you?"
type="number"
placeholder="25"
help="Select your age"
/>
</div>
</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 { en } from '@braid/vue-formulate-i18n'
import fauxUploader from './libs/faux-uploader'
import FormulateSlot from './FormulateSlot'
import FormulateInput from './FormulateInput.vue'
import FormulateForm from './FormulateForm.vue'
import FormulateErrors from './FormulateErrors.vue'
import FormulateHelp from './slots/FormulateHelp.vue'
import FormulateGrouping from './FormulateGrouping.vue'
import FormulateLabel from './slots/FormulateLabel.vue'
import FormulateInputGroup from './FormulateInputGroup.vue'
import FormulateInputBox from './inputs/FormulateInputBox.vue'
import FormulateInputText from './inputs/FormulateInputText.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 FormulateInputSelect from './inputs/FormulateInputSelect.vue'
import FormulateInputSlider from './inputs/FormulateInputSlider.vue'
@ -31,14 +34,17 @@ class Formulate {
this.options = {}
this.defaults = {
components: {
FormulateSlot,
FormulateForm,
FormulateHelp,
FormulateLabel,
FormulateInput,
FormulateErrors,
FormulateGrouping,
FormulateInputBox,
FormulateInputText,
FormulateInputFile,
FormulateRepeatable,
FormulateInputGroup,
FormulateInputButton,
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"
>
<component
:is="slotComponents.help"
:is="context.slotComponents.help"
v-if="context.help"
:context="context"
/>
</slot>
<FormulateErrors
v-if="!disableErrors"
:type="`input`"
<slot
name="errors"
v-bind="context"
>
<component
:is="context.slotComponents.errors"
v-if="!context.disableErrors"
:type="context.slotComponents.errors === 'FormulateErrors' ? 'input' : false"
:context="context"
/>
</slot>
</div>
</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,7 +1,9 @@
<template>
<div class="formulate-input-group">
<component
:is="subComponent"
<template
v-if="subType !== 'grouping'"
>
<FormulateInput
v-for="optionContext in optionsWithContext"
:key="optionContext.id"
v-model="context.model"
@ -10,6 +12,16 @@
class="formulate-input-group-item"
@blur="context.blurHandler"
/>
</template>
<template
v-else
>
<FormulateGrouping
:context="context"
>
<slot />
</FormulateGrouping>
</template>
</div>
</template>
@ -26,9 +38,8 @@ export default {
options () {
return this.context.options || []
},
subComponent () {
// @todo - rough-in for future flexible input-groups
return 'FormulateInput'
subType () {
return (this.context.type === 'group') ? 'grouping' : 'inputs'
},
optionsWithContext () {
const {

View File

@ -13,6 +13,7 @@ export default {
blurHandler: blurHandler.bind(this),
classification: this.classification,
component: this.component,
disableErrors: this.disableErrors,
errors: this.explicitErrors,
getValidationErrors: this.getValidationErrors.bind(this),
hasLabel: (this.label && this.classification !== 'button'),
@ -238,7 +239,8 @@ function hasVisibleErrors () {
function slotComponents () {
return {
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: 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', () => {
const components = [
'FormulateSlot',
'FormulateForm',
'FormulateHelp',
'FormulateLabel',
'FormulateInput',
'FormulateErrors',
'FormulateGrouping',
'FormulateInputBox',
'FormulateInputText',
'FormulateInputFile',
'FormulateRepeatable',
'FormulateInputGroup',
'FormulateInputButton',
'FormulateInputSelect',

View File

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

View File

@ -272,4 +272,15 @@ describe('FormulateInputText', () => {
})
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)
})
})