@rachelallyson/hero-hook-form 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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,50 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.0.0] - 2024-08-23
9
+
10
+ ### Added
11
+
12
+ - Initial release of Hero Hook Form
13
+ - Complete form field components for HeroUI integration
14
+ - InputField
15
+ - TextareaField
16
+ - SelectField
17
+ - RadioGroupField
18
+ - CheckboxField
19
+ - SwitchField
20
+ - SliderField
21
+ - DateField
22
+ - FileField
23
+ - ConfigurableForm component for rapid form development
24
+ - FormProvider for form context management
25
+ - ConfigProvider for global configuration defaults
26
+ - SubmitButton component with loading states
27
+ - Zod integration with ZodForm component
28
+ - Dual entrypoint support (default and /react)
29
+ - Comprehensive TypeScript support
30
+ - Full documentation with examples
31
+ - Cypress test suite for all components
32
+
33
+ ### Features
34
+
35
+ - Strongly-typed field components
36
+ - Multiple form layouts (vertical, horizontal, grid)
37
+ - Global configuration system
38
+ - Validation integration with React Hook Form
39
+ - Optional Zod schema validation
40
+ - Responsive design support
41
+ - Accessibility features from HeroUI
42
+ - Tree-shaking support for individual components
43
+
44
+ ### Technical
45
+
46
+ - Built with TypeScript
47
+ - ESM and CommonJS support
48
+ - Dual entrypoint architecture
49
+ - Comprehensive test coverage
50
+ - Full documentation suite
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2024, Rachel Higley
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,440 @@
1
+ # Hero Hook Form
2
+
3
+ [![npm version](https://badge.fury.io/js/%40rachelallyson%2Fhero-hook-form.svg)](https://badge.fury.io/js/%40rachelallyson%2Fhero-hook-form)
4
+ [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC)
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue.svg)](https://www.typescriptlang.org/)
6
+ [![React](https://img.shields.io/badge/React-18.2+-blue.svg)](https://reactjs.org/)
7
+ [![HeroUI](https://img.shields.io/badge/HeroUI-2.x-purple.svg)](https://heroui.com/)
8
+
9
+ > **Typed form helpers that combine React Hook Form and HeroUI components.**
10
+
11
+ Build beautiful, accessible forms with full TypeScript support, validation, and HeroUI's design system.
12
+
13
+ ## ✨ Features
14
+
15
+ - 🎯 **Strongly-typed** field components for HeroUI + React Hook Form
16
+ - πŸ—οΈ **Single codebase, dual entrypoints**:
17
+ - Default entrypoint for individual HeroUI packages
18
+ - `/react` entrypoint for the aggregate `@heroui/react`
19
+ - πŸ“¦ **Optional peers** so apps can install only what they need
20
+ - πŸ”§ **Global configuration** system for consistent styling
21
+ - βœ… **Zod integration** for schema-based validation
22
+ - 🎨 **Multiple layouts** (vertical, horizontal, grid)
23
+ - β™Ώ **Accessibility-first** with HeroUI's built-in features
24
+ - 🌳 **Tree-shakeable** for optimal bundle sizes
25
+
26
+ ## πŸš€ Quick Start
27
+
28
+ ```bash
29
+ npm install @rachelallyson/hero-hook-form react-hook-form @heroui/react
30
+ ```
31
+
32
+ ```tsx
33
+ import { useForm } from "react-hook-form";
34
+ import { Form, InputField, SubmitButton } from "@rachelallyson/hero-hook-form/react";
35
+
36
+ export function ContactForm() {
37
+ const methods = useForm();
38
+
39
+ return (
40
+ <Form methods={methods} onSubmit={console.log}>
41
+ <InputField control={methods.control} label="Email" name="email" />
42
+ <SubmitButton>Send</SubmitButton>
43
+ </Form>
44
+ );
45
+ }
46
+ ```
47
+
48
+ ## πŸ“Š Why Hero Hook Form?
49
+
50
+ | Feature | Manual Setup | Hero Hook Form |
51
+ |---------|--------------|----------------|
52
+ | TypeScript | ❌ Manual types | βœ… Automatic inference |
53
+ | Validation | ❌ Complex setup | βœ… Built-in + Zod |
54
+ | Styling | ❌ Inconsistent | βœ… Global defaults |
55
+ | Accessibility | ❌ Manual work | βœ… HeroUI built-in |
56
+ | Bundle size | ❌ Large | βœ… Tree-shakeable |
57
+ | Development | ❌ Slow | βœ… Rapid prototyping |
58
+
59
+ ## Requirements
60
+
61
+ - react: >=18.2 <20
62
+ - react-dom: >=18.2 <20
63
+ - react-hook-form: >=7 <8
64
+ - HeroUI: 2.x (either the aggregate or individual component packages)
65
+
66
+ ## Installation
67
+
68
+ ### Option A: Using individual HeroUI packages (default entrypoint)
69
+
70
+ Install the library, React Hook Form, and the HeroUI components you actually use. If you only use a subset, install just that subset.
71
+
72
+ ```bash
73
+ # minimal set that covers all included fields
74
+ npm i @rachelallyson/hero-hook-form react-hook-form \
75
+ @heroui/input @heroui/checkbox @heroui/radio @heroui/select \
76
+ @heroui/switch @heroui/button @heroui/spinner
77
+ ```
78
+
79
+ Then import from the package root:
80
+
81
+ ```tsx
82
+ import { InputField, SelectField, CheckboxField, RadioGroupField, SwitchField, TextareaField, SubmitButton } from "@rachelallyson/hero-hook-form";
83
+ ```
84
+
85
+ ### Option B: Using the aggregate `@heroui/react` (react entrypoint)
86
+
87
+ Install the library, React Hook Form, and the aggregate package:
88
+
89
+ ```bash
90
+ npm i @rachelallyson/hero-hook-form react-hook-form @heroui/react
91
+ ```
92
+
93
+ Then import from the `/react` subpath:
94
+
95
+ ```tsx
96
+ import { InputField, SelectField, CheckboxField, RadioGroupField, SwitchField, TextareaField, SubmitButton } from "@rachelallyson/hero-hook-form/react";
97
+ ```
98
+
99
+ ## Setup (recommended)
100
+
101
+ Most HeroUI apps wrap the app with the `HeroUIProvider` from `@heroui/system` and typically set up theming via `next-themes` or similar. Example (Next.js):
102
+
103
+ ```tsx
104
+ import { HeroUIProvider } from "@heroui/system";
105
+ import { ThemeProvider } from "next-themes";
106
+
107
+ export function Providers({ children }: { children: React.ReactNode }) {
108
+ return (
109
+ <HeroUIProvider>
110
+ <ThemeProvider attribute="class" defaultTheme="dark">
111
+ {children}
112
+ </ThemeProvider>
113
+ </HeroUIProvider>
114
+ );
115
+ }
116
+ ```
117
+
118
+ ## Global configuration (defaults)
119
+
120
+ Set global defaults for all fields with `HeroHookFormProvider`. You can set a `common` bucket (applies to all supported components) and/or per-component buckets. Per-instance props always win.
121
+
122
+ Import the provider from the entrypoint you use (root or `/react`):
123
+
124
+ ```tsx
125
+ import { HeroHookFormProvider } from "@rachelallyson/hero-hook-form"; // or "/react"
126
+
127
+ export function AppProviders({ children }: { children: React.ReactNode }) {
128
+ return (
129
+ <HeroHookFormProvider
130
+ defaults={{
131
+ // Common keys shared across text-like controls (Input, Textarea, Select)
132
+ // and safely narrowed for toggles and the submit button.
133
+ common: {
134
+ color: "primary",
135
+ size: "md",
136
+ variant: "faded",
137
+ radius: "sm",
138
+ labelPlacement: "outside",
139
+ },
140
+ // Component-specific defaults override 'common' for that component
141
+ input: { variant: "underlined" },
142
+ select: { variant: "flat" },
143
+ submitButton: { color: "secondary" },
144
+ }}
145
+ >
146
+ {children}
147
+ </HeroHookFormProvider>
148
+ );
149
+ }
150
+ ```
151
+
152
+ - Precedence (highest last):
153
+ 1) `defaults.common`
154
+ 2) `defaults.{component}` (e.g., `input`, `select`, `checkbox`, `radioGroup`, `switch`, `textarea`, `submitButton`)
155
+ 3) Per-instance props (e.g., `inputProps`, `selectProps`, `checkboxProps`, etc.)
156
+
157
+ - Supported `common` keys (strongly typed and intersected across text-like controls):
158
+ - `color`, `size`, `variant`, `radius`, `labelPlacement`
159
+ - For toggles (`checkbox`, `radioGroup`, `switch`) and `submitButton`, only `color` and `size` are applied.
160
+
161
+ - Example instance override:
162
+
163
+ ```tsx
164
+ <InputField
165
+ control={methods.control}
166
+ label="Name"
167
+ name="name"
168
+ inputProps={{ color: "danger" }} // overrides global defaults for this field
169
+ />
170
+ ```
171
+
172
+ - Scoping defaults: you can nest providers to scope different defaults to specific sections of your app.
173
+
174
+ ## Zod Integration (Optional)
175
+
176
+ For type-safe validation with Zod schemas, install the additional dependencies:
177
+
178
+ ```bash
179
+ npm i zod @hookform/resolvers
180
+ ```
181
+
182
+ Then use the `ZodForm` component with Zod schemas:
183
+
184
+ ```tsx
185
+ import { z } from "zod";
186
+ import { ZodForm, createZodFormConfig } from "@rachelallyson/hero-hook-form";
187
+
188
+ // Define your schema
189
+ const contactSchema = z.object({
190
+ firstName: z.string().min(2, "First name must be at least 2 characters"),
191
+ email: z.string().email("Please enter a valid email address"),
192
+ message: z.string().min(10, "Message must be at least 10 characters"),
193
+ terms: z.boolean().refine((val) => val === true, "You must agree to the terms"),
194
+ });
195
+
196
+ // Create form configuration
197
+ const config = createZodFormConfig(contactSchema, [
198
+ { name: "firstName", type: "input", label: "First Name" },
199
+ { name: "email", type: "input", label: "Email", inputProps: { type: "email" } },
200
+ { name: "message", type: "textarea", label: "Message" },
201
+ { name: "terms", type: "checkbox", label: "I agree to the terms" },
202
+ ]);
203
+
204
+ // Use in your component
205
+ <ZodForm
206
+ config={config}
207
+ onSubmit={handleSubmit}
208
+ title="Contact Form"
209
+ showResetButton={true}
210
+ />
211
+ ```
212
+
213
+ ### Zod Features
214
+
215
+ - **Type Safety**: Full TypeScript support with automatic type inference
216
+ - **Runtime Validation**: Comprehensive validation with custom error messages
217
+ - **Schema Reusability**: Define schemas once and reuse across your app
218
+ - **Complex Validation**: Support for enums, numbers, custom refinements, and more
219
+ - **Optional Integration**: Only install Zod if you need it
220
+
221
+ ### Zod vs Standard Validation
222
+
223
+ | Feature | Standard Form | Zod Form |
224
+ |---------|---------------|----------|
225
+ | Validation Rules | In field config | In schema |
226
+ | Type Safety | Manual types | Automatic inference |
227
+ | Error Messages | Inline | In schema |
228
+ | Reusability | Per field | Schema-wide |
229
+ | Runtime Safety | Basic | Comprehensive |
230
+
231
+ ## Quick start
232
+
233
+ A small form wired with React Hook Form using our typed field components.
234
+
235
+ ```tsx
236
+ import { useForm } from "react-hook-form";
237
+ import { Form } from "@rachelallyson/hero-hook-form"; // or "/react"
238
+ import { InputField, SelectField, CheckboxField, TextareaField, RadioGroupField, SwitchField, SubmitButton } from "@rachelallyson/hero-hook-form"; // or "/react"
239
+
240
+ type Values = {
241
+ name: string;
242
+ email: string;
243
+ bio: string;
244
+ plan: "free" | "pro" | "team";
245
+ agree: boolean;
246
+ enabled: boolean;
247
+ };
248
+
249
+ export function ExampleForm() {
250
+ const methods = useForm<Values>({
251
+ defaultValues: {
252
+ name: "",
253
+ email: "",
254
+ bio: "",
255
+ plan: "free",
256
+ agree: false,
257
+ enabled: false,
258
+ },
259
+ mode: "onBlur",
260
+ });
261
+
262
+ return (
263
+ <Form
264
+ className="flex flex-col gap-4"
265
+ methods={methods}
266
+ onSubmit={async (values) => {
267
+ // submit values to your API
268
+ await new Promise((r) => setTimeout(r, 300));
269
+ console.log(values);
270
+ }}
271
+ >
272
+ <InputField control={methods.control} label="Name" name="name" rules={{ required: "Enter your name" }} />
273
+ <InputField control={methods.control} label="Email" name="email" inputProps={{ type: "email" }} rules={{ required: "Enter your email" }} />
274
+
275
+ <TextareaField control={methods.control} label="Bio" name="bio" description="Tell us about yourself" />
276
+
277
+ <SelectField
278
+ control={methods.control}
279
+ label="Plan"
280
+ name="plan"
281
+ options={[
282
+ { label: "Free", value: "free" },
283
+ { label: "Pro", value: "pro" },
284
+ { label: "Team", value: "team" },
285
+ ]}
286
+ />
287
+
288
+ <RadioGroupField
289
+ control={methods.control}
290
+ label="Plan (radio)"
291
+ name="plan"
292
+ options={[
293
+ { label: "Free", value: "free" },
294
+ { label: "Pro", value: "pro" },
295
+ { label: "Team", value: "team" },
296
+ ]}
297
+ />
298
+
299
+ <CheckboxField control={methods.control} label="I agree to the terms" name="agree" rules={{ required: "You must agree" }} />
300
+ <SwitchField control={methods.control} label="Enable feature" name="enabled" />
301
+
302
+ <div className="flex justify-end">
303
+ <SubmitButton buttonProps={{ color: "primary" }}>Submit</SubmitButton>
304
+ </div>
305
+ </Form>
306
+ );
307
+ }
308
+ ```
309
+
310
+ ## API
311
+
312
+ ### Field components
313
+
314
+ All field components are strongly typed over your form values and expose a `...Props` prop for passing through component props in a type-safe way. We derive prop types via `React.ComponentProps<typeof Component>` to avoid tight coupling to HeroUI’s internal type names.
315
+
316
+ - `InputField<TFieldValues>`
317
+ - `inputProps?: Omit<ComponentProps<typeof Input>, "value" | "onValueChange" | "label" | "isInvalid" | "errorMessage" | "isDisabled">`
318
+ - `transform?: (value: string) => string` – modify the value before writing to the form state
319
+ - `TextareaField<TFieldValues>`
320
+ - `textareaProps?: Omit<ComponentProps<typeof Textarea>, ...>`
321
+ - `SelectField<TFieldValues, TValue extends string | number = string>`
322
+ - `options: readonly { label: string; value: TValue; description?: string; disabled?: boolean }[]`
323
+ - `selectProps?: Omit<ComponentProps<typeof Select>, "selectedKeys" | "onSelectionChange" | ...>`
324
+ - `RadioGroupField<TFieldValues, TValue extends string | number = string>`
325
+ - `options: readonly { label: string; value: TValue; description?: string; disabled?: boolean }[]`
326
+ - `radioGroupProps?: Omit<ComponentProps<typeof RadioGroup>, "value" | "onValueChange" | "label">`
327
+ - `CheckboxField<TFieldValues>`
328
+ - `checkboxProps?: Omit<ComponentProps<typeof Checkbox>, ...>`
329
+ - `SwitchField<TFieldValues>`
330
+ - `switchProps?: Omit<ComponentProps<typeof Switch>, ...>`
331
+ - `SubmitButton`
332
+ - `isLoading?: boolean` – if omitted, reflects RHF’s `formState.isSubmitting`
333
+ - `buttonProps?: Omit<ComponentProps<typeof Button>, "type" | "isLoading">`
334
+
335
+ ### Form provider
336
+
337
+ - `Form<TFieldValues>` – light wrapper around RHF’s `FormProvider` that renders a `<form>` and wires `handleSubmit` safely.
338
+
339
+ ```tsx
340
+ import { Form } from "@rachelallyson/hero-hook-form"; // or "/react"
341
+
342
+ <Form methods={methods} onSubmit={onSubmit} className="space-y-4">
343
+ {/* fields */}
344
+ </Form>
345
+ ```
346
+
347
+ ### Server error helper
348
+
349
+ - `applyServerErrors(form, serverErrors)` – map API validation errors into RHF field errors.
350
+
351
+ ```ts
352
+ import { applyServerErrors } from "@rachelallyson/hero-hook-form"; // or "/react"
353
+
354
+ try {
355
+ await api.save(values);
356
+ } catch (e) {
357
+ applyServerErrors(methods, e.errors);
358
+ }
359
+ ```
360
+
361
+ ## Choosing an entrypoint
362
+
363
+ - Use the default entrypoint if your app installs individual HeroUI packages.
364
+ - Use `/react` if your app installs the aggregate `@heroui/react` and you prefer a single HeroUI dep.
365
+
366
+ Peers are marked optional. Install only the set required by your chosen entrypoint.
367
+
368
+ ## Version compatibility
369
+
370
+ - HeroUI: `>=2 <3`
371
+ - React: `>=18.2.0 <20`
372
+ - react-hook-form: `>=7 <8`
373
+
374
+ ## πŸ“š Documentation
375
+
376
+ For comprehensive documentation, examples, and guides, visit our [documentation](./docs/README.md).
377
+
378
+ ### Quick Links
379
+
380
+ - [πŸš€ Getting Started](./docs/getting-started.md) - Installation, setup, and first form
381
+ - [🧩 Components](./docs/components.md) - All available field components
382
+ - [πŸ—οΈ Form Builder](./docs/form-builder.md) - ConfigurableForm component guide
383
+ - [βš™οΈ Configuration](./docs/configuration.md) - Global configuration and providers
384
+ - [βœ… Validation](./docs/validation.md) - Form validation patterns
385
+ - [πŸ”’ Zod Integration](./docs/zod-integration.md) - Schema-based validation with Zod
386
+ - [🎨 Layouts](./docs/layouts.md) - Form layout options
387
+ - [πŸ“– API Reference](./docs/api-reference.md) - Complete API documentation
388
+
389
+ ## 🎯 Examples
390
+
391
+ Check out our [comprehensive demo](../example/app/comprehensive-demo/page.tsx) to see Hero Hook Form in action with all field types and layouts!
392
+
393
+ ## ❓ FAQ
394
+
395
+ <details>
396
+ <summary><strong>Do I need to wrap with HeroUIProvider?</strong></summary>
397
+
398
+ Recommended for proper styling and navigation integration. Most HeroUI apps already do this.
399
+
400
+ </details>
401
+
402
+ <details>
403
+ <summary><strong>Can I tree-shake?</strong></summary>
404
+
405
+ Yes! Both entrypoints are tree-shakeable. Individual packages make size more explicit, while the aggregate is convenient.
406
+
407
+ </details>
408
+
409
+ <details>
410
+ <summary><strong>Do I have to install all individual packages?</strong></summary>
411
+
412
+ No! Install only the components you actually render. If you don't use `RadioGroupField`, you can omit `@heroui/radio`.
413
+
414
+ </details>
415
+
416
+ <details>
417
+ <summary><strong>What's the difference between the two entrypoints?</strong></summary>
418
+
419
+ - **Default**: For apps using individual HeroUI packages (better tree-shaking)
420
+ - **/react**: For apps using the aggregate `@heroui/react` (convenient single dependency)
421
+
422
+ </details>
423
+
424
+ ## 🀝 Contributing
425
+
426
+ We welcome contributions! Please see our [contributing guidelines](CONTRIBUTING.md) for details.
427
+
428
+ ## πŸ“„ License
429
+
430
+ ISC License - see [LICENSE](LICENSE) file for details.
431
+
432
+ ---
433
+
434
+ <div align="center">
435
+
436
+ **Built with ❀️ by [Rachel Higley](https://github.com/rachelallyson)**
437
+
438
+ [Report Bug](https://github.com/rachelallyson/hero-hook-form/issues) Β· [Request Feature](https://github.com/rachelallyson/hero-hook-form/issues) Β· [View Examples](../example/app/comprehensive-demo/page.tsx)
439
+
440
+ </div>
@@ -0,0 +1,8 @@
1
+ "use client";
2
+
3
+ // node_modules/@heroui/dom-animation/dist/index.mjs
4
+ import { domAnimation } from "framer-motion";
5
+ var index_default = domAnimation;
6
+ export {
7
+ index_default as default
8
+ };