@samline/forms 2.8.0 → 2.10.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 +29 -1
- package/README.md +43 -31
- package/dist/browser/global.d.ts +49 -3
- package/dist/browser/global.global.js +20 -12
- package/dist/browser/global.global.js.map +1 -1
- package/dist/browser/index.cjs +253 -37
- package/dist/browser/index.cjs.map +1 -1
- package/dist/browser/index.d.cts +1 -1
- package/dist/browser/index.d.ts +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/{chunk-23VZAYA3.js → chunk-JAEFD56I.js} +254 -38
- package/dist/chunk-JAEFD56I.js.map +1 -0
- package/dist/index.cjs +253 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/{registry-GzopYPCR.d.cts → registry-CPe_lf8-.d.cts} +50 -4
- package/dist/{registry-GzopYPCR.d.ts → registry-CPe_lf8-.d.ts} +50 -4
- package/package.json +11 -8
- package/dist/chunk-23VZAYA3.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,32 @@ All notable changes to `@samline/forms` are documented in this file. The format
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [2.10.0] - 2026-11-12
|
|
8
|
+
|
|
9
|
+
No breaking API changes.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Support for `@samline/formatter` 3.0.0. The optional peer now accepts `^2.1.0 || ^3.0.0`. Formatter 3 makes phones opt-in, so forms loads `@samline/formatter/phone` and calls `registerPhone()` the first time a field is formatted with `type: 'phone'`. Forms without phone fields never load libphonenumber-js, and bundlers put the phone subpath in its own lazy chunk. If the subpath cannot be loaded, forms logs one `console.error` and leaves the field unformatted.
|
|
14
|
+
- The standalone script bundles formatter 3.0.0, with phone support included.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- A submit the user starts while a debounced auto-submit is pending cancels the pending one. Before, the form was submitted twice.
|
|
19
|
+
|
|
20
|
+
## [2.9.0] - 2026-11-12
|
|
21
|
+
|
|
22
|
+
No breaking API changes.
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- `setOptions(name, options, config?)` replaces the options of a `<select>` with strings, numbers, `{ value, label, disabled, selected }` objects or `{ label, options }` groups. Labels are written as text. The current value is kept when it is still listed (`keepValue: true` by default), and the change pipeline runs once, only when the selected value changes ([#13](https://github.com/samline/forms/issues/13)). New exported types: `SelectOption`, `SelectOptionGroup`, `SelectOptionInput` and `SetOptionsConfig`.
|
|
27
|
+
- `watch()` and `observe()` accept an array of field names. The callback receives `(values, changed, form, state)`: one value per listed field and the name of the field that changed (`null` on registration and after `reset()`). It fires once per change of any listed field. `unwatch(fields, callback?)` removes these watchers. New exported type: `FormFieldsWatcher` ([#10](https://github.com/samline/forms/issues/10)).
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- Adding or removing `<option>` elements outside the controller is no longer ignored. When it changes a select's value, the controller revalidates, updates `css-filled` / `css-error`, fires watchers and notifies subscribers.
|
|
32
|
+
|
|
7
33
|
## [2.8.0] - 2026-11-06
|
|
8
34
|
|
|
9
35
|
No breaking API changes. The behavior changes below fix incorrect or surprising results; review them if your code relied on the old behavior.
|
|
@@ -277,7 +303,9 @@ No breaking API changes. The behavior changes below fix incorrect or surprising
|
|
|
277
303
|
|
|
278
304
|
- Initial release of `@samline/forms`. Vanilla JS form controller with framework-specific variants (React, Vue, Svelte) initially included; bundled `.local/` agent docs at the repo root.
|
|
279
305
|
|
|
280
|
-
[Unreleased]: https://github.com/samline/forms/compare/v2.
|
|
306
|
+
[Unreleased]: https://github.com/samline/forms/compare/v2.10.0...HEAD
|
|
307
|
+
[2.10.0]: https://github.com/samline/forms/compare/v2.9.0...v2.10.0
|
|
308
|
+
[2.9.0]: https://github.com/samline/forms/compare/v2.8.0...v2.9.0
|
|
281
309
|
[2.8.0]: https://github.com/samline/forms/compare/v2.7.2...v2.8.0
|
|
282
310
|
[2.7.2]: https://github.com/samline/forms/compare/v2.7.1...v2.7.2
|
|
283
311
|
[2.7.1]: https://github.com/samline/forms/compare/v2.7.0...v2.7.1
|
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ pnpm add @samline/forms
|
|
|
30
30
|
bun add @samline/forms
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
Requires Node 20+ when bundling; the runtime targets ES2020 browsers. Formatting needs the optional peer `@samline/formatter` (`npm install @samline/formatter`); validation, state and serialization do not.
|
|
33
|
+
Requires Node 20+ when bundling; the runtime targets ES2020 browsers. Formatting needs the optional peer `@samline/formatter` (`npm install @samline/formatter`); validation, state and serialization do not. No runtime stylesheet is required; the application owns form styling.
|
|
34
34
|
|
|
35
35
|
## Quick start
|
|
36
36
|
|
|
@@ -78,7 +78,7 @@ Invalid submits are always prevented and focus moves to the first invalid field.
|
|
|
78
78
|
The standalone build defines `window.Forms` and already includes `@samline/formatter`. Pin the version.
|
|
79
79
|
|
|
80
80
|
```html
|
|
81
|
-
<script src="https://unpkg.com/@samline/forms@2.
|
|
81
|
+
<script src="https://unpkg.com/@samline/forms@2.10.0/dist/browser/global.global.js"></script>
|
|
82
82
|
<script>
|
|
83
83
|
const signup = window.Forms.form('signup', {
|
|
84
84
|
validators: { email: { required: true, pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/ } },
|
|
@@ -104,27 +104,35 @@ One controller owns one form's listeners, `MutationObserver` and auto-submit tim
|
|
|
104
104
|
|
|
105
105
|
## API at a glance
|
|
106
106
|
|
|
107
|
-
|
|
|
108
|
-
|
|
|
109
|
-
| `form(target, options?)`
|
|
110
|
-
| `createFormController(target, options?)`
|
|
111
|
-
| `browser`
|
|
112
|
-
| `parseFormData(form, submitter?)`
|
|
113
|
-
| `validateValues(values, schema)`
|
|
114
|
-
| `validateFieldValue(field, value, rules, values)` | Validate one value.
|
|
115
|
-
| `@samline/forms/browser`
|
|
116
|
-
| `@samline/forms/browser/global`
|
|
107
|
+
| API | Purpose |
|
|
108
|
+
| ------------------------------------------------- | ------------------------------------------------------------------ |
|
|
109
|
+
| `form(target, options?)` | Create a controller for an id, `HTMLFormElement` or `{ current }`. |
|
|
110
|
+
| `createFormController(target, options?)` | The same factory under its descriptive name. |
|
|
111
|
+
| `browser` | `{ form, newForm, destroyForm, available }` registry singleton. |
|
|
112
|
+
| `parseFormData(form, submitter?)` | Serialize a form into `{ data, formData }`. |
|
|
113
|
+
| `validateValues(values, schema)` | Validate a plain values object against a `ValidationSchema`. |
|
|
114
|
+
| `validateFieldValue(field, value, rules, values)` | Validate one value. |
|
|
115
|
+
| `@samline/forms/browser` | The registry as a module namespace; also sets `globalThis.Forms`. |
|
|
116
|
+
| `@samline/forms/browser/global` | The standalone IIFE that defines `window.Forms`. |
|
|
117
|
+
|
|
118
|
+
### Entrypoints
|
|
119
|
+
|
|
120
|
+
| Entrypoint | When to use |
|
|
121
|
+
| ------------------------------- | ---------------------------------------------------------------------------------------- |
|
|
122
|
+
| `@samline/forms` | Controller factory, pure validation/serialization helpers and types for ESM or CommonJS. |
|
|
123
|
+
| `@samline/forms/browser` | Module registry that also installs `globalThis.Forms`. |
|
|
124
|
+
| `@samline/forms/browser/global` | Standalone script with `window.Forms` and the bundled formatter. |
|
|
117
125
|
|
|
118
126
|
### Controller methods
|
|
119
127
|
|
|
120
|
-
| Group
|
|
121
|
-
|
|
|
122
|
-
| Submission
|
|
123
|
-
| Validation
|
|
124
|
-
| State
|
|
125
|
-
| Values
|
|
126
|
-
| Formatting
|
|
127
|
-
| Lifecycle
|
|
128
|
+
| Group | Methods |
|
|
129
|
+
| ---------- | ------------------------------------------------------------------------------- |
|
|
130
|
+
| Submission | `onSubmit`, `autoSubmit`, `disableAutoSubmit` |
|
|
131
|
+
| Validation | `validate`, `revalidate`, `setErrors`, `clearErrors` |
|
|
132
|
+
| State | `subscribe`, `observe`, `watch`, `unwatch`, `getState` |
|
|
133
|
+
| Values | `setValue`, `setOptions`, `getValue`, `getField`, `getData`, `prefill`, `reset` |
|
|
134
|
+
| Formatting | `format`, `formatAll` |
|
|
135
|
+
| Lifecycle | `element`, `f`, `options`, `append`, `addCleanup`, `destroy` |
|
|
128
136
|
|
|
129
137
|
### Options
|
|
130
138
|
|
|
@@ -132,19 +140,21 @@ One controller owns one form's listeners, `MutationObserver` and auto-submit tim
|
|
|
132
140
|
|
|
133
141
|
## Documentation
|
|
134
142
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
|
138
|
-
|
|
|
139
|
-
| [
|
|
140
|
-
| [
|
|
141
|
-
| [
|
|
142
|
-
| [
|
|
143
|
-
| [
|
|
143
|
+
Read the [documentation](https://samline.github.io/forms/docs/) for the full guides and API contracts, and explore [working examples](https://samline.github.io/forms/examples/) with complete and separate source files for both loading modes.
|
|
144
|
+
|
|
145
|
+
| Guide | What it covers |
|
|
146
|
+
| ----------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
|
|
147
|
+
| [Get started](https://samline.github.io/forms/docs/getting-started/) | Installation, the first form, CDN use and cleanup. |
|
|
148
|
+
| [Examples](https://samline.github.io/forms/docs/guides/examples/) | Twelve live forms with their code. |
|
|
149
|
+
| [Validation and errors](https://samline.github.io/forms/docs/guides/validation/) | Every rule, cross-field checks and accessible messages. |
|
|
150
|
+
| [State and submission](https://samline.github.io/forms/docs/guides/state-and-submission/) | Subscribers, async submits, auto-submit, prefill and reset. |
|
|
151
|
+
| [Formatting fields](https://samline.github.io/forms/docs/guides/formatting/) | The optional formatter and the hidden raw mirror. |
|
|
152
|
+
| [Framework integrations](https://samline.github.io/forms/docs/guides/frameworks/) | React, Vue, Svelte, Astro, Shopify and WordPress. |
|
|
153
|
+
| [API reference](https://samline.github.io/forms/docs/reference/api/) | Every method, grouped by task, with one page per method. |
|
|
144
154
|
|
|
145
155
|
## Changelog
|
|
146
156
|
|
|
147
|
-
Read [CHANGELOG.md](CHANGELOG.md) or the [published changelog](https://samline.github.io/forms/docs/changelog/) for release history and explicitly marked behavior changes.
|
|
157
|
+
Read [CHANGELOG.md](CHANGELOG.md) or the [published changelog](https://samline.github.io/forms/docs/changelog/) for release history and explicitly marked breaking and behavior changes. Review the notes before upgrading.
|
|
148
158
|
|
|
149
159
|
### Upgrading to 2.8
|
|
150
160
|
|
|
@@ -156,6 +166,8 @@ Read [CHANGELOG.md](CHANGELOG.md) or the [published changelog](https://samline.g
|
|
|
156
166
|
|
|
157
167
|
The [Forms skill](https://samline.github.io/forms/skills/forms/SKILL.md) describes 2.8 integration: loading modes, validation rules and accessible messages, state and submission, formatting and host ownership. Pass it to an agent or install it using a skills-compatible tool. Verify the installed package version before applying its guidance.
|
|
158
168
|
|
|
169
|
+
The maintained [repository source](skills/forms/SKILL.md) and website download are the same file.
|
|
170
|
+
|
|
159
171
|
Download [SKILL.md](https://samline.github.io/forms/skills/forms/SKILL.md) into a `forms/` folder in your agent's supported skill directory. For agents that discover project skills from `.agents/skills/`:
|
|
160
172
|
|
|
161
173
|
```sh
|
|
@@ -168,4 +180,4 @@ When working from this repository, copy `skills/forms/SKILL.md` instead. Keep th
|
|
|
168
180
|
|
|
169
181
|
## License
|
|
170
182
|
|
|
171
|
-
MIT — [LICENSE.md](LICENSE.md)
|
|
183
|
+
MIT — [LICENSE.md](LICENSE.md).
|
package/dist/browser/global.d.ts
CHANGED
|
@@ -106,7 +106,38 @@ interface AppendContentOptions {
|
|
|
106
106
|
class?: string;
|
|
107
107
|
atStart?: boolean;
|
|
108
108
|
}
|
|
109
|
+
/** One `<option>` written by `setOptions()`. */
|
|
110
|
+
interface SelectOption {
|
|
111
|
+
value: string | number;
|
|
112
|
+
/** Visible text. Defaults to `String(value)`. Written as text, never HTML. */
|
|
113
|
+
label?: string;
|
|
114
|
+
disabled?: boolean;
|
|
115
|
+
/** Selects the option and makes it the default restored by `reset()`. */
|
|
116
|
+
selected?: boolean;
|
|
117
|
+
}
|
|
118
|
+
/** One `<optgroup>` written by `setOptions()`. */
|
|
119
|
+
interface SelectOptionGroup {
|
|
120
|
+
label: string;
|
|
121
|
+
options: Array<string | number | SelectOption>;
|
|
122
|
+
disabled?: boolean;
|
|
123
|
+
}
|
|
124
|
+
/** A plain string or number is shorthand for `{ value, label: String(value) }`. */
|
|
125
|
+
type SelectOptionInput = string | number | SelectOption | SelectOptionGroup;
|
|
126
|
+
interface SetOptionsConfig {
|
|
127
|
+
/**
|
|
128
|
+
* Keep the current selection when its value is still in the new list.
|
|
129
|
+
* Ignored for a select when any new option has `selected: true`.
|
|
130
|
+
* Defaults to `true`.
|
|
131
|
+
*/
|
|
132
|
+
keepValue?: boolean;
|
|
133
|
+
}
|
|
109
134
|
type FormFieldWatcher = (value: FormFieldValue, field: FormFieldElement | FormFieldElement[] | null, form: HTMLFormElement, state: FormStateSnapshot) => void;
|
|
135
|
+
/**
|
|
136
|
+
* Callback for `watch()` / `observe()` with a list of fields. `values` has
|
|
137
|
+
* one entry per watched field. `changed` is the field that triggered the
|
|
138
|
+
* call, or `null` on registration and after `reset()`.
|
|
139
|
+
*/
|
|
140
|
+
type FormFieldsWatcher = (values: FormValues, changed: string | null, form: HTMLFormElement, state: FormStateSnapshot) => void;
|
|
110
141
|
type FormSubmitHandler = (form: HTMLFormElement, data: Record<string, SerializedFormValue>, formData: FormData, state: FormStateSnapshot) => void | Promise<void>;
|
|
111
142
|
type FormCleanup = () => void;
|
|
112
143
|
interface FormController {
|
|
@@ -115,15 +146,30 @@ interface FormController {
|
|
|
115
146
|
readonly options: FormControllerOptions;
|
|
116
147
|
onSubmit: (callback: FormSubmitHandler, preventDefault?: boolean) => FormController;
|
|
117
148
|
addCleanup: (cleanup: FormCleanup) => () => void;
|
|
118
|
-
watch:
|
|
119
|
-
|
|
120
|
-
|
|
149
|
+
watch: {
|
|
150
|
+
(field: string, callback: FormFieldWatcher): FormController;
|
|
151
|
+
(fields: string[], callback: FormFieldsWatcher): FormController;
|
|
152
|
+
};
|
|
153
|
+
observe: {
|
|
154
|
+
(field: string, callback: FormFieldWatcher): () => void;
|
|
155
|
+
(fields: string[], callback: FormFieldsWatcher): () => void;
|
|
156
|
+
};
|
|
157
|
+
unwatch: {
|
|
158
|
+
(field?: string, callback?: FormFieldWatcher): FormController;
|
|
159
|
+
(fields: string[], callback?: FormFieldsWatcher): FormController;
|
|
160
|
+
};
|
|
121
161
|
subscribe: (listener: FormStateListener) => () => void;
|
|
122
162
|
prefill: (fieldName?: string) => FormController;
|
|
123
163
|
append: (options: AppendContentOptions) => HTMLElement | null;
|
|
124
164
|
setErrors: (fields: string[] | FormErrors) => FormController;
|
|
125
165
|
clearErrors: (fields?: string[]) => FormController;
|
|
126
166
|
setValue: (name: string, value: unknown) => FormController;
|
|
167
|
+
/**
|
|
168
|
+
* Replace the `<option>` / `<optgroup>` children of every `<select>`
|
|
169
|
+
* named `name`. Fires the normal change pipeline only when the
|
|
170
|
+
* selected value changes. Chainable.
|
|
171
|
+
*/
|
|
172
|
+
setOptions: (name: string, options: SelectOptionInput[], config?: SetOptionsConfig) => FormController;
|
|
127
173
|
validate: (fields?: string[]) => ValidationResult;
|
|
128
174
|
revalidate: (fields?: string[]) => ValidationResult;
|
|
129
175
|
/**
|