Source: components/editor/index.js

  1. import React, { memo, useState } from "react";
  2. import "@remirror/styles/all.css";
  3. import {
  4. BlockquoteExtension,
  5. BoldExtension,
  6. BulletListExtension,
  7. CodeExtension,
  8. HardBreakExtension,
  9. HeadingExtension,
  10. ItalicExtension,
  11. LinkExtension,
  12. ListItemExtension,
  13. MarkdownExtension,
  14. OrderedListExtension,
  15. PlaceholderExtension,
  16. StrikeExtension,
  17. TableExtension,
  18. TrailingNodeExtension,
  19. } from "remirror/extensions";
  20. import { Remirror, ThemeProvider, useRemirror, Toolbar } from "@remirror/react";
  21. import { BRAND_HEX } from "../../lib/config";
  22. import {
  23. ToggleBoldButton,
  24. ToggleItalicButton,
  25. ToggleStrikeButton,
  26. ToggleBlockquoteButton,
  27. HeadingLevelButtonGroup,
  28. HistoryButtonGroup,
  29. CommandButtonGroup,
  30. } from "./buttons";
  31. import { css } from "@emotion/css";
  32. import SyncManagerHook from "./sync-manager-hook";
  33. import { ExtensionPriority } from "remirror";
  34. import { CommandsExtension } from "@remirror/core";
  35. import { Box } from "grommet";
  36. import { useTranslation } from "next-i18next";
  37. const extensions = (placeholder) => [
  38. new CommandsExtension(),
  39. new PlaceholderExtension({ placeholder }),
  40. new LinkExtension({ autoLink: true }),
  41. new BoldExtension(),
  42. new StrikeExtension(),
  43. new ItalicExtension(),
  44. new HeadingExtension(),
  45. new LinkExtension(),
  46. new BlockquoteExtension(),
  47. new BulletListExtension({ enableSpine: true }),
  48. new OrderedListExtension(),
  49. new ListItemExtension({
  50. priority: ExtensionPriority.High,
  51. enableCollapsible: true,
  52. }),
  53. new CodeExtension(),
  54. new TrailingNodeExtension(),
  55. new TableExtension(),
  56. new MarkdownExtension({ copyAsMarkdown: false }),
  57. /**
  58. * `HardBreakExtension` allows us to create a newline inside paragraphs.
  59. * e.g. in a list item
  60. */
  61. new HardBreakExtension(),
  62. ];
  63. /**
  64. * The editor which is used to create the annotation. Supports formatting.
  65. */
  66. function Editor(props) {
  67. const { defaultValue, save } = props;
  68. const { t, ready } = useTranslation("editor");
  69. const { manager } = useRemirror({
  70. extensions: extensions(ready ? t("i-had-a-dream") : ""),
  71. stringHandler: "html",
  72. });
  73. return (
  74. <>
  75. <ThemeProvider>
  76. <MarkdownTextEditor
  77. manager={manager}
  78. save={save}
  79. defaultValue={defaultValue}
  80. t={t}
  81. ready={ready}
  82. />
  83. </ThemeProvider>
  84. </>
  85. );
  86. }
  87. function MarkdownToolbar(props) {
  88. const { t, ready } = props;
  89. return (
  90. <Toolbar
  91. style={{
  92. width: "100vw",
  93. backgroundColor: BRAND_HEX,
  94. padding: "1rem",
  95. display: "flex",
  96. justifyContent: "center",
  97. flexWrap: "wrap",
  98. }}
  99. >
  100. <CommandButtonGroup>
  101. <ToggleBoldButton t={t} ready={ready} />
  102. <ToggleItalicButton t={t} ready={ready} />
  103. <ToggleStrikeButton t={t} ready={ready} />
  104. </CommandButtonGroup>
  105. <HeadingLevelButtonGroup t={t} ready={ready} />
  106. <CommandButtonGroup>
  107. <ToggleBlockquoteButton t={t} ready={ready} />
  108. </CommandButtonGroup>
  109. <HistoryButtonGroup t={t} ready={ready} />
  110. </Toolbar>
  111. );
  112. }
  113. function MarkdownTextEditor(props) {
  114. const { manager, save, defaultValue, t, ready } = props;
  115. const [html, setHtml] = useState();
  116. return (
  117. <>
  118. <Remirror
  119. manager={manager}
  120. onChange={({ helpers, state }) => {
  121. const html = helpers.getHTML(state);
  122. setHtml(html);
  123. }}
  124. autoRender="end"
  125. initialContent={defaultValue}
  126. classNames={[
  127. css`
  128. &.ProseMirror {
  129. box-shadow: none !important;
  130. overflow-y: unset !important;
  131. }
  132. `,
  133. ]}
  134. >
  135. <MarkdownToolbar t={t} ready={ready} />
  136. <SyncManagerHook html={html} save={save} />
  137. </Remirror>
  138. <Box
  139. style={{
  140. position: "absolute",
  141. height: "22rem",
  142. width: "100vw",
  143. }}
  144. />
  145. </>
  146. );
  147. }
  148. export default memo(Editor);