@processhub-lib/react 1.0.0

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 (43) hide show
  1. package/README.md +6 -0
  2. package/dist/context/ThemeContext.d.ts +22 -0
  3. package/dist/index-B6iFW4Kz.js +1171 -0
  4. package/dist/index-fvSAulfO.cjs +30 -0
  5. package/dist/index.cjs.js +1 -0
  6. package/dist/index.d.ts +4 -0
  7. package/dist/index.es.js +10 -0
  8. package/dist/style.css +1 -0
  9. package/dist/ui/Button/colors.d.ts +162 -0
  10. package/dist/ui/Button/index.d.ts +3 -0
  11. package/dist/ui/Button/types/button.d.ts +16 -0
  12. package/dist/ui/Input/index.d.ts +3 -0
  13. package/dist/ui/Input/types/input.d.ts +10 -0
  14. package/dist/ui/Select/index.d.ts +3 -0
  15. package/dist/ui/Select/types/select.d.ts +16 -0
  16. package/dist/ui/index.d.ts +3 -0
  17. package/dist/ui.cjs.js +1 -0
  18. package/dist/ui.d.ts +1 -0
  19. package/dist/ui.es.js +6 -0
  20. package/dist/utils/classnames.d.ts +16 -0
  21. package/dist/utils/index.d.ts +1 -0
  22. package/dist/utils.cjs.js +1 -0
  23. package/dist/utils.d.ts +1 -0
  24. package/dist/utils.es.js +29 -0
  25. package/package.json +56 -0
  26. package/postcss.config.js +5 -0
  27. package/src/context/ThemeContext.tsx +45 -0
  28. package/src/index.ts +4 -0
  29. package/src/style.css +1 -0
  30. package/src/ui/Button/colors.tsx +163 -0
  31. package/src/ui/Button/index.tsx +46 -0
  32. package/src/ui/Button/types/button.ts +17 -0
  33. package/src/ui/Input/index.tsx +74 -0
  34. package/src/ui/Input/types/input.ts +11 -0
  35. package/src/ui/Select/index.tsx +149 -0
  36. package/src/ui/Select/types/select.ts +16 -0
  37. package/src/ui/index.ts +3 -0
  38. package/src/utils/classnames.tsx +89 -0
  39. package/src/utils/index.ts +1 -0
  40. package/tailwind.config.js +13 -0
  41. package/tsconfig.json +26 -0
  42. package/tsconfig.node.json +10 -0
  43. package/vite.config.ts +31 -0
