@pushpak_jangela/pushpak-ui-cli 1.0.0 → 1.1.2
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/bin/index.js +104 -71
- package/package.json +3 -2
- package/templates/components/ts/muiComponents/SelectComponent/index.tsx +244 -0
- package/templates/components/ts/muiComponents/SelectComponent/selectComponentProps.ts +63 -0
- package/templates/components/ts/muiComponents/SelectComponent/styledSelectComponent.tsx +63 -0
- package/templates/components/ts/uiComponents/SelectComponent/index.tsx +124 -0
- package/templates/components/ts/uiComponents/SelectComponent/selectComponentProps.ts +46 -0
- package/templates/components/ts/uiComponents/SelectComponent/styledSelectComponent.tsx +67 -0
package/bin/index.js
CHANGED
|
@@ -4,6 +4,8 @@ const { Command } = require("commander");
|
|
|
4
4
|
const chalk = require("chalk");
|
|
5
5
|
const path = require("path");
|
|
6
6
|
const fs = require("fs-extra");
|
|
7
|
+
const inquirer = require("inquirer");
|
|
8
|
+
const { execSync } = require("child_process");
|
|
7
9
|
|
|
8
10
|
const program = new Command();
|
|
9
11
|
|
|
@@ -11,11 +13,8 @@ const program = new Command();
|
|
|
11
13
|
Helpers
|
|
12
14
|
-------------------------------------------------------- */
|
|
13
15
|
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function ensureReactProject(srcDir) {
|
|
16
|
+
function ensureReactProject(projectRoot) {
|
|
17
|
+
const srcDir = path.join(projectRoot, "src");
|
|
19
18
|
if (!fs.existsSync(srcDir)) {
|
|
20
19
|
console.log(
|
|
21
20
|
chalk.red("❌ src folder not found. Run this inside a React project.")
|
|
@@ -30,98 +29,132 @@ function ensureReactProject(srcDir) {
|
|
|
30
29
|
|
|
31
30
|
program
|
|
32
31
|
.name("pushpak-ui")
|
|
33
|
-
.description("Pushpak UI CLI –
|
|
34
|
-
.version("1.
|
|
32
|
+
.description("Pushpak UI CLI – Component generator")
|
|
33
|
+
.version("1.1.0");
|
|
35
34
|
|
|
36
35
|
/* -------------------------------------------------------
|
|
37
|
-
INIT
|
|
36
|
+
INIT (MAIN ENTRY)
|
|
38
37
|
-------------------------------------------------------- */
|
|
39
38
|
|
|
40
39
|
program
|
|
41
40
|
.command("init")
|
|
42
|
-
.description("
|
|
43
|
-
.action(() => {
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
.description("Initialize Pushpak UI components")
|
|
42
|
+
.action(async () => {
|
|
43
|
+
await initProject();
|
|
44
|
+
});
|
|
46
45
|
|
|
47
|
-
|
|
46
|
+
/* -------------------------------------------------------
|
|
47
|
+
INIT LOGIC
|
|
48
|
+
-------------------------------------------------------- */
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
async function initProject() {
|
|
51
|
+
const projectRoot = process.cwd();
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
chalk.cyan(`ℹ Detected ${isTS ? "TypeScript" : "JavaScript"} project`)
|
|
54
|
-
);
|
|
53
|
+
ensureReactProject(projectRoot);
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
__dirname,
|
|
58
|
-
`../templates/components/${lang}`
|
|
59
|
-
);
|
|
60
|
-
const dashboardSrc = path.join(
|
|
61
|
-
__dirname,
|
|
62
|
-
`../templates/dashboard/${lang}`
|
|
63
|
-
);
|
|
55
|
+
const answers = await askQuestions();
|
|
64
56
|
|
|
65
|
-
|
|
66
|
-
const dashboardDest = path.join(srcDir, "dashboard");
|
|
57
|
+
const lang = answers.language === "TypeScript" ? "ts" : "js";
|
|
67
58
|
|
|
68
|
-
|
|
69
|
-
|
|
59
|
+
for (const componentType of answers.componentTypes) {
|
|
60
|
+
for (const component of answers.components) {
|
|
61
|
+
copyComponent({
|
|
62
|
+
lang,
|
|
63
|
+
componentType,
|
|
64
|
+
componentName: component,
|
|
65
|
+
projectRoot,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
70
69
|
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
if (answers.componentTypes.includes("muiComponent")) {
|
|
71
|
+
installMui();
|
|
72
|
+
}
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
});
|
|
74
|
+
console.log(chalk.green("\n✅ Components installed successfully\n"));
|
|
75
|
+
}
|
|
77
76
|
|
|
78
77
|
/* -------------------------------------------------------
|
|
79
|
-
|
|
78
|
+
INQUIRER QUESTIONS
|
|
80
79
|
-------------------------------------------------------- */
|
|
81
80
|
|
|
82
|
-
|
|
83
|
-
.
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
81
|
+
async function askQuestions() {
|
|
82
|
+
return inquirer.prompt([
|
|
83
|
+
{
|
|
84
|
+
type: "list",
|
|
85
|
+
name: "language",
|
|
86
|
+
message: "Which language do you want?",
|
|
87
|
+
choices: ["TypeScript", "JavaScript"],
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
type: "checkbox",
|
|
91
|
+
name: "componentTypes",
|
|
92
|
+
message: "Which component layers do you want?",
|
|
93
|
+
choices: [
|
|
94
|
+
{ name: "uiComponent (Plain React)", value: "uiComponent" },
|
|
95
|
+
{ name: "muiComponent (MUI-based)", value: "muiComponent" },
|
|
96
|
+
],
|
|
97
|
+
validate: (value) =>
|
|
98
|
+
value.length > 0 || "Select at least one component type",
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
type: "checkbox",
|
|
102
|
+
name: "components",
|
|
103
|
+
message: "Select components to install",
|
|
104
|
+
choices: ["Button", "Select", "Input"],
|
|
105
|
+
validate: (value) =>
|
|
106
|
+
value.length > 0 || "Select at least one component",
|
|
107
|
+
},
|
|
108
|
+
]);
|
|
109
|
+
}
|
|
90
110
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
111
|
+
/* -------------------------------------------------------
|
|
112
|
+
COPY COMPONENT FOLDER
|
|
113
|
+
-------------------------------------------------------- */
|
|
94
114
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
115
|
+
function copyComponent({ lang, componentType, componentName, projectRoot }) {
|
|
116
|
+
const src = path.join(
|
|
117
|
+
__dirname,
|
|
118
|
+
"../templates/components",
|
|
119
|
+
lang,
|
|
120
|
+
componentType,
|
|
121
|
+
componentName
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
const dest = path.join(
|
|
125
|
+
projectRoot,
|
|
126
|
+
"src/components",
|
|
127
|
+
componentType,
|
|
128
|
+
componentName
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
if (!fs.existsSync(src)) {
|
|
132
|
+
console.log(
|
|
133
|
+
chalk.red(`❌ Missing template: ${componentType}/${componentName}`)
|
|
98
134
|
);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
99
137
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
chalk.red(`❌ Component "${component}" does not exist.`)
|
|
103
|
-
);
|
|
104
|
-
process.exit(1);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const destDir = path.join(srcDir, "components/ui");
|
|
108
|
-
const destFile = path.join(destDir, `${component}.${ext}`);
|
|
138
|
+
fs.ensureDirSync(dest);
|
|
139
|
+
fs.copySync(src, dest);
|
|
109
140
|
|
|
110
|
-
|
|
141
|
+
console.log(
|
|
142
|
+
chalk.green(`✔ Added ${componentType}/${componentName}`)
|
|
143
|
+
);
|
|
144
|
+
}
|
|
111
145
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
);
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
146
|
+
/* -------------------------------------------------------
|
|
147
|
+
INSTALL MUI (ONLY IF SELECTED)
|
|
148
|
+
-------------------------------------------------------- */
|
|
118
149
|
|
|
119
|
-
|
|
150
|
+
function installMui() {
|
|
151
|
+
console.log(chalk.cyan("\n📦 Installing MUI dependencies...\n"));
|
|
120
152
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
153
|
+
execSync(
|
|
154
|
+
"npm install @mui/material @mui/icons-material @emotion/react @emotion/styled",
|
|
155
|
+
{ stdio: "inherit" }
|
|
156
|
+
);
|
|
157
|
+
}
|
|
125
158
|
|
|
126
159
|
/* -------------------------------------------------------
|
|
127
160
|
Parse CLI
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pushpak_jangela/pushpak-ui-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"bin": {
|
|
5
5
|
"pushpak-ui": "bin/index.js"
|
|
6
6
|
},
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"chalk": "^4.1.2",
|
|
17
17
|
"commander": "^14.0.2",
|
|
18
|
-
"fs-extra": "^11.3.3"
|
|
18
|
+
"fs-extra": "^11.3.3",
|
|
19
|
+
"inquirer": "^13.1.0"
|
|
19
20
|
}
|
|
20
21
|
}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import React, { useCallback, useState } from "react";
|
|
3
|
+
import { COLORS } from "@/constants/Enums";
|
|
4
|
+
import FormControl from "@mui/material/FormControl";
|
|
5
|
+
import FormHelperText from "@mui/material/FormHelperText";
|
|
6
|
+
import FormLabel from "@mui/material/FormLabel";
|
|
7
|
+
import InfoIcon from '@mui/icons-material/Info';
|
|
8
|
+
import MenuItem from "@mui/material/MenuItem";
|
|
9
|
+
import { RootState } from "@/redux/store";
|
|
10
|
+
import { SelectChangeEvent } from "@mui/material/Select";
|
|
11
|
+
import Stack from "@mui/material/Stack";
|
|
12
|
+
import StyledSelect from "./StyledSelect";
|
|
13
|
+
import { Tooltip } from "@mui/material";
|
|
14
|
+
import Typography from "@mui/material/Typography";
|
|
15
|
+
import { useSelector } from "react-redux";
|
|
16
|
+
import { initializeFieldValidation, INSelectInputProps } from "./selectComponentProps";
|
|
17
|
+
|
|
18
|
+
const INSelectInput: React.FC<INSelectInputProps> = ({
|
|
19
|
+
defaultOpen,
|
|
20
|
+
defaultValue,
|
|
21
|
+
disabled,
|
|
22
|
+
error,
|
|
23
|
+
helperText,
|
|
24
|
+
label,
|
|
25
|
+
menuItems,
|
|
26
|
+
onBlur,
|
|
27
|
+
onBlurValidator,
|
|
28
|
+
onFieldErrorChange,
|
|
29
|
+
onValueChange,
|
|
30
|
+
required,
|
|
31
|
+
selectVariant,
|
|
32
|
+
size,
|
|
33
|
+
sx,
|
|
34
|
+
value,
|
|
35
|
+
validatorOptions,
|
|
36
|
+
variant,
|
|
37
|
+
tooltipMsg,
|
|
38
|
+
}) => {
|
|
39
|
+
const mode = useSelector((state: RootState) => state.appStylesState.mode);
|
|
40
|
+
|
|
41
|
+
const [fieldValue, setFieldValue] = useState(defaultValue ?? value ?? "");
|
|
42
|
+
|
|
43
|
+
let defaultPlaceHolder = label ? `Select ${label}` : "Select";
|
|
44
|
+
|
|
45
|
+
let updatedMenuItems = (menuItems.length > 0)
|
|
46
|
+
? [{ "label": defaultPlaceHolder, "value": "" }, ...menuItems]
|
|
47
|
+
: [{ "label": defaultPlaceHolder, "value": "" }];
|
|
48
|
+
|
|
49
|
+
// const handleOnChange = useCallback(async (event: SelectChangeEvent<unknown>) => {
|
|
50
|
+
// let result:any = event.target.value;
|
|
51
|
+
|
|
52
|
+
// if (typeof onValueChange !== "undefined") onValueChange(result);
|
|
53
|
+
// setFieldValue(result);
|
|
54
|
+
|
|
55
|
+
// let validation = initializeFieldValidation();
|
|
56
|
+
|
|
57
|
+
// if (typeof onFieldErrorChange !== "undefined") onFieldErrorChange(validation);
|
|
58
|
+
// }, [onValueChange, onFieldErrorChange]);
|
|
59
|
+
|
|
60
|
+
const handleOnChange = useCallback(async (event: SelectChangeEvent<unknown>) => {
|
|
61
|
+
let result = event.target.value as string;
|
|
62
|
+
|
|
63
|
+
if (typeof onValueChange !== "undefined") onValueChange(result);
|
|
64
|
+
setFieldValue(result);
|
|
65
|
+
|
|
66
|
+
let validation = initializeFieldValidation();
|
|
67
|
+
|
|
68
|
+
if (typeof onFieldErrorChange !== "undefined") onFieldErrorChange(validation);
|
|
69
|
+
|
|
70
|
+
if (
|
|
71
|
+
result !== "" &&
|
|
72
|
+
typeof onBlurValidator !== "undefined" &&
|
|
73
|
+
typeof validatorOptions !== "undefined" &&
|
|
74
|
+
typeof onFieldErrorChange !== "undefined"
|
|
75
|
+
) {
|
|
76
|
+
await onBlurValidator(result, validatorOptions)
|
|
77
|
+
.then((result:any) => {
|
|
78
|
+
onFieldErrorChange(result)
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
}, [onValueChange, onBlurValidator, onFieldErrorChange, validatorOptions]);
|
|
82
|
+
|
|
83
|
+
const handleOnBlur = useCallback(() => {
|
|
84
|
+
let result = fieldValue;
|
|
85
|
+
|
|
86
|
+
if (fieldValue == "") {
|
|
87
|
+
result = defaultValue ?? "";
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (typeof onFieldErrorChange !== "undefined") {
|
|
91
|
+
onFieldErrorChange(initializeFieldValidation());
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (
|
|
95
|
+
required &&
|
|
96
|
+
result === "" &&
|
|
97
|
+
typeof onFieldErrorChange !== "undefined"
|
|
98
|
+
) {
|
|
99
|
+
onFieldErrorChange({
|
|
100
|
+
"helperText": `${label ?? "Field"} is mandatory`,
|
|
101
|
+
"isError": true,
|
|
102
|
+
"isVerified": false,
|
|
103
|
+
"isWarning": false,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (typeof onBlur !== "undefined") onBlur();
|
|
108
|
+
}, [onBlur, onFieldErrorChange, fieldValue, defaultValue, label, required]);
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<>
|
|
112
|
+
<FormControl
|
|
113
|
+
error={error}
|
|
114
|
+
fullWidth
|
|
115
|
+
variant={variant ?? "filled"}
|
|
116
|
+
>
|
|
117
|
+
<FormLabel>
|
|
118
|
+
<Stack
|
|
119
|
+
display="flex"
|
|
120
|
+
flexDirection="row"
|
|
121
|
+
alignItems="flex-start"
|
|
122
|
+
gap={1}
|
|
123
|
+
>
|
|
124
|
+
{
|
|
125
|
+
label &&
|
|
126
|
+
<Typography sx={{
|
|
127
|
+
fontSize: "1rem", color: (mode === "dark") ? COLORS?.CL_DR_TY : COLORS?.BGD_DR_THEME,
|
|
128
|
+
"&.MuiTypography-root": {
|
|
129
|
+
lineHeight: "1.4375em"
|
|
130
|
+
},
|
|
131
|
+
}} variant="caption">
|
|
132
|
+
{required ? `${label} *` : label}
|
|
133
|
+
</Typography>
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
{
|
|
137
|
+
tooltipMsg &&
|
|
138
|
+
<Tooltip title={tooltipMsg} placement="right-end">
|
|
139
|
+
<InfoIcon style={{ color: 'gray', fontSize: '1rem' }} />
|
|
140
|
+
</Tooltip>
|
|
141
|
+
}
|
|
142
|
+
</Stack>
|
|
143
|
+
</FormLabel>
|
|
144
|
+
|
|
145
|
+
<StyledSelect
|
|
146
|
+
defaultOpen={defaultOpen}
|
|
147
|
+
defaultValue={defaultValue}
|
|
148
|
+
disabled={disabled}
|
|
149
|
+
disableUnderline={variant ? variant === "filled" : true}
|
|
150
|
+
displayEmpty
|
|
151
|
+
error={error}
|
|
152
|
+
fullWidth
|
|
153
|
+
inputProps={{
|
|
154
|
+
"sx": {
|
|
155
|
+
"color": ((value ?? fieldValue) === "") ? "rgba(0, 0, 0, 0.5)" : "rgba(0, 0, 0, 1)",
|
|
156
|
+
"fontStyle": ((value ?? fieldValue) === "") ? "italic" : "normal",
|
|
157
|
+
"&.MuiTypography-root": {
|
|
158
|
+
lineHeight: "1.4375em"
|
|
159
|
+
},
|
|
160
|
+
}
|
|
161
|
+
}}
|
|
162
|
+
MenuProps={{
|
|
163
|
+
"MenuListProps": {
|
|
164
|
+
"sx": {
|
|
165
|
+
// "borderRadius": "5px",
|
|
166
|
+
// "padding": "0px",
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}}
|
|
170
|
+
onBlur={handleOnBlur}
|
|
171
|
+
onChange={handleOnChange}
|
|
172
|
+
required={required}
|
|
173
|
+
selectVariant={selectVariant ?? "normal"}
|
|
174
|
+
size={size}
|
|
175
|
+
sx={{
|
|
176
|
+
...sx,
|
|
177
|
+
border: error ? "1px solid #D03240" : "",
|
|
178
|
+
}}
|
|
179
|
+
value={value ?? fieldValue}
|
|
180
|
+
>
|
|
181
|
+
{
|
|
182
|
+
updatedMenuItems.map((item) => {
|
|
183
|
+
return (
|
|
184
|
+
<MenuItem
|
|
185
|
+
value={item.value}
|
|
186
|
+
key={item.value}
|
|
187
|
+
sx={{
|
|
188
|
+
"&.Mui-selected": {
|
|
189
|
+
"backgroundColor": "rgba(0, 172, 172, 0.2)",
|
|
190
|
+
},
|
|
191
|
+
"&:hover": {
|
|
192
|
+
"backgroundColor": "rgba(0, 172, 172, 0.1)",
|
|
193
|
+
},
|
|
194
|
+
"padding": "10px",
|
|
195
|
+
}}
|
|
196
|
+
>
|
|
197
|
+
{item.label}
|
|
198
|
+
</MenuItem>
|
|
199
|
+
);
|
|
200
|
+
})
|
|
201
|
+
}
|
|
202
|
+
</StyledSelect>
|
|
203
|
+
|
|
204
|
+
<FormHelperText
|
|
205
|
+
sx={{
|
|
206
|
+
"color": "#d32f2f",
|
|
207
|
+
padding: "0 0.6em",
|
|
208
|
+
}}
|
|
209
|
+
>
|
|
210
|
+
{
|
|
211
|
+
helperText
|
|
212
|
+
?
|
|
213
|
+
<Stack
|
|
214
|
+
display="flex"
|
|
215
|
+
flexDirection="row"
|
|
216
|
+
alignItems="center"
|
|
217
|
+
gap="5px"
|
|
218
|
+
marginLeft="-15px"
|
|
219
|
+
sx={{
|
|
220
|
+
"fontSize": "10px",
|
|
221
|
+
}}
|
|
222
|
+
>
|
|
223
|
+
{/* {
|
|
224
|
+
error &&
|
|
225
|
+
<ErrorIcon
|
|
226
|
+
fontSize="inherit"
|
|
227
|
+
sx={{
|
|
228
|
+
"marginTop": '-2px',
|
|
229
|
+
}}
|
|
230
|
+
/>
|
|
231
|
+
} */}
|
|
232
|
+
|
|
233
|
+
{helperText}
|
|
234
|
+
</Stack>
|
|
235
|
+
:
|
|
236
|
+
""
|
|
237
|
+
}
|
|
238
|
+
</FormHelperText>
|
|
239
|
+
</FormControl>
|
|
240
|
+
</>
|
|
241
|
+
);
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
export default React.memo(INSelectInput);
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { SxProps } from "@mui/system";
|
|
3
|
+
|
|
4
|
+
export interface MenuItem {
|
|
5
|
+
value: string | number;
|
|
6
|
+
label: string;
|
|
7
|
+
}
|
|
8
|
+
export interface FieldValidation {
|
|
9
|
+
helperText: string;
|
|
10
|
+
isError: boolean;
|
|
11
|
+
isVerified: boolean;
|
|
12
|
+
isWarning?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function initializeFieldValidation(): FieldValidation {
|
|
16
|
+
return (
|
|
17
|
+
{
|
|
18
|
+
"helperText": "",
|
|
19
|
+
"isError": false,
|
|
20
|
+
"isVerified": false,
|
|
21
|
+
"isWarning": false,
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function initializeVerifiedFieldValidation(): FieldValidation {
|
|
27
|
+
return (
|
|
28
|
+
{
|
|
29
|
+
"helperText": "",
|
|
30
|
+
"isError": false,
|
|
31
|
+
"isVerified": true,
|
|
32
|
+
"isWarning": false,
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type SelectVariant =
|
|
38
|
+
"normal" |
|
|
39
|
+
"pagination";
|
|
40
|
+
|
|
41
|
+
export interface INSelectInputProps {
|
|
42
|
+
defaultOpen?: boolean;
|
|
43
|
+
defaultValue?: string|number;
|
|
44
|
+
disabled?: boolean;
|
|
45
|
+
error?: boolean;
|
|
46
|
+
helperText?: string;
|
|
47
|
+
label?: string;
|
|
48
|
+
menuItems: MenuItem[];
|
|
49
|
+
onBlur?: () => void;
|
|
50
|
+
onBlurValidator?: (value: string, dependencies: Object) => Promise<FieldValidation>;
|
|
51
|
+
onFieldErrorChange?: (error: FieldValidation) => void;
|
|
52
|
+
onValueChange?: (value: string|number) => void;
|
|
53
|
+
required?: boolean;
|
|
54
|
+
selectVariant?: SelectVariant;
|
|
55
|
+
size?: "small" | "medium";
|
|
56
|
+
sx?: SxProps;
|
|
57
|
+
value?: any;
|
|
58
|
+
validatorOptions?: Object;
|
|
59
|
+
variant?: "filled" | "outlined" | "standard";
|
|
60
|
+
warning?: boolean;
|
|
61
|
+
tooltip?:boolean;
|
|
62
|
+
tooltipMsg?:string;
|
|
63
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import Select, { SelectProps } from "@mui/material/Select";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { SxProps } from "@mui/system";
|
|
5
|
+
import styled from "@mui/system/styled";
|
|
6
|
+
import { SelectVariant } from "./selectComponentProps";
|
|
7
|
+
|
|
8
|
+
type StyledSelectProps = SelectProps & {
|
|
9
|
+
selectVariant?: SelectVariant;
|
|
10
|
+
error?:boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const NormalSelectField: SxProps = {
|
|
14
|
+
"& .MuiSelect-select": {
|
|
15
|
+
"fontSize":"0.8rem",
|
|
16
|
+
"fontStyle":"normal",
|
|
17
|
+
"&:focus": {
|
|
18
|
+
"backgroundColor": "rgba(255, 255, 255, 1)",
|
|
19
|
+
"borderRadius": "5px",
|
|
20
|
+
},
|
|
21
|
+
"padding": "0px",
|
|
22
|
+
},
|
|
23
|
+
"& .MuiFilledInput-root": {
|
|
24
|
+
"fontStyle":"normal",
|
|
25
|
+
"background": "rgba(255, 255, 255, 1)",
|
|
26
|
+
"border": "1px solid transparent",
|
|
27
|
+
"&.Mui-error": {
|
|
28
|
+
"border": "1px solid #D03240",
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
},
|
|
32
|
+
"&.MuiInputBase-root": {
|
|
33
|
+
"fontStyle":"normal",
|
|
34
|
+
"height":"4.5vh",
|
|
35
|
+
"&.Mui-focused": {
|
|
36
|
+
"backgroundColor": "rgba(255, 255, 255, 1)",
|
|
37
|
+
},
|
|
38
|
+
"&:hover": {
|
|
39
|
+
"backgroundColor": "rgba(255, 255, 255, 1)",
|
|
40
|
+
},
|
|
41
|
+
"borderRadius": "5px",
|
|
42
|
+
"padding": "10px",
|
|
43
|
+
"border": "1px solid rgba(0, 0, 0, 0.1)",
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
"backgroundColor": "rgba(255, 255, 255, 1)",
|
|
47
|
+
"border": "1px solid rgba(0, 0, 0, 0.2)",
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const StyledSelect = styled(Select, {
|
|
51
|
+
"shouldForwardProp": (prop:any) => prop !== "selectVariant"
|
|
52
|
+
})<StyledSelectProps>(( { selectVariant, error } ) => {
|
|
53
|
+
return {
|
|
54
|
+
...(selectVariant == "normal" && NormalSelectField),
|
|
55
|
+
...(error && {
|
|
56
|
+
"& .MuiFilledInput-root": {
|
|
57
|
+
border: "1px solid #D03240",
|
|
58
|
+
},
|
|
59
|
+
})
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
export default React.memo(StyledSelect);
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import React, { useCallback, useState } from "react";
|
|
3
|
+
|
|
4
|
+
import { selectStyles } from "./styledSelectComponent";
|
|
5
|
+
import { initializeFieldValidation, INSelectInputProps } from "./selectComponentProps";
|
|
6
|
+
|
|
7
|
+
const INSelectInput: React.FC<INSelectInputProps> = ({
|
|
8
|
+
defaultValue,
|
|
9
|
+
disabled,
|
|
10
|
+
error,
|
|
11
|
+
helperText,
|
|
12
|
+
label,
|
|
13
|
+
menuItems,
|
|
14
|
+
onBlur,
|
|
15
|
+
onBlurValidator,
|
|
16
|
+
onFieldErrorChange,
|
|
17
|
+
onValueChange,
|
|
18
|
+
required,
|
|
19
|
+
value,
|
|
20
|
+
validatorOptions,
|
|
21
|
+
tooltipMsg,
|
|
22
|
+
}) => {
|
|
23
|
+
const [fieldValue, setFieldValue] = useState(
|
|
24
|
+
defaultValue ?? value ?? ""
|
|
25
|
+
);
|
|
26
|
+
const [showTooltip, setShowTooltip] = useState(false);
|
|
27
|
+
|
|
28
|
+
const placeholder = label ? `Select ${label}` : "Select";
|
|
29
|
+
|
|
30
|
+
const handleChange = useCallback(
|
|
31
|
+
async (e: React.ChangeEvent<HTMLSelectElement>) => {
|
|
32
|
+
const selectedValue = e.target.value;
|
|
33
|
+
|
|
34
|
+
setFieldValue(selectedValue);
|
|
35
|
+
onValueChange?.(selectedValue);
|
|
36
|
+
onFieldErrorChange?.(initializeFieldValidation());
|
|
37
|
+
|
|
38
|
+
if (
|
|
39
|
+
selectedValue &&
|
|
40
|
+
onBlurValidator &&
|
|
41
|
+
validatorOptions &&
|
|
42
|
+
onFieldErrorChange
|
|
43
|
+
) {
|
|
44
|
+
const validation = await onBlurValidator(
|
|
45
|
+
selectedValue,
|
|
46
|
+
validatorOptions
|
|
47
|
+
);
|
|
48
|
+
onFieldErrorChange(validation);
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
[onValueChange, onBlurValidator, validatorOptions, onFieldErrorChange]
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const handleBlur = useCallback(() => {
|
|
55
|
+
const val = fieldValue || defaultValue || "";
|
|
56
|
+
|
|
57
|
+
onFieldErrorChange?.(initializeFieldValidation());
|
|
58
|
+
|
|
59
|
+
if (required && !val) {
|
|
60
|
+
onFieldErrorChange?.({
|
|
61
|
+
helperText: `${label ?? "Field"} is mandatory`,
|
|
62
|
+
isError: true,
|
|
63
|
+
isVerified: false,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
onBlur?.();
|
|
68
|
+
}, [fieldValue, defaultValue, required, label, onBlur]);
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<div style={selectStyles.container}>
|
|
72
|
+
{label && (
|
|
73
|
+
<div style={selectStyles.labelRow}>
|
|
74
|
+
<span style={selectStyles.label}>
|
|
75
|
+
{required ? `${label} *` : label}
|
|
76
|
+
</span>
|
|
77
|
+
|
|
78
|
+
{tooltipMsg && (
|
|
79
|
+
<span
|
|
80
|
+
style={selectStyles.tooltipWrapper}
|
|
81
|
+
onMouseEnter={() => setShowTooltip(true)}
|
|
82
|
+
onMouseLeave={() => setShowTooltip(false)}
|
|
83
|
+
>
|
|
84
|
+
ⓘ
|
|
85
|
+
{showTooltip && (
|
|
86
|
+
<span style={selectStyles.tooltipText}>
|
|
87
|
+
{tooltipMsg}
|
|
88
|
+
</span>
|
|
89
|
+
)}
|
|
90
|
+
</span>
|
|
91
|
+
)}
|
|
92
|
+
</div>
|
|
93
|
+
)}
|
|
94
|
+
|
|
95
|
+
<select
|
|
96
|
+
value={value ?? fieldValue}
|
|
97
|
+
disabled={disabled}
|
|
98
|
+
onChange={handleChange}
|
|
99
|
+
onBlur={handleBlur}
|
|
100
|
+
style={{
|
|
101
|
+
...selectStyles.select,
|
|
102
|
+
...(disabled ? selectStyles.selectDisabled : {}),
|
|
103
|
+
...(error ? selectStyles.selectError : {}),
|
|
104
|
+
}}
|
|
105
|
+
>
|
|
106
|
+
<option value="" disabled>
|
|
107
|
+
{placeholder}
|
|
108
|
+
</option>
|
|
109
|
+
|
|
110
|
+
{menuItems.map((item) => (
|
|
111
|
+
<option key={item.value} value={item.value}>
|
|
112
|
+
{item.label}
|
|
113
|
+
</option>
|
|
114
|
+
))}
|
|
115
|
+
</select>
|
|
116
|
+
|
|
117
|
+
{helperText && (
|
|
118
|
+
<div style={selectStyles.helperText}>{helperText}</div>
|
|
119
|
+
)}
|
|
120
|
+
</div>
|
|
121
|
+
);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export default React.memo(INSelectInput);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
|
|
2
|
+
export interface MenuItem {
|
|
3
|
+
value: string | number;
|
|
4
|
+
label: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface FieldValidation {
|
|
8
|
+
helperText: string;
|
|
9
|
+
isError: boolean;
|
|
10
|
+
isVerified: boolean;
|
|
11
|
+
isWarning?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function initializeFieldValidation(): FieldValidation {
|
|
15
|
+
return {
|
|
16
|
+
helperText: "",
|
|
17
|
+
isError: false,
|
|
18
|
+
isVerified: false,
|
|
19
|
+
isWarning: false,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type SelectVariant = "normal" | "pagination";
|
|
24
|
+
|
|
25
|
+
export interface INSelectInputProps {
|
|
26
|
+
defaultOpen?: boolean;
|
|
27
|
+
defaultValue?: string | number;
|
|
28
|
+
disabled?: boolean;
|
|
29
|
+
error?: boolean;
|
|
30
|
+
helperText?: string;
|
|
31
|
+
label?: string;
|
|
32
|
+
menuItems: MenuItem[];
|
|
33
|
+
onBlur?: () => void;
|
|
34
|
+
onBlurValidator?: (
|
|
35
|
+
value: string,
|
|
36
|
+
dependencies: Object
|
|
37
|
+
) => Promise<FieldValidation>;
|
|
38
|
+
onFieldErrorChange?: (error: FieldValidation) => void;
|
|
39
|
+
onValueChange?: (value: string | number) => void;
|
|
40
|
+
required?: boolean;
|
|
41
|
+
selectVariant?: SelectVariant;
|
|
42
|
+
size?: "small" | "medium";
|
|
43
|
+
value?: any;
|
|
44
|
+
validatorOptions?: Object;
|
|
45
|
+
tooltipMsg?: string;
|
|
46
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// select.styles.ts
|
|
2
|
+
|
|
3
|
+
export const selectStyles = {
|
|
4
|
+
container: {
|
|
5
|
+
display: "flex",
|
|
6
|
+
flexDirection: "column" as const,
|
|
7
|
+
width: "100%",
|
|
8
|
+
},
|
|
9
|
+
|
|
10
|
+
labelRow: {
|
|
11
|
+
display: "flex",
|
|
12
|
+
alignItems: "center",
|
|
13
|
+
gap: "6px",
|
|
14
|
+
marginBottom: "6px",
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
label: {
|
|
18
|
+
fontSize: "14px",
|
|
19
|
+
fontWeight: 500,
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
tooltipWrapper: {
|
|
23
|
+
position: "relative" as const,
|
|
24
|
+
cursor: "pointer",
|
|
25
|
+
fontSize: "12px",
|
|
26
|
+
color: "gray",
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
tooltipText: {
|
|
30
|
+
position: "absolute" as const,
|
|
31
|
+
top: "-6px",
|
|
32
|
+
left: "18px",
|
|
33
|
+
backgroundColor: "#333",
|
|
34
|
+
color: "#fff",
|
|
35
|
+
padding: "6px 8px",
|
|
36
|
+
borderRadius: "4px",
|
|
37
|
+
fontSize: "11px",
|
|
38
|
+
whiteSpace: "nowrap" as const,
|
|
39
|
+
zIndex: 10,
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
select: {
|
|
43
|
+
height: "40px",
|
|
44
|
+
padding: "8px 10px",
|
|
45
|
+
fontSize: "14px",
|
|
46
|
+
borderRadius: "5px",
|
|
47
|
+
border: "1px solid rgba(0,0,0,0.2)",
|
|
48
|
+
backgroundColor: "#fff",
|
|
49
|
+
outline: "none",
|
|
50
|
+
cursor: "pointer",
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
selectDisabled: {
|
|
54
|
+
backgroundColor: "#f3f3f3",
|
|
55
|
+
cursor: "not-allowed",
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
selectError: {
|
|
59
|
+
border: "1px solid #d03240",
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
helperText: {
|
|
63
|
+
marginTop: "4px",
|
|
64
|
+
fontSize: "11px",
|
|
65
|
+
color: "#d03240",
|
|
66
|
+
},
|
|
67
|
+
};
|