Skip to content

Commit 9e6f0f3

Browse files
committed
feat(Dropdown): Add optional container with ouiaId
Container component can be customized via a prop as well. Container does not render if containerOuiaId is not used, so as not to break existing consumers.
1 parent fe63802 commit 9e6f0f3

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

packages/react-core/src/components/Dropdown/Dropdown.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ export interface DropdownProps extends MenuProps, OUIAProps {
6363
ouiaId?: number | string;
6464
/** Set the value of data-ouia-safe. Only set to true when the component is in a static state, i.e. no animations are occurring. At all other times, this value must be false. */
6565
ouiaSafe?: boolean;
66+
/** When applied, wraps dropdown in a container with a data-ouia-component-id.*/
67+
containerOuiaId?: number | string;
68+
/** Set the value of data-ouia-safe for the container when containerOuiaId is applied. Only set to true when the component is in a static state, i.e. no animations are occurring. At all other times, this value must be false. */
69+
containerOuiaSafe?: boolean;
70+
/** Sets the base component to render for the container. Defaults to <span> */
71+
containerComponent?: React.ReactNode;
6672
/** z-index of the dropdown menu */
6773
zIndex?: number;
6874
/** Additional properties to pass to the Popper */
@@ -101,11 +107,16 @@ const DropdownBase: React.FunctionComponent<DropdownProps> = ({
101107
shouldFocusFirstItemOnOpen = false,
102108
shouldPreventScrollOnItemFocus = true,
103109
focusTimeoutDelay = 0,
110+
containerOuiaId,
111+
containerOuiaSafe = true,
112+
containerComponent = 'span',
104113
...props
105114
}: DropdownProps) => {
106115
const localMenuRef = useRef<HTMLDivElement>(undefined);
107116
const localToggleRef = useRef<HTMLButtonElement>(undefined);
108117
const ouiaProps = useOUIAProps(Dropdown.displayName, ouiaId, ouiaSafe);
118+
const ContainerComponent = containerComponent as any;
119+
const containerOuiaProps = useOUIAProps(Dropdown.displayName, containerOuiaId, containerOuiaSafe);
109120

110121
const menuRef = (innerRef as React.RefObject<HTMLDivElement | null>) || localMenuRef;
111122
const toggleRef =
@@ -200,7 +211,8 @@ const DropdownBase: React.FunctionComponent<DropdownProps> = ({
200211
</MenuContent>
201212
</Menu>
202213
);
203-
return (
214+
215+
const popper = (
204216
<Popper
205217
trigger={typeof toggle === 'function' ? toggle(toggleRef) : toggle.toggleNode}
206218
triggerRef={toggleRef}
@@ -211,6 +223,8 @@ const DropdownBase: React.FunctionComponent<DropdownProps> = ({
211223
{...popperProps}
212224
/>
213225
);
226+
227+
return containerOuiaId ? <ContainerComponent {...containerOuiaProps}>{popper}</ContainerComponent> : popper;
214228
};
215229

216230
export const Dropdown = forwardRef((props: DropdownProps, ref: React.Ref<any>) => (

packages/react-core/src/components/Dropdown/__tests__/Dropdown.test.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,32 @@ test('onOpenChange is called when passed and user presses esc key', async () =>
201201
expect(onOpenChange).toBeCalledTimes(1);
202202
});
203203

204+
test('applies containerOuiaId to parent element', () => {
205+
render(
206+
<Dropdown containerOuiaId="test-dropdown" toggle={(toggleRef) => toggle(toggleRef)}>
207+
{dropdownChildren}
208+
</Dropdown>
209+
);
210+
211+
const dropdownToggle = screen.getByRole('button', { name: 'Dropdown' });
212+
const dropdownParent = dropdownToggle?.parentNode?.parentNode;
213+
expect(dropdownParent).toHaveAttribute('data-ouia-component-id', 'test-dropdown');
214+
expect(dropdownParent).toHaveAttribute('data-ouia-component-type', 'PF6/Dropdown');
215+
expect(dropdownParent?.tagName).toBe('SPAN');
216+
});
217+
218+
test('applies containerOuiaId to parent element', () => {
219+
render(
220+
<Dropdown containerOuiaId="test-dropdown" containerComponent="div" toggle={(toggleRef) => toggle(toggleRef)}>
221+
{dropdownChildren}
222+
</Dropdown>
223+
);
224+
225+
const dropdownToggle = screen.getByRole('button', { name: 'Dropdown' });
226+
const dropdownParent = dropdownToggle?.parentNode?.parentNode;
227+
expect(dropdownParent?.tagName).toBe('DIV');
228+
});
229+
204230
test('match snapshot', () => {
205231
const { asFragment } = render(
206232
<Dropdown

0 commit comments

Comments
 (0)