UNPKG

@mozaic-ds/vue

Version:

Mozaic-Vue is the Vue.js implementation of ADEO Design system

150 lines (127 loc) 4.08 kB
import { computed } from 'vue'; import type { ListboxOption } from './MOptionListbox.types'; type SelectionValue = string | number | null | (string | number)[]; type Props = { modelValue: SelectionValue; options: ListboxOption[]; multiple?: boolean; readonly?: boolean; checkableSections?: boolean; }; export function useListboxSelection( props: Props, emit: (on: 'update:modelValue', value: SelectionValue) => void, ) { const selection = computed<SelectionValue>({ get() { return props.modelValue; }, set(value) { emit('update:modelValue', value); }, }); const sectionMap = computed(() => { const map = new Map<string, ListboxOption[]>(); let currentSection: ListboxOption | null = null; props.options.forEach((option) => { if (option.type === 'section') { currentSection = option; map.set(currentSection?.value?.toString() || currentSection.label, []); } else if (currentSection) { map .get(currentSection?.value?.toString() || currentSection.label)! .push(option); } }); return map; }); function isSelectable(item: ListboxOption): boolean { return !!( (item.type !== 'section' && !item.disabled) || (item.type === 'section' && props.checkableSections && props.multiple) ); } function isOptionSelected(item: ListboxOption) { if (item.value === undefined || item.value === null) return false; if (Array.isArray(selection.value)) { return (selection.value as (string | number)[]).includes(item.value); } return item.value === selection.value; } function isSectionSelected(item: ListboxOption) { if (!props.checkableSections || !props.multiple) return false; const sectionItems = sectionMap.value.get(item.value?.toString() || item.label) || []; const selectedItems = Array.isArray(selection.value) ? (selection.value as (string | number)[]) : []; return sectionItems.every((opt) => selectedItems.includes(opt.value!)); } function isIndeterminate(item: ListboxOption) { const section = sectionMap.value.get(item.value?.toString() || item.label); return ( section?.some((option) => isOptionSelected(option)) && !section?.every((option) => isOptionSelected(option)) ); } function toggleValue(item?: ListboxOption) { if (!item || !isSelectable(item)) return; if (Array.isArray(selection.value)) { if (isOptionSelected(item)) { selection.value = (selection.value as (string | number)[]).filter( (el) => el !== item.value, ); } else { selection.value = [...selection.value, item.value!]; } } else { selection.value = isOptionSelected(item) ? null : item.value!; } } function toggleSection(item: ListboxOption) { if (!props.checkableSections || !props.multiple) return; const sectionItems = sectionMap.value.get(item.value?.toString() || item.label) || []; const selectedItems = Array.isArray(selection.value) ? (selection.value as (string | number)[]) : []; if (isSectionSelected(item)) { selection.value = selectedItems.filter( (opt) => !sectionItems.find((i) => i.value === opt), ); } else { selection.value = [ ...selectedItems, ...sectionItems .filter((opt) => !selectedItems.includes(opt.value!)) .map((i) => i.value!), ]; } } function selectAll() { selection.value = props.options .filter( (option) => option.value !== undefined && option.value !== null && !option.disabled && option.type !== 'section', ) .map((item) => item.value!); } function clearSelection() { selection.value = Array.isArray(selection.value) ? [] : null; } return { selection, sectionMap, isSelectable, isOptionSelected, isSectionSelected, isIndeterminate, toggleValue, toggleSection, selectAll, clearSelection, }; }