FPSMS-frontend
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

MailToolbar.tsx 15 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. "use client";
  2. import {
  3. Button,
  4. ButtonGroup,
  5. Grid,
  6. IconButton,
  7. ToggleButton,
  8. ToggleButtonGroup,
  9. } from "@mui/material";
  10. import "./MailField.css";
  11. import { useEditor, EditorContent, Editor } from "@tiptap/react";
  12. import FormatBoldIcon from "@mui/icons-material/FormatBold";
  13. import React, { useCallback } from "react";
  14. import { FormatItalic, FormatUnderlined } from "@mui/icons-material";
  15. import {
  16. MuiColorInput,
  17. MuiColorInputColors,
  18. MuiColorInputValue,
  19. } from "mui-color-input";
  20. import BorderColorIcon from "@mui/icons-material/BorderColor";
  21. import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
  22. import FormatColorTextIcon from "@mui/icons-material/FormatColorText";
  23. import FormatAlignLeftIcon from "@mui/icons-material/FormatAlignLeft";
  24. import FormatAlignJustifyIcon from "@mui/icons-material/FormatAlignJustify";
  25. import FormatAlignRightIcon from "@mui/icons-material/FormatAlignRight";
  26. import { useTranslation } from "react-i18next";
  27. import GridOnIcon from "@mui/icons-material/GridOn";
  28. interface Props {
  29. editor: Editor | null;
  30. }
  31. const colorInputSx = {
  32. width: 150,
  33. height: 25,
  34. ".MuiInputBase-colorPrimary": {
  35. margin: -1,
  36. borderRadius: "0px 5px 5px 0px",
  37. borderColor: "rgba(0, 0, 0, 0)",
  38. backgroundColor: "rgba(0, 0, 0, 0)",
  39. },
  40. ".Mui-focused": {
  41. borderColor: "rgba(0, 0, 0, 0)",
  42. },
  43. ".MuiColorInput-Button": {
  44. marginBottom: 2,
  45. borderColor: "rgba(0, 0, 0, 0)",
  46. backgroundColor: "rgba(0, 0, 0, 0)",
  47. },
  48. ".MuiInputBase-input": {
  49. marginBottom: 1.5,
  50. },
  51. };
  52. const fontFamily = [
  53. {
  54. label: "Arial",
  55. value: "Arial",
  56. },
  57. {
  58. label: "Times New Roman",
  59. value: "Times New Roman",
  60. },
  61. {
  62. label: "Courier New",
  63. value: "Courier New",
  64. },
  65. {
  66. label: "Georgia",
  67. value: "Georgia",
  68. },
  69. {},
  70. ];
  71. const MailToolbar: React.FC<Props> = ({ editor }) => {
  72. const { t } = useTranslation();
  73. if (editor == null) {
  74. return null;
  75. }
  76. const [fontStyle, setFontStyle] = React.useState<string[]>(["alignLeft"]);
  77. const [colorHighlightValue, setColorHighlightValue] =
  78. React.useState<MuiColorInputValue>("red");
  79. const [colorTextValue, setColorTextValue] =
  80. React.useState<MuiColorInputValue>("black");
  81. const colorHighlightValueInputRef = React.useRef<any>(null);
  82. const colorTextValueInputRef = React.useRef<any>(null);
  83. const handleFontStyle = useCallback(
  84. (event: React.MouseEvent<HTMLElement>, newFontStyles: string[]) => {
  85. setFontStyle((prev) => {
  86. const id = event.currentTarget?.id;
  87. const include = prev.includes(id);
  88. if (include) {
  89. return prev.filter((ele) => ele !== id);
  90. } else {
  91. prev = prev.filter((ele) => !ele.includes("align"));
  92. prev.push(id);
  93. return prev;
  94. }
  95. });
  96. },
  97. [],
  98. );
  99. const handleColorHighlightValue = useCallback(
  100. (value: string, colors: MuiColorInputColors) => {
  101. // console.log(colors)
  102. setColorHighlightValue(() => value);
  103. // editor.chain().focus().toggleHighlight({ color: value }).run()
  104. },
  105. [],
  106. );
  107. const handleColorHighlightValueClick = useCallback(
  108. (event: React.MouseEvent<HTMLElement>) => {
  109. editor
  110. .chain()
  111. .focus()
  112. .toggleHighlight({ color: colorHighlightValue.toString() })
  113. .run();
  114. },
  115. [colorHighlightValue],
  116. );
  117. const handleColorHighlightValueClose = useCallback(
  118. (event: {}, reason: "backdropClick" | "escapeKeyDown") => {
  119. // console.log(event)
  120. editor
  121. .chain()
  122. .focus()
  123. .toggleHighlight({ color: colorHighlightValue.toString() })
  124. .run();
  125. },
  126. [colorHighlightValue],
  127. );
  128. const handleColorHighlightValueBlur = useCallback(
  129. (event: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => {
  130. editor
  131. .chain()
  132. .focus()
  133. .toggleHighlight({ color: colorHighlightValue.toString() })
  134. .run();
  135. },
  136. [colorHighlightValue],
  137. );
  138. const handleColorTextValue = useCallback(
  139. (value: string, colors: MuiColorInputColors) => {
  140. // console.log(colors)
  141. setColorTextValue(() => value);
  142. // if (editor.isActive("textStyle")) {
  143. // editor.chain().focus().unsetColor().run()
  144. // } else {
  145. // editor.chain().focus().setColor(value).run()
  146. // }
  147. },
  148. [],
  149. );
  150. const handleColorTextValueClick = useCallback(
  151. (event: React.MouseEvent<HTMLElement>) => {
  152. if (editor.isActive("textStyle", { color: colorTextValue.toString() })) {
  153. editor.chain().focus().unsetColor().run();
  154. } else {
  155. editor.chain().focus().setColor(colorTextValue.toString()).run();
  156. }
  157. },
  158. [colorTextValue],
  159. );
  160. const handleColorTextValueClose = useCallback(
  161. (event: {}, reason: "backdropClick" | "escapeKeyDown") => {
  162. if (editor.isActive("textStyle", { color: colorTextValue.toString() })) {
  163. editor.chain().focus().unsetColor().run();
  164. } else {
  165. editor.chain().focus().setColor(colorTextValue.toString()).run();
  166. }
  167. },
  168. [colorTextValue],
  169. );
  170. const handleColorTextValueBlur = useCallback(
  171. (event: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => {
  172. if (editor.isActive("textStyle", { color: colorTextValue.toString() })) {
  173. editor.chain().focus().unsetColor().run();
  174. } else {
  175. editor.chain().focus().setColor(colorTextValue.toString()).run();
  176. }
  177. },
  178. [colorTextValue],
  179. );
  180. const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
  181. if (event.key === "Enter") {
  182. if (colorHighlightValueInputRef.current !== null) {
  183. colorHighlightValueInputRef.current.blur();
  184. }
  185. if (colorTextValueInputRef.current !== null) {
  186. colorTextValueInputRef.current.blur();
  187. }
  188. }
  189. };
  190. const handleTextAlign = useCallback(
  191. (event: React.MouseEvent<HTMLElement, MouseEvent>, value: any) => {
  192. console.log(value);
  193. switch (value) {
  194. case "alignLeft":
  195. if (editor.isActive({ textAlign: "left" })) {
  196. editor.chain().focus().unsetTextAlign().run();
  197. } else {
  198. editor.chain().focus().setTextAlign("left").run();
  199. }
  200. break;
  201. case "alignCenter":
  202. if (editor.isActive({ textAlign: "center" })) {
  203. editor.chain().focus().unsetTextAlign().run();
  204. } else {
  205. editor.chain().focus().setTextAlign("center").run();
  206. }
  207. break;
  208. case "alignRight":
  209. if (editor.isActive({ textAlign: "right" })) {
  210. editor.chain().focus().unsetTextAlign().run();
  211. } else {
  212. editor.chain().focus().setTextAlign("right").run();
  213. }
  214. break;
  215. default:
  216. break;
  217. }
  218. },
  219. [],
  220. );
  221. const handleInsertTable = useCallback(() => {
  222. editor
  223. .chain()
  224. .focus()
  225. .insertTable({ rows: 3, cols: 3, withHeaderRow: true })
  226. .run();
  227. }, []);
  228. React.useEffect(() => {
  229. editor.on("selectionUpdate", ({ editor }) => {
  230. const currentFormatList: string[] = [];
  231. if (editor.isActive("bold")) {
  232. currentFormatList.push("bold");
  233. }
  234. if (editor.isActive("italic")) {
  235. currentFormatList.push("italic");
  236. }
  237. if (editor.isActive("underline")) {
  238. currentFormatList.push("underline");
  239. }
  240. if (
  241. editor.isActive("highlight", { color: colorHighlightValue.toString() })
  242. ) {
  243. currentFormatList.push("highlight");
  244. }
  245. if (editor.isActive("textStyle", { color: colorTextValue.toString() })) {
  246. currentFormatList.push("textStyle");
  247. }
  248. if (editor.isActive({ textAlign: "left" })) {
  249. currentFormatList.push("alignLeft");
  250. }
  251. if (editor.isActive({ textAlign: "center" })) {
  252. currentFormatList.push("alignCenter");
  253. }
  254. if (editor.isActive({ textAlign: "right" })) {
  255. currentFormatList.push("alignRight");
  256. }
  257. console.log(currentFormatList);
  258. setFontStyle(() => currentFormatList);
  259. });
  260. }, [editor]);
  261. return (
  262. <Grid container>
  263. <ToggleButtonGroup value={fontStyle} onChange={handleFontStyle}>
  264. <ToggleButton
  265. id="bold"
  266. value="bold"
  267. onClick={() => editor.chain().focus().toggleBold().run()}
  268. >
  269. <FormatBoldIcon />
  270. </ToggleButton>
  271. <ToggleButton
  272. id="italic"
  273. value="italic"
  274. onClick={() => editor.chain().focus().toggleItalic().run()}
  275. >
  276. <FormatItalic />
  277. </ToggleButton>
  278. <ToggleButton
  279. id="underline"
  280. value="underline"
  281. onClick={() => editor.chain().focus().toggleUnderline().run()}
  282. >
  283. <FormatUnderlined />
  284. </ToggleButton>
  285. </ToggleButtonGroup>
  286. <ToggleButtonGroup
  287. value={fontStyle}
  288. onChange={handleFontStyle}
  289. sx={{ marginLeft: 2 }}
  290. >
  291. <ToggleButton
  292. id="highlight"
  293. value="highlight"
  294. onClick={handleColorHighlightValueClick}
  295. >
  296. <BorderColorIcon sx={{ color: colorHighlightValue as string }} />
  297. </ToggleButton>
  298. {/* <ToggleButton value="" onClick={() => console.log("Expand more")}>
  299. <ExpandMoreIcon sx={{ width: 15 }} fontSize="large"/>
  300. </ToggleButton> */}
  301. <ToggleButton id="highlight" value="highlight">
  302. <MuiColorInput
  303. sx={colorInputSx}
  304. format="hex8"
  305. value={colorHighlightValue}
  306. onBlur={handleColorHighlightValueBlur}
  307. onChange={handleColorHighlightValue}
  308. onKeyDown={handleKeyDown}
  309. inputRef={colorHighlightValueInputRef}
  310. PopoverProps={{
  311. onClose: handleColorHighlightValueClose,
  312. }}
  313. />
  314. </ToggleButton>
  315. </ToggleButtonGroup>
  316. <ToggleButtonGroup
  317. value={fontStyle}
  318. onChange={handleFontStyle}
  319. sx={{ marginLeft: 2 }}
  320. >
  321. <ToggleButton
  322. id="textStyle"
  323. value="textStyle"
  324. onClick={handleColorTextValueClick}
  325. >
  326. <FormatColorTextIcon sx={{ color: colorTextValue as string }} />
  327. </ToggleButton>
  328. <ToggleButton id="textStyle" value="textStyle">
  329. <MuiColorInput
  330. sx={colorInputSx}
  331. format="hex8"
  332. value={colorTextValue}
  333. onBlur={handleColorTextValueBlur}
  334. onChange={handleColorTextValue}
  335. onKeyDown={handleKeyDown}
  336. inputRef={colorTextValueInputRef}
  337. PopoverProps={{
  338. onClose: handleColorTextValueClose,
  339. }}
  340. />
  341. </ToggleButton>
  342. </ToggleButtonGroup>
  343. <ToggleButtonGroup
  344. value={fontStyle}
  345. onChange={handleFontStyle}
  346. sx={{ marginLeft: 2 }}
  347. >
  348. <ToggleButton
  349. id="alignLeft"
  350. value="alignLeft"
  351. onClick={handleTextAlign}
  352. >
  353. <FormatAlignLeftIcon />
  354. </ToggleButton>
  355. <ToggleButton
  356. id="alignCenter"
  357. value="alignCenter"
  358. onClick={handleTextAlign}
  359. >
  360. <FormatAlignJustifyIcon />
  361. </ToggleButton>
  362. <ToggleButton
  363. id="alignRight"
  364. value="alignRight"
  365. onClick={handleTextAlign}
  366. >
  367. <FormatAlignRightIcon />
  368. </ToggleButton>
  369. </ToggleButtonGroup>
  370. <ToggleButtonGroup sx={{ marginTop: 2 }}>
  371. <ToggleButton
  372. id="insertTable"
  373. value="insertTable"
  374. onClick={() =>
  375. editor
  376. .chain()
  377. .focus()
  378. .insertTable({ rows: 3, cols: 3, withHeaderRow: true })
  379. .run()
  380. }
  381. >
  382. <GridOnIcon />
  383. {t("Insert Table")}
  384. </ToggleButton>
  385. <ToggleButton
  386. id="deleteTable"
  387. value="deleteTable"
  388. onClick={() => editor.chain().focus().deleteTable().run()}
  389. >
  390. {t("Delete table")}
  391. </ToggleButton>
  392. <ToggleButton
  393. id="addColumnBefore"
  394. value="addColumnBefore"
  395. onClick={() => editor.chain().focus().addColumnBefore().run()}
  396. >
  397. {t("Add column before")}
  398. </ToggleButton>
  399. <ToggleButton
  400. id="addColumnAfter"
  401. value="addColumnAfter"
  402. onClick={() => editor.chain().focus().addColumnAfter().run()}
  403. >
  404. {t("Add column after")}
  405. </ToggleButton>
  406. <ToggleButton
  407. id="deleteColumn"
  408. value="deleteColumn"
  409. onClick={() => editor.chain().focus().deleteColumn().run()}
  410. >
  411. {t("Delete column")}
  412. </ToggleButton>
  413. <ToggleButton
  414. id="addRowBefore"
  415. value="addRowBefore"
  416. onClick={() => editor.chain().focus().addRowBefore().run()}
  417. >
  418. {t("Add row before")}
  419. </ToggleButton>
  420. <ToggleButton
  421. id="addRowAfter"
  422. value="addRowAfter"
  423. onClick={() => editor.chain().focus().addRowAfter().run()}
  424. >
  425. {t("Add row after")}
  426. </ToggleButton>
  427. <ToggleButton
  428. id="deleteRow"
  429. value="deleteRow"
  430. onClick={() => editor.chain().focus().deleteRow().run()}
  431. >
  432. {t("Delete row")}
  433. </ToggleButton>
  434. <ToggleButton
  435. id="mergeCells"
  436. value="mergeCells"
  437. onClick={() => editor.chain().focus().mergeCells().run()}
  438. >
  439. {t("Merge cells")}
  440. </ToggleButton>
  441. <ToggleButton
  442. id="splitCell"
  443. value="splitCell"
  444. onClick={() => editor.chain().focus().splitCell().run()}
  445. >
  446. {t("Split cell")}
  447. </ToggleButton>
  448. </ToggleButtonGroup>
  449. <ToggleButtonGroup
  450. // sx={{ marginLeft: 2 }}
  451. >
  452. <ToggleButton
  453. id="toggleHeaderColumn"
  454. value="toggleHeaderColumn"
  455. onClick={() => editor.chain().focus().toggleHeaderColumn().run()}
  456. >
  457. {t("Toggle header column")}
  458. </ToggleButton>
  459. <ToggleButton
  460. id="toggleHeaderRow"
  461. value="toggleHeaderRow"
  462. onClick={() => editor.chain().focus().toggleHeaderRow().run()}
  463. >
  464. {t("Toggle header row")}
  465. </ToggleButton>
  466. <ToggleButton
  467. id="toggleHeaderCell"
  468. value="toggleHeaderCell"
  469. onClick={() => editor.chain().focus().toggleHeaderCell().run()}
  470. >
  471. {t("Toggle header cell")}
  472. </ToggleButton>
  473. <ToggleButton
  474. id="mergeOrSplit"
  475. value="mergeOrSplit"
  476. onClick={() => editor.chain().focus().mergeOrSplit().run()}
  477. >
  478. {t("Merge or split")}
  479. </ToggleButton>
  480. <ToggleButton
  481. id="setCellAttribute"
  482. value="setCellAttribute"
  483. onClick={() =>
  484. editor.chain().focus().setCellAttribute("colspan", 2).run()
  485. }
  486. >
  487. {t("Set cell attribute")}
  488. </ToggleButton>
  489. <ToggleButton
  490. id="fixTables"
  491. value="fixTables"
  492. onClick={() => editor.chain().focus().fixTables().run()}
  493. >
  494. {t("Fix tables")}
  495. </ToggleButton>
  496. <ToggleButton
  497. id="goToNextCell"
  498. value="goToNextCell"
  499. onClick={() => editor.chain().focus().goToNextCell().run()}
  500. >
  501. {t("Go to next cell")}
  502. </ToggleButton>
  503. <ToggleButton
  504. id="goToPreviousCell"
  505. value="goToPreviousCell"
  506. onClick={() => editor.chain().focus().goToPreviousCell().run()}
  507. >
  508. {t("Go to previous cell")}
  509. </ToggleButton>
  510. </ToggleButtonGroup>
  511. </Grid>
  512. );
  513. };
  514. export default MailToolbar;