Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(guidepup): popover #3010

Merged
merged 16 commits into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion packages/components/src/components/popover/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ export type DBPopoverProps = DBPopoverDefaultProps &
GapProps &
PopoverProps;

export interface DBPopoverDefaultState {}
export interface DBPopoverDefaultState {
isExpanded?: boolean;
getTrigger?: () => Element | undefined;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
handleLeave?: (event: any) => void;
}

export type DBPopoverState = DBPopoverDefaultState &
GlobalState &
Expand Down
53 changes: 49 additions & 4 deletions packages/components/src/components/popover/popover.lite.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,45 @@ export default function DBPopover(props: DBPopoverProps) {
// jscpd:ignore-start
const state = useStore<DBPopoverState>({
initialized: false,
isExpanded: false,
handleAutoPlacement: () => {
state.isExpanded = true;
if (!ref) return;
const article = ref.querySelector('article');
if (!article) return;
handleDataOutside(article);
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
handleLeave: (event: any) => {
const element = event.target as HTMLElement;
const parent = element.parentNode;
if (
!parent ||
(element.parentNode.querySelector(':focus') !== element &&
element.parentNode.querySelector(':focus-within') !==
element &&
element.parentNode.querySelector(':hover') !== element)
) {
state.isExpanded = false;
}
},
getTrigger: () => {
if (ref) {
const children: Element[] = Array.from(ref.children);
if (children.length >= 2) {
const firstChild = children[0];
if (firstChild.tagName.includes('-')) {
// this is a workaround for custom angular components
return firstChild.children?.length > 0
? firstChild.children[0]
: undefined;
} else {
return firstChild;
}
}
}

return undefined;
}
});

Expand All @@ -32,14 +66,23 @@ export default function DBPopover(props: DBPopoverProps) {

onUpdate(() => {
if (ref && state.initialized) {
const children: Element[] = Array.from(ref.children);
if (children.length >= 2) {
children[0].ariaHasPopup = 'true';
const child = state.getTrigger();
if (child) {
child.ariaHasPopup = 'true';
}
state.initialized = false;
}
}, [ref, state.initialized]);

onUpdate(() => {
if (ref) {
const child = state.getTrigger();
if (child) {
child.ariaExpanded = state.isExpanded.toString();
}
}
}, [ref, state.isExpanded]);

// jscpd:ignore-end

return (
Expand All @@ -48,7 +91,9 @@ export default function DBPopover(props: DBPopoverProps) {
id={props.id}
class={cls('db-popover', props.className)}
onFocus={() => state.handleAutoPlacement()}
onMouseEnter={() => state.handleAutoPlacement()}>
onBlur={(event: FocusEvent) => state.handleLeave(event)}
onMouseEnter={() => state.handleAutoPlacement()}
onMouseLeave={(event: MouseEvent) => state.handleLeave(event)}>
<Slot name="trigger" />
<article
class="db-popover-content"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
["article","list 2 items","• Popover Custom Item 1 1 of 2","• Popover Custom Item 2 2 of 2","end of list","Functional menu pop up button","end of article","(Default) Regular menu pop up button"]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
["(Default) Regular, menu button, expanded, sub Menu","list, with 2 items, bullet Popover Custom Item 1","bullet Popover Custom Item 2","out of list, button, Popover Custom Item 3","menu button, collapsed, sub Menu, Expressive"]
6 changes: 5 additions & 1 deletion showcases/screen-reader/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ const standardPhrases = [
'To select',
'To interact',
'Press Control',
'To begin interacting'
'To begin interacting',
'To display a',
'To move between items'
];

const cleanSpeakInstructions = (phraseLog: string[]): string[] =>
Expand All @@ -35,6 +37,8 @@ const cleanSpeakInstructions = (phraseLog: string[]): string[] =>
!standardPhrases.some((string) => sPhrase.includes(string))
)
.join('. ')
// We need to replace specific phrases, as they are being reported differently on localhost and within CI/CD
.replaceAll('pop-up', 'pop up')
);

export const generateSnapshot = async (
Expand Down
33 changes: 33 additions & 0 deletions showcases/screen-reader/tests/popover.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { getTest, testDefault } from '../default';

const test = getTest();
test.describe('DBPopover', () => {
testDefault({
test,
title: 'opened',
description: 'should open the popover',
url: './#/01/popover?page=density',
async testFn(voiceOver, nvda) {
if (nvda) {
await nvda?.act(); // Opening first popover
await nvda?.press('Tab'); // Tab to button inside popover
await nvda?.next(); // Navigating to default button
await nvda?.clearSpokenPhraseLog();
await nvda?.act(); // Read button + opening second popover -> should jump to article
await nvda?.next(); // Navigating to first item of list within popover
await nvda?.next(); // Navigating to section item of list within popover
await nvda?.next(); // Navigating to button within popover
await nvda?.next(); // Navigating to next button
} else if (voiceOver) {
await voiceOver?.next(); // Opening first popover and navigating to the included "article"
await voiceOver?.next(); // Navigating to list within popover
await voiceOver?.next(); // Navigating to first item of list within popover
await voiceOver?.next(); // Navigating to section item of list within popover
await voiceOver?.next(); // Navigating to end of list within popover
await voiceOver?.next(); // Navigating to button within popover
await voiceOver?.next(); // Navigating to end of article
await voiceOver?.next(); // Navigating to next button and open next popover
}
}
});
});
Loading