1<template>
2 <div class="flex flex-wrap gap-2 rounded-6 bg-surface-gray-2 p-2">
3 <Pill
4 v-for="item in items"
5 :key="item.value"
6 :label="item.label"
7 @click="(i) => remove(i)"
8 />
9
10 <TextInput
11 v-model="input"
12 class="w-full"
13 :placeholder="placeholder"
14 @keyup.enter="add({ label: input, value: input })"
15 />
16 </div>
17</template>
18
19<script setup lang="ts">
20import { TextInput, toast } from "frappe-ui";
21import { ref, toRefs } from "vue";
22import Pill from "./Pill.vue";
23
24type Item = {
25 label: string;
26 // eslint-disable-next-line @typescript-eslint/no-explicit-any
27 value: any;
28};
29
30const props = defineProps({
31 items: {
32 type: Array<Item>,
33 required: true,
34 },
35 placeholder: {
36 type: String,
37 required: false,
38 default: "Type...",
39 },
40 validate: {
41 type: Function,
42 required: false,
43 default: () => false,
44 },
45});
46
47const emit = defineEmits<{
48 (event: "update:items", items: Array<Item>): void;
49}>();
50
51const { items } = toRefs(props);
52const input = ref("");
53
54function add(item: Item) {
55 const err = props.validate(item);
56
57 if (err) {
58 toast.error(err);
59
60 return;
61 }
62
63 const res = [...items.value, item];
64 emit("update:items", res);
65 input.value = "";
66}
67
68function remove(item: Item) {
69 const res = items.value.filter((i) => i.value !== item);
70 emit("update:items", res);
71}
72</script>
73