mirror of
https://github.com/facebook/docusaurus.git
synced 2025-08-06 10:20:09 +02:00
fix(theme): refactor Tabs, make groupId + queryString work fine together (#8486)
This commit is contained in:
parent
949158d35b
commit
9c860ce419
12 changed files with 505 additions and 356 deletions
|
@ -1,89 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import React, {
|
||||
useState,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useContext,
|
||||
type ReactNode,
|
||||
} from 'react';
|
||||
import {createStorageSlot, listStorageKeys} from '../utils/storageUtils';
|
||||
import {ReactContextError} from '../utils/reactUtils';
|
||||
|
||||
const TAB_CHOICE_PREFIX = 'docusaurus.tab.';
|
||||
|
||||
type ContextValue = {
|
||||
/** A boolean that tells if choices have already been restored from storage */
|
||||
readonly ready: boolean;
|
||||
/** A map from `groupId` to the `value` of the saved choice. */
|
||||
readonly tabGroupChoices: {readonly [groupId: string]: string};
|
||||
/** Set the new choice value of a group. */
|
||||
readonly setTabGroupChoices: (groupId: string, newChoice: string) => void;
|
||||
};
|
||||
|
||||
const Context = React.createContext<ContextValue | undefined>(undefined);
|
||||
|
||||
function useContextValue(): ContextValue {
|
||||
const [ready, setReady] = useState(false);
|
||||
const [tabGroupChoices, setChoices] = useState<{
|
||||
readonly [groupId: string]: string;
|
||||
}>({});
|
||||
const setChoiceSyncWithLocalStorage = useCallback(
|
||||
(groupId: string, newChoice: string) => {
|
||||
createStorageSlot(`${TAB_CHOICE_PREFIX}${groupId}`).set(newChoice);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
const localStorageChoices: {[groupId: string]: string} = {};
|
||||
listStorageKeys().forEach((storageKey) => {
|
||||
if (storageKey.startsWith(TAB_CHOICE_PREFIX)) {
|
||||
const groupId = storageKey.substring(TAB_CHOICE_PREFIX.length);
|
||||
localStorageChoices[groupId] = createStorageSlot(storageKey).get()!;
|
||||
}
|
||||
});
|
||||
setChoices(localStorageChoices);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
setReady(true);
|
||||
}, []);
|
||||
|
||||
const setTabGroupChoices = useCallback(
|
||||
(groupId: string, newChoice: string) => {
|
||||
setChoices((oldChoices) => ({...oldChoices, [groupId]: newChoice}));
|
||||
setChoiceSyncWithLocalStorage(groupId, newChoice);
|
||||
},
|
||||
[setChoiceSyncWithLocalStorage],
|
||||
);
|
||||
|
||||
return useMemo(
|
||||
() => ({ready, tabGroupChoices, setTabGroupChoices}),
|
||||
[ready, tabGroupChoices, setTabGroupChoices],
|
||||
);
|
||||
}
|
||||
|
||||
export function TabGroupChoiceProvider({
|
||||
children,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
}): JSX.Element {
|
||||
const value = useContextValue();
|
||||
return <Context.Provider value={value}>{children}</Context.Provider>;
|
||||
}
|
||||
|
||||
export function useTabGroupChoice(): ContextValue {
|
||||
const context = useContext(Context);
|
||||
if (context == null) {
|
||||
throw new ReactContextError('TabGroupChoiceProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue