Skip to main content

@modular-component/with-components

Provides a with(components) stage that fills the components argument with a map of React components. Useful when running tests in an environment that does not allow module mocking: sub-components can be stubbed in tests by mocking the stage to replace their implementations.

Usage

import { ModularComponent } from '@modular-component/core'
import { components } from '@modular-component/with-components'

import { SomeComponent } from 'some-component'

const MyComponent = ModularComponent()
.with(components({ SomeComponent }))
.with(render(({ props, components }) => (
<components.SomeComponent />
)))

Replacing sub-components

Replacing sub-components can be done either by updating or mocking the stage. It allows creating a clone of the component with a different sub-component implementation, either for tests or for content. For instance, one could imagine a Layout base component taking advantage of this functionality:

const PageLayout = ModularComponent()
.with(components({
Title: React.Fragment,
Subtitle: React.Fragment,
Content: React.Fragment,
Footer: React.Fragment
}))
.with(render(({ components }) => (
// Build a layout using <components.Title />, <components.Subtitle />...
)))

const PageOne = PageLayout.with(components({
Title: () => <>First page</>,
Subtitle: () => <>I have a subtitle but no footer</>,
Content: () => <>First page content</>,
Footer: React.Fragment
}))

const PageTwo = PageLayout.with(components({
Title: () => <>Second page</>,
Subtitle: React.Fragment,
Content: () => <>Second page content</>,
Footer: () => <>I have a footer but no subtitle</>
}))

Implementation

with(components) is a simple stage adding the provided record as a components argument. It has a restriction on accepted values, to only accept a record of React components.

import { ComponentType } from 'react'
import { ModularStage } from '@modular-component/core'

export function components<Components extends Record<string, ComponentType>>(
components: Components,
): ModularStage<'components', () => Components> {
return { field: 'components', useStage: () => components }
}