suprform 1.0.6 → 1.0.8

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 CHANGED
@@ -1,363 +1,499 @@
1
- # suprform
2
-
3
- A lightweight, **design system agnostic** React form library built as a powerful wrapper on top of **[react-hook-form](https://react-hook-form.com)**. Manage complex forms, validation, and error handling with a clean, composable API—no UI components bundled, complete control over your design.
4
-
5
- > **What is SuprForm?** A thin, type-safe layer on top of `react-hook-form` that adds intuitive field management, built-in validation rules, and automatic error display—while staying completely design-system agnostic.
6
-
7
- ## Key Highlights
8
-
9
- - 🎨 **Design System Agnostic** - Works with any UI framework (Material-UI, Tailwind, custom components, etc.) or plain HTML
10
- - 🪝 **Built on react-hook-form** - Leverages the performance and flexibility of the most popular form library
11
- - 🔒 **TypeScript First** - Full type safety and IntelliSense support with complete type inference
12
- - **Seamless Validation** - Declarative validation rules with built-in validators and custom rule support
13
- - 🎯 **Field-Level Control** - Granular control over individual fields with automatic state tracking
14
- - 📊 **Automatic State Management** - Tracks dirty, touched, valid, error, and submission states
15
- - ⚡ **Async Validation** - Native support for asynchronous validation (API calls, etc.)
16
- - 🧪 **Well Tested** - Comprehensive test suite with full coverage
17
- - 📦 **Minimal Footprint** - Only requires React as a peer dependency
18
-
19
- ## Installation
20
-
21
- ````bash
22
- npm install suprform
23
-
24
- ## Quick Start with SuprForm.Control
25
-
26
- The easiest way to get started—use the composable `SuprForm.Control` component with your own UI components:
27
-
28
- ```tsx
29
- import SuprForm from 'suprform';
30
-
31
- function LoginForm() {
32
- return (
33
- <SuprForm
34
- onSubmit={(values) => {
35
- console.log('Form submitted:', values);
36
- }}
37
- >
38
- <SuprForm.Control
39
- name='email'
40
- label='Email Address'
41
- rules={{
42
- required: 'Email is required',
43
- pattern: {
44
- value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
45
- message: 'Invalid email address',
46
- },
47
- }}
48
- >
49
- <input type='email' placeholder='you@example.com' />
50
- </SuprForm.Control>
51
-
52
- <SuprForm.Control
53
- name='password'
54
- label='Password'
55
- rules={{
56
- required: 'Password is required',
57
- minLength: { value: 8, message: 'Password must be at least 8 characters' },
58
- }}
59
- >
60
- <input type='password' placeholder='••••••••' />
61
- </SuprForm.Control>
62
-
63
- <button type='submit'>Login</button>
64
- </SuprForm>
65
- );
66
- }
67
- ````
68
-
69
- **That's it!** `SuprForm.Control` automatically:
70
-
71
- - Renders a label above the input
72
- - Validates on blur and change
73
- - Displays error messages below the input
74
- - Manages field state (touched, dirty, value, etc.)
75
-
76
- Works with any input component—plain HTML, styled divs, Material-UI inputs, custom components, etc.
77
-
78
- ## Advanced Example: Custom UI Components
79
-
80
- Since SuprForm is **design system agnostic**, use it with your favorite component library:
81
-
82
- ```tsx
83
- import SuprForm from 'suprform';
84
- import { TextField, Button } from '@mui/material'; // or your own
85
-
86
- function SignupForm() {
87
- return (
88
- <SuprForm
89
- onSubmit={(values) => {
90
- console.log('User signed up:', values);
91
- }}
92
- >
93
- <SuprForm.Control
94
- name='username'
95
- label='Username'
96
- rules={{
97
- required: 'Username is required',
98
- minLength: { value: 3, message: 'Min 3 characters' },
99
- pattern: {
100
- value: /^[a-zA-Z0-9_]+$/,
101
- message: 'Only letters, numbers, and underscores',
102
- },
103
- }}
104
- >
105
- <TextField variant='outlined' fullWidth />
106
- </SuprForm.Control>
107
-
108
- <SuprForm.Control
109
- name='email'
110
- label='Email'
111
- rules={{
112
- required: 'Email is required',
113
- pattern: {
114
- value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
115
- message: 'Invalid email',
116
- },
117
- }}
118
- >
119
- <TextField type='email' variant='outlined' fullWidth />
120
- </SuprForm.Control>
121
-
122
- <Button variant='contained' type='submit'>
123
- Sign Up
124
- </Button>
125
- </SuprForm>
126
- );
127
- }
128
- ```
129
-
130
- ## Styling
131
-
132
- Since SuprForm is **design system agnostic**, styling is completely in your control. Here are the CSS classes generated:
133
-
134
- ```css
135
- /* Wrapper for the entire field */
136
- .controlled-field {
137
- /* Your styles */
138
- }
139
-
140
- /* Label element */
141
- .controlled-field-label {
142
- /* Your styles */
143
- }
144
-
145
- /* Error message container */
146
- .controlled-field-error {
147
- /* Defaults to red, 14px font, margin-top 4px */
148
- /* Override with your own styles */
149
- }
150
- ```
151
-
152
- **Example with Tailwind CSS:**
153
-
154
- ```tsx
155
- <SuprForm.Control
156
- name='email'
157
- label='Email'
158
- rules={{ required: 'Email is required' }}
159
- className='mb-4'
160
- >
161
- <input
162
- type='email'
163
- className='w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2'
164
- />
165
- </SuprForm.Control>
166
- ```
167
-
168
- **Example with styled-components:**
169
-
170
- ```tsx
171
- import styled from 'styled-components';
172
-
173
- const StyledField = styled.div`
174
- margin-bottom: 1.5rem;
175
-
176
- label {
177
- display: block;
178
- font-weight: 600;
179
- margin-bottom: 0.5rem;
180
- }
181
-
182
- input {
183
- width: 100%;
184
- padding: 0.75rem;
185
- border: 1px solid #ddd;
186
- border-radius: 4px;
187
-
188
- &:focus {
189
- outline: none;
190
- border-color: #0066cc;
191
- box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1);
192
- }
193
- }
194
-
195
- .controlled-field-error {
196
- color: #d32f2f;
197
- font-size: 0.875rem;
198
- margin-top: 0.5rem;
199
- }
200
- `;
201
-
202
- function EmailField() {
203
- return (
204
- <SuprForm.Control
205
- name='email'
206
- label='Email'
207
- rules={{ required: 'Email is required' }}
208
- className={StyledField}
209
- >
210
- <input type='email' />
211
- </SuprForm.Control>
212
- );
213
- }
214
- ```
215
-
216
- ## Publishing
217
-
218
- To publish a new version to npm:
219
-
220
- 1. Ensure you are logged in to npm:
221
-
222
- ```bash
223
- npm login
224
- ```
225
-
226
- 2. Build the package (runs automatically via `prepublishOnly`):
227
-
228
- ```bash
229
- npm run build
230
- ```
231
-
232
- 3. Bump the version and publish:
233
-
234
- ```bash
235
- npm version patch # or minor/major
236
- npm publish --access public --otp=XXXXXX
237
- ```
238
-
239
- (Replace `XXXXXX` with your 2FA code if you have 2FA enabled.)
240
-
241
- The published package contains only the compiled `dist/` files with ESM/CJS builds and TypeScript declarations.
242
-
243
- ## Validation Rules
244
-
245
- All validation rules come from **react-hook-form**. Pass them directly to the `rules` prop:
246
-
247
- ```tsx
248
- <SuprForm.Control
249
- name='age'
250
- rules={{
251
- required: 'Age is required',
252
- min: { value: 18, message: 'Must be 18 or older' },
253
- max: { value: 120, message: 'Please enter a valid age' },
254
- }}
255
- >
256
- <input type='number' />
257
- </SuprForm.Control>
258
- ```
259
-
260
- ### Common Rules
261
-
262
- - `required` / `required: "message"` - Field must not be empty
263
- - `minLength: { value: 5, message: "..." }` - Minimum string length
264
- - `maxLength: { value: 20, message: "..." }` - Maximum string length
265
- - `min: { value: 0, message: "..." }` - Minimum numeric value
266
- - `max: { value: 100, message: "..." }` - Maximum numeric value
267
- - `pattern: { value: /regex/, message: "..." }` - Match a regex pattern
268
- - `validate: (value) => true || "error message"` - Custom synchronous validation
269
- - `validate: async (value) => true || "error message"` - Custom async validation
270
-
271
- ### Custom Validation Example
272
-
273
- ```tsx
274
- <SuprForm.Control
275
- name='password'
276
- rules={{
277
- required: 'Password is required',
278
- minLength: { value: 8, message: 'Must be at least 8 characters' },
279
- validate: async (value) => {
280
- const isCommon = await checkIfPasswordIsCommon(value);
281
- return !isCommon || 'This password is too common';
282
- },
283
- }}
284
- >
285
- <input type='password' />
286
- </SuprForm.Control>
287
- ```
288
-
289
- ## API Reference
290
-
291
- ### SuprForm Component
292
-
293
- The root form wrapper (powered by `FormProvider` from react-hook-form).
294
-
295
- **Props:**
296
-
297
- - `children` - Form fields and elements
298
- - `onSubmit` - Handler called with form values when form is valid
299
- - `className` - CSS class for the `<form>` element
300
- - `style` - Inline styles for the `<form>` element
301
- - `formOptions` - Options passed to react-hook-form's `useForm()` hook
302
-
303
- **Example:**
304
-
305
- ```tsx
306
- <SuprForm
307
- onSubmit={(values) => console.log(values)}
308
- formOptions={{
309
- mode: 'onBlur', // Validate on blur instead of on change
310
- reValidateMode: 'onChange',
311
- }}
312
- >
313
- {/* controls */}
314
- </SuprForm>
315
- ```
316
-
317
- ### SuprForm.Control Component
318
-
319
- Composable field control component that wraps your input elements.
320
-
321
- **Props:**
322
-
323
- - `name` - Field name (must match form values)
324
- - `label` - Optional label text (rendered above input with `htmlFor` linking)
325
- - `children` - Your input component (any React element)
326
- - `rules` - Validation rules (react-hook-form's `RegisterOptions`)
327
- - `className` - CSS class for the wrapper div
328
-
329
- **Example:**
330
-
331
- ```tsx
332
- <SuprForm.Control
333
- name='email'
334
- label='Email'
335
- rules={{ required: 'Email is required' }}
336
- className='form-field'
337
- >
338
- <input type='email' />
339
- </SuprForm.Control>
340
- ```
341
-
342
- **Automatic Features:**
343
-
344
- - Renders `<label>` when `label` prop is provided
345
- - Displays error message below input (in red, styled as `.controlled-field-error`)
346
- - Injects `name`, `value`, `onChange`, `onBlur`, and `error` props to child input
347
- - Handles field state automatically (touched, dirty, valid)
348
- - `defaultValue` - Default field value
349
- - `validators` - Array of validators
350
-
351
- **Returns:**
352
-
353
- - `field` - Field props (value, onChange, onBlur, onFocus)
354
- - `meta` - Field metadata (error, touched, dirty, validating)
355
- - `helpers` - Field helper functions
356
-
357
- ## License
358
-
359
- MIT
360
-
361
- ## Contributing
362
-
363
- Contributions are welcome! Please feel free to submit a Pull Request.
1
+ # SuprForm
2
+
3
+ A **headless React form library** that wraps [react-hook-form](https://react-hook-form.com) with a composable API for effortless form management. Design system agnostic, TypeScript-first, and built for developer experience.
4
+
5
+ ## Core Features
6
+
7
+ ### 🎨 **Design System Agnostic**
8
+
9
+ Use with any UI frameworkMaterial-UI, Ant Design, Tailwind, shadcn/ui, or plain HTML. SuprForm provides the logic, you control the design.
10
+
11
+ ```tsx
12
+ // Works with Material-UI
13
+ <SuprForm.Control name="email" rules={{ required: true }}>
14
+ <TextField variant="outlined" />
15
+ </SuprForm.Control>
16
+
17
+ // Works with plain HTML
18
+ <SuprForm.Control name="email" rules={{ required: true }}>
19
+ <input type="email" />
20
+ </SuprForm.Control>
21
+ ```
22
+
23
+ ### 🎯 **Composable Field Control**
24
+
25
+ The `SuprForm.Control` component wraps your inputs with automatic label rendering, error display, and validation—no configuration needed.
26
+
27
+ - Automatic label and error rendering
28
+ - Field state tracking (touched, dirty, valid)
29
+ - Seamless integration with any input component
30
+ - Full TypeScript inference for field names and values
31
+
32
+ ### 🔒 **TypeScript-First Architecture**
33
+
34
+ Complete type safety with intelligent inference throughout your forms. Field names, validation rules, and form values are all fully typed.
35
+
36
+ ```tsx
37
+ interface FormData {
38
+ email: string;
39
+ age: number;
40
+ }
41
+
42
+ <SuprForm<FormData>
43
+ onSubmit={(values) => {
44
+ // values is typed as FormData
45
+ console.log(values.email); // Type-safe
46
+ }}
47
+ >
48
+ <SuprForm.Control name='email' /> {/* ✓ Type-checked */}
49
+ </SuprForm>;
50
+ ```
51
+
52
+ ### 👁️ **Conditional Field Visibility**
53
+
54
+ Advanced conditional rendering with declarative visibility rules. Show/hide fields based on other field values with AND/OR logic.
55
+
56
+ ```tsx
57
+ <SuprForm.Control
58
+ name='creditCard'
59
+ visibility={{
60
+ operator: 'AND',
61
+ conditions: [
62
+ { name: 'paymentMethod', operator: 'EQUALS', value: 'card' },
63
+ { name: 'amount', operator: 'GREATER_THAN', value: 0 },
64
+ ],
65
+ }}
66
+ >
67
+ <input />
68
+ </SuprForm.Control>
69
+ ```
70
+
71
+ **Supported operators:** EQUALS, NOT_EQUALS, GREATER_THAN, LESS_THAN, STARTS_WITH, ENDS_WITH, INCLUDES
72
+
73
+ ### **Declarative Validation**
74
+
75
+ Powered by react-hook-form's validation system with support for sync and async validators.
76
+
77
+ ```tsx
78
+ <SuprForm.Control
79
+ name='username'
80
+ rules={{
81
+ required: 'Username is required',
82
+ minLength: { value: 3, message: 'Min 3 characters' },
83
+ validate: async (value) => {
84
+ const available = await checkAvailability(value);
85
+ return available || 'Username taken';
86
+ },
87
+ }}
88
+ >
89
+ <input />
90
+ </SuprForm.Control>
91
+ ```
92
+
93
+ ### 🎛️ **Imperative Form Control**
94
+
95
+ Access react-hook-form methods via ref for programmatic form manipulation.
96
+
97
+ ```tsx
98
+ const formRef = useRef();
99
+
100
+ <SuprForm ref={formRef} onSubmit={handleSubmit}>
101
+ {/* ... */}
102
+ </SuprForm>;
103
+
104
+ // Later:
105
+ formRef.current.setValue('email', 'test@example.com');
106
+ formRef.current.trigger('email'); // Manually validate
107
+ formRef.current.reset(); // Reset form
108
+ ```
109
+
110
+ **Available methods:** `setValue`, `setError`, `clearErrors`, `getValues`, `reset`, `setFocus`, `resetField`, `trigger`, `unregister`, `watch`
111
+
112
+ ### 📦 **Zero UI Dependencies**
113
+
114
+ Only React as a peer dependency. No CSS framework lock-in, no component library coupling. Bring your own design system.
115
+
116
+ ---
117
+
118
+ ## Quick Start
119
+
120
+ ### Installation
121
+
122
+ ```bash
123
+ npm install suprform
124
+ ```
125
+
126
+ ### Basic Example
127
+
128
+ The composable `SuprForm.Control` component handles everything for you:
129
+
130
+ ```tsx
131
+ import SuprForm from 'suprform';
132
+
133
+ function LoginForm() {
134
+ return (
135
+ <SuprForm
136
+ onSubmit={(values) => {
137
+ console.log('Form submitted:', values);
138
+ }}
139
+ >
140
+ <SuprForm.Control
141
+ name='email'
142
+ label='Email Address'
143
+ rules={{
144
+ required: 'Email is required',
145
+ pattern: {
146
+ value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
147
+ message: 'Invalid email address',
148
+ },
149
+ }}
150
+ >
151
+ <input type='email' placeholder='you@example.com' />
152
+ </SuprForm.Control>
153
+
154
+ <SuprForm.Control
155
+ name='password'
156
+ label='Password'
157
+ rules={{
158
+ required: 'Password is required',
159
+ minLength: { value: 8, message: 'Password must be at least 8 characters' },
160
+ }}
161
+ >
162
+ <input type='password' placeholder='••••••••' />
163
+ </SuprForm.Control>
164
+
165
+ <button type='submit'>Login</button>
166
+ </SuprForm>
167
+ );
168
+ }
169
+ ```
170
+
171
+ SuprForm.Control **automatically handles**:
172
+
173
+ - Label rendering with proper `htmlFor` linking
174
+ - Validation on blur and change
175
+ - Error message display
176
+ - Field state management (value, touched, dirty, error)
177
+ - Works with any input component (HTML, Material-UI, custom, etc.)
178
+
179
+ ---
180
+
181
+ ## Advanced Usage
182
+
183
+ ### With UI Component Libraries
184
+
185
+ ```tsx
186
+ import SuprForm from 'suprform';
187
+ import { TextField, Button } from '@mui/material'; // or your own
188
+
189
+ function SignupForm() {
190
+ return (
191
+ <SuprForm
192
+ onSubmit={(values) => {
193
+ console.log('User signed up:', values);
194
+ }}
195
+ >
196
+ <SuprForm.Control
197
+ name='username'
198
+ label='Username'
199
+ rules={{
200
+ required: 'Username is required',
201
+ minLength: { value: 3, message: 'Min 3 characters' },
202
+ pattern: {
203
+ value: /^[a-zA-Z0-9_]+$/,
204
+ message: 'Only letters, numbers, and underscores',
205
+ },
206
+ }}
207
+ >
208
+ <TextField variant='outlined' fullWidth />
209
+ </SuprForm.Control>
210
+
211
+ <SuprForm.Control
212
+ name='email'
213
+ label='Email'
214
+ rules={{
215
+ required: 'Email is required',
216
+ pattern: {
217
+ value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
218
+ message: 'Invalid email',
219
+ },
220
+ }}
221
+ >
222
+ <TextField type='email' variant='outlined' fullWidth />
223
+ </SuprForm.Control>
224
+
225
+ <Button variant='contained' type='submit'>
226
+ Sign Up
227
+ </Button>
228
+ </SuprForm>
229
+ );
230
+ }
231
+ ```
232
+
233
+ ### Conditional Field Visibility
234
+
235
+ Show/hide fields based on other field values:
236
+
237
+ ```tsx
238
+ <SuprForm onSubmit={handleSubmit}>
239
+ <SuprForm.Control name='hasDiscount' label='Apply Discount?'>
240
+ <input type='checkbox' />
241
+ </SuprForm.Control>
242
+
243
+ {/* Only show when hasDiscount is checked */}
244
+ <SuprForm.Control
245
+ name='discountCode'
246
+ label='Discount Code'
247
+ visibility={{
248
+ operator: 'AND',
249
+ conditions: [{ name: 'hasDiscount', operator: 'EQUALS', value: true }],
250
+ }}
251
+ rules={{ required: 'Discount code required' }}
252
+ >
253
+ <input type='text' />
254
+ </SuprForm.Control>
255
+ </SuprForm>
256
+ ```
257
+
258
+ ### Async Validation
259
+
260
+ ```tsx
261
+ <SuprForm.Control
262
+ name='username'
263
+ rules={{
264
+ required: 'Username is required',
265
+ validate: async (value) => {
266
+ const response = await fetch(`/api/check-username/${value}`);
267
+ const data = await response.json();
268
+ return data.available || 'Username already taken';
269
+ },
270
+ }}
271
+ >
272
+ <input />
273
+ </SuprForm.Control>
274
+ ```
275
+
276
+ ### Programmatic Form Control
277
+
278
+ ```tsx
279
+ function MyForm() {
280
+ const formRef = useRef();
281
+
282
+ const prefillForm = () => {
283
+ formRef.current.setValue('email', 'user@example.com');
284
+ formRef.current.setFocus('password');
285
+ };
286
+
287
+ return (
288
+ <>
289
+ <button onClick={prefillForm}>Prefill</button>
290
+ <SuprForm ref={formRef} onSubmit={handleSubmit}>
291
+ <SuprForm.Control name='email'>
292
+ <input />
293
+ </SuprForm.Control>
294
+ <SuprForm.Control name='password'>
295
+ <input type='password' />
296
+ </SuprForm.Control>
297
+ </SuprForm>
298
+ </>
299
+ );
300
+ }
301
+ ```
302
+
303
+ ---
304
+
305
+ ## API Reference
306
+
307
+ ### `<SuprForm>`
308
+
309
+ Root form component that wraps your form fields.
310
+
311
+ **Props:**
312
+
313
+ | Prop | Type | Description |
314
+ | -------------- | --------------------- | -------------------------------------------- |
315
+ | `children` | `ReactNode` | Form fields and elements |
316
+ | `onSubmit` | `(values: T) => void` | Called with form values when valid |
317
+ | `onError` | `(errors) => void` | Called when form submission fails validation |
318
+ | `formOptions` | `UseFormProps` | Options for react-hook-form's `useForm()` |
319
+ | `className` | `string` | CSS class for `<form>` element |
320
+ | `style` | `CSSProperties` | Inline styles for `<form>` |
321
+ | `showAsterisk` | `boolean` | Show asterisk on required field labels |
322
+ | `ref` | `Ref` | Access form methods imperatively |
323
+
324
+ **Example:**
325
+
326
+ ```tsx
327
+ <SuprForm onSubmit={(values) => console.log(values)} formOptions={{ mode: 'onBlur' }} showAsterisk>
328
+ {/* fields */}
329
+ </SuprForm>
330
+ ```
331
+
332
+ ### `<SuprForm.Control>`
333
+
334
+ Composable field wrapper that handles labels, errors, and validation.
335
+
336
+ **Props:**
337
+
338
+ | Prop | Type | Description |
339
+ | ------------------ | ----------------------- | ----------------------------------------------------------- |
340
+ | `name` | `string` | **Required.** Field name (type-checked against form values) |
341
+ | `children` | `ReactElement` | **Required.** Your input component |
342
+ | `rules` | `RegisterOptions` | Validation rules (react-hook-form format) |
343
+ | `label` | `string` | Label text (rendered above input) |
344
+ | `className` | `string` | CSS class for wrapper div |
345
+ | `id` | `string` | HTML id (auto-generated if not provided) |
346
+ | `disabled` | `boolean` | Disable the field |
347
+ | `visibility` | `Visibility \| boolean` | Conditional visibility rules |
348
+ | `shouldUnregister` | `boolean` | Unregister field when unmounted |
349
+
350
+ **Example:**
351
+
352
+ ```tsx
353
+ <SuprForm.Control
354
+ name='email'
355
+ label='Email Address'
356
+ rules={{
357
+ required: 'Email is required',
358
+ pattern: { value: /^\S+@\S+$/, message: 'Invalid email' },
359
+ }}
360
+ className='mb-4'
361
+ >
362
+ <input type='email' />
363
+ </SuprForm.Control>
364
+ ```
365
+
366
+ ### Validation Rules
367
+
368
+ SuprForm uses [react-hook-form validation rules](https://react-hook-form.com/docs/useform/register#options):
369
+
370
+ | Rule | Type | Description |
371
+ | ----------- | ----------------------------------------- | -------------------------- |
372
+ | `required` | `string \| boolean` | Field is required |
373
+ | `min` | `{ value: number, message: string }` | Minimum numeric value |
374
+ | `max` | `{ value: number, message: string }` | Maximum numeric value |
375
+ | `minLength` | `{ value: number, message: string }` | Minimum string length |
376
+ | `maxLength` | `{ value: number, message: string }` | Maximum string length |
377
+ | `pattern` | `{ value: RegExp, message: string }` | Regex pattern match |
378
+ | `validate` | `(value) => boolean \| string \| Promise` | Custom validation function |
379
+
380
+ ### Conditional Visibility
381
+
382
+ The `visibility` prop accepts:
383
+
384
+ ```tsx
385
+ {
386
+ operator: 'AND' | 'OR',
387
+ conditions: [
388
+ {
389
+ name: 'fieldName',
390
+ operator: 'EQUALS' | 'NOT_EQUALS' | 'GREATER_THAN' | 'LESS_THAN' |
391
+ 'GREATER_THAN_OR_EQUAL' | 'LESS_THAN_OR_EQUAL' |
392
+ 'STARTS_WITH' | 'ENDS_WITH' | 'INCLUDES' | 'NOT_INCLUDES',
393
+ value: any
394
+ }
395
+ ]
396
+ }
397
+ ```
398
+
399
+ **Example:**
400
+
401
+ ```tsx
402
+ <SuprForm.Control
403
+ name='promoCode'
404
+ visibility={{
405
+ operator: 'OR',
406
+ conditions: [
407
+ { name: 'isVip', operator: 'EQUALS', value: true },
408
+ { name: 'orderTotal', operator: 'GREATER_THAN', value: 100 },
409
+ ],
410
+ }}
411
+ >
412
+ <input />
413
+ </SuprForm.Control>
414
+ ```
415
+
416
+ ### Form Ref Methods
417
+
418
+ When you pass a `ref` to `<SuprForm>`, you get access to:
419
+
420
+ ```tsx
421
+ formRef.current.setValue(name, value) // Set field value
422
+ formRef.current.setError(name, error) // Set field error
423
+ formRef.current.clearErrors(name?) // Clear errors
424
+ formRef.current.getValues(name?) // Get field value(s)
425
+ formRef.current.reset(values?) // Reset form
426
+ formRef.current.setFocus(name) // Focus field
427
+ formRef.current.resetField(name) // Reset specific field
428
+ formRef.current.trigger(name?) // Trigger validation
429
+ formRef.current.unregister(name) // Unregister field
430
+ formRef.current.watch(name?) // Watch field value(s)
431
+ ```
432
+
433
+ ---
434
+
435
+ ---
436
+
437
+ ## Styling
438
+
439
+ SuprForm is **design system agnostic**. Style using CSS classes:
440
+
441
+ ```css
442
+ .controlled-field {
443
+ /* Field wrapper */
444
+ }
445
+ .controlled-field-label {
446
+ /* Label element */
447
+ }
448
+ .controlled-field-error {
449
+ /* Error message (defaults: red, 14px, margin-top 4px) */
450
+ }
451
+ ```
452
+
453
+ **Tailwind Example:**
454
+
455
+ ```tsx
456
+ <SuprForm.Control name='email' className='mb-4'>
457
+ <input className='w-full px-4 py-2 border rounded-lg focus:ring-2' />
458
+ </SuprForm.Control>
459
+ ```
460
+
461
+ **styled-components Example:**
462
+
463
+ ```tsx
464
+ const StyledField = styled.div`
465
+ .controlled-field-label {
466
+ font-weight: 600;
467
+ }
468
+ .controlled-field-error {
469
+ color: #d32f2f;
470
+ }
471
+ `;
472
+
473
+ <SuprForm.Control className={StyledField} name='email'>
474
+ <input />
475
+ </SuprForm.Control>;
476
+ ```
477
+
478
+ ---
479
+
480
+ ## Publishing
481
+
482
+ ```bash
483
+ npm login
484
+ npm run build
485
+ npm version patch # or minor/major
486
+ npm publish --access public --otp=XXXXXX
487
+ ```
488
+
489
+ The published package contains only compiled `dist/` files (ESM/CJS + TypeScript declarations).
490
+
491
+ ---
492
+
493
+ ## License
494
+
495
+ MIT
496
+
497
+ ## Contributing
498
+
499
+ Contributions welcome! Submit a Pull Request on [GitHub](https://github.com/Albinbritto/suprform).