@bpmn-io/form-js-editor 0.11.1 → 0.12.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/dist/index.es.js CHANGED
@@ -1,15 +1,15 @@
1
- import { FormFieldRegistry as FormFieldRegistry$1, clone, FormContext, FormRenderContext, FormComponent, iconsByType, FormFields, getSchemaVariables, Default, DATETIME_SUBTYPES, DATE_LABEL_PATH, TIME_LABEL_PATH, DATETIME_SUBTYPE_PATH, DATETIME_SUBTYPES_LABELS, TIME_SERIALISING_FORMAT_PATH, TIME_SERIALISING_FORMATS, TIME_INTERVAL_PATH, TIME_USE24H_PATH, DATE_DISALLOW_PAST_PATH, TIME_SERIALISINGFORMAT_LABELS, getValuesSource, VALUES_SOURCES, VALUES_SOURCES_DEFAULTS, VALUES_SOURCES_PATHS, VALUES_SOURCES_LABELS, createFormContainer, createInjector, schemaVersion } from '@bpmn-io/form-js-viewer';
1
+ import { FormFieldRegistry as FormFieldRegistry$1, clone, iconsByType, isExpression, Text as Text$1, FormFields, formFields, FormContext, FormRenderContext, FormComponent, getSchemaVariables, Default, DATETIME_SUBTYPES, DATE_LABEL_PATH, TIME_LABEL_PATH, DATETIME_SUBTYPE_PATH, DATETIME_SUBTYPES_LABELS, TIME_SERIALISING_FORMAT_PATH, TIME_SERIALISING_FORMATS, TIME_INTERVAL_PATH, TIME_USE24H_PATH, DATE_DISALLOW_PAST_PATH, TIME_SERIALISINGFORMAT_LABELS, getValuesSource, VALUES_SOURCES, VALUES_SOURCES_DEFAULTS, VALUES_SOURCES_PATHS, VALUES_SOURCES_LABELS, createFormContainer, createInjector, schemaVersion } from '@bpmn-io/form-js-viewer';
2
2
  export { schemaVersion } from '@bpmn-io/form-js-viewer';
3
3
  import Ids from 'ids';
4
- import { isArray, isFunction, isNumber, bind, assign, debounce, forEach, get, isObject, uniqueBy, sortBy, find, set, isUndefined, without, has, isString } from 'min-dash';
4
+ import { isArray, isFunction, isNumber, bind, assign, debounce, forEach, get, isObject, uniqueBy, sortBy, find, set as set$1, isUndefined, without, has, isString } from 'min-dash';
5
+ import classnames from 'classnames';
6
+ import { jsx, jsxs } from 'preact/jsx-runtime';
5
7
  import { createContext, render, createElement } from 'preact';
6
- import { useContext, useRef, useState, useEffect, useCallback, useMemo, useLayoutEffect } from 'preact/hooks';
8
+ import { useContext, useState, useRef, useEffect, useCallback, useMemo, useLayoutEffect } from 'preact/hooks';
7
9
  import dragula from 'dragula';
8
- import { jsxs, jsx } from 'preact/jsx-runtime';
9
10
  import React, { forwardRef } from 'preact/compat';
10
- import { matches, closest, event, domify, query } from 'min-dom';
11
+ import { classes, closest, event, matches, domify, query } from 'min-dom';
11
12
  import { mutate } from 'array-move';
12
- import classnames from 'classnames';
13
13
  import FeelEditor from '@bpmn-io/feel-editor';
14
14
  import Big from 'big.js';
15
15
 
@@ -671,9 +671,98 @@ var importModule = {
671
671
  importer: ['type', Importer]
672
672
  };
673
673
 
674
+ function editorFormFieldClasses(type, {
675
+ disabled = false
676
+ } = {}) {
677
+ if (!type) {
678
+ throw new Error('type required');
679
+ }
680
+ return classnames('fjs-form-field', `fjs-form-field-${type}`, {
681
+ 'fjs-disabled': disabled
682
+ });
683
+ }
684
+
685
+ function _extends$2() { _extends$2 = 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$2.apply(this, arguments); }
686
+ var CloseIcon = (({
687
+ styles = {},
688
+ ...props
689
+ }) => /*#__PURE__*/React.createElement("svg", _extends$2({
690
+ width: "16",
691
+ height: "16",
692
+ fill: "currentColor",
693
+ xmlns: "http://www.w3.org/2000/svg"
694
+ }, props), /*#__PURE__*/React.createElement("path", {
695
+ fillRule: "evenodd",
696
+ clipRule: "evenodd",
697
+ 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"
698
+ })));
699
+
700
+ 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); }
701
+ var SearchIcon = (({
702
+ styles = {},
703
+ ...props
704
+ }) => /*#__PURE__*/React.createElement("svg", _extends$1({
705
+ width: "15",
706
+ height: "15",
707
+ fill: "none",
708
+ xmlns: "http://www.w3.org/2000/svg"
709
+ }, props), /*#__PURE__*/React.createElement("path", {
710
+ d: "M14.5 13.793l-3.776-3.776a5.508 5.508 0 10-.707.707l3.776 3.776.707-.707zM2 6.5a4.5 4.5 0 119 0 4.5 4.5 0 01-9 0z",
711
+ fill: "currentColor"
712
+ })));
713
+
714
+ function EditorText(props) {
715
+ const {
716
+ type,
717
+ text = ''
718
+ } = props.field;
719
+ const Icon = iconsByType['text'];
720
+ if (!text) {
721
+ return jsx("div", {
722
+ class: editorFormFieldClasses(type),
723
+ children: jsxs("div", {
724
+ class: "fjs-form-field-placeholder",
725
+ children: [jsx(Icon, {
726
+ viewBox: "0 0 54 54"
727
+ }), "Text view is empty"]
728
+ })
729
+ });
730
+ }
731
+ if (isExpression(text)) {
732
+ return jsx("div", {
733
+ class: editorFormFieldClasses(type),
734
+ children: jsxs("div", {
735
+ class: "fjs-form-field-placeholder",
736
+ children: [jsx(Icon, {
737
+ viewBox: "0 0 54 54"
738
+ }), "Text view is populated by an expression"]
739
+ })
740
+ });
741
+ }
742
+ return jsx(Text$1, {
743
+ ...props,
744
+ disableLinks: true
745
+ });
746
+ }
747
+ EditorText.create = Text$1.create;
748
+ EditorText.type = Text$1.type;
749
+ EditorText.keyed = Text$1.keyed;
750
+
751
+ const editorFormFields = [EditorText];
752
+
753
+ class EditorFormFields extends FormFields {
754
+ constructor() {
755
+ super();
756
+ editorFormFields.forEach(formField => {
757
+ this.register(formField.type, formField);
758
+ });
759
+ }
760
+ }
761
+
674
762
  const DragAndDropContext = createContext({
675
763
  drake: null
676
764
  });
765
+ var DragAndDropContext$1 = DragAndDropContext;
677
766
 
