@case-framework/survey-items 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.
- package/README.md +21 -0
- package/dist/choice.d.mts +36 -0
- package/dist/choice.d.mts.map +1 -0
- package/dist/choice.mjs +103 -0
- package/dist/choice.mjs.map +1 -0
- package/dist/form.d.mts +187 -0
- package/dist/form.d.mts.map +1 -0
- package/dist/form.mjs +766 -0
- package/dist/form.mjs.map +1 -0
- package/package.json +39 -0
package/README.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# `@case-framework/survey-items`
|
|
2
|
+
|
|
3
|
+
Headless domain models for the standard CASE survey item types. This package is
|
|
4
|
+
shared by participant, editor, and assistant integrations and contains no
|
|
5
|
+
React, editor, assistant, server, or localization dependencies.
|
|
6
|
+
|
|
7
|
+
Import only the item-family entry point you need:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import {
|
|
11
|
+
createChoiceItemConfig,
|
|
12
|
+
normalizeChoiceItemConfig,
|
|
13
|
+
} from "@case-framework/survey-items/choice";
|
|
14
|
+
|
|
15
|
+
const config = normalizeChoiceItemConfig(rawConfig, itemId);
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Choice configuration uses the canonical embedded-form model from
|
|
19
|
+
`@case-framework/survey-items/form`. Import that entry point directly for form
|
|
20
|
+
types, normalization, translation keys, defaults, layout helpers, and
|
|
21
|
+
authoring-mode transitions.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { FormItemConfig } from "./form.mjs";
|
|
2
|
+
import { ValueType } from "@case-framework/survey-core";
|
|
3
|
+
|
|
4
|
+
//#region src/choice.d.ts
|
|
5
|
+
/** `1` = single selection (radio). `null` = multiple selection with no upper cap. Integers above 1 cap how many options may be selected. */
|
|
6
|
+
type ChoiceMaxSelection = number | null;
|
|
7
|
+
interface ChoiceOptionConfig {
|
|
8
|
+
id: string;
|
|
9
|
+
key?: string;
|
|
10
|
+
hasDisplayCondition?: boolean;
|
|
11
|
+
embeddedFormItemId?: string;
|
|
12
|
+
embeddedForm?: FormItemConfig;
|
|
13
|
+
}
|
|
14
|
+
interface ChoiceItemConfig {
|
|
15
|
+
id: string;
|
|
16
|
+
maxSelection: ChoiceMaxSelection;
|
|
17
|
+
shuffleOptions: boolean;
|
|
18
|
+
options: ChoiceOptionConfig[];
|
|
19
|
+
}
|
|
20
|
+
declare function choiceIsSingleSelect(maxSelection: ChoiceMaxSelection): boolean;
|
|
21
|
+
declare function getChoiceResponseValueType(maxSelection: ChoiceMaxSelection): ValueType;
|
|
22
|
+
declare function createChoiceItemConfig(itemId: string): ChoiceItemConfig;
|
|
23
|
+
declare function getChoiceOptionLabelContentKey(optionId: string): string;
|
|
24
|
+
declare function getChoiceOptionEmbeddedFormTranslationPrefix(optionId: string): string;
|
|
25
|
+
declare function getChoiceOptionEmbeddedFormResponseSlotPrefix(optionId: string): string;
|
|
26
|
+
declare function getChoiceOptionEmbeddedFormResponseSlotId(optionId: string, fieldKey: string): string;
|
|
27
|
+
declare function getChoiceOptionEmbeddedFormResponseKeyPathSegment(option: Pick<ChoiceOptionConfig, "id" | "key">): string;
|
|
28
|
+
declare function choiceOptionHasEmbeddedForm(option: Pick<ChoiceOptionConfig, "embeddedFormItemId" | "embeddedForm">): boolean;
|
|
29
|
+
declare function normalizeChoiceOptionKey(value: string): string;
|
|
30
|
+
declare function normalizeChoiceItemConfig(rawConfig: unknown, itemId: string): ChoiceItemConfig;
|
|
31
|
+
declare function createChoiceOptionConfig(existingOptions: ChoiceOptionConfig[]): ChoiceOptionConfig;
|
|
32
|
+
declare function createDuplicatedChoiceOptionConfig(option: ChoiceOptionConfig, existingOptions: ChoiceOptionConfig[]): ChoiceOptionConfig;
|
|
33
|
+
declare function getDisplayOrder<T>(items: readonly T[], shouldShuffle: boolean, seed: string): T[];
|
|
34
|
+
//#endregion
|
|
35
|
+
export { ChoiceItemConfig, ChoiceMaxSelection, ChoiceOptionConfig, choiceIsSingleSelect, choiceOptionHasEmbeddedForm, createChoiceItemConfig, createChoiceOptionConfig, createDuplicatedChoiceOptionConfig, getChoiceOptionEmbeddedFormResponseKeyPathSegment, getChoiceOptionEmbeddedFormResponseSlotId, getChoiceOptionEmbeddedFormResponseSlotPrefix, getChoiceOptionEmbeddedFormTranslationPrefix, getChoiceOptionLabelContentKey, getChoiceResponseValueType, getDisplayOrder, normalizeChoiceItemConfig, normalizeChoiceOptionKey };
|
|
36
|
+
//# sourceMappingURL=choice.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"choice.d.mts","names":[],"sources":["../src/choice.ts"],"mappings":";;;;;KAUY,kBAAA;AAAA,UAEK,kBAAA;EACf,EAAA;EACA,GAAA;EACA,mBAAA;EACA,kBAAA;EACA,YAAA,GAAe,cAAA;AAAA;AAAA,UAGA,gBAAA;EACf,EAAA;EACA,YAAA,EAAc,kBAAA;EACd,cAAA;EACA,OAAA,EAAS,kBAAA;AAAA;AAAA,iBAGK,oBAAA,CAAqB,YAAA,EAAc,kBAAA;AAAA,iBAInC,0BAAA,CAA2B,YAAA,EAAc,kBAAA,GAAqB,SAAA;AAAA,iBAI9D,sBAAA,CAAuB,MAAA,WAAiB,gBAAA;AAAA,iBASxC,8BAAA,CAA+B,QAAA;AAAA,iBAI/B,4CAAA,CAA6C,QAAA;AAAA,iBAI7C,6CAAA,CAA8C,QAAA;AAAA,iBAI9C,yCAAA,CACd,QAAA,UACA,QAAA;AAAA,iBAKc,iDAAA,CACd,MAAA,EAAQ,IAAA,CAAK,kBAAA;AAAA,iBAKC,2BAAA,CACd,MAAA,EAAQ,IAAA,CAAK,kBAAA;AAAA,iBAKC,wBAAA,CAAyB,KAAA;AAAA,iBAuDzB,yBAAA,CAA0B,SAAA,WAAoB,MAAA,WAAiB,gBAAA;AAAA,iBAiB/D,wBAAA,CACd,eAAA,EAAiB,kBAAA,KAChB,kBAAA;AAAA,iBAea,kCAAA,CACd,MAAA,EAAQ,kBAAA,EACR,eAAA,EAAiB,kBAAA,KAChB,kBAAA;AAAA,iBAWa,eAAA,GAAA,CAAmB,KAAA,WAAgB,CAAA,IAAK,aAAA,WAAwB,IAAA,WAAe,CAAA"}
|
package/dist/choice.mjs
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { normalizeFormItemConfig } from "./form.mjs";
|
|
2
|
+
import { ValueType, createSeededRandom, generateId, shuffleArray, structuredCloneMethod } from "@case-framework/survey-core";
|
|
3
|
+
//#region src/choice.ts
|
|
4
|
+
function choiceIsSingleSelect(maxSelection) {
|
|
5
|
+
return maxSelection === 1;
|
|
6
|
+
}
|
|
7
|
+
function getChoiceResponseValueType(maxSelection) {
|
|
8
|
+
return choiceIsSingleSelect(maxSelection) ? ValueType.reference : ValueType.referenceArray;
|
|
9
|
+
}
|
|
10
|
+
function createChoiceItemConfig(itemId) {
|
|
11
|
+
return {
|
|
12
|
+
id: itemId,
|
|
13
|
+
maxSelection: 1,
|
|
14
|
+
shuffleOptions: false,
|
|
15
|
+
options: []
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function getChoiceOptionLabelContentKey(optionId) {
|
|
19
|
+
return `options.${optionId}.label`;
|
|
20
|
+
}
|
|
21
|
+
function getChoiceOptionEmbeddedFormTranslationPrefix(optionId) {
|
|
22
|
+
return `embeddedForms.${optionId}`;
|
|
23
|
+
}
|
|
24
|
+
function getChoiceOptionEmbeddedFormResponseSlotPrefix(optionId) {
|
|
25
|
+
return `embedded.${optionId}`;
|
|
26
|
+
}
|
|
27
|
+
function getChoiceOptionEmbeddedFormResponseSlotId(optionId, fieldKey) {
|
|
28
|
+
return `${getChoiceOptionEmbeddedFormResponseSlotPrefix(optionId)}.${fieldKey}`;
|
|
29
|
+
}
|
|
30
|
+
function getChoiceOptionEmbeddedFormResponseKeyPathSegment(option) {
|
|
31
|
+
return normalizeChoiceOptionKey(option.key ?? "") || option.id;
|
|
32
|
+
}
|
|
33
|
+
function choiceOptionHasEmbeddedForm(option) {
|
|
34
|
+
return Boolean(option.embeddedFormItemId || option.embeddedForm?.fieldGroups.length);
|
|
35
|
+
}
|
|
36
|
+
function normalizeChoiceOptionKey(value) {
|
|
37
|
+
return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "");
|
|
38
|
+
}
|
|
39
|
+
function normalizeChoiceOptionConfig(rawOption) {
|
|
40
|
+
if (!rawOption || typeof rawOption !== "object") return null;
|
|
41
|
+
const option = rawOption;
|
|
42
|
+
const trimmedId = typeof option.id === "string" ? option.id.trim() : "";
|
|
43
|
+
if (!trimmedId) return null;
|
|
44
|
+
const trimmedKey = typeof option.key === "string" ? option.key.trim() : "";
|
|
45
|
+
const trimmedEmbeddedFormItemId = typeof option.embeddedFormItemId === "string" ? option.embeddedFormItemId.trim() : "";
|
|
46
|
+
return {
|
|
47
|
+
id: trimmedId,
|
|
48
|
+
key: trimmedKey || void 0,
|
|
49
|
+
hasDisplayCondition: option.hasDisplayCondition === true ? true : void 0,
|
|
50
|
+
embeddedFormItemId: trimmedEmbeddedFormItemId || void 0,
|
|
51
|
+
embeddedForm: option.embeddedForm ? normalizeFormItemConfig(option.embeddedForm, trimmedId) : void 0
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function normalizeMaxSelection(config) {
|
|
55
|
+
const hasMaxSelectionKey = "maxSelection" in config && config.maxSelection !== void 0;
|
|
56
|
+
const rawMax = config.maxSelection;
|
|
57
|
+
if (rawMax === null) return null;
|
|
58
|
+
if (typeof rawMax === "number" && Number.isFinite(rawMax)) {
|
|
59
|
+
const n = Math.floor(rawMax);
|
|
60
|
+
return n >= 1 ? n : 1;
|
|
61
|
+
}
|
|
62
|
+
if (typeof rawMax === "string") {
|
|
63
|
+
const parsed = Number.parseInt(rawMax.trim(), 10);
|
|
64
|
+
if (Number.isFinite(parsed) && parsed >= 1) return parsed;
|
|
65
|
+
}
|
|
66
|
+
if (!hasMaxSelectionKey && config.mode === "multiple") return null;
|
|
67
|
+
return 1;
|
|
68
|
+
}
|
|
69
|
+
function normalizeChoiceItemConfig(rawConfig, itemId) {
|
|
70
|
+
const config = rawConfig ?? {};
|
|
71
|
+
return {
|
|
72
|
+
id: typeof config.id === "string" && config.id.trim() ? config.id : itemId,
|
|
73
|
+
maxSelection: normalizeMaxSelection(config),
|
|
74
|
+
shuffleOptions: config.shuffleOptions === true,
|
|
75
|
+
options: Array.isArray(config.options) ? config.options.map((option) => normalizeChoiceOptionConfig(option)).filter((option) => option !== null) : []
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function createChoiceOptionConfig(existingOptions) {
|
|
79
|
+
const usedNumbers = new Set(existingOptions.map((option) => normalizeChoiceOptionKey(option.key ?? "").match(/^opt_(\d+)$/)?.[1]).filter((value) => value !== void 0).map((value) => Number.parseInt(value, 10)).filter((value) => Number.isFinite(value)));
|
|
80
|
+
let nextNumber = 1;
|
|
81
|
+
while (usedNumbers.has(nextNumber)) nextNumber += 1;
|
|
82
|
+
return {
|
|
83
|
+
id: generateId(),
|
|
84
|
+
key: `opt_${nextNumber}`
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function createDuplicatedChoiceOptionConfig(option, existingOptions) {
|
|
88
|
+
const generatedOption = createChoiceOptionConfig(existingOptions);
|
|
89
|
+
return {
|
|
90
|
+
...option,
|
|
91
|
+
id: generatedOption.id,
|
|
92
|
+
key: generatedOption.key,
|
|
93
|
+
embeddedForm: option.embeddedForm ? structuredCloneMethod(option.embeddedForm) : void 0
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function getDisplayOrder(items, shouldShuffle, seed) {
|
|
97
|
+
if (!shouldShuffle || items.length < 2) return [...items];
|
|
98
|
+
return shuffleArray(items, createSeededRandom(seed));
|
|
99
|
+
}
|
|
100
|
+
//#endregion
|
|
101
|
+
export { choiceIsSingleSelect, choiceOptionHasEmbeddedForm, createChoiceItemConfig, createChoiceOptionConfig, createDuplicatedChoiceOptionConfig, getChoiceOptionEmbeddedFormResponseKeyPathSegment, getChoiceOptionEmbeddedFormResponseSlotId, getChoiceOptionEmbeddedFormResponseSlotPrefix, getChoiceOptionEmbeddedFormTranslationPrefix, getChoiceOptionLabelContentKey, getChoiceResponseValueType, getDisplayOrder, normalizeChoiceItemConfig, normalizeChoiceOptionKey };
|
|
102
|
+
|
|
103
|
+
//# sourceMappingURL=choice.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"choice.mjs","names":[],"sources":["../src/choice.ts"],"sourcesContent":["import {\n createSeededRandom,\n generateId,\n shuffleArray,\n structuredCloneMethod,\n ValueType,\n} from \"@case-framework/survey-core\";\nimport { normalizeFormItemConfig, type FormItemConfig } from \"./form\";\n\n/** `1` = single selection (radio). `null` = multiple selection with no upper cap. Integers above 1 cap how many options may be selected. */\nexport type ChoiceMaxSelection = number | null;\n\nexport interface ChoiceOptionConfig {\n id: string;\n key?: string;\n hasDisplayCondition?: boolean;\n embeddedFormItemId?: string;\n embeddedForm?: FormItemConfig;\n}\n\nexport interface ChoiceItemConfig {\n id: string;\n maxSelection: ChoiceMaxSelection;\n shuffleOptions: boolean;\n options: ChoiceOptionConfig[];\n}\n\nexport function choiceIsSingleSelect(maxSelection: ChoiceMaxSelection): boolean {\n return maxSelection === 1;\n}\n\nexport function getChoiceResponseValueType(maxSelection: ChoiceMaxSelection): ValueType {\n return choiceIsSingleSelect(maxSelection) ? ValueType.reference : ValueType.referenceArray;\n}\n\nexport function createChoiceItemConfig(itemId: string): ChoiceItemConfig {\n return {\n id: itemId,\n maxSelection: 1,\n shuffleOptions: false,\n options: [],\n };\n}\n\nexport function getChoiceOptionLabelContentKey(optionId: string): string {\n return `options.${optionId}.label`;\n}\n\nexport function getChoiceOptionEmbeddedFormTranslationPrefix(optionId: string): string {\n return `embeddedForms.${optionId}`;\n}\n\nexport function getChoiceOptionEmbeddedFormResponseSlotPrefix(optionId: string): string {\n return `embedded.${optionId}`;\n}\n\nexport function getChoiceOptionEmbeddedFormResponseSlotId(\n optionId: string,\n fieldKey: string,\n): string {\n return `${getChoiceOptionEmbeddedFormResponseSlotPrefix(optionId)}.${fieldKey}`;\n}\n\nexport function getChoiceOptionEmbeddedFormResponseKeyPathSegment(\n option: Pick<ChoiceOptionConfig, \"id\" | \"key\">,\n): string {\n return normalizeChoiceOptionKey(option.key ?? \"\") || option.id;\n}\n\nexport function choiceOptionHasEmbeddedForm(\n option: Pick<ChoiceOptionConfig, \"embeddedFormItemId\" | \"embeddedForm\">,\n): boolean {\n return Boolean(option.embeddedFormItemId || option.embeddedForm?.fieldGroups.length);\n}\n\nexport function normalizeChoiceOptionKey(value: string): string {\n return value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"_\")\n .replace(/_+/g, \"_\")\n .replace(/^_+|_+$/g, \"\");\n}\n\nfunction normalizeChoiceOptionConfig(rawOption: unknown): ChoiceOptionConfig | null {\n if (!rawOption || typeof rawOption !== \"object\") {\n return null;\n }\n\n const option = rawOption as Partial<ChoiceOptionConfig>;\n const trimmedId = typeof option.id === \"string\" ? option.id.trim() : \"\";\n if (!trimmedId) {\n return null;\n }\n\n const trimmedKey = typeof option.key === \"string\" ? option.key.trim() : \"\";\n const trimmedEmbeddedFormItemId =\n typeof option.embeddedFormItemId === \"string\" ? option.embeddedFormItemId.trim() : \"\";\n\n return {\n id: trimmedId,\n key: trimmedKey || undefined,\n hasDisplayCondition: option.hasDisplayCondition === true ? true : undefined,\n embeddedFormItemId: trimmedEmbeddedFormItemId || undefined,\n embeddedForm: option.embeddedForm\n ? normalizeFormItemConfig(option.embeddedForm, trimmedId)\n : undefined,\n };\n}\n\nfunction normalizeMaxSelection(config: {\n maxSelection?: unknown;\n mode?: \"single\" | \"multiple\";\n}): ChoiceMaxSelection {\n const hasMaxSelectionKey = \"maxSelection\" in config && config.maxSelection !== undefined;\n const rawMax = config.maxSelection;\n\n if (rawMax === null) return null;\n if (typeof rawMax === \"number\" && Number.isFinite(rawMax)) {\n const n = Math.floor(rawMax);\n return n >= 1 ? n : 1;\n }\n if (typeof rawMax === \"string\") {\n const parsed = Number.parseInt(rawMax.trim(), 10);\n if (Number.isFinite(parsed) && parsed >= 1) return parsed;\n }\n if (!hasMaxSelectionKey && config.mode === \"multiple\") return null;\n return 1;\n}\n\nexport function normalizeChoiceItemConfig(rawConfig: unknown, itemId: string): ChoiceItemConfig {\n const config = (rawConfig ?? {}) as Partial<ChoiceItemConfig> & {\n mode?: \"single\" | \"multiple\";\n };\n\n return {\n id: typeof config.id === \"string\" && config.id.trim() ? config.id : itemId,\n maxSelection: normalizeMaxSelection(config),\n shuffleOptions: config.shuffleOptions === true,\n options: Array.isArray(config.options)\n ? config.options\n .map((option) => normalizeChoiceOptionConfig(option))\n .filter((option): option is ChoiceOptionConfig => option !== null)\n : [],\n };\n}\n\nexport function createChoiceOptionConfig(\n existingOptions: ChoiceOptionConfig[],\n): ChoiceOptionConfig {\n const usedNumbers = new Set(\n existingOptions\n .map((option) => normalizeChoiceOptionKey(option.key ?? \"\").match(/^opt_(\\d+)$/)?.[1])\n .filter((value): value is string => value !== undefined)\n .map((value) => Number.parseInt(value, 10))\n .filter((value) => Number.isFinite(value)),\n );\n\n let nextNumber = 1;\n while (usedNumbers.has(nextNumber)) nextNumber += 1;\n\n return { id: generateId(), key: `opt_${nextNumber}` };\n}\n\nexport function createDuplicatedChoiceOptionConfig(\n option: ChoiceOptionConfig,\n existingOptions: ChoiceOptionConfig[],\n): ChoiceOptionConfig {\n const generatedOption = createChoiceOptionConfig(existingOptions);\n\n return {\n ...option,\n id: generatedOption.id,\n key: generatedOption.key,\n embeddedForm: option.embeddedForm ? structuredCloneMethod(option.embeddedForm) : undefined,\n };\n}\n\nexport function getDisplayOrder<T>(items: readonly T[], shouldShuffle: boolean, seed: string): T[] {\n if (!shouldShuffle || items.length < 2) return [...items];\n return shuffleArray(items, createSeededRandom(seed));\n}\n"],"mappings":"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"}
|
package/dist/form.d.mts
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { SurveyItemTranslations, ValueType } from "@case-framework/survey-core";
|
|
2
|
+
|
|
3
|
+
//#region src/form.d.ts
|
|
4
|
+
type FormFieldType = "input" | "textarea" | "number" | "datepicker" | "switch" | "select" | "slider";
|
|
5
|
+
declare const FORM_DATEPICKER_FIELD_MODES: readonly ["year", "year-month", "year-month-day"];
|
|
6
|
+
type FormDatepickerFieldMode = (typeof FORM_DATEPICKER_FIELD_MODES)[number];
|
|
7
|
+
declare function getFormFieldValueType(field: {
|
|
8
|
+
type?: unknown;
|
|
9
|
+
}): ValueType;
|
|
10
|
+
type FormFieldValidationType = "required" | "minLength" | "maxLength" | "pattern" | "email" | "url" | "integer" | "min" | "max" | "minDate" | "maxDate" | "mustBeTrue";
|
|
11
|
+
interface FormFieldValidationConfig {
|
|
12
|
+
id: string;
|
|
13
|
+
type: FormFieldValidationType;
|
|
14
|
+
value?: number | string;
|
|
15
|
+
message?: string;
|
|
16
|
+
}
|
|
17
|
+
type FormFieldEffectiveValidationType = "required" | FormFieldValidationType;
|
|
18
|
+
interface FormFieldEffectiveValidationConfig {
|
|
19
|
+
id: string;
|
|
20
|
+
type: FormFieldEffectiveValidationType;
|
|
21
|
+
value?: number | string;
|
|
22
|
+
message?: string;
|
|
23
|
+
source: "required" | "validation";
|
|
24
|
+
}
|
|
25
|
+
interface FormFieldSelectOptionConfig {
|
|
26
|
+
id: string;
|
|
27
|
+
value: string;
|
|
28
|
+
label?: string;
|
|
29
|
+
}
|
|
30
|
+
interface FormInputFieldControlConfig {
|
|
31
|
+
type: "input";
|
|
32
|
+
placeholder?: string;
|
|
33
|
+
inputMode?: "text" | "email" | "tel" | "url" | "password";
|
|
34
|
+
autocomplete?: string;
|
|
35
|
+
}
|
|
36
|
+
interface FormTextareaFieldControlConfig {
|
|
37
|
+
type: "textarea";
|
|
38
|
+
placeholder?: string;
|
|
39
|
+
rows?: number;
|
|
40
|
+
}
|
|
41
|
+
interface FormNumberFieldControlConfig {
|
|
42
|
+
type: "number";
|
|
43
|
+
placeholder?: string;
|
|
44
|
+
step?: number;
|
|
45
|
+
unit?: string;
|
|
46
|
+
defaultValue?: number;
|
|
47
|
+
}
|
|
48
|
+
interface FormDatepickerFieldControlConfig {
|
|
49
|
+
type: "datepicker";
|
|
50
|
+
placeholder?: string;
|
|
51
|
+
mode: FormDatepickerFieldMode;
|
|
52
|
+
}
|
|
53
|
+
interface FormSwitchFieldControlConfig {
|
|
54
|
+
type: "switch";
|
|
55
|
+
checkedLabel?: string;
|
|
56
|
+
uncheckedLabel?: string;
|
|
57
|
+
defaultChecked?: boolean;
|
|
58
|
+
}
|
|
59
|
+
interface FormSelectFieldControlConfig {
|
|
60
|
+
type: "select";
|
|
61
|
+
placeholder?: string;
|
|
62
|
+
allowClear?: boolean;
|
|
63
|
+
options: FormFieldSelectOptionConfig[];
|
|
64
|
+
}
|
|
65
|
+
interface FormSliderFieldControlConfig {
|
|
66
|
+
type: "slider";
|
|
67
|
+
min?: number;
|
|
68
|
+
max?: number;
|
|
69
|
+
step?: number;
|
|
70
|
+
defaultValue?: number;
|
|
71
|
+
showValue?: boolean;
|
|
72
|
+
}
|
|
73
|
+
type FormFieldControlConfig = FormInputFieldControlConfig | FormTextareaFieldControlConfig | FormNumberFieldControlConfig | FormDatepickerFieldControlConfig | FormSwitchFieldControlConfig | FormSelectFieldControlConfig | FormSliderFieldControlConfig;
|
|
74
|
+
interface FormFieldConfig {
|
|
75
|
+
id: string;
|
|
76
|
+
key: string;
|
|
77
|
+
type: FormFieldType;
|
|
78
|
+
label?: string;
|
|
79
|
+
description?: string;
|
|
80
|
+
errorMessage?: string;
|
|
81
|
+
required?: boolean;
|
|
82
|
+
controller: FormFieldControlConfig;
|
|
83
|
+
validations: FormFieldValidationConfig[];
|
|
84
|
+
hasValidations?: boolean;
|
|
85
|
+
isInvalid?: boolean;
|
|
86
|
+
}
|
|
87
|
+
declare function getFormFieldEffectiveValidations(field: Pick<FormFieldConfig, "id" | "required" | "validations">): FormFieldEffectiveValidationConfig[];
|
|
88
|
+
/**
|
|
89
|
+
* Column counts keyed by field group card width (container), not the viewport.
|
|
90
|
+
* Breakpoints match `@container (width >= …)` on `form-field-group`: 20rem / 24rem / 28rem / 36rem.
|
|
91
|
+
*/
|
|
92
|
+
interface FormFieldGroupLayoutConfig {
|
|
93
|
+
/** Below @xs (under 20rem) */
|
|
94
|
+
base: number;
|
|
95
|
+
/** @xs — width >= 20rem */
|
|
96
|
+
xs: number;
|
|
97
|
+
/** @sm — width >= 24rem */
|
|
98
|
+
sm: number;
|
|
99
|
+
/** @md — width >= 28rem */
|
|
100
|
+
md: number;
|
|
101
|
+
/** @xl — width >= 36rem */
|
|
102
|
+
xl: number;
|
|
103
|
+
}
|
|
104
|
+
interface FormFieldGroupConfig {
|
|
105
|
+
id: string;
|
|
106
|
+
title?: string;
|
|
107
|
+
description?: string;
|
|
108
|
+
hasDisplayCondition?: boolean;
|
|
109
|
+
layout: FormFieldGroupLayoutConfig;
|
|
110
|
+
fields: FormFieldConfig[];
|
|
111
|
+
}
|
|
112
|
+
interface FormItemConfig {
|
|
113
|
+
id: string;
|
|
114
|
+
/** Editor-facing complexity level; it does not change participant behavior. */
|
|
115
|
+
authoringMode: "simple" | "custom";
|
|
116
|
+
fieldGroups: FormFieldGroupConfig[];
|
|
117
|
+
}
|
|
118
|
+
declare function createFormItemConfig(itemId: string): FormItemConfig;
|
|
119
|
+
declare function getFormFieldGroupTranslationPrefix(groupId: string, translationNamespace?: string): string;
|
|
120
|
+
declare function getFormFieldGroupTitleContentKey(groupId: string, translationNamespace?: string): string;
|
|
121
|
+
declare function getFormFieldGroupDescriptionContentKey(groupId: string, translationNamespace?: string): string;
|
|
122
|
+
declare function getFormFieldTranslationPrefix(fieldId: string, translationNamespace?: string): string;
|
|
123
|
+
declare function getFormFieldLabelContentKey(fieldId: string, translationNamespace?: string): string;
|
|
124
|
+
declare function getFormFieldDescriptionContentKey(fieldId: string, translationNamespace?: string): string;
|
|
125
|
+
declare function getFormFieldErrorMessageContentKey(fieldId: string, translationNamespace?: string): string;
|
|
126
|
+
declare function getFormFieldPlaceholderContentKey(fieldId: string, translationNamespace?: string): string;
|
|
127
|
+
declare function getFormFieldUnitContentKey(fieldId: string, translationNamespace?: string): string;
|
|
128
|
+
declare function getFormFieldCheckedLabelContentKey(fieldId: string, translationNamespace?: string): string;
|
|
129
|
+
declare function getFormFieldUncheckedLabelContentKey(fieldId: string, translationNamespace?: string): string;
|
|
130
|
+
declare function getFormFieldOptionLabelContentKey(fieldId: string, optionId: string, translationNamespace?: string): string;
|
|
131
|
+
declare function getFormFieldValidationMessageContentKey(fieldId: string, validationId: string, translationNamespace?: string): string;
|
|
132
|
+
declare function getFormFieldTranslationKeys(field: Pick<FormFieldConfig, "id" | "type" | "controller" | "validations">, translationNamespace?: string): string[];
|
|
133
|
+
declare function getFormFieldGroupTranslationKeys(group: Pick<FormFieldGroupConfig, "id">, translationNamespace?: string): string[];
|
|
134
|
+
declare function writeFormFieldGroupTranslations(itemTranslations: SurveyItemTranslations, locale: string, group: Pick<FormFieldGroupConfig, "id" | "title" | "description">, translationNamespace?: string): void;
|
|
135
|
+
declare function writeFormFieldTranslations(itemTranslations: SurveyItemTranslations, locale: string, field: Pick<FormFieldConfig, "id" | "type" | "label" | "description" | "errorMessage" | "controller" | "validations">, translationNamespace?: string): void;
|
|
136
|
+
declare function withFormItemTranslatedContent(config: FormItemConfig, itemTranslations: SurveyItemTranslations | undefined, locale: string, options?: {
|
|
137
|
+
fallbackLocale?: string;
|
|
138
|
+
translationNamespace?: string;
|
|
139
|
+
}): FormItemConfig;
|
|
140
|
+
declare function withoutFormItemTranslatedContent(config: FormItemConfig): FormItemConfig;
|
|
141
|
+
/** CSS custom properties for `.form-field-group-layout-scope` + `.form-field-group-grid`. */
|
|
142
|
+
declare function formFieldGroupLayoutCssVars(layout: FormFieldGroupLayoutConfig): Record<string, string>;
|
|
143
|
+
declare function normalizeFormItemConfig(rawConfig: unknown, itemId: string): FormItemConfig;
|
|
144
|
+
declare function createFormFieldGroupConfig(): FormFieldGroupConfig;
|
|
145
|
+
declare function getNextAvailableFormFieldKey(fields: Pick<FormFieldConfig, "key">[]): string;
|
|
146
|
+
declare function createFormFieldConfig(type: FormFieldType, key?: string): FormFieldConfig;
|
|
147
|
+
type FormAuthoringMode = FormItemConfig["authoringMode"];
|
|
148
|
+
declare const getFormAuthoringMode: (config: unknown) => FormAuthoringMode;
|
|
149
|
+
declare const hasSingleFormField: (config: unknown) => boolean;
|
|
150
|
+
declare const isValidSimpleFormConfig: (config: unknown) => boolean;
|
|
151
|
+
/**
|
|
152
|
+
* Canonicalizes the editor-facing mode without modifying groups, fields, or translations.
|
|
153
|
+
* Missing modes and malformed simple forms become custom; valid simple forms stay simple.
|
|
154
|
+
*/
|
|
155
|
+
declare const normalizeFormAuthoringConfig: (config: unknown) => Record<string, unknown> | undefined;
|
|
156
|
+
/**
|
|
157
|
+
* Returns true only for an in-place edit of the existing sole field that the simple editor can
|
|
158
|
+
* still represent. Adding, moving, retyping, or exposing hidden field configuration is structural.
|
|
159
|
+
*/
|
|
160
|
+
declare const isCompatibleSimpleFieldUpsert: ({
|
|
161
|
+
config,
|
|
162
|
+
field,
|
|
163
|
+
groupId,
|
|
164
|
+
index
|
|
165
|
+
}: {
|
|
166
|
+
config: unknown;
|
|
167
|
+
field: Record<string, unknown> & {
|
|
168
|
+
id: string;
|
|
169
|
+
key: string;
|
|
170
|
+
type: string;
|
|
171
|
+
};
|
|
172
|
+
groupId: string;
|
|
173
|
+
index?: number;
|
|
174
|
+
}) => boolean;
|
|
175
|
+
/** Structural form edits leave simple mode unless the sole field remains representable there. */
|
|
176
|
+
declare const transitionFormAuthoringMode: ({
|
|
177
|
+
config,
|
|
178
|
+
fieldGroups,
|
|
179
|
+
preserveSimpleMode
|
|
180
|
+
}: {
|
|
181
|
+
config: Record<string, unknown>;
|
|
182
|
+
fieldGroups: Record<string, unknown>[];
|
|
183
|
+
preserveSimpleMode?: boolean;
|
|
184
|
+
}) => Record<string, unknown>;
|
|
185
|
+
//#endregion
|
|
186
|
+
export { FORM_DATEPICKER_FIELD_MODES, FormAuthoringMode, FormDatepickerFieldControlConfig, FormDatepickerFieldMode, FormFieldConfig, FormFieldControlConfig, FormFieldEffectiveValidationConfig, FormFieldEffectiveValidationType, FormFieldGroupConfig, FormFieldGroupLayoutConfig, FormFieldSelectOptionConfig, FormFieldType, FormFieldValidationConfig, FormFieldValidationType, FormInputFieldControlConfig, FormItemConfig, FormNumberFieldControlConfig, FormSelectFieldControlConfig, FormSliderFieldControlConfig, FormSwitchFieldControlConfig, FormTextareaFieldControlConfig, createFormFieldConfig, createFormFieldGroupConfig, createFormItemConfig, formFieldGroupLayoutCssVars, getFormAuthoringMode, getFormFieldCheckedLabelContentKey, getFormFieldDescriptionContentKey, getFormFieldEffectiveValidations, getFormFieldErrorMessageContentKey, getFormFieldGroupDescriptionContentKey, getFormFieldGroupTitleContentKey, getFormFieldGroupTranslationKeys, getFormFieldGroupTranslationPrefix, getFormFieldLabelContentKey, getFormFieldOptionLabelContentKey, getFormFieldPlaceholderContentKey, getFormFieldTranslationKeys, getFormFieldTranslationPrefix, getFormFieldUncheckedLabelContentKey, getFormFieldUnitContentKey, getFormFieldValidationMessageContentKey, getFormFieldValueType, getNextAvailableFormFieldKey, hasSingleFormField, isCompatibleSimpleFieldUpsert, isValidSimpleFormConfig, normalizeFormAuthoringConfig, normalizeFormItemConfig, transitionFormAuthoringMode, withFormItemTranslatedContent, withoutFormItemTranslatedContent, writeFormFieldGroupTranslations, writeFormFieldTranslations };
|
|
187
|
+
//# sourceMappingURL=form.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form.d.mts","names":[],"sources":["../src/form.ts"],"mappings":"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"}
|