Form Editor v2.5 (#599)
* Form Editor v2.5 * Remove log debug --------- Co-authored-by: Julien Nahum <julien@nahum.net>
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
:style="inputStyle"
|
||||
class="flex flex-col w-full items-center justify-center transition-colors duration-40"
|
||||
:class="[
|
||||
{'!cursor-not-allowed':disabled, 'cursor-pointer':!disabled,
|
||||
@@ -29,12 +30,18 @@
|
||||
theme.fileInput.spacing.horizontal,
|
||||
theme.fileInput.spacing.vertical,
|
||||
theme.fileInput.fontSize,
|
||||
theme.fileInput.minHeight
|
||||
theme.fileInput.minHeight,
|
||||
{'border-red-500 border-2':hasError},
|
||||
'focus:outline-none focus:ring-2'
|
||||
]"
|
||||
tabindex="0"
|
||||
role="button"
|
||||
:aria-label="multiple ? 'Choose files or drag here' : 'Choose a file or drag here'"
|
||||
@dragover.prevent="uploadDragoverEvent=true"
|
||||
@dragleave.prevent="uploadDragoverEvent=false"
|
||||
@drop.prevent="onUploadDropEvent"
|
||||
@click="openFileUpload"
|
||||
@keydown.enter.prevent="openFileUpload"
|
||||
>
|
||||
<div class="flex w-full items-center justify-center">
|
||||
<div
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
'!cursor-not-allowed !bg-gray-200': disabled,
|
||||
},
|
||||
]"
|
||||
class="resize-y"
|
||||
class="resize-y block"
|
||||
:name="name"
|
||||
:style="inputStyle"
|
||||
:placeholder="placeholder"
|
||||
@@ -63,7 +63,6 @@ export default {
|
||||
props: {
|
||||
...inputProps,
|
||||
maxCharLimit: {type: Number, required: false, default: null},
|
||||
showCharLimit: {type: Boolean, required: false, default: false},
|
||||
},
|
||||
|
||||
setup(props, context) {
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
:maxlength="maxCharLimit"
|
||||
@change="onChange"
|
||||
@keydown.enter.prevent="onEnterPress"
|
||||
@focus="onFocus"
|
||||
@blur="onBlur"
|
||||
>
|
||||
|
||||
<template
|
||||
@@ -74,7 +76,6 @@ export default {
|
||||
max: {type: Number, required: false, default: null},
|
||||
autocomplete: {type: [Boolean, String, Object], default: null},
|
||||
maxCharLimit: {type: Number, required: false, default: null},
|
||||
showCharLimit: {type: Boolean, required: false, default: false},
|
||||
pattern: {type: String, default: null},
|
||||
},
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
class="input-label"
|
||||
:class="[
|
||||
theme.default.label,
|
||||
{ 'uppercase text-xs': uppercaseLabels, 'text-sm': !uppercaseLabels },
|
||||
{ 'uppercase text-xs': uppercaseLabels, 'text-sm/none': !uppercaseLabels },
|
||||
]"
|
||||
>
|
||||
<slot>
|
||||
|
||||
@@ -45,7 +45,8 @@
|
||||
<has-error
|
||||
v-if="hasValidation && form"
|
||||
:form="form"
|
||||
:field="name"
|
||||
:field-id="name"
|
||||
:field-name="label"
|
||||
/>
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,11 @@
|
||||
:class="[
|
||||
theme.SelectInput.input,
|
||||
theme.SelectInput.borderRadius,
|
||||
{ '!ring-red-500 !ring-2 !border-transparent': hasError, '!cursor-not-allowed dark:!bg-gray-600 !bg-gray-200': disabled },
|
||||
{
|
||||
'!ring-red-500 !ring-2 !border-transparent': hasError,
|
||||
'!cursor-not-allowed dark:!bg-gray-600 !bg-gray-200': disabled,
|
||||
'focus-within:ring-2 focus-within:ring-opacity-100 focus-within:border-transparent': !hasError
|
||||
},
|
||||
inputClass
|
||||
]"
|
||||
>
|
||||
@@ -19,12 +23,14 @@
|
||||
aria-haspopup="listbox"
|
||||
aria-expanded="true"
|
||||
aria-labelledby="listbox-label"
|
||||
class="cursor-pointer w-full flex-grow relative"
|
||||
class="cursor-pointer w-full flex-grow relative focus:outline-none"
|
||||
:class="[
|
||||
theme.SelectInput.spacing.horizontal,
|
||||
theme.SelectInput.spacing.vertical
|
||||
]"
|
||||
@click="toggleDropdown"
|
||||
@focus="onFocus"
|
||||
@blur="onBlur"
|
||||
>
|
||||
<div
|
||||
class="flex items-center"
|
||||
@@ -237,12 +243,13 @@ export default {
|
||||
allowCreation: {type: Boolean, default: false},
|
||||
disabled: {type: Boolean, default: false}
|
||||
},
|
||||
emits: ['update:modelValue', 'update-options'],
|
||||
emits: ['update:modelValue', 'update-options', 'focus', 'blur'],
|
||||
data() {
|
||||
return {
|
||||
isOpen: false,
|
||||
searchTerm: '',
|
||||
defaultValue: this.modelValue ?? null
|
||||
defaultValue: this.modelValue ?? null,
|
||||
isFocused: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -311,11 +318,26 @@ export default {
|
||||
}
|
||||
return this.modelValue === value
|
||||
},
|
||||
onFocus(event) {
|
||||
this.isFocused = true
|
||||
this.$emit('focus', event)
|
||||
},
|
||||
|
||||
onBlur(event) {
|
||||
this.isFocused = false
|
||||
this.$emit('blur', event)
|
||||
},
|
||||
|
||||
toggleDropdown() {
|
||||
if (this.disabled) {
|
||||
this.isOpen = false
|
||||
} else {
|
||||
this.isOpen = !this.isOpen
|
||||
if (this.isOpen) {
|
||||
this.onFocus()
|
||||
} else {
|
||||
this.onBlur()
|
||||
}
|
||||
}
|
||||
if (!this.isOpen) {
|
||||
this.searchTerm = ''
|
||||
|
||||
10
client/components/forms/useFormInput.js
vendored
10
client/components/forms/useFormInput.js
vendored
@@ -88,6 +88,14 @@ export function useFormInput(props, context, options = {}) {
|
||||
return wrapperProps
|
||||
})
|
||||
|
||||
const onFocus = (event) => {
|
||||
context.emit('focus', event)
|
||||
}
|
||||
|
||||
const onBlur = (event) => {
|
||||
context.emit('blur', event)
|
||||
}
|
||||
|
||||
// Watch for changes in props.modelValue and update the local content
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
@@ -104,5 +112,7 @@ export function useFormInput(props, context, options = {}) {
|
||||
hasValidation,
|
||||
hasError,
|
||||
inputWrapperProps,
|
||||
onFocus,
|
||||
onBlur,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<transition name="fade">
|
||||
<div
|
||||
v-if="errorMessage"
|
||||
class="has-error text-sm text-red-500 -bottom-3"
|
||||
class="has-error text-xs text-red-500 mt-1"
|
||||
v-html="errorMessage"
|
||||
/>
|
||||
</transition>
|
||||
@@ -10,42 +10,57 @@
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "HasError",
|
||||
name: 'HasError',
|
||||
props: {
|
||||
form: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
field: {
|
||||
fieldId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
fieldName: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
errorMessage() {
|
||||
if (!this.form || !this.form.errors || !this.form.errors.any())
|
||||
if (!this.form.errors || !this.form.errors.any())
|
||||
return null
|
||||
const subErrorsKeys = Object.keys(this.form.errors.all()).filter(
|
||||
(key) => {
|
||||
return key.startsWith(this.field) && key !== this.field
|
||||
return key.startsWith(this.fieldId) && key !== this.fieldId
|
||||
},
|
||||
)
|
||||
const baseError =
|
||||
this.form.errors.get(this.field) ??
|
||||
(subErrorsKeys.length ? "This field has some errors:" : null)
|
||||
let baseError
|
||||
= this.form.errors.get(this.fieldId)
|
||||
?? (subErrorsKeys.length ? 'This field has some errors:' : null)
|
||||
// If no error and no sub errors, return
|
||||
if (!baseError) return null
|
||||
if (!baseError)
|
||||
return null
|
||||
|
||||
return `<p class="text-red-500">${baseError}</p><ul class="list-disc list-inside">${subErrorsKeys.map(
|
||||
(key) => {
|
||||
return "<li>" + this.getSubError(key) + "</li>"
|
||||
},
|
||||
)}</ul>`
|
||||
// Check if baseError starts with "The {field.name} field" and replace if necessary
|
||||
if (baseError.startsWith(`The ${this.fieldName} field`)) {
|
||||
baseError = baseError.replace(`The ${this.fieldName} field`, 'This field')
|
||||
}
|
||||
|
||||
const coreError = `<p class='text-red-500'>${baseError}</p>`
|
||||
if (subErrorsKeys.length) {
|
||||
return coreError + `<ul class='list-disc list-inside'>${subErrorsKeys.map(
|
||||
(key) => {
|
||||
return `<li>${this.getSubError(key)}</li>`
|
||||
},
|
||||
)}</ul>`
|
||||
}
|
||||
|
||||
return coreError
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getSubError(subErrorKey) {
|
||||
return this.form.errors.get(subErrorKey).replace(subErrorKey, "item")
|
||||
return this.form.errors.get(subErrorKey).replace(subErrorKey, 'item')
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user