@samline/forms 1.0.3 → 2.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.
Files changed (49) hide show
  1. package/README.md +87 -199
  2. package/dist/browser/global.d.ts +152 -0
  3. package/dist/browser/global.global.js +778 -474
  4. package/dist/browser/global.global.js.map +1 -1
  5. package/dist/index.cjs +753 -470
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.d.cts +141 -3
  8. package/dist/index.d.ts +141 -3
  9. package/dist/index.js +960 -13
  10. package/dist/index.js.map +1 -1
  11. package/package.json +8 -43
  12. package/dist/chunk-4NEGCRY2.js +0 -125
  13. package/dist/chunk-4NEGCRY2.js.map +0 -1
  14. package/dist/chunk-PCKGH2WA.js +0 -11
  15. package/dist/chunk-PCKGH2WA.js.map +0 -1
  16. package/dist/chunk-WM2CL7IO.js +0 -576
  17. package/dist/chunk-WM2CL7IO.js.map +0 -1
  18. package/dist/core/index.cjs +0 -154
  19. package/dist/core/index.cjs.map +0 -1
  20. package/dist/core/index.d.cts +0 -11
  21. package/dist/core/index.d.ts +0 -11
  22. package/dist/core/index.js +0 -13
  23. package/dist/core/index.js.map +0 -1
  24. package/dist/react/index.cjs +0 -734
  25. package/dist/react/index.cjs.map +0 -1
  26. package/dist/react/index.d.cts +0 -10
  27. package/dist/react/index.d.ts +0 -10
  28. package/dist/react/index.js +0 -43
  29. package/dist/react/index.js.map +0 -1
  30. package/dist/svelte/index.cjs +0 -764
  31. package/dist/svelte/index.cjs.map +0 -1
  32. package/dist/svelte/index.d.cts +0 -20
  33. package/dist/svelte/index.d.ts +0 -20
  34. package/dist/svelte/index.js +0 -72
  35. package/dist/svelte/index.js.map +0 -1
  36. package/dist/types-jYB7Wp7C.d.cts +0 -95
  37. package/dist/types-jYB7Wp7C.d.ts +0 -95
  38. package/dist/vanilla/index.cjs +0 -705
  39. package/dist/vanilla/index.cjs.map +0 -1
  40. package/dist/vanilla/index.d.cts +0 -7
  41. package/dist/vanilla/index.d.ts +0 -7
  42. package/dist/vanilla/index.js +0 -12
  43. package/dist/vanilla/index.js.map +0 -1
  44. package/dist/vue/index.cjs +0 -741
  45. package/dist/vue/index.cjs.map +0 -1
  46. package/dist/vue/index.d.cts +0 -13
  47. package/dist/vue/index.d.ts +0 -13
  48. package/dist/vue/index.js +0 -56
  49. package/dist/vue/index.js.map +0 -1
package/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # Forms
2
2
 
3
- Form controller for native HTML forms, React, Vue, Svelte, and direct browser usage.
3
+ > A small, framework-free form controller for vanilla JS and direct browser usage.
4
+
5
+ > It binds to an `HTMLFormElement`, keeps field state in sync with the DOM, runs validation, lets you react to changes via watchers or subscribers, and ships a serialized payload for `fetch` flows.
6
+
7
+ ---
4
8
 
5
9
  ## Table of Contents
6
10
 
