@marktiderman/genesis-forms 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -1
- package/dist/destinations.cjs +210 -33
- package/dist/destinations.cjs.map +1 -1
- package/dist/destinations.js +210 -33
- package/dist/destinations.js.map +1 -1
- package/dist/{engine-CPLtKVew.d.cts → engine-BkNuzlna.d.cts} +2 -1
- package/dist/{engine-DOrPgFDw.d.ts → engine-Dz9J5ej2.d.ts} +2 -1
- package/dist/index.cjs +758 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +195 -4
- package/dist/index.d.ts +195 -4
- package/dist/index.js +739 -24
- package/dist/index.js.map +1 -1
- package/dist/server.cjs +672 -19
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +5 -1
- package/dist/server.d.ts +5 -1
- package/dist/server.js +672 -19
- package/dist/server.js.map +1 -1
- package/dist/testing.cjs +674 -19
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +2 -2
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +674 -19
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { a as FieldBlock, C as ContentBlock, P as PageBreakBlock, F as FormDefinition, H as HiddenInput, b as FormLayout, L as LogicRule, E as Ending, c as FormSettings, J as Json, d as Condition, B as Block, O as Operator } from './types-BBKBQ8sp.cjs';
|
|
2
2
|
export { e as FormEvent, f as Operand } from './types-BBKBQ8sp.cjs';
|
|
3
|
-
import { F as FormEngine } from './engine-
|
|
4
|
-
export { C as CreateFormOptions, a as FormState, c as createForm, i as isFormEvent, b as isJson, r as replay } from './engine-
|
|
3
|
+
import { F as FormEngine } from './engine-BkNuzlna.cjs';
|
|
4
|
+
export { C as CreateFormOptions, a as FormState, c as createForm, i as isFormEvent, b as isJson, r as replay } from './engine-BkNuzlna.cjs';
|
|
5
5
|
import { F as FieldValidator } from './validate-BXXqi0fq.cjs';
|
|
6
6
|
export { R as REQUIRED_MESSAGE, S as StandardSchemaV1, v as validateField } from './validate-BXXqi0fq.cjs';
|
|
7
7
|
|
|
@@ -44,13 +44,45 @@ declare const f: {
|
|
|
44
44
|
}) => FieldSpec<K, string>;
|
|
45
45
|
email: <K extends string>(key: K, o: FieldOptions) => FieldSpec<K, string>;
|
|
46
46
|
phone: <K extends string>(key: K, o: FieldOptions) => FieldSpec<K, string>;
|
|
47
|
+
/**
|
|
48
|
+
* A 1-to-`max` scale. `lowLabel` and `highLabel` are optional words under
|
|
49
|
+
* its ends ("Poor", "Great"); `display: "stars"` draws stars instead of numbers.
|
|
50
|
+
*/
|
|
47
51
|
rating: <K extends string>(key: K, o: FieldOptions & {
|
|
48
52
|
max?: number | undefined;
|
|
53
|
+
lowLabel?: string | undefined;
|
|
54
|
+
highLabel?: string | undefined;
|
|
55
|
+
display?: "numbers" | "stars" | undefined;
|
|
56
|
+
}) => FieldSpec<K, number>;
|
|
57
|
+
/** A 0-to-10 Net Promoter Score. The end labels default to "Not likely" and "Very likely" in the renderer. */
|
|
58
|
+
nps: <K extends string>(key: K, o: FieldOptions & {
|
|
59
|
+
lowLabel?: string | undefined;
|
|
60
|
+
highLabel?: string | undefined;
|
|
49
61
|
}) => FieldSpec<K, number>;
|
|
50
|
-
nps: <K extends string>(key: K, o: FieldOptions) => FieldSpec<K, number>;
|
|
51
62
|
singleChoice: <K extends string, O extends string>(key: K, o: ChoiceFieldOptions<O>) => FieldSpec<K, O>;
|
|
52
63
|
multiChoice: <K extends string, O extends string>(key: K, o: ChoiceFieldOptions<O>) => FieldSpec<K, O[]>;
|
|
53
64
|
yesNo: <K extends string>(key: K, o: FieldOptions) => FieldSpec<K, boolean>;
|
|
65
|
+
/** One option from a compact menu: for a long list (a country, a class), where single choice would be a wall of buttons. */
|
|
66
|
+
dropdown: <K extends string, O extends string>(key: K, o: ChoiceFieldOptions<O>) => FieldSpec<K, O>;
|
|
67
|
+
/** A number, optionally between `min` and `max` and on a `step` (from `min`, else 0): `step: 1` for whole numbers. */
|
|
68
|
+
number: <K extends string>(key: K, o: FieldOptions & {
|
|
69
|
+
min?: number | undefined;
|
|
70
|
+
max?: number | undefined;
|
|
71
|
+
step?: number | undefined;
|
|
72
|
+
}) => FieldSpec<K, number>;
|
|
73
|
+
/** A calendar day, stored as `YYYY-MM-DD`, optionally between `min` and `max` (also `YYYY-MM-DD`). */
|
|
74
|
+
date: <K extends string>(key: K, o: FieldOptions & {
|
|
75
|
+
min?: string | undefined;
|
|
76
|
+
max?: string | undefined;
|
|
77
|
+
}) => FieldSpec<K, string>;
|
|
78
|
+
/**
|
|
79
|
+
* A single checkbox to agree to something. `text` is the checkbox's own
|
|
80
|
+
* words ("I agree to the terms"); the renderer defaults to "I agree".
|
|
81
|
+
* Checked stores `true`; unchecked is unanswered, so `required` means it must be checked.
|
|
82
|
+
*/
|
|
83
|
+
consent: <K extends string>(key: K, o: FieldOptions & {
|
|
84
|
+
text?: string | undefined;
|
|
85
|
+
}) => FieldSpec<K, true>;
|
|
54
86
|
/** Several short answers, one per line: goals, action items, three things that went well. */
|
|
55
87
|
list: <K extends string>(key: K, o: FieldOptions & {
|
|
56
88
|
min?: number | undefined;
|
|
@@ -58,6 +90,16 @@ declare const f: {
|
|
|
58
90
|
itemMaxLength?: number | undefined;
|
|
59
91
|
itemPlaceholder?: string | undefined;
|
|
60
92
|
}) => FieldSpec<K, string[]>;
|
|
93
|
+
/**
|
|
94
|
+
* A value worked out from other answers and shown read-only, such as a
|
|
95
|
+
* total or a score: `formula` names answers by key (`hours * rate`,
|
|
96
|
+
* `sum(plan.cost)`). Stored with the answers; never required.
|
|
97
|
+
*/
|
|
98
|
+
calculated: <K extends string>(key: K, o: Omit<FieldOptions, "required" | "placeholder"> & {
|
|
99
|
+
formula: string;
|
|
100
|
+
format?: "number" | "percent" | "text" | undefined;
|
|
101
|
+
decimals?: number | undefined;
|
|
102
|
+
}) => FieldSpec<K, string | number | boolean>;
|
|
61
103
|
/**
|
|
62
104
|
* A small table each answer fills row by row, one answer per column: an
|
|
63
105
|
* action plan (What / Who / By when), pros and cons.
|
|
@@ -341,6 +383,26 @@ interface ChoiceOption {
|
|
|
341
383
|
label?: string;
|
|
342
384
|
}
|
|
343
385
|
declare function choiceOptions(field: FieldBlock): ChoiceOption[];
|
|
386
|
+
/** The optional words under the ends of a rating or NPS scale ("Poor", "Great"). */
|
|
387
|
+
declare function scaleLabels(field: FieldBlock): {
|
|
388
|
+
low?: string;
|
|
389
|
+
high?: string;
|
|
390
|
+
};
|
|
391
|
+
/** How a rating is drawn: `"numbers"` (default) or `"stars"`. */
|
|
392
|
+
declare function ratingDisplay(field: FieldBlock): "numbers" | "stars";
|
|
393
|
+
/** A `number` field's limits: `min`, `max` and `step` (each optional; `step` is above 0). */
|
|
394
|
+
declare function numberLimits(field: FieldBlock): {
|
|
395
|
+
min?: number;
|
|
396
|
+
max?: number;
|
|
397
|
+
step?: number;
|
|
398
|
+
};
|
|
399
|
+
/** `YYYY-MM-DD`, a real calendar day (no 2026-02-30), years 0001 to 9999. */
|
|
400
|
+
declare function isIsoDate(value: string): boolean;
|
|
401
|
+
/** A `date` field's earliest and latest days (`YYYY-MM-DD`), when set. */
|
|
402
|
+
declare function dateLimits(field: FieldBlock): {
|
|
403
|
+
min?: string;
|
|
404
|
+
max?: string;
|
|
405
|
+
};
|
|
344
406
|
|
|
345
407
|
declare function listLimits(field: FieldBlock): {
|
|
346
408
|
min: number;
|
|
@@ -393,6 +455,135 @@ declare const HIGHLIGHT_NOTE_MESSAGE = "Add a note to each highlight.";
|
|
|
393
455
|
*/
|
|
394
456
|
declare const STRUCTURED_FIELD_TYPES: readonly ["list", "table", "media-notes", "text-highlights"];
|
|
395
457
|
|
|
458
|
+
/**
|
|
459
|
+
* A small, safe formula language for `calculated` fields. It is parsed and
|
|
460
|
+
* evaluated here, never with `eval` or `Function`, and it can only read the
|
|
461
|
+
* answers it names.
|
|
462
|
+
*
|
|
463
|
+
* - Numbers: `12`, `0.5`. Text: `"High"` or `'High'`.
|
|
464
|
+
* - Answers by key: `hours`, and one column of a table: `plan.cost`.
|
|
465
|
+
* - Arithmetic: `+ - * /` (also `− × ÷`), unary minus, parentheses.
|
|
466
|
+
* - Comparisons: `== != < <= > >=` (also `= ≠ ≤ ≥`), giving true or false.
|
|
467
|
+
* - A choice: `cond ? a : b`.
|
|
468
|
+
* - `sum(...)`, `avg(...)`, `min(...)`, `max(...)` over numbers, lists and
|
|
469
|
+
* table columns. Blanks and text that is not a number are skipped.
|
|
470
|
+
*
|
|
471
|
+
* An unanswered question reads as blank: arithmetic with a blank is blank
|
|
472
|
+
* (so a total stays empty until its answers are in), and so is dividing by
|
|
473
|
+
* zero. Text that holds a number ("12") counts as that number; yes / no
|
|
474
|
+
* counts as 1 / 0.
|
|
475
|
+
*/
|
|
476
|
+
|
|
477
|
+
type FormulaValue = number | string | boolean | null | FormulaValue[];
|
|
478
|
+
/** An answer a formula reads: `key`, or `key.column` for one column of a table. */
|
|
479
|
+
interface FormulaRef {
|
|
480
|
+
key: string;
|
|
481
|
+
column?: string;
|
|
482
|
+
}
|
|
483
|
+
type BinaryOp = "+" | "-" | "*" | "/" | "==" | "!=" | "<" | "<=" | ">" | ">=";
|
|
484
|
+
declare const FORMULA_FUNCTIONS: readonly ["sum", "avg", "min", "max"];
|
|
485
|
+
type FormulaFunction = (typeof FORMULA_FUNCTIONS)[number];
|
|
486
|
+
type FormulaNode = {
|
|
487
|
+
kind: "number";
|
|
488
|
+
value: number;
|
|
489
|
+
} | {
|
|
490
|
+
kind: "text";
|
|
491
|
+
value: string;
|
|
492
|
+
} | {
|
|
493
|
+
kind: "ref";
|
|
494
|
+
key: string;
|
|
495
|
+
column?: string;
|
|
496
|
+
at: number;
|
|
497
|
+
} | {
|
|
498
|
+
kind: "unary";
|
|
499
|
+
op: "-";
|
|
500
|
+
arg: FormulaNode;
|
|
501
|
+
} | {
|
|
502
|
+
kind: "binary";
|
|
503
|
+
op: BinaryOp;
|
|
504
|
+
left: FormulaNode;
|
|
505
|
+
right: FormulaNode;
|
|
506
|
+
} | {
|
|
507
|
+
kind: "if";
|
|
508
|
+
test: FormulaNode;
|
|
509
|
+
then: FormulaNode;
|
|
510
|
+
else: FormulaNode;
|
|
511
|
+
} | {
|
|
512
|
+
kind: "call";
|
|
513
|
+
fn: FormulaFunction;
|
|
514
|
+
args: FormulaNode[];
|
|
515
|
+
};
|
|
516
|
+
type FormulaParseResult = {
|
|
517
|
+
ok: true;
|
|
518
|
+
ast: FormulaNode;
|
|
519
|
+
refs: FormulaRef[];
|
|
520
|
+
} | {
|
|
521
|
+
ok: false;
|
|
522
|
+
message: string; /** Character offset of the problem. */
|
|
523
|
+
at: number;
|
|
524
|
+
};
|
|
525
|
+
/** Longest formula accepted. */
|
|
526
|
+
declare const MAX_FORMULA_LENGTH = 2000;
|
|
527
|
+
/**
|
|
528
|
+
* Parse a formula. Never throws: a mistake comes back as `{ ok: false,
|
|
529
|
+
* message, at }`, with the character offset of the problem.
|
|
530
|
+
*/
|
|
531
|
+
declare function parseFormula(source: string): FormulaParseResult;
|
|
532
|
+
/** The answers a formula names, each once (none when it doesn't parse). */
|
|
533
|
+
declare function formulaRefs(source: string): FormulaRef[];
|
|
534
|
+
/**
|
|
535
|
+
* The formula with every reference to the answer `from` renamed to `to`.
|
|
536
|
+
* Column names, function names and text are left alone. Returned unchanged
|
|
537
|
+
* when it has a character a formula can't hold.
|
|
538
|
+
*/
|
|
539
|
+
declare function renameFormulaKey(source: string, from: string, to: string): string;
|
|
540
|
+
/** A value as a number: numbers, numeric text ("1,200" too), yes / no as 1 / 0. Anything else is blank (`null`). */
|
|
541
|
+
declare function formulaNumber(v: FormulaValue | Json | undefined): number | null;
|
|
542
|
+
/** Reads an answer for `evaluateFormula`: its value, or `null` when unanswered or unknown. */
|
|
543
|
+
type FormulaReader = (ref: FormulaRef) => FormulaValue;
|
|
544
|
+
/** Evaluate a parsed formula. Never throws; a value it can't work out is `null`. */
|
|
545
|
+
declare function evaluateFormula(ast: FormulaNode, read: FormulaReader): FormulaValue;
|
|
546
|
+
|
|
547
|
+
/** The calculated field type's registry key. */
|
|
548
|
+
declare const CALCULATED_TYPE = "calculated";
|
|
549
|
+
/**
|
|
550
|
+
* Field types the builder offers only to a host that names them in its
|
|
551
|
+
* palette, like `STRUCTURED_FIELD_TYPES`: `calculated` shows a value worked
|
|
552
|
+
* out from other answers, so it is opt-in for hosts that want formulas.
|
|
553
|
+
*/
|
|
554
|
+
declare const COMPUTED_FIELD_TYPES: readonly ["calculated"];
|
|
555
|
+
type CalculatedFormat = "number" | "percent" | "text";
|
|
556
|
+
/** Most decimal places a calculated value may keep. */
|
|
557
|
+
declare const MAX_CALCULATED_DECIMALS = 10;
|
|
558
|
+
interface CalculatedProps {
|
|
559
|
+
formula: string;
|
|
560
|
+
format?: CalculatedFormat | undefined;
|
|
561
|
+
decimals?: number | undefined;
|
|
562
|
+
}
|
|
563
|
+
/** A calculated field's settings, with anything malformed left out. */
|
|
564
|
+
declare function calculatedProps(field: FieldBlock): CalculatedProps;
|
|
565
|
+
/**
|
|
566
|
+
* What a formula's result is stored as. `number` and `percent` keep a number
|
|
567
|
+
* (`0.25` for 25%), rounded to `decimals`; `text` keeps text. Without a
|
|
568
|
+
* format, numbers, text and true / false are kept as they are. A list, and
|
|
569
|
+
* anything the format can't hold, is no value (`undefined`).
|
|
570
|
+
*/
|
|
571
|
+
declare function calculatedValue(result: FormulaValue, field: FieldBlock): Json | undefined;
|
|
572
|
+
/** A calculated value as shown: `12.5`, `25%`, the text, Yes / No. Empty when there is none. */
|
|
573
|
+
declare function formatCalculated(value: Json | undefined, field: FieldBlock): string;
|
|
574
|
+
/**
|
|
575
|
+
* Most items a formula reads from one answer (a list's items, a table's
|
|
576
|
+
* rows). A longer answer reads as blank, so one oversized value sent to the
|
|
577
|
+
* server can't make every formula over it slow.
|
|
578
|
+
*/
|
|
579
|
+
declare const MAX_FORMULA_ITEMS = 10000;
|
|
580
|
+
/**
|
|
581
|
+
* The value a formula reads for an answer: numbers and text as they are, a
|
|
582
|
+
* list's items, one table column's cells. A list or table of more than
|
|
583
|
+
* `MAX_FORMULA_ITEMS` reads as blank.
|
|
584
|
+
*/
|
|
585
|
+
declare function formulaInput(value: Json | undefined, column?: string): FormulaValue;
|
|
586
|
+
|
|
396
587
|
interface RecallScope {
|
|
397
588
|
/** Fields by key. */
|
|
398
589
|
fieldsByKey: Map<string, FieldBlock>;
|
|
@@ -475,4 +666,4 @@ declare function explain(source: FormEngine | ExplainInput, blockId: string, opt
|
|
|
475
666
|
/** A condition as a plain-English clause: `contact_me is not Yes`. */
|
|
476
667
|
declare function describeCondition(condition: Condition, def: FormDefinition, fields?: Map<string, FieldBlock>): string;
|
|
477
668
|
|
|
478
|
-
export { type AnswersOf, Block, type ChoiceFieldOptions, type ChoiceOption, type CoerceHiddenOptions, type CoercedHidden, Condition, ContentBlock, Ending, type ExplainInput, type ExplainOptions, type Explanation, FieldBlock, type FieldOptions, type FieldSpec, type FieldTypeManifest, type FieldValidation, FieldValidator, type Form, FormDefinition, FormEngine, type FormInput, type FormIssue, FormLayout, FormSettings, HIGHLIGHT_NOTE_MESSAGE, HiddenInput, type Highlight, Json, type JumpTrace, type KeyResolver, LogicRule, MAX_HIDDEN_STRING_LENGTH, MAX_HIGHLIGHT_NOTE_LENGTH, MAX_HIGHLIGHT_QUOTE_LENGTH, MAX_TABLE_CELL_LENGTH, MAX_TABLE_COLUMNS, MAX_TIMESTAMP_SECONDS, type MediaNote, Operator, PageBreakBlock, type ParseResult, type PathResult, type RuleSpec, type RuleTrace, STRUCTURED_FIELD_TYPES, type TableColumn, canonicalJson, choiceOptions, coerceHidden, coerceHiddenValue, computePath, defineForm, describeCondition, evaluate, explain, f, fingerprint, formatTimestamp, getFieldType, isEmptyValue, isSensitive, listFieldTypes, listLimits, normalizeValue, parseForm, parseTimestamp, recall, registerFieldType, ruleVisible, steps, summarizeValue, tableColumns, tableLimits, when };
|
|
669
|
+
export { type AnswersOf, Block, CALCULATED_TYPE, COMPUTED_FIELD_TYPES, type CalculatedFormat, type CalculatedProps, type ChoiceFieldOptions, type ChoiceOption, type CoerceHiddenOptions, type CoercedHidden, Condition, ContentBlock, Ending, type ExplainInput, type ExplainOptions, type Explanation, FORMULA_FUNCTIONS, FieldBlock, type FieldOptions, type FieldSpec, type FieldTypeManifest, type FieldValidation, FieldValidator, type Form, FormDefinition, FormEngine, type FormInput, type FormIssue, FormLayout, FormSettings, type FormulaFunction, type FormulaNode, type FormulaParseResult, type FormulaReader, type FormulaRef, type FormulaValue, HIGHLIGHT_NOTE_MESSAGE, HiddenInput, type Highlight, Json, type JumpTrace, type KeyResolver, LogicRule, MAX_CALCULATED_DECIMALS, MAX_FORMULA_ITEMS, MAX_FORMULA_LENGTH, MAX_HIDDEN_STRING_LENGTH, MAX_HIGHLIGHT_NOTE_LENGTH, MAX_HIGHLIGHT_QUOTE_LENGTH, MAX_TABLE_CELL_LENGTH, MAX_TABLE_COLUMNS, MAX_TIMESTAMP_SECONDS, type MediaNote, Operator, PageBreakBlock, type ParseResult, type PathResult, type RuleSpec, type RuleTrace, STRUCTURED_FIELD_TYPES, type TableColumn, calculatedProps, calculatedValue, canonicalJson, choiceOptions, coerceHidden, coerceHiddenValue, computePath, dateLimits, defineForm, describeCondition, evaluate, evaluateFormula, explain, f, fingerprint, formatCalculated, formatTimestamp, formulaInput, formulaNumber, formulaRefs, getFieldType, isEmptyValue, isIsoDate, isSensitive, listFieldTypes, listLimits, normalizeValue, numberLimits, parseForm, parseFormula, parseTimestamp, ratingDisplay, recall, registerFieldType, renameFormulaKey, ruleVisible, scaleLabels, steps, summarizeValue, tableColumns, tableLimits, when };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { a as FieldBlock, C as ContentBlock, P as PageBreakBlock, F as FormDefinition, H as HiddenInput, b as FormLayout, L as LogicRule, E as Ending, c as FormSettings, J as Json, d as Condition, B as Block, O as Operator } from './types-BBKBQ8sp.js';
|
|
2
2
|
export { e as FormEvent, f as Operand } from './types-BBKBQ8sp.js';
|
|
3
|
-
import { F as FormEngine } from './engine-
|
|
4
|
-
export { C as CreateFormOptions, a as FormState, c as createForm, i as isFormEvent, b as isJson, r as replay } from './engine-
|
|
3
|
+
import { F as FormEngine } from './engine-Dz9J5ej2.js';
|
|
4
|
+
export { C as CreateFormOptions, a as FormState, c as createForm, i as isFormEvent, b as isJson, r as replay } from './engine-Dz9J5ej2.js';
|
|
5
5
|
import { F as FieldValidator } from './validate-BjNwF1UE.js';
|
|
6
6
|
export { R as REQUIRED_MESSAGE, S as StandardSchemaV1, v as validateField } from './validate-BjNwF1UE.js';
|
|
7
7
|
|
|
@@ -44,13 +44,45 @@ declare const f: {
|
|
|
44
44
|
}) => FieldSpec<K, string>;
|
|
45
45
|
email: <K extends string>(key: K, o: FieldOptions) => FieldSpec<K, string>;
|
|
46
46
|
phone: <K extends string>(key: K, o: FieldOptions) => FieldSpec<K, string>;
|
|
47
|
+
/**
|
|
48
|
+
* A 1-to-`max` scale. `lowLabel` and `highLabel` are optional words under
|
|
49
|
+
* its ends ("Poor", "Great"); `display: "stars"` draws stars instead of numbers.
|
|
50
|
+
*/
|
|
47
51
|
rating: <K extends string>(key: K, o: FieldOptions & {
|
|
48
52
|
max?: number | undefined;
|
|
53
|
+
lowLabel?: string | undefined;
|
|
54
|
+
highLabel?: string | undefined;
|
|
55
|
+
display?: "numbers" | "stars" | undefined;
|
|
56
|
+
}) => FieldSpec<K, number>;
|
|
57
|
+
/** A 0-to-10 Net Promoter Score. The end labels default to "Not likely" and "Very likely" in the renderer. */
|
|
58
|
+
nps: <K extends string>(key: K, o: FieldOptions & {
|
|
59
|
+
lowLabel?: string | undefined;
|
|
60
|
+
highLabel?: string | undefined;
|
|
49
61
|
}) => FieldSpec<K, number>;
|
|
50
|
-
nps: <K extends string>(key: K, o: FieldOptions) => FieldSpec<K, number>;
|
|
51
62
|
singleChoice: <K extends string, O extends string>(key: K, o: ChoiceFieldOptions<O>) => FieldSpec<K, O>;
|
|
52
63
|
multiChoice: <K extends string, O extends string>(key: K, o: ChoiceFieldOptions<O>) => FieldSpec<K, O[]>;
|
|
53
64
|
yesNo: <K extends string>(key: K, o: FieldOptions) => FieldSpec<K, boolean>;
|
|
65
|
+
/** One option from a compact menu: for a long list (a country, a class), where single choice would be a wall of buttons. */
|
|
66
|
+
dropdown: <K extends string, O extends string>(key: K, o: ChoiceFieldOptions<O>) => FieldSpec<K, O>;
|
|
67
|
+
/** A number, optionally between `min` and `max` and on a `step` (from `min`, else 0): `step: 1` for whole numbers. */
|
|
68
|
+
number: <K extends string>(key: K, o: FieldOptions & {
|
|
69
|
+
min?: number | undefined;
|
|
70
|
+
max?: number | undefined;
|
|
71
|
+
step?: number | undefined;
|
|
72
|
+
}) => FieldSpec<K, number>;
|
|
73
|
+
/** A calendar day, stored as `YYYY-MM-DD`, optionally between `min` and `max` (also `YYYY-MM-DD`). */
|
|
74
|
+
date: <K extends string>(key: K, o: FieldOptions & {
|
|
75
|
+
min?: string | undefined;
|
|
76
|
+
max?: string | undefined;
|
|
77
|
+
}) => FieldSpec<K, string>;
|
|
78
|
+
/**
|
|
79
|
+
* A single checkbox to agree to something. `text` is the checkbox's own
|
|
80
|
+
* words ("I agree to the terms"); the renderer defaults to "I agree".
|
|
81
|
+
* Checked stores `true`; unchecked is unanswered, so `required` means it must be checked.
|
|
82
|
+
*/
|
|
83
|
+
consent: <K extends string>(key: K, o: FieldOptions & {
|
|
84
|
+
text?: string | undefined;
|
|
85
|
+
}) => FieldSpec<K, true>;
|
|
54
86
|
/** Several short answers, one per line: goals, action items, three things that went well. */
|
|
55
87
|
list: <K extends string>(key: K, o: FieldOptions & {
|
|
56
88
|
min?: number | undefined;
|
|
@@ -58,6 +90,16 @@ declare const f: {
|
|
|
58
90
|
itemMaxLength?: number | undefined;
|
|
59
91
|
itemPlaceholder?: string | undefined;
|
|
60
92
|
}) => FieldSpec<K, string[]>;
|
|
93
|
+
/**
|
|
94
|
+
* A value worked out from other answers and shown read-only, such as a
|
|
95
|
+
* total or a score: `formula` names answers by key (`hours * rate`,
|
|
96
|
+
* `sum(plan.cost)`). Stored with the answers; never required.
|
|
97
|
+
*/
|
|
98
|
+
calculated: <K extends string>(key: K, o: Omit<FieldOptions, "required" | "placeholder"> & {
|
|
99
|
+
formula: string;
|
|
100
|
+
format?: "number" | "percent" | "text" | undefined;
|
|
101
|
+
decimals?: number | undefined;
|
|
102
|
+
}) => FieldSpec<K, string | number | boolean>;
|
|
61
103
|
/**
|
|
62
104
|
* A small table each answer fills row by row, one answer per column: an
|
|
63
105
|
* action plan (What / Who / By when), pros and cons.
|
|
@@ -341,6 +383,26 @@ interface ChoiceOption {
|
|
|
341
383
|
label?: string;
|
|
342
384
|
}
|
|
343
385
|
declare function choiceOptions(field: FieldBlock): ChoiceOption[];
|
|
386
|
+
/** The optional words under the ends of a rating or NPS scale ("Poor", "Great"). */
|
|
387
|
+
declare function scaleLabels(field: FieldBlock): {
|
|
388
|
+
low?: string;
|
|
389
|
+
high?: string;
|
|
390
|
+
};
|
|
391
|
+
/** How a rating is drawn: `"numbers"` (default) or `"stars"`. */
|
|
392
|
+
declare function ratingDisplay(field: FieldBlock): "numbers" | "stars";
|
|
393
|
+
/** A `number` field's limits: `min`, `max` and `step` (each optional; `step` is above 0). */
|
|
394
|
+
declare function numberLimits(field: FieldBlock): {
|
|
395
|
+
min?: number;
|
|
396
|
+
max?: number;
|
|
397
|
+
step?: number;
|
|
398
|
+
};
|
|
399
|
+
/** `YYYY-MM-DD`, a real calendar day (no 2026-02-30), years 0001 to 9999. */
|
|
400
|
+
declare function isIsoDate(value: string): boolean;
|
|
401
|
+
/** A `date` field's earliest and latest days (`YYYY-MM-DD`), when set. */
|
|
402
|
+
declare function dateLimits(field: FieldBlock): {
|
|
403
|
+
min?: string;
|
|
404
|
+
max?: string;
|
|
405
|
+
};
|
|
344
406
|
|
|
345
407
|
declare function listLimits(field: FieldBlock): {
|
|
346
408
|
min: number;
|
|
@@ -393,6 +455,135 @@ declare const HIGHLIGHT_NOTE_MESSAGE = "Add a note to each highlight.";
|
|
|
393
455
|
*/
|
|
394
456
|
declare const STRUCTURED_FIELD_TYPES: readonly ["list", "table", "media-notes", "text-highlights"];
|
|
395
457
|
|
|
458
|
+
/**
|
|
459
|
+
* A small, safe formula language for `calculated` fields. It is parsed and
|
|
460
|
+
* evaluated here, never with `eval` or `Function`, and it can only read the
|
|
461
|
+
* answers it names.
|
|
462
|
+
*
|
|
463
|
+
* - Numbers: `12`, `0.5`. Text: `"High"` or `'High'`.
|
|
464
|
+
* - Answers by key: `hours`, and one column of a table: `plan.cost`.
|
|
465
|
+
* - Arithmetic: `+ - * /` (also `− × ÷`), unary minus, parentheses.
|
|
466
|
+
* - Comparisons: `== != < <= > >=` (also `= ≠ ≤ ≥`), giving true or false.
|
|
467
|
+
* - A choice: `cond ? a : b`.
|
|
468
|
+
* - `sum(...)`, `avg(...)`, `min(...)`, `max(...)` over numbers, lists and
|
|
469
|
+
* table columns. Blanks and text that is not a number are skipped.
|
|
470
|
+
*
|
|
471
|
+
* An unanswered question reads as blank: arithmetic with a blank is blank
|
|
472
|
+
* (so a total stays empty until its answers are in), and so is dividing by
|
|
473
|
+
* zero. Text that holds a number ("12") counts as that number; yes / no
|
|
474
|
+
* counts as 1 / 0.
|
|
475
|
+
*/
|
|
476
|
+
|
|
477
|
+
type FormulaValue = number | string | boolean | null | FormulaValue[];
|
|
478
|
+
/** An answer a formula reads: `key`, or `key.column` for one column of a table. */
|
|
479
|
+
interface FormulaRef {
|
|
480
|
+
key: string;
|
|
481
|
+
column?: string;
|
|
482
|
+
}
|
|
483
|
+
type BinaryOp = "+" | "-" | "*" | "/" | "==" | "!=" | "<" | "<=" | ">" | ">=";
|
|
484
|
+
declare const FORMULA_FUNCTIONS: readonly ["sum", "avg", "min", "max"];
|
|
485
|
+
type FormulaFunction = (typeof FORMULA_FUNCTIONS)[number];
|
|
486
|
+
type FormulaNode = {
|
|
487
|
+
kind: "number";
|
|
488
|
+
value: number;
|
|
489
|
+
} | {
|
|
490
|
+
kind: "text";
|
|
491
|
+
value: string;
|
|
492
|
+
} | {
|
|
493
|
+
kind: "ref";
|
|
494
|
+
key: string;
|
|
495
|
+
column?: string;
|
|
496
|
+
at: number;
|
|
497
|
+
} | {
|
|
498
|
+
kind: "unary";
|
|
499
|
+
op: "-";
|
|
500
|
+
arg: FormulaNode;
|
|
501
|
+
} | {
|
|
502
|
+
kind: "binary";
|
|
503
|
+
op: BinaryOp;
|
|
504
|
+
left: FormulaNode;
|
|
505
|
+
right: FormulaNode;
|
|
506
|
+
} | {
|
|
507
|
+
kind: "if";
|
|
508
|
+
test: FormulaNode;
|
|
509
|
+
then: FormulaNode;
|
|
510
|
+
else: FormulaNode;
|
|
511
|
+
} | {
|
|
512
|
+
kind: "call";
|
|
513
|
+
fn: FormulaFunction;
|
|
514
|
+
args: FormulaNode[];
|
|
515
|
+
};
|
|
516
|
+
type FormulaParseResult = {
|
|
517
|
+
ok: true;
|
|
518
|
+
ast: FormulaNode;
|
|
519
|
+
refs: FormulaRef[];
|
|
520
|
+
} | {
|
|
521
|
+
ok: false;
|
|
522
|
+
message: string; /** Character offset of the problem. */
|
|
523
|
+
at: number;
|
|
524
|
+
};
|
|
525
|
+
/** Longest formula accepted. */
|
|
526
|
+
declare const MAX_FORMULA_LENGTH = 2000;
|
|
527
|
+
/**
|
|
528
|
+
* Parse a formula. Never throws: a mistake comes back as `{ ok: false,
|
|
529
|
+
* message, at }`, with the character offset of the problem.
|
|
530
|
+
*/
|
|
531
|
+
declare function parseFormula(source: string): FormulaParseResult;
|
|
532
|
+
/** The answers a formula names, each once (none when it doesn't parse). */
|
|
533
|
+
declare function formulaRefs(source: string): FormulaRef[];
|
|
534
|
+
/**
|
|
535
|
+
* The formula with every reference to the answer `from` renamed to `to`.
|
|
536
|
+
* Column names, function names and text are left alone. Returned unchanged
|
|
537
|
+
* when it has a character a formula can't hold.
|
|
538
|
+
*/
|
|
539
|
+
declare function renameFormulaKey(source: string, from: string, to: string): string;
|
|
540
|
+
/** A value as a number: numbers, numeric text ("1,200" too), yes / no as 1 / 0. Anything else is blank (`null`). */
|
|
541
|
+
declare function formulaNumber(v: FormulaValue | Json | undefined): number | null;
|
|
542
|
+
/** Reads an answer for `evaluateFormula`: its value, or `null` when unanswered or unknown. */
|
|
543
|
+
type FormulaReader = (ref: FormulaRef) => FormulaValue;
|
|
544
|
+
/** Evaluate a parsed formula. Never throws; a value it can't work out is `null`. */
|
|
545
|
+
declare function evaluateFormula(ast: FormulaNode, read: FormulaReader): FormulaValue;
|
|
546
|
+
|
|
547
|
+
/** The calculated field type's registry key. */
|
|
548
|
+
declare const CALCULATED_TYPE = "calculated";
|
|
549
|
+
/**
|
|
550
|
+
* Field types the builder offers only to a host that names them in its
|
|
551
|
+
* palette, like `STRUCTURED_FIELD_TYPES`: `calculated` shows a value worked
|
|
552
|
+
* out from other answers, so it is opt-in for hosts that want formulas.
|
|
553
|
+
*/
|
|
554
|
+
declare const COMPUTED_FIELD_TYPES: readonly ["calculated"];
|
|
555
|
+
type CalculatedFormat = "number" | "percent" | "text";
|
|
556
|
+
/** Most decimal places a calculated value may keep. */
|
|
557
|
+
declare const MAX_CALCULATED_DECIMALS = 10;
|
|
558
|
+
interface CalculatedProps {
|
|
559
|
+
formula: string;
|
|
560
|
+
format?: CalculatedFormat | undefined;
|
|
561
|
+
decimals?: number | undefined;
|
|
562
|
+
}
|
|
563
|
+
/** A calculated field's settings, with anything malformed left out. */
|
|
564
|
+
declare function calculatedProps(field: FieldBlock): CalculatedProps;
|
|
565
|
+
/**
|
|
566
|
+
* What a formula's result is stored as. `number` and `percent` keep a number
|
|
567
|
+
* (`0.25` for 25%), rounded to `decimals`; `text` keeps text. Without a
|
|
568
|
+
* format, numbers, text and true / false are kept as they are. A list, and
|
|
569
|
+
* anything the format can't hold, is no value (`undefined`).
|
|
570
|
+
*/
|
|
571
|
+
declare function calculatedValue(result: FormulaValue, field: FieldBlock): Json | undefined;
|
|
572
|
+
/** A calculated value as shown: `12.5`, `25%`, the text, Yes / No. Empty when there is none. */
|
|
573
|
+
declare function formatCalculated(value: Json | undefined, field: FieldBlock): string;
|
|
574
|
+
/**
|
|
575
|
+
* Most items a formula reads from one answer (a list's items, a table's
|
|
576
|
+
* rows). A longer answer reads as blank, so one oversized value sent to the
|
|
577
|
+
* server can't make every formula over it slow.
|
|
578
|
+
*/
|
|
579
|
+
declare const MAX_FORMULA_ITEMS = 10000;
|
|
580
|
+
/**
|
|
581
|
+
* The value a formula reads for an answer: numbers and text as they are, a
|
|
582
|
+
* list's items, one table column's cells. A list or table of more than
|
|
583
|
+
* `MAX_FORMULA_ITEMS` reads as blank.
|
|
584
|
+
*/
|
|
585
|
+
declare function formulaInput(value: Json | undefined, column?: string): FormulaValue;
|
|
586
|
+
|
|
396
587
|
interface RecallScope {
|
|
397
588
|
/** Fields by key. */
|
|
398
589
|
fieldsByKey: Map<string, FieldBlock>;
|
|
@@ -475,4 +666,4 @@ declare function explain(source: FormEngine | ExplainInput, blockId: string, opt
|
|
|
475
666
|
/** A condition as a plain-English clause: `contact_me is not Yes`. */
|
|
476
667
|
declare function describeCondition(condition: Condition, def: FormDefinition, fields?: Map<string, FieldBlock>): string;
|
|
477
668
|
|
|
478
|
-
export { type AnswersOf, Block, type ChoiceFieldOptions, type ChoiceOption, type CoerceHiddenOptions, type CoercedHidden, Condition, ContentBlock, Ending, type ExplainInput, type ExplainOptions, type Explanation, FieldBlock, type FieldOptions, type FieldSpec, type FieldTypeManifest, type FieldValidation, FieldValidator, type Form, FormDefinition, FormEngine, type FormInput, type FormIssue, FormLayout, FormSettings, HIGHLIGHT_NOTE_MESSAGE, HiddenInput, type Highlight, Json, type JumpTrace, type KeyResolver, LogicRule, MAX_HIDDEN_STRING_LENGTH, MAX_HIGHLIGHT_NOTE_LENGTH, MAX_HIGHLIGHT_QUOTE_LENGTH, MAX_TABLE_CELL_LENGTH, MAX_TABLE_COLUMNS, MAX_TIMESTAMP_SECONDS, type MediaNote, Operator, PageBreakBlock, type ParseResult, type PathResult, type RuleSpec, type RuleTrace, STRUCTURED_FIELD_TYPES, type TableColumn, canonicalJson, choiceOptions, coerceHidden, coerceHiddenValue, computePath, defineForm, describeCondition, evaluate, explain, f, fingerprint, formatTimestamp, getFieldType, isEmptyValue, isSensitive, listFieldTypes, listLimits, normalizeValue, parseForm, parseTimestamp, recall, registerFieldType, ruleVisible, steps, summarizeValue, tableColumns, tableLimits, when };
|
|
669
|
+
export { type AnswersOf, Block, CALCULATED_TYPE, COMPUTED_FIELD_TYPES, type CalculatedFormat, type CalculatedProps, type ChoiceFieldOptions, type ChoiceOption, type CoerceHiddenOptions, type CoercedHidden, Condition, ContentBlock, Ending, type ExplainInput, type ExplainOptions, type Explanation, FORMULA_FUNCTIONS, FieldBlock, type FieldOptions, type FieldSpec, type FieldTypeManifest, type FieldValidation, FieldValidator, type Form, FormDefinition, FormEngine, type FormInput, type FormIssue, FormLayout, FormSettings, type FormulaFunction, type FormulaNode, type FormulaParseResult, type FormulaReader, type FormulaRef, type FormulaValue, HIGHLIGHT_NOTE_MESSAGE, HiddenInput, type Highlight, Json, type JumpTrace, type KeyResolver, LogicRule, MAX_CALCULATED_DECIMALS, MAX_FORMULA_ITEMS, MAX_FORMULA_LENGTH, MAX_HIDDEN_STRING_LENGTH, MAX_HIGHLIGHT_NOTE_LENGTH, MAX_HIGHLIGHT_QUOTE_LENGTH, MAX_TABLE_CELL_LENGTH, MAX_TABLE_COLUMNS, MAX_TIMESTAMP_SECONDS, type MediaNote, Operator, PageBreakBlock, type ParseResult, type PathResult, type RuleSpec, type RuleTrace, STRUCTURED_FIELD_TYPES, type TableColumn, calculatedProps, calculatedValue, canonicalJson, choiceOptions, coerceHidden, coerceHiddenValue, computePath, dateLimits, defineForm, describeCondition, evaluate, evaluateFormula, explain, f, fingerprint, formatCalculated, formatTimestamp, formulaInput, formulaNumber, formulaRefs, getFieldType, isEmptyValue, isIsoDate, isSensitive, listFieldTypes, listLimits, normalizeValue, numberLimits, parseForm, parseFormula, parseTimestamp, ratingDisplay, recall, registerFieldType, renameFormulaKey, ruleVisible, scaleLabels, steps, summarizeValue, tableColumns, tableLimits, when };
|