From c2c0a2aa794a26b85a478210d2c5521f211551b5 Mon Sep 17 00:00:00 2001 From: upsiflu Date: Tue, 1 Apr 2025 09:30:11 +0200 Subject: [PATCH] docs(ui): #2390 bind external sources and sinks to tags lists (Pills) --- front/src/components/ui/Pill.vue | 14 ++- front/src/components/ui/Pills.vue | 23 +++- front/ui-docs/components/ui/pills.md | 182 +++++++++++++++++++++++++-- 3 files changed, 200 insertions(+), 19 deletions(-) diff --git a/front/src/components/ui/Pill.vue b/front/src/components/ui/Pill.vue index 567b43df4..84764d0d4 100644 --- a/front/src/components/ui/Pill.vue +++ b/front/src/components/ui/Pill.vue @@ -7,12 +7,14 @@ import Button from './Button.vue' import Input from './Input.vue' import Popover from './Popover.vue' import PopoverItem from './popover/PopoverItem.vue' +import { uniqBy } from 'lodash-es' /* Event */ const emit = defineEmits<{ confirmed: [], - closed: [] + closed: [], + opened: [] }>() /* Model */ @@ -31,6 +33,9 @@ type Item = { type: 'custom' | 'preset', label: string } const currentItem = defineModel('current'), otherItems = defineModel('others') +// Make sure there are no duplicate labels +const unique = (value: Item[]) => uniqBy(value, item => item.label) + const isEditing = ref(false) /* Lifecycle */ @@ -52,9 +57,11 @@ watch(isEditing, (isTrue, wasTrue) => { if (!currentItem.value || !otherItems.value) return // Cache the previous value, in case the user cancels later if (isTrue && !wasTrue) { + emit('opened') previousValue = { ...currentItem.value } if (currentItem.value.type === 'preset') { otherItems.value.push({...currentItem.value}) + otherItems.value = unique(otherItems.value) currentItem.value.type = 'custom' } // Shift focus between the input and the previously focused element @@ -170,13 +177,13 @@ const other = computed(() => (option: Item) => ({ onClick: () => { if (!currentItem.value || !otherItems.value) return; currentItem.value = { ...option, type: 'custom' } - otherItems.value = [...( + otherItems.value = unique([...( currentItem.value.label.trim() === '' || otherItems.value.find(({ label }) => label === currentItem.value?.label.trim()) ? [] : [{ ...currentItem.value }] ), ...otherItems.value.filter( ({ label, type }) => label !== option.label || type === 'preset' - )] + )]) isEditing.value = false }, isMatch: match.value?.label === option.label, @@ -232,6 +239,7 @@ const current = computed(() => ( onClick: () => { if (!otherItems.value || !currentItem.value || otherItems.value.find(({ label })=>label === currentItem.value?.label.trim())) return otherItems.value.push({...currentItem.value}) + otherItems.value = unique(otherItems.value) } } as const : undefined diff --git a/front/src/components/ui/Pills.vue b/front/src/components/ui/Pills.vue index 0a07b6977..a68f57694 100644 --- a/front/src/components/ui/Pills.vue +++ b/front/src/components/ui/Pills.vue @@ -1,5 +1,5 @@