Components
Vue Components structure
Components allow us to split the UI into independent and reusable pieces, and think about each piece in isolation.
For more info check the official Vue documentation.
This is an example of a widely used component within Balance, BaseInput:
<template>
<div v-if="hasLabel" class="w-full pt-1">
<label :for="name" :class="labelClassName ?? LabelClassEnum.DEFAULT">
{{ label }} {{ required ? '*' : '' }}
</label>
</div>
<div class="flex-1">
<textarea
v-if="type == BaseInputTypeEnum.TEXTAREA"
:class="
className ??
InputClassEnum.DEFAULT +
(requestErrors && requestErrors.length > 0
? ' border-red-500'
: '')
"
:value="value"
:placeholder="placeholder ?? ' '"
:readonly="readonly"
@input="(value) => $emit('onInput', value)"
@keyup.enter="$emit('onPressEnter')"
@keydown.enter.exact.prevent
/>
<input
v-else
ref="inputRef"
:class="
className ??
InputClassEnum.DEFAULT +
(requestErrors && requestErrors.length > 0
? ' border-red-500'
: '')
"
:value="value"
:placeholder="placeholder ?? ' '"
:type="type"
:name="name"
:disabled="disabled"
:alt="alt"
:autocomplete="autocomplete ? 'on' : 'off'"
:checked="!!value"
:autofocus="autofocus"
:form="form"
:formaction="formaction"
:formenctype="formenctype"
:formmethod="formmethod"
:formnovalidate="formnovalidate"
:formtarget="formtarget"
:height="height"
:list="list"
:max="max"
:maxlength="maxlength"
:min="min"
:minlength="minlength"
:multiple="multiple"
:pattern="pattern"
:readonly="readonly"
:size="size"
:src="src"
:step="step"
:width="width"
:accept="accept"
@input="(value) => $emit('onInput', value)"
@keyup.exact.enter="$emit('onPressEnter')"
@focusout="$emit('onFocusOut')"
@keyup.exact.ctrl.enter="$emit('onPressCtrlEnter')"
/>
</div>
<div
v-if="requestErrors && requestErrors.length > 0"
:for="name"
class="flex w-full flex-col gap-2"
>
<span
v-for="(error, i) in requestErrors"
:key="`request-error-${i}`"
class="text-sm font-bold text-red-500"
>
{{ error }}
</span>
</div>
</template>
<script setup lang="ts">
import {
InputClassEnum,
LabelClassEnum,
} from '@/enums/styles/BaseInputClassEnum'
import { BaseInputTypeEnum } from '@enums/components/BaseInputTypeEnum'
import { onMounted, ref } from 'vue'
defineEmits(['onInput', 'onPressEnter', 'onFocusOut', 'onPressCtrlEnter'])
const props = defineProps<{
placeholder?: string
className?: string
value?: any
name?: string
type?: BaseInputTypeEnum
required?: boolean
hasLabel?: boolean
labelClassName?: LabelClassEnum
label?: string
disabled?: boolean
alt?: string
checked?: boolean
autocomplete?: boolean
autofocus?: boolean
form?: string
formaction?: string
formenctype?: string
formmethod?: string
formnovalidate?: boolean
formtarget?: string
height?: number
list?: string
max?: number
maxlength?: number
min?: number
minlength?: number
multiple?: boolean
pattern?: string
readonly?: boolean
size?: number
src?: string
step?: string
width?: number
accept?: string
accesskey?: string
contenteditable?: boolean
contextmenu?: string
requestErrors?: Array<string>
dir?: string
}>()
const inputRef = ref<HTMLInputElement>()
onMounted(() => {
if (props.autofocus) {
inputRef.value?.focus()
}
})
</script>And this is its usage:
<BaseInput
:label="
t('cruds.user.fields.external_source')
"
name="external_source"
:value="
usersSingleStore.entry.external_source
"
has-label
autocomplete
:type="BaseInputTypeEnum.TEXT"
:request-errors="
usersSingleStore.errorRequest.external_source
"
@on-input="updateExternalSource"
/>Last updated