diff --git a/packages/dockview-core/src/__tests__/api/dockviewPanelApi.spec.ts b/packages/dockview-core/src/__tests__/api/dockviewPanelApi.spec.ts index d4255ab223..4061c4701c 100644 --- a/packages/dockview-core/src/__tests__/api/dockviewPanelApi.spec.ts +++ b/packages/dockview-core/src/__tests__/api/dockviewPanelApi.spec.ts @@ -50,6 +50,7 @@ describe('groupPanelApi', () => { const accessor = fromPartial({ onDidAddPanel: jest.fn(), onDidRemovePanel: jest.fn(), + onDidActivePanelChange: jest.fn(), options: {}, onDidOptionsChange: jest.fn(), }); @@ -83,6 +84,7 @@ describe('groupPanelApi', () => { const accessor = fromPartial({ onDidAddPanel: jest.fn(), onDidRemovePanel: jest.fn(), + onDidActivePanelChange: jest.fn(), options: {}, onDidOptionsChange: jest.fn(), }); diff --git a/packages/dockview-core/src/__tests__/dockview/components/titlebar/tabsContainer.spec.ts b/packages/dockview-core/src/__tests__/dockview/components/titlebar/tabsContainer.spec.ts index bb79949cfe..116f14cf37 100644 --- a/packages/dockview-core/src/__tests__/dockview/components/titlebar/tabsContainer.spec.ts +++ b/packages/dockview-core/src/__tests__/dockview/components/titlebar/tabsContainer.spec.ts @@ -17,6 +17,7 @@ describe('tabsContainer', () => { const accessor = fromPartial({ 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(), diff --git a/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts b/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts index c8619b8e12..6109041bc2 100644 --- a/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts +++ b/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts @@ -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(); + }); }); diff --git a/packages/dockview-core/src/__tests__/dockview/dockviewGroupPanelModel.spec.ts b/packages/dockview-core/src/__tests__/dockview/dockviewGroupPanelModel.spec.ts index 6e24cd53f3..02e1c8f6d7 100644 --- a/packages/dockview-core/src/__tests__/dockview/dockviewGroupPanelModel.spec.ts +++ b/packages/dockview-core/src/__tests__/dockview/dockviewGroupPanelModel.spec.ts @@ -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({}) @@ -653,6 +658,7 @@ describe('dockviewGroupPanelModel', () => { onDidAddPanel: jest.fn(), onDidRemovePanel: jest.fn(), onDidOptionsChange: jest.fn(), + onDidActivePanelChange: jest.fn(), }); const groupviewMock = jest.fn, []>( @@ -716,6 +722,7 @@ describe('dockviewGroupPanelModel', () => { onDidAddPanel: jest.fn(), onDidRemovePanel: jest.fn(), onDidOptionsChange: jest.fn(), + onDidActivePanelChange: jest.fn(), }); const groupviewMock = jest.fn, []>( @@ -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({}) @@ -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({}) @@ -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({}) @@ -1030,6 +1040,7 @@ describe('dockviewGroupPanelModel', () => { return { id: 'testgroupid', model: groupView, + dispose: jest.fn() }; }); diff --git a/packages/dockview-core/src/__tests__/gridview/gridviewPanel.spec.ts b/packages/dockview-core/src/__tests__/gridview/gridviewPanel.spec.ts index 18ed7d1d6b..7f9824b117 100644 --- a/packages/dockview-core/src/__tests__/gridview/gridviewPanel.spec.ts +++ b/packages/dockview-core/src/__tests__/gridview/gridviewPanel.spec.ts @@ -7,6 +7,7 @@ describe('gridviewPanel', () => { return { onDidAddPanel: jest.fn(), onDidRemovePanel: jest.fn(), + onDidActivePanelChange: jest.fn(), options: {}, onDidOptionsChange: jest.fn(), } as any; diff --git a/packages/dockview-core/src/dockview/components/panel/content.ts b/packages/dockview-core/src/dockview/components/panel/content.ts index 6c37035b07..c7de9e5682 100644 --- a/packages/dockview-core/src/dockview/components/panel/content.ts +++ b/packages/dockview-core/src/dockview/components/panel/content.ts @@ -51,6 +51,7 @@ export class ContentContainer super(); this._element = document.createElement('div'); this._element.className = 'dv-content-container'; + this.element.role = 'tabpanel'; this._element.tabIndex = -1; this.addDisposables(this._onDidFocus, this._onDidBlur); diff --git a/packages/dockview-core/src/dockview/components/tab/defaultTab.ts b/packages/dockview-core/src/dockview/components/tab/defaultTab.ts index 205e4e562c..82d4b4b3f3 100644 --- a/packages/dockview-core/src/dockview/components/tab/defaultTab.ts +++ b/packages/dockview-core/src/dockview/components/tab/defaultTab.ts @@ -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,39 @@ 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 " 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 +67,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; + } }) ); diff --git a/packages/dockview-core/src/dockview/components/tab/tab.ts b/packages/dockview-core/src/dockview/components/tab/tab.ts index c56bcaccba..8e92db1f81 100644 --- a/packages/dockview-core/src/dockview/components/tab/tab.ts +++ b/packages/dockview-core/src/dockview/components/tab/tab.ts @@ -53,6 +53,9 @@ export class Tab extends CompositeDisposable { private readonly _onPointDown = new Emitter(); readonly onPointerDown: Event = this._onPointDown.event; + private readonly _onKeyDown = new Emitter(); + readonly onKeyDown: Event = this._onKeyDown.event; + private readonly _onDropped = new Emitter(); readonly onDrop: Event = this._onDropped.event; @@ -74,8 +77,16 @@ export class Tab extends CompositeDisposable { this._element = document.createElement('div'); 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'; + + Object.entries(this.panel.tabComponentAttributes).forEach( + ([key, value]) => { + this._element.setAttribute(key, value); + } + ); toggleClass(this.element, 'dv-inactive-tab', true); @@ -139,6 +150,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 +161,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); } diff --git a/packages/dockview-core/src/dockview/components/titlebar/tabs.ts b/packages/dockview-core/src/dockview/components/titlebar/tabs.ts index 53486ed7cc..a0ca25df31 100644 --- a/packages/dockview-core/src/dockview/components/titlebar/tabs.ts +++ b/packages/dockview-core/src/dockview/components/titlebar/tabs.ts @@ -98,6 +98,10 @@ export class Tabs extends CompositeDisposable { this._tabsList = document.createElement('div'); this._tabsList.className = 'dv-tabs-container dv-horizontal'; + this._tabsList.ariaOrientation = 'horizontal'; + 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.showTabsOverflowControl = options.showTabsOverflowControl; @@ -115,6 +119,13 @@ export class Tabs extends CompositeDisposable { 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 +165,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 +236,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, diff --git a/packages/dockview-core/src/dockview/dockviewComponent.scss b/packages/dockview-core/src/dockview/dockviewComponent.scss index 440f6cc5ee..df182caab8 100644 --- a/packages/dockview-core/src/dockview/dockviewComponent.scss +++ b/packages/dockview-core/src/dockview/dockviewComponent.scss @@ -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 diff --git a/packages/dockview-core/src/dockview/dockviewComponent.ts b/packages/dockview-core/src/dockview/dockviewComponent.ts index a0c4fb6f1c..43320e6c64 100644 --- a/packages/dockview-core/src/dockview/dockviewComponent.ts +++ b/packages/dockview-core/src/dockview/dockviewComponent.ts @@ -2524,6 +2524,12 @@ export class DockviewComponent tabComponent ); + Object.entries(options.componentAttributes ?? {}).forEach( + ([key, value]) => { + view.content.element.setAttribute(key, value); + } + ); + const panel = new DockviewPanel( options.id, contentComponent, @@ -2538,6 +2544,8 @@ export class DockviewComponent minimumHeight: options.minimumHeight, maximumWidth: options.maximumWidth, maximumHeight: options.maximumHeight, + componentAttributes: options.componentAttributes, + tabComponentAttributes: options.tabComponentAttributes, } ); diff --git a/packages/dockview-core/src/dockview/dockviewPanel.ts b/packages/dockview-core/src/dockview/dockviewPanel.ts index bf71ca6c1b..44c2f2b0c5 100644 --- a/packages/dockview-core/src/dockview/dockviewPanel.ts +++ b/packages/dockview-core/src/dockview/dockviewPanel.ts @@ -19,6 +19,8 @@ export interface IDockviewPanel extends IDisposable, IPanel { readonly api: DockviewPanelApi; readonly title: string | undefined; readonly params: Parameters | undefined; + readonly componentAttributes: Record; + readonly tabComponentAttributes: Record; readonly minimumWidth?: number; readonly minimumHeight?: number; readonly maximumWidth?: number; @@ -40,6 +42,9 @@ export class DockviewPanel { readonly api: DockviewPanelApiImpl; + readonly componentAttributes: Record; + readonly tabComponentAttributes: Record; + private _group: DockviewGroupPanel; private _params?: Parameters; private _title: string | undefined; @@ -90,7 +95,10 @@ export class DockviewPanel private readonly containerApi: DockviewApi, group: DockviewGroupPanel, readonly view: IDockviewPanelModel, - options: { renderer?: DockviewPanelRenderer } & Partial + options: { renderer?: DockviewPanelRenderer } & Partial & { + componentAttributes?: Record; + tabComponentAttributes?: Record; + } ) { super(); this._renderer = options.renderer; @@ -100,6 +108,9 @@ export class DockviewPanel this._maximumWidth = options.maximumWidth; this._maximumHeight = options.maximumHeight; + this.componentAttributes = options.componentAttributes ?? {}; + this.tabComponentAttributes = options.tabComponentAttributes ?? {}; + this.api = new DockviewPanelApiImpl( this, this._group, diff --git a/packages/dockview-core/src/dockview/options.ts b/packages/dockview-core/src/dockview/options.ts index 39e66d2c36..bde41b22d8 100644 --- a/packages/dockview-core/src/dockview/options.ts +++ b/packages/dockview-core/src/dockview/options.ts @@ -260,6 +260,8 @@ export type AddPanelOptions

= { inactive?: boolean; initialWidth?: number; initialHeight?: number; + componentAttributes?: Record; + tabComponentAttributes?: Record; } & Partial & Partial; diff --git a/packages/dockview-core/src/gridview/gridview.ts b/packages/dockview-core/src/gridview/gridview.ts index bda8c06388..f44f81286d 100644 --- a/packages/dockview-core/src/gridview/gridview.ts +++ b/packages/dockview-core/src/gridview/gridview.ts @@ -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); diff --git a/packages/dockview-core/src/overlay/overlayRenderContainer.ts b/packages/dockview-core/src/overlay/overlayRenderContainer.ts index f83f50e5e0..c16af704a9 100644 --- a/packages/dockview-core/src/overlay/overlayRenderContainer.ts +++ b/packages/dockview-core/src/overlay/overlayRenderContainer.ts @@ -73,12 +73,12 @@ export class OverlayRenderContainer extends CompositeDisposable { if (!this.map[panel.api.id]) { const element = createFocusableElement(); element.className = 'dv-render-overlay'; + element.tabIndex = 0; this.map[panel.api.id] = { panel, disposable: Disposable.NONE, destroy: Disposable.NONE, - element, }; } diff --git a/packages/dockview-core/src/splitview/splitview.ts b/packages/dockview-core/src/splitview/splitview.ts index c511d54f65..57d9094673 100644 --- a/packages/dockview-core/src/splitview/splitview.ts +++ b/packages/dockview-core/src/splitview/splitview.ts @@ -102,7 +102,7 @@ export class Splitview { private readonly sashContainer: HTMLElement; private readonly viewItems: ViewItem[] = []; private readonly sashes: ISashItem[] = []; - private _orientation: Orientation; + private _orientation = Orientation.VERTICAL; private _size = 0; private _orthogonalSize = 0; private _contentSize = 0; @@ -159,12 +159,20 @@ export class Splitview { this.size = this.orthogonalSize; this.orthogonalSize = tmp; - removeClasses(this.element, 'dv-horizontal', 'dv-vertical'); - this.element.classList.add( - this.orientation == Orientation.HORIZONTAL - ? 'dv-horizontal' - : 'dv-vertical' + toggleClass( + this.element, + 'dv-horizontal', + this._orientation == Orientation.HORIZONTAL ); + toggleClass( + this.element, + 'dv-vertical', + this._orientation == Orientation.VERTICAL + ); + this.element.ariaOrientation = + this.orientation == Orientation.HORIZONTAL + ? 'horizontal' + : 'vertical'; } get minimumSize(): number { @@ -227,8 +235,8 @@ export class Splitview { private readonly container: HTMLElement, options: SplitViewOptions ) { - this._orientation = options.orientation ?? Orientation.VERTICAL; this.element = this.createContainer(); + this.orientation = options.orientation ?? Orientation.VERTICAL; this.margin = options.margin ?? 0; @@ -1143,11 +1151,7 @@ export class Splitview { private createContainer(): HTMLElement { const element = document.createElement('div'); - const orientationClassname = - this._orientation === Orientation.HORIZONTAL - ? 'dv-horizontal' - : 'dv-vertical'; - element.className = `dv-split-view-container ${orientationClassname}`; + element.className = `dv-split-view-container`; return element; }