refactor: rework TagsSelectizeItem with multiple choices types

This commit is contained in:
axolotle 2024-08-12 23:54:07 +02:00
parent cba781d809
commit 837e92789a
2 changed files with 44 additions and 30 deletions

View file

@ -3,17 +3,14 @@ import type { BDropdown, BFormInput } from 'bootstrap-vue-next'
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { fromEntries } from '@/helpers/commons'
import type { import type {
BaseItemComputedProps, BaseItemComputedProps,
Choice,
TagUpdateArgs,
TagsSelectizeItemProps, TagsSelectizeItemProps,
} from '@/types/form' } from '@/types/form'
type TagUpdateArgs = {
action: 'add' | 'remove'
option: string
applyFn: (tag: string) => void
}
defineOptions({ defineOptions({
inheritAttrs: false, inheritAttrs: false,
}) })
@ -55,19 +52,26 @@ const criteria = computed(() => {
return search.value.trim().toLowerCase() return search.value.trim().toLowerCase()
}) })
const availableOptions = computed(() => { const availableOptions = computed(() => {
const options = props.options.filter((opt) => { return props.options.filter((opt) => {
return ( const tag = typeof opt === 'string' ? opt : opt.value
props.modelValue?.indexOf(opt) === -1 && let filterIn =
props.disabledItems?.includes(opt) model.value?.indexOf(tag) === -1 &&
) !(props.disabledItems?.includes(tag) ?? false)
}) if (filterIn && criteria.value) {
if (criteria.value) { filterIn = tag.toLowerCase().indexOf(criteria.value) > -1
return options.filter(
(opt) => opt.toLowerCase().indexOf(criteria.value) > -1,
)
} }
return options return filterIn
}) })
})
const texts = computed(() =>
fromEntries(
props.options.map((opt) => {
const tag = typeof opt === 'string' ? opt : opt.value
const text = typeof opt === 'string' ? opt : opt.text
return [tag, text]
}),
),
)
const searchI18n = computed(() => { const searchI18n = computed(() => {
const params = { items: t('items.' + props.itemsName, 0) } const params = { items: t('items.' + props.itemsName, 0) }
return { return {
@ -80,18 +84,20 @@ const searchState = computed(() => {
return criteria.value && availableOptions.value.length === 0 ? false : null return criteria.value && availableOptions.value.length === 0 ? false : null
}) })
function onAddTag(option: string, applyFn: TagUpdateArgs['applyFn']) { function onAddTag(option: Choice, applyFn: TagUpdateArgs['applyFn']) {
emit('tag-update', { action: 'add', option, applyFn }) const tag = typeof option === 'string' ? option : option.value
emit('tag-update', { action: 'add', tag, applyFn })
search.value = '' search.value = ''
if (props.auto) { if (props.auto) {
applyFn(option) applyFn(tag)
} }
} }
function onRemoveTag(option: string, applyFn: TagUpdateArgs['applyFn']) { function onRemoveTag(option: Choice, applyFn: TagUpdateArgs['applyFn']) {
emit('tag-update', { action: 'remove', option, applyFn }) const tag = typeof option === 'string' ? option : option.value
emit('tag-update', { action: 'remove', tag, applyFn })
if (props.auto) { if (props.auto) {
applyFn(option) applyFn(tag)
} }
} }
@ -134,11 +140,11 @@ function onDropdownKeydown(e: KeyboardEvent) {
> >
<BFormTag <BFormTag
:title="tag" :title="tag"
:disabled="disabled || disabledItems?.includes(tag)" :disabled="disabled || (disabledItems?.includes(tag) ?? false)"
class="border border-dark mb-2" class="border border-dark mb-2"
@remove="onRemoveTag(tag, removeTag)" @remove="onRemoveTag(tag, removeTag)"
> >
<YIcon v-if="tagIcon" :iname="tagIcon" /> {{ tag }} <YIcon v-if="tagIcon" :iname="tagIcon" /> {{ texts[tag] }}
</BFormTag> </BFormTag>
</li> </li>
</ul> </ul>
@ -173,6 +179,7 @@ function onDropdownKeydown(e: KeyboardEvent) {
autocomplete="off" autocomplete="off"
size="sm" size="sm"
type="search" type="search"
@click.stop
/> />
</BFormGroup> </BFormGroup>
</BDropdownForm> </BDropdownForm>
@ -180,11 +187,11 @@ function onDropdownKeydown(e: KeyboardEvent) {
</BDropdownGroup> </BDropdownGroup>
<BDropdownItemButton <BDropdownItemButton
v-for="option in availableOptions" v-for="(option, i) in availableOptions"
:key="option" :key="i"
@click="onAddTag(option, addTag)" @click="onAddTag(option, addTag)"
> >
{{ option }} {{ typeof option === 'string' ? option : option.text }}
</BDropdownItemButton> </BDropdownItemButton>
<BDropdownText v-if="!criteria && availableOptions.length === 0"> <BDropdownText v-if="!criteria && availableOptions.length === 0">
<YIcon iname="exclamation-triangle" /> <YIcon iname="exclamation-triangle" />

View file

@ -10,7 +10,14 @@ import { isObjectLiteral } from '@/helpers/commons'
import type { ArrInnerType, Cols, Obj, StateVariant } from '@/types/commons' import type { ArrInnerType, Cols, Obj, StateVariant } from '@/types/commons'
type StateValidation = false | null type StateValidation = false | null
type Choices = string[] | { text: string; value: string }[] export type Choice = string | { text: string; value: string }
type Choices = Choice[]
export type TagUpdateArgs = {
action: 'add' | 'remove'
tag: string
applyFn: (tag: string) => void
}
// DISPLAY // DISPLAY
@ -121,7 +128,7 @@ export type TagsItemProps = BaseWritableItemProps & {
export type TagsSelectizeItemProps = BaseWritableItemProps & { export type TagsSelectizeItemProps = BaseWritableItemProps & {
itemsName: string itemsName: string
options: string[] options: Choices
auto?: boolean auto?: boolean
disabledItems?: string[] disabledItems?: string[]
label: string label: string