Merge remote-tracking branch 'upstream/master' into tab-accessibility

This commit is contained in:
Ademola Adedeji 2025-02-19 09:35:57 -04:00
commit 86d1ea7f01
19 changed files with 345 additions and 50 deletions

View File

@ -2,7 +2,7 @@
"packages": [
"packages/*"
],
"version": "3.1.0",
"version": "3.2.0",
"npmClient": "yarn",
"command": {
"publish": {

View File

@ -1,6 +1,6 @@
{
"name": "dockview-angular",
"version": "3.1.0",
"version": "3.2.0",
"description": "Zero dependency layout manager supporting tabs, grids and splitviews",
"keywords": [
"splitview",
@ -54,6 +54,6 @@
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview --coverage"
},
"dependencies": {
"dockview-core": "^3.1.0"
"dockview-core": "^3.2.0"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "dockview-core",
"version": "3.1.0",
"version": "3.2.0",
"description": "Zero dependency layout manager supporting tabs, grids and splitviews",
"keywords": [
"splitview",

View File

@ -49,8 +49,8 @@ export class Tab extends CompositeDisposable {
private readonly dropTarget: Droptarget;
private content: ITabRenderer | undefined = undefined;
private readonly _onChanged = new Emitter<MouseEvent>();
readonly onChanged: Event<MouseEvent> = this._onChanged.event;
private readonly _onPointDown = new Emitter<MouseEvent>();
readonly onPointerDown: Event<MouseEvent> = this._onPointDown.event;
private readonly _onDropped = new Emitter<DroptargetEvent>();
readonly onDrop: Event<DroptargetEvent> = this._onDropped.event;
@ -123,7 +123,7 @@ export class Tab extends CompositeDisposable {
this.onWillShowOverlay = this.dropTarget.onWillShowOverlay;
this.addDisposables(
this._onChanged,
this._onPointDown,
this._onDropped,
this._onDragStart,
dragHandler.onDragStart((event) => {
@ -131,11 +131,7 @@ export class Tab extends CompositeDisposable {
}),
dragHandler,
addDisposableListener(this._element, 'pointerdown', (event) => {
if (event.defaultPrevented) {
return;
}
this._onChanged.fire(event);
this._onPointDown.fire(event);
}),
this.dropTarget.onDrop((event) => {
this._onDropped.fire(event);

View File

@ -360,7 +360,7 @@ export class TabsContainer
tab.onDragStart((event) => {
this._onTabDragStart.fire({ nativeEvent: event, panel });
}),
tab.onChanged((event) => {
tab.onPointerDown((event) => {
if (event.defaultPrevented) {
return;
}
@ -399,9 +399,6 @@ export class TabsContainer
this.group.model.openPanel(panel);
}
break;
case 1: // middle click
panel.api.close();
break;
}
}),
tab.onDrop((event) => {

View File

@ -117,15 +117,16 @@
-ms-user-select: none; // IE 10 and IE 11
touch-action: none;
&:not(.disabled):active {
transition: background-color 0.1s ease-in-out;
background-color: var(--dv-active-sash-color, transparent);
}
&:not(.disabled):active,
&:not(.disabled):hover {
background-color: var(--dv-active-sash-color, transparent);
transition: background-color 0.1s ease-in-out;
transition-delay: 0.5s;
transition-property: background-color;
transition-timing-function: ease-in-out;
transition-duration: var(
--dv-active-sash-transition-duration,
0.1s
);
transition-delay: var(--dv-active-sash-transition-delay, 0.5s);
}
}
}

View File

@ -8,6 +8,8 @@
--dv-icon-hover-background-color: rgba(90, 93, 94, 0.31);
--dv-floating-box-shadow: 8px 8px 8px 0px rgba(83, 89, 93, 0.5);
--dv-overlay-z-index: 999;
--dv-active-sash-transition-duration: 0.1s;
--dv-active-sash-transition-delay: 0.5s;
}
@mixin dockview-theme-dark-mixin {

View File

@ -1,6 +1,6 @@
{
"name": "dockview-react",
"version": "3.1.0",
"version": "3.2.0",
"description": "Zero dependency layout manager supporting tabs, grids and splitviews",
"keywords": [
"splitview",
@ -54,6 +54,6 @@
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview-react --coverage"
},
"dependencies": {
"dockview": "^3.1.0"
"dockview": "^3.2.0"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "dockview-vue",
"version": "3.1.0",
"version": "3.2.0",
"description": "Zero dependency layout manager supporting tabs, grids and splitviews",
"keywords": [
"splitview",
@ -52,7 +52,7 @@
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview-vue --coverage"
},
"dependencies": {
"dockview-core": "^3.1.0"
"dockview-core": "^3.2.0"
},
"peerDependencies": {
"vue": "^3.4.0"

View File

@ -1,6 +1,6 @@
{
"name": "dockview",
"version": "3.1.0",
"version": "3.2.0",
"description": "Zero dependency layout manager supporting tabs, grids and splitviews",
"keywords": [
"splitview",
@ -54,7 +54,7 @@
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview --coverage"
},
"dependencies": {
"dockview-core": "^3.1.0"
"dockview-core": "^3.2.0"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"

View File

@ -32,10 +32,15 @@ export const DockviewDefaultTab: React.FunctionComponent<
params: _params,
hideClose,
closeActionOverride,
onPointerDown,
onPointerUp,
onPointerLeave,
...rest
}) => {
const title = useTitle(api);
const isMiddleMouseButton = React.useRef<boolean>(false);
const onClose = React.useCallback(
(event: React.MouseEvent<HTMLSpanElement>) => {
event.preventDefault();
@ -49,21 +54,52 @@ export const DockviewDefaultTab: React.FunctionComponent<
[api, closeActionOverride]
);
const onPointerDown = React.useCallback((e: React.MouseEvent) => {
e.preventDefault();
const onBtnPointerDown = React.useCallback((event: React.MouseEvent) => {
event.preventDefault();
}, []);
const _onPointerDown = React.useCallback(
(event: React.PointerEvent<HTMLDivElement>) => {
isMiddleMouseButton.current = event.button === 1;
onPointerDown?.(event);
},
[onPointerDown]
);
const _onPointerUp = React.useCallback(
(event: React.PointerEvent<HTMLDivElement>) => {
if (isMiddleMouseButton && event.button === 1 && !hideClose) {
isMiddleMouseButton.current = false;
onClose(event);
}
onPointerUp?.(event);
},
[onPointerUp, onClose, hideClose]
);
const _onPointerLeave = React.useCallback(
(event: React.PointerEvent<HTMLDivElement>) => {
isMiddleMouseButton.current = false;
onPointerLeave?.(event);
},
[onPointerLeave]
);
return (
<div
data-testid="dockview-dv-default-tab"
{...rest}
onPointerDown={_onPointerDown}
onPointerUp={_onPointerUp}
onPointerLeave={_onPointerLeave}
className="dv-default-tab"
>
<span className="dv-default-tab-content">{title}</span>
{!hideClose && (
<div
className="dv-default-tab-action"
onPointerDown={onPointerDown}
onPointerDown={onBtnPointerDown}
onClick={onClose}
>
<CloseButton />

View File

@ -0,0 +1,18 @@
---
slug: dockview-3.1.1-release
title: Dockview 3.1.1
tags: [release]
---
# Release Notes
Please reference docs @ [dockview.dev](https://dockview.dev).
## 🚀 Features
## 🛠 Miscs
- Bug: Fix Middle mouse button to close tab [#835](https://github.com/mathuo/dockview/issues/853)
## 🔥 Breaking changes

View File

@ -0,0 +1,18 @@
---
slug: dockview-3.2.0-release
title: Dockview 3.2.0
tags: [release]
---
# Release Notes
Please reference docs @ [dockview.dev](https://dockview.dev).
## 🚀 Features
- Add CSS properties `--dv-active-sash-transition-duration` and `--dv-active-sash-transition-delay` [#835](https://github.com/mathuo/dockview/issues/859)
## 🛠 Miscs
## 🔥 Breaking changes

View File

@ -184,17 +184,8 @@ const config = {
label: 'API',
},
{ to: '/blog', label: 'Blog', position: 'left' },
{ href: '/templates', target:"_blank", label: 'Examples', position: 'left' },
{ to: '/demo', label: 'Demo', position: 'left' },
// {
// to: 'https://dockview.dev/typedocs',
// label: 'TSDoc',
// position: 'left',
// },
// {
// type: 'docsVersionDropdown',
// position: 'right',
// },
{
href: 'https://github.com/mathuo/dockview',
position: 'right',

View File

@ -1,6 +1,6 @@
{
"name": "dockview-docs",
"version": "3.1.0",
"version": "3.2.0",
"private": true,
"scripts": {
"build": "npm run build-templates && docusaurus build",
@ -38,7 +38,7 @@
"ag-grid-react": "^31.0.2",
"axios": "^1.6.3",
"clsx": "^2.1.0",
"dockview": "^3.1.0",
"dockview": "^3.2.0",
"prism-react-renderer": "^2.3.1",
"react-dnd": "^16.0.1",
"react-laag": "^2.0.5",

View File

@ -1,7 +1,6 @@
import fs from 'fs-extra';
import * as path from 'path';
import { argv } from 'process';
import { execSync } from 'child_process';
import { fileURLToPath } from 'url';
@ -86,7 +85,8 @@ function createIndexHTML(options) {
.map(([key, value]) => `"${key}": "${value}"`)
.join(',\n')}`
)
.replace('{{app}}', options.app);
.replace('{{app}}', options.app)
.replace('{{githubLink}}', options.githubUrl)
}
const input_dir = path.join(__dirname, '../templates');
@ -97,6 +97,8 @@ const FRAMEWORKS = ['react', 'vue', 'typescript'];
const list = [];
const githubUrl = "https://github.com/mathuo/dockview/tree/master/packages/docs/templates"
for (const component of COMPONENTS) {
const componentDir = path.join(input_dir, component);
@ -115,6 +117,9 @@ for (const component of COMPONENTS) {
path.join(componentDir, folder, framework, 'src'),
path.join(output, component, folder, framework, 'src')
);
const templateGithubUrl = `${githubUrl}/${component}/${folder}/${framework}/src`
const template = createIndexHTML({
title: `Dockview | ${folder} ${framework}`,
app:
@ -127,6 +132,7 @@ for (const component of COMPONENTS) {
USE_LOCAL_CDN ? 'local' : 'remote'
],
},
githubUrl: templateGithubUrl
});
fs.writeFileSync(
path.join(output, component, folder, framework, 'index.html'),

View File

@ -12,7 +12,7 @@
<style media="only screen">
html,
body,
#app {
#root {
height: 100%;
width: 100%;
margin: 0;
@ -22,6 +22,26 @@
BlinkMacSystemFont, Segoe UI, Roboto;
}
#header {
height: 25px;
display: flex;
justify-content: flex-end;
align-items: center;
}
#header-btn {
height: 22px;
}
#gh-logo {
height: 22px;
width: 22px;
}
#app {
height: calc(100% - 25px);
}
html {
position: absolute;
top: 0;
@ -31,7 +51,7 @@
}
body {
padding: 16px;
padding: 8px;
overflow: auto;
}
</style>
@ -62,9 +82,18 @@
</head>
<body>
<div id="app">
<script type="systemjs-module" src="import:{{app}}"></script>
<div id="root">
<div id="header">
<a target="_blank" rel="noopener noreferrer" href="{{githubLink}}">
<button id="header-btn">
View Source
</button>
</a>
<img id="gh-logo" src="https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png"/>
</div>
<div id="app"></div>
</div>
<script type="systemjs-module" src="import:{{app}}"></script>
<object
id="loading-spinner"
style="

View File

@ -0,0 +1,23 @@
.dockview-groupcontrol-demo {
height: 100%;
display: flex;
align-items: center;
color: white;
background-color: black;
padding: 0px 8px;
margin: 1px;
border: 1px dotted orange;
}
.dockview-groupcontrol-demo .dockview-groupcontrol-demo-group-active {
padding: 0px 8px;
}
.dockview-groupcontrol-demo .dockview-groupcontrol-demo-active-panel {
color: yellow;
padding: 0px 8px;
}

View File

@ -0,0 +1,178 @@
import 'dockview-core/dist/styles/dockview.css';
import {
createDockview,
DockviewGroupPanel,
GroupPanelPartInitParameters,
IContentRenderer,
IGroupHeaderProps,
IHeaderActionsRenderer,
} from 'dockview-core';
import './index.css';
class Panel implements IContentRenderer {
private readonly _element: HTMLElement;
get element(): HTMLElement {
return this._element;
}
constructor() {
this._element = document.createElement('div');
this._element.style.display = 'flex';
this._element.style.justifyContent = 'center';
this._element.style.alignItems = 'center';
this._element.style.color = 'gray';
this._element.style.height = '100%';
}
init(parameters: GroupPanelPartInitParameters): void {
//
}
}
class PrefixHeader implements IHeaderActionsRenderer {
private readonly _element: HTMLElement;
get element(): HTMLElement {
return this._element;
}
constructor(group: DockviewGroupPanel) {
this._element = document.createElement('div');
this._element.className = 'dockview-groupcontrol-demo';
this._element.innerText = '🌲';
}
init(parameters: IGroupHeaderProps): void {
//
}
dispose(): void {
//
}
}
class RightHeaderActions implements IHeaderActionsRenderer {
private readonly _element: HTMLElement;
private readonly _disposables: (() => void)[] = [];
get element(): HTMLElement {
return this._element;
}
constructor(group: DockviewGroupPanel) {
this._element = document.createElement('div');
this._element.className = 'dockview-groupcontrol-demo';
}
init(parameters: IGroupHeaderProps): void {
const group = parameters.group;
const span = document.createElement('span');
span.className = 'dockview-groupcontrol-demo-group-active';
this._element.appendChild(span);
const d1 = group.api.onDidActiveChange(() => {
span.style.background = group.api.isActive ? 'green' : 'red';
span.innerText = `${
group.api.isActive ? 'Group Active' : 'Group Inactive'
}`;
});
span.style.background = group.api.isActive ? 'green' : 'red';
span.innerText = `${
group.api.isActive ? 'Group Active' : 'Group Inactive'
}`;
this._disposables.push(() => d1.dispose());
}
dispose(): void {
this._disposables.forEach((dispose) => dispose());
}
}
class LeftHeaderActions implements IHeaderActionsRenderer {
private readonly _element: HTMLElement;
private readonly _disposables: (() => void)[] = [];
get element(): HTMLElement {
return this._element;
}
constructor(group: DockviewGroupPanel) {
console.log('group', group);
this._element = document.createElement('div');
this._element.className = 'dockview-groupcontrol-demo';
}
init(parameters: IGroupHeaderProps): void {
const group = parameters.group;
const span = document.createElement('span');
span.className = 'dockview-groupcontrol-demo-active-panel';
this._element.appendChild(span);
const d1 = group.api.onDidActivePanelChange((event) => {
console.log('event', event);
span.innerText = `activePanel: ${event.panel?.id || 'null'}`;
});
console.log('group.activePanel', group.activePanel);
span.innerText = `activePanel: ${group.activePanel?.id || 'null'}`;
this._disposables.push(() => d1.dispose());
}
dispose(): void {
this._disposables.forEach((dispose) => dispose());
}
}
const api = createDockview(document.getElementById('app'), {
className: 'dockview-theme-abyss',
createComponent: (options): IContentRenderer => {
switch (options.name) {
case 'default':
return new Panel();
default:
throw new Error('Panel not found');
}
},
createPrefixHeaderActionComponent: (group): IHeaderActionsRenderer => {
return new PrefixHeader(group);
},
createLeftHeaderActionComponent: (group): IHeaderActionsRenderer => {
return new LeftHeaderActions(group);
},
createRightHeaderActionComponent: (group): IHeaderActionsRenderer => {
return new RightHeaderActions(group);
},
});
api.addPanel({
id: 'panel_1',
component: 'default',
title: 'Panel 1',
});
api.addPanel({
id: 'panel_2',
component: 'default',
title: 'Panel 2',
position: {
direction: 'right',
},
});
api.addPanel({
id: 'panel_3',
component: 'default',
title: 'Panel 3',
position: {
direction: 'below',
},
});