@bpmn-io/form-js-viewer 0.10.0-alpha.0 → 0.10.0-alpha.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/assets/form-js.css +156 -7
- package/dist/index.cjs +619 -94
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +618 -95
- package/dist/index.es.js.map +1 -1
- package/dist/types/Form.d.ts +4 -0
- package/dist/types/core/ConditionChecker.d.ts +57 -0
- package/dist/types/core/index.d.ts +2 -0
- package/dist/types/import/Importer.d.ts +2 -2
- package/dist/types/render/components/Sanitizer.d.ts +1 -0
- package/dist/types/render/components/Util.d.ts +10 -0
- package/dist/types/render/components/form-fields/Image.d.ts +8 -0
- package/dist/types/render/components/form-fields/Number.d.ts +6 -5
- package/dist/types/render/components/index.d.ts +4 -3
- package/dist/types/render/components/util/numberFieldUtil.d.ts +4 -0
- package/dist/types/render/hooks/useCondition.d.ts +9 -0
- package/dist/types/render/hooks/useEvaluation.d.ts +6 -0
- package/dist/types/render/hooks/useExpressionValue.d.ts +5 -0
- package/dist/types/{types.d.ts → src/types.d.ts} +0 -0
- package/dist/types/util/feel.d.ts +14 -0
- package/package.json +5 -3
package/dist/index.es.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import Ids from 'ids';
|
|
2
|
-
import { isArray, isFunction, isNumber, bind, assign, isNil, get, isUndefined, isObject, set
|
|
2
|
+
import { isString, isArray, isFunction, isNumber, bind, assign, isNil, get, isUndefined, isObject, set } from 'min-dash';
|
|
3
|
+
import { unaryTest, evaluate, parseUnaryTests, parseExpressions } from 'feelin';
|
|
4
|
+
import Big from 'big.js';
|
|
3
5
|
import snarkdown from '@bpmn-io/snarkdown';
|
|
4
6
|
import classNames from 'classnames';
|
|
5
7
|
import { jsx, jsxs } from 'preact/jsx-runtime';
|
|
@@ -9,6 +11,126 @@ import React, { createPortal } from 'preact/compat';
|
|
|
9
11
|
import Markup from 'preact-markup';
|
|
10
12
|
import { Injector } from 'didi';
|
|
11
13
|
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {object} Condition
|
|
16
|
+
* @property {string} [hide]
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
class ConditionChecker {
|
|
20
|
+
constructor(formFieldRegistry, eventBus) {
|
|
21
|
+
this._formFieldRegistry = formFieldRegistry;
|
|
22
|
+
this._eventBus = eventBus;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* For given data, remove properties based on condition.
|
|
27
|
+
*
|
|
28
|
+
* @param {Object<string, any>} properties
|
|
29
|
+
* @param {Object<string, any>} data
|
|
30
|
+
*/
|
|
31
|
+
applyConditions(properties, data = {}) {
|
|
32
|
+
const conditions = this._getConditions();
|
|
33
|
+
const newProperties = {
|
|
34
|
+
...properties
|
|
35
|
+
};
|
|
36
|
+
for (const {
|
|
37
|
+
key,
|
|
38
|
+
condition
|
|
39
|
+
} of conditions) {
|
|
40
|
+
const shouldRemove = this._checkHideCondition(condition, data);
|
|
41
|
+
if (shouldRemove) {
|
|
42
|
+
delete newProperties[key];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return newProperties;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Check if given condition is met. Returns null for invalid/missing conditions.
|
|
50
|
+
*
|
|
51
|
+
* @param {string} condition
|
|
52
|
+
* @param {import('../types').Data} [data]
|
|
53
|
+
*
|
|
54
|
+
* @returns {boolean|null}
|
|
55
|
+
*/
|
|
56
|
+
check(condition, data = {}) {
|
|
57
|
+
if (!condition) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
if (!isString(condition) || !condition.startsWith('=')) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
// cut off initial '='
|
|
65
|
+
const result = unaryTest(condition.slice(1), data);
|
|
66
|
+
return result;
|
|
67
|
+
} catch (error) {
|
|
68
|
+
this._eventBus.fire('error', {
|
|
69
|
+
error
|
|
70
|
+
});
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Check if hide condition is met.
|
|
77
|
+
*
|
|
78
|
+
* @param {Condition} condition
|
|
79
|
+
* @param {Object<string, any>} data
|
|
80
|
+
* @returns {boolean}
|
|
81
|
+
*/
|
|
82
|
+
_checkHideCondition(condition, data) {
|
|
83
|
+
if (!condition.hide) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
const result = this.check(condition.hide, data);
|
|
87
|
+
return result === true;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Evaluate an expression.
|
|
92
|
+
*
|
|
93
|
+
* @param {string} expression
|
|
94
|
+
* @param {import('../types').Data} [data]
|
|
95
|
+
*
|
|
96
|
+
* @returns {any}
|
|
97
|
+
*/
|
|
98
|
+
evaluate(expression, data = {}) {
|
|
99
|
+
if (!expression) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
if (!isString(expression) || !expression.startsWith('=')) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
const result = evaluate(expression.slice(1), data);
|
|
107
|
+
return result;
|
|
108
|
+
} catch (error) {
|
|
109
|
+
this._eventBus.fire('error', {
|
|
110
|
+
error
|
|
111
|
+
});
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
_getConditions() {
|
|
116
|
+
const formFields = this._formFieldRegistry.getAll();
|
|
117
|
+
return formFields.reduce((conditions, formField) => {
|
|
118
|
+
const {
|
|
119
|
+
key,
|
|
120
|
+
conditional: condition
|
|
121
|
+
} = formField;
|
|
122
|
+
if (key && condition) {
|
|
123
|
+
return [...conditions, {
|
|
124
|
+
key,
|
|
125
|
+
condition
|
|
126
|
+
}];
|
|
127
|
+
}
|
|
128
|
+
return conditions;
|
|
129
|
+
}, []);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
ConditionChecker.$inject = ['formFieldRegistry', 'eventBus'];
|
|
133
|
+
|
|
12
134
|
var FN_REF = '__fn';
|
|
13
135
|
var DEFAULT_PRIORITY = 1000;
|
|
14
136
|
var slice = Array.prototype.slice;
|
|
@@ -442,14 +564,63 @@ function invokeFunction(fn, args) {
|
|
|
442
564
|
return fn.apply(null, args);
|
|
443
565
|
}
|
|
444
566
|
|
|
567
|
+
function countDecimals(number) {
|
|
568
|
+
const num = Big(number);
|
|
569
|
+
if (num.toString() === num.toFixed(0)) return 0;
|
|
570
|
+
return num.toFixed().split('.')[1].length || 0;
|
|
571
|
+
}
|
|
572
|
+
function isValidNumber(value) {
|
|
573
|
+
return (typeof value === 'number' || typeof value === 'string') && value !== '' && !isNaN(Number(value));
|
|
574
|
+
}
|
|
575
|
+
function willKeyProduceValidNumber(key, previousValue, carretIndex, selectionWidth, decimalDigits) {
|
|
576
|
+
// Dot and comma are both treated as dot
|
|
577
|
+
previousValue = previousValue.replace(',', '.');
|
|
578
|
+
const isFirstDot = !previousValue.includes('.') && (key === '.' || key === ',');
|
|
579
|
+
const isFirstMinus = !previousValue.includes('-') && key === '-' && carretIndex === 0;
|
|
580
|
+
const keypressIsNumeric = /^[0-9]$/i.test(key);
|
|
581
|
+
const dotIndex = previousValue?.indexOf('.') ?? -1;
|
|
582
|
+
|
|
583
|
+
// If the carret is positioned after a dot, and the current decimal digits count is equal or greater to the maximum, disallow the key press
|
|
584
|
+
const overflowsDecimalSpace = typeof decimalDigits === 'number' && selectionWidth === 0 && dotIndex !== -1 && previousValue.includes('.') && previousValue.split('.')[1].length >= decimalDigits && carretIndex > dotIndex;
|
|
585
|
+
const keypressIsAllowedChar = keypressIsNumeric || decimalDigits !== 0 && isFirstDot || isFirstMinus;
|
|
586
|
+
return keypressIsAllowedChar && !overflowsDecimalSpace;
|
|
587
|
+
}
|
|
588
|
+
function isNullEquivalentValue(value) {
|
|
589
|
+
return value === undefined || value === null || value === '';
|
|
590
|
+
}
|
|
591
|
+
|
|
445
592
|
const EMAIL_PATTERN = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
|
|
446
593
|
const PHONE_PATTERN = /(\+|00)(297|93|244|1264|358|355|376|971|54|374|1684|1268|61|43|994|257|32|229|226|880|359|973|1242|387|590|375|501|1441|591|55|1246|673|975|267|236|1|61|41|56|86|225|237|243|242|682|57|269|238|506|53|5999|61|1345|357|420|49|253|1767|45|1809|1829|1849|213|593|20|291|212|34|372|251|358|679|500|33|298|691|241|44|995|44|233|350|224|590|220|245|240|30|1473|299|502|594|1671|592|852|504|385|509|36|62|44|91|246|353|98|964|354|972|39|1876|44|962|81|76|77|254|996|855|686|1869|82|383|965|856|961|231|218|1758|423|94|266|370|352|371|853|590|212|377|373|261|960|52|692|389|223|356|95|382|976|1670|258|222|1664|596|230|265|60|262|264|687|227|672|234|505|683|31|47|977|674|64|968|92|507|64|51|63|680|675|48|1787|1939|850|351|595|970|689|974|262|40|7|250|966|249|221|65|500|4779|677|232|503|378|252|508|381|211|239|597|421|386|46|268|1721|248|963|1649|235|228|66|992|690|993|670|676|1868|216|90|688|886|255|256|380|598|1|998|3906698|379|1784|58|1284|1340|84|678|681|685|967|27|260|263)(9[976]\d|8[987530]\d|6[987]\d|5[90]\d|42\d|3[875]\d|2[98654321]\d|9[8543210]|8[6421]|6[6543210]|5[87654321]|4[987654310]|3[9643210]|2[70]|7|1)\d{4,20}$/;
|
|
447
594
|
class Validator {
|
|
448
595
|
validateField(field, value) {
|
|
449
596
|
const {
|
|
597
|
+
type,
|
|
450
598
|
validate
|
|
451
599
|
} = field;
|
|
452
600
|
let errors = [];
|
|
601
|
+
if (type === 'number') {
|
|
602
|
+
const {
|
|
603
|
+
decimalDigits,
|
|
604
|
+
step
|
|
605
|
+
} = field;
|
|
606
|
+
if (value === 'NaN') {
|
|
607
|
+
errors = [...errors, 'Value is not a number.'];
|
|
608
|
+
} else if (value) {
|
|
609
|
+
if (decimalDigits >= 0 && countDecimals(value) > decimalDigits) {
|
|
610
|
+
errors = [...errors, 'Value is expected to ' + (decimalDigits === 0 ? 'be an integer' : `have at most ${decimalDigits} decimal digit${decimalDigits > 1 ? 's' : ''}`) + '.'];
|
|
611
|
+
}
|
|
612
|
+
if (step) {
|
|
613
|
+
const bigValue = Big(value);
|
|
614
|
+
const bigStep = Big(step);
|
|
615
|
+
const offset = bigValue.mod(bigStep);
|
|
616
|
+
if (offset.cmp(0) !== 0) {
|
|
617
|
+
const previousValue = bigValue.minus(offset);
|
|
618
|
+
const nextValue = previousValue.plus(bigStep);
|
|
619
|
+
errors = [...errors, `Please select a valid value, the two nearest valid values are ${previousValue} and ${nextValue}.`];
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
453
624
|
if (!validate) {
|
|
454
625
|
return errors;
|
|
455
626
|
}
|
|
@@ -531,6 +702,44 @@ class FormFieldRegistry {
|
|
|
531
702
|
}
|
|
532
703
|
FormFieldRegistry.$inject = ['eventBus'];
|
|
533
704
|
|
|
705
|
+
/**
|
|
706
|
+
* Retrieve variable names from given FEEL unary test.
|
|
707
|
+
*
|
|
708
|
+
* @param {string} unaryTest
|
|
709
|
+
* @returns {string[]}
|
|
710
|
+
*/
|
|
711
|
+
function getVariableNames(unaryTest) {
|
|
712
|
+
const tree = parseUnaryTests(unaryTest);
|
|
713
|
+
const cursor = tree.cursor();
|
|
714
|
+
const variables = new Set();
|
|
715
|
+
do {
|
|
716
|
+
const node = cursor.node;
|
|
717
|
+
if (node.type.name === 'VariableName') {
|
|
718
|
+
variables.add(unaryTest.slice(node.from, node.to));
|
|
719
|
+
}
|
|
720
|
+
} while (cursor.next());
|
|
721
|
+
return Array.from(variables);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* Retrieve variable names from given FEEL expression.
|
|
726
|
+
*
|
|
727
|
+
* @param {string} expression
|
|
728
|
+
* @returns {string[]}
|
|
729
|
+
*/
|
|
730
|
+
function getExpressionVariableNames(expression) {
|
|
731
|
+
const tree = parseExpressions(expression);
|
|
732
|
+
const cursor = tree.cursor();
|
|
733
|
+
const variables = new Set();
|
|
734
|
+
do {
|
|
735
|
+
const node = cursor.node;
|
|
736
|
+
if (node.type.name === 'VariableName') {
|
|
737
|
+
variables.add(expression.slice(node.from, node.to));
|
|
738
|
+
}
|
|
739
|
+
} while (cursor.next());
|
|
740
|
+
return Array.from(variables);
|
|
741
|
+
}
|
|
742
|
+
|
|
534
743
|
function createInjector(bootstrapModules) {
|
|
535
744
|
const injector = new Injector(bootstrapModules);
|
|
536
745
|
injector.init();
|
|
@@ -548,6 +757,7 @@ function createFormContainer(prefix = 'fjs') {
|
|
|
548
757
|
return container;
|
|
549
758
|
}
|
|
550
759
|
|
|
760
|
+
const EXPRESSION_PROPERTIES = ['alt', 'source'];
|
|
551
761
|
function findErrors(errors, path) {
|
|
552
762
|
return errors[pathStringify(path)];
|
|
553
763
|
}
|
|
@@ -601,16 +811,16 @@ function clone(data, replacer) {
|
|
|
601
811
|
*
|
|
602
812
|
* @return {string[]}
|
|
603
813
|
*/
|
|
604
|
-
|
|
605
814
|
function getSchemaVariables(schema) {
|
|
606
815
|
if (!schema.components) {
|
|
607
816
|
return [];
|
|
608
817
|
}
|
|
609
|
-
|
|
818
|
+
const variables = schema.components.reduce((variables, component) => {
|
|
610
819
|
const {
|
|
611
820
|
key,
|
|
612
821
|
valuesKey,
|
|
613
|
-
type
|
|
822
|
+
type,
|
|
823
|
+
conditional
|
|
614
824
|
} = component;
|
|
615
825
|
if (['text', 'button'].includes(type)) {
|
|
616
826
|
return variables;
|
|
@@ -618,11 +828,33 @@ function getSchemaVariables(schema) {
|
|
|
618
828
|
if (key) {
|
|
619
829
|
variables = [...variables, key];
|
|
620
830
|
}
|
|
621
|
-
if (valuesKey
|
|
831
|
+
if (valuesKey) {
|
|
622
832
|
variables = [...variables, valuesKey];
|
|
623
833
|
}
|
|
834
|
+
if (conditional && conditional.hide) {
|
|
835
|
+
// cut off initial '='
|
|
836
|
+
const conditionVariables = getVariableNames(conditional.hide.slice(1));
|
|
837
|
+
variables = [...variables, ...conditionVariables];
|
|
838
|
+
}
|
|
839
|
+
EXPRESSION_PROPERTIES.forEach(prop => {
|
|
840
|
+
const property = component[prop];
|
|
841
|
+
if (property && isExpression$1(property)) {
|
|
842
|
+
// cut off initial '='
|
|
843
|
+
const expressionVariables = getExpressionVariableNames(property.slice(1));
|
|
844
|
+
variables = [...variables, ...expressionVariables];
|
|
845
|
+
}
|
|
846
|
+
});
|
|
624
847
|
return variables;
|
|
625
848
|
}, []);
|
|
849
|
+
|
|
850
|
+
// remove duplicates
|
|
851
|
+
return Array.from(new Set(variables));
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
// helper ///////////////
|
|
855
|
+
|
|
856
|
+
function isExpression$1(value) {
|
|
857
|
+
return isString(value) && value.startsWith('=');
|
|
626
858
|
}
|
|
627
859
|
|
|
628
860
|
class Importer {
|
|
@@ -651,11 +883,11 @@ class Importer {
|
|
|
651
883
|
const warnings = [];
|
|
652
884
|
try {
|
|
653
885
|
const importedSchema = this.importFormField(clone(schema)),
|
|
654
|
-
|
|
886
|
+
initializedData = this.initializeFieldValues(clone(data));
|
|
655
887
|
return {
|
|
656
888
|
warnings,
|
|
657
889
|
schema: importedSchema,
|
|
658
|
-
data:
|
|
890
|
+
data: initializedData
|
|
659
891
|
};
|
|
660
892
|
} catch (err) {
|
|
661
893
|
err.warnings = warnings;
|
|
@@ -721,26 +953,16 @@ class Importer {
|
|
|
721
953
|
/**
|
|
722
954
|
* @param {Object} data
|
|
723
955
|
*
|
|
724
|
-
* @return {Object}
|
|
956
|
+
* @return {Object} initializedData
|
|
725
957
|
*/
|
|
726
|
-
|
|
727
|
-
return this._formFieldRegistry.getAll().reduce((
|
|
958
|
+
initializeFieldValues(data) {
|
|
959
|
+
return this._formFieldRegistry.getAll().reduce((initializedData, formField) => {
|
|
728
960
|
const {
|
|
729
961
|
defaultValue,
|
|
730
962
|
_path,
|
|
731
|
-
type
|
|
732
|
-
valuesKey
|
|
963
|
+
type
|
|
733
964
|
} = formField;
|
|
734
965
|
|
|
735
|
-
// get values defined via valuesKey
|
|
736
|
-
|
|
737
|
-
if (valuesKey) {
|
|
738
|
-
importedData = {
|
|
739
|
-
...importedData,
|
|
740
|
-
[valuesKey]: get(data, [valuesKey])
|
|
741
|
-
};
|
|
742
|
-
}
|
|
743
|
-
|
|
744
966
|
// try to get value from data
|
|
745
967
|
// if unavailable - try to get default value from form field
|
|
746
968
|
// if unavailable - get empty value from form field
|
|
@@ -755,14 +977,14 @@ class Importer {
|
|
|
755
977
|
value: valueData
|
|
756
978
|
});
|
|
757
979
|
}
|
|
758
|
-
const
|
|
759
|
-
|
|
760
|
-
...
|
|
761
|
-
[_path[0]]:
|
|
980
|
+
const initializedFieldValue = !isUndefined(valueData) ? valueData : !isUndefined(defaultValue) ? defaultValue : fieldImplementation.emptyValue;
|
|
981
|
+
initializedData = {
|
|
982
|
+
...initializedData,
|
|
983
|
+
[_path[0]]: initializedFieldValue
|
|
762
984
|
};
|
|
763
985
|
}
|
|
764
|
-
return
|
|
765
|
-
},
|
|
986
|
+
return initializedData;
|
|
987
|
+
}, data);
|
|
766
988
|
}
|
|
767
989
|
}
|
|
768
990
|
Importer.$inject = ['formFieldRegistry', 'formFields'];
|
|
@@ -776,6 +998,7 @@ const NODE_TYPE_TEXT = 3,
|
|
|
776
998
|
const ALLOWED_NODES = ['h1', 'h2', 'h3', 'h4', 'h5', 'span', 'em', 'a', 'p', 'div', 'ul', 'ol', 'li', 'hr', 'blockquote', 'img', 'pre', 'code', 'br', 'strong'];
|
|
777
999
|
const ALLOWED_ATTRIBUTES = ['align', 'alt', 'class', 'href', 'id', 'name', 'rel', 'target', 'src'];
|
|
778
1000
|
const ALLOWED_URI_PATTERN = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i; // eslint-disable-line no-useless-escape
|
|
1001
|
+
const ALLOWED_IMAGE_SRC_PATTERN = /^(https?|data):.*/i; // eslint-disable-line no-useless-escape
|
|
779
1002
|
const ATTR_WHITESPACE_PATTERN = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g; // eslint-disable-line no-control-regex
|
|
780
1003
|
|
|
781
1004
|
const FORM_ELEMENT = document.createElement('form');
|
|
@@ -799,6 +1022,10 @@ function sanitizeHTML(html) {
|
|
|
799
1022
|
return '';
|
|
800
1023
|
}
|
|
801
1024
|
}
|
|
1025
|
+
function sanitizeImageSource(src) {
|
|
1026
|
+
const valid = ALLOWED_IMAGE_SRC_PATTERN.test(src);
|
|
1027
|
+
return valid ? src : '';
|
|
1028
|
+
}
|
|
802
1029
|
|
|
803
1030
|
/**
|
|
804
1031
|
* Recursively sanitize a HTML node, potentially
|
|
@@ -909,6 +1136,19 @@ function safeMarkdown(markdown) {
|
|
|
909
1136
|
const html = markdownToHTML(markdown);
|
|
910
1137
|
return sanitizeHTML(html);
|
|
911
1138
|
}
|
|
1139
|
+
|
|
1140
|
+
/**
|
|
1141
|
+
* Sanitizes an image source to ensure we only allow for data URI and links
|
|
1142
|
+
* that start with http(s).
|
|
1143
|
+
*
|
|
1144
|
+
* Note: Most browsers anyway do not support script execution in <img> elements.
|
|
1145
|
+
*
|
|
1146
|
+
* @param {string} src
|
|
1147
|
+
* @returns {string}
|
|
1148
|
+
*/
|
|
1149
|
+
function safeImageSource(src) {
|
|
1150
|
+
return sanitizeImageSource(src);
|
|
1151
|
+
}
|
|
912
1152
|
function sanitizeSingleSelectValue(options) {
|
|
913
1153
|
const {
|
|
914
1154
|
formField,
|
|
@@ -948,7 +1188,7 @@ function sanitizeMultiSelectValue(options) {
|
|
|
948
1188
|
}
|
|
949
1189
|
}
|
|
950
1190
|
|
|
951
|
-
const type$
|
|
1191
|
+
const type$a = 'button';
|
|
952
1192
|
function Button(props) {
|
|
953
1193
|
const {
|
|
954
1194
|
disabled,
|
|
@@ -958,7 +1198,7 @@ function Button(props) {
|
|
|
958
1198
|
action = 'submit'
|
|
959
1199
|
} = field;
|
|
960
1200
|
return jsx("div", {
|
|
961
|
-
class: formFieldClasses(type$
|
|
1201
|
+
class: formFieldClasses(type$a),
|
|
962
1202
|
children: jsx("button", {
|
|
963
1203
|
class: "fjs-button",
|
|
964
1204
|
type: action,
|
|
@@ -973,7 +1213,7 @@ Button.create = function (options = {}) {
|
|
|
973
1213
|
...options
|
|
974
1214
|
};
|
|
975
1215
|
};
|
|
976
|
-
Button.type = type$
|
|
1216
|
+
Button.type = type$a;
|
|
977
1217
|
Button.label = 'Button';
|
|
978
1218
|
Button.keyed = true;
|
|
979
1219
|
|
|
@@ -1049,7 +1289,7 @@ function Label(props) {
|
|
|
1049
1289
|
});
|
|
1050
1290
|
}
|
|
1051
1291
|
|
|
1052
|
-
const type$
|
|
1292
|
+
const type$9 = 'checkbox';
|
|
1053
1293
|
function Checkbox(props) {
|
|
1054
1294
|
const {
|
|
1055
1295
|
disabled,
|
|
@@ -1074,7 +1314,7 @@ function Checkbox(props) {
|
|
|
1074
1314
|
formId
|
|
1075
1315
|
} = useContext(FormContext);
|
|
1076
1316
|
return jsxs("div", {
|
|
1077
|
-
class: classNames(formFieldClasses(type$
|
|
1317
|
+
class: classNames(formFieldClasses(type$9, {
|
|
1078
1318
|
errors,
|
|
1079
1319
|
disabled
|
|
1080
1320
|
}), {
|
|
@@ -1104,7 +1344,7 @@ Checkbox.create = function (options = {}) {
|
|
|
1104
1344
|
...options
|
|
1105
1345
|
};
|
|
1106
1346
|
};
|
|
1107
|
-
Checkbox.type = type$
|
|
1347
|
+
Checkbox.type = type$9;
|
|
1108
1348
|
Checkbox.label = 'Checkbox';
|
|
1109
1349
|
Checkbox.keyed = true;
|
|
1110
1350
|
Checkbox.emptyValue = false;
|
|
@@ -1179,7 +1419,7 @@ const buildLoadedState = values => ({
|
|
|
1179
1419
|
state: LOAD_STATES.LOADED
|
|
1180
1420
|
});
|
|
1181
1421
|
|
|
1182
|
-
const type$
|
|
1422
|
+
const type$8 = 'checklist';
|
|
1183
1423
|
function Checklist(props) {
|
|
1184
1424
|
const {
|
|
1185
1425
|
disabled,
|
|
@@ -1212,7 +1452,7 @@ function Checklist(props) {
|
|
|
1212
1452
|
formId
|
|
1213
1453
|
} = useContext(FormContext);
|
|
1214
1454
|
return jsxs("div", {
|
|
1215
|
-
class: classNames(formFieldClasses(type$
|
|
1455
|
+
class: classNames(formFieldClasses(type$8, {
|
|
1216
1456
|
errors,
|
|
1217
1457
|
disabled
|
|
1218
1458
|
})),
|
|
@@ -1252,12 +1492,28 @@ Checklist.create = function (options = {}) {
|
|
|
1252
1492
|
...options
|
|
1253
1493
|
};
|
|
1254
1494
|
};
|
|
1255
|
-
Checklist.type = type$
|
|
1495
|
+
Checklist.type = type$8;
|
|
1256
1496
|
Checklist.label = 'Checklist';
|
|
1257
1497
|
Checklist.keyed = true;
|
|
1258
1498
|
Checklist.emptyValue = [];
|
|
1259
1499
|
Checklist.sanitizeValue = sanitizeMultiSelectValue;
|
|
1260
1500
|
|
|
1501
|
+
/**
|
|
1502
|
+
* Check if condition is met with given variables.
|
|
1503
|
+
*
|
|
1504
|
+
* @param {string | undefined} condition
|
|
1505
|
+
* @param {import('../../types').Data} data
|
|
1506
|
+
*
|
|
1507
|
+
* @returns {boolean} true if condition is met or no condition or condition checker exists
|
|
1508
|
+
*/
|
|
1509
|
+
function useCondition(condition, data) {
|
|
1510
|
+
const conditionChecker = useService('conditionChecker', false);
|
|
1511
|
+
if (!conditionChecker) {
|
|
1512
|
+
return null;
|
|
1513
|
+
}
|
|
1514
|
+
return conditionChecker.check(condition, data);
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1261
1517
|
const noop$1 = () => false;
|
|
1262
1518
|
function FormField(props) {
|
|
1263
1519
|
const {
|
|
@@ -1275,7 +1531,8 @@ function FormField(props) {
|
|
|
1275
1531
|
properties
|
|
1276
1532
|
} = form._getState();
|
|
1277
1533
|
const {
|
|
1278
|
-
Element
|
|
1534
|
+
Element,
|
|
1535
|
+
Empty
|
|
1279
1536
|
} = useContext(FormRenderContext);
|
|
1280
1537
|
const FormFieldComponent = formFields.get(field.type);
|
|
1281
1538
|
if (!FormFieldComponent) {
|
|
@@ -1284,6 +1541,10 @@ function FormField(props) {
|
|
|
1284
1541
|
const value = get(data, _path);
|
|
1285
1542
|
const fieldErrors = findErrors(errors, _path);
|
|
1286
1543
|
const disabled = properties.readOnly || field.disabled || false;
|
|
1544
|
+
const hidden = useHideCondition(field, data);
|
|
1545
|
+
if (hidden) {
|
|
1546
|
+
return jsx(Empty, {});
|
|
1547
|
+
}
|
|
1287
1548
|
return jsx(Element, {
|
|
1288
1549
|
field: field,
|
|
1289
1550
|
children: jsx(FormFieldComponent, {
|
|
@@ -1295,6 +1556,10 @@ function FormField(props) {
|
|
|
1295
1556
|
})
|
|
1296
1557
|
});
|
|
1297
1558
|
}
|
|
1559
|
+
function useHideCondition(field, data) {
|
|
1560
|
+
const hideCondition = field.conditional && field.conditional.hide;
|
|
1561
|
+
return useCondition(hideCondition, data) === true;
|
|
1562
|
+
}
|
|
1298
1563
|
|
|
1299
1564
|
function Default(props) {
|
|
1300
1565
|
const {
|
|
@@ -1440,6 +1705,7 @@ function FormComponent(props) {
|
|
|
1440
1705
|
class: "fjs-form",
|
|
1441
1706
|
onSubmit: handleSubmit,
|
|
1442
1707
|
onReset: handleReset,
|
|
1708
|
+
noValidate: true,
|
|
1443
1709
|
children: [jsx(FormField, {
|
|
1444
1710
|
field: schema,
|
|
1445
1711
|
onChange: onChange
|
|
@@ -1447,32 +1713,226 @@ function FormComponent(props) {
|
|
|
1447
1713
|
});
|
|
1448
1714
|
}
|
|
1449
1715
|
|
|
1716
|
+
/**
|
|
1717
|
+
*
|
|
1718
|
+
* @param {string | undefined} expression
|
|
1719
|
+
* @param {import('../../types').Data} data
|
|
1720
|
+
*/
|
|
1721
|
+
function useEvaluation(expression, data) {
|
|
1722
|
+
const conditionChecker = useService('conditionChecker', false);
|
|
1723
|
+
if (!conditionChecker) {
|
|
1724
|
+
return null;
|
|
1725
|
+
}
|
|
1726
|
+
return conditionChecker.evaluate(expression, data);
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
/**
|
|
1730
|
+
*
|
|
1731
|
+
* @param {string} value
|
|
1732
|
+
*/
|
|
1733
|
+
function useExpressionValue(value) {
|
|
1734
|
+
const formData = useService('form')._getState().data;
|
|
1735
|
+
if (!isExpression(value)) {
|
|
1736
|
+
return value;
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
// We can ignore this hook rule as we do not use
|
|
1740
|
+
// state or effects in our custom hooks
|
|
1741
|
+
/* eslint-disable-next-line react-hooks/rules-of-hooks */
|
|
1742
|
+
return useEvaluation(value, formData);
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
// helper ///////////////
|
|
1746
|
+
|
|
1747
|
+
function isExpression(value) {
|
|
1748
|
+
return isString(value) && value.startsWith('=');
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
function _extends$1() { _extends$1 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$1.apply(this, arguments); }
|
|
1752
|
+
var ImagePlaceholder = (({
|
|
1753
|
+
styles = {},
|
|
1754
|
+
...props
|
|
1755
|
+
}) => /*#__PURE__*/React.createElement("svg", _extends$1({
|
|
1756
|
+
width: "64",
|
|
1757
|
+
height: "64",
|
|
1758
|
+
viewBox: "0 0 1280 1280",
|
|
1759
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1760
|
+
fillRule: "evenodd",
|
|
1761
|
+
clipRule: "evenodd",
|
|
1762
|
+
strokeLinejoin: "round",
|
|
1763
|
+
strokeMiterlimit: "2"
|
|
1764
|
+
}, props), /*#__PURE__*/React.createElement("path", {
|
|
1765
|
+
fill: "#e5e9ed",
|
|
1766
|
+
d: "M0 0h1280v1280H0z"
|
|
1767
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
1768
|
+
d: "M910 410H370v470h540V410zm-57.333 57.333v355.334H427.333V467.333h425.334z",
|
|
1769
|
+
fill: "#cad3db"
|
|
1770
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
1771
|
+
d: "M810 770H480v-60l100-170 130 170 100-65v125z",
|
|
1772
|
+
fill: "#cad3db"
|
|
1773
|
+
}), /*#__PURE__*/React.createElement("circle", {
|
|
1774
|
+
cx: "750",
|
|
1775
|
+
cy: "550",
|
|
1776
|
+
r: "50",
|
|
1777
|
+
fill: "#cad3db",
|
|
1778
|
+
transform: "translate(10 10)"
|
|
1779
|
+
})));
|
|
1780
|
+
|
|
1781
|
+
const type$7 = 'image';
|
|
1782
|
+
function Image(props) {
|
|
1783
|
+
const {
|
|
1784
|
+
field
|
|
1785
|
+
} = props;
|
|
1786
|
+
const {
|
|
1787
|
+
alt,
|
|
1788
|
+
id,
|
|
1789
|
+
source
|
|
1790
|
+
} = field;
|
|
1791
|
+
const safeSource = safeImageSource(useExpressionValue(source));
|
|
1792
|
+
const altText = useExpressionValue(alt);
|
|
1793
|
+
const {
|
|
1794
|
+
formId
|
|
1795
|
+
} = useContext(FormContext);
|
|
1796
|
+
return jsx("div", {
|
|
1797
|
+
class: formFieldClasses(type$7),
|
|
1798
|
+
children: jsxs("div", {
|
|
1799
|
+
class: "fjs-image-container",
|
|
1800
|
+
children: [safeSource && jsx("img", {
|
|
1801
|
+
alt: altText,
|
|
1802
|
+
src: safeSource,
|
|
1803
|
+
class: "fjs-image",
|
|
1804
|
+
id: prefixId(id, formId)
|
|
1805
|
+
}), !safeSource && jsx("div", {
|
|
1806
|
+
class: "fjs-image-placeholder",
|
|
1807
|
+
children: jsx(ImagePlaceholder, {
|
|
1808
|
+
alt: "This is an image placeholder"
|
|
1809
|
+
})
|
|
1810
|
+
})]
|
|
1811
|
+
})
|
|
1812
|
+
});
|
|
1813
|
+
}
|
|
1814
|
+
Image.create = function (options = {}) {
|
|
1815
|
+
return {
|
|
1816
|
+
...options
|
|
1817
|
+
};
|
|
1818
|
+
};
|
|
1819
|
+
Image.type = type$7;
|
|
1820
|
+
Image.keyed = false;
|
|
1821
|
+
|
|
1450
1822
|
const type$6 = 'number';
|
|
1451
|
-
function
|
|
1823
|
+
function Numberfield(props) {
|
|
1452
1824
|
const {
|
|
1453
1825
|
disabled,
|
|
1454
1826
|
errors = [],
|
|
1455
1827
|
field,
|
|
1456
|
-
value
|
|
1828
|
+
value,
|
|
1829
|
+
onChange
|
|
1457
1830
|
} = props;
|
|
1458
1831
|
const {
|
|
1459
1832
|
description,
|
|
1460
1833
|
id,
|
|
1461
1834
|
label,
|
|
1462
|
-
validate = {}
|
|
1835
|
+
validate = {},
|
|
1836
|
+
decimalDigits,
|
|
1837
|
+
serializeToString = false,
|
|
1838
|
+
increment: incrementValue
|
|
1463
1839
|
} = field;
|
|
1464
1840
|
const {
|
|
1465
1841
|
required
|
|
1466
1842
|
} = validate;
|
|
1467
|
-
const
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1843
|
+
const inputRef = useRef();
|
|
1844
|
+
const [stringValueCache, setStringValueCache] = useState('');
|
|
1845
|
+
|
|
1846
|
+
// checks whether the value currently in the form data is practically different from the one in the input field cache
|
|
1847
|
+
// this allows us to guarantee the field always displays valid form data, but without auto-simplifying values like 1.000 to 1
|
|
1848
|
+
const cacheValueMatchesState = useMemo(() => Numberfield.sanitizeValue({
|
|
1849
|
+
value,
|
|
1850
|
+
formField: field
|
|
1851
|
+
}) === Numberfield.sanitizeValue({
|
|
1852
|
+
value: stringValueCache,
|
|
1853
|
+
formField: field
|
|
1854
|
+
}), [stringValueCache, value, field]);
|
|
1855
|
+
const displayValue = useMemo(() => {
|
|
1856
|
+
if (value === 'NaN') return 'NaN';
|
|
1857
|
+
return cacheValueMatchesState ? stringValueCache : value || value === 0 ? Big(value).toFixed() : '';
|
|
1858
|
+
}, [stringValueCache, value, cacheValueMatchesState]);
|
|
1859
|
+
const arrowIncrementValue = useMemo(() => {
|
|
1860
|
+
if (incrementValue) return Big(incrementValue);
|
|
1861
|
+
if (decimalDigits) return Big(`1e-${decimalDigits}`);
|
|
1862
|
+
return Big('1');
|
|
1863
|
+
}, [decimalDigits, incrementValue]);
|
|
1864
|
+
const setValue = useCallback(stringValue => {
|
|
1865
|
+
if (isNullEquivalentValue(stringValue)) {
|
|
1866
|
+
setStringValueCache('');
|
|
1867
|
+
onChange({
|
|
1868
|
+
field,
|
|
1869
|
+
value: null
|
|
1870
|
+
});
|
|
1871
|
+
return;
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
// treat commas as dots
|
|
1875
|
+
stringValue = stringValue.replaceAll(',', '.');
|
|
1876
|
+
if (isNaN(Number(stringValue))) {
|
|
1877
|
+
setStringValueCache('NaN');
|
|
1878
|
+
onChange({
|
|
1879
|
+
field,
|
|
1880
|
+
value: 'NaN'
|
|
1881
|
+
});
|
|
1882
|
+
return;
|
|
1883
|
+
}
|
|
1884
|
+
setStringValueCache(stringValue);
|
|
1885
|
+
onChange({
|
|
1471
1886
|
field,
|
|
1472
|
-
value: Number
|
|
1473
|
-
value: target.value
|
|
1474
|
-
})
|
|
1887
|
+
value: serializeToString ? stringValue : Number(stringValue)
|
|
1475
1888
|
});
|
|
1889
|
+
}, [field, onChange, serializeToString]);
|
|
1890
|
+
const increment = () => {
|
|
1891
|
+
const base = isValidNumber(value) ? Big(value) : Big(0);
|
|
1892
|
+
const stepFlooredValue = base.minus(base.mod(arrowIncrementValue));
|
|
1893
|
+
|
|
1894
|
+
// note: toFixed() behaves differently in big.js
|
|
1895
|
+
setValue(stepFlooredValue.plus(arrowIncrementValue).toFixed());
|
|
1896
|
+
};
|
|
1897
|
+
const decrement = () => {
|
|
1898
|
+
const base = isValidNumber(value) ? Big(value) : Big(0);
|
|
1899
|
+
const offset = base.mod(arrowIncrementValue);
|
|
1900
|
+
if (offset.cmp(0) === 0) {
|
|
1901
|
+
// if we're already on a valid step, decrement
|
|
1902
|
+
setValue(base.minus(arrowIncrementValue).toFixed());
|
|
1903
|
+
} else {
|
|
1904
|
+
// otherwise floor to the step
|
|
1905
|
+
const stepFlooredValue = base.minus(base.mod(arrowIncrementValue));
|
|
1906
|
+
setValue(stepFlooredValue.toFixed());
|
|
1907
|
+
}
|
|
1908
|
+
};
|
|
1909
|
+
const onKeyDown = e => {
|
|
1910
|
+
// delete the NaN state all at once on backspace or delete
|
|
1911
|
+
if (value === 'NaN' && (e.code === 'Backspace' || e.code === 'Delete')) {
|
|
1912
|
+
setValue(null);
|
|
1913
|
+
e.preventDefault();
|
|
1914
|
+
return;
|
|
1915
|
+
}
|
|
1916
|
+
if (e.code === 'ArrowUp') {
|
|
1917
|
+
increment();
|
|
1918
|
+
e.preventDefault();
|
|
1919
|
+
return;
|
|
1920
|
+
}
|
|
1921
|
+
if (e.code === 'ArrowDown') {
|
|
1922
|
+
decrement();
|
|
1923
|
+
e.preventDefault();
|
|
1924
|
+
return;
|
|
1925
|
+
}
|
|
1926
|
+
};
|
|
1927
|
+
|
|
1928
|
+
// intercept key presses which would lead to an invalid number
|
|
1929
|
+
const onKeyPress = e => {
|
|
1930
|
+
const carretIndex = inputRef.current.selectionStart;
|
|
1931
|
+
const selectionWidth = inputRef.current.selectionStart - inputRef.current.selectionEnd;
|
|
1932
|
+
const previousValue = inputRef.current.value;
|
|
1933
|
+
if (!willKeyProduceValidNumber(e.key, previousValue, carretIndex, selectionWidth, decimalDigits)) {
|
|
1934
|
+
e.preventDefault();
|
|
1935
|
+
}
|
|
1476
1936
|
};
|
|
1477
1937
|
const {
|
|
1478
1938
|
formId
|
|
@@ -1486,13 +1946,45 @@ function Number(props) {
|
|
|
1486
1946
|
id: prefixId(id, formId),
|
|
1487
1947
|
label: label,
|
|
1488
1948
|
required: required
|
|
1489
|
-
}),
|
|
1490
|
-
class:
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1949
|
+
}), jsxs("div", {
|
|
1950
|
+
class: classNames('fjs-input-group', {
|
|
1951
|
+
'disabled': disabled
|
|
1952
|
+
}, {
|
|
1953
|
+
'hasErrors': errors.length
|
|
1954
|
+
}),
|
|
1955
|
+
children: [jsx("input", {
|
|
1956
|
+
ref: inputRef,
|
|
1957
|
+
class: "fjs-input",
|
|
1958
|
+
disabled: disabled,
|
|
1959
|
+
id: prefixId(id, formId),
|
|
1960
|
+
onKeyDown: onKeyDown,
|
|
1961
|
+
onKeyPress: onKeyPress
|
|
1962
|
+
|
|
1963
|
+
// @ts-ignore
|
|
1964
|
+
,
|
|
1965
|
+
onInput: e => setValue(e.target.value),
|
|
1966
|
+
type: "text",
|
|
1967
|
+
autoComplete: "off",
|
|
1968
|
+
step: arrowIncrementValue,
|
|
1969
|
+
value: displayValue
|
|
1970
|
+
}), jsxs("div", {
|
|
1971
|
+
class: classNames('fjs-number-arrow-container', {
|
|
1972
|
+
'disabled': disabled
|
|
1973
|
+
}),
|
|
1974
|
+
children: [jsx("button", {
|
|
1975
|
+
class: "fjs-number-arrow-up",
|
|
1976
|
+
onClick: () => increment(),
|
|
1977
|
+
tabIndex: -1,
|
|
1978
|
+
children: "\u02C4"
|
|
1979
|
+
}), jsx("div", {
|
|
1980
|
+
class: "fjs-number-arrow-separator"
|
|
1981
|
+
}), jsx("button", {
|
|
1982
|
+
class: "fjs-number-arrow-down",
|
|
1983
|
+
onClick: () => decrement(),
|
|
1984
|
+
tabIndex: -1,
|
|
1985
|
+
children: "\u02C5"
|
|
1986
|
+
})]
|
|
1987
|
+
})]
|
|
1496
1988
|
}), jsx(Description, {
|
|
1497
1989
|
description: description
|
|
1498
1990
|
}), jsx(Errors, {
|
|
@@ -1500,21 +1992,24 @@ function Number(props) {
|
|
|
1500
1992
|
})]
|
|
1501
1993
|
});
|
|
1502
1994
|
}
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
};
|
|
1508
|
-
Number.sanitizeValue = ({
|
|
1509
|
-
value
|
|
1995
|
+
Numberfield.create = (options = {}) => options;
|
|
1996
|
+
Numberfield.sanitizeValue = ({
|
|
1997
|
+
value,
|
|
1998
|
+
formField
|
|
1510
1999
|
}) => {
|
|
1511
|
-
|
|
1512
|
-
|
|
2000
|
+
// null state is allowed
|
|
2001
|
+
if (isNullEquivalentValue(value)) return null;
|
|
2002
|
+
|
|
2003
|
+
// if data cannot be parsed as a valid number, go into invalid NaN state
|
|
2004
|
+
if (!isValidNumber(value)) return 'NaN';
|
|
2005
|
+
|
|
2006
|
+
// otherwise parse to formatting type
|
|
2007
|
+
return formField.serializeToString ? value.toString() : Number(value);
|
|
1513
2008
|
};
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
2009
|
+
Numberfield.type = type$6;
|
|
2010
|
+
Numberfield.keyed = true;
|
|
2011
|
+
Numberfield.label = 'Number';
|
|
2012
|
+
Numberfield.emptyValue = null;
|
|
1518
2013
|
|
|
1519
2014
|
const type$5 = 'radio';
|
|
1520
2015
|
function Radio(props) {
|
|
@@ -1886,6 +2381,18 @@ function Taglist(props) {
|
|
|
1886
2381
|
break;
|
|
1887
2382
|
}
|
|
1888
2383
|
};
|
|
2384
|
+
const onTagRemoveClick = (event, value) => {
|
|
2385
|
+
const {
|
|
2386
|
+
target
|
|
2387
|
+
} = event;
|
|
2388
|
+
deselectValue(value);
|
|
2389
|
+
|
|
2390
|
+
// restore focus if there is no next sibling to focus
|
|
2391
|
+
const nextTag = target.closest('.fjs-taglist-tag').nextSibling;
|
|
2392
|
+
if (!nextTag) {
|
|
2393
|
+
searchbarRef.current.focus();
|
|
2394
|
+
}
|
|
2395
|
+
};
|
|
1889
2396
|
return jsxs("div", {
|
|
1890
2397
|
class: formFieldClasses(type$3, {
|
|
1891
2398
|
errors,
|
|
@@ -1898,19 +2405,24 @@ function Taglist(props) {
|
|
|
1898
2405
|
class: classNames('fjs-taglist', {
|
|
1899
2406
|
'disabled': disabled
|
|
1900
2407
|
}),
|
|
1901
|
-
children: [!disabled && loadState === LOAD_STATES.LOADED &&
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
children:
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
2408
|
+
children: [!disabled && loadState === LOAD_STATES.LOADED && jsx("div", {
|
|
2409
|
+
class: "fjs-taglist-tags",
|
|
2410
|
+
children: values.map(v => {
|
|
2411
|
+
return jsxs("div", {
|
|
2412
|
+
class: "fjs-taglist-tag",
|
|
2413
|
+
onMouseDown: e => e.preventDefault(),
|
|
2414
|
+
children: [jsx("span", {
|
|
2415
|
+
class: "fjs-taglist-tag-label",
|
|
2416
|
+
children: valueToOptionMap[v] ? valueToOptionMap[v].label : `unexpected value{${v}}`
|
|
2417
|
+
}), jsx("button", {
|
|
2418
|
+
type: "button",
|
|
2419
|
+
title: "Remove tag",
|
|
2420
|
+
class: "fjs-taglist-tag-remove",
|
|
2421
|
+
onClick: event => onTagRemoveClick(event, v),
|
|
2422
|
+
children: jsx(CloseIcon, {})
|
|
2423
|
+
})]
|
|
2424
|
+
});
|
|
2425
|
+
})
|
|
1914
2426
|
}), jsx("input", {
|
|
1915
2427
|
disabled: disabled,
|
|
1916
2428
|
class: "fjs-taglist-input",
|
|
@@ -2131,7 +2643,7 @@ Textarea.sanitizeValue = ({
|
|
|
2131
2643
|
value
|
|
2132
2644
|
}) => isArray(value) || isObject(value) ? '' : String(value);
|
|
2133
2645
|
|
|
2134
|
-
const formFields = [Button, Checkbox, Checklist, Default,
|
|
2646
|
+
const formFields = [Button, Checkbox, Checklist, Default, Image, Numberfield, Radio, Select, Taglist, Text, Textfield, Textarea];
|
|
2135
2647
|
|
|
2136
2648
|
class FormFields {
|
|
2137
2649
|
constructor() {
|
|
@@ -2211,6 +2723,7 @@ var renderModule = {
|
|
|
2211
2723
|
|
|
2212
2724
|
var core = {
|
|
2213
2725
|
__depends__: [importModule, renderModule],
|
|
2726
|
+
conditionChecker: ['type', ConditionChecker],
|
|
2214
2727
|
eventBus: ['type', EventBus],
|
|
2215
2728
|
formFieldRegistry: ['type', FormFieldRegistry],
|
|
2216
2729
|
validator: ['type', Validator]
|
|
@@ -2326,14 +2839,14 @@ class Form {
|
|
|
2326
2839
|
this.clear();
|
|
2327
2840
|
const {
|
|
2328
2841
|
schema: importedSchema,
|
|
2329
|
-
data:
|
|
2842
|
+
data: initializedData,
|
|
2330
2843
|
warnings
|
|
2331
2844
|
} = this.get('importer').importSchema(schema, data);
|
|
2332
2845
|
this._setState({
|
|
2333
|
-
data:
|
|
2846
|
+
data: initializedData,
|
|
2334
2847
|
errors: {},
|
|
2335
2848
|
schema: importedSchema,
|
|
2336
|
-
initialData: clone(
|
|
2849
|
+
initialData: clone(initializedData)
|
|
2337
2850
|
});
|
|
2338
2851
|
this._emit('import.done', {
|
|
2339
2852
|
warnings
|
|
@@ -2365,14 +2878,13 @@ class Form {
|
|
|
2365
2878
|
}
|
|
2366
2879
|
const data = this._getSubmitData();
|
|
2367
2880
|
const errors = this.validate();
|
|
2368
|
-
this.
|
|
2369
|
-
|
|
2370
|
-
errors
|
|
2371
|
-
});
|
|
2372
|
-
return {
|
|
2881
|
+
const filteredErrors = this._applyConditions(errors, data);
|
|
2882
|
+
const result = {
|
|
2373
2883
|
data,
|
|
2374
|
-
errors
|
|
2884
|
+
errors: filteredErrors
|
|
2375
2885
|
};
|
|
2886
|
+
this._emit('submit', result);
|
|
2887
|
+
return result;
|
|
2376
2888
|
}
|
|
2377
2889
|
reset() {
|
|
2378
2890
|
this._emit('reset');
|
|
@@ -2553,7 +3065,8 @@ class Form {
|
|
|
2553
3065
|
*/
|
|
2554
3066
|
_getSubmitData() {
|
|
2555
3067
|
const formFieldRegistry = this.get('formFieldRegistry');
|
|
2556
|
-
|
|
3068
|
+
const formData = this._getState().data;
|
|
3069
|
+
const submitData = formFieldRegistry.getAll().reduce((previous, field) => {
|
|
2557
3070
|
const {
|
|
2558
3071
|
disabled,
|
|
2559
3072
|
_path
|
|
@@ -2561,14 +3074,24 @@ class Form {
|
|
|
2561
3074
|
|
|
2562
3075
|
// do not submit disabled form fields
|
|
2563
3076
|
if (disabled || !_path) {
|
|
2564
|
-
return
|
|
3077
|
+
return previous;
|
|
2565
3078
|
}
|
|
2566
|
-
const value = get(
|
|
3079
|
+
const value = get(formData, _path);
|
|
2567
3080
|
return {
|
|
2568
|
-
...
|
|
3081
|
+
...previous,
|
|
2569
3082
|
[_path[0]]: value
|
|
2570
3083
|
};
|
|
2571
3084
|
}, {});
|
|
3085
|
+
const filteredSubmitData = this._applyConditions(submitData, formData);
|
|
3086
|
+
return filteredSubmitData;
|
|
3087
|
+
}
|
|
3088
|
+
|
|
3089
|
+
/**
|
|
3090
|
+
* @internal
|
|
3091
|
+
*/
|
|
3092
|
+
_applyConditions(toFilter, data) {
|
|
3093
|
+
const conditionChecker = this.get('conditionChecker');
|
|
3094
|
+
return conditionChecker.applyConditions(toFilter, data);
|
|
2572
3095
|
}
|
|
2573
3096
|
}
|
|
2574
3097
|
|
|
@@ -2597,5 +3120,5 @@ function createForm(options) {
|
|
|
2597
3120
|
});
|
|
2598
3121
|
}
|
|
2599
3122
|
|
|
2600
|
-
export { Button, Checkbox, Checklist, Default, Form, FormComponent, FormContext, FormFieldRegistry, FormFields, FormRenderContext,
|
|
3123
|
+
export { Button, Checkbox, Checklist, Default, Form, FormComponent, FormContext, FormFieldRegistry, FormFields, FormRenderContext, Image, Numberfield, Radio, Select, Taglist, Text, Textarea, Textfield, clone, createForm, createFormContainer, createInjector, findErrors, formFields, generateIdForType, generateIndexForType, getSchemaVariables, isRequired, pathParse, pathStringify, pathsEqual, schemaVersion };
|
|
2601
3124
|
//# sourceMappingURL=index.es.js.map
|