@theredhead/lucid-forms 0.1.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.
@@ -0,0 +1,1138 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { WritableSignal, Signal, Type, InjectionToken, EnvironmentProviders } from '@angular/core';
3
+ import { TextAdapter, SelectOption } from '@theredhead/lucid-kit';
4
+ import * as i1 from '@theredhead/lucid-foundation';
5
+
6
+ /**
7
+ * Operators available for field/group conditions.
8
+ *
9
+ * These compare the **live** value of a referenced field against
10
+ * a target value to determine visibility or enabled state.
11
+ */
12
+ type ConditionOperator = "equals" | "notEquals" | "contains" | "notContains" | "empty" | "notEmpty" | "greaterThan" | "lessThan" | "greaterThanOrEqual" | "lessThanOrEqual" | "in" | "notIn";
13
+ /**
14
+ * A single condition that controls whether a field or group is
15
+ * visible / enabled, based on the live value of another field.
16
+ *
17
+ * Conditions are JSON-serializable so a form schema can be stored
18
+ * as pure JSON and restored later.
19
+ *
20
+ * @example
21
+ * ```json
22
+ * { "field": "country", "operator": "equals", "value": "NL" }
23
+ * ```
24
+ */
25
+ interface FieldCondition {
26
+ /** ID of the field whose value is evaluated. */
27
+ readonly field: string;
28
+ /** Comparison operator. */
29
+ readonly operator: ConditionOperator;
30
+ /**
31
+ * Target value to compare against. Omitted for unary operators
32
+ * like `"empty"` and `"notEmpty"`.
33
+ */
34
+ readonly value?: unknown;
35
+ }
36
+ /**
37
+ * Logical combination of multiple conditions.
38
+ *
39
+ * When `mode` is `"every"` (default), **all** conditions must pass.
40
+ * When `mode` is `"some"`, **at least one** must pass.
41
+ */
42
+ interface ConditionGroup {
43
+ /** How to combine the conditions. Defaults to `"every"`. */
44
+ readonly mode?: "every" | "some";
45
+ /** The individual conditions to evaluate. */
46
+ readonly conditions: readonly FieldCondition[];
47
+ }
48
+ /**
49
+ * Either a single condition or a group of conditions.
50
+ * Used for both visibility and enabled state.
51
+ */
52
+ type Condition = FieldCondition | ConditionGroup;
53
+ /**
54
+ * Check whether a `Condition` is a `ConditionGroup` (has nested
55
+ * `conditions` array) rather than a single `FieldCondition`.
56
+ */
57
+ declare function isConditionGroup(c: Condition): c is ConditionGroup;
58
+
59
+ /**
60
+ * Built-in validation rule identifiers.
61
+ *
62
+ * The form engine ships validators for each of these. Custom
63
+ * validators can extend this set via the `"custom"` type.
64
+ */
65
+ type ValidationRuleType = "required" | "minLength" | "maxLength" | "min" | "max" | "pattern" | "email" | "custom";
66
+ /**
67
+ * A single validation rule, JSON-serializable.
68
+ *
69
+ * @example
70
+ * ```json
71
+ * { "type": "required", "message": "This field is required." }
72
+ * { "type": "minLength", "params": { "min": 3 }, "message": "At least 3 characters." }
73
+ * { "type": "pattern", "params": { "pattern": "^[A-Z]" }, "message": "Must start with uppercase." }
74
+ * ```
75
+ */
76
+ interface ValidationRule {
77
+ /** The validator to apply. */
78
+ readonly type: ValidationRuleType;
79
+ /**
80
+ * Additional parameters for the validator. The shape depends on
81
+ * the `type`:
82
+ *
83
+ * | Type | Params |
84
+ * |-------------|-------------------------------|
85
+ * | required | — |
86
+ * | minLength | `{ min: number }` |
87
+ * | maxLength | `{ max: number }` |
88
+ * | min | `{ min: number }` |
89
+ * | max | `{ max: number }` |
90
+ * | pattern | `{ pattern: string }` |
91
+ * | email | — |
92
+ * | custom | `{ validatorId: string, … }` |
93
+ */
94
+ readonly params?: Readonly<Record<string, unknown>>;
95
+ /** Human-readable error message shown when the rule fails. */
96
+ readonly message?: string;
97
+ }
98
+ /**
99
+ * A single validation error produced by the validation engine.
100
+ */
101
+ interface ValidationError {
102
+ /** The rule type that failed. */
103
+ readonly type: string;
104
+ /** Human-readable error message. */
105
+ readonly message: string;
106
+ }
107
+ /**
108
+ * Complete validation result for a single field.
109
+ */
110
+ interface ValidationResult {
111
+ /** Whether all rules passed. */
112
+ readonly valid: boolean;
113
+ /** Errors for every failed rule (empty when valid). */
114
+ readonly errors: readonly ValidationError[];
115
+ }
116
+
117
+ /**
118
+ * An option for select / radio / autocomplete fields.
119
+ *
120
+ * @example
121
+ * ```json
122
+ * { "label": "Netherlands", "value": "NL" }
123
+ * ```
124
+ */
125
+ interface FormFieldOption {
126
+ readonly label: string;
127
+ readonly value: unknown;
128
+ /** Whether the option is disabled. */
129
+ readonly disabled?: boolean;
130
+ }
131
+ /**
132
+ * Definition of a single form field. Fully JSON-serializable.
133
+ *
134
+ * The `component` key is resolved at runtime through the
135
+ * {@link FormFieldRegistry} to an actual Angular component that
136
+ * exposes a two-way `value` (or mapped model) signal.
137
+ *
138
+ * @example
139
+ * ```json
140
+ * {
141
+ * "id": "email",
142
+ * "title": "E-mail address",
143
+ * "component": "text",
144
+ * "config": { "type": "email", "placeholder": "you@example.com" },
145
+ * "validation": [
146
+ * { "type": "required", "message": "E-mail is required." },
147
+ * { "type": "email", "message": "Enter a valid e-mail address." }
148
+ * ]
149
+ * }
150
+ * ```
151
+ */
152
+ interface FormFieldDefinition {
153
+ /** Unique ID — used as the key in the form values object. */
154
+ readonly id: string;
155
+ /** Human-readable label shown above the field. */
156
+ readonly title: string;
157
+ /** Optional helper text shown below the field. */
158
+ readonly description?: string;
159
+ /**
160
+ * Registry key that maps to an Angular component.
161
+ *
162
+ * Built-in keys: `"text"`, `"select"`, `"checkbox"`, `"toggle"`,
163
+ * `"radio"`, `"autocomplete"`, `"date"`, `"time"`, `"datetime"`,
164
+ * `"color"`, `"slider"`, `"richtext"`, `"file"`.
165
+ */
166
+ readonly component: string;
167
+ /**
168
+ * Arbitrary key–value config forwarded as inputs to the
169
+ * resolved component. Keys must match the component's `input()`
170
+ * signal names.
171
+ */
172
+ readonly config?: Readonly<Record<string, unknown>>;
173
+ /**
174
+ * Options for select, radio, and autocomplete fields.
175
+ * Passed to the component's `options` or equivalent input.
176
+ */
177
+ readonly options?: readonly FormFieldOption[];
178
+ /** Validation rules evaluated by the form engine. */
179
+ readonly validation?: readonly ValidationRule[];
180
+ /**
181
+ * When set, the field is only visible if the condition is met.
182
+ * Hidden fields are excluded from the output JSON.
183
+ */
184
+ readonly visibleWhen?: Condition;
185
+ /**
186
+ * When set, the field is disabled (non-interactive) unless the
187
+ * condition is met.
188
+ */
189
+ readonly enabledWhen?: Condition;
190
+ /** Default value used when the form is first created. */
191
+ readonly defaultValue?: unknown;
192
+ }
193
+ /**
194
+ * A named group of fields. Rendered as a fieldset / section, or
195
+ * as a single step in wizard mode.
196
+ *
197
+ * @example
198
+ * ```json
199
+ * {
200
+ * "id": "personal",
201
+ * "title": "Personal information",
202
+ * "fields": [
203
+ * { "id": "firstName", "title": "First name", "component": "text" },
204
+ * { "id": "lastName", "title": "Last name", "component": "text" }
205
+ * ]
206
+ * }
207
+ * ```
208
+ */
209
+ interface FormGroupDefinition {
210
+ /** Unique ID for the group. */
211
+ readonly id: string;
212
+ /** Group heading. */
213
+ readonly title?: string;
214
+ /** Optional description shown below the heading. */
215
+ readonly description?: string;
216
+ /** Ordered list of fields in this group. */
217
+ readonly fields: readonly FormFieldDefinition[];
218
+ /** Condition controlling group visibility. */
219
+ readonly visibleWhen?: Condition;
220
+ /** Condition controlling group enabled state. */
221
+ readonly enabledWhen?: Condition;
222
+ }
223
+ /**
224
+ * Top-level form schema. This is the JSON document that fully
225
+ * describes a form — its structure, fields, validation, and
226
+ * conditional logic.
227
+ *
228
+ * @example
229
+ * ```json
230
+ * {
231
+ * "id": "contact",
232
+ * "title": "Contact form",
233
+ * "groups": [
234
+ * {
235
+ * "id": "main",
236
+ * "title": "Your details",
237
+ * "fields": [
238
+ * { "id": "name", "title": "Name", "component": "text" },
239
+ * { "id": "email", "title": "E-mail", "component": "text",
240
+ * "config": { "type": "email" } }
241
+ * ]
242
+ * }
243
+ * ]
244
+ * }
245
+ * ```
246
+ */
247
+ interface FormSchema {
248
+ /** Unique form identifier. */
249
+ readonly id: string;
250
+ /** Form title (rendered as a heading). */
251
+ readonly title?: string;
252
+ /** Optional description shown below the title. */
253
+ readonly description?: string;
254
+ /** Ordered list of field groups. */
255
+ readonly groups: readonly FormGroupDefinition[];
256
+ }
257
+ /**
258
+ * The plain-object output produced by the form engine.
259
+ *
260
+ * Keys are field IDs, values are the current field values.
261
+ * Only visible fields are included.
262
+ */
263
+ type FormValues = Record<string, unknown>;
264
+ /**
265
+ * Known flair component keys. Flair items are purely presentational
266
+ * elements that do not collect user input.
267
+ */
268
+ declare const FLAIR_COMPONENTS: readonly ["flair:richtext", "flair:image", "flair:media"];
269
+ /** A flair component key. */
270
+ type FlairComponent = (typeof FLAIR_COMPONENTS)[number];
271
+ /**
272
+ * Returns `true` if the given component key is a flair (non-data)
273
+ * component.
274
+ */
275
+ declare function isFlairComponent(component: string): component is FlairComponent;
276
+
277
+ /**
278
+ * Signature for a custom validator function.
279
+ *
280
+ * Returns `null` when valid, or a `ValidationError` on failure.
281
+ */
282
+ type ValidatorFn = (value: unknown, params: Readonly<Record<string, unknown>>) => ValidationError | null;
283
+ /**
284
+ * Register a custom validator that can be referenced by
285
+ * `{ type: "custom", params: { validatorId: "myId" } }` in a
286
+ * form schema.
287
+ */
288
+ declare function registerCustomValidator(id: string, fn: ValidatorFn): void;
289
+ /**
290
+ * Validate a value against an array of rules and return a
291
+ * {@link ValidationResult}.
292
+ */
293
+ declare function validate(rules: readonly ValidationRule[], value: unknown): ValidationResult;
294
+
295
+ /**
296
+ * Evaluate a {@link Condition} (single or group) against the
297
+ * current form values.
298
+ *
299
+ * @returns `true` when the condition is satisfied.
300
+ */
301
+ declare function evaluateCondition(condition: Condition, values: FormValues): boolean;
302
+
303
+ /**
304
+ * Runtime state for a single field managed by the form engine.
305
+ */
306
+ interface FieldState {
307
+ /** The field definition from the schema. */
308
+ readonly definition: FormFieldDefinition;
309
+ /** Current value (writable signal). */
310
+ readonly value: WritableSignal<unknown>;
311
+ /** Whether the field is currently visible. */
312
+ readonly visible: Signal<boolean>;
313
+ /** Whether the field is currently enabled (interactive). */
314
+ readonly enabled: Signal<boolean>;
315
+ /** Live validation result. */
316
+ readonly validation: Signal<ValidationResult>;
317
+ /** Whether the field has been interacted with. */
318
+ readonly touched: WritableSignal<boolean>;
319
+ /** Whether the field has been changed from its default. */
320
+ readonly dirty: Signal<boolean>;
321
+ }
322
+ /**
323
+ * Runtime state for a field group.
324
+ */
325
+ interface GroupState {
326
+ /** The group definition from the schema. */
327
+ readonly definition: FormGroupDefinition;
328
+ /** Runtime states for every field in this group. */
329
+ readonly fields: readonly FieldState[];
330
+ /** Whether the group is currently visible. */
331
+ readonly visible: Signal<boolean>;
332
+ /** Whether the group is currently enabled. */
333
+ readonly enabled: Signal<boolean>;
334
+ /** Whether every visible field in the group is valid. */
335
+ readonly valid: Signal<boolean>;
336
+ }
337
+ /**
338
+ * Signal-based form engine. Takes a {@link FormSchema}, creates
339
+ * reactive state for every field and group, evaluates conditions,
340
+ * runs validation, and produces a JSON output object.
341
+ *
342
+ * The engine is framework-agnostic (no Angular DI required) — it
343
+ * operates purely on signals and plain objects.
344
+ *
345
+ * @example
346
+ * ```ts
347
+ * const engine = new FormEngine(schema);
348
+ * engine.setValue("email", "test@example.com");
349
+ * console.log(engine.values()); // { email: "test@example.com", … }
350
+ * console.log(engine.valid()); // true / false
351
+ * ```
352
+ */
353
+ declare class FormEngine {
354
+ readonly schema: FormSchema;
355
+ /** All field states indexed by field ID. */
356
+ private readonly fieldMap;
357
+ /** Ordered group states. */
358
+ readonly groups: readonly GroupState[];
359
+ /** Live snapshot of all field values (including hidden fields). */
360
+ readonly values: Signal<FormValues>;
361
+ /** Whether every visible field passes validation. */
362
+ readonly valid: Signal<boolean>;
363
+ /** Whether any field has been interacted with. */
364
+ readonly touched: Signal<boolean>;
365
+ /** Whether any field value differs from its default. */
366
+ readonly dirty: Signal<boolean>;
367
+ constructor(schema: FormSchema);
368
+ /**
369
+ * Get the {@link FieldState} for a field by ID.
370
+ * Throws if the field is not found.
371
+ */
372
+ getField(id: string): FieldState;
373
+ /** Set the value of a single field by ID. */
374
+ setValue(id: string, value: unknown): void;
375
+ /** Mark a field as touched. */
376
+ markTouched(id: string): void;
377
+ /** Mark all fields as touched (e.g. on submit attempt). */
378
+ markAllTouched(): void;
379
+ /**
380
+ * Reset the form to its initial default values and clear
381
+ * touched/dirty state.
382
+ */
383
+ reset(): void;
384
+ /**
385
+ * Produce the JSON output — a plain object containing only
386
+ * **visible** field values.
387
+ */
388
+ output(): Signal<FormValues>;
389
+ private buildGroupState;
390
+ private buildFieldState;
391
+ /**
392
+ * Read all current field values reactively. When called inside a
393
+ * `computed()`, it tracks every field's value signal so the
394
+ * computed re-evaluates whenever any field changes.
395
+ */
396
+ private readFieldValues;
397
+ /**
398
+ * Produce a sensible default value for a given component type so
399
+ * fields without explicit `defaultValue` still have a typed zero.
400
+ */
401
+ private defaultForComponent;
402
+ }
403
+
404
+ /**
405
+ * Transforms a raw config value (typically a JSON-serializable string
406
+ * or number) into the runtime value expected by the component input.
407
+ *
408
+ * Used by {@link FormFieldRegistration.configTransforms} to bridge
409
+ * JSON-friendly config keys to complex runtime objects.
410
+ */
411
+ interface ConfigTransform {
412
+ /** The actual component input name to set. */
413
+ readonly inputKey: string;
414
+ /** Convert the raw config value to the runtime input value. */
415
+ readonly transform: (value: unknown) => unknown;
416
+ }
417
+ /**
418
+ * Describes how a component is integrated into the form system.
419
+ */
420
+ interface FormFieldRegistration {
421
+ /**
422
+ * The Angular component class to instantiate.
423
+ * Must be a standalone component.
424
+ */
425
+ readonly component: Type<unknown>;
426
+ /**
427
+ * Name of the model signal used for two-way value binding.
428
+ *
429
+ * Most ui-kit components use `"value"`. Exceptions:
430
+ * - `UICheckbox` → `"checked"`
431
+ * - `UIFileUpload` → `"files"`
432
+ */
433
+ readonly modelProperty: string;
434
+ /**
435
+ * Static inputs to apply by default (e.g. `{ type: "email" }`).
436
+ * Merged with (overridden by) the field definition's `config`.
437
+ */
438
+ readonly defaultConfig?: Readonly<Record<string, unknown>>;
439
+ /**
440
+ * Optional map from config keys to {@link ConfigTransform} entries.
441
+ *
442
+ * When a config key appears in this map, the raw JSON value is
443
+ * passed through the transform and set on the component input
444
+ * specified by `inputKey` instead of the config key itself.
445
+ *
446
+ * @example
447
+ * ```ts
448
+ * configTransforms: {
449
+ * textAdapter: {
450
+ * inputKey: 'adapter',
451
+ * transform: (key) => resolveTextAdapter(key as string),
452
+ * },
453
+ * }
454
+ * ```
455
+ */
456
+ readonly configTransforms?: Readonly<Record<string, ConfigTransform>>;
457
+ }
458
+ /**
459
+ * Multi-provider token that collects field registrations from
460
+ * across the application.
461
+ */
462
+ declare const FORM_FIELD_REGISTRATIONS: InjectionToken<ReadonlyMap<string, FormFieldRegistration>>;
463
+ /**
464
+ * Register one or more field types for use in form schemas.
465
+ *
466
+ * @example
467
+ * ```ts
468
+ * // app.config.ts
469
+ * import { provideFormFields } from '@theredhead/lucid-forms';
470
+ * import { UIInput, UISelect, UICheckbox } from '@theredhead/lucid-kit';
471
+ *
472
+ * export const appConfig = {
473
+ * providers: [
474
+ * provideFormFields({
475
+ * text: { component: UIInput, modelProperty: 'value' },
476
+ * select: { component: UISelect, modelProperty: 'value' },
477
+ * checkbox: { component: UICheckbox, modelProperty: 'checked' },
478
+ * }),
479
+ * ],
480
+ * };
481
+ * ```
482
+ */
483
+ declare function provideFormFields(fields: Readonly<Record<string, FormFieldRegistration>>): EnvironmentProviders;
484
+ /**
485
+ * Injectable service that resolves a component key (e.g. `"text"`)
486
+ * to a {@link FormFieldRegistration}.
487
+ *
488
+ * It merges all maps provided via `FORM_FIELD_REGISTRATIONS`.
489
+ */
490
+ declare class FormFieldRegistry {
491
+ private readonly maps;
492
+ private merged;
493
+ private getMerged;
494
+ /** Resolve a component key to its registration, or `null`. */
495
+ resolve(key: string): FormFieldRegistration | null;
496
+ /** All registered keys. */
497
+ keys(): string[];
498
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FormFieldRegistry, never>;
499
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<FormFieldRegistry>;
500
+ }
501
+
502
+ /**
503
+ * Built-in field registrations that map common component keys
504
+ * to `@theredhead/lucid-kit` components.
505
+ *
506
+ * | Key | Component | Model property |
507
+ * |-----------------|---------------------|----------------|
508
+ * | `"text"` | `UIInput` | `value` |
509
+ * | `"select"` | `UIDropdownList` | `value` |
510
+ * | `"checkbox"` | `UICheckbox` | `checked` |
511
+ * | `"toggle"` | `UIToggle` | `value` |
512
+ * | `"radio"` | `UIRadioGroup` | `value` |
513
+ * | `"autocomplete"`| `UIAutocomplete` | `value` |
514
+ * | `"date"` | `UIInput` + `DateInputAdapter` | `value` |
515
+ * | `"time"` | `UIInput` + `TimeTextAdapter` | `value` |
516
+ * | `"datetime"` | `UIInput` + `DateInputAdapter` | `value` |
517
+ * | `"color"` | `UIColorPicker` | `value` |
518
+ * | `"slider"` | `UISlider` | `value` |
519
+ * | `"richtext"` | `UIRichTextEditor` | `value` |
520
+ * | `"file"` | `UIFileUpload` | `files` |
521
+ * | `"flair:richtext"` | `UIRichTextView` | `content` |
522
+ * | `"flair:image"` | `UIImage` | `src` |
523
+ * | `"flair:media"` | `UIMediaPlayer` | `source` |
524
+ */
525
+ declare const BUILT_IN_FIELDS: Readonly<Record<string, FormFieldRegistration>>;
526
+ /**
527
+ * Convenience provider that registers all built-in
528
+ * `@theredhead/lucid-kit` field types.
529
+ *
530
+ * @example
531
+ * ```ts
532
+ * import { provideBuiltInFormFields } from '@theredhead/lucid-forms';
533
+ *
534
+ * export const appConfig = {
535
+ * providers: [provideBuiltInFormFields()],
536
+ * };
537
+ * ```
538
+ */
539
+ declare function provideBuiltInFormFields(): EnvironmentProviders;
540
+
541
+ /**
542
+ * All available text adapter keys, in display order.
543
+ */
544
+ declare const TEXT_ADAPTER_KEYS: readonly string[];
545
+ /**
546
+ * Resolve a text adapter key to a {@link TextAdapter} instance.
547
+ *
548
+ * Returns `undefined` for empty/unknown keys.
549
+ *
550
+ * @param key Adapter key (e.g. `"email"`, `"phone"`, `"money"`).
551
+ */
552
+ declare function resolveTextAdapter(key: unknown): TextAdapter | undefined;
553
+
554
+ /**
555
+ * The result of an export operation.
556
+ *
557
+ * Contains the generated content as a string together with metadata
558
+ * about the suggested file name and MIME type.
559
+ */
560
+ interface ExportResult {
561
+ /** MIME type for the exported content (e.g. `"application/json"`, `"text/typescript"`). */
562
+ readonly mimeType: string;
563
+ /** Suggested file name for the exported artefact. */
564
+ readonly fileName: string;
565
+ /** The exported content as a string. */
566
+ readonly content: string;
567
+ }
568
+ /**
569
+ * Strategy interface for exporting a {@link FormSchema} into a
570
+ * specific format.
571
+ *
572
+ * Implementations must be plain classes — no Angular DI required.
573
+ *
574
+ * @example
575
+ * ```ts
576
+ * class MyExportStrategy implements ExportStrategy {
577
+ * readonly label = 'My Format';
578
+ * readonly description = 'Export as My Format.';
579
+ *
580
+ * export(schema: FormSchema): ExportResult {
581
+ * return {
582
+ * mimeType: 'text/plain',
583
+ * fileName: 'form.txt',
584
+ * content: JSON.stringify(schema),
585
+ * };
586
+ * }
587
+ * }
588
+ * ```
589
+ */
590
+ interface ExportStrategy {
591
+ /** Human-readable label displayed in the export format selector. */
592
+ readonly label: string;
593
+ /** Short description of the export format. */
594
+ readonly description: string;
595
+ /** Generate an {@link ExportResult} from the given schema. */
596
+ export(schema: FormSchema): ExportResult;
597
+ }
598
+
599
+ /**
600
+ * Exports a {@link FormSchema} as a formatted JSON file.
601
+ *
602
+ * The output is a standard JSON document — identical to
603
+ * `JSON.stringify(schema, null, 2)`.
604
+ */
605
+ declare class JsonExportStrategy implements ExportStrategy {
606
+ readonly label = "JSON Schema";
607
+ readonly description = "Export the form schema as a JSON file.";
608
+ export(schema: FormSchema): ExportResult;
609
+ }
610
+
611
+ /**
612
+ * Exports a {@link FormSchema} as a standalone Angular component
613
+ * with a fully declarative HTML template.
614
+ *
615
+ * The generated `.component.ts` file contains:
616
+ *
617
+ * - A typed `<Title>FormValues` interface with one property per field
618
+ * - Individual `signal()` fields for two-way binding
619
+ * - A `computed()` `formValues` signal that assembles the full typed object
620
+ * - A template that directly uses `@theredhead/lucid-kit` components
621
+ * (`<ui-input>`, `<ui-select>`, …) — no `FormEngine` or `<ui-form>`
622
+ *
623
+ * The component is almost entirely declarative: the TypeScript class
624
+ * is just signals and a single computed.
625
+ */
626
+ declare class AngularComponentExportStrategy implements ExportStrategy {
627
+ readonly label = "Angular Component";
628
+ readonly description = "Standalone Angular component with declarative template.";
629
+ export(schema: FormSchema): ExportResult;
630
+ /** @internal Build the import statements. */
631
+ private buildImports;
632
+ /** @internal Build the values interface. */
633
+ private buildInterface;
634
+ /** @internal Build the full @Component class. */
635
+ private buildComponent;
636
+ /** @internal Build the HTML template with fieldsets and components. */
637
+ private buildTemplate;
638
+ /** @internal Build the class body: signals, options, computed. */
639
+ private buildClassBody;
640
+ }
641
+
642
+ /**
643
+ * Renders a single form field by dynamically creating the component
644
+ * registered for the field's `component` key and wiring up two-way
645
+ * value binding, config inputs, and validation display.
646
+ *
647
+ * This component is used internally by {@link UIFormGroup} and
648
+ * {@link UIForm}. It can also be used standalone for custom layouts.
649
+ *
650
+ * @example
651
+ * ```html
652
+ * <ui-form-field [state]="fieldState" />
653
+ * ```
654
+ */
655
+ declare class UIFormField {
656
+ /** The field state managed by the {@link FormEngine}. */
657
+ readonly state: _angular_core.InputSignal<FieldState>;
658
+ private readonly registry;
659
+ private readonly log;
660
+ private readonly outlet;
661
+ /** @internal Show errors only when the field has been touched. */
662
+ protected readonly showErrors: _angular_core.Signal<boolean>;
663
+ /** @internal Whether this field is a flair (non-data) component. */
664
+ protected readonly isFlair: _angular_core.Signal<boolean>;
665
+ /** @internal Whether the field has a `required` validation rule. */
666
+ protected readonly isRequired: _angular_core.Signal<boolean>;
667
+ constructor();
668
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UIFormField, never>;
669
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<UIFormField, "ui-form-field", never, { "state": { "alias": "state"; "required": true; "isSignal": true; }; }, {}, never, never, true, [{ directive: typeof i1.UISurface; inputs: { "surfaceType": "surfaceType"; }; outputs: {}; }]>;
670
+ }
671
+
672
+ /**
673
+ * Renders a group of form fields as a visual section (fieldset).
674
+ *
675
+ * In sequential (non-wizard) mode every group is displayed
676
+ * vertically. In wizard mode, {@link UIFormWizard} controls which
677
+ * group is visible.
678
+ *
679
+ * @example
680
+ * ```html
681
+ * <ui-form-group [state]="groupState" />
682
+ * ```
683
+ */
684
+ declare class UIFormGroup {
685
+ /** The group state managed by the {@link FormEngine}. */
686
+ readonly state: _angular_core.InputSignal<GroupState>;
687
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UIFormGroup, never>;
688
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<UIFormGroup, "ui-form-group", never, { "state": { "alias": "state"; "required": true; "isSignal": true; }; }, {}, never, never, true, [{ directive: typeof i1.UISurface; inputs: { "surfaceType": "surfaceType"; }; outputs: {}; }]>;
689
+ }
690
+
691
+ /**
692
+ * Top-level form component that renders all groups sequentially.
693
+ *
694
+ * Takes a {@link FormEngine} instance and displays every group's
695
+ * fields in order, with validation and conditional visibility.
696
+ *
697
+ * @example
698
+ * ```html
699
+ * <ui-form [engine]="engine" (formSubmit)="onSubmit($event)" />
700
+ * ```
701
+ */
702
+ declare class UIForm {
703
+ /** The form engine instance that drives this form. */
704
+ readonly engine: _angular_core.InputSignal<FormEngine>;
705
+ /** Label for the submit button. Defaults to `"Submit"`. */
706
+ readonly submitLabel: _angular_core.InputSignal<string>;
707
+ /** Whether to show the built-in submit button. Defaults to `true`. */
708
+ readonly showSubmit: _angular_core.InputSignal<boolean>;
709
+ /** Minimum width (in pixels) for form field controls. Defaults to `200`. */
710
+ readonly fieldMinWidth: _angular_core.InputSignal<number>;
711
+ /** Emitted when the submit button is clicked and the form is valid. */
712
+ readonly formSubmit: _angular_core.OutputEmitterRef<FormValues>;
713
+ /** @internal */
714
+ protected readonly isValid: _angular_core.Signal<boolean>;
715
+ /** @internal — collects all invalid visible fields for the summary. */
716
+ protected readonly validationSummary: _angular_core.Signal<{
717
+ fieldId: string;
718
+ title: string;
719
+ errors: string[];
720
+ }[]>;
721
+ /** @internal */
722
+ protected onSubmit(): void;
723
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UIForm, never>;
724
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<UIForm, "ui-form", never, { "engine": { "alias": "engine"; "required": true; "isSignal": true; }; "submitLabel": { "alias": "submitLabel"; "required": false; "isSignal": true; }; "showSubmit": { "alias": "showSubmit"; "required": false; "isSignal": true; }; "fieldMinWidth": { "alias": "fieldMinWidth"; "required": false; "isSignal": true; }; }, { "formSubmit": "formSubmit"; }, never, never, true, [{ directive: typeof i1.UISurface; inputs: { "surfaceType": "surfaceType"; }; outputs: {}; }]>;
725
+ }
726
+
727
+ /**
728
+ * Renders a {@link FormEngine}'s groups as wizard steps — one group
729
+ * at a time with previous / next / submit navigation.
730
+ *
731
+ * Only visible groups are included as steps. The wizard validates
732
+ * the current step before allowing navigation to the next.
733
+ *
734
+ * @example
735
+ * ```html
736
+ * <ui-form-wizard
737
+ * [engine]="engine"
738
+ * (formSubmit)="onSubmit($event)"
739
+ * />
740
+ * ```
741
+ */
742
+ declare class UIFormWizard {
743
+ /** The form engine instance that drives this wizard. */
744
+ readonly engine: _angular_core.InputSignal<FormEngine>;
745
+ /** Label for the "Next" button. */
746
+ readonly nextLabel: _angular_core.InputSignal<string>;
747
+ /** Label for the "Previous" button. */
748
+ readonly prevLabel: _angular_core.InputSignal<string>;
749
+ /** Label for the "Submit" button (last step). */
750
+ readonly submitLabel: _angular_core.InputSignal<string>;
751
+ /** Minimum width (in pixels) for form field controls. Defaults to `200`. */
752
+ readonly fieldMinWidth: _angular_core.InputSignal<number>;
753
+ /** Emitted when the form is submitted (last step, valid). */
754
+ readonly formSubmit: _angular_core.OutputEmitterRef<FormValues>;
755
+ /** Current step index. */
756
+ protected readonly currentIndex: _angular_core.WritableSignal<number>;
757
+ /** Only visible groups are wizard steps. */
758
+ protected readonly visibleGroups: _angular_core.Signal<GroupState[]>;
759
+ /** The currently displayed group state. */
760
+ protected readonly currentGroup: _angular_core.Signal<GroupState | null>;
761
+ /** Whether the current step is the last one. */
762
+ protected readonly isLastStep: _angular_core.Signal<boolean>;
763
+ /** Whether the current step's fields are all valid. */
764
+ protected readonly currentStepValid: _angular_core.Signal<boolean>;
765
+ /** Navigate to the next step (marks current fields touched). */
766
+ next(): void;
767
+ /** Navigate to the previous step. */
768
+ prev(): void;
769
+ /** Jump to a specific step. */
770
+ goTo(index: number): void;
771
+ /** @internal Submit handler. */
772
+ protected onSubmit(): void;
773
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UIFormWizard, never>;
774
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<UIFormWizard, "ui-form-wizard", never, { "engine": { "alias": "engine"; "required": true; "isSignal": true; }; "nextLabel": { "alias": "nextLabel"; "required": false; "isSignal": true; }; "prevLabel": { "alias": "prevLabel"; "required": false; "isSignal": true; }; "submitLabel": { "alias": "submitLabel"; "required": false; "isSignal": true; }; "fieldMinWidth": { "alias": "fieldMinWidth"; "required": false; "isSignal": true; }; }, { "formSubmit": "formSubmit"; }, never, never, true, [{ directive: typeof i1.UISurface; inputs: { "surfaceType": "surfaceType"; }; outputs: {}; }]>;
775
+ }
776
+
777
+ /**
778
+ * Mutable counterpart of {@link FormFieldDefinition} used
779
+ * exclusively inside the designer. Signal-driven so every
780
+ * property change is immediately reflected in the live preview
781
+ * and schema output.
782
+ */
783
+ interface MutableFieldDefinition {
784
+ readonly uid: string;
785
+ readonly id: WritableSignal<string>;
786
+ readonly title: WritableSignal<string>;
787
+ readonly description: WritableSignal<string>;
788
+ readonly component: WritableSignal<string>;
789
+ readonly config: WritableSignal<Record<string, unknown>>;
790
+ readonly options: WritableSignal<FormFieldOption[]>;
791
+ readonly validation: WritableSignal<ValidationRule[]>;
792
+ readonly visibleWhen: WritableSignal<Condition | null>;
793
+ readonly enabledWhen: WritableSignal<Condition | null>;
794
+ readonly defaultValue: WritableSignal<unknown>;
795
+ }
796
+ /**
797
+ * Mutable counterpart of {@link FormGroupDefinition}.
798
+ */
799
+ interface MutableGroupDefinition {
800
+ readonly uid: string;
801
+ readonly id: WritableSignal<string>;
802
+ readonly title: WritableSignal<string>;
803
+ readonly description: WritableSignal<string>;
804
+ readonly fields: WritableSignal<MutableFieldDefinition[]>;
805
+ readonly visibleWhen: WritableSignal<Condition | null>;
806
+ readonly enabledWhen: WritableSignal<Condition | null>;
807
+ }
808
+ /** What kind of item is currently selected in the designer. */
809
+ type DesignerSelectionKind = "field" | "group" | "form";
810
+ /**
811
+ * Describes the currently selected item in the designer canvas.
812
+ */
813
+ interface DesignerSelection {
814
+ readonly kind: DesignerSelectionKind;
815
+ readonly groupUid: string | null;
816
+ readonly fieldUid: string | null;
817
+ }
818
+ /**
819
+ * Signal-based engine that maintains the mutable designer state
820
+ * and produces a readonly {@link FormSchema} snapshot on demand.
821
+ *
822
+ * All mutations go through public methods so the UI stays in sync
823
+ * via Angular's signal-based change detection.
824
+ *
825
+ * @example
826
+ * ```ts
827
+ * const engine = new FormDesignerEngine();
828
+ * engine.addGroup();
829
+ * engine.addField(engine.groups()[0].uid, 'text');
830
+ * const schema = engine.schema();
831
+ * ```
832
+ */
833
+ declare class FormDesignerEngine {
834
+ /** Form ID. */
835
+ readonly formId: WritableSignal<string>;
836
+ /** Form title. */
837
+ readonly formTitle: WritableSignal<string>;
838
+ /** Form description. */
839
+ readonly formDescription: WritableSignal<string>;
840
+ /** Ordered list of mutable group definitions. */
841
+ readonly groups: WritableSignal<MutableGroupDefinition[]>;
842
+ /** Currently selected item in the canvas. */
843
+ readonly selection: WritableSignal<DesignerSelection | null>;
844
+ /** The currently selected mutable field (convenience). */
845
+ readonly selectedField: Signal<MutableFieldDefinition | null>;
846
+ /** The currently selected mutable group (convenience). */
847
+ readonly selectedGroup: Signal<MutableGroupDefinition | null>;
848
+ /**
849
+ * Produces a readonly {@link FormSchema} snapshot from the current
850
+ * mutable state. Fully JSON-serializable.
851
+ */
852
+ readonly schema: Signal<FormSchema>;
853
+ /** Add a new empty group at the end. Returns the new group's uid. */
854
+ addGroup(): string;
855
+ /** Remove a group by uid. Clears selection if it pointed at the group. */
856
+ removeGroup(uid: string): void;
857
+ /** Move a group to a new index. */
858
+ moveGroup(uid: string, newIndex: number): void;
859
+ /**
860
+ * Add a new field to a group. Returns the new field's uid.
861
+ *
862
+ * @param groupUid — Target group
863
+ * @param component — Field component key (e.g. `"text"`, `"select"`)
864
+ * @param atIndex — Optional insertion index (appends if omitted)
865
+ */
866
+ addField(groupUid: string, component: string, atIndex?: number): string;
867
+ /** Remove a field by uid from its containing group. */
868
+ removeField(groupUid: string, fieldUid: string): void;
869
+ /** Move a field to a new position within its group, or to another group. */
870
+ moveField(sourceGroupUid: string, fieldUid: string, targetGroupUid: string, targetIndex: number): void;
871
+ /** Duplicate a field within its group (inserted right after the original). */
872
+ duplicateField(groupUid: string, fieldUid: string): string | null;
873
+ /** Select a field for editing in the inspector. */
874
+ selectField(groupUid: string, fieldUid: string): void;
875
+ /** Select a group for editing in the inspector. */
876
+ selectGroup(groupUid: string): void;
877
+ /** Select the form-level properties for editing. */
878
+ selectForm(): void;
879
+ /** Clear the selection. */
880
+ clearSelection(): void;
881
+ /**
882
+ * Load an existing {@link FormSchema} into the designer,
883
+ * replacing all current state.
884
+ */
885
+ loadSchema(schema: FormSchema): void;
886
+ /**
887
+ * Produce a pretty-printed JSON string of the current schema.
888
+ */
889
+ toJSON(): string;
890
+ private createMutableField;
891
+ private createMutableGroup;
892
+ private buildSchema;
893
+ /**
894
+ * Generate a sensible default label from a component key.
895
+ */
896
+ private labelForComponent;
897
+ }
898
+
899
+ /**
900
+ * Metadata for a draggable field type shown in the palette.
901
+ */
902
+ interface PaletteFieldType {
903
+ /** Registry component key (e.g. `"text"`, `"select"`). */
904
+ readonly key: string;
905
+ /** Display label. */
906
+ readonly label: string;
907
+ /** Short description shown on hover. */
908
+ readonly description: string;
909
+ /** SVG icon content from the `UIIcons` registry. */
910
+ readonly icon: string;
911
+ }
912
+ /**
913
+ * Palette sidebar that lists available field types. Clicking or
914
+ * dragging a type emits the component key so the parent can add
915
+ * it to the canvas.
916
+ *
917
+ * @example
918
+ * ```html
919
+ * <ui-field-palette (fieldRequested)="onAddField($event)" />
920
+ * ```
921
+ */
922
+ declare class UIFieldPalette {
923
+ /** Emitted when the user clicks a field type to add it. */
924
+ readonly fieldRequested: _angular_core.OutputEmitterRef<string>;
925
+ /** @internal Available field types. */
926
+ protected readonly fieldTypes: readonly PaletteFieldType[];
927
+ /** @internal Available flair types. */
928
+ protected readonly flairTypes: readonly PaletteFieldType[];
929
+ /** @internal */
930
+ protected onDragStart(event: DragEvent, key: string): void;
931
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UIFieldPalette, never>;
932
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<UIFieldPalette, "ui-field-palette", never, {}, { "fieldRequested": "fieldRequested"; }, never, never, true, [{ directive: typeof i1.UISurface; inputs: { "surfaceType": "surfaceType"; }; outputs: {}; }]>;
933
+ }
934
+
935
+ /**
936
+ * The central canvas of the form designer. Displays all groups
937
+ * and their fields as interactive cards that can be selected,
938
+ * reordered, and deleted.
939
+ *
940
+ * @example
941
+ * ```html
942
+ * <ui-designer-canvas [engine]="engine" />
943
+ * ```
944
+ */
945
+ declare class UIDesignerCanvas {
946
+ /** The designer engine driving this canvas. */
947
+ readonly engine: _angular_core.InputSignal<FormDesignerEngine>;
948
+ /** Emitted when "Add field" is clicked on a group (passes group uid). */
949
+ readonly addFieldRequest: _angular_core.OutputEmitterRef<string>;
950
+ /** @internal Icon references exposed to the template. */
951
+ protected readonly icons: {
952
+ readonly ChevronUp: "<path d=\"m18 15-6-6-6 6\" />";
953
+ readonly ChevronDown: "<path d=\"m6 9 6 6 6-6\" />";
954
+ readonly Copy: "<rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\" /><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\" />";
955
+ readonly X: "<path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />";
956
+ };
957
+ /** @internal Whether a component key is a flair type. */
958
+ protected readonly isFlair: typeof isFlairComponent;
959
+ /** @internal */
960
+ protected moveGroupUp(event: Event, uid: string, index: number): void;
961
+ /** @internal */
962
+ protected moveGroupDown(event: Event, uid: string, index: number): void;
963
+ /** @internal */
964
+ protected removeGroup(event: Event, uid: string): void;
965
+ /** @internal */
966
+ protected moveFieldUp(event: Event, groupUid: string, fieldUid: string, index: number): void;
967
+ /** @internal */
968
+ protected moveFieldDown(event: Event, groupUid: string, fieldUid: string, index: number): void;
969
+ /** @internal */
970
+ protected duplicateField(event: Event, groupUid: string, fieldUid: string): void;
971
+ /** @internal */
972
+ protected removeField(event: Event, groupUid: string, fieldUid: string): void;
973
+ /** @internal */
974
+ protected onDragOver(event: DragEvent): void;
975
+ /** @internal */
976
+ protected onDropField(event: DragEvent, group: MutableGroupDefinition): void;
977
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UIDesignerCanvas, never>;
978
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<UIDesignerCanvas, "ui-designer-canvas", never, { "engine": { "alias": "engine"; "required": true; "isSignal": true; }; }, { "addFieldRequest": "addFieldRequest"; }, never, never, true, [{ directive: typeof i1.UISurface; inputs: { "surfaceType": "surfaceType"; }; outputs: {}; }]>;
979
+ }
980
+
981
+ /**
982
+ * Describes a single config property that the property inspector
983
+ * renders as a structured form control.
984
+ */
985
+ interface ConfigPropertySchema {
986
+ /** The config key name (e.g. `"type"`, `"multiline"`). */
987
+ readonly key: string;
988
+ /** Human-readable label shown in the inspector. */
989
+ readonly label: string;
990
+ /** The editor to use. */
991
+ readonly editor: "text" | "number" | "boolean" | "select" | "richtext";
992
+ /**
993
+ * For `"select"` editors — the list of allowed values.
994
+ * Each entry is either a plain string (used as both label and value)
995
+ * or a `{ label, value }` pair.
996
+ */
997
+ readonly options?: readonly (string | {
998
+ label: string;
999
+ value: string;
1000
+ })[];
1001
+ /** Default value when the property is not set. */
1002
+ readonly defaultValue?: unknown;
1003
+ /** Optional short hint shown as placeholder text. */
1004
+ readonly placeholder?: string;
1005
+ /**
1006
+ * When provided, the property is only shown in the inspector if this
1007
+ * predicate returns `true` for the current config values.
1008
+ */
1009
+ readonly visibleWhen?: (config: Record<string, unknown>) => boolean;
1010
+ }
1011
+
1012
+ /**
1013
+ * Property inspector panel for editing the properties of the
1014
+ * currently selected field, group, or form.
1015
+ *
1016
+ * @example
1017
+ * ```html
1018
+ * <ui-property-inspector [engine]="engine" />
1019
+ * ```
1020
+ */
1021
+ declare class UIPropertyInspector {
1022
+ /** The designer engine driving this inspector. */
1023
+ readonly engine: _angular_core.InputSignal<FormDesignerEngine>;
1024
+ /** @internal */
1025
+ protected readonly componentOptions: SelectOption[];
1026
+ /** @internal */
1027
+ protected readonly validationTypeOptions: SelectOption[];
1028
+ /** @internal */
1029
+ protected readonly configError: _angular_core.WritableSignal<string>;
1030
+ /** @internal X icon for remove buttons. */
1031
+ protected readonly iconX: "<path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />";
1032
+ /** @internal Edit icon for the rich text button. */
1033
+ protected readonly iconEdit: "<path d=\"M12 4v16\" /><path d=\"M4 7V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2\" /><path d=\"M9 20h6\" />";
1034
+ private readonly modalService;
1035
+ /** @internal Extract input value from a DOM event. */
1036
+ protected inputValue(event: Event): string;
1037
+ /** @internal Whether the field type supports options. */
1038
+ protected showOptions(field: MutableFieldDefinition): boolean;
1039
+ /** @internal Whether the field is a flair (non-data) component. */
1040
+ protected isFieldFlair(field: MutableFieldDefinition): boolean;
1041
+ /** @internal */
1042
+ protected addOption(field: MutableFieldDefinition): void;
1043
+ /** @internal */
1044
+ protected removeOption(field: MutableFieldDefinition, index: number): void;
1045
+ /** @internal */
1046
+ protected updateOption(field: MutableFieldDefinition, index: number, key: "label" | "value", value: string): void;
1047
+ /** @internal */
1048
+ protected addValidationRule(field: MutableFieldDefinition): void;
1049
+ /** @internal */
1050
+ protected removeValidationRule(field: MutableFieldDefinition, index: number): void;
1051
+ /** @internal */
1052
+ protected updateValidationRule(field: MutableFieldDefinition, index: number, key: string, value: string): void;
1053
+ /** @internal */
1054
+ protected ruleHasParam(type: string): boolean;
1055
+ /** @internal */
1056
+ protected paramPlaceholder(type: string): string;
1057
+ /** @internal */
1058
+ protected ruleParamValue(rule: ValidationRule): string;
1059
+ /** @internal */
1060
+ protected updateValidationParam(field: MutableFieldDefinition, index: number, type: string, value: string): void;
1061
+ /** @internal Returns the config property schemas for the field's component. */
1062
+ protected configSchemaFor(field: MutableFieldDefinition): readonly ConfigPropertySchema[];
1063
+ /** @internal Read a single config value. */
1064
+ protected configValue(field: MutableFieldDefinition, key: string): unknown;
1065
+ /** @internal Set a string config value (removes key if empty). */
1066
+ protected setConfigValue(field: MutableFieldDefinition, key: string, value: string): void;
1067
+ /** @internal Set a numeric config value (removes key if empty/NaN). */
1068
+ protected setConfigNumber(field: MutableFieldDefinition, key: string, raw: string): void;
1069
+ /** @internal Set a boolean config value. */
1070
+ protected setConfigBoolean(field: MutableFieldDefinition, key: string, checked: boolean): void;
1071
+ /** @internal Normalize select options to SelectOption[] with empty option. */
1072
+ protected configSelectOptions(prop: ConfigPropertySchema): SelectOption[];
1073
+ /** @internal Open a richtext editor dialog for the given config key. */
1074
+ protected openRichTextEditor(field: MutableFieldDefinition, key: string): void;
1075
+ /** @internal Whether the field has config keys not covered by the schema. */
1076
+ protected hasExtraConfig(field: MutableFieldDefinition): boolean;
1077
+ /** @internal JSON string of config keys NOT in the structured schema. */
1078
+ protected extraConfigJSON(field: MutableFieldDefinition): string;
1079
+ /** @internal Parse and merge extra config JSON back into the field. */
1080
+ protected onExtraConfigChange(field: MutableFieldDefinition, event: Event): void;
1081
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UIPropertyInspector, never>;
1082
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<UIPropertyInspector, "ui-property-inspector", never, { "engine": { "alias": "engine"; "required": true; "isSignal": true; }; }, {}, never, never, true, [{ directive: typeof i1.UISurface; inputs: { "surfaceType": "surfaceType"; }; outputs: {}; }]>;
1083
+ }
1084
+
1085
+ /**
1086
+ * Full-featured form designer that lets users visually build
1087
+ * a {@link FormSchema} via a palette + canvas + inspector layout.
1088
+ *
1089
+ * Includes a live preview panel that renders the designed form
1090
+ * using {@link UIForm} and {@link FormEngine}.
1091
+ *
1092
+ * @example
1093
+ * ```html
1094
+ * <ui-form-designer
1095
+ * [schema]="existingSchema"
1096
+ * (schemaChange)="onSave($event)"
1097
+ * />
1098
+ * ```
1099
+ */
1100
+ declare class UIFormDesigner {
1101
+ /**
1102
+ * Optional initial schema to load into the designer.
1103
+ * When set, the designer engine imports it on init.
1104
+ */
1105
+ readonly schema: _angular_core.InputSignal<FormSchema | null>;
1106
+ /** Emitted when the user clicks "Export" — always emits the raw schema. */
1107
+ readonly schemaChange: _angular_core.OutputEmitterRef<FormSchema>;
1108
+ /** @internal Icon SVG for the copy button. */
1109
+ protected readonly copyIcon: "<rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\" /><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\" />";
1110
+ /** @internal Active tab: design, preview, or json. */
1111
+ protected readonly activeTab: _angular_core.WritableSignal<"json" | "design" | "preview">;
1112
+ /** @internal The designer engine instance. */
1113
+ protected readonly designerEngine: FormDesignerEngine;
1114
+ /**
1115
+ * @internal Preview engine — rebuilt whenever the schema changes.
1116
+ * Returns null if the schema has no groups/fields.
1117
+ */
1118
+ protected readonly previewEngine: _angular_core.Signal<FormEngine | null>;
1119
+ /** @internal Live output from the preview engine. */
1120
+ protected readonly previewOutput: _angular_core.Signal<FormValues | null>;
1121
+ /** @internal The group uid to add a field to when palette is clicked. */
1122
+ private lastGroupUid;
1123
+ constructor();
1124
+ /** @internal Handle palette field click — add to first or last-used group. */
1125
+ protected onFieldRequested(componentKey: string): void;
1126
+ /** @internal Handle "Add field" click within a specific group. */
1127
+ protected onAddFieldToGroup(groupUid: string): void;
1128
+ /** @internal Copy the current JSON schema to the clipboard. */
1129
+ protected onCopyJson(): void;
1130
+ /** @internal Show submitted values in a native dialog. */
1131
+ protected onPreviewSubmit(values: FormValues): void;
1132
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UIFormDesigner, never>;
1133
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<UIFormDesigner, "ui-form-designer", never, { "schema": { "alias": "schema"; "required": false; "isSignal": true; }; }, { "schemaChange": "schemaChange"; }, never, never, true, [{ directive: typeof i1.UISurface; inputs: { "surfaceType": "surfaceType"; }; outputs: {}; }]>;
1134
+ }
1135
+
1136
+ export { AngularComponentExportStrategy, BUILT_IN_FIELDS, FLAIR_COMPONENTS, FORM_FIELD_REGISTRATIONS, FormDesignerEngine, FormEngine, FormFieldRegistry, JsonExportStrategy, TEXT_ADAPTER_KEYS, UIDesignerCanvas, UIFieldPalette, UIForm, UIFormDesigner, UIFormField, UIFormGroup, UIFormWizard, UIPropertyInspector, evaluateCondition, isConditionGroup, isFlairComponent, provideBuiltInFormFields, provideFormFields, registerCustomValidator, resolveTextAdapter, validate };
1137
+ export type { Condition, ConditionGroup, ConditionOperator, ConfigTransform, DesignerSelection, DesignerSelectionKind, ExportResult, ExportStrategy, FieldCondition, FieldState, FlairComponent, FormFieldDefinition, FormFieldOption, FormFieldRegistration, FormGroupDefinition, FormSchema, FormValues, GroupState, MutableFieldDefinition, MutableGroupDefinition, PaletteFieldType, ValidationError, ValidationResult, ValidationRule, ValidationRuleType, ValidatorFn };
1138
+ //# sourceMappingURL=theredhead-lucid-forms.d.ts.map