Files
2023-05-30 15:04:51 -05:00

95 lines
2.6 KiB
Vue

<script setup>
const props = defineProps({
type: {
type: String,
default: "single"
},
defaultValue: {
type: String || Array,
}
})
const emit = defineEmits(['update:modelValue'])
const toggleGroup = ref(null);
const selected = ref((props.type === "single") ? props.defaultValue : [].concat(props.defaultValue));
watch(selected, (newValue) => {
emit('update:modelValue', newValue);
})
emit('update:modelValue', selected.value);
const items = ref([]);
function registerToggleItem(value) {
const item = { value, tabIndex: (props.defaultValue.includes(value)) ? ref('0') : ref('-1') }
const itemIndex = (items.value.push(item)) - 1
return { item, index: itemIndex };
}
function toggleItem(index) {
if (props.type === "single") {
selected.value = items.value[index].value;
return;
}
if (selected.value.indexOf(items.value[index].value) > -1) {
selected.value = selected.value.filter((e) => e !== items.value[index].value)
return;
}
selected.value.push(items.value[index].value);
}
function keydown(event) {
const elements = Array.from(toggleGroup.value.children).filter(
(el) => el.nodeName.toLowerCase() === 'button'
);
if (event.key === "Home") {
event.preventDefault();
items.value.forEach((el, i) => {
if (i === 0) return items.value[i].tabIndex = '0';
return items.value[i].tabIndex = '-1';
});
elements[0].focus();
}
if (event.key === "End") {
event.preventDefault();
items.value.forEach((el, i) => {
if (i === items.value.length - 1) return items.value[i].tabIndex = '0';
return items.value[i].tabIndex = '-1';
});
elements[items.value.length-1].focus();
}
const focusedElement = document.activeElement;
const currentIndex = elements.indexOf(focusedElement);
if (event.key === "ArrowRight" || event.key === "ArrowDown") {
event.preventDefault();
const nextIndex = currentIndex < elements.length - 1 ? currentIndex + 1 : 0;
items.value.forEach((el, i) => {
if (i === nextIndex) return items.value[i].tabIndex = '0';
return items.value[i].tabIndex = '-1';
});
elements[nextIndex].focus();
}
if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
event.preventDefault();
const nextIndex = currentIndex > 0 ? currentIndex - 1 : elements.length - 1;
items.value.forEach((el, i) => {
if (i === nextIndex) return items.value[i].tabIndex = '0';
return items.value[i].tabIndex = '-1';
});
elements[nextIndex].focus();
}
}
provide('toggleGroup', { registerToggleItem, toggleItem, selected })
</script>
<template>
<div role="group" ref="toggleGroup" class="vl-toggle-group" @keydown="keydown($event)">
<slot />
</div>
</template>