goobs-frontend 0.8.9 → 0.8.11
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.
- package/package.json +7 -2
- package/src/components/Accordion/index.tsx +64 -25
- package/src/components/Button/index.tsx +89 -48
- package/src/components/Card/index.tsx +9 -19
- package/src/components/ComplexTextEditor/MarkdownEditor/index.tsx +107 -0
- package/src/components/ComplexTextEditor/RichEditor/index.tsx +214 -0
- package/src/components/ComplexTextEditor/SimpleEditor/index.tsx +65 -0
- package/src/components/ComplexTextEditor/ToolbarButton/index.tsx +111 -0
- package/src/components/ComplexTextEditor/Toolbars/Complex/index.tsx +128 -0
- package/src/components/ComplexTextEditor/Toolbars/Markdown/index.tsx +325 -0
- package/src/components/ComplexTextEditor/Toolbars/Rich/index.tsx +349 -0
- package/src/components/ComplexTextEditor/index.tsx +102 -0
- package/src/components/ComplexTextEditor/types/index.ts +43 -0
- package/src/components/ComplexTextEditor/utils/useMarkdownEditor.tsx +122 -0
- package/src/components/ComplexTextEditor/utils/useRichtextEditor.tsx +301 -0
- package/src/components/Content/Structure/complexeditor/useComplexEditor.tsx +69 -0
- package/src/components/Content/Structure/searchableDropdown/useSearchableDropdown.tsx +65 -0
- package/src/components/Content/Structure/stepper/useStepper.tsx +5 -14
- package/src/components/Content/Structure/textfield/useTextField.tsx +7 -2
- package/src/components/Content/index.tsx +13 -0
- package/src/components/DateField/index.tsx +207 -63
- package/src/components/Dropdown/index.tsx +48 -44
- package/src/components/Grid/index.tsx +131 -155
- package/src/components/Nav/VerticalVariant/index.tsx +38 -58
- package/src/components/Nav/index.tsx +16 -13
- package/src/components/SearchableDropdown/index.tsx +378 -0
- package/src/components/Stepper/index.tsx +88 -53
- package/src/components/TextField/index.tsx +109 -23
- package/src/index.ts +9 -3
- 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.
|
|
3
|
+
"version": "0.8.11",
|
|
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",
|
|
@@ -25,13 +25,18 @@
|
|
|
25
25
|
"@mui/icons-material": "^6.1.10",
|
|
26
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
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
42
|
"@next/eslint-plugin-next": "^15.0.4",
|
|
@@ -1,44 +1,83 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import React from 'react'
|
|
3
|
+
import React, { JSX } from 'react'
|
|
4
4
|
import { styled } from '@mui/material/styles'
|
|
5
5
|
import MuiAccordion, { AccordionProps } from '@mui/material/Accordion'
|
|
6
6
|
import MuiAccordionSummary, {
|
|
7
7
|
AccordionSummaryProps,
|
|
8
8
|
} from '@mui/material/AccordionSummary'
|
|
9
|
-
import MuiAccordionDetails
|
|
9
|
+
import MuiAccordionDetails, {
|
|
10
|
+
AccordionDetailsProps,
|
|
11
|
+
} from '@mui/material/AccordionDetails'
|
|
10
12
|
import { ExpandMore } from '@mui/icons-material'
|
|
11
13
|
import { black } from '../../styles/palette'
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
<
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
15
|
+
type CustomAccordionProps = Omit<AccordionProps, 'children'> & {
|
|
16
|
+
children: NonNullable<React.ReactNode>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type CustomAccordionSummaryProps = Omit<AccordionSummaryProps, 'children'> & {
|
|
20
|
+
children: NonNullable<React.ReactNode>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type CustomAccordionDetailsProps = Omit<AccordionDetailsProps, 'children'> & {
|
|
24
|
+
children: NonNullable<React.ReactNode>
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const StyledAccordion = styled(MuiAccordion)({
|
|
28
|
+
'&.MuiAccordion-root': {
|
|
29
|
+
'&:before': {
|
|
30
|
+
display: 'none',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
const StyledAccordionSummary = styled(MuiAccordionSummary)({
|
|
31
36
|
fontSize: '20px',
|
|
32
37
|
fontFamily: 'merriweather',
|
|
33
38
|
fontWeight: 500,
|
|
34
39
|
})
|
|
35
40
|
|
|
36
|
-
|
|
37
|
-
* Custom styled AccordionDetails component.
|
|
38
|
-
* Wraps MUI's AccordionDetails with custom padding based on the theme's spacing.
|
|
39
|
-
*/
|
|
40
|
-
const AccordionDetails = styled(MuiAccordionDetails)(({ theme }) => ({
|
|
41
|
+
const StyledAccordionDetails = styled(MuiAccordionDetails)(({ theme }) => ({
|
|
41
42
|
padding: theme.spacing(2),
|
|
42
43
|
}))
|
|
43
44
|
|
|
45
|
+
function Accordion({ children, ...props }: CustomAccordionProps): JSX.Element {
|
|
46
|
+
return (
|
|
47
|
+
<StyledAccordion disableGutters {...props}>
|
|
48
|
+
{children}
|
|
49
|
+
</StyledAccordion>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function AccordionSummary({
|
|
54
|
+
children,
|
|
55
|
+
...props
|
|
56
|
+
}: CustomAccordionSummaryProps): JSX.Element {
|
|
57
|
+
return (
|
|
58
|
+
<StyledAccordionSummary
|
|
59
|
+
expandIcon={<ExpandMore sx={{ color: black.main }} />}
|
|
60
|
+
{...props}
|
|
61
|
+
>
|
|
62
|
+
{children}
|
|
63
|
+
</StyledAccordionSummary>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function AccordionDetails({
|
|
68
|
+
children,
|
|
69
|
+
...props
|
|
70
|
+
}: CustomAccordionDetailsProps): JSX.Element {
|
|
71
|
+
return <StyledAccordionDetails {...props}>{children}</StyledAccordionDetails>
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
Accordion.displayName = 'Accordion'
|
|
75
|
+
AccordionSummary.displayName = 'AccordionSummary'
|
|
76
|
+
AccordionDetails.displayName = 'AccordionDetails'
|
|
77
|
+
|
|
44
78
|
export { Accordion, AccordionSummary, AccordionDetails }
|
|
79
|
+
export type {
|
|
80
|
+
CustomAccordionProps,
|
|
81
|
+
CustomAccordionSummaryProps,
|
|
82
|
+
CustomAccordionDetailsProps,
|
|
83
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
'use client'
|
|
2
|
-
import React from 'react'
|
|
3
|
-
import { Button, Box, ButtonProps
|
|
2
|
+
import React, { JSX } from 'react'
|
|
3
|
+
import { Button, Box, ButtonProps } from '@mui/material'
|
|
4
4
|
import Typography from '../Typography'
|
|
5
5
|
import { SvgIconProps } from '@mui/material/SvgIcon'
|
|
6
|
+
import { styled } from '@mui/material/styles'
|
|
6
7
|
|
|
7
8
|
export interface CustomButtonProps extends ButtonProps {
|
|
8
9
|
text?: string
|
|
@@ -19,9 +20,73 @@ export interface CustomButtonProps extends ButtonProps {
|
|
|
19
20
|
fontlocation?: 'left' | 'center' | 'right'
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
const
|
|
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
|
+
}))
|
|
61
|
+
|
|
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
|
+
})
|
|
70
|
+
|
|
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
|
+
}))
|
|
86
|
+
|
|
87
|
+
function CustomButton({
|
|
23
88
|
text,
|
|
24
|
-
variant,
|
|
89
|
+
variant = 'contained',
|
|
25
90
|
fontvariant = 'merriparagraph',
|
|
26
91
|
onClick,
|
|
27
92
|
fontcolor,
|
|
@@ -36,7 +101,7 @@ const CustomButton: React.FC<CustomButtonProps> = ({
|
|
|
36
101
|
fontlocation = 'center',
|
|
37
102
|
sx,
|
|
38
103
|
...restProps
|
|
39
|
-
})
|
|
104
|
+
}: CustomButtonProps): JSX.Element {
|
|
40
105
|
const handleButtonClick = (
|
|
41
106
|
event: React.MouseEvent<HTMLButtonElement>
|
|
42
107
|
): void => {
|
|
@@ -44,27 +109,16 @@ const CustomButton: React.FC<CustomButtonProps> = ({
|
|
|
44
109
|
onClick?.(event)
|
|
45
110
|
}
|
|
46
111
|
|
|
47
|
-
const buttonSx: SxProps<Theme> = {
|
|
48
|
-
...(backgroundcolor && { backgroundColor: backgroundcolor }),
|
|
49
|
-
...(width && { width }),
|
|
50
|
-
...(height && { height }),
|
|
51
|
-
flexDirection: iconlocation === 'above' ? 'column' : 'row',
|
|
52
|
-
justifyContent:
|
|
53
|
-
fontlocation === 'left'
|
|
54
|
-
? 'flex-start'
|
|
55
|
-
: fontlocation === 'right'
|
|
56
|
-
? 'flex-end'
|
|
57
|
-
: 'center',
|
|
58
|
-
...(sx as object),
|
|
59
|
-
}
|
|
60
|
-
|
|
61
112
|
const isDisabled = disableButton === 'true'
|
|
62
113
|
|
|
63
114
|
const IconComponent = icon
|
|
64
115
|
? React.cloneElement(icon, {
|
|
65
116
|
sx: {
|
|
66
|
-
color: iconcolor,
|
|
67
|
-
fontSize: iconsize,
|
|
117
|
+
color: iconcolor || 'inherit',
|
|
118
|
+
fontSize: iconsize || '20px',
|
|
119
|
+
minWidth: iconsize || '20px',
|
|
120
|
+
minHeight: iconsize || '20px',
|
|
121
|
+
margin: 0,
|
|
68
122
|
},
|
|
69
123
|
} as Partial<SvgIconProps>)
|
|
70
124
|
: null
|
|
@@ -72,50 +126,37 @@ const CustomButton: React.FC<CustomButtonProps> = ({
|
|
|
72
126
|
const buttonContent = (
|
|
73
127
|
<>
|
|
74
128
|
{iconlocation === 'above' && IconComponent}
|
|
75
|
-
<
|
|
76
|
-
display="flex"
|
|
77
|
-
alignItems="center"
|
|
78
|
-
justifyContent={
|
|
79
|
-
fontlocation === 'left'
|
|
80
|
-
? 'flex-start'
|
|
81
|
-
: fontlocation === 'right'
|
|
82
|
-
? 'flex-end'
|
|
83
|
-
: 'center'
|
|
84
|
-
}
|
|
85
|
-
width="100%"
|
|
86
|
-
height="100%"
|
|
87
|
-
>
|
|
129
|
+
<ContentWrapper fontlocation={fontlocation}>
|
|
88
130
|
{iconlocation === 'left' && IconComponent}
|
|
89
131
|
<Typography
|
|
90
132
|
fontvariant={fontvariant}
|
|
91
|
-
fontcolor={isDisabled ? 'grey' : fontcolor}
|
|
133
|
+
fontcolor={isDisabled ? 'grey' : fontcolor || 'white'}
|
|
92
134
|
text={text || ''}
|
|
93
135
|
/>
|
|
94
136
|
{iconlocation === 'right' && IconComponent}
|
|
95
|
-
</
|
|
137
|
+
</ContentWrapper>
|
|
96
138
|
</>
|
|
97
139
|
)
|
|
98
140
|
|
|
99
141
|
return (
|
|
100
|
-
<
|
|
101
|
-
|
|
102
|
-
flexDirection="column"
|
|
103
|
-
alignItems="center"
|
|
104
|
-
width={width}
|
|
105
|
-
height={height}
|
|
106
|
-
>
|
|
107
|
-
<Button
|
|
142
|
+
<StyledBox sx={{ width, height }}>
|
|
143
|
+
<StyledButton
|
|
108
144
|
{...restProps}
|
|
109
145
|
variant={variant}
|
|
110
146
|
onClick={handleButtonClick}
|
|
111
|
-
sx={buttonSx}
|
|
112
147
|
disabled={isDisabled}
|
|
148
|
+
disableElevation
|
|
149
|
+
disableRipple
|
|
150
|
+
fullWidth
|
|
151
|
+
backgroundcolor={backgroundcolor}
|
|
152
|
+
iconlocation={iconlocation}
|
|
153
|
+
fontlocation={fontlocation}
|
|
154
|
+
sx={sx}
|
|
113
155
|
>
|
|
114
156
|
{buttonContent}
|
|
115
|
-
</
|
|
116
|
-
</
|
|
157
|
+
</StyledButton>
|
|
158
|
+
</StyledBox>
|
|
117
159
|
)
|
|
118
160
|
}
|
|
119
161
|
|
|
120
|
-
CustomButton.displayName = 'CustomButton'
|
|
121
162
|
export default CustomButton
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React, { JSX } from 'react'
|
|
2
4
|
import { BoxProps } from '@mui/material'
|
|
3
5
|
import { CustomStepperProps } from '../Stepper'
|
|
4
6
|
import InventoryCard from './variants/inventory'
|
|
@@ -10,11 +12,7 @@ import DefaultCard from './variants/defaultconfig'
|
|
|
10
12
|
import { columnconfig } from '../Grid'
|
|
11
13
|
import { CustomButtonProps } from '../Button'
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
* Props for the Card component.
|
|
15
|
-
* Extends BoxProps from Material-UI and includes additional custom properties.
|
|
16
|
-
*/
|
|
17
|
-
export interface CardProps extends BoxProps {
|
|
15
|
+
type CardProps = Omit<BoxProps, 'children'> & {
|
|
18
16
|
/** Title of the card */
|
|
19
17
|
title?: string
|
|
20
18
|
/** Whether to show an underline for the title */
|
|
@@ -124,11 +122,7 @@ export interface CardProps extends BoxProps {
|
|
|
124
122
|
columnconfig?: columnconfig
|
|
125
123
|
}
|
|
126
124
|
|
|
127
|
-
|
|
128
|
-
* Card component that renders different card variants based on the provided props.
|
|
129
|
-
* It supports various card types including default, inventory, pricing summary, product, and more.
|
|
130
|
-
*/
|
|
131
|
-
const Card: React.FC<CardProps> = ({
|
|
125
|
+
function Card({
|
|
132
126
|
title,
|
|
133
127
|
titleUnderline = true,
|
|
134
128
|
body,
|
|
@@ -154,8 +148,7 @@ const Card: React.FC<CardProps> = ({
|
|
|
154
148
|
productProps,
|
|
155
149
|
productSummaryProps,
|
|
156
150
|
...rest
|
|
157
|
-
})
|
|
158
|
-
// Render the default card variant
|
|
151
|
+
}: CardProps): JSX.Element | null {
|
|
159
152
|
if (variant === 'default') {
|
|
160
153
|
return (
|
|
161
154
|
<DefaultCard
|
|
@@ -182,7 +175,6 @@ const Card: React.FC<CardProps> = ({
|
|
|
182
175
|
)
|
|
183
176
|
}
|
|
184
177
|
|
|
185
|
-
// Render the inventory card variant
|
|
186
178
|
if (variant === 'inventory') {
|
|
187
179
|
return (
|
|
188
180
|
<InventoryCard
|
|
@@ -196,7 +188,6 @@ const Card: React.FC<CardProps> = ({
|
|
|
196
188
|
)
|
|
197
189
|
}
|
|
198
190
|
|
|
199
|
-
// Render the simple pricing summary card variant
|
|
200
191
|
if (variant === 'pricingsummary') {
|
|
201
192
|
return (
|
|
202
193
|
<SimplePricingSummary
|
|
@@ -208,7 +199,6 @@ const Card: React.FC<CardProps> = ({
|
|
|
208
199
|
)
|
|
209
200
|
}
|
|
210
201
|
|
|
211
|
-
// Render the detailed pricing summary card variant
|
|
212
202
|
if (variant === 'detailedpricingsummary') {
|
|
213
203
|
return (
|
|
214
204
|
<DetailedPricingSummary
|
|
@@ -220,14 +210,12 @@ const Card: React.FC<CardProps> = ({
|
|
|
220
210
|
)
|
|
221
211
|
}
|
|
222
212
|
|
|
223
|
-
// Render the product card variant
|
|
224
213
|
if (variant === 'product') {
|
|
225
214
|
return (
|
|
226
215
|
<ProductCard width={width} height={height} {...productProps} {...rest} />
|
|
227
216
|
)
|
|
228
217
|
}
|
|
229
218
|
|
|
230
|
-
// Render the product summary card variant
|
|
231
219
|
if (variant === 'productsummary') {
|
|
232
220
|
return (
|
|
233
221
|
<ProductSummaryCard
|
|
@@ -244,8 +232,10 @@ const Card: React.FC<CardProps> = ({
|
|
|
244
232
|
)
|
|
245
233
|
}
|
|
246
234
|
|
|
247
|
-
// Return null if no matching variant is found
|
|
248
235
|
return null
|
|
249
236
|
}
|
|
250
237
|
|
|
238
|
+
Card.displayName = 'Card'
|
|
239
|
+
|
|
251
240
|
export default Card
|
|
241
|
+
export type { CardProps }
|
|
@@ -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
|