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]