goobs-frontend 0.8.17 → 0.8.19

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 (46) hide show
  1. package/package.json +13 -10
  2. package/src/components/Button/index.tsx +120 -112
  3. package/src/components/Card/index.tsx +52 -1
  4. package/src/components/Card/variants/task/index.tsx +89 -0
  5. package/src/components/Checkbox/index.tsx +1 -1
  6. package/src/components/Content/Structure/projectboard/useProjectBoard.tsx +84 -0
  7. package/src/components/Content/index.tsx +5 -0
  8. package/src/components/DataGrid/Footer/index.tsx +41 -24
  9. package/src/components/DataGrid/ManageColumn/index.tsx +1 -1
  10. package/src/components/DataGrid/ManageRow/index.tsx +19 -14
  11. package/src/components/DataGrid/Table/ColumnHeaderRow/index.tsx +152 -0
  12. package/src/components/DataGrid/Table/Rows/index.tsx +216 -0
  13. package/src/components/DataGrid/Table/index.tsx +182 -235
  14. package/src/components/DataGrid/index.tsx +122 -230
  15. package/src/components/DataGrid/types/index.ts +163 -0
  16. package/src/components/DataGrid/utils/useComputeTableResize.tsx +194 -0
  17. package/src/components/DataGrid/utils/useInitializeGrid.tsx +71 -0
  18. package/src/components/DataGrid/utils/useManageColumn.tsx +1 -1
  19. package/src/components/DataGrid/utils/useManageRow.tsx +38 -0
  20. package/src/components/DataGrid/utils/useSelectColumn.tsx +37 -0
  21. package/src/components/DataGrid/utils/useSelectRows.tsx +47 -0
  22. package/src/components/DataGrid/utils/useToolbarSearchbar.tsx +152 -0
  23. package/src/components/Dropdown/index.tsx +44 -10
  24. package/src/components/Form/DataGrid/index.tsx +4 -1
  25. package/src/components/Form/ProjectBoard/index.tsx +142 -0
  26. package/src/components/Grid/index.tsx +89 -39
  27. package/src/components/Nav/VerticalVariant/mainNav/{index.tsx → expanding.tsx} +41 -55
  28. package/src/components/Nav/VerticalVariant/mainNav/list.tsx +56 -0
  29. package/src/components/Nav/VerticalVariant/subNav/{index.tsx → expanding.tsx} +31 -53
  30. package/src/components/Nav/VerticalVariant/subNav/list.tsx +59 -0
  31. package/src/components/Nav/VerticalVariant/viewNav/index.tsx +2 -2
  32. package/src/components/Nav/index.tsx +81 -47
  33. package/src/components/ProjectBoard/AddTask/client.tsx +316 -0
  34. package/src/components/ProjectBoard/Column/index.tsx +139 -0
  35. package/src/components/ProjectBoard/ManageTask/client.tsx +421 -0
  36. package/src/components/ProjectBoard/ShowTask/client.tsx +413 -0
  37. package/src/components/ProjectBoard/index.tsx +523 -0
  38. package/src/components/ProjectBoard/jotai/task.ts +0 -0
  39. package/src/components/ProjectBoard/utils/useDragandDropColumns.tsx +200 -0
  40. package/src/components/SearchableDropdown/index.tsx +156 -239
  41. package/src/components/Tabs/index.tsx +63 -111
  42. package/src/components/Toolbar/index.tsx +159 -68
  43. package/src/components/TransferList/index.tsx +283 -74
  44. package/src/index.ts +33 -8
  45. package/src/styles/palette.ts +1 -1
  46. package/src/components/DataGrid/utils/useSearchbar.tsx +0 -122
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "goobs-frontend",
3
- "version": "0.8.17",
3
+ "version": "0.8.19",
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,28 +22,31 @@
22
22
  "@emotion/cache": "^11.14.0",
23
23
  "@emotion/react": "^11.14.0",
24
24
  "@emotion/styled": "^11.14.0",
