@webiny/app-admin 6.3.0-beta.1 → 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 +31 -25
- 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
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import React, { useMemo } from "react";
|
|
2
|
+
import { observer } from "mobx-react-lite";
|
|
3
|
+
import { useFeature } from "@webiny/app";
|
|
4
|
+
import { Button } from "@webiny/admin-ui";
|
|
5
|
+
import { FormView } from "../FormView.js";
|
|
6
|
+
import { FormModelFeature } from "../feature.js";
|
|
7
|
+
import { FieldRenderersDemoPresenter } from "./FieldRenderersDemoPresenter.js";
|
|
8
|
+
import { FormModelDemoPresenter } from "./FormModelDemoPresenter.js";
|
|
9
|
+
import { FormModelPhase8c1Presenter } from "./FormModelPhase8c1Presenter.js";
|
|
10
|
+
import { FormModelPhase11Presenter } from "./FormModelPhase11Presenter.js";
|
|
11
|
+
export const FormModelDemo = observer(() => {
|
|
12
|
+
const {
|
|
13
|
+
formModelFactory
|
|
14
|
+
} = useFeature(FormModelFeature);
|
|
15
|
+
const presenter = useMemo(() => new FormModelDemoPresenter(formModelFactory), [formModelFactory]);
|
|
16
|
+
const {
|
|
17
|
+
form,
|
|
18
|
+
data,
|
|
19
|
+
lastSubmitted,
|
|
20
|
+
isSubmitting,
|
|
21
|
+
runtimeTemplateAdded,
|
|
22
|
+
textTemplateRemoved
|
|
23
|
+
} = presenter.vm;
|
|
24
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
25
|
+
className: "p-lg flex flex-col gap-2xl max-w-4xl mx-auto"
|
|
26
|
+
}, /*#__PURE__*/React.createElement(FieldRenderersSection, null), /*#__PURE__*/React.createElement("div", {
|
|
27
|
+
className: "flex flex-col gap-lg"
|
|
28
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
29
|
+
className: "flex flex-col gap-sm"
|
|
30
|
+
}, /*#__PURE__*/React.createElement("h2", {
|
|
31
|
+
className: "text-xl font-semibold"
|
|
32
|
+
}, "FormModel Demo \u2014 Phase 8"), /*#__PURE__*/React.createElement("p", {
|
|
33
|
+
className: "text-sm text-neutral-strong"
|
|
34
|
+
}, "Exercises the full Phase 8 surface: single-object templates (\"Content Block\"), templated lists (\"Page Sections\"), per-template layouts (Hero spans two rows; Rich Text uses a single row; templates without a layout entry fall back to default), and runtime template management via", " ", /*#__PURE__*/React.createElement("code", null, "field.templates.add/remove"), ". Change Plan to", " ", /*#__PURE__*/React.createElement("code", null, "enterprise"), " to reveal the \"Premium Widget\" template in the Content Block picker.")), /*#__PURE__*/React.createElement(FormView, {
|
|
35
|
+
form: form
|
|
36
|
+
}), /*#__PURE__*/React.createElement("div", {
|
|
37
|
+
className: "flex flex-wrap gap-sm"
|
|
38
|
+
}, /*#__PURE__*/React.createElement(Button, {
|
|
39
|
+
text: isSubmitting ? "Submitting…" : "Submit",
|
|
40
|
+
variant: "primary",
|
|
41
|
+
onClick: () => presenter.submit(),
|
|
42
|
+
disabled: isSubmitting
|
|
43
|
+
}), /*#__PURE__*/React.createElement(Button, {
|
|
44
|
+
text: "Reset",
|
|
45
|
+
variant: "secondary",
|
|
46
|
+
onClick: () => presenter.reset(),
|
|
47
|
+
disabled: isSubmitting
|
|
48
|
+
}), /*#__PURE__*/React.createElement(Button, {
|
|
49
|
+
text: runtimeTemplateAdded ? 'Remove "Runtime Banner" from sections' : 'Add "Runtime Banner" to sections',
|
|
50
|
+
variant: "tertiary",
|
|
51
|
+
onClick: () => presenter.toggleRuntimeTemplate()
|
|
52
|
+
}), /*#__PURE__*/React.createElement(Button, {
|
|
53
|
+
text: textTemplateRemoved ? 'Restore "Rich Text" on content' : 'Remove "Rich Text" from content',
|
|
54
|
+
variant: "tertiary",
|
|
55
|
+
onClick: () => presenter.toggleTextTemplate()
|
|
56
|
+
})), /*#__PURE__*/React.createElement("div", {
|
|
57
|
+
className: "grid grid-cols-2 gap-md"
|
|
58
|
+
}, /*#__PURE__*/React.createElement(DataPanel, {
|
|
59
|
+
title: "Current getData()",
|
|
60
|
+
data: data
|
|
61
|
+
}), /*#__PURE__*/React.createElement(DataPanel, {
|
|
62
|
+
title: "Last submitted",
|
|
63
|
+
data: lastSubmitted
|
|
64
|
+
}))), /*#__PURE__*/React.createElement(Phase8c1Section, null), /*#__PURE__*/React.createElement(Phase11Section, null));
|
|
65
|
+
});
|
|
66
|
+
const FieldRenderersSection = observer(() => {
|
|
67
|
+
const {
|
|
68
|
+
formModelFactory
|
|
69
|
+
} = useFeature(FormModelFeature);
|
|
70
|
+
const presenter = useMemo(() => new FieldRenderersDemoPresenter(formModelFactory), [formModelFactory]);
|
|
71
|
+
const {
|
|
72
|
+
form,
|
|
73
|
+
data,
|
|
74
|
+
lastSubmitted,
|
|
75
|
+
isSubmitting,
|
|
76
|
+
formErrors
|
|
77
|
+
} = presenter.vm;
|
|
78
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
79
|
+
className: "flex flex-col gap-lg"
|
|
80
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
81
|
+
className: "flex flex-col gap-sm"
|
|
82
|
+
}, /*#__PURE__*/React.createElement("h2", {
|
|
83
|
+
className: "text-xl font-semibold"
|
|
84
|
+
}, "Field Renderers Showcase"), /*#__PURE__*/React.createElement("p", {
|
|
85
|
+
className: "text-sm text-neutral-strong"
|
|
86
|
+
}, "All field renderer variants: text, number, boolean, select (dropdown/radio/checkboxes), date/time (4 variants), tags, textarea, multi-value lists, hidden, and dynamic zones. Renderers not yet implemented show nothing (console warning).")), /*#__PURE__*/React.createElement(FormView, {
|
|
87
|
+
form: form
|
|
88
|
+
}), formErrors.length > 0 && /*#__PURE__*/React.createElement("div", {
|
|
89
|
+
className: "flex flex-col gap-xs"
|
|
90
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
91
|
+
className: "text-sm font-medium"
|
|
92
|
+
}, "Form errors"), /*#__PURE__*/React.createElement("ul", {
|
|
93
|
+
className: "text-xs text-error-strong list-disc pl-md"
|
|
94
|
+
}, formErrors.map((e, i) => /*#__PURE__*/React.createElement("li", {
|
|
95
|
+
key: i
|
|
96
|
+
}, e.path ? /*#__PURE__*/React.createElement("button", {
|
|
97
|
+
type: "button",
|
|
98
|
+
className: "underline cursor-pointer hover:text-error-default",
|
|
99
|
+
onClick: () => presenter.focusField(e.path)
|
|
100
|
+
}, /*#__PURE__*/React.createElement("code", null, e.path)) : null, " ", e.message)))), /*#__PURE__*/React.createElement("div", {
|
|
101
|
+
className: "flex flex-wrap gap-sm"
|
|
102
|
+
}, /*#__PURE__*/React.createElement(Button, {
|
|
103
|
+
text: isSubmitting ? "Submitting…" : "Submit",
|
|
104
|
+
variant: "primary",
|
|
105
|
+
onClick: () => presenter.submit(),
|
|
106
|
+
disabled: isSubmitting
|
|
107
|
+
}), /*#__PURE__*/React.createElement(Button, {
|
|
108
|
+
text: "Reset",
|
|
109
|
+
variant: "secondary",
|
|
110
|
+
onClick: () => presenter.reset(),
|
|
111
|
+
disabled: isSubmitting
|
|
112
|
+
})), /*#__PURE__*/React.createElement("div", {
|
|
113
|
+
className: "grid grid-cols-2 gap-md"
|
|
114
|
+
}, /*#__PURE__*/React.createElement(DataPanel, {
|
|
115
|
+
title: "Current getData()",
|
|
116
|
+
data: data
|
|
117
|
+
}), /*#__PURE__*/React.createElement(DataPanel, {
|
|
118
|
+
title: "Last submitted",
|
|
119
|
+
data: lastSubmitted
|
|
120
|
+
})));
|
|
121
|
+
});
|
|
122
|
+
const Phase8c1Section = observer(() => {
|
|
123
|
+
const {
|
|
124
|
+
formModelFactory
|
|
125
|
+
} = useFeature(FormModelFeature);
|
|
126
|
+
const presenter = useMemo(() => new FormModelPhase8c1Presenter(formModelFactory), [formModelFactory]);
|
|
127
|
+
const {
|
|
128
|
+
form,
|
|
129
|
+
data,
|
|
130
|
+
lastSubmitted,
|
|
131
|
+
isSubmitting
|
|
132
|
+
} = presenter.vm;
|
|
133
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
134
|
+
className: "flex flex-col gap-lg border-t border-neutral-dimmed pt-lg"
|
|
135
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
136
|
+
className: "flex flex-col gap-sm"
|
|
137
|
+
}, /*#__PURE__*/React.createElement("h2", {
|
|
138
|
+
className: "text-xl font-semibold"
|
|
139
|
+
}, "FormModel Demo \u2014 Phase 8c.1"), /*#__PURE__*/React.createElement("p", {
|
|
140
|
+
className: "text-sm text-neutral-strong"
|
|
141
|
+
}, "Nested object layouts. A top-level ", /*#__PURE__*/React.createElement("code", null, "page"), " object whose inner layout is split across tabs (General / SEO). The SEO tab contains a nested", " ", /*#__PURE__*/React.createElement("code", null, "layout.object(\"seo\", ...)"), " with its own row layout, and the SEO object itself contains another nested", " ", /*#__PURE__*/React.createElement("code", null, "layout.object(\"og\", ...)"), " for the Open Graph fields. Phase 8c.1 walks the inner layout (including across tabs) and forwards each nested", " ", /*#__PURE__*/React.createElement("code", null, "layout.object()"), " to the matching child at build time.")), /*#__PURE__*/React.createElement(FormView, {
|
|
142
|
+
form: form
|
|
143
|
+
}), /*#__PURE__*/React.createElement("div", {
|
|
144
|
+
className: "flex flex-wrap gap-sm"
|
|
145
|
+
}, /*#__PURE__*/React.createElement(Button, {
|
|
146
|
+
text: isSubmitting ? "Submitting…" : "Submit",
|
|
147
|
+
variant: "primary",
|
|
148
|
+
onClick: () => presenter.submit(),
|
|
149
|
+
disabled: isSubmitting
|
|
150
|
+
}), /*#__PURE__*/React.createElement(Button, {
|
|
151
|
+
text: "Reset",
|
|
152
|
+
variant: "secondary",
|
|
153
|
+
onClick: () => presenter.reset(),
|
|
154
|
+
disabled: isSubmitting
|
|
155
|
+
})), /*#__PURE__*/React.createElement("div", {
|
|
156
|
+
className: "grid grid-cols-2 gap-md"
|
|
157
|
+
}, /*#__PURE__*/React.createElement(DataPanel, {
|
|
158
|
+
title: "Current getData()",
|
|
159
|
+
data: data
|
|
160
|
+
}), /*#__PURE__*/React.createElement(DataPanel, {
|
|
161
|
+
title: "Last submitted",
|
|
162
|
+
data: lastSubmitted
|
|
163
|
+
})));
|
|
164
|
+
});
|
|
165
|
+
const Phase11Section = observer(() => {
|
|
166
|
+
const {
|
|
167
|
+
formModelFactory
|
|
168
|
+
} = useFeature(FormModelFeature);
|
|
169
|
+
const presenter = useMemo(() => new FormModelPhase11Presenter(formModelFactory), [formModelFactory]);
|
|
170
|
+
const {
|
|
171
|
+
form,
|
|
172
|
+
data,
|
|
173
|
+
lastSubmitted,
|
|
174
|
+
isSubmitting,
|
|
175
|
+
formErrors
|
|
176
|
+
} = presenter.vm;
|
|
177
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
178
|
+
className: "flex flex-col gap-lg border-t border-neutral-dimmed pt-lg"
|
|
179
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
180
|
+
className: "flex flex-col gap-sm"
|
|
181
|
+
}, /*#__PURE__*/React.createElement("h2", {
|
|
182
|
+
className: "text-xl font-semibold"
|
|
183
|
+
}, "FormModel Demo \u2014 Phase 11"), /*#__PURE__*/React.createElement("p", {
|
|
184
|
+
className: "text-sm text-neutral-strong"
|
|
185
|
+
}, "Conditional required (", /*#__PURE__*/React.createElement("code", null, "requiredWhen"), " on Seats \u2014 chained builder + modifier rules), derived fields (", /*#__PURE__*/React.createElement("code", null, "computed"), " Full Name and", " ", /*#__PURE__*/React.createElement("code", null, "computedUntilDirty"), " Slug), modifier-style child addition via", " ", /*#__PURE__*/React.createElement("code", null, "field.as(\"object\").fields()"), " adding Company/Bio to Profile, form-level rules (", /*#__PURE__*/React.createElement("code", null, "addRule"), " with a Zod refinement for password match plus an imperative slug-length rule), and a layout assembled via", " ", /*#__PURE__*/React.createElement("code", null, "setLayout"), ".")), /*#__PURE__*/React.createElement(FormView, {
|
|
186
|
+
form: form
|
|
187
|
+
}), formErrors.length > 0 && /*#__PURE__*/React.createElement("div", {
|
|
188
|
+
className: "flex flex-col gap-xs"
|
|
189
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
190
|
+
className: "text-sm font-medium"
|
|
191
|
+
}, "Form errors"), /*#__PURE__*/React.createElement("ul", {
|
|
192
|
+
className: "text-xs text-error-strong list-disc pl-md"
|
|
193
|
+
}, formErrors.map((e, i) => /*#__PURE__*/React.createElement("li", {
|
|
194
|
+
key: i
|
|
195
|
+
}, e.path ? /*#__PURE__*/React.createElement("code", null, e.path) : null, " ", e.message)))), /*#__PURE__*/React.createElement("div", {
|
|
196
|
+
className: "flex flex-wrap gap-sm"
|
|
197
|
+
}, /*#__PURE__*/React.createElement(Button, {
|
|
198
|
+
text: isSubmitting ? "Submitting…" : "Submit",
|
|
199
|
+
variant: "primary",
|
|
200
|
+
onClick: () => presenter.submit(),
|
|
201
|
+
disabled: isSubmitting
|
|
202
|
+
}), /*#__PURE__*/React.createElement(Button, {
|
|
203
|
+
text: "Reset",
|
|
204
|
+
variant: "secondary",
|
|
205
|
+
onClick: () => presenter.reset(),
|
|
206
|
+
disabled: isSubmitting
|
|
207
|
+
})), /*#__PURE__*/React.createElement("div", {
|
|
208
|
+
className: "grid grid-cols-2 gap-md"
|
|
209
|
+
}, /*#__PURE__*/React.createElement(DataPanel, {
|
|
210
|
+
title: "Current getData()",
|
|
211
|
+
data: data
|
|
212
|
+
}), /*#__PURE__*/React.createElement(DataPanel, {
|
|
213
|
+
title: "Last submitted",
|
|
214
|
+
data: lastSubmitted
|
|
215
|
+
})));
|
|
216
|
+
});
|
|
217
|
+
const DataPanel = ({
|
|
218
|
+
title,
|
|
219
|
+
data
|
|
220
|
+
}) => {
|
|
221
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
222
|
+
className: "flex flex-col gap-xs"
|
|
223
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
224
|
+
className: "text-sm font-medium"
|
|
225
|
+
}, title), /*#__PURE__*/React.createElement("pre", {
|
|
226
|
+
className: "text-xs bg-neutral-subtle p-sm rounded border border-neutral-dimmed overflow-auto"
|
|
227
|
+
}, data === null ? "null" : JSON.stringify(data, null, 2)));
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
//# sourceMappingURL=FormModelDemo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["React","useMemo","observer","useFeature","Button","FormView","FormModelFeature","FieldRenderersDemoPresenter","FormModelDemoPresenter","FormModelPhase8c1Presenter","FormModelPhase11Presenter","FormModelDemo","formModelFactory","presenter","form","data","lastSubmitted","isSubmitting","runtimeTemplateAdded","textTemplateRemoved","vm","createElement","className","FieldRenderersSection","text","variant","onClick","submit","disabled","reset","toggleRuntimeTemplate","toggleTextTemplate","DataPanel","title","Phase8c1Section","Phase11Section","formErrors","length","map","e","i","key","path","type","focusField","message","JSON","stringify"],"sources":["FormModelDemo.tsx"],"sourcesContent":["import React, { useMemo } from \"react\";\nimport { observer } from \"mobx-react-lite\";\nimport { useFeature } from \"@webiny/app\";\nimport { Button } from \"@webiny/admin-ui\";\nimport { FormView } from \"../FormView.js\";\nimport { FormModelFeature } from \"../feature.js\";\nimport { FieldRenderersDemoPresenter } from \"./FieldRenderersDemoPresenter.js\";\nimport { FormModelDemoPresenter } from \"./FormModelDemoPresenter.js\";\nimport { FormModelPhase8c1Presenter } from \"./FormModelPhase8c1Presenter.js\";\nimport { FormModelPhase11Presenter } from \"./FormModelPhase11Presenter.js\";\n\nexport const FormModelDemo = observer(() => {\n const { formModelFactory } = useFeature(FormModelFeature);\n const presenter = useMemo(\n () => new FormModelDemoPresenter(formModelFactory),\n [formModelFactory]\n );\n\n const { form, data, lastSubmitted, isSubmitting, runtimeTemplateAdded, textTemplateRemoved } =\n presenter.vm;\n\n return (\n <div className={\"p-lg flex flex-col gap-2xl max-w-4xl mx-auto\"}>\n <FieldRenderersSection />\n\n <div className={\"flex flex-col gap-lg\"}>\n <div className={\"flex flex-col gap-sm\"}>\n <h2 className={\"text-xl font-semibold\"}>FormModel Demo — Phase 8</h2>\n <p className={\"text-sm text-neutral-strong\"}>\n Exercises the full Phase 8 surface: single-object templates ("Content\n Block"), templated lists ("Page Sections"), per-template\n layouts (Hero spans two rows; Rich Text uses a single row; templates without\n a layout entry fall back to default), and runtime template management via{\" \"}\n <code>field.templates.add/remove</code>. Change Plan to{\" \"}\n <code>enterprise</code> to reveal the "Premium Widget" template in\n the Content Block picker.\n </p>\n </div>\n\n <FormView form={form} />\n\n <div className={\"flex flex-wrap gap-sm\"}>\n <Button\n text={isSubmitting ? \"Submitting…\" : \"Submit\"}\n variant={\"primary\"}\n onClick={() => presenter.submit()}\n disabled={isSubmitting}\n />\n <Button\n text={\"Reset\"}\n variant={\"secondary\"}\n onClick={() => presenter.reset()}\n disabled={isSubmitting}\n />\n <Button\n text={\n runtimeTemplateAdded\n ? 'Remove \"Runtime Banner\" from sections'\n : 'Add \"Runtime Banner\" to sections'\n }\n variant={\"tertiary\"}\n onClick={() => presenter.toggleRuntimeTemplate()}\n />\n <Button\n text={\n textTemplateRemoved\n ? 'Restore \"Rich Text\" on content'\n : 'Remove \"Rich Text\" from content'\n }\n variant={\"tertiary\"}\n onClick={() => presenter.toggleTextTemplate()}\n />\n </div>\n\n <div className={\"grid grid-cols-2 gap-md\"}>\n <DataPanel title={\"Current getData()\"} data={data} />\n <DataPanel title={\"Last submitted\"} data={lastSubmitted} />\n </div>\n </div>\n\n <Phase8c1Section />\n\n <Phase11Section />\n </div>\n );\n});\n\nconst FieldRenderersSection = observer(() => {\n const { formModelFactory } = useFeature(FormModelFeature);\n const presenter = useMemo(\n () => new FieldRenderersDemoPresenter(formModelFactory),\n [formModelFactory]\n );\n\n const { form, data, lastSubmitted, isSubmitting, formErrors } = presenter.vm;\n\n return (\n <div className={\"flex flex-col gap-lg\"}>\n <div className={\"flex flex-col gap-sm\"}>\n <h2 className={\"text-xl font-semibold\"}>Field Renderers Showcase</h2>\n <p className={\"text-sm text-neutral-strong\"}>\n All field renderer variants: text, number, boolean, select\n (dropdown/radio/checkboxes), date/time (4 variants), tags, textarea, multi-value\n lists, hidden, and dynamic zones. Renderers not yet implemented show nothing\n (console warning).\n </p>\n </div>\n\n <FormView form={form} />\n\n {formErrors.length > 0 && (\n <div className={\"flex flex-col gap-xs\"}>\n <div className={\"text-sm font-medium\"}>Form errors</div>\n <ul className={\"text-xs text-error-strong list-disc pl-md\"}>\n {formErrors.map((e, i) => (\n <li key={i}>\n {e.path ? (\n <button\n type={\"button\"}\n className={\n \"underline cursor-pointer hover:text-error-default\"\n }\n onClick={() => presenter.focusField(e.path)}\n >\n <code>{e.path}</code>\n </button>\n ) : null}{\" \"}\n {e.message}\n </li>\n ))}\n </ul>\n </div>\n )}\n\n <div className={\"flex flex-wrap gap-sm\"}>\n <Button\n text={isSubmitting ? \"Submitting…\" : \"Submit\"}\n variant={\"primary\"}\n onClick={() => presenter.submit()}\n disabled={isSubmitting}\n />\n <Button\n text={\"Reset\"}\n variant={\"secondary\"}\n onClick={() => presenter.reset()}\n disabled={isSubmitting}\n />\n </div>\n\n <div className={\"grid grid-cols-2 gap-md\"}>\n <DataPanel title={\"Current getData()\"} data={data} />\n <DataPanel title={\"Last submitted\"} data={lastSubmitted} />\n </div>\n </div>\n );\n});\n\nconst Phase8c1Section = observer(() => {\n const { formModelFactory } = useFeature(FormModelFeature);\n const presenter = useMemo(\n () => new FormModelPhase8c1Presenter(formModelFactory),\n [formModelFactory]\n );\n\n const { form, data, lastSubmitted, isSubmitting } = presenter.vm;\n\n return (\n <div className={\"flex flex-col gap-lg border-t border-neutral-dimmed pt-lg\"}>\n <div className={\"flex flex-col gap-sm\"}>\n <h2 className={\"text-xl font-semibold\"}>FormModel Demo — Phase 8c.1</h2>\n <p className={\"text-sm text-neutral-strong\"}>\n Nested object layouts. A top-level <code>page</code> object whose inner layout\n is split across tabs (General / SEO). The SEO tab contains a nested{\" \"}\n <code>layout.object("seo", ...)</code> with its own row layout, and\n the SEO object itself contains another nested{\" \"}\n <code>layout.object("og", ...)</code> for the Open Graph fields. Phase\n 8c.1 walks the inner layout (including across tabs) and forwards each nested{\" \"}\n <code>layout.object()</code> to the matching child at build time.\n </p>\n </div>\n\n <FormView form={form} />\n\n <div className={\"flex flex-wrap gap-sm\"}>\n <Button\n text={isSubmitting ? \"Submitting…\" : \"Submit\"}\n variant={\"primary\"}\n onClick={() => presenter.submit()}\n disabled={isSubmitting}\n />\n <Button\n text={\"Reset\"}\n variant={\"secondary\"}\n onClick={() => presenter.reset()}\n disabled={isSubmitting}\n />\n </div>\n\n <div className={\"grid grid-cols-2 gap-md\"}>\n <DataPanel title={\"Current getData()\"} data={data} />\n <DataPanel title={\"Last submitted\"} data={lastSubmitted} />\n </div>\n </div>\n );\n});\n\nconst Phase11Section = observer(() => {\n const { formModelFactory } = useFeature(FormModelFeature);\n const presenter = useMemo(\n () => new FormModelPhase11Presenter(formModelFactory),\n [formModelFactory]\n );\n\n const { form, data, lastSubmitted, isSubmitting, formErrors } = presenter.vm;\n\n return (\n <div className={\"flex flex-col gap-lg border-t border-neutral-dimmed pt-lg\"}>\n <div className={\"flex flex-col gap-sm\"}>\n <h2 className={\"text-xl font-semibold\"}>FormModel Demo — Phase 11</h2>\n <p className={\"text-sm text-neutral-strong\"}>\n Conditional required (<code>requiredWhen</code> on Seats — chained builder +\n modifier rules), derived fields (<code>computed</code> Full Name and{\" \"}\n <code>computedUntilDirty</code> Slug), modifier-style child addition via{\" \"}\n <code>field.as("object").fields()</code> adding Company/Bio to\n Profile, form-level rules (<code>addRule</code> with a Zod refinement for\n password match plus an imperative slug-length rule), and a layout assembled via{\" \"}\n <code>setLayout</code>.\n </p>\n </div>\n\n <FormView form={form} />\n\n {formErrors.length > 0 && (\n <div className={\"flex flex-col gap-xs\"}>\n <div className={\"text-sm font-medium\"}>Form errors</div>\n <ul className={\"text-xs text-error-strong list-disc pl-md\"}>\n {formErrors.map((e, i) => (\n <li key={i}>\n {e.path ? <code>{e.path}</code> : null} {e.message}\n </li>\n ))}\n </ul>\n </div>\n )}\n\n <div className={\"flex flex-wrap gap-sm\"}>\n <Button\n text={isSubmitting ? \"Submitting…\" : \"Submit\"}\n variant={\"primary\"}\n onClick={() => presenter.submit()}\n disabled={isSubmitting}\n />\n <Button\n text={\"Reset\"}\n variant={\"secondary\"}\n onClick={() => presenter.reset()}\n disabled={isSubmitting}\n />\n </div>\n\n <div className={\"grid grid-cols-2 gap-md\"}>\n <DataPanel title={\"Current getData()\"} data={data} />\n <DataPanel title={\"Last submitted\"} data={lastSubmitted} />\n </div>\n </div>\n );\n});\n\nconst DataPanel = ({ title, data }: { title: string; data: unknown }) => {\n return (\n <div className={\"flex flex-col gap-xs\"}>\n <div className={\"text-sm font-medium\"}>{title}</div>\n <pre\n className={\n \"text-xs bg-neutral-subtle p-sm rounded border border-neutral-dimmed overflow-auto\"\n }\n >\n {data === null ? \"null\" : JSON.stringify(data, null, 2)}\n </pre>\n </div>\n );\n};\n"],"mappings":"AAAA,OAAOA,KAAK,IAAIC,OAAO,QAAQ,OAAO;AACtC,SAASC,QAAQ,QAAQ,iBAAiB;AAC1C,SAASC,UAAU,QAAQ,aAAa;AACxC,SAASC,MAAM,QAAQ,kBAAkB;AACzC,SAASC,QAAQ;AACjB,SAASC,gBAAgB;AACzB,SAASC,2BAA2B;AACpC,SAASC,sBAAsB;AAC/B,SAASC,0BAA0B;AACnC,SAASC,yBAAyB;AAElC,OAAO,MAAMC,aAAa,GAAGT,QAAQ,CAAC,MAAM;EACxC,MAAM;IAAEU;EAAiB,CAAC,GAAGT,UAAU,CAACG,gBAAgB,CAAC;EACzD,MAAMO,SAAS,GAAGZ,OAAO,CACrB,MAAM,IAAIO,sBAAsB,CAACI,gBAAgB,CAAC,EAClD,CAACA,gBAAgB,CACrB,CAAC;EAED,MAAM;IAAEE,IAAI;IAAEC,IAAI;IAAEC,aAAa;IAAEC,YAAY;IAAEC,oBAAoB;IAAEC;EAAoB,CAAC,GACxFN,SAAS,CAACO,EAAE;EAEhB,oBACIpB,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAA+C,gBAC3DtB,KAAA,CAAAqB,aAAA,CAACE,qBAAqB,MAAE,CAAC,eAEzBvB,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAAuB,gBACnCtB,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAAuB,gBACnCtB,KAAA,CAAAqB,aAAA;IAAIC,SAAS,EAAE;EAAwB,GAAC,+BAA4B,CAAC,eACrEtB,KAAA,CAAAqB,aAAA;IAAGC,SAAS,EAAE;EAA8B,GAAC,2RAIgC,EAAC,GAAG,eAC7EtB,KAAA,CAAAqB,aAAA,eAAM,4BAAgC,CAAC,oBAAgB,EAAC,GAAG,eAC3DrB,KAAA,CAAAqB,aAAA,eAAM,YAAgB,CAAC,2EAExB,CACF,CAAC,eAENrB,KAAA,CAAAqB,aAAA,CAAChB,QAAQ;IAACS,IAAI,EAAEA;EAAK,CAAE,CAAC,eAExBd,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAAwB,gBACpCtB,KAAA,CAAAqB,aAAA,CAACjB,MAAM;IACHoB,IAAI,EAAEP,YAAY,GAAG,aAAa,GAAG,QAAS;IAC9CQ,OAAO,EAAE,SAAU;IACnBC,OAAO,EAAEA,CAAA,KAAMb,SAAS,CAACc,MAAM,CAAC,CAAE;IAClCC,QAAQ,EAAEX;EAAa,CAC1B,CAAC,eACFjB,KAAA,CAAAqB,aAAA,CAACjB,MAAM;IACHoB,IAAI,EAAE,OAAQ;IACdC,OAAO,EAAE,WAAY;IACrBC,OAAO,EAAEA,CAAA,KAAMb,SAAS,CAACgB,KAAK,CAAC,CAAE;IACjCD,QAAQ,EAAEX;EAAa,CAC1B,CAAC,eACFjB,KAAA,CAAAqB,aAAA,CAACjB,MAAM;IACHoB,IAAI,EACAN,oBAAoB,GACd,uCAAuC,GACvC,kCACT;IACDO,OAAO,EAAE,UAAW;IACpBC,OAAO,EAAEA,CAAA,KAAMb,SAAS,CAACiB,qBAAqB,CAAC;EAAE,CACpD,CAAC,eACF9B,KAAA,CAAAqB,aAAA,CAACjB,MAAM;IACHoB,IAAI,EACAL,mBAAmB,GACb,gCAAgC,GAChC,iCACT;IACDM,OAAO,EAAE,UAAW;IACpBC,OAAO,EAAEA,CAAA,KAAMb,SAAS,CAACkB,kBAAkB,CAAC;EAAE,CACjD,CACA,CAAC,eAEN/B,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAA0B,gBACtCtB,KAAA,CAAAqB,aAAA,CAACW,SAAS;IAACC,KAAK,EAAE,mBAAoB;IAAClB,IAAI,EAAEA;EAAK,CAAE,CAAC,eACrDf,KAAA,CAAAqB,aAAA,CAACW,SAAS;IAACC,KAAK,EAAE,gBAAiB;IAAClB,IAAI,EAAEC;EAAc,CAAE,CACzD,CACJ,CAAC,eAENhB,KAAA,CAAAqB,aAAA,CAACa,eAAe,MAAE,CAAC,eAEnBlC,KAAA,CAAAqB,aAAA,CAACc,cAAc,MAAE,CAChB,CAAC;AAEd,CAAC,CAAC;AAEF,MAAMZ,qBAAqB,GAAGrB,QAAQ,CAAC,MAAM;EACzC,MAAM;IAAEU;EAAiB,CAAC,GAAGT,UAAU,CAACG,gBAAgB,CAAC;EACzD,MAAMO,SAAS,GAAGZ,OAAO,CACrB,MAAM,IAAIM,2BAA2B,CAACK,gBAAgB,CAAC,EACvD,CAACA,gBAAgB,CACrB,CAAC;EAED,MAAM;IAAEE,IAAI;IAAEC,IAAI;IAAEC,aAAa;IAAEC,YAAY;IAAEmB;EAAW,CAAC,GAAGvB,SAAS,CAACO,EAAE;EAE5E,oBACIpB,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAAuB,gBACnCtB,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAAuB,gBACnCtB,KAAA,CAAAqB,aAAA;IAAIC,SAAS,EAAE;EAAwB,GAAC,0BAA4B,CAAC,eACrEtB,KAAA,CAAAqB,aAAA;IAAGC,SAAS,EAAE;EAA8B,GAAC,6OAK1C,CACF,CAAC,eAENtB,KAAA,CAAAqB,aAAA,CAAChB,QAAQ;IAACS,IAAI,EAAEA;EAAK,CAAE,CAAC,EAEvBsB,UAAU,CAACC,MAAM,GAAG,CAAC,iBAClBrC,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAAuB,gBACnCtB,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAAsB,GAAC,aAAgB,CAAC,eACxDtB,KAAA,CAAAqB,aAAA;IAAIC,SAAS,EAAE;EAA4C,GACtDc,UAAU,CAACE,GAAG,CAAC,CAACC,CAAC,EAAEC,CAAC,kBACjBxC,KAAA,CAAAqB,aAAA;IAAIoB,GAAG,EAAED;EAAE,GACND,CAAC,CAACG,IAAI,gBACH1C,KAAA,CAAAqB,aAAA;IACIsB,IAAI,EAAE,QAAS;IACfrB,SAAS,EACL,mDACH;IACDI,OAAO,EAAEA,CAAA,KAAMb,SAAS,CAAC+B,UAAU,CAACL,CAAC,CAACG,IAAI;EAAE,gBAE5C1C,KAAA,CAAAqB,aAAA,eAAOkB,CAAC,CAACG,IAAW,CAChB,CAAC,GACT,IAAI,EAAE,GAAG,EACZH,CAAC,CAACM,OACH,CACP,CACD,CACH,CACR,eAED7C,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAAwB,gBACpCtB,KAAA,CAAAqB,aAAA,CAACjB,MAAM;IACHoB,IAAI,EAAEP,YAAY,GAAG,aAAa,GAAG,QAAS;IAC9CQ,OAAO,EAAE,SAAU;IACnBC,OAAO,EAAEA,CAAA,KAAMb,SAAS,CAACc,MAAM,CAAC,CAAE;IAClCC,QAAQ,EAAEX;EAAa,CAC1B,CAAC,eACFjB,KAAA,CAAAqB,aAAA,CAACjB,MAAM;IACHoB,IAAI,EAAE,OAAQ;IACdC,OAAO,EAAE,WAAY;IACrBC,OAAO,EAAEA,CAAA,KAAMb,SAAS,CAACgB,KAAK,CAAC,CAAE;IACjCD,QAAQ,EAAEX;EAAa,CAC1B,CACA,CAAC,eAENjB,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAA0B,gBACtCtB,KAAA,CAAAqB,aAAA,CAACW,SAAS;IAACC,KAAK,EAAE,mBAAoB;IAAClB,IAAI,EAAEA;EAAK,CAAE,CAAC,eACrDf,KAAA,CAAAqB,aAAA,CAACW,SAAS;IAACC,KAAK,EAAE,gBAAiB;IAAClB,IAAI,EAAEC;EAAc,CAAE,CACzD,CACJ,CAAC;AAEd,CAAC,CAAC;AAEF,MAAMkB,eAAe,GAAGhC,QAAQ,CAAC,MAAM;EACnC,MAAM;IAAEU;EAAiB,CAAC,GAAGT,UAAU,CAACG,gBAAgB,CAAC;EACzD,MAAMO,SAAS,GAAGZ,OAAO,CACrB,MAAM,IAAIQ,0BAA0B,CAACG,gBAAgB,CAAC,EACtD,CAACA,gBAAgB,CACrB,CAAC;EAED,MAAM;IAAEE,IAAI;IAAEC,IAAI;IAAEC,aAAa;IAAEC;EAAa,CAAC,GAAGJ,SAAS,CAACO,EAAE;EAEhE,oBACIpB,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAA4D,gBACxEtB,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAAuB,gBACnCtB,KAAA,CAAAqB,aAAA;IAAIC,SAAS,EAAE;EAAwB,GAAC,kCAA+B,CAAC,eACxEtB,KAAA,CAAAqB,aAAA;IAAGC,SAAS,EAAE;EAA8B,GAAC,qCACN,eAAAtB,KAAA,CAAAqB,aAAA,eAAM,MAAU,CAAC,kGACe,EAAC,GAAG,eACvErB,KAAA,CAAAqB,aAAA,eAAM,6BAAyC,CAAC,+EACH,EAAC,GAAG,eACjDrB,KAAA,CAAAqB,aAAA,eAAM,4BAAwC,CAAC,kHAC6B,EAAC,GAAG,eAChFrB,KAAA,CAAAqB,aAAA,eAAM,iBAAqB,CAAC,yCAC7B,CACF,CAAC,eAENrB,KAAA,CAAAqB,aAAA,CAAChB,QAAQ;IAACS,IAAI,EAAEA;EAAK,CAAE,CAAC,eAExBd,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAAwB,gBACpCtB,KAAA,CAAAqB,aAAA,CAACjB,MAAM;IACHoB,IAAI,EAAEP,YAAY,GAAG,aAAa,GAAG,QAAS;IAC9CQ,OAAO,EAAE,SAAU;IACnBC,OAAO,EAAEA,CAAA,KAAMb,SAAS,CAACc,MAAM,CAAC,CAAE;IAClCC,QAAQ,EAAEX;EAAa,CAC1B,CAAC,eACFjB,KAAA,CAAAqB,aAAA,CAACjB,MAAM;IACHoB,IAAI,EAAE,OAAQ;IACdC,OAAO,EAAE,WAAY;IACrBC,OAAO,EAAEA,CAAA,KAAMb,SAAS,CAACgB,KAAK,CAAC,CAAE;IACjCD,QAAQ,EAAEX;EAAa,CAC1B,CACA,CAAC,eAENjB,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAA0B,gBACtCtB,KAAA,CAAAqB,aAAA,CAACW,SAAS;IAACC,KAAK,EAAE,mBAAoB;IAAClB,IAAI,EAAEA;EAAK,CAAE,CAAC,eACrDf,KAAA,CAAAqB,aAAA,CAACW,SAAS;IAACC,KAAK,EAAE,gBAAiB;IAAClB,IAAI,EAAEC;EAAc,CAAE,CACzD,CACJ,CAAC;AAEd,CAAC,CAAC;AAEF,MAAMmB,cAAc,GAAGjC,QAAQ,CAAC,MAAM;EAClC,MAAM;IAAEU;EAAiB,CAAC,GAAGT,UAAU,CAACG,gBAAgB,CAAC;EACzD,MAAMO,SAAS,GAAGZ,OAAO,CACrB,MAAM,IAAIS,yBAAyB,CAACE,gBAAgB,CAAC,EACrD,CAACA,gBAAgB,CACrB,CAAC;EAED,MAAM;IAAEE,IAAI;IAAEC,IAAI;IAAEC,aAAa;IAAEC,YAAY;IAAEmB;EAAW,CAAC,GAAGvB,SAAS,CAACO,EAAE;EAE5E,oBACIpB,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAA4D,gBACxEtB,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAAuB,gBACnCtB,KAAA,CAAAqB,aAAA;IAAIC,SAAS,EAAE;EAAwB,GAAC,gCAA6B,CAAC,eACtEtB,KAAA,CAAAqB,aAAA;IAAGC,SAAS,EAAE;EAA8B,GAAC,wBACnB,eAAAtB,KAAA,CAAAqB,aAAA,eAAM,cAAkB,CAAC,wEACd,eAAArB,KAAA,CAAAqB,aAAA,eAAM,UAAc,CAAC,kBAAc,EAAC,GAAG,eACxErB,KAAA,CAAAqB,aAAA,eAAM,oBAAwB,CAAC,6CAAyC,EAAC,GAAG,eAC5ErB,KAAA,CAAAqB,aAAA,eAAM,+BAA2C,CAAC,sDACvB,eAAArB,KAAA,CAAAqB,aAAA,eAAM,SAAa,CAAC,8GACgC,EAAC,GAAG,eACnFrB,KAAA,CAAAqB,aAAA,eAAM,WAAe,CAAC,KACvB,CACF,CAAC,eAENrB,KAAA,CAAAqB,aAAA,CAAChB,QAAQ;IAACS,IAAI,EAAEA;EAAK,CAAE,CAAC,EAEvBsB,UAAU,CAACC,MAAM,GAAG,CAAC,iBAClBrC,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAAuB,gBACnCtB,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAAsB,GAAC,aAAgB,CAAC,eACxDtB,KAAA,CAAAqB,aAAA;IAAIC,SAAS,EAAE;EAA4C,GACtDc,UAAU,CAACE,GAAG,CAAC,CAACC,CAAC,EAAEC,CAAC,kBACjBxC,KAAA,CAAAqB,aAAA;IAAIoB,GAAG,EAAED;EAAE,GACND,CAAC,CAACG,IAAI,gBAAG1C,KAAA,CAAAqB,aAAA,eAAOkB,CAAC,CAACG,IAAW,CAAC,GAAG,IAAI,EAAC,GAAC,EAACH,CAAC,CAACM,OAC3C,CACP,CACD,CACH,CACR,eAED7C,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAAwB,gBACpCtB,KAAA,CAAAqB,aAAA,CAACjB,MAAM;IACHoB,IAAI,EAAEP,YAAY,GAAG,aAAa,GAAG,QAAS;IAC9CQ,OAAO,EAAE,SAAU;IACnBC,OAAO,EAAEA,CAAA,KAAMb,SAAS,CAACc,MAAM,CAAC,CAAE;IAClCC,QAAQ,EAAEX;EAAa,CAC1B,CAAC,eACFjB,KAAA,CAAAqB,aAAA,CAACjB,MAAM;IACHoB,IAAI,EAAE,OAAQ;IACdC,OAAO,EAAE,WAAY;IACrBC,OAAO,EAAEA,CAAA,KAAMb,SAAS,CAACgB,KAAK,CAAC,CAAE;IACjCD,QAAQ,EAAEX;EAAa,CAC1B,CACA,CAAC,eAENjB,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAA0B,gBACtCtB,KAAA,CAAAqB,aAAA,CAACW,SAAS;IAACC,KAAK,EAAE,mBAAoB;IAAClB,IAAI,EAAEA;EAAK,CAAE,CAAC,eACrDf,KAAA,CAAAqB,aAAA,CAACW,SAAS;IAACC,KAAK,EAAE,gBAAiB;IAAClB,IAAI,EAAEC;EAAc,CAAE,CACzD,CACJ,CAAC;AAEd,CAAC,CAAC;AAEF,MAAMgB,SAAS,GAAGA,CAAC;EAAEC,KAAK;EAAElB;AAAuC,CAAC,KAAK;EACrE,oBACIf,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAAuB,gBACnCtB,KAAA,CAAAqB,aAAA;IAAKC,SAAS,EAAE;EAAsB,GAAEW,KAAW,CAAC,eACpDjC,KAAA,CAAAqB,aAAA;IACIC,SAAS,EACL;EACH,GAEAP,IAAI,KAAK,IAAI,GAAG,MAAM,GAAG+B,IAAI,CAACC,SAAS,CAAChC,IAAI,EAAE,IAAI,EAAE,CAAC,CACrD,CACJ,CAAC;AAEd,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { IFormModelFactory, IFormVM } from "../abstractions.js";
|
|
2
|
+
export interface FormModelDemoVM {
|
|
3
|
+
form: IFormVM;
|
|
4
|
+
data: Record<string, unknown>;
|
|
5
|
+
lastSubmitted: Record<string, unknown> | null;
|
|
6
|
+
isSubmitting: boolean;
|
|
7
|
+
runtimeTemplateAdded: boolean;
|
|
8
|
+
textTemplateRemoved: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare class FormModelDemoPresenter {
|
|
11
|
+
private form;
|
|
12
|
+
private lastSubmitted;
|
|
13
|
+
private isSubmitting;
|
|
14
|
+
private runtimeTemplateAdded;
|
|
15
|
+
private textTemplateRemoved;
|
|
16
|
+
constructor(formFactory: IFormModelFactory);
|
|
17
|
+
get vm(): FormModelDemoVM;
|
|
18
|
+
submit(): Promise<void>;
|
|
19
|
+
reset(): void;
|
|
20
|
+
toggleRuntimeTemplate(): void;
|
|
21
|
+
toggleTextTemplate(): void;
|
|
22
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { makeAutoObservable, toJS } from "mobx";
|
|
2
|
+
const RUNTIME_TEMPLATE_ID = "runtimeBanner";
|
|
3
|
+
export class FormModelDemoPresenter {
|
|
4
|
+
lastSubmitted = null;
|
|
5
|
+
isSubmitting = false;
|
|
6
|
+
runtimeTemplateAdded = false;
|
|
7
|
+
textTemplateRemoved = false;
|
|
8
|
+
constructor(formFactory) {
|
|
9
|
+
this.form = formFactory.create({
|
|
10
|
+
fields: fields => ({
|
|
11
|
+
title: fields.text().label("Title").required("Title is required"),
|
|
12
|
+
content: fields.object().label("Content Block").required("Pick a template").template("hero", t => {
|
|
13
|
+
t.label("Hero Banner").fields(f => ({
|
|
14
|
+
heading: f.text().label("Heading").required("Required"),
|
|
15
|
+
subheading: f.text().label("Subheading"),
|
|
16
|
+
image: f.text().label("Image URL"),
|
|
17
|
+
cta: f.text().label("Call To Action")
|
|
18
|
+
}));
|
|
19
|
+
}).template("text", t => {
|
|
20
|
+
t.label("Rich Text").fields(f => ({
|
|
21
|
+
body: f.text().label("Body").required("Required")
|
|
22
|
+
}));
|
|
23
|
+
}).template("premium", t => {
|
|
24
|
+
t.label("Premium Widget").visible(form => form.field("plan").getValue() === "enterprise").fields(f => ({
|
|
25
|
+
config: f.text().label("Widget Config")
|
|
26
|
+
}));
|
|
27
|
+
}),
|
|
28
|
+
sections: fields.object().label("Page Sections").list().template("hero", t => {
|
|
29
|
+
t.label("Hero Banner").fields(f => ({
|
|
30
|
+
heading: f.text().label("Heading").required("Required"),
|
|
31
|
+
subheading: f.text().label("Subheading"),
|
|
32
|
+
image: f.text().label("Image URL")
|
|
33
|
+
}));
|
|
34
|
+
}).template("text", t => {
|
|
35
|
+
t.label("Rich Text").fields(f => ({
|
|
36
|
+
body: f.text().label("Body").required("Required")
|
|
37
|
+
}));
|
|
38
|
+
}).template("cta", t => {
|
|
39
|
+
t.label("Call To Action").fields(f => ({
|
|
40
|
+
label: f.text().label("Button Label").required("Required"),
|
|
41
|
+
url: f.text().label("Link URL")
|
|
42
|
+
}));
|
|
43
|
+
}),
|
|
44
|
+
plan: fields.text().label("Plan").defaultValue("free").options([{
|
|
45
|
+
label: "Free",
|
|
46
|
+
value: "free"
|
|
47
|
+
}, {
|
|
48
|
+
label: "Pro",
|
|
49
|
+
value: "pro"
|
|
50
|
+
}, {
|
|
51
|
+
label: "Enterprise",
|
|
52
|
+
value: "enterprise"
|
|
53
|
+
}])
|
|
54
|
+
}),
|
|
55
|
+
layout: layout => [layout.row("title"), layout.row("plan"), layout.object("content", {
|
|
56
|
+
hero: l => [l.row("heading", "subheading"), l.row("image"), l.row("cta")],
|
|
57
|
+
text: l => [l.row("body")]
|
|
58
|
+
}), layout.object("sections", {
|
|
59
|
+
hero: l => [l.row("heading", "subheading"), l.row("image")],
|
|
60
|
+
cta: l => [l.row("label", "url")]
|
|
61
|
+
})]
|
|
62
|
+
});
|
|
63
|
+
makeAutoObservable(this);
|
|
64
|
+
}
|
|
65
|
+
get vm() {
|
|
66
|
+
return {
|
|
67
|
+
form: this.form.vm,
|
|
68
|
+
data: toJS(this.form.getData()),
|
|
69
|
+
lastSubmitted: this.lastSubmitted,
|
|
70
|
+
isSubmitting: this.isSubmitting,
|
|
71
|
+
runtimeTemplateAdded: this.runtimeTemplateAdded,
|
|
72
|
+
textTemplateRemoved: this.textTemplateRemoved
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
async submit() {
|
|
76
|
+
this.isSubmitting = true;
|
|
77
|
+
try {
|
|
78
|
+
const result = await this.form.submit();
|
|
79
|
+
if (result !== false) {
|
|
80
|
+
this.lastSubmitted = toJS(result);
|
|
81
|
+
}
|
|
82
|
+
} finally {
|
|
83
|
+
this.isSubmitting = false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
reset() {
|
|
87
|
+
this.form.reset();
|
|
88
|
+
this.lastSubmitted = null;
|
|
89
|
+
}
|
|
90
|
+
toggleRuntimeTemplate() {
|
|
91
|
+
const sections = this.form.field("sections").as("object");
|
|
92
|
+
if (this.runtimeTemplateAdded) {
|
|
93
|
+
sections.templates.remove(RUNTIME_TEMPLATE_ID);
|
|
94
|
+
this.runtimeTemplateAdded = false;
|
|
95
|
+
} else {
|
|
96
|
+
sections.templates.add(RUNTIME_TEMPLATE_ID, t => {
|
|
97
|
+
t.label("Runtime Banner").fields(f => ({
|
|
98
|
+
headline: f.text().label("Headline").required("Required"),
|
|
99
|
+
note: f.text().label("Note")
|
|
100
|
+
}));
|
|
101
|
+
});
|
|
102
|
+
this.runtimeTemplateAdded = true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
toggleTextTemplate() {
|
|
106
|
+
const content = this.form.field("content").as("object");
|
|
107
|
+
if (this.textTemplateRemoved) {
|
|
108
|
+
content.templates.add("text", t => {
|
|
109
|
+
t.label("Rich Text").fields(f => ({
|
|
110
|
+
body: f.text().label("Body").required("Required")
|
|
111
|
+
}));
|
|
112
|
+
});
|
|
113
|
+
this.textTemplateRemoved = false;
|
|
114
|
+
} else {
|
|
115
|
+
content.templates.remove("text");
|
|
116
|
+
this.textTemplateRemoved = true;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
//# sourceMappingURL=FormModelDemoPresenter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["makeAutoObservable","toJS","RUNTIME_TEMPLATE_ID","FormModelDemoPresenter","lastSubmitted","isSubmitting","runtimeTemplateAdded","textTemplateRemoved","constructor","formFactory","form","create","fields","title","text","label","required","content","object","template","t","f","heading","subheading","image","cta","body","visible","field","getValue","config","sections","list","url","plan","defaultValue","options","value","layout","row","hero","l","vm","data","getData","submit","result","reset","toggleRuntimeTemplate","as","templates","remove","add","headline","note","toggleTextTemplate"],"sources":["FormModelDemoPresenter.ts"],"sourcesContent":["import { makeAutoObservable, toJS } from \"mobx\";\nimport type { IFormModel, IFormModelFactory, IFormVM } from \"../abstractions.js\";\n\nexport interface FormModelDemoVM {\n form: IFormVM;\n data: Record<string, unknown>;\n lastSubmitted: Record<string, unknown> | null;\n isSubmitting: boolean;\n runtimeTemplateAdded: boolean;\n textTemplateRemoved: boolean;\n}\n\nconst RUNTIME_TEMPLATE_ID = \"runtimeBanner\";\n\nexport class FormModelDemoPresenter {\n private form: IFormModel;\n private lastSubmitted: Record<string, unknown> | null = null;\n private isSubmitting = false;\n private runtimeTemplateAdded = false;\n private textTemplateRemoved = false;\n\n constructor(formFactory: IFormModelFactory) {\n this.form = formFactory.create({\n fields: fields => ({\n title: fields.text().label(\"Title\").required(\"Title is required\"),\n content: fields\n .object()\n .label(\"Content Block\")\n .required(\"Pick a template\")\n .template(\"hero\", t => {\n t.label(\"Hero Banner\").fields(f => ({\n heading: f.text().label(\"Heading\").required(\"Required\"),\n subheading: f.text().label(\"Subheading\"),\n image: f.text().label(\"Image URL\"),\n cta: f.text().label(\"Call To Action\")\n }));\n })\n .template(\"text\", t => {\n t.label(\"Rich Text\").fields(f => ({\n body: f.text().label(\"Body\").required(\"Required\")\n }));\n })\n .template(\"premium\", t => {\n t.label(\"Premium Widget\")\n .visible(form => form.field(\"plan\").getValue() === \"enterprise\")\n .fields(f => ({\n config: f.text().label(\"Widget Config\")\n }));\n }),\n sections: fields\n .object()\n .label(\"Page Sections\")\n .list()\n .template(\"hero\", t => {\n t.label(\"Hero Banner\").fields(f => ({\n heading: f.text().label(\"Heading\").required(\"Required\"),\n subheading: f.text().label(\"Subheading\"),\n image: f.text().label(\"Image URL\")\n }));\n })\n .template(\"text\", t => {\n t.label(\"Rich Text\").fields(f => ({\n body: f.text().label(\"Body\").required(\"Required\")\n }));\n })\n .template(\"cta\", t => {\n t.label(\"Call To Action\").fields(f => ({\n label: f.text().label(\"Button Label\").required(\"Required\"),\n url: f.text().label(\"Link URL\")\n }));\n }),\n plan: fields\n .text()\n .label(\"Plan\")\n .defaultValue(\"free\")\n .options([\n { label: \"Free\", value: \"free\" },\n { label: \"Pro\", value: \"pro\" },\n { label: \"Enterprise\", value: \"enterprise\" }\n ])\n }),\n layout: layout => [\n layout.row(\"title\"),\n layout.row(\"plan\"),\n layout.object(\"content\", {\n hero: l => [l.row(\"heading\", \"subheading\"), l.row(\"image\"), l.row(\"cta\")],\n text: l => [l.row(\"body\")]\n }),\n layout.object(\"sections\", {\n hero: l => [l.row(\"heading\", \"subheading\"), l.row(\"image\")],\n cta: l => [l.row(\"label\", \"url\")]\n })\n ]\n });\n\n makeAutoObservable(this);\n }\n\n get vm(): FormModelDemoVM {\n return {\n form: this.form.vm,\n data: toJS(this.form.getData()),\n lastSubmitted: this.lastSubmitted,\n isSubmitting: this.isSubmitting,\n runtimeTemplateAdded: this.runtimeTemplateAdded,\n textTemplateRemoved: this.textTemplateRemoved\n };\n }\n\n async submit(): Promise<void> {\n this.isSubmitting = true;\n try {\n const result = await this.form.submit<Record<string, unknown>>();\n if (result !== false) {\n this.lastSubmitted = toJS(result);\n }\n } finally {\n this.isSubmitting = false;\n }\n }\n\n reset(): void {\n this.form.reset();\n this.lastSubmitted = null;\n }\n\n toggleRuntimeTemplate(): void {\n const sections = this.form.field(\"sections\").as(\"object\");\n if (this.runtimeTemplateAdded) {\n sections.templates.remove(RUNTIME_TEMPLATE_ID);\n this.runtimeTemplateAdded = false;\n } else {\n sections.templates.add(RUNTIME_TEMPLATE_ID, t => {\n t.label(\"Runtime Banner\").fields(f => ({\n headline: f.text().label(\"Headline\").required(\"Required\"),\n note: f.text().label(\"Note\")\n }));\n });\n this.runtimeTemplateAdded = true;\n }\n }\n\n toggleTextTemplate(): void {\n const content = this.form.field(\"content\").as(\"object\");\n if (this.textTemplateRemoved) {\n content.templates.add(\"text\", t => {\n t.label(\"Rich Text\").fields(f => ({\n body: f.text().label(\"Body\").required(\"Required\")\n }));\n });\n this.textTemplateRemoved = false;\n } else {\n content.templates.remove(\"text\");\n this.textTemplateRemoved = true;\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { IFormModelFactory, IFormVM } from "../abstractions.js";
|
|
2
|
+
export interface FormModelPhase11VM {
|
|
3
|
+
form: IFormVM;
|
|
4
|
+
data: Record<string, unknown>;
|
|
5
|
+
lastSubmitted: Record<string, unknown> | null;
|
|
6
|
+
isSubmitting: boolean;
|
|
7
|
+
formErrors: {
|
|
8
|
+
path: string;
|
|
9
|
+
message: string;
|
|
10
|
+
}[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Demo presenter exercising Phase 11 features: requiredWhen (builder + modifier
|
|
14
|
+
* chaining), computed/computedUntilDirty, .extend() on object fields, form-level
|
|
15
|
+
* addRule (Zod + imperative), and setLayout.
|
|
16
|
+
*/
|
|
17
|
+
export declare class FormModelPhase11Presenter {
|
|
18
|
+
private form;
|
|
19
|
+
private lastSubmitted;
|
|
20
|
+
private isSubmitting;
|
|
21
|
+
constructor(formFactory: IFormModelFactory);
|
|
22
|
+
get vm(): FormModelPhase11VM;
|
|
23
|
+
submit(): Promise<void>;
|
|
24
|
+
reset(): void;
|
|
25
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { makeAutoObservable, toJS } from "mobx";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
/**
|
|
4
|
+
* Demo presenter exercising Phase 11 features: requiredWhen (builder + modifier
|
|
5
|
+
* chaining), computed/computedUntilDirty, .extend() on object fields, form-level
|
|
6
|
+
* addRule (Zod + imperative), and setLayout.
|
|
7
|
+
*/
|
|
8
|
+
export class FormModelPhase11Presenter {
|
|
9
|
+
lastSubmitted = null;
|
|
10
|
+
isSubmitting = false;
|
|
11
|
+
constructor(formFactory) {
|
|
12
|
+
this.form = formFactory.create({
|
|
13
|
+
fields: fields => ({
|
|
14
|
+
first: fields.text().label("First name").defaultValue("Ada"),
|
|
15
|
+
last: fields.text().label("Last name").defaultValue("Lovelace"),
|
|
16
|
+
fullName: fields.text().label("Full name (computed)").computed(f => `${f.field("first").getValue()} ${f.field("last").getValue()}`),
|
|
17
|
+
slug: fields.text().label("Slug (computed until you edit it)").computedUntilDirty(f => {
|
|
18
|
+
const full = `${f.field("first").getValue()} ${f.field("last").getValue()}`;
|
|
19
|
+
return full.trim().toLowerCase().replace(/\s+/g, "-");
|
|
20
|
+
}),
|
|
21
|
+
plan: fields.text().label("Plan").defaultValue("free").options([{
|
|
22
|
+
label: "Free",
|
|
23
|
+
value: "free"
|
|
24
|
+
}, {
|
|
25
|
+
label: "Pro",
|
|
26
|
+
value: "pro"
|
|
27
|
+
}, {
|
|
28
|
+
label: "Enterprise",
|
|
29
|
+
value: "enterprise"
|
|
30
|
+
}]),
|
|
31
|
+
seats: fields.text().label("Number of seats").help("Required when plan is pro or enterprise").requiredWhen(f => f.field("plan").getValue() === "pro", "Pro plan needs a seat count"),
|
|
32
|
+
profile: fields.object().label("Profile").fields(f => ({
|
|
33
|
+
title: f.text().label("Title")
|
|
34
|
+
})),
|
|
35
|
+
password: fields.text().label("Password"),
|
|
36
|
+
confirm: fields.text().label("Confirm password")
|
|
37
|
+
})
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Modifier-style: add children to the existing "profile" object field.
|
|
41
|
+
this.form.field("profile").as("object").fields(f => ({
|
|
42
|
+
company: f.text().label("Company"),
|
|
43
|
+
bio: f.text().label("Short bio")
|
|
44
|
+
}));
|
|
45
|
+
|
|
46
|
+
// Modifier-style requiredWhen: chains with the builder-defined one above.
|
|
47
|
+
// First truthy callback wins.
|
|
48
|
+
this.form.field("seats").addRequiredWhen(f => f.field("plan").getValue() === "enterprise", "Enterprise plan needs a seat count too");
|
|
49
|
+
|
|
50
|
+
// Form-level Zod rule: confirm must match password.
|
|
51
|
+
this.form.addRule(z.object({
|
|
52
|
+
password: z.string().nullable(),
|
|
53
|
+
confirm: z.string().nullable()
|
|
54
|
+
}).refine(d => d.password === d.confirm || !d.password && !d.confirm, {
|
|
55
|
+
message: "Passwords must match",
|
|
56
|
+
path: ["confirm"]
|
|
57
|
+
}));
|
|
58
|
+
|
|
59
|
+
// Imperative form-level rule.
|
|
60
|
+
this.form.addRule(f => {
|
|
61
|
+
const slug = String(f.field("slug").getValue() ?? "");
|
|
62
|
+
if (slug.length > 0 && slug.length < 3) {
|
|
63
|
+
return [{
|
|
64
|
+
path: "slug",
|
|
65
|
+
message: "Slug must be at least 3 characters"
|
|
66
|
+
}];
|
|
67
|
+
}
|
|
68
|
+
return [];
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// setLayout — full replacement.
|
|
72
|
+
this.form.setLayout(layout => [layout.row("first", "last"), layout.row("fullName"), layout.row("slug"), layout.separator(), layout.row("plan", "seats"), layout.separator(), layout.object("profile", l => [l.row("title"), l.row("company"), l.row("bio")]), layout.separator(), layout.row("password", "confirm")]);
|
|
73
|
+
makeAutoObservable(this);
|
|
74
|
+
}
|
|
75
|
+
get vm() {
|
|
76
|
+
return {
|
|
77
|
+
form: this.form.vm,
|
|
78
|
+
data: toJS(this.form.getData()),
|
|
79
|
+
lastSubmitted: this.lastSubmitted,
|
|
80
|
+
isSubmitting: this.isSubmitting,
|
|
81
|
+
formErrors: this.form.errors.map(e => ({
|
|
82
|
+
path: e.path,
|
|
83
|
+
message: e.message
|
|
84
|
+
}))
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
async submit() {
|
|
88
|
+
this.isSubmitting = true;
|
|
89
|
+
try {
|
|
90
|
+
const result = await this.form.submit();
|
|
91
|
+
if (result !== false) {
|
|
92
|
+
this.lastSubmitted = toJS(result);
|
|
93
|
+
}
|
|
94
|
+
} finally {
|
|
95
|
+
this.isSubmitting = false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
reset() {
|
|
99
|
+
this.form.reset();
|
|
100
|
+
this.lastSubmitted = null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
//# sourceMappingURL=FormModelPhase11Presenter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["makeAutoObservable","toJS","z","FormModelPhase11Presenter","lastSubmitted","isSubmitting","constructor","formFactory","form","create","fields","first","text","label","defaultValue","last","fullName","computed","f","field","getValue","slug","computedUntilDirty","full","trim","toLowerCase","replace","plan","options","value","seats","help","requiredWhen","profile","object","title","password","confirm","as","company","bio","addRequiredWhen","addRule","string","nullable","refine","d","message","path","String","length","setLayout","layout","row","separator","l","vm","data","getData","formErrors","errors","map","e","submit","result","reset"],"sources":["FormModelPhase11Presenter.ts"],"sourcesContent":["import { makeAutoObservable, toJS } from \"mobx\";\nimport { z } from \"zod\";\nimport type { IFormModel, IFormModelFactory, IFormVM } from \"../abstractions.js\";\n\nexport interface FormModelPhase11VM {\n form: IFormVM;\n data: Record<string, unknown>;\n lastSubmitted: Record<string, unknown> | null;\n isSubmitting: boolean;\n formErrors: { path: string; message: string }[];\n}\n\n/**\n * Demo presenter exercising Phase 11 features: requiredWhen (builder + modifier\n * chaining), computed/computedUntilDirty, .extend() on object fields, form-level\n * addRule (Zod + imperative), and setLayout.\n */\nexport class FormModelPhase11Presenter {\n private form: IFormModel;\n private lastSubmitted: Record<string, unknown> | null = null;\n private isSubmitting = false;\n\n constructor(formFactory: IFormModelFactory) {\n this.form = formFactory.create({\n fields: fields => ({\n first: fields.text().label(\"First name\").defaultValue(\"Ada\"),\n last: fields.text().label(\"Last name\").defaultValue(\"Lovelace\"),\n fullName: fields\n .text()\n .label(\"Full name (computed)\")\n .computed(f => `${f.field(\"first\").getValue()} ${f.field(\"last\").getValue()}`),\n slug: fields\n .text()\n .label(\"Slug (computed until you edit it)\")\n .computedUntilDirty(f => {\n const full = `${f.field(\"first\").getValue()} ${f.field(\"last\").getValue()}`;\n return full.trim().toLowerCase().replace(/\\s+/g, \"-\");\n }),\n plan: fields\n .text()\n .label(\"Plan\")\n .defaultValue(\"free\")\n .options([\n { label: \"Free\", value: \"free\" },\n { label: \"Pro\", value: \"pro\" },\n { label: \"Enterprise\", value: \"enterprise\" }\n ]),\n seats: fields\n .text()\n .label(\"Number of seats\")\n .help(\"Required when plan is pro or enterprise\")\n .requiredWhen(\n f => f.field(\"plan\").getValue() === \"pro\",\n \"Pro plan needs a seat count\"\n ),\n profile: fields\n .object()\n .label(\"Profile\")\n .fields(f => ({\n title: f.text().label(\"Title\")\n })),\n password: fields.text().label(\"Password\"),\n confirm: fields.text().label(\"Confirm password\")\n })\n });\n\n // Modifier-style: add children to the existing \"profile\" object field.\n this.form\n .field(\"profile\")\n .as(\"object\")\n .fields(f => ({\n company: f.text().label(\"Company\"),\n bio: f.text().label(\"Short bio\")\n }));\n\n // Modifier-style requiredWhen: chains with the builder-defined one above.\n // First truthy callback wins.\n this.form\n .field(\"seats\")\n .addRequiredWhen(\n f => f.field(\"plan\").getValue() === \"enterprise\",\n \"Enterprise plan needs a seat count too\"\n );\n\n // Form-level Zod rule: confirm must match password.\n this.form.addRule(\n z\n .object({\n password: z.string().nullable(),\n confirm: z.string().nullable()\n })\n .refine(d => d.password === d.confirm || (!d.password && !d.confirm), {\n message: \"Passwords must match\",\n path: [\"confirm\"]\n })\n );\n\n // Imperative form-level rule.\n this.form.addRule(f => {\n const slug = String(f.field(\"slug\").getValue() ?? \"\");\n if (slug.length > 0 && slug.length < 3) {\n return [{ path: \"slug\", message: \"Slug must be at least 3 characters\" }];\n }\n return [];\n });\n\n // setLayout — full replacement.\n this.form.setLayout(layout => [\n layout.row(\"first\", \"last\"),\n layout.row(\"fullName\"),\n layout.row(\"slug\"),\n layout.separator(),\n layout.row(\"plan\", \"seats\"),\n layout.separator(),\n layout.object(\"profile\", l => [l.row(\"title\"), l.row(\"company\"), l.row(\"bio\")]),\n layout.separator(),\n layout.row(\"password\", \"confirm\")\n ]);\n\n makeAutoObservable(this);\n }\n\n get vm(): FormModelPhase11VM {\n return {\n form: this.form.vm,\n data: toJS(this.form.getData()),\n lastSubmitted: this.lastSubmitted,\n isSubmitting: this.isSubmitting,\n formErrors: this.form.errors.map(e => ({\n path: e.path,\n message: e.message\n }))\n };\n }\n\n async submit(): Promise<void> {\n this.isSubmitting = true;\n try {\n const result = await this.form.submit<Record<string, unknown>>();\n if (result !== false) {\n this.lastSubmitted = toJS(result);\n }\n } finally {\n this.isSubmitting = false;\n }\n }\n\n reset(): void {\n this.form.reset();\n this.lastSubmitted = null;\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { IFormModelFactory, IFormVM } from "../abstractions.js";
|
|
2
|
+
export interface FormModelPhase8c1VM {
|
|
3
|
+
form: IFormVM;
|
|
4
|
+
data: Record<string, unknown>;
|
|
5
|
+
lastSubmitted: Record<string, unknown> | null;
|
|
6
|
+
isSubmitting: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Demo presenter exercising Phase 8c.1: nested object layouts. The form has a
|
|
10
|
+
* top-level `page` object whose inner layout contains tabs, and one of those
|
|
11
|
+
* tabs contains a nested `seo` object with its own row layout. The Phase 8c.1
|
|
12
|
+
* registrar walks the inner layout (including tabs) and forwards the nested
|
|
13
|
+
* `layout.object("seo", ...)` to the seo field at build time.
|
|
14
|
+
*/
|
|
15
|
+
export declare class FormModelPhase8c1Presenter {
|
|
16
|
+
private form;
|
|
17
|
+
private lastSubmitted;
|
|
18
|
+
private isSubmitting;
|
|
19
|
+
constructor(formFactory: IFormModelFactory);
|
|
20
|
+
get vm(): FormModelPhase8c1VM;
|
|
21
|
+
submit(): Promise<void>;
|
|
22
|
+
reset(): void;
|
|
23
|
+
}
|