@atomic-design/di
v0.1.3
Published
Lightweight, type-safe dependency inversion utilities for Atomic Design architectures in React
Maintainers
Readme
@atomic-design/di
Dependency Injection utilities for Atomic Design contexts in React.
Overview
@atomic-design/di provides a lightweight, type-safe dependency injection system tailored for Atomic Design architectures. It enables:
- Context-based injection of styles, atoms, molecules, and custom services into React components.
- Named variants: Swap implementations at runtime (e.g., feature flags, themes).
- Server-ready components: Support for SSR/CSR via React Server Components and Suspense.
- Automatic dependency wiring: Components don’t need manual prop drilling for shared dependencies.
Installation
npm install @atomic-design/di
# or
yarn add @atomic-design/diKey Concepts
Spaces & Variants
- Space: A logical group of dependencies (e.g.,
styles,atoms,molecules, or your own service spaces). - Variant: A named version of a space (e.g.,
default,v1,v2) that can provide different implementations.
Hooks & Providers
useAtomic(): Hook to access the merged dependencies for the current React tree.AtomicProvider: React component to set variants for a subtree.getServerReadyComponent(space, name): Wraps a component for server rendering without needingdepsprop.
Automatic Injection
extractComponentDeps(): Wraps a set of components so they automatically receive adepsprop from context.blankDeps(): Utility to create a stub dependency context (useful for testing or simple values).
Usage
Creating a Variants Context
import { createVariantsContext, extractComponentDeps, blankDeps } from '@atomic-design/di';
import { usePathname } from 'next/navigation';
// Define how each space is loaded (async or sync)
const atomicContext = {
styles: async () => blankDeps((await import('@atomic-design/styles-base')).stylesContext.styles),
atoms: async () => extractComponentDeps((await import('@atomic-design/atoms-base')).atomsContext.atoms),
molecules: async () => extractComponentDeps((await import('@atomic-design/molecules-base')).moleculesContext.molecules),
// Custom helper space
moleculesHelpers: () => blankDeps({
useIsActiveLink: (href?: string) => {
const pathname = usePathname() || '/';
return href ? (href === '/' ? pathname === href : pathname.startsWith(href)) : false;
}
})
};
// Optional variants for a custom "contextName" space
const variantsBySpace = {
contextName: {
v1: () => blankDeps('Variant 1'),
v2: () => blankDeps('Variant 2'),
}
};
const [useAtomic, AtomicProvider, getServerReadyComponent] =
createVariantsContext(atomicContext, variantsBySpace);Providing Variants
<AtomicProvider space="contextName" variant="v1">
<App />
</AtomicProvider>You can nest multiple providers to switch variants for subtrees.
Using Dependencies in Components
import React from 'react';
function MyButton(props) {
const { atoms: { Button } } = useAtomic();
return <Button {...props}>Click me</Button>;
}Server-Ready Components
Instead of manually wiring deps, you can export:
export const Link = getServerReadyComponent('molecules', 'Link');Then in your UI code:
<Link href="/about">About us</Link>API Reference
createVariantsContext(context, variantsBySpace)
context: Record of space loaders (() => WrappedPromise<Context, AllSpaces>).variantsBySpace: Optional record defining named variants per space.
Returns: [useAtomic, AtomicProvider, getServerReadyComponent]
extractComponentDeps(components)
Wraps components so each receives deps automatically from the nearest AtomicProvider.
components: Object mapping names to React components expecting adepsprop.
Returns: { output: wrappedComponents, setDepsHook }
blankDeps(output)
Creates a stub context with a fixed output and no-op setDepsHook.
Contributing
- Fork the repo.
- Create your feature branch:
git checkout -b feature/foo. - Commit your changes.
- Push to the branch.
- Open a Pull Request.
Please follow existing code conventions (TypeScript, React JSX, ESLint, Prettier).
