|
| 1 | +<script lang="ts" setup> |
| 2 | +import FormLabel from "./FormLabel.vue"; |
| 3 | +import FormHelptext from "./FormHelptext.vue"; |
| 4 | +import { computed, toRefs } from "vue"; |
| 5 | +import { |
| 6 | + XMarkIcon, |
| 7 | + PlusIcon, |
| 8 | + ArrowSmallUpIcon, |
| 9 | +} from "@heroicons/vue/24/outline"; |
| 10 | +
|
| 11 | +const props = defineProps<{ |
| 12 | + label: string; |
| 13 | + name: string; |
| 14 | + modelValue: string[]; |
| 15 | + required?: boolean; |
| 16 | + helptext?: string; |
| 17 | +}>(); |
| 18 | +const { modelValue } = toRefs(props); |
| 19 | +
|
| 20 | +const emit = defineEmits(["update:modelValue"]); |
| 21 | +
|
| 22 | +type Value = Record<string, string>; |
| 23 | +
|
| 24 | +const value = computed<Value>({ |
| 25 | + get: () => { |
| 26 | + const ret = modelValue.value.reduce( |
| 27 | + (acc, curr, index) => ({ ...acc, [index + 1]: curr }), |
| 28 | + {}, |
| 29 | + ); |
| 30 | + return ret; |
| 31 | + }, |
| 32 | + set: (val: Value) => { |
| 33 | + emit("update:modelValue", Object.values(val)); |
| 34 | + }, |
| 35 | +}); |
| 36 | +
|
| 37 | +function add() { |
| 38 | + const key = |
| 39 | + Math.max(...Object.keys(value.value).map((x) => parseInt(x)), 0) + 1; |
| 40 | + const newValue = { ...value.value, [key]: "" }; |
| 41 | + value.value = newValue; |
| 42 | +} |
| 43 | +
|
| 44 | +function remove(key: string) { |
| 45 | + const newValue = { ...value.value }; |
| 46 | + delete newValue[key]; |
| 47 | + value.value = newValue; |
| 48 | +} |
| 49 | +
|
| 50 | +function up(k: string) { |
| 51 | + const key = parseInt(k); |
| 52 | + const newValue = { ...value.value }; |
| 53 | + if (key > 0) { |
| 54 | + newValue[key] = value.value[key - 1]; |
| 55 | + newValue[key - 1] = value.value[key]; |
| 56 | + } |
| 57 | + value.value = newValue; |
| 58 | +} |
| 59 | +
|
| 60 | +function change() { |
| 61 | + emit("update:modelValue", Object.values(value.value)); |
| 62 | +} |
| 63 | +</script> |
| 64 | + |
1 | 65 | <template> |
2 | | - <label :for="name" class="relative block"> |
3 | | - <FormLabel :required="required" :label="label" /> |
| 66 | + <fieldset class="relative block"> |
| 67 | + <legend> |
| 68 | + <FormLabel :required="required" :label="label" /> |
| 69 | + </legend> |
4 | 70 | <div class="flex items-center mt-2 space-x-2"> |
5 | 71 | <div class="flex flex-col items-start w-full space-y-2"> |
6 | 72 | <div |
|
9 | 75 | class="flex items-center w-full space-x-3" |
10 | 76 | > |
11 | 77 | <input |
| 78 | + :id="`form-input-${name}-${key}`" |
12 | 79 | v-model="value[key]" |
| 80 | + :name="name" |
13 | 81 | type="text" |
14 | 82 | class="flex-grow block w-full px-3 py-2 placeholder-gray-400 border border-gray-300 rounded-md shadow-sm appearance-none focus:outline-none focus:ring-formcolor focus:border-formcolor focus:ring-1 sm:text-sm" |
15 | 83 | @change="change()" |
|
39 | 107 | </div> |
40 | 108 | </div> |
41 | 109 | <FormHelptext :helptext="helptext" /> |
42 | | - </label> |
| 110 | + </fieldset> |
43 | 111 | </template> |
44 | | - |
45 | | -<script lang="ts"> |
46 | | -import FormLabel from "./FormLabel.vue"; |
47 | | -import FormHelptext from "./FormHelptext.vue"; |
48 | | -import { defineComponent, PropType } from "vue"; |
49 | | -import { |
50 | | - XMarkIcon, |
51 | | - PlusIcon, |
52 | | - ArrowSmallUpIcon, |
53 | | -} from "@heroicons/vue/24/outline"; |
54 | | -
|
55 | | -export default defineComponent({ |
56 | | - components: { |
57 | | - FormHelptext, |
58 | | - XMarkIcon, |
59 | | - FormLabel, |
60 | | - PlusIcon, |
61 | | - ArrowSmallUpIcon, |
62 | | - }, |
63 | | - props: { |
64 | | - label: { |
65 | | - required: true, |
66 | | - type: String, |
67 | | - }, |
68 | | - name: { |
69 | | - required: true, |
70 | | - type: String, |
71 | | - }, |
72 | | - modelValue: { |
73 | | - required: false, |
74 | | - default: () => [], |
75 | | - type: Array as PropType<string[]>, |
76 | | - }, |
77 | | - required: { |
78 | | - required: false, |
79 | | - default: false, |
80 | | - type: Boolean, |
81 | | - }, |
82 | | - helptext: { |
83 | | - required: false, |
84 | | - default: "", |
85 | | - type: String, |
86 | | - }, |
87 | | - }, |
88 | | - emits: ["update:modelValue"], |
89 | | - data() { |
90 | | - return { |
91 | | - value: {} as { [key: number]: string }, |
92 | | - }; |
93 | | - }, |
94 | | - watch: { |
95 | | - modelValue(newValue) { |
96 | | - this.value = {}; |
97 | | - newValue.forEach((element: string, index: number) => { |
98 | | - this.value[index] = element; |
99 | | - }); |
100 | | - }, |
101 | | - }, |
102 | | - methods: { |
103 | | - add() { |
104 | | - const key = |
105 | | - Math.max(...Object.keys(this.value).map((x) => parseInt(x)), 0) + 1; |
106 | | - this.value[key] = ""; |
107 | | - this.change(); |
108 | | - }, |
109 | | - remove(key: string) { |
110 | | - delete this.value[key]; |
111 | | - this.change(); |
112 | | - }, |
113 | | - up(k: string) { |
114 | | - const key = parseInt(k); |
115 | | - if (key > 0) { |
116 | | - const temp = this.value[key]; |
117 | | - this.value[key] = this.value[key - 1]; |
118 | | - this.value[key - 1] = temp; |
119 | | - } |
120 | | - this.change(); |
121 | | - }, |
122 | | - change() { |
123 | | - this.$emit("update:modelValue", Object.values(this.value)); |
124 | | - }, |
125 | | - }, |
126 | | -}); |
127 | | -</script> |
0 commit comments