@dmitryvim/form-builder 0.2.34 → 0.3.1

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.
@@ -0,0 +1,4 @@
1
+ import type { BooleanElement, RenderContext, ComponentContext, ValidationResult, Element } from "../types/index.js";
2
+ export declare function renderBooleanElement(element: BooleanElement, ctx: RenderContext, wrapper: HTMLElement, pathKey: string): void;
3
+ export declare function validateBooleanElement(element: Element, key: string, context: ComponentContext): ValidationResult;
4
+ export declare function updateBooleanField(_element: Element, fieldPath: string, value: any, context: ComponentContext): void;
@@ -1,27 +1,51 @@
1
1
  import type { FormBuilderInstance } from "../../instance/FormBuilderInstance.js";
2
2
  import type { State } from "../../types/state.js";
3
3
  import type { FileElement, FilesElement } from "../../types/index.js";
4
+ import type { BatchCoordinator } from "./upload.js";
5
+ export interface HandleLibraryPickMultiOptions {
6
+ state: State;
7
+ element: FileElement | FilesElement;
8
+ /** The `[data-files-wrapper]` element — used as the error-message target. */
9
+ wrapper: HTMLElement;
10
+ /** Bracket-notation field path (e.g. "slides[2].image"). */
11
+ fieldPath: string;
12
+ /** The mutable live array of current resource IDs (mutated in-place). */
13
+ resourceIds: string[];
14
+ /** Maximum files allowed (Infinity = no limit). */
15
+ maxCount: number;
16
+ /** Re-render callback (same role as in setupFilesPickerHandler). */
17
+ updateCallback: () => void;
18
+ instance: FormBuilderInstance;
19
+ /**
20
+ * Coordinator shared with the upload handlers. Used to read the true
21
+ * occupied count (committed + in-flight), commit picked rids instantly,
22
+ * and detect whether peer batches are still uploading so we can avoid a
23
+ * full rebuild that would wipe their in-flight tiles.
24
+ */
25
+ coordinator: BatchCoordinator;
26
+ /** The grid container (`.files-list`) where picked tiles are appended when peer batches are in flight. */
27
+ list: HTMLElement;
28
+ /** Builds the per-rid preview tile (same callback used by uploadBatch's in-place swap). */
29
+ buildSuccessTile: (rid: string) => HTMLElement;
30
+ }
4
31
  /**
5
32
  * Handle a library pick action for a MULTI-file field.
6
33
  *
7
- * End-to-end handler (mirrors upload.ts pattern):
8
- * 1. Calls pickExistingFiles with context
9
- * 2. Validates, deduplicates, enforces slot limit
10
- * 3. Registers in resourceIndex, mutates resourceIds array
11
- * 4. Updates data-resource-ids attribute
12
- * 5. Calls updateCallback() to re-render tiles
13
- * 6. Fires triggerOnChange
34
+ * Goes through the same coordinator queue as uploadBatch — `beginBatch`
35
+ * claims an ordinal at the moment of click, `setResults` stages the picked
36
+ * rids at that ordinal, and `end` releases the reservation. Library tiles
37
+ * are appended to the DOM right away so the user sees them, but their rids
38
+ * only land in resourceIds once every earlier-started batch has also
39
+ * committed. This is what keeps the final form data in user-selection order
40
+ * when a library pick is interleaved with an in-flight upload batch — the
41
+ * upload's ordinal drains first regardless of which one settled later.
14
42
  *
15
- * @param state Form builder state
16
- * @param element File / FilesElement schema definition
17
- * @param wrapper The [data-files-wrapper] element
18
- * @param fieldPath Bracket-notation field path (e.g. "slides[2].image")
19
- * @param resourceIds The mutable live array of current resource IDs (mutated in-place)
20
- * @param maxCount Maximum files allowed (Infinity = no limit)
21
- * @param updateCallback Re-render callback (same pattern as upload.ts)
22
- * @param instance FormBuilderInstance (for onChange events)
43
+ * `getOccupiedCount` (committed + in-flight) gates both the pre-picker
44
+ * `remainingSlots` and the post-picker `freshRemaining` so a host UI can't
45
+ * accept more files than maxCount even with a concurrent upload reserving
46
+ * slots invisibly.
23
47
  */
