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.
Files changed (30) hide show
  1. package/package.json +7 -2
  2. package/src/components/Accordion/index.tsx +64 -25
  3. package/src/components/Button/index.tsx +89 -48
  4. package/src/components/Card/index.tsx +9 -19
  5. package/src/components/ComplexTextEditor/MarkdownEditor/index.tsx +107 -0
  6. package/src/components/ComplexTextEditor/RichEditor/index.tsx +214 -0
  7. package/src/components/ComplexTextEditor/SimpleEditor/index.tsx +65 -0
  8. package/src/components/ComplexTextEditor/ToolbarButton/index.tsx +111 -0
  9. package/src/components/ComplexTextEditor/Toolbars/Complex/index.tsx +128 -0
  10. package/src/components/ComplexTextEditor/Toolbars/Markdown/index.tsx +325 -0
  11. package/src/components/ComplexTextEditor/Toolbars/Rich/index.tsx +349 -0
  12. package/src/components/ComplexTextEditor/index.tsx +102 -0
  13. package/src/components/ComplexTextEditor/types/index.ts +43 -0
  14. package/src/components/ComplexTextEditor/utils/useMarkdownEditor.tsx +122 -0
  15. package/src/components/ComplexTextEditor/utils/useRichtextEditor.tsx +301 -0
  16. package/src/components/Content/Structure/complexeditor/useComplexEditor.tsx +69 -0
  17. package/src/components/Content/Structure/searchableDropdown/useSearchableDropdown.tsx +65 -0
  18. package/src/components/Content/Structure/stepper/useStepper.tsx +5 -14
  19. package/src/components/Content/Structure/textfield/useTextField.tsx +7 -2
  20. package/src/components/Content/index.tsx +13 -0
  21. package/src/components/DateField/index.tsx +207 -63
  22. package/src/components/Dropdown/index.tsx +48 -44
  23. package/src/components/Grid/index.tsx +131 -155
  24. package/src/components/Nav/VerticalVariant/index.tsx +38 -58
  25. package/src/components/Nav/index.tsx +16 -13
  26. package/src/components/SearchableDropdown/index.tsx +378 -0
  27. package/src/components/Stepper/index.tsx +88 -53
  28. package/src/components/TextField/index.tsx +109 -23
  29. package/src/index.ts +9 -3
  30. 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.9",
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 from '@mui/material/AccordionDetails'
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
- * Custom styled Accordion component.
15
- * Wraps MUI's Accordion with custom styling and disables gutters by default.
16
- */
17
- const Accordion = styled((props: AccordionProps) => (
18
- <MuiAccordion disableGutters {...props} />
19
- ))({})
20
-
21
- /**
22
- * Custom styled AccordionSummary component.
23
- * Wraps MUI's AccordionSummary with custom styling and a custom expand icon.
24
- */
25
- const AccordionSummary = styled((props: AccordionSummaryProps) => (
26
- <MuiAccordionSummary
27
- expandIcon={<ExpandMore sx={{ color: black.main }} />}
28
- {...props}
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, SxProps, Theme } from '@mui/material'
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 CustomButton: React.FC<CustomButtonProps> = ({
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
- <Box
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
- </Box>
137
+ </ContentWrapper>
96
138
  </>
97
139
  )
98
140
 
99
141
  return (
100
- <Box
101
- display="flex"
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
- </Button>
116
- </Box>
157
+ </StyledButton>
158
+ </StyledBox>
117
159
  )
118
160
  }
119
161
 
120
- CustomButton.displayName = 'CustomButton'
121
162
  export default CustomButton
@@ -1,4 +1,6 @@
1
- import React from 'react'
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