import * as React from 'react' import { Conditional, cn, merge } from '@maker-ui/utils' import { Skiplinks, Header, Footer, Topbar, MobileMenu, Main, Sidebar, Panel, defaultSettings, type MakerUIOptions, type Options, type MenuItemProps, type LayoutButtonProps, type PanelProps, } from '@maker-ui/layout-server' import { Menu, MenuButton, LayoutSettings } from '@maker-ui/layout-client' interface LayoutProps { /** You can use Layout dot children to build layouts with JSX */ children?: React.ReactNode /** A valid Maker UI Options configuration object */ options?: MakerUIOptions /** Allows you to nest multiple different layouts without re-rerendering container components */ fragment?: boolean } function isMenu(i: any): i is MenuItemProps[] { return !!(i && typeof i[0] === 'object' && i[0].label) } function isIcon(i: any): i is LayoutButtonProps { return !!(i && typeof i === 'object' && ('icon' in i || 'defaultIcon' in i)) } const LeftPanel = (props: PanelProps) => LeftPanel.defaultProps = { _type: 'leftPanel' } const RightPanel = (props: PanelProps) => RightPanel.defaultProps = { _type: 'rightPanel' } /** * This function sorts all Layout dot children into an object with corresponding keys. * We use this to merge JSX with the slots prop and MakerUIOptions. */ function assign(children: React.ReactNode) { let c: { [k: string]: any } = {} let layout = 'content' React.Children.toArray(children).forEach((child: any) => { const type = child.props._type if (type) { c[type] = child } else { c['children'] = child } }) if (c.leftPanel && !c?.rightPanel) layout = 'left-content' if (c.rightPanel && !c?.leftPanel) layout = 'content-right' if (c.leftPanel && c.rightPanel) layout = 'left-content-right' return { slots: c, layoutType: layout } } /** * Wrap your application in the `Layout` component to use Maker UI. * * @link https://maker-ui.com/docs/layout/layout */ export const Layout = ({ options = {}, fragment = false, children, }: LayoutProps) => { const opts = merge(defaultSettings, options) as Options const { slots, layoutType } = assign(children) // Helpers const isPanel = !!(slots.leftPanel || slots.rightPanel) const isSidebar = !!slots.sidebar const dir = opts?.content?.sidebar || 'left' /** * Merged and formatted props for the Header component. */ const headerProps = merge(opts.header, { ...slots?.header?.props, menu: isMenu(slots?.header?.props?.menu) ? ( ) : ( slots?.header?.props?.menu ), menuSplit: isMenu(slots?.header?.props?.menuSplit) ? ( ) : ( slots?.header?.props?.menuSplit ), menuButton: isIcon(slots?.header?.props?.menuButton) ? ( ) : ( slots?.header?.props?.menuButton ), }) /** * Merged and formatted props for the MobileMenu component. */ const mobileMenuProps = merge(opts.mobileMenu, { ...slots?.mobileMenu?.props, closeButton: isIcon(slots?.mobileMenu?.props?.closeButton) ? ( ) : ( slots?.mobileMenu?.props?.closeButton ), children: isMenu(slots?.mobileMenu?.props?.menu) ? ( ) : ( slots?.mobileMenu?.props?.children ), }) /** * Merged and formatted props for the Left Panel. */ const leftProps = merge(opts.leftPanel || {}, { ...slots?.leftPanel?.props, menuButton: isIcon(slots?.leftPanel?.props?.menuButton) ? ( ) : ( slots?.leftPanel?.menuButton ), }) /** * Merged and formatted props for the Right Panel. */ const rightProps = merge(opts.rightPanel || {}, { ...slots?.rightPanel?.props, menuButton: isIcon(slots?.rightPanel?.props?.menuButton) ? ( ) : ( slots?.rightPanel?.menuButton ), }) return ( <> {(fragment && options) || slots?.settings ? ( ) : null} {!fragment && } {slots?.topbar && } {slots?.header ? (
: null } /> ) : null} {slots?.children || (
{isPanel &&
} {slots?.leftPanel && } (
{c}
)}>
{slots?.rightPanel && }
)} {slots?.footer &&