|
| 1 | +import type { InjectionKey, Ref } from 'vue' |
| 2 | +import { computed, inject, onMounted, ref } from 'vue' |
| 3 | + |
| 4 | +type TabsSharedState = { |
| 5 | + content?: TabsSharedStateContent |
| 6 | +} |
| 7 | +type TabsSharedStateContent = Record<string, string> |
| 8 | + |
| 9 | +// Use the same injection key as the original vitepress-plugin-tabs |
| 10 | +const injectionKey: InjectionKey<TabsSharedState> = |
| 11 | + 'vitepress:tabSharedState' as unknown as symbol |
| 12 | +const ls = typeof localStorage !== 'undefined' ? localStorage : null |
| 13 | +const localStorageKey = 'vitepress:tabsSharedState' |
| 14 | + |
| 15 | +const getLocalStorageValue = (): TabsSharedStateContent => { |
| 16 | + const rawValue = ls?.getItem(localStorageKey) |
| 17 | + if (rawValue) { |
| 18 | + try { |
| 19 | + return JSON.parse(rawValue) |
| 20 | + } catch {} |
| 21 | + } |
| 22 | + return {} |
| 23 | +} |
| 24 | + |
| 25 | +export const useTabsSelectedState = <T extends string>( |
| 26 | + acceptValues: Ref<T[]>, |
| 27 | + sharedStateKey: Ref<string | undefined>, |
| 28 | +) => { |
| 29 | + const sharedState = inject(injectionKey) |
| 30 | + if (!sharedState) { |
| 31 | + throw new Error( |
| 32 | + '[vitepress-plugin-tabs] TabsSharedState should be injected', |
| 33 | + ) |
| 34 | + } |
| 35 | + |
| 36 | + onMounted(() => { |
| 37 | + if (!sharedState.content) { |
| 38 | + sharedState.content = getLocalStorageValue() |
| 39 | + } |
| 40 | + }) |
| 41 | + |
| 42 | + const nonSharedState = ref<T | undefined>() |
| 43 | + |
| 44 | + const selected = computed({ |
| 45 | + get() { |
| 46 | + const key = sharedStateKey.value |
| 47 | + const acceptVals = acceptValues.value |
| 48 | + if (key) { |
| 49 | + const value = sharedState.content?.[key] |
| 50 | + if (value && (acceptVals as string[]).includes(value)) { |
| 51 | + return value as T |
| 52 | + } |
| 53 | + } else { |
| 54 | + const nonSharedStateVal = nonSharedState.value |
| 55 | + if (nonSharedStateVal) { |
| 56 | + return nonSharedStateVal |
| 57 | + } |
| 58 | + } |
| 59 | + return acceptVals[0] |
| 60 | + }, |
| 61 | + set(v) { |
| 62 | + const key = sharedStateKey.value |
| 63 | + if (key) { |
| 64 | + if (sharedState.content) { |
| 65 | + sharedState.content[key] = v |
| 66 | + } |
| 67 | + } else { |
| 68 | + nonSharedState.value = v |
| 69 | + } |
| 70 | + }, |
| 71 | + }) |
| 72 | + |
| 73 | + const select = (newValue: T) => { |
| 74 | + selected.value = newValue |
| 75 | + } |
| 76 | + |
| 77 | + return { selected, select } |
| 78 | +} |
0 commit comments