goobs-frontend 0.8.8 → 0.8.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/package.json +21 -16
  2. package/src/components/Button/index.tsx +134 -110
  3. package/src/components/{DataGrid/Checkbox → Checkbox}/index.tsx +1 -1
  4. package/src/components/ComplexTextEditor/MarkdownEditor/index.tsx +107 -0
  5. package/src/components/ComplexTextEditor/RichEditor/index.tsx +214 -0
  6. package/src/components/ComplexTextEditor/SimpleEditor/index.tsx +65 -0
  7. package/src/components/ComplexTextEditor/ToolbarButton/index.tsx +111 -0
  8. package/src/components/ComplexTextEditor/Toolbars/Complex/index.tsx +128 -0
  9. package/src/components/ComplexTextEditor/Toolbars/Markdown/index.tsx +325 -0
  10. package/src/components/ComplexTextEditor/Toolbars/Rich/index.tsx +349 -0
  11. package/src/components/ComplexTextEditor/index.tsx +102 -0
  12. package/src/components/ComplexTextEditor/types/index.ts +43 -0
  13. package/src/components/ComplexTextEditor/utils/useMarkdownEditor.tsx +122 -0
  14. package/src/components/ComplexTextEditor/utils/useRichtextEditor.tsx +301 -0
  15. package/src/components/Content/Structure/checkbox/useCheckbox.tsx +65 -0
  16. package/src/components/Content/Structure/complexeditor/useComplexEditor.tsx +69 -0
  17. package/src/components/Content/Structure/textfield/useTextField.tsx +7 -2
  18. package/src/components/Content/Structure/typography/useGridTypography.tsx +2 -0
  19. package/src/components/Content/index.tsx +11 -0
  20. package/src/components/DataGrid/ManageColumn/index.tsx +1 -1
  21. package/src/components/DataGrid/ManageRow/index.tsx +269 -103
  22. package/src/components/DataGrid/Table/index.tsx +101 -53
  23. package/src/components/DataGrid/index.tsx +77 -48
  24. package/src/components/DateField/index.tsx +207 -63
  25. package/src/components/Dropdown/index.tsx +105 -52
  26. package/src/components/Form/DataGrid/index.tsx +9 -0
  27. package/src/components/Form/Popup/index.tsx +30 -63
  28. package/src/components/Grid/index.tsx +121 -166
  29. package/src/components/Nav/VerticalVariant/index.tsx +14 -10
  30. package/src/components/TextField/index.tsx +107 -23
  31. package/src/components/Toolbar/index.tsx +28 -8
  32. package/src/components/Typography/index.tsx +8 -4
  33. package/src/index.ts +3 -0
  34. package/src/types/react-datepicker.d.ts +75 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "goobs-frontend",
3
- "version": "0.8.8",
3
+ "version": "0.8.10",
4
4
  "type": "module",
5
5
  "description": "A comprehensive React-based UI library built on Material-UI, offering a wide range of customizable components including grids, typography, buttons, cards, forms, navigation, pricing tables, steppers, tooltips, accordions, and more. Designed for building responsive and consistent user interfaces with advanced features like form validation, theming, and code syntax highlighting.",
6
6
  "license": "MIT",
@@ -22,31 +22,36 @@
22
22
  "@emotion/cache": "^11.13.5",
23
23
  "@emotion/react": "^11.13.5",
24
24
  "@emotion/styled": "^11.13.5",
25
- "@mui/icons-material": "^6.1.8",
26
- "@mui/material": "^6.1.8",
25
+ "@mui/icons-material": "^6.1.10",
26
+ "@mui/material": "^6.1.10",
27
27
  "@types/lodash": "^4.17.13",
28
+ "@types/react-datepicker": "^7.0.0",
28
29
  "highlight.js": "^11.10.0",
29
30
  "jotai": "^2.10.3",
30
31
  "lodash": "^4.17.21",
31
- "next": "15.0.3",
32
+ "next": "15.0.4",
32
33
  "otplib": "^12.0.1",
33
34
  "react-datepicker": "^7.5.0",
34
- "react-qr-code": "^2.0.15"
35
+ "react-qr-code": "^2.0.15",
36
+ "slate": "^0.112.0",
37
+ "slate-dom": "^0.111.0",
38
+ "slate-history": "^0.110.3",
39
+ "slate-react": "^0.112.0"
35
40
  },
