@bpmn-io/properties-panel 1.5.0 → 1.6.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.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- import { useContext, useRef, useEffect, useMemo, useCallback, useState, useLayoutEffect } from '../preact/hooks';
1
+ import { useContext, useRef, useEffect, useMemo, useState, useCallback, useLayoutEffect } from '../preact/hooks';
2
2
  import { isFunction, isArray, get, assign, set, sortBy, find, isNumber, debounce } from 'min-dash';
3
3
  import classnames from 'classnames';
4
4
  import { forwardRef } from '../preact/compat';
@@ -167,19 +167,19 @@ const ErrorsContext = createContext({
167
167
  errors: {}
168
168
  });
169
169
 
170
- /**
171
- * @typedef {Function} <propertiesPanel.showEntry> callback
172
- *
173
- * @example
174
- *
175
- * useEvent('propertiesPanel.showEntry', ({ focus = false, ...rest }) => {
176
- * // ...
177
- * });
178
- *
179
- * @param {Object} context
180
- * @param {boolean} [context.focus]
181
- *
182
- * @returns void
170
+ /**
171
+ * @typedef {Function} <propertiesPanel.showEntry> callback
172
+ *
173
+ * @example
174
+ *
175
+ * useEvent('propertiesPanel.showEntry', ({ focus = false, ...rest }) => {
176
+ * // ...
177
+ * });
178
+ *
179
+ * @param {Object} context
180
+ * @param {boolean} [context.focus]
181
+ *
182
+ * @returns void
183
183
  */