678
767
  /**
679
768
  * @param {string} type
@@ -685,11 +774,12 @@ function getService$1(type, strict) {}
685
774
  const FormEditorContext = createContext({
686
775
  getService: getService$1
687
776
  });
777
+ var FormEditorContext$1 = FormEditorContext;
688
778
 
689
779
  function useService$1 (type, strict) {
690
780
  const {
691
781
  getService
692
- } = useContext(FormEditorContext);
782
+ } = useContext(FormEditorContext$1);
693
783
  return getService(type, strict);
694
784
  }
695
785
 
@@ -705,6 +795,149 @@ var ListDeleteIcon = (({
705
795
  d: "M10 4v8c0 1.1-.9 2-2 2H3c-1.1 0-2-.9-2-2V4h9zM8 6H3v4.8c0 .66.5 1.2 1.111 1.2H6.89C7.5 12 8 11.46 8 10.8V6zm3-5H8.5l-1-1h-4l-1 1H0v1.5h11V1z"
706
796
  })));
707
797
 
798
+ const PALETTE_ENTRIES = formFields.filter(f => f.type !== 'default').map(f => {
799
+ return {
800
+ label: f.label,
801
+ type: f.type,
802
+ group: f.group
803
+ };
804
+ });
805
+ const PALETTE_GROUPS = [{
806
+ label: 'Basic input',
807
+ id: 'basic-input'
808
+ }, {
809
+ label: 'Selection',
810
+ id: 'selection'
811
+ }, {
812
+ label: 'Presentation',
813
+ id: 'presentation'
814
+ }, {
815
+ label: 'Action',
816
+ id: 'action'
817
+ }];
818
+ function Palette(props) {
819
+ const [entries, setEntries] = useState(PALETTE_ENTRIES);
820
+ const [searchTerm, setSearchTerm] = useState('');
821
+ const inputRef = useRef();
822
+ const groups = groupEntries(entries);
823
+
824
+ // filter entries on search change
825
+ useEffect(() => {
826
+ const filter = entry => {
827
+ if (!searchTerm) {
828
+ return true;
829
+ }
830
+ const search = entry.label.toLowerCase();
831
+ return searchTerm.toLowerCase().split(/\s/g).every(term => search.includes(term));
832
+ };
833
+ const entries = PALETTE_ENTRIES.filter(filter);
834
+ setEntries(entries);
835
+ }, [searchTerm]);
836
+ const handleInput = useCallback(event => {
837
+ setSearchTerm(() => event.target.value);
838
+ }, [setSearchTerm]);
839
+ const handleClear = useCallback(event => {
840
+ setSearchTerm('');
841
+ inputRef.current.focus();
842
+ }, [inputRef, setSearchTerm]);
843
+ return jsxs("div", {
844
+ class: "fjs-palette",
845
+ children: [jsx("div", {
846
+ class: "fjs-palette-header",
847
+ title: "Components",
848
+ children: "Components"
849
+ }), jsxs("div", {
850
+ class: "fjs-palette-search-container",
851
+ children: [jsx("span", {
852
+ class: "fjs-palette-search-icon",
853
+ children: jsx(SearchIcon, {})
854
+ }), jsx("input", {
855
+ class: "fjs-palette-search",
856
+ ref: inputRef,
857
+ type: "text",
858
+ placeholder: "Search components",
859
+ value: searchTerm,
860
+ onInput: handleInput
861
+ }), searchTerm && jsx("button", {
862
+ title: "Clear content",
863
+ class: "fjs-palette-search-clear",
864
+ onClick: handleClear,
865
+ children: jsx(CloseIcon, {})
866
+ })]
867
+ }), jsxs("div", {
868
+ class: "fjs-palette-entries",
869
+ children: [groups.map(({
870
+ label,
871
+ entries,
872
+ id
873
+ }) => jsxs("div", {
874
+ class: "fjs-palette-group",
875
+ "data-group-id": id,
876
+ children: [jsx("span", {
877
+ class: "fjs-palette-group-title",
878
+ children: label
879
+ }), jsx("div", {
880
+ class: "fjs-palette-fields fjs-drag-container fjs-no-drop",
881
+ children: entries.map(({
882
+ label,
883
+ type
884
+ }) => {
885
+ const Icon = iconsByType[type];
886
+ return jsxs("div", {
887
+ class: "fjs-palette-field fjs-drag-copy fjs-no-drop",
888
+ "data-field-type": type,
889
+ title: `Create a ${label} element`,
890
+ children: [Icon ? jsx(Icon, {
891
+ class: "fjs-palette-field-icon",
892
+ width: "36",
893
+ height: "36",
894
+ viewBox: "0 0 54 54"
895
+ }) : null, jsx("span", {
896
+ class: "fjs-palette-field-text",
897
+ children: label
898
+ })]
899
+ });
900
+ })
901
+ })]
902
+ })), groups.length == 0 && jsx("div", {
903
+ class: "fjs-palette-no-entries",
904
+ children: "No components found."
905
+ })]
906
+ })]
907
+ });
908
+ }
909
+
910
+ // helpers ///////
911
+
912
+ function groupEntries(entries) {
913
+ const groups = PALETTE_GROUPS.map(group => {
914
+ return {
915
+ ...group,
916
+ entries: []
917
+ };
918
+ });
919
+ const getGroup = id => groups.find(group => id === group.id);
920
+ entries.forEach(entry => {
921
+ const {
922
+ group
923
+ } = entry;
924
+ getGroup(group).entries.push(entry);
925
+ });
926
+ return groups.filter(g => g.entries.length);
927
+ }
928
+
929
+ const CURSOR_CLS_PATTERN = /^fjs-cursor-.*$/;
930
+ function set(mode) {
931
+ const classes$1 = classes(document.body);
932
+ classes$1.removeMatching(CURSOR_CLS_PATTERN);
933
+ if (mode) {
934
+ classes$1.add('fjs-cursor-' + mode);
935
+ }
936
+ }
937
+ function unset() {
938
+ set(null);
939
+ }
940
+
708
941
  function ContextPad(props) {
709
942
  if (!props.children) {
710
943
  return null;
@@ -828,6 +1061,9 @@ function FormEditor$1(props) {
828
1061
  drake
829
1062
  };
830
1063
  useEffect(() => {
1064
+ const handleDragEvent = (type, context) => {
1065
+ return eventBus.fire(type, context);
1066
+ };
831
1067
  const createDragulaInstance = () => {
832
1068
  const dragulaInstance = dragula({
833
1069
  isContainer(el) {
@@ -842,6 +1078,56 @@ function FormEditor$1(props) {
842
1078
  slideFactorX: 10,
843
1079
  slideFactorY: 5
844
1080
  });
1081
+
1082
+ // bind life cycle events
1083
+ dragulaInstance.on('drag', (element, source) => {
1084
+ handleDragEvent('drag.start', {
1085
+ element,
1086
+ source
1087
+ });
1088
+ });
1089
+ dragulaInstance.on('dragend', element => {
1090
+ handleDragEvent('drag.end', {
1091
+ element
1092
+ });
1093
+ });
1094
+ dragulaInstance.on('drop', (element, target, source, sibling) => {
1095
+ handleDragEvent('drag.drop', {
1096
+ element,
1097
+ target,
1098
+ source,
1099
+ sibling
1100
+ });
1101
+ });
1102
+ dragulaInstance.on('over', (element, container, source) => {
1103
+ handleDragEvent('drag.hover', {
1104
+ element,
1105
+ container,
1106
+ source
1107
+ });
1108
+ });
1109
+ dragulaInstance.on('out', (element, container, source) => {
1110
+ handleDragEvent('drag.out', {
1111
+ element,
1112
+ container,
1113
+ source
1114
+ });
1115
+ });
1116
+ dragulaInstance.on('cancel', (element, container, source) => {
1117
+ handleDragEvent('drag.cancel', {
1118
+ element,
1119
+ container,
1120
+ source
1121
+ });
1122
+ });
1123
+
1124
+ // set custom styling
1125
+ dragulaInstance.on('drag', () => {
1126
+ set('grabbing');
1127
+ });
1128
+ dragulaInstance.on('dragend', () => {
1129
+ unset();
1130
+ });
845
1131
  dragulaInstance.on('drop', (el, target, source, sibling) => {
846
1132
  dragulaInstance.remove();
847
1133
  if (!target) {
@@ -898,9 +1184,7 @@ function FormEditor$1(props) {
898
1184
  const formContext = {
899
1185
  getService(type, strict = true) {
900
1186
  // TODO(philippfromme): clean up
901
- if (type === 'formFieldRegistry') {
902
- return new Map();
903
- } else if (type === 'form') {
1187
+ if (type === 'form') {
904
1188
  return {
905
1189
  _getState() {
906
1190
  return {
@@ -938,7 +1222,7 @@ function FormEditor$1(props) {
938
1222
  }, [propertiesPanelRef, propertiesPanel, hasDefaultPropertiesPanel]);
939
1223
  return jsxs("div", {
940
1224
  class: "fjs-form-editor",
941
- children: [jsxs(DragAndDropContext.Provider, {
1225
+ children: [jsxs(DragAndDropContext$1.Provider, {
942
1226
  value: dragAndDropContext,
943
1227
  children: [hasDefaultPalette && jsx("div", {
944
1228
  class: "fjs-editor-palette-container",
@@ -976,14 +1260,32 @@ function getFormFieldIndex(parent, formField) {
976
1260
  function CreatePreview(props) {
977
1261
  const {
978
1262
  drake
979
- } = useContext(DragAndDropContext);
1263
+ } = useContext(DragAndDropContext$1);
980
1264
  function handleCloned(clone, original, type) {
981
1265
  const fieldType = clone.dataset.fieldType;
982
1266
  const Icon = iconsByType[fieldType];
1267
+ const {
1268
+ label
1269
+ } = findPaletteEntry(fieldType);
983
1270
  if (fieldType) {
984
1271
  clone.innerHTML = '';
985
1272
  clone.class = 'gu-mirror';
986
- render(jsx(Icon, {}), clone);
1273
+ if (original.classList.contains('fjs-palette-field')) {
1274
+ render(jsxs("div", {
1275
+ class: "fjs-palette-field",
1276
+ children: [jsx(Icon, {
1277
+ class: "fjs-palette-field-icon",
1278
+ width: "36",
1279
+ height: "36",
1280
+ viewBox: "0 0 54 54"
1281
+ }), jsx("span", {
1282
+ class: "fjs-palette-field-text",
1283
+ children: label
1284
+ })]
1285
+ }), clone);
1286
+ } else {
1287
+ render(jsx(Icon, {}), clone);
1288
+ }
987
1289
  }
988
1290
  }
989
1291
  useEffect(() => {
@@ -1004,6 +1306,9 @@ function defaultPalette(paletteConfig) {
1004
1306
  function defaultPropertiesPanel(propertiesPanelConfig) {
1005
1307
  return !(propertiesPanelConfig && propertiesPanelConfig.parent);
1006
1308
  }
1309
+ function findPaletteEntry(type) {
1310
+ return PALETTE_ENTRIES.find(entry => entry.type === type);
1311
+ }
1007
1312
 
1008
1313
  class Renderer {
1009
1314
  constructor(renderConfig, eventBus, formEditor, injector) {
@@ -1029,7 +1334,7 @@ class Renderer {
1029
1334
  }
1030
1335
  return jsx("div", {
1031
1336
  class: `fjs-container fjs-editor-container ${compact ? 'fjs-editor-compact' : ''}`,
1032
- children: jsx(FormEditorContext.Provider, {
1337
+ children: jsx(FormEditorContext$1.Provider, {
1033
1338
  value: formEditorContext,
1034
1339
  children: jsx(FormEditor$1, {})
1035
1340
  })
@@ -1047,7 +1352,7 @@ Renderer.$inject = ['config.renderer', 'eventBus', 'formEditor', 'injector'];
1047
1352
 
1048
1353
  var renderModule = {
1049
1354
  __init__: ['formFields', 'renderer'],
1050
- formFields: ['type', FormFields],
1355
+ formFields: ['type', EditorFormFields],
1051
1356
  renderer: ['type', Renderer]
1052
1357
  };
1053
1358
 
@@ -2898,79 +3203,6 @@ var SelectionModule = {
2898
3203
  selectionBehavior: ['type', SelectionBehavior]
2899
3204
  };
2900
3205
 
2901
- const types = [{
2902
- label: 'Text field',
2903
- type: 'textfield'
2904
- }, {
2905
- label: 'Text area',
2906
- type: 'textarea'
2907
- }, {
2908
- label: 'Number',
2909
- type: 'number'
2910
- }, {
2911
- label: 'Datetime',
2912
- type: 'datetime'
2913
- }, {
2914
- label: 'Checkbox',
2915
- type: 'checkbox'
2916
- }, {
2917
- label: 'Checklist',
2918
- type: 'checklist'
2919
- }, {
2920
- label: 'Taglist',
2921
- type: 'taglist'
2922
- }, {
2923
- label: 'Radio',
2924
- type: 'radio'
2925
- }, {
2926
- label: 'Select',
2927
- type: 'select'
2928
- }, {
2929
- label: 'Text view',
2930
- type: 'text'
2931
- }, {
2932
- label: 'Image view',
2933
- type: 'image'
2934
- }, {
2935
- label: 'Button',
2936
- type: 'button'
2937
- }];
2938
- function Palette(props) {
2939
- return jsxs("div", {
2940
- class: "fjs-palette",
2941
- children: [jsxs("div", {
2942
- class: "fjs-palette-header",
2943
- title: "Form elements library",
2944
- children: [jsx("span", {
2945
- class: "fjs-hide-compact",
2946
- children: "FORM ELEMENTS "
2947
- }), "LIBRARY"]
2948
- }), jsx("div", {
2949
- class: "fjs-palette-fields fjs-drag-container fjs-no-drop",
2950
- children: types.map(({
2951
- label,
2952
- type
2953
- }) => {
2954
- const Icon = iconsByType[type];
2955
- return jsxs("div", {
2956
- class: "fjs-palette-field fjs-drag-copy fjs-no-drop",
2957
- "data-field-type": type,
2958
- title: `Create a ${label} element`,
2959
- children: [Icon ? jsx(Icon, {
2960
- class: "fjs-palette-field-icon",
2961
- width: "36",
2962
- height: "36",
2963
- viewBox: "0 0 54 54"
2964
- }) : null, jsx("span", {
2965
- class: "fjs-palette-field-text",
2966
- children: label
2967
- })]
2968
- });
2969
- })
2970
- })]
2971
- });
2972
- }
2973
-
2974
3206
  class PaletteRenderer {
2975
3207
  constructor(paletteConfig, eventBus) {
2976
3208
  const {
@@ -3192,19 +3424,19 @@ const ErrorsContext = createContext({
3192
3424
  errors: {}
3193
3425
  });
3194
3426
 
3195
- /**
3196
- * @typedef {Function} <propertiesPanel.showEntry> callback
3197
- *
3198
- * @example
3199
- *
3200
- * useEvent('propertiesPanel.showEntry', ({ focus = false, ...rest }) => {
3201
- * // ...
3202
- * });
3203
- *
3204
- * @param {Object} context
3205
- * @param {boolean} [context.focus]
3206
- *
3207
- * @returns void
3427
+ /**
3428
+ * @typedef {Function} <propertiesPanel.showEntry> callback
3429
+ *
3430
+ * @example
3431
+ *
3432
+ * useEvent('propertiesPanel.showEntry', ({ focus = false, ...rest }) => {
3433
+ * // ...
3434
+ * });
3435
+ *
3436
+ * @param {Object} context
3437
+ * @param {boolean} [context.focus]
3438
+ *
3439
+ * @returns void
3208
3440
  */
