mirror of
https://github.com/mathuo/dockview
synced 2025-02-02 14:35:46 +00:00
Merge pull request #212 from mathuo/210-setconstraints-on-gridview-enable-size-locking-1
fix: dockview panel group should derive constraints
This commit is contained in:
commit
464c4fd938
@ -50,6 +50,39 @@ describe('dockviewPanel', () => {
|
||||
disposable.dispose();
|
||||
});
|
||||
|
||||
test('that .setTitle updates the title', () => {
|
||||
const dockviewApiMock = jest.fn<DockviewApi, []>(() => {
|
||||
return {
|
||||
onDidActiveChange: jest.fn(),
|
||||
} as any;
|
||||
});
|
||||
const accessorMock = jest.fn<DockviewComponent, []>(() => {
|
||||
return {} as any;
|
||||
});
|
||||
const groupMock = jest.fn<DockviewGroupPanel, []>(() => {
|
||||
return {} as any;
|
||||
});
|
||||
const panelModelMock = jest.fn<Partial<IDockviewPanelModel>, []>(() => {
|
||||
return {
|
||||
update: jest.fn(),
|
||||
init: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
const api = new dockviewApiMock();
|
||||
const accessor = new accessorMock();
|
||||
const group = new groupMock();
|
||||
const model = <IDockviewPanelModel>new panelModelMock();
|
||||
|
||||
const cut = new DockviewPanel('fake-id', accessor, api, group, model);
|
||||
|
||||
cut.init({ title: 'myTitle', params: {} });
|
||||
expect(cut.title).toBe('myTitle');
|
||||
|
||||
cut.setTitle('newTitle');
|
||||
expect(cut.title).toBe('newTitle');
|
||||
});
|
||||
|
||||
test('dispose cleanup', () => {
|
||||
const dockviewApiMock = jest.fn<DockviewApi, []>(() => {
|
||||
return {} as any;
|
||||
|
@ -12,7 +12,11 @@ export interface TitleEvent {
|
||||
* omit visibility modifiers since the visibility of a single group doesn't make sense
|
||||
* because it belongs to a groupview
|
||||
*/
|
||||
export interface DockviewPanelApi extends Omit<GridviewPanelApi, 'setVisible'> {
|
||||
export interface DockviewPanelApi
|
||||
extends Omit<
|
||||
GridviewPanelApi,
|
||||
'setVisible' | 'onDidConstraintsChange' | 'setConstraints'
|
||||
> {
|
||||
readonly group: DockviewGroupPanel;
|
||||
readonly isGroupActive: boolean;
|
||||
readonly title: string;
|
||||
|
@ -4,13 +4,14 @@ import { GridviewPanelApi } from '../api/gridviewPanelApi';
|
||||
import {
|
||||
DockviewGroupPanelModel,
|
||||
GroupOptions,
|
||||
IDockviewGroupPanelModel,
|
||||
IHeader,
|
||||
} from './dockviewGroupPanelModel';
|
||||
import { GridviewPanel, IGridviewPanel } from '../gridview/gridviewPanel';
|
||||
import { IDockviewPanel } from '../dockview/dockviewPanel';
|
||||
|
||||
export interface IDockviewGroupPanel extends IGridviewPanel {
|
||||
model: DockviewGroupPanelModel;
|
||||
model: IDockviewGroupPanelModel;
|
||||
locked: boolean;
|
||||
readonly size: number;
|
||||
readonly panels: IDockviewPanel[];
|
||||
@ -25,7 +26,7 @@ export class DockviewGroupPanel
|
||||
extends GridviewPanel
|
||||
implements IDockviewGroupPanel
|
||||
{
|
||||
private readonly _model: DockviewGroupPanelModel;
|
||||
private readonly _model: IDockviewGroupPanelModel;
|
||||
|
||||
get panels(): IDockviewPanel[] {
|
||||
return this._model.panels;
|
||||
@ -39,26 +40,10 @@ export class DockviewGroupPanel
|
||||
return this._model.size;
|
||||
}
|
||||
|
||||
get model(): DockviewGroupPanelModel {
|
||||
get model(): IDockviewGroupPanelModel {
|
||||
return this._model;
|
||||
}
|
||||
|
||||
get minimumHeight(): number {
|
||||
return this._model.minimumHeight;
|
||||
}
|
||||
|
||||
get maximumHeight(): number {
|
||||
return this._model.maximumHeight;
|
||||
}
|
||||
|
||||
get minimumWidth(): number {
|
||||
return this._model.minimumWidth;
|
||||
}
|
||||
|
||||
get maximumWidth(): number {
|
||||
return this._model.maximumWidth;
|
||||
}
|
||||
|
||||
get locked(): boolean {
|
||||
return this._model.locked;
|
||||
}
|
||||
@ -76,7 +61,10 @@ export class DockviewGroupPanel
|
||||
id: string,
|
||||
options: GroupOptions
|
||||
) {
|
||||
super(id, 'groupview_default');
|
||||
super(id, 'groupview_default', {
|
||||
minimumHeight: 100,
|
||||
minimumWidth: 100,
|
||||
});
|
||||
|
||||
this._model = new DockviewGroupPanelModel(
|
||||
this.element,
|
||||
|
@ -4,10 +4,9 @@ import { Droptarget, Position } from '../dnd/droptarget';
|
||||
import { DockviewComponent } from './dockviewComponent';
|
||||
import { isAncestor, toggleClass } from '../dom';
|
||||
import { addDisposableListener, Emitter, Event } from '../events';
|
||||
import { IGridPanelView } from '../gridview/baseComponentGridview';
|
||||
import { IViewSize } from '../gridview/gridview';
|
||||
import { CompositeDisposable } from '../lifecycle';
|
||||
import { PanelInitParameters, PanelUpdateEvent } from '../panel/types';
|
||||
import { IPanel, PanelInitParameters, PanelUpdateEvent } from '../panel/types';
|
||||
import {
|
||||
ContentContainer,
|
||||
IContentContainer,
|
||||
@ -82,7 +81,7 @@ export interface IHeader {
|
||||
height: number | undefined;
|
||||
}
|
||||
|
||||
export interface IDockviewGroupPanelModel extends IGridPanelView {
|
||||
export interface IDockviewGroupPanelModel extends IPanel {
|
||||
readonly isActive: boolean;
|
||||
readonly size: number;
|
||||
readonly panels: IDockviewPanel[];
|
||||
@ -95,13 +94,20 @@ export interface IDockviewGroupPanelModel extends IGridPanelView {
|
||||
readonly onDidActivePanelChange: Event<GroupviewChangeEvent>;
|
||||
readonly onMove: Event<GroupMoveEvent>;
|
||||
locked: boolean;
|
||||
setActive(isActive: boolean): void;
|
||||
initialize(): void;
|
||||
// state
|
||||
isPanelActive: (panel: IDockviewPanel) => boolean;
|
||||
indexOf(panel: IDockviewPanel): number;
|
||||
// panel lifecycle
|
||||
openPanel(
|
||||
panel: IDockviewPanel,
|
||||
options?: { index?: number; skipFocus?: boolean }
|
||||
options?: {
|
||||
index?: number;
|
||||
skipFocus?: boolean;
|
||||
skipSetPanelActive?: boolean;
|
||||
skipSetGroupActive?: boolean;
|
||||
}
|
||||
): void;
|
||||
closePanel(panel: IDockviewPanel): void;
|
||||
closeAllPanels(): void;
|
||||
@ -199,22 +205,6 @@ export class DockviewGroupPanelModel
|
||||
return this._panels.length === 0;
|
||||
}
|
||||
|
||||
get minimumHeight(): number {
|
||||
return 100;
|
||||
}
|
||||
|
||||
get maximumHeight(): number {
|
||||
return Number.MAX_SAFE_INTEGER;
|
||||
}
|
||||
|
||||
get minimumWidth(): number {
|
||||
return 100;
|
||||
}
|
||||
|
||||
get maximumWidth(): number {
|
||||
return Number.MAX_SAFE_INTEGER;
|
||||
}
|
||||
|
||||
get hasWatermark(): boolean {
|
||||
return !!(
|
||||
this.watermark && this.container.contains(this.watermark.element)
|
||||
|
@ -126,9 +126,31 @@ export abstract class GridviewPanel
|
||||
return this.api.isActive;
|
||||
}
|
||||
|
||||
constructor(id: string, component: string) {
|
||||
constructor(
|
||||
id: string,
|
||||
component: string,
|
||||
options?: {
|
||||
minimumWidth?: number;
|
||||
maximumWidth?: number;
|
||||
minimumHeight?: number;
|
||||
maximumHeight?: number;
|
||||
}
|
||||
) {
|
||||
super(id, component, new GridviewPanelApiImpl(id));
|
||||
|
||||
if (typeof options?.minimumWidth === 'number') {
|
||||
this._minimumWidth = options.minimumWidth;
|
||||
}
|
||||
if (typeof options?.maximumWidth === 'number') {
|
||||
this._maximumWidth = options.maximumWidth;
|
||||
}
|
||||
if (typeof options?.minimumHeight === 'number') {
|
||||
this._minimumHeight = options.minimumHeight;
|
||||
}
|
||||
if (typeof options?.maximumHeight === 'number') {
|
||||
this._maximumHeight = options.maximumHeight;
|
||||
}
|
||||
|
||||
this.api.initialize(this); // TODO: required to by-pass 'super before this' requirement
|
||||
|
||||
this.addDisposables(
|
||||
|
@ -1,92 +0,0 @@
|
||||
import { trackFocus } from './dom';
|
||||
import { Emitter, Event } from './events';
|
||||
import { IDisposable } from './lifecycle';
|
||||
|
||||
export interface HostedContainerOptions {
|
||||
id: string;
|
||||
parent?: HTMLElement;
|
||||
}
|
||||
|
||||
export class HostedContainer implements IDisposable {
|
||||
private readonly _element: HTMLElement;
|
||||
|
||||
private readonly _onDidFocus = new Emitter<void>();
|
||||
readonly onDidFocus: Event<void> = this._onDidFocus.event;
|
||||
|
||||
private readonly _onDidBlur = new Emitter<void>();
|
||||
readonly onDidBlur: Event<void> = this._onDidBlur.event;
|
||||
|
||||
get element() {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
constructor(private readonly options: HostedContainerOptions) {
|
||||
if (!options.parent) {
|
||||
options.parent = document.getElementById('app') as HTMLElement;
|
||||
options.parent.style.position = 'relative';
|
||||
}
|
||||
|
||||
this._element = document.createElement('div');
|
||||
this._element.style.visibility = 'hidden';
|
||||
this._element.style.overflow = 'hidden';
|
||||
// this._element.style.pointerEvents = 'none';
|
||||
this._element.id = `webview-${options.id}`;
|
||||
this._element.tabIndex = -1;
|
||||
|
||||
const { onDidFocus, onDidBlur } = trackFocus(this._element);
|
||||
|
||||
onDidFocus(() => this._onDidFocus.fire());
|
||||
onDidBlur(() => this._onDidBlur.fire());
|
||||
|
||||
/**
|
||||
* When dragging somebody
|
||||
*/
|
||||
|
||||
window.addEventListener('dragstart', () => {
|
||||
this.element.style.pointerEvents = 'none';
|
||||
});
|
||||
window.addEventListener('dragend', () => {
|
||||
this.element.style.pointerEvents = '';
|
||||
});
|
||||
window.addEventListener('mousemove', (ev) => {
|
||||
if (ev.buttons === 0) {
|
||||
this.element.style.pointerEvents = '';
|
||||
}
|
||||
});
|
||||
|
||||
options.parent.appendChild(this._element);
|
||||
}
|
||||
|
||||
hide() {
|
||||
this._element.style.visibility = 'hidden';
|
||||
}
|
||||
|
||||
show() {
|
||||
this._element.style.visibility = 'visible';
|
||||
}
|
||||
|
||||
layout(
|
||||
element: HTMLElement,
|
||||
dimension?: { width: number; height: number }
|
||||
) {
|
||||
if (!this.element || !this.element.parentElement) {
|
||||
return;
|
||||
}
|
||||
const frameRect = element.getBoundingClientRect();
|
||||
const containerRect =
|
||||
this.element.parentElement.getBoundingClientRect();
|
||||
this.element.style.position = 'absolute';
|
||||
this.element.style.top = `${frameRect.top - containerRect.top}px`;
|
||||
this.element.style.left = `${frameRect.left - containerRect.left}px`;
|
||||
this.element.style.width = `${
|
||||
dimension ? dimension.width : frameRect.width
|
||||
}px`;
|
||||
this.element.style.height = `${
|
||||
dimension ? dimension.height : frameRect.height
|
||||
}px`;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._element.remove();
|
||||
}
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
export * from './hostedContainer';
|
||||
|
||||
export * from './dnd/dataTransfer';
|
||||
|
||||
export { watchElementResize } from './dom';
|
||||
|
@ -9,10 +9,9 @@ import {
|
||||
toggleClass,
|
||||
getElementsByTagName,
|
||||
} from '../dom';
|
||||
import { clamp } from '../math';
|
||||
import { Event, Emitter } from '../events';
|
||||
import { pushToStart, pushToEnd, firstIndex } from '../array';
|
||||
import { range } from '../math';
|
||||
import { range, clamp } from '../math';
|
||||
import { ViewItem } from './viewItem';
|
||||
|
||||
export enum Orientation {
|
||||
|
@ -1,6 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { ReactPart, ReactPortalStore } from '../react';
|
||||
import { IGroupPanelBaseProps } from './dockview';
|
||||
import {
|
||||
PanelUpdateEvent,
|
||||
DockviewGroupPanel,
|
||||
|
@ -32,7 +32,7 @@ import DockviewSetTitle from '@site/sandboxes/updatetitle-dockview/src/app';
|
||||
|
||||
Dockview is an abstraction built on top of [Gridviews](./gridview) where each view is a container of many tabbed panels.
|
||||
|
||||
<Container>
|
||||
<Container sandboxId="simple-dockview">
|
||||
<SimpleDockview />
|
||||
</Container>
|
||||
|
||||
@ -209,7 +209,7 @@ const onReady = (event: DockviewReadyEvent) => {
|
||||
Here is an example using the above code loading from and saving to localStorage.
|
||||
If you refresh the page you should notice your layout is loaded as you left it.
|
||||
|
||||
<Container>
|
||||
<Container sandboxId="layout-dockview">
|
||||
<DockviewPersistance />
|
||||
</Container>
|
||||
|
||||
@ -238,7 +238,7 @@ props.api.group.api.setSize({
|
||||
|
||||
You can see an example invoking both approaches below.
|
||||
|
||||
<Container>
|
||||
<Container sandboxId="resize-dockview">
|
||||
<ResizeDockview />
|
||||
</Container>
|
||||
|
||||
@ -248,7 +248,7 @@ When the dockview is empty you may want to display some fallback content, this i
|
||||
By default there the watermark has no content but you can provide as a prop to `DockviewReact` a `watermarkComponent`
|
||||
which will be rendered when there are no panels or groups.
|
||||
|
||||
<Container>
|
||||
<Container sandboxId="watermark-dockview">
|
||||
<DockviewWatermark />
|
||||
</Container>
|
||||
|
||||
@ -327,7 +327,7 @@ return (
|
||||
);
|
||||
```
|
||||
|
||||
<Container>
|
||||
<Container sandboxId="dnd-dockview">
|
||||
<DndDockview />
|
||||
</Container>
|
||||
|
||||
@ -525,7 +525,7 @@ As a simple example the below attaches a custom event handler for the context me
|
||||
The below example uses a custom tab renderer to reigster a popover when the user right clicked on a tab.
|
||||
This still makes use of the `DockviewDefaultTab` since it's only a minor change.
|
||||
|
||||
<Container>
|
||||
<Container sandboxId="customheader-dockview">
|
||||
<CustomHeadersDockview />
|
||||
</Container>
|
||||
|
||||
@ -550,7 +550,7 @@ api.setTitle('my_new_custom_title');
|
||||
|
||||
> Note this only works when using the default tab implementation.
|
||||
|
||||
<Container>
|
||||
<Container sandboxId="updatetitle-dockview">
|
||||
<DockviewSetTitle />
|
||||
</Container>
|
||||
|
||||
@ -599,7 +599,7 @@ to the entire width of the group. For example:
|
||||
<DockviewReactComponent singleTabMode="fullwidth" {...otherProps} />
|
||||
```
|
||||
|
||||
<Container>
|
||||
<Container sandboxId="fullwidthtab-dockview">
|
||||
<DockviewNative />
|
||||
</Container>
|
||||
|
||||
@ -653,7 +653,7 @@ const GroupControlComponent = (props: IDockviewGroupControlProps) => {
|
||||
};
|
||||
```
|
||||
|
||||
<Container>
|
||||
<Container sandboxId="groupcontrol-dockview">
|
||||
<DockviewGroupControl />
|
||||
</Container>
|
||||
|
||||
@ -669,13 +669,15 @@ api.group.api.setConstraints(...)
|
||||
> If you specific a constraint on a group and move a panel within that group to another group it will no
|
||||
> longer be subject to those constraints since those constraints were on the group and not on the individual panel.
|
||||
|
||||
<Container height={500}>
|
||||
<Container height={500} sandboxId="constraints-dockview">
|
||||
<DockviewConstraints />
|
||||
</Container>
|
||||
|
||||
## Events
|
||||
|
||||
<Container height={600}>
|
||||
A simple example showing events fired by `dockviewz that can be interacted with.
|
||||
|
||||
<Container height={600} sandboxId="events-dockview">
|
||||
<EventsDockview />
|
||||
</Container>
|
||||
|
||||
@ -686,7 +688,7 @@ api.group.api.setConstraints(...)
|
||||
You can safely create multiple dockview instances within one page and nest dockviews within other dockviews.
|
||||
If you wish to interact with the drop event from one dockview instance in another dockview instance you can implement the `showDndOverlay` and `onDidDrop` props on `DockviewReact`.
|
||||
|
||||
<Container>
|
||||
<Container sandboxId="nested-dockview">
|
||||
<NestedDockview />
|
||||
</Container>
|
||||
|
||||
|
@ -9,39 +9,14 @@ import {
|
||||
import * as React from 'react';
|
||||
|
||||
const components = {
|
||||
default: (props: IDockviewPanelProps<{ title: string }>) => {
|
||||
default: (props: IDockviewPanelProps) => {
|
||||
const [contraints, setContraints] =
|
||||
React.useState<GridConstraintChangeEvent | null>(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
props.api.group.api.setConstraints({
|
||||
maximumHeight: 200,
|
||||
maximumWidth: 200,
|
||||
});
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
const disposable1 = new DockviewMutableDisposable();
|
||||
|
||||
const disposable = props.api.onDidGroupChange(() => {
|
||||
disposable1.value = props.api.group.api.onDidConstraintsChange(
|
||||
(event) => {
|
||||
props.api.group.api.onDidConstraintsChange((event) => {
|
||||
setContraints(event);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
setContraints({
|
||||
maximumHeight: props.api.group.maximumHeight,
|
||||
minimumHeight: props.api.group.minimumHeight,
|
||||
maximumWidth: props.api.group.maximumWidth,
|
||||
minimumWidth: props.api.group.minimumWidth,
|
||||
});
|
||||
|
||||
return () => {
|
||||
disposable1.dispose();
|
||||
disposable.dispose();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
@ -53,13 +28,64 @@ const components = {
|
||||
color: 'white',
|
||||
}}
|
||||
>
|
||||
<span> {props.params.title}</span>
|
||||
{contraints && (
|
||||
<div>
|
||||
<div>{`minHeight=${contraints.minimumHeight}`}</div>
|
||||
<div>{`maxHeight=${contraints.maximumHeight}`}</div>
|
||||
<div>{`minWidth=${contraints.minimumWidth}`}</div>
|
||||
<div>{`maxWidth=${contraints.maximumWidth}`}</div>
|
||||
<div style={{ fontSize: '13px' }}>
|
||||
{typeof contraints.maximumHeight === 'number' && (
|
||||
<div
|
||||
style={{
|
||||
border: '1px solid grey',
|
||||
margin: '2px',
|
||||
padding: '1px',
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{ color: 'grey' }}
|
||||
>{`Maximum Height: `}</span>
|
||||
<span>{`${contraints.maximumHeight}px`}</span>
|
||||
</div>
|
||||
)}
|
||||
{typeof contraints.minimumHeight === 'number' && (
|
||||
<div
|
||||
style={{
|
||||
border: '1px solid grey',
|
||||
margin: '2px',
|
||||
padding: '1px',
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{ color: 'grey' }}
|
||||
>{`Minimum Height: `}</span>
|
||||
<span>{`${contraints.minimumHeight}px`}</span>
|
||||
</div>
|
||||
)}
|
||||
{typeof contraints.maximumWidth === 'number' && (
|
||||
<div
|
||||
style={{
|
||||
border: '1px solid grey',
|
||||
margin: '2px',
|
||||
padding: '1px',
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{ color: 'grey' }}
|
||||
>{`Maximum Width: `}</span>
|
||||
<span>{`${contraints.maximumWidth}px`}</span>
|
||||
</div>
|
||||
)}
|
||||
{typeof contraints.minimumWidth === 'number' && (
|
||||
<div
|
||||
style={{
|
||||
border: '1px solid grey',
|
||||
margin: '2px',
|
||||
padding: '1px',
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{ color: 'grey' }}
|
||||
>{`Minimum Width: `}</span>
|
||||
<span>{`${contraints.minimumWidth}px`}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -71,19 +97,40 @@ const App = () => {
|
||||
const [api, setApi] = React.useState<DockviewApi>();
|
||||
|
||||
const onReady = (event: DockviewReadyEvent) => {
|
||||
event.api.addPanel({
|
||||
const panel1 = event.api.addPanel({
|
||||
id: 'panel_1',
|
||||
component: 'default',
|
||||
});
|
||||
|
||||
event.api.addPanel({
|
||||
const panel2 = event.api.addPanel({
|
||||
id: 'panel_2',
|
||||
component: 'default',
|
||||
position: {
|
||||
referencePanel: panel1,
|
||||
direction: 'right',
|
||||
},
|
||||
});
|
||||
|
||||
event.api.addPanel({
|
||||
const panel3 = event.api.addPanel({
|
||||
id: 'panel_3',
|
||||
component: 'default',
|
||||
position: {
|
||||
referencePanel: panel2,
|
||||
direction: 'right',
|
||||
},
|
||||
});
|
||||
|
||||
const panel4 = event.api.addPanel({
|
||||
id: 'panel_4',
|
||||
component: 'default',
|
||||
position: {
|
||||
direction: 'below',
|
||||
},
|
||||
});
|
||||
|
||||
panel2.api.group.api.setConstraints({
|
||||
maximumWidth: 300,
|
||||
maximumHeight: 300,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -182,49 +182,49 @@ const EventsDockview = () => {
|
||||
panels: {
|
||||
panel_1: {
|
||||
id: 'panel_1',
|
||||
view: { content: { id: 'default' } },
|
||||
contentComponent: 'default',
|
||||
params: { title: 'Panel 1' },
|
||||
title: 'panel_1',
|
||||
},
|
||||
panel_2: {
|
||||
id: 'panel_2',
|
||||
view: { content: { id: 'default' } },
|
||||
contentComponent: 'default',
|
||||
params: { title: 'Panel 2' },
|
||||
title: 'panel_2',
|
||||
},
|
||||
panel_3: {
|
||||
id: 'panel_3',
|
||||
view: { content: { id: 'default' } },
|
||||
contentComponent: 'default',
|
||||
params: { title: 'Panel 3' },
|
||||
title: 'panel_3',
|
||||
},
|
||||
panel_4: {
|
||||
id: 'panel_4',
|
||||
view: { content: { id: 'default' } },
|
||||
contentComponent: 'default',
|
||||
params: { title: 'Panel 4' },
|
||||
title: 'panel_4',
|
||||
},
|
||||
panel_5: {
|
||||
id: 'panel_5',
|
||||
view: { content: { id: 'default' } },
|
||||
contentComponent: 'default',
|
||||
params: { title: 'Panel 5' },
|
||||
title: 'panel_5',
|
||||
},
|
||||
panel_6: {
|
||||
id: 'panel_6',
|
||||
view: { content: { id: 'default' } },
|
||||
contentComponent: 'default',
|
||||
params: { title: 'Panel 6' },
|
||||
title: 'panel_6',
|
||||
},
|
||||
panel_8: {
|
||||
id: 'panel_8',
|
||||
view: { content: { id: 'default' } },
|
||||
contentComponent: 'default',
|
||||
params: { title: 'Panel 8' },
|
||||
title: 'panel_8',
|
||||
},
|
||||
panel_7: {
|
||||
id: 'panel_7',
|
||||
view: { content: { id: 'default' } },
|
||||
contentComponent: 'default',
|
||||
params: { title: 'Panel 7' },
|
||||
title: 'panel_7',
|
||||
},
|
||||
@ -334,7 +334,7 @@ const EventsDockview = () => {
|
||||
className="dockview-theme-abyss"
|
||||
/>
|
||||
</div>
|
||||
<div style={{ flexGrow: 1 }}>
|
||||
<div style={{ flexGrow: 1, paddingTop: '5px' }}>
|
||||
<Console lines={lines} />
|
||||
</div>
|
||||
</div>
|
||||
|
22
packages/docs/sandboxes/vanilla-dockview/package.json
Normal file
22
packages/docs/sandboxes/vanilla-dockview/package.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "vanilla-dockview",
|
||||
"description": "",
|
||||
"keywords": [
|
||||
"dockview"
|
||||
],
|
||||
"version": "1.0.0",
|
||||
"main": "src/index.ts",
|
||||
"dependencies": {
|
||||
"dockview-core": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"scripts": {},
|
||||
"browserslist": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not ie <= 11",
|
||||
"not op_mini all"
|
||||
]
|
||||
}
|
43
packages/docs/sandboxes/vanilla-dockview/public/index.html
Normal file
43
packages/docs/sandboxes/vanilla-dockview/public/index.html
Normal file
@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="#000000">
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
|
||||
</html>
|
88
packages/docs/sandboxes/vanilla-dockview/src/app.ts
Normal file
88
packages/docs/sandboxes/vanilla-dockview/src/app.ts
Normal file
@ -0,0 +1,88 @@
|
||||
import {
|
||||
DockviewComponent,
|
||||
IContentRenderer,
|
||||
IGroupPanelInitParameters,
|
||||
} from 'dockview';
|
||||
|
||||
class DefaultPanel implements IContentRenderer {
|
||||
private _element: HTMLElement;
|
||||
|
||||
get element(): HTMLElement {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this._element = document.createElement('div');
|
||||
}
|
||||
|
||||
init(params: IGroupPanelInitParameters): void {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
export function attach(parent: HTMLElement): {
|
||||
dispose: () => void;
|
||||
} {
|
||||
const element = document.createElement('div');
|
||||
element.className = 'dockview-theme-abyss';
|
||||
parent.appendChild(element);
|
||||
|
||||
const dockview = new DockviewComponent(element, {
|
||||
components: {
|
||||
default: DefaultPanel,
|
||||
},
|
||||
});
|
||||
|
||||
const observer = new ResizeObserver((entires) => {
|
||||
const firstEntry = entires[0];
|
||||
|
||||
const { width, height } = firstEntry.contentRect;
|
||||
dockview.layout(width, height);
|
||||
});
|
||||
|
||||
observer.observe(parent);
|
||||
|
||||
const panel1 = dockview.addPanel({
|
||||
id: 'panel_1',
|
||||
title: 'Panel 1',
|
||||
component: 'default',
|
||||
});
|
||||
|
||||
const panel2 = dockview.addPanel({
|
||||
id: 'panel_2',
|
||||
title: 'Panel 2',
|
||||
component: 'default',
|
||||
position: {
|
||||
referencePanel: panel1,
|
||||
direction: 'right',
|
||||
},
|
||||
});
|
||||
|
||||
const panel3 = dockview.addPanel({
|
||||
id: 'panel_3',
|
||||
title: 'Panel 3',
|
||||
component: 'default',
|
||||
position: {
|
||||
referenceGroup: panel2.group,
|
||||
},
|
||||
});
|
||||
|
||||
const pane4 = dockview.addPanel({
|
||||
id: 'panel_4',
|
||||
title: 'Panel 4',
|
||||
component: 'default',
|
||||
position: {
|
||||
direction: 'below',
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
dispose: () => {
|
||||
observer.unobserve(element);
|
||||
observer.disconnect();
|
||||
|
||||
dockview.dispose();
|
||||
element.remove();
|
||||
},
|
||||
};
|
||||
}
|
10
packages/docs/sandboxes/vanilla-dockview/src/index.ts
Normal file
10
packages/docs/sandboxes/vanilla-dockview/src/index.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import './styles.css';
|
||||
import 'dockview/dist/styles/dockview.css';
|
||||
|
||||
import { attach } from './app';
|
||||
|
||||
const rootElement = document.getElementById('root');
|
||||
|
||||
if (rootElement) {
|
||||
attach(rootElement);
|
||||
}
|
16
packages/docs/sandboxes/vanilla-dockview/src/styles.css
Normal file
16
packages/docs/sandboxes/vanilla-dockview/src/styles.css
Normal file
@ -0,0 +1,16 @@
|
||||
body {
|
||||
margin: 0px;
|
||||
color: white;
|
||||
font-family: sans-serif;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#root {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
.app {
|
||||
height: 100%;
|
||||
|
||||
}
|
20
packages/docs/sandboxes/vanilla-dockview/tsconfig.json
Normal file
20
packages/docs/sandboxes/vanilla-dockview/tsconfig.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "build/dist",
|
||||
"module": "esnext",
|
||||
"target": "es5",
|
||||
"lib": ["es6", "dom"],
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"jsx": "react-jsx",
|
||||
"moduleResolution": "node",
|
||||
"rootDir": "src",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true,
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"noUnusedLocals": true
|
||||
}
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
import * as React from 'react';
|
||||
import './container.scss';
|
||||
|
||||
const BASE_SANDBOX_URL =
|
||||
'https://codesandbox.io/s/github/mathuo/dockview/tree/master/packages/docs/sandboxes';
|
||||
|
||||
const createSvgElementFromPath = (params: {
|
||||
height: string;
|
||||
width: string;
|
||||
@ -33,9 +35,17 @@ export const Container = (props: {
|
||||
children?: React.ReactNode;
|
||||
height?: number;
|
||||
injectVanillaJS?: (parent: HTMLElement) => void;
|
||||
sandboxId?: string;
|
||||
}) => {
|
||||
const ref = React.useRef<HTMLDivElement>(null);
|
||||
|
||||
const url = React.useMemo(() => {
|
||||
if (!props.sandboxId) {
|
||||
return '';
|
||||
}
|
||||
return `${BASE_SANDBOX_URL}/${props.sandboxId}`;
|
||||
}, [props.sandboxId]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!props.injectVanillaJS) {
|
||||
return;
|
||||
@ -64,24 +74,29 @@ export const Container = (props: {
|
||||
>
|
||||
<span style={{ flexGrow: 1 }} />
|
||||
|
||||
{url && (
|
||||
<span
|
||||
className="codesandbox-button"
|
||||
style={{ display: 'flex', alignItems: 'center' }}
|
||||
>
|
||||
<span className="codesandbox-button-pretext">{`Open in `}</span>
|
||||
<a
|
||||
href="https://www.google.com"
|
||||
href={url}
|
||||
target={'_blank'}
|
||||
className="codesandbox-button-content"
|
||||
>
|
||||
<span
|
||||
style={{ fontWeight: 'bold', paddingRight: '4px' }}
|
||||
style={{
|
||||
fontWeight: 'bold',
|
||||
paddingRight: '4px',
|
||||
}}
|
||||
>
|
||||
CodeSandbox
|
||||
</span>
|
||||
<CreateCloseButton />
|
||||
</a>
|
||||
</span>
|
||||
)}
|
||||
{/* <span
|
||||
style={{ fontSize: '16px' }}
|
||||
className="material-symbols-outlined"
|
||||
|
Loading…
Reference in New Issue
Block a user