184
184
  const EventContext = createContext({
185
185
  eventBus: null
@@ -192,20 +192,20 @@ const LayoutContext = createContext({
192
192
  setLayoutForKey: () => {}
193
193
  });
194
194
 
195
- /**
196
- * Accesses the global DescriptionContext and returns a description for a given id and element.
197
- *
198
- * @example
199
- * ```jsx
200
- * function TextField(props) {
201
- * const description = useDescriptionContext('input1', element);
202
- * }
203
- * ```
204
- *
205
- * @param {string} id
206
- * @param {object} element
207
- *
208
- * @returns {string}
195
+ /**
196
+ * Accesses the global DescriptionContext and returns a description for a given id and element.
197
+ *
198
+ * @example
199
+ * ```jsx
200
+ * function TextField(props) {
201
+ * const description = useDescriptionContext('input1', element);
202
+ * }
203
+ * ```
204
+ *
205
+ * @param {string} id
206
+ * @param {object} element
207
+ *
208
+ * @returns {string}
209
209
  */
210
210
  function useDescriptionContext(id, element) {
211
211
  const {
@@ -221,11 +221,11 @@ function useError(id) {
221
221
  return errors[id];
222
222
  }
223
223
 
224
- /**
225
- * Subscribe to an event immediately. Update subscription after inputs changed.
226
- *
227
- * @param {string} event
228
- * @param {Function} callback
224
+ /**
225
+ * Subscribe to an event immediately. Update subscription after inputs changed.
226
+ *
227
+ * @param {string} event
228
+ * @param {Function} callback
229
229
  */
230
230
  function useEvent(event, callback, eventBus) {
231
231
  const eventContext = useContext(EventContext);
@@ -257,24 +257,24 @@ function useEvent(event, callback, eventBus) {
257
257
 
258
258
  const KEY_LENGTH = 6;
259
259
 
260
- /**
261
- * Create a persistent key factory for plain objects without id.
262
- *
263
- * @example
264
- * ```jsx
265
- * function List({ objects }) {
266
- * const getKey = useKeyFactory();
267
- * return (<ol>{
268
- * objects.map(obj => {
269
- * const key = getKey(obj);
270
- * return <li key={key}>obj.name</li>
271
- * })
272
- * }</ol>);
273
- * }
274
- * ```
275
- *
276
- * @param {any[]} dependencies
277
- * @returns {(element: object) => string}
260
+ /**
261
+ * Create a persistent key factory for plain objects without id.
262
+ *
263
+ * @example
264
+ * ```jsx
265
+ * function List({ objects }) {
266
+ * const getKey = useKeyFactory();
267
+ * return (<ol>{
268
+ * objects.map(obj => {
269
+ * const key = getKey(obj);
270
+ * return <li key={key}>obj.name</li>
271
+ * })
272
+ * }</ol>);
273
+ * }
274
+ * ```
275
+ *
276
+ * @param {any[]} dependencies
277
+ * @returns {(element: object) => string}
278
278
  */
279
279
  function useKeyFactory(dependencies = []) {
280
280
  const map = useMemo(() => new Map(), dependencies);
@@ -289,20 +289,20 @@ function useKeyFactory(dependencies = []) {
289
289
  return getKey;
290
290
  }
291
291
 
292
- /**
293
- * Creates a state that persists in the global LayoutContext.
294
- *
295
- * @example
296
- * ```jsx
297
- * function Group(props) {
298
- * const [ open, setOpen ] = useLayoutState([ 'groups', 'foo', 'open' ], false);
299
- * }
300
- * ```
301
- *
302
- * @param {(string|number)[]} path
303
- * @param {any} [defaultValue]
304
- *
305
- * @returns {[ any, Function ]}
292
+ /**
293
+ * Creates a state that persists in the global LayoutContext.
294
+ *
295
+ * @example
296
+ * ```jsx
297
+ * function Group(props) {
298
+ * const [ open, setOpen ] = useLayoutState([ 'groups', 'foo', 'open' ], false);
299
+ * }
300
+ * ```
301
+ *
302
+ * @param {(string|number)[]} path
303
+ * @param {any} [defaultValue]
304
+ *
305
+ * @returns {[ any, Function ]}
306
306
  */
307
307
  function useLayoutState(path, defaultValue) {
308
308
  const {
@@ -310,17 +310,22 @@ function useLayoutState(path, defaultValue) {
310
310
  setLayoutForKey
311
311
  } = useContext(LayoutContext);
312
312
  const layoutForKey = getLayoutForKey(path, defaultValue);
313
- const setState = useCallback(newValue => {
313
+ const [value, set] = useState(layoutForKey);
314
+ const setState = newValue => {
315
+ // (1) set component state
316
+ set(newValue);
317
+
318
+ // (2) set context
314
319
  setLayoutForKey(path, newValue);
315
- }, [setLayoutForKey]);
316
- return [layoutForKey, setState];
320
+ };
321
+ return [value, setState];
317
322
  }
318
323
 
319
- /**
320
- * @pinussilvestrus: we need to introduce our own hook to persist the previous
321
- * state on updates.
322
- *
323
- * cf. https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
324
+ /**
325
+ * @pinussilvestrus: we need to introduce our own hook to persist the previous
326
+ * state on updates.
327
+ *
328
+ * cf. https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
324
329
  */
325
330
 
326
331
  function usePrevious(value) {
@@ -331,12 +336,12 @@ function usePrevious(value) {
331
336
  return ref.current;
332
337
  }
333
338
 
334
- /**
335
- * Subscribe to `propertiesPanel.showEntry`.
336
- *
337
- * @param {string} id
338
- *
339
- * @returns {import('preact').Ref}
339
+ /**
340
+ * Subscribe to `propertiesPanel.showEntry`.
341
+ *
342
+ * @param {string} id
343
+ *
344
+ * @returns {import('preact').Ref}
340
345
  */
341
346
  function useShowEntryEvent(id) {
342
347
  const {
@@ -367,20 +372,20 @@ function useShowEntryEvent(id) {
367
372
  return ref;
368
373
  }
369
374
 
370
- /**
371
- * @callback setSticky
372
- * @param {boolean} value
375
+ /**
376
+ * @callback setSticky
377
+ * @param {boolean} value
373
378
  */
374
379
 
375
- /**
376
- * Use IntersectionObserver to identify when DOM element is in sticky mode.
377
- * If sticky is observered setSticky(true) will be called.
378
- * If sticky mode is left, setSticky(false) will be called.
379
- *
380
- *
381
- * @param {Object} ref
382
- * @param {string} scrollContainerSelector
383
- * @param {setSticky} setSticky
380
+ /**
381
+ * Use IntersectionObserver to identify when DOM element is in sticky mode.
382
+ * If sticky is observered setSticky(true) will be called.
383
+ * If sticky mode is left, setSticky(false) will be called.
384
+ *
385
+ *
386
+ * @param {Object} ref
387
+ * @param {string} scrollContainerSelector
388
+ * @param {setSticky} setSticky
384
389
  */
385
390
  function useStickyIntersectionObserver(ref, scrollContainerSelector, setSticky) {
386
391
  useEffect(() => {
@@ -419,19 +424,19 @@ function useStickyIntersectionObserver(ref, scrollContainerSelector, setSticky)
419
424
  }, [ref, scrollContainerSelector, setSticky]);
420
425
  }
421
426
 
422
- /**
423
- * Creates a static function reference with changing body.
424
- * This is necessary when external libraries require a callback function
425
- * that has references to state variables.
426
- *
427
- * Usage:
428
- * const callback = useStaticCallback((val) => {val === currentState});
429
- *
430
- * The `callback` reference is static and can be safely used in external
431
- * libraries or as a prop that does not cause rerendering of children.
432
- *
433
- * @param {Function} callback function with changing reference
434
- * @returns {Function} static function reference
427
+ /**
428
+ * Creates a static function reference with changing body.
429
+ * This is necessary when external libraries require a callback function
430
+ * that has references to state variables.
431
+ *
432
+ * Usage:
433
+ * const callback = useStaticCallback((val) => {val === currentState});
434
+ *
435
+ * The `callback` reference is static and can be safely used in external
436
+ * libraries or as a prop that does not cause rerendering of children.
437
+ *
438
+ * @param {Function} callback function with changing reference
439
+ * @returns {Function} static function reference
435
440
  */
436
441
  function useStaticCallback(callback) {
437
442
  const callbackRef = useRef(callback);
@@ -524,13 +529,13 @@ function DataMarker() {
524
529
  });
525
530
  }
526
531
 
527
- /**
528
- * @typedef { {
529
- * text: (element: object) => string,
530
- * icon?: (element: Object) => import('preact').Component
531
- * } } PlaceholderDefinition
532
- *
533
- * @param { PlaceholderDefinition } props
532
+ /**
533
+ * @typedef { {
534
+ * text: (element: object) => string,
535
+ * icon?: (element: Object) => import('preact').Component
536
+ * } } PlaceholderDefinition
537
+ *
538
+ * @param { PlaceholderDefinition } props
534
539
  */
535
540
  function Placeholder(props) {
536
541
  const {
@@ -556,72 +561,72 @@ const DEFAULT_LAYOUT = {
556
561
  };
557
562
  const DEFAULT_DESCRIPTION = {};
558
563
 
559
- /**
560
- * @typedef { {
561
- * component: import('preact').Component,
562
- * id: String,
563
- * isEdited?: Function
564
- * } } EntryDefinition
565
- *
566
- * @typedef { {
567
- * autoFocusEntry: String,
568
- * autoOpen?: Boolean,
569
- * entries: Array<EntryDefinition>,
570
- * id: String,
571
- * label: String,
572
- * remove: (event: MouseEvent) => void
573
- * } } ListItemDefinition
574
- *
575
- * @typedef { {
576
- * add: (event: MouseEvent) => void,
577
- * component: import('preact').Component,
578
- * element: Object,
579
- * id: String,
580
- * items: Array<ListItemDefinition>,
581
- * label: String,
582
- * shouldSort?: Boolean,
583
- * shouldOpen?: Boolean
584
- * } } ListGroupDefinition
585
- *
586
- * @typedef { {
587
- * component?: import('preact').Component,
588
- * entries: Array<EntryDefinition>,
589
- * id: String,
590
- * label: String,
591
- * shouldOpen?: Boolean
592
- * } } GroupDefinition
593
- *
594
- * @typedef { {
595
- * [id: String]: GetDescriptionFunction
596
- * } } DescriptionConfig
597
- *
598
- * @callback { {
599
- * @param {string} id
600
- * @param {Object} element
601
- * @returns {string}
602
- * } } GetDescriptionFunction
603
- *
604
- * @typedef { {
605
- * getEmpty: (element: object) => import('./components/Placeholder').PlaceholderDefinition,
606
- * getMultiple: (element: Object) => import('./components/Placeholder').PlaceholderDefinition
607
- * } } PlaceholderProvider
608
- *
564
+ /**
565
+ * @typedef { {
566
+ * component: import('preact').Component,
567
+ * id: String,
568
+ * isEdited?: Function
569
+ * } } EntryDefinition
570
+ *
571
+ * @typedef { {
572
+ * autoFocusEntry: String,
573
+ * autoOpen?: Boolean,
574
+ * entries: Array<EntryDefinition>,
575
+ * id: String,
576
+ * label: String,
577
+ * remove: (event: MouseEvent) => void
578
+ * } } ListItemDefinition
579
+ *
580
+ * @typedef { {
581
+ * add: (event: MouseEvent) => void,
582
+ * component: import('preact').Component,
583
+ * element: Object,
584
+ * id: String,
585
+ * items: Array<ListItemDefinition>,
586
+ * label: String,
587
+ * shouldSort?: Boolean,
588
+ * shouldOpen?: Boolean
589
+ * } } ListGroupDefinition
590
+ *
591
+ * @typedef { {
592
+ * component?: import('preact').Component,
593
+ * entries: Array<EntryDefinition>,
594
+ * id: String,
595
+ * label: String,
596
+ * shouldOpen?: Boolean
597
+ * } } GroupDefinition
598
+ *
599
+ * @typedef { {
600
+ * [id: String]: GetDescriptionFunction
601
+ * } } DescriptionConfig
602
+ *
603
+ * @callback { {
604
+ * @param {string} id
605
+ * @param {Object} element
606
+ * @returns {string}
607
+ * } } GetDescriptionFunction
608
+ *
609
+ * @typedef { {
610
+ * getEmpty: (element: object) => import('./components/Placeholder').PlaceholderDefinition,
611
+ * getMultiple: (element: Object) => import('./components/Placeholder').PlaceholderDefinition
612
+ * } } PlaceholderProvider
613
+ *
609
614
  */
610
615
 
611
- /**
612
- * A basic properties panel component. Describes *how* content will be rendered, accepts
613
- * data from implementor to describe *what* will be rendered.
614
- *
615
- * @param {Object} props
616
- * @param {Object|Array} props.element
617
- * @param {import('./components/Header').HeaderProvider} props.headerProvider
618
- * @param {PlaceholderProvider} [props.placeholderProvider]
619
- * @param {Array<GroupDefinition|ListGroupDefinition>} props.groups
620
- * @param {Object} [props.layoutConfig]
621
- * @param {Function} [props.layoutChanged]
622
- * @param {DescriptionConfig} [props.descriptionConfig]
623
- * @param {Function} [props.descriptionLoaded]
624
- * @param {Object} [props.eventBus]
616
+ /**
617
+ * A basic properties panel component. Describes *how* content will be rendered, accepts
618
+ * data from implementor to describe *what* will be rendered.
619
+ *
620
+ * @param {Object} props
621
+ * @param {Object|Array} props.element
622
+ * @param {import('./components/Header').HeaderProvider} props.headerProvider
623
+ * @param {PlaceholderProvider} [props.placeholderProvider]
624
+ * @param {Array<GroupDefinition|ListGroupDefinition>} props.groups
625
+ * @param {Object} [props.layoutConfig]
626
+ * @param {Function} [props.layoutChanged]
627
+ * @param {DescriptionConfig} [props.descriptionConfig]
628
+ * @param {Function} [props.descriptionLoaded]
629
+ * @param {Object} [props.eventBus]
625
630
  */
626
631
  function PropertiesPanel(props) {
627
632
  const {
@@ -638,12 +643,6 @@ function PropertiesPanel(props) {
638
643
 
639
644
  // set-up layout context
640
645
  const [layout, setLayout] = useState(createLayout(layoutConfig));
641
-
642
- // react to external changes in the layout config
643
- useEffect(() => {
644
- const newLayout = createLayout(layoutConfig);
645
- setLayout(newLayout);
646
- }, [layoutConfig]);
647
646
  useEffect(() => {
648
647
  if (typeof layoutChanged === 'function') {
649
648
  layoutChanged(layout);
@@ -743,9 +742,9 @@ function PropertiesPanel(props) {
743
742
 
744
743
  // helpers //////////////////
745
744
 
746
- function createLayout(overrides, defaults = DEFAULT_LAYOUT) {
745
+ function createLayout(overrides) {
747
746
  return {
748
- ...defaults,
747
+ ...DEFAULT_LAYOUT,
749
748
  ...overrides
750
749
  };
751
750
  }
@@ -817,15 +816,15 @@ function MenuItem({
817
816
  });
818
817
  }
819
818
 
820
- /**
821
- *
822
- * @param {Array<null | Element>} ignoredElements
823
- * @param {Function} callback
819
+ /**
820
+ *
821
+ * @param {Array<null | Element>} ignoredElements
822
+ * @param {Function} callback
824
823
  */
825
824
  function useGlobalClick(ignoredElements, callback) {
826
825
  useEffect(() => {
827
- /**
828
- * @param {MouseEvent} event
826
+ /**
827
+ * @param {MouseEvent} event
829
828
  */
830
829
  function listener(event) {
831
830
  if (ignoredElements.some(element => element && element.contains(event.target))) {
@@ -956,8 +955,8 @@ function ListItem(props) {
956
955
 
957
956
  const noop$3 = () => {};
958
957
 
959
- /**
960
- * @param {import('../PropertiesPanel').ListGroupDefinition} props
958
+ /**
959
+ * @param {import('../PropertiesPanel').ListGroupDefinition} props
961
960
  */
962
961
  function ListGroup(props) {
963
962
  const {
@@ -1120,8 +1119,8 @@ function ListGroup(props) {
1120
1119
 
1121
1120
  // helpers ////////////////////
1122
1121
 
1123
- /**
1124
- * Sorts given items alphanumeric by label
1122
+ /**
1123
+ * Sorts given items alphanumeric by label
1125
1124
  */
1126
1125
  function sortItems(items) {
1127
1126
  return sortBy(items, i => i.label.toLowerCase());
@@ -1197,17 +1196,17 @@ function Checkbox(props) {
1197
1196
  });
1198
1197
  }
1199
1198
 
1200
- /**
1201
- * @param {Object} props
1202
- * @param {Object} props.element
1203
- * @param {String} props.id
1204
- * @param {String} props.description
1205
- * @param {String} props.label
1206
- * @param {Function} props.getValue
1207
- * @param {Function} props.setValue
1208
- * @param {Function} props.onFocus
1209
- * @param {Function} props.onBlur
1210
- * @param {boolean} [props.disabled]
1199
+ /**
1200
+ * @param {Object} props
1201
+ * @param {Object} props.element
1202
+ * @param {String} props.id
1203
+ * @param {String} props.description
1204
+ * @param {String} props.label
1205
+ * @param {Function} props.getValue
1206
+ * @param {Function} props.setValue
1207
+ * @param {Function} props.onFocus
1208
+ * @param {Function} props.onBlur
1209
+ * @param {boolean} [props.disabled]
1211
1210
  */
1212
1211
  function CheckboxEntry(props) {
1213
1212
  const {
@@ -1296,10 +1295,10 @@ const CodeEditor$1 = forwardRef((props, ref) => {
1296
1295
  useEffect(() => {
1297
1296
  let editor;
1298
1297
 
1299
- /* Trigger FEEL toggle when
1300
- *
1301
- * - `backspace` is pressed
1302
- * - AND the cursor is at the beginning of the input
1298
+ /* Trigger FEEL toggle when
1299
+ *
1300
+ * - `backspace` is pressed
1301
+ * - AND the cursor is at the beginning of the input
1303
1302
  */
1304
1303
  const onKeyDown = e => {
1305
1304
  if (e.key !== 'Backspace' || !editor) {
@@ -1372,10 +1371,10 @@ function FeelIndicator(props) {
1372
1371
 
1373
1372
  const noop$2 = () => {};
1374
1373
 
1375
- /**
1376
- * @param {Object} props
1377
- * @param {Object} props.label
1378
- * @param {String} props.feel
1374
+ /**
1375
+ * @param {Object} props
1376
+ * @param {Object} props.label
1377
+ * @param {String} props.feel
1379
1378
  */
1380
1379
  function FeelIcon(props) {
1381
1380
  const {
@@ -1650,24 +1649,24 @@ const OptionalFeelTextArea = forwardRef((props, ref) => {
1650
1649
  });
1651
1650
  });
1652
1651
 
1653
- /**
1654
- * @param {Object} props
1655
- * @param {Object} props.element
1656
- * @param {String} props.id
1657
- * @param {String} props.description
1658
- * @param {Boolean} props.debounce
1659
- * @param {Boolean} props.disabled
1660
- * @param {Boolean} props.feel
1661
- * @param {String} props.label
1662
- * @param {Function} props.getValue
1663
- * @param {Function} props.setValue
1664
- * @param {Function} props.tooltipContainer
1665
- * @param {Function} props.validate
1666
- * @param {Function} props.show
1667
- * @param {Function} props.example
1668
- * @param {Function} props.variables
1669
- * @param {Function} props.onFocus
1670
- * @param {Function} props.onBlur
1652
+ /**
1653
+ * @param {Object} props
1654
+ * @param {Object} props.element
1655
+ * @param {String} props.id
1656
+ * @param {String} props.description
1657
+ * @param {Boolean} props.debounce
1658
+ * @param {Boolean} props.disabled
1659
+ * @param {Boolean} props.feel
1660
+ * @param {String} props.label
1661
+ * @param {Function} props.getValue
1662
+ * @param {Function} props.setValue
1663
+ * @param {Function} props.tooltipContainer
1664
+ * @param {Function} props.validate
1665
+ * @param {Function} props.show
1666
+ * @param {Function} props.example
1667
+ * @param {Function} props.variables
1668
+ * @param {Function} props.onFocus
1669
+ * @param {Function} props.onBlur
1671
1670
  */
1672
1671
  function FeelEntry(props) {
1673
1672
  const {
@@ -1752,24 +1751,24 @@ function FeelEntry(props) {
1752
1751
  });
1753
1752
  }
1754
1753
 
1755
- /**
1756
- * @param {Object} props
1757
- * @param {Object} props.element
1758
- * @param {String} props.id
1759
- * @param {String} props.description
1760
- * @param {Boolean} props.debounce
1761
- * @param {Boolean} props.disabled
1762
- * @param {Boolean} props.feel
1763
- * @param {String} props.label
1764
- * @param {Function} props.getValue
1765
- * @param {Function} props.setValue
1766
- * @param {Function} props.tooltipContainer
1767
- * @param {Function} props.validate
1768
- * @param {Function} props.show
1769
- * @param {Function} props.example
1770
- * @param {Function} props.variables
1771
- * @param {Function} props.onFocus
1772
- * @param {Function} props.onBlur
1754
+ /**
1755
+ * @param {Object} props
1756
+ * @param {Object} props.element
1757
+ * @param {String} props.id
1758
+ * @param {String} props.description
1759
+ * @param {Boolean} props.debounce
1760
+ * @param {Boolean} props.disabled
1761
+ * @param {Boolean} props.feel
1762
+ * @param {String} props.label
1763
+ * @param {Function} props.getValue
1764
+ * @param {Function} props.setValue
1765
+ * @param {Function} props.tooltipContainer
1766
+ * @param {Function} props.validate
1767
+ * @param {Function} props.show
1768
+ * @param {Function} props.example
1769
+ * @param {Function} props.variables
1770
+ * @param {Function} props.onFocus
1771
+ * @param {Function} props.onBlur
1773
1772
  */
1774
1773
  function FeelTextArea(props) {
1775
1774
  return jsx(FeelEntry, {
@@ -1870,19 +1869,19 @@ const CodeEditor = forwardRef((props, ref) => {
1870
1869
 
1871
1870
  const noop = () => {};
1872
1871
 
1873
- /**
1874
- * @param {Object} props
1875
- * @param {Object} props.element
1876
- * @param {String} props.id
1877
- * @param {String} props.description
1878
- * @param {Boolean} props.debounce
1879
- * @param {Boolean} props.disabled
1880
- * @param {String} props.label
1881
- * @param {Function} props.getValue
1882
- * @param {Function} props.setValue
1883
- * @param {Function} props.tooltipContainer
1884
- * @param {Function} props.validate
1885
- * @param {Function} props.show
1872
+ /**
1873
+ * @param {Object} props
1874
+ * @param {Object} props.element
1875
+ * @param {String} props.id
1876
+ * @param {String} props.description
1877
+ * @param {Boolean} props.debounce
1878
+ * @param {Boolean} props.disabled
1879
+ * @param {String} props.label
1880
+ * @param {Function} props.getValue
1881
+ * @param {Function} props.setValue
1882
+ * @param {Function} props.tooltipContainer
1883
+ * @param {Function} props.validate
1884
+ * @param {Function} props.show
1886
1885
  */
1887
1886
  function FeelTemplatingEntry(props) {
1888
1887
  const {
@@ -2070,8 +2069,8 @@ function List(props) {
2070
2069
  }
2071
2070
  }, [open, hasItems]);
2072
2071
 
2073
- /**
2074
- * @param {MouseEvent} event
2072
+ /**
2073
+ * @param {MouseEvent} event
2075
2074
  */
2076
2075
  function addItem(event) {
2077
2076
  event.stopPropagation();
@@ -2183,14 +2182,14 @@ function ItemsList(props) {
2183
2182
  });
2184
2183
  }
2185
2184
 
2186
- /**
2187
- * Place new items in the beginning of the list and sort the rest with provided function.
2188
- *
2189
- * @template Item
2190
- * @param {Item[]} currentItems
2191
- * @param {(a: Item, b: Item) => 0 | 1 | -1} [compareFn] function used to sort items
2192
- * @param {boolean} [shouldReset=false] set to `true` to reset state of the hook
2193
- * @returns {Item[]}
2185
+ /**
2186
+ * Place new items in the beginning of the list and sort the rest with provided function.
2187
+ *
2188
+ * @template Item
2189
+ * @param {Item[]} currentItems
2190
+ * @param {(a: Item, b: Item) => 0 | 1 | -1} [compareFn] function used to sort items
2191
+ * @param {boolean} [shouldReset=false] set to `true` to reset state of the hook
2192
+ * @returns {Item[]}
2194
2193
  */
2195
2194
  function useSortedItems(currentItems, compareFn, shouldReset = false) {
2196
2195
  const itemsRef = useRef(currentItems.slice());
@@ -2286,22 +2285,22 @@ function NumberField(props) {
2286
2285
  });
2287
2286
  }
2288
2287
 
2289
- /**
2290
- * @param {Object} props
2291
- * @param {Boolean} props.debounce
2292
- * @param {String} props.description
2293
- * @param {Boolean} props.disabled
2294
- * @param {Object} props.element
2295
- * @param {Function} props.getValue
2296
- * @param {String} props.id
2297
- * @param {String} props.label
2298
- * @param {String} props.max
2299
- * @param {String} props.min
2300
- * @param {Function} props.setValue
2301
- * @param {Function} props.onFocus
2302
- * @param {Function} props.onBlur
2303
- * @param {String} props.step
2304
- * @param {Function} props.validate
2288
+ /**
2289
+ * @param {Object} props
2290
+ * @param {Boolean} props.debounce
2291
+ * @param {String} props.description
2292
+ * @param {Boolean} props.disabled
2293
+ * @param {Object} props.element
2294
+ * @param {Function} props.getValue
2295
+ * @param {String} props.id
2296
+ * @param {String} props.label
2297
+ * @param {String} props.max
2298
+ * @param {String} props.min
2299
+ * @param {Function} props.setValue
2300
+ * @param {Function} props.onFocus
2301
+ * @param {Function} props.onBlur
2302
+ * @param {String} props.step
2303
+ * @param {Function} props.validate
2305
2304
  */
2306
2305
  function NumberFieldEntry(props) {
2307
2306
  const {
@@ -2447,18 +2446,19 @@ function Select(props) {
2447
2446
  });
2448
2447
  }
2449
2448
 
2450
- /**
2451
- * @param {object} props
2452
- * @param {object} props.element
2453
- * @param {string} props.id
2454
- * @param {string} [props.description]
2455
- * @param {string} props.label
2456
- * @param {Function} props.getValue
2457
- * @param {Function} props.setValue
2458
- * @param {Function} props.onFocus
2459
- * @param {Function} props.onBlur
2460
- * @param {Function} props.getOptions
2461
- * @param {boolean} [props.disabled]
2449
+ /**
2450
+ * @param {object} props
2451
+ * @param {object} props.element
2452
+ * @param {string} props.id
2453
+ * @param {string} [props.description]
2454
+ * @param {string} props.label
2455
+ * @param {Function} props.getValue
2456
+ * @param {Function} props.setValue
2457
+ * @param {Function} props.onFocus
2458
+ * @param {Function} props.onBlur
2459
+ * @param {Function} props.getOptions
2460
+ * @param {boolean} [props.disabled]
2461
+ * @param {Function} [props.validate]
2462
2462
  */
2463
2463
  function SelectEntry(props) {
2464
2464
  const {
@@ -2471,11 +2471,37 @@ function SelectEntry(props) {
2471
2471
  getOptions,
2472
2472
  disabled,
2473
2473
  onFocus,
2474
- onBlur
2474
+ onBlur,
2475
+ validate
2475
2476
  } = props;
2476
- const value = getValue(element);
2477
2477
  const options = getOptions(element);
2478
- const error = useError(id);
2478
+ const [cachedInvalidValue, setCachedInvalidValue] = useState(null);
2479
+ const globalError = useError(id);
2480
+ const [localError, setLocalError] = useState(null);
2481
+ let value = getValue(element);
2482
+ const previousValue = usePrevious(value);
2483
+ useEffect(() => {
2484
+ if (isFunction(validate)) {
2485
+ const newValidationError = validate(value) || null;
2486
+ setLocalError(newValidationError);
2487
+ }
2488
+ }, [value]);
2489
+ const onChange = newValue => {
2490
+ let newValidationError = null;
2491
+ if (isFunction(validate)) {
2492
+ newValidationError = validate(newValue) || null;
2493
+ }
2494
+ if (newValidationError) {
2495
+ setCachedInvalidValue(newValue);
2496
+ } else {
2497
+ setValue(newValue);
2498
+ }
2499
+ setLocalError(newValidationError);
2500
+ };
2501
+ if (previousValue === value && localError) {
2502
+ value = cachedInvalidValue;
2503
+ }
2504
+ const error = globalError || localError;
2479
2505
  return jsxs("div", {
2480
2506
  class: classnames('bio-properties-panel-entry', error ? 'has-error' : ''),
2481
2507
  "data-entry-id": id,
@@ -2483,7 +2509,7 @@ function SelectEntry(props) {
2483
2509
  id: id,
2484
2510
  label: label,
2485
2511
  value: value,
2486
- onChange: setValue,
2512
+ onChange: onChange,
2487
2513
  onFocus: onFocus,
2488
2514
  onBlur: onBlur,
2489
2515
  options: options,
@@ -2629,20 +2655,20 @@ function TextArea(props) {
2629
2655
  });
2630
2656
  }
2631
2657
 
2632
- /**
2633
- * @param {object} props
2634
- * @param {object} props.element
2635
- * @param {string} props.id
2636
- * @param {string} props.description
2637
- * @param {boolean} props.debounce
2638
- * @param {string} props.label
2639
- * @param {Function} props.getValue
2640
- * @param {Function} props.setValue
2641
- * @param {Function} props.onFocus
2642
- * @param {Function} props.onBlur
2643
- * @param {number} props.rows
2644
- * @param {boolean} props.monospace
2645
- * @param {boolean} [props.disabled]
2658
+ /**
2659
+ * @param {object} props
2660
+ * @param {object} props.element
2661
+ * @param {string} props.id
2662
+ * @param {string} props.description
2663
+ * @param {boolean} props.debounce
2664
+ * @param {string} props.label
2665
+ * @param {Function} props.getValue
2666
+ * @param {Function} props.setValue
2667
+ * @param {Function} props.onFocus
2668
+ * @param {Function} props.onBlur
2669
+ * @param {number} props.rows
2670
+ * @param {boolean} props.monospace
2671
+ * @param {boolean} [props.disabled]
2646
2672
  */
2647
2673
  function TextAreaEntry(props) {
2648
2674
  const {
@@ -2748,19 +2774,19 @@ function Textfield(props) {
2748
2774
  });
2749
2775
  }
2750
2776
 
2751
- /**
2752
- * @param {Object} props
2753
- * @param {Object} props.element
2754
- * @param {String} props.id
2755
- * @param {String} props.description
2756
- * @param {Boolean} props.debounce
2757
- * @param {Boolean} props.disabled
2758
- * @param {String} props.label
2759
- * @param {Function} props.getValue
2760
- * @param {Function} props.setValue
2761
- * @param {Function} props.onFocus
2762
- * @param {Function} props.onBlur
2763
- * @param {Function} props.validate
2777
+ /**
2778
+ * @param {Object} props
2779
+ * @param {Object} props.element
2780
+ * @param {String} props.id
2781
+ * @param {String} props.description
2782
+ * @param {Boolean} props.debounce
2783
+ * @param {Boolean} props.disabled
2784
+ * @param {String} props.label
2785
+ * @param {Function} props.getValue
2786
+ * @param {Function} props.setValue
2787
+ * @param {Function} props.onFocus
2788
+ * @param {Function} props.onBlur
2789
+ * @param {Function} props.validate
2764
2790
  */
2765
2791
  function TextfieldEntry(props) {
2766
2792
  const {
@@ -2889,17 +2915,17 @@ function ToggleSwitch(props) {
2889
2915
  });
2890
2916
  }
2891
2917
 
2892
- /**
2893
- * @param {Object} props
2894
- * @param {Object} props.element
2895
- * @param {String} props.id
2896
- * @param {String} props.description
2897
- * @param {String} props.label
2898
- * @param {String} props.switcherLabel
2899
- * @param {Function} props.getValue
2900
- * @param {Function} props.setValue
2901
- * @param {Function} props.onFocus
2902
- * @param {Function} props.onBlur
2918
+ /**
2919
+ * @param {Object} props
2920
+ * @param {Object} props.element
2921
+ * @param {String} props.id
2922
+ * @param {String} props.description
2923
+ * @param {String} props.label
2924
+ * @param {String} props.switcherLabel
2925
+ * @param {Function} props.getValue
2926
+ * @param {Function} props.setValue
2927
+ * @param {Function} props.onFocus
2928
+ * @param {Function} props.onBlur
2903
2929
  */
2904
2930
  function ToggleSwitchEntry(props) {
2905
2931
  const {