Field Help as Html text & Help Position (#115)

* Field Help as Html text & Help Position

* Re-organize field options modal

* put margin for above help
This commit is contained in:
Chirag Chhatrala 2023-04-19 13:43:50 +05:30 committed by GitHub
parent 5e7eb60674
commit 3f2fe352e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 124 additions and 40 deletions

View File

@ -82,6 +82,7 @@ abstract class UserFormRequest extends \Illuminate\Foundation\Http\FormRequest
'properties.*.placeholder' => 'sometimes|nullable', 'properties.*.placeholder' => 'sometimes|nullable',
'properties.*.prefill' => 'sometimes|nullable', 'properties.*.prefill' => 'sometimes|nullable',
'properties.*.help' => 'sometimes|nullable', 'properties.*.help' => 'sometimes|nullable',
'properties.*.help_position' => ['sometimes', Rule::in(['below_input', 'above_input'])],
'properties.*.hidden' => 'boolean|nullable', 'properties.*.hidden' => 'boolean|nullable',
'properties.*.required' => 'boolean|nullable', 'properties.*.required' => 'boolean|nullable',
'properties.*.multiple' => 'boolean|nullable', 'properties.*.multiple' => 'boolean|nullable',

View File

@ -1,12 +1,15 @@
<template> <template>
<div :class="wrapperClass"> <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>
<v-checkbox :id="id?id:name" v-model="compVal" :disabled="disabled" :name="name" @input="$emit('input',$event)"> <v-checkbox :id="id?id:name" v-model="compVal" :disabled="disabled" :name="name" @input="$emit('input',$event)">
<slot name="label"> <slot name="label">
{{ label }} <span v-if="required" class="text-red-500 required-dot">*</span> {{ label }} <span v-if="required" class="text-red-500 required-dot">*</span>
</slot> </slot>
</v-checkbox> </v-checkbox>
<small v-if="help" :class="theme.default.help"> <small v-if="help && helpPosition=='below_input'" :class="theme.default.help">
<slot name="help">{{ help }}</slot> <slot name="help"><span class="field-help" v-html="help" /></slot>
</small> </small>
<has-error v-if="hasValidation" :form="form" :field="name" /> <has-error v-if="hasValidation" :form="form" :field="name" />
</div> </div>

View File

@ -16,7 +16,7 @@
/> />
<small v-if="help" :class="theme.CodeInput.help"> <small v-if="help" :class="theme.CodeInput.help">
<slot name="help">{{ help }}</slot> <slot name="help"><span class="field-help" v-html="help" /></slot>
</small> </small>
<has-error v-if="hasValidation" :form="form" :field="name" /> <has-error v-if="hasValidation" :form="form" :field="name" />
</div> </div>

View File

@ -9,7 +9,7 @@
<span v-if="required" class="text-red-500 required-dot">*</span> <span v-if="required" class="text-red-500 required-dot">*</span>
</label> </label>
<small v-if="help" :class="theme.default.help"> <small v-if="help" :class="theme.default.help">
<slot name="help">{{ help }}</slot> <slot name="help"><span class="field-help" v-html="help" /></slot>
</small> </small>
<has-error v-if="hasValidation" :form="form" :field="name" /> <has-error v-if="hasValidation" :form="form" :field="name" />
</div> </div>

View File

@ -6,6 +6,9 @@
{{ label }} {{ label }}
<span v-if="required" class="text-red-500 required-dot">*</span> <span v-if="required" class="text-red-500 required-dot">*</span>
</label> </label>
<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-if="!dateRange"> <div class="flex" v-if="!dateRange">
<input :type="useTime ? 'datetime-local' : 'date'" :id="id?id:name" v-model="fromDate" :class="inputClasses" :disabled="disabled" <input :type="useTime ? 'datetime-local' : 'date'" :id="id?id:name" v-model="fromDate" :class="inputClasses" :disabled="disabled"
@ -28,8 +31,8 @@
</div> </div>
</div> </div>
<small v-if="help" :class="theme.default.help"> <small v-if="help && helpPosition=='below_input'" :class="theme.default.help">
<slot name="help">{{ help }}</slot> <slot name="help"><span class="field-help" v-html="help" /></slot>
</small> </small>
<has-error v-if="hasValidation" :form="form" :field="name"/> <has-error v-if="hasValidation" :form="form" :field="name"/>
</div> </div>

View File

@ -6,6 +6,9 @@
{{ label }} {{ label }}
<span v-if="required" class="text-red-500 required-dot">*</span> <span v-if="required" class="text-red-500 required-dot">*</span>
</label> </label>
<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>
<span class="inline-block w-full rounded-md shadow-sm"> <span class="inline-block w-full rounded-md shadow-sm">
<button type="button" aria-haspopup="listbox" aria-expanded="true" aria-labelledby="listbox-label" role="button" <button type="button" aria-haspopup="listbox" aria-expanded="true" aria-labelledby="listbox-label" role="button"
class="cursor-pointer relative flex" class="cursor-pointer relative flex"
@ -60,8 +63,8 @@
</template> </template>
</button> </button>
</span> </span>
<small v-if="help" :class="theme.default.help"> <small v-if="help && helpPosition=='below_input'" :class="theme.default.help">
<slot name="help">{{ help }}</slot> <slot name="help"><span class="field-help" v-html="help" /></slot>
</small> </small>
<has-error v-if="hasValidation" :form="form" :field="name" /> <has-error v-if="hasValidation" :form="form" :field="name" />

View File

@ -6,8 +6,8 @@
{{ label }} {{ label }}
<span v-if="required" class="text-red-500 required-dot">*</span> <span v-if="required" class="text-red-500 required-dot">*</span>
</label> </label>
<small v-if="help" :class="theme.SelectInput.help" class="block mb-2"> <small v-if="help && helpPosition=='above_input'" :class="theme.SelectInput.help" class="block mb-1">
<slot name="help">{{ help }}</slot> <slot name="help"><span class="field-help" v-html="help" /></slot>
</small> </small>
<loader v-if="loading" key="loader" class="h-6 w-6 text-nt-blue mx-auto" /> <loader v-if="loading" key="loader" class="h-6 w-6 text-nt-blue mx-auto" />
@ -25,6 +25,9 @@
</div> </div>
</div> </div>
<small v-if="help && helpPosition=='below_input'" :class="theme.SelectInput.help" class="block">
<slot name="help"><span class="field-help" v-html="help" /></slot>
</small>
<has-error v-if="hasValidation" :form="form" :field="name" /> <has-error v-if="hasValidation" :form="form" :field="name" />
</div> </div>
</template> </template>

View File

@ -36,7 +36,7 @@
</button> </button>
</span> </span>
<small v-if="help" :class="theme.default.help"> <small v-if="help" :class="theme.default.help">
<slot name="help">{{ help }}</slot> <slot name="help"><span class="field-help" v-html="help" /></slot>
</small> </small>
<has-error v-if="hasValidation" :form="form" :field="name" /> <has-error v-if="hasValidation" :form="form" :field="name" />

View File

@ -6,6 +6,9 @@
{{ label }} {{ label }}
<span v-if="required" class="text-red-500 required-dot">*</span> <span v-if="required" class="text-red-500 required-dot">*</span>
</label> </label>
<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="stars-outer"> <div class="stars-outer">
<div v-for="i in numberOfStars" :key="i" <div v-for="i in numberOfStars" :key="i"
@ -23,8 +26,8 @@
</div> </div>
</div> </div>
<small v-if="help" :class="theme.default.help"> <small v-if="help && helpPosition=='below_input'" :class="theme.default.help">
<slot name="help">{{ help }}</slot> <slot name="help"><span class="field-help" v-html="help" /></slot>
</small> </small>
<has-error v-if="hasValidation" :form="form" :field="name" /> <has-error v-if="hasValidation" :form="form" :field="name" />
</div> </div>

View File

@ -6,14 +6,19 @@
{{ label }} {{ label }}
<span v-if="required" class="text-red-500 required-dot">*</span> <span v-if="required" class="text-red-500 required-dot">*</span>
</label> </label>
<div v-if="help && helpPosition=='above_input'" class="flex mb-1">
<small :class="theme.RichTextAreaInput.help" class="grow">
<slot name="help"><span class="field-help" v-html="help" /></slot>
</small>
</div>
<vue-editor :id="id?id:name" ref="editor" v-model="compVal" :disabled="disabled" <vue-editor :id="id?id:name" ref="editor" v-model="compVal" :disabled="disabled"
:placeholder="placeholder" :class="[{ '!ring-red-500 !ring-2': hasValidation && form.errors.has(name), '!cursor-not-allowed !bg-gray-200':disabled }, theme.RichTextAreaInput.input]" :placeholder="placeholder" :class="[{ '!ring-red-500 !ring-2': hasValidation && form.errors.has(name), '!cursor-not-allowed !bg-gray-200':disabled }, theme.RichTextAreaInput.input]"
:editor-toolbar="editorToolbar" class="rich-editor resize-y" :editor-toolbar="editorToolbar" class="rich-editor resize-y"
:style="inputStyle" :style="inputStyle"
/> />
<small v-if="help" :class="theme.RichTextAreaInput.help"> <small v-if="help && helpPosition=='below_input'" :class="theme.RichTextAreaInput.help">
<slot name="help">{{ help }}</slot> <slot name="help"><span class="field-help" v-html="help" /></slot>
</small> </small>
<has-error v-if="hasValidation" :form="form" :field="name" /> <has-error v-if="hasValidation" :form="form" :field="name" />
</div> </div>

View File

@ -17,6 +17,8 @@
:has-error="hasValidation && form.errors.has(name)" :has-error="hasValidation && form.errors.has(name)"
:allowCreation="allowCreation" :allowCreation="allowCreation"
:disabled="disabled" :disabled="disabled"
:help="help"
:help-position="helpPosition"
@update-options="updateOptions" @update-options="updateOptions"
> >
@ -55,9 +57,7 @@
</slot> </slot>
</template> </template>
</v-select> </v-select>
<small v-if="help" :class="theme.SelectInput.help">
<slot name="help">{{ help }}</slot>
</small>
<has-error v-if="hasValidation" :form="form" :field="name" /> <has-error v-if="hasValidation" :form="form" :field="name" />
</div> </div>
</template> </template>

View File

@ -6,6 +6,11 @@
{{ label }} {{ label }}
<span v-if="required" class="text-red-500 required-dot">*</span> <span v-if="required" class="text-red-500 required-dot">*</span>
</label> </label>
<div v-if="help && helpPosition=='above_input'" class="flex mb-1">
<small :class="theme.default.help" class="flex-grow">
<slot name="help"><span class="field-help" v-html="help" /></slot>
</small>
</div>
<VueSignaturePad ref="signaturePad" <VueSignaturePad ref="signaturePad"
:class="[theme.default.input,{ '!ring-red-500 !ring-2': hasValidation && form.errors.has(name), '!cursor-not-allowed !bg-gray-200':disabled }]" height="150px" :class="[theme.default.input,{ '!ring-red-500 !ring-2': hasValidation && form.errors.has(name), '!cursor-not-allowed !bg-gray-200':disabled }]" height="150px"
@ -14,7 +19,7 @@
/> />
<div class="flex"> <div class="flex">
<small v-if="help" :class="theme.default.help" class="flex-grow"> <small v-if="help && helpPosition=='below_input'" :class="theme.default.help" class="flex-grow">
<slot name="help"><span class="field-help" v-html="help" /></slot> <slot name="help"><span class="field-help" v-html="help" /></slot>
</small> </small>
<small v-else class="flex-grow" /> <small v-else class="flex-grow" />

View File

@ -6,6 +6,11 @@
{{ label }} {{ label }}
<span v-if="required" class="text-red-500 required-dot">*</span> <span v-if="required" class="text-red-500 required-dot">*</span>
</label> </label>
<div v-if="help && helpPosition=='above_input'" class="flex mb-1">
<small :class="theme.default.help" class="flex-grow">
<slot name="help"><span class="field-help" v-html="help" /></slot>
</small>
</div>
<textarea :id="id?id:name" v-model="compVal" :disabled="disabled" <textarea :id="id?id:name" v-model="compVal" :disabled="disabled"
:class="[theme.default.input,{ '!ring-red-500 !ring-2': hasValidation && form.errors.has(name), '!cursor-not-allowed !bg-gray-200':disabled }]" :class="[theme.default.input,{ '!ring-red-500 !ring-2': hasValidation && form.errors.has(name), '!cursor-not-allowed !bg-gray-200':disabled }]"
class="resize-y" class="resize-y"
@ -13,9 +18,9 @@
:placeholder="placeholder" :placeholder="placeholder"
:maxlength="maxCharLimit" :maxlength="maxCharLimit"
/> />
<div v-if="help || showCharLimit" class="flex"> <div v-if="(help && helpPosition=='below_input') || showCharLimit" class="flex">
<small v-if="help" :class="theme.default.help" class="flex-grow"> <small v-if="help && helpPosition=='below_input'" :class="theme.default.help" class="flex-grow">
<slot name="help">{{ help }}</slot> <slot name="help"><span class="field-help" v-html="help" /></slot>
</small> </small>
<small v-else class="flex-grow"></small> <small v-else class="flex-grow"></small>
<small v-if="showCharLimit && maxCharLimit" :class="theme.default.help"> <small v-if="showCharLimit && maxCharLimit" :class="theme.default.help">

View File

@ -8,6 +8,11 @@
<span v-if="required" class="text-red-500 required-dot">*</span> <span v-if="required" class="text-red-500 required-dot">*</span>
</label> </label>
</slot> </slot>
<div v-if="help && helpPosition=='above_input'" class="flex mb-1">
<small :class="theme.default.help" class="grow">
<slot name="help"><span class="field-help" v-html="help" /></slot>
</small>
</div>
<input :id="id?id:name" v-model="compVal" :disabled="disabled" <input :id="id?id:name" v-model="compVal" :disabled="disabled"
:type="nativeType" :type="nativeType"
:style="inputStyle" :style="inputStyle"
@ -16,9 +21,9 @@
:placeholder="placeholder" :min="min" :max="max" :maxlength="maxCharLimit" :placeholder="placeholder" :min="min" :max="max" :maxlength="maxCharLimit"
@change="onChange" @keydown.enter.prevent="onEnterPress" @change="onChange" @keydown.enter.prevent="onEnterPress"
> >
<div v-if="help || showCharLimit" class="flex"> <div v-if="(help && helpPosition=='below_input') || showCharLimit" class="flex">
<small v-if="help" :class="theme.default.help" class="flex-grow"> <small v-if="help && helpPosition=='below_input'" :class="theme.default.help" class="flex-grow">
<slot name="help">{{ help }}</slot> <slot name="help"><span class="field-help" v-html="help" /></slot>
</small> </small>
<small v-else class="flex-grow"></small> <small v-else class="flex-grow"></small>
<small v-if="showCharLimit && maxCharLimit" :class="theme.default.help"> <small v-if="showCharLimit && maxCharLimit" :class="theme.default.help">

View File

@ -1,11 +1,14 @@
<template> <template>
<div :class="wrapperClass"> <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"> <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)" /> <v-switch :id="id?id:name" v-model="compVal" class="inline-block mr-2" :disabled="disabled" :name="name" @input="$emit('input',$event)" />
<span>{{ label }} <span v-if="required" class="text-red-500 required-dot">*</span></span> <span>{{ label }} <span v-if="required" class="text-red-500 required-dot">*</span></span>
</div> </div>
<small v-if="help" :class="theme.default.help"> <small v-if="help && helpPosition=='below_input'" :class="theme.default.help">
<slot name="help">{{ help }}</slot> <slot name="help"><span class="field-help" v-html="help" /></slot>
</small> </small>
<has-error v-if="hasValidation" :form="form" :field="name" /> <has-error v-if="hasValidation" :form="form" :field="name" />
</div> </div>

View File

@ -6,6 +6,9 @@
{{ label }} {{ label }}
<span v-if="required" class="text-red-500 required-dot">*</span> <span v-if="required" class="text-red-500 required-dot">*</span>
</label> </label>
<small v-if="help && helpPosition=='above_input'" :class="theme.SelectInput.help" class="flex mb-1">
<slot name="help"><span class="field-help" v-html="help" /></slot>
</small>
<div v-on-clickaway="closeDropdown" <div v-on-clickaway="closeDropdown"
class="relative" class="relative"
@ -73,6 +76,10 @@
</ul> </ul>
</div> </div>
</div> </div>
<small v-if="help && helpPosition=='below_input'" :class="theme.SelectInput.help">
<slot name="help"><span class="field-help" v-html="help" /></slot>
</small>
</div> </div>
</template> </template>
@ -108,7 +115,9 @@ export default {
uppercaseLabels: { type: Boolean, default: true }, uppercaseLabels: { type: Boolean, default: true },
theme: { type: Object, default: () => themes.default }, theme: { type: Object, default: () => themes.default },
allowCreation: { type: Boolean, default: false }, allowCreation: { type: Boolean, default: false },
disabled: { type: Boolean, default: false } disabled: { type: Boolean, default: false },
help: { type: String, default: null },
helpPosition: { type: String, default: 'below_input' },
}, },
data () { data () {
return { return {

View File

@ -462,6 +462,7 @@ export default {
color: this.form.color, color: this.form.color,
placeholder: field.placeholder, placeholder: field.placeholder,
help: field.help, help: field.help,
helpPosition: (field.help_position) ? field.help_position : 'below_input',
uppercaseLabels: this.form.uppercase_labels, uppercaseLabels: this.form.uppercase_labels,
theme: this.theme, theme: this.theme,
maxCharLimit: (field.max_char_limit) ? parseInt(field.max_char_limit) : 2000, maxCharLimit: (field.max_char_limit) ? parseInt(field.max_char_limit) : 2000,

View File

@ -268,6 +268,7 @@ export default {
field.placeholder = field.placeholder || null field.placeholder = field.placeholder || null
field.prefill = field.prefill || null field.prefill = field.prefill || null
field.help = field.help || null field.help = field.help || null
field.help_position = field.help_position || 'below_input'
return field return field
}) })

View File

@ -295,6 +295,7 @@ export default {
if (['select', 'multi_select'].includes(this.blockForm.type)) { if (['select', 'multi_select'].includes(this.blockForm.type)) {
data[this.blockForm.type] = {'options': []} data[this.blockForm.type] = {'options': []}
} }
data.help_position = 'below_input'
this.$emit('block-added', data) this.$emit('block-added', data)
this.close() this.close()
}, },

View File

@ -144,7 +144,11 @@ export default {
} }
}, },
data() { data() {
return {} return {
editorToolbarCustom: [
['bold', 'italic', 'underline', 'link'],
]
}
}, },
computed: {}, computed: {},
@ -172,6 +176,11 @@ export default {
if (this.field.hidden) { if (this.field.hidden) {
this.$set(this.field, 'required', false) this.$set(this.field, 'required', false)
} }
},
onFieldHelpPositionChange (val) {
if(!val){
this.$set(this.field, 'help_position', 'below_input')
}
} }
} }
} }

