datasync-dynamic-form 1.3.3 → 1.3.5
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/DsDynamicForm.js +71 -23
- package/dist/flex-grid.css +51 -0
- package/dist/types/DsDynamicForm.d.ts +14 -1
- package/package.json +5 -3
package/dist/DsDynamicForm.js
CHANGED
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
11
2
|
import React, { Component, useImperativeHandle, forwardRef } from "react";
|
|
12
3
|
import Multiselect from 'multiselect-react-dropdown';
|
|
@@ -15,11 +6,15 @@ import { DsBlob } from "datasync-blob";
|
|
|
15
6
|
import { DsPdf } from "datasync-pdf";
|
|
16
7
|
// reactstrap components
|
|
17
8
|
import { Button, Label, FormGroup, Input, InputGroupText, InputGroup, Row as ReactstrapRow, Col as ReactstrapCol, } from "reactstrap";
|
|
9
|
+
import "./flex-grid.css";
|
|
10
|
+
const FlexRow = ({ className, ...props }) => (_jsx(ReactstrapRow, { className: ["flex-row", className].filter(Boolean).join(" "), ...props }));
|
|
11
|
+
const FlexCol = ({ className, ...props }) => (_jsx(ReactstrapCol, { className: ["flex-col", className].filter(Boolean).join(" "), ...props }));
|
|
18
12
|
const debugging = false;
|
|
19
13
|
const globals = {
|
|
20
14
|
parameters: {
|
|
21
15
|
debugging: debugging,
|
|
22
16
|
local: true,
|
|
17
|
+
production: false,
|
|
23
18
|
use_navigate: false,
|
|
24
19
|
save_failed_alert: false,
|
|
25
20
|
form_version: "1.0",
|
|
@@ -187,8 +182,11 @@ export class DsDynamicForm extends Component {
|
|
|
187
182
|
this.onFormSavedLocalHandler, this.onFormUpdatedLocalHandler, this.onFormFailedLocalHandler, null);
|
|
188
183
|
};
|
|
189
184
|
/** Form Handlers */
|
|
190
|
-
this.onClickSubmitFormHandler = (event) =>
|
|
185
|
+
this.onClickSubmitFormHandler = async (event) => {
|
|
191
186
|
try {
|
|
187
|
+
//Trigger handler as user click submit button in order to animate checking + saving progress bar.
|
|
188
|
+
if (this.props.onBeforeFormSubmit)
|
|
189
|
+
this.props.onBeforeFormSubmit(this.local_data_blob);
|
|
192
190
|
if (event)
|
|
193
191
|
event.preventDefault();
|
|
194
192
|
//Force all fields check
|
|
@@ -247,7 +245,50 @@ export class DsDynamicForm extends Component {
|
|
|
247
245
|
console.error(`onClickSubmitFormHandler raises "${error}"`);
|
|
248
246
|
return false;
|
|
249
247
|
}
|
|
250
|
-
}
|
|
248
|
+
};
|
|
249
|
+
this.checkCurrentPage = async (event) => {
|
|
250
|
+
try {
|
|
251
|
+
/*Trigger typically called from external to check curetn page fields.
|
|
252
|
+
returns true when all fields are correct. User is then allowed to pursue to next page*/
|
|
253
|
+
if (event)
|
|
254
|
+
event.preventDefault();
|
|
255
|
+
//Force all fields check
|
|
256
|
+
let canSubmit = true;
|
|
257
|
+
let firstErrFieldName = null;
|
|
258
|
+
let iPage = this.props.active_page || 0; //Process only current page
|
|
259
|
+
let iRow = 0;
|
|
260
|
+
while (iRow < this.state.form.Pages[iPage].Rows.length) {
|
|
261
|
+
let iCol = 0;
|
|
262
|
+
while (iCol < this.state.form.Pages[iPage].Rows[iRow].Cols.length) {
|
|
263
|
+
let ii = 0;
|
|
264
|
+
while (ii < this.state.form.Pages[iPage].Rows[iRow].Cols[iCol].Fields.length) {
|
|
265
|
+
const field = this.state.form.Pages[iPage].Rows[iRow].Cols[iCol].Fields[ii];
|
|
266
|
+
const isValid = this.checkValidation(field);
|
|
267
|
+
if (!isValid && firstErrFieldName === null) {
|
|
268
|
+
firstErrFieldName = field.name;
|
|
269
|
+
}
|
|
270
|
+
canSubmit = canSubmit && isValid;
|
|
271
|
+
ii++;
|
|
272
|
+
}
|
|
273
|
+
iCol++;
|
|
274
|
+
}
|
|
275
|
+
iRow++;
|
|
276
|
+
}
|
|
277
|
+
if (!canSubmit) {
|
|
278
|
+
let err_message = `La page ${iPage} de formulaire comporte des erreurs !`;
|
|
279
|
+
if (this.props.onFormFailed)
|
|
280
|
+
this.props.onFormFailed(err_message);
|
|
281
|
+
else
|
|
282
|
+
console.error(`checkCurrentPage ${iPage} raises "${err_message}"`);
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
return canSubmit;
|
|
286
|
+
}
|
|
287
|
+
catch (error) {
|
|
288
|
+
console.error(`checkCurrentPage raises "${error}"`);
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
};
|
|
251
292
|
this.onFormSavedLocalHandler = (blob) => {
|
|
252
293
|
if (this.props.onFormSaved)
|
|
253
294
|
this.props.onFormSaved(blob);
|
|
@@ -385,22 +426,22 @@ export class DsDynamicForm extends Component {
|
|
|
385
426
|
};
|
|
386
427
|
this._rowRendering = (row) => {
|
|
387
428
|
try {
|
|
388
|
-
return (_jsx(
|
|
429
|
+
return (_jsx(FlexRow, { children: row.Cols.map((col, ii) => {
|
|
389
430
|
return (this._colRendering(col));
|
|
390
431
|
}) }));
|
|
391
432
|
}
|
|
392
433
|
catch (err) {
|
|
393
|
-
return (_jsxs(
|
|
434
|
+
return (_jsxs(FlexCol, { children: ["Error ", err.message] }));
|
|
394
435
|
}
|
|
395
436
|
};
|
|
396
437
|
this._colRendering = (col) => {
|
|
397
438
|
try {
|
|
398
|
-
return (_jsx(
|
|
439
|
+
return (_jsx(FlexCol, { id: `${col.Id ? col.Id : ''}`, children: col.Fields.map((field, ii) => {
|
|
399
440
|
return this._fieldRendering(field, ii);
|
|
400
441
|
}) }));
|
|
401
442
|
}
|
|
402
443
|
catch (err) {
|
|
403
|
-
return (_jsxs(
|
|
444
|
+
return (_jsxs(FlexCol, { children: ["Error ", err.message] }));
|
|
404
445
|
}
|
|
405
446
|
};
|
|
406
447
|
this._fieldRendering = (field, ii) => {
|
|
@@ -474,7 +515,7 @@ export class DsDynamicForm extends Component {
|
|
|
474
515
|
if (buttonIsHidden)
|
|
475
516
|
return (_jsx(_Fragment, {}));
|
|
476
517
|
else {
|
|
477
|
-
return (_jsx(
|
|
518
|
+
return (_jsx(FlexCol, { children: _jsx(Button, { id: "dsdf_clear_button", block: true, className: "btn-round", color: "danger", outline: true, type: "reset", onClick: () => { this.clearForm(); }, children: buttonCaption }) }));
|
|
478
519
|
}
|
|
479
520
|
};
|
|
480
521
|
this._submitButton = () => {
|
|
@@ -483,7 +524,7 @@ export class DsDynamicForm extends Component {
|
|
|
483
524
|
if (buttonIsHidden)
|
|
484
525
|
return (_jsx(_Fragment, {}));
|
|
485
526
|
else {
|
|
486
|
-
return (_jsx(
|
|
527
|
+
return (_jsx(FlexCol, { children: _jsx(Button, { id: "dsdf_submit_button", block: true, className: "btn-round", color: "danger", outline: true, type: "submit", onClick: () => { this.onClickSubmitFormHandler(); }, children: buttonCaption }) }));
|
|
487
528
|
}
|
|
488
529
|
};
|
|
489
530
|
this.render = () => {
|
|
@@ -498,12 +539,12 @@ export class DsDynamicForm extends Component {
|
|
|
498
539
|
return (_jsx("div", { id: `dsdf_page_${pageIndex}`, className: `form-page ${((pageIndex == this.state.active_page) || this.props.read_only) ? "page_visible" : ""}`, children: page.Rows.map((row, rowIndex) => {
|
|
499
540
|
return (_jsx("div", { children: this._rowRendering(row) }, rowIndex));
|
|
500
541
|
}) }, pageIndex));
|
|
501
|
-
}) }), _jsxs(
|
|
502
|
-
_jsx(
|
|
542
|
+
}) }), _jsxs(FlexRow, { id: "dsdf_buttons_container", className: "buttons-row", children: [this._cancelButton(), this._submitButton(), this.props.custom_button_caption &&
|
|
543
|
+
_jsx(FlexCol, { children: _jsx(Button, { id: "dsdf_custom_button", block: true, className: "btn-round", color: "primary", type: "submit", onClick: (e) => { if (this.props.custom_button_handler)
|
|
503
544
|
this.props.custom_button_handler(this.state.form);
|
|
504
545
|
else
|
|
505
546
|
console.error("custom_button_handler unset !"); }, children: this.props.custom_button_caption }) }), this.props.custom_button_caption2 &&
|
|
506
|
-
_jsx(
|
|
547
|
+
_jsx(FlexCol, { children: _jsx(Button, { id: "dsdf_custom_button2", block: true, className: "btn-round", color: "primary", type: "submit", onClick: (e) => { if (this.props.custom_button_handler2)
|
|
507
548
|
this.props.custom_button_handler2(this.state.form);
|
|
508
549
|
else
|
|
509
550
|
console.error("custom_button_handler2 unset !"); }, children: this.props.custom_button_caption2 }) })] })] }));
|
|
@@ -522,6 +563,9 @@ export class DsDynamicForm extends Component {
|
|
|
522
563
|
this.clearForm();
|
|
523
564
|
}
|
|
524
565
|
if (this.props.active_page != prevProps.active_page) {
|
|
566
|
+
//Page is about to change, then triger onPageChanging Handler
|
|
567
|
+
if (this.props.onPageChanging)
|
|
568
|
+
this.props.onPageChanging({ "active_page": prevProps.active_page ?? 0, "next_page": this.props.active_page ?? 0, "last_page": this.state.form.Pages.length - 1 });
|
|
525
569
|
if (globals.parameters.debugging)
|
|
526
570
|
console.log("active_page has changed !");
|
|
527
571
|
try {
|
|
@@ -548,14 +592,18 @@ export const DsDynamicFormForwardRef = forwardRef((props, ref) => {
|
|
|
548
592
|
const innerRef = React.useRef(null);
|
|
549
593
|
useImperativeHandle(ref, () => ({
|
|
550
594
|
clearForm: () => {
|
|
551
|
-
|
|
552
|
-
(_a = innerRef.current) === null || _a === void 0 ? void 0 : _a.clearForm();
|
|
595
|
+
innerRef.current?.clearForm();
|
|
553
596
|
},
|
|
554
597
|
onClickSubmitFormHandler: (event) => {
|
|
555
598
|
return innerRef.current
|
|
556
599
|
? innerRef.current.onClickSubmitFormHandler(event)
|
|
557
600
|
: Promise.resolve(false);
|
|
558
601
|
},
|
|
602
|
+
checkCurrentPage: (event) => {
|
|
603
|
+
return innerRef.current
|
|
604
|
+
? innerRef.current.checkCurrentPage(event)
|
|
605
|
+
: Promise.resolve(false);
|
|
606
|
+
},
|
|
559
607
|
}));
|
|
560
|
-
return (_jsx(DsDynamicForm,
|
|
608
|
+
return (_jsx(DsDynamicForm, { ...props, ref: innerRef }));
|
|
561
609
|
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
.flex-row {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-wrap: wrap;
|
|
4
|
+
gap: 10px;
|
|
5
|
+
margin-bottom: 10px;
|
|
6
|
+
/* Make all .flex-col in a flex-row equal height */
|
|
7
|
+
align-items: stretch;
|
|
8
|
+
/* For multi-line rows, ensure lines use full vertical space */
|
|
9
|
+
align-content: stretch;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.flex-col {
|
|
13
|
+
flex: 1 1 0;
|
|
14
|
+
/* Fill available vertical space of its flex line */
|
|
15
|
+
height: 100%;
|
|
16
|
+
min-height: 100px;
|
|
17
|
+
border: 3px solid;
|
|
18
|
+
border-radius: 8px;
|
|
19
|
+
display: flex;
|
|
20
|
+
align-items: center;
|
|
21
|
+
justify-content: center;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.box-next {
|
|
25
|
+
flex: 1 1 0;
|
|
26
|
+
display: flex;
|
|
27
|
+
flex-wrap: wrap;
|
|
28
|
+
align-content: center;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* Media query pour 600px : diviser par 2 le nombre de div par ligne */
|
|
32
|
+
@media (max-width: 600px) {
|
|
33
|
+
.box {
|
|
34
|
+
flex: 1 1 calc(50% - 5px);
|
|
35
|
+
max-width: calc(50% - 5px);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* Si une div est seule sur sa ligne, elle prend 100% */
|
|
39
|
+
.box:only-child {
|
|
40
|
+
flex: 1 1 100%;
|
|
41
|
+
max-width: 100%;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* Media query pour 300px : toutes les divs à 100% de la largeur */
|
|
46
|
+
@media (max-width: 300px) {
|
|
47
|
+
.box {
|
|
48
|
+
flex: 1 1 100%;
|
|
49
|
+
max-width: 100%;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { Component, ChangeEvent } from "react";
|
|
2
|
+
import "./flex-grid.css";
|
|
2
3
|
interface Field {
|
|
3
4
|
name: string;
|
|
4
5
|
input_type: string;
|
|
@@ -79,10 +80,16 @@ interface DsDynamicFormProps {
|
|
|
79
80
|
read_only?: boolean;
|
|
80
81
|
foreign_keys?: DataTier;
|
|
81
82
|
onFormChange?: (data: DataTier) => void;
|
|
83
|
+
onBeforeFormSubmit?: (data: DataBlob) => void;
|
|
82
84
|
onFormSubmit?: (data: DataBlob) => void;
|
|
83
85
|
onFormSaved?: (blob: DataBlob) => void;
|
|
84
86
|
onFormUpdated?: (blob: DataBlob) => void;
|
|
85
87
|
onFormFailed?: (error: string) => void;
|
|
88
|
+
onPageChanging?: (pageInfo: {
|
|
89
|
+
active_page: number;
|
|
90
|
+
next_page: number;
|
|
91
|
+
last_page: number;
|
|
92
|
+
}) => void;
|
|
86
93
|
clearOnSave?: boolean;
|
|
87
94
|
clearOnUpdate?: boolean;
|
|
88
95
|
onTerminated?: () => void;
|
|
@@ -97,6 +104,10 @@ interface DsDynamicFormProps {
|
|
|
97
104
|
custom_button_handler2?: (form: Form) => void;
|
|
98
105
|
show_hidden?: boolean;
|
|
99
106
|
active_page?: number;
|
|
107
|
+
col_xs?: number | string;
|
|
108
|
+
col_sm?: number | string;
|
|
109
|
+
col_md?: number | string;
|
|
110
|
+
col_lg?: number | string;
|
|
100
111
|
}
|
|
101
112
|
interface DsDynamicFormState {
|
|
102
113
|
form: Form;
|
|
@@ -140,6 +151,7 @@ export declare class DsDynamicForm extends Component<DsDynamicFormProps, DsDynam
|
|
|
140
151
|
saveFormToDatasyncProcess: () => void;
|
|
141
152
|
/** Form Handlers */
|
|
142
153
|
onClickSubmitFormHandler: (event?: React.MouseEvent<HTMLButtonElement>) => Promise<boolean>;
|
|
154
|
+
checkCurrentPage: (event?: React.MouseEvent<HTMLButtonElement>) => Promise<boolean>;
|
|
143
155
|
onFormSavedLocalHandler: (blob: DataBlob) => void;
|
|
144
156
|
onFormUpdatedLocalHandler: (blob: DataBlob) => void;
|
|
145
157
|
onFormFailedLocalHandler: (err: string) => void;
|
|
@@ -163,6 +175,7 @@ export declare class DsDynamicForm extends Component<DsDynamicFormProps, DsDynam
|
|
|
163
175
|
export type DsDynamicFormRef = {
|
|
164
176
|
clearForm: () => void;
|
|
165
177
|
onClickSubmitFormHandler: (event?: React.MouseEvent<HTMLButtonElement>) => Promise<boolean>;
|
|
178
|
+
checkCurrentPage: (event?: React.MouseEvent<HTMLButtonElement>) => Promise<boolean>;
|
|
166
179
|
};
|
|
167
|
-
export declare const DsDynamicFormForwardRef:
|
|
180
|
+
export declare const DsDynamicFormForwardRef: React.ForwardRefExoticComponent<DsDynamicFormProps & React.RefAttributes<DsDynamicFormRef>>;
|
|
168
181
|
export {};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "datasync-dynamic-form",
|
|
3
3
|
"description": "Datasync Dynamic Form component",
|
|
4
|
-
"version": "1.3.
|
|
4
|
+
"version": "1.3.5",
|
|
5
5
|
"main": "dist/DsDynamicForm.js",
|
|
6
6
|
"module": "dist/DsDynamicForm.js",
|
|
7
7
|
"types": "dist/types/DsDynamicForm.d.ts",
|
|
@@ -21,14 +21,16 @@
|
|
|
21
21
|
"multiselect-react-dropdown": "^2.0.25",
|
|
22
22
|
"react": ">=18.2.0",
|
|
23
23
|
"reactstrap": ">=8.4.1",
|
|
24
|
-
"typescript": "^5.9.2"
|
|
24
|
+
"typescript": "^5.9.2",
|
|
25
|
+
"@types/react": "^18.2.75",
|
|
26
|
+
"@types/react-dom": "^18.2.25"
|
|
25
27
|
},
|
|
26
28
|
"peerDependencies": {
|
|
27
29
|
"multiselect-react-dropdown": "^2.0.25",
|
|
28
30
|
"react": "^17 || ^18"
|
|
29
31
|
},
|
|
30
32
|
"scripts": {
|
|
31
|
-
"hybrid": "tsc"
|
|
33
|
+
"hybrid": "tsc && cp src/flex-grid.css dist/flex-grid.css"
|
|
32
34
|
},
|
|
33
35
|
"keywords": [],
|
|
34
36
|
"author": "",
|