24
- export declare function handleLibraryPickMulti(state: State, element: FileElement | FilesElement, wrapper: HTMLElement, fieldPath: string, resourceIds: string[], maxCount: number, updateCallback: () => void, instance: FormBuilderInstance): Promise<void>;
48
+ export declare function handleLibraryPickMulti(opts: HandleLibraryPickMultiOptions): Promise<void>;
25
49
  /**
26
50
  * Handle a library pick action for a SINGLE-file field.
27
51
  *
@@ -31,5 +31,114 @@ export interface UploadBatchFailure {
31
31
  file: File;
32
32
  error: Error;
33
33
  }
34
- export declare function setupFilesDropHandler(filesContainer: HTMLElement, resourceIds: string[], state: State, updateCallback: () => void, constraints: FileUploadConstraints, pathKey?: string, instance?: FormBuilderInstance | null): void;
35
- export declare function setupFilesPickerHandler(filesPicker: HTMLInputElement, resourceIds: string[], state: State, updateCallback: () => void, constraints: FileUploadConstraints, pathKey?: string, instance?: FormBuilderInstance | null): void;
34
+ export interface UploadBatchOptions {
35
+ /** Files that have already passed extension / mime / size / count filtering. */
36
+ accepted: File[];
37
+ /** Container that hosts the tile grid (`.files-list`); receives uploading tiles. */
38
+ listEl: HTMLElement | null;
39
+ state: State;
40
+ /**
41
+ * Whether to hide the add-tile while this batch is in flight. Computed by
42
+ * the caller from `coordinator.getOccupiedCount() >= maxCount` *after*
43
+ * reserving slots, so concurrent batches that together saturate maxCount
44
+ * still hide the trigger.
45
+ */
46
+ shouldHideAddTile: boolean;
47
+ /**
48
+ * Builds the real preview tile to swap in-place when each upload resolves.
49
+ * When omitted, the placeholder is simply removed and the file only becomes
50
+ * visible after the caller re-renders the grid — used by paths that don't
51
+ * own a per-rid render strategy.
52
+ */
53
+ buildSuccessTile?: (rid: string) => HTMLElement;
54
+ /**
55
+ * Runs once after add-tile visibility is settled but before any upload
56
+ * promise starts. Hook for the caller to dispose of empty placeholders and
57
+ * the placeholder ResizeObserver — they would otherwise compete with the
58
+ * uploading tiles and the observer would immediately re-add removed slots.
59
+ */
60
+ prepareForUpload?: () => void;
61
+ }
62
+ export interface UploadBatchResult {
63
+ failures: UploadBatchFailure[];
64
+ /**
65
+ * One slot per `accepted[i]`, filled with the uploaded resource id when its
66
+ * upload succeeded and `null` when it failed. Callers commit these into
67
+ * `resourceIds` themselves so they can filter out IDs the user removed
68
+ * mid-batch (see `BatchCoordinator.wasRemovedDuringBatch`).
69
+ */
70
+ orderedIds: (string | null)[];
71
+ }
72
+ /**
73
+ * Owns the cross-batch invariants the handlers can't enforce on their own:
74
+ * tracking how many slots are reserved by in-flight uploads, preserving
75
+ * user-selection order across concurrent batches that settle out-of-start
76
+ * order, filtering out resources the user removed before a batch settles,
77
+ * and gating the final grid rebuild until the last concurrent batch finishes.
78
+ *
79
+ * Both the drop and picker handlers share a single coordinator instance per
80
+ * field so that batches started while another batch is still pending can't
81
+ * bypass maxCount, scramble the form-data order, or have their tiles wiped
82
+ * by a peer's rebuild.
83
+ */
84
+ export interface BatchCoordinator {
85
+ /** Settled resource count plus in-flight reservations. */
86
+ getOccupiedCount: () => number;
87
+ /**
88
+ * Snapshot of every rid currently in the system: committed in resourceIds
89
+ * plus rids staged behind an earlier ordinal awaiting drain. Used by the
90
+ * library picker to dedupe against — committed-only would let a staged rid
91
+ * be re-picked and committed twice.
92
+ */
93
+ getAllKnownRids: () => string[];
94
+ /** True if any batches are currently in flight (used to gate full rebuilds). */
95
+ hasInFlightBatches: () => boolean;
96
+ /** True if `rid` was removed during the current in-flight period. */
97
+ wasRemovedDuringBatch: (rid: string) => boolean;
98
+ /**
99
+ * Reserve N slots and begin a new batch. The returned handle is the only
100
+ * way to stage results and release the reservation — staging through a
101
+ * handle keyed by batch ordinal is what guarantees start-order commits
102
+ * even when batches settle out of order. Both the upload path and the
103
+ * library picker go through this so they share the same ordering queue.
104
+ */
105
+ beginBatch: (count: number) => BatchHandle;
106
+ }
107
+ /**
108
+ * Per-batch handle. `setResults` stages the batch's `orderedIds` keyed by its
109
+ * start ordinal; the coordinator then commits the contiguous prefix of
110
+ * already-settled batches into the field's resourceIds. `end` releases the
111
+ * reservation and reports whether no other batches remain in flight.
112
+ */
113
+ export interface BatchHandle {
114
+ setResults: (orderedIds: (string | null)[]) => void;
115
+ end: () => {
116
+ wasLast: boolean;
117
+ };
118
+ }
119
+ /**
120
+ * Shared inputs for both drop and picker handlers — the only difference is
121
+ * which DOM event source feeds files into the batch upload.
122
+ */
123
+ export interface MultiFileHandlerOptions {
124
+ resourceIds: string[];
125
+ state: State;
126
+ /** Re-renders the grid after the *last* batch settles (counter, placeholders, etc.). */
127
+ updateCallback: () => void;
128
+ constraints: FileUploadConstraints;
129
+ pathKey?: string;
130
+ instance?: FormBuilderInstance | null;
131
+ /** Forwarded into uploadBatch — builds the per-rid preview tile. */
132
+ buildSuccessTile?: (rid: string) => HTMLElement;
133
+ /** Forwarded into uploadBatch — runs once before any upload starts. */
134
+ prepareForUpload?: () => void;
135
+ coordinator: BatchCoordinator;
136
+ }
137
+ export interface SetupFilesDropHandlerOptions extends MultiFileHandlerOptions {
138
+ filesContainer: HTMLElement;
139
+ }
140
+ export declare function setupFilesDropHandler(opts: SetupFilesDropHandlerOptions): void;
141
+ export interface SetupFilesPickerHandlerOptions extends MultiFileHandlerOptions {
142
+ filesPicker: HTMLInputElement;
143
+ }
144
+ export declare function setupFilesPickerHandler(opts: SetupFilesPickerHandlerOptions): void;
@@ -1,6 +1,17 @@
1
1
  import type { TextElement, RenderContext, ComponentContext, ValidationResult } from "../types/index.js";