3209
3441
  const EventContext = createContext({
3210
3442
  eventBus: null
@@ -3216,20 +3448,20 @@ const LayoutContext = createContext({
3216
3448
  setLayoutForKey: () => {}
3217
3449
  });
3218
3450
 
3219
- /**
3220
- * Accesses the global DescriptionContext and returns a description for a given id and element.
3221
- *
3222
- * @example
3223
- * ```jsx
3224
- * function TextField(props) {
3225
- * const description = useDescriptionContext('input1', element);
3226
- * }
3227
- * ```
3228
- *
3229
- * @param {string} id
3230
- * @param {object} element
3231
- *
3232
- * @returns {string}
3451
+ /**
3452
+ * Accesses the global DescriptionContext and returns a description for a given id and element.
3453
+ *
3454
+ * @example
3455
+ * ```jsx
3456
+ * function TextField(props) {
3457
+ * const description = useDescriptionContext('input1', element);
3458
+ * }
3459
+ * ```
3460
+ *
3461
+ * @param {string} id
3462
+ * @param {object} element
3463
+ *
3464
+ * @returns {string}
3233
3465
  */
3234
3466
  function useDescriptionContext(id, element) {
3235
3467
  const {
@@ -3244,11 +3476,11 @@ function useError(id) {
3244
3476
  return errors[id];
3245
3477
  }
3246
3478
 
3247
- /**
3248
- * Subscribe to an event immediately. Update subscription after inputs changed.
3249
- *
3250
- * @param {string} event
3251
- * @param {Function} callback
3479
+ /**
3480
+ * Subscribe to an event immediately. Update subscription after inputs changed.
3481
+ *
3482
+ * @param {string} event
3483
+ * @param {Function} callback
3252
3484
  */
3253
3485
  function useEvent(event, callback, eventBus) {
3254
3486
  const eventContext = useContext(EventContext);
@@ -3278,20 +3510,20 @@ function useEvent(event, callback, eventBus) {
3278
3510
  }, [callback, event, eventBus]);
3279
3511
  }
3280
3512
 
3281
- /**
3282
- * Creates a state that persists in the global LayoutContext.
3283
- *
3284
- * @example
3285
- * ```jsx
3286
- * function Group(props) {
3287
- * const [ open, setOpen ] = useLayoutState([ 'groups', 'foo', 'open' ], false);
3288
- * }
3289
- * ```
3290
- *
3291
- * @param {(string|number)[]} path
3292
- * @param {any} [defaultValue]
3293
- *
3294
- * @returns {[ any, Function ]}
3513
+ /**
3514
+ * Creates a state that persists in the global LayoutContext.
3515
+ *
3516
+ * @example
3517
+ * ```jsx
3518
+ * function Group(props) {
3519
+ * const [ open, setOpen ] = useLayoutState([ 'groups', 'foo', 'open' ], false);
3520
+ * }
3521
+ * ```
3522
+ *
3523
+ * @param {(string|number)[]} path
3524
+ * @param {any} [defaultValue]
3525
+ *
3526
+ * @returns {[ any, Function ]}
3295
3527
  */
3296
3528
  function useLayoutState(path, defaultValue) {
3297
3529
  const {
@@ -3310,11 +3542,11 @@ function useLayoutState(path, defaultValue) {
3310
3542
  return [value, setState];
3311
3543
  }
3312
3544
 
3313
- /**
3314
- * @pinussilvestrus: we need to introduce our own hook to persist the previous
3315
- * state on updates.
3316
- *
3317
- * cf. https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
3545
+ /**
3546
+ * @pinussilvestrus: we need to introduce our own hook to persist the previous
3547
+ * state on updates.
3548
+ *
3549
+ * cf. https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
3318
3550
  */
3319
3551
 
3320
3552
  function usePrevious(value) {
@@ -3325,12 +3557,12 @@ function usePrevious(value) {
3325
3557
  return ref.current;
3326
3558
  }
3327
3559
 
3328
- /**
3329
- * Subscribe to `propertiesPanel.showEntry`.
3330
- *
3331
- * @param {string} id
3332
- *
3333
- * @returns {import('preact').Ref}
3560
+ /**
3561
+ * Subscribe to `propertiesPanel.showEntry`.
3562
+ *
3563
+ * @param {string} id
3564
+ *
3565
+ * @returns {import('preact').Ref}
3334
3566
  */
3335
3567
  function useShowEntryEvent(id) {
3336
3568
  const {
@@ -3361,20 +3593,20 @@ function useShowEntryEvent(id) {
3361
3593
  return ref;
3362
3594
  }
3363
3595
 
3364
- /**
3365
- * @callback setSticky
3366
- * @param {boolean} value
3596
+ /**
3597
+ * @callback setSticky
3598
+ * @param {boolean} value
3367
3599
  */
3368
3600
 
3369
- /**
3370
- * Use IntersectionObserver to identify when DOM element is in sticky mode.
3371
- * If sticky is observered setSticky(true) will be called.
3372
- * If sticky mode is left, setSticky(false) will be called.
3373
- *
3374
- *
3375
- * @param {Object} ref
3376
- * @param {string} scrollContainerSelector
3377
- * @param {setSticky} setSticky
3601
+ /**
3602
+ * Use IntersectionObserver to identify when DOM element is in sticky mode.
3603
+ * If sticky is observered setSticky(true) will be called.
3604
+ * If sticky mode is left, setSticky(false) will be called.
3605
+ *
3606
+ *
3607
+ * @param {Object} ref
3608
+ * @param {string} scrollContainerSelector
3609
+ * @param {setSticky} setSticky
3378
3610
  */
3379
3611
  function useStickyIntersectionObserver(ref, scrollContainerSelector, setSticky) {
3380
3612
  useEffect(() => {
@@ -3413,19 +3645,19 @@ function useStickyIntersectionObserver(ref, scrollContainerSelector, setSticky)
3413
3645
  }, [ref, scrollContainerSelector, setSticky]);
3414
3646
  }
3415
3647
 
3416
- /**
3417
- * Creates a static function reference with changing body.
3418
- * This is necessary when external libraries require a callback function
3419
- * that has references to state variables.
3420
- *
3421
- * Usage:
3422
- * const callback = useStaticCallback((val) => {val === currentState});
3423
- *
3424
- * The `callback` reference is static and can be safely used in external
3425
- * libraries or as a prop that does not cause rerendering of children.
3426
- *
3427
- * @param {Function} callback function with changing reference
3428
- * @returns {Function} static function reference
3648
+ /**
3649
+ * Creates a static function reference with changing body.
3650
+ * This is necessary when external libraries require a callback function
3651
+ * that has references to state variables.
3652
+ *
3653
+ * Usage:
3654
+ * const callback = useStaticCallback((val) => {val === currentState});
3655
+ *
3656
+ * The `callback` reference is static and can be safely used in external
3657
+ * libraries or as a prop that does not cause rerendering of children.
3658
+ *
3659
+ * @param {Function} callback function with changing reference
3660
+ * @returns {Function} static function reference
3429
3661
  */
3430
3662
  function useStaticCallback(callback) {
3431
3663
  const callbackRef = useRef(callback);
@@ -3517,13 +3749,13 @@ function DataMarker() {
3517
3749
  });
3518
3750
  }
3519
3751
 
3520
- /**
3521
- * @typedef { {
3522
- * text: (element: object) => string,
3523
- * icon?: (element: Object) => import('preact').Component
3524
- * } } PlaceholderDefinition
3525
- *
3526
- * @param { PlaceholderDefinition } props
3752
+ /**
3753
+ * @typedef { {
3754
+ * text: (element: object) => string,
3755
+ * icon?: (element: Object) => import('preact').Component
3756
+ * } } PlaceholderDefinition
3757
+ *
3758
+ * @param { PlaceholderDefinition } props
3527
3759
  */
3528
3760
  function Placeholder(props) {
3529
3761
  const {
@@ -3548,72 +3780,72 @@ const DEFAULT_LAYOUT = {
3548
3780
  };
3549
3781
  const DEFAULT_DESCRIPTION = {};
3550
3782
 
3551
- /**
3552
- * @typedef { {
3553
- * component: import('preact').Component,
3554
- * id: String,
3555
- * isEdited?: Function
3556
- * } } EntryDefinition
3557
- *
3558
- * @typedef { {
3559
- * autoFocusEntry: String,
3560
- * autoOpen?: Boolean,
3561
- * entries: Array<EntryDefinition>,
3562
- * id: String,
3563
- * label: String,
3564
- * remove: (event: MouseEvent) => void
3565
- * } } ListItemDefinition
3566
- *
3567
- * @typedef { {
3568
- * add: (event: MouseEvent) => void,
3569
- * component: import('preact').Component,
3570
- * element: Object,
3571
- * id: String,
3572
- * items: Array<ListItemDefinition>,
3573
- * label: String,
3574
- * shouldSort?: Boolean,
3575
- * shouldOpen?: Boolean
3576
- * } } ListGroupDefinition
3577
- *
3578
- * @typedef { {
3579
- * component?: import('preact').Component,
3580
- * entries: Array<EntryDefinition>,
3581
- * id: String,
3582
- * label: String,
3583
- * shouldOpen?: Boolean
3584
- * } } GroupDefinition
3585
- *
3586
- * @typedef { {
3587
- * [id: String]: GetDescriptionFunction
3588
- * } } DescriptionConfig
3589
- *
3590
- * @callback { {
3591
- * @param {string} id
3592
- * @param {Object} element
3593
- * @returns {string}
3594
- * } } GetDescriptionFunction
3595
- *
3596
- * @typedef { {
3597
- * getEmpty: (element: object) => import('./components/Placeholder').PlaceholderDefinition,
3598
- * getMultiple: (element: Object) => import('./components/Placeholder').PlaceholderDefinition
3599
- * } } PlaceholderProvider
3600
- *
3783
+ /**
3784
+ * @typedef { {
3785
+ * component: import('preact').Component,
3786
+ * id: String,
3787
+ * isEdited?: Function
3788
+ * } } EntryDefinition
3789
+ *
3790
+ * @typedef { {
3791
+ * autoFocusEntry: String,
3792
+ * autoOpen?: Boolean,
3793
+ * entries: Array<EntryDefinition>,
3794
+ * id: String,
3795
+ * label: String,
3796
+ * remove: (event: MouseEvent) => void
3797
+ * } } ListItemDefinition
3798
+ *
3799
+ * @typedef { {
3800
+ * add: (event: MouseEvent) => void,
3801
+ * component: import('preact').Component,
3802
+ * element: Object,
3803
+ * id: String,
3804
+ * items: Array<ListItemDefinition>,
3805
+ * label: String,
3806
+ * shouldSort?: Boolean,
3807
+ * shouldOpen?: Boolean
3808
+ * } } ListGroupDefinition
3809
+ *
3810
+ * @typedef { {
3811
+ * component?: import('preact').Component,
3812
+ * entries: Array<EntryDefinition>,
3813
+ * id: String,
3814
+ * label: String,
3815
+ * shouldOpen?: Boolean
3816
+ * } } GroupDefinition
3817
+ *
3818
+ * @typedef { {
3819
+ * [id: String]: GetDescriptionFunction
3820
+ * } } DescriptionConfig
3821
+ *
3822
+ * @callback { {
3823
+ * @param {string} id
3824
+ * @param {Object} element
3825
+ * @returns {string}
3826
+ * } } GetDescriptionFunction
3827
+ *
3828
+ * @typedef { {
3829
+ * getEmpty: (element: object) => import('./components/Placeholder').PlaceholderDefinition,
3830
+ * getMultiple: (element: Object) => import('./components/Placeholder').PlaceholderDefinition
3831
+ * } } PlaceholderProvider
3832
+ *
3601
3833
  */
3602
3834
 
3603
- /**
3604
- * A basic properties panel component. Describes *how* content will be rendered, accepts
3605
- * data from implementor to describe *what* will be rendered.
3606
- *
3607
- * @param {Object} props
3608
- * @param {Object|Array} props.element
3609
- * @param {import('./components/Header').HeaderProvider} props.headerProvider
3610
- * @param {PlaceholderProvider} [props.placeholderProvider]
3611
- * @param {Array<GroupDefinition|ListGroupDefinition>} props.groups
3612
- * @param {Object} [props.layoutConfig]
3613
- * @param {Function} [props.layoutChanged]
3614
- * @param {DescriptionConfig} [props.descriptionConfig]
3615
- * @param {Function} [props.descriptionLoaded]
3616
- * @param {Object} [props.eventBus]
3835
+ /**
3836
+ * A basic properties panel component. Describes *how* content will be rendered, accepts
3837
+ * data from implementor to describe *what* will be rendered.
3838
+ *
3839
+ * @param {Object} props
3840
+ * @param {Object|Array} props.element
3841
+ * @param {import('./components/Header').HeaderProvider} props.headerProvider
3842
+ * @param {PlaceholderProvider} [props.placeholderProvider]
3843
+ * @param {Array<GroupDefinition|ListGroupDefinition>} props.groups
3844
+ * @param {Object} [props.layoutConfig]
3845
+ * @param {Function} [props.layoutChanged]
3846
+ * @param {DescriptionConfig} [props.descriptionConfig]
3847
+ * @param {Function} [props.descriptionLoaded]
3848
+ * @param {Object} [props.eventBus]
3617
3849
  */
3618
3850
  function PropertiesPanel(props) {
3619
3851
  const {
@@ -3640,7 +3872,7 @@ function PropertiesPanel(props) {
3640
3872
  };
3641
3873
  const setLayoutForKey = (key, config) => {
3642
3874
  const newLayout = assign({}, layout);
3643
- set(newLayout, key, config);
3875
+ set$1(newLayout, key, config);
3644
3876
  setLayout(newLayout);
3645
3877
  };
3646
3878
  const layoutContext = {
@@ -3838,8 +4070,8 @@ function ListItem(props) {
3838
4070
  }
3839
4071
  const noop$2 = () => {};
3840
4072
 
3841
- /**
3842
- * @param {import('../PropertiesPanel').ListGroupDefinition} props
4073
+ /**
4074
+ * @param {import('../PropertiesPanel').ListGroupDefinition} props
3843
4075
  */
3844
4076
  function ListGroup(props) {
3845
4077
  const {
@@ -4002,8 +4234,8 @@ function ListGroup(props) {
4002
4234
 
4003
4235
  // helpers ////////////////////
4004
4236
 
4005
- /**
4006
- * Sorts given items alphanumeric by label
4237
+ /**
4238
+ * Sorts given items alphanumeric by label
4007
4239
  */
4008
4240
  function sortItems(items) {
4009
4241
  return sortBy(items, i => i.label.toLowerCase());
@@ -4077,17 +4309,17 @@ function Checkbox(props) {
4077
4309
  });
4078
4310
  }
4079
4311
 
4080
- /**
4081
- * @param {Object} props
4082
- * @param {Object} props.element
4083
- * @param {String} props.id
4084
- * @param {String} props.description
4085
- * @param {String} props.label
4086
- * @param {Function} props.getValue
4087
- * @param {Function} props.setValue
4088
- * @param {Function} props.onFocus
4089
- * @param {Function} props.onBlur
4090
- * @param {boolean} [props.disabled]
4312
+ /**
4313
+ * @param {Object} props
4314
+ * @param {Object} props.element
4315
+ * @param {String} props.id
4316
+ * @param {String} props.description
4317
+ * @param {String} props.label
4318
+ * @param {Function} props.getValue
4319
+ * @param {Function} props.setValue
4320
+ * @param {Function} props.onFocus
4321
+ * @param {Function} props.onBlur
4322
+ * @param {boolean} [props.disabled]
4091
4323
  */
4092
4324
  function CheckboxEntry(props) {
4093
4325
  const {
@@ -4175,10 +4407,10 @@ const CodeEditor = forwardRef((props, ref) => {
4175
4407
  useEffect(() => {
4176
4408
  let editor;
4177
4409
 
4178
- /* Trigger FEEL toggle when
4179
- *
4180
- * - `backspace` is pressed
4181
- * - AND the cursor is at the beginning of the input
4410
+ /* Trigger FEEL toggle when
4411
+ *
4412
+ * - `backspace` is pressed
4413
+ * - AND the cursor is at the beginning of the input
4182
4414
  */
4183
4415
  const onKeyDown = e => {
4184
4416
  if (e.key !== 'Backspace' || !editor) {
@@ -4249,10 +4481,10 @@ function FeelIndicator(props) {
4249
4481
  }
4250
4482
  const noop$1 = () => {};
4251
4483
 
4252
- /**
4253
- * @param {Object} props
4254
- * @param {Object} props.label
4255
- * @param {String} props.feel
4484
+ /**
4485
+ * @param {Object} props
4486
+ * @param {Object} props.label
4487
+ * @param {String} props.feel
4256
4488
  */
4257
4489
  function FeelIcon(props) {
4258
4490
  const {
@@ -4526,17 +4758,17 @@ const OptionalFeelTextArea = forwardRef((props, ref) => {
4526
4758
  });
4527
4759
  });
4528
4760
 
4529
- /**
4530
- * @param {Object} props
4531
- * @param {Object} props.element
4532
- * @param {String} props.id
4533
- * @param {String} props.description
4534
- * @param {Boolean} props.debounce
4535
- * @param {Boolean} props.disabled
4536
- * @param {String} props.label
4537
- * @param {Function} props.getValue
4538
- * @param {Function} props.setValue
4539
- * @param {Function} props.validate
4761
+ /**
4762
+ * @param {Object} props
4763
+ * @param {Object} props.element
4764
+ * @param {String} props.id
4765
+ * @param {String} props.description
4766
+ * @param {Boolean} props.debounce
4767
+ * @param {Boolean} props.disabled
4768
+ * @param {String} props.label
4769
+ * @param {Function} props.getValue
4770
+ * @param {Function} props.setValue
4771
+ * @param {Function} props.validate
4540
4772
  */
4541
4773
  function FeelEntry(props) {
4542
4774
  const {
@@ -4621,19 +4853,19 @@ function FeelEntry(props) {
4621
4853
  });
4622
4854
  }
4623
4855
 
4624
- /**
4625
- * @param {Object} props
4626
- * @param {Object} props.element
4627
- * @param {String} props.id
4628
- * @param {String} props.description
4629
- * @param {Boolean} props.debounce
4630
- * @param {Boolean} props.disabled
4631
- * @param {String} props.label
4632
- * @param {Function} props.getValue
4633
- * @param {Function} props.setValue
4634
- * @param {Function} props.onFocus
4635
- * @param {Function} props.onBlur
4636
- * @param {Function} props.validate
4856
+ /**
4857
+ * @param {Object} props
4858
+ * @param {Object} props.element
4859
+ * @param {String} props.id
4860
+ * @param {String} props.description
4861
+ * @param {Boolean} props.debounce
4862
+ * @param {Boolean} props.disabled
4863
+ * @param {String} props.label
4864
+ * @param {Function} props.getValue
4865
+ * @param {Function} props.setValue
4866
+ * @param {Function} props.onFocus
4867
+ * @param {Function} props.onBlur
4868
+ * @param {Function} props.validate
4637
4869
  */
4638
4870
  function FeelTextArea(props) {
4639
4871
  return jsx(FeelEntry, {
@@ -4712,21 +4944,22 @@ function NumberField(props) {
4712
4944
  });
4713
4945
  }
4714
4946
 
4715
- /**
4716
- * @param {Object} props
4717
- * @param {Boolean} props.debounce
4718
- * @param {String} props.description
4719
- * @param {Boolean} props.disabled
4720
- * @param {Object} props.element
4721
- * @param {Function} props.getValue
4722
- * @param {String} props.id
4723
- * @param {String} props.label
4724
- * @param {String} props.max
4725
- * @param {String} props.min
4726
- * @param {Function} props.setValue
4727
- * @param {Function} props.onFocus
4728
- * @param {Function} props.onBlur
4729
- * @param {String} props.step
4947
+ /**
4948
+ * @param {Object} props
4949
+ * @param {Boolean} props.debounce
4950
+ * @param {String} props.description
4951
+ * @param {Boolean} props.disabled
4952
+ * @param {Object} props.element
4953
+ * @param {Function} props.getValue
4954
+ * @param {String} props.id
4955
+ * @param {String} props.label
4956
+ * @param {String} props.max
4957
+ * @param {String} props.min
4958
+ * @param {Function} props.setValue
4959
+ * @param {Function} props.onFocus
4960
+ * @param {Function} props.onBlur
4961
+ * @param {String} props.step
4962
+ * @param {Function} props.validate
4730
4963
  */
4731
4964
  function NumberFieldEntry(props) {
4732
4965
  const {
@@ -4742,25 +4975,55 @@ function NumberFieldEntry(props) {
4742
4975
  setValue,
4743
4976
  step,
4744
4977
  onFocus,
4745
- onBlur
4978
+ onBlur,
4979
+ validate
4746
4980
  } = props;
4747
- const value = getValue(element);
4981
+ const [cachedInvalidValue, setCachedInvalidValue] = useState(null);
4982
+ const globalError = useError(id);
4983
+ const [localError, setLocalError] = useState(null);
4984
+ let value = getValue(element);
4985
+ const previousValue = usePrevious(value);
4986
+ useEffect(() => {
4987
+ if (isFunction(validate)) {
4988
+ const newValidationError = validate(value) || null;
4989
+ setLocalError(newValidationError);
4990
+ }
4991
+ }, [value]);
4992
+ const onInput = newValue => {
4993
+ let newValidationError = null;
4994
+ if (isFunction(validate)) {
4995
+ newValidationError = validate(newValue) || null;
4996
+ }
4997
+ if (newValidationError) {
4998
+ setCachedInvalidValue(newValue);
4999
+ } else {
5000
+ setValue(newValue);
5001
+ }
5002
+ setLocalError(newValidationError);
5003
+ };
5004
+ if (previousValue === value && localError) {
5005
+ value = cachedInvalidValue;
5006
+ }
5007
+ const error = globalError || localError;
4748
5008
  return jsxs("div", {
4749
- class: "bio-properties-panel-entry",
5009
+ class: classnames('bio-properties-panel-entry', error ? 'has-error' : ''),
4750
5010
  "data-entry-id": id,
4751
5011
  children: [jsx(NumberField, {
4752
5012
  debounce: debounce,
4753
5013
  disabled: disabled,
4754
5014
  id: id,
4755
5015
  label: label,
4756
- onInput: setValue,
4757
5016
  onFocus: onFocus,
4758
5017
  onBlur: onBlur,
5018
+ onInput: onInput,
4759
5019
  max: max,
4760
5020
  min: min,
4761
5021
  step: step,
4762
5022
  value: value
4763
- }, element), jsx(Description$1, {
5023
+ }, element), error && jsx("div", {
5024
+ class: "bio-properties-panel-error",
5025
+ children: error
5026
+ }), jsx(Description$1, {
4764
5027
  forId: id,
4765
5028
  element: element,
4766
5029
  value: description
@@ -4782,7 +5045,7 @@ function Select(props) {
4782
5045
  label,
4783
5046
  onChange,
4784
5047
  options = [],
4785
- value,
5048
+ value = '',
4786
5049
  disabled,
4787
5050
  onFocus,
4788
5051
  onBlur
@@ -4831,18 +5094,18 @@ function Select(props) {
4831
5094
  });
4832
5095
  }
4833
5096
 
4834
- /**
4835
- * @param {object} props
4836
- * @param {object} props.element
4837
- * @param {string} props.id
4838
- * @param {string} [props.description]
4839
- * @param {string} props.label
4840
- * @param {Function} props.getValue
4841
- * @param {Function} props.setValue
4842
- * @param {Function} props.onFocus
4843
- * @param {Function} props.onBlur
4844
- * @param {Function} props.getOptions
4845
- * @param {boolean} [props.disabled]
5097
+ /**
5098
+ * @param {object} props
5099
+ * @param {object} props.element
5100
+ * @param {string} props.id
5101
+ * @param {string} [props.description]
5102
+ * @param {string} props.label
5103
+ * @param {Function} props.getValue
5104
+ * @param {Function} props.setValue
5105
+ * @param {Function} props.onFocus
5106
+ * @param {Function} props.onBlur
5107
+ * @param {Function} props.getOptions
5108
+ * @param {boolean} [props.disabled]
4846
5109
  */
4847
5110
  function SelectEntry(props) {
4848
5111
  const {
@@ -4944,20 +5207,20 @@ function TextArea(props) {
4944
5207
  });
4945
5208
  }
4946
5209
 
4947
- /**
4948
- * @param {object} props
4949
- * @param {object} props.element
4950
- * @param {string} props.id
4951
- * @param {string} props.description
4952
- * @param {boolean} props.debounce
4953
- * @param {string} props.label
4954
- * @param {Function} props.getValue
4955
- * @param {Function} props.setValue
4956
- * @param {Function} props.onFocus
4957
- * @param {Function} props.onBlur
4958
- * @param {number} props.rows
4959
- * @param {boolean} props.monospace
4960
- * @param {boolean} [props.disabled]
5210
+ /**
5211
+ * @param {object} props
5212
+ * @param {object} props.element
5213
+ * @param {string} props.id
5214
+ * @param {string} props.description
5215
+ * @param {boolean} props.debounce
5216
+ * @param {string} props.label
5217
+ * @param {Function} props.getValue
5218
+ * @param {Function} props.setValue
5219
+ * @param {Function} props.onFocus
5220
+ * @param {Function} props.onBlur
5221
+ * @param {number} props.rows
5222
+ * @param {boolean} props.monospace
5223
+ * @param {boolean} [props.disabled]
4961
5224
  */
4962
5225
  function TextAreaEntry(props) {
4963
5226
  const {
@@ -5060,19 +5323,19 @@ function Textfield(props) {
5060
5323
  });
5061
5324
  }
5062
5325
 
5063
- /**
5064
- * @param {Object} props
5065
- * @param {Object} props.element
5066
- * @param {String} props.id
5067
- * @param {String} props.description
5068
- * @param {Boolean} props.debounce
5069
- * @param {Boolean} props.disabled
5070
- * @param {String} props.label
5071
- * @param {Function} props.getValue
5072
- * @param {Function} props.setValue
5073
- * @param {Function} props.onFocus
5074
- * @param {Function} props.onBlur
5075
- * @param {Function} props.validate
5326
+ /**
5327
+ * @param {Object} props
5328
+ * @param {Object} props.element
5329
+ * @param {String} props.id
5330
+ * @param {String} props.description
5331
+ * @param {Boolean} props.debounce
5332
+ * @param {Boolean} props.disabled
5333
+ * @param {String} props.label
5334
+ * @param {Function} props.getValue
5335
+ * @param {Function} props.setValue
5336
+ * @param {Function} props.onFocus
5337
+ * @param {Function} props.onBlur
5338
+ * @param {Function} props.validate
5076
5339
  */
5077
5340
  function TextfieldEntry(props) {
5078
5341
  const {
@@ -5157,6 +5420,7 @@ function getService(type, strict) {}
5157
5420
  const PropertiesPanelContext = createContext({
5158
5421
  getService
5159
5422
  });
5423
+ var FormPropertiesPanelContext = PropertiesPanelContext;
5160
5424
 
5161
5425
  function arrayAdd(array, index, item) {
5162
5426
  const copy = [...array];
@@ -5308,7 +5572,7 @@ function Action(props) {
5308
5572
  function useService (type, strict) {
5309
5573
  const {
5310
5574
  getService
5311
- } = useContext(PropertiesPanelContext);
5575
+ } = useContext(FormPropertiesPanelContext);
5312
5576
  return getService(type, strict);
5313
5577
  }
5314
5578
 
@@ -5923,6 +6187,46 @@ const SimpleStringComponent = props => {
5923
6187
  });
5924
6188
  };
5925
6189
 
6190
+ function simpleBoolEntryFactory(options) {
6191
+ const {
6192
+ id,
6193
+ label,
6194
+ path,
6195
+ props
6196
+ } = options;
6197
+ const {
6198
+ editField,
6199
+ field
6200
+ } = props;
6201
+ return {
6202
+ id,
6203
+ label,
6204
+ path,
6205
+ field,
6206
+ editField,
6207
+ component: SimpleBoolComponent,
6208
+ isEdited: isEdited$7
6209
+ };
6210
+ }
6211
+ const SimpleBoolComponent = props => {
6212
+ const {
6213
+ id,
6214
+ label,
6215
+ path,
6216
+ field,
6217
+ editField
6218
+ } = props;
6219
+ const getValue = () => get(field, path, '');
6220
+ const setValue = value => editField(field, path, value);
6221
+ return CheckboxEntry({
6222
+ element: field,
6223
+ getValue,
6224
+ id,
6225
+ label,
6226
+ setValue
6227
+ });
6228
+ };
6229
+
5926
6230
  function LabelEntry(props) {
5927
6231
  const {
5928
6232
  field
@@ -6102,11 +6406,15 @@ function NumberDecimalDigits(props) {
6102
6406
  debounce,
6103
6407
  label: 'Decimal digits',
6104
6408
  element: field,
6105
- min: 0,
6106
- step: 1,
6409
+ step: 'any',
6107
6410
  getValue,
6108
6411
  id,
6109
- setValue
6412
+ setValue,
6413
+ validate: value => {
6414
+ if (value === undefined || value === null) return;
6415
+ if (value < 0) return 'Should be greater than or equal to zero.';
6416
+ if (!Number.isInteger(value)) return 'Should be an integer.';
6417
+ }
6110
6418
  });
6111
6419
  }
6112
6420
  function NumberArrowStep(props) {
@@ -6196,7 +6504,7 @@ function SerializeToString(props) {
6196
6504
  element: field,
6197
6505
  getValue,
6198
6506
  id,
6199
- label: 'Serialize to string',
6507
+ label: 'Output as string',
6200
6508
  description: 'Allows arbitrary precision values',
6201
6509
  setValue
6202
6510
  });
@@ -6439,6 +6747,25 @@ function TimeFormatSelect(props) {
6439
6747
  });
6440
6748
  }
6441
6749
 
6750
+ function SelectEntries(props) {
6751
+ const {
6752
+ field
6753
+ } = props;
6754
+ const {
6755
+ type
6756
+ } = field;
6757
+ if (type !== 'select') {
6758
+ return [];
6759
+ }
6760
+ const entries = [simpleBoolEntryFactory({
6761
+ id: 'searchable',
6762
+ path: ['searchable'],
6763
+ label: 'Searchable',
6764
+ props
6765
+ })];
6766
+ return entries;
6767
+ }
6768
+
6442
6769
  function ValueEntry(props) {
6443
6770
  const {
6444
6771
  editField,
@@ -6477,7 +6804,7 @@ function Label(props) {
6477
6804
  const debounce = useService('debounce');
6478
6805
  const setValue = value => {
6479
6806
  const values = get(field, ['values']);
6480
- return editField(field, 'values', set(values, [index, 'label'], value));
6807
+ return editField(field, 'values', set$1(values, [index, 'label'], value));
6481
6808
  };
6482
6809
  const getValue = () => {
6483
6810
  return get(field, ['values', index, 'label']);
@@ -6503,7 +6830,7 @@ function Value$1(props) {
6503
6830
  const debounce = useService('debounce');
6504
6831
  const setValue = value => {
6505
6832
  const values = get(field, ['values']);
6506
- return editField(field, 'values', set(values, [index, 'value'], value));
6833
+ return editField(field, 'values', set$1(values, [index, 'value'], value));
6507
6834
  };
6508
6835
  const getValue = () => {
6509
6836
  return get(field, ['values', index, 'value']);
@@ -6818,7 +7145,7 @@ function AdornerEntry(props) {
6818
7145
  const onChange = key => {
6819
7146
  return value => {
6820
7147
  const appearance = get(field, ['appearance'], {});
6821
- editField(field, ['appearance'], set(appearance, [key], value));
7148
+ editField(field, ['appearance'], set$1(appearance, [key], value));
6822
7149
  };
6823
7150
  };
6824
7151
  const getValue = key => {
@@ -6968,6 +7295,9 @@ function GeneralGroup(field, editField) {
6968
7295
  }), ...AltTextEntry({
6969
7296
  field,
6970
7297
  editField
7298
+ }), ...SelectEntries({
7299
+ field,
7300
+ editField
6971
7301
  }), ...DisabledEntry({
6972
7302
  field,
6973
7303
  editField
@@ -7031,14 +7361,14 @@ function ValidationGroup(field, editField) {
7031
7361
  type
7032
7362
  } = field;
7033
7363
  const validate = get(field, ['validate'], {});
7034
- const isCustomValidation = [undefined, VALIDATION_TYPE_OPTIONS.custom.value].includes(validate?.validationType);
7364
+ const isCustomValidation = [undefined, VALIDATION_TYPE_OPTIONS.custom.value].includes(validate && validate.validationType);
7035
7365
  if (!(INPUTS.includes(type) && type !== 'checkbox' && type !== 'checklist' && type !== 'taglist')) {
7036
7366
  return null;
7037
7367
  }
7038
7368
  const onChange = key => {
7039
7369
  return value => {
7040
7370
  const validate = get(field, ['validate'], {});
7041
- editField(field, ['validate'], set(validate, [key], value));
7371
+ editField(field, ['validate'], set$1(validate, [key], value));
7042
7372
  };
7043
7373
  };
7044
7374
  const getValue = key => {
@@ -7179,7 +7509,7 @@ function Pattern(props) {
7179
7509
  element: field,
7180
7510
  getValue: getValue('pattern'),
7181
7511
  id,
7182
- label: 'Regular expression pattern',
7512
+ label: 'Custom regular expression',
7183
7513
  setValue: onChange('pattern')
7184
7514
  });
7185
7515
  }
@@ -7235,7 +7565,7 @@ function ValidationType(props) {
7235
7565
  element: field,
7236
7566
  getValue: getValue('validationType'),
7237
7567
  id,
7238
- label: 'Regular expression validation',
7568
+ label: 'Validation pattern',
7239
7569
  setValue,
7240
7570
  getOptions: () => Object.values(VALIDATION_TYPE_OPTIONS)
7241
7571
  });
@@ -7481,7 +7811,7 @@ function FormPropertiesPanel(props) {
7481
7811
  "data-field": selectedFormField && selectedFormField.id,
7482
7812
  onFocusCapture: onFocus,
7483
7813
  onBlurCapture: onBlur,
7484
- children: jsx(PropertiesPanelContext.Provider, {
7814
+ children: jsx(FormPropertiesPanelContext.Provider, {
7485
7815
  value: propertiesPanelContext,
7486
7816
  children: jsx(PropertiesPanel, {
7487
7817
  element: selectedFormField,
@@ -7745,7 +8075,7 @@ class FormEditor {
7745
8075
  * @param {any} value
7746
8076
  */
7747
8077
  setProperty(property, value) {
7748
- const properties = set(this._getState().properties, [property], value);
8078
+ const properties = set$1(this._getState().properties, [property], value);
7749
8079
  this._setState({
7750
8080
  properties
7751
8081
  });