@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 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 isTypeScriptProject(projectRoot) {
15
- return fs.existsSync(path.join(projectRoot, "tsconfig.json"));
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 – React component & dashboard generator")
34
- .version("1.0.0");
32
+ .description("Pushpak UI CLI – Component generator")
33
+ .version("1.1.0");
35
34
 
36
35
  /* -------------------------------------------------------
37
- INIT Install EVERYTHING
36
+ INIT (MAIN ENTRY)
38
37
  -------------------------------------------------------- */
39
38
 
40
39
  program
41
40
  .command("init")
42
- .description("Install all UI components & dashboard")
43
- .action(() => {
44
- const projectRoot = process.cwd();
45
- const srcDir = path.join(projectRoot, "src");
41
+ .description("Initialize Pushpak UI components")
42
+ .action(async () => {
43
+ await initProject();
44
+ });
46
45
 
47
- ensureReactProject(srcDir);
46
+ /* -------------------------------------------------------
47
+ INIT LOGIC
48
+ -------------------------------------------------------- */
48
49
 
49
- const isTS = isTypeScriptProject(projectRoot);
50
- const lang = isTS ? "ts" : "js";
50
+ async function initProject() {
51
+ const projectRoot = process.cwd();
51
52
 
52
- console.log(
53
- chalk.cyan(`ℹ Detected ${isTS ? "TypeScript" : "JavaScript"} project`)
54
- );
53
+ ensureReactProject(projectRoot);
55
54
 
56
- const componentsSrc = path.join(
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
- const componentsDest = path.join(srcDir, "components/ui");
66
- const dashboardDest = path.join(srcDir, "dashboard");
57
+ const lang = answers.language === "TypeScript" ? "ts" : "js";
67
58
 
68
- fs.ensureDirSync(componentsDest);
69
- fs.ensureDirSync(dashboardDest);
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
- fs.copySync(componentsSrc, componentsDest);
72
- fs.copySync(dashboardSrc, dashboardDest);
70
+ if (answers.componentTypes.includes("muiComponent")) {
71
+ installMui();
72
+ }
73
73
 
74
- console.log(chalk.green(" All UI components added"));
75
- console.log(chalk.green("✔ Dashboard added"));
76
- });
74
+ console.log(chalk.green("\n✅ Components installed successfully\n"));
75
+ }
77
76
 
78
77
  /* -------------------------------------------------------
79
- ADD → Install SINGLE component
78
+ INQUIRER QUESTIONS
80
79
  -------------------------------------------------------- */
81
80
 
82
- program
83
- .command("add <component>")
84
- .description("Install a single UI component")
85
- .action((component) => {
86
- const projectRoot = process.cwd();
87
- const srcDir = path.join(projectRoot, "src");
88
-
89
- ensureReactProject(srcDir);
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
- const isTS = isTypeScriptProject(projectRoot);
92
- const lang = isTS ? "ts" : "js";
93
- const ext = isTS ? "tsx" : "jsx";
111
+ /* -------------------------------------------------------
112
+ COPY COMPONENT FOLDER
113
+ -------------------------------------------------------- */
94
114
 
95
- const componentSrc = path.join(
96
- __dirname,
97
- `../templates/components/${lang}/${component}.${ext}`
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
- if (!fs.existsSync(componentSrc)) {
101
- console.log(
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
- fs.ensureDirSync(destDir);
141
+ console.log(
142
+ chalk.green(`✔ Added ${componentType}/${componentName}`)
143
+ );
144
+ }
111
145
 
112
- if (fs.existsSync(destFile)) {
113
- console.log(
114
- chalk.yellow(`⚠ "${component}" already exists. Skipping.`)
115
- );
116
- return;
117
- }
146
+ /* -------------------------------------------------------
147
+ INSTALL MUI (ONLY IF SELECTED)
148
+ -------------------------------------------------------- */
118
149
 
119
- fs.copySync(componentSrc, destFile);
150
+ function installMui() {
151
+ console.log(chalk.cyan("\n📦 Installing MUI dependencies...\n"));
120
152
 
121
- console.log(
122
- chalk.green(`✔ "${component}" component added`)
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.0.0",
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
+ };