2
- export declare function createCharCounter(element: TextElement, input: HTMLInputElement | HTMLTextAreaElement, isTextarea?: boolean): HTMLElement;
2
+ export declare function createCharCounter(element: TextElement, input: HTMLInputElement | HTMLTextAreaElement): HTMLElement;
3
3
  export declare function renderTextElement(element: TextElement, ctx: RenderContext, wrapper: HTMLElement, pathKey: string): void;
4
+ /**
5
+ * `text.multiple` is always rendered as a vertical list of chip rows:
6
+ * [● input 🗑]
7
+ * Each chip = colored dot marker + single-line input + trash button that
8
+ * fades in on hover. Tint and dot color are pure CSS via --fb-chip-* vars;
9
+ * per-field overrides go through `[data-field-key="..."]` (see theming.md).
10
+ *
11
+ * Why no character-counter / no soft-wrap textarea like single-text:
12
+ * - chip rows are deliberately one-line; long values are unusual here.
13
+ * - min/max length still validate at field level via `validateTextElement`.
14
+ */
4
15
  export declare function renderMultipleTextElement(element: TextElement, ctx: RenderContext, wrapper: HTMLElement, pathKey: string): void;
5
16
  /**
6
17
  * Validate text input field and return extracted value with errors
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { FormBuilderInstance } from "./instance/FormBuilderInstance.js";
7
7
  import { validateSchema } from "./utils/validation.js";
8
- export type { SelectOption, ElementAction, BaseElement, TextElement, TextareaElement, NumberElement, SelectElement, FileElement, FilesElement, ContainerElement, GroupElement, MarkdownElement, RichInputElement, Element, Schema, ExternalAction, FormData, RenderContext, Translations, Locale, Config, ResourceMetadata, PickedResource, State, } from "./types/index.js";
8
+ export type { SelectOption, ElementAction, BaseElement, TextElement, TextareaElement, NumberElement, SelectElement, BooleanElement, FileElement, FilesElement, ContainerElement, GroupElement, MarkdownElement, RichInputElement, Element, Schema, ExternalAction, FormData, RenderContext, Translations, Locale, Config, ResourceMetadata, PickedResource, State, } from "./types/index.js";
9
9
  export type { Theme } from "./styles/theme.js";
10
10
  export { defaultTheme, exampleThemes } from "./styles/theme.js";
11
11
  /**
@@ -60,7 +60,20 @@ export declare class FormBuilderInstance {
60
60
  */
