@webiny/app-admin 6.3.0-beta.2 → 6.3.0-beta.3
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/base/Base/DefaultFieldRenderers.js +69 -5
- package/base/Base/DefaultFieldRenderers.js.map +1 -1
- package/base/Base/DefaultLayoutRenderers.js +5 -1
- package/base/Base/DefaultLayoutRenderers.js.map +1 -1
- package/base/Base/FieldRenderers/CheckboxesRenderer.d.ts +13 -0
- package/base/Base/FieldRenderers/CheckboxesRenderer.js +28 -0
- package/base/Base/FieldRenderers/CheckboxesRenderer.js.map +1 -0
- package/base/Base/FieldRenderers/CodeEditorRenderer.d.ts +15 -0
- package/base/Base/FieldRenderers/CodeEditorRenderer.js +17 -0
- package/base/Base/FieldRenderers/CodeEditorRenderer.js.map +1 -0
- package/base/Base/FieldRenderers/DateTimeInputsRenderer.d.ts +17 -0
- package/base/Base/FieldRenderers/DateTimeInputsRenderer.js +66 -0
- package/base/Base/FieldRenderers/DateTimeInputsRenderer.js.map +1 -0
- package/base/Base/FieldRenderers/DateTimeRenderer.d.ts +21 -0
- package/base/Base/FieldRenderers/DateTimeRenderer.js +46 -0
- package/base/Base/FieldRenderers/DateTimeRenderer.js.map +1 -0
- package/base/Base/FieldRenderers/FilePickerRenderer.d.ts +12 -0
- package/base/Base/FieldRenderers/FilePickerRenderer.js +47 -0
- package/base/Base/FieldRenderers/FilePickerRenderer.js.map +1 -0
- package/base/Base/FieldRenderers/FileUrlPickerRenderer.d.ts +12 -0
- package/base/Base/FieldRenderers/FileUrlPickerRenderer.js +25 -0
- package/base/Base/FieldRenderers/FileUrlPickerRenderer.js.map +1 -0
- package/base/Base/FieldRenderers/HiddenRenderer.d.ts +12 -0
- package/base/Base/FieldRenderers/HiddenRenderer.js +5 -0
- package/base/Base/FieldRenderers/HiddenRenderer.js.map +1 -0
- package/base/Base/FieldRenderers/HorizontalTabsRenderer.d.ts +5 -0
- package/base/Base/FieldRenderers/HorizontalTabsRenderer.js +27 -0
- package/base/Base/FieldRenderers/HorizontalTabsRenderer.js.map +1 -0
- package/base/Base/FieldRenderers/InputRenderer.d.ts +4 -7
- package/base/Base/FieldRenderers/InputRenderer.js +2 -2
- package/base/Base/FieldRenderers/InputRenderer.js.map +1 -1
- package/base/Base/FieldRenderers/NumberInputRenderer.d.ts +12 -0
- package/base/Base/FieldRenderers/NumberInputRenderer.js +23 -0
- package/base/Base/FieldRenderers/NumberInputRenderer.js.map +1 -0
- package/base/Base/FieldRenderers/NumberInputsRenderer.d.ts +14 -0
- package/base/Base/FieldRenderers/NumberInputsRenderer.js +49 -0
- package/base/Base/FieldRenderers/NumberInputsRenderer.js.map +1 -0
- package/base/Base/FieldRenderers/ObjectRenderer/DynamicZoneRenderer.d.ts +14 -0
- package/base/Base/FieldRenderers/ObjectRenderer/DynamicZoneRenderer.js +20 -0
- package/base/Base/FieldRenderers/ObjectRenderer/DynamicZoneRenderer.js.map +1 -0
- package/base/Base/FieldRenderers/ObjectRenderer/KeyValueTagsRenderer.d.ts +14 -0
- package/base/Base/FieldRenderers/ObjectRenderer/KeyValueTagsRenderer.js +65 -0
- package/base/Base/FieldRenderers/ObjectRenderer/KeyValueTagsRenderer.js.map +1 -0
- package/base/Base/FieldRenderers/ObjectRenderer/MultiValueDynamicZone.d.ts +10 -0
- package/base/Base/FieldRenderers/ObjectRenderer/MultiValueDynamicZone.js +109 -0
- package/base/Base/FieldRenderers/ObjectRenderer/MultiValueDynamicZone.js.map +1 -0
- package/base/Base/FieldRenderers/ObjectRenderer/ObjectAccordionMultipleRenderer.d.ts +17 -0
- package/base/Base/FieldRenderers/ObjectRenderer/ObjectAccordionMultipleRenderer.js +55 -0
- package/base/Base/FieldRenderers/ObjectRenderer/ObjectAccordionMultipleRenderer.js.map +1 -0
- package/base/Base/FieldRenderers/ObjectRenderer/ObjectFieldComponents.d.ts +7 -3
- package/base/Base/FieldRenderers/ObjectRenderer/ObjectFieldComponents.js +15 -19
- package/base/Base/FieldRenderers/ObjectRenderer/ObjectFieldComponents.js.map +1 -1
- package/base/Base/FieldRenderers/ObjectRenderer/ObjectRenderer.d.ts +5 -8
- package/base/Base/FieldRenderers/ObjectRenderer/ObjectRenderer.js +7 -50
- package/base/Base/FieldRenderers/ObjectRenderer/ObjectRenderer.js.map +1 -1
- package/base/Base/FieldRenderers/ObjectRenderer/SingleValueDynamicZone.d.ts +10 -0
- package/base/Base/FieldRenderers/ObjectRenderer/SingleValueDynamicZone.js +64 -0
- package/base/Base/FieldRenderers/ObjectRenderer/SingleValueDynamicZone.js.map +1 -0
- package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker.d.ts +10 -0
- package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker.js +85 -0
- package/base/Base/FieldRenderers/ObjectRenderer/TemplatePicker.js.map +1 -0
- package/base/Base/FieldRenderers/PassthroughRenderer.d.ts +3 -6
- package/base/Base/FieldRenderers/PassthroughRenderer.js +9 -23
- package/base/Base/FieldRenderers/PassthroughRenderer.js.map +1 -1
- package/base/Base/FieldRenderers/RadioButtonsRenderer.d.ts +13 -0
- package/base/Base/FieldRenderers/RadioButtonsRenderer.js +27 -0
- package/base/Base/FieldRenderers/RadioButtonsRenderer.js.map +1 -0
- package/base/Base/FieldRenderers/SelectRenderer.d.ts +6 -8
- package/base/Base/FieldRenderers/SelectRenderer.js +8 -5
- package/base/Base/FieldRenderers/SelectRenderer.js.map +1 -1
- package/base/Base/FieldRenderers/SwitchRenderer.d.ts +12 -0
- package/base/Base/FieldRenderers/SwitchRenderer.js +19 -0
- package/base/Base/FieldRenderers/SwitchRenderer.js.map +1 -0
- package/base/Base/FieldRenderers/TagsRenderer.d.ts +12 -0
- package/base/Base/FieldRenderers/TagsRenderer.js +21 -0
- package/base/Base/FieldRenderers/TagsRenderer.js.map +1 -0
- package/base/Base/FieldRenderers/TextInputsRenderer.d.ts +14 -0
- package/base/Base/FieldRenderers/TextInputsRenderer.js +48 -0
- package/base/Base/FieldRenderers/TextInputsRenderer.js.map +1 -0
- package/base/Base/FieldRenderers/TextareaRenderer.d.ts +3 -6
- package/base/Base/FieldRenderers/TextareaRenderer.js +3 -4
- package/base/Base/FieldRenderers/TextareaRenderer.js.map +1 -1
- package/base/Base/FieldRenderers/TextareasRenderer.d.ts +14 -0
- package/base/Base/FieldRenderers/TextareasRenderer.js +51 -0
- package/base/Base/FieldRenderers/TextareasRenderer.js.map +1 -0
- package/base/Base/FieldRenderers/VerticalTabsRenderer.js +2 -2
- package/base/Base/FieldRenderers/VerticalTabsRenderer.js.map +1 -1
- package/base/Base/Menus.js +5 -64
- package/base/Base/Menus.js.map +1 -1
- package/base/Base/RoutesConfig.js +6 -0
- package/base/Base/RoutesConfig.js.map +1 -1
- package/exports/admin/build-params.d.ts +2 -0
- package/exports/admin/build-params.js +3 -0
- package/exports/admin/build-params.js.map +1 -1
- package/exports/admin/form.d.ts +5 -0
- package/exports/admin/form.js +8 -0
- package/exports/admin/form.js.map +1 -1
- package/exports/admin/ui.d.ts +1 -0
- package/exports/admin/ui.js +1 -0
- package/exports/admin/ui.js.map +1 -1
- package/exports/admin.d.ts +3 -1
- package/exports/admin.js +3 -1
- package/exports/admin.js.map +1 -1
- package/features/formModel/ConditionRuleEvaluator.d.ts +9 -0
- package/features/formModel/ConditionRuleEvaluator.js +56 -0
- package/features/formModel/ConditionRuleEvaluator.js.map +1 -0
- package/features/formModel/Field.d.ts +50 -4
- package/features/formModel/Field.js +254 -35
- package/features/formModel/Field.js.map +1 -1
- package/features/formModel/FieldBuilder.d.ts +17 -35
- package/features/formModel/FieldBuilder.js +63 -100
- package/features/formModel/FieldBuilder.js.map +1 -1
- package/features/formModel/FieldBuilder.test.js +127 -13
- package/features/formModel/FieldBuilder.test.js.map +1 -1
- package/features/formModel/FieldBuilderRegistry.d.ts +4 -0
- package/features/formModel/FieldBuilderRegistry.js +31 -0
- package/features/formModel/FieldBuilderRegistry.js.map +1 -0
- package/features/formModel/FocusManager.d.ts +14 -0
- package/features/formModel/FocusManager.js +109 -0
- package/features/formModel/FocusManager.js.map +1 -0
- package/features/formModel/FormModel.d.ts +27 -31
- package/features/formModel/FormModel.js +210 -403
- package/features/formModel/FormModel.js.map +1 -1
- package/features/formModel/FormModel.test.js +2044 -193
- package/features/formModel/FormModel.test.js.map +1 -1
- package/features/formModel/FormModelFactory.d.ts +4 -2
- package/features/formModel/FormModelFactory.js +13 -3
- package/features/formModel/FormModelFactory.js.map +1 -1
- package/features/formModel/FormView.d.ts +2 -0
- package/features/formModel/FormView.js +44 -37
- package/features/formModel/FormView.js.map +1 -1
- package/features/formModel/LayoutBuilderFactory.d.ts +61 -0
- package/features/formModel/LayoutBuilderFactory.js +386 -0
- package/features/formModel/LayoutBuilderFactory.js.map +1 -0
- package/features/formModel/LayoutMutator.d.ts +11 -0
- package/features/formModel/LayoutMutator.js +136 -0
- package/features/formModel/LayoutMutator.js.map +1 -0
- package/features/formModel/LayoutResolver.d.ts +26 -0
- package/features/formModel/LayoutResolver.js +239 -0
- package/features/formModel/LayoutResolver.js.map +1 -0
- package/features/formModel/ObjectField.d.ts +55 -4
- package/features/formModel/ObjectField.js +499 -82
- package/features/formModel/ObjectField.js.map +1 -1
- package/features/formModel/Rules.test.d.ts +1 -0
- package/features/formModel/Rules.test.js +289 -0
- package/features/formModel/Rules.test.js.map +1 -0
- package/features/formModel/abstractions.d.ts +402 -52
- package/features/formModel/abstractions.js +55 -0
- package/features/formModel/abstractions.js.map +1 -1
- package/features/formModel/createFieldRenderer.d.ts +20 -0
- package/features/formModel/createFieldRenderer.js +15 -0
- package/features/formModel/createFieldRenderer.js.map +1 -0
- package/features/formModel/demo/FieldRenderersDemoPresenter.d.ts +18 -0
- package/features/formModel/demo/FieldRenderersDemoPresenter.js +225 -0
- package/features/formModel/demo/FieldRenderersDemoPresenter.js.map +1 -0
- package/features/formModel/demo/FormModelDemo.d.ts +4 -0
- package/features/formModel/demo/FormModelDemo.js +230 -0
- package/features/formModel/demo/FormModelDemo.js.map +1 -0
- package/features/formModel/demo/FormModelDemoPresenter.d.ts +22 -0
- package/features/formModel/demo/FormModelDemoPresenter.js +121 -0
- package/features/formModel/demo/FormModelDemoPresenter.js.map +1 -0
- package/features/formModel/demo/FormModelPhase11Presenter.d.ts +25 -0
- package/features/formModel/demo/FormModelPhase11Presenter.js +104 -0
- package/features/formModel/demo/FormModelPhase11Presenter.js.map +1 -0
- package/features/formModel/demo/FormModelPhase8c1Presenter.d.ts +23 -0
- package/features/formModel/demo/FormModelPhase8c1Presenter.js +62 -0
- package/features/formModel/demo/FormModelPhase8c1Presenter.js.map +1 -0
- package/features/formModel/feature.js +12 -0
- package/features/formModel/feature.js.map +1 -1
- package/features/formModel/fieldTypes/BooleanFieldType.d.ts +19 -0
- package/features/formModel/fieldTypes/BooleanFieldType.js +23 -0
- package/features/formModel/fieldTypes/BooleanFieldType.js.map +1 -0
- package/features/formModel/fieldTypes/DateTimeFieldType.d.ts +173 -0
- package/features/formModel/fieldTypes/DateTimeFieldType.js +369 -0
- package/features/formModel/fieldTypes/DateTimeFieldType.js.map +1 -0
- package/features/formModel/fieldTypes/FileFieldType.d.ts +18 -0
- package/features/formModel/fieldTypes/FileFieldType.js +20 -0
- package/features/formModel/fieldTypes/FileFieldType.js.map +1 -0
- package/features/formModel/fieldTypes/FileUrlFieldType.d.ts +18 -0
- package/features/formModel/fieldTypes/FileUrlFieldType.js +20 -0
- package/features/formModel/fieldTypes/FileUrlFieldType.js.map +1 -0
- package/features/formModel/fieldTypes/NumberFieldType.d.ts +19 -0
- package/features/formModel/fieldTypes/NumberFieldType.js +27 -0
- package/features/formModel/fieldTypes/NumberFieldType.js.map +1 -0
- package/features/formModel/fieldTypes/ObjectFieldType.d.ts +34 -0
- package/features/formModel/fieldTypes/ObjectFieldType.js +109 -0
- package/features/formModel/fieldTypes/ObjectFieldType.js.map +1 -0
- package/features/formModel/fieldTypes/TextFieldType.d.ts +18 -0
- package/features/formModel/fieldTypes/TextFieldType.js +20 -0
- package/features/formModel/fieldTypes/TextFieldType.js.map +1 -0
- package/features/formModel/fieldTypes/index.d.ts +7 -0
- package/features/formModel/fieldTypes/index.js +9 -0
- package/features/formModel/fieldTypes/index.js.map +1 -0
- package/features/formModel/index.d.ts +13 -4
- package/features/formModel/index.js +21 -2
- package/features/formModel/index.js.map +1 -1
- package/features/formModel/renderers.d.ts +15 -1
- package/features/formModel/renderers.js +15 -1
- package/features/formModel/renderers.js.map +1 -1
- package/features/tools/LexicalContext/LexicalContext.d.ts +14 -0
- package/features/tools/LexicalContext/LexicalContext.js +22 -0
- package/features/tools/LexicalContext/LexicalContext.js.map +1 -0
- package/features/tools/LexicalContext/abstractions.d.ts +11 -0
- package/features/tools/LexicalContext/abstractions.js +4 -0
- package/features/tools/LexicalContext/abstractions.js.map +1 -0
- package/features/tools/LexicalContext/index.d.ts +2 -0
- package/features/tools/LexicalContext/index.js +3 -0
- package/features/tools/LexicalContext/index.js.map +1 -0
- package/features/tools/feature.js +2 -0
- package/features/tools/feature.js.map +1 -1
- package/features/tools/index.d.ts +1 -0
- package/features/tools/index.js +1 -0
- package/features/tools/index.js.map +1 -1
- package/index.d.ts +8 -1
- package/index.js +7 -0
- package/index.js.map +1 -1
- package/package.json +30 -24
- package/presentation/installation/components/SystemInstaller/steps/AdminUserStep/createPasswordValidator.js +1 -1
- package/presentation/installation/components/SystemInstaller/steps/AdminUserStep/createPasswordValidator.js.map +1 -1
- package/presentation/lexicalContext/useLexicalContext.d.ts +3 -0
- package/presentation/lexicalContext/useLexicalContext.js +14 -0
- package/presentation/lexicalContext/useLexicalContext.js.map +1 -0
- package/presentation/textToLexicalTool/TextToLexicalTool.d.ts +3 -0
- package/presentation/textToLexicalTool/TextToLexicalTool.js +6 -2
- package/presentation/textToLexicalTool/TextToLexicalTool.js.map +1 -1
- package/presentation/textToLexicalTool/textToLexicalState.d.ts +2 -1
- package/presentation/textToLexicalTool/textToLexicalState.js +15 -3
- package/presentation/textToLexicalTool/textToLexicalState.js.map +1 -1
- package/routes.d.ts +1 -0
- package/routes.js +4 -0
- package/routes.js.map +1 -1
- package/base/Base/FieldRenderers/ObjectRenderer/ObjectListFlatRenderer.d.ts +0 -21
- package/base/Base/FieldRenderers/ObjectRenderer/ObjectListFlatRenderer.js +0 -28
- package/base/Base/FieldRenderers/ObjectRenderer/ObjectListFlatRenderer.js.map +0 -1
|
@@ -1,83 +1,97 @@
|
|
|
1
1
|
import { makeAutoObservable, computed, toJS, runInAction, observable } from "mobx";
|
|
2
2
|
import { Field } from "./Field.js";
|
|
3
3
|
import { ObjectField, isObjectField } from "./ObjectField.js";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
type: "row",
|
|
9
|
-
fieldIds
|
|
10
|
-
};
|
|
11
|
-
},
|
|
12
|
-
separator() {
|
|
13
|
-
return {
|
|
14
|
-
type: "separator"
|
|
15
|
-
};
|
|
16
|
-
},
|
|
17
|
-
tabs(config) {
|
|
18
|
-
return {
|
|
19
|
-
type: "tabs",
|
|
20
|
-
id: config.id,
|
|
21
|
-
renderer: config.renderer,
|
|
22
|
-
tabs: config.tabs
|
|
23
|
-
};
|
|
24
|
-
},
|
|
25
|
-
element(renderer, props) {
|
|
26
|
-
return {
|
|
27
|
-
type: "element",
|
|
28
|
-
renderer,
|
|
29
|
-
props
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
};
|
|
4
|
+
import { LayoutBuilderFactory } from "./LayoutBuilderFactory.js";
|
|
5
|
+
import { LayoutMutator } from "./LayoutMutator.js";
|
|
6
|
+
import { LayoutResolver } from "./LayoutResolver.js";
|
|
7
|
+
import { FocusManager } from "./FocusManager.js";
|
|
33
8
|
export class FormModel {
|
|
34
9
|
_fields = new Map();
|
|
10
|
+
_builders = new Map();
|
|
35
11
|
_layout = [];
|
|
36
12
|
_baseline = new Map();
|
|
37
13
|
_submitted = false;
|
|
38
14
|
_validateOnChange = false;
|
|
39
15
|
_isValid = null;
|
|
40
|
-
|
|
16
|
+
_formRuleErrors = [];
|
|
41
17
|
_activeTabs = observable.map();
|
|
42
|
-
|
|
43
|
-
|
|
18
|
+
_ruleEvaluators = [];
|
|
19
|
+
_warnedRuleTypes = new Set();
|
|
20
|
+
_formRules = [];
|
|
21
|
+
_lastFocusedField = null;
|
|
22
|
+
_layoutMutator = new LayoutMutator();
|
|
23
|
+
_layoutResolver = null;
|
|
24
|
+
_focusManager = null;
|
|
25
|
+
constructor(config, registry) {
|
|
26
|
+
this._registry = registry;
|
|
27
|
+
this._ruleEvaluators = config.ruleEvaluators ?? [];
|
|
44
28
|
const builders = config.fields(registry);
|
|
45
|
-
|
|
46
|
-
// Build fields from builders
|
|
47
29
|
for (const [name, builder] of Object.entries(builders)) {
|
|
30
|
+
this._builders.set(name, builder);
|
|
48
31
|
const fieldConfig = builder.build(name);
|
|
49
32
|
const field = this._createField(fieldConfig);
|
|
50
33
|
field.setForm(this);
|
|
51
34
|
this._fields.set(name, field);
|
|
52
35
|
}
|
|
53
|
-
|
|
54
|
-
// Build layout
|
|
55
36
|
if (config.layout) {
|
|
56
|
-
this._layout = config.layout(
|
|
37
|
+
this._layout = LayoutBuilderFactory.buildNodes(config.layout(LayoutBuilderFactory.create()));
|
|
57
38
|
this._warnOrphanFields();
|
|
58
39
|
} else {
|
|
59
40
|
this._layout = this._generateDefaultLayout();
|
|
60
41
|
}
|
|
61
|
-
|
|
62
|
-
|
|
42
|
+
this._registerObjectNodeLayouts(this._layout);
|
|
43
|
+
this._propagateAncestorRules();
|
|
63
44
|
this._validateOnChange = config.validateOnSubmit === false;
|
|
64
|
-
|
|
65
|
-
// Snapshot baseline from defaults
|
|
66
45
|
this._snapshotBaseline();
|
|
67
46
|
makeAutoObservable(this, {
|
|
68
|
-
vm: computed
|
|
47
|
+
vm: computed,
|
|
48
|
+
_layoutMutator: false,
|
|
49
|
+
_layoutResolver: false,
|
|
50
|
+
_focusManager: false
|
|
69
51
|
}, {
|
|
70
52
|
autoBind: true
|
|
71
53
|
});
|
|
54
|
+
this._layoutResolver = new LayoutResolver(this._fields, this._activeTabs, this.evaluateRules.bind(this));
|
|
55
|
+
this._focusManager = new FocusManager(this._fields);
|
|
56
|
+
}
|
|
57
|
+
evaluateRules(rules) {
|
|
58
|
+
let visible = true;
|
|
59
|
+
let disabled = false;
|
|
60
|
+
if (!rules || rules.length === 0) {
|
|
61
|
+
return {
|
|
62
|
+
visible,
|
|
63
|
+
disabled
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
for (const rule of rules) {
|
|
67
|
+
const evaluator = this._ruleEvaluators.find(e => e.canEvaluate(rule));
|
|
68
|
+
if (!evaluator) {
|
|
69
|
+
if (process.env.NODE_ENV === "development" && !this._warnedRuleTypes.has(rule.type)) {
|
|
70
|
+
this._warnedRuleTypes.add(rule.type);
|
|
71
|
+
console.warn(`[FormModel] No evaluator registered for rule type "${rule.type}". Rule is ignored.`);
|
|
72
|
+
}
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const matched = evaluator.evaluate(rule, this);
|
|
76
|
+
if (!matched) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (rule.action === "hide") {
|
|
80
|
+
visible = false;
|
|
81
|
+
} else if (rule.action === "disable") {
|
|
82
|
+
disabled = true;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
visible,
|
|
87
|
+
disabled
|
|
88
|
+
};
|
|
72
89
|
}
|
|
73
90
|
field(name) {
|
|
74
|
-
// Try exact match first (supports dotted field names like "properties.language").
|
|
75
91
|
const field = this._fields.get(name);
|
|
76
92
|
if (field) {
|
|
77
93
|
return field;
|
|
78
94
|
}
|
|
79
|
-
|
|
80
|
-
// Try dot-notation traversal through ObjectField children.
|
|
81
95
|
const parts = name.split(".");
|
|
82
96
|
if (parts.length > 1) {
|
|
83
97
|
let current = this._fields.get(parts[0]);
|
|
@@ -94,63 +108,59 @@ export class FormModel {
|
|
|
94
108
|
}
|
|
95
109
|
throw new Error(`Field "${name}" not found.`);
|
|
96
110
|
}
|
|
111
|
+
focusField(name) {
|
|
112
|
+
if (this._lastFocusedField) {
|
|
113
|
+
this._lastFocusedField.clearFocusRequest();
|
|
114
|
+
this._lastFocusedField = null;
|
|
115
|
+
}
|
|
116
|
+
const activations = this._focusManager.buildFocusPath(name, this._layout);
|
|
117
|
+
let field;
|
|
118
|
+
try {
|
|
119
|
+
field = this.field(name);
|
|
120
|
+
} catch {
|
|
121
|
+
// Field not found — no-op.
|
|
122
|
+
}
|
|
123
|
+
runInAction(() => {
|
|
124
|
+
if (activations) {
|
|
125
|
+
for (const act of activations) {
|
|
126
|
+
this._activeTabs.set(act.tabKey, act.tabId);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (field) {
|
|
130
|
+
field.requestFocus();
|
|
131
|
+
this._lastFocusedField = field;
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
97
135
|
fields(factory) {
|
|
98
|
-
const
|
|
99
|
-
const builders = factory(registry);
|
|
136
|
+
const builders = factory(this._registry);
|
|
100
137
|
for (const [name, builder] of Object.entries(builders)) {
|
|
101
138
|
if (builder === undefined) {
|
|
102
|
-
|
|
139
|
+
this._builders.delete(name);
|
|
103
140
|
this.removeField(name);
|
|
104
141
|
continue;
|
|
105
142
|
}
|
|
143
|
+
this._builders.set(name, builder);
|
|
106
144
|
const fieldConfig = builder.build(name);
|
|
107
145
|
const field = this._createField(fieldConfig);
|
|
108
146
|
field.setForm(this);
|
|
109
|
-
|
|
110
|
-
// Replace or add — same operation on the map
|
|
111
147
|
this._fields.set(name, field);
|
|
112
148
|
}
|
|
113
|
-
|
|
114
|
-
// Re-snapshot baseline to include new fields
|
|
115
149
|
this._snapshotBaseline();
|
|
150
|
+
this._propagateAncestorRules();
|
|
116
151
|
}
|
|
117
152
|
layout(factoryOrNodeId) {
|
|
118
153
|
if (typeof factoryOrNodeId === "string") {
|
|
119
|
-
return this.
|
|
120
|
-
}
|
|
121
|
-
const factory = factoryOrNodeId;
|
|
122
|
-
const removals = [];
|
|
123
|
-
const modifierLayoutAPI = this._createModifierLayoutAPI(removals);
|
|
124
|
-
const entries = factory(modifierLayoutAPI);
|
|
125
|
-
|
|
126
|
-
// Process removals first
|
|
127
|
-
for (const target of removals) {
|
|
128
|
-
this._layout = this._removeFromLayout(this._layout, target);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Process additions with positional modifiers
|
|
132
|
-
for (const entry of entries) {
|
|
133
|
-
if (this._isPositionedNode(entry)) {
|
|
134
|
-
const {
|
|
135
|
-
node,
|
|
136
|
-
position
|
|
137
|
-
} = entry;
|
|
138
|
-
if (position) {
|
|
139
|
-
this._layout = this._insertIntoLayout(this._layout, node, position);
|
|
140
|
-
} else {
|
|
141
|
-
this._layout.push(node);
|
|
142
|
-
}
|
|
143
|
-
} else {
|
|
144
|
-
this._layout.push(entry);
|
|
145
|
-
}
|
|
154
|
+
return this._layoutMutator.accessNode(this._layout, factoryOrNodeId);
|
|
146
155
|
}
|
|
156
|
+
this._layout = this._layoutMutator.applyModifications(this._layout, factoryOrNodeId);
|
|
157
|
+
this._registerObjectNodeLayouts(this._layout);
|
|
158
|
+
this._propagateAncestorRules();
|
|
147
159
|
}
|
|
148
160
|
removeField(name) {
|
|
149
161
|
this._fields.delete(name);
|
|
150
162
|
this._baseline.delete(name);
|
|
151
|
-
|
|
152
|
-
// Remove from layout
|
|
153
|
-
this._layout = this._removeFromLayout(this._layout, name);
|
|
163
|
+
this._layout = this._layoutMutator.removeFromLayout(this._layout, name);
|
|
154
164
|
}
|
|
155
165
|
getData() {
|
|
156
166
|
const data = {};
|
|
@@ -174,7 +184,7 @@ export class FormModel {
|
|
|
174
184
|
this._resetAllValidation();
|
|
175
185
|
this._submitted = false;
|
|
176
186
|
this._isValid = null;
|
|
177
|
-
this.
|
|
187
|
+
this._formRuleErrors = [];
|
|
178
188
|
}
|
|
179
189
|
reset() {
|
|
180
190
|
for (const [name, field] of this._fields) {
|
|
@@ -184,7 +194,7 @@ export class FormModel {
|
|
|
184
194
|
this._resetAllValidation();
|
|
185
195
|
this._submitted = false;
|
|
186
196
|
this._isValid = null;
|
|
187
|
-
this.
|
|
197
|
+
this._formRuleErrors = [];
|
|
188
198
|
}
|
|
189
199
|
get isDirty() {
|
|
190
200
|
for (const [name, field] of this._fields) {
|
|
@@ -199,14 +209,17 @@ export class FormModel {
|
|
|
199
209
|
get isValid() {
|
|
200
210
|
return this._isValid;
|
|
201
211
|
}
|
|
202
|
-
get
|
|
203
|
-
return this.
|
|
212
|
+
get submitted() {
|
|
213
|
+
return this._submitted;
|
|
204
214
|
}
|
|
205
|
-
|
|
215
|
+
get errors() {
|
|
216
|
+
if (!this._submitted) {
|
|
217
|
+
return [];
|
|
218
|
+
}
|
|
219
|
+
const ruleErrorPaths = new Set(this._formRuleErrors.filter(e => e.path).map(e => e.path));
|
|
206
220
|
const errors = [];
|
|
207
221
|
for (const [, field] of this._fields) {
|
|
208
|
-
|
|
209
|
-
if (!valid) {
|
|
222
|
+
if (field.vm.validation.isValid === false && !ruleErrorPaths.has(field.name)) {
|
|
210
223
|
errors.push({
|
|
211
224
|
path: field.name,
|
|
212
225
|
label: field.config.label,
|
|
@@ -214,9 +227,46 @@ export class FormModel {
|
|
|
214
227
|
});
|
|
215
228
|
}
|
|
216
229
|
}
|
|
217
|
-
|
|
230
|
+
return [...errors, ...this._formRuleErrors];
|
|
231
|
+
}
|
|
232
|
+
addRule(rule) {
|
|
233
|
+
this._formRules.push(rule);
|
|
234
|
+
}
|
|
235
|
+
setLayout(factory) {
|
|
236
|
+
this._layout = LayoutBuilderFactory.buildNodes(factory(LayoutBuilderFactory.create()));
|
|
237
|
+
this._warnOrphanFields();
|
|
238
|
+
this._registerObjectNodeLayouts(this._layout);
|
|
239
|
+
this._propagateAncestorRules();
|
|
240
|
+
}
|
|
241
|
+
async validate() {
|
|
242
|
+
let allFieldsValid = true;
|
|
243
|
+
for (const [, field] of this._fields) {
|
|
244
|
+
const valid = await field.validate({
|
|
245
|
+
force: true
|
|
246
|
+
});
|
|
247
|
+
if (!valid) {
|
|
248
|
+
allFieldsValid = false;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
const ruleErrors = [];
|
|
252
|
+
for (const rule of this._formRules) {
|
|
253
|
+
const errors = await this._runFormRule(rule);
|
|
254
|
+
for (const err of errors) {
|
|
255
|
+
ruleErrors.push(err);
|
|
256
|
+
if (err.path) {
|
|
257
|
+
const target = this._tryGetField(err.path);
|
|
258
|
+
if (target) {
|
|
259
|
+
target.setValidation({
|
|
260
|
+
isValid: false,
|
|
261
|
+
message: err.message
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
const isValid = allFieldsValid && ruleErrors.length === 0;
|
|
218
268
|
runInAction(() => {
|
|
219
|
-
this.
|
|
269
|
+
this._formRuleErrors = ruleErrors;
|
|
220
270
|
this._isValid = isValid;
|
|
221
271
|
this._submitted = true;
|
|
222
272
|
});
|
|
@@ -231,121 +281,97 @@ export class FormModel {
|
|
|
231
281
|
}
|
|
232
282
|
get vm() {
|
|
233
283
|
return {
|
|
234
|
-
layout: this.
|
|
235
|
-
errors: this.
|
|
284
|
+
layout: this._layoutResolver.resolve(this._layout),
|
|
285
|
+
errors: this.errors,
|
|
236
286
|
isDirty: this.isDirty,
|
|
237
287
|
isValid: this._isValid
|
|
238
288
|
};
|
|
239
289
|
}
|
|
290
|
+
get registry() {
|
|
291
|
+
return this._registry;
|
|
292
|
+
}
|
|
293
|
+
resolveChildLayout(layout, children) {
|
|
294
|
+
return this._layoutResolver.resolveChildLayout(layout, children);
|
|
295
|
+
}
|
|
240
296
|
getField(name) {
|
|
241
297
|
return this._fields.get(name);
|
|
242
298
|
}
|
|
243
299
|
getFields() {
|
|
244
300
|
return this._fields;
|
|
245
301
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
case "row":
|
|
252
|
-
return this._resolveRowNode(node);
|
|
253
|
-
case "separator":
|
|
254
|
-
return this._resolveSeparatorNode();
|
|
255
|
-
case "tabs":
|
|
256
|
-
return this._resolveTabsNode(node);
|
|
257
|
-
case "element":
|
|
258
|
-
return this._resolveElementNode(node);
|
|
259
|
-
default:
|
|
260
|
-
return null;
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
_resolveRowNode(node) {
|
|
264
|
-
const fields = node.fieldIds.map(id => this._fields.get(id)).filter(f => f !== undefined && f.visible).map(f => f.vm);
|
|
265
|
-
if (fields.length === 0) {
|
|
266
|
-
return null;
|
|
267
|
-
}
|
|
268
|
-
return {
|
|
269
|
-
type: "row",
|
|
270
|
-
fields
|
|
271
|
-
};
|
|
272
|
-
}
|
|
273
|
-
_resolveSeparatorNode() {
|
|
274
|
-
return {
|
|
275
|
-
type: "separator"
|
|
276
|
-
};
|
|
302
|
+
getFieldBuilders(predicate) {
|
|
303
|
+
const pred = predicate ?? (() => true);
|
|
304
|
+
const result = [];
|
|
305
|
+
LayoutBuilderFactory.collectBuilders(this._fields, this._builders, pred, result);
|
|
306
|
+
return result;
|
|
277
307
|
}
|
|
278
|
-
|
|
279
|
-
if (
|
|
280
|
-
|
|
308
|
+
async _runFormRule(rule) {
|
|
309
|
+
if (typeof rule === "function") {
|
|
310
|
+
const fn = rule;
|
|
311
|
+
const result = await fn(this);
|
|
312
|
+
return Array.isArray(result) ? result : [];
|
|
281
313
|
}
|
|
282
|
-
const
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
description: tab.description,
|
|
287
|
-
icon: tab.icon,
|
|
288
|
-
hasErrors: this._tabHasErrors(tab.layout),
|
|
289
|
-
layout: tab.layout.map(child => this._resolveLayoutNode(child)).filter(Boolean)
|
|
290
|
-
}));
|
|
291
|
-
if (tabs.length === 0) {
|
|
292
|
-
return null;
|
|
314
|
+
const data = this.getData();
|
|
315
|
+
const result = await rule.safeParseAsync(data);
|
|
316
|
+
if (result.success) {
|
|
317
|
+
return [];
|
|
293
318
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
activeTabId: validActive,
|
|
304
|
-
setActiveTab: id => {
|
|
305
|
-
runInAction(() => {
|
|
306
|
-
this._activeTabs.set(tabKey, id);
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
_resolveElementNode(node) {
|
|
312
|
-
return {
|
|
313
|
-
type: "element",
|
|
314
|
-
renderer: node.renderer,
|
|
315
|
-
props: node.props
|
|
316
|
-
};
|
|
319
|
+
return result.error.issues.map(issue => {
|
|
320
|
+
const path = issue.path.map(String).join(".");
|
|
321
|
+
const field = path ? this._tryGetField(path) : undefined;
|
|
322
|
+
return {
|
|
323
|
+
path,
|
|
324
|
+
label: field?.config.label,
|
|
325
|
+
message: issue.message || "Invalid value."
|
|
326
|
+
};
|
|
327
|
+
});
|
|
317
328
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
continue;
|
|
324
|
-
}
|
|
325
|
-
if (field.vm.validation.isValid === false) {
|
|
326
|
-
return true;
|
|
327
|
-
}
|
|
328
|
-
if (isObjectField(field) && field.hasErrors) {
|
|
329
|
-
return true;
|
|
330
|
-
}
|
|
329
|
+
_tryGetField(path) {
|
|
330
|
+
try {
|
|
331
|
+
return this.field(path);
|
|
332
|
+
} catch {
|
|
333
|
+
return undefined;
|
|
331
334
|
}
|
|
332
|
-
return false;
|
|
333
335
|
}
|
|
334
|
-
|
|
335
|
-
const ids = [];
|
|
336
|
+
_registerObjectNodeLayouts(layout) {
|
|
336
337
|
for (const node of layout) {
|
|
337
|
-
if (node.type === "
|
|
338
|
-
|
|
338
|
+
if (node.type === "object") {
|
|
339
|
+
const field = this._fields.get(node.fieldName);
|
|
340
|
+
if (field && isObjectField(field)) {
|
|
341
|
+
field.setInnerLayout(node.inner);
|
|
342
|
+
}
|
|
339
343
|
} else if (node.type === "tabs") {
|
|
340
344
|
for (const tab of node.tabs) {
|
|
341
|
-
|
|
345
|
+
this._registerObjectNodeLayouts(tab.layout);
|
|
342
346
|
}
|
|
343
347
|
}
|
|
344
348
|
}
|
|
345
|
-
return ids;
|
|
346
349
|
}
|
|
347
|
-
|
|
348
|
-
|
|
350
|
+
_propagateAncestorRules() {
|
|
351
|
+
const ancestry = new Map();
|
|
352
|
+
const walk = (nodes, rules) => {
|
|
353
|
+
for (const node of nodes) {
|
|
354
|
+
if (node.type === "row") {
|
|
355
|
+
for (const id of node.fieldIds) {
|
|
356
|
+
const existing = ancestry.get(id) ?? [];
|
|
357
|
+
ancestry.set(id, [...existing, ...rules]);
|
|
358
|
+
}
|
|
359
|
+
} else if (node.type === "tabs") {
|
|
360
|
+
const containerRules = [...rules, ...(node.rules ?? [])];
|
|
361
|
+
for (const tab of node.tabs) {
|
|
362
|
+
const tabRules = [...containerRules, ...(tab.rules ?? [])];
|
|
363
|
+
walk(tab.layout, tabRules);
|
|
364
|
+
}
|
|
365
|
+
} else if (node.type === "object") {
|
|
366
|
+
const existing = ancestry.get(node.fieldName) ?? [];
|
|
367
|
+
ancestry.set(node.fieldName, [...existing, ...rules]);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
walk(this._layout, []);
|
|
372
|
+
for (const [, field] of this._fields) {
|
|
373
|
+
field.setAncestorRules(ancestry.get(field.name) ?? []);
|
|
374
|
+
}
|
|
349
375
|
}
|
|
350
376
|
_generateDefaultLayout() {
|
|
351
377
|
const layout = [];
|
|
@@ -360,7 +386,7 @@ export class FormModel {
|
|
|
360
386
|
return layout;
|
|
361
387
|
}
|
|
362
388
|
_warnOrphanFields() {
|
|
363
|
-
const layoutFieldIds = new Set(
|
|
389
|
+
const layoutFieldIds = new Set(LayoutBuilderFactory.collectFieldIds(this._layout));
|
|
364
390
|
for (const [name, field] of this._fields) {
|
|
365
391
|
if (field.visible && !layoutFieldIds.has(name)) {
|
|
366
392
|
console.warn(`[FormModel] Field "${name}" is not in the layout and not marked as .hidden(). ` + `Add it to the layout or mark it as .hidden() to suppress this warning.`);
|
|
@@ -378,231 +404,12 @@ export class FormModel {
|
|
|
378
404
|
field.resetValidation();
|
|
379
405
|
}
|
|
380
406
|
}
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* Find the index of a layout node that matches the given target.
|
|
384
|
-
* Matches: row containing fieldId, tabs by id, element by id/renderer.
|
|
385
|
-
* Returns -1 if not found.
|
|
386
|
-
*/
|
|
387
|
-
_findLayoutIndex(layout, target) {
|
|
388
|
-
return layout.findIndex(node => this._nodeMatchesTarget(node, target));
|
|
389
|
-
}
|
|
390
|
-
_nodeMatchesTarget(node, target) {
|
|
391
|
-
switch (node.type) {
|
|
392
|
-
case "row":
|
|
393
|
-
return node.fieldIds.includes(target);
|
|
394
|
-
case "tabs":
|
|
395
|
-
return node.id === target;
|
|
396
|
-
case "element":
|
|
397
|
-
return node.id === target || node.renderer === target;
|
|
398
|
-
default:
|
|
399
|
-
return false;
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
/**
|
|
404
|
-
* Remove a target from the layout tree. Handles field IDs in rows,
|
|
405
|
-
* and node IDs for tabs/elements. Drops rows that become empty.
|
|
406
|
-
*/
|
|
407
|
-
_removeFromLayout(layout, target) {
|
|
408
|
-
return layout.map(node => {
|
|
409
|
-
if (node.type === "row") {
|
|
410
|
-
const filtered = node.fieldIds.filter(id => id !== target);
|
|
411
|
-
if (filtered.length === 0) {
|
|
412
|
-
return null;
|
|
413
|
-
}
|
|
414
|
-
return {
|
|
415
|
-
...node,
|
|
416
|
-
fieldIds: filtered
|
|
417
|
-
};
|
|
418
|
-
}
|
|
419
|
-
// Remove tabs/elements by their ID
|
|
420
|
-
if (node.type === "tabs" && node.id === target || node.type === "element" && (node.id === target || node.renderer === target)) {
|
|
421
|
-
return null;
|
|
422
|
-
}
|
|
423
|
-
return node;
|
|
424
|
-
}).filter(Boolean);
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
/**
|
|
428
|
-
* Insert a layout node relative to a target field ID.
|
|
429
|
-
*/
|
|
430
|
-
_insertIntoLayout(layout, node, position) {
|
|
431
|
-
const targetIndex = this._findLayoutIndex(layout, position.target);
|
|
432
|
-
if (targetIndex === -1) {
|
|
433
|
-
// Target not found — append
|
|
434
|
-
return [...layout, node];
|
|
435
|
-
}
|
|
436
|
-
const result = [...layout];
|
|
437
|
-
switch (position.type) {
|
|
438
|
-
case "before":
|
|
439
|
-
result.splice(targetIndex, 0, node);
|
|
440
|
-
break;
|
|
441
|
-
case "after":
|
|
442
|
-
result.splice(targetIndex + 1, 0, node);
|
|
443
|
-
break;
|
|
444
|
-
case "replace":
|
|
445
|
-
result.splice(targetIndex, 1, node);
|
|
446
|
-
break;
|
|
447
|
-
}
|
|
448
|
-
return result;
|
|
449
|
-
}
|
|
450
|
-
_createModifierLayoutAPI(removals) {
|
|
451
|
-
return {
|
|
452
|
-
row(...fieldIds) {
|
|
453
|
-
const node = {
|
|
454
|
-
type: "row",
|
|
455
|
-
fieldIds
|
|
456
|
-
};
|
|
457
|
-
return createLayoutNodeHandle(node);
|
|
458
|
-
},
|
|
459
|
-
separator() {
|
|
460
|
-
const node = {
|
|
461
|
-
type: "separator"
|
|
462
|
-
};
|
|
463
|
-
return createLayoutNodeHandle(node);
|
|
464
|
-
},
|
|
465
|
-
tabs(config) {
|
|
466
|
-
const node = {
|
|
467
|
-
type: "tabs",
|
|
468
|
-
id: config.id,
|
|
469
|
-
renderer: config.renderer,
|
|
470
|
-
tabs: config.tabs
|
|
471
|
-
};
|
|
472
|
-
return createLayoutNodeHandle(node);
|
|
473
|
-
},
|
|
474
|
-
element(renderer, props) {
|
|
475
|
-
const node = {
|
|
476
|
-
type: "element",
|
|
477
|
-
renderer,
|
|
478
|
-
props
|
|
479
|
-
};
|
|
480
|
-
return createLayoutNodeHandle(node);
|
|
481
|
-
},
|
|
482
|
-
remove(target) {
|
|
483
|
-
removals.push(target);
|
|
484
|
-
}
|
|
485
|
-
};
|
|
486
|
-
}
|
|
487
|
-
_accessLayoutNode(nodeId) {
|
|
488
|
-
const findTabsNode = layout => {
|
|
489
|
-
for (const node of layout) {
|
|
490
|
-
if (node.type === "tabs" && node.id === nodeId) {
|
|
491
|
-
return node;
|
|
492
|
-
}
|
|
493
|
-
// Search inside nested tabs
|
|
494
|
-
if (node.type === "tabs") {
|
|
495
|
-
for (const tab of node.tabs) {
|
|
496
|
-
const found = findTabsNode(tab.layout);
|
|
497
|
-
if (found) {
|
|
498
|
-
return found;
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
return undefined;
|
|
504
|
-
};
|
|
505
|
-
return {
|
|
506
|
-
as: type => {
|
|
507
|
-
const tabsNode = findTabsNode(this._layout);
|
|
508
|
-
if (!tabsNode) {
|
|
509
|
-
throw new Error(`Layout node "${nodeId}" not found.`);
|
|
510
|
-
}
|
|
511
|
-
if (tabsNode.type !== type) {
|
|
512
|
-
throw new Error(`Layout node "${nodeId}" is type "${tabsNode.type}", not "${type}".`);
|
|
513
|
-
}
|
|
514
|
-
return {
|
|
515
|
-
tab: definitionOrId => {
|
|
516
|
-
if (typeof definitionOrId === "string") {
|
|
517
|
-
// Access existing tab
|
|
518
|
-
const tab = tabsNode.tabs.find(t => t.id === definitionOrId);
|
|
519
|
-
if (!tab) {
|
|
520
|
-
throw new Error(`Tab "${definitionOrId}" not found in tabs node "${nodeId}".`);
|
|
521
|
-
}
|
|
522
|
-
return {
|
|
523
|
-
layout: factory => {
|
|
524
|
-
const nodes = factory(layoutAPI);
|
|
525
|
-
tab.layout.push(...nodes);
|
|
526
|
-
},
|
|
527
|
-
before: () => {
|
|
528
|
-
/* no-op for existing tabs */
|
|
529
|
-
},
|
|
530
|
-
after: () => {
|
|
531
|
-
/* no-op for existing tabs */
|
|
532
|
-
}
|
|
533
|
-
};
|
|
534
|
-
} else {
|
|
535
|
-
// Add new tab
|
|
536
|
-
const newTab = {
|
|
537
|
-
...definitionOrId
|
|
538
|
-
};
|
|
539
|
-
// Resolve layout if it's a factory
|
|
540
|
-
if (typeof definitionOrId.layout === "function") {
|
|
541
|
-
newTab.layout = definitionOrId.layout(layoutAPI);
|
|
542
|
-
}
|
|
543
|
-
return {
|
|
544
|
-
layout: factory => {
|
|
545
|
-
newTab.layout = factory(layoutAPI);
|
|
546
|
-
},
|
|
547
|
-
before: targetTabId => {
|
|
548
|
-
const idx = tabsNode.tabs.findIndex(t => t.id === targetTabId);
|
|
549
|
-
if (idx !== -1) {
|
|
550
|
-
tabsNode.tabs.splice(idx, 0, newTab);
|
|
551
|
-
} else {
|
|
552
|
-
tabsNode.tabs.push(newTab);
|
|
553
|
-
}
|
|
554
|
-
},
|
|
555
|
-
after: targetTabId => {
|
|
556
|
-
const idx = tabsNode.tabs.findIndex(t => t.id === targetTabId);
|
|
557
|
-
if (idx !== -1) {
|
|
558
|
-
tabsNode.tabs.splice(idx + 1, 0, newTab);
|
|
559
|
-
} else {
|
|
560
|
-
tabsNode.tabs.push(newTab);
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
};
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
};
|
|
567
|
-
}
|
|
568
|
-
};
|
|
569
|
-
}
|
|
570
407
|
_createField(config) {
|
|
571
408
|
if (config.childBuilders) {
|
|
572
409
|
return new ObjectField(config);
|
|
573
410
|
}
|
|
574
411
|
return new Field(config);
|
|
575
412
|
}
|
|
576
|
-
_isPositionedNode(entry) {
|
|
577
|
-
return "node" in entry;
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
function createLayoutNodeHandle(node) {
|
|
581
|
-
const handle = {
|
|
582
|
-
node,
|
|
583
|
-
before(target) {
|
|
584
|
-
handle.position = {
|
|
585
|
-
type: "before",
|
|
586
|
-
target
|
|
587
|
-
};
|
|
588
|
-
return handle;
|
|
589
|
-
},
|
|
590
|
-
after(target) {
|
|
591
|
-
handle.position = {
|
|
592
|
-
type: "after",
|
|
593
|
-
target
|
|
594
|
-
};
|
|
595
|
-
return handle;
|
|
596
|
-
},
|
|
597
|
-
replace(target) {
|
|
598
|
-
handle.position = {
|
|
599
|
-
type: "replace",
|
|
600
|
-
target
|
|
601
|
-
};
|
|
602
|
-
return handle;
|
|
603
|
-
}
|
|
604
|
-
};
|
|
605
|
-
return handle;
|
|
606
413
|
}
|
|
607
414
|
|
|
608
415
|
//# sourceMappingURL=FormModel.js.map
|