@bpmn-io/properties-panel 3.40.4 → 3.40.5

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
@@ -551,10 +551,10 @@ function useDescriptionContext(id, element) {
551
551
  function useDebounce(callback, debounceFn) {
552
552
  const debouncedCallback = useCallback(debounceFn(callback), [callback, debounceFn]);
553
553
 
554
- // make sure previous call is not stalled
554
+ // flush pending calls before unmount the debounced function
555
555
  useEffect(() => {
556
556
  return () => {
557
- debouncedCallback.cancel?.();
557
+ debouncedCallback.flush?.();
558
558
  };
559
559
  }, [debouncedCallback]);
560
560
  return debouncedCallback;
@@ -1971,6 +1971,7 @@ const FeelEditor = forwardRef((props, ref) => {
1971
1971
  value,
1972
1972
  onInput,
1973
1973
  onKeyDown: onKeyDownProp = noop$4,
1974
+ onBlur = noop$4,
1974
1975
  onFeelToggle = noop$4,
1975
1976
  onLint = noop$4,
1976
1977
  onOpenPopup = noop$4,
@@ -1994,6 +1995,9 @@ const FeelEditor = forwardRef((props, ref) => {
1994
1995
  onInput(newValue);
1995
1996
  setLocalValue(newValue);
1996
1997
  });
1998
+ const handleBlur = useStaticCallback(() => {
1999
+ onBlur();
2000
+ });
1997
2001
  useEffect(() => {
1998
2002
  let editor;
1999
2003
 
@@ -2026,7 +2030,9 @@ const FeelEditor = forwardRef((props, ref) => {
2026
2030
  builtins,
2027
2031
  dialect,
2028
2032
  parserDialect,
2029
- extensions: [...(enableGutters ? [lineNumbers()] : []), EditorView.lineWrapping],
2033
+ extensions: [...(enableGutters ? [lineNumbers()] : []), EditorView.lineWrapping, EditorView.domEventHandlers({
2034
+ blur: handleBlur
2035
+ })],
2030
2036
  contentAttributes
2031
2037
  });
2032
2038
  setEditor(editor);
@@ -2495,19 +2501,23 @@ function FeelTextfield(props) {
2495
2501
  * @type { import('min-dash').DebouncedFunction }
2496
2502
  */
2497
2503
  const handleInput = useDebounce(onInput, debounce);
2504
+ const setAndCommitValue = newValue => {
2505
+ // cancel any pending debounced value
2506
+ handleInput.cancel?.();
2507
+ setLocalValue(newValue);
2508
+ onInput(newValue);
2509
+ };
2498
2510
  const handleFeelToggle = useStaticCallback(() => {
2499
2511
  if (feel === 'required') {
2500
2512
  return;
2501
2513
  }
2502
2514
  if (!feelActive) {
2503
- setLocalValue('=' + localValue);
2504
- handleInput('=' + localValue);
2515
+ setAndCommitValue('=' + localValue);
2505
2516
  } else {
2506
- setLocalValue(feelOnlyValue);
2507
- handleInput(feelOnlyValue);
2517
+ setAndCommitValue(feelOnlyValue);
2508
2518
  }
2509
2519
  });
2510
- const handleLocalInput = (newValue, useDebounce = true) => {
2520
+ const handleInputChange = newValue => {
2511
2521
  if (feelActive) {
2512
2522
  newValue = '=' + newValue;
2513
2523
  }
@@ -2515,28 +2525,32 @@ function FeelTextfield(props) {
2515
2525
  return;
2516
2526
  }
2517
2527
  setLocalValue(newValue);
2518
- if (useDebounce) {
2519
- handleInput(newValue);
2520
- } else {
2521
- onInput(newValue);
2522
- }
2528
+ handleInput(newValue);
2523
2529
  if (!feelActive && isString(newValue) && newValue.startsWith('=')) {
2524
2530
  // focus is behind `=` sign that will be removed
2525
2531
  setFocus(-1);
2526
2532
  }
2527
2533
  };
2528
- const handleOnBlur = e => {
2529
- handleInput.cancel?.();
2534
+ const handleOptionalInputOnBlur = e => {
2530
2535
  if (e.target.type === 'checkbox') {
2531
- onInput(e.target.checked);
2536
+ setAndCommitValue(e.target.checked);
2532
2537
  } else {
2533
2538
  const trimmedValue = e.target.value.trim();
2534
- handleLocalInput(trimmedValue, false);
2539
+ if (trimmedValue !== localValue) {
2540
+ // Trim changed the value — commit trimmed
2541
+ setAndCommitValue(trimmedValue);
2542
+ } else {
2543
+ // Value unchanged — flush any pending debounce
2544
+ handleInput.flush?.();
2545
+ }
2535
2546
  }
2536
2547
  if (onBlur) {
2537
2548
  onBlur(e);
2538
2549
  }
2539
2550
  };
2551
+ const handleFeelEditorOnBlur = () => {
2552
+ handleInput.flush?.();
2553
+ };
2540
2554
  const handleOnKeyDown = e => {
2541
2555
  if (isCmdWithChar(e)) {
2542
2556
  handleInput.flush?.();
@@ -2556,7 +2570,7 @@ function FeelTextfield(props) {
2556
2570
  entryId: id,
2557
2571
  hostLanguage,
2558
2572
  label,
2559
- onInput: handleLocalInput,
2573
+ onInput: handleInputChange,
2560
2574
  singleLine,
2561
2575
  sourceElement: editorRef.current,
2562
2576
  tooltipContainer,
@@ -2622,8 +2636,7 @@ function FeelTextfield(props) {
2622
2636
  if (isFieldEmpty || isAllSelected) {
2623
2637
  const textData = event.clipboardData.getData('text');
2624
2638
  const trimmedValue = textData.trim();
2625
- setLocalValue(trimmedValue);
2626
- handleInput(trimmedValue);
2639
+ setAndCommitValue(trimmedValue);
2627
2640
  if (!feelActive && isString(trimmedValue) && trimmedValue.startsWith('=')) {
2628
2641
  setFocus(trimmedValue.length - 1);
2629
2642
  }
@@ -2667,7 +2680,8 @@ function FeelTextfield(props) {
2667
2680
  onClick: handleFeelToggle
2668
2681
  }), feelActive ? jsx(FeelEditor, {
2669
2682
  name: id,
2670
- onInput: handleLocalInput,
2683
+ onInput: handleInputChange,
2684
+ onBlur: handleFeelEditorOnBlur,
2671
2685
  onKeyDown: handleOnKeyDown,
2672
2686
  contentAttributes: {
2673
2687
  'id': prefixId$5(id),
@@ -2690,9 +2704,9 @@ function FeelTextfield(props) {
2690
2704
  }) : jsx(OptionalComponent, {
2691
2705
  ...props,
2692
2706
  popupOpen: isPopupOpen,
2693
- onInput: handleLocalInput,
2707
+ onInput: handleInputChange,
2694
2708
  onKeyDown: handleOnKeyDown,
2695
- onBlur: handleOnBlur,
2709
+ onBlur: handleOptionalInputOnBlur,
2696
2710
  contentAttributes: {
2697
2711
  'id': prefixId$5(id),
2698
2712
  'aria-label': label