25
- "@mui/icons-material": "^6.3.0",
26
- "@mui/material": "^6.3.0",
27
- "@types/lodash": "^4.17.13",
25
+ "@mui/icons-material": "^6.3.1",
26
+ "@mui/material": "^6.3.1",
27
+ "@types/lodash": "^4.17.14",
28
+ "formik": "^2.4.6",
28
29
  "highlight.js": "^11.11.1",
29
30
  "jotai": "^2.11.0",
30
31
  "lodash": "^4.17.21",
31
32
  "next": "15.1.3",
32
33
  "otplib": "^12.0.1",
33
- "react-datepicker": "^7.5.0",
34
+ "react-datepicker": "^7.6.0",
34
35
  "react-qr-code": "^2.0.15",
35
36
  "slate": "^0.112.0",
36
37
  "slate-dom": "^0.111.0",
37
38
  "slate-history": "^0.110.3",
38
- "slate-react": "^0.112.0"
39
+ "slate-react": "^0.112.0",
40
+ "zod": "^3.24.1",
41
+ "zod-formik-adapter": "^1.3.0"
39
42
  },
40
43
  "devDependencies": {
41
44
  "@next/eslint-plugin-next": "^15.1.3",
42
- "@types/node": "^22.10.2",
43
- "@types/react": "19.0.2",
45
+ "@types/node": "^22.10.5",
46
+ "@types/react": "19.0.3",
44
47
  "@types/react-dom": "^19.0.2",
45
- "@typescript-eslint/eslint-plugin": "^8.19.0",
46
- "@typescript-eslint/parser": "^8.19.0",
48
+ "@typescript-eslint/eslint-plugin": "^8.19.1",
49
+ "@typescript-eslint/parser": "^8.19.1",
47
50
  "eslint": "^9.17.0",
48
51
  "eslint-config-next": "^15.1.3",
49
52
  "eslint-config-prettier": "^9.1.0",
@@ -1,18 +1,29 @@
1
1
  'use client'
2
2
  import React, { JSX } from 'react'
3
3
  import { Button, Box, ButtonProps } from '@mui/material'
4
+ import { SxProps, Theme } from '@mui/system'
4
5
  import Typography from '../Typography'
5
6
  import { SvgIconProps } from '@mui/material/SvgIcon'
6
- import { styled } from '@mui/material/styles'
7
7
 
8
8
  export interface CustomButtonProps extends ButtonProps {
9
9
  text?: string
10
+ /**
11
+ * The background color for the button when not disabled.
12
+ * If `backgroundcolor` is "none", it behaves like a text button.
13
+ */
10
14
  backgroundcolor?: string
15
+ /** The text color. Defaults to white unless disabled. */
11
16
  fontcolor?: string
12
17
  fontvariant?: 'merriparagraph' | 'merrihelperfooter'
13
18
  width?: string
14
19
  height?: string
20
+ /**
21
+ * If you want to disable the button in a custom way (string),
22
+ * we unify this with MUI's `disabled` boolean.
23
+ */
15
24
  disableButton?: 'true' | 'false'
25
+
26
+ /** Optional icon to display. */
16
27
  icon?: React.ReactElement<SvgIconProps>
17
28
  iconcolor?: string
18
29
  iconsize?: string
@@ -20,87 +31,10 @@ export interface CustomButtonProps extends ButtonProps {
20
31
  fontlocation?: 'left' | 'center' | 'right'
21
32
  }
22
33
 
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
- // Determine styles based on backgroundcolor
34
- let backgroundStyles = {}
35
- if (backgroundcolor && backgroundcolor !== 'none') {
36
- backgroundStyles = {
37
- backgroundColor: backgroundcolor,
38
- '&:hover': {
39
- backgroundColor: backgroundcolor,
40
- opacity: 0.9,
41
- },
42
- }
43
- } else if (backgroundcolor === 'none') {
44
- // No background, behave like a text button
45
- backgroundStyles = {
46
- backgroundColor: 'transparent',
47
- '&:hover': {
48
- backgroundColor: 'transparent',
49
- opacity: 0.9,
50
- },
51
- }
52
- }
53
-
54
- return {
55
- minWidth: 'auto',
56
- width: '100%',
57
- height: '40px',
58
- padding: '8px 16px',
59
- display: 'flex',
60
- flexDirection: iconlocation === 'above' ? 'column' : 'row',
61
- alignItems: 'center',
62
- justifyContent:
63
- fontlocation === 'left'
64
- ? 'flex-start'
65
- : fontlocation === 'right'
66
- ? 'flex-end'
67
- : 'center',
68
- gap: '8px',
69
- ...backgroundStyles,
70
- '& .MuiButton-startIcon': {
71
- margin: 0,
72
- },
73
- '& .MuiButton-endIcon': {
74
- margin: 0,
75
- },
76
- }
77
- })
78
-
79
- const StyledBox = styled(Box)({
80
- display: 'flex',
81
- flexDirection: 'column',
82
- alignItems: 'center',
83
- width: '100%',
84
- height: '40px',
85
- minWidth: 'fit-content',
86
- })
87
-
88
- const ContentWrapper = styled(Box)<{
89
- fontlocation?: 'left' | 'center' | 'right'
90
- }>(({ fontlocation }) => ({
91
- display: 'flex',
92
- alignItems: 'center',
93
- justifyContent:
94
- fontlocation === 'left'
95
- ? 'flex-start'
96
- : fontlocation === 'right'
97
- ? 'flex-end'
98
- : 'center',
99
- width: '100%',
100
- height: '100%',
101
- gap: '8px',
102
- }))
103
-
34
+ /**
35
+ * CustomButton uses sx props for styling:
36
+ * - We define dynamic logic based on "disabled", "backgroundcolor", etc.
37
+ */
104
38
  function CustomButton({
105
39
  text,
106
40
  variant = 'contained',
@@ -117,17 +51,18 @@ function CustomButton({
117
51
  iconlocation = 'left',
118
52
  fontlocation = 'center',
119
53
  sx,
54
+ disabled,
120
55
  ...restProps
121
56
  }: CustomButtonProps): JSX.Element {
122
- const handleButtonClick = (
123
- event: React.MouseEvent<HTMLButtonElement>
124
- ): void => {
57
+ // Merge MUI's "disabled" with our "disableButton"
58
+ const isReallyDisabled = disabled || disableButton === 'true'
59
+
60
+ const handleButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
125
61
  event.preventDefault()
126
62
  onClick?.(event)
127
63
  }
128
64
 
129
- const isDisabled = disableButton === 'true'
130
-
65
+ // If user provides an icon, clone it to override color/size if desired
131
66
  const IconComponent = icon
132
67
  ? React.cloneElement(icon, {
133
68
  sx: {
@@ -140,39 +75,112 @@ function CustomButton({
140
75
  } as Partial<SvgIconProps>)
141
76
  : null
142
77
 
143
- const buttonContent = (
144
- <>
145
- {iconlocation === 'above' && IconComponent}
146
- <ContentWrapper fontlocation={fontlocation}>
147
- {iconlocation === 'left' && IconComponent}
148
- <Typography
149
- fontvariant={fontvariant}
150
- fontcolor={isDisabled ? 'grey' : fontcolor || 'white'}
151
- text={text || ''}
152
- />
153
- {iconlocation === 'right' && IconComponent}
154
- </ContentWrapper>
155
- </>
156
- )
78
+ // Construct base sx styles
79
+ const buttonSx: SxProps<Theme> = {
80
+ minWidth: 'fit-content',
81
+ width: 'auto',
82
+ height: '40px',
83
+ padding: '8px 16px',
84
+ display: 'inline-flex',
85
+ flexShrink: 0,
86
+ flexWrap: 'nowrap',
87
+ whiteSpace: 'nowrap',
88
+
89
+ flexDirection: iconlocation === 'above' ? 'column' : 'row',
90
+ alignItems: 'center',
91
+ justifyContent:
92
+ fontlocation === 'left'
93
+ ? 'flex-start'
94
+ : fontlocation === 'right'
95
+ ? 'flex-end'
96
+ : 'center',
97
+
98
+ gap: '8px',
99
+
100
+ '& .MuiButton-startIcon': { margin: 0 },
101
+ '& .MuiButton-endIcon': { margin: 0 },
102
+ }
103
+
104
+ // If disabled, force a grey background with no hover effect
105
+ if (isReallyDisabled) {
106
+ buttonSx.backgroundColor = '#cccccc'
107
+ buttonSx['&:hover'] = {
108
+ backgroundColor: '#cccccc',
109
+ opacity: 1,
110
+ cursor: 'not-allowed',
111
+ }
112
+ } else if (backgroundcolor && backgroundcolor !== 'none') {
113
+ // Normal colored background
114
+ buttonSx.backgroundColor = backgroundcolor
115
+ buttonSx['&:hover'] = {
116
+ backgroundColor: backgroundcolor,
117
+ opacity: 0.9,
118
+ }
119
+ } else if (backgroundcolor === 'none') {
120
+ // No background => text button
121
+ buttonSx.backgroundColor = 'transparent'
122
+ buttonSx['&:hover'] = {
123
+ backgroundColor: 'transparent',
124
+ opacity: 0.9,
125
+ }
126
+ }
127
+
128
+ // Merge any sx passed in from parent
129
+ const mergedSx = Array.isArray(sx)
130
+ ? [buttonSx, ...sx]
131
+ : { ...buttonSx, ...sx }
157
132
 
158
133
  return (
159
- <StyledBox sx={{ width, height }}>
160
- <StyledButton
134
+ <Box
135
+ sx={{
136
+ display: 'flex',
137
+ flexDirection: 'column',
138
+ alignItems: 'center',
139
+ width: width || 'auto',
140
+ height: height || '40px',
141
+ minWidth: 'fit-content',
142
+ }}
143
+ >
144
+ <Button
161
145
  {...restProps}
162
146
  variant={variant}
163
147
  onClick={handleButtonClick}
164
- disabled={isDisabled}
148
+ disabled={isReallyDisabled}
165
149
  disableElevation
166
150
  disableRipple
167
- fullWidth
168
- backgroundcolor={backgroundcolor}
169
- iconlocation={iconlocation}
170
- fontlocation={fontlocation}
171
- sx={sx}
151
+ sx={mergedSx}
172
152
  >
173
- {buttonContent}
174
- </StyledButton>
175
- </StyledBox>
153
+ {/* If iconlocation="above", show the icon first */}
154
+ {iconlocation === 'above' && IconComponent}
155
+
156
+ {/* The text+icon container */}
157
+ <Box
158
+ sx={{
159
+ display: 'flex',
160
+ alignItems: 'center',
161
+ justifyContent:
162
+ fontlocation === 'left'
163
+ ? 'flex-start'
164
+ : fontlocation === 'right'
165
+ ? 'flex-end'
166
+ : 'center',
167
+ width: '100%',
168
+ height: '100%',
169
+ gap: '8px',
170
+ }}
171
+ >
172
+ {iconlocation === 'left' && IconComponent}
173
+
174
+ <Typography
175
+ fontvariant={fontvariant}
176
+ fontcolor={isReallyDisabled ? 'grey' : fontcolor || 'white'}
177
+ text={text || ''}
178
+ />
179
+
180
+ {iconlocation === 'right' && IconComponent}
181
+ </Box>
182
+ </Button>
183
+ </Box>
176
184
  )
177
185
  }
178
186
 
@@ -9,10 +9,19 @@ import DetailedPricingSummary from './variants/detailedpricingsummary'
9
9
  import ProductCard from './variants/product'
10
10
  import ProductSummaryCard from './variants/productsummary'
11
11
  import DefaultCard from './variants/defaultconfig'
12
+ import TaskCard from './variants/task' // <-- NEW
12
13
  import { columnconfig } from '../Grid'
13
14
  import { CustomButtonProps } from '../Button'
14
15
 
15
- type CardProps = Omit<BoxProps, 'children'> & {
16
+ /**
17
+ * We omit children, draggable, and the drag event props from BoxProps,
18
+ * to avoid conflicts with our custom "draggable" and "onDragX" logic
19
+ * for the task variant.
20
+ */
21
+ type CardProps = Omit<
22
+ BoxProps,
23
+ 'children' | 'draggable' | 'onDragStart' | 'onDragOver' | 'onDrop'
24
+ > & {
16
25
  /** Title of the card */
17
26
  title?: string
18
27
  /** Whether to show an underline for the title */
@@ -57,6 +66,7 @@ type CardProps = Omit<BoxProps, 'children'> & {
57
66
  | 'detailedpricingsummary'
58
67
  | 'product'
59
68
  | 'productsummary'
69
+ | 'task' // <-- NEW
60
70
  /** Props for the pricing summary variant */
61
71
  pricingSummaryProps?: {
62
72
  subtotal?: string
@@ -118,6 +128,27 @@ type CardProps = Omit<BoxProps, 'children'> & {
118
128
  button1Props?: CustomButtonProps
119
129
  button2Props?: CustomButtonProps
120
130
  }
131
+ /** Props for the new "task" variant */
132
+ taskProps?: {
133
+ /** Title of the task */
134
+ title?: string
135
+ /** Description of the task */
136
+ description?: string
137
+ /** Whether the task is completed (checked) */
138
+ checked?: boolean
139
+ /** Callback when the checkbox changes */
140
+ onCheck?: (event: React.ChangeEvent<HTMLInputElement>) => void
141
+
142
+ /**
143
+ * Optional drag & drop props if you want the card itself
144
+ * to handle drag events.
145
+ * Must be booleans or DragEventHandlers, not strings like "true".
146
+ */
147
+ draggable?: boolean
148
+ onDragStart?: React.DragEventHandler<HTMLDivElement>
149
+ onDragOver?: React.DragEventHandler<HTMLDivElement>
150
+ onDrop?: React.DragEventHandler<HTMLDivElement>
151
+ }
121
152
  /** Configuration for grid columns */
122
153
  columnconfig?: columnconfig
123
154
  }
@@ -147,6 +178,7 @@ function Card({
147
178
  inventoryProps,
148
179
  productProps,
149
180
  productSummaryProps,
181
+ taskProps,
150
182
  ...rest
151
183
  }: CardProps): JSX.Element | null {
152
184
  if (variant === 'default') {
@@ -232,6 +264,25 @@ function Card({
232
264
  )
233
265
  }
234
266
 
267
+ // NEW: Return our "task" variant
268
+ if (variant === 'task') {
269
+ return (
270
+ <TaskCard
271
+ title={taskProps?.title}
272
+ description={taskProps?.description}
273
+ checked={taskProps?.checked}
274
+ onCheck={taskProps?.onCheck}
275
+ draggable={taskProps?.draggable}
276
+ onDragStart={taskProps?.onDragStart}
277
+ onDragOver={taskProps?.onDragOver}
278
+ onDrop={taskProps?.onDrop}
279
+ width={width}
280
+ height={height}
281
+ {...rest}
282
+ />
283
+ )
284
+ }
285
+
235
286
  return null
236
287
  }
237
288
 
@@ -0,0 +1,89 @@
1
+ 'use client'
2
+
3
+ import React from 'react'
4
+ import { Paper, Box, Checkbox } from '@mui/material'
5
+ import Typography from '../../../../components/Typography'
6
+
7
+ interface TaskCardProps {
8
+ title?: string
9
+ description?: string
10
+ /** Whether the card is currently checked/selected. */
11
+ checked?: boolean
12
+ /** Called when the user toggles the checkbox. */
13
+ onCheck?: (event: React.ChangeEvent<HTMLInputElement>) => void
14
+ /** Whether this card is “draggable.” Typically true only if `checked` is true. */
15
+ draggable?: boolean
16
+ /** Drag event handlers from your board logic. */
17
+ onDragStart?: (e: React.DragEvent<HTMLDivElement>) => void
18
+ onDragOver?: (e: React.DragEvent<HTMLDivElement>) => void
19
+ onDrop?: (e: React.DragEvent<HTMLDivElement>) => void
20
+
21
+ width?: string
22
+ height?: string | number
23
+ }
24
+
25
+ const TaskCard: React.FC<TaskCardProps> = ({
26
+ title = 'Task Title',
27
+ description = 'Description',
28
+ checked = false,
29
+ onCheck,
30
+ draggable = false, // default to not draggable
31
+ onDragStart,
32
+ onDragOver,
33
+ onDrop,
34
+ width = '100%',
35
+ height = 'auto',
36
+ }) => {
37
+ return (
38
+ <Paper
39
+ elevation={1}
40
+ /*
41
+ Make the entire Paper draggable if the parent says so
42
+ (based on whether it’s selected).
43
+ */
44
+ draggable={draggable}
45
+ onDragStart={onDragStart}
46
+ onDragOver={onDragOver}
47
+ onDrop={onDrop}
48
+ sx={{
49
+ position: 'relative',
50
+ display: 'flex',
51
+ flexDirection: 'column',
52
+ justifyContent: 'flex-start',
53
+ alignItems: 'flex-start',
54
+ width,
55
+ height,
56
+ p: 2,
57
+ border: '1px solid #e8e8e8',
58
+ }}
59
+ >
60
+ {/* A checkbox in the upper-right corner */}
61
+ <Checkbox
62
+ checked={checked}
63
+ onChange={onCheck}
64
+ color="primary"
65
+ sx={{
66
+ position: 'absolute',
67
+ top: 8,
68
+ right: 8,
69
+ }}
70
+ />
71
+
72
+ <Box sx={{ display: 'flex', flexDirection: 'column', marginRight: 4 }}>
73
+ <Typography
74
+ text={title}
75
+ fontcolor="black"
76
+ fontvariant="merrih5"
77
+ sx={{ marginBottom: '4px' }}
78
+ />
79
+ <Typography
80
+ text={description}
81
+ fontcolor="black"
82
+ fontvariant="merriparagraph"
83
+ />
84
+ </Box>
85
+ </Paper>
86
+ )
87
+ }
88
+
89
+ export default TaskCard
@@ -59,7 +59,7 @@ function DataGridCheckbox({
59
59
  color: palette.marine.main,
60
60
  },
61
61
  '&.Mui-disabled': {
62
- color: palette.greyborder.main,
62
+ color: palette.grey.main,
63
63
  },
64
64
  '&:hover': {
65
65
  backgroundColor: palette.marine.light,
@@ -0,0 +1,84 @@
1
+ 'use client'
2
+ import React from 'react'
3
+ import ProjectBoard, { ProjectBoardProps } from '../../../ProjectBoard'
4
+ import { columnconfig, cellconfig } from '../../../Grid'
5
+
6
+ /**
7
+ * This mirrors the pattern of your Extended*Props from useTextField, etc.
8
+ * ExtendedProjectBoardProps extends your ProjectBoardProps but also includes:
9
+ * - optional columnconfig for row/col positioning
10
+ * - optional cellconfig for styling
11
+ *
12
+ * If you’d like to pass more custom props, add them here.
13
+ */
14
+ type ExtendedColumnConfig = Omit<columnconfig, 'component'> & {
15
+ component?: columnconfig['component']
16
+ }
17
+
18
+ export interface ExtendedProjectBoardProps extends ProjectBoardProps {
19
+ columnconfig?: ExtendedColumnConfig
20
+ cellconfig?: cellconfig
21
+ }
22
+
23
+ const useProjectBoard = (grid: {
24
+ /**
25
+ * We can accept a single ExtendedProjectBoardProps or an array of them.
26
+ * This matches how your existing hooks handle single vs array items.
27
+ */
28
+ projectboard?: ExtendedProjectBoardProps | ExtendedProjectBoardProps[]
29
+ }): columnconfig | columnconfig[] | null => {
30
+ if (!grid.projectboard) return null
31
+
32
+ // This helper function converts a single ExtendedProjectBoardProps
33
+ // into a columnconfig object for your <CustomGrid> layout system.
34
+ const renderProjectBoard = (
35
+ item: ExtendedProjectBoardProps,
36
+ index: number
37
+ ): columnconfig => {
38
+ const {
39
+ columnconfig: itemColumnConfig,
40
+ cellconfig,
41
+ // In your existing `ProjectBoardProps`, you have `columns` plus any other props.
42
+ columns,
43
+ ...restProps
44
+ } = item
45
+
46
+ // Ensure columnconfig is valid
47
+ if (
48
+ !itemColumnConfig ||
49
+ typeof itemColumnConfig.row !== 'number' ||
50
+ typeof itemColumnConfig.column !== 'number'
51
+ ) {
52
+ throw new Error(
53
+ 'columnconfig must be an object with numeric row and column'
54
+ )
55
+ }
56
+
57
+ // Build the final columnconfig
58
+ const mergedConfig: columnconfig = {
59
+ ...itemColumnConfig,
60
+ cellconfig: {
61
+ ...cellconfig,
62
+ },
63
+ component: (
64
+ <ProjectBoard
65
+ key={`projectboard-${index}`}
66
+ columns={columns}
67
+ {...restProps}
68
+ />
69
+ ),
70
+ }
71
+
72
+ return mergedConfig
73
+ }
74
+
75
+ if (Array.isArray(grid.projectboard)) {
76
+ // If it's an array, map each item to a columnconfig
77
+ return grid.projectboard.map(renderProjectBoard)
78
+ } else {
79
+ // If it's a single item, just render one
80
+ return renderProjectBoard(grid.projectboard, 0)
81
+ }
82
+ }
83
+
84
+ export default useProjectBoard
@@ -72,6 +72,9 @@ import useSearchableDropdown, {
72
72
  import useAccordion, {
73
73
  ExtendedAccordionProps,
74
74
  } from './Structure/accordion/useAccordion'
75
+ import useProjectBoard, {
76
+ ExtendedProjectBoardProps,
77
+ } from './Structure/projectboard/useProjectBoard'
75
78
 
76
79
  /**
77
80
  * Props for the ContentSection component.
@@ -88,6 +91,7 @@ export interface ContentSectionProps {
88
91
  searchableDropdown?:
89
92
  | ExtendedSearchableDropdownProps
90
93
  | ExtendedSearchableDropdownProps[]
94
+ projectboard?: ExtendedProjectBoardProps | ExtendedProjectBoardProps[]
91
95
  complexeditor?: ExtendedComplexEditorProps | ExtendedComplexEditorProps[]
92
96
  typography?: TypographyProps | TypographyProps[]
93
97
  accordion?: ExtendedAccordionProps | ExtendedAccordionProps[]
@@ -156,6 +160,7 @@ const RenderContent: React.FC<
156
160
  addToColumnConfigs(useSearchableDropdown(props))
157
161
  addToColumnConfigs(useTextField(props))
158
162
  addToColumnConfigs(useDateField(props))
163
+ addToColumnConfigs(useProjectBoard(props))
159
164
  addToColumnConfigs(useAccordion(props))
160
165
  addToColumnConfigs(useCheckbox(props))
161
166
  addToColumnConfigs(usePhoneNumber(props))