Files
gitbook/packages/gitbook/src/components/DocumentView/Blocks.tsx
T
2025-03-25 15:13:18 +00:00

83 lines
2.4 KiB
TypeScript

import type { DocumentBlock, JSONDocument } from '@gitbook/api';
import { type ClassValue, tcls } from '@/lib/tailwind';
import { Block } from './Block';
import type { DocumentContextProps } from './DocumentView';
import { isBlockOffscreen } from './utils';
/**
* Renders a list of blocks with a wrapper element.
*/
export function Blocks<TBlock extends DocumentBlock, Tag extends React.ElementType = 'div'>(
props: UnwrappedBlocksProps<TBlock> & {
/** HTML tag to use for the wrapper */
tag?: Tag;
/** Style passed to the wrapper */
style?: ClassValue;
/** Props to pass to the wrapper element */
wrapperProps?: React.ComponentProps<Tag>;
}
) {
const { tag: Tag = 'div', style, wrapperProps, ...blocksProps } = props;
return (
<Tag {...wrapperProps} className={tcls(style)}>
<UnwrappedBlocks {...blocksProps} />
</Tag>
);
}
type UnwrappedBlocksProps<TBlock extends DocumentBlock> = DocumentContextProps & {
/** Blocks to render */
nodes: TBlock[];
/** Document being rendered */
document: JSONDocument;
/** Ancestors of the blocks */
ancestorBlocks: DocumentBlock[];
/** Style passed to all blocks */
blockStyle?: ClassValue;
/** True if all blocks should be considered offscreen */
isOffscreen?: boolean;
};
/**
* Renders a list of blocks without a wrapper element.
*/
export function UnwrappedBlocks<TBlock extends DocumentBlock>(props: UnwrappedBlocksProps<TBlock>) {
const { nodes, blockStyle, isOffscreen: defaultIsOffscreen = false, ...contextProps } = props;
let isOffscreen = defaultIsOffscreen;
return nodes.map((node, index) => {
isOffscreen =
isOffscreen ||
isBlockOffscreen({
document: props.document,
block: node,
ancestorBlocks: props.ancestorBlocks,
});
return (
<Block
key={node.key || `${node.type}-${index}`}
block={node}
style={[
'mx-auto w-full decoration-primary/6',
node.data && 'fullWidth' in node.data && node.data.fullWidth
? 'max-w-screen-xl'
: 'max-w-3xl',
blockStyle,
]}
isEstimatedOffscreen={isOffscreen}
{...contextProps}
/>
);
});
}