WIP
This commit is contained in:
@@ -132,7 +132,7 @@ export default {
|
||||
|
||||
methods: {
|
||||
clearUrl () {
|
||||
this.$set(this.form, this.name, null)
|
||||
this.form[this.name] = null
|
||||
},
|
||||
onUploadDragoverEvent (e) {
|
||||
this.uploadDragoverEvent = true
|
||||
|
||||
@@ -50,11 +50,11 @@ export default {
|
||||
this.onEnd()
|
||||
},
|
||||
onEnd () {
|
||||
if(this.disabled){
|
||||
if (this.disabled) {
|
||||
this.$refs.signaturePad.clearSignature()
|
||||
}else{
|
||||
} else {
|
||||
const { isEmpty, data } = this.$refs.signaturePad.saveSignature()
|
||||
this.$set(this.form, this.name, (!isEmpty && data) ? data : null)
|
||||
this.form[this.name] = (!isEmpty && data) ? data : null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,14 @@
|
||||
<template>
|
||||
<div :class="wrapperClass" :style="inputStyle">
|
||||
<slot name="label">
|
||||
<input-label v-if="label"
|
||||
:label="label"
|
||||
:theme="theme"
|
||||
:required="true"
|
||||
:native-for="id?id:name"
|
||||
:uppercase-labels="uppercaseLabels"
|
||||
/>
|
||||
</slot>
|
||||
<input-help v-if="help && helpPosition=='above_input'" :help="help" :theme="theme">
|
||||
<template #help>
|
||||
<slot name="help" />
|
||||
</template>
|
||||
</input-help>
|
||||
<input-wrapper
|
||||
v-bind="$props"
|
||||
>
|
||||
<template #label>
|
||||
<slot name="label" />
|
||||
</template>
|
||||
<template v-if="helpPosition==='above_input'" #help>
|
||||
<slot name="help" />
|
||||
</template>
|
||||
|
||||
<input :id="id?id:name" v-model="compVal" :disabled="disabled"
|
||||
:type="nativeType"
|
||||
:pattern="pattern"
|
||||
@@ -23,25 +18,34 @@
|
||||
:placeholder="placeholder" :min="min" :max="max" :maxlength="maxCharLimit"
|
||||
@change="onChange" @keydown.enter.prevent="onEnterPress"
|
||||
>
|
||||
<!-- <input-help v-if="(help && helpPosition=='below_input') || showCharLimit" :help="help" :theme="theme">-->
|
||||
|
||||
<!-- TODO: fix this in the case of below input there's something off -->
|
||||
<!-- <input-help v-if="helpPosition==='below_input' || showCharLimit" :help="help" :theme="theme">-->
|
||||
<!-- <template #help>-->
|
||||
<!-- <slot name="help" />-->
|
||||
<!-- </template>-->
|
||||
<!-- <template v-if="showCharLimit" #after-help>-->
|
||||
<!-- <small v-if="showCharLimit && maxCharLimit" :class="theme.default.help">-->
|
||||
<!-- {{ charCount }}/{{ maxCharLimit }}-->
|
||||
<!-- </small>-->
|
||||
<!-- </template>-->
|
||||
<!-- </input-help>-->
|
||||
<has-error v-if="hasValidation" :form="form" :field="name" />
|
||||
</div>
|
||||
|
||||
<template #error>
|
||||
<slot name="error" />
|
||||
</template>
|
||||
</input-wrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { inputProps, useFormInput } from './useFormInput.js'
|
||||
import InputLabel from './components/InputLabel.vue'
|
||||
import InputHelp from './components/InputHelp.vue'
|
||||
import InputWrapper from './components/InputWrapper.vue'
|
||||
|
||||
export default {
|
||||
name: 'TextInput',
|
||||
components: { InputHelp, InputLabel },
|
||||
components: { InputWrapper, InputHelp, InputLabel },
|
||||
|
||||
props: {
|
||||
...inputProps,
|
||||
@@ -54,11 +58,15 @@ export default {
|
||||
pattern: { type: String, default: null }
|
||||
},
|
||||
|
||||
setup (props) {
|
||||
const { compVal, inputStyle, hasValidation, hasError } = useFormInput(props)
|
||||
setup (props, context) {
|
||||
const {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
} = useFormInput(props, context, props.nativeType === 'file' ? 'file-' : null)
|
||||
|
||||
const onChange = (event) => {
|
||||
console.log(props)
|
||||
if (props.nativeType !== 'file') return
|
||||
|
||||
const file = event.target.files[0]
|
||||
@@ -77,6 +85,11 @@ export default {
|
||||
hasValidation,
|
||||
hasError
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
charCount () {
|
||||
return (this.compVal) ? this.compVal.length : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,36 +1,50 @@
|
||||
<template>
|
||||
<div :class="wrapperClass">
|
||||
<small v-if="help && helpPosition=='above_input'" :class="theme.default.help" class="flex mb-1">
|
||||
<slot name="help"><span class="field-help" v-html="help" /></slot>
|
||||
</small>
|
||||
<div class="flex">
|
||||
<v-switch :id="id?id:name" v-model="compVal" class="inline-block mr-2" :disabled="disabled" :name="name" @input="$emit('input',$event)" />
|
||||
<slot name="label">
|
||||
<span>{{ label }} <span v-if="required" class="text-red-500 required-dot">*</span></span>
|
||||
</slot>
|
||||
</div>
|
||||
<small v-if="help && helpPosition=='below_input'" :class="theme.default.help">
|
||||
<slot name="help"><span class="field-help" v-html="help" /></slot>
|
||||
</small>
|
||||
<has-error v-if="hasValidation" :form="form" :field="name" />
|
||||
<div :class="wrapperClass">
|
||||
<input-help v-if="help && helpPosition=='above_input'" :help="help" :theme="theme">
|
||||
<template #help>
|
||||
<slot name="help" />
|
||||
</template>
|
||||
</input-help>
|
||||
<div class="flex">
|
||||
<v-switch :id="id?id:name" v-model="compVal" class="inline-block mr-2" :disabled="disabled" />
|
||||
<slot name="label">
|
||||
<span>{{ label }} <span v-if="required" class="text-red-500 required-dot">*</span></span>
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import inputMixin from '~/mixins/forms/input.js'
|
||||
|
||||
import VSwitch from './components/VSwitch.vue'
|
||||
export default {
|
||||
name: 'ToggleSwitchInput',
|
||||
|
||||
components: { VSwitch },
|
||||
mixins: [inputMixin],
|
||||
props: {},
|
||||
|
||||
mounted () {
|
||||
this.compVal = !!this.compVal
|
||||
this.$emit('input', !!this.compVal)
|
||||
<input-help v-if="help && helpPosition=='below_input'" :help="help" :theme="theme">
|
||||
<template #help>
|
||||
<slot name="help" />
|
||||
</template>
|
||||
</input-help>
|
||||
<has-error v-if="hasValidation" :form="form" :field="name" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { inputProps, useFormInput } from './useFormInput.js'
|
||||
import InputHelp from './components/InputHelp.vue'
|
||||
import VSwitch from './components/VSwitch.vue'
|
||||
export default {
|
||||
name: 'ToggleSwitchInput',
|
||||
|
||||
components: { InputHelp, VSwitch },
|
||||
props: {
|
||||
...inputProps
|
||||
},
|
||||
|
||||
setup (props, context) {
|
||||
const { compVal, inputStyle, hasValidation, hasError } = useFormInput(props, context)
|
||||
|
||||
return {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.compVal = !!this.compVal
|
||||
}
|
||||
</script>
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="flex mb-1">
|
||||
<div class="flex mb-1 input-help">
|
||||
<small :class="theme.default.help" class="grow flex">
|
||||
<slot name="help"><span class="field-help" v-html="help" /></slot>
|
||||
</small>
|
||||
@@ -15,7 +15,7 @@ export default {
|
||||
|
||||
props: {
|
||||
theme: { type: Object, required: true },
|
||||
help: { type: String, required: true }
|
||||
help: { type: String, required: false }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
<template>
|
||||
<label :for="nativeFor"
|
||||
class="input-label"
|
||||
:class="[theme.default.label,{'uppercase text-xs': uppercaseLabels, 'text-sm': !uppercaseLabels}]"
|
||||
>
|
||||
{{ label }}
|
||||
<span v-if="required" class="text-red-500 required-dot">*</span>
|
||||
<slot>
|
||||
{{ label }}
|
||||
<span v-if="required" class="text-red-500 required-dot">*</span>
|
||||
</slot>
|
||||
</label>
|
||||
</template>
|
||||
|
||||
|
||||
47
resources/js/components/forms/components/InputWrapper.vue
Normal file
47
resources/js/components/forms/components/InputWrapper.vue
Normal file
@@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<div :class="wrapperClass" :style="inputStyle">
|
||||
<slot name="label">
|
||||
<input-label v-if="label"
|
||||
:label="label"
|
||||
:theme="theme"
|
||||
:required="true"
|
||||
:native-for="id?id:name"
|
||||
:uppercase-labels="uppercaseLabels"
|
||||
/>
|
||||
</slot>
|
||||
<slot v-if="help && helpPosition==='above_input'" name="help">
|
||||
<input-help :help="help" :theme="theme" />
|
||||
</slot>
|
||||
<slot />
|
||||
<slot v-if="help && helpPosition==='below_input'" name="help">
|
||||
<input-help :help="help" :theme="theme" />
|
||||
</slot>
|
||||
<slot name="error">
|
||||
<has-error v-if="hasValidation" :form="form" :field="name" />
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import InputLabel from './InputLabel.vue'
|
||||
import InputHelp from './InputHelp.vue'
|
||||
|
||||
export default {
|
||||
name: 'InputWrapper',
|
||||
components: { InputLabel, InputHelp },
|
||||
|
||||
props: {
|
||||
id: { type: String, required: false },
|
||||
name: { type: String, required: false },
|
||||
theme: { type: Object, required: true },
|
||||
wrapperClass: { type: String, required: false },
|
||||
inputStyle: { type: Object, required: false },
|
||||
help: { type: String, required: false },
|
||||
label: { type: String, required: false },
|
||||
helpPosition: { type: String, default: 'below_input' },
|
||||
uppercaseLabels: { type: Boolean, default: true },
|
||||
hasValidation: { type: Boolean, default: true },
|
||||
form: { type: Object, required: false }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,45 +1,23 @@
|
||||
<template>
|
||||
<div @click="onClick">
|
||||
<div class="inline-flex items-center h-6 w-12 p-1 bg-gray-300 border rounded-full cursor-pointer focus:outline-none transition-all transform ease-in-out duration-100" :class="{'bg-nt-blue': internalValue}">
|
||||
<div class="inline-block h-4 w-4 rounded-full bg-white shadow transition-all transform ease-in-out duration-150 rounded-2xl scale-100" :class="{'translate-x-5.5': internalValue}" />
|
||||
<div role="button" @click="onClick">
|
||||
<div class="inline-flex items-center h-6 w-12 p-1 bg-gray-300 border rounded-full cursor-pointer focus:outline-none transition-all transform ease-in-out duration-100" :class="{'bg-nt-blue': modelValue}">
|
||||
<div class="inline-block h-4 w-4 rounded-full bg-white shadow transition-all transform ease-in-out duration-150 rounded-2xl scale-100" :class="{'translate-x-5.5': modelValue}" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'VSwitch',
|
||||
components: { },
|
||||
<script setup>
|
||||
import { defineProps, defineEmits } from 'vue'
|
||||
|
||||
props: {
|
||||
value: { type: Boolean, default: false },
|
||||
disabled: { type: Boolean, default: false }
|
||||
},
|
||||
const { modelValue, disabled } = defineProps({
|
||||
modelValue: { type: Boolean, default: false },
|
||||
disabled: { type: Boolean, default: false }
|
||||
})
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
data () {
|
||||
return {
|
||||
internalValue: this.value
|
||||
}
|
||||
},
|
||||
|
||||
computed: {},
|
||||
|
||||
watch: {
|
||||
value (val) {
|
||||
this.internalValue = val
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.internalValue = this.value
|
||||
},
|
||||
|
||||
methods: {
|
||||
onClick () {
|
||||
if(this.disabled) return
|
||||
this.$emit('input', !this.internalValue)
|
||||
this.internalValue = !this.internalValue
|
||||
}
|
||||
}
|
||||
const onClick = () => {
|
||||
if (disabled) return
|
||||
console.log('ok emiting', !modelValue)
|
||||
emit('update:modelValue', !modelValue)
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
61
resources/js/components/forms/index.js
vendored
61
resources/js/components/forms/index.js
vendored
@@ -1,4 +1,4 @@
|
||||
import Vue from 'vue'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
import HasError from './validation/HasError.vue'
|
||||
import AlertError from './validation/AlertError.vue'
|
||||
@@ -16,29 +16,38 @@ import RatingInput from './RatingInput.vue'
|
||||
import FlatSelectInput from './FlatSelectInput.vue'
|
||||
import ToggleSwitchInput from './ToggleSwitchInput.vue'
|
||||
|
||||
// Components that are registered globaly.
|
||||
[
|
||||
HasError,
|
||||
AlertError,
|
||||
AlertSuccess,
|
||||
VCheckbox,
|
||||
VSelect,
|
||||
CheckboxInput,
|
||||
ColorInput,
|
||||
TextInput,
|
||||
SelectInput,
|
||||
TextAreaInput,
|
||||
FileInput,
|
||||
ImageInput,
|
||||
RatingInput,
|
||||
FlatSelectInput,
|
||||
ToggleSwitchInput
|
||||
].forEach(Component => {
|
||||
Vue.component(Component.name, Component)
|
||||
})
|
||||
export function registerComponents (app) {
|
||||
[
|
||||
HasError,
|
||||
AlertError,
|
||||
AlertSuccess,
|
||||
VCheckbox,
|
||||
VSelect,
|
||||
CheckboxInput,
|
||||
ColorInput,
|
||||
TextInput,
|
||||
SelectInput,
|
||||
TextAreaInput,
|
||||
FileInput,
|
||||
ImageInput,
|
||||
RatingInput,
|
||||
FlatSelectInput,
|
||||
ToggleSwitchInput
|
||||
].forEach(Component => {
|
||||
app.component(Component.name, Component)
|
||||
})
|
||||
|
||||
// Lazy load some heavy component
|
||||
Vue.component('SignatureInput', () => import('./SignatureInput.vue'))
|
||||
Vue.component('RichTextAreaInput', () => import('./RichTextAreaInput.vue'))
|
||||
Vue.component('DateInput', () => import('./DateInput.vue'))
|
||||
Vue.component('PhoneInput', () => import('./PhoneInput.vue'))
|
||||
// Register async components
|
||||
app.component('SignatureInput', defineAsyncComponent(() =>
|
||||
import('./SignatureInput.vue')
|
||||
))
|
||||
app.component('RichTextAreaInput', defineAsyncComponent(() =>
|
||||
import('./RichTextAreaInput.vue')
|
||||
))
|
||||
app.component('PhoneInput', defineAsyncComponent(() =>
|
||||
import('./PhoneInput.vue')
|
||||
))
|
||||
app.component('DateInput', defineAsyncComponent(() =>
|
||||
import('./DateInput.vue')
|
||||
))
|
||||
}
|
||||
|
||||
10
resources/js/components/forms/useFormInput.js
vendored
10
resources/js/components/forms/useFormInput.js
vendored
@@ -1,4 +1,4 @@
|
||||
import { ref, computed, watch, defineEmits } from 'vue'
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { themes } from '~/config/form-themes.js'
|
||||
|
||||
export const inputProps = {
|
||||
@@ -18,7 +18,7 @@ export const inputProps = {
|
||||
wrapperClass: { type: String, default: 'relative mb-3' }
|
||||
}
|
||||
|
||||
export function useFormInput (props) {
|
||||
export function useFormInput (props, context, formPrefixKey = null) {
|
||||
const content = ref(props.modelValue)
|
||||
|
||||
const inputStyle = computed(() => {
|
||||
@@ -38,13 +38,13 @@ export function useFormInput (props) {
|
||||
const compVal = computed({
|
||||
get: () => {
|
||||
if (props.form) {
|
||||
return props.form[props.name]
|
||||
return props.form[(formPrefixKey || '') + props.name]
|
||||
}
|
||||
return content.value
|
||||
},
|
||||
set: (val) => {
|
||||
if (props.form) {
|
||||
props.form[props.name] = val
|
||||
props.form[(formPrefixKey || '') + props.name] = val
|
||||
} else {
|
||||
content.value = val
|
||||
}
|
||||
@@ -53,7 +53,7 @@ export function useFormInput (props) {
|
||||
props.form.errors.clear(props.name)
|
||||
}
|
||||
|
||||
defineEmits('update:modelValue', compVal.value)
|
||||
context.emit('update:modelValue', compVal.value)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user