@nomos-ui/form 0.0.1
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/README.md +277 -0
- package/dist/components/button.d.ts +20 -0
- package/dist/components/button.d.ts.map +1 -0
- package/dist/components/button.js +94 -0
- package/dist/components/button.js.map +1 -0
- package/dist/components/form-input.d.ts +41 -0
- package/dist/components/form-input.d.ts.map +1 -0
- package/dist/components/form-input.js +38 -0
- package/dist/components/form-input.js.map +1 -0
- package/dist/components/input.d.ts +69 -0
- package/dist/components/input.d.ts.map +1 -0
- package/dist/components/input.js +85 -0
- package/dist/components/input.js.map +1 -0
- package/dist/exports/index.d.ts +8 -0
- package/dist/exports/index.d.ts.map +1 -0
- package/dist/exports/index.js +30 -0
- package/dist/exports/index.js.map +1 -0
- package/dist/utils/shadcn-ui/utils.d.ts +3 -0
- package/dist/utils/shadcn-ui/utils.d.ts.map +1 -0
- package/dist/utils/shadcn-ui/utils.js +9 -0
- package/dist/utils/shadcn-ui/utils.js.map +1 -0
- package/package.json +123 -0
package/README.md
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# @nomos-ui/react
|
|
2
|
+
|
|
3
|
+
> **νόμος** (nomos) - Greek: law, order, principle
|
|
4
|
+
|
|
5
|
+
Beautiful, validated form components that integrate seamlessly with React Hook Form. Built on the principle that forms should enforce order and validation effortlessly.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @nomos-ui/react react-hook-form
|
|
11
|
+
# or
|
|
12
|
+
yarn add @nomos-ui/react react-hook-form
|
|
13
|
+
# or
|
|
14
|
+
pnpm add @nomos-ui/react react-hook-form
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```jsx
|
|
20
|
+
import { useForm } from "react-hook-form";
|
|
21
|
+
import { Input, Button, Form } from "@nomos-ui/react";
|
|
22
|
+
|
|
23
|
+
function LoginForm() {
|
|
24
|
+
const form = useForm();
|
|
25
|
+
|
|
26
|
+
const onSubmit = (data) => {
|
|
27
|
+
console.log(data);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<Form form={form} onSubmit={onSubmit}>
|
|
32
|
+
<Input
|
|
33
|
+
name="email"
|
|
34
|
+
label="Email"
|
|
35
|
+
type="email"
|
|
36
|
+
rules={{ required: "Email is required" }}
|
|
37
|
+
/>
|
|
38
|
+
<Input
|
|
39
|
+
name="password"
|
|
40
|
+
label="Password"
|
|
41
|
+
type="password"
|
|
42
|
+
rules={{ required: "Password is required", minLength: 8 }}
|
|
43
|
+
/>
|
|
44
|
+
<Button type="submit">Sign In</Button>
|
|
45
|
+
</Form>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Why Nomos UI?
|
|
51
|
+
|
|
52
|
+
- **Zero Boilerplate** - Components auto-register with React Hook Form
|
|
53
|
+
- **Built-in Validation** - Error states handled automatically
|
|
54
|
+
- **Accessible** - WCAG 2.1 AA compliant
|
|
55
|
+
- **Customizable** - Style with Tailwind or your own CSS
|
|
56
|
+
- **Type Safe** - Full TypeScript support
|
|
57
|
+
- **Lightweight** - Tree-shakeable, minimal bundle size
|
|
58
|
+
|
|
59
|
+
## Components
|
|
60
|
+
|
|
61
|
+
### Form Components
|
|
62
|
+
|
|
63
|
+
- `<Input />` - Text, email, password, number inputs
|
|
64
|
+
- `<Textarea />` - Multi-line text input
|
|
65
|
+
- `<Select />` - Dropdown selection
|
|
66
|
+
- `<Checkbox />` - Single checkbox
|
|
67
|
+
- `<CheckboxGroup />` - Multiple checkboxes
|
|
68
|
+
- `<Radio />` - Radio button
|
|
69
|
+
- `<RadioGroup />` - Radio button group
|
|
70
|
+
- `<Switch />` - Toggle switch
|
|
71
|
+
- `<DatePicker />` - Date selection
|
|
72
|
+
- `<FileUpload />` - File input with drag & drop
|
|
73
|
+
|
|
74
|
+
### Layout & UI
|
|
75
|
+
|
|
76
|
+
- `<Form />` - Form wrapper with context
|
|
77
|
+
- `<Button />` - Submit and action buttons
|
|
78
|
+
- `<FieldGroup />` - Group related fields
|
|
79
|
+
- `<FormSection />` - Organize form into sections
|
|
80
|
+
|
|
81
|
+
## Examples
|
|
82
|
+
|
|
83
|
+
### Basic Input with Validation
|
|
84
|
+
|
|
85
|
+
```jsx
|
|
86
|
+
<Input
|
|
87
|
+
name="username"
|
|
88
|
+
label="Username"
|
|
89
|
+
placeholder="Enter username"
|
|
90
|
+
rules={{
|
|
91
|
+
required: "Username is required",
|
|
92
|
+
minLength: { value: 3, message: "Minimum 3 characters" },
|
|
93
|
+
pattern: { value: /^[a-zA-Z0-9_]+$/, message: "Alphanumeric only" },
|
|
94
|
+
}}
|
|
95
|
+
helperText="Choose a unique username"
|
|
96
|
+
/>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Select with Options
|
|
100
|
+
|
|
101
|
+
```jsx
|
|
102
|
+
<Select
|
|
103
|
+
name="country"
|
|
104
|
+
label="Country"
|
|
105
|
+
rules={{ required: "Please select a country" }}
|
|
106
|
+
options={[
|
|
107
|
+
{ value: "us", label: "United States" },
|
|
108
|
+
{ value: "uk", label: "United Kingdom" },
|
|
109
|
+
{ value: "ca", label: "Canada" },
|
|
110
|
+
]}
|
|
111
|
+
/>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Checkbox Group
|
|
115
|
+
|
|
116
|
+
```jsx
|
|
117
|
+
<CheckboxGroup
|
|
118
|
+
name="interests"
|
|
119
|
+
label="Interests"
|
|
120
|
+
options={[
|
|
121
|
+
{ value: "sports", label: "Sports" },
|
|
122
|
+
{ value: "music", label: "Music" },
|
|
123
|
+
{ value: "reading", label: "Reading" },
|
|
124
|
+
]}
|
|
125
|
+
rules={{ required: "Select at least one interest" }}
|
|
126
|
+
/>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Custom Styling
|
|
130
|
+
|
|
131
|
+
```jsx
|
|
132
|
+
<Input
|
|
133
|
+
name="email"
|
|
134
|
+
label="Email"
|
|
135
|
+
className="custom-input"
|
|
136
|
+
labelClassName="custom-label"
|
|
137
|
+
errorClassName="custom-error"
|
|
138
|
+
/>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Controlled Components
|
|
142
|
+
|
|
143
|
+
```jsx
|
|
144
|
+
const { watch, setValue } = useForm();
|
|
145
|
+
const emailValue = watch("email");
|
|
146
|
+
|
|
147
|
+
<Input
|
|
148
|
+
name="email"
|
|
149
|
+
label="Email"
|
|
150
|
+
onChange={(e) => {
|
|
151
|
+
// Custom logic
|
|
152
|
+
setValue("email", e.target.value.toLowerCase());
|
|
153
|
+
}}
|
|
154
|
+
/>;
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## API Reference
|
|
158
|
+
|
|
159
|
+
### Common Props
|
|
160
|
+
|
|
161
|
+
All form components share these props:
|
|
162
|
+
|
|
163
|
+
| Prop | Type | Description |
|
|
164
|
+
| ------------ | --------- | -------------------------------- |
|
|
165
|
+
| `name` | `string` | Field name (required) |
|
|
166
|
+
| `label` | `string` | Field label |
|
|
167
|
+
| `rules` | `object` | React Hook Form validation rules |
|
|
168
|
+
| `helperText` | `string` | Help text shown below field |
|
|
169
|
+
| `disabled` | `boolean` | Disable the field |
|
|
170
|
+
| `className` | `string` | Custom CSS class |
|
|
171
|
+
| `...rest` | `any` | Native HTML attributes |
|
|
172
|
+
|
|
173
|
+
### Input Props
|
|
174
|
+
|
|
175
|
+
| Prop | Type | Default | Description |
|
|
176
|
+
| -------------- | -------- | -------- | ---------------------------------------- |
|
|
177
|
+
| `type` | `string` | `'text'` | Input type (text, email, password, etc.) |
|
|
178
|
+
| `placeholder` | `string` | - | Placeholder text |
|
|
179
|
+
| `autoComplete` | `string` | - | Browser autocomplete hint |
|
|
180
|
+
|
|
181
|
+
### Button Props
|
|
182
|
+
|
|
183
|
+
| Prop | Type | Default | Description |
|
|
184
|
+
| ----------- | --------------------------------------------------- | ----------- | -------------------- |
|
|
185
|
+
| `variant` | `'primary' \| 'secondary' \| 'outline' \| 'danger'` | `'primary'` | Button style variant |
|
|
186
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Button size |
|
|
187
|
+
| `loading` | `boolean` | `false` | Show loading spinner |
|
|
188
|
+
| `fullWidth` | `boolean` | `false` | Take full width |
|
|
189
|
+
|
|
190
|
+
## Customization
|
|
191
|
+
|
|
192
|
+
### Theming
|
|
193
|
+
|
|
194
|
+
Override default styles with CSS variables:
|
|
195
|
+
|
|
196
|
+
```css
|
|
197
|
+
:root {
|
|
198
|
+
--nomos-primary: #3b82f6;
|
|
199
|
+
--nomos-error: #ef4444;
|
|
200
|
+
--nomos-border: #d1d5db;
|
|
201
|
+
--nomos-radius: 0.5rem;
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Tailwind Integration
|
|
206
|
+
|
|
207
|
+
Components use Tailwind classes by default. Extend with your own:
|
|
208
|
+
|
|
209
|
+
```jsx
|
|
210
|
+
<Input
|
|
211
|
+
name="email"
|
|
212
|
+
className="shadow-xl border-purple-500 focus:ring-purple-500"
|
|
213
|
+
/>
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## TypeScript
|
|
217
|
+
|
|
218
|
+
Full type safety with TypeScript:
|
|
219
|
+
|
|
220
|
+
```tsx
|
|
221
|
+
import { useForm } from "react-hook-form";
|
|
222
|
+
import { Input, Button } from "@nomos-ui/react";
|
|
223
|
+
|
|
224
|
+
interface FormData {
|
|
225
|
+
email: string;
|
|
226
|
+
password: string;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function LoginForm() {
|
|
230
|
+
const form = useForm<FormData>();
|
|
231
|
+
|
|
232
|
+
const onSubmit = (data: FormData) => {
|
|
233
|
+
console.log(data);
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
return (
|
|
237
|
+
<Form form={form} onSubmit={onSubmit}>
|
|
238
|
+
<Input<FormData> name="email" label="Email" />
|
|
239
|
+
<Input<FormData> name="password" label="Password" type="password" />
|
|
240
|
+
<Button type="submit">Sign In</Button>
|
|
241
|
+
</Form>
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Roadmap
|
|
247
|
+
|
|
248
|
+
- [ ] `@nomos-ui/vue` - Vue 3 components
|
|
249
|
+
- [ ] `@nomos-ui/svelte` - Svelte components
|
|
250
|
+
- [ ] Advanced components (Autocomplete, MultiSelect, RichText)
|
|
251
|
+
- [ ] Form builder/generator
|
|
252
|
+
- [ ] Headless components
|
|
253
|
+
- [ ] Theme presets
|
|
254
|
+
|
|
255
|
+
## Philosophy
|
|
256
|
+
|
|
257
|
+
**νόμος** (nomos) means "law" or "order" in Greek. In the New Testament, it often refers to divine law and principles. Just as law brings order to society, Nomos UI brings order to your forms - enforcing validation rules, maintaining structure, and ensuring data integrity.
|
|
258
|
+
|
|
259
|
+
> "For the law was given through Moses; grace and truth came through Jesus Christ." - John 1:17
|
|
260
|
+
|
|
261
|
+
We believe forms should be both functional and graceful, enforcing rules while remaining pleasant to use.
|
|
262
|
+
|
|
263
|
+
## Contributing
|
|
264
|
+
|
|
265
|
+
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) first.
|
|
266
|
+
|
|
267
|
+
## License
|
|
268
|
+
|
|
269
|
+
MIT ©
|
|
270
|
+
|
|
271
|
+
## Credits
|
|
272
|
+
|
|
273
|
+
Built on top of [React Hook Form](https://react-hook-form.com/) - the most performant, flexible form library for React.
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
**Made with ♥︎ for developers who value order in chaos**
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type VariantProps } from "class-variance-authority";
|
|
3
|
+
declare const buttonVariants: (props?: ({
|
|
4
|
+
variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | null | undefined;
|
|
5
|
+
size?: "default" | "sm" | "lg" | "icon" | "icon-sm" | "icon-lg" | null | undefined;
|
|
6
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
|
+
type ButtonProps = React.ComponentProps<"button"> & VariantProps<typeof buttonVariants> & {
|
|
8
|
+
/** Render as a child component (Radix Slot pattern) */
|
|
9
|
+
asChild?: boolean;
|
|
10
|
+
/** Show loading spinner and disable button */
|
|
11
|
+
isLoading?: boolean;
|
|
12
|
+
/** Render as Next.js Link with href */
|
|
13
|
+
href?: string;
|
|
14
|
+
/** Mark button as selected (adds data-selected attribute) */
|
|
15
|
+
selected?: boolean;
|
|
16
|
+
};
|
|
17
|
+
export default function Button({ className, variant, size, asChild, isLoading, href, type, selected, disabled, children, ...props }: ButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export { buttonVariants };
|
|
19
|
+
export type { ButtonProps };
|
|
20
|
+
//# sourceMappingURL=button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../src/components/button.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAIlE,QAAA,MAAM,cAAc;;;8EA8BnB,CAAC;AAEF,KAAK,WAAW,GAAG,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,GAC/C,YAAY,CAAC,OAAO,cAAc,CAAC,GAAG;IACpC,uDAAuD;IACvD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEJ,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,EAC7B,SAAS,EACT,OAAO,EACP,IAAI,EACJ,OAAe,EACf,SAAiB,EACjB,IAAI,EACJ,IAAe,EACf,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,WAAW,2CA4Cb;AAED,OAAO,EAAE,cAAc,EAAE,CAAC;AAE1B,YAAY,EAAE,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.buttonVariants = void 0;
|
|
38
|
+
exports.default = Button;
|
|
39
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
40
|
+
const React = __importStar(require("react"));
|
|
41
|
+
const react_slot_1 = require("@radix-ui/react-slot");
|
|
42
|
+
const class_variance_authority_1 = require("class-variance-authority");
|
|
43
|
+
const lucide_react_1 = require("lucide-react");
|
|
44
|
+
const utils_1 = require("../utils/shadcn-ui/utils");
|
|
45
|
+
const buttonVariants = (0, class_variance_authority_1.cva)("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive active:opacity-80 relative", {
|
|
46
|
+
variants: {
|
|
47
|
+
variant: {
|
|
48
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
49
|
+
destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
|
50
|
+
outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
|
51
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
52
|
+
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50 data-[selected=true]:bg-accent dark:data-[selected=true]:bg-accent/50",
|
|
53
|
+
link: "text-primary underline-offset-4 hover:underline p-0",
|
|
54
|
+
},
|
|
55
|
+
size: {
|
|
56
|
+
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
57
|
+
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
|
|
58
|
+
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
59
|
+
icon: "size-9",
|
|
60
|
+
"icon-sm": "size-8",
|
|
61
|
+
"icon-lg": "size-10",
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
defaultVariants: {
|
|
65
|
+
variant: "default",
|
|
66
|
+
size: "default",
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
exports.buttonVariants = buttonVariants;
|
|
70
|
+
function Button({ className, variant, size, asChild = false, isLoading = false, href, type = "button", selected, disabled, children, ...props }) {
|
|
71
|
+
const [buttonWidth, setButtonWidth] = React.useState();
|
|
72
|
+
const buttonRef = React.useRef(null);
|
|
73
|
+
React.useEffect(() => {
|
|
74
|
+
if (isLoading && buttonRef.current && !buttonWidth) {
|
|
75
|
+
setButtonWidth(buttonRef.current.offsetWidth);
|
|
76
|
+
}
|
|
77
|
+
else if (!isLoading && buttonWidth) {
|
|
78
|
+
setButtonWidth(undefined);
|
|
79
|
+
}
|
|
80
|
+
}, [isLoading, buttonWidth]);
|
|
81
|
+
const commonProps = {
|
|
82
|
+
"data-slot": "button",
|
|
83
|
+
"data-selected": selected,
|
|
84
|
+
className: (0, utils_1.cn)(buttonVariants({ variant, size, className })),
|
|
85
|
+
style: buttonWidth ? { width: buttonWidth } : undefined,
|
|
86
|
+
ref: buttonRef,
|
|
87
|
+
};
|
|
88
|
+
const content = isLoading ? ((0, jsx_runtime_1.jsx)(lucide_react_1.LoaderIcon, { className: "size-4 animate-spin" })) : (children);
|
|
89
|
+
if (asChild) {
|
|
90
|
+
return ((0, jsx_runtime_1.jsx)(react_slot_1.Slot, { ...commonProps, ...props, children: content }));
|
|
91
|
+
}
|
|
92
|
+
return ((0, jsx_runtime_1.jsx)("button", { type: type, disabled: isLoading || disabled, ...commonProps, ...props, children: content }));
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=button.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button.js","sourceRoot":"","sources":["../../src/components/button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDb,yBAwDC;;AA1GD,6CAA+B;AAC/B,qDAA4C;AAC5C,uEAAkE;AAClE,+CAA0C;AAC1C,oDAA8C;AAE9C,MAAM,cAAc,GAAG,IAAA,8BAAG,EACxB,wdAAwd,EACxd;IACE,QAAQ,EAAE;QACR,OAAO,EAAE;YACP,OAAO,EAAE,wDAAwD;YACjE,WAAW,EACT,mJAAmJ;YACrJ,OAAO,EACL,uIAAuI;YACzI,SAAS,EACP,8DAA8D;YAChE,KAAK,EACH,4IAA4I;YAC9I,IAAI,EAAE,qDAAqD;SAC5D;QACD,IAAI,EAAE;YACJ,OAAO,EAAE,+BAA+B;YACxC,EAAE,EAAE,+CAA+C;YACnD,EAAE,EAAE,sCAAsC;YAC1C,IAAI,EAAE,QAAQ;YACd,SAAS,EAAE,QAAQ;YACnB,SAAS,EAAE,SAAS;SACrB;KACF;IACD,eAAe,EAAE;QACf,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,SAAS;KAChB;CACF,CACF,CAAC;AAwEO,wCAAc;AA1DvB,SAAwB,MAAM,CAAC,EAC7B,SAAS,EACT,OAAO,EACP,IAAI,EACJ,OAAO,GAAG,KAAK,EACf,SAAS,GAAG,KAAK,EACjB,IAAI,EACJ,IAAI,GAAG,QAAQ,EACf,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,GAAG,KAAK,EACI;IACZ,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,KAAK,CAAC,QAAQ,EAAsB,CAAC;IAC3E,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAoB,IAAI,CAAC,CAAC;IAExD,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,IAAI,SAAS,IAAI,SAAS,CAAC,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC;YACnD,cAAc,CAAC,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAChD,CAAC;aAAM,IAAI,CAAC,SAAS,IAAI,WAAW,EAAE,CAAC;YACrC,cAAc,CAAC,SAAS,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,EAAE,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC;IAE7B,MAAM,WAAW,GAAG;QAClB,WAAW,EAAE,QAAQ;QACrB,eAAe,EAAE,QAAQ;QACzB,SAAS,EAAE,IAAA,UAAE,EAAC,cAAc,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;QAC3D,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS;QACvD,GAAG,EAAE,SAAS;KACf,CAAC;IAEF,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAC1B,uBAAC,yBAAU,IAAC,SAAS,EAAC,qBAAqB,GAAG,CAC/C,CAAC,CAAC,CAAC,CACF,QAAQ,CACT,CAAC;IAEF,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CACL,uBAAC,iBAAI,OAAK,WAAW,KAAM,KAAK,YAC7B,OAAO,GACH,CACR,CAAC;IACJ,CAAC;IAED,OAAO,CACL,mCACE,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,SAAS,IAAI,QAAQ,KAC3B,WAAW,KACX,KAAK,YAER,OAAO,GACD,CACV,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Control, FieldValues, Path, PathValue } from "react-hook-form";
|
|
2
|
+
import Input from "./input";
|
|
3
|
+
import React from "react";
|
|
4
|
+
/**
|
|
5
|
+
* Props for the `FormInput` component with type-safe form integration
|
|
6
|
+
*/
|
|
7
|
+
export type FormInputProps<TFieldValues extends FieldValues> = {
|
|
8
|
+
/** React Hook Form control instance */
|
|
9
|
+
control: Control<TFieldValues>;
|
|
10
|
+
/** The name of the field (type-safe, must match form schema) */
|
|
11
|
+
name: Path<TFieldValues>;
|
|
12
|
+
/** Default value of the input (type-safe based on field) */
|
|
13
|
+
defaultValue?: PathValue<TFieldValues, Path<TFieldValues>>;
|
|
14
|
+
} & Omit<React.ComponentProps<typeof Input>, "value" | "onChange" | "error" | "control">;
|
|
15
|
+
/**
|
|
16
|
+
* A form input component that adds type-safe form functionality to the base Input component.
|
|
17
|
+
* Designed to integrate with React Hook Form with full TypeScript support.
|
|
18
|
+
*
|
|
19
|
+
* @component
|
|
20
|
+
* @example
|
|
21
|
+
* ```tsx
|
|
22
|
+
* type FormData = {
|
|
23
|
+
* email: string;
|
|
24
|
+
* age: number;
|
|
25
|
+
* };
|
|
26
|
+
*
|
|
27
|
+
* const { control } = useForm<FormData>();
|
|
28
|
+
*
|
|
29
|
+
* <FormInput
|
|
30
|
+
* control={control}
|
|
31
|
+
* name="email" // ✅ Type-safe: only "email" or "age" allowed
|
|
32
|
+
* defaultValue="test@example.com" // ✅ Type-safe: must be string
|
|
33
|
+
* label="Email"
|
|
34
|
+
* placeholder="Enter your email"
|
|
35
|
+
* required
|
|
36
|
+
* tip="Enter a valid email address"
|
|
37
|
+
* />
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export default function FormInput<TFieldValues extends FieldValues>({ control, name, defaultValue, required, ...props }: FormInputProps<TFieldValues>): import("react/jsx-runtime").JSX.Element;
|
|
41
|
+
//# sourceMappingURL=form-input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-input.d.ts","sourceRoot":"","sources":["../../src/components/form-input.tsx"],"names":[],"mappings":"AAAA,OAAO,EAEL,OAAO,EACP,WAAW,EACX,IAAI,EACJ,SAAS,EACV,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,MAAM,SAAS,CAAC;AAC5B,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;GAEG;AACH,MAAM,MAAM,cAAc,CAAC,YAAY,SAAS,WAAW,IAAI;IAC7D,uCAAuC;IACvC,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAC/B,gEAAgE;IAChE,IAAI,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;IACzB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,SAAS,CAAC,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;CAC5D,GAAG,IAAI,CACN,KAAK,CAAC,cAAc,CAAC,OAAO,KAAK,CAAC,EAClC,OAAO,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,CAC3C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,YAAY,SAAS,WAAW,EAAE,EAClE,OAAO,EACP,IAAI,EACJ,YAAY,EACZ,QAAe,EACf,GAAG,KAAK,EACT,EAAE,cAAc,CAAC,YAAY,CAAC,2CAmB9B"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = FormInput;
|
|
7
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
|
+
const react_hook_form_1 = require("react-hook-form");
|
|
9
|
+
const input_1 = __importDefault(require("./input"));
|
|
10
|
+
/**
|
|
11
|
+
* A form input component that adds type-safe form functionality to the base Input component.
|
|
12
|
+
* Designed to integrate with React Hook Form with full TypeScript support.
|
|
13
|
+
*
|
|
14
|
+
* @component
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* type FormData = {
|
|
18
|
+
* email: string;
|
|
19
|
+
* age: number;
|
|
20
|
+
* };
|
|
21
|
+
*
|
|
22
|
+
* const { control } = useForm<FormData>();
|
|
23
|
+
*
|
|
24
|
+
* <FormInput
|
|
25
|
+
* control={control}
|
|
26
|
+
* name="email" // ✅ Type-safe: only "email" or "age" allowed
|
|
27
|
+
* defaultValue="test@example.com" // ✅ Type-safe: must be string
|
|
28
|
+
* label="Email"
|
|
29
|
+
* placeholder="Enter your email"
|
|
30
|
+
* required
|
|
31
|
+
* tip="Enter a valid email address"
|
|
32
|
+
* />
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
function FormInput({ control, name, defaultValue, required = true, ...props }) {
|
|
36
|
+
return ((0, jsx_runtime_1.jsx)(react_hook_form_1.Controller, { control: control, name: name, defaultValue: defaultValue, rules: { required: required ? "Required" : false }, render: ({ field: { onChange, value }, fieldState: { error } }) => ((0, jsx_runtime_1.jsx)(input_1.default, { id: `form-input-${name}`, value: value ?? "", onChange: onChange, required: required, error: error?.message, ...props })) }));
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=form-input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-input.js","sourceRoot":"","sources":["../../src/components/form-input.tsx"],"names":[],"mappings":";;;;;AAkDA,4BAyBC;;AA3ED,qDAMyB;AACzB,oDAA4B;AAkB5B;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,SAAwB,SAAS,CAAmC,EAClE,OAAO,EACP,IAAI,EACJ,YAAY,EACZ,QAAQ,GAAG,IAAI,EACf,GAAG,KAAK,EACqB;IAC7B,OAAO,CACL,uBAAC,4BAAU,IACT,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,YAAY,EAC1B,KAAK,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,EAClD,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,CACjE,uBAAC,eAAK,IACJ,EAAE,EAAE,cAAc,IAAI,EAAE,EACxB,KAAK,EAAE,KAAK,IAAI,EAAE,EAClB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,KAAK,EAAE,OAAO,KACjB,KAAK,GACT,CACH,GACD,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Props for the enhanced Input component
|
|
4
|
+
*/
|
|
5
|
+
export type InputProps = {
|
|
6
|
+
/** Additional class name for the input element */
|
|
7
|
+
inputClassName?: string;
|
|
8
|
+
/** Additional class name for the container */
|
|
9
|
+
className?: string;
|
|
10
|
+
/** Placeholder text for the input */
|
|
11
|
+
placeholder?: string;
|
|
12
|
+
/** Label text for the input */
|
|
13
|
+
label?: string;
|
|
14
|
+
/** Additional class name for the label */
|
|
15
|
+
labelClassName?: string;
|
|
16
|
+
/** Additional class name for the input container/wrapper */
|
|
17
|
+
inputContainerClassName?: string;
|
|
18
|
+
/** Input type (e.g., text, number, password) */
|
|
19
|
+
type?: string;
|
|
20
|
+
/** Whether the input is disabled */
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
/** Whether to trim input value before calling onChange */
|
|
23
|
+
trim?: boolean;
|
|
24
|
+
/** Current value of the input */
|
|
25
|
+
value?: string | number;
|
|
26
|
+
/** Callback fired when input value changes */
|
|
27
|
+
onChange?: (value: string | number | null, e?: React.ChangeEvent<HTMLInputElement>) => void;
|
|
28
|
+
/** Whether the field is required */
|
|
29
|
+
required?: boolean;
|
|
30
|
+
/** Whether to show an asterisk for required fields */
|
|
31
|
+
showRequiredSign?: boolean;
|
|
32
|
+
/** Tooltip text providing additional information */
|
|
33
|
+
tip?: string;
|
|
34
|
+
/** Error message to display */
|
|
35
|
+
error?: string;
|
|
36
|
+
/** Ref for the container div */
|
|
37
|
+
ref?: any;
|
|
38
|
+
/** Ref for the input element */
|
|
39
|
+
inputRef?: any;
|
|
40
|
+
/** Whether to show search icon (overrides type="search" icon display) */
|
|
41
|
+
showSearchIcon?: boolean;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* An enhanced input component combining the best of both worlds:
|
|
45
|
+
* - Semantic color tokens from design system (foreground, muted-foreground, etc.)
|
|
46
|
+
* - Label support with required indicators
|
|
47
|
+
* - Password visibility toggle
|
|
48
|
+
* - Search icon support
|
|
49
|
+
* - Focus state management
|
|
50
|
+
* - Error state with validation
|
|
51
|
+
* - Value trimming and type coercion
|
|
52
|
+
* - Datetime/date value formatting
|
|
53
|
+
*
|
|
54
|
+
* @component
|
|
55
|
+
* @example
|
|
56
|
+
* ```tsx
|
|
57
|
+
* <Input
|
|
58
|
+
* label="Username"
|
|
59
|
+
* placeholder="Enter username"
|
|
60
|
+
* type="text"
|
|
61
|
+
* required
|
|
62
|
+
* showRequiredSign
|
|
63
|
+
* error="Username is required"
|
|
64
|
+
* onChange={(value) => console.log(value)}
|
|
65
|
+
* />
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export default function Input({ inputClassName, className, placeholder, label, labelClassName, type, disabled, trim, value, onChange, required, showRequiredSign, tip, error, inputContainerClassName, ref, inputRef, showSearchIcon, ...props }: InputProps & Omit<React.InputHTMLAttributes<HTMLInputElement>, keyof InputProps>): import("react/jsx-runtime").JSX.Element;
|
|
69
|
+
//# sourceMappingURL=input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/components/input.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,kDAAkD;IAClD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4DAA4D;IAC5D,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,0DAA0D;IAC1D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,EAC7B,CAAC,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC,gBAAgB,CAAC,KACpC,IAAI,CAAC;IACV,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sDAAsD;IACtD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,oDAAoD;IACpD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,gCAAgC;IAChC,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf,yEAAyE;IACzE,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,EAC5B,cAAc,EACd,SAAS,EACT,WAAW,EACX,KAAK,EACL,cAAc,EACd,IAAa,EACb,QAAgB,EAChB,IAAY,EACZ,KAAU,EACV,QAAQ,EACR,QAAgB,EAChB,gBAAwB,EACxB,GAAG,EACH,KAAK,EACL,uBAAuB,EACvB,GAAG,EACH,QAAQ,EACR,cAAc,EACd,GAAG,KAAK,EACT,EAAE,UAAU,GACX,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,MAAM,UAAU,CAAC,2CA6IpE"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.default = Input;
|
|
5
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
+
const react_1 = require("react");
|
|
7
|
+
const lucide_react_1 = require("lucide-react");
|
|
8
|
+
const utils_1 = require("../utils/shadcn-ui/utils");
|
|
9
|
+
/**
|
|
10
|
+
* An enhanced input component combining the best of both worlds:
|
|
11
|
+
* - Semantic color tokens from design system (foreground, muted-foreground, etc.)
|
|
12
|
+
* - Label support with required indicators
|
|
13
|
+
* - Password visibility toggle
|
|
14
|
+
* - Search icon support
|
|
15
|
+
* - Focus state management
|
|
16
|
+
* - Error state with validation
|
|
17
|
+
* - Value trimming and type coercion
|
|
18
|
+
* - Datetime/date value formatting
|
|
19
|
+
*
|
|
20
|
+
* @component
|
|
21
|
+
* @example
|
|
22
|
+
* ```tsx
|
|
23
|
+
* <Input
|
|
24
|
+
* label="Username"
|
|
25
|
+
* placeholder="Enter username"
|
|
26
|
+
* type="text"
|
|
27
|
+
* required
|
|
28
|
+
* showRequiredSign
|
|
29
|
+
* error="Username is required"
|
|
30
|
+
* onChange={(value) => console.log(value)}
|
|
31
|
+
* />
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
function Input({ inputClassName, className, placeholder, label, labelClassName, type = "text", disabled = false, trim = false, value = "", onChange, required = false, showRequiredSign = false, tip, error, inputContainerClassName, ref, inputRef, showSearchIcon, ...props }) {
|
|
35
|
+
const isPassword = type.includes("password");
|
|
36
|
+
const [showPassword, setShowPassword] = (0, react_1.useState)(!isPassword);
|
|
37
|
+
const [isFocused, setIsFocused] = (0, react_1.useState)(false);
|
|
38
|
+
function handleOnChange(text) {
|
|
39
|
+
if (disabled || !onChange)
|
|
40
|
+
return;
|
|
41
|
+
const processedValue = trim ? text.trim() : text;
|
|
42
|
+
onChange(type === "number" && processedValue
|
|
43
|
+
? Number(processedValue)
|
|
44
|
+
: processedValue);
|
|
45
|
+
}
|
|
46
|
+
const currentValue = (0, react_1.useMemo)(() => {
|
|
47
|
+
if (type === "datetime-local") {
|
|
48
|
+
let newValue = value.toString().split(".");
|
|
49
|
+
if (newValue.length === 2)
|
|
50
|
+
return newValue[0]?.slice?.(0, -3);
|
|
51
|
+
else
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
if (type === "date")
|
|
55
|
+
return value.toString().split("T")[0];
|
|
56
|
+
return value;
|
|
57
|
+
}, [value, type]);
|
|
58
|
+
return ((0, jsx_runtime_1.jsxs)("div", { ref: ref, className: (0, utils_1.cn)("gap-1 grid", className), children: [label && ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-row items-center gap-1", children: [(0, jsx_runtime_1.jsx)("label", { htmlFor: props.id, className: (0, utils_1.cn)("text-sm font-bold text-foreground", labelClassName), children: label }), required && showRequiredSign && ((0, jsx_runtime_1.jsx)(lucide_react_1.AsteriskIcon, { size: 12, className: "text-destructive" }))] })), (0, jsx_runtime_1.jsxs)("div", { "data-focus": isFocused, className: (0, utils_1.cn)(
|
|
59
|
+
// Base styles with semantic colors
|
|
60
|
+
"flex w-full min-w-0 rounded-md border bg-transparent shadow-xs transition-[color,box-shadow,border-color]", "border-input file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground", "placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground",
|
|
61
|
+
// Focus styles
|
|
62
|
+
"focus-within:border-ring focus-within:ring-ring/50 focus-within:ring-[3px]", "data-[focus=true]:border-ring data-[focus=true]:ring-ring/50 data-[focus=true]:ring-[3px]",
|
|
63
|
+
// Error/Invalid styles
|
|
64
|
+
error &&
|
|
65
|
+
"border-destructive ring-destructive/20 dark:ring-destructive/40", "aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
|
|
66
|
+
// Disabled styles
|
|
67
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
68
|
+
// Dark mode
|
|
69
|
+
"dark:bg-input/30",
|
|
70
|
+
// Layout
|
|
71
|
+
"flex-row items-center", inputContainerClassName), children: [(type === "search" || showSearchIcon) && ((0, jsx_runtime_1.jsx)(lucide_react_1.SearchIcon, { size: 18, className: "text-muted-foreground ml-3 flex-shrink-0" })), (0, jsx_runtime_1.jsx)("input", { type: isPassword && showPassword ? "text" : type, disabled: disabled, required: required, "aria-invalid": error ? "true" : "false", onBlur: (e) => {
|
|
72
|
+
props?.onBlur?.(e);
|
|
73
|
+
setIsFocused(false);
|
|
74
|
+
}, onFocus: (e) => {
|
|
75
|
+
props?.onFocus?.(e);
|
|
76
|
+
setIsFocused(true);
|
|
77
|
+
}, onChange: (e) => {
|
|
78
|
+
const value = e.currentTarget.value;
|
|
79
|
+
if (onChange) {
|
|
80
|
+
handleOnChange(value);
|
|
81
|
+
onChange(value, e);
|
|
82
|
+
}
|
|
83
|
+
}, value: currentValue, placeholder: placeholder, className: (0, utils_1.cn)("h-9 w-full flex-1 bg-transparent px-3 py-1 text-base outline-none", "file:inline-flex file:h-7", "disabled:cursor-not-allowed disabled:bg-transparent", "md:text-sm", inputClassName), step: "any", ref: inputRef, ...props }), isPassword && ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => !disabled && setShowPassword((prev) => !prev), disabled: disabled, className: "mr-3 flex-shrink-0 cursor-pointer text-muted-foreground hover:text-foreground disabled:cursor-not-allowed disabled:opacity-50", tabIndex: -1, children: showPassword ? (0, jsx_runtime_1.jsx)(lucide_react_1.EyeIcon, { size: 16 }) : (0, jsx_runtime_1.jsx)(lucide_react_1.EyeOffIcon, { size: 16 }) }))] }), tip && !error && ((0, jsx_runtime_1.jsx)("p", { className: "text-xs text-muted-foreground tip-message", children: tip })), error && ((0, jsx_runtime_1.jsxs)("p", { className: "text-xs text-destructive error-message", children: ["*", error] }))] }));
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input.js","sourceRoot":"","sources":["../../src/components/input.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import Button from "../components/button";
|
|
2
|
+
import FormInput from "../components/form-input";
|
|
3
|
+
import Input from "../components/input";
|
|
4
|
+
export { Button, FormInput, Input };
|
|
5
|
+
export * from "../components/input";
|
|
6
|
+
export * from "../components/form-input";
|
|
7
|
+
export * from "../components/button";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/exports/index.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,sBAAsB,CAAC;AAC1C,OAAO,SAAS,MAAM,0BAA0B,CAAC;AACjD,OAAO,KAAK,MAAM,qBAAqB,CAAC;AAExC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
17
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.Input = exports.FormInput = exports.Button = void 0;
|
|
21
|
+
const button_1 = __importDefault(require("../components/button"));
|
|
22
|
+
exports.Button = button_1.default;
|
|
23
|
+
const form_input_1 = __importDefault(require("../components/form-input"));
|
|
24
|
+
exports.FormInput = form_input_1.default;
|
|
25
|
+
const input_1 = __importDefault(require("../components/input"));
|
|
26
|
+
exports.Input = input_1.default;
|
|
27
|
+
__exportStar(require("../components/input"), exports);
|
|
28
|
+
__exportStar(require("../components/form-input"), exports);
|
|
29
|
+
__exportStar(require("../components/button"), exports);
|
|
30
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/exports/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,kEAA0C;AAIjC,iBAJF,gBAAM,CAIE;AAHf,0EAAiD;AAGhC,oBAHV,oBAAS,CAGU;AAF1B,gEAAwC;AAEZ,gBAFrB,eAAK,CAEqB;AACjC,sDAAoC;AACpC,2DAAyC;AACzC,uDAAqC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/utils/shadcn-ui/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAQ,MAAM,MAAM,CAAC;AAG7C,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,UAEzC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cn = cn;
|
|
4
|
+
const clsx_1 = require("clsx");
|
|
5
|
+
const tailwind_merge_1 = require("tailwind-merge");
|
|
6
|
+
function cn(...inputs) {
|
|
7
|
+
return (0, tailwind_merge_1.twMerge)((0, clsx_1.clsx)(...inputs));
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/utils/shadcn-ui/utils.ts"],"names":[],"mappings":";;AAGA,gBAEC;AALD,+BAA6C;AAC7C,mDAAyC;AAEzC,SAAgB,EAAE,CAAC,GAAG,MAAoB;IACxC,OAAO,IAAA,wBAAO,EAAC,IAAA,WAAI,EAAC,GAAG,MAAM,CAAC,CAAC,CAAC;AAClC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nomos-ui/form",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "The Shadcn library for building robust React forms",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/exports/index.js",
|
|
7
|
+
"types": "dist/exports/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/exports/index.d.ts",
|
|
11
|
+
"import": "./dist/exports/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./hooks": {
|
|
14
|
+
"types": "./dist/hooks/index.d.ts",
|
|
15
|
+
"import": "./dist/hooks/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./utils": {
|
|
18
|
+
"types": "./dist/utils/index.d.ts",
|
|
19
|
+
"import": "./dist/utils/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./types": {
|
|
22
|
+
"types": "./dist/types/index.d.ts",
|
|
23
|
+
"import": "./dist/types/index.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"typesVersions": {
|
|
27
|
+
"*": {
|
|
28
|
+
"components": ["./dist/components/index.d.ts"],
|
|
29
|
+
"hooks": ["./dist/hooks/index.d.ts"],
|
|
30
|
+
"utils": ["./dist/utils/index.d.ts"],
|
|
31
|
+
"types": ["./dist/types/index.d.ts"]
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "trash dist && tsc",
|
|
36
|
+
"dev": "tsc --watch",
|
|
37
|
+
"clean": "rm -rf dist",
|
|
38
|
+
"lint": "eslint src --ext .ts,.tsx",
|
|
39
|
+
"type-check": "tsc --noEmit",
|
|
40
|
+
"test": "vitest",
|
|
41
|
+
"test:watch": "vitest --watch",
|
|
42
|
+
"test:ui": "vitest --ui",
|
|
43
|
+
"test:coverage": "vitest --coverage",
|
|
44
|
+
"prepublishOnly": "pnpm run build"
|
|
45
|
+
},
|
|
46
|
+
"keywords": [
|
|
47
|
+
"react",
|
|
48
|
+
"react-hook-form",
|
|
49
|
+
"form",
|
|
50
|
+
"forms",
|
|
51
|
+
"validation",
|
|
52
|
+
"components",
|
|
53
|
+
"ui",
|
|
54
|
+
"input",
|
|
55
|
+
"select",
|
|
56
|
+
"checkbox",
|
|
57
|
+
"accessible",
|
|
58
|
+
"a11y",
|
|
59
|
+
"tailwind",
|
|
60
|
+
"typescript",
|
|
61
|
+
"nomos"
|
|
62
|
+
],
|
|
63
|
+
"author": "Uanela Como",
|
|
64
|
+
"license": "MIT",
|
|
65
|
+
"repository": {
|
|
66
|
+
"type": "git",
|
|
67
|
+
"url": "git+https://github.com/uanela/nomos-ui.git",
|
|
68
|
+
"directory": "packages/react"
|
|
69
|
+
},
|
|
70
|
+
"bugs": {
|
|
71
|
+
"url": "https://github.com/uanela/nomos-ui/issues"
|
|
72
|
+
},
|
|
73
|
+
"homepage": "https://github.com/uanela/nomos-ui/tree/main/packages/react#readme",
|
|
74
|
+
"files": ["dist", "README.md", "LICENSE"],
|
|
75
|
+
"sideEffects": false,
|
|
76
|
+
"packageManager": "pnpm@10.13.1",
|
|
77
|
+
"dependencies": {
|
|
78
|
+
"@radix-ui/react-slot": "^1.2.3",
|
|
79
|
+
"@tailwindcss/postcss": "^4.1.16",
|
|
80
|
+
"@tailwindcss/vite": "^4.1.16",
|
|
81
|
+
"class-variance-authority": "^0.7.1",
|
|
82
|
+
"clsx": "^2.1.1",
|
|
83
|
+
"lucide-react": "^0.548.0",
|
|
84
|
+
"tailwind-merge": "^3.3.1"
|
|
85
|
+
},
|
|
86
|
+
"devDependencies": {
|
|
87
|
+
"@types/node": "^24.9.1",
|
|
88
|
+
"@types/react": "^19.2.2",
|
|
89
|
+
"@types/react-dom": "^19.2.0",
|
|
90
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
91
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
92
|
+
"eslint": "^8.56.0",
|
|
93
|
+
"eslint-plugin-react": "^7.33.2",
|
|
94
|
+
"eslint-plugin-react-hooks": "^4.6.0",
|
|
95
|
+
"tailwindcss": "^4.1.16",
|
|
96
|
+
"trash-cli": "^7.0.0",
|
|
97
|
+
"tsx": "^4.20.3",
|
|
98
|
+
"typescript": "^5.9.3",
|
|
99
|
+
"vitest": "^4.0.3"
|
|
100
|
+
},
|
|
101
|
+
"peerDependencies": {
|
|
102
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
103
|
+
"react-dom": "^18.0.0 || ^19.0.0",
|
|
104
|
+
"react-hook-form": "^7.0.0"
|
|
105
|
+
},
|
|
106
|
+
"peerDependenciesMeta": {
|
|
107
|
+
"react": {
|
|
108
|
+
"optional": false
|
|
109
|
+
},
|
|
110
|
+
"react-dom": {
|
|
111
|
+
"optional": false
|
|
112
|
+
},
|
|
113
|
+
"react-hook-form": {
|
|
114
|
+
"optional": false
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
"engines": {
|
|
118
|
+
"node": ">=18.0.0"
|
|
119
|
+
},
|
|
120
|
+
"publishConfig": {
|
|
121
|
+
"access": "public"
|
|
122
|
+
}
|
|
123
|
+
}
|