mirror of
https://github.com/facebook/docusaurus.git
synced 2025-06-02 02:42:41 +02:00
fix(v2): Fix announcementBar layout shifts (#5040)
* Fix announcementBar layout shift * useAnnouncementBar should return correct state after hydration * refactor announcementBar => move utils to theme-common * restore previous announcementBar * typo
This commit is contained in:
parent
814455f88e
commit
9916a0b4a4
11 changed files with 179 additions and 110 deletions
|
@ -0,0 +1,115 @@
|
|||
/**
|
||||
* 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,
|
||||
useEffect,
|
||||
useCallback,
|
||||
useMemo,
|
||||
ReactNode,
|
||||
useContext,
|
||||
createContext,
|
||||
} from 'react';
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
import {createStorageSlot} from './storageUtils';
|
||||
import {useThemeConfig} from './useThemeConfig';
|
||||
|
||||
export const AnnouncementBarDismissStorageKey =
|
||||
'docusaurus.announcement.dismiss';
|
||||
const AnnouncementBarIdStorageKey = 'docusaurus.announcement.id';
|
||||
|
||||
const AnnouncementBarDismissStorage = createStorageSlot(
|
||||
AnnouncementBarDismissStorageKey,
|
||||
);
|
||||
const IdStorage = createStorageSlot(AnnouncementBarIdStorageKey);
|
||||
|
||||
const isDismissedInStorage = () =>
|
||||
AnnouncementBarDismissStorage.get() === 'true';
|
||||
const setDismissedInStorage = (bool: boolean) =>
|
||||
AnnouncementBarDismissStorage.set(String(bool));
|
||||
|
||||
type AnnouncementBarAPI = {
|
||||
readonly isClosed: boolean;
|
||||
readonly close: () => void;
|
||||
};
|
||||
|
||||
const useAnnouncementBarContextValue = (): AnnouncementBarAPI => {
|
||||
const {announcementBar} = useThemeConfig();
|
||||
const {isClient} = useDocusaurusContext();
|
||||
|
||||
const [isClosed, setClosed] = useState(() => {
|
||||
return isClient
|
||||
? // On client navigation: init with localstorage value
|
||||
isDismissedInStorage()
|
||||
: // On server/hydration: always visible to prevent layout shifts (will be hidden with css if needed)
|
||||
false;
|
||||
});
|
||||
// Update state after hydration
|
||||
useEffect(() => {
|
||||
setClosed(isDismissedInStorage());
|
||||
}, []);
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
setDismissedInStorage(true);
|
||||
setClosed(true);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!announcementBar) {
|
||||
return;
|
||||
}
|
||||
const {id} = announcementBar;
|
||||
|
||||
let viewedId = IdStorage.get();
|
||||
|
||||
// retrocompatibility due to spelling mistake of default id
|
||||
// see https://github.com/facebook/docusaurus/issues/3338
|
||||
if (viewedId === 'annoucement-bar') {
|
||||
viewedId = 'announcement-bar';
|
||||
}
|
||||
|
||||
const isNewAnnouncement = id !== viewedId;
|
||||
|
||||
IdStorage.set(id);
|
||||
|
||||
if (isNewAnnouncement) {
|
||||
setDismissedInStorage(false);
|
||||
}
|
||||
|
||||
if (isNewAnnouncement || !isDismissedInStorage()) {
|
||||
setClosed(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return useMemo(() => {
|
||||
return {
|
||||
isClosed,
|
||||
close: handleClose,
|
||||
};
|
||||
}, [isClosed]);
|
||||
};
|
||||
|
||||
const AnnouncementBarContext = createContext<AnnouncementBarAPI | null>(null);
|
||||
|
||||
export const AnnouncementBarProvider = ({children}: {children: ReactNode}) => {
|
||||
const value = useAnnouncementBarContextValue();
|
||||
return (
|
||||
<AnnouncementBarContext.Provider value={value}>
|
||||
{children}
|
||||
</AnnouncementBarContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useAnnouncementBar = (): AnnouncementBarAPI => {
|
||||
const api = useContext(AnnouncementBarContext);
|
||||
if (!api) {
|
||||
throw new Error(
|
||||
'useAnnouncementBar(): AnnouncementBar not found in React context: make sure to use the AnnouncementBarProvider on top of the tree',
|
||||
);
|
||||
}
|
||||
return api;
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue