@page-speed/forms 0.7.9 → 0.8.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 (2) hide show
  1. package/README.md +198 -114
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
- ![Page Speed React Forms](https://octane.cdn.ing/api/v1/images/transform?url=https://cdn.ing/assets/i/r/286339/nwqgw37pigfluhcmmjmpql3yj9y4/github.png&q=90)
1
+ # ⌨️ `@page-speed/forms`
2
2
 
3
- # `@page-speed/forms`
3
+ ![Page Speed React Forms](https://octane.cdn.ing/api/v1/images/transform?url=https://cdn.ing/assets/i/r/286339/nwqgw37pigfluhcmmjmpql3yj9y4/github.png&f=webp&q=90)
4
4
 
5
- Type-safe, high-performance React form state and input components for OpenSite/DashTrack workloads.
5
+ > Type-safe, high-performance React form state and input components for OpenSite/DashTrack workloads.
6
6
 
7
7
  [![npm version](https://img.shields.io/npm/v/@page-speed/forms?style=flat-square)](https://www.npmjs.com/package/@page-speed/forms)
8
8
  [![npm downloads](https://img.shields.io/npm/dm/@page-speed/forms?style=flat-square)](https://www.npmjs.com/package/@page-speed/forms)
@@ -10,8 +10,8 @@ Type-safe, high-performance React form state and input components for OpenSite/D
10
10
 
11
11
  ## Highlights
12
12
 
13
+ - **`FormEngine`** — declarative form component with built-in API integration
13
14
  - Field-level reactivity via `@legendapp/state/react`
14
- - Typed `useForm` and `useField` APIs
15
15
  - Built-in input library (text, select, date, time, upload, rich text)
16
16
  - Tree-shakable subpath exports (`/core`, `/inputs`, `/validation`, `/upload`, `/integration`)
17
17
  - Validation rules and utilities (sync + async)
@@ -30,112 +30,151 @@ Peer dependencies:
30
30
  - `react >= 16.8.0`
31
31
  - `react-dom >= 16.8.0`
32
32
 
33
- ## Quick Start
33
+ ## Quick Start with FormEngine
34
+
35
+ `FormEngine` is the recommended entry point for most use cases. It provides a declarative API for rendering forms with built-in API integration, validation, file uploads, and styling.
34
36
 
35
37
  ```tsx
36
38
  import * as React from "react";
37
- import { Form, Field, useForm } from "@page-speed/forms";
38
- import { TextInput, Select } from "@page-speed/forms/inputs";
39
- import { required, email } from "@page-speed/forms/validation/rules";
39
+ import {
40
+ FormEngine,
41
+ type FormFieldConfig,
42
+ } from "@page-speed/forms/integration";
40
43
 
41
- export function ContactForm() {
42
- const form = useForm({
43
- initialValues: {
44
- fullName: "",
45
- email: "",
46
- inquiryType: "",
47
- },
48
- validationSchema: {
49
- fullName: required(),
50
- email: [required(), email()],
51
- inquiryType: required(),
52
- },
53
- onSubmit: async (values) => {
54
- console.log(values);
55
- },
56
- });
44
+ const fields: FormFieldConfig[] = [
45
+ {
46
+ name: "fullName",
47
+ type: "text",
48
+ label: "Full Name",
49
+ required: true,
50
+ placeholder: "Your name",
51
+ columnSpan: 12,
52
+ },
53
+ {
54
+ name: "email",
55
+ type: "email",
56
+ label: "Email",
57
+ required: true,
58
+ placeholder: "you@example.com",
59
+ columnSpan: 6,
60
+ },
61
+ {
62
+ name: "phone",
63
+ type: "tel",
64
+ label: "Phone",
65
+ columnSpan: 6,
66
+ },
67
+ {
68
+ name: "message",
69
+ type: "textarea",
70
+ label: "Message",
71
+ required: true,
72
+ columnSpan: 12,
73
+ },
74
+ ];
57
75
 
76
+ export function ContactForm() {
58
77
  return (
59
- <Form form={form}>
60
- <Field name="fullName" label="Full Name" required>
61
- {({ field, meta }) => (
62
- <TextInput
63
- {...field}
64
- placeholder="Your name"
65
- error={Boolean(meta.touched && meta.error)}
66
- />
67
- )}
68
- </Field>
78
+ <FormEngine
79
+ api={{
80
+ endpoint: "/api/contact",
81
+ method: "post",
82
+ submissionConfig: { behavior: "showConfirmation" },
83
+ }}
84
+ fields={fields}
85
+ successMessage="Thanks for reaching out!"
86
+ formLayoutSettings={{
87
+ submitButtonSetup: {
88
+ submitLabel: "Send Message",
89
+ },
90
+ }}
91
+ />
92
+ );
93
+ }
94
+ ```
69
95
 
70
- <Field name="email" label="Email" required>
71
- {({ field, meta }) => (
72
- <TextInput
73
- {...field}
74
- type="email"
75
- placeholder="you@example.com"
76
- error={Boolean(meta.touched && meta.error)}
77
- />
78
- )}
79
- </Field>
96
+ ### FormEngine Props
80
97
 
81
- <Field name="inquiryType" label="Inquiry Type" required>
82
- {({ field, meta }) => (
83
- <Select
84
- {...field}
85
- options={[
86
- { label: "General", value: "general" },
87
- { label: "Sales", value: "sales" },
88
- { label: "Support", value: "support" },
89
- ]}
90
- error={Boolean(meta.touched && meta.error)}
91
- />
92
- )}
93
- </Field>
98
+ | Prop | Type | Description |
99
+ |------|------|-------------|
100
+ | `api` | `PageSpeedFormConfig` | API endpoint and submission configuration |
101
+ | `fields` | `FormFieldConfig[]` | Array of field definitions |
102
+ | `formLayoutSettings` | `FormEngineLayoutSettings` | Layout, style, and submit button settings |
103
+ | `successMessage` | `ReactNode` | Message shown after successful submission |
104
+ | `onSubmit` | `(values) => void \| Promise<void>` | Custom submit handler |
105
+ | `onSuccess` | `(data) => void` | Called after successful submission |
106
+ | `onError` | `(error) => void` | Called when submission fails |
107
+ | `resetOnSuccess` | `boolean` | Reset form after success (default: `true`) |
94
108
 
95
- <button type="submit" disabled={form.isSubmitting}>
96
- Submit
97
- </button>
98
- </Form>
99
- );
109
+ ### Field Configuration
110
+
111
+ Each field in the `fields` array supports:
112
+
113
+ ```tsx
114
+ interface FormFieldConfig {
115
+ name: string;
116
+ type: "text" | "email" | "tel" | "textarea" | "select" | "multiselect" |
117
+ "date" | "daterange" | "time" | "file" | "checkbox" | "radio";
118
+ label?: string;
119
+ placeholder?: string;
120
+ required?: boolean;
121
+ columnSpan?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
122
+ className?: string;
123
+ options?: { label: string; value: string }[]; // For select/multiselect/radio
124
+ // File-specific props
125
+ accept?: string;
126
+ maxFiles?: number;
127
+ maxFileSize?: number;
100
128
  }
101
129
  ```
102
130
 
103
- ### Grouped Form Configuration
131
+ ### Layout Options
104
132
 
105
- `Form` supports both classic props and grouped config objects for cleaner callsites.
133
+ #### Standard Layout (default)
106
134
 
107
- ```tsx
108
- import * as React from "react";
109
- import { Form } from "@page-speed/forms";
135
+ Multi-column grid with a submit button below the fields:
110
136
 
111
- <Form
112
- form={form}
113
- notificationConfig={{
114
- successMessage: "Thanks, submission received.",
115
- submissionError,
116
- }}
117
- styleConfig={{
118
- formClassName: "space-y-6",
119
- successMessageClassName: "bg-emerald-600 text-white",
120
- errorMessageClassName: "bg-red-600 text-white",
137
+ ```tsx
138
+ <FormEngine
139
+ fields={fields}
140
+ formLayoutSettings={{
141
+ formLayout: "standard",
142
+ submitButtonSetup: {
143
+ submitLabel: "Submit",
144
+ submitVariant: "default", // | "destructive" | "outline" | "secondary" | "ghost" | "link"
145
+ },
146
+ styleRules: {
147
+ formContainer: "max-w-2xl mx-auto",
148
+ fieldsContainer: "gap-6",
149
+ formClassName: "space-y-4",
150
+ },
121
151
  }}
122
- formConfig={{
123
- endpoint: "/api/contact",
124
- method: "post",
125
- submissionConfig: {
126
- behavior: "showConfirmation",
152
+ />
153
+ ```
154
+
155
+ #### Button-Group Layout
156
+
157
+ Inline input with submit button (e.g., newsletter signup):
158
+
159
+ ```tsx
160
+ <FormEngine
161
+ fields={[{ name: "email", type: "email", label: "Email", required: true }]}
162
+ formLayoutSettings={{
163
+ formLayout: "button-group",
164
+ buttonGroupSetup: {
165
+ size: "lg", // | "xs" | "sm" | "default"
166
+ submitLabel: "Subscribe",
167
+ submitVariant: "default",
127
168
  },
128
169
  }}
129
- />;
170
+ />
130
171
  ```
131
172
 
132
- ### `FormEngine` Defaults + Wrapper Setup
173
+ ### Using formEngineSetup Wrapper
133
174
 
134
- `FormEngine` supports both direct props and a wrapper setup object. This is useful
135
- for block/component libraries that want to provide local default fields and styles.
175
+ For block/component libraries that provide default configurations:
136
176
 
137
177
  ```tsx
138
- import * as React from "react";
139
178
  import {
140
179
  FormEngine,
141
180
  type FormEngineSetup,
@@ -151,16 +190,16 @@ const defaultStyleRules: FormEngineStyleRules = {
151
190
  formClassName: "space-y-6",
152
191
  };
153
192
 
154
- const setup: FormEngineSetup = {
155
- api: { endpoint: "/api/contact", method: "post" },
156
- formLayoutSettings: { formLayout: "standard" },
157
- };
158
-
159
- <FormEngine
160
- formEngineSetup={setup}
161
- defaultFields={defaultFields}
162
- defaultStyleRules={defaultStyleRules}
163
- />;
193
+ // Consumer passes setup, component provides defaults
194
+ function ContactBlock({ formEngineSetup }: { formEngineSetup?: FormEngineSetup }) {
195
+ return (
196
+ <FormEngine
197
+ formEngineSetup={formEngineSetup}
198
+ defaultFields={defaultFields}
199
+ defaultStyleRules={defaultStyleRules}
200
+ />
201
+ );
202
+ }
164
203
  ```
165
204
 
166
205
  ## Package Entry Points
@@ -170,22 +209,22 @@ const setup: FormEngineSetup = {
170
209
 
171
210
  Exports:
172
211
  - `useForm`, `useField`, `Form`, `Field`, `FormContext`
173
- - core form/types interfaces
212
+ - Core form/types interfaces
213
+
214
+ ### Integration (Recommended)
215
+ - `@page-speed/forms/integration`
216
+
217
+ Exports:
218
+ - `FormEngine`, `FormEngineSetup`, `FormEngineProps`
219
+ - `FormFieldConfig`, `FormEngineStyleRules`, `FormEngineLayoutSettings`
220
+ - `DynamicFormField`, `useContactForm`, `useFileUpload`
174
221
 
175
222
  ### Inputs
176
223
  - `@page-speed/forms/inputs`
177
224
 
178
225
  Exports:
179
- - `TextInput`
180
- - `TextArea`
181
- - `Checkbox`
182
- - `CheckboxGroup`
183
- - `Radio`
184
- - `Select`
185
- - `MultiSelect`
186
- - `DatePicker`
187
- - `DateRangePicker`
188
- - `TimePicker`
226
+ - `TextInput`, `TextArea`, `Checkbox`, `CheckboxGroup`, `Radio`
227
+ - `Select`, `MultiSelect`, `DatePicker`, `DateRangePicker`, `TimePicker`
189
228
  - `FileInput`
190
229
 
191
230
  ### Validation
@@ -194,14 +233,13 @@ Exports:
194
233
  - `@page-speed/forms/validation/utils`
195
234
  - `@page-speed/forms/validation/valibot`
196
235
 
197
- ### Upload and Integration
236
+ ### Upload
198
237
  - `@page-speed/forms/upload`
199
- - `@page-speed/forms/integration`
200
238
 
201
239
  ## Input Notes
202
240
 
203
241
  ### `TimePicker`
204
- `TimePicker` now uses a native `input[type="time"]` UX internally.
242
+ `TimePicker` uses a native `input[type="time"]` UX internally.
205
243
 
206
244
  - Accepts controlled values in `HH:mm` (24-hour) or `h:mm AM/PM` (12-hour)
207
245
  - Emits `HH:mm` when `use24Hour` is `true`
@@ -222,8 +260,6 @@ Exports:
222
260
 
223
261
  This library ships with Tailwind utility classes and semantic token class names.
224
262
 
225
- It is **not** a BEM-only unstyled package anymore.
226
-
227
263
  ### Base conventions
228
264
 
229
265
  - Inputs/triggers are transparent shells with semantic borders/rings
@@ -231,6 +267,19 @@ It is **not** a BEM-only unstyled package anymore.
231
267
  - Error states use destructive border/ring
232
268
  - Dropdown selected rows use muted backgrounds
233
269
 
270
+ ### FormEngine Style Rules
271
+
272
+ ```tsx
273
+ interface FormEngineStyleRules {
274
+ formContainer?: string; // Wrapper around <form>
275
+ fieldsContainer?: string; // Grid wrapper for fields
276
+ fieldClassName?: string; // Fallback className for fields
277
+ formClassName?: string; // Applied to <form> element
278
+ successMessageClassName?: string;
279
+ errorMessageClassName?: string;
280
+ }
281
+ ```
282
+
234
283
  ### Autofill normalization
235
284
 
236
285
  Text-like controls apply autofill reset classes to avoid browser-injected background/text colors breaking your theme contrast.
@@ -249,6 +298,41 @@ Ensure your app defines semantic tokens used in classes such as:
249
298
 
250
299
  For complete styling guidance, see [`docs/STYLES.md`](./docs/STYLES.md).
251
300
 
301
+ ## Advanced: Low-Level APIs
302
+
303
+ For custom form implementations, the lower-level `useForm`, `Form`, and `Field` APIs are available:
304
+
305
+ ```tsx
306
+ import { Form, Field, useForm } from "@page-speed/forms";
307
+ import { TextInput } from "@page-speed/forms/inputs";
308
+
309
+ function CustomForm() {
310
+ const form = useForm({
311
+ initialValues: { email: "" },
312
+ validationSchema: {
313
+ email: (value) => (!value ? "Required" : undefined),
314
+ },
315
+ onSubmit: async (values) => {
316
+ console.log(values);
317
+ },
318
+ });
319
+
320
+ return (
321
+ <Form form={form}>
322
+ <Field name="email" label="Email">
323
+ {({ field, meta }) => (
324
+ <TextInput
325
+ {...field}
326
+ error={Boolean(meta.touched && meta.error)}
327
+ />
328
+ )}
329
+ </Field>
330
+ <button type="submit">Submit</button>
331
+ </Form>
332
+ );
333
+ }
334
+ ```
335
+
252
336
  ## Validation Utilities
253
337
 
254
338
  Use built-in rules:
@@ -264,7 +348,7 @@ Use utilities from `/validation/utils`:
264
348
 
265
349
  ## File Uploads
266
350
 
267
- `FileInput` supports validation, drag/drop, preview, and crop workflows.
351
+ `FileInput` and `FormEngine` support validation, drag/drop, preview, and crop workflows.
268
352
 
269
353
  For full two-phase upload patterns and serializer usage, see:
270
354
  - [`docs/FILE_UPLOADS.md`](./docs/FILE_UPLOADS.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@page-speed/forms",
3
- "version": "0.7.9",
3
+ "version": "0.8.0",
4
4
  "description": "Ultra-high-performance React form library with field-level reactivity and tree-shakable architecture",
5
5
  "keywords": [
6
6
  "react",