Skip to content

Commit

Permalink
Better DX for RichText block/renderer types
Browse files Browse the repository at this point in the history
  • Loading branch information
CarsonF committed Oct 2, 2024
1 parent 7d22d90 commit 2a21319
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 20 deletions.
35 changes: 22 additions & 13 deletions src/components/RichText/RichTextView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,24 @@ import type { OutputData as RichTextData } from '@editorjs/editorjs';
import { Divider, Typography } from '@mui/material';
import Blocks from 'editorjs-blocks-react-renderer';
import HTMLReactParser from 'html-react-parser';
import { memo, ReactElement, useMemo } from 'react';
import { ToolKey } from './editorJsTools';
import { ComponentType, memo, useMemo } from 'react';
import { BlockDataMap, ToolKey } from './editorJsTools';

export type RichTextRenderers = { [K in ToolKey]?: RenderFn<any> };
export type Renderers = {
[K in ToolKey]?: ComponentType<BlockProps<K>>;
};

export type RenderFn<T = undefined> = (_: { data?: T }) => ReactElement;
export interface BlockProps<K extends ToolKey> {
data?: K extends keyof BlockDataMap ? BlockDataMap[K] : never;
className?: string;
}

export const RichTextView = memo(function RichTextView({
data,
renderers: renderersInput,
}: {
data?: RichTextData | null;
renderers?: RichTextRenderers;
renderers?: Renderers;
}) {
const renderers = useMemo(
() => ({ ...defaultRenderers, ...renderersInput }),
Expand All @@ -24,23 +29,27 @@ export const RichTextView = memo(function RichTextView({
return null;
}
const data1 = { version: '0', time: 0, ...data };
return <Blocks data={data1} renderers={renderers} />;
return (
<Blocks
data={data1}
// @ts-expect-error our types are stricter
renderers={renderers}
/>
);
});

const ParagraphBlock: RenderFn<{ text: string }> = ({ data }) => (
const ParagraphBlock = ({ data }: BlockProps<'paragraph'>) => (
<Typography paragraph>
<Text data={data} />
</Typography>
);

export const Text: RenderFn<{ text: string }> = ({ data }) => {
export const Text = ({ data }: BlockProps<'paragraph'>) => {
const { text } = data ?? {};
return <>{text && HTMLReactParser(text)}</>;
};

const HeaderBlock: RenderFn<{ text: string; level: 1 | 2 | 3 | 4 | 5 | 6 }> = ({
data,
}) => {
const HeaderBlock = ({ data }: BlockProps<'header'>) => {
const { text, level = 1 } = data ?? {};
return (
<Typography variant={`h${level}`} gutterBottom>
Expand All @@ -49,9 +58,9 @@ const HeaderBlock: RenderFn<{ text: string; level: 1 | 2 | 3 | 4 | 5 | 6 }> = ({
);
};

const DelimiterBlock: RenderFn = () => <Divider sx={{ my: 2 }} />;
const DelimiterBlock = () => <Divider sx={{ my: 2 }} />;

const defaultRenderers: RichTextRenderers = {
const defaultRenderers: Renderers = {
paragraph: ParagraphBlock,
header: HeaderBlock,
delimiter: DelimiterBlock,
Expand Down
6 changes: 6 additions & 0 deletions src/components/RichText/editorJsTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,9 @@ export type ToolKey = keyof typeof EDITOR_JS_TOOLS;

export const customTools = (toolsNames: ToolKey[]) =>
pick(EDITOR_JS_TOOLS, toolsNames);

export interface BlockDataMap {
paragraph: { text: string };
header: { text: string; level: 1 | 2 | 3 | 4 | 5 | 6 };
list: { style: 'unordered' | 'ordered'; items: string[] };
}
12 changes: 5 additions & 7 deletions src/scenes/Dashboard/ProgressReportsWidget/RichTextCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {
} from '@mui/x-data-grid';
import { extendSx, RichTextJson, StyleProps } from '~/common';
import {
RenderFn,
RichTextRenderers,
BlockProps,
Renderers,
RichTextView,
Text,
} from '../../../components/RichText';
Expand Down Expand Up @@ -52,15 +52,13 @@ export const RichTextCell = ({
);
};

const ParagraphBlock: RenderFn<{ text: string }> = ({ data }) => (
const ParagraphBlock = ({ data }: BlockProps<'paragraph'>) => (
<Typography variant="body2" paragraph>
<Text data={data} />
</Typography>
);

const List: RenderFn<{ style: 'unordered' | 'ordered'; items: string[] }> = ({
data,
}) => {
const List = ({ data }: BlockProps<'list'>) => {
// eslint-disable-next-line react/jsx-no-useless-fragment
if (!data) return <></>;
const { style, items } = data;
Expand Down Expand Up @@ -90,7 +88,7 @@ const List: RenderFn<{ style: 'unordered' | 'ordered'; items: string[] }> = ({
);
};

const renderers: RichTextRenderers = {
const renderers: Renderers = {
paragraph: ParagraphBlock,
list: List,
};

0 comments on commit 2a21319

Please sign in to comment.