import { createContext, useContext, useRef } from 'react'; import { shallow } from 'zustand/shallow'; import { createWithEqualityFn } from 'zustand/traditional'; import type { PersistStoreProps, PersistStoreProviderProps } from '../types.js'; import type { HeaderState, HeaderStore } from './types.js'; export const HeaderStoreContext = createContext(null); export function HeaderStoreProvider({ children, ...props }: PersistStoreProviderProps) { const storeRef = useRef(); if (!storeRef.current) { storeRef.current = createHeaderStore(props); } return ( {children} ); } export function useHeaderStoreContext() { const useStore = useContext(HeaderStoreContext); if (!useStore) { throw new Error( `You forgot to wrap your component in <${HeaderStoreProvider.name}>.`, ); } return useStore; } export function useHeaderStore( selector: (state: HeaderState) => T, equalityCheck?: (objA: T, objB: T) => boolean, ): T { const useStore = useHeaderStoreContext(); return useStore(selector, equalityCheck); } // We use fixed position on the header when Widget is in Full Height layout. // We do this to get it to work like the sticky header does in the other layout modes. // As the header is position fixed its not in the document flow anymore. // To prevent the remaining page content from appearing behind the header we need to // pass the headers height so that the position of the page content can be adjusted export function useHeaderHeight() { const [headerHeight] = useHeaderStore( (state) => [state.headerHeight], shallow, ); return { headerHeight, }; } export function useSetHeaderHeight() { const [setHeaderHeight] = useHeaderStore( (state) => [state.setHeaderHeight], shallow, ); return { setHeaderHeight, }; } export const createHeaderStore = ({ namePrefix }: PersistStoreProps) => createWithEqualityFn( (set, get) => ({ headerHeight: 108, element: null, title: undefined, setAction: (element) => { // Use Promise.resolve().then to batch updates Promise.resolve().then(() => { set(() => ({ element })); }); return () => get().removeAction(); }, setTitle: (title) => { Promise.resolve().then(() => { set(() => ({ title })); }); return () => get().removeTitle(); }, removeAction: () => { Promise.resolve().then(() => { set(() => ({ element: null })); }); }, removeTitle: () => { Promise.resolve().then(() => { set(() => ({ title: undefined })); }); }, setHeaderHeight: (headerHeight) => { Promise.resolve().then(() => { set(() => ({ headerHeight })); }); }, }), Object.is, );