Description
The idea is to make react-notion
more extensible by allowing users to optionally override individual components.
This is extremely useful in practice. For example, using next/link
within a Next.js app if you want to override all of the page link components (where Next.js does some fancy pre-fetching that's disabled if you just use normal <a>
tags). Or if you want to override all img
instances to use lazy loading. Or if you want to use a custom table component in the future. etc. etc.
Docz has a great implementation of this by @pedronauck. Here's links to their implementation and docs.
The idea is to add a single hook useNotionComponents
that uses React Context to get a component mapping that users can override via a NotionComponentsProvider
.
This would also solve #10 and deprecate #11 @josemussa because you could override the link
component and provide whatever default props you want.
I've already implemented this for notion2site.
Here's a quick overview of my implementation which is a slimmed down version of Docz's impl:
import * as React from 'react'
import { SFC, useContext, createContext } from 'react'
export interface NotionComponentsMap {
[key: string]: any
}
const DefaultLink: SFC = (props) => <a {...props} />
const defaultComponents: NotionComponentsMap = {
link: DefaultLink,
pageLink: DefaultLink
}
export interface ComponentsProviderProps {
components: NotionComponentsMap
}
const ctx = createContext<NotionComponentsMap>(defaultComponents)
export const NotionComponentsProvider: SFC<ComponentsProviderProps> = ({
components: themeComponents = {},
children
}) => (
<ctx.Provider value={{ ...defaultComponents, ...themeComponents }}>
{children}
</ctx.Provider>
)
export const useNotionComponents = (): NotionComponentsMap => {
return useContext(ctx)
}
And then in block.tsx
:
export const Block: React.FC<Block> = (props) => {
// ...
const components = useNotionComponents()
// ...
return (
<components.pageLink
className='notion-page-link'
href={mapPageUrl(blockValue.id)}
>
...
</components.pageLink
)
}
And here's how a user of react-notion
would configure this (optional):
import Link from 'next/link'
// ...
render() {
return (
<NotionComponentsProvider
components={{
pageLink: ({ href = '', ...rest }) => {
return (
<Link href='/[pageId'] as={href}>
<a {...rest} />
</Link>
)
}
}}
>
<NotionRenderer
blockMap={blockMap}
mapPageUrl={mapPageUrl}
fullPage
/>
</NotionComponentsProvider>
)
}