initial commit
This commit is contained in:
95
components/vlToggleGroup/index.vue
Normal file
95
components/vlToggleGroup/index.vue
Normal file
@@ -0,0 +1,95 @@
|
||||
<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>
|
||||
17
components/vlToggleGroup/item.vue
Normal file
17
components/vlToggleGroup/item.vue
Normal file
@@ -0,0 +1,17 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
value: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
})
|
||||
const toggleGroup = inject('toggleGroup');
|
||||
|
||||
const item = toggleGroup.registerToggleItem(props.value);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button role="radio" type="button" @click="toggleGroup.toggleItem(item.index)" :aria-checked="toggleGroup.selected.value === props.value || toggleGroup.selected.value.indexOf(props.value) > -1" :tabindex="item.item.tabIndex.value" :data-state="(toggleGroup.selected.value === props.value || toggleGroup.selected.value.indexOf(props.value) > -1) ? 'checked' : 'unchecked'" class="vl-toggle-button">
|
||||
<slot />
|
||||
</button>
|
||||
</template>
|
||||
Reference in New Issue
Block a user