xmlui 0.10.26 → 0.11.2
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/dist/lib/{index-DHXWMb-6.mjs → index-DyhCY6Ga.js} +263 -643
- package/dist/lib/index.css +1 -1
- package/dist/lib/{initMock-TxnkId6_.mjs → initMock-DN7MXrdn.js} +1 -1
- package/dist/lib/{language-server-web-worker.mjs → language-server-web-worker.js} +1 -1
- package/dist/lib/{language-server.mjs → language-server.js} +1 -1
- package/dist/lib/{metadata-utils-DXUdlyja.mjs → metadata-utils-D27cn-XB.js} +1 -1
- package/dist/lib/{server-common-CtpN0Z4h.mjs → server-common-2DaoOOL5.js} +625 -616
- package/dist/lib/testing.d.ts +2011 -0
- package/dist/lib/testing.js +2386 -0
- package/dist/lib/vite-xmlui-plugin/index.js +13968 -0
- package/dist/lib/vite-xmlui-plugin/package.json +3 -0
- package/dist/lib/xmlui-parser-BZZ430Wm.js +523 -0
- package/dist/lib/xmlui-parser.d.ts +2 -1
- package/dist/lib/{xmlui-parser.mjs → xmlui-parser.js} +2 -2
- package/dist/lib/{xmlui-serializer-uCYa8_tZ.mjs → xmlui-serializer-D9D2mQ8m.js} +1 -1
- package/dist/lib/xmlui.d.ts +1 -0
- package/dist/lib/{xmlui.mjs → xmlui.js} +24 -23
- package/dist/metadata/{collectedComponentMetadata-BgHIc2Iu.mjs → collectedComponentMetadata-BNSnCrzh.js} +698 -567
- package/dist/metadata/{initMock-B3UDa-rw.mjs → initMock-CVnDRyRf.js} +1 -1
- package/dist/metadata/style.css +1 -1
- package/dist/metadata/{xmlui-metadata.mjs → xmlui-metadata.js} +1 -1
- package/dist/metadata/xmlui-metadata.umd.cjs +207 -0
- package/dist/scripts/bin/bootstrap.cjs +4 -0
- package/dist/scripts/bin/index.js +85 -13
- package/dist/scripts/package.json +31 -24
- package/dist/scripts/src/components/App/App.spec.js +27 -15
- package/dist/scripts/src/components/Avatar/Avatar.spec.js +0 -29
- package/dist/scripts/src/components/Button/Button.spec.js +0 -29
- package/dist/scripts/src/components/Charts/BarChart/BarChartNative.js +2 -0
- package/dist/scripts/src/components/Charts/LineChart/LineChartNative.js +2 -2
- package/dist/scripts/src/components/Charts/Tooltip/TooltipContent.spec.js +8 -6
- package/dist/scripts/src/components/Form/Form.js +19 -0
- package/dist/scripts/src/components/Form/Form.spec.js +444 -0
- package/dist/scripts/src/components/Form/FormNative.js +46 -15
- package/dist/scripts/src/components/Form/formActions.js +3 -2
- package/dist/scripts/src/components/FormItem/FormItem.js +10 -2
- package/dist/scripts/src/components/FormItem/FormItem.spec.js +159 -0
- package/dist/scripts/src/components/FormItem/FormItemNative.js +6 -5
- package/dist/scripts/src/components/Heading/Heading.spec.js +34 -47
- package/dist/scripts/src/components/Queue/Queue.js +1 -16
- package/dist/scripts/src/components/Queue/QueueNative.js +60 -2
- package/dist/scripts/src/components/TableOfContents/TableOfContents.js +7 -5
- package/dist/scripts/src/components-core/appContext/misc-utils.js +2 -1
- package/dist/scripts/src/components-core/devtools/InspectorDialog.js +2 -2
- package/dist/scripts/src/components-core/script-runner/eval-tree-async.js +2 -0
- package/dist/scripts/src/components-core/utils/base64-utils.js +2 -0
- package/dist/scripts/src/components-core/utils/misc.js +44 -0
- package/dist/scripts/src/language-server/server-common.js +2 -2
- package/dist/scripts/src/language-server/{xmlui-metadata-generated.mjs → xmlui-metadata-generated.js} +625 -615
- package/dist/scripts/src/testing/drivers/index.js +9 -0
- package/dist/scripts/src/testing/index.js +69 -0
- package/dist/standalone/xmlui-standalone.es.d.ts +32 -16
- package/dist/standalone/xmlui-standalone.umd.js +36 -36
- package/package.json +46 -39
- package/dist/metadata/xmlui-metadata.umd.js +0 -207
- package/dist/scripts/bin/bootstrap.js +0 -11
- /package/dist/lib/{apiInterceptorWorker-QiltRtq1.mjs → apiInterceptorWorker-QiltRtq1.js} +0 -0
- /package/dist/lib/{syntax-monaco.mjs → syntax-monaco.js} +0 -0
- /package/dist/lib/{syntax-textmate.mjs → syntax-textmate.js} +0 -0
- /package/dist/lib/{transform-Tooy42EB.mjs → transform-Tooy42EB.js} +0 -0
- /package/dist/metadata/{apiInterceptorWorker-Dql7QGw2.mjs → apiInterceptorWorker-Dql7QGw2.js} +0 -0
|
@@ -97,6 +97,334 @@ fixtures_1.test.describe("Basic Functionality", () => {
|
|
|
97
97
|
yield (0, fixtures_1.expect)(buttons.last()).toHaveText("Cancel");
|
|
98
98
|
}));
|
|
99
99
|
// =============================================================================
|
|
100
|
+
// HIDE BUTTON ROW TESTS
|
|
101
|
+
// =============================================================================
|
|
102
|
+
fixtures_1.test.describe("hideButtonRow property", () => {
|
|
103
|
+
(0, fixtures_1.test)("hides button row when set to true", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
104
|
+
yield initTestBed(`<Form hideButtonRow="true"/>`);
|
|
105
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Cancel" })).not.toBeVisible();
|
|
106
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).not.toBeVisible();
|
|
107
|
+
}));
|
|
108
|
+
(0, fixtures_1.test)("shows button row when set to false", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
109
|
+
yield initTestBed(`<Form hideButtonRow="false"/>`);
|
|
110
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Cancel" })).toBeVisible();
|
|
111
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).toBeVisible();
|
|
112
|
+
}));
|
|
113
|
+
(0, fixtures_1.test)("shows button row by default when property not set", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
114
|
+
yield initTestBed(`<Form/>`);
|
|
115
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Cancel" })).toBeVisible();
|
|
116
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).toBeVisible();
|
|
117
|
+
}));
|
|
118
|
+
(0, fixtures_1.test)("hides custom button row template when set to true", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
119
|
+
yield initTestBed(`
|
|
120
|
+
<Form hideButtonRow="true">
|
|
121
|
+
<property name="buttonRowTemplate">
|
|
122
|
+
<Button label="Custom Save" type="submit" testId="customSave" />
|
|
123
|
+
<Button label="Custom Cancel" type="button" testId="customCancel" />
|
|
124
|
+
</property>
|
|
125
|
+
</Form>
|
|
126
|
+
`);
|
|
127
|
+
yield (0, fixtures_1.expect)(page.getByTestId("customSave")).not.toBeVisible();
|
|
128
|
+
yield (0, fixtures_1.expect)(page.getByTestId("customCancel")).not.toBeVisible();
|
|
129
|
+
}));
|
|
130
|
+
(0, fixtures_1.test)("overrides hideButtonRowUntilDirty when both are set", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page, createFormItemDriver, createTextBoxDriver, }) {
|
|
131
|
+
yield initTestBed(`
|
|
132
|
+
<Form hideButtonRow="true" hideButtonRowUntilDirty="true">
|
|
133
|
+
<FormItem label="Name" bindTo="name" testId="nameField" />
|
|
134
|
+
</Form>
|
|
135
|
+
`);
|
|
136
|
+
// Button row should be hidden even before making changes
|
|
137
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).not.toBeVisible();
|
|
138
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Cancel" })).not.toBeVisible();
|
|
139
|
+
// Make the form dirty
|
|
140
|
+
const driver = yield createFormItemDriver("nameField");
|
|
141
|
+
const input = yield createTextBoxDriver(driver.input);
|
|
142
|
+
yield input.field.fill("John");
|
|
143
|
+
// Button row should still be hidden even after making changes
|
|
144
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).not.toBeVisible();
|
|
145
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Cancel" })).not.toBeVisible();
|
|
146
|
+
}));
|
|
147
|
+
(0, fixtures_1.test)("handles null value gracefully", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
148
|
+
yield initTestBed(`<Form hideButtonRow="{null}"/>`);
|
|
149
|
+
// Should show button row (default behavior)
|
|
150
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Cancel" })).toBeVisible();
|
|
151
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).toBeVisible();
|
|
152
|
+
}));
|
|
153
|
+
(0, fixtures_1.test)("handles undefined value gracefully", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
154
|
+
yield initTestBed(`<Form hideButtonRow="{undefined}"/>`);
|
|
155
|
+
// Should show button row (default behavior)
|
|
156
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Cancel" })).toBeVisible();
|
|
157
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).toBeVisible();
|
|
158
|
+
}));
|
|
159
|
+
(0, fixtures_1.test)("handles string 'true' value", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
160
|
+
yield initTestBed(`<Form hideButtonRow="true"/>`);
|
|
161
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Cancel" })).not.toBeVisible();
|
|
162
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).not.toBeVisible();
|
|
163
|
+
}));
|
|
164
|
+
(0, fixtures_1.test)("handles string 'false' value", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
165
|
+
yield initTestBed(`<Form hideButtonRow="false"/>`);
|
|
166
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Cancel" })).toBeVisible();
|
|
167
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).toBeVisible();
|
|
168
|
+
}));
|
|
169
|
+
(0, fixtures_1.test)("form submission still works with hidden button row via external submit", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page, createFormItemDriver, createTextBoxDriver, }) {
|
|
170
|
+
const { testStateDriver } = yield initTestBed(`
|
|
171
|
+
<Fragment>
|
|
172
|
+
<Form id="testForm" hideButtonRow="true" onSubmit="arg => testState = arg">
|
|
173
|
+
<FormItem label="Name" bindTo="name" testId="nameField" />
|
|
174
|
+
<Button type="submit" label="External Submit" testId="externalSubmit" />
|
|
175
|
+
</Form>
|
|
176
|
+
</Fragment>
|
|
177
|
+
`);
|
|
178
|
+
const driver = yield createFormItemDriver("nameField");
|
|
179
|
+
const input = yield createTextBoxDriver(driver.input);
|
|
180
|
+
yield input.field.fill("John Doe");
|
|
181
|
+
yield page.getByTestId("externalSubmit").click();
|
|
182
|
+
const submittedData = yield testStateDriver.testState();
|
|
183
|
+
(0, fixtures_1.expect)(submittedData).toEqual({ name: "John Doe" });
|
|
184
|
+
}));
|
|
185
|
+
});
|
|
186
|
+
// =============================================================================
|
|
187
|
+
// HIDE BUTTON ROW UNTIL DIRTY TESTS
|
|
188
|
+
// =============================================================================
|
|
189
|
+
fixtures_1.test.describe("hideButtonRowUntilDirty property", () => {
|
|
190
|
+
(0, fixtures_1.test)("hides button row initially when form is not dirty", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
191
|
+
yield initTestBed(`
|
|
192
|
+
<Form hideButtonRowUntilDirty="true">
|
|
193
|
+
<FormItem label="Name" bindTo="name" testId="nameField" />
|
|
194
|
+
</Form>
|
|
195
|
+
`);
|
|
196
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Cancel" })).not.toBeVisible();
|
|
197
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).not.toBeVisible();
|
|
198
|
+
}));
|
|
199
|
+
(0, fixtures_1.test)("shows button row when form becomes dirty", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page, createFormItemDriver, createTextBoxDriver, }) {
|
|
200
|
+
yield initTestBed(`
|
|
201
|
+
<Form hideButtonRowUntilDirty="true">
|
|
202
|
+
<FormItem label="Name" bindTo="name" testId="nameField" />
|
|
203
|
+
</Form>
|
|
204
|
+
`);
|
|
205
|
+
// Initially hidden
|
|
206
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).not.toBeVisible();
|
|
207
|
+
// Make form dirty
|
|
208
|
+
const driver = yield createFormItemDriver("nameField");
|
|
209
|
+
const input = yield createTextBoxDriver(driver.input);
|
|
210
|
+
yield input.field.fill("John");
|
|
211
|
+
// Now visible
|
|
212
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Cancel" })).toBeVisible();
|
|
213
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).toBeVisible();
|
|
214
|
+
}));
|
|
215
|
+
(0, fixtures_1.test)("keeps button row visible after form becomes dirty", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page, createFormItemDriver, createTextBoxDriver, }) {
|
|
216
|
+
yield initTestBed(`
|
|
217
|
+
<Form hideButtonRowUntilDirty="true">
|
|
218
|
+
<FormItem label="Name" bindTo="name" testId="nameField" />
|
|
219
|
+
</Form>
|
|
220
|
+
`);
|
|
221
|
+
const driver = yield createFormItemDriver("nameField");
|
|
222
|
+
const input = yield createTextBoxDriver(driver.input);
|
|
223
|
+
// Make form dirty
|
|
224
|
+
yield input.field.fill("John");
|
|
225
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).toBeVisible();
|
|
226
|
+
// Clear the input (form is still dirty)
|
|
227
|
+
yield input.field.clear();
|
|
228
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).toBeVisible();
|
|
229
|
+
}));
|
|
230
|
+
(0, fixtures_1.test)("shows button row by default when property set to false", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page, }) {
|
|
231
|
+
yield initTestBed(`
|
|
232
|
+
<Form hideButtonRowUntilDirty="false">
|
|
233
|
+
<FormItem label="Name" bindTo="name" testId="nameField" />
|
|
234
|
+
</Form>
|
|
235
|
+
`);
|
|
236
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Cancel" })).toBeVisible();
|
|
237
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).toBeVisible();
|
|
238
|
+
}));
|
|
239
|
+
(0, fixtures_1.test)("shows button row by default when property not set", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
240
|
+
yield initTestBed(`
|
|
241
|
+
<Form>
|
|
242
|
+
<FormItem label="Name" bindTo="name" testId="nameField" />
|
|
243
|
+
</Form>
|
|
244
|
+
`);
|
|
245
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Cancel" })).toBeVisible();
|
|
246
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).toBeVisible();
|
|
247
|
+
}));
|
|
248
|
+
(0, fixtures_1.test)("works with multiple form items", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page, createFormItemDriver, createTextBoxDriver, }) {
|
|
249
|
+
yield initTestBed(`
|
|
250
|
+
<Form hideButtonRowUntilDirty="true">
|
|
251
|
+
<FormItem label="Name" bindTo="name" testId="nameField" />
|
|
252
|
+
<FormItem label="Email" bindTo="email" testId="emailField" />
|
|
253
|
+
</Form>
|
|
254
|
+
`);
|
|
255
|
+
// Initially hidden
|
|
256
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).not.toBeVisible();
|
|
257
|
+
// Modify second field
|
|
258
|
+
const emailDriver = yield createFormItemDriver("emailField");
|
|
259
|
+
const emailInput = yield createTextBoxDriver(emailDriver.input);
|
|
260
|
+
yield emailInput.field.fill("test@example.com");
|
|
261
|
+
// Now visible
|
|
262
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).toBeVisible();
|
|
263
|
+
}));
|
|
264
|
+
(0, fixtures_1.test)("hides custom button row template until dirty", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page, createFormItemDriver, createTextBoxDriver, }) {
|
|
265
|
+
yield initTestBed(`
|
|
266
|
+
<Form hideButtonRowUntilDirty="true">
|
|
267
|
+
<FormItem label="Name" bindTo="name" testId="nameField" />
|
|
268
|
+
<property name="buttonRowTemplate">
|
|
269
|
+
<Button label="Custom Save" type="submit" testId="customSave" />
|
|
270
|
+
</property>
|
|
271
|
+
</Form>
|
|
272
|
+
`);
|
|
273
|
+
// Initially hidden
|
|
274
|
+
yield (0, fixtures_1.expect)(page.getByTestId("customSave")).not.toBeVisible();
|
|
275
|
+
// Make form dirty
|
|
276
|
+
const driver = yield createFormItemDriver("nameField");
|
|
277
|
+
const input = yield createTextBoxDriver(driver.input);
|
|
278
|
+
yield input.field.fill("John");
|
|
279
|
+
// Now visible
|
|
280
|
+
yield (0, fixtures_1.expect)(page.getByTestId("customSave")).toBeVisible();
|
|
281
|
+
}));
|
|
282
|
+
(0, fixtures_1.test)("handles null value gracefully", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
283
|
+
yield initTestBed(`
|
|
284
|
+
<Form hideButtonRowUntilDirty="{null}">
|
|
285
|
+
<FormItem label="Name" bindTo="name" testId="nameField" />
|
|
286
|
+
</Form>
|
|
287
|
+
`);
|
|
288
|
+
// Should show button row (default behavior)
|
|
289
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Cancel" })).toBeVisible();
|
|
290
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).toBeVisible();
|
|
291
|
+
}));
|
|
292
|
+
(0, fixtures_1.test)("handles undefined value gracefully", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
293
|
+
yield initTestBed(`
|
|
294
|
+
<Form hideButtonRowUntilDirty="{undefined}">
|
|
295
|
+
<FormItem label="Name" bindTo="name" testId="nameField" />
|
|
296
|
+
</Form>
|
|
297
|
+
`);
|
|
298
|
+
// Should show button row (default behavior)
|
|
299
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Cancel" })).toBeVisible();
|
|
300
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).toBeVisible();
|
|
301
|
+
}));
|
|
302
|
+
(0, fixtures_1.test)("works with form initialized with data", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page, createFormItemDriver, createTextBoxDriver, }) {
|
|
303
|
+
yield initTestBed(`
|
|
304
|
+
<Form hideButtonRowUntilDirty="true" data="{{ name: 'Initial' }}">
|
|
305
|
+
<FormItem label="Name" bindTo="name" testId="nameField" />
|
|
306
|
+
</Form>
|
|
307
|
+
`);
|
|
308
|
+
// Initially hidden (form has data but is not dirty)
|
|
309
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).not.toBeVisible();
|
|
310
|
+
// Make form dirty
|
|
311
|
+
const driver = yield createFormItemDriver("nameField");
|
|
312
|
+
const input = yield createTextBoxDriver(driver.input);
|
|
313
|
+
yield input.field.fill("Modified");
|
|
314
|
+
// Now visible
|
|
315
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).toBeVisible();
|
|
316
|
+
}));
|
|
317
|
+
(0, fixtures_1.test)("button row appears when checkbox is checked", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
318
|
+
yield initTestBed(`
|
|
319
|
+
<Form hideButtonRowUntilDirty="true">
|
|
320
|
+
<FormItem label="Accept Terms" bindTo="terms" type="checkbox" />
|
|
321
|
+
</Form>
|
|
322
|
+
`);
|
|
323
|
+
// Initially hidden
|
|
324
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).not.toBeVisible();
|
|
325
|
+
// Check the checkbox
|
|
326
|
+
const checkbox = page.getByRole("checkbox");
|
|
327
|
+
yield checkbox.check();
|
|
328
|
+
// Now visible
|
|
329
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).toBeVisible();
|
|
330
|
+
}));
|
|
331
|
+
(0, fixtures_1.test)("button row appears when slider value changes", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
332
|
+
yield initTestBed(`
|
|
333
|
+
<Form hideButtonRowUntilDirty="true">
|
|
334
|
+
<FormItem label="Volume" bindTo="volume" type="slider" testId="volumeField" />
|
|
335
|
+
</Form>
|
|
336
|
+
`);
|
|
337
|
+
// Initially hidden
|
|
338
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).not.toBeVisible();
|
|
339
|
+
// Move the slider using keyboard
|
|
340
|
+
const slider = page.getByRole("slider");
|
|
341
|
+
yield slider.press("ArrowRight");
|
|
342
|
+
// Now visible
|
|
343
|
+
yield (0, fixtures_1.expect)(page.getByRole("button", { name: "Save" })).toBeVisible();
|
|
344
|
+
}));
|
|
345
|
+
});
|
|
346
|
+
// =============================================================================
|
|
347
|
+
// ENABLE SUBMIT PROPERTY TESTS
|
|
348
|
+
// =============================================================================
|
|
349
|
+
fixtures_1.test.describe("enableSubmit property", () => {
|
|
350
|
+
(0, fixtures_1.test)("disables submit button when set to false", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
351
|
+
yield initTestBed(`<Form enableSubmit="false"/>`);
|
|
352
|
+
const saveButton = page.getByRole("button", { name: "Save" });
|
|
353
|
+
yield (0, fixtures_1.expect)(saveButton).toBeVisible();
|
|
354
|
+
yield (0, fixtures_1.expect)(saveButton).toBeDisabled();
|
|
355
|
+
}));
|
|
356
|
+
(0, fixtures_1.test)("enables submit button when set to true", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
357
|
+
yield initTestBed(`<Form enableSubmit="true"/>`);
|
|
358
|
+
const saveButton = page.getByRole("button", { name: "Save" });
|
|
359
|
+
yield (0, fixtures_1.expect)(saveButton).toBeVisible();
|
|
360
|
+
yield (0, fixtures_1.expect)(saveButton).toBeEnabled();
|
|
361
|
+
}));
|
|
362
|
+
(0, fixtures_1.test)("submit button is enabled by default when property not set", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page, }) {
|
|
363
|
+
yield initTestBed(`<Form/>`);
|
|
364
|
+
const saveButton = page.getByRole("button", { name: "Save" });
|
|
365
|
+
yield (0, fixtures_1.expect)(saveButton).toBeEnabled();
|
|
366
|
+
}));
|
|
367
|
+
(0, fixtures_1.test)("prevents form submission when set to false", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
368
|
+
const { testStateDriver } = yield initTestBed(`
|
|
369
|
+
<Form enableSubmit="false" onSubmit="arg => testState = arg">
|
|
370
|
+
<FormItem label="Name" bindTo="name" testId="nameField" />
|
|
371
|
+
</Form>
|
|
372
|
+
`);
|
|
373
|
+
const saveButton = page.getByRole("button", { name: "Save" });
|
|
374
|
+
yield (0, fixtures_1.expect)(saveButton).toBeDisabled();
|
|
375
|
+
// Verify form does not submit (button is disabled, so click won't work)
|
|
376
|
+
yield saveButton.click({ force: true }); // Force click on disabled button
|
|
377
|
+
// testState should remain null since submit was prevented
|
|
378
|
+
yield fixtures_1.expect.poll(testStateDriver.testState).toBeNull();
|
|
379
|
+
}));
|
|
380
|
+
(0, fixtures_1.test)("allows form submission when set to true", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page, createFormItemDriver, createTextBoxDriver, }) {
|
|
381
|
+
const { testStateDriver } = yield initTestBed(`
|
|
382
|
+
<Form enableSubmit="true" onSubmit="arg => testState = arg">
|
|
383
|
+
<FormItem label="Name" bindTo="name" testId="nameField" />
|
|
384
|
+
</Form>
|
|
385
|
+
`);
|
|
386
|
+
const driver = yield createFormItemDriver("nameField");
|
|
387
|
+
const input = yield createTextBoxDriver(driver.input);
|
|
388
|
+
yield input.field.fill("John Doe");
|
|
389
|
+
const saveButton = page.getByRole("button", { name: "Save" });
|
|
390
|
+
yield (0, fixtures_1.expect)(saveButton).toBeEnabled();
|
|
391
|
+
yield saveButton.click();
|
|
392
|
+
const submittedData = yield testStateDriver.testState();
|
|
393
|
+
(0, fixtures_1.expect)(submittedData).toEqual({ name: "John Doe" });
|
|
394
|
+
}));
|
|
395
|
+
(0, fixtures_1.test)("handles null value gracefully (defaults to enabled)", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
396
|
+
yield initTestBed(`<Form enableSubmit="{null}"/>`);
|
|
397
|
+
const saveButton = page.getByRole("button", { name: "Save" });
|
|
398
|
+
yield (0, fixtures_1.expect)(saveButton).toBeEnabled();
|
|
399
|
+
}));
|
|
400
|
+
(0, fixtures_1.test)("handles string 'true' value", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
401
|
+
yield initTestBed(`<Form enableSubmit="true"/>`);
|
|
402
|
+
const saveButton = page.getByRole("button", { name: "Save" });
|
|
403
|
+
yield (0, fixtures_1.expect)(saveButton).toBeEnabled();
|
|
404
|
+
}));
|
|
405
|
+
(0, fixtures_1.test)("handles string 'false' value", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
406
|
+
yield initTestBed(`<Form enableSubmit="false"/>`);
|
|
407
|
+
const saveButton = page.getByRole("button", { name: "Save" });
|
|
408
|
+
yield (0, fixtures_1.expect)(saveButton).toBeDisabled();
|
|
409
|
+
}));
|
|
410
|
+
(0, fixtures_1.test)("does not affect cancel button", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
411
|
+
yield initTestBed(`<Form enableSubmit="false"/>`);
|
|
412
|
+
const cancelButton = page.getByRole("button", { name: "Cancel" });
|
|
413
|
+
yield (0, fixtures_1.expect)(cancelButton).toBeEnabled();
|
|
414
|
+
}));
|
|
415
|
+
(0, fixtures_1.test)("works with custom submit button label", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
416
|
+
yield initTestBed(`<Form enableSubmit="false" saveLabel="Submit Now"/>`);
|
|
417
|
+
const submitButton = page.getByRole("button", { name: "Submit Now" });
|
|
418
|
+
yield (0, fixtures_1.expect)(submitButton).toBeDisabled();
|
|
419
|
+
}));
|
|
420
|
+
(0, fixtures_1.test)("works together with form disabled state", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
|
|
421
|
+
yield initTestBed(`<Form enabled="false" enableSubmit="true"/>`);
|
|
422
|
+
const saveButton = page.getByRole("button", { name: "Save" });
|
|
423
|
+
// Form disabled takes precedence
|
|
424
|
+
yield (0, fixtures_1.expect)(saveButton).toBeDisabled();
|
|
425
|
+
}));
|
|
426
|
+
});
|
|
427
|
+
// =============================================================================
|
|
100
428
|
// DATA PROPERTY TESTS
|
|
101
429
|
// =============================================================================
|
|
102
430
|
fixtures_1.test.describe("data property", () => {
|
|
@@ -366,6 +694,122 @@ fixtures_1.test.describe("Basic Functionality", () => {
|
|
|
366
694
|
yield page.getByRole("button", { name: "Reset" }).click();
|
|
367
695
|
yield (0, fixtures_1.expect)(nameInput.field).toHaveValue("Initial");
|
|
368
696
|
}));
|
|
697
|
+
(0, fixtures_1.test)("validate method returns validation results without submitting", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page, createFormItemDriver, createTextBoxDriver, }) {
|
|
698
|
+
const { testStateDriver } = yield initTestBed(`
|
|
699
|
+
<Form id="testForm">
|
|
700
|
+
<FormItem label="Name" bindTo="name" required="true" testId="nameField" />
|
|
701
|
+
<FormItem label="Email" bindTo="email" testId="emailField" />
|
|
702
|
+
<Button onClick="testState = testForm.validate()" label="Validate" testId="validateBtn" />
|
|
703
|
+
</Form>
|
|
704
|
+
`);
|
|
705
|
+
// Click validate button without filling required field
|
|
706
|
+
yield page.getByTestId("validateBtn").click();
|
|
707
|
+
// Wait for validation to complete
|
|
708
|
+
yield page.waitForTimeout(100);
|
|
709
|
+
const result = yield testStateDriver.testState();
|
|
710
|
+
(0, fixtures_1.expect)(result).toBeTruthy();
|
|
711
|
+
(0, fixtures_1.expect)(result.isValid).toBe(false);
|
|
712
|
+
(0, fixtures_1.expect)(result.errors).toBeDefined();
|
|
713
|
+
(0, fixtures_1.expect)(result.errors.length).toBeGreaterThan(0);
|
|
714
|
+
}));
|
|
715
|
+
(0, fixtures_1.test)("validate method returns isValid true when all validations pass", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page, createFormItemDriver, createTextBoxDriver, }) {
|
|
716
|
+
const { testStateDriver } = yield initTestBed(`
|
|
717
|
+
<Form id="testForm">
|
|
718
|
+
<FormItem label="Name" bindTo="name" required="true" testId="nameField" />
|
|
719
|
+
<Button onClick="testState = testForm.validate()" label="Validate" testId="validateBtn" />
|
|
720
|
+
</Form>
|
|
721
|
+
`);
|
|
722
|
+
// Fill the required field
|
|
723
|
+
const nameDriver = yield createFormItemDriver("nameField");
|
|
724
|
+
const nameInput = yield createTextBoxDriver(nameDriver.input);
|
|
725
|
+
yield nameInput.field.fill("John Doe");
|
|
726
|
+
// Click validate button
|
|
727
|
+
yield page.getByTestId("validateBtn").click();
|
|
728
|
+
// Wait for validation to complete
|
|
729
|
+
yield page.waitForTimeout(100);
|
|
730
|
+
const result = yield testStateDriver.testState();
|
|
731
|
+
(0, fixtures_1.expect)(result).toBeTruthy();
|
|
732
|
+
(0, fixtures_1.expect)(result.isValid).toBe(true);
|
|
733
|
+
(0, fixtures_1.expect)(result.errors.length).toBe(0);
|
|
734
|
+
}));
|
|
735
|
+
(0, fixtures_1.test)("validate method returns cleaned form data", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page, createFormItemDriver, createTextBoxDriver, }) {
|
|
736
|
+
const { testStateDriver } = yield initTestBed(`
|
|
737
|
+
<Form id="testForm">
|
|
738
|
+
<FormItem label="Name" bindTo="name" testId="nameField" />
|
|
739
|
+
<FormItem label="Age" bindTo="age" type="integer" testId="ageField" />
|
|
740
|
+
<Button onClick="testState = testForm.validate()" label="Validate" testId="validateBtn" />
|
|
741
|
+
</Form>
|
|
742
|
+
`);
|
|
743
|
+
// Fill form fields
|
|
744
|
+
const nameDriver = yield createFormItemDriver("nameField");
|
|
745
|
+
const nameInput = yield createTextBoxDriver(nameDriver.input);
|
|
746
|
+
yield nameInput.field.fill("John Doe");
|
|
747
|
+
const ageDriver = yield createFormItemDriver("ageField");
|
|
748
|
+
const ageInput = yield createTextBoxDriver(ageDriver.input);
|
|
749
|
+
yield ageInput.field.fill("30");
|
|
750
|
+
// Click validate button
|
|
751
|
+
yield page.getByTestId("validateBtn").click();
|
|
752
|
+
// Wait for validation to complete
|
|
753
|
+
yield page.waitForTimeout(100);
|
|
754
|
+
const result = yield testStateDriver.testState();
|
|
755
|
+
(0, fixtures_1.expect)(result).toBeTruthy();
|
|
756
|
+
(0, fixtures_1.expect)(result.data).toEqual({ name: "John Doe", age: "30" });
|
|
757
|
+
}));
|
|
758
|
+
(0, fixtures_1.test)("validate method displays validation errors on form", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page, createFormItemDriver, }) {
|
|
759
|
+
yield initTestBed(`
|
|
760
|
+
<Form id="testForm">
|
|
761
|
+
<FormItem label="Name" bindTo="name" required="true" testId="nameField" />
|
|
762
|
+
<Button onClick="testForm.validate()" label="Validate" testId="validateBtn" />
|
|
763
|
+
</Form>
|
|
764
|
+
`);
|
|
765
|
+
// Click validate without filling required field
|
|
766
|
+
yield page.getByTestId("validateBtn").click();
|
|
767
|
+
// Validation error should be displayed
|
|
768
|
+
const nameField = page.getByTestId("nameField");
|
|
769
|
+
yield (0, fixtures_1.expect)(nameField).toContainText("This field is required");
|
|
770
|
+
}));
|
|
771
|
+
(0, fixtures_1.test)("validate method does not trigger form submission", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page, createFormItemDriver, createTextBoxDriver, }) {
|
|
772
|
+
const { testStateDriver } = yield initTestBed(`
|
|
773
|
+
<Form id="testForm" onSubmit="testState = 'submitted'">
|
|
774
|
+
<FormItem label="Name" bindTo="name" testId="nameField" />
|
|
775
|
+
<Button onClick="testForm.validate()" label="Validate" testId="validateBtn" />
|
|
776
|
+
</Form>
|
|
777
|
+
`);
|
|
778
|
+
// Fill form
|
|
779
|
+
const nameDriver = yield createFormItemDriver("nameField");
|
|
780
|
+
const nameInput = yield createTextBoxDriver(nameDriver.input);
|
|
781
|
+
yield nameInput.field.fill("John");
|
|
782
|
+
// Click validate button
|
|
783
|
+
yield page.getByTestId("validateBtn").click();
|
|
784
|
+
// Wait a bit
|
|
785
|
+
yield page.waitForTimeout(200);
|
|
786
|
+
// testState should remain null (not 'submitted')
|
|
787
|
+
yield fixtures_1.expect.poll(testStateDriver.testState).toBeNull();
|
|
788
|
+
}));
|
|
789
|
+
(0, fixtures_1.test)("validate method returns complete validation results object", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page, createFormItemDriver, createTextBoxDriver, }) {
|
|
790
|
+
const { testStateDriver } = yield initTestBed(`
|
|
791
|
+
<Form id="testForm">
|
|
792
|
+
<FormItem label="Name" bindTo="name" required="true" testId="nameField" />
|
|
793
|
+
<FormItem label="Email" bindTo="email" testId="emailField" />
|
|
794
|
+
<Button onClick="testState = testForm.validate()" label="Validate" testId="validateBtn" />
|
|
795
|
+
</Form>
|
|
796
|
+
`);
|
|
797
|
+
// Fill only email (name is required)
|
|
798
|
+
const emailDriver = yield createFormItemDriver("emailField");
|
|
799
|
+
const emailInput = yield createTextBoxDriver(emailDriver.input);
|
|
800
|
+
yield emailInput.field.fill("test@example.com");
|
|
801
|
+
// Click validate button
|
|
802
|
+
yield page.getByTestId("validateBtn").click();
|
|
803
|
+
// Wait for validation to complete
|
|
804
|
+
yield page.waitForTimeout(100);
|
|
805
|
+
const result = yield testStateDriver.testState();
|
|
806
|
+
(0, fixtures_1.expect)(result).toBeTruthy();
|
|
807
|
+
(0, fixtures_1.expect)(result.isValid).toBeDefined();
|
|
808
|
+
(0, fixtures_1.expect)(result.data).toBeDefined();
|
|
809
|
+
(0, fixtures_1.expect)(result.errors).toBeDefined();
|
|
810
|
+
(0, fixtures_1.expect)(result.warnings).toBeDefined();
|
|
811
|
+
(0, fixtures_1.expect)(result.validationResults).toBeDefined();
|
|
812
|
+
}));
|
|
369
813
|
});
|
|
370
814
|
// =============================================================================
|
|
371
815
|
// CONTEXT VARIABLE TESTS
|
|
@@ -68,14 +68,24 @@ const formReducer = (0, immer_1.default)((state, action) => {
|
|
|
68
68
|
}
|
|
69
69
|
switch (action.type) {
|
|
70
70
|
case formActions_1.FormActionKind.FIELD_INITIALIZED: {
|
|
71
|
-
if (
|
|
71
|
+
// Only set the value if initialValue is defined and field is not dirty (or force is true)
|
|
72
|
+
if (action.payload.value !== undefined && (!state.interactionFlags[uid].isDirty || action.payload.force)) {
|
|
72
73
|
(0, lodash_es_1.set)(state.subject, uid, action.payload.value);
|
|
73
74
|
}
|
|
75
|
+
// Track noSubmit flag - if multiple FormItems reference the same bindTo,
|
|
76
|
+
// and any of them has noSubmit: true, the field should NOT be submitted.
|
|
77
|
+
if (state.noSubmitFields[uid] === true || action.payload.noSubmit === true) {
|
|
78
|
+
state.noSubmitFields[uid] = true;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
state.noSubmitFields[uid] = false;
|
|
82
|
+
}
|
|
74
83
|
break;
|
|
75
84
|
}
|
|
76
85
|
case formActions_1.FormActionKind.FIELD_REMOVED: {
|
|
77
86
|
delete state.validationResults[uid];
|
|
78
87
|
delete state.interactionFlags[uid];
|
|
88
|
+
delete state.noSubmitFields[uid];
|
|
79
89
|
break;
|
|
80
90
|
}
|
|
81
91
|
case formActions_1.FormActionKind.FIELD_VALUE_CHANGED: {
|
|
@@ -180,6 +190,7 @@ const initialState = {
|
|
|
180
190
|
validationResults: {},
|
|
181
191
|
generalValidationResults: [],
|
|
182
192
|
interactionFlags: {},
|
|
193
|
+
noSubmitFields: {},
|
|
183
194
|
submitInProgress: false,
|
|
184
195
|
resetVersion: 0,
|
|
185
196
|
};
|
|
@@ -192,18 +203,21 @@ exports.defaultProps = {
|
|
|
192
203
|
keepModalOpenOnSubmit: false,
|
|
193
204
|
swapCancelAndSave: false,
|
|
194
205
|
hideButtonRowUntilDirty: false,
|
|
206
|
+
hideButtonRow: false,
|
|
207
|
+
enableSubmit: true,
|
|
195
208
|
};
|
|
196
209
|
// --- Remove the properties from formState.subject where the property name ends with UNBOUND_FIELD_SUFFIX
|
|
197
|
-
|
|
210
|
+
// --- or where the field has noSubmit set to true
|
|
211
|
+
function cleanUpSubject(subject, noSubmitFields) {
|
|
198
212
|
return Object.entries(subject || {}).reduce((acc, [key, value]) => {
|
|
199
|
-
if (!key.endsWith(formActions_1.UNBOUND_FIELD_SUFFIX)) {
|
|
213
|
+
if (!key.endsWith(formActions_1.UNBOUND_FIELD_SUFFIX) && !noSubmitFields[key]) {
|
|
200
214
|
acc[key] = value;
|
|
201
215
|
}
|
|
202
216
|
return acc;
|
|
203
217
|
}, {});
|
|
204
218
|
}
|
|
205
219
|
const Form = (0, react_2.forwardRef)(function (_a, ref) {
|
|
206
|
-
var { formState, dispatch, initialValue = constants_1.EMPTY_OBJECT, children, style, className, enabled = true, cancelLabel = exports.defaultProps.cancelLabel, saveLabel = exports.defaultProps.saveLabel, saveInProgressLabel = exports.defaultProps.saveInProgressLabel, swapCancelAndSave, onWillSubmit, onSubmit, onCancel, onReset, onSuccess, buttonRow, id, registerComponentApi, itemLabelBreak = exports.defaultProps.itemLabelBreak, itemLabelWidth, itemLabelPosition = exports.defaultProps.itemLabelPosition, keepModalOpenOnSubmit = exports.defaultProps.keepModalOpenOnSubmit, hideButtonRowUntilDirty } = _a, rest = __rest(_a, ["formState", "dispatch", "initialValue", "children", "style", "className", "enabled", "cancelLabel", "saveLabel", "saveInProgressLabel", "swapCancelAndSave", "onWillSubmit", "onSubmit", "onCancel", "onReset", "onSuccess", "buttonRow", "id", "registerComponentApi", "itemLabelBreak", "itemLabelWidth", "itemLabelPosition", "keepModalOpenOnSubmit", "hideButtonRowUntilDirty"]);
|
|
220
|
+
var { formState, dispatch, initialValue = constants_1.EMPTY_OBJECT, children, style, className, enabled = true, cancelLabel = exports.defaultProps.cancelLabel, saveLabel = exports.defaultProps.saveLabel, saveInProgressLabel = exports.defaultProps.saveInProgressLabel, swapCancelAndSave, onWillSubmit, onSubmit, onCancel, onReset, onSuccess, buttonRow, id, registerComponentApi, itemLabelBreak = exports.defaultProps.itemLabelBreak, itemLabelWidth, itemLabelPosition = exports.defaultProps.itemLabelPosition, keepModalOpenOnSubmit = exports.defaultProps.keepModalOpenOnSubmit, hideButtonRowUntilDirty, hideButtonRow = exports.defaultProps.hideButtonRow, enableSubmit = exports.defaultProps.enableSubmit } = _a, rest = __rest(_a, ["formState", "dispatch", "initialValue", "children", "style", "className", "enabled", "cancelLabel", "saveLabel", "saveInProgressLabel", "swapCancelAndSave", "onWillSubmit", "onSubmit", "onCancel", "onReset", "onSuccess", "buttonRow", "id", "registerComponentApi", "itemLabelBreak", "itemLabelWidth", "itemLabelPosition", "keepModalOpenOnSubmit", "hideButtonRowUntilDirty", "hideButtonRow", "enableSubmit"]);
|
|
207
221
|
const formRef = (0, react_2.useRef)(null);
|
|
208
222
|
const [confirmSubmitModalVisible, setConfirmSubmitModalVisible] = (0, react_2.useState)(false);
|
|
209
223
|
const requestModalFormClose = (0, ModalVisibilityContext_1.useModalFormClose)();
|
|
@@ -243,6 +257,22 @@ const Form = (0, react_2.forwardRef)(function (_a, ref) {
|
|
|
243
257
|
onCancel === null || onCancel === void 0 ? void 0 : onCancel();
|
|
244
258
|
void requestModalFormClose();
|
|
245
259
|
});
|
|
260
|
+
const doValidate = (0, misc_1.useEvent)(() => __awaiter(this, void 0, void 0, function* () {
|
|
261
|
+
// Trigger validation display on all fields
|
|
262
|
+
dispatch((0, formActions_1.triedToSubmit)());
|
|
263
|
+
// Get validation results grouped by severity
|
|
264
|
+
const { error, warning } = (0, Validations_1.groupInvalidValidationResultsBySeverity)(Object.values(formState.validationResults));
|
|
265
|
+
// Prepare cleaned data
|
|
266
|
+
const cleanedData = cleanUpSubject(formState.subject, formState.noSubmitFields);
|
|
267
|
+
// Return validation result
|
|
268
|
+
return {
|
|
269
|
+
isValid: error.length === 0,
|
|
270
|
+
data: cleanedData,
|
|
271
|
+
errors: error,
|
|
272
|
+
warnings: warning,
|
|
273
|
+
validationResults: formState.validationResults,
|
|
274
|
+
};
|
|
275
|
+
}));
|
|
246
276
|
const doSubmit = (0, misc_1.useEvent)((event) => __awaiter(this, void 0, void 0, function* () {
|
|
247
277
|
var _a;
|
|
248
278
|
/* console.log(`🚀 Form submit started`);
|
|
@@ -258,19 +288,19 @@ const Form = (0, react_2.forwardRef)(function (_a, ref) {
|
|
|
258
288
|
return;
|
|
259
289
|
}
|
|
260
290
|
setConfirmSubmitModalVisible(false);
|
|
261
|
-
|
|
262
|
-
const
|
|
263
|
-
if (
|
|
291
|
+
// Use the extracted validation logic
|
|
292
|
+
const validationResult = yield doValidate();
|
|
293
|
+
if (!validationResult.isValid) {
|
|
264
294
|
return;
|
|
265
295
|
}
|
|
266
|
-
if (
|
|
296
|
+
if (validationResult.warnings.length > 0 && !confirmSubmitModalVisible) {
|
|
267
297
|
setConfirmSubmitModalVisible(true);
|
|
268
298
|
return;
|
|
269
299
|
}
|
|
270
300
|
const prevFocused = document.activeElement;
|
|
271
301
|
dispatch((0, formActions_1.formSubmitting)());
|
|
272
302
|
try {
|
|
273
|
-
const filteredSubject =
|
|
303
|
+
const filteredSubject = validationResult.data;
|
|
274
304
|
const canSubmit = yield (onWillSubmit === null || onWillSubmit === void 0 ? void 0 : onWillSubmit(filteredSubject));
|
|
275
305
|
if (canSubmit === false) {
|
|
276
306
|
// --- We do not reset the form but allow the next submit.
|
|
@@ -352,18 +382,19 @@ const Form = (0, react_2.forwardRef)(function (_a, ref) {
|
|
|
352
382
|
});
|
|
353
383
|
});
|
|
354
384
|
const cancelButton = cancelLabel === "" ? null : ((0, jsx_runtime_1.jsx)(ButtonNative_1.Button, { "data-part-id": PART_CANCEL_BUTTON, type: "button", themeColor: "secondary", variant: "ghost", onClick: doCancel, children: cancelLabel }, "cancel"));
|
|
355
|
-
const submitButton = (0, react_2.useMemo)(() => ((0, jsx_runtime_1.jsx)(ButtonNative_1.Button, { "data-part-id": PART_SUBMIT_BUTTON, type: "submit", disabled: !isEnabled, children: formState.submitInProgress ? saveInProgressLabel : saveLabel }, "submit")), [isEnabled, formState.submitInProgress, saveInProgressLabel, saveLabel]);
|
|
385
|
+
const submitButton = (0, react_2.useMemo)(() => ((0, jsx_runtime_1.jsx)(ButtonNative_1.Button, { "data-part-id": PART_SUBMIT_BUTTON, type: "submit", disabled: !isEnabled || !enableSubmit, children: formState.submitInProgress ? saveInProgressLabel : saveLabel }, "submit")), [isEnabled, enableSubmit, formState.submitInProgress, saveInProgressLabel, saveLabel]);
|
|
356
386
|
(0, react_2.useEffect)(() => {
|
|
357
387
|
registerComponentApi === null || registerComponentApi === void 0 ? void 0 : registerComponentApi({
|
|
358
388
|
reset: doReset,
|
|
359
389
|
update: updateData,
|
|
390
|
+
validate: doValidate,
|
|
360
391
|
});
|
|
361
|
-
}, [doReset, updateData, registerComponentApi]);
|
|
392
|
+
}, [doReset, updateData, doValidate, registerComponentApi]);
|
|
362
393
|
let safeButtonRow = ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: buttonRow || ((0, jsx_runtime_1.jsxs)("div", { className: Form_module_scss_1.default.buttonRow, children: [swapCancelAndSave && [submitButton, cancelButton], !swapCancelAndSave && [cancelButton, submitButton]] })) }));
|
|
363
394
|
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, react_1.createElement)("form", Object.assign({}, rest, { style: style, className: (0, classnames_1.default)(Form_module_scss_1.default.wrapper, className), onSubmit: doSubmit, onReset: doReset, id: id, key: formState.resetVersion, ref: formRef }),
|
|
364
395
|
(0, jsx_runtime_1.jsx)(ValidationSummary_1.ValidationSummary, { generalValidationResults: formState.generalValidationResults }),
|
|
365
396
|
(0, jsx_runtime_1.jsx)(FormContext_1.FormContext.Provider, { value: formContextValue, children: children }),
|
|
366
|
-
(!hideButtonRowUntilDirty || isDirty) && safeButtonRow), confirmSubmitModalVisible && ((0, jsx_runtime_1.jsx)(ModalDialogNative_1.ModalDialog, { onClose: () => setConfirmSubmitModalVisible(false), isInitiallyOpen: true, title: "Are you sure want to move forward?", children: (0, jsx_runtime_1.jsxs)(StackNative_1.Stack, { orientation: "vertical", style: { gap: "0.5rem" }, children: [(0, jsx_runtime_1.jsx)(TextNative_1.Text, { children: "The following warnings were found during validation. Please make sure you are willing to move forward despite these issues." }), (0, jsx_runtime_1.jsx)(ValidationSummary_1.ValidationSummary, { generalValidationResults: formState.generalValidationResults, fieldValidationResults: formState.validationResults }), (0, jsx_runtime_1.jsxs)(StackNative_1.Stack, { orientation: "horizontal", horizontalAlignment: "end", style: { gap: "1em" }, children: [(0, jsx_runtime_1.jsx)(ButtonNative_1.Button, { variant: "ghost", themeColor: "secondary", onClick: () => setConfirmSubmitModalVisible(false), children: "No" }), (0, jsx_runtime_1.jsx)(ButtonNative_1.Button, { onClick: () => doSubmit(), autoFocus: true, children: "Yes, proceed" })] })] }) }))] }));
|
|
397
|
+
!hideButtonRow && (!hideButtonRowUntilDirty || isDirty) && safeButtonRow), confirmSubmitModalVisible && ((0, jsx_runtime_1.jsx)(ModalDialogNative_1.ModalDialog, { onClose: () => setConfirmSubmitModalVisible(false), isInitiallyOpen: true, title: "Are you sure want to move forward?", children: (0, jsx_runtime_1.jsxs)(StackNative_1.Stack, { orientation: "vertical", style: { gap: "0.5rem" }, children: [(0, jsx_runtime_1.jsx)(TextNative_1.Text, { children: "The following warnings were found during validation. Please make sure you are willing to move forward despite these issues." }), (0, jsx_runtime_1.jsx)(ValidationSummary_1.ValidationSummary, { generalValidationResults: formState.generalValidationResults, fieldValidationResults: formState.validationResults }), (0, jsx_runtime_1.jsxs)(StackNative_1.Stack, { orientation: "horizontal", horizontalAlignment: "end", style: { gap: "1em" }, children: [(0, jsx_runtime_1.jsx)(ButtonNative_1.Button, { variant: "ghost", themeColor: "secondary", onClick: () => setConfirmSubmitModalVisible(false), children: "No" }), (0, jsx_runtime_1.jsx)(ButtonNative_1.Button, { onClick: () => doSubmit(), autoFocus: true, children: "Yes, proceed" })] })] }) }))] }));
|
|
367
398
|
});
|
|
368
399
|
Form.displayName = "Form";
|
|
369
400
|
exports.FormWithContextVar = (0, react_2.forwardRef)(function ({ node, renderChild, extractValue, style, className, lookupEventHandler, registerComponentApi, }, ref) {
|
|
@@ -383,8 +414,8 @@ exports.FormWithContextVar = (0, react_2.forwardRef)(function ({ node, renderChi
|
|
|
383
414
|
});
|
|
384
415
|
});
|
|
385
416
|
};
|
|
386
|
-
return Object.assign(Object.assign({}, cleanUpSubject(formState.subject)), { update: updateData });
|
|
387
|
-
}, [formState.subject]);
|
|
417
|
+
return Object.assign(Object.assign({}, cleanUpSubject(formState.subject, formState.noSubmitFields)), { update: updateData });
|
|
418
|
+
}, [formState.subject, formState.noSubmitFields]);
|
|
388
419
|
const nodeWithItem = (0, react_2.useMemo)(() => {
|
|
389
420
|
return {
|
|
390
421
|
type: "Fragment",
|
|
@@ -403,7 +434,7 @@ exports.FormWithContextVar = (0, react_2.forwardRef)(function ({ node, renderChi
|
|
|
403
434
|
extractValue.asOptionalString(node.props._data_url);
|
|
404
435
|
const itemLabelWidth = extractValue.asOptionalString(node.props.itemLabelWidth);
|
|
405
436
|
const { cssProps: itemLabelWidthCssProps } = (0, layout_resolver_1.resolveLayoutProps)({ width: itemLabelWidth });
|
|
406
|
-
return ((0, jsx_runtime_1.jsx)(react_slot_1.Slot, { ref: ref, style: style, children: (0, jsx_runtime_1.jsx)(Form, { keepModalOpenOnSubmit: extractValue.asOptionalBoolean(node.props.keepModalOpenOnSubmit), itemLabelPosition: extractValue.asOptionalString(node.props.itemLabelPosition), itemLabelBreak: extractValue.asOptionalBoolean(node.props.itemLabelBreak), itemLabelWidth: itemLabelWidthCssProps.width, hideButtonRowUntilDirty: extractValue.asOptionalBoolean(node.props.hideButtonRowUntilDirty), formState: formState, dispatch: dispatch, id: node.uid, className: className, cancelLabel: extractValue(node.props.cancelLabel), saveLabel: extractValue(node.props.saveLabel), saveInProgressLabel: extractValue(node.props.saveInProgressLabel), swapCancelAndSave: extractValue.asOptionalBoolean(node.props.swapCancelAndSave, false), onWillSubmit: lookupEventHandler("willSubmit", {
|
|
437
|
+
return ((0, jsx_runtime_1.jsx)(react_slot_1.Slot, { ref: ref, style: style, children: (0, jsx_runtime_1.jsx)(Form, { keepModalOpenOnSubmit: extractValue.asOptionalBoolean(node.props.keepModalOpenOnSubmit), itemLabelPosition: extractValue.asOptionalString(node.props.itemLabelPosition), itemLabelBreak: extractValue.asOptionalBoolean(node.props.itemLabelBreak), itemLabelWidth: itemLabelWidthCssProps.width, hideButtonRowUntilDirty: extractValue.asOptionalBoolean(node.props.hideButtonRowUntilDirty), hideButtonRow: extractValue.asOptionalBoolean(node.props.hideButtonRow), enableSubmit: extractValue.asOptionalBoolean(node.props.enableSubmit), formState: formState, dispatch: dispatch, id: node.uid, className: className, cancelLabel: extractValue(node.props.cancelLabel), saveLabel: extractValue(node.props.saveLabel), saveInProgressLabel: extractValue(node.props.saveInProgressLabel), swapCancelAndSave: extractValue.asOptionalBoolean(node.props.swapCancelAndSave, false), onWillSubmit: lookupEventHandler("willSubmit", {
|
|
407
438
|
context: {
|
|
408
439
|
$data,
|
|
409
440
|
},
|
|
@@ -27,13 +27,14 @@ var FormActionKind;
|
|
|
27
27
|
FormActionKind["SUBMITTED"] = "FormActionKind:SUBMITTED";
|
|
28
28
|
FormActionKind["RESET"] = "FormActionKind:RESET";
|
|
29
29
|
})(FormActionKind || (exports.FormActionKind = FormActionKind = {}));
|
|
30
|
-
function fieldInitialized(uid, value, force = false) {
|
|
30
|
+
function fieldInitialized(uid, value, force = false, noSubmit = false) {
|
|
31
31
|
return {
|
|
32
32
|
type: FormActionKind.FIELD_INITIALIZED,
|
|
33
33
|
payload: {
|
|
34
34
|
uid,
|
|
35
35
|
value,
|
|
36
|
-
force
|
|
36
|
+
force,
|
|
37
|
+
noSubmit
|
|
37
38
|
},
|
|
38
39
|
};
|
|
39
40
|
}
|