goobs-frontend 0.8.2 → 0.8.4
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 +15 -15
- package/src/components/DateField/index.tsx +4 -2
- package/src/components/Dropdown/index.tsx +41 -52
- package/src/components/Nav/VerticalVariant/index.tsx +12 -3
- package/src/components/Searchbar/index.tsx +14 -13
- package/src/components/Toolbar/index.tsx +3 -2
- package/src/components/TransferList/index.tsx +23 -20
- package/src/index.ts +4 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "goobs-frontend",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.4",
|
|
4
4
|
"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.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -21,31 +21,31 @@
|
|
|
21
21
|
"@emotion/cache": "^11.13.1",
|
|
22
22
|
"@emotion/react": "^11.13.3",
|
|
23
23
|
"@emotion/styled": "^11.13.0",
|
|
24
|
-
"@mui/icons-material": "^6.1.
|
|
25
|
-
"@mui/material": "^6.1.
|
|
26
|
-
"@types/lodash": "^4.17.
|
|
24
|
+
"@mui/icons-material": "^6.1.1",
|
|
25
|
+
"@mui/material": "^6.1.1",
|
|
26
|
+
"@types/lodash": "^4.17.9",
|
|
27
27
|
"highlight.js": "^11.10.0",
|
|
28
|
-
"jotai": "^2.
|
|
28
|
+
"jotai": "^2.10.0",
|
|
29
29
|
"lodash": "^4.17.21",
|
|
30
|
-
"next": "14.2.
|
|
31
|
-
"react-datepicker": "^7.
|
|
30
|
+
"next": "14.2.13",
|
|
31
|
+
"react-datepicker": "^7.4.0",
|
|
32
32
|
"react-qr-code": "^2.0.15"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@next/eslint-plugin-next": "^14.2.
|
|
36
|
-
"@types/node": "^22.
|
|
37
|
-
"@types/react": "18.3.
|
|
35
|
+
"@next/eslint-plugin-next": "^14.2.13",
|
|
36
|
+
"@types/node": "^22.7.3",
|
|
37
|
+
"@types/react": "18.3.9",
|
|
38
38
|
"@types/react-dom": "^18.3.0",
|
|
39
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
40
|
-
"@typescript-eslint/parser": "^8.
|
|
41
|
-
"eslint": "^9.
|
|
42
|
-
"eslint-config-next": "^14.2.
|
|
39
|
+
"@typescript-eslint/eslint-plugin": "^8.7.0",
|
|
40
|
+
"@typescript-eslint/parser": "^8.7.0",
|
|
41
|
+
"eslint": "^9.11.1",
|
|
42
|
+
"eslint-config-next": "^14.2.13",
|
|
43
43
|
"eslint-config-prettier": "^9.1.0",
|
|
44
44
|
"eslint-plugin-prettier": "^5.2.1",
|
|
45
45
|
"prettier": "^3.3.3",
|
|
46
46
|
"react": "^18.3.1",
|
|
47
47
|
"react-dom": "^18.3.1",
|
|
48
|
-
"typescript": "^5.
|
|
48
|
+
"typescript": "^5.6.2"
|
|
49
49
|
},
|
|
50
50
|
"files": [
|
|
51
51
|
"src"
|
|
@@ -7,7 +7,7 @@ import 'react-datepicker/dist/react-datepicker.css'
|
|
|
7
7
|
import CalendarTodayIcon from '@mui/icons-material/CalendarToday'
|
|
8
8
|
|
|
9
9
|
export interface DateFieldProps extends Omit<TextFieldProps, 'onChange'> {
|
|
10
|
-
onChange?: () => void
|
|
10
|
+
onChange?: (date: Date) => void
|
|
11
11
|
backgroundcolor?: string
|
|
12
12
|
outlinecolor?: string
|
|
13
13
|
fontcolor?: string
|
|
@@ -58,7 +58,9 @@ const DateField: React.FC<DateFieldProps> = ({
|
|
|
58
58
|
|
|
59
59
|
const handleChange = (dates: [Date | null, Date | null]) => {
|
|
60
60
|
setDateRange(dates)
|
|
61
|
-
|
|
61
|
+
if (dates[0]) {
|
|
62
|
+
onChange?.(dates[0])
|
|
63
|
+
}
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
const formatDateRange = (range: [Date | null, Date | null]) => {
|
|
@@ -6,70 +6,35 @@ import {
|
|
|
6
6
|
InputLabel,
|
|
7
7
|
SelectProps,
|
|
8
8
|
FormHelperText,
|
|
9
|
+
Typography,
|
|
9
10
|
} from '@mui/material'
|
|
10
11
|
import { styled } from '@mui/material/styles'
|
|
11
12
|
|
|
12
|
-
export interface
|
|
13
|
+
export interface SimpleDropdownOption {
|
|
13
14
|
value: string
|
|
14
|
-
label: string
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
export interface ComplexDropdownOption extends SimpleDropdownOption {
|
|
18
|
+
attribute1?: string
|
|
19
|
+
attribute2?: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type DropdownOption = SimpleDropdownOption | ComplexDropdownOption
|
|
23
|
+
|
|
17
24
|
export interface DropdownProps extends Omit<SelectProps, 'onChange'> {
|
|
18
|
-
/**
|
|
19
|
-
* The label for the dropdown.
|
|
20
|
-
*/
|
|
21
25
|
label: string
|
|
22
|
-
/**
|
|
23
|
-
* The options for the dropdown.
|
|
24
|
-
*/
|
|
25
26
|
options: DropdownOption[]
|
|
26
|
-
/**
|
|
27
|
-
* The default value for the dropdown.
|
|
28
|
-
*/
|
|
29
27
|
defaultValue?: string
|
|
30
|
-
/**
|
|
31
|
-
* The background color of the dropdown.
|
|
32
|
-
*/
|
|
33
28
|
backgroundcolor?: string
|
|
34
|
-
/**
|
|
35
|
-
* The outline color of the dropdown.
|
|
36
|
-
*/
|
|
37
29
|
outlinecolor?: string
|
|
38
|
-
/**
|
|
39
|
-
* The font color of the dropdown.
|
|
40
|
-
*/
|
|
41
30
|
fontcolor?: string
|
|
42
|
-
/**
|
|
43
|
-
* The font color of the dropdown label when shrunk.
|
|
44
|
-
*/
|
|
45
31
|
shrunkfontcolor?: string
|
|
46
|
-
/**
|
|
47
|
-
* Callback function triggered when the dropdown value changes.
|
|
48
|
-
*/
|
|
49
32
|
onChange?: SelectProps['onChange']
|
|
50
|
-
/**
|
|
51
|
-
* Indicates if the dropdown is in an error state.
|
|
52
|
-
*/
|
|
53
33
|
error?: boolean
|
|
54
|
-
/**
|
|
55
|
-
* The helper text to display below the dropdown.
|
|
56
|
-
*/
|
|
57
34
|
helperText?: string
|
|
58
|
-
/**
|
|
59
|
-
* The name of the dropdown.
|
|
60
|
-
*/
|
|
61
35
|
name?: string
|
|
62
|
-
/**
|
|
63
|
-
* Indicates if the dropdown is required.
|
|
64
|
-
*/
|
|
65
36
|
required?: boolean
|
|
66
|
-
/**
|
|
67
|
-
* Callback function triggered when the dropdown loses focus.
|
|
68
|
-
*/
|
|
69
37
|
onBlur?: SelectProps['onBlur']
|
|
70
|
-
/**
|
|
71
|
-
* Callback function triggered when the dropdown receives focus.
|
|
72
|
-
*/
|
|
73
38
|
onFocus?: SelectProps['onFocus']
|
|
74
39
|
}
|
|
75
40
|
|
|
@@ -100,9 +65,16 @@ const StyledInputLabel = styled(InputLabel)<{ shrunkfontcolor?: string }>(
|
|
|
100
65
|
})
|
|
101
66
|
)
|
|
102
67
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
68
|
+
const StyledMenuItem = styled(MenuItem)(({ theme }) => ({
|
|
69
|
+
display: 'flex',
|
|
70
|
+
flexDirection: 'column',
|
|
71
|
+
alignItems: 'flex-start',
|
|
72
|
+
}))
|
|
73
|
+
|
|
74
|
+
const capitalizeFirstLetter = (string: string) => {
|
|
75
|
+
return string.charAt(0).toUpperCase() + string.slice(1)
|
|
76
|
+
}
|
|
77
|
+
|
|
106
78
|
const Dropdown: React.FC<DropdownProps> = ({
|
|
107
79
|
label,
|
|
108
80
|
options,
|
|
@@ -139,6 +111,27 @@ const Dropdown: React.FC<DropdownProps> = ({
|
|
|
139
111
|
onFocus?.(event)
|
|
140
112
|
}
|
|
141
113
|
|
|
114
|
+
const renderMenuItem = (option: DropdownOption) => {
|
|
115
|
+
const label = capitalizeFirstLetter(option.value.replace(/_/g, ' '))
|
|
116
|
+
if (!('attribute1' in option)) {
|
|
117
|
+
return (
|
|
118
|
+
<MenuItem key={option.value} value={option.value}>
|
|
119
|
+
{label}
|
|
120
|
+
</MenuItem>
|
|
121
|
+
)
|
|
122
|
+
} else {
|
|
123
|
+
return (
|
|
124
|
+
<StyledMenuItem key={option.value} value={option.value}>
|
|
125
|
+
<Typography variant="body1">{label}</Typography>
|
|
126
|
+
<Typography variant="caption" color="textSecondary">
|
|
127
|
+
{option.attribute1}
|
|
128
|
+
{option.attribute2 && ` | ${option.attribute2}`}
|
|
129
|
+
</Typography>
|
|
130
|
+
</StyledMenuItem>
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
142
135
|
return (
|
|
143
136
|
<StyledFormControl
|
|
144
137
|
backgroundcolor={backgroundcolor}
|
|
@@ -161,11 +154,7 @@ const Dropdown: React.FC<DropdownProps> = ({
|
|
|
161
154
|
aria-labelledby={`${name}-label`}
|
|
162
155
|
{...rest}
|
|
163
156
|
>
|
|
164
|
-
{options.map(
|
|
165
|
-
<MenuItem key={option.value} value={option.value}>
|
|
166
|
-
{option.label}
|
|
167
|
-
</MenuItem>
|
|
168
|
-
))}
|
|
157
|
+
{options.map(renderMenuItem)}
|
|
169
158
|
</Select>
|
|
170
159
|
{helperText && <FormHelperText>{helperText}</FormHelperText>}
|
|
171
160
|
</StyledFormControl>
|
|
@@ -62,6 +62,7 @@ function VerticalVariant({
|
|
|
62
62
|
}: VerticalVariantProps) {
|
|
63
63
|
const router = useRouter()
|
|
64
64
|
const [selectedNav, setSelectedNav] = useState<string | null>(null)
|
|
65
|
+
const [searchValue, setSearchValue] = useState('')
|
|
65
66
|
|
|
66
67
|
const navOptions = items
|
|
67
68
|
.filter((item): item is NavProps => 'title' in item && 'subnavs' in item)
|
|
@@ -92,6 +93,15 @@ function VerticalVariant({
|
|
|
92
93
|
[]
|
|
93
94
|
)
|
|
94
95
|
|
|
96
|
+
const handleSearchChange = useCallback(
|
|
97
|
+
(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
98
|
+
const newValue = e.target.value
|
|
99
|
+
setSearchValue(newValue)
|
|
100
|
+
console.log('Search value changed to:', newValue)
|
|
101
|
+
},
|
|
102
|
+
[]
|
|
103
|
+
)
|
|
104
|
+
|
|
95
105
|
const renderItem = useCallback(
|
|
96
106
|
(
|
|
97
107
|
item: NavProps | SubNav | View,
|
|
@@ -390,9 +400,8 @@ function VerticalVariant({
|
|
|
390
400
|
outlinecolor="none"
|
|
391
401
|
fontcolor={white.main}
|
|
392
402
|
placeholder="Search..."
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
}}
|
|
403
|
+
value={searchValue}
|
|
404
|
+
onChange={handleSearchChange}
|
|
396
405
|
/>
|
|
397
406
|
)}
|
|
398
407
|
</Stack>
|
|
@@ -9,13 +9,14 @@ export interface SearchbarProps {
|
|
|
9
9
|
outlinecolor?: string
|
|
10
10
|
fontcolor?: string
|
|
11
11
|
placeholder?: string
|
|
12
|
-
|
|
12
|
+
value: string
|
|
13
|
+
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
const StyledTextField = styled(TextField)<{
|
|
16
17
|
backgroundcolor?: string
|
|
17
18
|
outlinecolor?: string
|
|
18
|
-
$fontcolor?: string
|
|
19
|
+
$fontcolor?: string
|
|
19
20
|
}>(({ theme, backgroundcolor, outlinecolor, $fontcolor }) => ({
|
|
20
21
|
'& .MuiOutlinedInput-root': {
|
|
21
22
|
backgroundColor: backgroundcolor || theme.palette.background.paper,
|
|
@@ -47,12 +48,9 @@ const Searchbar: React.FC<SearchbarProps> = ({
|
|
|
47
48
|
outlinecolor,
|
|
48
49
|
fontcolor,
|
|
49
50
|
placeholder,
|
|
51
|
+
value,
|
|
50
52
|
onChange,
|
|
51
53
|
}) => {
|
|
52
|
-
const handleChange = () => {
|
|
53
|
-
onChange?.()
|
|
54
|
-
}
|
|
55
|
-
|
|
56
54
|
return (
|
|
57
55
|
<StyledTextField
|
|
58
56
|
label={label}
|
|
@@ -62,14 +60,17 @@ const Searchbar: React.FC<SearchbarProps> = ({
|
|
|
62
60
|
backgroundcolor={backgroundcolor}
|
|
63
61
|
outlinecolor={outlinecolor}
|
|
64
62
|
$fontcolor={fontcolor}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
63
|
+
value={value}
|
|
64
|
+
onChange={onChange}
|
|
65
|
+
slotProps={{
|
|
66
|
+
input: {
|
|
67
|
+
startAdornment: (
|
|
68
|
+
<InputAdornment position="start">
|
|
69
|
+
<SearchIcon style={{ color: iconcolor }} />
|
|
70
|
+
</InputAdornment>
|
|
71
|
+
),
|
|
72
|
+
},
|
|
71
73
|
}}
|
|
72
|
-
onChange={handleChange}
|
|
73
74
|
/>
|
|
74
75
|
)
|
|
75
76
|
}
|
|
@@ -20,7 +20,7 @@ const VerticalDivider = styled(Box)({
|
|
|
20
20
|
export interface ToolbarProps {
|
|
21
21
|
buttons?: CustomButtonProps[]
|
|
22
22
|
dropdowns?: DropdownProps[]
|
|
23
|
-
searchbarProps?: SearchbarProps
|
|
23
|
+
searchbarProps?: Partial<SearchbarProps>
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
@@ -106,7 +106,8 @@ function CustomToolbar({ buttons, dropdowns, searchbarProps }: ToolbarProps) {
|
|
|
106
106
|
label="Search the DataGrid"
|
|
107
107
|
fontcolor={black.main}
|
|
108
108
|
iconcolor={black.main}
|
|
109
|
-
|
|
109
|
+
value={searchbarProps?.value || ''}
|
|
110
|
+
onChange={searchbarProps?.onChange || (() => {})}
|
|
110
111
|
{...searchbarProps}
|
|
111
112
|
/>
|
|
112
113
|
</Box>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import React from 'react'
|
|
3
|
+
import React, { useEffect } from 'react'
|
|
4
4
|
import Grid from '@mui/material/Grid'
|
|
5
5
|
import List from '@mui/material/List'
|
|
6
6
|
import ListItemButton from '@mui/material/ListItemButton'
|
|
@@ -21,7 +21,7 @@ function intersection(a: readonly string[], b: readonly string[]) {
|
|
|
21
21
|
export interface TransferListProps {
|
|
22
22
|
leftItems: readonly string[]
|
|
23
23
|
rightItems: readonly string[]
|
|
24
|
-
onChange
|
|
24
|
+
onChange: (leftItems: string[], rightItems: string[]) => void
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
const TransferList: React.FC<TransferListProps> = ({
|
|
@@ -33,6 +33,11 @@ const TransferList: React.FC<TransferListProps> = ({
|
|
|
33
33
|
const [left, setLeft] = React.useState<readonly string[]>(leftItems)
|
|
34
34
|
const [right, setRight] = React.useState<readonly string[]>(rightItems)
|
|
35
35
|
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
setLeft(leftItems)
|
|
38
|
+
setRight(rightItems)
|
|
39
|
+
}, [leftItems, rightItems])
|
|
40
|
+
|
|
36
41
|
const leftChecked = intersection(checked, left)
|
|
37
42
|
const rightChecked = intersection(checked, right)
|
|
38
43
|
|
|
@@ -50,37 +55,35 @@ const TransferList: React.FC<TransferListProps> = ({
|
|
|
50
55
|
}
|
|
51
56
|
|
|
52
57
|
const handleAllRight = () => {
|
|
53
|
-
|
|
58
|
+
const newRight = right.concat(left)
|
|
59
|
+
setRight(newRight)
|
|
54
60
|
setLeft([])
|
|
55
|
-
|
|
56
|
-
onChange()
|
|
57
|
-
}
|
|
61
|
+
onChange([], newRight)
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
const handleCheckedRight = () => {
|
|
61
|
-
|
|
62
|
-
|
|
65
|
+
const newRight = right.concat(leftChecked)
|
|
66
|
+
const newLeft = not(left, leftChecked)
|
|
67
|
+
setRight(newRight)
|
|
68
|
+
setLeft(newLeft)
|
|
63
69
|
setChecked(not(checked, leftChecked))
|
|
64
|
-
|
|
65
|
-
onChange()
|
|
66
|
-
}
|
|
70
|
+
onChange(newLeft, newRight)
|
|
67
71
|
}
|
|
68
72
|
|
|
69
73
|
const handleCheckedLeft = () => {
|
|
70
|
-
|
|
71
|
-
|
|
74
|
+
const newLeft = left.concat(rightChecked)
|
|
75
|
+
const newRight = not(right, rightChecked)
|
|
76
|
+
setLeft(newLeft)
|
|
77
|
+
setRight(newRight)
|
|
72
78
|
setChecked(not(checked, rightChecked))
|
|
73
|
-
|
|
74
|
-
onChange()
|
|
75
|
-
}
|
|
79
|
+
onChange(newLeft, newRight)
|
|
76
80
|
}
|
|
77
81
|
|
|
78
82
|
const handleAllLeft = () => {
|
|
79
|
-
|
|
83
|
+
const newLeft = left.concat(right)
|
|
84
|
+
setLeft(newLeft)
|
|
80
85
|
setRight([])
|
|
81
|
-
|
|
82
|
-
onChange()
|
|
83
|
-
}
|
|
86
|
+
onChange(newLeft, [])
|
|
84
87
|
}
|
|
85
88
|
|
|
86
89
|
const customList = (items: readonly string[]) => (
|
package/src/index.ts
CHANGED
|
@@ -40,7 +40,7 @@ import QRCodeComponent, { QRCodeProps } from './components/QRCode'
|
|
|
40
40
|
|
|
41
41
|
// New imports
|
|
42
42
|
import DateField from './components/DateField'
|
|
43
|
-
import Dropdown from './components/Dropdown'
|
|
43
|
+
import Dropdown, { DropdownOption } from './components/Dropdown'
|
|
44
44
|
import IncrementNumberField from './components/IncrementNumberField'
|
|
45
45
|
import NumberField from './components/NumberField'
|
|
46
46
|
import PasswordField from './components/PasswordField'
|
|
@@ -71,7 +71,7 @@ import { ExtendedImageProps } from './components/Content/Structure/image/useImag
|
|
|
71
71
|
import { ExtendedConfirmationCodeInputsProps } from './components/Content/Structure/confirmationinput/useConfirmationInput'
|
|
72
72
|
import { ExtendedRadioGroupProps } from './components/Content/Structure/radiogroup/useRadioGroup'
|
|
73
73
|
import { ExtendedPhoneNumberFieldProps } from './components/Content/Structure/phoneNumber/usePhoneNumber'
|
|
74
|
-
|
|
74
|
+
import { CustomTextFieldProps } from './components/TextField'
|
|
75
75
|
// Colors
|
|
76
76
|
import {
|
|
77
77
|
moss,
|
|
@@ -267,6 +267,8 @@ export type { CustomStepperComponentProps }
|
|
|
267
267
|
export type { CustomToolbarComponentProps }
|
|
268
268
|
export type { TransferListComponentProps }
|
|
269
269
|
export type { StyledTooltipComponentProps }
|
|
270
|
+
export type { DropdownOption }
|
|
271
|
+
export type { CustomTextFieldProps }
|
|
270
272
|
|
|
271
273
|
// New type exports
|
|
272
274
|
export type { DateFieldProps }
|