@@ -8,12 +12,13 @@ Form controller for native HTML forms, React, Vue, Svelte, and direct browser us
8
12
  - [CDN / Browser](#cdn--browser)
9
13
  - [Entrypoints](#entrypoints)
10
14
  - [Quick Start](#quick-start)
11
- - [What You Can Do](#what-you-can-do)
12
- - [API Reference](#api-reference)
13
- - [Examples](#examples)
15
+ - [What You Can Build](#what-you-can-build)
16
+ - [API at a Glance](#api-at-a-glance)
14
17
  - [Documentation](#documentation)
15
18
  - [License](#license)
16
19
 
20
+ ---
21
+
17
22
  ## Installation
18
23
 
19
24
  ```bash
@@ -24,49 +29,58 @@ npm install @samline/forms
24
29
  pnpm add @samline/forms
25
30
  ```
26
31
 
27
- ```bash
28
- yarn add @samline/forms
29
- ```
30
-
31
32
  ```bash
32
33
  bun add @samline/forms
33
34
  ```
34
35
 
36
+ Requires Node 20+ when bundling. Runtime target is ES2020.
37
+
38
+ ---
39
+
35
40
  ## CDN / Browser
36
41
 
37
- Use the browser build when you do not have a bundler and need to run the package directly in HTML.
42
+ Use the browser build when you do not have a bundler and need to run the package directly in HTML, Shopify, WordPress, or any traditional template.
38
43
 
39
44
  ```html
40
- <script src="https://unpkg.com/@samline/forms@1.0.3/dist/browser/global.global.js"></script>
45
+ <script src="https://unpkg.com/@samline/forms@2.0.0/dist/browser/global.global.js"></script>
41
46
  ```
42
47
 
43
- Pin the version in production.
48
+ > Pin the version in production. Replace `2.0.0` with the version you ship.
44
49
 
45
- The browser build exposes `window.forms`.
50
+ The browser bundle exposes a single global: `window.Forms`.
46
51
 
47
52
  ```html
48
53
  <form id="contact-form">
49
54
  <input name="email" type="email" />
55
+ <button type="submit">Send</button>
50
56
  </form>
51
57
 
52
- <script src="https://unpkg.com/@samline/forms@1.0.3/dist/browser/global.global.js"></script>
58
+ <script src="https://unpkg.com/@samline/forms@2.0.0/dist/browser/global.global.js"></script>
53
59
  <script>
54
- const contactForm = window.forms.form('contact-form')
60
+ const contactForm = window.Forms.newForm({ id: 'contact-form' })
61
+
62
+ contactForm.onSubmit(async (form, data, formData) => {
63
+ await fetch('/api/contact', { method: 'POST', body: formData })
64
+ })
65
+
55
66
  contactForm.validate()
56
67
  </script>
57
68
  ```
58
69
 
70
+ The browser surface keeps a small registry under `Forms.available`, keyed by the `id` you pass to `Forms.newForm`. Each successful `newForm` call stores the returned controller there, and `Forms.destroyForm(id)` calls `destroy()` and removes the entry. Use `Forms.form` directly when you need the factory without the registry side-effect.
71
+
72
+ See [docs/browser.md](docs/browser.md) for the full browser surface.
73
+
74
+ ---
75
+
59
76
  ## Entrypoints
60
77
 
61
- | Entrypoint | Use |
78
+ | Entrypoint | When to use |
62
79
  | --- | --- |
63
- | `@samline/forms` | Main vanilla API |
64
- | `@samline/forms/core` | Types, serialization, and validation |
65
- | `@samline/forms/vanilla` | Explicit DOM API entrypoint |
66
- | `@samline/forms/react` | React hook |
67
- | `@samline/forms/vue` | Vue composable |
68
- | `@samline/forms/svelte` | Svelte store and action |
69
- | `@samline/forms/browser` | Browser global bundle |
80
+ | `@samline/forms` | Main vanilla API for bundlers, ESM, or CJS consumers. |
81
+ | `@samline/forms/browser` | Pre-bundled IIFE that registers `window.Forms` for direct `<script>` usage. |
82
+
83
+ ---
70
84
 
71
85
  ## Quick Start
72
86
 
@@ -82,207 +96,81 @@ const contactForm = form('contact-form', {
82
96
  }
83
97
  })
84
98
 
85
- contactForm.onSubmit((element, data, formData, state) => {
86
- console.log(element, data, formData, state)
99
+ contactForm.watch('email', value => {
100
+ console.log('email is now:', value)
87
101
  })
88
- ```
89
-
90
- ## What You Can Do
91
-
92
- - bind to a form by id, element, or ref-like target
93
- - read and write field values
94
- - serialize form values to both a plain object and `FormData`
95
- - watch individual fields and subscribe to global form state
96
- - prefill values from the current URL query string
97
- - mark filled and error states through DOM attributes for styling
98
- - run built-in validation rules and custom validators
99
- - trigger submit handlers with optional auto-submit behavior
100
- - reset, inspect, and destroy the controller cleanly
101
-
102
- ## API Reference
103
-
104
- ### form(target, options)
105
-
106
- Creates a controller from:
107
-
108
- - a form id string
109
- - a real `HTMLFormElement`
110
- - a ref-like object with `current`
111
102
 
112
- ### Properties
113
-
114
- - `element`: the bound `HTMLFormElement | null`
115
- - `f`: alias of `element`
116
- - `options`: normalized controller options
117
-
118
- ### Submission
119
-
120
- - `onSubmit(callback, preventDefault?)`
121
- - `autoSubmit(options?)`
122
- - `disableAutoSubmit()`
123
-
124
- `onSubmit` accepts an optional second argument named `preventDefault`.
125
-
126
- - `onSubmit(callback)` is equivalent to `onSubmit(callback, true)`
127
- - with `true`, valid submissions are intercepted, which is the right choice for `fetch` or AJAX flows
128
- - with `false`, valid submissions continue with the browser's native form submit behavior
129
- - invalid submissions are still prevented, even when you pass `false`
130
-
131
- ### Field observation
132
-
133
- - `watch(field, callback)`
134
- - `observe(field, callback)`
135
- - `subscribe(listener)`
136
- - `unwatch(field?, callback?)`
137
-
138
- ### Field values
139
-
140
- - `setValue(name, value)`
141
- - `getValue(name)`
142
- - `getField(name)`
143
- - `prefill(fieldName?)`
144
-
145
- ### Validation and errors
146
-
147
- - `validate(fields?)`
148
- - `revalidate(fields?)`
149
- - `setErrors(fields)`
150
- - `clearErrors(fields?)`
151
-
152
- Manual errors created with `setErrors()` are cleared per field by default as soon as that field changes, including updates triggered through `setValue()`. Pass `clearManualErrorsOnChange: false` to keep manual errors until you clear them explicitly.
153
-
154
- ### Form lifecycle and state
155
-
156
- - `getData()`
157
- - `getState()`
158
- - `append(options)`
159
- - `reset()`
160
- - `destroy()`
161
-
162
- ### Validation options
163
-
164
- Built-in rules supported through `validators`:
165
-
166
- - `required`
167
- - `minLength`
168
- - `maxLength`
169
- - `pattern`
170
- - `validate` for custom callbacks
171
-
172
- Controller options also include:
173
-
174
- - `autoValidate` to validate on initialization and subsequent field changes
175
- - `clearErrorsOnSubmit` to reset manual errors before submit validation runs
176
- - `clearManualErrorsOnChange` to clear only the changed field's manual error before the normal validation flow continues
177
-
178
- ```ts
179
- const profileForm = form('profile-form', {
180
- clearManualErrorsOnChange: false
103
+ contactForm.onSubmit(async (_element, _data, formData) => {
104
+ await fetch('/api/contact', { method: 'POST', body: formData })
181
105
  })
182
106
  ```
183
107
 
184
- ## Examples
108
+ What this does:
185
109
 
186
- ### Bind by id
110
+ - Binds to the form with id `contact-form`.
111
+ - Adds `css-filled` / `css-error` attributes on fields so you can style them with CSS.
112
+ - Validates `email` on every change and on submit.
113
+ - Intercepts valid submits (the default for `onSubmit`) and hands a real `FormData` instance to your handler.
187
114
 
188
- ```ts
189
- import { form } from '@samline/forms'
190
-
191
- const profileForm = form('profile-form')
192
- ```
193
-
194
- ### Bind by element
195
-
196
- ```ts
197
- const element = document.querySelector('#profile-form') as HTMLFormElement
198
- const profileForm = form(element)
199
- ```
200
-
201
- ### Watch a field
202
-
203
- ```ts
204
- const profileForm = form('profile-form')
205
-
206
- profileForm.watch('email', value => {
207
- console.log('email changed:', value)
208
- })
209
- ```
210
-
211
- ### Validate with built-in rules
212
-
213
- ```ts
214
- const profileForm = form('profile-form', {
215
- validators: {
216
- email: {
217
- required: true,
218
- pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/
219
- },
220
- password: {
221
- minLength: 8
222
- }
223
- }
224
- })
115
+ ---
225
116
 
226
- const result = profileForm.validate()
227
- console.log(result.isValid, result.errors)
228
- ```
117
+ ## What You Can Build
229
118
 
230
- ### Submit with fetch
119
+ - Contact, newsletter, login, signup, checkout, and profile forms.
120
+ - Forms that submit with `fetch` while keeping native `FormData` payloads.
121
+ - Autosave / autosubmit flows with optional debounce.
122
+ - Visual feedback driven by `css-filled` and `css-error` attributes.
123
+ - Progressive enhancement on top of any existing HTML form.
124
+ - Forms rendered server-side (Blade, Twig, ERB) that still want client-side validation.
231
125
 
232
- ```ts
233
- const profileForm = form('profile-form')
126
+ ---
234
127
 
235
- profileForm.onSubmit(async (_element, _data, formData) => {
236
- await fetch('/api/profile', {
237
- method: 'POST',
238
- body: formData
239
- })
240
- })
241
- ```
128
+ ## API at a Glance
242
129
 
243
- This uses the default `preventDefault = true`, so the package intercepts the valid submit and lets you handle the request yourself.
130
+ The controller is built around one factory and a small set of focused methods. Most methods are chainable.
244
131
 
245
- ### Submit with native form behavior
132
+ | Group | Methods |
133
+ | --- | --- |
134
+ | Lifecycle | [`form`](docs/api/form.md) · [`destroy`](docs/api/destroy.md) · [`reset`](docs/api/reset.md) |
135
+ | Properties | [`element`](docs/api/element.md) · [`options`](docs/options.md) |
136
+ | Submission | [`onSubmit`](docs/api/on-submit.md) · [`autoSubmit`](docs/api/auto-submit.md) · [`disableAutoSubmit`](docs/api/disable-auto-submit.md) |
137
+ | Field observation | [`watch`](docs/api/watch.md) · [`observe`](docs/api/observe.md) · [`unwatch`](docs/api/unwatch.md) · [`subscribe`](docs/api/subscribe.md) |
138
+ | Field values | [`setValue`](docs/api/set-value.md) · [`getValue`](docs/api/get-value.md) · [`getField`](docs/api/get-field.md) · [`prefill`](docs/api/prefill.md) · [`format`](docs/api/format.md) · [`formatAll`](docs/api/format.md) |
139
+ | Validation | [`validate`](docs/api/validate.md) · [`revalidate`](docs/api/revalidate.md) · [`setErrors`](docs/api/set-errors.md) · [`clearErrors`](docs/api/clear-errors.md) |
140
+ | State and data | [`getData`](docs/api/get-data.md) · [`getState`](docs/api/get-state.md) · [`append`](docs/api/append.md) |
141
+ | Pure helpers | [`parseFormData`](docs/api/parse-form-data.md) · [`validateValues`](docs/api/validate-values.md) · [`validateFieldValue`](docs/api/validate-field-value.md) |
246
142
 
247
- ```ts
248
- const profileForm = form('profile-form')
143
+ See the full per-method reference in [`docs/api/`](docs/api/index.md).
249
144
 
250
- profileForm.onSubmit(() => {
251
- console.log('validation passed')
252
- }, false)
253
- ```
145
+ ---
254
146
 
255
- Use `false` when the form should continue with its normal HTML submission after validation succeeds, for example in server-rendered applications such as Laravel with Blade.
147
+ ## Optional peer: `@samline/formatter`
256
148
 
257
- If validation fails, the package still prevents the submit.
149
+ [`format`](docs/api/format.md) and [`formatAll`](docs/api/format.md) rely on the optional peer dependency [`@samline/formatter`](https://github.com/samline/formatter). Install it when you need input masks (phone, credit-card, date, time, numeral, general):
258
150
 
259
- ### Prefill from the URL
260
-
261
- ```ts
262
- const profileForm = form('profile-form')
263
- profileForm.prefill()
151
+ ```bash
152
+ npm install @samline/formatter
264
153
  ```
265
154
 
266
- ### Work with form state
267
-
268
- ```ts
269
- const profileForm = form('profile-form')
270
-
271
- const unsubscribe = profileForm.subscribe(state => {
272
- console.log(state.values)
273
- console.log(state.errors)
274
- })
155
+ If the peer is not installed, the methods log a single `console.error` explaining how to install it and return the controller unchanged — the rest of the form keeps working. See [docs/recipes.md → 13. Format inputs with `@samline/formatter`](docs/recipes.md#13-format-inputs-with-samlineformatter) for end-to-end examples.
275
156
 
276
- unsubscribe()
277
- ```
157
+ ---
278
158
 
279
159
  ## Documentation
280
160
 
281
- - [docs/vanilla.md](docs/vanilla.md)
282
- - [docs/react.md](docs/react.md)
283
- - [docs/vue.md](docs/vue.md)
284
- - [docs/svelte.md](docs/svelte.md)
285
- - [docs/browser.md](docs/browser.md)
161
+ Full API reference, guides, and examples are available at **[samline.github.io/forms](https://samline.github.io/forms)**.
162
+
163
+ | Doc | Purpose |
164
+ | --- | --- |
165
+ | [docs/getting-started.md](docs/getting-started.md) | Concepts, observable contract, lifecycle, and side-effect overview. |
166
+ | [docs/options.md](docs/options.md) | Full `FormControllerOptions` reference. |
167
+ | [docs/css-styling.md](docs/css-styling.md) | `css-filled` and `css-error` styling recipes. |
168
+ | [docs/typescript.md](docs/typescript.md) | Every exported TypeScript type, with examples. |
169
+ | [docs/api/index.md](docs/api/index.md) | One page per public method. |
170
+ | [docs/recipes.md](docs/recipes.md) | End-to-end patterns: fetch submit, server errors, autosave, multi-step, etc. |
171
+ | [docs/browser.md](docs/browser.md) | Browser global (`window.Forms`) usage. |
172
+
173
+ ---
286
174
 
287
175
  ## License
288
176
 
@@ -0,0 +1,152 @@
1
+ type FormatType = 'general' | 'phone' | 'numeral' | 'date' | 'time' | 'creditCard' | 'creditCardType';
2
+ interface FieldFormatConfig {
3
+ /** One of the supported `@samline/formatter` `FormatType` values. */
4
+ type: FormatType;
5
+ /** Name of the visible input(s) inside the bound form. */
6
+ field: string | string[];
7
+ /**
8
+ * Optional name for the hidden raw mirror. Defaults to
9
+ * `${fieldName}Raw`. The mirror is created on first `format()`
10
+ * call and reused on subsequent calls.
11
+ */
12
+ rawField?: string;
13
+ /**
14
+ * Format-specific options forwarded to `@samline/formatter`.
15
+ * Any key documented for the chosen `type` is accepted (e.g.
16
+ * `country`, `delimiter`, `numeralDecimalMark`, `datePattern`).
17
+ */
18
+ options?: Record<string, unknown>;
19
+ }
20
+ type FieldFormatConfigMap = Record<string, FieldFormatConfig>;
21
+ type FormDataPrimitive = FormDataEntryValue;
22
+ type SerializedFormValue = FormDataPrimitive | FormDataPrimitive[];
23
+ type FormFieldValue = string | string[] | File[] | undefined;
24
+ type FormValues = Record<string, FormFieldValue>;
25
+ type FormErrors = Record<string, string[]>;
26
+ type RuleConfig<T> = T | {
27
+ value: T;
28
+ message?: string;
29
+ };
30
+ interface FieldValidationContext {
31
+ field: string;
32
+ value: FormFieldValue;
33
+ values: FormValues;
34
+ }
35
+ type FieldValidator = (context: FieldValidationContext) => string | undefined | null | false | true;
36
+ interface FieldValidationRules {
37
+ required?: RuleConfig<boolean>;
38
+ minLength?: RuleConfig<number>;
39
+ maxLength?: RuleConfig<number>;
40
+ pattern?: RuleConfig<RegExp>;
41
+ validate?: FieldValidator | FieldValidator[];
42
+ }
43
+ type ValidationSchema = Record<string, FieldValidationRules>;
44
+ interface VisualAttributes {
45
+ filled: string;
46
+ error: string;
47
+ }
48
+ interface AutoSubmitOptions {
49
+ debounce?: number;
50
+ }
51
+ interface FormControllerOptions {
52
+ attributes?: Partial<VisualAttributes>;
53
+ autoValidate?: boolean;
54
+ autoSubmit?: boolean | AutoSubmitOptions;
55
+ clearManualErrorsOnChange?: boolean;
56
+ clearErrorsOnSubmit?: boolean;
57
+ validators?: ValidationSchema;
58
+ /**
59
+ * Declarative format configuration. Each entry is applied during
60
+ * `form()` initialization using the same logic as `controller.format(...)`.
61
+ * The key is just an identifier — the visible field name lives in
62
+ * `FieldFormatConfig.field`.
63
+ */
64
+ formats?: FieldFormatConfigMap;
65
+ }
66
+ interface SerializedFormResult {
67
+ data: Record<string, SerializedFormValue>;
68
+ formData: FormData;
69
+ }
70
+ interface ValidationResult {
71
+ isValid: boolean;
72
+ errors: FormErrors;
73
+ }
74
+ interface FormStateSnapshot {
75
+ values: FormValues;
76
+ errors: FormErrors;
77
+ filledFields: string[];
78
+ isValid: boolean;
79
+ isValidated: boolean;
80
+ autoSubmit: boolean;
81
+ submitCount: number;
82
+ }
83
+ type FormStateListener = (state: FormStateSnapshot) => void;
84
+ type FormFieldElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
85
+ type FormTarget = string | HTMLFormElement | {
86
+ current: HTMLFormElement | null;
87
+ } | null | undefined;
88
+ interface AppendContentOptions {
89
+ tag: keyof HTMLElementTagNameMap;
90
+ content: string;
91
+ class?: string;
92
+ atStart?: boolean;
93
+ }
94
+ type FormFieldWatcher = (value: FormFieldValue, field: FormFieldElement | FormFieldElement[] | null, form: HTMLFormElement, state: FormStateSnapshot) => void;
95
+ type FormSubmitHandler = (form: HTMLFormElement, data: Record<string, SerializedFormValue>, formData: FormData, state: FormStateSnapshot) => void;
96
+ interface FormController {
97
+ readonly element: HTMLFormElement | null;
98
+ readonly f: HTMLFormElement | null;
99
+ readonly options: FormControllerOptions;
100
+ onSubmit: (callback: FormSubmitHandler, preventDefault?: boolean) => FormController;
101
+ watch: (field: string, callback: FormFieldWatcher) => FormController;
102
+ observe: (field: string, callback: FormFieldWatcher) => () => void;
103
+ unwatch: (field?: string, callback?: FormFieldWatcher) => FormController;
104
+ subscribe: (listener: FormStateListener) => () => void;
105
+ prefill: (fieldName?: string) => FormController;
106
+ append: (options: AppendContentOptions) => HTMLElement | null;
107
+ setErrors: (fields: string[] | FormErrors) => FormController;
108
+ clearErrors: (fields?: string[]) => FormController;
109
+ setValue: (name: string, value: unknown) => FormController;
110
+ validate: (fields?: string[]) => ValidationResult;
111
+ revalidate: (fields?: string[]) => ValidationResult;
112
+ /**
113
+ * Apply the same `@samline/formatter` pipeline to a single field or
114
+ * to a list of fields sharing one configuration. Chainable.
115
+ *
116
+ * Requires the optional peer dependency `@samline/formatter`. When
117
+ * the peer is not installed the call logs a single `console.error`
118
+ * and returns the controller unchanged.
119
+ */
120
+ format: (config: FieldFormatConfig) => FormController;
121
+ formatAll: (config: FieldFormatConfig) => FormController;
122
+ reset: () => FormController;
123
+ autoSubmit: (options?: boolean | AutoSubmitOptions) => FormController;
124
+ disableAutoSubmit: () => FormController;
125
+ getValue: (name: string) => FormFieldValue;
126
+ getField: (name: string) => FormFieldElement | FormFieldElement[] | null;
127
+ getData: () => SerializedFormResult;
128
+ getState: () => FormStateSnapshot;
129
+ destroy: () => void;
130
+ }
131
+
132
+ interface NewFormInput {
133
+ id: string;
134
+ options?: FormControllerOptions;
135
+ }
136
+ interface FormsAvailable {
137
+ [id: string]: FormController;
138
+ }
139
+ interface FormsApi {
140
+ form: (target: FormTarget, options?: FormControllerOptions) => FormController;
141
+ newForm: (input: NewFormInput) => FormController | undefined;
142
+ destroyForm: (id: string) => void;
143
+ available: FormsAvailable;
144
+ }
145
+ declare const Forms: FormsApi;
146
+ declare global {
147
+ interface Window {
148
+ Forms: FormsApi;
149
+ }
150
+ }
151
+
152
+ export { type FormsApi, type FormsAvailable, type NewFormInput, Forms as default };