index.tsx 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import React, { forwardRef } from 'react';
  2. import { BlockCommonProps, BlockType } from '$app/interfaces';
  3. import PageBlock from '../PageBlock';
  4. import TextBlock from '../TextBlock';
  5. import HeadingBlock from '../HeadingBlock';
  6. import ListBlock from '../ListBlock';
  7. import CodeBlock from '../CodeBlock';
  8. import { TreeNode } from '@/appflowy_app/block_editor/view/tree_node';
  9. import { withErrorBoundary } from 'react-error-boundary';
  10. import { ErrorBoundaryFallbackComponent } from '../BlockList/BlockList.hooks';
  11. import { useBlockComponent } from './BlockComponet.hooks';
  12. const BlockComponent = forwardRef(
  13. (
  14. {
  15. node,
  16. renderChild,
  17. ...props
  18. }: { node: TreeNode; renderChild?: (_node: TreeNode) => React.ReactNode } & React.DetailedHTMLProps<
  19. React.HTMLAttributes<HTMLDivElement>,
  20. HTMLDivElement
  21. >,
  22. ref: React.ForwardedRef<HTMLDivElement>
  23. ) => {
  24. const { myRef, className, version, isSelected } = useBlockComponent({
  25. node,
  26. });
  27. const renderComponent = () => {
  28. let BlockComponentClass: (_: BlockCommonProps<TreeNode>) => JSX.Element | null;
  29. switch (node.type) {
  30. case BlockType.PageBlock:
  31. BlockComponentClass = PageBlock;
  32. break;
  33. case BlockType.TextBlock:
  34. BlockComponentClass = TextBlock;
  35. break;
  36. case BlockType.HeadingBlock:
  37. BlockComponentClass = HeadingBlock;
  38. break;
  39. case BlockType.ListBlock:
  40. BlockComponentClass = ListBlock;
  41. break;
  42. case BlockType.CodeBlock:
  43. BlockComponentClass = CodeBlock;
  44. break;
  45. default:
  46. break;
  47. }
  48. const blockProps: BlockCommonProps<TreeNode> = {
  49. version,
  50. node,
  51. };
  52. // eslint-disable-next-line @typescript-eslint/ban-ts-comment
  53. // @ts-ignore
  54. if (BlockComponentClass) {
  55. return <BlockComponentClass {...blockProps} />;
  56. }
  57. return null;
  58. };
  59. return (
  60. <div
  61. ref={(el: HTMLDivElement | null) => {
  62. myRef.current = el;
  63. if (typeof ref === 'function') {
  64. ref(el);
  65. } else if (ref) {
  66. ref.current = el;
  67. }
  68. }}
  69. {...props}
  70. data-block-id={node.id}
  71. data-block-selected={isSelected}
  72. className={props.className ? `${props.className} ${className}` : className}
  73. >
  74. {renderComponent()}
  75. {renderChild ? node.children.map(renderChild) : null}
  76. <div className='block-overlay'></div>
  77. {isSelected ? <div className='pointer-events-none absolute inset-0 z-[-1] rounded-[4px] bg-[#E0F8FF]' /> : null}
  78. </div>
  79. );
  80. }
  81. );
  82. const ComponentWithErrorBoundary = withErrorBoundary(BlockComponent, {
  83. FallbackComponent: ErrorBoundaryFallbackComponent,
  84. });
  85. export default React.memo(ComponentWithErrorBoundary);