BlockRenderer.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /**
  2. * BlockRenderer.tsx - 块渲染器组件
  3. *
  4. * 根据block类型路由到对应的块组件
  5. *
  6. * @module components/Editor
  7. */
  8. import React from 'react';
  9. import type { DocumentBlock } from '../../types/editor';
  10. import { HeadingBlock } from './blocks/HeadingBlock';
  11. import { ParagraphBlock } from './blocks/ParagraphBlock';
  12. import { TableBlock } from './blocks/TableBlock';
  13. import { ImageBlock } from './blocks/ImageBlock';
  14. import { TOCBlock } from './blocks/TOCBlock';
  15. // ══════════════════════════════════════════════════════════════════════════════
  16. // Component Props
  17. // ══════════════════════════════════════════════════════════════════════════════
  18. export interface BlockRendererProps {
  19. /** 文档块 */
  20. block: DocumentBlock;
  21. /** 块在画布排序结果中的位置 */
  22. index?: number;
  23. /** 画布中的块总数 */
  24. blockCount?: number;
  25. /** 是否只读 */
  26. readOnly?: boolean;
  27. /** 标题是否存在可折叠内容 */
  28. collapsible?: boolean;
  29. /** 标题内容是否已折叠 */
  30. collapsed?: boolean;
  31. /** 段落列表标记 */
  32. listMarker?: string;
  33. /** 切换标题折叠状态 */
  34. onToggleCollapse?: () => void;
  35. }
  36. // ══════════════════════════════════════════════════════════════════════════════
  37. // Component
  38. // ══════════════════════════════════════════════════════════════════════════════
  39. /**
  40. * BlockRenderer - 块渲染器
  41. *
  42. * 根据block.type渲染对应的组件
  43. */
  44. export const BlockRenderer = React.memo(function BlockRenderer({
  45. block,
  46. index,
  47. blockCount,
  48. collapsible,
  49. collapsed,
  50. listMarker,
  51. onToggleCollapse,
  52. readOnly = false,
  53. }: BlockRendererProps) {
  54. switch (block.type) {
  55. case 'heading':
  56. return (
  57. <HeadingBlock
  58. block={block}
  59. index={index ?? 0}
  60. blockCount={blockCount ?? 0}
  61. listMarker={listMarker}
  62. collapsible={collapsible}
  63. collapsed={collapsed}
  64. onToggleCollapse={onToggleCollapse}
  65. readOnly={readOnly}
  66. />
  67. );
  68. case 'paragraph':
  69. return (
  70. <ParagraphBlock
  71. block={block}
  72. index={index ?? 0}
  73. blockCount={blockCount ?? 0}
  74. readOnly={readOnly}
  75. listMarker={listMarker}
  76. />
  77. );
  78. case 'table':
  79. return <TableBlock block={block} readOnly={readOnly} />;
  80. case 'image':
  81. return (
  82. <ImageBlock
  83. block={block}
  84. index={index ?? 0}
  85. blockCount={blockCount ?? 0}
  86. readOnly={readOnly}
  87. />
  88. );
  89. case 'toc':
  90. return <TOCBlock block={block} readOnly={true} />;
  91. default:
  92. // 未知类型,显示警告
  93. return (
  94. <div style={{ padding: '12px', backgroundColor: '#fff7e6', border: '1px solid #ffd591' }}>
  95. <p style={{ margin: 0, color: '#d48806' }}>
  96. 未知的块类型: {String((block as { type?: unknown }).type)}
  97. </p>
  98. </div>
  99. );
  100. }
  101. });
  102. export default BlockRenderer;