@processhub-lib/react 1.0.3 → 1.0.5
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/dist/classnames-2Mts7qXW.js +29 -0
- package/dist/classnames-BqI3URgS.cjs +1 -0
- package/dist/context/ThemeContext.d.ts +22 -0
- package/dist/index-BkvGc2p8.cjs +30 -0
- package/dist/index-r3s8teR_.js +1170 -0
- package/dist/index.cjs.js +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.es.js +14 -0
- package/dist/scripts/generate-endpoints.d.ts +1 -0
- package/dist/style.css +1 -0
- package/dist/ui/Button/colors.d.ts +162 -0
- package/dist/ui/Button/index.d.ts +3 -0
- package/dist/ui/Button/types/button.d.ts +16 -0
- package/dist/ui/Input/index.d.ts +3 -0
- package/{src/ui/Input/types/input.ts → dist/ui/Input/types/input.d.ts} +6 -7
- package/dist/ui/Select/index.d.ts +3 -0
- package/dist/ui/Select/types/select.d.ts +16 -0
- package/dist/ui/index.d.ts +3 -0
- package/dist/ui.cjs.js +1 -0
- package/dist/ui.d.ts +1 -0
- package/dist/ui.es.js +6 -0
- package/dist/utils/applyMask.d.ts +9 -0
- package/dist/utils/classnames.d.ts +16 -0
- package/dist/utils/formatar.d.ts +62 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/isDocumento.d.ts +11 -0
- package/dist/utils.cjs.js +1 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.es.js +128 -0
- package/package.json +7 -3
- package/postcss.config.js +0 -5
- package/src/context/ThemeContext.tsx +0 -45
- package/src/index.ts +0 -4
- package/src/scripts/generate-endpoints.ts +0 -184
- package/src/style.css +0 -1
- package/src/ui/Button/colors.tsx +0 -163
- package/src/ui/Button/index.tsx +0 -45
- package/src/ui/Button/types/button.ts +0 -17
- package/src/ui/Input/index.tsx +0 -74
- package/src/ui/Select/index.tsx +0 -150
- package/src/ui/Select/types/select.ts +0 -16
- package/src/ui/index.ts +0 -3
- package/src/utils/applyMask.tsx +0 -49
- package/src/utils/classnames.tsx +0 -89
- package/src/utils/formatar.tsx +0 -173
- package/src/utils/index.ts +0 -4
- package/src/utils/isDocumento.tsx +0 -46
- package/tailwind.config.js +0 -13
- package/tsconfig.json +0 -26
- package/tsconfig.node.json +0 -10
- package/vite.config.ts +0 -31
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { fileURLToPath } from "url";
|
|
4
|
-
|
|
5
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
-
const __dirname = path.dirname(__filename);
|
|
7
|
-
|
|
8
|
-
const INPUT_FILE = path.resolve(__dirname, "../../endpoints.json");
|
|
9
|
-
const OUTPUT_FILE = path.resolve(__dirname, "../../endpoints.ts");
|
|
10
|
-
|
|
11
|
-
const KEY_MAPPING: Record<string, string> = {
|
|
12
|
-
lista: "list",
|
|
13
|
-
busca: "search",
|
|
14
|
-
incluir: "create",
|
|
15
|
-
alterar: "update",
|
|
16
|
-
deletar: "delete",
|
|
17
|
-
posicao: "position",
|
|
18
|
-
etapa: "etapas",
|
|
19
|
-
form: "form",
|
|
20
|
-
usuario: "user",
|
|
21
|
-
auth: "auth",
|
|
22
|
-
cidade: "city",
|
|
23
|
-
pais: "country",
|
|
24
|
-
provincia: "province",
|
|
25
|
-
tipo: "type",
|
|
26
|
-
status: "status",
|
|
27
|
-
pergunta: "questions",
|
|
28
|
-
lead: "lead",
|
|
29
|
-
apoio: "support",
|
|
30
|
-
organizacao: "organization",
|
|
31
|
-
atualizar: "update",
|
|
32
|
-
resposta: "response",
|
|
33
|
-
reservar: "reserve",
|
|
34
|
-
cancelar: "cancel",
|
|
35
|
-
vendedor: "seller",
|
|
36
|
-
inativar: "inactivate",
|
|
37
|
-
ativar: "activate",
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
function mapKey(key: string): string {
|
|
41
|
-
return KEY_MAPPING[key] || key;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function cleanPath(urlPath: string[]): string[] {
|
|
45
|
-
// Remove empty strings and common prefixes
|
|
46
|
-
return urlPath.filter(
|
|
47
|
-
(segment) =>
|
|
48
|
-
segment &&
|
|
49
|
-
segment !== "api" &&
|
|
50
|
-
// segment !== "v1" && // Keep version
|
|
51
|
-
!segment.startsWith("{{")
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function setNestedValue(obj: any, path: string[], value: string) {
|
|
56
|
-
let current = obj;
|
|
57
|
-
for (let i = 0; i < path.length; i++) {
|
|
58
|
-
const segment = path[i];
|
|
59
|
-
const key = mapKey(segment);
|
|
60
|
-
|
|
61
|
-
if (i === path.length - 1) {
|
|
62
|
-
// We are at the leaf, trying to set a value
|
|
63
|
-
if (current[key] && typeof current[key] === "object") {
|
|
64
|
-
// Collision: key is already an object (container)
|
|
65
|
-
// Assign to .list
|
|
66
|
-
current[key].list = value;
|
|
67
|
-
} else {
|
|
68
|
-
// If it's a string, we overwrite (or it's the first time)
|
|
69
|
-
current[key] = value;
|
|
70
|
-
}
|
|
71
|
-
} else {
|
|
72
|
-
// We are traversing down
|
|
73
|
-
if (!current[key]) {
|
|
74
|
-
current[key] = {};
|
|
75
|
-
} else if (typeof current[key] === "string") {
|
|
76
|
-
// Collision: key is a string (leaf), but we need to go deeper
|
|
77
|
-
// Convert string to object with .list
|
|
78
|
-
current[key] = { list: current[key] };
|
|
79
|
-
}
|
|
80
|
-
current = current[key];
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function generateEndpoints() {
|
|
86
|
-
try {
|
|
87
|
-
const content = fs.readFileSync(INPUT_FILE, "utf-8");
|
|
88
|
-
const collection = JSON.parse(content);
|
|
89
|
-
const endpoints: any = {};
|
|
90
|
-
|
|
91
|
-
function traverse(items: any[]) {
|
|
92
|
-
items.forEach((item) => {
|
|
93
|
-
if (item.item) {
|
|
94
|
-
traverse(item.item);
|
|
95
|
-
} else if (item.request && item.request.url) {
|
|
96
|
-
const url = item.request.url;
|
|
97
|
-
let pathSegments: string[] = [];
|
|
98
|
-
|
|
99
|
-
if (Array.isArray(url.path)) {
|
|
100
|
-
pathSegments = url.path;
|
|
101
|
-
} else if (typeof url === "string") {
|
|
102
|
-
// Handle raw string if necessary, but Postman v2.1 usually has object
|
|
103
|
-
// If it's a string we might need to parse it
|
|
104
|
-
const urlObj = new URL(
|
|
105
|
-
url.replace("{{develop}}", "http://placeholder")
|
|
106
|
-
);
|
|
107
|
-
pathSegments = urlObj.pathname.split("/").filter(Boolean);
|
|
108
|
-
} else if (url.raw) {
|
|
109
|
-
// Fallback to raw if path array is missing/empty but raw exists
|
|
110
|
-
// Remove query params
|
|
111
|
-
const rawPath = url.raw.split("?")[0];
|
|
112
|
-
pathSegments = rawPath.split("/").filter(Boolean);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const cleanedPath = cleanPath(pathSegments);
|
|
116
|
-
|
|
117
|
-
if (cleanedPath.length > 0) {
|
|
118
|
-
// Reconstruct the full path for the value
|
|
119
|
-
// We want the path starting with /api/v1...
|
|
120
|
-
// The user example shows: '/api/v1/funil/lista'
|
|
121
|
-
// So we should find where 'api' starts in the original segments
|
|
122
|
-
|
|
123
|
-
let fullPath = "";
|
|
124
|
-
if (Array.isArray(url.path)) {
|
|
125
|
-
fullPath = "/" + url.path.join("/");
|
|
126
|
-
} else if (url.raw) {
|
|
127
|
-
const urlStr = url.raw.split("?")[0];
|
|
128
|
-
// Try to extract from api/v1
|
|
129
|
-
const match = urlStr.match(/(api\/v1\/.*)/);
|
|
130
|
-
if (match) {
|
|
131
|
-
fullPath = "/" + match[1];
|
|
132
|
-
} else {
|
|
133
|
-
fullPath = urlStr;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Ensure it starts with /api/v1 if possible, or just use what we have
|
|
138
|
-
// The user example has /api/v1 prefix.
|
|
139
|
-
|
|
140
|
-
setNestedValue(endpoints, cleanedPath, fullPath);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (collection.item) {
|
|
147
|
-
traverse(collection.item);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Fix quotes to single quotes to match style if needed, but JSON.stringify uses double.
|
|
151
|
-
// The user example used single quotes for values and keys (where possible).
|
|
152
|
-
// Let's try to make it prettier.
|
|
153
|
-
|
|
154
|
-
// We can use a regex to replace double quotes with single quotes for values,
|
|
155
|
-
// and remove quotes from keys if they are valid identifiers.
|
|
156
|
-
|
|
157
|
-
// Actually, JSON.stringify is fine, but let's try to match the user's requested format strictly.
|
|
158
|
-
// The user example:
|
|
159
|
-
// export const ENDPOINTS = {
|
|
160
|
-
// funil: {
|
|
161
|
-
// list: '/api/v1/funil/lista',
|
|
162
|
-
// ...
|
|
163
|
-
|
|
164
|
-
// Let's use a custom stringifier or just simple replacement.
|
|
165
|
-
|
|
166
|
-
const finalOutput = `// ⚠️ Arquivo gerado automaticamente — NÃO EDITE
|
|
167
|
-
|
|
168
|
-
export const ENDPOINTS = ${JSON.stringify(endpoints, null, 2)
|
|
169
|
-
.replace(/"([^"]+)":/g, "$1:")
|
|
170
|
-
.replace(/: "([^"]+)"/g, ": '$1'")} as const;
|
|
171
|
-
|
|
172
|
-
type DeepValueOf<T> = T extends object ? DeepValueOf<T[keyof T]> : T;
|
|
173
|
-
export type Route = DeepValueOf<typeof ENDPOINTS>;
|
|
174
|
-
`;
|
|
175
|
-
|
|
176
|
-
fs.writeFileSync(OUTPUT_FILE, finalOutput);
|
|
177
|
-
console.log(`Successfully generated endpoints to ${OUTPUT_FILE}`);
|
|
178
|
-
} catch (error) {
|
|
179
|
-
console.error("Error generating endpoints:", error);
|
|
180
|
-
process.exit(1);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
generateEndpoints();
|
package/src/style.css
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
@import "tailwindcss";
|
package/src/ui/Button/colors.tsx
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
export const COLORS = {
|
|
2
|
-
green: {
|
|
3
|
-
solid: {
|
|
4
|
-
bg: "bg-green-500",
|
|
5
|
-
hover: "hover:bg-green-600 hover:text-white",
|
|
6
|
-
text: "text-white",
|
|
7
|
-
border: "border-green-500",
|
|
8
|
-
},
|
|
9
|
-
outline: {
|
|
10
|
-
bg: "bg-transparent",
|
|
11
|
-
hover: "hover:bg-green-600 hover:text-white",
|
|
12
|
-
text: "text-green-600",
|
|
13
|
-
border: "border-green-500",
|
|
14
|
-
},
|
|
15
|
-
ghost: {
|
|
16
|
-
bg: "bg-transparent",
|
|
17
|
-
hover: "hover:bg-green-600 hover:text-white",
|
|
18
|
-
text: "text-green-600",
|
|
19
|
-
border: "border-transparent",
|
|
20
|
-
},
|
|
21
|
-
},
|
|
22
|
-
blue: {
|
|
23
|
-
solid: {
|
|
24
|
-
bg: "bg-blue-500",
|
|
25
|
-
hover: "hover:bg-blue-600 hover:text-white",
|
|
26
|
-
text: "text-white",
|
|
27
|
-
border: "border-blue-500",
|
|
28
|
-
},
|
|
29
|
-
outline: {
|
|
30
|
-
bg: "bg-transparent",
|
|
31
|
-
hover: "hover:bg-blue-500 hover:text-white",
|
|
32
|
-
text: "text-blue-600",
|
|
33
|
-
border: "border-blue-500",
|
|
34
|
-
},
|
|
35
|
-
ghost: {
|
|
36
|
-
bg: "bg-transparent",
|
|
37
|
-
hover: "hover:bg-blue-500 hover:text-white",
|
|
38
|
-
text: "text-blue-600",
|
|
39
|
-
border: "border-transparent",
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
red: {
|
|
43
|
-
solid: {
|
|
44
|
-
bg: "bg-red-500",
|
|
45
|
-
hover: "hover:bg-red-600 hover:text-white",
|
|
46
|
-
text: "text-white",
|
|
47
|
-
border: "border-red-500",
|
|
48
|
-
},
|
|
49
|
-
outline: {
|
|
50
|
-
bg: "bg-transparent",
|
|
51
|
-
hover: "hover:bg-red-500 hover:text-white",
|
|
52
|
-
text: "text-red-600",
|
|
53
|
-
border: "border-red-500",
|
|
54
|
-
},
|
|
55
|
-
ghost: {
|
|
56
|
-
bg: "bg-transparent",
|
|
57
|
-
hover: "hover:bg-red-500 hover:text-white",
|
|
58
|
-
text: "text-red-600",
|
|
59
|
-
border: "border-transparent",
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
yellow: {
|
|
63
|
-
solid: {
|
|
64
|
-
bg: "bg-yellow-500",
|
|
65
|
-
hover: "hover:bg-yellow-600 hover:text-black",
|
|
66
|
-
text: "text-black",
|
|
67
|
-
border: "border-yellow-500",
|
|
68
|
-
},
|
|
69
|
-
outline: {
|
|
70
|
-
bg: "bg-transparent",
|
|
71
|
-
hover: "hover:bg-yellow-500 hover:text-white",
|
|
72
|
-
text: "text-yellow-600",
|
|
73
|
-
border: "border-yellow-500",
|
|
74
|
-
},
|
|
75
|
-
ghost: {
|
|
76
|
-
bg: "bg-transparent",
|
|
77
|
-
hover: "hover:bg-yellow-500 hover:text-white",
|
|
78
|
-
text: "text-yellow-600",
|
|
79
|
-
border: "border-transparent",
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
|
|
83
|
-
primary: {
|
|
84
|
-
solid: {
|
|
85
|
-
bg: "bg-primary",
|
|
86
|
-
hover: "hover:bg-primary-hover hover:text-foreground",
|
|
87
|
-
text: "text-foreground",
|
|
88
|
-
border: "border-primary",
|
|
89
|
-
},
|
|
90
|
-
outline: {
|
|
91
|
-
bg: "bg-transparent",
|
|
92
|
-
hover: "hover:bg-primary hover:text-foreground",
|
|
93
|
-
text: "text-primary",
|
|
94
|
-
border: "border-primary",
|
|
95
|
-
},
|
|
96
|
-
ghost: {
|
|
97
|
-
bg: "bg-transparent",
|
|
98
|
-
hover: "hover:bg-primary hover:text-foreground",
|
|
99
|
-
text: "text-primary",
|
|
100
|
-
border: "border-transparent",
|
|
101
|
-
},
|
|
102
|
-
},
|
|
103
|
-
secondary: {
|
|
104
|
-
solid: {
|
|
105
|
-
bg: "bg-secondary",
|
|
106
|
-
hover: "hover:bg-secondary/80 hover:text-secondary-foreground",
|
|
107
|
-
text: "text-secondary-foreground",
|
|
108
|
-
border: "border-secondary",
|
|
109
|
-
},
|
|
110
|
-
outline: {
|
|
111
|
-
bg: "bg-transparent",
|
|
112
|
-
hover: "hover:bg-secondary hover:text-secondary-foreground",
|
|
113
|
-
text: "text-secondary",
|
|
114
|
-
border: "border-secondary",
|
|
115
|
-
},
|
|
116
|
-
ghost: {
|
|
117
|
-
bg: "bg-transparent",
|
|
118
|
-
hover: "hover:bg-secondary hover:text-secondary-foreground",
|
|
119
|
-
text: "text-secondary",
|
|
120
|
-
border: "border-transparent",
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
destructive: {
|
|
124
|
-
solid: {
|
|
125
|
-
bg: "bg-destructive",
|
|
126
|
-
hover: "hover:bg-destructive/90 hover:text-destructive-foreground",
|
|
127
|
-
text: "text-destructive-foreground",
|
|
128
|
-
border: "border-destructive",
|
|
129
|
-
},
|
|
130
|
-
outline: {
|
|
131
|
-
bg: "bg-transparent",
|
|
132
|
-
hover: "hover:bg-destructive hover:text-destructive-foreground",
|
|
133
|
-
text: "text-destructive",
|
|
134
|
-
border: "border-destructive",
|
|
135
|
-
},
|
|
136
|
-
ghost: {
|
|
137
|
-
bg: "bg-transparent",
|
|
138
|
-
hover: "hover:bg-destructive hover:text-destructive-foreground",
|
|
139
|
-
text: "text-destructive",
|
|
140
|
-
border: "border-transparent",
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
card: {
|
|
144
|
-
solid: {
|
|
145
|
-
bg: "bg-card",
|
|
146
|
-
hover: "hover:bg-accent hover:text-card-foreground",
|
|
147
|
-
text: "text-card-foreground",
|
|
148
|
-
border: "border-border",
|
|
149
|
-
},
|
|
150
|
-
outline: {
|
|
151
|
-
bg: "bg-transparent",
|
|
152
|
-
hover: "hover:bg-accent hover:text-card-foreground",
|
|
153
|
-
text: "text-card-foreground",
|
|
154
|
-
border: "border-border",
|
|
155
|
-
},
|
|
156
|
-
ghost: {
|
|
157
|
-
bg: "bg-transparent",
|
|
158
|
-
hover: "hover:bg-accent hover:text-card-foreground",
|
|
159
|
-
text: "text-card-foreground",
|
|
160
|
-
border: "border-transparent",
|
|
161
|
-
},
|
|
162
|
-
},
|
|
163
|
-
};
|
package/src/ui/Button/index.tsx
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
export * from "./types/button";
|
|
2
|
-
import { ButtonProps } from "./types/button";
|
|
3
|
-
import { useTheme } from "../../context/ThemeContext";
|
|
4
|
-
import { classnames } from "../../utils";
|
|
5
|
-
|
|
6
|
-
export function Button({
|
|
7
|
-
title,
|
|
8
|
-
icon,
|
|
9
|
-
positionIcon,
|
|
10
|
-
color = "green",
|
|
11
|
-
variant = "solid",
|
|
12
|
-
disable = false,
|
|
13
|
-
className,
|
|
14
|
-
type = "button",
|
|
15
|
-
onClick = () => {},
|
|
16
|
-
}: ButtonProps) {
|
|
17
|
-
const theme = useTheme();
|
|
18
|
-
const colorSet = theme[color]?.[variant] || theme.green.solid;
|
|
19
|
-
|
|
20
|
-
const classes = classnames(
|
|
21
|
-
// "cursor-pointer flex items-center justify-center gap-2 text-md font-bold rounded-lg p-2.5 w-auto border transition-colors duration-150",
|
|
22
|
-
"cursor-pointer flex items-center justify-center gap-2 px-4 py-2 rounded-lg transition-colors shadow-sm font-medium text-sm border",
|
|
23
|
-
colorSet.bg,
|
|
24
|
-
colorSet.hover,
|
|
25
|
-
colorSet.text,
|
|
26
|
-
colorSet.border,
|
|
27
|
-
{
|
|
28
|
-
"opacity-50 cursor-not-allowed": disable,
|
|
29
|
-
},
|
|
30
|
-
className
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
return (
|
|
34
|
-
<button
|
|
35
|
-
type={type}
|
|
36
|
-
onClick={(e) => !disable && onClick?.(e)}
|
|
37
|
-
disabled={disable}
|
|
38
|
-
className={classes}
|
|
39
|
-
>
|
|
40
|
-
{positionIcon === "left" && icon}
|
|
41
|
-
{title && <span className="first-letter:uppercase">{title}</span>}
|
|
42
|
-
{positionIcon === "right" && icon}
|
|
43
|
-
</button>
|
|
44
|
-
);
|
|
45
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { COLORS } from "../colors";
|
|
2
|
-
|
|
3
|
-
export interface ButtonProps {
|
|
4
|
-
onClick?: (e?: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
|
5
|
-
title: string;
|
|
6
|
-
icon?: JSX.Element;
|
|
7
|
-
positionIcon?: "left" | "right";
|
|
8
|
-
disable?: boolean;
|
|
9
|
-
className?: string;
|
|
10
|
-
type?: "button" | "submit" | "reset";
|
|
11
|
-
color: Color;
|
|
12
|
-
variant?: "solid" | "outline" | "ghost";
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface CustomColors {}
|
|
16
|
-
|
|
17
|
-
export type Color = keyof typeof COLORS | keyof CustomColors | (string & {});
|
package/src/ui/Input/index.tsx
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { classnames } from "../../utils";
|
|
2
|
-
import { InputProps } from "./types/input";
|
|
3
|
-
|
|
4
|
-
export function Input<T>({
|
|
5
|
-
field,
|
|
6
|
-
title,
|
|
7
|
-
id,
|
|
8
|
-
type,
|
|
9
|
-
placeholder,
|
|
10
|
-
className,
|
|
11
|
-
value,
|
|
12
|
-
iconPosition,
|
|
13
|
-
icon,
|
|
14
|
-
error,
|
|
15
|
-
...rest
|
|
16
|
-
}: InputProps<T>) {
|
|
17
|
-
return (
|
|
18
|
-
<div className="flex flex-col gap-2">
|
|
19
|
-
{title && (
|
|
20
|
-
<label
|
|
21
|
-
htmlFor={id}
|
|
22
|
-
className={classnames("block text-md font-medium text-foreground", {
|
|
23
|
-
"text-red-700": error,
|
|
24
|
-
})}
|
|
25
|
-
>
|
|
26
|
-
{rest.required && <span className="text-red-500">* </span>}
|
|
27
|
-
{title}:
|
|
28
|
-
</label>
|
|
29
|
-
)}
|
|
30
|
-
<div
|
|
31
|
-
className={classnames(
|
|
32
|
-
"flex items-center justify-between border border-border text-foreground text-sm rounded-lg w-full",
|
|
33
|
-
{
|
|
34
|
-
"text-red-500 placeholder-red-500 border-red-500 focus:ring-red-500 focus:border-red-500":
|
|
35
|
-
error,
|
|
36
|
-
"p-2.5": icon,
|
|
37
|
-
"bg-input cursor-pointer": !rest.disabled,
|
|
38
|
-
"bg-gray-400/40 cursor-not-allowed": rest.disabled,
|
|
39
|
-
}
|
|
40
|
-
)}
|
|
41
|
-
>
|
|
42
|
-
{iconPosition === "left" && icon}
|
|
43
|
-
<input
|
|
44
|
-
type={type}
|
|
45
|
-
id={id}
|
|
46
|
-
name={String(field)}
|
|
47
|
-
value={value}
|
|
48
|
-
placeholder={placeholder}
|
|
49
|
-
className={classnames(
|
|
50
|
-
"bg-transparent border-none text-foreground text-sm focus:outline-none w-full",
|
|
51
|
-
{
|
|
52
|
-
"ml-3": iconPosition === "left",
|
|
53
|
-
"p-2.5": !icon,
|
|
54
|
-
"cursor-pointer": !rest.disabled,
|
|
55
|
-
"cursor-not-allowed": rest.disabled,
|
|
56
|
-
className: className,
|
|
57
|
-
}
|
|
58
|
-
)}
|
|
59
|
-
// className={`bg-transparent border-none text-foreground text-sm focus:outline-none w-full p-2.5 cursor-not-allowed ${
|
|
60
|
-
// iconPosition === "left" && "ml-3"
|
|
61
|
-
// } ${className}`}
|
|
62
|
-
onChange={rest.onChange}
|
|
63
|
-
{...rest}
|
|
64
|
-
/>
|
|
65
|
-
{iconPosition === "right" && icon}
|
|
66
|
-
</div>
|
|
67
|
-
{error && (
|
|
68
|
-
<div className="mt-2">
|
|
69
|
-
<p className="text-sm text-red-600 dark:text-red-500">{error}</p>
|
|
70
|
-
</div>
|
|
71
|
-
)}
|
|
72
|
-
</div>
|
|
73
|
-
);
|
|
74
|
-
}
|
package/src/ui/Select/index.tsx
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import { SelectProps } from "./types/select";
|
|
2
|
-
import { useEffect, useRef, useState } from "react";
|
|
3
|
-
import { classnames } from "../../utils";
|
|
4
|
-
import { Input } from "../Input";
|
|
5
|
-
import { Button } from "../Button";
|
|
6
|
-
import { v4 } from "uuid";
|
|
7
|
-
import { BroomIcon, MagnifyingGlassIcon } from "@phosphor-icons/react";
|
|
8
|
-
|
|
9
|
-
function getNested(obj: any, path: string) {
|
|
10
|
-
return path.split(".").reduce((o, key) => (o ? o[key] : undefined), obj);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function Select<T>({
|
|
14
|
-
field,
|
|
15
|
-
title,
|
|
16
|
-
id,
|
|
17
|
-
placeholder,
|
|
18
|
-
value,
|
|
19
|
-
options,
|
|
20
|
-
icon,
|
|
21
|
-
iconPosition = "right",
|
|
22
|
-
error,
|
|
23
|
-
required,
|
|
24
|
-
onChange,
|
|
25
|
-
selected,
|
|
26
|
-
isClearable,
|
|
27
|
-
searchable = false,
|
|
28
|
-
}: SelectProps<T>) {
|
|
29
|
-
const [search, setSearch] = useState<string>("");
|
|
30
|
-
const [open, setOpen] = useState<boolean>(false);
|
|
31
|
-
const containerRef = useRef<HTMLDivElement>(null);
|
|
32
|
-
const [label, setLabel] = useState<string>("");
|
|
33
|
-
|
|
34
|
-
// Fecha o dropdown ao clicar fora
|
|
35
|
-
useEffect(() => {
|
|
36
|
-
function handleClickOutside(event: MouseEvent) {
|
|
37
|
-
if (
|
|
38
|
-
containerRef.current &&
|
|
39
|
-
!containerRef.current.contains(event.target as Node)
|
|
40
|
-
) {
|
|
41
|
-
setOpen(false);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
45
|
-
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
46
|
-
}, []);
|
|
47
|
-
|
|
48
|
-
const handleSelect = (val: T) => {
|
|
49
|
-
onChange?.(val);
|
|
50
|
-
setOpen(false);
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
setLabel(value);
|
|
55
|
-
}, [value]);
|
|
56
|
-
|
|
57
|
-
return (
|
|
58
|
-
<div className="flex flex-col gap-2 w-full relative" ref={containerRef}>
|
|
59
|
-
{title && (
|
|
60
|
-
<label
|
|
61
|
-
htmlFor={id}
|
|
62
|
-
className={classnames("block text-md font-medium text-foreground", {
|
|
63
|
-
"text-red-700": error,
|
|
64
|
-
})}
|
|
65
|
-
>
|
|
66
|
-
{required && <span className="text-red-500">*</span>}{" "}
|
|
67
|
-
{title ? `${title}:` : ""}
|
|
68
|
-
</label>
|
|
69
|
-
)}
|
|
70
|
-
|
|
71
|
-
<div
|
|
72
|
-
className={classnames(
|
|
73
|
-
"cursor-pointer flex items-center justify-between bg-input border border-border text-foreground text-sm rounded-lg w-full p-2.5 pr-8",
|
|
74
|
-
{ "border-red-500": error }
|
|
75
|
-
)}
|
|
76
|
-
onClick={() => setOpen(!open)}
|
|
77
|
-
>
|
|
78
|
-
{iconPosition === "left" && icon}
|
|
79
|
-
<span className={`flex-1 ${iconPosition === "left" && "ml-3"}`}>
|
|
80
|
-
{label ? label : placeholder || "Selecione..."}
|
|
81
|
-
</span>
|
|
82
|
-
{iconPosition === "right" && icon}
|
|
83
|
-
</div>
|
|
84
|
-
|
|
85
|
-
{open && (
|
|
86
|
-
<ul className="absolute top-full left-0 w-[600px] max-h-72 overflow-y-auto border border-border rounded-lg bg-card z-10 shadow-lg mt-1">
|
|
87
|
-
<li
|
|
88
|
-
key={v4()}
|
|
89
|
-
className="p-3 cursor-pointer text-foreground"
|
|
90
|
-
onClick={() => isClearable && handleSelect({} as T)}
|
|
91
|
-
>
|
|
92
|
-
{placeholder || "Selecione..."}
|
|
93
|
-
</li>
|
|
94
|
-
{searchable && (
|
|
95
|
-
<li className="px-2 cursor-pointer text-foreground flex gap-2 items-center justify-start">
|
|
96
|
-
<div className="flex-1">
|
|
97
|
-
<Input
|
|
98
|
-
field=""
|
|
99
|
-
title=""
|
|
100
|
-
placeholder="Buscar"
|
|
101
|
-
icon={<MagnifyingGlassIcon />}
|
|
102
|
-
iconPosition="left"
|
|
103
|
-
onChange={(e) => setSearch(e.target.value)}
|
|
104
|
-
value={search}
|
|
105
|
-
/>
|
|
106
|
-
</div>
|
|
107
|
-
<Button
|
|
108
|
-
color="blue"
|
|
109
|
-
title=""
|
|
110
|
-
icon={<BroomIcon />}
|
|
111
|
-
positionIcon="left"
|
|
112
|
-
onClick={(e) => {
|
|
113
|
-
e?.stopPropagation();
|
|
114
|
-
onChange?.({} as T);
|
|
115
|
-
setSearch("");
|
|
116
|
-
}}
|
|
117
|
-
className="m-0"
|
|
118
|
-
/>
|
|
119
|
-
</li>
|
|
120
|
-
)}
|
|
121
|
-
{options
|
|
122
|
-
.filter((opt) => {
|
|
123
|
-
const fieldValue = getNested(opt, field);
|
|
124
|
-
return String(fieldValue)
|
|
125
|
-
.toLowerCase()
|
|
126
|
-
.includes(search.toLowerCase());
|
|
127
|
-
})
|
|
128
|
-
.map((opt) => (
|
|
129
|
-
<li
|
|
130
|
-
key={v4()}
|
|
131
|
-
className={classnames(
|
|
132
|
-
"p-2 hover:bg-primary cursor-pointer text-foreground",
|
|
133
|
-
{
|
|
134
|
-
"bg-primary":
|
|
135
|
-
getNested(opt, field) === value ||
|
|
136
|
-
selected?.[field] === opt[field],
|
|
137
|
-
}
|
|
138
|
-
)}
|
|
139
|
-
onClick={() => handleSelect(opt)}
|
|
140
|
-
>
|
|
141
|
-
{getNested(opt, field)}
|
|
142
|
-
</li>
|
|
143
|
-
))}
|
|
144
|
-
</ul>
|
|
145
|
-
)}
|
|
146
|
-
|
|
147
|
-
{error && <p className="text-sm text-red-600 mt-1">{error}</p>}
|
|
148
|
-
</div>
|
|
149
|
-
);
|
|
150
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export type SelectProps<T> = {
|
|
2
|
-
title: string;
|
|
3
|
-
id: string;
|
|
4
|
-
placeholder?: string;
|
|
5
|
-
field: keyof T & string;
|
|
6
|
-
value: string;
|
|
7
|
-
options: T[];
|
|
8
|
-
icon?: React.ReactNode;
|
|
9
|
-
iconPosition?: "left" | "right";
|
|
10
|
-
error?: string;
|
|
11
|
-
required?: boolean;
|
|
12
|
-
onChange?: (value: T) => void;
|
|
13
|
-
selected?: T;
|
|
14
|
-
isClearable?: boolean;
|
|
15
|
-
searchable?: boolean;
|
|
16
|
-
};
|
package/src/ui/index.ts
DELETED