36
41
  "devDependencies": {
37
- "@next/eslint-plugin-next": "^15.0.3",
38
- "@types/node": "^22.10.0",
39
- "@types/react": "18.3.12",
40
- "@types/react-dom": "^18.3.1",
41
- "@typescript-eslint/eslint-plugin": "^8.16.0",
42
- "@typescript-eslint/parser": "^8.16.0",
43
- "eslint": "^9.15.0",
44
- "eslint-config-next": "^15.0.3",
42
+ "@next/eslint-plugin-next": "^15.0.4",
43
+ "@types/node": "^22.10.1",
44
+ "@types/react": "19.0.1",
45
+ "@types/react-dom": "^19.0.1",
46
+ "@typescript-eslint/eslint-plugin": "^8.17.0",
47
+ "@typescript-eslint/parser": "^8.17.0",
48
+ "eslint": "^9.16.0",
49
+ "eslint-config-next": "^15.0.4",
45
50
  "eslint-config-prettier": "^9.1.0",
46
51
  "eslint-plugin-prettier": "^5.2.1",
47
- "prettier": "^3.4.1",
48
- "react": "^18.3.1",
49
- "react-dom": "^18.3.1",
52
+ "prettier": "^3.4.2",
53
+ "react": "^19.0.0",
54
+ "react-dom": "^19.0.0",
50
55
  "typescript": "^5.7.2"
51
56
  },
