Interface 1.2+ Directives
Use directives to to pass values to upper contexts using JSX components.
Directives are React components that can be used to pass values to upper contexts
just by rendering <Directive>
components and specifying the name and content.
Similar to slots that give you a way to escape from the tied page layout, directives give you a way to escape from the tied page behavior.
In most cases you can use it to control your app from within the page to direct it what to do (hence the name), e.g. when you need some pages to stretch to the full width of the screen.
Creating Directives
To create a directive, you need to use the createDirectiveContext
factory function.
import { Directives } from '@contember/layout';
export type DirectivesType = {
'full-width': boolean
}
export const initialDirectives: DirectivesType = {
'full-width': false,
}
// Local export with current DirectivesType specific to the project
export const Directive = Directives.Directive as unknown as Directives.DirectiveComponentType<DirectivesType>
// Local export with current DirectivesType specific to the project
export const useDirectives = Directives.useDirectives<DirectivesType>
To make the usage of directives easier, you can create a shorthand component.
For example, you can create a FullWidth
component that will render the Directive
that will set the full width directive to true
.
import { Directive } from './Directives'
export function FullWidth() {
return <Directive name={'full-width'} content={true} />
}
Setting values with a directive in the page
To use a directive that will push value to the parent context just render the Directive
component with the name
and content
props.
import * as React from 'react'
import { CommonSlots } from '@contember/layout'
import { Directive } from '../components/Directives'
export default () => (
<>
<Directive name="full-width" content={true} />
<p>Some content</p>
</>
)
Accessing the directive values
To use the directives in the layout, you need to use the useDirectives
hook.
import { useDirectives } from "../Directives"
export const Layout = ({ children: pages }: React.PropsWithChildren) => {
const directives = useDirectives()
return (
<div className={directives['full-width']
? "full-width"
: undefined
}>
{pages}
</div>
)
}
Caveats
You can use directives to control any aspect of your page at any nesting depth and you can render as many directives as you want, the last one rendered wins. This principle ensures the ability to override the value of a directive from within any nested component.
import * as React from 'react'
import { CommonSlots } from '@contember/layout'
import { Directive } from '../components/Directives'
export default () => (
<>
<Directive name="full-width" content={true} />
<p>Some content</p>
<div>
<p>Nested component</p>
<Directive name="full-width" content={false} />
</div>
</>
)
import { useDirectives } from "../Directives"
export const Layout = ({ children: pages }: React.PropsWithChildren) => {
const directives = useDirectives()
return (
<div className={directives['full-width']
? "full-width"
: undefined
}>
{pages}
</div>
)
}
The result is that the page will not be full width, because the directive from the nested component overrides the directive from the page.
Context Providers
Using directives is optional. Their respective providers are included in our project templates in the application entry point.
Once you decide to go your own way just remove the <Directives.Provider>
from the index.tsx
file.