test02/node_modules/@vuepress/theme-default/lib/client/components/global/CodeGroup.js
罗佳鸿 6aa1ebe342
Some checks are pending
部署文档 / deploy-gh-pages (push) Waiting to run
first commit
2024-08-13 10:11:19 +08:00

122 lines
4.7 KiB
JavaScript

import { useStorage } from '@vueuse/core';
import { computed, defineComponent, h, onBeforeUpdate, onMounted, ref, watch, } from 'vue';
import '../../styles/code-group.scss';
export const CodeGroup = defineComponent({
name: 'CodeGroup',
slots: Object,
setup(_, { slots }) {
// refs of the tab buttons
const tabRefs = ref([]);
if (__VUEPRESS_DEV__) {
// in dev mode, we need to clear the tabs ref to avoid HMR issues
// after removing a code-group-item
onBeforeUpdate(() => {
tabRefs.value = [];
});
}
// index of current active item
const activeIndex = ref(-1);
const codeGroupStorage = useStorage('vuepress-code-group', {});
const codeGroupKey = computed(() => tabRefs.value.map((tab) => tab.innerText).join(','));
onMounted(() => {
watch(() => codeGroupStorage.value[codeGroupKey.value], (val = -1) => {
if (activeIndex.value !== val) {
activeIndex.value = val;
}
}, { immediate: true });
watch(activeIndex, (val) => {
if (codeGroupStorage.value[codeGroupKey.value] !== val) {
codeGroupStorage.value[codeGroupKey.value] = val;
}
});
});
// activate next tab
const activateNext = (i = activeIndex.value) => {
if (i < tabRefs.value.length - 1) {
activeIndex.value = i + 1;
}
else {
activeIndex.value = 0;
}
tabRefs.value[activeIndex.value].focus();
};
// activate previous tab
const activatePrev = (i = activeIndex.value) => {
if (i > 0) {
activeIndex.value = i - 1;
}
else {
activeIndex.value = tabRefs.value.length - 1;
}
tabRefs.value[activeIndex.value].focus();
};
// handle keyboard event
const keyboardHandler = (event, i) => {
if (event.key === ' ' || event.key === 'Enter') {
event.preventDefault();
activeIndex.value = i;
}
else if (event.key === 'ArrowRight') {
event.preventDefault();
activateNext(i);
}
else if (event.key === 'ArrowLeft') {
event.preventDefault();
activatePrev(i);
}
};
return () => {
// get children code-group-item from default slots
const items = (slots.default?.() || [])
.filter((vnode) => vnode.type.name === 'CodeGroupItem')
.map((vnode) => {
if (vnode.props === null) {
vnode.props = {};
}
return vnode;
});
// do not render anything if there is no code-group-item
if (items.length === 0) {
return null;
}
// if activeIndex is invalid
if (activeIndex.value < 0 || activeIndex.value > items.length - 1) {
// find the index of the code-group-item with `active` props
activeIndex.value = items.findIndex((vnode) => vnode.props.active === '' || vnode.props.active === true);
// if there is no `active` props on code-group-item, set the first item active
if (activeIndex.value === -1) {
activeIndex.value = 0;
}
}
// if activeIndex is valid
else {
// set the active item
items.forEach((vnode, i) => {
vnode.props.active = i === activeIndex.value;
});
}
return h('div', { class: 'code-group' }, [
h('div', { class: 'code-group-nav', role: 'tablist' }, items.map((vnode, i) => {
const isActive = i === activeIndex.value;
return h('button', {
ref: (element) => {
if (element) {
tabRefs.value[i] = element;
}
},
class: {
'code-group-nav-tab': true,
'active': isActive,
},
role: 'tab',
ariaSelected: isActive,
onClick: () => (activeIndex.value = i),
onKeydown: (e) => keyboardHandler(e, i),
}, vnode.props.title);
})),
items,
]);
};
},
});