mirror of
https://github.com/mathuo/dockview
synced 2025-07-24 19:06:02 +00:00
Merge pull request #701 from iammola/tab-accessibility
feat: dockview accessibility
This commit is contained in:
commit
9c04db8093
@ -50,6 +50,7 @@ describe('groupPanelApi', () => {
|
||||
const accessor = fromPartial<DockviewComponent>({
|
||||
onDidAddPanel: jest.fn(),
|
||||
onDidRemovePanel: jest.fn(),
|
||||
onDidActivePanelChange: jest.fn(),
|
||||
options: {},
|
||||
onDidOptionsChange: jest.fn(),
|
||||
});
|
||||
@ -83,6 +84,7 @@ describe('groupPanelApi', () => {
|
||||
const accessor = fromPartial<DockviewComponent>({
|
||||
onDidAddPanel: jest.fn(),
|
||||
onDidRemovePanel: jest.fn(),
|
||||
onDidActivePanelChange: jest.fn(),
|
||||
options: {},
|
||||
onDidOptionsChange: jest.fn(),
|
||||
});
|
||||
|
@ -17,6 +17,7 @@ describe('tabsContainer', () => {
|
||||
const accessor = fromPartial<DockviewComponent>({
|
||||
onDidAddPanel: jest.fn(),
|
||||
onDidRemovePanel: jest.fn(),
|
||||
onDidActivePanelChange: jest.fn(),
|
||||
options: {},
|
||||
onDidOptionsChange: jest.fn(),
|
||||
});
|
||||
@ -71,6 +72,7 @@ describe('tabsContainer', () => {
|
||||
id: 'testcomponentid',
|
||||
onDidAddPanel: jest.fn(),
|
||||
onDidRemovePanel: jest.fn(),
|
||||
onDidActivePanelChange: jest.fn(),
|
||||
options: {},
|
||||
onDidOptionsChange: jest.fn(),
|
||||
});
|
||||
@ -141,6 +143,7 @@ describe('tabsContainer', () => {
|
||||
id: 'testcomponentid',
|
||||
onDidAddPanel: jest.fn(),
|
||||
onDidRemovePanel: jest.fn(),
|
||||
onDidActivePanelChange: jest.fn(),
|
||||
options: {},
|
||||
onDidOptionsChange: jest.fn(),
|
||||
});
|
||||
@ -205,6 +208,7 @@ describe('tabsContainer', () => {
|
||||
id: 'testcomponentid',
|
||||
onDidAddPanel: jest.fn(),
|
||||
onDidRemovePanel: jest.fn(),
|
||||
onDidActivePanelChange: jest.fn(),
|
||||
options: {},
|
||||
onDidOptionsChange: jest.fn(),
|
||||
});
|
||||
@ -269,6 +273,7 @@ describe('tabsContainer', () => {
|
||||
id: 'testcomponentid',
|
||||
onDidAddPanel: jest.fn(),
|
||||
onDidRemovePanel: jest.fn(),
|
||||
onDidActivePanelChange: jest.fn(),
|
||||
options: {},
|
||||
onDidOptionsChange: jest.fn(),
|
||||
});
|
||||
@ -338,6 +343,7 @@ describe('tabsContainer', () => {
|
||||
id: 'testcomponentid',
|
||||
onDidAddPanel: jest.fn(),
|
||||
onDidRemovePanel: jest.fn(),
|
||||
onDidActivePanelChange: jest.fn(),
|
||||
options: {},
|
||||
onDidOptionsChange: jest.fn(),
|
||||
});
|
||||
@ -403,6 +409,7 @@ describe('tabsContainer', () => {
|
||||
id: 'testcomponentid',
|
||||
onDidAddPanel: jest.fn(),
|
||||
onDidRemovePanel: jest.fn(),
|
||||
onDidActivePanelChange: jest.fn(),
|
||||
options: {},
|
||||
onDidOptionsChange: jest.fn(),
|
||||
});
|
||||
@ -468,6 +475,7 @@ describe('tabsContainer', () => {
|
||||
options: {},
|
||||
onDidAddPanel: jest.fn(),
|
||||
onDidRemovePanel: jest.fn(),
|
||||
onDidActivePanelChange: jest.fn(),
|
||||
element: document.createElement('div'),
|
||||
addFloatingGroup: jest.fn(),
|
||||
doSetGroupActive: jest.fn(),
|
||||
@ -525,6 +533,7 @@ describe('tabsContainer', () => {
|
||||
options: {},
|
||||
onDidAddPanel: jest.fn(),
|
||||
onDidRemovePanel: jest.fn(),
|
||||
onDidActivePanelChange: jest.fn(),
|
||||
element: document.createElement('div'),
|
||||
addFloatingGroup: jest.fn(),
|
||||
doSetGroupActive: jest.fn(),
|
||||
@ -577,6 +586,7 @@ describe('tabsContainer', () => {
|
||||
options: {},
|
||||
onDidAddPanel: jest.fn(),
|
||||
onDidRemovePanel: jest.fn(),
|
||||
onDidActivePanelChange: jest.fn(),
|
||||
element: document.createElement('div'),
|
||||
addFloatingGroup: jest.fn(),
|
||||
getGroupPanel: jest.fn(),
|
||||
@ -634,6 +644,7 @@ describe('tabsContainer', () => {
|
||||
options: {},
|
||||
onDidAddPanel: jest.fn(),
|
||||
onDidRemovePanel: jest.fn(),
|
||||
onDidActivePanelChange: jest.fn(),
|
||||
element: document.createElement('div'),
|
||||
addFloatingGroup: jest.fn(),
|
||||
getGroupPanel: jest.fn(),
|
||||
@ -702,6 +713,7 @@ describe('tabsContainer', () => {
|
||||
options: {},
|
||||
onDidAddPanel: jest.fn(),
|
||||
onDidRemovePanel: jest.fn(),
|
||||
onDidActivePanelChange: jest.fn(),
|
||||
element: document.createElement('div'),
|
||||
addFloatingGroup: jest.fn(),
|
||||
getGroupPanel: jest.fn(),
|
||||
@ -770,6 +782,7 @@ describe('tabsContainer', () => {
|
||||
options: {},
|
||||
onDidAddPanel: jest.fn(),
|
||||
onDidRemovePanel: jest.fn(),
|
||||
onDidActivePanelChange: jest.fn(),
|
||||
element: document.createElement('div'),
|
||||
addFloatingGroup: jest.fn(),
|
||||
getGroupPanel: jest.fn(),
|
||||
|
@ -6917,4 +6917,91 @@ describe('dockviewComponent', () => {
|
||||
dockview.layout(1000, 1000);
|
||||
});
|
||||
});
|
||||
|
||||
test('that arrow keys should activate appropriate tabs', () => {
|
||||
dockview.layout(500, 1000);
|
||||
|
||||
dockview.addPanel({
|
||||
id: 'panel1',
|
||||
component: 'default',
|
||||
});
|
||||
|
||||
dockview.addPanel({
|
||||
id: 'panel2',
|
||||
component: 'default',
|
||||
position: { referencePanel: 'panel1', direction: 'within' },
|
||||
});
|
||||
|
||||
dockview.addPanel({
|
||||
id: 'panel3',
|
||||
component: 'default',
|
||||
});
|
||||
|
||||
dockview.addPanel({
|
||||
id: 'panel4',
|
||||
component: 'default',
|
||||
position: { referencePanel: 'panel3', direction: 'below' },
|
||||
});
|
||||
|
||||
const panel1 = dockview.getGroupPanel('panel1')!;
|
||||
const panel2 = dockview.getGroupPanel('panel2')!;
|
||||
const panel3 = dockview.getGroupPanel('panel3')!;
|
||||
const panel4 = dockview.getGroupPanel('panel4')!;
|
||||
|
||||
panel1.api.setActive();
|
||||
|
||||
expect(panel1.api.isActive).toBeTruthy();
|
||||
expect(panel2.api.isActive).toBeFalsy();
|
||||
expect(panel3.api.isActive).toBeFalsy();
|
||||
expect(panel4.api.isActive).toBeFalsy();
|
||||
|
||||
const tabsContainer = (panel: IDockviewPanel) =>
|
||||
panel.api.group.element.querySelector('.tabs-container')!;
|
||||
|
||||
const event = new KeyboardEvent('keydown', { key: 'ArrowRight' });
|
||||
|
||||
fireEvent(tabsContainer(panel1), event);
|
||||
expect(panel1.api.isActive).toBeFalsy();
|
||||
expect(panel2.api.isActive).toBeTruthy();
|
||||
expect(panel3.api.isActive).toBeFalsy();
|
||||
expect(panel4.api.isActive).toBeFalsy();
|
||||
|
||||
fireEvent(tabsContainer(panel1), event);
|
||||
expect(panel1.api.isActive).toBeFalsy();
|
||||
expect(panel2.api.isActive).toBeFalsy();
|
||||
expect(panel3.api.isActive).toBeTruthy();
|
||||
expect(panel4.api.isActive).toBeFalsy();
|
||||
|
||||
const event2 = new KeyboardEvent('keydown', { key: 'ArrowLeft' });
|
||||
|
||||
fireEvent(tabsContainer(panel1), event2);
|
||||
expect(panel1.api.isActive).toBeFalsy();
|
||||
expect(panel2.api.isActive).toBeTruthy();
|
||||
expect(panel3.api.isActive).toBeFalsy();
|
||||
expect(panel4.api.isActive).toBeFalsy();
|
||||
|
||||
fireEvent(tabsContainer(panel1), event2);
|
||||
expect(panel1.api.isActive).toBeTruthy();
|
||||
expect(panel2.api.isActive).toBeFalsy();
|
||||
expect(panel3.api.isActive).toBeFalsy();
|
||||
expect(panel4.api.isActive).toBeFalsy();
|
||||
|
||||
panel4.api.setActive();
|
||||
expect(panel1.api.isActive).toBeFalsy();
|
||||
expect(panel2.api.isActive).toBeFalsy();
|
||||
expect(panel3.api.isActive).toBeFalsy();
|
||||
expect(panel4.api.isActive).toBeTruthy();
|
||||
|
||||
fireEvent(tabsContainer(panel4), event2);
|
||||
expect(panel1.api.isActive).toBeFalsy();
|
||||
expect(panel2.api.isActive).toBeFalsy();
|
||||
expect(panel3.api.isActive).toBeFalsy();
|
||||
expect(panel4.api.isActive).toBeTruthy();
|
||||
|
||||
fireEvent(tabsContainer(panel4), event);
|
||||
expect(panel1.api.isActive).toBeFalsy();
|
||||
expect(panel2.api.isActive).toBeFalsy();
|
||||
expect(panel3.api.isActive).toBeFalsy();
|
||||
expect(panel4.api.isActive).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
@ -174,6 +174,8 @@ export class TestPanel implements IDockviewPanel {
|
||||
private _group: DockviewGroupPanel | undefined;
|
||||
private _params: IGroupPanelInitParameters | undefined;
|
||||
readonly view: IDockviewPanelModel;
|
||||
readonly componentElId: string;
|
||||
readonly tabComponentElId: string;
|
||||
|
||||
get title() {
|
||||
return '';
|
||||
@ -189,6 +191,8 @@ export class TestPanel implements IDockviewPanel {
|
||||
|
||||
constructor(public readonly id: string, public api: DockviewPanelApi) {
|
||||
this.view = new TestModel(id);
|
||||
this.tabComponentElId = `tab-${id}`;
|
||||
this.componentElId = `tab-panel-${id}`;
|
||||
this.init({
|
||||
title: `${id}`,
|
||||
params: {},
|
||||
@ -266,6 +270,7 @@ describe('dockviewGroupPanelModel', () => {
|
||||
removeGroup: removeGroupMock,
|
||||
onDidAddPanel: () => ({ dispose: jest.fn() }),
|
||||
onDidRemovePanel: () => ({ dispose: jest.fn() }),
|
||||
onDidActivePanelChange: () => ({ dispose: jest.fn() }),
|
||||
overlayRenderContainer: new OverlayRenderContainer(
|
||||
document.createElement('div'),
|
||||
fromPartial<DockviewComponent>({})
|
||||
@ -653,6 +658,7 @@ describe('dockviewGroupPanelModel', () => {
|
||||
onDidAddPanel: jest.fn(),
|
||||
onDidRemovePanel: jest.fn(),
|
||||
onDidOptionsChange: jest.fn(),
|
||||
onDidActivePanelChange: jest.fn(),
|
||||
});
|
||||
|
||||
const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
|
||||
@ -716,6 +722,7 @@ describe('dockviewGroupPanelModel', () => {
|
||||
onDidAddPanel: jest.fn(),
|
||||
onDidRemovePanel: jest.fn(),
|
||||
onDidOptionsChange: jest.fn(),
|
||||
onDidActivePanelChange: jest.fn(),
|
||||
});
|
||||
|
||||
const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
|
||||
@ -808,6 +815,7 @@ describe('dockviewGroupPanelModel', () => {
|
||||
doSetGroupActive: jest.fn(),
|
||||
onDidAddPanel: jest.fn(),
|
||||
onDidRemovePanel: jest.fn(),
|
||||
onDidActivePanelChange: jest.fn(),
|
||||
overlayRenderContainer: new OverlayRenderContainer(
|
||||
document.createElement('div'),
|
||||
fromPartial<DockviewComponent>({})
|
||||
@ -875,6 +883,7 @@ describe('dockviewGroupPanelModel', () => {
|
||||
doSetGroupActive: jest.fn(),
|
||||
onDidAddPanel: jest.fn(),
|
||||
onDidRemovePanel: jest.fn(),
|
||||
onDidActivePanelChange: jest.fn(),
|
||||
overlayRenderContainer: new OverlayRenderContainer(
|
||||
document.createElement('div'),
|
||||
fromPartial<DockviewComponent>({})
|
||||
@ -949,6 +958,7 @@ describe('dockviewGroupPanelModel', () => {
|
||||
doSetGroupActive: jest.fn(),
|
||||
onDidAddPanel: jest.fn(),
|
||||
onDidRemovePanel: jest.fn(),
|
||||
onDidActivePanelChange: jest.fn(),
|
||||
overlayRenderContainer: new OverlayRenderContainer(
|
||||
document.createElement('div'),
|
||||
fromPartial<DockviewComponent>({})
|
||||
@ -1030,6 +1040,7 @@ describe('dockviewGroupPanelModel', () => {
|
||||
return {
|
||||
id: 'testgroupid',
|
||||
model: groupView,
|
||||
dispose: jest.fn()
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -7,6 +7,7 @@ describe('gridviewPanel', () => {
|
||||
return {
|
||||
onDidAddPanel: jest.fn(),
|
||||
onDidRemovePanel: jest.fn(),
|
||||
onDidActivePanelChange: jest.fn(),
|
||||
options: {},
|
||||
onDidOptionsChange: jest.fn(),
|
||||
} as any;
|
||||
|
@ -6,7 +6,7 @@ import { createCloseButton } from '../../../svg';
|
||||
export class DefaultTab extends CompositeDisposable implements ITabRenderer {
|
||||
private readonly _element: HTMLElement;
|
||||
private readonly _content: HTMLElement;
|
||||
private readonly action: HTMLElement;
|
||||
private readonly action: HTMLButtonElement;
|
||||
private _title: string | undefined;
|
||||
|
||||
get element(): HTMLElement {
|
||||
@ -22,22 +22,38 @@ export class DefaultTab extends CompositeDisposable implements ITabRenderer {
|
||||
this._content = document.createElement('div');
|
||||
this._content.className = 'dv-default-tab-content';
|
||||
|
||||
this.action = document.createElement('div');
|
||||
this.action = document.createElement('button');
|
||||
this.action.type = 'button';
|
||||
this.action.className = 'dv-default-tab-action';
|
||||
// originally hide this, so only when it is focused is it read out.
|
||||
// so the SR when focused on the tab, doesn't read "<Tab Content> Close Button"
|
||||
this.action.ariaHidden = 'true';
|
||||
|
||||
this.action.appendChild(createCloseButton());
|
||||
|
||||
this._element.appendChild(this._content);
|
||||
this._element.appendChild(this.action);
|
||||
|
||||
this.addDisposables(
|
||||
addDisposableListener(this.action, 'focus', (event) => {
|
||||
this.action.ariaHidden = 'false';
|
||||
}),
|
||||
addDisposableListener(this.action, 'blur', (event) => {
|
||||
this.action.ariaHidden = 'true';
|
||||
})
|
||||
);
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
init(params: GroupPanelPartInitParameters): void {
|
||||
this._title = params.title;
|
||||
|
||||
this.action.ariaLabel = `Close "${this._title}" tab`;
|
||||
|
||||
this.addDisposables(
|
||||
params.api.onDidTitleChange((event) => {
|
||||
this._title = event.title;
|
||||
this.action.ariaLabel = `Close "${event.title}" tab`;
|
||||
this.render();
|
||||
}),
|
||||
addDisposableListener(this.action, 'pointerdown', (ev) => {
|
||||
@ -50,6 +66,18 @@ export class DefaultTab extends CompositeDisposable implements ITabRenderer {
|
||||
|
||||
ev.preventDefault();
|
||||
params.api.close();
|
||||
}),
|
||||
addDisposableListener(this.action, 'keydown', (ev) => {
|
||||
if (ev.defaultPrevented) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ev.key) {
|
||||
case 'Enter':
|
||||
case 'Space':
|
||||
params.api.close();
|
||||
break;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -52,6 +52,9 @@ export class Tab extends CompositeDisposable {
|
||||
|
||||
private readonly _onPointDown = new Emitter<MouseEvent>();
|
||||
readonly onPointerDown: Event<MouseEvent> = this._onPointDown.event;
|
||||
|
||||
private readonly _onKeyDown = new Emitter<KeyboardEvent>();
|
||||
readonly onKeyDown: Event<KeyboardEvent> = this._onKeyDown.event;
|
||||
|
||||
private readonly _onDropped = new Emitter<DroptargetEvent>();
|
||||
readonly onDrop: Event<DroptargetEvent> = this._onDropped.event;
|
||||
@ -73,9 +76,13 @@ export class Tab extends CompositeDisposable {
|
||||
super();
|
||||
|
||||
this._element = document.createElement('div');
|
||||
this._element.id = this.panel.tabComponentElId;
|
||||
this._element.className = 'dv-tab';
|
||||
this._element.tabIndex = 0;
|
||||
this._element.role = 'tab';
|
||||
this._element.tabIndex = -1;
|
||||
this._element.draggable = true;
|
||||
this._element.ariaSelected = 'false';
|
||||
this._element.setAttribute('aria-controls', this.panel.componentElId);
|
||||
|
||||
toggleClass(this.element, 'dv-inactive-tab', true);
|
||||
|
||||
@ -139,6 +146,9 @@ export class Tab extends CompositeDisposable {
|
||||
addDisposableListener(this._element, 'pointerdown', (event) => {
|
||||
this._onPointDown.fire(event);
|
||||
}),
|
||||
addDisposableListener(this._element, 'keydown', (event) => {
|
||||
this._onKeyDown.fire(event);
|
||||
}),
|
||||
this.dropTarget.onDrop((event) => {
|
||||
this._onDropped.fire(event);
|
||||
}),
|
||||
@ -147,6 +157,9 @@ export class Tab extends CompositeDisposable {
|
||||
}
|
||||
|
||||
public setActive(isActive: boolean): void {
|
||||
this.element.tabIndex = isActive ? 0 : -1;
|
||||
this.element.ariaSelected = isActive.toString();
|
||||
|
||||
toggleClass(this.element, 'dv-active-tab', isActive);
|
||||
toggleClass(this.element, 'dv-inactive-tab', !isActive);
|
||||
}
|
||||
|
@ -98,6 +98,7 @@ export class Tabs extends CompositeDisposable {
|
||||
|
||||
this._tabsList = document.createElement('div');
|
||||
this._tabsList.className = 'dv-tabs-container dv-horizontal';
|
||||
this._tabsList.ariaOrientation = 'horizontal';
|
||||
|
||||
this.showTabsOverflowControl = options.showTabsOverflowControl;
|
||||
|
||||
@ -109,12 +110,23 @@ export class Tabs extends CompositeDisposable {
|
||||
this.addDisposables(scrollbar);
|
||||
}
|
||||
|
||||
this.element.role = 'tablist';
|
||||
this.element.ariaLabel =
|
||||
'Use the Left Arrow to select the previous tab, Right Arrow for the next tab, Home for the first tab, and End for the last tab. Press Enter to select the focused tab.';
|
||||
|
||||
this.addDisposables(
|
||||
this._onOverflowTabsChange,
|
||||
this._observerDisposable,
|
||||
this._onWillShowOverlay,
|
||||
this._onDrop,
|
||||
this._onTabDragStart,
|
||||
this.accessor.onDidActivePanelChange((e) => {
|
||||
if (e?.api.group === this.group) {
|
||||
this.selectedIndex = this.indexOf(e.id);
|
||||
} else {
|
||||
this.selectedIndex = -1;
|
||||
}
|
||||
}),
|
||||
addDisposableListener(this.element, 'pointerdown', (event) => {
|
||||
if (event.defaultPrevented) {
|
||||
return;
|
||||
@ -154,6 +166,7 @@ export class Tabs extends CompositeDisposable {
|
||||
for (const tab of this._tabs) {
|
||||
const isActivePanel = panel.id === tab.value.panel.id;
|
||||
tab.value.setActive(isActivePanel);
|
||||
tab.value.panel.runEvents();
|
||||
|
||||
if (isActivePanel) {
|
||||
const element = tab.value.element;
|
||||
@ -224,6 +237,40 @@ export class Tabs extends CompositeDisposable {
|
||||
break;
|
||||
}
|
||||
}),
|
||||
tab.onKeyDown((event) => {
|
||||
if (event.defaultPrevented) {
|
||||
return;
|
||||
}
|
||||
|
||||
const index = this.indexOf(tab.panel.id);
|
||||
let nextTab: Tab | undefined = undefined;
|
||||
|
||||
switch (event.key) {
|
||||
case 'ArrowLeft':
|
||||
nextTab = this.tabs[Math.max(0, index - 1)];
|
||||
break;
|
||||
case 'ArrowRight':
|
||||
nextTab = this.tabs[Math.min(this.size - 1, index + 1)];
|
||||
break;
|
||||
case 'Home':
|
||||
nextTab = this.tabs[0];
|
||||
break;
|
||||
case 'End':
|
||||
nextTab = this.tabs[this.size - 1];
|
||||
break;
|
||||
case 'Enter':
|
||||
case 'Space':
|
||||
nextTab = tab;
|
||||
}
|
||||
|
||||
if (
|
||||
nextTab != null &&
|
||||
this.group.activePanel !== nextTab.panel
|
||||
) {
|
||||
nextTab.element.focus();
|
||||
this.group.model.openPanel(nextTab.panel);
|
||||
}
|
||||
}),
|
||||
tab.onDrop((event) => {
|
||||
this._onDrop.fire({
|
||||
event: event.nativeEvent,
|
||||
|
@ -20,6 +20,9 @@
|
||||
&.dv-active-group {
|
||||
> .dv-tabs-and-actions-container {
|
||||
.dv-tabs-container > .dv-tab {
|
||||
&:focus {
|
||||
outline: 1px solid var(--dv-paneview-active-outline-color);
|
||||
}
|
||||
&.dv-active-tab {
|
||||
background-color: var(
|
||||
--dv-activegroup-visiblepanel-tab-background-color
|
||||
@ -38,6 +41,9 @@
|
||||
&.dv-inactive-group {
|
||||
> .dv-tabs-and-actions-container {
|
||||
.dv-tabs-container > .dv-tab {
|
||||
&:focus {
|
||||
outline: 1px solid var(--dv-paneview-active-outline-color);
|
||||
}
|
||||
&.dv-active-tab {
|
||||
background-color: var(
|
||||
--dv-inactivegroup-visiblepanel-tab-background-color
|
||||
|
@ -19,6 +19,8 @@ export interface IDockviewPanel extends IDisposable, IPanel {
|
||||
readonly api: DockviewPanelApi;
|
||||
readonly title: string | undefined;
|
||||
readonly params: Parameters | undefined;
|
||||
readonly componentElId: string;
|
||||
readonly tabComponentElId: string;
|
||||
readonly minimumWidth?: number;
|
||||
readonly minimumHeight?: number;
|
||||
readonly maximumWidth?: number;
|
||||
@ -39,6 +41,18 @@ export class DockviewPanel
|
||||
implements IDockviewPanel
|
||||
{
|
||||
readonly api: DockviewPanelApiImpl;
|
||||
/**
|
||||
* The unique DOM id for the rendered panel element
|
||||
*
|
||||
* Used for accessibility attributes
|
||||
*/
|
||||
readonly componentElId: string;
|
||||
/**
|
||||
* The unique DOM id for the rendered tab element
|
||||
*
|
||||
* Used for accessibility attributes
|
||||
*/
|
||||
readonly tabComponentElId: string;
|
||||
|
||||
private _group: DockviewGroupPanel;
|
||||
private _params?: Parameters;
|
||||
@ -100,6 +114,11 @@ export class DockviewPanel
|
||||
this._maximumWidth = options.maximumWidth;
|
||||
this._maximumHeight = options.maximumHeight;
|
||||
|
||||
const randomId = Math.random().toString(36).slice(2);
|
||||
|
||||
this.tabComponentElId = `tab-${id}-${randomId}`;
|
||||
this.componentElId = `tab-panel-${id}-${randomId}`;
|
||||
|
||||
this.api = new DockviewPanelApiImpl(
|
||||
this,
|
||||
this._group,
|
||||
|
@ -642,7 +642,7 @@ export class Gridview implements IDisposable {
|
||||
}
|
||||
|
||||
this._root = root;
|
||||
this.element.appendChild(this._root.element);
|
||||
this.element.prepend(this._root.element);
|
||||
this.disposable.value = this._root.onDidChange((e) => {
|
||||
this._onDidChange.fire(e);
|
||||
});
|
||||
@ -698,7 +698,7 @@ export class Gridview implements IDisposable {
|
||||
this._root.addChild(oldRoot, Sizing.Distribute, 0);
|
||||
}
|
||||
|
||||
this.element.appendChild(this._root.element);
|
||||
this.element.prepend(this._root.element);
|
||||
|
||||
this.disposable.value = this._root.onDidChange((e) => {
|
||||
this._onDidChange.fire(e);
|
||||
|
@ -73,12 +73,14 @@ export class OverlayRenderContainer extends CompositeDisposable {
|
||||
if (!this.map[panel.api.id]) {
|
||||
const element = createFocusableElement();
|
||||
element.className = 'dv-render-overlay';
|
||||
element.role = 'tabpanel';
|
||||
element.tabIndex = 0;
|
||||
element.setAttribute('aria-labelledby', panel.tabComponentElId);
|
||||
|
||||
this.map[panel.api.id] = {
|
||||
panel,
|
||||
disposable: Disposable.NONE,
|
||||
destroy: Disposable.NONE,
|
||||
|
||||
element,
|
||||
};
|
||||
}
|
||||
|
@ -165,6 +165,10 @@ export class Splitview {
|
||||
? 'dv-horizontal'
|
||||
: 'dv-vertical'
|
||||
);
|
||||
this.element.ariaOrientation =
|
||||
this.orientation == Orientation.HORIZONTAL
|
||||
? 'horizontal'
|
||||
: 'vertical';
|
||||
}
|
||||
|
||||
get minimumSize(): number {
|
||||
@ -1148,6 +1152,10 @@ export class Splitview {
|
||||
? 'dv-horizontal'
|
||||
: 'dv-vertical';
|
||||
element.className = `dv-split-view-container ${orientationClassname}`;
|
||||
element.ariaOrientation =
|
||||
this._orientation == Orientation.HORIZONTAL
|
||||
? 'horizontal'
|
||||
: 'vertical';
|
||||
return element;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user