ngx-t-forms-types 0.0.30 → 0.0.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/interfaces/Form/formSubmissionHandleInterface.d.ts +6 -0
  2. package/dist/interfaces/FormBuilder/DefaultEelement.js +76 -0
  3. package/dist/interfaces/FormBuilder/DefaultInputConfigInterface.d.ts +13 -0
  4. package/dist/interfaces/FormBuilder/FormInputKeys.d.ts +6 -0
  5. package/dist/interfaces/FormBuilder/FormInputKeys.js +6 -0
  6. package/dist/interfaces/FormBuilder/inputConfig/ElementEditConfig.js +188 -3
  7. package/dist/interfaces/Import/ImportIdentity.d.ts +32 -0
  8. package/dist/interfaces/Import/ImportIdentity.js +1 -0
  9. package/dist/interfaces/Import/ImportProgress.d.ts +12 -1
  10. package/dist/interfaces/Import/ImportRowState.d.ts +52 -1
  11. package/dist/interfaces/Import/index.d.ts +2 -1
  12. package/dist/interfaces/formInput/APIDataFetchingConfigurationInterface.d.ts +34 -0
  13. package/dist/interfaces/formInput/BasicFormInputInterface.d.ts +1 -0
  14. package/dist/interfaces/formInput/BasicFormInputInterface.js +1 -0
  15. package/dist/interfaces/formInput/IMscoaAccount.d.ts +19 -3
  16. package/dist/interfaces/formInput/ISelectInputInterface.d.ts +12 -0
  17. package/dist/interfaces/formInput/MultipleInterface.d.ts +10 -0
  18. package/dist/interfaces/formInput/WorkflowDocumentPicker.d.ts +2 -0
  19. package/dist/schemas/FormInputSchema.js +41 -2
  20. package/dist/schemas/MatOptionsSchema.js +7 -0
  21. package/dist/schemas/MscoaConfigSchema.js +1 -0
  22. package/dist/schemas/index.d.ts +2 -1
  23. package/dist/schemas/index.js +2 -1
  24. package/dist/skillet/authoring-rules.d.ts +41 -0
  25. package/dist/skillet/authoring-rules.js +61 -0
  26. package/dist/skillet/extra-members.d.ts +143 -0
  27. package/dist/skillet/extra-members.js +79 -0
  28. package/dist/skillet/form.d.ts +170 -0
  29. package/dist/skillet/form.js +139 -0
  30. package/dist/skillet/index.d.ts +43 -0
  31. package/dist/skillet/index.js +46 -0
  32. package/dist/skillet/input-members.d.ts +375 -0
  33. package/dist/skillet/input-members.js +186 -0
  34. package/dist/skillet/internal/coupling.d.ts +63 -0
  35. package/dist/skillet/internal/coupling.js +69 -0
  36. package/dist/skillet/internal/editor-guidance.d.ts +64 -0
  37. package/dist/skillet/internal/editor-guidance.js +291 -0
  38. package/dist/skillet/members/calculated-field.d.ts +155 -0
  39. package/dist/skillet/members/calculated-field.js +105 -0
  40. package/dist/skillet/members/conditional.d.ts +69 -0
  41. package/dist/skillet/members/conditional.js +16 -0
  42. package/dist/skillet/members/document-picker.d.ts +182 -0
  43. package/dist/skillet/members/document-picker.js +111 -0
  44. package/dist/skillet/members/mat-options.d.ts +187 -0
  45. package/dist/skillet/members/mat-options.js +92 -0
  46. package/dist/skillet/members/mscoa.d.ts +182 -0
  47. package/dist/skillet/members/mscoa.js +129 -0
  48. package/dist/skillet/members/pagination.d.ts +59 -0
  49. package/dist/skillet/members/pagination.js +16 -0
  50. package/dist/skillet/members/table.d.ts +178 -0
  51. package/dist/skillet/members/table.js +105 -0
  52. package/dist/skillet/members/validators.d.ts +197 -0
  53. package/dist/skillet/members/validators.js +74 -0
  54. package/dist/skillet/members/value.d.ts +154 -0
  55. package/dist/skillet/members/value.js +97 -0
  56. package/dist/skillet/shared-types.d.ts +57 -0
  57. package/dist/skillet/shared-types.js +69 -0
  58. package/dist/skillet/tests/house-rules.spec.d.ts +1 -0
  59. package/dist/skillet/tests/house-rules.spec.js +162 -0
  60. package/dist/skillet/tests/skillet-coupling.spec.d.ts +1 -0
  61. package/dist/skillet/tests/skillet-coupling.spec.js +191 -0
  62. package/dist/skillet/tests/variant-assembly.spec.d.ts +1 -0
  63. package/dist/skillet/tests/variant-assembly.spec.js +643 -0
  64. package/dist/skillet/variants.d.ts +138 -0
  65. package/dist/skillet/variants.js +536 -0
  66. package/dist/skillet/workflow-context.d.ts +95 -0
  67. package/dist/skillet/workflow-context.js +128 -0
  68. package/package.json +78 -60
@@ -199,6 +199,40 @@ export interface APIDataFetchingConfigurationInterface extends DataFetchingBaseC
199
199
  * interpreted — mirrors the other `captured*` seeds.
200
200
  */
201
201
  capturedDocs?: string;
