create-nexu 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 (73) hide show
  1. package/README.md +149 -0
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.js +603 -0
  4. package/package.json +41 -0
  5. package/templates/default/.changeset/config.json +11 -0
  6. package/templates/default/.eslintignore +13 -0
  7. package/templates/default/.eslintrc.js +66 -0
  8. package/templates/default/.github/actions/quality/action.yml +53 -0
  9. package/templates/default/.github/dependabot.yml +51 -0
  10. package/templates/default/.github/workflows/deploy-dev.yml +83 -0
  11. package/templates/default/.github/workflows/deploy-prod.yml +83 -0
  12. package/templates/default/.github/workflows/deploy-rec.yml +83 -0
  13. package/templates/default/.husky/commit-msg +1 -0
  14. package/templates/default/.husky/pre-commit +1 -0
  15. package/templates/default/.prettierignore +7 -0
  16. package/templates/default/.prettierrc +19 -0
  17. package/templates/default/.vscode/extensions.json +14 -0
  18. package/templates/default/.vscode/settings.json +36 -0
  19. package/templates/default/apps/.gitkeep +0 -0
  20. package/templates/default/commitlint.config.js +26 -0
  21. package/templates/default/docker/docker-compose.dev.yml +49 -0
  22. package/templates/default/docker/docker-compose.prod.yml +64 -0
  23. package/templates/default/docker/docker-compose.yml +5 -0
  24. package/templates/default/package.json +56 -0
  25. package/templates/default/packages/cache/package.json +26 -0
  26. package/templates/default/packages/cache/src/index.ts +137 -0
  27. package/templates/default/packages/cache/tsconfig.json +9 -0
  28. package/templates/default/packages/cache/tsup.config.ts +9 -0
  29. package/templates/default/packages/config/eslint/index.js +20 -0
  30. package/templates/default/packages/config/package.json +9 -0
  31. package/templates/default/packages/config/typescript/base.json +26 -0
  32. package/templates/default/packages/constants/package.json +26 -0
  33. package/templates/default/packages/constants/src/index.ts +121 -0
  34. package/templates/default/packages/constants/tsconfig.json +9 -0
  35. package/templates/default/packages/constants/tsup.config.ts +9 -0
  36. package/templates/default/packages/logger/package.json +27 -0
  37. package/templates/default/packages/logger/src/index.ts +197 -0
  38. package/templates/default/packages/logger/tsconfig.json +11 -0
  39. package/templates/default/packages/logger/tsup.config.ts +9 -0
  40. package/templates/default/packages/result/package.json +26 -0
  41. package/templates/default/packages/result/src/index.ts +142 -0
  42. package/templates/default/packages/result/tsconfig.json +9 -0
  43. package/templates/default/packages/result/tsup.config.ts +9 -0
  44. package/templates/default/packages/types/package.json +26 -0
  45. package/templates/default/packages/types/src/index.ts +78 -0
  46. package/templates/default/packages/types/tsconfig.json +9 -0
  47. package/templates/default/packages/types/tsup.config.ts +10 -0
  48. package/templates/default/packages/ui/package.json +38 -0
  49. package/templates/default/packages/ui/src/components/Button.tsx +65 -0
  50. package/templates/default/packages/ui/src/components/Card.tsx +90 -0
  51. package/templates/default/packages/ui/src/components/Input.tsx +51 -0
  52. package/templates/default/packages/ui/src/index.ts +15 -0
  53. package/templates/default/packages/ui/tsconfig.json +11 -0
  54. package/templates/default/packages/ui/tsup.config.ts +11 -0
  55. package/templates/default/packages/utils/package.json +30 -0
  56. package/templates/default/packages/utils/src/index.test.ts +130 -0
  57. package/templates/default/packages/utils/src/index.ts +154 -0
  58. package/templates/default/packages/utils/tsconfig.json +10 -0
  59. package/templates/default/packages/utils/tsup.config.ts +10 -0
  60. package/templates/default/pnpm-workspace.yaml +3 -0
  61. package/templates/default/scripts/deploy.sh +25 -0
  62. package/templates/default/scripts/generate-app.sh +166 -0
  63. package/templates/default/scripts/publish-cli.sh +54 -0
  64. package/templates/default/scripts/setup.sh +70 -0
  65. package/templates/default/services/.env.example +16 -0
  66. package/templates/default/services/docker-compose.yml +207 -0
  67. package/templates/default/services/grafana/provisioning/dashboards/dashboards.yml +11 -0
  68. package/templates/default/services/grafana/provisioning/datasources/datasources.yml +9 -0
  69. package/templates/default/services/postgres/init/.gitkeep +2 -0
  70. package/templates/default/services/prometheus/prometheus.yml +13 -0
  71. package/templates/default/tsconfig.json +27 -0
  72. package/templates/default/turbo.json +40 -0
  73. package/templates/default/vitest.config.ts +15 -0
