@bpmn-io/properties-panel 1.1.1 → 1.2.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
@@ -166,19 +166,19 @@ const ErrorsContext = createContext({
166
166
  errors: {}
167
167
  });
168
168
 
169
- /**
170
- * @typedef {Function} <propertiesPanel.showEntry> callback
171
- *
172
- * @example
173
- *
174
- * useEvent('propertiesPanel.showEntry', ({ focus = false, ...rest }) => {
175
- * // ...
176
- * });
177
- *
178
- * @param {Object} context
179
- * @param {boolean} [context.focus]
180
- *
181
- * @returns void
169
+ /**
170
+ * @typedef {Function} <propertiesPanel.showEntry> callback
171
+ *
172
+ * @example
173
+ *
174
+ * useEvent('propertiesPanel.showEntry', ({ focus = false, ...rest }) => {
175
+ * // ...
176
+ * });
177
+ *
178
+ * @param {Object} context
179
+ * @param {boolean} [context.focus]
180
+ *
181
+ * @returns void
182
182
  */
183
183
  const EventContext = createContext({
184
184
  eventBus: null
@@ -191,20 +191,20 @@ const LayoutContext = createContext({
191
191
  setLayoutForKey: () => {}
192
192
  });
193
193
 
194
- /**
195
- * Accesses the global DescriptionContext and returns a description for a given id and element.
196
- *
197
- * @example
198
- * ```jsx
199
- * function TextField(props) {
200
- * const description = useDescriptionContext('input1', element);
201
- * }
202
- * ```
203
- *
204
- * @param {string} id
205
- * @param {object} element
206
- *
207
- * @returns {string}
194
+ /**
195
+ * Accesses the global DescriptionContext and returns a description for a given id and element.
196
+ *
197
+ * @example
198
+ * ```jsx
199
+ * function TextField(props) {
200
+ * const description = useDescriptionContext('input1', element);
201
+ * }
202
+ * ```
203
+ *
204
+ * @param {string} id
205
+ * @param {object} element
206
+ *
207
+ * @returns {string}
208
208
  */
209
209
  function useDescriptionContext(id, element) {
210
210
  const {
@@ -220,11 +220,11 @@ function useError(id) {
220
220
  return errors[id];
221
221
  }
222
222
 
223
- /**
224
- * Subscribe to an event immediately. Update subscription after inputs changed.
225
- *
226
- * @param {string} event
227
- * @param {Function} callback
223
+ /**
224
+ * Subscribe to an event immediately. Update subscription after inputs changed.
225
+ *
226
+ * @param {string} event
227
+ * @param {Function} callback
228
228
  */
229
229
  function useEvent(event, callback, eventBus) {
230
230
  const eventContext = useContext(EventContext);
@@ -256,24 +256,24 @@ function useEvent(event, callback, eventBus) {
256
256
 
257
257
  const KEY_LENGTH = 6;
258
258
 
259
- /**
260
- * Create a persistent key factory for plain objects without id.
261
- *
262
- * @example
263
- * ```jsx
264
- * function List({ objects }) {
265
- * const getKey = useKeyFactory();
266
- * return (<ol>{
267
- * objects.map(obj => {
268
- * const key = getKey(obj);
269
- * return <li key={key}>obj.name</li>
270
- * })
271
- * }</ol>);
272
- * }
273
- * ```
274
- *
275
- * @param {any[]} dependencies
276
- * @returns {(element: object) => string}
259
+ /**
260
+ * Create a persistent key factory for plain objects without id.
261
+ *
262
+ * @example
263
+ * ```jsx
264
+ * function List({ objects }) {
265
+ * const getKey = useKeyFactory();
266
+ * return (<ol>{
267
+ * objects.map(obj => {
268
+ * const key = getKey(obj);
269
+ * return <li key={key}>obj.name</li>
270
+ * })
271
+ * }</ol>);
272
+ * }
273
+ * ```
274
+ *
275
+ * @param {any[]} dependencies
276
+ * @returns {(element: object) => string}
277
277
  */
278
278
  function useKeyFactory(dependencies = []) {
279
279
  const map = useMemo(() => new Map(), dependencies);
@@ -288,20 +288,20 @@ function useKeyFactory(dependencies = []) {
288
288
  return getKey;
289
289
  }
290
290
 
291
- /**
292
- * Creates a state that persists in the global LayoutContext.
293
- *
294
- * @example
295
- * ```jsx
296
- * function Group(props) {
297
- * const [ open, setOpen ] = useLayoutState([ 'groups', 'foo', 'open' ], false);
298
- * }
299
- * ```
300
- *
301
- * @param {(string|number)[]} path
302
- * @param {any} [defaultValue]
303
- *
304
- * @returns {[ any, Function ]}
291
+ /**
292
+ * Creates a state that persists in the global LayoutContext.
293
+ *
294
+ * @example
295
+ * ```jsx
296
+ * function Group(props) {
297
+ * const [ open, setOpen ] = useLayoutState([ 'groups', 'foo', 'open' ], false);
298
+ * }
299
+ * ```
300
+ *
301
+ * @param {(string|number)[]} path
302
+ * @param {any} [defaultValue]
303
+ *
304
+ * @returns {[ any, Function ]}
305
305
  */
306
306
  function useLayoutState(path, defaultValue) {
307
307
  const {
@@ -320,11 +320,11 @@ function useLayoutState(path, defaultValue) {
320
320
  return [value, setState];
321
321
  }
322
322
 
323
- /**
324
- * @pinussilvestrus: we need to introduce our own hook to persist the previous
325
- * state on updates.
326
- *
327
- * cf. https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
323
+ /**
324
+ * @pinussilvestrus: we need to introduce our own hook to persist the previous
325
+ * state on updates.
326
+ *
327
+ * cf. https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
328
328
  */
329
329
 
330
330
  function usePrevious(value) {
@@ -335,12 +335,12 @@ function usePrevious(value) {
335
335
  return ref.current;
336
336
  }
337
337
 
338
- /**
339
- * Subscribe to `propertiesPanel.showEntry`.
340
- *
341
- * @param {string} id
342
- *
343
- * @returns {import('preact').Ref}
338
+ /**
339
+ * Subscribe to `propertiesPanel.showEntry`.
340
+ *
341
+ * @param {string} id
342
+ *
343
+ * @returns {import('preact').Ref}
344
344
  */
345
345
  function useShowEntryEvent(id) {
346
346
  const {
@@ -371,20 +371,20 @@ function useShowEntryEvent(id) {
371
371
  return ref;
372
372
  }
373
373
 
374
- /**
375
- * @callback setSticky
376
- * @param {boolean} value
374
+ /**
375
+ * @callback setSticky
376
+ * @param {boolean} value
377
377
  */
378
378
 
379
- /**
380
- * Use IntersectionObserver to identify when DOM element is in sticky mode.
381
- * If sticky is observered setSticky(true) will be called.
382
- * If sticky mode is left, setSticky(false) will be called.
383
- *
384
- *
385
- * @param {Object} ref
386
- * @param {string} scrollContainerSelector
387
- * @param {setSticky} setSticky
379
+ /**
380
+ * Use IntersectionObserver to identify when DOM element is in sticky mode.
381
+ * If sticky is observered setSticky(true) will be called.
382
+ * If sticky mode is left, setSticky(false) will be called.
383
+ *
384
+ *
385
+ * @param {Object} ref
386
+ * @param {string} scrollContainerSelector
387
+ * @param {setSticky} setSticky
388
388
  */
389
389
  function useStickyIntersectionObserver(ref, scrollContainerSelector, setSticky) {
390
390
  useEffect(() => {
@@ -423,19 +423,19 @@ function useStickyIntersectionObserver(ref, scrollContainerSelector, setSticky)
423
423
  }, [ref, scrollContainerSelector, setSticky]);
424
424
  }
425
425
 
426
- /**
427
- * Creates a static function reference with changing body.
428
- * This is necessary when external libraries require a callback function
429
- * that has references to state variables.
430
- *
431
- * Usage:
432
- * const callback = useStaticCallback((val) => {val === currentState});
433
- *
434
- * The `callback` reference is static and can be safely used in external
435
- * libraries or as a prop that does not cause rerendering of children.
436
- *
437
- * @param {Function} callback function with changing reference
438
- * @returns {Function} static function reference
426
+ /**
427
+ * Creates a static function reference with changing body.
428
+ * This is necessary when external libraries require a callback function
429
+ * that has references to state variables.
430
+ *
431
+ * Usage:
432
+ * const callback = useStaticCallback((val) => {val === currentState});
433
+ *
434
+ * The `callback` reference is static and can be safely used in external
435
+ * libraries or as a prop that does not cause rerendering of children.
436
+ *
437
+ * @param {Function} callback function with changing reference
438
+ * @returns {Function} static function reference
439
439
  */
440
440
  function useStaticCallback(callback) {
441
441
  const callbackRef = useRef(callback);
@@ -528,13 +528,13 @@ function DataMarker() {
528
528
  });
529
529
  }
530
530
 
531
- /**
532
- * @typedef { {
533
- * text: (element: object) => string,
534
- * icon?: (element: Object) => import('preact').Component
535
- * } } PlaceholderDefinition
536
- *
537
- * @param { PlaceholderDefinition } props
531
+ /**
532
+ * @typedef { {
533
+ * text: (element: object) => string,
534
+ * icon?: (element: Object) => import('preact').Component
535
+ * } } PlaceholderDefinition
536
+ *
537
+ * @param { PlaceholderDefinition } props
538
538
  */
539
539
  function Placeholder(props) {
540
540
  const {
@@ -560,72 +560,72 @@ const DEFAULT_LAYOUT = {
560
560
  };
561
561
  const DEFAULT_DESCRIPTION = {};
562
562
 
563
- /**
564
- * @typedef { {
565
- * component: import('preact').Component,
566
- * id: String,
567
- * isEdited?: Function
568
- * } } EntryDefinition
569
- *
570
- * @typedef { {
571
- * autoFocusEntry: String,
572
- * autoOpen?: Boolean,
573
- * entries: Array<EntryDefinition>,
574
- * id: String,
575
- * label: String,
576
- * remove: (event: MouseEvent) => void
577
- * } } ListItemDefinition
578
- *
579
- * @typedef { {
580
- * add: (event: MouseEvent) => void,
581
- * component: import('preact').Component,
582
- * element: Object,
583
- * id: String,
584
- * items: Array<ListItemDefinition>,
585
- * label: String,
586
- * shouldSort?: Boolean,
587
- * shouldOpen?: Boolean
588
- * } } ListGroupDefinition
589
- *
590
- * @typedef { {
591
- * component?: import('preact').Component,
592
- * entries: Array<EntryDefinition>,
593
- * id: String,
594
- * label: String,
595
- * shouldOpen?: Boolean
596
- * } } GroupDefinition
597
- *
598
- * @typedef { {
599
- * [id: String]: GetDescriptionFunction
600
- * } } DescriptionConfig
601
- *
602
- * @callback { {
603
- * @param {string} id
604
- * @param {Object} element
605
- * @returns {string}
606
- * } } GetDescriptionFunction
607
- *
608
- * @typedef { {
609
- * getEmpty: (element: object) => import('./components/Placeholder').PlaceholderDefinition,
610
- * getMultiple: (element: Object) => import('./components/Placeholder').PlaceholderDefinition
611
- * } } PlaceholderProvider
612
- *
563
+ /**
564
+ * @typedef { {
565
+ * component: import('preact').Component,
566
+ * id: String,
567
+ * isEdited?: Function
568
+ * } } EntryDefinition
569
+ *
570
+ * @typedef { {
571
+ * autoFocusEntry: String,
572
+ * autoOpen?: Boolean,
573
+ * entries: Array<EntryDefinition>,
574
+ * id: String,
575
+ * label: String,
576
+ * remove: (event: MouseEvent) => void
577
+ * } } ListItemDefinition
578
+ *
579
+ * @typedef { {
580
+ * add: (event: MouseEvent) => void,
581
+ * component: import('preact').Component,
582
+ * element: Object,
583
+ * id: String,
584
+ * items: Array<ListItemDefinition>,
585
+ * label: String,
586
+ * shouldSort?: Boolean,
587
+ * shouldOpen?: Boolean
588
+ * } } ListGroupDefinition
589
+ *
590
+ * @typedef { {
591
+ * component?: import('preact').Component,
592
+ * entries: Array<EntryDefinition>,
593
+ * id: String,
594
+ * label: String,
595
+ * shouldOpen?: Boolean
596
+ * } } GroupDefinition
597
+ *
598
+ * @typedef { {
599
+ * [id: String]: GetDescriptionFunction
600
+ * } } DescriptionConfig
601
+ *
602
+ * @callback { {
603
+ * @param {string} id
604
+ * @param {Object} element
605
+ * @returns {string}
606
+ * } } GetDescriptionFunction
607
+ *
608
+ * @typedef { {
609
+ * getEmpty: (element: object) => import('./components/Placeholder').PlaceholderDefinition,
610
+ * getMultiple: (element: Object) => import('./components/Placeholder').PlaceholderDefinition
611
+ * } } PlaceholderProvider
612
+ *
613
613
  */
614
614
 
615
- /**
616
- * A basic properties panel component. Describes *how* content will be rendered, accepts
617
- * data from implementor to describe *what* will be rendered.
618
- *
619
- * @param {Object} props
620
- * @param {Object|Array} props.element
621
- * @param {import('./components/Header').HeaderProvider} props.headerProvider
622
- * @param {PlaceholderProvider} [props.placeholderProvider]
623
- * @param {Array<GroupDefinition|ListGroupDefinition>} props.groups
624
- * @param {Object} [props.layoutConfig]
625
- * @param {Function} [props.layoutChanged]
626
- * @param {DescriptionConfig} [props.descriptionConfig]
627
- * @param {Function} [props.descriptionLoaded]
628
- * @param {Object} [props.eventBus]
615
+ /**
616
+ * A basic properties panel component. Describes *how* content will be rendered, accepts
617
+ * data from implementor to describe *what* will be rendered.
618
+ *
619
+ * @param {Object} props
620
+ * @param {Object|Array} props.element
621
+ * @param {import('./components/Header').HeaderProvider} props.headerProvider
622
+ * @param {PlaceholderProvider} [props.placeholderProvider]
623
+ * @param {Array<GroupDefinition|ListGroupDefinition>} props.groups
624
+ * @param {Object} [props.layoutConfig]
625
+ * @param {Function} [props.layoutChanged]
626
+ * @param {DescriptionConfig} [props.descriptionConfig]
627
+ * @param {Function} [props.descriptionLoaded]
628
+ * @param {Object} [props.eventBus]
629
629
  */
630
630
  function PropertiesPanel(props) {
631
631
  const {
@@ -815,15 +815,15 @@ function MenuItem({
815
815
  });
816
816
  }
817
817
 
818
- /**
819
- *
820
- * @param {Array<null | Element>} ignoredElements
821
- * @param {Function} callback
818
+ /**
819
+ *
820
+ * @param {Array<null | Element>} ignoredElements
821
+ * @param {Function} callback
822
822
  */
823
823
  function useGlobalClick(ignoredElements, callback) {
824
824
  useEffect(() => {
825
- /**
826
- * @param {MouseEvent} event
825
+ /**
826
+ * @param {MouseEvent} event
827
827
  */
828
828
  function listener(event) {
829
829
  if (ignoredElements.some(element => element && element.contains(event.target))) {
@@ -954,8 +954,8 @@ function ListItem(props) {
954
954
 
955
955
  const noop$2 = () => {};
956
956
 
957
- /**
958
- * @param {import('../PropertiesPanel').ListGroupDefinition} props
957
+ /**
958
+ * @param {import('../PropertiesPanel').ListGroupDefinition} props
959
959
  */
960
960
  function ListGroup(props) {
961
961
  const {
@@ -1118,8 +1118,8 @@ function ListGroup(props) {
1118
1118
 
1119
1119
  // helpers ////////////////////
1120
1120
 
1121
- /**
1122
- * Sorts given items alphanumeric by label
1121
+ /**
1122
+ * Sorts given items alphanumeric by label
1123
1123
  */
1124
1124
  function sortItems(items) {
1125
1125
  return sortBy(items, i => i.label.toLowerCase());
@@ -1195,17 +1195,17 @@ function Checkbox(props) {
1195
1195
  });
1196
1196
  }
1197
1197
 
1198
- /**
1199
- * @param {Object} props
1200
- * @param {Object} props.element
1201
- * @param {String} props.id
1202
- * @param {String} props.description
1203
- * @param {String} props.label
1204
- * @param {Function} props.getValue
1205
- * @param {Function} props.setValue
1206
- * @param {Function} props.onFocus
1207
- * @param {Function} props.onBlur
1208
- * @param {boolean} [props.disabled]
1198
+ /**
1199
+ * @param {Object} props
1200
+ * @param {Object} props.element
1201
+ * @param {String} props.id
1202
+ * @param {String} props.description
1203
+ * @param {String} props.label
1204
+ * @param {Function} props.getValue
1205
+ * @param {Function} props.setValue
1206
+ * @param {Function} props.onFocus
1207
+ * @param {Function} props.onBlur
1208
+ * @param {boolean} [props.disabled]
1209
1209
  */
1210
1210
  function CheckboxEntry(props) {
1211
1211
  const {
@@ -1294,10 +1294,10 @@ const CodeEditor = forwardRef((props, ref) => {
1294
1294
  useEffect(() => {
1295
1295
  let editor;
1296
1296
 
1297
- /* Trigger FEEL toggle when
1298
- *
1299
- * - `backspace` is pressed
1300
- * - AND the cursor is at the beginning of the input
1297
+ /* Trigger FEEL toggle when
1298
+ *
1299
+ * - `backspace` is pressed
1300
+ * - AND the cursor is at the beginning of the input
1301
1301
  */
1302
1302
  const onKeyDown = e => {
1303
1303
  if (e.key !== 'Backspace' || !editor) {
@@ -1370,10 +1370,10 @@ function FeelIndicator(props) {
1370
1370
 
1371
1371
  const noop$1 = () => {};
1372
1372
 
1373
- /**
1374
- * @param {Object} props
1375
- * @param {Object} props.label
1376
- * @param {String} props.feel
1373
+ /**
1374
+ * @param {Object} props
1375
+ * @param {Object} props.label
1376
+ * @param {String} props.feel
1377
1377
  */
1378
1378
  function FeelIcon(props) {
1379
1379
  const {
@@ -1648,17 +1648,17 @@ const OptionalFeelTextArea = forwardRef((props, ref) => {
1648
1648
  });
1649
1649
  });
1650
1650
 
1651
- /**
1652
- * @param {Object} props
1653
- * @param {Object} props.element
1654
- * @param {String} props.id
1655
- * @param {String} props.description
1656
- * @param {Boolean} props.debounce
1657
- * @param {Boolean} props.disabled
1658
- * @param {String} props.label
1659
- * @param {Function} props.getValue
1660
- * @param {Function} props.setValue
1661
- * @param {Function} props.validate
1651
+ /**
1652
+ * @param {Object} props
1653
+ * @param {Object} props.element
1654
+ * @param {String} props.id
1655
+ * @param {String} props.description
1656
+ * @param {Boolean} props.debounce
1657
+ * @param {Boolean} props.disabled
1658
+ * @param {String} props.label
1659
+ * @param {Function} props.getValue
1660
+ * @param {Function} props.setValue
1661
+ * @param {Function} props.validate
1662
1662
  */
1663
1663
  function FeelEntry(props) {
1664
1664
  const {
@@ -1743,19 +1743,19 @@ function FeelEntry(props) {
1743
1743
  });
1744
1744
  }
1745
1745
 
1746
- /**
1747
- * @param {Object} props
1748
- * @param {Object} props.element
1749
- * @param {String} props.id
1750
- * @param {String} props.description
1751
- * @param {Boolean} props.debounce
1752
- * @param {Boolean} props.disabled
1753
- * @param {String} props.label
1754
- * @param {Function} props.getValue
1755
- * @param {Function} props.setValue
1756
- * @param {Function} props.onFocus
1757
- * @param {Function} props.onBlur
1758
- * @param {Function} props.validate
1746
+ /**
1747
+ * @param {Object} props
1748
+ * @param {Object} props.element
1749
+ * @param {String} props.id
1750
+ * @param {String} props.description
1751
+ * @param {Boolean} props.debounce
1752
+ * @param {Boolean} props.disabled
1753
+ * @param {String} props.label
1754
+ * @param {Function} props.getValue
1755
+ * @param {Function} props.setValue
1756
+ * @param {Function} props.onFocus
1757
+ * @param {Function} props.onBlur
1758
+ * @param {Function} props.validate
1759
1759
  */
1760
1760
  function FeelTextArea(props) {
1761
1761
  return jsx(FeelEntry, {
@@ -1802,8 +1802,8 @@ function List(props) {
1802
1802
  }
1803
1803
  }, [open, hasItems]);
1804
1804
 
1805
- /**
1806
- * @param {MouseEvent} event
1805
+ /**
1806
+ * @param {MouseEvent} event
1807
1807
  */
1808
1808
  function addItem(event) {
1809
1809
  event.stopPropagation();
@@ -1915,14 +1915,14 @@ function ItemsList(props) {
1915
1915
  });
1916
1916
  }
1917
1917
 
1918
- /**
1919
- * Place new items in the beginning of the list and sort the rest with provided function.
1920
- *
1921
- * @template Item
1922
- * @param {Item[]} currentItems
1923
- * @param {(a: Item, b: Item) => 0 | 1 | -1} [compareFn] function used to sort items
1924
- * @param {boolean} [shouldReset=false] set to `true` to reset state of the hook
1925
- * @returns {Item[]}
1918
+ /**
1919
+ * Place new items in the beginning of the list and sort the rest with provided function.
1920
+ *
1921
+ * @template Item
1922
+ * @param {Item[]} currentItems
1923
+ * @param {(a: Item, b: Item) => 0 | 1 | -1} [compareFn] function used to sort items
1924
+ * @param {boolean} [shouldReset=false] set to `true` to reset state of the hook
1925
+ * @returns {Item[]}
1926
1926
  */
1927
1927
  function useSortedItems(currentItems, compareFn, shouldReset = false) {
1928
1928
  const itemsRef = useRef(currentItems.slice());
@@ -2018,21 +2018,22 @@ function NumberField(props) {
2018
2018
  });
2019
2019
  }
2020
2020
 
2021
- /**
2022
- * @param {Object} props
2023
- * @param {Boolean} props.debounce
2024
- * @param {String} props.description
2025
- * @param {Boolean} props.disabled
2026
- * @param {Object} props.element
2027
- * @param {Function} props.getValue
2028
- * @param {String} props.id
2029
- * @param {String} props.label
2030
- * @param {String} props.max
2031
- * @param {String} props.min
2032
- * @param {Function} props.setValue
2033
- * @param {Function} props.onFocus
2034
- * @param {Function} props.onBlur
2035
- * @param {String} props.step
2021
+ /**
2022
+ * @param {Object} props
2023
+ * @param {Boolean} props.debounce
2024
+ * @param {String} props.description
2025
+ * @param {Boolean} props.disabled
2026
+ * @param {Object} props.element
2027
+ * @param {Function} props.getValue
2028
+ * @param {String} props.id
2029
+ * @param {String} props.label
2030
+ * @param {String} props.max
2031
+ * @param {String} props.min
2032
+ * @param {Function} props.setValue
2033
+ * @param {Function} props.onFocus
2034
+ * @param {Function} props.onBlur
2035
+ * @param {String} props.step
2036
+ * @param {Function} props.validate
2036
2037
  */
2037
2038
  function NumberFieldEntry(props) {
2038
2039
  const {
@@ -2048,25 +2049,55 @@ function NumberFieldEntry(props) {
2048
2049
  setValue,
2049
2050
  step,
2050
2051
  onFocus,
2051
- onBlur
2052
+ onBlur,
2053
+ validate
2052
2054
  } = props;
2053
- const value = getValue(element);
2055
+ const [cachedInvalidValue, setCachedInvalidValue] = useState(null);
2056
+ const globalError = useError(id);
2057
+ const [localError, setLocalError] = useState(null);
2058
+ let value = getValue(element);
2059
+ const previousValue = usePrevious(value);
2060
+ useEffect(() => {
2061
+ if (isFunction(validate)) {
2062
+ const newValidationError = validate(value) || null;
2063
+ setLocalError(newValidationError);
2064
+ }
2065
+ }, [value]);
2066
+ const onInput = newValue => {
2067
+ let newValidationError = null;
2068
+ if (isFunction(validate)) {
2069
+ newValidationError = validate(newValue) || null;
2070
+ }
2071
+ if (newValidationError) {
2072
+ setCachedInvalidValue(newValue);
2073
+ } else {
2074
+ setValue(newValue);
2075
+ }
2076
+ setLocalError(newValidationError);
2077
+ };
2078
+ if (previousValue === value && localError) {
2079
+ value = cachedInvalidValue;
2080
+ }
2081
+ const error = globalError || localError;
2054
2082
  return jsxs("div", {
2055
- class: "bio-properties-panel-entry",
2083
+ class: classnames('bio-properties-panel-entry', error ? 'has-error' : ''),
2056
2084
  "data-entry-id": id,
2057
2085
  children: [jsx(NumberField, {
2058
2086
  debounce: debounce,
2059
2087
  disabled: disabled,
2060
2088
  id: id,
2061
2089
  label: label,
2062
- onInput: setValue,
2063
2090
  onFocus: onFocus,
2064
2091
  onBlur: onBlur,
2092
+ onInput: onInput,
2065
2093
  max: max,
2066
2094
  min: min,
2067
2095
  step: step,
2068
2096
  value: value
2069
- }, element), jsx(Description, {
2097
+ }, element), error && jsx("div", {
2098
+ class: "bio-properties-panel-error",
2099
+ children: error
2100
+ }), jsx(Description, {
2070
2101
  forId: id,
2071
2102
  element: element,
2072
2103
  value: description
@@ -2138,18 +2169,18 @@ function Select(props) {
2138
2169
  });
2139
2170
  }
2140
2171
 
2141
- /**
2142
- * @param {object} props
2143
- * @param {object} props.element
2144
- * @param {string} props.id
2145
- * @param {string} [props.description]
2146
- * @param {string} props.label
2147
- * @param {Function} props.getValue
2148
- * @param {Function} props.setValue
2149
- * @param {Function} props.onFocus
2150
- * @param {Function} props.onBlur
2151
- * @param {Function} props.getOptions
2152
- * @param {boolean} [props.disabled]
2172
+ /**
2173
+ * @param {object} props
2174
+ * @param {object} props.element
2175
+ * @param {string} props.id
2176
+ * @param {string} [props.description]
2177
+ * @param {string} props.label
2178
+ * @param {Function} props.getValue
2179
+ * @param {Function} props.setValue
2180
+ * @param {Function} props.onFocus
2181
+ * @param {Function} props.onBlur
2182
+ * @param {Function} props.getOptions
2183
+ * @param {boolean} [props.disabled]
2153
2184
  */
2154
2185
  function SelectEntry(props) {
2155
2186
  const {
@@ -2308,20 +2339,20 @@ function TextArea(props) {
2308
2339
  });
2309
2340
  }
2310
2341
 
2311
- /**
2312
- * @param {object} props
2313
- * @param {object} props.element
2314
- * @param {string} props.id
2315
- * @param {string} props.description
2316
- * @param {boolean} props.debounce
2317
- * @param {string} props.label
2318
- * @param {Function} props.getValue
2319
- * @param {Function} props.setValue
2320
- * @param {Function} props.onFocus
2321
- * @param {Function} props.onBlur
2322
- * @param {number} props.rows
2323
- * @param {boolean} props.monospace
2324
- * @param {boolean} [props.disabled]
2342
+ /**
2343
+ * @param {object} props
2344
+ * @param {object} props.element
2345
+ * @param {string} props.id
2346
+ * @param {string} props.description
2347
+ * @param {boolean} props.debounce
2348
+ * @param {string} props.label
2349
+ * @param {Function} props.getValue
2350
+ * @param {Function} props.setValue
2351
+ * @param {Function} props.onFocus
2352
+ * @param {Function} props.onBlur
2353
+ * @param {number} props.rows
2354
+ * @param {boolean} props.monospace
2355
+ * @param {boolean} [props.disabled]
2325
2356
  */
2326
2357
  function TextAreaEntry(props) {
2327
2358
  const {
@@ -2425,19 +2456,19 @@ function Textfield(props) {
2425
2456
  });
2426
2457
  }
2427
2458
 
2428
- /**
2429
- * @param {Object} props
2430
- * @param {Object} props.element
2431
- * @param {String} props.id
2432
- * @param {String} props.description
2433
- * @param {Boolean} props.debounce
2434
- * @param {Boolean} props.disabled
2435
- * @param {String} props.label
2436
- * @param {Function} props.getValue
2437
- * @param {Function} props.setValue
2438
- * @param {Function} props.onFocus
2439
- * @param {Function} props.onBlur
2440
- * @param {Function} props.validate
2459
+ /**
2460
+ * @param {Object} props
2461
+ * @param {Object} props.element
2462
+ * @param {String} props.id
2463
+ * @param {String} props.description
2464
+ * @param {Boolean} props.debounce
2465
+ * @param {Boolean} props.disabled
2466
+ * @param {String} props.label
2467
+ * @param {Function} props.getValue
2468
+ * @param {Function} props.setValue
2469
+ * @param {Function} props.onFocus
2470
+ * @param {Function} props.onBlur
2471
+ * @param {Function} props.validate
2441
2472
  */
2442
2473
  function TextfieldEntry(props) {
2443
2474
  const {
@@ -2566,17 +2597,17 @@ function ToggleSwitch(props) {
2566
2597
  });
2567
2598
  }
2568
2599
 
2569
- /**
2570
- * @param {Object} props
2571
- * @param {Object} props.element
2572
- * @param {String} props.id
2573
- * @param {String} props.description
2574
- * @param {String} props.label
2575
- * @param {String} props.switcherLabel
2576
- * @param {Function} props.getValue
2577
- * @param {Function} props.setValue
2578
- * @param {Function} props.onFocus
2579
- * @param {Function} props.onBlur
2600
+ /**
2601
+ * @param {Object} props
2602
+ * @param {Object} props.element
2603
+ * @param {String} props.id
2604
+ * @param {String} props.description
2605
+ * @param {String} props.label
2606
+ * @param {String} props.switcherLabel
2607
+ * @param {Function} props.getValue
2608
+ * @param {Function} props.setValue
2609
+ * @param {Function} props.onFocus
2610
+ * @param {Function} props.onBlur
2580
2611
  */
2581
2612
  function ToggleSwitchEntry(props) {
2582
2613
  const {