Text.vue 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. <!--
  2. Champs de saisie de texte, à placer dans un composant UiForm
  3. @see https://vuetifyjs.com/en/components/text-fields/
  4. -->
  5. <template>
  6. <v-text-field
  7. ref="input"
  8. :model-value="modelValue"
  9. :label="label || field ? $t(label ?? field) : undefined"
  10. :rules="rules"
  11. :disabled="readonly"
  12. :type="type === 'password' && show ? 'text' : type"
  13. :error="error || !!fieldViolations"
  14. :error-messages="
  15. errorMessage || (fieldViolations ? $t(fieldViolations) : '')
  16. "
  17. :append-icon="type === 'password' ? (show ? 'mdi-eye' : 'mdi-eye-off') : ''"
  18. :variant="variant"
  19. density="compact"
  20. @click:append="show = !show"
  21. @update:model-value="onUpdate($event)"
  22. @change="onChange($event)"
  23. />
  24. <!-- v-cleave="mask"-->
  25. </template>
  26. <script setup lang="ts">
  27. import type { PropType, Ref } from 'vue'
  28. import { ref } from 'vue'
  29. import { useFieldViolation } from '~/composables/form/useFieldViolation'
  30. type ValidationRule = (value: string | number | null) => boolean | string
  31. const props = defineProps({
  32. /**
  33. * v-model
  34. */
  35. modelValue: {
  36. type: [String, Number] as PropType<string | number | null>,
  37. required: false,
  38. default: null,
  39. },
  40. /**
  41. * Nom de la propriété d'une entité lorsque l'input concerne cette propriété
  42. * - Utilisé par la validation
  43. * - Laisser null si le champ ne s'applique pas à une entité
  44. */
  45. field: {
  46. type: String,
  47. required: false,
  48. default: null,
  49. },
  50. /**
  51. * Label du champ
  52. * Si non défini, c'est le nom de propriété qui est utilisé
  53. */
  54. label: {
  55. type: String,
  56. required: false,
  57. default: null,
  58. },
  59. /**
  60. * Type d'input HTML
  61. * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/button
  62. */
  63. type: {
  64. type: String,
  65. required: false,
  66. default: null,
  67. },
  68. /**
  69. * Définit si le champ est en lecture seule
  70. */
  71. readonly: {
  72. type: Boolean,
  73. required: false,
  74. default: false,
  75. },
  76. /**
  77. * Règles de validation
  78. * @see https://vuetify.cn/en/components/forms/#validation-with-submit-clear
  79. */
  80. rules: {
  81. type: Array as PropType<ValidationRule[]>,
  82. required: false,
  83. default: () => [],
  84. },
  85. /**
  86. * Le champ est-il actuellement en état d'erreur
  87. */
  88. error: {
  89. type: Boolean,
  90. required: false,
  91. default: false,
  92. },
  93. /**
  94. * Si le champ est en état d'erreur, quel est le message d'erreur?
  95. */
  96. errorMessage: {
  97. type: String,
  98. required: false,
  99. default: null,
  100. },
  101. /**
  102. * Masque de saisie
  103. * @see https://github.com/nosir/cleave.js/
  104. */
  105. mask: {
  106. type: [Array, Boolean],
  107. required: false,
  108. default: false,
  109. },
  110. /**
  111. * @see https://vuetifyjs.com/en/api/v-autocomplete/#props-variant
  112. */
  113. variant: {
  114. type: String as PropType<
  115. | 'filled'
  116. | 'outlined'
  117. | 'plain'
  118. | 'underlined'
  119. | 'solo'
  120. | 'solo-inverted'
  121. | 'solo-filled'
  122. | undefined
  123. >,
  124. required: false,
  125. default: 'outlined',
  126. },
  127. })
  128. const input = ref(null)
  129. const { fieldViolations, updateViolationState } = useFieldViolation(props.field)
  130. const show: Ref<boolean> = ref(false)
  131. const emit = defineEmits(['update:model-value', 'change'])
  132. const onUpdate = (event: string) => {
  133. emit('update:model-value', event)
  134. }
  135. const onChange = (event: Event | undefined) => {
  136. updateViolationState()
  137. emit('change', event)
  138. }
  139. onUnmounted(() => {
  140. updateViolationState()
  141. })
  142. </script>
  143. <style scoped lang="scss">
  144. input:read-only {
  145. color: rgb(var(--v-theme-neutral));
  146. }
  147. </style>