You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
51 lines
1.4 KiB
51 lines
1.4 KiB
import type { ReactElement } from 'react'; |
|
import { createContext, useContext, useMemo, useState } from 'react'; |
|
import { createPortal } from 'react-dom'; |
|
|
|
export const ColumnsContext = createContext<{ |
|
tabsBarElement: HTMLElement | null; |
|
setTabsBarElement: (element: HTMLElement) => void; |
|
multiColumn: boolean; |
|
}>({ |
|
tabsBarElement: null, |
|
multiColumn: false, |
|
setTabsBarElement: () => undefined, // no-op |
|
}); |
|
|
|
export function useColumnsContext() { |
|
return useContext(ColumnsContext); |
|
} |
|
|
|
export const ButtonInTabsBar: React.FC<{ |
|
children: ReactElement | string | undefined; |
|
}> = ({ children }) => { |
|
const { multiColumn, tabsBarElement } = useColumnsContext(); |
|
|
|
if (multiColumn) { |
|
return children; |
|
} else if (!tabsBarElement) { |
|
return children; |
|
} else { |
|
return createPortal(children, tabsBarElement); |
|
} |
|
}; |
|
|
|
type ContextValue = React.ContextType<typeof ColumnsContext>; |
|
|
|
export const ColumnsContextProvider: React.FC< |
|
React.PropsWithChildren<{ multiColumn: boolean }> |
|
> = ({ multiColumn, children }) => { |
|
const [tabsBarElement, setTabsBarElement] = |
|
useState<ContextValue['tabsBarElement']>(null); |
|
|
|
const contextValue = useMemo<ContextValue>( |
|
() => ({ multiColumn, tabsBarElement, setTabsBarElement }), |
|
[multiColumn, tabsBarElement], |
|
); |
|
|
|
return ( |
|
<ColumnsContext.Provider value={contextValue}> |
|
{children} |
|
</ColumnsContext.Provider> |
|
); |
|
};
|
|
|