You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

BlockButton.js 2.0KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import React from "react";
  2. import PropTypes from "prop-types";
  3. import { Button, Icon } from "@mui/material";
  4. import { useSlate } from "slate-react";
  5. import { Editor, Transforms, Element as SlateElement } from "slate";
  6. const LIST_TYPES = ["numbered-list", "bulleted-list"];
  7. const TEXT_ALIGN_TYPES = ["left", "center", "right", "justify"];
  8. const BlockButton = ({ format, icon }) => {
  9. const editor = useSlate();
  10. return (
  11. <Button
  12. active={isBlockActive(
  13. editor,
  14. format,
  15. TEXT_ALIGN_TYPES.includes(format) ? "align" : "type"
  16. )}
  17. onMouseDown={(event) => {
  18. event.preventDefault();
  19. toggleBlock(editor, format);
  20. }}
  21. >
  22. <Icon>{icon}</Icon>
  23. </Button>
  24. );
  25. };
  26. const isBlockActive = (editor, format, blockType = "type") => {
  27. const { selection } = editor;
  28. if (!selection) return false;
  29. const [match] = Array.from(
  30. Editor.nodes(editor, {
  31. at: Editor.unhangRange(editor, selection),
  32. match: (n) =>
  33. !Editor.isEditor(n) &&
  34. SlateElement.isElement(n) &&
  35. n[blockType] === format,
  36. })
  37. );
  38. return !!match;
  39. };
  40. const toggleBlock = (editor, format) => {
  41. const isActive = isBlockActive(
  42. editor,
  43. format,
  44. TEXT_ALIGN_TYPES.includes(format) ? "align" : "type"
  45. );
  46. const isList = LIST_TYPES.includes(format);
  47. Transforms.unwrapNodes(editor, {
  48. match: (n) =>
  49. !Editor.isEditor(n) &&
  50. SlateElement.isElement(n) &&
  51. LIST_TYPES.includes(n.type) &&
  52. !TEXT_ALIGN_TYPES.includes(format),
  53. split: true,
  54. });
  55. let newProperties;
  56. if (TEXT_ALIGN_TYPES.includes(format)) {
  57. newProperties = {
  58. align: isActive ? undefined : format,
  59. };
  60. } else {
  61. newProperties = {
  62. type: isActive ? "paragraph" : isList ? "list-item" : format,
  63. };
  64. }
  65. Transforms.setNodes < SlateElement > (editor, newProperties);
  66. if (!isActive && isList) {
  67. const block = { type: format, children: [] };
  68. Transforms.wrapNodes(editor, block);
  69. }
  70. };
  71. BlockButton.propTypes = {
  72. format: PropTypes.any,
  73. icon: PropTypes.any,
  74. };
  75. export default BlockButton;