From a088d83e43068c8c787e14f6707605ffa71fd66e Mon Sep 17 00:00:00 2001 From: Justin Bennett Date: Mon, 18 May 2020 08:47:24 -0400 Subject: [PATCH 1/2] Groups list items together so that their markup structure will be correct --- src/block.tsx | 37 +++++++++---------------- src/renderer.tsx | 35 ++++++++++++++++++------ src/utils.ts | 8 ------ src/utils.tsx | 70 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 41 deletions(-) delete mode 100644 src/utils.ts create mode 100644 src/utils.tsx diff --git a/src/block.tsx b/src/block.tsx index f1776ba..352d371 100644 --- a/src/block.tsx +++ b/src/block.tsx @@ -51,7 +51,7 @@ interface Block { } export const Block: React.FC = props => { - const { block, parentBlock, children } = props; + const { block, children } = props; const blockValue = block?.value; switch (blockValue.type) { case "page": @@ -90,33 +90,20 @@ export const Block: React.FC = props => { ); case "bulleted_list": case "numbered_list": - const isTopLevel = block.value.type !== parentBlock.value.type; - - const wrapList = (content: React.ReactNode) => - blockValue.type === "bulleted_list" ? ( -
    {content}
- ) : ( -
    {content}
- ); - let output: JSX.Element | null = null; - if (blockValue.content) { - output = ( - <> - {blockValue.properties && ( -
  • {renderChildText(blockValue.properties.title)}
  • - )} - {wrapList(children)} - - ); - } else { - output = blockValue.properties ? ( -
  • {renderChildText(blockValue.properties.title)}
  • - ) : null; - } + output = blockValue.properties ? ( + <> +
  • + {renderChildText(blockValue.properties.title)} + {children} +
  • + + ) : ( + <>{React.Children.count(children) > 0 &&
  • {children}
  • } + ); - return isTopLevel ? wrapList(output) : output; + return output; case "image": case "embed": diff --git a/src/renderer.tsx b/src/renderer.tsx index fb06b18..2e4bf9e 100644 --- a/src/renderer.tsx +++ b/src/renderer.tsx @@ -1,6 +1,7 @@ import React from "react"; import { BlockMapType } from "./types"; import { Block } from "./block"; +import { reduceBlockGroups, BlockGroup } from "./utils"; interface NotionRendererProps { blockMap: BlockMapType; @@ -24,14 +25,32 @@ export const NotionRenderer: React.FC = ({ block={currentBlock} parentBlock={parentBlock} > - {currentBlock?.value?.content?.map(contentId => ( - - ))} + {currentBlock?.value?.content + ?.reduce>( + reduceBlockGroups(blockMap, level), + [] + ) + .map(contentIdOrGroup => + typeof contentIdOrGroup === "string" ? ( + + ) : ( + + {contentIdOrGroup.blockIds.map(contentId => ( + + ))} + + ) + )}
    ); }; diff --git a/src/utils.ts b/src/utils.ts deleted file mode 100644 index dacb804..0000000 --- a/src/utils.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { DecorationType } from "./types"; - -export const classNames = (...classes: Array) => - classes.filter(a => !!a).join(" "); - -export const getTextContent = (text: DecorationType[]) => { - return text.reduce((prev, current) => prev + current[0], ""); -}; diff --git a/src/utils.tsx b/src/utils.tsx new file mode 100644 index 0000000..5545afb --- /dev/null +++ b/src/utils.tsx @@ -0,0 +1,70 @@ +import { DecorationType, BlockValueType, BlockMapType } from "./types"; +import React, { ComponentType } from "react"; + +export const classNames = (...classes: Array) => + classes.filter(a => !!a).join(" "); + +export const getTextContent = (text: DecorationType[]) => { + return text.reduce((prev, current) => prev + current[0], ""); +}; + +export interface BlockGroup { + type: BlockValueType["type"]; + wrapper: string | ComponentType; + blockIds: string[]; + level: number; +} + +const groupedTypes = ["bulleted_list", "numbered_list"]; +export const reduceBlockGroups = (blockMap: BlockMapType, level: number) => ( + contentIdList: Array, + currentId: string +) => { + const currentType = blockMap[currentId]?.value?.type; + if (!groupedTypes.includes(currentType)) { + contentIdList.push(currentId); + return contentIdList; + } + let wrapper: ComponentType; + switch (currentType) { + case "numbered_list": + wrapper = (props: any) => ( +
      + ); + break; + case "bulleted_list": + wrapper = (props: any) => ( +
        + ); + break; + default: + throw new Error(`Type ${currentType} has no specified wrapper`); + } + + const lastIdIndex = contentIdList.length - 1; + if (lastIdIndex < 0 || typeof contentIdList[lastIdIndex] === "string") { + contentIdList.push({ + type: currentType, + wrapper, + blockIds: [currentId], + level + }); + return contentIdList; + } + const lastContentIdListItem = contentIdList[lastIdIndex] as BlockGroup; + + if ( + lastContentIdListItem.type === currentType && + lastContentIdListItem.level === level + ) { + lastContentIdListItem.blockIds.push(currentId); + } else { + contentIdList.push({ + type: currentType, + wrapper, + blockIds: [currentId], + level + }); + } + return contentIdList; +}; From 374f90cabca2e2d472988a63e09c67826313c14f Mon Sep 17 00:00:00 2001 From: Justin Bennett Date: Mon, 18 May 2020 11:47:44 -0400 Subject: [PATCH 2/2] correct wrapper for unordered lists --- src/utils.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.tsx b/src/utils.tsx index 5545afb..e5f8bab 100644 --- a/src/utils.tsx +++ b/src/utils.tsx @@ -34,7 +34,7 @@ export const reduceBlockGroups = (blockMap: BlockMapType, level: number) => ( break; case "bulleted_list": wrapper = (props: any) => ( -
          +
            ); break; default: