This is an automated email from the ASF dual-hosted git repository.

thiagoelg pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-tools.git


The following commit(s) were added to refs/heads/main by this push:
     new 10a99e1331b kie-issues#2323: BPMN Editor: Refactor TypeaheadSelect 
component using React's best practices (#3601)
10a99e1331b is described below

commit 10a99e1331bef7ea6cf20147d2d3d4a81516b0e8
Author: Thiago Lugli <[email protected]>
AuthorDate: Fri May 22 15:12:39 2026 -0300

    kie-issues#2323: BPMN Editor: Refactor TypeaheadSelect component using 
React's best practices (#3601)
---
 .vscode/settings.json                              |   1 +
 .../src/typeaheadSelect/TypeaheadSelect.tsx        | 417 ++++++++++++---------
 .../propertiesPanel/dataObjectPropertiesPanel.ts   |   1 +
 .../propertiesPanel/endEventPropertiesPanel.ts     |   4 +
 .../intermediateEventPropertiesPanel.ts            |   5 +
 .../propertiesPanel/parts/nameProperties.ts        |   4 +-
 .../propertiesPanel/startEventPropertiesPanel.ts   |   4 +
 .../exclusive-gateway-configured.png               | Bin 65614 -> 65400 bytes
 .../parallel-gateway-configured.png                | Bin 59459 -> 58970 bytes
 .../propertiesPanel/start-event-name-changed.png   | Bin 71181 -> 71125 bytes
 .../propertiesPanel/task-name-changed.png          | Bin 60827 -> 60867 bytes
 .../exclusive-gateway-configured.png               | Bin 65978 -> 65508 bytes
 .../parallel-gateway-configured.png                | Bin 60180 -> 59626 bytes
 .../propertiesPanel/start-event-name-changed.png   | Bin 71031 -> 70517 bytes
 .../chromium/propertiesPanel/task-name-changed.png | Bin 60162 -> 59912 bytes
 .../exclusive-gateway-configured.png               | Bin 70575 -> 71055 bytes
 .../parallel-gateway-configured.png                | Bin 64713 -> 63235 bytes
 .../propertiesPanel/start-event-name-changed.png   | Bin 67344 -> 67399 bytes
 .../webkit/propertiesPanel/task-name-changed.png   | Bin 56551 -> 55775 bytes
 19 files changed, 249 insertions(+), 187 deletions(-)

diff --git a/.vscode/settings.json b/.vscode/settings.json
index 144d864290c..7dfb9c81a82 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,4 +1,5 @@
 {
+  "js/ts.tsdk.path": 
"node_modules/.pnpm/[email protected]/node_modules/typescript/lib",
   "eslint.options": {
     "overrideConfigFile": "packages/eslint/.eslintrc.js"
   },
diff --git a/packages/bpmn-editor/src/typeaheadSelect/TypeaheadSelect.tsx 
b/packages/bpmn-editor/src/typeaheadSelect/TypeaheadSelect.tsx
index 47b2eeb510a..937c62e93c4 100644
--- a/packages/bpmn-editor/src/typeaheadSelect/TypeaheadSelect.tsx
+++ b/packages/bpmn-editor/src/typeaheadSelect/TypeaheadSelect.tsx
@@ -28,21 +28,31 @@ import {
 } from "@patternfly/react-core/dist/js/components/TextInputGroup";
 import { TimesIcon } from "@patternfly/react-icons/dist/js/icons/times-icon";
 import * as React from "react";
-import { useMemo } from "react";
+import { useCallback, useMemo } from "react";
 import "./TypeaheadSelect.css";
 import { Label } from "@patternfly/react-core/dist/js/components/Label";
 import { useBpmnEditorI18n } from "../i18n";
 
 export type TypeaheadSelectOption = SelectOptionProps & { customLabel?: string 
| React.ReactElement };
 
-const hasRenderableOptionLabel = (option: TypeaheadSelectOption) => {
-  return (
-    !!option.customLabel ||
-    React.isValidElement(option.children) ||
-    (option.children !== undefined && option.children !== null && 
String(option.children).trim().length > 0)
-  );
+const hasRenderableOptionLabel = (option: TypeaheadSelectOption): boolean => {
+  if (option.customLabel !== null && option.customLabel !== undefined) {
+    return true;
+  }
+  const { children } = option;
+  if (children === null || children === undefined || typeof children === 
"boolean") {
+    return false;
+  }
+  // React elements and arrays are objects — we can't inspect their text, but 
they're renderable
+  return typeof children === "object" || String(children).trim().length > 0;
 };
 
+// Handles undefined and non-string values (e.g. numbers) safely
+const getSelectOptionId = (value: string | number | undefined) =>
+  `select-typeahead-${String(value ?? "").replaceAll(" ", "-")}`;
+
+const POPPER_PROPS = { appendTo: document.body };
+
 // Based on 
https://v5-archive.patternfly.org/components/menus/select/#typeahead-with-create-option
 export function TypeaheadSelect({
   id,
@@ -77,18 +87,17 @@ export function TypeaheadSelect({
 }) {
   const { i18n } = useBpmnEditorI18n();
   const [isOpen, setIsOpen] = React.useState(false);
-  const [inputValue, setInputValue] = React.useState<string | undefined>();
+  const [inputValue, setInputValue] = React.useState("");
   const [filterValue, setFilterValue] = React.useState<string>("");
   const [focusedItemIndex, setFocusedItemIndex] = React.useState<number | 
null>(null);
   const [activeItemId, setActiveItemId] = React.useState<string | null>(null);
-  const textInputRef = React.useRef<HTMLInputElement>();
-  const keepOpenRef = React.useRef(false);
+  const textInputRef = React.useRef<HTMLInputElement>(null);
 
   const CREATE_NEW = useMemo(() => generateUuid(), []);
 
   React.useEffect(() => {
     const optionText = options.find((option) => option.value === 
selected)?.children;
-    setInputValue(optionText as string);
+    setInputValue(typeof optionText === "string" ? optionText : "");
     setFilterValue("");
   }, [options, selected]);
 
@@ -133,226 +142,266 @@ export function TypeaheadSelect({
     () => renderableOptions.some((option) => option.value === selected),
     [renderableOptions, selected]
   );
-  const safeSelected = selectedOptionExists ? selected : undefined;
 
-  const getSelectOptionId = (value: any) => 
`select-typeahead-${value?.replace(" ", "-")}`;
+  const safeSelected = useMemo(() => (selectedOptionExists ? selected : 
undefined), [selected, selectedOptionExists]);
 
-  const setActiveAndFocusedItem = (itemIndex: number) => {
-    setFocusedItemIndex(itemIndex);
-    const focusedItem = selectOptions[itemIndex];
-    setActiveItemId(getSelectOptionId(focusedItem.value));
-  };
+  const setActiveAndFocusedItem = useCallback(
+    (itemIndex: number) => {
+      setFocusedItemIndex(itemIndex);
+      const focusedItem = selectOptions[itemIndex];
+      setActiveItemId(getSelectOptionId(focusedItem.value));
+    },
+    [selectOptions]
+  );
 
-  const resetActiveAndFocusedItem = () => {
+  const resetActiveAndFocusedItem = useCallback(() => {
     setFocusedItemIndex(null);
     setActiveItemId(null);
-  };
+  }, []);
 
-  const closeMenu = () => {
+  const closeMenu = useCallback(() => {
     if (closeAfterSelect ?? true) {
       setIsOpen(false);
       resetActiveAndFocusedItem();
     }
-  };
+  }, [closeAfterSelect, resetActiveAndFocusedItem]);
 
-  const onInputClick = () => {
+  const onInputClick = useCallback(() => {
     if (!isOpen) {
       setIsOpen(true);
     } else if (!inputValue) {
       closeMenu();
     }
-  };
-
-  const onSelect = (_event: React.MouseEvent<Element, MouseEvent> | undefined, 
value: string | number | undefined) => {
-    if (value) {
-      if (value === CREATE_NEW) {
-        const newOptionLabel = filterValue;
-        const newValue = onCreateNewOption?.(newOptionLabel);
-        setSelected(newValue, newOptionLabel, { triggeredByCreateNewOption: 
true });
-
-        if (isMultiple) {
-          keepOpenRef.current = true;
-          setInputValue("");
+  }, [closeMenu, inputValue, isOpen]);
+
+  const onSelect = useCallback(
+    (_event: React.MouseEvent<Element, MouseEvent> | undefined, value: string 
| number | undefined) => {
+      if (value) {
+        if (value === CREATE_NEW) {
+          const newOptionLabel = filterValue;
+          const newValue = onCreateNewOption?.(newOptionLabel);
+          setSelected(newValue, newOptionLabel, { triggeredByCreateNewOption: 
true });
+
+          if (isMultiple) {
+            setInputValue("");
+            // PF's window click listener sees the CREATE_NEW <li> as detached 
after
+            // React's synchronous re-render and calls onOpenChange(false). 
Re-open in
+            // the next macrotask so the dropdown stays visible after adding a 
custom tag.
+            setTimeout(() => {
+              setIsOpen(true);
+              setFilterValue("");
+            }, 0);
+            return;
+          } else {
+            setInputValue(newOptionLabel);
+            closeMenu();
+          }
+        } else if (isMultiple) {
+          const optionText = selectOptions.find((option) => option.value === 
value)?.children;
+          setSelected(String(value), String(optionText), { 
triggeredByCreateNewOption: false });
         } else {
-          setInputValue(newOptionLabel);
+          const optionText = selectOptions.find((option) => option.value === 
value)?.children;
+          setInputValue(typeof optionText === "string" ? optionText : "");
+          setSelected(String(value), String(optionText), { 
triggeredByCreateNewOption: false });
           closeMenu();
         }
-      } else if (isMultiple) {
-        keepOpenRef.current = true;
-        const optionText = selectOptions.find((option) => option.value === 
value)?.children;
-        setSelected(String(value), String(optionText), { 
triggeredByCreateNewOption: false });
-      } else {
-        const optionText = selectOptions.find((option) => option.value === 
value)?.children;
-        setInputValue(String(optionText));
-        setSelected(String(value), String(optionText), { 
triggeredByCreateNewOption: false });
-        closeMenu();
+        setFilterValue("");
       }
-      setFilterValue("");
-    }
-  };
-
-  const onTextInputChange = (_event: React.FormEvent<HTMLInputElement>, value: 
string) => {
-    setInputValue(value);
-    setFilterValue(value);
+    },
+    [CREATE_NEW, closeMenu, filterValue, isMultiple, onCreateNewOption, 
selectOptions, setSelected]
+  );
 
-    if (!isOpen && value) {
-      setIsOpen(true);
-    }
+  const onTextInputChange = useCallback(
+    (_event: React.FormEvent<HTMLInputElement>, value: string) => {
+      setInputValue(value);
+      setFilterValue(value);
 
-    resetActiveAndFocusedItem();
-    setActiveAndFocusedItem(0);
-  };
+      if (!isOpen && value) {
+        setIsOpen(true);
+      }
 
-  const handleMenuArrowKeys = (key: string) => {
-    let indexToFocus = 0;
+      resetActiveAndFocusedItem();
+      if (selectOptions.length > 0) {
+        setActiveAndFocusedItem(0);
+      }
+    },
+    [isOpen, resetActiveAndFocusedItem, selectOptions, setActiveAndFocusedItem]
+  );
 
-    if (!isOpen) {
-      setIsOpen(true);
-    }
+  const handleMenuArrowKeys = useCallback(
+    (key: string) => {
+      let indexToFocus = 0;
 
-    if (selectOptions.every((option) => option.isDisabled)) {
-      return;
-    }
+      if (!isOpen) {
+        setIsOpen(true);
+      }
 
-    if (key === "ArrowUp") {
-      // When no index is set or at the first index, focus to the last, 
otherwise decrement focus index
-      if (focusedItemIndex === null || focusedItemIndex === 0) {
-        indexToFocus = selectOptions.length - 1;
-      } else {
-        indexToFocus = focusedItemIndex - 1;
+      if (selectOptions.every((option) => option.isDisabled)) {
+        return;
       }
 
-      // Skip disabled options
-      while (selectOptions[indexToFocus].isDisabled) {
-        indexToFocus--;
-        if (indexToFocus === -1) {
+      if (key === "ArrowUp") {
+        // When no index is set or at the first index, focus to the last, 
otherwise decrement focus index
+        if (focusedItemIndex === null || focusedItemIndex === 0) {
           indexToFocus = selectOptions.length - 1;
+        } else {
+          indexToFocus = focusedItemIndex - 1;
         }
-      }
-    }
 
-    if (key === "ArrowDown") {
-      // When no index is set or at the last index, focus to the first, 
otherwise increment focus index
-      if (focusedItemIndex === null || focusedItemIndex === 
selectOptions.length - 1) {
-        indexToFocus = 0;
-      } else {
-        indexToFocus = focusedItemIndex + 1;
+        // Skip disabled options
+        while (selectOptions[indexToFocus].isDisabled) {
+          indexToFocus--;
+          if (indexToFocus === -1) {
+            indexToFocus = selectOptions.length - 1;
+          }
+        }
       }
 
-      // Skip disabled options
-      while (selectOptions[indexToFocus].isDisabled) {
-        indexToFocus++;
-        if (indexToFocus === selectOptions.length) {
+      if (key === "ArrowDown") {
+        // When no index is set or at the last index, focus to the first, 
otherwise increment focus index
+        if (focusedItemIndex === null || focusedItemIndex === 
selectOptions.length - 1) {
           indexToFocus = 0;
+        } else {
+          indexToFocus = focusedItemIndex + 1;
         }
-      }
-    }
 
-    setActiveAndFocusedItem(indexToFocus);
-  };
-
-  const onInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
-    const focusedItem = focusedItemIndex !== null ? 
selectOptions[focusedItemIndex] : null;
-
-    switch (event.key) {
-      case "Enter":
-        if (isOpen && focusedItem && !focusedItem.isAriaDisabled) {
-          event.stopPropagation();
-          event.preventDefault();
-          onSelect(undefined, focusedItem.value as string);
+        // Skip disabled options
+        while (selectOptions[indexToFocus].isDisabled) {
+          indexToFocus++;
+          if (indexToFocus === selectOptions.length) {
+            indexToFocus = 0;
+          }
         }
+      }
 
-        if (!isOpen) {
-          setIsOpen(true);
-        }
+      setActiveAndFocusedItem(indexToFocus);
+    },
+    [focusedItemIndex, isOpen, selectOptions, setActiveAndFocusedItem]
+  );
 
-        break;
-      case "Escape":
-        if (isOpen) {
-          event.stopPropagation();
+  const onInputKeyDown = useCallback(
+    (event: React.KeyboardEvent<HTMLInputElement>) => {
+      const focusedItem = focusedItemIndex !== null ? 
selectOptions[focusedItemIndex] : null;
+
+      switch (event.key) {
+        case "Enter":
+          if (isOpen && focusedItem && !focusedItem.isAriaDisabled) {
+            event.stopPropagation();
+            event.preventDefault();
+            onSelect(undefined, focusedItem.value as string);
+          }
+
+          if (!isOpen) {
+            setIsOpen(true);
+          }
+
+          break;
+        case "Escape":
+          if (isOpen) {
+            event.stopPropagation();
+            event.preventDefault();
+
+            setIsOpen(false);
+            const optionText = options.find((option) => option.value === 
selected)?.children;
+            setInputValue(typeof optionText === "string" ? optionText : "");
+            setFilterValue("");
+          }
+          break;
+        case "ArrowUp":
+        case "ArrowDown":
           event.preventDefault();
+          handleMenuArrowKeys(event.key);
+          break;
+      }
+    },
+    [focusedItemIndex, handleMenuArrowKeys, isOpen, onSelect, options, 
selectOptions, selected]
+  );
 
-          // Blur
-          setIsOpen(false);
-          const optionText = options.find((option) => option.value === 
selected)?.children;
-          setInputValue(optionText as string);
-          setFilterValue("");
-        }
-        break;
-      case "ArrowUp":
-      case "ArrowDown":
-        event.preventDefault();
-        handleMenuArrowKeys(event.key);
-        break;
-    }
-  };
-
-  const onToggleClick = () => {
-    setIsOpen(!isOpen);
-    textInputRef?.current?.focus();
-  };
+  const onToggleClick = useCallback(() => {
+    setIsOpen((prev) => !prev);
+    textInputRef.current?.focus();
+  }, []);
 
-  const onClearButtonClick = () => {
+  const onClearButtonClick = useCallback(() => {
     setSelected(undefined, undefined, { triggeredByCreateNewOption: false });
     setInputValue("");
     setFilterValue("");
     resetActiveAndFocusedItem();
     textInputRef?.current?.focus();
-  };
+  }, [resetActiveAndFocusedItem, setSelected]);
 
-  const onBlur = () => {
+  const onBlur = useCallback(() => {
     const optionText = options.find((option) => option.value === 
selected)?.children;
-    setInputValue(optionText as string);
+    setInputValue(typeof optionText === "string" ? optionText : "");
     setFilterValue("");
-  };
+  }, [options, selected]);
 
-  const onOpenChange = (nextOpen: boolean) => {
-    if (!nextOpen && keepOpenRef.current) {
-      keepOpenRef.current = false;
-      return;
-    }
-    setIsOpen(nextOpen);
-    if (!nextOpen) {
-      resetActiveAndFocusedItem();
-    }
-  };
-
-  const toggle = (toggleRef: React.Ref<MenuToggleElement>) => (
-    <MenuToggle
-      ref={toggleRef}
-      variant={"typeahead"}
-      aria-label={"Typeahead creatable menu toggle"}
-      onClick={onToggleClick}
-      isExpanded={isOpen}
-      isDisabled={isDisabled}
-      isFullWidth={true}
-    >
-      <TextInputGroup isPlain>
-        <TextInputGroupMain
-          value={inputValue}
-          onClick={onInputClick}
-          onChange={onTextInputChange}
-          onKeyDown={onInputKeyDown}
-          onBlur={onBlur}
-          id={"create-typeahead-select-input"}
-          autoComplete={"off"}
-          innerRef={textInputRef}
-          placeholder={placeholder ?? i18n.propertiesPanel.undefined}
-          {...(activeItemId && { "aria-activedescendant": activeItemId })}
-          role={"combobox"}
-          isExpanded={isOpen}
-          aria-controls={"select-create-typeahead-listbox"}
-          style={{ flexWrap: "nowrap" }}
-        >
-          {isMultiple && <Label>{options.filter((s) => 
s.isSelected).length}</Label>}
-        </TextInputGroupMain>
-        <TextInputGroupUtilities {...(!inputValue ? { style: { display: "none" 
} } : {})}>
-          <Button variant="plain" onClick={onClearButtonClick} 
aria-label="Clear input value">
-            <TimesIcon aria-hidden />
-          </Button>
-        </TextInputGroupUtilities>
-      </TextInputGroup>
-    </MenuToggle>
+  const onOpenChange = useCallback(
+    (nextOpen: boolean) => {
+      setIsOpen(nextOpen);
+      if (!nextOpen) {
+        resetActiveAndFocusedItem();
+      }
+    },
+    [resetActiveAndFocusedItem]
+  );
+
+  const onSelectListMouseDown = useCallback((e: React.MouseEvent) => 
e.preventDefault(), []);
+
+  const toggle = useCallback(
+    (toggleRef: React.Ref<MenuToggleElement>) => (
+      <MenuToggle
+        ref={toggleRef}
+        variant={"typeahead"}
+        aria-label={"Typeahead creatable menu toggle"}
+        onClick={onToggleClick}
+        isExpanded={isOpen}
+        isDisabled={isDisabled}
+        isFullWidth={true}
+      >
+        <TextInputGroup isPlain>
+          <TextInputGroupMain
+            value={inputValue}
+            onClick={onInputClick}
+            onChange={onTextInputChange}
+            onKeyDown={onInputKeyDown}
+            onBlur={onBlur}
+            id={"create-typeahead-select-input"}
+            autoComplete={"off"}
+            innerRef={textInputRef}
+            placeholder={placeholder ?? i18n.propertiesPanel.undefined}
+            {...(activeItemId && { "aria-activedescendant": activeItemId })}
+            role={"combobox"}
+            isExpanded={isOpen}
+            aria-controls={"select-create-typeahead-listbox"}
+            style={{ flexWrap: "nowrap" }}
+          >
+            {isMultiple && <Label>{options.filter((s) => 
s.isSelected).length}</Label>}
+          </TextInputGroupMain>
+          <TextInputGroupUtilities {...(!inputValue ? { style: { display: 
"none" } } : {})}>
+            <Button variant="plain" onClick={onClearButtonClick} 
aria-label="Clear input value">
+              <TimesIcon aria-hidden />
+            </Button>
+          </TextInputGroupUtilities>
+        </TextInputGroup>
+      </MenuToggle>
+    ),
+    [
+      activeItemId,
+      i18n.propertiesPanel.undefined,
+      inputValue,
+      isDisabled,
+      isMultiple,
+      isOpen,
+      onBlur,
+      onClearButtonClick,
+      onInputClick,
+      onInputKeyDown,
+      onTextInputChange,
+      onToggleClick,
+      options,
+      placeholder,
+    ]
   );
 
   return (
@@ -363,13 +412,11 @@ export function TypeaheadSelect({
       onSelect={onSelect}
       className={"kie-bpmn-editor--typeahead-selector"}
       onOpenChange={onOpenChange}
-      popperProps={{
-        appendTo: document.body,
-      }}
+      popperProps={POPPER_PROPS}
       toggle={toggle}
       shouldFocusFirstItemOnOpen={false}
     >
-      <SelectList id="select-create-typeahead-listbox" onMouseDown={(e) => 
e.preventDefault()}>
+      <SelectList id="select-create-typeahead-listbox" 
onMouseDown={onSelectListMouseDown}>
         {selectOptions.length <= 0 && (
           <>
             {(!filterValue && (
@@ -387,7 +434,7 @@ export function TypeaheadSelect({
           const { children, customLabel, ...option } = { ..._option };
           return (
             <SelectOption
-              key={option.value || children}
+              key={String(option.value ?? index)}
               isFocused={focusedItemIndex === index}
               className={option.className}
               id={getSelectOptionId(option.value)}
diff --git 
a/packages/bpmn-editor/tests-e2e/__fixtures__/propertiesPanel/dataObjectPropertiesPanel.ts
 
b/packages/bpmn-editor/tests-e2e/__fixtures__/propertiesPanel/dataObjectPropertiesPanel.ts
index 5c3e0ec3025..1e7cda3e8ab 100644
--- 
a/packages/bpmn-editor/tests-e2e/__fixtures__/propertiesPanel/dataObjectPropertiesPanel.ts
+++ 
b/packages/bpmn-editor/tests-e2e/__fixtures__/propertiesPanel/dataObjectPropertiesPanel.ts
@@ -40,6 +40,7 @@ export class DataObjectPropertiesPanel extends 
PropertiesPanelBase {
     } else {
       await this.page.getByRole("option", { name: args.itemSubjectRef, exact: 
true }).click();
     }
+    await this.panel().getByRole("combobox").first().blur();
   }
 
   public async getItemSubjectRef(): Promise<string> {
diff --git 
a/packages/bpmn-editor/tests-e2e/__fixtures__/propertiesPanel/endEventPropertiesPanel.ts
 
b/packages/bpmn-editor/tests-e2e/__fixtures__/propertiesPanel/endEventPropertiesPanel.ts
index fd7bbad88a5..18d25d63fac 100644
--- 
a/packages/bpmn-editor/tests-e2e/__fixtures__/propertiesPanel/endEventPropertiesPanel.ts
+++ 
b/packages/bpmn-editor/tests-e2e/__fixtures__/propertiesPanel/endEventPropertiesPanel.ts
@@ -55,6 +55,7 @@ export class EndEventPropertiesPanel extends 
PropertiesPanelBase {
     } else {
       await this.page.getByRole("option", { name: args.messageName, exact: 
true }).click();
     }
+    await this.panel().getByRole("combobox").first().blur();
   }
 
   public async setSignalDefinition(args: { signalName: string; 
endEventLocator: Locator }) {
@@ -70,6 +71,7 @@ export class EndEventPropertiesPanel extends 
PropertiesPanelBase {
     } else {
       await this.page.getByRole("option", { name: args.signalName, exact: true 
}).click();
     }
+    await this.panel().getByRole("combobox").first().blur();
   }
 
   public async getSignalName(): Promise<string> {
@@ -90,6 +92,7 @@ export class EndEventPropertiesPanel extends 
PropertiesPanelBase {
     } else {
       await this.page.getByRole("option", { name: args.errorName, exact: true 
}).click();
     }
+    await this.panel().getByRole("combobox").first().blur();
 
     if (args.errorCode) {
       const errorCodeInput = this.panel().getByPlaceholder("Error code");
@@ -130,6 +133,7 @@ export class EndEventPropertiesPanel extends 
PropertiesPanelBase {
     } else {
       await this.page.getByRole("option", { name: args.escalationName, exact: 
true }).click();
     }
+    await this.panel().getByRole("combobox").first().blur();
 
     if (args.escalationCode) {
       const escalationCodeInput = this.panel().getByPlaceholder("Escalation 
code");
diff --git 
a/packages/bpmn-editor/tests-e2e/__fixtures__/propertiesPanel/intermediateEventPropertiesPanel.ts
 
b/packages/bpmn-editor/tests-e2e/__fixtures__/propertiesPanel/intermediateEventPropertiesPanel.ts
index d64748df3f4..653ce5b2d20 100644
--- 
a/packages/bpmn-editor/tests-e2e/__fixtures__/propertiesPanel/intermediateEventPropertiesPanel.ts
+++ 
b/packages/bpmn-editor/tests-e2e/__fixtures__/propertiesPanel/intermediateEventPropertiesPanel.ts
@@ -76,6 +76,7 @@ export class IntermediateEventPropertiesPanel extends 
PropertiesPanelBase {
     } else {
       await this.page.getByRole("option", { name: args.messageName, exact: 
true }).click();
     }
+    await this.panel().getByRole("combobox").first().blur();
   }
 
   public async setSignalDefinition(args: {
@@ -94,6 +95,7 @@ export class IntermediateEventPropertiesPanel extends 
PropertiesPanelBase {
     } else {
       await this.page.getByRole("option", { name: args.signalName, exact: true 
}).click();
     }
+    await this.panel().getByRole("combobox").first().blur();
 
     if (args.scope) {
       const scopeSelect = this.panel().getByRole("combobox").nth(1);
@@ -146,6 +148,7 @@ export class IntermediateEventPropertiesPanel extends 
PropertiesPanelBase {
     } else {
       await this.page.getByRole("option", { name: args.errorName, exact: true 
}).click();
     }
+    await this.panel().getByRole("combobox").first().blur();
 
     if (args.errorCode) {
       const errorCodeInput = this.panel().getByRole("textbox").nth(1);
@@ -172,6 +175,7 @@ export class IntermediateEventPropertiesPanel extends 
PropertiesPanelBase {
     } else {
       await this.page.getByRole("option", { name: args.escalationName, exact: 
true }).click();
     }
+    await this.panel().getByRole("combobox").first().blur();
 
     if (args.escalationCode) {
       const escalationCodeInput = this.panel().getByRole("textbox").nth(1);
@@ -197,6 +201,7 @@ export class IntermediateEventPropertiesPanel extends 
PropertiesPanelBase {
       if (optionCount > 0 && (await option.isVisible())) {
         await option.click();
       }
+      await this.panel().getByRole("combobox").first().blur();
     }
   }
 
diff --git 
a/packages/bpmn-editor/tests-e2e/__fixtures__/propertiesPanel/parts/nameProperties.ts
 
b/packages/bpmn-editor/tests-e2e/__fixtures__/propertiesPanel/parts/nameProperties.ts
index 6c9f35b489f..117f45ee2ac 100644
--- 
a/packages/bpmn-editor/tests-e2e/__fixtures__/propertiesPanel/parts/nameProperties.ts
+++ 
b/packages/bpmn-editor/tests-e2e/__fixtures__/propertiesPanel/parts/nameProperties.ts
@@ -28,7 +28,7 @@ export class NameProperties {
   public async setName(args: { newName: string }) {
     const nameInput = this.panel.getByPlaceholder("Enter a name...");
     await nameInput.fill(args.newName);
-    await this.page.keyboard.press("Enter");
+    await nameInput.blur();
   }
 
   public async getName(): Promise<string> {
@@ -39,6 +39,6 @@ export class NameProperties {
   public async clearName() {
     const nameInput = this.panel.getByPlaceholder("Enter a name...");
     await nameInput.clear();
-    await this.page.keyboard.press("Enter");
+    await nameInput.blur();
   }
 }
diff --git 
a/packages/bpmn-editor/tests-e2e/__fixtures__/propertiesPanel/startEventPropertiesPanel.ts
 
b/packages/bpmn-editor/tests-e2e/__fixtures__/propertiesPanel/startEventPropertiesPanel.ts
index 2bc6116a6e6..b90306b151d 100644
--- 
a/packages/bpmn-editor/tests-e2e/__fixtures__/propertiesPanel/startEventPropertiesPanel.ts
+++ 
b/packages/bpmn-editor/tests-e2e/__fixtures__/propertiesPanel/startEventPropertiesPanel.ts
@@ -117,6 +117,7 @@ export class StartEventPropertiesPanel extends 
PropertiesPanelBase {
     } else {
       await this.page.getByRole("option", { name: args.messageName, exact: 
true }).click();
     }
+    await this.panel().getByRole("combobox").first().blur();
   }
 
   public async setSignalDefinition(args: { signalName: string; 
startEventLocator: Locator }) {
@@ -132,6 +133,7 @@ export class StartEventPropertiesPanel extends 
PropertiesPanelBase {
     } else {
       await this.page.getByRole("option", { name: args.signalName, exact: true 
}).click();
     }
+    await this.panel().getByRole("combobox").first().blur();
   }
 
   public async setConditionalExpression(args: { expression: string; 
startEventLocator: Locator }) {
@@ -160,6 +162,7 @@ export class StartEventPropertiesPanel extends 
PropertiesPanelBase {
     } else {
       await this.page.getByRole("option", { name: args.errorName, exact: true 
}).click();
     }
+    await this.panel().getByRole("combobox").first().blur();
   }
 
   public async getErrorName(): Promise<string> {
@@ -180,6 +183,7 @@ export class StartEventPropertiesPanel extends 
PropertiesPanelBase {
     } else {
       await this.page.getByRole("option", { name: args.escalationName, exact: 
true }).click();
     }
+    await this.panel().getByRole("combobox").first().blur();
   }
 
   public async getEscalationName(): Promise<string> {
diff --git 
a/packages/bpmn-editor/tests-e2e/__screenshots__/Google-Chrome/propertiesPanel/exclusive-gateway-configured.png
 
b/packages/bpmn-editor/tests-e2e/__screenshots__/Google-Chrome/propertiesPanel/exclusive-gateway-configured.png
index 07d1bbae9bb..6a78838c7b0 100644
Binary files 
a/packages/bpmn-editor/tests-e2e/__screenshots__/Google-Chrome/propertiesPanel/exclusive-gateway-configured.png
 and 
b/packages/bpmn-editor/tests-e2e/__screenshots__/Google-Chrome/propertiesPanel/exclusive-gateway-configured.png
 differ
diff --git 
a/packages/bpmn-editor/tests-e2e/__screenshots__/Google-Chrome/propertiesPanel/parallel-gateway-configured.png
 
b/packages/bpmn-editor/tests-e2e/__screenshots__/Google-Chrome/propertiesPanel/parallel-gateway-configured.png
index 0210203953c..f9919357ed9 100644
Binary files 
a/packages/bpmn-editor/tests-e2e/__screenshots__/Google-Chrome/propertiesPanel/parallel-gateway-configured.png
 and 
b/packages/bpmn-editor/tests-e2e/__screenshots__/Google-Chrome/propertiesPanel/parallel-gateway-configured.png
 differ
diff --git 
a/packages/bpmn-editor/tests-e2e/__screenshots__/Google-Chrome/propertiesPanel/start-event-name-changed.png
 
b/packages/bpmn-editor/tests-e2e/__screenshots__/Google-Chrome/propertiesPanel/start-event-name-changed.png
index 1a653bacf63..51dfd23ab98 100644
Binary files 
a/packages/bpmn-editor/tests-e2e/__screenshots__/Google-Chrome/propertiesPanel/start-event-name-changed.png
 and 
b/packages/bpmn-editor/tests-e2e/__screenshots__/Google-Chrome/propertiesPanel/start-event-name-changed.png
 differ
diff --git 
a/packages/bpmn-editor/tests-e2e/__screenshots__/Google-Chrome/propertiesPanel/task-name-changed.png
 
b/packages/bpmn-editor/tests-e2e/__screenshots__/Google-Chrome/propertiesPanel/task-name-changed.png
index 5e2d4789125..08f33c661db 100644
Binary files 
a/packages/bpmn-editor/tests-e2e/__screenshots__/Google-Chrome/propertiesPanel/task-name-changed.png
 and 
b/packages/bpmn-editor/tests-e2e/__screenshots__/Google-Chrome/propertiesPanel/task-name-changed.png
 differ
diff --git 
a/packages/bpmn-editor/tests-e2e/__screenshots__/chromium/propertiesPanel/exclusive-gateway-configured.png
 
b/packages/bpmn-editor/tests-e2e/__screenshots__/chromium/propertiesPanel/exclusive-gateway-configured.png
index a0704cd4971..4ccfc3c1ec5 100644
Binary files 
a/packages/bpmn-editor/tests-e2e/__screenshots__/chromium/propertiesPanel/exclusive-gateway-configured.png
 and 
b/packages/bpmn-editor/tests-e2e/__screenshots__/chromium/propertiesPanel/exclusive-gateway-configured.png
 differ
diff --git 
a/packages/bpmn-editor/tests-e2e/__screenshots__/chromium/propertiesPanel/parallel-gateway-configured.png
 
b/packages/bpmn-editor/tests-e2e/__screenshots__/chromium/propertiesPanel/parallel-gateway-configured.png
index 0325ee2d8ea..a5da5440705 100644
Binary files 
a/packages/bpmn-editor/tests-e2e/__screenshots__/chromium/propertiesPanel/parallel-gateway-configured.png
 and 
b/packages/bpmn-editor/tests-e2e/__screenshots__/chromium/propertiesPanel/parallel-gateway-configured.png
 differ
diff --git 
a/packages/bpmn-editor/tests-e2e/__screenshots__/chromium/propertiesPanel/start-event-name-changed.png
 
b/packages/bpmn-editor/tests-e2e/__screenshots__/chromium/propertiesPanel/start-event-name-changed.png
index b20525d4446..59580137eb9 100644
Binary files 
a/packages/bpmn-editor/tests-e2e/__screenshots__/chromium/propertiesPanel/start-event-name-changed.png
 and 
b/packages/bpmn-editor/tests-e2e/__screenshots__/chromium/propertiesPanel/start-event-name-changed.png
 differ
diff --git 
a/packages/bpmn-editor/tests-e2e/__screenshots__/chromium/propertiesPanel/task-name-changed.png
 
b/packages/bpmn-editor/tests-e2e/__screenshots__/chromium/propertiesPanel/task-name-changed.png
index a86ca10eb8e..23bda5996bb 100644
Binary files 
a/packages/bpmn-editor/tests-e2e/__screenshots__/chromium/propertiesPanel/task-name-changed.png
 and 
b/packages/bpmn-editor/tests-e2e/__screenshots__/chromium/propertiesPanel/task-name-changed.png
 differ
diff --git 
a/packages/bpmn-editor/tests-e2e/__screenshots__/webkit/propertiesPanel/exclusive-gateway-configured.png
 
b/packages/bpmn-editor/tests-e2e/__screenshots__/webkit/propertiesPanel/exclusive-gateway-configured.png
index ab25d219b8f..9cbad9d991b 100644
Binary files 
a/packages/bpmn-editor/tests-e2e/__screenshots__/webkit/propertiesPanel/exclusive-gateway-configured.png
 and 
b/packages/bpmn-editor/tests-e2e/__screenshots__/webkit/propertiesPanel/exclusive-gateway-configured.png
 differ
diff --git 
a/packages/bpmn-editor/tests-e2e/__screenshots__/webkit/propertiesPanel/parallel-gateway-configured.png
 
b/packages/bpmn-editor/tests-e2e/__screenshots__/webkit/propertiesPanel/parallel-gateway-configured.png
index bcd5e350ca3..ec31e233a16 100644
Binary files 
a/packages/bpmn-editor/tests-e2e/__screenshots__/webkit/propertiesPanel/parallel-gateway-configured.png
 and 
b/packages/bpmn-editor/tests-e2e/__screenshots__/webkit/propertiesPanel/parallel-gateway-configured.png
 differ
diff --git 
a/packages/bpmn-editor/tests-e2e/__screenshots__/webkit/propertiesPanel/start-event-name-changed.png
 
b/packages/bpmn-editor/tests-e2e/__screenshots__/webkit/propertiesPanel/start-event-name-changed.png
index fce04f4c1d5..5a76b824ed9 100644
Binary files 
a/packages/bpmn-editor/tests-e2e/__screenshots__/webkit/propertiesPanel/start-event-name-changed.png
 and 
b/packages/bpmn-editor/tests-e2e/__screenshots__/webkit/propertiesPanel/start-event-name-changed.png
 differ
diff --git 
a/packages/bpmn-editor/tests-e2e/__screenshots__/webkit/propertiesPanel/task-name-changed.png
 
b/packages/bpmn-editor/tests-e2e/__screenshots__/webkit/propertiesPanel/task-name-changed.png
index 3532ff05230..81f65750a33 100644
Binary files 
a/packages/bpmn-editor/tests-e2e/__screenshots__/webkit/propertiesPanel/task-name-changed.png
 and 
b/packages/bpmn-editor/tests-e2e/__screenshots__/webkit/propertiesPanel/task-name-changed.png
 differ


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to