@dmitryvim/form-builder 0.5.4 → 0.7.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/README.md +13 -2
- package/dist/browser/formbuilder.min.js +145 -153
- package/dist/browser/formbuilder.v0.7.0.min.js +1482 -0
- package/dist/cjs/index.cjs +1416 -1296
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/index.js +1377 -1260
- package/dist/esm/index.js.map +1 -1
- package/dist/form-builder.js +145 -153
- package/dist/types/components/container.d.ts +0 -7
- package/dist/types/components/file/dom.d.ts +16 -4
- package/dist/types/components/file/render-edit.d.ts +6 -5
- package/dist/types/components/index.d.ts +1 -2
- package/dist/types/instance/FormBuilderInstance.d.ts +49 -8
- package/dist/types/instance/state.d.ts +8 -0
- package/dist/types/types/component-operations.d.ts +28 -2
- package/dist/types/types/config.d.ts +2 -0
- package/dist/types/types/state.d.ts +25 -0
- package/dist/types/utils/helpers.d.ts +18 -1
- package/dist/types/utils/styles.d.ts +75 -7
- package/dist/types/utils/validation.d.ts +14 -0
- package/package.json +1 -1
- package/dist/browser/formbuilder.v0.5.4.min.js +0 -1490
|
@@ -2,13 +2,6 @@ import type { ContainerElement, RenderContext, ComponentContext, ValidationResul
|
|
|
2
2
|
export declare function setRenderElement(fn: (element: any, ctx: RenderContext) => HTMLElement): void;
|
|
3
3
|
export declare function renderSingleContainerElement(element: ContainerElement, ctx: RenderContext, wrapper: HTMLElement, pathKey: string): void;
|
|
4
4
|
export declare function renderMultipleContainerElement(element: ContainerElement, ctx: RenderContext, wrapper: HTMLElement, pathKey: string): void;
|
|
5
|
-
export declare function setValidateElement(fn: (element: Element, ctx: {
|
|
6
|
-
path: string;
|
|
7
|
-
}, customScopeRoot?: HTMLElement | null) => {
|
|
8
|
-
value: any;
|
|
9
|
-
spread: boolean;
|
|
10
|
-
skip?: boolean;
|
|
11
|
-
}): void;
|
|
12
5
|
/**
|
|
13
6
|
* Validate container field and return extracted value with errors
|
|
14
7
|
*/
|
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
import type { State } from "../../types/state.js";
|
|
2
|
+
import type { ValidityScope } from "../../utils/styles.js";
|
|
2
3
|
/**
|
|
3
4
|
* Create a base square tile element. Sizing comes from CSS — `.fb-tile` and
|
|
4
5
|
* its descendants resolve aspect-ratio/dimensions via the theme variables.
|
|
5
6
|
*/
|
|
6
7
|
export declare function createFileTile(): HTMLElement;
|
|
7
8
|
/**
|
|
8
|
-
*
|
|
9
|
+
* Who raised a file field's message. "action": an upload or library pick;
|
|
10
|
+
* "limit": the render-owned over-limit notice; "validation": a validation
|
|
11
|
+
* pass.
|
|
9
12
|
*/
|
|
10
|
-
export
|
|
13
|
+
export type FileErrorKind = "action" | "limit" | "validation";
|
|
11
14
|
/**
|
|
12
|
-
*
|
|
15
|
+
* Show an inline error message below the nearest [data-files-wrapper]
|
|
16
|
+
* ancestor. Only an "action" message — the direct result of the user's
|
|
17
|
+
* upload or pick — is announced as an alert.
|
|
13
18
|
*/
|
|
14
|
-
export declare function
|
|
19
|
+
export declare function showFileError(container: HTMLElement, message: string, state: State, kind?: FileErrorKind): void;
|
|
20
|
+
/**
|
|
21
|
+
* Remove the inline file error message of `kind` below the nearest
|
|
22
|
+
* [data-files-wrapper] ancestor; a message of another kind stays.
|
|
23
|
+
*/
|
|
24
|
+
export declare function clearFileError(container: HTMLElement, kind?: FileErrorKind): void;
|
|
25
|
+
/** Validation's write into the slot, under the shared mark decision. */
|
|
26
|
+
export declare function markFileValidity(wrapper: HTMLElement, message: string | null, scope: ValidityScope): void;
|
|
15
27
|
/**
|
|
16
28
|
* Render (or replace) a delete-overlay with a centred "Delete" button on a tile.
|
|
17
29
|
* Used by the single-file edit-mode path.
|
|
@@ -6,7 +6,6 @@ export interface RenderPillsOptions {
|
|
|
6
6
|
state: State;
|
|
7
7
|
onRemove: ((rid: string) => void) | null;
|
|
8
8
|
hint?: string;
|
|
9
|
-
countInfo?: string;
|
|
10
9
|
maxCount?: number;
|
|
11
10
|
isReadonly?: boolean;
|
|
12
11
|
onLibraryPick?: (() => void) | null;
|
|
@@ -15,7 +14,9 @@ export interface RenderPillsOptions {
|
|
|
15
14
|
}
|
|
16
15
|
export declare function renderResourcePills(opts: RenderPillsOptions): void;
|
|
17
16
|
export declare function renderFileElementEdit(element: FileElement, ctx: RenderContext, wrapper: HTMLElement, pathKey: string): void;
|
|
18
|
-
/**
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Multi-file edit-mode renderer for both the legacy `files` element and the
|
|
19
|
+
* `file` type with `multiple: true` — they behave identically, `maxCount`
|
|
20
|
+
* included.
|
|
21
|
+
*/
|
|
22
|
+
export declare function renderMultiFileElementEdit(element: FileElement | FilesElement, ctx: RenderContext, wrapper: HTMLElement, pathKey: string): void;
|
|
@@ -7,10 +7,9 @@ import { renderSwitcherElement, renderMultipleSwitcherElement } from "./switcher
|
|
|
7
7
|
import { renderFileElement, renderFilesElement, renderMultipleFileElement } from "./file.js";
|
|
8
8
|
import { renderColourElement, renderMultipleColourElement } from "./colour.js";
|
|
9
9
|
import { renderSliderElement, renderMultipleSliderElement } from "./slider.js";
|
|
10
|
-
import { renderSingleContainerElement, renderMultipleContainerElement
|
|
10
|
+
import { renderSingleContainerElement, renderMultipleContainerElement } from "./container.js";
|
|
11
11
|
import { renderGroupElement } from "./group.js";
|
|
12
12
|
import { renderTableElement } from "./table.js";
|
|
13
13
|
import { renderRichInputElement } from "./richinput.js";
|
|
14
14
|
export declare function renderElement(element: Element, ctx: RenderContext): HTMLElement;
|
|
15
|
-
export { setContainerValidateElement };
|
|
16
15
|
export { renderTextElement, renderMultipleTextElement, renderTextareaElement, renderMultipleTextareaElement, renderNumberElement, renderMultipleNumberElement, renderSelectElement, renderMultipleSelectElement, renderSwitcherElement, renderMultipleSwitcherElement, renderFileElement, renderFilesElement, renderMultipleFileElement, renderColourElement, renderMultipleColourElement, renderSliderElement, renderMultipleSliderElement, renderSingleContainerElement, renderMultipleContainerElement, renderGroupElement, renderTableElement, renderRichInputElement, };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Schema, ExternalAction, FormData as FormDataResult, Config, State } from "../types/index.js";
|
|
1
|
+
import type { Schema, ExternalAction, FormData as FormDataResult, Config, Locale, State } from "../types/index.js";
|
|
2
2
|
/**
|
|
3
3
|
* FormBuilderInstance - Encapsulates all form state and operations
|
|
4
4
|
* Allows multiple independent forms on the same page without state collisions
|
|
@@ -6,6 +6,7 @@ import type { Schema, ExternalAction, FormData as FormDataResult, Config, State
|
|
|
6
6
|
export declare class FormBuilderInstance {
|
|
7
7
|
private state;
|
|
8
8
|
private instanceId;
|
|
9
|
+
private prefillHintHandler;
|
|
9
10
|
constructor(config?: Partial<Config>);
|
|
10
11
|
/**
|
|
11
12
|
* Get instance ID (useful for debugging and resource prefixing)
|
|
@@ -20,7 +21,9 @@ export declare class FormBuilderInstance {
|
|
|
20
21
|
*/
|
|
21
22
|
setFormRoot(element: HTMLElement): void;
|
|
22
23
|
/**
|
|
23
|
-
* Configure the form builder
|
|
24
|
+
* Configure the form builder. Translations deep-merge per locale (same as
|
|
25
|
+
* the constructor); a locale without translations — configured or default —
|
|
26
|
+
* is rejected, matching setLocale.
|
|
24
27
|
*/
|
|
25
28
|
configure(config: Partial<Config>): void;
|
|
26
29
|
/**
|
|
@@ -44,9 +47,10 @@ export declare class FormBuilderInstance {
|
|
|
44
47
|
*/
|
|
45
48
|
setMode(mode: "edit" | "readonly"): void;
|
|
46
49
|
/**
|
|
47
|
-
* Set locale
|
|
50
|
+
* Set locale. Custom locales are allowed — their translations must have
|
|
51
|
+
* been provided via the constructor or configure() first.
|
|
48
52
|
*/
|
|
49
|
-
setLocale(locale:
|
|
53
|
+
setLocale(locale: Locale): void;
|
|
50
54
|
/**
|
|
51
55
|
* Trigger onChange callbacks with debouncing
|
|
52
56
|
* @param fieldPath - Optional field path for field-specific change events
|
|
@@ -122,15 +126,43 @@ export declare class FormBuilderInstance {
|
|
|
122
126
|
*/
|
|
123
127
|
renderForm(root: HTMLElement, schema: Schema, prefill?: Record<string, any>, actions?: ExternalAction[]): void;
|
|
124
128
|
/**
|
|
125
|
-
* Validate form and extract data
|
|
126
|
-
*
|
|
127
|
-
*
|
|
129
|
+
* Validate the form and extract its data. `skipValidation` is the draft
|
|
130
|
+
* contract of saveDraft() and the onChange payload: marks are only
|
|
131
|
+
* refreshed or cleared, and the result reports `valid: true, errors: []`.
|
|
128
132
|
*/
|
|
129
133
|
validateForm(skipValidation?: boolean): FormDataResult;
|
|
130
134
|
/**
|
|
131
|
-
*
|
|
135
|
+
* Run every rule and return the real result. `marks` decides only what is
|
|
136
|
+
* painted: "full" raises and clears marks and records reported fields;
|
|
137
|
+
* "draft" refreshes or clears marks of reported fields and raises none
|
|
138
|
+
* (see ValidityScope in utils/styles.ts).
|
|
139
|
+
*/
|
|
140
|
+
private runValidation;
|
|
141
|
+
/**
|
|
142
|
+
* Read the form: every rule runs and the result is the real
|
|
143
|
+
* `{valid, errors, data}`. Safe to poll — it never paints a new error
|
|
144
|
+
* mark (so a pristine form never turns red), it only refreshes or clears
|
|
145
|
+
* marks that showErrors()/submitForm() drew, and a repeated call on
|
|
146
|
+
* unchanged state touches no DOM at all.
|
|
132
147
|
*/
|
|
133
148
|
getFormData(): FormDataResult;
|
|
149
|
+
/**
|
|
150
|
+
* Paint every validation error next to its field (and clear marks of
|
|
151
|
+
* fields that are now valid), then return the same result as
|
|
152
|
+
* getFormData(). Call it when the user asks to submit, followed by
|
|
153
|
+
* focusFirstError() to take them to the first problem.
|
|
154
|
+
*/
|
|
155
|
+
showErrors(): FormDataResult;
|
|
156
|
+
/**
|
|
157
|
+
* Focus the first field marked invalid, in DOM order, and scroll it into
|
|
158
|
+
* view. A marked group (container, multi-value field, file field) gets
|
|
159
|
+
* focus on its first focusable control, else on the group itself.
|
|
160
|
+
* Does not validate: marks are drawn by showErrors() (or submitForm()),
|
|
161
|
+
* so call showErrors() first. Fields hidden by enableIf are skipped, as is
|
|
162
|
+
* any field that cannot take focus (e.g. inside a hidden slide).
|
|
163
|
+
* @returns true only when focus actually landed on an invalid field
|
|
164
|
+
*/
|
|
165
|
+
focusFirstError(): boolean;
|
|
134
166
|
/**
|
|
135
167
|
* Submit form with validation
|
|
136
168
|
*/
|
|
@@ -139,6 +171,13 @@ export declare class FormBuilderInstance {
|
|
|
139
171
|
* Save draft without validation
|
|
140
172
|
*/
|
|
141
173
|
saveDraft(): FormDataResult;
|
|
174
|
+
/**
|
|
175
|
+
* Post form data to the parent frame — only when the host opted in via
|
|
176
|
+
* `postMessageTarget`. Outside an iframe `window.parent === window`, so an
|
|
177
|
+
* unconditional post broadcast form data and the full schema to any
|
|
178
|
+
* embedding page (targetOrigin "*") on every submit. See CHANGELOG 0.6.0.
|
|
179
|
+
*/
|
|
180
|
+
private postToParent;
|
|
142
181
|
/**
|
|
143
182
|
* Clear the form - reset all field values to empty while preserving form structure
|
|
144
183
|
* This is done by re-rendering the form with empty data
|
|
@@ -191,5 +230,7 @@ export declare class FormBuilderInstance {
|
|
|
191
230
|
*/
|
|
192
231
|
destroy(): void;
|
|
193
232
|
private disconnectEnableIfObservers;
|
|
233
|
+
private disconnectAutoExpandObservers;
|
|
234
|
+
private removePrefillHintListener;
|
|
194
235
|
private removeTooltipElements;
|
|
195
236
|
}
|
|
@@ -3,6 +3,14 @@ import type { State, Config } from "../types/index.js";
|
|
|
3
3
|
* Default configuration for new instances
|
|
4
4
|
*/
|
|
5
5
|
export declare const defaultConfig: Config;
|
|
6
|
+
/**
|
|
7
|
+
* Merge user-provided translations over a base map, per locale — the base
|
|
8
|
+
* packs survive, and each provided locale merges over the base's same-locale
|
|
9
|
+
* pack. Used by the constructor and configure(); a wholesale replacement
|
|
10
|
+
* (Object.assign) dropped the default en/ru packs and made t() return key
|
|
11
|
+
* names.
|
|
12
|
+
*/
|
|
13
|
+
export declare function mergeTranslations(base: Config["translations"], overrides: Partial<Config>["translations"]): Config["translations"];
|
|
6
14
|
/**
|
|
7
15
|
* Create a new isolated state object for a FormBuilderInstance
|
|
8
16
|
* Uses deep merge for translations to preserve default en/ru fallbacks
|
|
@@ -13,8 +13,34 @@ export interface ComponentContext {
|
|
|
13
13
|
instance: FormBuilderInstance;
|
|
14
14
|
/** Path prefix for nested fields */
|
|
15
15
|
path: string;
|
|
16
|
-
/**
|
|
17
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Draft marking (getFormData, debounced onChange, saveDraft): every rule
|
|
18
|
+
* runs, but only fields a full pass (showErrors, submitForm) reported may
|
|
19
|
+
* be marked. Affects painting only, never the returned errors. See
|
|
20
|
+
* ValidityScope in utils/styles.ts.
|
|
21
|
+
*/
|
|
22
|
+
draftMarks?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* The element being validated is readonly (itself, form-wide, or through a
|
|
25
|
+
* readonly ancestor container): its errors are reported, never marked.
|
|
26
|
+
*/
|
|
27
|
+
readonly?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Recursive element validator, threaded per validateForm pass by
|
|
30
|
+
* FormBuilderInstance. Containers use it to validate children with the
|
|
31
|
+
* instance's full context. Threaded through the context — never a module
|
|
32
|
+
* global — so per-instance state cannot leak between instances (the old
|
|
33
|
+
* setContainerValidateElement setter only worked because validateForm is
|
|
34
|
+
* synchronous and re-set it before every pass).
|
|
35
|
+
*/
|
|
36
|
+
validateElement?: (element: Element, ctx: {
|
|
37
|
+
path: string;
|
|
38
|
+
inheritedReadonly?: boolean;
|
|
39
|
+
}, customScopeRoot?: HTMLElement | null) => {
|
|
40
|
+
value: any;
|
|
41
|
+
spread: boolean;
|
|
42
|
+
skip?: boolean;
|
|
43
|
+
};
|
|
18
44
|
}
|
|
19
45
|
/**
|
|
20
46
|
* Validation result from a component validator
|
|
@@ -23,6 +23,7 @@ export interface Translations {
|
|
|
23
23
|
openInNewTab: string;
|
|
24
24
|
changeButton: string;
|
|
25
25
|
placeholderText: string;
|
|
26
|
+
selectPlaceholder?: string;
|
|
26
27
|
previewAlt: string;
|
|
27
28
|
previewUnavailable: string;
|
|
28
29
|
previewError: string;
|
|
@@ -110,6 +111,7 @@ export interface Config {
|
|
|
110
111
|
onDownloadError: ((error: Error, resourceId: string, fileName: string) => void) | null;
|
|
111
112
|
debounceMs: number;
|
|
112
113
|
verboseErrors: boolean;
|
|
114
|
+
postMessageTarget: string | null;
|
|
113
115
|
enableFilePreview: boolean;
|
|
114
116
|
maxPreviewSize: string;
|
|
115
117
|
readonly: boolean;
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import type { Schema, ExternalAction, Element } from "./schema.js";
|
|
2
2
|
import type { Config, ResourceMetadata } from "./config.js";
|
|
3
3
|
export interface State {
|
|
4
|
+
/** `inst-{timestamp}-{random}`; prefixes ids of nodes the instance creates. */
|
|
5
|
+
instanceId: string;
|
|
6
|
+
/** Sequence for instance-unique ids of nodes the instance creates. */
|
|
7
|
+
domIdCounter: number;
|
|
8
|
+
/**
|
|
9
|
+
* Marked elements a full validation pass reported invalid. Draft passes
|
|
10
|
+
* (debounced onChange, saveDraft) may only raise marks for these — see
|
|
11
|
+
* ValidityScope in utils/styles.ts.
|
|
12
|
+
*/
|
|
13
|
+
reportedInvalid: WeakSet<HTMLElement>;
|
|
4
14
|
schema: Schema | null;
|
|
5
15
|
formRoot: HTMLElement | null;
|
|
6
16
|
resourceIndex: Map<string, ResourceMetadata>;
|
|
@@ -13,6 +23,13 @@ export interface State {
|
|
|
13
23
|
syntheticElementIds: WeakMap<Element, string>;
|
|
14
24
|
/** Counter for generating unique synthetic IDs. */
|
|
15
25
|
syntheticElementIdCounter: number;
|
|
26
|
+
/**
|
|
27
|
+
* Replaces the file list of an edit-mode multi-file field, keyed by its
|
|
28
|
+
* [data-files-wrapper] element. setFormData/updateField must go through the
|
|
29
|
+
* field's own list — writing only the DOM attribute was reverted by the next
|
|
30
|
+
* add/remove, which re-serializes that list.
|
|
31
|
+
*/
|
|
32
|
+
multiFileSetters: WeakMap<HTMLElement, (resourceIds: string[]) => void>;
|
|
16
33
|
/**
|
|
17
34
|
* Pending MutationObservers from setupEnableIfListeners that are waiting for a
|
|
18
35
|
* dependency input to appear in the DOM. They must be disconnected on destroy()
|
|
@@ -23,6 +40,14 @@ export interface State {
|
|
|
23
40
|
* with a torn-down ctx. Reproducible under React StrictMode (double mount).
|
|
24
41
|
*/
|
|
25
42
|
enableIfObservers: Set<MutationObserver>;
|
|
43
|
+
/**
|
|
44
|
+
* ResizeObservers created by applyAutoExpand (text/textarea/richinput
|
|
45
|
+
* auto-height). Each observer's own callback disconnects it when its
|
|
46
|
+
* textarea has left the DOM — but that check only runs if the observer ever
|
|
47
|
+
* fires again, so a silently removed field held its observer forever.
|
|
48
|
+
* destroy() and every renderForm() disconnect the whole set.
|
|
49
|
+
*/
|
|
50
|
+
autoExpandObservers: Set<ResizeObserver>;
|
|
26
51
|
/**
|
|
27
52
|
* Info-button tooltip nodes created by this instance. They live on
|
|
28
53
|
* document.body (position: fixed, moved there so tile overflow can't clip
|
|
@@ -47,11 +47,16 @@ export declare function clear(node: HTMLElement): void;
|
|
|
47
47
|
export declare function formatFileSize(bytes: number): string;
|
|
48
48
|
/**
|
|
49
49
|
* Serialize a value for storage in a hidden input's value attribute.
|
|
50
|
-
*
|
|
50
|
+
* undefined → "", everything else — null included — → JSON.
|
|
51
51
|
*
|
|
52
52
|
* JSON for every type — including strings — so deserialization is exact.
|
|
53
53
|
* The previous String() form was lossy: a hidden text field prefilled with
|
|
54
54
|
* "true" or "123" came back from getFormData() as a boolean/number.
|
|
55
|
+
*
|
|
56
|
+
* null serializes as JSON "null" (not "") so that an explicit null survives
|
|
57
|
+
* the round-trip: "" used to be re-read as "unset", which let the hidden
|
|
58
|
+
* validator substitute element.default — updateField(key, null) on a field
|
|
59
|
+
* with a default could never actually produce null.
|
|
55
60
|
*/
|
|
56
61
|
export declare function serializeHiddenValue(value: any): string;
|
|
57
62
|
/**
|
|
@@ -62,6 +67,18 @@ export declare function serializeHiddenValue(value: any): string;
|
|
|
62
67
|
* (not through serializeHiddenValue) — hosts poking the input by hand.
|
|
63
68
|
*/
|
|
64
69
|
export declare function deserializeHiddenValue(raw: string): any;
|
|
70
|
+
/**
|
|
71
|
+
* Read an input's value the way typed extraction reports it — the DOM
|
|
72
|
+
* scrapers feeding enableIf (extractDOMValue, extractRootFormData) must
|
|
73
|
+
* agree with getFormData() for SCALAR fields, or a condition flips on the
|
|
74
|
+
* keystroke and is corrected only by the debounced pass (visible flicker):
|
|
75
|
+
* empty scalar -> null, number/range -> number (rounded per data-decimals),
|
|
76
|
+
* checkbox -> boolean, data-hidden-field -> JSON. Radio stays with the
|
|
77
|
+
* callers (needs a :checked query against a scope). Composite fields (file,
|
|
78
|
+
* table, richinput) extract arrays/objects that no single input carries —
|
|
79
|
+
* the parity guarantee does not extend to them.
|
|
80
|
+
*/
|
|
81
|
+
export declare function readTypedInputValue(input: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement): any;
|
|
65
82
|
/**
|
|
66
83
|
* Create a hidden input element for a hidden form field.
|
|
67
84
|
*/
|
|
@@ -1,13 +1,79 @@
|
|
|
1
1
|
import type { State } from "../types/index.js";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
3
|
+
* What a validation pass may change on screen. A full pass (showErrors,
|
|
4
|
+
* submitForm) raises and clears marks and records each field it reported
|
|
5
|
+
* invalid. A draft pass (`draftMarks`: getFormData, the debounced onChange,
|
|
6
|
+
* saveDraft) raises, refreshes or clears marks only for fields a full pass
|
|
7
|
+
* reported — polling or typing must not light up fields the user has not
|
|
8
|
+
* submitted — and still clears any mark whose field became valid. Every
|
|
9
|
+
* write below is skipped when the DOM already holds the value, so a
|
|
10
|
+
* repeated pass on unchanged state produces no mutation records (hosts
|
|
11
|
+
* poll getFormData() from MutationObservers). A readonly field
|
|
12
|
+
* (`readonly`) is never marked: the user could not fix it. A field that
|
|
13
|
+
* enableIf hides and shows again is re-rendered as a new element and so
|
|
14
|
+
* comes back unmarked until the next full pass — intended: it reappears
|
|
15
|
+
* clean.
|
|
16
|
+
* ComponentContext satisfies this shape.
|
|
17
|
+
*/
|
|
18
|
+
export interface ValidityScope {
|
|
19
|
+
state: State;
|
|
20
|
+
draftMarks?: boolean;
|
|
21
|
+
readonly?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The single mark decision shared by input, field and file marks: the
|
|
25
|
+
* message to draw, null to clear, or undefined to leave `target` as it is.
|
|
26
|
+
* Reported fields are tracked by their marked element rather than by path:
|
|
27
|
+
* chip rows renumber their names on removal, which would hand a path-keyed
|
|
28
|
+
* flag to a neighbouring row.
|
|
29
|
+
*/
|
|
30
|
+
export declare function resolveMark(target: HTMLElement, message: string | null, scope: ValidityScope): string | null | undefined;
|
|
31
|
+
/** Several rule messages of one field, shown as one line. */
|
|
32
|
+
export declare function joinErrorMessages(messages: string[]): string | null;
|
|
33
|
+
/**
|
|
34
|
+
* Error node shared by input, field and file marks. The id is
|
|
35
|
+
* instance-prefixed so aria-describedby cannot resolve into another form on
|
|
36
|
+
* the page, even one loaded from a second copy of the bundle. No live-region
|
|
37
|
+
* role: a validation message is reached through aria-describedby, and only
|
|
38
|
+
* the direct result of a user action is announced (see showFileError).
|
|
39
|
+
*/
|
|
40
|
+
export declare function createErrorNode(state: State, className: string): HTMLElement;
|
|
41
|
+
/** setAttribute, skipped when unchanged (a same-value write still notifies observers). */
|
|
42
|
+
export declare function setAttr(el: Element, name: string, value: string): void;
|
|
43
|
+
/** Point `target` at `node` through aria-describedby, once. */
|
|
44
|
+
export declare function linkDescription(target: HTMLElement, node: HTMLElement): void;
|
|
45
|
+
/** Flag `target` invalid and point it at `node` (null = invalid without text). */
|
|
46
|
+
export declare function setInvalidMark(target: HTMLElement, node: HTMLElement | null, state: State): void;
|
|
47
|
+
/**
|
|
48
|
+
* Drop the invalid state (aria-invalid and what exposeAsGroup added) but
|
|
49
|
+
* keep any description link — for a notice that is not a field state.
|
|
50
|
+
*/
|
|
51
|
+
export declare function unsetInvalidState(target: HTMLElement): void;
|
|
52
|
+
/** Undo setInvalidMark and remove `node`; attributes a host set stay. */
|
|
53
|
+
export declare function clearInvalidMark(target: HTMLElement, node: HTMLElement | null): void;
|
|
54
|
+
/**
|
|
55
|
+
* Mark an input's validity: toggle `invalid`/title/aria-invalid and create,
|
|
56
|
+
* update or remove the paired `.error-message` node. Shared by every scalar
|
|
57
|
+
* component's validator — this used to be six near-identical copies, each
|
|
58
|
+
* with its own `error-${Math.random()}` fallback id.
|
|
59
|
+
*/
|
|
60
|
+
export declare function markFieldValidity(input: HTMLElement | null, errorMessage: string | null, scope: ValidityScope): void;
|
|
61
|
+
/**
|
|
62
|
+
* Clear an input's mark entirely. Called from updateField paths so a
|
|
63
|
+
* programmatic update to a valid value clears any stale error surface left
|
|
64
|
+
* over from the previous validation pass — otherwise the field stays
|
|
65
|
+
* visibly "invalid" until the next validate cycle.
|
|
9
66
|
*/
|
|
10
67
|
export declare function clearFieldError(input: HTMLElement): void;
|
|
68
|
+
/**
|
|
69
|
+
* Field-level counterpart of markFieldValidity for rules that belong to the
|
|
70
|
+
* field as a whole — item counts of multi-value fields and containers, table
|
|
71
|
+
* and richinput rules. The mark sits on the element whose `data-field-path`
|
|
72
|
+
* is `fieldPath` — the `.fb-field-wrapper` — with its message as the
|
|
73
|
+
* wrapper's last child. A field hidden by enableIf (its wrapper, or the
|
|
74
|
+
* placeholder that replaced it) is not marked.
|
|
75
|
+
*/
|
|
76
|
+
export declare function markFieldGroupValidity(scopeRoot: HTMLElement, fieldPath: string, errorMessage: string | null, scope: ValidityScope): void;
|
|
11
77
|
/**
|
|
12
78
|
* Shared trash-can icon used by every per-item remove button (multi-text
|
|
13
79
|
* chips, multi-container items, etc.). Stays as one inline SVG so a single
|
|
@@ -23,6 +89,7 @@ export declare const BIN_ICON_SVG = "<svg width=\"14\" height=\"14\" viewBox=\"0
|
|
|
23
89
|
* - `[data-fb-slide-card]` — items inside `container.displayMode:"slides"`
|
|
24
90
|
* - `[data-fb-label-row]` — every standard field-label container
|
|
25
91
|
* - `.fb-prefill-hint` — schema-driven prefill suggestion pills
|
|
92
|
+
* - `[aria-invalid]` — controls marked invalid by validation
|
|
26
93
|
*
|
|
27
94
|
* Idempotent via a flag attribute on the document head.
|
|
28
95
|
*/
|
|
@@ -53,8 +120,9 @@ export declare function ensureThemingHooks(doc: Document): void;
|
|
|
53
120
|
* where width hasn't moved — otherwise our own height writes would feed back
|
|
54
121
|
* into the observer.
|
|
55
122
|
*/
|
|
56
|
-
export declare function applyAutoExpand(textarea: HTMLTextAreaElement, options
|
|
123
|
+
export declare function applyAutoExpand(textarea: HTMLTextAreaElement, options: {
|
|
57
124
|
minRows?: number;
|
|
125
|
+
observers: Set<ResizeObserver>;
|
|
58
126
|
}): void;
|
|
59
127
|
/**
|
|
60
128
|
* Enforce single-line semantics on a textarea: block the Enter key and
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
import type { ComponentContext, Element } from "../types/index.js";
|
|
1
2
|
import type { State } from "../types/state.js";
|
|
3
|
+
/**
|
|
4
|
+
* required / minCount / maxCount over a field's `count` items. The message
|
|
5
|
+
* keys differ per field family: files say "files", everything else "items".
|
|
6
|
+
*/
|
|
7
|
+
export declare function countRuleMessages(element: Element, count: number, state: State, keys?: {
|
|
8
|
+
min: string;
|
|
9
|
+
max: string;
|
|
10
|
+
}): string[];
|
|
11
|
+
/**
|
|
12
|
+
* Count rules of a multi-value field or container over its `filledCount`
|
|
13
|
+
* items: pushes "path: message" errors and marks the field with all of them.
|
|
14
|
+
*/
|
|
15
|
+
export declare function validateItemCount(element: Element, key: string, filledCount: number, context: ComponentContext, errors: string[]): void;
|
|
2
16
|
export declare function makeFieldHint(element: any, state: State): string;
|
|
3
17
|
export declare function validateSchema(schema: any): string[];
|