61
61
  registerAction(action: ExternalAction): void;
62
62
  /**
63
- * Find the DOM element corresponding to a field path (instance-scoped)
63
+ * Find the DOM element corresponding to a field path (instance-scoped).
64
+ *
65
+ * Strategy:
66
+ * 1. Try a `[name="…"]` lookup first — works for any field that renders
67
+ * an input/hidden with the path as its name, in either mode. Some
68
+ * readonly renderers still emit a hidden input (boolean, switcher),
69
+ * so this path must run regardless of `state.config.readonly`. A
70
+ * prior version gated this on edit mode only, which made
71
+ * `updateField` / `setFormData` silently miss readonly boolean
72
+ * fields whose component also opts out of the standard label row
73
+ * (`ownsLabel: true`).
74
+ * 2. If no input matched, fall back to locating the field wrapper by
75
+ * its visible label text — needed for readonly previews that don't
76
+ * emit any `name=` attribute (e.g. file/markdown previews).
64
77
  */
65
78
  private findFormElementByFieldPath;
66
79
  /**
@@ -1,17 +1,41 @@
1
1
  export interface Theme {
2
2
  primaryColor: string;
3
3
  primaryHoverColor: string;
4
+ /** Light tint of primary — used for chip backgrounds, hover surfaces, focused-state backgrounds. */
5
+ primarySoftColor: string;
6
+ /** Slightly stronger tint of primary — used for chip borders and hovered soft surfaces. */
7
+ primarySoftHoverColor: string;
4
8
  errorColor: string;
5
9
  errorHoverColor: string;
6
10
  successColor: string;
11
+ /** Secondary accent color (e.g. amber) used for highlights distinct from primary. */
12
+ accentColor: string;
13
+ /** Soft tint of accent for chip/badge backgrounds. */
14
+ accentSoftColor: string;
15
+ /** Border color paired with accentSoftColor. */
16
+ accentBorderColor: string;
17
+ /** Text color used on accent-tinted surfaces. */
18
+ accentTextColor: string;
7
19
  borderColor: string;
