From a33c5d9215512f739e08bd8fb81d27e2de8caf1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81d=C3=A1m=20Hassan?= Date: Wed, 5 Jun 2024 15:57:15 +0200 Subject: [PATCH 1/4] feature: accordion --- .../components/controls/accordion-control.tsx | 250 ++++++++++++++++++ .../controls/html-editor-control.tsx | 14 +- .../src/components/controls/index.ts | 1 + .../sn-editor-react/src/components/editor.tsx | 49 ++++ .../src/components/menu-bar.tsx | 23 +- .../src/context/localization-context.tsx | 7 + .../sn-editor-react/src/extension-list.ts | 25 +- .../src/extensions/PanelGroup.ts | 56 ++++ .../src/extensions/ParagraphExtend.ts | 26 ++ .../sn-editor-react/src/extensions/div.ts | 56 ++++ .../sn-editor-react/src/extensions/index.ts | 10 + .../src/extensions/linkExtend.ts | 20 ++ .../src/extensions/panel-body.ts | 33 +++ .../src/extensions/panel-collapse.ts | 41 +++ .../src/extensions/panel-heading.ts | 33 +++ .../src/extensions/panel-icon.ts | 43 +++ .../src/extensions/panel-link.ts | 55 ++++ .../src/extensions/panel-title.ts | 54 ++++ .../sn-editor-react/src/extensions/panel.ts | 31 +++ 19 files changed, 819 insertions(+), 8 deletions(-) create mode 100644 packages/sn-editor-react/src/components/controls/accordion-control.tsx create mode 100644 packages/sn-editor-react/src/extensions/PanelGroup.ts create mode 100644 packages/sn-editor-react/src/extensions/ParagraphExtend.ts create mode 100644 packages/sn-editor-react/src/extensions/div.ts create mode 100644 packages/sn-editor-react/src/extensions/linkExtend.ts create mode 100644 packages/sn-editor-react/src/extensions/panel-body.ts create mode 100644 packages/sn-editor-react/src/extensions/panel-collapse.ts create mode 100644 packages/sn-editor-react/src/extensions/panel-heading.ts create mode 100644 packages/sn-editor-react/src/extensions/panel-icon.ts create mode 100644 packages/sn-editor-react/src/extensions/panel-link.ts create mode 100644 packages/sn-editor-react/src/extensions/panel-title.ts create mode 100644 packages/sn-editor-react/src/extensions/panel.ts diff --git a/packages/sn-editor-react/src/components/controls/accordion-control.tsx b/packages/sn-editor-react/src/components/controls/accordion-control.tsx new file mode 100644 index 000000000..bf0d885e6 --- /dev/null +++ b/packages/sn-editor-react/src/components/controls/accordion-control.tsx @@ -0,0 +1,250 @@ +import { + Button, + createStyles, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + IconButtonProps, + makeStyles, + TextField, + Theme, + Tooltip, + useTheme, +} from '@material-ui/core' +import { ArrowDropDown, Close, DragHandle } from '@material-ui/icons' + +import { Editor } from '@tiptap/react' +import React, { FC, useCallback, useRef, useState } from 'react' +import { renderToString } from 'react-dom/server' +import { useLocalization } from '../../hooks' + +const useStyles = makeStyles((theme: Theme) => { + return createStyles({ + ListIcon: { + paddingLeft: '0px', + '& .down-arrow': { + position: 'absolute', + right: '0', + marginRight: '-6px', + top: '0', + marginTop: '3px', + }, + }, + accordion: { + display: 'flex', + flexDirection: 'column', + rowGap: '15px', + border: '2px solid', + borderColor: theme.palette.primary.main, + position: 'relative', + padding: '10px', + borderRadius: '10px', + '& .panel-close-button': { + position: 'absolute', + right: '0', + top: '0', + }, + }, + accordionContainer: { + display: 'flex', + flexDirection: 'column', + rowGap: '20px', + }, + actionPanel: { + display: 'flex', + flex: 1, + justifyContent: 'space-between', + }, + dialog: { + '& .MuiDialogContent-root': { + padding: '8px 15px', + }, + }, + }) +}) + +interface AccordionControlProps { + editor: Editor + buttonProps?: Partial +} + +type TAccordions = { + title: string + body: string +} + +type PanelPros = { + title: string + body: string +} + +const Panel = ({ title, body }: PanelPros) => { + return ( +
+
+

+ + + {title} + +

+
+
+
{body}
+
+
+ ) +} + +const initialAccordion = { title: '', body: '' } + +export const AccordionControl: FC = ({ buttonProps, editor }) => { + const [open, setOpen] = useState(false) + + const [accordions, setAccordions] = useState([initialAccordion]) + const form = useRef(null) + + const theme = useTheme() + + const classes = useStyles(theme) + const localization = useLocalization() + + const handleClickOpen = () => { + setOpen(true) + } + + const handleClose = useCallback(() => { + setAccordions([initialAccordion]) + + setOpen(false) + }, []) + + const handleSubmit = () => { + if (accordions.length === 0) { + handleClose() + return + } + + if (!form.current?.reportValidity()) { + return + } + + const panelGroup = renderToString( + <> +
+ {accordions.map((item, index) => { + return + })} +
+ {/* eslint-disable-next-line react/self-closing-comp*/} +

+ , + ) + + editor.chain().focus().insertContent(panelGroup).run() + + handleClose() + } + + const handleClosePanel = (index: number) => { + setAccordions((prev) => { + return prev.filter((_, i) => i !== index) + }) + } + + return ( + <> + + + + + + + + {localization.accordionControl.title} + +
+ {accordions.map((accordion, index) => { + return ( +
+ + handleClosePanel(index)} {...buttonProps}> + + + + + { + const newAccordions = [...accordions] + + newAccordions[index] = { ...accordions[index], title: e.target.value } + + setAccordions(newAccordions) + }} + /> + + { + const newAccordions = [...accordions] + + newAccordions[index] = { ...accordions[index], body: e.target.value } + + setAccordions(newAccordions) + }} + /> +
+ ) + })} +
+
+ +
+ + +
+ + +
+
+
+
+ + ) +} diff --git a/packages/sn-editor-react/src/components/controls/html-editor-control.tsx b/packages/sn-editor-react/src/components/controls/html-editor-control.tsx index a410f737a..be14c8d11 100644 --- a/packages/sn-editor-react/src/components/controls/html-editor-control.tsx +++ b/packages/sn-editor-react/src/components/controls/html-editor-control.tsx @@ -28,6 +28,11 @@ export const HTMLEditorControl: FC = ({ editor, buttonPr setOpen(true) } + const saveHTMLContent = () => { + editor.chain().focus().setContent(html, true).run() + setOpen(false) + } + const handleClose = () => { if (editor.getHTML() === html) { setOpen(false) @@ -38,9 +43,7 @@ export const HTMLEditorControl: FC = ({ editor, buttonPr if (!confirmResult) { return } - editor.commands.setContent(html) - - setOpen(false) + saveHTMLContent() } return ( @@ -60,7 +63,7 @@ export const HTMLEditorControl: FC = ({ editor, buttonPr aria-labelledby="html-editor-control-title" fullWidth maxWidth="lg" - onExited={() => { }}> + onExited={() => {}}> {localization.HTMLEditorControl.title} @@ -74,8 +77,7 @@ export const HTMLEditorControl: FC = ({ editor, buttonPr