UNPKG

@coreui/vue

Version:

UI Components Library for Vue.js

116 lines (112 loc) 4.53 kB
'use strict'; var vue = require('vue'); var _const = require('../chip/const.js'); var isRTL = require('../../utils/isRTL.js'); const chipSetContextKey = Symbol('CChipSet'); /** * Shared chip-set engine for CChipSet and CChipInput — the Vue equivalent of the * vanilla `ChipInput extends ChipSet`. It owns selection coordination * (single/multiple, controlled-or-uncontrolled), roving focus, and the * focus-a-neighbor-after-removal behavior, and `provide`s a context that CChip * injects. Existence of the chips stays with the caller. */ const useChipSet = (options) => { const { config, selectionMode = () => 'multiple', selected = () => undefined, defaultSelected = [], restoreFocusOnRemove = true, onSelectionChange, onRemove, } = options; const rootRef = vue.ref(); const internalSelected = vue.ref(defaultSelected); const selectedValues = vue.computed(() => { const controlled = selected(); return controlled === undefined ? internalSelected.value : controlled; }); const getFocusableChips = () => [ ...(rootRef.value?.querySelectorAll(_const.SELECTOR_CHIP_FOCUSABLE) ?? []), ]; const emitSelection = (next) => { if (selected() === undefined) { internalSelected.value = next; } onSelectionChange?.(next); }; const toggleSelected = (value, next) => { const isSelected = selectedValues.value.includes(value); if (next === isSelected) { return; } if (next) { // Single selection mode keeps only the freshly selected chip. emitSelection(selectionMode() === 'single' ? [value] : [...selectedValues.value, value]); return; } emitSelection(selectedValues.value.filter((item) => item !== value)); }; const clearSelection = () => { if (selectedValues.value.length > 0) { emitSelection([]); } }; const removeChip = (value) => { if (restoreFocusOnRemove) { const chips = getFocusableChips(); const index = chips.findIndex((chip) => chip.dataset.coreuiChipValue === value); // Prefer the next chip, fall back to the previous one at the end. const neighbor = chips[index + 1] ?? chips[index - 1] ?? null; const neighborValue = neighbor?.dataset.coreuiChipValue ?? null; if (neighborValue !== null) { vue.nextTick(() => { rootRef.value ?.querySelector(`[data-coreui-chip-value="${neighborValue}"]`) ?.focus(); }); } } emitSelection(selectedValues.value.filter((item) => item !== value)); onRemove?.(value); }; // Roving focus: arrow keys move between chips and Home/End jump to the edges, // with no cycling. Returns true when the key was handled. const handleKeydown = (event) => { const chip = event.target.closest(_const.SELECTOR_CHIP_FOCUSABLE); if (!chip) { return false; } const chips = getFocusableChips(); const index = chips.indexOf(chip); // In RTL the visual direction is mirrored, so left/right swap. const rtl = isRTL.default(rootRef.value); switch (event.key) { case 'ArrowLeft': { event.preventDefault(); chips[rtl ? index + 1 : index - 1]?.focus(); return true; } case 'ArrowRight': { event.preventDefault(); chips[rtl ? index - 1 : index + 1]?.focus(); return true; } case 'Home': { event.preventDefault(); chips[0]?.focus(); return true; } case 'End': { event.preventDefault(); chips[chips.length - 1]?.focus(); return true; } default: { return false; } } }; vue.provide(chipSetContextKey, { config, isSelected: (value) => selectedValues.value.includes(value), toggleSelected: (value, next) => toggleSelected(value, next), removeChip: (value) => removeChip(value), }); return { rootRef, selectedValues, clearSelection, getFocusableChips, handleKeydown }; }; exports.chipSetContextKey = chipSetContextKey; exports.useChipSet = useChipSet; //# sourceMappingURL=useChipSet.js.map