8
20
  borderHoverColor: string;
9
21
  borderFocusColor: string;
22
+ /** Stronger border for inputs/dropzones that need more contrast. */
23
+ borderStrongColor: string;
10
24
  backgroundColor: string;
11
25
  backgroundHoverColor: string;
12
26
  backgroundReadonlyColor: string;
27
+ /** Page-level background (the surface the form card sits on). */
28
+ pageBackgroundColor: string;
29
+ /** Soft tinted surface (mix of primary and white) for inset blocks. */
30
+ surfaceSoftColor: string;
31
+ /** Subtle tinted surface for very-light backgrounds. */
32
+ surfaceTintColor: string;
13
33
  textColor: string;
14
34
  textSecondaryColor: string;
35
+ /** Lighter text tone (between secondary and disabled). */
36
+ textMutedColor: string;
37
+ /** Faintest text tone, used for small uppercase group labels. */
38
+ textFaintColor: string;
15
39
  textPlaceholderColor: string;
16
40
  textDisabledColor: string;
17
41
  buttonBgColor: string;
@@ -31,6 +55,12 @@ export interface Theme {
31
55
  inputPaddingX: string;
32
56
  inputPaddingY: string;
33
57
  borderRadius: string;
58
+ /** Smaller corner radius (e.g. for chips and compact controls). */
59
+ borderRadiusSmall: string;
60
+ /** Larger corner radius for cards and dropzones. */
61
+ borderRadiusLarge: string;
62
+ /** Extra-large corner radius for section cards. */
63
+ borderRadiusXLarge: string;
34
64
  borderWidth: string;
35
65
  fontSize: string;
36
66
  fontSizeSmall: string;
@@ -38,10 +68,26 @@ export interface Theme {
38
68
  fontFamily: string;
39
69
  fontWeightNormal: string;
40
70
  fontWeightMedium: string;
71
+ /** Line height applied to text inputs and textarea/chip inputs. */
72
+ lineHeight: string;
73
+ /** Subtle card shadow. */
74
+ shadowCard: string;
75
+ /** Elevated popover/hover shadow. */
76
+ shadowPopover: string;
41
77
  focusRingWidth: string;
42
78
  focusRingColor: string;
43
79
  focusRingOpacity: string;
44
80
  transitionDuration: string;
81
+ slideCardBg: string;
82
+ slideCardShadow: string;
83
+ slideCardRadius: string;
84
+ /** Minimum card height — useful when content varies wildly across slides. */
85
+ slideCardMinHeight: string;
86
+ /** Inner padding of each slide card. Default sits a bit roomier than stack-mode. */
87
+ slideCardPadding: string;
88
+ labelSectionFontSize: string;
89
+ labelSectionLetterSpacing: string;
90
+ labelSectionTextTransform: string;
45
91
  }
46
92
  export declare const defaultTheme: Theme;
47
93
  /**
@@ -60,4 +106,5 @@ export declare const exampleThemes: {
60
106
  default: Theme;
61
107
  dark: Theme;
62
108
  klein: Theme;
109
+ picaz: Theme;
63
110
  };
@@ -49,4 +49,11 @@ export type ComponentUpdater = (element: Element, fieldPath: string, value: any,
49
49
  export interface ComponentOperations {
50
50
  validate: ComponentValidator;
51
51
  update: ComponentUpdater;
52
+ /**
53
+ * Set to true when the component renders its own title/label inline
54
+ * (e.g. boolean's `.toggle-row` puts the label next to the pill). When
55
+ * true, the main dispatcher skips `createLabelContainer` and lets the
56
+ * component own the entire field row.
57
+ */
58
+ ownsLabel?: boolean;
52
59
  }
