@bpmn-io/form-js-viewer 0.7.2 → 0.8.0
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/LICENSE +22 -22
- package/README.md +158 -158
- package/dist/assets/form-js.css +339 -238
- package/dist/index.cjs +688 -145
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +685 -147
- package/dist/index.es.js.map +1 -1
- package/dist/types/Form.d.ts +136 -136
- package/dist/types/core/EventBus.d.ts +1 -1
- package/dist/types/core/FormFieldRegistry.d.ts +17 -17
- package/dist/types/core/Validator.d.ts +7 -7
- package/dist/types/core/index.d.ts +16 -16
- package/dist/types/import/Importer.d.ts +43 -43
- package/dist/types/import/index.d.ts +5 -5
- package/dist/types/index.d.ts +18 -18
- package/dist/types/render/FormFields.d.ts +5 -5
- package/dist/types/render/Renderer.d.ts +23 -23
- package/dist/types/render/components/Description.d.ts +1 -1
- package/dist/types/render/components/Errors.d.ts +1 -1
- package/dist/types/render/components/FormComponent.d.ts +1 -1
- package/dist/types/render/components/FormField.d.ts +1 -1
- package/dist/types/render/components/Label.d.ts +1 -1
- package/dist/types/render/components/PoweredBy.d.ts +1 -1
- package/dist/types/render/components/Sanitizer.d.ts +7 -7
- package/dist/types/render/components/Util.d.ts +6 -4
- package/dist/types/render/components/form-fields/Button.d.ts +11 -11
- package/dist/types/render/components/form-fields/Checkbox.d.ts +13 -10
- package/dist/types/render/components/form-fields/Checklist.d.ts +12 -0
- package/dist/types/render/components/form-fields/Default.d.ts +9 -9
- package/dist/types/render/components/form-fields/Number.d.ts +13 -10
- package/dist/types/render/components/form-fields/Radio.d.ts +12 -15
- package/dist/types/render/components/form-fields/Select.d.ts +12 -15
- package/dist/types/render/components/form-fields/Taglist.d.ts +12 -0
- package/dist/types/render/components/form-fields/Text.d.ts +10 -10
- package/dist/types/render/components/form-fields/Textfield.d.ts +13 -10
- package/dist/types/render/components/form-fields/parts/DropdownList.d.ts +1 -0
- package/dist/types/render/components/index.d.ts +13 -11
- package/dist/types/render/context/FormContext.d.ts +12 -12
- package/dist/types/render/context/FormRenderContext.d.ts +6 -6
- package/dist/types/render/context/index.d.ts +2 -2
- package/dist/types/render/hooks/useKeyDownAction.d.ts +1 -0
- package/dist/types/render/hooks/useService.d.ts +1 -1
- package/dist/types/render/hooks/useValuesAsync.d.ts +28 -0
- package/dist/types/render/index.d.ts +11 -11
- package/dist/types/types.d.ts +35 -35
- package/dist/types/util/form.d.ts +6 -6
- package/dist/types/util/index.d.ts +24 -16
- package/dist/types/util/injector.d.ts +2 -1
- package/package.json +6 -5
package/dist/index.cjs
CHANGED
|
@@ -8,14 +8,17 @@ var snarkdown = require('@bpmn-io/snarkdown');
|
|
|
8
8
|
var jsxRuntime = require('preact/jsx-runtime');
|
|
9
9
|
var hooks = require('preact/hooks');
|
|
10
10
|
var preact = require('preact');
|
|
11
|
+
var React = require('preact/compat');
|
|
12
|
+
var classNames = require('classnames');
|
|
11
13
|
var Markup = require('preact-markup');
|
|
12
|
-
var compat = require('preact/compat');
|
|
13
14
|
var didi = require('didi');
|
|
14
15
|
|
|
15
16
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
16
17
|
|
|
17
18
|
var Ids__default = /*#__PURE__*/_interopDefaultLegacy(Ids);
|
|
18
19
|
var snarkdown__default = /*#__PURE__*/_interopDefaultLegacy(snarkdown);
|
|
20
|
+
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
|
|
21
|
+
var classNames__default = /*#__PURE__*/_interopDefaultLegacy(classNames);
|
|
19
22
|
var Markup__default = /*#__PURE__*/_interopDefaultLegacy(Markup);
|
|
20
23
|
|
|
21
24
|
var FN_REF = '__fn';
|
|
@@ -598,52 +601,15 @@ class FormFieldRegistry {
|
|
|
598
601
|
FormFieldRegistry.$inject = ['eventBus'];
|
|
599
602
|
|
|
600
603
|
function createInjector(bootstrapModules) {
|
|
601
|
-
const
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
function hasModule(module) {
|
|
605
|
-
return modules.includes(module);
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
function addModule(module) {
|
|
609
|
-
modules.push(module);
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
function visit(module) {
|
|
613
|
-
if (hasModule(module)) {
|
|
614
|
-
return;
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
(module.__depends__ || []).forEach(visit);
|
|
618
|
-
|
|
619
|
-
if (hasModule(module)) {
|
|
620
|
-
return;
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
addModule(module);
|
|
624
|
-
(module.__init__ || []).forEach(function (component) {
|
|
625
|
-
components.push(component);
|
|
626
|
-
});
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
bootstrapModules.forEach(visit);
|
|
630
|
-
const injector = new didi.Injector(modules);
|
|
631
|
-
components.forEach(function (component) {
|
|
632
|
-
try {
|
|
633
|
-
injector[typeof component === 'string' ? 'get' : 'invoke'](component);
|
|
634
|
-
} catch (err) {
|
|
635
|
-
console.error('Failed to instantiate component');
|
|
636
|
-
console.error(err.stack);
|
|
637
|
-
throw err;
|
|
638
|
-
}
|
|
639
|
-
});
|
|
604
|
+
const injector = new didi.Injector(bootstrapModules);
|
|
605
|
+
injector.init();
|
|
640
606
|
return injector;
|
|
641
607
|
}
|
|
642
608
|
|
|
643
|
-
/**
|
|
644
|
-
* @param {string?} prefix
|
|
645
|
-
*
|
|
646
|
-
* @returns Element
|
|
609
|
+
/**
|
|
610
|
+
* @param {string?} prefix
|
|
611
|
+
*
|
|
612
|
+
* @returns Element
|
|
647
613
|
*/
|
|
648
614
|
function createFormContainer(prefix = 'fjs') {
|
|
649
615
|
const container = document.createElement('div');
|
|
@@ -689,41 +655,76 @@ function generateIndexForType(type) {
|
|
|
689
655
|
function generateIdForType(type) {
|
|
690
656
|
return `${type}${generateIndexForType(type)}`;
|
|
691
657
|
}
|
|
692
|
-
/**
|
|
693
|
-
* @template T
|
|
694
|
-
* @param {T} data
|
|
695
|
-
* @param {(this: any, key: string, value: any) => any} [replacer]
|
|
696
|
-
* @return {T}
|
|
658
|
+
/**
|
|
659
|
+
* @template T
|
|
660
|
+
* @param {T} data
|
|
661
|
+
* @param {(this: any, key: string, value: any) => any} [replacer]
|
|
662
|
+
* @return {T}
|
|
697
663
|
*/
|
|
698
664
|
|
|
699
665
|
function clone(data, replacer) {
|
|
700
666
|
return JSON.parse(JSON.stringify(data, replacer));
|
|
701
667
|
}
|
|
668
|
+
/**
|
|
669
|
+
* Parse the schema for input variables a form might make use of
|
|
670
|
+
*
|
|
671
|
+
* @param {any} schema
|
|
672
|
+
*
|
|
673
|
+
* @return {string[]}
|
|
674
|
+
*/
|
|
675
|
+
|
|
676
|
+
function getSchemaVariables(schema) {
|
|
677
|
+
if (!schema.components) {
|
|
678
|
+
return [];
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
return schema.components.reduce((variables, component) => {
|
|
682
|
+
const {
|
|
683
|
+
key,
|
|
684
|
+
valuesKey,
|
|
685
|
+
type
|
|
686
|
+
} = component;
|
|
687
|
+
|
|
688
|
+
if (['text', 'button'].includes(type)) {
|
|
689
|
+
return variables;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
if (key) {
|
|
693
|
+
variables = [...variables, key];
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
if (valuesKey && !variables.includes(valuesKey)) {
|
|
697
|
+
variables = [...variables, valuesKey];
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
return variables;
|
|
701
|
+
}, []);
|
|
702
|
+
}
|
|
702
703
|
|
|
703
704
|
class Importer {
|
|
704
|
-
/**
|
|
705
|
-
* @constructor
|
|
706
|
-
* @param { import('../core').FormFieldRegistry } formFieldRegistry
|
|
707
|
-
* @param { import('../render/FormFields').default } formFields
|
|
705
|
+
/**
|
|
706
|
+
* @constructor
|
|
707
|
+
* @param { import('../core').FormFieldRegistry } formFieldRegistry
|
|
708
|
+
* @param { import('../render/FormFields').default } formFields
|
|
708
709
|
*/
|
|
709
710
|
constructor(formFieldRegistry, formFields) {
|
|
710
711
|
this._formFieldRegistry = formFieldRegistry;
|
|
711
712
|
this._formFields = formFields;
|
|
712
713
|
}
|
|
713
|
-
/**
|
|
714
|
-
* Import schema adding `id`, `_parent` and `_path`
|
|
715
|
-
* information to each field and adding it to the
|
|
716
|
-
* form field registry.
|
|
717
|
-
*
|
|
718
|
-
* @param {any} schema
|
|
719
|
-
* @param {any} [data]
|
|
720
|
-
*
|
|
721
|
-
* @return { { warnings: Array<any>, schema: any, data: any } }
|
|
714
|
+
/**
|
|
715
|
+
* Import schema adding `id`, `_parent` and `_path`
|
|
716
|
+
* information to each field and adding it to the
|
|
717
|
+
* form field registry.
|
|
718
|
+
*
|
|
719
|
+
* @param {any} schema
|
|
720
|
+
* @param {any} [data]
|
|
721
|
+
*
|
|
722
|
+
* @return { { warnings: Array<any>, schema: any, data: any } }
|
|
722
723
|
*/
|
|
723
724
|
|
|
724
725
|
|
|
725
726
|
importSchema(schema, data = {}) {
|
|
726
|
-
// TODO: Add warnings
|
|
727
|
+
// TODO: Add warnings - https://github.com/bpmn-io/form-js/issues/289
|
|
727
728
|
const warnings = [];
|
|
728
729
|
|
|
729
730
|
try {
|
|
@@ -739,11 +740,11 @@ class Importer {
|
|
|
739
740
|
throw err;
|
|
740
741
|
}
|
|
741
742
|
}
|
|
742
|
-
/**
|
|
743
|
-
* @param {any} formField
|
|
744
|
-
* @param {string} [parentId]
|
|
745
|
-
*
|
|
746
|
-
* @return {any} importedField
|
|
743
|
+
/**
|
|
744
|
+
* @param {any} formField
|
|
745
|
+
* @param {string} [parentId]
|
|
746
|
+
*
|
|
747
|
+
* @return {any} importedField
|
|
747
748
|
*/
|
|
748
749
|
|
|
749
750
|
|
|
@@ -805,10 +806,10 @@ class Importer {
|
|
|
805
806
|
this.importFormField(component, parentId);
|
|
806
807
|
});
|
|
807
808
|
}
|
|
808
|
-
/**
|
|
809
|
-
* @param {Object} data
|
|
810
|
-
*
|
|
811
|
-
* @return {Object} importedData
|
|
809
|
+
/**
|
|
810
|
+
* @param {Object} data
|
|
811
|
+
*
|
|
812
|
+
* @return {Object} importedData
|
|
812
813
|
*/
|
|
813
814
|
|
|
814
815
|
|
|
@@ -817,19 +818,39 @@ class Importer {
|
|
|
817
818
|
const {
|
|
818
819
|
defaultValue,
|
|
819
820
|
_path,
|
|
820
|
-
type
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
821
|
+
type,
|
|
822
|
+
valuesKey
|
|
823
|
+
} = formField; // get values defined via valuesKey
|
|
824
|
+
|
|
825
|
+
if (valuesKey) {
|
|
826
|
+
importedData = { ...importedData,
|
|
827
|
+
[valuesKey]: minDash.get(data, [valuesKey])
|
|
828
|
+
};
|
|
829
|
+
} // try to get value from data
|
|
830
|
+
// if unavailable - try to get default value from form field
|
|
831
|
+
// if unavailable - get empty value from form field
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
if (_path) {
|
|
835
|
+
const fieldImplementation = this._formFields.get(type);
|
|
836
|
+
|
|
837
|
+
let valueData = minDash.get(data, _path);
|
|
838
|
+
|
|
839
|
+
if (!minDash.isUndefined(valueData) && fieldImplementation.sanitizeValue) {
|
|
840
|
+
valueData = fieldImplementation.sanitizeValue({
|
|
841
|
+
formField,
|
|
842
|
+
data,
|
|
843
|
+
value: valueData
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
const initialFieldValue = !minDash.isUndefined(valueData) ? valueData : !minDash.isUndefined(defaultValue) ? defaultValue : fieldImplementation.emptyValue;
|
|
848
|
+
importedData = { ...importedData,
|
|
849
|
+
[_path[0]]: initialFieldValue
|
|
850
|
+
};
|
|
851
|
+
}
|
|
829
852
|
|
|
830
|
-
return
|
|
831
|
-
[_path[0]]: minDash.get(data, _path, minDash.isUndefined(defaultValue) ? this._formFields.get(type).emptyValue : defaultValue)
|
|
832
|
-
};
|
|
853
|
+
return importedData;
|
|
833
854
|
}, {});
|
|
834
855
|
}
|
|
835
856
|
|
|
@@ -849,11 +870,11 @@ const ALLOWED_URI_PATTERN = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^
|
|
|
849
870
|
const ATTR_WHITESPACE_PATTERN = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g; // eslint-disable-line no-control-regex
|
|
850
871
|
|
|
851
872
|
const FORM_ELEMENT = document.createElement('form');
|
|
852
|
-
/**
|
|
853
|
-
* Sanitize a HTML string and return the cleaned, safe version.
|
|
854
|
-
*
|
|
855
|
-
* @param {string} html
|
|
856
|
-
* @return {string}
|
|
873
|
+
/**
|
|
874
|
+
* Sanitize a HTML string and return the cleaned, safe version.
|
|
875
|
+
*
|
|
876
|
+
* @param {string} html
|
|
877
|
+
* @return {string}
|
|
857
878
|
*/
|
|
858
879
|
|
|
859
880
|
function sanitizeHTML(html) {
|
|
@@ -872,15 +893,15 @@ function sanitizeHTML(html) {
|
|
|
872
893
|
return '';
|
|
873
894
|
}
|
|
874
895
|
}
|
|
875
|
-
/**
|
|
876
|
-
* Recursively sanitize a HTML node, potentially
|
|
877
|
-
* removing it, its children or attributes.
|
|
878
|
-
*
|
|
879
|
-
* Inspired by https://github.com/developit/snarkdown/issues/70
|
|
880
|
-
* and https://github.com/cure53/DOMPurify. Simplified
|
|
881
|
-
* for our use-case.
|
|
882
|
-
*
|
|
883
|
-
* @param {Element} node
|
|
896
|
+
/**
|
|
897
|
+
* Recursively sanitize a HTML node, potentially
|
|
898
|
+
* removing it, its children or attributes.
|
|
899
|
+
*
|
|
900
|
+
* Inspired by https://github.com/developit/snarkdown/issues/70
|
|
901
|
+
* and https://github.com/cure53/DOMPurify. Simplified
|
|
902
|
+
* for our use-case.
|
|
903
|
+
*
|
|
904
|
+
* @param {Element} node
|
|
884
905
|
*/
|
|
885
906
|
|
|
886
907
|
function sanitizeNode(node) {
|
|
@@ -927,13 +948,13 @@ function sanitizeNode(node) {
|
|
|
927
948
|
node.childNodes[i]);
|
|
928
949
|
}
|
|
929
950
|
}
|
|
930
|
-
/**
|
|
931
|
-
* Validates attributes for validity.
|
|
932
|
-
*
|
|
933
|
-
* @param {string} lcTag
|
|
934
|
-
* @param {string} lcName
|
|
935
|
-
* @param {string} value
|
|
936
|
-
* @return {boolean}
|
|
951
|
+
/**
|
|
952
|
+
* Validates attributes for validity.
|
|
953
|
+
*
|
|
954
|
+
* @param {string} lcTag
|
|
955
|
+
* @param {string} lcName
|
|
956
|
+
* @param {string} value
|
|
957
|
+
* @return {boolean}
|
|
937
958
|
*/
|
|
938
959
|
|
|
939
960
|
|
|
@@ -989,8 +1010,48 @@ function safeMarkdown(markdown) {
|
|
|
989
1010
|
const html = markdownToHTML(markdown);
|
|
990
1011
|
return sanitizeHTML(html);
|
|
991
1012
|
}
|
|
1013
|
+
function sanitizeSingleSelectValue(options) {
|
|
1014
|
+
const {
|
|
1015
|
+
formField,
|
|
1016
|
+
data,
|
|
1017
|
+
value
|
|
1018
|
+
} = options;
|
|
1019
|
+
const {
|
|
1020
|
+
valuesKey,
|
|
1021
|
+
values
|
|
1022
|
+
} = formField;
|
|
1023
|
+
|
|
1024
|
+
try {
|
|
1025
|
+
const validValues = (valuesKey ? minDash.get(data, [valuesKey]) : values).map(v => v.value) || [];
|
|
1026
|
+
return validValues.includes(value) ? value : null;
|
|
1027
|
+
} catch (error) {
|
|
1028
|
+
// use default value in case of formatting error
|
|
1029
|
+
// TODO(@Skaiir): log a warning when this happens - https://github.com/bpmn-io/form-js/issues/289
|
|
1030
|
+
return null;
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
function sanitizeMultiSelectValue(options) {
|
|
1034
|
+
const {
|
|
1035
|
+
formField,
|
|
1036
|
+
data,
|
|
1037
|
+
value
|
|
1038
|
+
} = options;
|
|
1039
|
+
const {
|
|
1040
|
+
valuesKey,
|
|
1041
|
+
values
|
|
1042
|
+
} = formField;
|
|
1043
|
+
|
|
1044
|
+
try {
|
|
1045
|
+
const validValues = (valuesKey ? minDash.get(data, [valuesKey]) : values).map(v => v.value) || [];
|
|
1046
|
+
return value.filter(v => validValues.includes(v));
|
|
1047
|
+
} catch (error) {
|
|
1048
|
+
// use default value in case of formatting error
|
|
1049
|
+
// TODO(@Skaiir): log a warning when this happens - https://github.com/bpmn-io/form-js/issues/289
|
|
1050
|
+
return [];
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
992
1053
|
|
|
993
|
-
const type$
|
|
1054
|
+
const type$8 = 'button';
|
|
994
1055
|
function Button(props) {
|
|
995
1056
|
const {
|
|
996
1057
|
disabled,
|
|
@@ -1000,7 +1061,7 @@ function Button(props) {
|
|
|
1000
1061
|
action = 'submit'
|
|
1001
1062
|
} = field;
|
|
1002
1063
|
return jsxRuntime.jsx("div", {
|
|
1003
|
-
class: formFieldClasses(type$
|
|
1064
|
+
class: formFieldClasses(type$8),
|
|
1004
1065
|
children: jsxRuntime.jsx("button", {
|
|
1005
1066
|
class: "fjs-button",
|
|
1006
1067
|
type: action,
|
|
@@ -1017,7 +1078,7 @@ Button.create = function (options = {}) {
|
|
|
1017
1078
|
};
|
|
1018
1079
|
};
|
|
1019
1080
|
|
|
1020
|
-
Button.type = type$
|
|
1081
|
+
Button.type = type$8;
|
|
1021
1082
|
Button.label = 'Button';
|
|
1022
1083
|
Button.keyed = true;
|
|
1023
1084
|
|
|
@@ -1033,11 +1094,11 @@ const FormRenderContext = preact.createContext({
|
|
|
1033
1094
|
}
|
|
1034
1095
|
});
|
|
1035
1096
|
|
|
1036
|
-
/**
|
|
1037
|
-
* @param {string} type
|
|
1038
|
-
* @param {boolean} [strict]
|
|
1039
|
-
*
|
|
1040
|
-
* @returns {any}
|
|
1097
|
+
/**
|
|
1098
|
+
* @param {string} type
|
|
1099
|
+
* @param {boolean} [strict]
|
|
1100
|
+
*
|
|
1101
|
+
* @returns {any}
|
|
1041
1102
|
*/
|
|
1042
1103
|
|
|
1043
1104
|
function getService(type, strict) {}
|
|
@@ -1099,7 +1160,7 @@ function Label(props) {
|
|
|
1099
1160
|
});
|
|
1100
1161
|
}
|
|
1101
1162
|
|
|
1102
|
-
const type$
|
|
1163
|
+
const type$7 = 'checkbox';
|
|
1103
1164
|
function Checkbox(props) {
|
|
1104
1165
|
const {
|
|
1105
1166
|
disabled,
|
|
@@ -1126,7 +1187,7 @@ function Checkbox(props) {
|
|
|
1126
1187
|
formId
|
|
1127
1188
|
} = hooks.useContext(FormContext);
|
|
1128
1189
|
return jsxRuntime.jsxs("div", {
|
|
1129
|
-
class: formFieldClasses(type$
|
|
1190
|
+
class: formFieldClasses(type$7, errors),
|
|
1130
1191
|
children: [jsxRuntime.jsx(Label, {
|
|
1131
1192
|
id: prefixId(id, formId),
|
|
1132
1193
|
label: label,
|
|
@@ -1152,11 +1213,15 @@ Checkbox.create = function (options = {}) {
|
|
|
1152
1213
|
};
|
|
1153
1214
|
};
|
|
1154
1215
|
|
|
1155
|
-
Checkbox.type = type$
|
|
1216
|
+
Checkbox.type = type$7;
|
|
1156
1217
|
Checkbox.label = 'Checkbox';
|
|
1157
1218
|
Checkbox.keyed = true;
|
|
1158
1219
|
Checkbox.emptyValue = false;
|
|
1159
1220
|
|
|
1221
|
+
Checkbox.sanitizeValue = ({
|
|
1222
|
+
value
|
|
1223
|
+
}) => value === true;
|
|
1224
|
+
|
|
1160
1225
|
function useService (type, strict) {
|
|
1161
1226
|
const {
|
|
1162
1227
|
getService
|
|
@@ -1164,6 +1229,153 @@ function useService (type, strict) {
|
|
|
1164
1229
|
return getService(type, strict);
|
|
1165
1230
|
}
|
|
1166
1231
|
|
|
1232
|
+
/**
|
|
1233
|
+
* @enum { String }
|
|
1234
|
+
*/
|
|
1235
|
+
|
|
1236
|
+
const LOAD_STATES = {
|
|
1237
|
+
LOADING: 'loading',
|
|
1238
|
+
LOADED: 'loaded',
|
|
1239
|
+
ERROR: 'error'
|
|
1240
|
+
};
|
|
1241
|
+
/**
|
|
1242
|
+
* @typedef {Object} ValuesGetter
|
|
1243
|
+
* @property {Object[]} values - The values data
|
|
1244
|
+
* @property {(LOAD_STATES)} state - The values data's loading state, to use for conditional rendering
|
|
1245
|
+
*/
|
|
1246
|
+
|
|
1247
|
+
/**
|
|
1248
|
+
* A hook to load values for single and multiselect components.
|
|
1249
|
+
*
|
|
1250
|
+
* @param {Object} field - The form field to handle values for
|
|
1251
|
+
* @return {ValuesGetter} valuesGetter - A values getter object providing loading state and values
|
|
1252
|
+
*/
|
|
1253
|
+
|
|
1254
|
+
function useValuesAsync (field) {
|
|
1255
|
+
const {
|
|
1256
|
+
valuesKey,
|
|
1257
|
+
values: staticValues
|
|
1258
|
+
} = field;
|
|
1259
|
+
const [valuesGetter, setValuesGetter] = hooks.useState({
|
|
1260
|
+
values: [],
|
|
1261
|
+
error: undefined,
|
|
1262
|
+
state: LOAD_STATES.LOADING
|
|
1263
|
+
});
|
|
1264
|
+
|
|
1265
|
+
const initialData = useService('form')._getState().initialData;
|
|
1266
|
+
|
|
1267
|
+
hooks.useEffect(() => {
|
|
1268
|
+
let values = [];
|
|
1269
|
+
|
|
1270
|
+
if (valuesKey !== undefined) {
|
|
1271
|
+
const keyedValues = (initialData || {})[valuesKey];
|
|
1272
|
+
|
|
1273
|
+
if (keyedValues && Array.isArray(keyedValues)) {
|
|
1274
|
+
values = keyedValues;
|
|
1275
|
+
}
|
|
1276
|
+
} else if (staticValues !== undefined) {
|
|
1277
|
+
values = Array.isArray(staticValues) ? staticValues : [];
|
|
1278
|
+
} else {
|
|
1279
|
+
setValuesGetter(getErrorState('No values source defined in the form definition'));
|
|
1280
|
+
return;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
setValuesGetter(buildLoadedState(values));
|
|
1284
|
+
}, [valuesKey, staticValues, initialData]);
|
|
1285
|
+
return valuesGetter;
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
const getErrorState = error => ({
|
|
1289
|
+
values: [],
|
|
1290
|
+
error,
|
|
1291
|
+
state: LOAD_STATES.ERROR
|
|
1292
|
+
});
|
|
1293
|
+
|
|
1294
|
+
const buildLoadedState = values => ({
|
|
1295
|
+
values,
|
|
1296
|
+
error: undefined,
|
|
1297
|
+
state: LOAD_STATES.LOADED
|
|
1298
|
+
});
|
|
1299
|
+
|
|
1300
|
+
const type$6 = 'checklist';
|
|
1301
|
+
function Checklist(props) {
|
|
1302
|
+
const {
|
|
1303
|
+
disabled,
|
|
1304
|
+
errors = [],
|
|
1305
|
+
field,
|
|
1306
|
+
value = []
|
|
1307
|
+
} = props;
|
|
1308
|
+
const {
|
|
1309
|
+
description,
|
|
1310
|
+
id,
|
|
1311
|
+
label
|
|
1312
|
+
} = field;
|
|
1313
|
+
|
|
1314
|
+
const toggleCheckbox = v => {
|
|
1315
|
+
let newValue = [...value];
|
|
1316
|
+
|
|
1317
|
+
if (!newValue.includes(v)) {
|
|
1318
|
+
newValue.push(v);
|
|
1319
|
+
} else {
|
|
1320
|
+
newValue = newValue.filter(x => x != v);
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
props.onChange({
|
|
1324
|
+
field,
|
|
1325
|
+
value: newValue
|
|
1326
|
+
});
|
|
1327
|
+
};
|
|
1328
|
+
|
|
1329
|
+
const {
|
|
1330
|
+
state: loadState,
|
|
1331
|
+
values: options
|
|
1332
|
+
} = useValuesAsync(field);
|
|
1333
|
+
const {
|
|
1334
|
+
formId
|
|
1335
|
+
} = hooks.useContext(FormContext);
|
|
1336
|
+
return jsxRuntime.jsxs("div", {
|
|
1337
|
+
class: formFieldClasses(type$6, errors),
|
|
1338
|
+
children: [jsxRuntime.jsx(Label, {
|
|
1339
|
+
label: label
|
|
1340
|
+
}), loadState == LOAD_STATES.LOADED && options.map((v, index) => {
|
|
1341
|
+
return jsxRuntime.jsx(Label, {
|
|
1342
|
+
id: prefixId(`${id}-${index}`, formId),
|
|
1343
|
+
label: v.label,
|
|
1344
|
+
required: false,
|
|
1345
|
+
children: jsxRuntime.jsx("input", {
|
|
1346
|
+
checked: value.includes(v.value),
|
|
1347
|
+
class: "fjs-input",
|
|
1348
|
+
disabled: disabled,
|
|
1349
|
+
id: prefixId(`${id}-${index}`, formId),
|
|
1350
|
+
type: "checkbox",
|
|
1351
|
+
onClick: () => toggleCheckbox(v.value)
|
|
1352
|
+
})
|
|
1353
|
+
}, `${id}-${index}`);
|
|
1354
|
+
}), jsxRuntime.jsx(Description, {
|
|
1355
|
+
description: description
|
|
1356
|
+
}), jsxRuntime.jsx(Errors, {
|
|
1357
|
+
errors: errors
|
|
1358
|
+
})]
|
|
1359
|
+
});
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
Checklist.create = function (options = {}) {
|
|
1363
|
+
if (options.valuesKey) return options;
|
|
1364
|
+
return {
|
|
1365
|
+
values: [{
|
|
1366
|
+
label: 'Value',
|
|
1367
|
+
value: 'value'
|
|
1368
|
+
}],
|
|
1369
|
+
...options
|
|
1370
|
+
};
|
|
1371
|
+
};
|
|
1372
|
+
|
|
1373
|
+
Checklist.type = type$6;
|
|
1374
|
+
Checklist.label = 'Checklist';
|
|
1375
|
+
Checklist.keyed = true;
|
|
1376
|
+
Checklist.emptyValue = [];
|
|
1377
|
+
Checklist.sanitizeValue = sanitizeMultiSelectValue;
|
|
1378
|
+
|
|
1167
1379
|
const noop$1 = () => false;
|
|
1168
1380
|
|
|
1169
1381
|
function FormField(props) {
|
|
@@ -1239,10 +1451,10 @@ Default.create = function (options = {}) {
|
|
|
1239
1451
|
Default.type = 'default';
|
|
1240
1452
|
Default.keyed = false;
|
|
1241
1453
|
|
|
1242
|
-
/**
|
|
1243
|
-
* This file must not be changed or exchanged.
|
|
1244
|
-
*
|
|
1245
|
-
* @see http://bpmn.io/license for more information.
|
|
1454
|
+
/**
|
|
1455
|
+
* This file must not be changed or exchanged.
|
|
1456
|
+
*
|
|
1457
|
+
* @see http://bpmn.io/license for more information.
|
|
1246
1458
|
*/
|
|
1247
1459
|
|
|
1248
1460
|
function Logo() {
|
|
@@ -1327,7 +1539,7 @@ function PoweredBy(props) {
|
|
|
1327
1539
|
}
|
|
1328
1540
|
|
|
1329
1541
|
return jsxRuntime.jsxs(preact.Fragment, {
|
|
1330
|
-
children: [
|
|
1542
|
+
children: [React.createPortal(jsxRuntime.jsx(Lightbox, {
|
|
1331
1543
|
open: open,
|
|
1332
1544
|
onBackdropClick: toggleOpen(false)
|
|
1333
1545
|
}), document.body), jsxRuntime.jsx(Link, {
|
|
@@ -1372,7 +1584,7 @@ function FormComponent(props) {
|
|
|
1372
1584
|
});
|
|
1373
1585
|
}
|
|
1374
1586
|
|
|
1375
|
-
const type$
|
|
1587
|
+
const type$5 = 'number';
|
|
1376
1588
|
function Number(props) {
|
|
1377
1589
|
const {
|
|
1378
1590
|
disabled,
|
|
@@ -1393,10 +1605,11 @@ function Number(props) {
|
|
|
1393
1605
|
const onChange = ({
|
|
1394
1606
|
target
|
|
1395
1607
|
}) => {
|
|
1396
|
-
const parsedValue = parseInt(target.value, 10);
|
|
1397
1608
|
props.onChange({
|
|
1398
1609
|
field,
|
|
1399
|
-
value:
|
|
1610
|
+
value: Number.sanitizeValue({
|
|
1611
|
+
value: target.value
|
|
1612
|
+
})
|
|
1400
1613
|
});
|
|
1401
1614
|
};
|
|
1402
1615
|
|
|
@@ -1404,7 +1617,7 @@ function Number(props) {
|
|
|
1404
1617
|
formId
|
|
1405
1618
|
} = hooks.useContext(FormContext);
|
|
1406
1619
|
return jsxRuntime.jsxs("div", {
|
|
1407
|
-
class: formFieldClasses(type$
|
|
1620
|
+
class: formFieldClasses(type$5, errors),
|
|
1408
1621
|
children: [jsxRuntime.jsx(Label, {
|
|
1409
1622
|
id: prefixId(id, formId),
|
|
1410
1623
|
label: label,
|
|
@@ -1429,12 +1642,19 @@ Number.create = function (options = {}) {
|
|
|
1429
1642
|
};
|
|
1430
1643
|
};
|
|
1431
1644
|
|
|
1432
|
-
Number.
|
|
1645
|
+
Number.sanitizeValue = ({
|
|
1646
|
+
value
|
|
1647
|
+
}) => {
|
|
1648
|
+
const parsedValue = parseInt(value, 10);
|
|
1649
|
+
return isNaN(parsedValue) ? null : parsedValue;
|
|
1650
|
+
};
|
|
1651
|
+
|
|
1652
|
+
Number.type = type$5;
|
|
1433
1653
|
Number.keyed = true;
|
|
1434
1654
|
Number.label = 'Number';
|
|
1435
1655
|
Number.emptyValue = null;
|
|
1436
1656
|
|
|
1437
|
-
const type$
|
|
1657
|
+
const type$4 = 'radio';
|
|
1438
1658
|
function Radio(props) {
|
|
1439
1659
|
const {
|
|
1440
1660
|
disabled,
|
|
@@ -1446,8 +1666,7 @@ function Radio(props) {
|
|
|
1446
1666
|
description,
|
|
1447
1667
|
id,
|
|
1448
1668
|
label,
|
|
1449
|
-
validate = {}
|
|
1450
|
-
values
|
|
1669
|
+
validate = {}
|
|
1451
1670
|
} = field;
|
|
1452
1671
|
const {
|
|
1453
1672
|
required
|
|
@@ -1460,26 +1679,30 @@ function Radio(props) {
|
|
|
1460
1679
|
});
|
|
1461
1680
|
};
|
|
1462
1681
|
|
|
1682
|
+
const {
|
|
1683
|
+
state: loadState,
|
|
1684
|
+
values: options
|
|
1685
|
+
} = useValuesAsync(field);
|
|
1463
1686
|
const {
|
|
1464
1687
|
formId
|
|
1465
1688
|
} = hooks.useContext(FormContext);
|
|
1466
1689
|
return jsxRuntime.jsxs("div", {
|
|
1467
|
-
class: formFieldClasses(type$
|
|
1690
|
+
class: formFieldClasses(type$4, errors),
|
|
1468
1691
|
children: [jsxRuntime.jsx(Label, {
|
|
1469
1692
|
label: label,
|
|
1470
1693
|
required: required
|
|
1471
|
-
}),
|
|
1694
|
+
}), loadState == LOAD_STATES.LOADED && options.map((option, index) => {
|
|
1472
1695
|
return jsxRuntime.jsx(Label, {
|
|
1473
1696
|
id: prefixId(`${id}-${index}`, formId),
|
|
1474
|
-
label:
|
|
1697
|
+
label: option.label,
|
|
1475
1698
|
required: false,
|
|
1476
1699
|
children: jsxRuntime.jsx("input", {
|
|
1477
|
-
checked:
|
|
1700
|
+
checked: option.value === value,
|
|
1478
1701
|
class: "fjs-input",
|
|
1479
1702
|
disabled: disabled,
|
|
1480
1703
|
id: prefixId(`${id}-${index}`, formId),
|
|
1481
1704
|
type: "radio",
|
|
1482
|
-
onClick: () => onChange(
|
|
1705
|
+
onClick: () => onChange(option.value)
|
|
1483
1706
|
})
|
|
1484
1707
|
}, `${id}-${index}`);
|
|
1485
1708
|
}), jsxRuntime.jsx(Description, {
|
|
@@ -1491,6 +1714,7 @@ function Radio(props) {
|
|
|
1491
1714
|
}
|
|
1492
1715
|
|
|
1493
1716
|
Radio.create = function (options = {}) {
|
|
1717
|
+
if (options.valuesKey) return options;
|
|
1494
1718
|
return {
|
|
1495
1719
|
values: [{
|
|
1496
1720
|
label: 'Value',
|
|
@@ -1500,12 +1724,13 @@ Radio.create = function (options = {}) {
|
|
|
1500
1724
|
};
|
|
1501
1725
|
};
|
|
1502
1726
|
|
|
1503
|
-
Radio.type = type$
|
|
1727
|
+
Radio.type = type$4;
|
|
1504
1728
|
Radio.label = 'Radio';
|
|
1505
1729
|
Radio.keyed = true;
|
|
1506
1730
|
Radio.emptyValue = null;
|
|
1731
|
+
Radio.sanitizeValue = sanitizeSingleSelectValue;
|
|
1507
1732
|
|
|
1508
|
-
const type$
|
|
1733
|
+
const type$3 = 'select';
|
|
1509
1734
|
function Select(props) {
|
|
1510
1735
|
const {
|
|
1511
1736
|
disabled,
|
|
@@ -1517,8 +1742,7 @@ function Select(props) {
|
|
|
1517
1742
|
description,
|
|
1518
1743
|
id,
|
|
1519
1744
|
label,
|
|
1520
|
-
validate = {}
|
|
1521
|
-
values
|
|
1745
|
+
validate = {}
|
|
1522
1746
|
} = field;
|
|
1523
1747
|
const {
|
|
1524
1748
|
required
|
|
@@ -1533,11 +1757,15 @@ function Select(props) {
|
|
|
1533
1757
|
});
|
|
1534
1758
|
};
|
|
1535
1759
|
|
|
1760
|
+
const {
|
|
1761
|
+
state: loadState,
|
|
1762
|
+
values: options
|
|
1763
|
+
} = useValuesAsync(field);
|
|
1536
1764
|
const {
|
|
1537
1765
|
formId
|
|
1538
1766
|
} = hooks.useContext(FormContext);
|
|
1539
1767
|
return jsxRuntime.jsxs("div", {
|
|
1540
|
-
class: formFieldClasses(type$
|
|
1768
|
+
class: formFieldClasses(type$3, errors),
|
|
1541
1769
|
children: [jsxRuntime.jsx(Label, {
|
|
1542
1770
|
id: prefixId(id, formId),
|
|
1543
1771
|
label: label,
|
|
@@ -1550,10 +1778,10 @@ function Select(props) {
|
|
|
1550
1778
|
value: value || '',
|
|
1551
1779
|
children: [jsxRuntime.jsx("option", {
|
|
1552
1780
|
value: ""
|
|
1553
|
-
}),
|
|
1781
|
+
}), loadState == LOAD_STATES.LOADED && options.map((option, index) => {
|
|
1554
1782
|
return jsxRuntime.jsx("option", {
|
|
1555
|
-
value:
|
|
1556
|
-
children:
|
|
1783
|
+
value: option.value,
|
|
1784
|
+
children: option.label
|
|
1557
1785
|
}, `${id}-${index}`);
|
|
1558
1786
|
})]
|
|
1559
1787
|
}), jsxRuntime.jsx(Description, {
|
|
@@ -1565,6 +1793,7 @@ function Select(props) {
|
|
|
1565
1793
|
}
|
|
1566
1794
|
|
|
1567
1795
|
Select.create = function (options = {}) {
|
|
1796
|
+
if (options.valuesKey) return options;
|
|
1568
1797
|
return {
|
|
1569
1798
|
values: [{
|
|
1570
1799
|
label: 'Value',
|
|
@@ -1574,10 +1803,317 @@ Select.create = function (options = {}) {
|
|
|
1574
1803
|
};
|
|
1575
1804
|
};
|
|
1576
1805
|
|
|
1577
|
-
Select.type = type$
|
|
1806
|
+
Select.type = type$3;
|
|
1578
1807
|
Select.label = 'Select';
|
|
1579
1808
|
Select.keyed = true;
|
|
1580
1809
|
Select.emptyValue = null;
|
|
1810
|
+
Select.sanitizeValue = sanitizeSingleSelectValue;
|
|
1811
|
+
|
|
1812
|
+
function _extends() { _extends = 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.apply(this, arguments); }
|
|
1813
|
+
var CloseIcon = (({
|
|
1814
|
+
styles = {},
|
|
1815
|
+
...props
|
|
1816
|
+
}) => /*#__PURE__*/React__default['default'].createElement("svg", _extends({
|
|
1817
|
+
width: "16",
|
|
1818
|
+
height: "16",
|
|
1819
|
+
fill: "none",
|
|
1820
|
+
xmlns: "http://www.w3.org/2000/svg"
|
|
1821
|
+
}, props), /*#__PURE__*/React__default['default'].createElement("path", {
|
|
1822
|
+
fillRule: "evenodd",
|
|
1823
|
+
clipRule: "evenodd",
|
|
1824
|
+
d: "M12 4.7l-.7-.7L8 7.3 4.7 4l-.7.7L7.3 8 4 11.3l.7.7L8 8.7l3.3 3.3.7-.7L8.7 8 12 4.7z",
|
|
1825
|
+
fill: "#000"
|
|
1826
|
+
})));
|
|
1827
|
+
|
|
1828
|
+
function useKeyDownAction(targetKey, action, listenerElement = window) {
|
|
1829
|
+
function downHandler({
|
|
1830
|
+
key
|
|
1831
|
+
}) {
|
|
1832
|
+
if (key === targetKey) {
|
|
1833
|
+
action();
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1837
|
+
hooks.useEffect(() => {
|
|
1838
|
+
listenerElement.addEventListener('keydown', downHandler);
|
|
1839
|
+
return () => {
|
|
1840
|
+
listenerElement.removeEventListener('keydown', downHandler);
|
|
1841
|
+
};
|
|
1842
|
+
});
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
const DEFAULT_LABEL_GETTER = value => value;
|
|
1846
|
+
|
|
1847
|
+
const NOOP = () => {};
|
|
1848
|
+
|
|
1849
|
+
function DropdownList(props) {
|
|
1850
|
+
const {
|
|
1851
|
+
keyEventsListener = window,
|
|
1852
|
+
values = [],
|
|
1853
|
+
getLabel = DEFAULT_LABEL_GETTER,
|
|
1854
|
+
onValueSelected = NOOP,
|
|
1855
|
+
height = 235,
|
|
1856
|
+
emptyListMessage = 'No results'
|
|
1857
|
+
} = props;
|
|
1858
|
+
const [mouseControl, setMouseControl] = hooks.useState(true);
|
|
1859
|
+
const [focusedValueIndex, setFocusedValueIndex] = hooks.useState(0);
|
|
1860
|
+
const dropdownContainer = hooks.useRef();
|
|
1861
|
+
const mouseScreenPos = hooks.useRef();
|
|
1862
|
+
const focusedItem = hooks.useMemo(() => values.length ? values[focusedValueIndex] : null, [focusedValueIndex, values]);
|
|
1863
|
+
const changeFocusedValueIndex = hooks.useCallback(delta => {
|
|
1864
|
+
setFocusedValueIndex(x => Math.min(Math.max(0, x + delta), values.length - 1));
|
|
1865
|
+
}, [values.length]);
|
|
1866
|
+
hooks.useEffect(() => {
|
|
1867
|
+
if (focusedValueIndex === 0) return;
|
|
1868
|
+
|
|
1869
|
+
if (!focusedValueIndex || !values.length) {
|
|
1870
|
+
setFocusedValueIndex(0);
|
|
1871
|
+
} else if (focusedValueIndex >= values.length) {
|
|
1872
|
+
setFocusedValueIndex(values.length - 1);
|
|
1873
|
+
}
|
|
1874
|
+
}, [focusedValueIndex, values.length]);
|
|
1875
|
+
useKeyDownAction('ArrowUp', () => {
|
|
1876
|
+
if (values.length) {
|
|
1877
|
+
changeFocusedValueIndex(-1);
|
|
1878
|
+
setMouseControl(false);
|
|
1879
|
+
}
|
|
1880
|
+
}, keyEventsListener);
|
|
1881
|
+
useKeyDownAction('ArrowDown', () => {
|
|
1882
|
+
if (values.length) {
|
|
1883
|
+
changeFocusedValueIndex(1);
|
|
1884
|
+
setMouseControl(false);
|
|
1885
|
+
}
|
|
1886
|
+
}, keyEventsListener);
|
|
1887
|
+
useKeyDownAction('Enter', () => {
|
|
1888
|
+
if (focusedItem) {
|
|
1889
|
+
onValueSelected(focusedItem);
|
|
1890
|
+
}
|
|
1891
|
+
}, keyEventsListener);
|
|
1892
|
+
hooks.useEffect(() => {
|
|
1893
|
+
const individualEntries = dropdownContainer.current.children;
|
|
1894
|
+
|
|
1895
|
+
if (individualEntries.length && !mouseControl) {
|
|
1896
|
+
individualEntries[focusedValueIndex].scrollIntoView({
|
|
1897
|
+
block: 'nearest',
|
|
1898
|
+
inline: 'nearest'
|
|
1899
|
+
});
|
|
1900
|
+
}
|
|
1901
|
+
}, [focusedValueIndex, mouseControl]);
|
|
1902
|
+
|
|
1903
|
+
const mouseMove = (e, i) => {
|
|
1904
|
+
const userMoved = !mouseScreenPos.current || mouseScreenPos.current.x !== e.screenX && mouseScreenPos.current.y !== e.screenY;
|
|
1905
|
+
|
|
1906
|
+
if (userMoved) {
|
|
1907
|
+
mouseScreenPos.current = {
|
|
1908
|
+
x: e.screenX,
|
|
1909
|
+
y: e.screenY
|
|
1910
|
+
};
|
|
1911
|
+
|
|
1912
|
+
if (!mouseControl) {
|
|
1913
|
+
setMouseControl(true);
|
|
1914
|
+
setFocusedValueIndex(i);
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
};
|
|
1918
|
+
|
|
1919
|
+
return jsxRuntime.jsxs("div", {
|
|
1920
|
+
ref: dropdownContainer,
|
|
1921
|
+
tabIndex: -1,
|
|
1922
|
+
class: "fjs-dropdownlist",
|
|
1923
|
+
style: {
|
|
1924
|
+
maxHeight: height
|
|
1925
|
+
},
|
|
1926
|
+
children: [!!values.length && values.map((v, i) => {
|
|
1927
|
+
return jsxRuntime.jsx("div", {
|
|
1928
|
+
class: 'fjs-dropdownlist-item' + (focusedValueIndex === i ? ' focused' : ''),
|
|
1929
|
+
onMouseMove: e => mouseMove(e, i),
|
|
1930
|
+
onMouseEnter: mouseControl ? () => setFocusedValueIndex(i) : undefined,
|
|
1931
|
+
onMouseDown: e => {
|
|
1932
|
+
e.preventDefault();
|
|
1933
|
+
onValueSelected(v);
|
|
1934
|
+
},
|
|
1935
|
+
children: getLabel(v)
|
|
1936
|
+
});
|
|
1937
|
+
}), !values.length && jsxRuntime.jsx("div", {
|
|
1938
|
+
class: "fjs-dropdownlist-empty",
|
|
1939
|
+
children: emptyListMessage
|
|
1940
|
+
})]
|
|
1941
|
+
});
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
const type$2 = 'taglist';
|
|
1945
|
+
function Taglist(props) {
|
|
1946
|
+
const {
|
|
1947
|
+
disabled,
|
|
1948
|
+
errors = [],
|
|
1949
|
+
field,
|
|
1950
|
+
value: values = []
|
|
1951
|
+
} = props;
|
|
1952
|
+
const {
|
|
1953
|
+
description,
|
|
1954
|
+
id,
|
|
1955
|
+
label
|
|
1956
|
+
} = field;
|
|
1957
|
+
const {
|
|
1958
|
+
formId
|
|
1959
|
+
} = hooks.useContext(FormContext);
|
|
1960
|
+
const [filter, setFilter] = hooks.useState('');
|
|
1961
|
+
const [filteredOptions, setFilteredOptions] = hooks.useState([]);
|
|
1962
|
+
const [isDropdownExpanded, setIsDropdownExpanded] = hooks.useState(false);
|
|
1963
|
+
const [hasOptionsLeft, setHasOptionsLeft] = hooks.useState(true);
|
|
1964
|
+
const [isEscapeClosed, setIsEscapeClose] = hooks.useState(false);
|
|
1965
|
+
const searchbarRef = hooks.useRef();
|
|
1966
|
+
const {
|
|
1967
|
+
state: loadState,
|
|
1968
|
+
values: options
|
|
1969
|
+
} = useValuesAsync(field); // We cache a map of option values to their index so that we don't need to search the whole options array every time to correlate the label
|
|
1970
|
+
|
|
1971
|
+
const valueToOptionMap = hooks.useMemo(() => Object.assign({}, ...options.map((o, x) => ({
|
|
1972
|
+
[o.value]: options[x]
|
|
1973
|
+
}))), [options]); // Usage of stringify is necessary here because we want this effect to only trigger when there is a value change to the array
|
|
1974
|
+
|
|
1975
|
+
hooks.useEffect(() => {
|
|
1976
|
+
if (loadState === LOAD_STATES.LOADED) {
|
|
1977
|
+
setFilteredOptions(options.filter(o => o.label && o.value && o.label.toLowerCase().includes(filter.toLowerCase()) && !values.includes(o.value)));
|
|
1978
|
+
} else {
|
|
1979
|
+
setFilteredOptions([]);
|
|
1980
|
+
}
|
|
1981
|
+
}, [filter, JSON.stringify(values), options, loadState]);
|
|
1982
|
+
hooks.useEffect(() => {
|
|
1983
|
+
setHasOptionsLeft(options.length > values.length);
|
|
1984
|
+
}, [options.length, values.length]);
|
|
1985
|
+
|
|
1986
|
+
const onFilterChange = ({
|
|
1987
|
+
target
|
|
1988
|
+
}) => {
|
|
1989
|
+
setIsEscapeClose(false);
|
|
1990
|
+
setFilter(target.value);
|
|
1991
|
+
};
|
|
1992
|
+
|
|
1993
|
+
const selectValue = value => {
|
|
1994
|
+
if (filter) {
|
|
1995
|
+
setFilter('');
|
|
1996
|
+
} // Ensure values cannot be double selected due to latency
|
|
1997
|
+
|
|
1998
|
+
|
|
1999
|
+
if (values.at(-1) === value) {
|
|
2000
|
+
return;
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
props.onChange({
|
|
2004
|
+
value: [...values, value],
|
|
2005
|
+
field
|
|
2006
|
+
});
|
|
2007
|
+
};
|
|
2008
|
+
|
|
2009
|
+
const deselectValue = value => {
|
|
2010
|
+
props.onChange({
|
|
2011
|
+
value: values.filter(v => v != value),
|
|
2012
|
+
field
|
|
2013
|
+
});
|
|
2014
|
+
};
|
|
2015
|
+
|
|
2016
|
+
const onInputKeyDown = e => {
|
|
2017
|
+
switch (e.key) {
|
|
2018
|
+
case 'ArrowUp':
|
|
2019
|
+
case 'ArrowDown':
|
|
2020
|
+
// We do not want the cursor to seek in the search field when we press up and down
|
|
2021
|
+
e.preventDefault();
|
|
2022
|
+
break;
|
|
2023
|
+
|
|
2024
|
+
case 'Backspace':
|
|
2025
|
+
if (!filter && values.length) {
|
|
2026
|
+
deselectValue(values[values.length - 1]);
|
|
2027
|
+
}
|
|
2028
|
+
|
|
2029
|
+
break;
|
|
2030
|
+
|
|
2031
|
+
case 'Escape':
|
|
2032
|
+
setIsEscapeClose(true);
|
|
2033
|
+
break;
|
|
2034
|
+
|
|
2035
|
+
case 'Enter':
|
|
2036
|
+
if (isEscapeClosed) {
|
|
2037
|
+
setIsEscapeClose(false);
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2040
|
+
break;
|
|
2041
|
+
}
|
|
2042
|
+
};
|
|
2043
|
+
|
|
2044
|
+
return jsxRuntime.jsxs("div", {
|
|
2045
|
+
class: formFieldClasses(type$2, errors),
|
|
2046
|
+
children: [jsxRuntime.jsx(Label, {
|
|
2047
|
+
label: label,
|
|
2048
|
+
id: prefixId(id, formId)
|
|
2049
|
+
}), jsxRuntime.jsxs("div", {
|
|
2050
|
+
class: classNames__default['default']('fjs-taglist', {
|
|
2051
|
+
'disabled': disabled
|
|
2052
|
+
}),
|
|
2053
|
+
children: [!disabled && loadState === LOAD_STATES.LOADED && values.map(v => {
|
|
2054
|
+
return jsxRuntime.jsxs("div", {
|
|
2055
|
+
class: "fjs-taglist-tag",
|
|
2056
|
+
onMouseDown: e => e.preventDefault(),
|
|
2057
|
+
children: [jsxRuntime.jsx("span", {
|
|
2058
|
+
class: "fjs-taglist-tag-label",
|
|
2059
|
+
children: valueToOptionMap[v] ? valueToOptionMap[v].label : `unexpected value{${v}}`
|
|
2060
|
+
}), jsxRuntime.jsx("span", {
|
|
2061
|
+
class: "fjs-taglist-tag-remove",
|
|
2062
|
+
onMouseDown: () => deselectValue(v),
|
|
2063
|
+
children: jsxRuntime.jsx(CloseIcon, {})
|
|
2064
|
+
})]
|
|
2065
|
+
});
|
|
2066
|
+
}), jsxRuntime.jsx("input", {
|
|
2067
|
+
disabled: disabled,
|
|
2068
|
+
class: "fjs-taglist-input",
|
|
2069
|
+
ref: searchbarRef,
|
|
2070
|
+
id: prefixId(`${id}-search`, formId),
|
|
2071
|
+
onChange: onFilterChange,
|
|
2072
|
+
type: "text",
|
|
2073
|
+
value: filter,
|
|
2074
|
+
placeholder: 'Search',
|
|
2075
|
+
autoComplete: "off",
|
|
2076
|
+
onKeyDown: e => onInputKeyDown(e),
|
|
2077
|
+
onMouseDown: () => setIsEscapeClose(false),
|
|
2078
|
+
onFocus: () => setIsDropdownExpanded(true),
|
|
2079
|
+
onBlur: () => {
|
|
2080
|
+
setIsDropdownExpanded(false);
|
|
2081
|
+
setFilter('');
|
|
2082
|
+
}
|
|
2083
|
+
})]
|
|
2084
|
+
}), jsxRuntime.jsx("div", {
|
|
2085
|
+
class: "fjs-taglist-anchor",
|
|
2086
|
+
children: !disabled && loadState === LOAD_STATES.LOADED && isDropdownExpanded && !isEscapeClosed && jsxRuntime.jsx(DropdownList, {
|
|
2087
|
+
values: filteredOptions,
|
|
2088
|
+
getLabel: o => o.label,
|
|
2089
|
+
onValueSelected: o => selectValue(o.value),
|
|
2090
|
+
emptyListMessage: hasOptionsLeft ? 'No results' : 'All values selected',
|
|
2091
|
+
listenerElement: searchbarRef.current
|
|
2092
|
+
})
|
|
2093
|
+
}), jsxRuntime.jsx(Description, {
|
|
2094
|
+
description: description
|
|
2095
|
+
}), jsxRuntime.jsx(Errors, {
|
|
2096
|
+
errors: errors
|
|
2097
|
+
})]
|
|
2098
|
+
});
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
Taglist.create = function (options = {}) {
|
|
2102
|
+
if (options.valuesKey) return options;
|
|
2103
|
+
return {
|
|
2104
|
+
values: [{
|
|
2105
|
+
label: 'Value',
|
|
2106
|
+
value: 'value'
|
|
2107
|
+
}],
|
|
2108
|
+
...options
|
|
2109
|
+
};
|
|
2110
|
+
};
|
|
2111
|
+
|
|
2112
|
+
Taglist.type = type$2;
|
|
2113
|
+
Taglist.label = 'Taglist';
|
|
2114
|
+
Taglist.keyed = true;
|
|
2115
|
+
Taglist.emptyValue = [];
|
|
2116
|
+
Taglist.sanitizeValue = sanitizeMultiSelectValue;
|
|
1581
2117
|
|
|
1582
2118
|
const type$1 = 'text';
|
|
1583
2119
|
function Text(props) {
|
|
@@ -1667,7 +2203,11 @@ Textfield.label = 'Text Field';
|
|
|
1667
2203
|
Textfield.keyed = true;
|
|
1668
2204
|
Textfield.emptyValue = '';
|
|
1669
2205
|
|
|
1670
|
-
|
|
2206
|
+
Textfield.sanitizeValue = ({
|
|
2207
|
+
value
|
|
2208
|
+
}) => minDash.isArray(value) || minDash.isObject(value) ? null : String(value);
|
|
2209
|
+
|
|
2210
|
+
const formFields = [Button, Checkbox, Checklist, Default, Number, Radio, Select, Taglist, Text, Textfield];
|
|
1671
2211
|
|
|
1672
2212
|
class FormFields {
|
|
1673
2213
|
constructor() {
|
|
@@ -2154,7 +2694,7 @@ class Form {
|
|
|
2154
2694
|
|
|
2155
2695
|
}
|
|
2156
2696
|
|
|
2157
|
-
const schemaVersion =
|
|
2697
|
+
const schemaVersion = 5;
|
|
2158
2698
|
/**
|
|
2159
2699
|
* @typedef { import('./types').CreateFormOptions } CreateFormOptions
|
|
2160
2700
|
*/
|
|
@@ -2181,6 +2721,7 @@ function createForm(options) {
|
|
|
2181
2721
|
|
|
2182
2722
|
exports.Button = Button;
|
|
2183
2723
|
exports.Checkbox = Checkbox;
|
|
2724
|
+
exports.Checklist = Checklist;
|
|
2184
2725
|
exports.Default = Default;
|
|
2185
2726
|
exports.Form = Form;
|
|
2186
2727
|
exports.FormComponent = FormComponent;
|
|
@@ -2191,6 +2732,7 @@ exports.FormRenderContext = FormRenderContext;
|
|
|
2191
2732
|
exports.Number = Number;
|
|
2192
2733
|
exports.Radio = Radio;
|
|
2193
2734
|
exports.Select = Select;
|
|
2735
|
+
exports.Taglist = Taglist;
|
|
2194
2736
|
exports.Text = Text;
|
|
2195
2737
|
exports.Textfield = Textfield;
|
|
2196
2738
|
exports.clone = clone;
|
|
@@ -2201,6 +2743,7 @@ exports.findErrors = findErrors;
|
|
|
2201
2743
|
exports.formFields = formFields;
|
|
2202
2744
|
exports.generateIdForType = generateIdForType;
|
|
2203
2745
|
exports.generateIndexForType = generateIndexForType;
|
|
2746
|
+
exports.getSchemaVariables = getSchemaVariables;
|
|
2204
2747
|
exports.isRequired = isRequired;
|
|
2205
2748
|
exports.pathParse = pathParse;
|
|
2206
2749
|
exports.pathStringify = pathStringify;
|