52
57
  "files": [
@@ -2,6 +2,8 @@
2
2
  import React from 'react'
3
3
  import { Button, Box, ButtonProps } from '@mui/material'
4
4
  import Typography from '../Typography'
5
+ import { SvgIconProps } from '@mui/material/SvgIcon'
6
+ import { styled } from '@mui/material/styles'
5
7
 
6
8
  export interface CustomButtonProps extends ButtonProps {
7
9
  text?: string
@@ -9,131 +11,153 @@ export interface CustomButtonProps extends ButtonProps {
9
11
  fontcolor?: string
10
12
  fontvariant?: 'merriparagraph' | 'merrihelperfooter'
11
13
  width?: string
14
+ height?: string
12
15
  disableButton?: 'true' | 'false'
13
- icon?: React.ReactNode
16
+ icon?: React.ReactElement<SvgIconProps>
14
17
  iconcolor?: string
15
18
  iconsize?: string
16
19
  iconlocation?: 'left' | 'right' | 'above'
17
20
  fontlocation?: 'left' | 'center' | 'right'
18
21
  }
19
22
 
20
- const CustomButton: React.FC<CustomButtonProps> = React.memo(
21
- props => {
22
- const {
23
- text,
24
- variant,
25
- fontvariant = 'merriparagraph',
26
- onClick,
27
- fontcolor,
28
- backgroundcolor,
29
- width,
30
- disableButton,
31
- icon,
32
- iconcolor,
33
- iconsize,
34
- iconlocation = 'left',
35
- fontlocation = 'center',
36
- ...restProps
37
- } = props
23
+ const StyledButton = styled(Button, {
24
+ shouldForwardProp: prop =>
25
+ prop !== 'backgroundcolor' &&
26
+ prop !== 'iconlocation' &&
27
+ prop !== 'fontlocation',
28
+ })<{
29
+ backgroundcolor?: string
30
+ iconlocation?: 'left' | 'right' | 'above'
31
+ fontlocation?: 'left' | 'center' | 'right'
32
+ }>(({ backgroundcolor, iconlocation, fontlocation }) => ({
33
+ minWidth: 'auto',
34
+ width: '100%',
35
+ height: '40px',
36
+ padding: '8px 16px',
37
+ display: 'flex',
38
+ flexDirection: iconlocation === 'above' ? 'column' : 'row',
39
+ alignItems: 'center',
40
+ justifyContent:
41
+ fontlocation === 'left'
42
+ ? 'flex-start'
43
+ : fontlocation === 'right'
44
+ ? 'flex-end'
45
+ : 'center',
46
+ gap: '8px',
47
+ ...(backgroundcolor && {
48
+ backgroundColor: backgroundcolor,
49
+ '&:hover': {
50
+ backgroundColor: backgroundcolor,
51
+ opacity: 0.9,
52
+ },
53
+ }),
54
+ '& .MuiButton-startIcon': {
55
+ margin: 0,
56
+ },
57
+ '& .MuiButton-endIcon': {
58
+ margin: 0,
59
+ },
60
+ }))
38
61
 
39
- const handleButtonClick = (
40
- event: React.MouseEvent<HTMLButtonElement>
41
- ): void => {
42
- event.preventDefault()
43
- onClick?.(event)
44
- }
62
+ const StyledBox = styled(Box)({
63
+ display: 'flex',
64
+ flexDirection: 'column',
65
+ alignItems: 'center',
66
+ width: '100%',
67
+ height: '40px',
68
+ minWidth: 'fit-content',
69
+ })
45
70
 
46
- const buttonStyle = {
47
- backgroundColor: backgroundcolor,
48
- width: width,
49
- }
71
+ const ContentWrapper = styled(Box)<{
72
+ fontlocation?: 'left' | 'center' | 'right'
73
+ }>(({ fontlocation }) => ({
74
+ display: 'flex',
75
+ alignItems: 'center',
76
+ justifyContent:
77
+ fontlocation === 'left'
78
+ ? 'flex-start'
79
+ : fontlocation === 'right'
80
+ ? 'flex-end'
81
+ : 'center',
82
+ width: '100%',
83
+ height: '100%',
84
+ gap: '8px',
85
+ }))
50
86
 
51
- const isDisabled = disableButton === 'true'
87
+ const CustomButton: React.FC<CustomButtonProps> = ({
88
+ text,
89
+ variant = 'contained',
90
+ fontvariant = 'merriparagraph',
91
+ onClick,
92
+ fontcolor,
93
+ backgroundcolor,
94
+ width,
95
+ height,
96
+ disableButton,
97
+ icon,
98
+ iconcolor,
99
+ iconsize,
100
+ iconlocation = 'left',
101
+ fontlocation = 'center',
102
+ sx,
103
+ ...restProps
104
+ }) => {
105
+ const handleButtonClick = (
106
+ event: React.MouseEvent<HTMLButtonElement>
107
+ ): void => {
108
+ event.preventDefault()
109
+ onClick?.(event)
110
+ }
52
111
 
53
- const iconStyle = {
54
- color: iconcolor,
55
- fontSize: iconsize,
56
- }
112
+ const isDisabled = disableButton === 'true'
57
113
 
58
- const IconComponent = icon
59
- ? React.cloneElement(icon as React.ReactElement, {
60
- style: { ...iconStyle, ...(icon as React.ReactElement).props.style },
61
- })
62
- : null
114
+ const IconComponent = icon
115
+ ? React.cloneElement(icon, {
116
+ sx: {
117
+ color: iconcolor || 'inherit',
118
+ fontSize: iconsize || '20px',
119
+ minWidth: iconsize || '20px',
120
+ minHeight: iconsize || '20px',
121
+ margin: 0,
122
+ },
123
+ } as Partial<SvgIconProps>)
124
+ : null
63
125
 
64
- const buttonContent = (
65
- <>
66
- {iconlocation === 'above' && IconComponent}
67
- <Box
68
- display="flex"
69
- alignItems="center"
70
- justifyContent={
71
- fontlocation === 'left'
72
- ? 'flex-start'
73
- : fontlocation === 'right'
74
- ? 'flex-end'
75
- : 'center'
76
- }
77
- width="100%"
78
- >
79
- {iconlocation === 'left' && IconComponent}
80
- <Typography
81
- fontvariant={fontvariant}
82
- fontcolor={isDisabled ? 'grey' : fontcolor}
83
- text={text || ''}
84
- />
85
- {iconlocation === 'right' && IconComponent}
86
- </Box>
87
- </>
88
- )
126
+ const buttonContent = (
127
+ <>
128
+ {iconlocation === 'above' && IconComponent}
129
+ <ContentWrapper fontlocation={fontlocation}>
130
+ {iconlocation === 'left' && IconComponent}
131
+ <Typography
132
+ fontvariant={fontvariant}
133
+ fontcolor={isDisabled ? 'grey' : fontcolor || 'white'}
134
+ text={text || ''}
135
+ />
136
+ {iconlocation === 'right' && IconComponent}
137
+ </ContentWrapper>
138
+ </>
139
+ )
89
140
 
90
- return (
91
- <Box
92
- display="flex"
93
- flexDirection="column"
94
- alignItems="center"
95
- width={width}
141
+ return (
142
+ <StyledBox sx={{ width, height }}>
143
+ <StyledButton
144
+ {...restProps}
145
+ variant={variant}
146
+ onClick={handleButtonClick}
147
+ disabled={isDisabled}
148
+ disableElevation
149
+ disableRipple
150
+ fullWidth
151
+ backgroundcolor={backgroundcolor}
152
+ iconlocation={iconlocation}
153
+ fontlocation={fontlocation}
154
+ sx={sx}
96
155
  >
97
- <Button
98
- {...restProps}
99
- variant={variant}
100
- onClick={handleButtonClick}
101
- style={{
102
- ...buttonStyle,
103
- flexDirection: iconlocation === 'above' ? 'column' : 'row',
104
- justifyContent:
105
- fontlocation === 'left'
106
- ? 'flex-start'
107
- : fontlocation === 'right'
108
- ? 'flex-end'
109
- : 'center',
110
- }}
111
- disabled={isDisabled}
112
- >
113
- {buttonContent}
114
- </Button>
115
- </Box>
116
- )
117
- },
118
- (prevProps, nextProps) => {
119
- const propsAreEqual =
120
- prevProps.text === nextProps.text &&
121
- prevProps.variant === nextProps.variant &&
122
- prevProps.fontvariant === nextProps.fontvariant &&
123
- prevProps.onClick === nextProps.onClick &&
124
- prevProps.fontcolor === nextProps.fontcolor &&
125
- prevProps.backgroundcolor === nextProps.backgroundcolor &&
126
- prevProps.width === nextProps.width &&
127
- prevProps.disableButton === nextProps.disableButton &&
128
- prevProps.icon === nextProps.icon &&
129
- prevProps.iconcolor === nextProps.iconcolor &&
130
- prevProps.iconsize === nextProps.iconsize &&
131
- prevProps.iconlocation === nextProps.iconlocation &&
132
- prevProps.fontlocation === nextProps.fontlocation
133
-
134
- return propsAreEqual
135
- }
136
- )
156
+ {buttonContent}
157
+ </StyledButton>
158
+ </StyledBox>
159
+ )
160
+ }
137
161
 
138
162
  CustomButton.displayName = 'CustomButton'
139
163
  export default CustomButton
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { Checkbox } from '@mui/material'
4
4
  import React from 'react'
5
- import * as palette from '../../../styles/palette'
5
+ import * as palette from '../../styles/palette'
6
6
 
7
7
  interface DataGridCheckboxProps {
8
8
  onClick?: (event: React.MouseEvent) => void
@@ -0,0 +1,107 @@
1
+ // File: src/components/RichTextEditor/MarkdownEditor/index.tsx
2
+
3
+ import React, { useEffect, useState } from 'react'
4
+ import {
5
+ handleSwitchToRichText,
6
+ handleBoldClick,
7
+ handleItalicClick,
8
+ } from '../utils/useMarkdownEditor'
9
+ import Toolbar from '../Toolbars/Markdown'
10
+ import { Box, Divider, TextField } from '@mui/material'
11
+ import { RichTextEditorTypes } from '../types'
12
+
13
+ type MarkdownEditorProps = {
14
+ markdown: string
15
+ setMarkdown: (value: string) => void
16
+ markdownMode: boolean
17
+ setMarkdownMode: (value: boolean) => void
18
+ setNewSlateValue: (value: RichTextEditorTypes['CustomElement'][]) => void
19
+ }
20
+
21
+ const MarkdownEditor: React.FC<MarkdownEditorProps> = ({
22
+ markdown,
23
+ setMarkdown,
24
+ markdownMode,
25
+ setMarkdownMode,
26
+ setNewSlateValue,
27
+ }) => {
28
+ const [markdownValue, setMarkdownValue] = useState(markdown)
29
+ const [selectedText, setSelectedText] = useState('')
30
+
31
+ useEffect(() => {
32
+ if (!markdownMode) {
33
+ console.log('MarkdownEditor: markdownMode = ', markdownMode)
34
+ // Perform any action you want when markdownMode changes to false
35
+ }
36
+ }, [markdownMode])
37
+
38
+ useEffect(() => {
39
+ if (markdown !== markdownValue) {
40
+ setMarkdownValue(markdown)
41
+ }
42
+ }, [markdown, markdownValue])
43
+
44
+ const handleLocalMarkdownChange = (
45
+ event: React.ChangeEvent<HTMLInputElement>
46
+ ) => {
47
+ const newValue = event.target.value
48
+ setMarkdownValue(newValue)
49
+ setMarkdown(newValue)
50
+ }
51
+
52
+ const handleSwitchMode = () => {
53
+ handleSwitchToRichText(
54
+ markdown,
55
+ setNewSlateValue,
56
+ setNewSlateValue,
57
+ setMarkdownMode
58
+ )
59
+ }
60
+
61
+ const handleSelect = (event: React.SyntheticEvent<HTMLDivElement>) => {
62
+ const target = event.target as HTMLTextAreaElement
63
+ setSelectedText(
64
+ target.value.substring(target.selectionStart, target.selectionEnd)
65
+ )
66
+ }
67
+
68
+ return (
69
+ <Box
70
+ sx={{
71
+ border: '1px solid black',
72
+ borderRadius: '8px',
73
+ width: 'auto',
74
+ }}
75
+ >
76
+ <Toolbar
77
+ markdownMode={markdownMode}
78
+ setMarkdownMode={setMarkdownMode}
79
+ setMarkdown={setMarkdown}
80
+ handleBoldClick={() =>
81
+ handleBoldClick(selectedText, markdown, setMarkdown)
82
+ }
83
+ handleItalicClick={() =>
84
+ handleItalicClick(selectedText, markdown, setMarkdown)
85
+ }
86
+ switchModeLabel="RichText Mode"
87
+ onSwitchMode={handleSwitchMode}
88
+ />
89
+ <Divider sx={{ backgroundColor: 'black' }} />
90
+ <TextField
91
+ fullWidth
92
+ multiline
93
+ variant="standard"
94
+ rows={10}
95
+ value={markdownValue}
96
+ onChange={handleLocalMarkdownChange}
97
+ onSelect={handleSelect}
98
+ sx={{
99
+ boxSizing: 'border-box',
100
+ p: 1,
101
+ }}
102
+ />
103
+ </Box>
104
+ )
105
+ }
106
+
107
+ export default MarkdownEditor
@@ -0,0 +1,214 @@
1
+ import React, { useCallback, useState } from 'react'
2
+ import {
3
+ Slate,
4
+ Editable,
5
+ RenderLeafProps,
6
+ RenderElementProps,
7
+ } from 'slate-react'
8
+ import { Descendant } from 'slate'
9
+ import Toolbar from '../Toolbars/Rich'
10
+ import {
11
+ Box,
12
+ Divider,
13
+ Accordion,
14
+ AccordionSummary,
15
+ AccordionDetails,
16
+ } from '@mui/material'
17
+ import { ExpandMore } from '@mui/icons-material'
18
+ import { useRichTextEditor } from '../utils/useRichtextEditor'
19
+ import { RichTextEditorTypes } from '../types'
20
+ import Typography from '../../Typography'
21
+
22
+ export interface RichTextEditorProps {
23
+ value: Descendant[]
24
+ name?: string
25
+ label?: string
26
+ minRows?: number
27
+ onChange?: () => void
28
+ onSelectionChange?: () => void
29
+ onValueChange?: () => void
30
+ accordion?: boolean
31
+ }
32
+
33
+ const Leaf: React.FC<RenderLeafProps> = ({ attributes, children, leaf }) => {
34
+ const customLeaf = leaf as RichTextEditorTypes['CustomText']
35
+
36
+ if (customLeaf.bold) {
37
+ children = <strong>{children}</strong>
38
+ }
39
+ if (customLeaf.italic) {
40
+ children = <em>{children}</em>
41
+ }
42
+ if (customLeaf.underline) {
43
+ children = <u>{children}</u>
44
+ }
45
+ if (customLeaf.strikethrough) {
46
+ children = <s>{children}</s>
47
+ }
48
+ if (customLeaf.link) {
49
+ children = <a href={customLeaf.link}>{children}</a>
50
+ }
51
+ if (customLeaf.code) {
52
+ children = <code>{children}</code>
53
+ }
54
+ return <span {...attributes}>{children}</span>
55
+ }
56
+
57
+ export function RichTextEditor({
58
+ value,
59
+ onChange,
60
+ label,
61
+ minRows = 5,
62
+ accordion = false,
63
+ }: RichTextEditorProps) {
64
+ const {
65
+ editor,
66
+ markdownMode,
67
+ setMarkdown,
68
+ internalValue,
69
+ handleChange,
70
+ handleBoldClick,
71
+ handleItalicClick,
72
+ insertLink,
73
+ onKeyDown,
74
+ } = useRichTextEditor(value, onChange ? () => onChange() : undefined)
75
+
76
+ const [expanded, setExpanded] = useState(false)
77
+
78
+ const renderElement = useCallback(
79
+ (props: RenderElementProps) => <Element {...props} />,
80
+ []
81
+ )
82
+
83
+ const renderLeaf = useCallback(
84
+ (props: RenderLeafProps) => <Leaf {...props} />,
85
+ []
86
+ )
87
+
88
+ const handleAccordionChange = () => {
89
+ setExpanded(!expanded)
90
+ }
91
+
92
+ return (
93
+ <Box
94
+ sx={{
95
+ display: 'flex',
96
+ flexDirection: 'column',
97
+ width: '100%',
98
+ justifyContent: 'center',
99
+ }}
100
+ >
101
+ {accordion ? (
102
+ <Accordion expanded={expanded} onChange={handleAccordionChange}>
103
+ <AccordionSummary expandIcon={<ExpandMore />}>
104
+ <Typography fontvariant="merrih4">{label}</Typography>
105
+ </AccordionSummary>
106
+ <AccordionDetails>
107
+ <Box
108
+ sx={{
109
+ border: '1px solid black',
110
+ borderRadius: '8px',
111
+ width: 'auto',
112
+ }}
113
+ >
114
+ <Slate
115
+ editor={editor}
116
+ initialValue={internalValue}
117
+ onChange={handleChange}
118
+ >
119
+ <Toolbar
120
+ editor={editor}
121
+ markdownMode={markdownMode}
122
+ setMarkdown={setMarkdown}
123
+ handleBoldClick={handleBoldClick}
124
+ handleItalicClick={handleItalicClick}
125
+ handleLinkClick={insertLink}
126
+ />
127
+ <Divider sx={{ backgroundColor: 'black' }} />
128
+ <Editable
129
+ style={{ minHeight: `${minRows * 20}px` }}
130
+ onKeyDown={onKeyDown}
131
+ renderElement={renderElement}
132
+ renderLeaf={renderLeaf}
133
+ />
134
+ </Slate>
135
+ </Box>
136
+ </AccordionDetails>
137
+ </Accordion>
138
+ ) : (
139
+ <>
140
+ {label && <Typography fontvariant="merrih4">{label}</Typography>}
141
+ <Box
142
+ sx={{
143
+ border: '1px solid black',
144
+ borderRadius: '8px',
145
+ width: 'auto',
146
+ }}
147
+ >
148
+ <Slate
149
+ editor={editor}
150
+ initialValue={internalValue}
151
+ onChange={handleChange}
152
+ >
153
+ <Toolbar
154
+ editor={editor}
155
+ markdownMode={markdownMode}
156
+ setMarkdown={setMarkdown}
157
+ handleBoldClick={handleBoldClick}
158
+ handleItalicClick={handleItalicClick}
159
+ handleLinkClick={insertLink}
160
+ />
161
+ <Divider sx={{ backgroundColor: 'black' }} />
162
+ <Editable
163
+ style={{ minHeight: `${minRows * 20}px` }}
164
+ onKeyDown={onKeyDown}
165
+ renderElement={renderElement}
166
+ renderLeaf={renderLeaf}
167
+ />
168
+ </Slate>
169
+ </Box>
170
+ </>
171
+ )}
172
+ </Box>
173
+ )
174
+ }
175
+
176
+ const Element = ({ attributes, children, element }: RenderElementProps) => {
177
+ const customElement = element as RichTextEditorTypes['CustomElement']
178
+ if (!customElement.type) return null
179
+ const style = { textAlign: customElement.align }
180
+ switch (customElement.type) {
181
+ case 'list-item':
182
+ return (
183
+ <li style={style} {...attributes}>
184
+ {children}
185
+ </li>
186
+ )
187
+ case 'link':
188
+ return (
189
+ <a href={customElement.url} {...attributes}>
190
+ {children}
191
+ </a>
192
+ )
193
+ case 'bulleted-list':
194
+ return (
195
+ <ul style={style} {...attributes}>
196
+ {children}
197
+ </ul>
198
+ )
199
+ case 'numbered-list':
200
+ return (
201
+ <ol style={style} {...attributes}>
202
+ {children}
203
+ </ol>
204
+ )
205
+ default:
206
+ return (
207
+ <p style={style} {...attributes}>
208
+ {children}
209
+ </p>
210
+ )
211
+ }
212
+ }
213
+
214
+ export default RichTextEditor