@@ -1,4 +1,4 @@
1
- export type { SelectOption, ElementAction, EnableCondition, BaseElement, TextElement, TextareaElement, NumberElement, SelectElement, SwitcherElement, FileElement, FilesElement, ColourElement, SliderElement, ContainerElement, GroupElement, TableElement, TableMerge, TableData, RichInputElement, MarkdownElement, Element, Schema, ExternalAction, FormData, RenderContext, } from "./schema.js";
1
+ export type { SelectOption, ElementAction, EnableCondition, BaseElement, TextElement, TextareaElement, NumberElement, SelectElement, SwitcherElement, BooleanElement, FileElement, FilesElement, ColourElement, SliderElement, ContainerElement, GroupElement, TableElement, TableMerge, TableData, RichInputElement, MarkdownElement, Element, Schema, ExternalAction, FormData, RenderContext, } from "./schema.js";
2
2
  export type { Translations, Locale, Config, ResourceMetadata, PickedResource, } from "./config.js";
3
3
  export type { State } from "./state.js";
4
4
  export type { ComponentContext, ValidationResult, ComponentValidator, ComponentUpdater, ComponentOperations, } from "./component-operations.js";
@@ -1,6 +1,20 @@
1
1
  export interface SelectOption {
2
2
  value: string;
3
3
  label: string;
4
+ /**
5
+ * Optional secondary line under the label.
6
+ * Used by `switcher` to render preset-pill buttons (icon + name + subtitle).
7
+ * Ignored by `select` (native <option> shows label only).
8
+ */
9
+ subtitle?: string;
10
+ /**
11
+ * Optional image URL rendered to the left of the label.
12
+ * Accepts any `<img src>` value — typically a small SVG/PNG icon, or a
13
+ * `data:image/...;base64,...` URI for inline assets without a network round-trip.
14
+ * Used by `switcher` to show a visual preview (e.g. an aspect-ratio
15
+ * sketch for size presets). Ignored by `select`.
16
+ */
17
+ iconUrl?: string;
4
18
  }