202
+ /**
203
+ * Opts this value out of the automatic read-only lock, so a user may supply
204
+ * what the tower's own value leaves out.
205
+ *
206
+ * An input whose value the tower owns is rendered read-only by default — a
207
+ * typed-over value would only be overwritten on the derived signal's next
208
+ * evaluation. This flag lifts that lock, and what it then means depends on
209
+ * the SHAPE the input declares in its `dataType`:
210
+ *
211
+ * **Scalar** (`string`, `number`, `boolean`, `date`, …) — the editor's *Allow
212
+ * manual entry when the API returns nothing* toggle, offered only on an `api`
213
+ * value source. The manually entered value stands **whenever the fetch
214
+ * contributes nothing** — no response yet, a `null` / empty response, or a
215
+ * failed request. A non-empty response always wins. A scalar that is
216
+ * calculated (`calculatedFieldRules`) or inherited from another input
217
+ * (`source: 'local'`) is read-only unconditionally and ignores this flag,
218
+ * because its derived signal recomputes synchronously from inputs the user
219
+ * can already edit.
220
+ *
221
+ * **Complex** (`dataType: 'object' | 'array'` — mSCOA, MultipleInput) — the
222
+ * editor's *Allow the user to complete this value* toggle, offered on a
223
+ * `local` value source as well as an `api` one. A multi-dimensional value can
224
+ * arrive partially populated (an mSCOA that inherits two of its segments,
225
+ * rows that come back missing a column), so the field stays editable and the
226
+ * tower **re-merges** rather than replacing: every change in the derived value
227
+ * is applied over the live value as a delta — what the tower supplies updates,
228
+ * what the user added survives. The first value the tower produces is taken
229
+ * whole; there is no earlier value to diff it against.
230
+ *
231
+ * Absent / `false` ⇒ the historical behaviour: the field is locked.
232
+ *
233
+ * @defaultValue false
234
+ */
235
+ allowManualValueEntry?: boolean;
202
236
  backEndConfig: {
203
237
  /**
204
238
  * The default/mapTo mapping that shapes the POST body in `'mappedInputs'` mode.
@@ -24,6 +24,7 @@ export declare enum ElementTypes {
24
24
  IconSelect = "iconSelect",
25
25
  Textarea = "textarea",
26
26
  DatePicker = "datePicker",
27
+ DateTimePicker = "dateTimePicker",
27
28
  DateRangePicker = "dateRangePicker",
28
29
  FileUpload = "fileUpload",
29
30
  Signature = "signature",
@@ -8,6 +8,7 @@ export var ElementTypes;
8
8
  ElementTypes["IconSelect"] = "iconSelect";
9
9
  ElementTypes["Textarea"] = "textarea";
10
10
  ElementTypes["DatePicker"] = "datePicker";
11
+ ElementTypes["DateTimePicker"] = "dateTimePicker";
11
12
  ElementTypes["DateRangePicker"] = "dateRangePicker";
12
13
  ElementTypes["FileUpload"] = "fileUpload";
13
14
  ElementTypes["Signature"] = "signature";
@@ -133,9 +133,11 @@ export type DualCashExclusionMatchMode = 'any' | 'all';
133
133
  * one selected accrual account value in its segment scope.
134
134
  *
135
135
  * The pattern is tested against the account's `SCOAAccount` value AND the value
136
- * of the field named by {@link IScoaInputConfig.accountValueLabel} (what the
137
- * user sees selected in the chart). An invalid pattern never matches — it can
138
- * therefore never suppress the cash requirement by accident.
136
+ * of ONE labelled field: by default the field named by
137
+ * {@link IScoaInputConfig.accountValueLabel} (what the user sees selected in the
138
+ * chart), or — when the rule sets one — the field named by
139
+ * {@link IDualCashExclusionRule.matchField}. An invalid pattern never matches, so
140
+ * it can never suppress the cash requirement by accident.
139
141
  */
140
142
  export interface IDualCashExclusionRule {
141
143
  /** Stable record id (stamped by the builder's record-list editor). */
@@ -144,6 +146,20 @@ export interface IDualCashExclusionRule {
144
146
  pattern: string;
145
147
  /** Optional regex flags (e.g. `i`). Invalid flags make the rule evaluate as not matched. */
146
148
  flags?: string;
149
+ /**
150
+ * Optional per-rule override of WHICH labelled account field the pattern is
151
+ * tested against, named exactly as the account carries it — the same pool the
152
+ * `accountValueLabel` picker offers (e.g. `ShortDescription`).
153
+ *
154
+ * Empty or absent means the input's configured
155
+ * {@link IScoaInputConfig.accountValueLabel}, which is the default and leaves
156
+ * every rule saved before this member existed evaluating exactly as it did.
157
+ * The account's `SCOAAccount` value is always tested as well, whatever this
158
+ * holds — the override replaces the labelled field only. A field the selected
159
+ * account does not carry contributes no candidate, so such a rule falls back to
160
+ * testing `SCOAAccount` alone rather than matching everything.
161
+ */
162
+ matchField?: string;
147
163
  /**
148
164
  * Optional segment scope (matched case-insensitively against the accrual
149
165
  * segment key, e.g. `ITEM`). Empty/absent = every accrual segment.
@@ -4,9 +4,21 @@ import { IBasicFormInput, OptionSelectTypes } from "./BasicFormInputInterface.js
4
4
  export interface ISelectInputInterface extends IBasicFormInput {
5
5
  [AllFormInputPrimaryKeys.OptionSelectType]: OptionSelectTypes;
6
6
  [AllFormInputPrimaryKeys.AllowMultipleSelection]: boolean;
7
+ /**
8
+ * The most options a user may choose at once.
9
+ *
10
+ * Only meaningful alongside {@link ISelectInputInterface.allowMultipleSelection};
11
+ * a single-selection control is already capped at one. Declared on each
12
+ * multi-select interface rather than on `IBasicFormInput`, the same way
13
+ * `allowMultipleSelection` itself is, so a control that cannot select
14
+ * several things does not appear to offer a limit on how many.
15
+ */
16
+ selectUpto?: number;
7
17
  }
8
18
  export interface IPaginatedSelectionTableInputInterface extends IBasicFormInput {
9
19
  [AllFormInputPrimaryKeys.AllowMultipleSelection]: boolean;
20
+ /** @see ISelectInputInterface.selectUpto */
21
+ selectUpto?: number;
10
22
  [AllFormInputPrimaryKeys.PaginationSelectionConfig]: {
11
23
  useLocalPagination: boolean;
12
24
  primaryIdentifierKey?: TreeNode[];
@@ -15,6 +15,16 @@ export interface IMultiple extends IBasicFormInput {
15
15
  multipleInputAvailableOperations?: Array<MultipleInputAvailableOperations>;
16
16
  calculateListFunctions: Array<IMultipleInputCal>;
17
17
  groupBy?: string[];
18
+ /**
19
+ * The `formControlName`s of columns inside this group whose values are
20
+ * summed and shown as a total beneath the rows.
21
+ *
22
+ * Belongs here rather than on `IBasicFormInput` because a total only means
23
+ * something over a set of rows: each name must be a field declared in
24
+ * {@link IMultiple.formInputs}. The legacy `init-form` shape grouped it with
25
+ * `formInputs` and `groupBy` for the same reason.
26
+ */
27
+ showTotalsOf?: string[];
18
28
  }
19
29
  export interface IMultipleInputCal {
20
30
  id: string;
@@ -5,6 +5,8 @@ import { IBasicFormInput } from "./BasicFormInputInterface.js";
5
5
  export interface IWorkflowDocumentPicker extends IBasicFormInput {
6
6
  workflowPickerConfig: IWorkflowDocumentPickerConfig;
7
7
  [AllFormInputPrimaryKeys.AllowMultipleSelection]: boolean;
8
+ /** @see ISelectInputInterface.selectUpto */
9
+ selectUpto?: number;
8
10
  }
9
11
  /**
10
12
  * Document-picker configuration.
@@ -1,6 +1,6 @@
1
1
  import Joi from 'joi';
2
- import { AllFormInputPrimaryKeys, SpecialElementKeys } from '../interfaces/FormBuilder/index.js';
3
- import { AdjudicationSteps, AutocapitalizeOptions, ElementTypes, InputDataTypes, InputPipeTypes, InputTypes } from '../interfaces/formInput/index.js';
2
+ import { AllFormInputPrimaryKeys, FormInputKeys, SpecialElementKeys } from '../interfaces/FormBuilder/index.js';
3
+ import { AdjudicationSteps, AutocapitalizeOptions, AutocompleteOptions, ElementTypes, InputDataTypes, InputPipeTypes, InputTypes } from '../interfaces/formInput/index.js';
4
4
  // import { InputFileType } from '../interfaces/formInput/FileUploadInputInterface.js';
5
5
  // import { LabelPosition } from '../interfaces/formInput/ToggleInputInterface.js';
6
6
  // import { MscoaInputConfigSchema } from './MscoaConfigSchema.js';
@@ -49,6 +49,45 @@ export const baseFormColumnInputsSchema = Joi.object({
49
49
  [AllFormInputPrimaryKeys.Max]: Joi.alternatives().try(Joi.number(), Joi.string(), Joi.date()).optional(),
50
50
  [AllFormInputPrimaryKeys.MinLength]: Joi.alternatives().try(Joi.number(), Joi.string()).optional(),
51
51
  [AllFormInputPrimaryKeys.MaxLength]: Joi.alternatives().try(Joi.number(), Joi.string()).optional(),
52
+ [FormInputKeys.Pattern]: Joi.string().allow('').optional(),
53
+ // --- presentation members declared on IBasicFormInput ----------------------
54
+ //
55
+ // These were declared on the interfaces and listed in DefaultInputConfig, but
56
+ // never here — and because Joi rejects unknown keys, a column carrying one
57
+ // failed the WHOLE form with '"Slides > Columns > Placeholder" is not
58
+ // allowed'. Empty strings are allowed throughout: the settings panel writes
59
+ // '' when an author clears a text row, and rejecting that made clearing a
60
+ // prefix a validation error.
61
+ [FormInputKeys.Placeholder]: Joi.string().allow('').optional(),
62
+ [FormInputKeys.Autocomplete]: Joi.string().valid(...Object.values(AutocompleteOptions)).optional(),
63
+ [FormInputKeys.Disabled]: Joi.boolean().optional(),
64
+ [FormInputKeys.PrefixText]: Joi.string().allow('').optional(),
65
+ [FormInputKeys.SuffixText]: Joi.string().allow('').optional(),
66
+ [FormInputKeys.PrefixIcon]: Joi.string().allow('').optional(),
67
+ [FormInputKeys.SuffixIcon]: Joi.string().allow('').optional(),
68
+ // Only meaningful alongside allowMultipleSelection; a single-selection
69
+ // control is already capped at one. `min(1)` because "select up to zero" is
70
+ // not a limit, it is a disabled control.
71
+ [FormInputKeys.SelectUpto]: Joi.number().integer().min(1).optional(),
72
+ // formControlNames of columns inside a multipleInput group to total.
73
+ [FormInputKeys.ShowTotalsOf]: Joi.array().items(Joi.string()).optional(),
74
+ // --- matrix table ---------------------------------------------------------
75
+ //
76
+ // Declared by IMatrixInput and accepted here so a stored form carrying either
77
+ // still validates. No element offers them: ElementTypes.MatrixTable is
78
+ // commented out of the enum, so nothing can currently be built with one.
79
+ //
80
+ // `columnsConfig` is keyed by column name and typed
81
+ // `TableColumnConfigInterface | any`, so its values are only checked to be
82
+ // objects — constraining them further here would reject the `any` half the
83
+ // interface explicitly permits.
84
+ [FormInputKeys.MatrixTableConfig]: Joi.object({
85
+ dataSource: Joi.string().required()
86
+ }).optional(),
87
+ [FormInputKeys.TableConfig]: Joi.object({
88
+ displayedColumnsInOrder: Joi.array().items(Joi.string()).required(),
89
+ columnsConfig: Joi.object().pattern(Joi.string(), Joi.object()).required()
90
+ }).optional(),
52
91
  [AllFormInputPrimaryKeys.LinkedSegmentId]: Joi.string().optional(),
53
92
  [AllFormInputPrimaryKeys.MscoaConfig]: MscoaInputConfigSchema.optional(),
54
93
  [AllFormInputPrimaryKeys.SystemDefault]: Joi.boolean().optional(),
@@ -59,6 +59,13 @@ const APIDataFetchingConfigurationSchema = Joi.object({
59
59
  capturedQuery: queryTemplateSchema.optional(),
60
60
  // The endpoint's Postman description, verbatim; display-only (Docs tab).
61
61
  capturedDocs: Joi.string().allow('').optional(),
62
+ // Opt-out of the automatic read-only lock on a value the tower owns. On a
63
+ // SCALAR it is gap-filling on an 'api' slot: a manually entered value stands
64
+ // whenever the fetch contributes nothing. On a COMPLEX value (the input
65
+ // declares dataType 'object' or 'array') it is also offered on a 'local'
66
+ // slot, and the tower re-merges each new derived value over the live one as a
67
+ // delta instead of replacing it. Only meaningful on a value slot.
68
+ allowManualValueEntry: Joi.boolean().optional(),
62
69
  backEndConfig: Joi.object({
63
70
  // Optional: a 'template'-mode fetch shapes its body from payloadTemplate and
64
71
  // carries no mapping; GET fetches never had one. Readers default it to [].
@@ -16,6 +16,7 @@ export const DualCashExclusionRuleSchema = Joi.object({
16
16
  id: Joi.string().optional(),
17
17
  pattern: Joi.string().required(),
18
18
  flags: Joi.string().allow('').optional(),
19
+ matchField: Joi.string().allow('').optional(),
19
20
  segment: Joi.string().allow('').optional(),
20
21
  description: Joi.string().allow('').optional()
21
22
  });
@@ -1,4 +1,5 @@
1
1
  import { validateCalculatedFieldRules } from "./CalculatedFieldRulesSchema.js";
2
2
  import { formColumnInputsSchema, validateFormColumnInputs, validateFormColumnInputsWithRequired } from "./FormInputSchema.js";
3
3
  import { DatabaseFormSchema, FormSchema, validateApiDataFetchingConfiguration, validateForm, validateFormSlide } from "./FormSchema.js";
4
- export { FormSchema, DatabaseFormSchema, formColumnInputsSchema, validateCalculatedFieldRules, validateFormColumnInputs, validateFormSlide, validateFormColumnInputsWithRequired, validateForm, validateApiDataFetchingConfiguration };
4
+ import { MscoaInputConfigSchema, validateMscoaInputConfig } from "./MscoaConfigSchema.js";
5
+ export { FormSchema, DatabaseFormSchema, formColumnInputsSchema, validateCalculatedFieldRules, validateFormColumnInputs, validateFormSlide, validateFormColumnInputsWithRequired, validateForm, validateApiDataFetchingConfiguration, MscoaInputConfigSchema, validateMscoaInputConfig };
@@ -1,4 +1,5 @@
1
1
  import { validateCalculatedFieldRules } from "./CalculatedFieldRulesSchema.js";
2
2
  import { formColumnInputsSchema, validateFormColumnInputs, validateFormColumnInputsWithRequired } from "./FormInputSchema.js";
3
3
  import { DatabaseFormSchema, FormSchema, validateApiDataFetchingConfiguration, validateForm, validateFormSlide } from "./FormSchema.js";
4
- export { FormSchema, DatabaseFormSchema, formColumnInputsSchema, validateCalculatedFieldRules, validateFormColumnInputs, validateFormSlide, validateFormColumnInputsWithRequired, validateForm, validateApiDataFetchingConfiguration };
4
+ import { MscoaInputConfigSchema, validateMscoaInputConfig } from "./MscoaConfigSchema.js";
5
+ export { FormSchema, DatabaseFormSchema, formColumnInputsSchema, validateCalculatedFieldRules, validateFormColumnInputs, validateFormSlide, validateFormColumnInputsWithRequired, validateForm, validateApiDataFetchingConfiguration, MscoaInputConfigSchema, validateMscoaInputConfig };
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Form-wide authoring rules from the Form Creation Guide, stated once.
3
+ *
4
+ * ## Why these are not on the members they concern
5
+ *
6
+ * Hashbrown names every hoisted `$defs` entry by camel-casing the node's
7
+ * DESCRIPTION, and every `$ref` repeats that name in full. A member shared by
8
+ * every element — `label`, `formControlName`, `colSize` — is referenced once
9
+ * per element per nesting level, so each character of its description is paid
10
+ * around forty times in the full column schema. Measured before this split,
11
+ * `$ref` names were 58% of the full schema and 44% of the common one, and the
12
+ * seven most-shared members accounted for most of that.
13
+ *
14
+ * So a shared member's description carries its definition and the one rule
15
+ * that has to be read at that member, and the guidance that applies across the
16
+ * form is stated here, on the root, which is emitted exactly once. The
17
+ * sentences are the guide's — see `doc/features/skillet-internals.md`, "Where
18
+ * the prose comes from" — and they are the ones a model needs before it writes
19
+ * any field rather than while it writes one.
20
+ *
21
+ * `createFormDraftSchema()` composes these into the form's description. A
22
+ * caller using `createColumnSchema()` on its own has no root to carry them and
23
+ * should put {@link describeAuthoringRules} in the system prompt instead.
24
+ */
25
+ /**
26
+ * The shape of a control name: lowerCamelCase, letters and digits only.
27
+ *
28
+ * Narrower than the engine, which also allows underscores — narrower is the
29
+ * permitted direction, and one convention is easier to follow than two.
30
+ * Exported so a test can hold the reserved-names rule to it: a reserved name
31
+ * the pattern would accept must be named in the rules, and one it rejects
32
+ * need not be.
33
+ */
34
+ export declare const CONTROL_NAME_PATTERN = "^[a-z][a-zA-Z0-9]*$";
35
+ /**
36
+ * The rules, one sentence group each, in the order the guide states them:
37
+ * naming, words, types, what the engine reads, layout, error timing.
38
+ */
39
+ export declare const AUTHORING_RULES: readonly string[];
40
+ /** The rules as one paragraph, for a form description or a system prompt. */
41
+ export declare function describeAuthoringRules(): string;
@@ -0,0 +1,61 @@
1
+ import { RESERVED_CONTROL_NAMES } from './workflow-context.js';
2
+ /**
3
+ * Form-wide authoring rules from the Form Creation Guide, stated once.
4
+ *
5
+ * ## Why these are not on the members they concern
6
+ *
7
+ * Hashbrown names every hoisted `$defs` entry by camel-casing the node's
8
+ * DESCRIPTION, and every `$ref` repeats that name in full. A member shared by
9
+ * every element — `label`, `formControlName`, `colSize` — is referenced once
10
+ * per element per nesting level, so each character of its description is paid
11
+ * around forty times in the full column schema. Measured before this split,
12
+ * `$ref` names were 58% of the full schema and 44% of the common one, and the
13
+ * seven most-shared members accounted for most of that.
14
+ *
15
+ * So a shared member's description carries its definition and the one rule
16
+ * that has to be read at that member, and the guidance that applies across the
17
+ * form is stated here, on the root, which is emitted exactly once. The
18
+ * sentences are the guide's — see `doc/features/skillet-internals.md`, "Where
19
+ * the prose comes from" — and they are the ones a model needs before it writes
20
+ * any field rather than while it writes one.
21
+ *
22
+ * `createFormDraftSchema()` composes these into the form's description. A
23
+ * caller using `createColumnSchema()` on its own has no root to carry them and
24
+ * should put {@link describeAuthoringRules} in the system prompt instead.
25
+ */
26
+ /**
27
+ * The shape of a control name: lowerCamelCase, letters and digits only.
28
+ *
29
+ * Narrower than the engine, which also allows underscores — narrower is the
30
+ * permitted direction, and one convention is easier to follow than two.
31
+ * Exported so a test can hold the reserved-names rule to it: a reserved name
32
+ * the pattern would accept must be named in the rules, and one it rejects
33
+ * need not be.
34
+ */
35
+ export const CONTROL_NAME_PATTERN = '^[a-z][a-zA-Z0-9]*$';
36
+ /**
37
+ * The reserved names the pattern alone does not stop.
38
+ *
39
+ * `_id` and the `SYSTEM_*` inputs fail the pattern and need no mention;
40
+ * `reference`, `status` and `data` pass it, so the rule has to carry them.
41
+ * Filtered at evaluation rather than listed by hand, so the sentence says
42
+ * exactly what the pattern leaves open — no more, which would be noise, and no
43
+ * less, which would be a hole.
44
+ */
45
+ const RESERVED_WELL_FORMED_NAMES = RESERVED_CONTROL_NAMES.filter((name) => new RegExp(CONTROL_NAME_PATTERN).test(name));
46
+ /**
47
+ * The rules, one sentence group each, in the order the guide states them:
48
+ * naming, words, types, what the engine reads, layout, error timing.
49
+ */
50
+ export const AUTHORING_RULES = [
51
+ `Control names are unique across the whole form and across every other form of the same workflow unless the same answer is deliberately carried forward, never change once the form is live, and are never one of the names the transaction document already owns: ${RESERVED_WELL_FORMED_NAMES.join(', ')}.`,
52
+ "A label never explains — that is the hint's job. Required fields are marked automatically, so add '(optional)' to the label of a field that is not required. A hint gives the format ('As it appears on your ID document, 13 digits'), the source ('Top right of the invoice, starts with INV') or the reason for asking something sensitive ('Used only to send delivery updates by SMS'); every field that could be misunderstood gets one.",
53
+ 'Set type and dataType to the data. A number is never left as text: the engine compares strictly, so a number stored as text never equals a number. A phone number is type tel with dataType string.',
54
+ 'A review decision toggle, a date the engine schedules on and any value a decision gate reads are always required and never conditionally hidden.',
55
+ 'Related short values share one row (start and end as 6 and 6; quantity, unit price and line total as 4, 4 and 4); a textarea, an item list, a picker, an uploader or a signature never shares a row; the same kind of field keeps the same width all the way down a slide.',
56
+ 'Errors are shown only after the user has left a field, so onlySetTempErrorOnTouch is true on nearly every field.',
57
+ ];
58
+ /** The rules as one paragraph, for a form description or a system prompt. */
59
+ export function describeAuthoringRules() {
60
+ return AUTHORING_RULES.join(' ');
61
+ }
@@ -0,0 +1,143 @@
1
+ import { s } from '@hashbrownai/core';
2
+ import type { FormColumnInputs } from '../interfaces/Form/index.js';
3
+ import { FormInputKeys, SpecialElementKeys } from '../interfaces/FormBuilder/FormInputKeys.js';
4
+ import { AssertNever } from './internal/coupling.js';
5
+ import { type TableConfigDraft } from './members/table.js';
6
+ /**
7
+ * The members an element can carry that `AllFormInputPrimaryKeys` does not
8
+ * declare.
9
+ *
10
+ * `DefaultInputConfig[element].properties` is typed
11
+ * `Array<FormInputKeys | SpecialElementKeys | AllFormInputPrimaryKeys>`, and it
12
+ * uses all three. Keying the main registry on `AllFormInputPrimaryKeys` alone
13
+ * left fourteen keys unresolvable at assembly time, including `pattern` and
14
+ * `placeholder` — properties too ordinary for a form generator to do without.
15
+ *
16
+ * ## `properties` is not a property list
17
+ *
18
+ * It is the list of ROWS the settings panel shows for that element, which is a
19
+ * superset of what the input stores. `matOptionsApiCall` and
20
+ * `showAllMcoaSegments` open editors; they are not keys on a form input and no
21
+ * interface declares them. Those are recorded in {@link EDITOR_ONLY_KEYS} and
22
+ * skipped during assembly — absent by intent, not by oversight.
23
+ *
24
+ * Enum membership does not decide this, which is worth stating because it looks
25
+ * like it should: `multipleInputAvailableOperations` sits in
26
+ * `SpecialElementKeys` beside the editor directives, yet `IMultiple` really
27
+ * does declare it. The test that settles it is whether an interface declares
28
+ * the key, so that is the test used.
29
+ */
30
+ /** The type an extra member must produce, read off the real interface. */
31
+ type MemberValue<K extends string> = K extends keyof FormColumnInputs ? NonNullable<FormColumnInputs[K]> : unknown;
32
+ /**
33
+ * Keys that open an editor rather than store a value. They appear in
34
+ * `properties` and must never appear in a generation schema.
35
+ */
36
+ export declare const EDITOR_ONLY_KEYS: readonly [SpecialElementKeys.FormValueFromInputSelector, SpecialElementKeys.FormInputSelector, SpecialElementKeys.MatOptionsApiCall, SpecialElementKeys.MatOptionsRequiredInputs, SpecialElementKeys.MatOptionsApiValueAccessRules, SpecialElementKeys.DefaultCalculatedFieldRules, SpecialElementKeys.MatOptionsItemType, SpecialElementKeys.MatOptionsSelectionOptions, SpecialElementKeys.DefaultValuePipe, SpecialElementKeys.DefaultCurrencySelect, SpecialElementKeys.DefaultDecimalNumberInput, SpecialElementKeys.Default, SpecialElementKeys.ShowAllMcoaSegments];
37
+ /**
38
+ * Extra members still to be modelled.
39
+ *
40
+ * The four date bounds are all typed `Date`. A model emits JSON, so the best it
41
+ * can produce is an ISO string, which is not assignable to `Date` — they need
42
+ * the same draft-and-expand treatment as `matOptions` rather than a quiet
43
+ * mistyping. `tableConfig` and `matrixTableConfig` are nested configuration
44
+ * objects awaiting their own modules.
45
+ */
46
+ export declare const PENDING_EXTRA_MEMBERS: readonly [FormInputKeys.StartMinDate, FormInputKeys.StartMaxDate, FormInputKeys.EndMinDate, FormInputKeys.EndMaxDate];
47
+ /**
48
+ * Extra members whose schema produces an AUTHORING DRAFT rather than the stored
49
+ * shape — the same category `DRAFT_INPUT_MEMBERS` defines in
50
+ * `input-members.ts`, for keys that live in the other two enums.
51
+ *
52
+ * `tableConfig` is the only one. Its `columnsConfig` is keyed by column name —
53
+ * an index signature, which Skillet has no node for — so the model emits an
54
+ * ARRAY of columns each carrying its own key, and the application folds that
55
+ * into the record. See `members/table.ts`.
56
+ */
57
+ export declare const DRAFT_EXTRA_MEMBERS: readonly [FormInputKeys.TableConfig];
58
+ /** The draft each drafted extra member is held to. */
59
+ interface ExtraMemberDrafts {
60
+ [FormInputKeys.TableConfig]: TableConfigDraft;
61
+ }
62
+ export declare const extraDraftMemberSchemas: {
63
+ tableConfig: s.ObjectType<{
64
+ displayedColumnsInOrder: s.ArrayType<s.StringType>;
65
+ columns: s.ArrayType<s.ObjectType<{
66
+ key: s.StringType;
67
+ type: s.EnumType<["caluculated", "property", "checkBox", "primaryKey"]>;
68
+ property: s.StringType;
69
+ label: s.StringType;
70
+ inEdit: s.BooleanType;
71
+ checkUpto: s.StringType;
72
+ calculatedFieldRules: s.ObjectType<{
73
+ formula: s.StringType;
74
+ variables: s.ArrayType<import("@hashbrownai/core/src/schema/base").SchemaForUnion<{
75
+ bindingType: "field";
76
+ variable: string;
77
+ label: string;
78
+ formControlName: string;
79
+ } | {
80
+ bindingType: "listAggregate";
81
+ variable: string;
82
+ label: string;
83
+ formControlName: string;
84
+ parentInputFormControl: string;
85
+ function: import("..").CalculationFunctions;
86
+ applyFunctionToCol: string;
87
+ applyFunctionToLabel: string | null;
88
+ filterValuesByCol: string | null;
89
+ filterValuesByThisColLabel: string | null;
90
+ tableCell: boolean | null;
91
+ }>>;
92
+ decimalPlaces: import("@hashbrownai/core/src/schema/base").SchemaForUnion<number | null>;
93
+ roundingMode: import("@hashbrownai/core/src/schema/base").SchemaForUnion<"FLOOR" | "CEIL" | "ROUND" | null>;
94
+ getFormulaFromAFormInput: import("@hashbrownai/core/src/schema/base").SchemaForUnion<boolean | null>;
95
+ formControlWithFormula: import("@hashbrownai/core/src/schema/base").SchemaForUnion<string | null>;
96
+ }>;
97
+ reductionFunction: import("@hashbrownai/core/src/schema/base").SchemaForUnion<"sum" | null>;
98
+ colorScale: import("@hashbrownai/core/src/schema/base").SchemaForUnion<string | null>;
99
+ }>>;
100
+ }>;
101
+ };
102
+ export declare const extraInputMemberSchemas: {
103
+ pattern: s.StringType;
104
+ placeholder: s.StringType;
105
+ autocomplete: s.EnumType<import("..").AutocompleteOptions[]>;
106
+ disabled: s.BooleanType;
107
+ prefixText: s.StringType;
108
+ suffixText: s.StringType;
109
+ prefixIcon: s.StringType;
110
+ suffixIcon: s.StringType;
111
+ selectUpto: s.IntegerType;
112
+ showTotalsOf: s.ArrayType<s.StringType>;
113
+ multipleInputAvailableOperations: s.ArrayType<s.EnumType<import("..").MultipleInputAvailableOperations[]>>;
114
+ matrixTableConfig: s.ObjectType<{
115
+ dataSource: s.StringType;
116
+ }>;
117
+ };
118
+ export type ExtraMemberKey = keyof typeof extraInputMemberSchemas;
119
+ type EditorOnlyKey = (typeof EDITOR_ONLY_KEYS)[number];
120
+ type PendingExtraKey = (typeof PENDING_EXTRA_MEMBERS)[number];
121
+ type DraftExtraKey = (typeof DRAFT_EXTRA_MEMBERS)[number];
122
+ /**
123
+ * Every `FormInputKeys` and `SpecialElementKeys` member is accounted for —
124
+ * modelled, deferred, declared editor-only, or already covered by the primary
125
+ * registry because both enums spell the same key.
126
+ */
127
+ export type _EveryExtraKeyClassified = AssertNever<Exclude<FormInputKeys | SpecialElementKeys, ExtraMemberKey | EditorOnlyKey | PendingExtraKey | DraftExtraKey | FormInputKeys.Accept | FormInputKeys.ConditionalInputConfig | FormInputKeys.GroupBy>>;
128
+ /** Every extra node produces a value its interface member can hold. */
129
+ export type _NoExtraValueDrift = AssertNever<{
130
+ [K in ExtraMemberKey]: [
131
+ s.Infer<(typeof extraInputMemberSchemas)[K]>
132
+ ] extends [MemberValue<K>] ? never : K;
133
+ }[ExtraMemberKey]>;
134
+ /** Every drafted extra node produces the draft it declares. */
135
+ export type _NoExtraDraftDrift = AssertNever<{
136
+ [K in DraftExtraKey]: [
137
+ s.Infer<(typeof extraDraftMemberSchemas)[K]>
138
+ ] extends [ExtraMemberDrafts[K]] ? never : K;
139
+ }[DraftExtraKey]>;
140
+ /** Runtime key lists, derived from the enums. */
141
+ export declare const ALL_FORM_INPUT_KEYS: FormInputKeys[];
142
+ export declare const ALL_SPECIAL_ELEMENT_KEYS: SpecialElementKeys[];
143
+ export {};
@@ -0,0 +1,79 @@
1
+ import { s } from '@hashbrownai/core';
2
+ import { FormInputKeys, SpecialElementKeys, } from '../interfaces/FormBuilder/FormInputKeys.js';
3
+ import { enumValues } from './internal/coupling.js';
4
+ import { describe } from './internal/editor-guidance.js';
5
+ import { autocompleteSchema, multipleInputOperationSchema } from './shared-types.js';
6
+ import { matrixTableConfigSchema, tableConfigSchema, } from './members/table.js';
7
+ /**
8
+ * Keys that open an editor rather than store a value. They appear in
9
+ * `properties` and must never appear in a generation schema.
10
+ */
11
+ export const EDITOR_ONLY_KEYS = [
12
+ SpecialElementKeys.FormValueFromInputSelector,
13
+ SpecialElementKeys.FormInputSelector,
14
+ SpecialElementKeys.MatOptionsApiCall,
15
+ SpecialElementKeys.MatOptionsRequiredInputs,
16
+ SpecialElementKeys.MatOptionsApiValueAccessRules,
17
+ SpecialElementKeys.DefaultCalculatedFieldRules,
18
+ SpecialElementKeys.MatOptionsItemType,
19
+ SpecialElementKeys.MatOptionsSelectionOptions,
20
+ SpecialElementKeys.DefaultValuePipe,
21
+ SpecialElementKeys.DefaultCurrencySelect,
22
+ SpecialElementKeys.DefaultDecimalNumberInput,
23
+ SpecialElementKeys.Default,
24
+ SpecialElementKeys.ShowAllMcoaSegments,
25
+ ];
26
+ /**
27
+ * Extra members still to be modelled.
28
+ *
29
+ * The four date bounds are all typed `Date`. A model emits JSON, so the best it
30
+ * can produce is an ISO string, which is not assignable to `Date` — they need
31
+ * the same draft-and-expand treatment as `matOptions` rather than a quiet
32
+ * mistyping. `tableConfig` and `matrixTableConfig` are nested configuration
33
+ * objects awaiting their own modules.
34
+ */
35
+ export const PENDING_EXTRA_MEMBERS = [
36
+ FormInputKeys.StartMinDate,
37
+ FormInputKeys.StartMaxDate,
38
+ FormInputKeys.EndMinDate,
39
+ FormInputKeys.EndMaxDate,
40
+ ];
41
+ /**
42
+ * Extra members whose schema produces an AUTHORING DRAFT rather than the stored
43
+ * shape — the same category `DRAFT_INPUT_MEMBERS` defines in
44
+ * `input-members.ts`, for keys that live in the other two enums.
45
+ *
46
+ * `tableConfig` is the only one. Its `columnsConfig` is keyed by column name —
47
+ * an index signature, which Skillet has no node for — so the model emits an
48
+ * ARRAY of columns each carrying its own key, and the application folds that
49
+ * into the record. See `members/table.ts`.
50
+ */
51
+ export const DRAFT_EXTRA_MEMBERS = [FormInputKeys.TableConfig];
52
+ export const extraDraftMemberSchemas = {
53
+ [FormInputKeys.TableConfig]: tableConfigSchema,
54
+ };
55
+ export const extraInputMemberSchemas = {
56
+ [FormInputKeys.Pattern]: s.string(describe("A regular expression the typed value must match, as a JavaScript pattern without delimiters. Only for a code with a fixed shape that nothing looks up, such as an ID number or an order reference; never on a lookup key such as a supplier number, where the endpoint's error is the check.", FormInputKeys.Pattern)),
57
+ // Each authored sentence below is the DEFINITION only. The advice that goes
58
+ // with it — give an example, turn autofill off for one-time values, when a
59
+ // selection cap applies at all — is written once, on the editor row, and
60
+ // composed in by `describe()`. Saying it in both places produced descriptions
61
+ // that made the same point twice in slightly different words.
62
+ [FormInputKeys.Placeholder]: s.string(describe('Ghost text shown inside the field while it is empty. Prefer none: it disappears as the user types and screen readers may skip it, so anything that matters belongs in the hint.', FormInputKeys.Placeholder)),
63
+ [FormInputKeys.Autocomplete]: autocompleteSchema,
64
+ [FormInputKeys.Disabled]: s.boolean(describe('Whether the control is rendered but cannot be interacted with.', FormInputKeys.Disabled)),
65
+ [FormInputKeys.PrefixText]: s.string(describe('Short static text shown before the field, for example a currency symbol. It stops the user typing the unit into the box.', FormInputKeys.PrefixText)),
66
+ [FormInputKeys.SuffixText]: s.string(describe('Short static text shown after the field, for example a unit such as kg or %. It stops the user typing the unit into the box.', FormInputKeys.SuffixText)),
67
+ [FormInputKeys.PrefixIcon]: s.string(describe('Name of the Material icon shown before the field.', FormInputKeys.PrefixIcon)),
68
+ [FormInputKeys.SuffixIcon]: s.string(describe('Name of the Material icon shown after the field.', FormInputKeys.SuffixIcon)),
69
+ // The applicability rule is the valuable half here: the editor row declares
70
+ // `allowMultipleSelection === true`, and Skillet cannot express that
71
+ // structurally, so it arrives as the sentence a model actually needs.
72
+ [FormInputKeys.SelectUpto]: s.integer(describe('The most options the user may choose at once.', FormInputKeys.SelectUpto), { minimum: 1 }),
73
+ [FormInputKeys.ShowTotalsOf]: s.array(describe("The formControlNames of columns inside this list whose values are summed and shown as a total. For the user's eyes only: a total used anywhere else must also be a calculated field on the form itself.", FormInputKeys.ShowTotalsOf), s.string('A formControlName inside this list to total.')),
74
+ [SpecialElementKeys.MultipleInputAvailableOperations]: s.array(describe("Which operations the user may perform on the rows of this repeatable group: usually 'add', 'remove' and 'update'; add 'lockEditOnFormSubmit' when rows must not change once submitted.", SpecialElementKeys.MultipleInputAvailableOperations), multipleInputOperationSchema),
75
+ [FormInputKeys.MatrixTableConfig]: matrixTableConfigSchema,
76
+ };
77
+ /** Runtime key lists, derived from the enums. */
78
+ export const ALL_FORM_INPUT_KEYS = enumValues(FormInputKeys);
79
+ export const ALL_SPECIAL_ELEMENT_KEYS = enumValues(SpecialElementKeys);