@@ -0,0 +1,11 @@
1
+ {
2
+ "extends": "../config/typescript/base.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src",
6
+ "lib": ["ES2022"],
7
+ "types": ["node"]
8
+ },
9
+ "include": ["src/**/*"],
10
+ "exclude": ["node_modules", "dist"]
11
+ }
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from 'tsup';
2
+
3
+ export default defineConfig({
4
+ entry: ['src/index.ts'],
5
+ format: ['cjs', 'esm'],
6
+ dts: true,
7
+ clean: true,
8
+ sourcemap: true,
9
+ });
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@repo/result",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.mjs",
11
+ "require": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "scripts": {
16
+ "build": "tsup",
17
+ "dev": "tsup --watch",
18
+ "lint": "eslint src/",
19
+ "lint:fix": "eslint src/ --fix",
20
+ "typecheck": "tsc --noEmit"
21
+ },
22
+ "devDependencies": {
23
+ "tsup": "^8.0.0",
24
+ "typescript": "^5.4.0"
25
+ }
26
+ }
@@ -0,0 +1,142 @@
1
+ // Result type - Either success with data or failure with error
2
+ export type Result<T, E = Error> = { ok: true; data: T } | { ok: false; error: E };
3
+
4
+ // Create success result
5
+ export function ok<T>(data: T): Result<T, never> {
6
+ return { ok: true, data };
7
+ }
8
+
9
+ // Create failure result
10
+ export function err<E = Error>(error: E): Result<never, E> {
11
+ return { ok: false, error };
12
+ }
13
+
14
+ // Try/catch wrapper for sync functions
15
+ export function tryCatch<T, E = Error>(fn: () => T, onError?: (e: unknown) => E): Result<T, E> {
16
+ try {
17
+ return ok(fn());
18
+ } catch (e) {
19
+ const error = onError ? onError(e) : e instanceof Error ? e : new Error(String(e));
20
+ return err(error as E);
21
+ }
22
+ }
23
+
24
+ // Try/catch wrapper for async functions
25
+ export async function tryCatchAsync<T, E = Error>(
26
+ fn: () => Promise<T>,
27
+ onError?: (e: unknown) => E
28
+ ): Promise<Result<T, E>> {
29
+ try {
30
+ const data = await fn();
31
+ return ok(data);
32
+ } catch (e) {
33
+ const error = onError ? onError(e) : e instanceof Error ? e : new Error(String(e));
34
+ return err(error as E);
35
+ }
36
+ }
37
+
38
+ // Wrap a function to return Result
39
+ export function wrap<T, Args extends unknown[], E = Error>(
40
+ fn: (...args: Args) => T,
41
+ onError?: (e: unknown) => E
42
+ ): (...args: Args) => Result<T, E> {
43
+ return (...args: Args) => tryCatch(() => fn(...args), onError);
44
+ }
45
+
46
+ // Wrap an async function to return Result
47
+ export function wrapAsync<T, Args extends unknown[], E = Error>(
48
+ fn: (...args: Args) => Promise<T>,
49
+ onError?: (e: unknown) => E
50
+ ): (...args: Args) => Promise<Result<T, E>> {
51
+ return (...args: Args) => tryCatchAsync(() => fn(...args), onError);
52
+ }
53
+
54
+ // Type guards
55
+ export function isOk<T, E>(result: Result<T, E>): result is { ok: true; data: T } {
56
+ return result.ok === true;
57
+ }
58
+
59
+ export function isErr<T, E>(result: Result<T, E>): result is { ok: false; error: E } {
60
+ return result.ok === false;
61
+ }
62
+
63
+ // Unwrap - get data or throw
64
+ export function unwrap<T, E>(result: Result<T, E>): T {
65
+ if (result.ok) return result.data;
66
+ throw result.error;
67
+ }
68
+
69
+ // Unwrap with default value
70
+ export function unwrapOr<T, E>(result: Result<T, E>, defaultValue: T): T {
71
+ return result.ok ? result.data : defaultValue;
72
+ }
73
+
74
+ // Unwrap error or throw
75
+ export function unwrapErr<T, E>(result: Result<T, E>): E {
76
+ if (!result.ok) return result.error;
77
+ throw new Error('Called unwrapErr on Ok result');
78
+ }
79
+
80
+ // Map data if ok
81
+ export function map<T, U, E>(result: Result<T, E>, fn: (data: T) => U): Result<U, E> {
82
+ return result.ok ? ok(fn(result.data)) : result;
83
+ }
84
+
85
+ // Map error if err
86
+ export function mapErr<T, E, F>(result: Result<T, E>, fn: (error: E) => F): Result<T, F> {
87
+ return result.ok ? result : err(fn(result.error));
88
+ }
89
+
90
+ // FlatMap / chain
91
+ export function flatMap<T, U, E>(
92
+ result: Result<T, E>,
93
+ fn: (data: T) => Result<U, E>
94
+ ): Result<U, E> {
95
+ return result.ok ? fn(result.data) : result;
96
+ }
97
+
98
+ // Async flatMap
99
+ export async function flatMapAsync<T, U, E>(
100
+ result: Result<T, E>,
101
+ fn: (data: T) => Promise<Result<U, E>>
102
+ ): Promise<Result<U, E>> {
103
+ return result.ok ? fn(result.data) : result;
104
+ }
105
+
106
+ // Match pattern
107
+ export function match<T, E, U>(
108
+ result: Result<T, E>,
109
+ handlers: { ok: (data: T) => U; err: (error: E) => U }
110
+ ): U {
111
+ return result.ok ? handlers.ok(result.data) : handlers.err(result.error);
112
+ }
113
+
114
+ // Combine multiple results
115
+ export function all<T extends Result<unknown, unknown>[]>(
116
+ results: [...T]
117
+ ): Result<
118
+ { [K in keyof T]: T[K] extends Result<infer U, unknown> ? U : never },
119
+ T[number] extends Result<unknown, infer E> ? E : never
120
+ > {
121
+ const data: unknown[] = [];
122
+
123
+ for (const result of results) {
124
+ if (!result.ok) return result as Result<never, unknown> as never;
125
+ data.push(result.data);
126
+ }
127
+
128
+ return ok(data) as never;
129
+ }
130
+
131
+ // fromPromise - convert Promise to Result
132
+ export async function fromPromise<T, E = Error>(
133
+ promise: Promise<T>,
134
+ onError?: (e: unknown) => E
135
+ ): Promise<Result<T, E>> {
136
+ return tryCatchAsync(() => promise, onError);
137
+ }
138
+
139
+ // toPromise - convert Result to Promise
140
+ export function toPromise<T, E>(result: Result<T, E>): Promise<T> {
141
+ return result.ok ? Promise.resolve(result.data) : Promise.reject(result.error);
142
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../config/typescript/base.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src"
6
+ },
7
+ "include": ["src/**/*"],
8
+ "exclude": ["node_modules", "dist"]
9
+ }
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from 'tsup';
2
+
3
+ export default defineConfig({
4
+ entry: ['src/index.ts'],
5
+ format: ['cjs', 'esm'],
6
+ dts: true,
7
+ clean: true,
8
+ sourcemap: true,
9
+ });
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@repo/types",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.mjs",
11
+ "require": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "scripts": {
16
+ "build": "tsup",
17
+ "dev": "tsup --watch",
18
+ "lint": "eslint src/",
19
+ "lint:fix": "eslint src/ --fix",
20
+ "typecheck": "tsc --noEmit"
21
+ },
22
+ "devDependencies": {
23
+ "tsup": "^8.0.0",
24
+ "typescript": "^5.4.0"
25
+ }
26
+ }
@@ -0,0 +1,78 @@
1
+ // User types
2
+ export interface User {
3
+ id: string;
4
+ email: string;
5
+ name: string;
6
+ avatar?: string;
7
+ createdAt: Date;
8
+ updatedAt: Date;
9
+ }
10
+
11
+ export interface CreateUserInput {
12
+ email: string;
13
+ name: string;
14
+ password: string;
15
+ }
16
+
17
+ export interface UpdateUserInput {
18
+ email?: string;
19
+ name?: string;
20
+ avatar?: string;
21
+ }
22
+
23
+ // API Response types
24
+ export interface ApiResponse<T> {
25
+ success: boolean;
26
+ data?: T;
27
+ error?: ApiError;
28
+ meta?: ApiMeta;
29
+ }
30
+
31
+ export interface ApiError {
32
+ code: string;
33
+ message: string;
34
+ details?: Record<string, unknown>;
35
+ }
36
+
37
+ export interface ApiMeta {
38
+ page?: number;
39
+ limit?: number;
40
+ total?: number;
41
+ totalPages?: number;
42
+ }
43
+
44
+ // Pagination types
45
+ export interface PaginationParams {
46
+ page?: number;
47
+ limit?: number;
48
+ sortBy?: string;
49
+ sortOrder?: 'asc' | 'desc';
50
+ }
51
+
52
+ export interface PaginatedResponse<T> {
53
+ items: T[];
54
+ meta: Required<ApiMeta>;
55
+ }
56
+
57
+ // Auth types
58
+ export interface AuthTokens {
59
+ accessToken: string;
60
+ refreshToken: string;
61
+ expiresIn: number;
62
+ }
63
+
64
+ export interface LoginInput {
65
+ email: string;
66
+ password: string;
67
+ }
68
+
69
+ export interface RegisterInput extends CreateUserInput {
70
+ confirmPassword: string;
71
+ }
72
+
73
+ // Utility types
74
+ export type Nullable<T> = T | null;
75
+ export type Optional<T> = T | undefined;
76
+ export type DeepPartial<T> = {
77
+ [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
78
+ };
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../config/typescript/base.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src"
6
+ },
7
+ "include": ["src/**/*"],
8
+ "exclude": ["node_modules", "dist"]
9
+ }
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from 'tsup';
2
+
3
+ export default defineConfig({
4
+ entry: ['src/index.ts'],
5
+ format: ['cjs', 'esm'],
6
+ dts: true,
7
+ splitting: false,
8
+ sourcemap: true,
9
+ clean: true,
10
+ });
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@repo/ui",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.mjs",
11
+ "require": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ },
14
+ "./components/*": {
15
+ "import": "./dist/components/*.mjs",
16
+ "require": "./dist/components/*.js",
17
+ "types": "./dist/components/*.d.ts"
18
+ }
19
+ },
20
+ "scripts": {
21
+ "build": "tsup",
22
+ "dev": "tsup --watch",
23
+ "lint": "eslint src/",
24
+ "lint:fix": "eslint src/ --fix",
25
+ "typecheck": "tsc --noEmit"
26
+ },
27
+ "devDependencies": {
28
+ "@types/react": "^18.2.0",
29
+ "@types/react-dom": "^18.2.0",
30
+ "react": "^18.2.0",
31
+ "tsup": "^8.0.0",
32
+ "typescript": "^5.4.0"
33
+ },
34
+ "peerDependencies": {
35
+ "react": "^18.2.0",
36
+ "react-dom": "^18.2.0"
37
+ }
38
+ }
@@ -0,0 +1,65 @@
1
+ import React from 'react';
2
+
3
+ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
4
+ variant?: 'primary' | 'secondary' | 'outline' | 'ghost';
5
+ size?: 'sm' | 'md' | 'lg';
6
+ isLoading?: boolean;
7
+ children: React.ReactNode;
8
+ }
9
+
10
+ const variantStyles = {
11
+ primary: 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500',
12
+ secondary: 'bg-gray-600 text-white hover:bg-gray-700 focus:ring-gray-500',
13
+ outline: 'border-2 border-blue-600 text-blue-600 hover:bg-blue-50 focus:ring-blue-500',
14
+ ghost: 'text-gray-600 hover:bg-gray-100 focus:ring-gray-500',
15
+ };
16
+
17
+ const sizeStyles = {
18
+ sm: 'px-3 py-1.5 text-sm',
19
+ md: 'px-4 py-2 text-base',
20
+ lg: 'px-6 py-3 text-lg',
21
+ };
22
+
23
+ export const Button: React.FC<ButtonProps> = ({
24
+ variant = 'primary',
25
+ size = 'md',
26
+ isLoading = false,
27
+ disabled,
28
+ className = '',
29
+ children,
30
+ ...props
31
+ }) => {
32
+ return (
33
+ <button
34
+ className={`
35
+ inline-flex items-center justify-center rounded-lg font-medium
36
+ transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2
37
+ disabled:cursor-not-allowed disabled:opacity-50
38
+ ${variantStyles[variant]}
39
+ ${sizeStyles[size]}
40
+ ${className}
41
+ `}
42
+ disabled={disabled || isLoading}
43
+ {...props}
44
+ >
45
+ {isLoading && (
46
+ <svg className="-ml-1 mr-2 h-4 w-4 animate-spin" fill="none" viewBox="0 0 24 24">
47
+ <circle
48
+ className="opacity-25"
49
+ cx="12"
50
+ cy="12"
51
+ r="10"
52
+ stroke="currentColor"
53
+ strokeWidth="4"
54
+ />
55
+ <path
56
+ className="opacity-75"
57
+ fill="currentColor"
58
+ d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
59
+ />
60
+ </svg>
61
+ )}
62
+ {children}
63
+ </button>
64
+ );
65
+ };
@@ -0,0 +1,90 @@
1
+ import React from 'react';
2
+
3
+ export interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
4
+ variant?: 'default' | 'bordered' | 'elevated';
5
+ padding?: 'none' | 'sm' | 'md' | 'lg';
6
+ children: React.ReactNode;
7
+ }
8
+
9
+ const variantStyles = {
10
+ default: 'bg-white',
11
+ bordered: 'bg-white border border-gray-200',
12
+ elevated: 'bg-white shadow-lg',
13
+ };
14
+
15
+ const paddingStyles = {
16
+ none: '',
17
+ sm: 'p-3',
18
+ md: 'p-4',
19
+ lg: 'p-6',
20
+ };
21
+
22
+ export const Card: React.FC<CardProps> = ({
23
+ variant = 'bordered',
24
+ padding = 'md',
25
+ className = '',
26
+ children,
27
+ ...props
28
+ }) => {
29
+ return (
30
+ <div
31
+ className={`
32
+ rounded-lg
33
+ ${variantStyles[variant]}
34
+ ${paddingStyles[padding]}
35
+ ${className}
36
+ `}
37
+ {...props}
38
+ >
39
+ {children}
40
+ </div>
41
+ );
42
+ };
43
+
44
+ export interface CardHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
45
+ children: React.ReactNode;
46
+ }
47
+
48
+ export const CardHeader: React.FC<CardHeaderProps> = ({ className = '', children, ...props }) => {
49
+ return (
50
+ <div className={`mb-4 ${className}`} {...props}>
51
+ {children}
52
+ </div>
53
+ );
54
+ };
55
+
56
+ export interface CardTitleProps extends React.HTMLAttributes<HTMLHeadingElement> {
57
+ children: React.ReactNode;
58
+ }
59
+
60
+ export const CardTitle: React.FC<CardTitleProps> = ({ className = '', children, ...props }) => {
61
+ return (
62
+ <h3 className={`text-lg font-semibold text-gray-900 ${className}`} {...props}>
63
+ {children}
64
+ </h3>
65
+ );
66
+ };
67
+
68
+ export interface CardContentProps extends React.HTMLAttributes<HTMLDivElement> {
69
+ children: React.ReactNode;
70
+ }
71
+
72
+ export const CardContent: React.FC<CardContentProps> = ({ className = '', children, ...props }) => {
73
+ return (
74
+ <div className={`text-gray-600 ${className}`} {...props}>
75
+ {children}
76
+ </div>
77
+ );
78
+ };
79
+
80
+ export interface CardFooterProps extends React.HTMLAttributes<HTMLDivElement> {
81
+ children: React.ReactNode;
82
+ }
83
+
84
+ export const CardFooter: React.FC<CardFooterProps> = ({ className = '', children, ...props }) => {
85
+ return (
86
+ <div className={`mt-4 border-t border-gray-200 pt-4 ${className}`} {...props}>
87
+ {children}
88
+ </div>
89
+ );
90
+ };
@@ -0,0 +1,51 @@
1
+ import React from 'react';
2
+
3
+ export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
4
+ label?: string;
5
+ error?: string;
6
+ helperText?: string;
7
+ }
8
+
9
+ export const Input = React.forwardRef<HTMLInputElement, InputProps>(
10
+ ({ label, error, helperText, className = '', id, ...props }, ref) => {
11
+ const inputId = id || label?.toLowerCase().replace(/\s+/g, '-');
12
+
13
+ return (
14
+ <div className="w-full">
15
+ {label && (
16
+ <label htmlFor={inputId} className="mb-1 block text-sm font-medium text-gray-700">
17
+ {label}
18
+ </label>
19
+ )}
20
+ <input
21
+ ref={ref}
22
+ id={inputId}
23
+ className={`
24
+ w-full rounded-lg border px-3 py-2 shadow-sm
25
+ focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500
26
+ disabled:cursor-not-allowed disabled:bg-gray-100
27
+ ${error ? 'border-red-500 focus:border-red-500 focus:ring-red-500' : 'border-gray-300'}
28
+ ${className}
29
+ `}
30
+ aria-invalid={error ? 'true' : 'false'}
31
+ aria-describedby={
32
+ error ? `${inputId}-error` : helperText ? `${inputId}-helper` : undefined
33
+ }
34
+ {...props}
35
+ />
36
+ {error && (
37
+ <p id={`${inputId}-error`} className="mt-1 text-sm text-red-600">
38
+ {error}
39
+ </p>
40
+ )}
41
+ {helperText && !error && (
42
+ <p id={`${inputId}-helper`} className="mt-1 text-sm text-gray-500">
43
+ {helperText}
44
+ </p>
45
+ )}
46
+ </div>
47
+ );
48
+ }
49
+ );
50
+
51
+ Input.displayName = 'Input';
@@ -0,0 +1,15 @@
1
+ // Components
2
+ export { Button } from './components/Button';
3
+ export type { ButtonProps } from './components/Button';
4
+
5
+ export { Input } from './components/Input';
6
+ export type { InputProps } from './components/Input';
7
+
8
+ export { Card, CardHeader, CardTitle, CardContent, CardFooter } from './components/Card';
9
+ export type {
10
+ CardProps,
11
+ CardHeaderProps,
12
+ CardTitleProps,
13
+ CardContentProps,
14
+ CardFooterProps,
15
+ } from './components/Card';
@@ -0,0 +1,11 @@
1
+ {
2
+ "extends": "../config/typescript/base.json",
3
+ "compilerOptions": {
4
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
5
+ "jsx": "react-jsx",
6
+ "outDir": "./dist",
7
+ "rootDir": "./src"
8
+ },
9
+ "include": ["src/**/*"],
10
+ "exclude": ["node_modules", "dist"]
11
+ }
@@ -0,0 +1,11 @@
1
+ import { defineConfig } from 'tsup';
2
+
3
+ export default defineConfig({
4
+ entry: ['src/index.ts', 'src/components/*.tsx'],
5
+ format: ['cjs', 'esm'],
6
+ dts: true,
7
+ splitting: true,
8
+ sourcemap: true,
9
+ clean: true,
10
+ external: ['react', 'react-dom'],
11
+ });
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@repo/utils",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.mjs",
11
+ "require": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "scripts": {
16
+ "build": "tsup",
17
+ "dev": "tsup --watch",
18
+ "lint": "eslint src/",
19
+ "lint:fix": "eslint src/ --fix",
20
+ "typecheck": "tsc --noEmit",
21
+ "test": "vitest run",
22
+ "test:coverage": "vitest run --coverage"
23
+ },
24
+ "devDependencies": {
25
+ "@vitest/coverage-v8": "^2.0.0",
26
+ "tsup": "^8.0.0",
27
+ "typescript": "^5.4.0",
28
+ "vitest": "^2.0.0"
29
+ }
30
+ }