From d1a006c0ca8584d05ece37093b1a5890eb6bd3d6 Mon Sep 17 00:00:00 2001 From: antoine Date: Fri, 17 Jul 2026 16:08:37 +0200 Subject: [PATCH 1/2] Fix max tags count --- .../js/components/ui/tags-input/TagsInput.vue | 2 +- resources/js/form/components/fields/Tags.vue | 71 +++++++++++++------ 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/resources/js/components/ui/tags-input/TagsInput.vue b/resources/js/components/ui/tags-input/TagsInput.vue index 82f456e3c..94e43074c 100644 --- a/resources/js/components/ui/tags-input/TagsInput.vue +++ b/resources/js/components/ui/tags-input/TagsInput.vue @@ -16,7 +16,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits) diff --git a/resources/js/form/components/fields/Tags.vue b/resources/js/form/components/fields/Tags.vue index 57bc3cbfe..6228bc7b5 100644 --- a/resources/js/form/components/fields/Tags.vue +++ b/resources/js/form/components/fields/Tags.vue @@ -3,7 +3,7 @@ import { FormTagsFieldData } from "@/types"; import { TagsInput, TagsInputInput, TagsInputItem, TagsInputItemText, TagsInputItemDelete } from "@/components/ui/tags-input"; import { ComboboxAnchor, ComboboxContent, ComboboxPortal, ComboboxRoot, ComboboxInput } from "reka-ui"; - import { computed, ref } from "vue"; + import { computed, ref, useTemplateRef, watch, nextTick } from "vue"; import { __ } from "@/utils/i18n"; import { CommandEmpty, CommandGroup, CommandItem, CommandList, CommandSeparator } from "@/components/ui/command"; import FormFieldLayout from "@/form/components/FormFieldLayout.vue"; @@ -13,6 +13,7 @@ const emit = defineEmits>(); const open = ref(false); + const input = useTemplateRef>('input'); const searchTerm = ref(''); let itemKeyIndex = 0; @@ -24,27 +25,58 @@ } } + const canAdd = computed(() => { + return !props.field.maxTagCount + || props.value.length < props.field.maxTagCount + }); + const canCreate = computed(() => { + return props.field.creatable + && searchTerm.value.length > 0 + && !props.value?.find(v => v.label === searchTerm.value) + && !props.field.options.find(o => o.label === searchTerm.value); + }); + function onCreateClick() { - emit('input', [ - ...(props.value ?? []), - withItemKey({ - id: null, - label: searchTerm.value, - }), - ]); + if(canAdd.value) { + emit('input', [ + ...(props.value ?? []), + withItemKey({ + id: null, + label: searchTerm.value, + }), + ]); + } } function onOptionClick(option: FormTagsFieldData['options'][0]) { - emit('input', [ - ...(props.value ?? []), - withItemKey(option), - ]); + if(canAdd.value) { + emit('input', [ + ...(props.value ?? []), + withItemKey(option), + ]); + } } - function onDeleteClick(item: FormTagsFieldData['value'][0]) { + async function onDeleteClick(item: FormTagsFieldData['value'][0]) { emit('input', props.value.filter(i => i[itemKey] !== item[itemKey])); + await nextTick(); + onInputClick(); + } + + async function onInputClick() { + if(canAdd.value) { + open.value = true; + await nextTick(); + input.value.$el.focus(); + } } + watch(canAdd, () => { + if(!canAdd.value && open.value) { + open.value = false; + } + }); + const { fullTextSearch } = useFullTextSearch(() => props.field.options, { id: 'id', searchKeys: ['label'] }); const filteredOptions = computed(() => { const filtered = searchTerm.value.length > 0 @@ -53,12 +85,6 @@ return filtered .filter(o => !props.value?.find(v => o.id != null && v.id != null && o.id === v.id)); // show only unselected options }); - const canCreate = computed(() => { - return props.field.creatable - && searchTerm.value.length > 0 - && !props.value?.find(v => v.label === searchTerm.value) - && !props.field.options.find(o => o.label === searchTerm.value); - }); emit('input', props.value?.map(option => withItemKey(option)), { skipRefresh: true }); @@ -73,11 +99,12 @@ > - + From 8ea224bcecd1cf385979be11fc46982c09402a02 Mon Sep 17 00:00:00 2001 From: antoine Date: Fri, 17 Jul 2026 16:10:05 +0200 Subject: [PATCH 2/2] fail-safe --- resources/js/form/components/fields/Tags.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/form/components/fields/Tags.vue b/resources/js/form/components/fields/Tags.vue index 6228bc7b5..523d16673 100644 --- a/resources/js/form/components/fields/Tags.vue +++ b/resources/js/form/components/fields/Tags.vue @@ -27,7 +27,7 @@ const canAdd = computed(() => { return !props.field.maxTagCount - || props.value.length < props.field.maxTagCount + || (props.value ?? []).length < props.field.maxTagCount }); const canCreate = computed(() => { return props.field.creatable