import React from 'react'; function slotHandler(props: React.PropsWithChildren<any>): JSX.Element { return <>{props.children}</>; } export function initSlot(template?: (props?: any) => React.ReactElement) { if (template !== undefined) { return template.bind({}); } return slotHandler.bind({}); } export function filterForSlot( nodes: React.ReactElement | React.ReactElement[], type: any ): React.ReactNode | React.ReactNode[] { if ( nodes !== null && nodes !== undefined && 'type' in nodes && nodes.type === type ) { return nodes; } if (nodes !== null && nodes !== undefined && 'find' in nodes) { const items = nodes.filter((child: React.ReactNode): boolean => { if ( typeof child !== 'string' && typeof child !== 'number' && typeof child !== 'boolean' && child !== null && child !== undefined && 'type' in child ) { return child.type === type; } return false; }); return items; } return false; } interface SlotProps { type: React.ReactNode; } export class Slot extends React.Component<SlotProps, {}> { render() { const items: React.ReactNode | React.ReactNode[] = filterForSlot( // @ts-ignore this.props.children, this.props.type ); if ( typeof items !== 'string' && typeof items !== 'number' && typeof items !== 'boolean' && items !== null && items !== undefined ) { if ('map' in items) { return items.map((item: React.ReactNode, index: number) => { // eslint-disable-next-line react/no-array-index-key return <React.Fragment key={index}>{item}</React.Fragment>; }); } return <>{items && 'props' in items ? items.props.children : null}</>; } return <></>; } }
import { Component } from 'react'; import { initSlot, Slot } from './slots.tsx'; export class Layout extends Component<{}, {}> { static Main = initSlot(); static Side = initSlot(); render() { return ( <div> <div className={"main"}> <Slot type={MainContentContainer.Main} children={this.props.children} /> </div> <div className={"side"}> <Slot type={MainContentContainer.Side} children={this.props.children} /> </div> </div> ); } }
import { Component } from 'react'; import {Layout} from './layout.tsx'; export class MyApp extends Component<{}, {}> { static Main = initSlot(); static Side = initSlot(); render() { return ( <Layout> <Layout.Main>Will render in main slot</Layout.Main> <Layout.Side>And this on in the side slot</Layout.Side> </Layout> ) } }
dx, react — Aug 20, 2021