@@ -0,0 +1,163 @@
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
+ };
@@ -0,0 +1,46 @@
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
+ testedsad
42
+ {title && <span className="first-letter:uppercase">{title}</span>}
43
+ {positionIcon === "right" && icon}
44
+ </button>
45
+ );
46
+ }
@@ -0,0 +1,17 @@
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 & {});
@@ -0,0 +1,74 @@
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
+ }
@@ -0,0 +1,11 @@
1
+ export type inputElementsType<T> = {
2
+ mask?: string;
3
+ field: keyof T;
4
+ title: string;
5
+ iconPosition?: "left" | "right";
6
+ icon?: React.JSX.Element;
7
+ } & React.InputHTMLAttributes<HTMLInputElement | HTMLSelectElement>;
8
+
9
+ export type InputProps<T> = {
10
+ error?: string;
11
+ } & inputElementsType<T>;
@@ -0,0 +1,149 @@
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={() => {
113
+ handleSelect({} as T);
114
+ setSearch("");
115
+ }}
116
+ className="m-0"
117
+ />
118
+ </li>
119
+ )}
120
+ {options
121
+ .filter((opt) => {
122
+ const fieldValue = getNested(opt, field);
123
+ return String(fieldValue)
124
+ .toLowerCase()
125
+ .includes(search.toLowerCase());
126
+ })
127
+ .map((opt) => (
128
+ <li
129
+ key={v4()}
130
+ className={classnames(
131
+ "p-2 hover:bg-primary cursor-pointer text-foreground",
132
+ {
133
+ "bg-primary":
134
+ getNested(opt, field) === value ||
135
+ selected?.[field] === opt[field],
136
+ }
137
+ )}
138
+ onClick={() => handleSelect(opt)}
139
+ >
140
+ {getNested(opt, field)}
141
+ </li>
142
+ ))}
143
+ </ul>
144
+ )}
145
+
146
+ {error && <p className="text-sm text-red-600 mt-1">{error}</p>}
147
+ </div>
148
+ );
149
+ }
@@ -0,0 +1,16 @@
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
+ };
@@ -0,0 +1,3 @@
1
+ export * from "./Button";
2
+ export * from "./Input";
3
+ export * from "./Select";
@@ -0,0 +1,89 @@
1
+ const hasOwn = {}.hasOwnProperty;
2
+
3
+ /**
4
+ * Constrói uma string de classes CSS dinamicamente.
5
+ *
6
+ * Aceita qualquer número de argumentos do tipo string, boolean, null, undefined ou objeto:
7
+ * - Strings são adicionadas diretamente.
8
+ * - Objetos: chaves com valor truthy são incluídas como classes.
9
+ * - Arrays são processados recursivamente.
10
+ *
11
+ * @example
12
+ * classnames("btn", { active: isActive, disabled: false }, ["px-2", null])
13
+ * // Resultado: "btn active px-2"
14
+ *
15
+ * @param {...(string | object | undefined | null | boolean)[]} args - Lista de classes e condições.
16
+ * @returns {string} String final de classes separadas por espaço.
17
+ */
18
+ export function classnames(
19
+ ...args: (string | object | undefined | null | boolean)[]
20
+ ): string {
21
+ let classes = "";
22
+ for (let i = 0; i < args.length; i++) {
23
+ const arg = args[i];
24
+ if (arg) {
25
+ classes = appendClass(classes, parseValue(arg));
26
+ }
27
+ }
28
+
29
+ return classes;
30
+ }
31
+
32
+ /**
33
+ * Converte um argumento em string de classes.
34
+ *
35
+ * - Strings são retornadas como estão.
36
+ * - Objetos: inclui chaves com valor truthy.
37
+ * - Arrays: processados recursivamente.
38
+ *
39
+ * @param arg - Argumento a ser processado.
40
+ * @returns String de classes ou vazia.
41
+ */
42
+ function parseValue(arg: string | object | undefined | null | boolean): string {
43
+ if (typeof arg === "string") {
44
+ return arg;
45
+ }
46
+
47
+ if (typeof arg !== "object" || arg === null) {
48
+ return "";
49
+ }
50
+
51
+ // Processa array de classes
52
+ if (Array.isArray(arg)) {
53
+ return classnames(...arg);
54
+ }
55
+
56
+ // Suporte a objetos com `toString()` customizados (não nativos)
57
+ if (
58
+ arg.toString !== Object.prototype.toString &&
59
+ !arg.toString.toString().includes("[native code]")
60
+ ) {
61
+ return arg.toString();
62
+ }
63
+
64
+ // Processa objetos: adiciona chave se valor for truthy
65
+ let classes = "";
66
+
67
+ for (const key in arg) {
68
+ if (hasOwn.call(arg, key) && (arg as Record<string, unknown>)[key]) {
69
+ classes = appendClass(classes, key);
70
+ }
71
+ }
72
+
73
+ return classes;
74
+ }
75
+
76
+ /**
77
+ * Concatena duas strings de classe com espaço.
78
+ *
79
+ * @param value - String atual.
80
+ * @param newClass - Nova classe a ser adicionada.
81
+ * @returns String combinada.
82
+ */
83
+ function appendClass(value: string, newClass: string): string {
84
+ if (!newClass) {
85
+ return value;
86
+ }
87
+
88
+ return value ? `${value} ${newClass}` : newClass;
89
+ }
@@ -0,0 +1 @@
1
+ export * from "./classnames";
@@ -0,0 +1,13 @@
1
+ /** @type {import('tailwindcss').Config} */
2
+ export default {
3
+ prefix: "ph-",
4
+ content: [
5
+ "./index.html",
6
+ "./src/**/*.{js,ts,jsx,tsx}",
7
+ "../processhub-lib/src/**/*.{js,ts,jsx,tsx}",
8
+ ],
9
+ theme: {
10
+ extend: {},
11
+ },
12
+ plugins: [],
13
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "useDefineForClassFields": true,
5
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
6
+ "module": "ESNext",
7
+ "skipLibCheck": true,
8
+
9
+ /* Bundler mode */
10
+ "moduleResolution": "bundler",
11
+ "allowImportingTsExtensions": true,
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "noEmit": true,
15
+ "jsx": "react-jsx",
16
+
17
+ /* Linting */
18
+ "strict": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "noFallthroughCasesInSwitch": true,
22
+ "declaration": true
23
+ },
24
+ "include": ["src"],
25
+ "references": [{ "path": "./tsconfig.node.json" }]
26
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "compilerOptions": {
3
+ "composite": true,
4
+ "skipLibCheck": true,
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "allowSyntheticDefaultImports": true
8
+ },
9
+ "include": ["vite.config.ts"]
10
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,31 @@
1
+ import { defineConfig } from "vite";
2
+ import path from "path";
3
+ import tailwindcss from "@tailwindcss/vite";
4
+ import dts from "vite-plugin-dts";
5
+
6
+ export default defineConfig({
7
+ build: {
8
+ lib: {
9
+ entry: {
10
+ index: path.resolve(__dirname, "src/index.ts"),
11
+ ui: path.resolve(__dirname, "src/ui/index.ts"),
12
+ utils: path.resolve(__dirname, "src/utils/index.ts"),
13
+ },
14
+ name: "ProcessHubLib",
15
+ formats: ["es", "cjs"],
16
+ fileName: (format, entryName) => `${entryName}.${format}.js`,
17
+ },
18
+ rollupOptions: {
19
+ external: ["react", "react-dom"],
20
+ output: {
21
+ globals: { react: "React" },
22
+ },
23
+ },
24
+ },
25
+ plugins: [
26
+ tailwindcss(),
27
+ dts({
28
+ insertTypesEntry: true,
29
+ }),
30
+ ],
31
+ });