5
19
  export interface ElementAction {
6
20
  key: string;
@@ -70,6 +84,12 @@ export interface NumberElement extends BaseElement {
70
84
  minCount?: number;
71
85
  maxCount?: number;
72
86
  addLabel?: string;
87
+ /**
88
+ * When true, renders a compact pill: `−` button, narrow input, `+` button.
89
+ * Native browser spinner arrows are hidden; range-hint chip is hidden.
90
+ * Clamped to `min`/`max`; uses `step` (default 1).
91
+ */
92
+ stepper?: boolean;
73
93
  }
74
94
  export interface SelectElement extends BaseElement {
75
95
  type: "select";
@@ -151,6 +171,25 @@ export interface SwitcherElement extends BaseElement {
151
171
  maxCount?: number;
152
172
  addLabel?: string;
153
173
  }
174
+ /**
175
+ * Boolean / toggle element. Renders as a `.toggle-row` card: pill switch
176
+ * on the left, label + hint stacked to the right. Form data value is a
177
+ * real boolean (`true` / `false`).
178
+ *
179
+ * Field-text layout (matches the design reference):
180
+ * - `label` → bold title (t1) inside the row, replacing the standard
181
+ * label that other field types render above.
182
+ * - `hint` → grey subtitle (t2) directly under the title.
183
+ * - `description` → text shown via a small info-icon tooltip next to the
184
+ * title (use a longer explanation here; keep `hint`
185
+ * short).
186
+ *
187
+ * `required` is ignored — `false` is a valid value.
188
+ */
189
+ export interface BooleanElement extends BaseElement {
190
+ type: "boolean";
191
+ default?: boolean;
192
+ }
154
193
  export interface GroupElement extends BaseElement {
155
194
  type: "group";
156
195
  elements: Element[];
@@ -229,7 +268,7 @@ export interface RichInputElement extends BaseElement {
229
268
  filesKey?: string;
230
269
  flatOutput?: boolean;
231
270
  }
232
- export type Element = TextElement | TextareaElement | NumberElement | SelectElement | SwitcherElement | FileElement | FilesElement | HiddenElement | ColourElement | SliderElement | ContainerElement | GroupElement | TableElement | RichInputElement | MarkdownElement;
271
+ export type Element = TextElement | TextareaElement | NumberElement | SelectElement | SwitcherElement | BooleanElement | FileElement | FilesElement | HiddenElement | ColourElement | SliderElement | ContainerElement | GroupElement | TableElement | RichInputElement | MarkdownElement;
233
272
  export interface Schema {
234
273
  version?: string;
235
274
  elements: Element[];
@@ -1,4 +1,51 @@
1
1
  import type { State } from "../types/index.js";
2
+ /**
3
+ * Strip the `.error-message` node paired with an input by id convention
4
+ * (markValidity creates `error-${input.name}` across text/select/slider/
5
+ * colour/switcher). Called from updateField paths so a programmatic update
6
+ * to a valid value clears any stale error surface left over from the
7
+ * previous validation pass — otherwise the field stays visibly "invalid"
8
+ * until the next validate cycle.
9
+ */
10
+ export declare function clearFieldError(input: HTMLElement): void;
11
+ /**
12
+ * Shared trash-can icon used by every per-item remove button (multi-text
13
+ * chips, multi-container items, etc.). Stays as one inline SVG so a single
14
+ * style sweep affects all remove affordances at once.
15
+ */
16
+ export declare const BIN_ICON_SVG = "<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6\"/><path d=\"M10 11v6\"/><path d=\"M14 11v6\"/><path d=\"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"/></svg>";
17
+ /**
18
+ * Inject the theming-hook stylesheet: rules that map `data-fb-*` attributes
19
+ * to their CSS-variable counterparts. Without this, themes that set
20
+ * `Theme.slideCardBg` etc. have no effect — defaults live in `defaultTheme`,
21
+ * so the rules below pick them up automatically for every form instance.
22
+ *
23
+ * - `[data-fb-slide-card]` — items inside `container.displayMode:"slides"`
24
+ * - `[data-fb-label-row]` — every standard field-label container
25
+ * - `.fb-prefill-hint` — schema-driven prefill suggestion pills
26
+ *
27
+ * Idempotent via a flag attribute on the document head.
28
+ */
29
+ export declare function ensureThemingHooks(doc: Document): void;
30
+ /**
31
+ * Make a textarea grow vertically with its content. Starts at the height
32
+ * required by the current value; on each input, sets height to scrollHeight
33
+ * plus borders.
34
+ *
35
+ * Why add borders: `scrollHeight` includes padding but not border, and our
36
+ * textareas use `box-sizing: border-box`. Setting `height = scrollHeight`
37
+ * makes the total box (border + padding + content) equal scrollHeight, which
38
+ * leaves the content area short by `2 * border-width` — at compact density
39
+ * (8px padding, 21px line-height) that's enough to clip a single line.
40
+ */
41
+ export declare function applyAutoExpand(textarea: HTMLTextAreaElement): void;
42
+ /**
43
+ * Enforce single-line semantics on a textarea: block the Enter key and
44
+ * strip newlines from pasted content. Used to render <textarea rows=1> as
45
+ * a soft-wrapping single-line input — text wraps visually but the value
46
+ * never contains a newline.
47
+ */
48
+ export declare function applySingleLineMode(textarea: HTMLTextAreaElement): void;
2
49
  /**
3
50
  * Apply themed input styles to an HTMLInputElement, HTMLTextAreaElement, or HTMLSelectElement
4
51
  */
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.2.34",
6
+ "version": "0.3.1",
7
7
  "description": "A reusable JSON schema form builder library",
8
8
  "main": "./dist/cjs/index.cjs",
9
9
  "module": "./dist/esm/index.js",