-
Notifications
You must be signed in to change notification settings - Fork 673
Popover: support content reading on opening #34311
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
Merged
Merged
Changes from all commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
5ccace2
Popover: support content reading on opening
EugeniyKiyashko f5e4c3b
Apply aria role to containers
Raushen 1b99a65
Add jest tests
Raushen 3ccd065
Fix QUnit tests
Raushen 72272ac
Popover: update aria-describedby logic in popover and remove it from …
dmlvr a85bed3
Merge branch 'main' into feature/26_2_popover_support_content_reading
dmlvr 048ec5f
refactoring
dmlvr 6947bd8
remove multiple target tests
dmlvr 8e0f3d5
Popover: focus management for dialog role (#34413)
dmlvr 7c5f974
refactoring
dmlvr 25530d7
_syncTargetAriaDescription refactoring
dmlvr 3358b17
_ensurePopoverContentId refactoring
dmlvr 7858fb2
fix tests errors
dmlvr 1bee023
remove basic _forceFocusLost
dmlvr be1129a
refactoring
dmlvr 9e76bf2
add testcases for addAriaDescriptionId and removeAriaDescriptionId
dmlvr c76193e
update _getFocusTarget
dmlvr 990cde6
update Note for excluded e2e tests
dmlvr 1f633ba
add getCloseButton for DataGrid ColumnChooser
dmlvr 6613f78
fix by review
dmlvr 34b47cb
fix _syncFocusOptions and add some tests for change focusStateEnabled…
dmlvr 58ba85c
update scheduler's appointment tooltip
dmlvr 95970ab
prevent tooltip Focus Behavior for appointment tooltip
dmlvr 0ed0f35
update comment for popover a11y tests
dmlvr b9be9a9
update _forceFocusLost for role "dialog"
dmlvr 6e19d16
change options order for appointment tooltip
dmlvr 1358c99
update expected options count for appointment tooltip
dmlvr File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
154 changes: 154 additions & 0 deletions
154
packages/devextreme/js/__internal/core/utils/__tests__/m_dom.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,154 @@ | ||
| import { | ||
| beforeEach, describe, expect, it, jest, | ||
| } from '@jest/globals'; | ||
| import { | ||
| addAriaDescriptionId, | ||
| getAriaDescriptionIds, | ||
| removeAriaDescriptionId, | ||
| setAriaDescriptionIds, | ||
| } from '@ts/core/utils/m_dom'; | ||
|
|
||
| describe('DOM utils', () => { | ||
| let element: HTMLElement; | ||
|
|
||
| beforeEach(() => { | ||
| element = document.createElement('div'); | ||
| }); | ||
|
|
||
| describe('getAriaDescriptionIds', () => { | ||
| it('should return an empty array when the attribute is absent', () => { | ||
| expect(getAriaDescriptionIds(element)).toEqual([]); | ||
| }); | ||
|
|
||
| it('should return an empty array when the attribute is empty', () => { | ||
| element.setAttribute('aria-describedby', ''); | ||
|
|
||
| expect(getAriaDescriptionIds(element)).toEqual([]); | ||
| }); | ||
|
|
||
| it('should return a single id', () => { | ||
| element.setAttribute('aria-describedby', 'id-1'); | ||
|
|
||
| expect(getAriaDescriptionIds(element)).toEqual(['id-1']); | ||
| }); | ||
|
|
||
| it('should split multiple ids separated by spaces', () => { | ||
| element.setAttribute('aria-describedby', 'id-1 id-2 id-3'); | ||
|
|
||
| expect(getAriaDescriptionIds(element)).toEqual(['id-1', 'id-2', 'id-3']); | ||
| }); | ||
|
|
||
| it('should ignore extra whitespace between ids', () => { | ||
| element.setAttribute('aria-describedby', ' id-1 id-2 '); | ||
|
|
||
| expect(getAriaDescriptionIds(element)).toEqual(['id-1', 'id-2']); | ||
| }); | ||
| }); | ||
|
|
||
| describe('setAriaDescriptionIds', () => { | ||
| it('should set the attribute for a single id', () => { | ||
| setAriaDescriptionIds(element, ['id-1']); | ||
|
|
||
| expect(element.getAttribute('aria-describedby')).toBe('id-1'); | ||
| }); | ||
|
|
||
| it('should join multiple ids with a single space', () => { | ||
| setAriaDescriptionIds(element, ['id-1', 'id-2', 'id-3']); | ||
|
|
||
| expect(element.getAttribute('aria-describedby')).toBe('id-1 id-2 id-3'); | ||
| }); | ||
|
|
||
| it('should remove the attribute when the ids list is empty', () => { | ||
| element.setAttribute('aria-describedby', 'id-1'); | ||
|
|
||
| setAriaDescriptionIds(element, []); | ||
|
|
||
| expect(element.hasAttribute('aria-describedby')).toBe(false); | ||
| }); | ||
|
|
||
| it('should not rewrite the attribute when the value is unchanged', () => { | ||
| element.setAttribute('aria-describedby', 'id-1 id-2'); | ||
| const setAttributeSpy = jest.spyOn(element, 'setAttribute'); | ||
|
|
||
| setAriaDescriptionIds(element, ['id-1', 'id-2']); | ||
|
|
||
| expect(setAttributeSpy).not.toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it('should be reversible with getAriaDescriptionIds', () => { | ||
| setAriaDescriptionIds(element, ['id-1', 'id-2']); | ||
|
|
||
| expect(getAriaDescriptionIds(element)).toEqual(['id-1', 'id-2']); | ||
| }); | ||
| }); | ||
|
|
||
| describe('addAriaDescriptionId', () => { | ||
| it('should add the id to the empty attribute and return true', () => { | ||
| const result = addAriaDescriptionId(element, 'id-1'); | ||
|
|
||
| expect(result).toBe(true); | ||
| expect(element.getAttribute('aria-describedby')).toBe('id-1'); | ||
| }); | ||
|
|
||
| it('should append the id to existing ids and return true', () => { | ||
| element.setAttribute('aria-describedby', 'id-1 id-2'); | ||
|
|
||
| const result = addAriaDescriptionId(element, 'id-3'); | ||
|
|
||
| expect(result).toBe(true); | ||
| expect(element.getAttribute('aria-describedby')).toBe('id-1 id-2 id-3'); | ||
| }); | ||
|
|
||
| it('should not add the id if it already exists and return false', () => { | ||
| element.setAttribute('aria-describedby', 'id-1 id-2'); | ||
| const setAttributeSpy = jest.spyOn(element, 'setAttribute'); | ||
|
|
||
| const result = addAriaDescriptionId(element, 'id-2'); | ||
|
|
||
| expect(result).toBe(false); | ||
| expect(element.getAttribute('aria-describedby')).toBe('id-1 id-2'); | ||
| expect(setAttributeSpy).not.toHaveBeenCalled(); | ||
| }); | ||
| }); | ||
|
|
||
| describe('removeAriaDescriptionId', () => { | ||
| it('should do nothing if the attribute is absent', () => { | ||
| const removeAttributeSpy = jest.spyOn(element, 'removeAttribute'); | ||
| const setAttributeSpy = jest.spyOn(element, 'setAttribute'); | ||
|
|
||
| removeAriaDescriptionId(element, 'id-1'); | ||
|
|
||
| expect(element.hasAttribute('aria-describedby')).toBe(false); | ||
| expect(removeAttributeSpy).not.toHaveBeenCalled(); | ||
| expect(setAttributeSpy).not.toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it('should remove the attribute when the last id is removed', () => { | ||
| element.setAttribute('aria-describedby', 'id-1'); | ||
|
|
||
| removeAriaDescriptionId(element, 'id-1'); | ||
|
|
||
| expect(element.hasAttribute('aria-describedby')).toBe(false); | ||
| }); | ||
|
|
||
| it('should remove a single id from the list of multiple ids', () => { | ||
| element.setAttribute('aria-describedby', 'id-1 id-2 id-3'); | ||
|
|
||
| removeAriaDescriptionId(element, 'id-2'); | ||
|
|
||
| expect(element.getAttribute('aria-describedby')).toBe('id-1 id-3'); | ||
| }); | ||
|
|
||
| it('should not change the attribute if the id is not present', () => { | ||
| element.setAttribute('aria-describedby', 'id-1 id-3'); | ||
| const setAttributeSpy = jest.spyOn(element, 'setAttribute'); | ||
| const removeAttributeSpy = jest.spyOn(element, 'removeAttribute'); | ||
|
|
||
| removeAriaDescriptionId(element, 'id-2'); | ||
|
|
||
| expect(element.getAttribute('aria-describedby')).toBe('id-1 id-3'); | ||
| expect(setAttributeSpy).not.toHaveBeenCalled(); | ||
| expect(removeAttributeSpy).not.toHaveBeenCalled(); | ||
| }); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
packages/devextreme/js/__internal/ui/__tests__/__mock__/model/popover.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| import Popover from '@ts/ui/popover/popover'; | ||
| import type Popup from '@ts/ui/popup/popup'; | ||
|
|
||
| import { PopupModel } from './popup'; | ||
|
|
||
| const CLASSES = { | ||
| popover: 'dx-popover', | ||
| popoverWrapper: 'dx-popover-wrapper', | ||
| }; | ||
|
|
||
| export class PopoverModel extends PopupModel { | ||
| protected getRootClass(): string { | ||
| return CLASSES.popover; | ||
| } | ||
|
|
||
| protected getWrapperClass(): string { | ||
| return CLASSES.popoverWrapper; | ||
| } | ||
|
|
||
| public getInstance(): Popup { | ||
| return Popover.getInstance<Popup>(this.getRoot()); | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.