View File

@ -222,7 +222,7 @@
</h3> </h3>
<p class="text-gray-400 mb-5"> <p class="text-gray-400 mb-5">
Change your form field name, pre-fill a value, add hints. Change your form field name, pre-fill a value, add hints, etc.
</p> </p>
<text-input name="name" class="mt-4" <text-input name="name" class="mt-4"
@ -275,14 +275,6 @@
label="Empty Input Text (Placeholder)" label="Empty Input Text (Placeholder)"
/> />
<!-- Help -->
<text-input name="help" class="mt-4"
:form="field"
label="Field Help"
help="Your field help will be shown below the field, just like this message."
/>
<select-input name="width" class="mt-4" <select-input name="width" class="mt-4"
:options="[ :options="[
{name:'Full',value:'full'}, {name:'Full',value:'full'},
@ -295,6 +287,23 @@
:form="field" label="Field Width" :form="field" label="Field Width"
/> />
<!-- Help -->
<rich-text-area-input name="help" class="mt-4"
:form="field"
:editorToolbar="editorToolbarCustom"
label="Field Help"
help="Your field help will be shown below/above the field, just like this message."
:help-position="field.help_position"
/>
<select-input name="help_position" class="mt-4"
:options="[
{name:'Below input',value:'below_input'},
{name:'Above input',value:'above_input'},
]"
:form="field" label="Field Help Position"
@input="onFieldHelpPositionChange"
/>
<template v-if="['text','number','url','email','phone_number'].includes(field.type)"> <template v-if="['text','number','url','email','phone_number'].includes(field.type)">
<text-input v-model="field.max_char_limit" name="max_char_limit" native-type="number" :min="1" :max="2000" <text-input v-model="field.max_char_limit" name="max_char_limit" native-type="number" :min="1" :max="2000"
:form="field" :form="field"
@ -379,7 +388,10 @@ export default {
}, },
data() { data() {
return { return {
typesWithoutPlaceholder: ['date', 'checkbox', 'files'] typesWithoutPlaceholder: ['date', 'checkbox', 'files'],
editorToolbarCustom: [
['bold', 'italic', 'underline', 'link'],
]
} }
}, },
@ -546,6 +558,11 @@ export default {
this.$set(this.field, 'disable_past_dates', false) this.$set(this.field, 'disable_past_dates', false)
this.$set(this.field, 'prefill_today', false) this.$set(this.field, 'prefill_today', false)
} }
},
onFieldHelpPositionChange (val) {
if (!val) {
this.$set(this.field, 'help_position', 'below_input')
}
} }
} }
} }

View File

@ -11,7 +11,8 @@ export default {
disabled: { type: Boolean, default: false }, disabled: { type: Boolean, default: false },
placeholder: { type: String, default: null }, placeholder: { type: String, default: null },
uppercaseLabels: { type: Boolean, default: false }, uppercaseLabels: { type: Boolean, default: false },
help: { type: String, default: null }, // Show help or bot help: { type: String, default: null },
helpPosition: { type: String, default: 'below_input' },
theme: { type: Object, default: () => themes.default }, theme: { type: Object, default: () => themes.default },
color: { type: String, default: '#3B82F6' }, color: { type: String, default: '#3B82F6' },
wrapperClass: { type: String, default: 'relative mb-3' } wrapperClass: { type: String, default: 'relative mb-3' }

View File

@ -46,3 +46,9 @@ body.dark * {
.bg-gray-50 { .bg-gray-50 {
@apply dark:bg-notion-dark-light; @apply dark:bg-notion-dark-light;
} }
.field-help {
p {
@apply text-gray-400 dark:text-gray-500;
}
}