mirror of
https://github.com/mathuo/dockview
synced 2025-02-02 14:35:46 +00:00
Merge pull request #214 from mathuo/213-internal-refactoring
refactor: internal refactoring
This commit is contained in:
commit
84e88f458f
@ -3,7 +3,6 @@ import {
|
||||
last,
|
||||
pushToEnd,
|
||||
pushToStart,
|
||||
range,
|
||||
sequenceEquals,
|
||||
tail,
|
||||
} from '../array';
|
||||
@ -37,12 +36,6 @@ describe('array', () => {
|
||||
expect(arr1).toEqual([3, 1, 2, 4]);
|
||||
});
|
||||
|
||||
test('range', () => {
|
||||
expect(range(0, 5)).toEqual([0, 1, 2, 3, 4]);
|
||||
expect(range(5, 0)).toEqual([5, 4, 3, 2, 1]);
|
||||
expect(range(5)).toEqual([0, 1, 2, 3, 4]);
|
||||
});
|
||||
|
||||
test('firstIndex', () => {
|
||||
expect(firstIndex([1, 2, 3, 4, 3], (item) => item === 3)).toBe(2);
|
||||
expect(firstIndex([1, 2, 3, 4, 3], (item) => item === 5)).toBe(-1);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { clamp } from '../math';
|
||||
import { clamp, range } from '../math';
|
||||
|
||||
describe('math', () => {
|
||||
describe('clamp', () => {
|
||||
@ -14,4 +14,10 @@ describe('math', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test('range', () => {
|
||||
expect(range(0, 5)).toEqual([0, 1, 2, 3, 4]);
|
||||
expect(range(5, 0)).toEqual([5, 4, 3, 2, 1]);
|
||||
expect(range(5)).toEqual([0, 1, 2, 3, 4]);
|
||||
});
|
||||
});
|
||||
|
@ -47,27 +47,6 @@ export function pushToEnd<T>(arr: T[], value: T): void {
|
||||
}
|
||||
}
|
||||
|
||||
export const range = (from: number, to?: number): number[] => {
|
||||
const result: number[] = [];
|
||||
|
||||
if (typeof to !== 'number') {
|
||||
to = from;
|
||||
from = 0;
|
||||
}
|
||||
|
||||
if (from <= to) {
|
||||
for (let i = from; i < to; i++) {
|
||||
result.push(i);
|
||||
}
|
||||
} else {
|
||||
for (let i = from; i > to; i--) {
|
||||
result.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export function firstIndex<T>(
|
||||
array: T[] | ReadonlyArray<T>,
|
||||
fn: (item: T) => boolean
|
||||
|
@ -4,7 +4,6 @@ import { CompositeDisposable } from '../lifecycle';
|
||||
import { DragAndDropObserver } from './dnd';
|
||||
import { clamp } from '../math';
|
||||
import { Direction } from '../gridview/baseComponentGridview';
|
||||
import { isBooleanValue } from '../types';
|
||||
|
||||
function numberOrFallback(maybeNumber: any, fallback: number): number {
|
||||
return typeof maybeNumber === 'number' ? maybeNumber : fallback;
|
||||
@ -120,7 +119,7 @@ export class Droptarget extends CompositeDisposable {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isBooleanValue(this.options.canDisplayOverlay)) {
|
||||
if (typeof this.options.canDisplayOverlay === 'boolean') {
|
||||
if (!this.options.canDisplayOverlay) {
|
||||
return;
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ export class ContentContainer
|
||||
private readonly _onDidBlur = new Emitter<void>();
|
||||
readonly onDidBlur: Event<void> = this._onDidBlur.event;
|
||||
|
||||
get element() {
|
||||
get element(): HTMLElement {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
@ -51,15 +51,15 @@ export class ContentContainer
|
||||
// 4) register mouseMove events (if no buttons are present we take this as a dragEnd event)
|
||||
}
|
||||
|
||||
show() {
|
||||
show(): void {
|
||||
this.element.style.display = '';
|
||||
}
|
||||
|
||||
hide() {
|
||||
hide(): void {
|
||||
this.element.style.display = 'none';
|
||||
}
|
||||
|
||||
public openPanel(panel: IDockviewPanel) {
|
||||
public openPanel(panel: IDockviewPanel): void {
|
||||
if (this.panel === panel) {
|
||||
return;
|
||||
}
|
||||
@ -105,14 +105,14 @@ export class ContentContainer
|
||||
// noop
|
||||
}
|
||||
|
||||
public closePanel() {
|
||||
public closePanel(): void {
|
||||
if (this.panel?.view?.content?.element) {
|
||||
this._element.removeChild(this.panel.view.content.element);
|
||||
this.panel = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
public dispose(): void {
|
||||
this.disposable.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import { toggleClass } from '../../../dom';
|
||||
import { IDockviewPanel } from '../../dockviewPanel';
|
||||
|
||||
export interface TabDropIndexEvent {
|
||||
event: DragEvent;
|
||||
readonly event: DragEvent;
|
||||
readonly index: number;
|
||||
}
|
||||
|
||||
@ -23,7 +23,6 @@ export interface ITabsContainer extends IDisposable {
|
||||
height: number | undefined;
|
||||
delete: (id: string) => void;
|
||||
indexOf: (id: string) => number;
|
||||
at: (index: number) => ITab;
|
||||
onDrop: Event<TabDropIndexEvent>;
|
||||
setActive: (isGroupActive: boolean) => void;
|
||||
setActivePanel: (panel: IDockviewPanel) => void;
|
||||
@ -55,11 +54,11 @@ export class TabsContainer
|
||||
private readonly _onDrop = new Emitter<TabDropIndexEvent>();
|
||||
readonly onDrop: Event<TabDropIndexEvent> = this._onDrop.event;
|
||||
|
||||
get panels() {
|
||||
get panels(): string[] {
|
||||
return this.tabs.map((_) => _.value.panelId);
|
||||
}
|
||||
|
||||
get size() {
|
||||
get size(): number {
|
||||
return this.tabs.length;
|
||||
}
|
||||
|
||||
@ -114,21 +113,17 @@ export class TabsContainer
|
||||
}
|
||||
}
|
||||
|
||||
public get element() {
|
||||
get element(): HTMLElement {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
public isActive(tab: ITab) {
|
||||
public isActive(tab: ITab): boolean {
|
||||
return (
|
||||
this.selectedIndex > -1 &&
|
||||
this.tabs[this.selectedIndex].value === tab
|
||||
);
|
||||
}
|
||||
|
||||
public at(index: number) {
|
||||
return this.tabs[index]?.value;
|
||||
}
|
||||
|
||||
public indexOf(id: string): number {
|
||||
return this.tabs.findIndex((tab) => tab.value.panelId === id);
|
||||
}
|
||||
@ -214,7 +209,7 @@ export class TabsContainer
|
||||
private addTab(
|
||||
tab: IValueDisposable<ITab>,
|
||||
index: number = this.tabs.length
|
||||
) {
|
||||
): void {
|
||||
if (index < 0 || index > this.tabs.length) {
|
||||
throw new Error('invalid location');
|
||||
}
|
||||
@ -235,7 +230,7 @@ export class TabsContainer
|
||||
}
|
||||
}
|
||||
|
||||
public delete(id: string) {
|
||||
public delete(id: string): void {
|
||||
const index = this.tabs.findIndex((tab) => tab.value.panelId === id);
|
||||
|
||||
const tabToRemove = this.tabs.splice(index, 1)[0];
|
||||
@ -246,14 +241,17 @@ export class TabsContainer
|
||||
value.element.remove();
|
||||
}
|
||||
|
||||
public setActivePanel(panel: IDockviewPanel) {
|
||||
public setActivePanel(panel: IDockviewPanel): void {
|
||||
this.tabs.forEach((tab) => {
|
||||
const isActivePanel = panel.id === tab.value.panelId;
|
||||
tab.value.setActive(isActivePanel);
|
||||
});
|
||||
}
|
||||
|
||||
public openPanel(panel: IDockviewPanel, index: number = this.tabs.length) {
|
||||
public openPanel(
|
||||
panel: IDockviewPanel,
|
||||
index: number = this.tabs.length
|
||||
): void {
|
||||
if (this.tabs.find((tab) => tab.value.panelId === panel.id)) {
|
||||
return;
|
||||
}
|
||||
@ -292,11 +290,11 @@ export class TabsContainer
|
||||
this.addTab(value, index);
|
||||
}
|
||||
|
||||
public closePanel(panel: IDockviewPanel) {
|
||||
public closePanel(panel: IDockviewPanel): void {
|
||||
this.delete(panel.id);
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
public dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
this.tabs.forEach((tab) => {
|
||||
|
@ -15,7 +15,7 @@ export class VoidContainer extends CompositeDisposable {
|
||||
private readonly _onDrop = new Emitter<DroptargetEvent>();
|
||||
readonly onDrop: Event<DroptargetEvent> = this._onDrop.event;
|
||||
|
||||
get element() {
|
||||
get element(): HTMLElement {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ export class Watermark
|
||||
private group: DockviewGroupPanel | undefined;
|
||||
private params: GroupPanelPartInitParameters | undefined;
|
||||
|
||||
get element() {
|
||||
get element(): HTMLElement {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
@ -61,19 +61,19 @@ export class Watermark
|
||||
);
|
||||
}
|
||||
|
||||
update(_event: PanelUpdateEvent) {
|
||||
update(_event: PanelUpdateEvent): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
focus() {
|
||||
focus(): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
layout(_width: number, _height: number) {
|
||||
layout(_width: number, _height: number): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
init(_params: WatermarkRendererInitParameters) {
|
||||
init(_params: WatermarkRendererInitParameters): void {
|
||||
this.render();
|
||||
}
|
||||
|
||||
@ -82,11 +82,11 @@ export class Watermark
|
||||
this.render();
|
||||
}
|
||||
|
||||
dispose() {
|
||||
dispose(): void {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private render() {
|
||||
private render(): void {
|
||||
const isOneGroup = !!(
|
||||
this.params && this.params.containerApi.size <= 1
|
||||
);
|
||||
|
@ -13,11 +13,11 @@ import {
|
||||
DockviewGroupPanelApi,
|
||||
} from './dockviewGroupPanel';
|
||||
import { ISplitviewStyles, Orientation } from '../splitview/splitview';
|
||||
import { FrameworkFactory } from '../types';
|
||||
import { PanelTransfer } from '../dnd/dataTransfer';
|
||||
import { IDisposable } from '../lifecycle';
|
||||
import { Position } from '../dnd/droptarget';
|
||||
import { IDockviewPanel } from './dockviewPanel';
|
||||
import { FrameworkFactory } from '../panel/componentFactory';
|
||||
|
||||
export interface IGroupControlRenderer extends IDisposable {
|
||||
readonly element: HTMLElement;
|
||||
|
@ -9,9 +9,9 @@ import {
|
||||
import { PanelApi, PanelApiImpl } from '../api/panelApi';
|
||||
|
||||
export interface BasePanelViewState {
|
||||
id: string;
|
||||
component: string;
|
||||
params?: Record<string, any>;
|
||||
readonly id: string;
|
||||
readonly component: string;
|
||||
readonly params?: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface BasePanelViewExported<T extends PanelApi> {
|
||||
@ -35,9 +35,7 @@ export abstract class BasePanelView<T extends PanelApiImpl>
|
||||
protected part?: IFrameworkPart;
|
||||
protected _params?: PanelInitParameters;
|
||||
|
||||
/**
|
||||
* Provide an IFrameworkPart that will determine the rendered UI of this view piece.
|
||||
*/
|
||||
// provide an IFrameworkPart that will determine the rendered UI of this view piece.
|
||||
protected abstract getComponent(): IFrameworkPart;
|
||||
|
||||
get element(): HTMLElement {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { GridviewPanel } from './gridviewPanel';
|
||||
import { ISplitviewStyles, Orientation } from '../splitview/splitview';
|
||||
import { FrameworkFactory } from '../types';
|
||||
import { FrameworkFactory } from '../panel/componentFactory';
|
||||
|
||||
export interface GridviewComponentOptions {
|
||||
proportionalLayout: boolean;
|
||||
|
@ -18,7 +18,7 @@ export namespace Disposable {
|
||||
export class CompositeDisposable {
|
||||
private readonly disposables: IDisposable[];
|
||||
|
||||
public static from(...args: IDisposable[]) {
|
||||
public static from(...args: IDisposable[]): CompositeDisposable {
|
||||
return new CompositeDisposable(...args);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
export const clamp = (value: number, min: number, max: number) => {
|
||||
export const clamp = (value: number, min: number, max: number): number => {
|
||||
if (min > max) {
|
||||
throw new Error(`${min} > ${max} is an invalid condition`);
|
||||
}
|
||||
@ -9,3 +9,24 @@ export const sequentialNumberGenerator = () => {
|
||||
let value = 1;
|
||||
return { next: () => (value++).toString() };
|
||||
};
|
||||
|
||||
export const range = (from: number, to?: number): number[] => {
|
||||
const result: number[] = [];
|
||||
|
||||
if (typeof to !== 'number') {
|
||||
to = from;
|
||||
from = 0;
|
||||
}
|
||||
|
||||
if (from <= to) {
|
||||
for (let i = from; i < to; i++) {
|
||||
result.push(i);
|
||||
}
|
||||
} else {
|
||||
for (let i = from; i > to; i--) {
|
||||
result.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { FrameworkFactory } from '../types';
|
||||
export interface FrameworkFactory<T> {
|
||||
createComponent: (id: string, componentId: string, component: any) => T;
|
||||
}
|
||||
|
||||
export function createComponent<T>(
|
||||
id: string,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { FrameworkFactory } from '../types';
|
||||
import { FrameworkFactory } from '../panel/componentFactory';
|
||||
import { PaneviewDndOverlayEvent } from './paneviewComponent';
|
||||
import { IPaneBodyPart, IPaneHeaderPart, PaneviewPanel } from './paneviewPanel';
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { IPanel, PanelInitParameters } from '../panel/types';
|
||||
import { IView, SplitViewOptions, LayoutPriority } from './splitview';
|
||||
import { FrameworkFactory } from '../types';
|
||||
import { SplitviewPanel } from './splitviewPanel';
|
||||
import { SplitviewComponent } from './splitviewComponent';
|
||||
import { FrameworkFactory } from '../panel/componentFactory';
|
||||
|
||||
export interface PanelViewInitParameters extends PanelInitParameters {
|
||||
minimumSize?: number;
|
||||
|
@ -120,6 +120,7 @@
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: var(--dv-background-color);
|
||||
|
||||
.view {
|
||||
height: 100%;
|
||||
|
@ -11,7 +11,8 @@ import {
|
||||
} from '../dom';
|
||||
import { clamp } from '../math';
|
||||
import { Event, Emitter } from '../events';
|
||||
import { pushToStart, pushToEnd, range, firstIndex } from '../array';
|
||||
import { pushToStart, pushToEnd, firstIndex } from '../array';
|
||||
import { range } from '../math';
|
||||
import { ViewItem } from './viewItem';
|
||||
|
||||
export enum Orientation {
|
||||
|
@ -3,7 +3,7 @@ const createSvgElementFromPath = (params: {
|
||||
width: string;
|
||||
viewbox: string;
|
||||
path: string;
|
||||
}) => {
|
||||
}): SVGSVGElement => {
|
||||
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||||
svg.setAttributeNS(null, 'height', params.height);
|
||||
svg.setAttributeNS(null, 'width', params.width);
|
||||
@ -17,7 +17,7 @@ const createSvgElementFromPath = (params: {
|
||||
return svg;
|
||||
};
|
||||
|
||||
export const createCloseButton = () =>
|
||||
export const createCloseButton = (): SVGSVGElement =>
|
||||
createSvgElementFromPath({
|
||||
width: '11',
|
||||
height: '11',
|
||||
@ -25,7 +25,7 @@ export const createCloseButton = () =>
|
||||
path: 'M2.1 27.3L0 25.2L11.55 13.65L0 2.1L2.1 0L13.65 11.55L25.2 0L27.3 2.1L15.75 13.65L27.3 25.2L25.2 27.3L13.65 15.75L2.1 27.3Z',
|
||||
});
|
||||
|
||||
export const createExpandMoreButton = () =>
|
||||
export const createExpandMoreButton = (): SVGSVGElement =>
|
||||
createSvgElementFromPath({
|
||||
width: '11',
|
||||
height: '11',
|
||||
@ -33,7 +33,7 @@ export const createExpandMoreButton = () =>
|
||||
path: 'M12 14.15L0 2.15L2.15 0L12 9.9L21.85 0.0499992L24 2.2L12 14.15Z',
|
||||
});
|
||||
|
||||
export const createChevronRightButton = () =>
|
||||
export const createChevronRightButton = (): SVGSVGElement =>
|
||||
createSvgElementFromPath({
|
||||
width: '11',
|
||||
height: '11',
|
||||
|
@ -1,4 +1,5 @@
|
||||
@mixin dockview-theme-core-mixin {
|
||||
--dv-background-color: black;
|
||||
--dv-paneview-active-outline-color: dodgerblue;
|
||||
--dv-tabs-and-actions-container-font-size: 13px;
|
||||
--dv-tabs-and-actions-container-height: 35px;
|
||||
|
@ -1,11 +1,3 @@
|
||||
export interface FrameworkFactory<T> {
|
||||
createComponent: (id: string, componentId: string, component: any) => T;
|
||||
}
|
||||
|
||||
export function isBooleanValue(value: any): value is boolean {
|
||||
return typeof value === 'boolean';
|
||||
}
|
||||
|
||||
export type FunctionOrValue<T> = (() => T) | T;
|
||||
|
||||
export type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
|
||||
|
@ -16,7 +16,7 @@ export class ReactPanelView extends SplitviewPanel {
|
||||
super(id, component);
|
||||
}
|
||||
|
||||
getComponent() {
|
||||
getComponent(): ReactPart<ISplitviewPanelProps> {
|
||||
return new ReactPart(
|
||||
this.element,
|
||||
this.reactPortalStore,
|
||||
|
@ -24,6 +24,7 @@ import CustomHeadersDockview from '@site/sandboxes/customheader-dockview/src/app
|
||||
import DockviewNative from '@site/sandboxes/fullwidthtab-dockview/src/app';
|
||||
import DockviewNative2 from '@site/sandboxes/nativeapp-dockview/src/app';
|
||||
import DockviewSetTitle from '@site/sandboxes/updatetitle-dockview/src/app';
|
||||
// import { attach as attachDockviewVanilla } from '@site/sandboxes/vanilla-dockview/src/app';
|
||||
|
||||
# Dockview
|
||||
|
||||
@ -656,6 +657,22 @@ const GroupControlComponent = (props: IDockviewGroupControlProps) => {
|
||||
<DockviewGroupControl />
|
||||
</Container>
|
||||
|
||||
### Constraints
|
||||
|
||||
You may wish to specify a minimum or maximum height or width for a group which can be done through the group api.
|
||||
|
||||
```tsx
|
||||
api.group.api.setConstraints(...)
|
||||
```
|
||||
|
||||
> Constraints are currently only supported for groups and not individual panels.
|
||||
> 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}>
|
||||
<DockviewConstraints />
|
||||
</Container>
|
||||
|
||||
## Events
|
||||
|
||||
<Container height={600}>
|
||||
@ -685,8 +702,14 @@ hello 2
|
||||
<App />
|
||||
</div>
|
||||
|
||||
## Contraints
|
||||
<!-- ## VanillaJS
|
||||
|
||||
<Container>
|
||||
<DockviewConstraints />
|
||||
</Container>
|
||||
> Note: This section is experimental and support for Vanilla JS is a work in progress.
|
||||
|
||||
The `dockview` package contains `ReactJS` wrappers for the core library.
|
||||
The core library is published as an independant package under the name `dockview-core` which you can install standalone.
|
||||
|
||||
> When using `dockview` there is no need to also install `dockview-core`.
|
||||
> `dockview-core` is a dependency of `dockview` and automatically installed during the installation process of `dockview` via `npm install dockview`.
|
||||
|
||||
<Container injectVanillaJS={attachDockviewVanilla} /> -->
|
||||
|
@ -30,12 +30,24 @@ export const CreateCloseButton = () =>
|
||||
});
|
||||
|
||||
export const Container = (props: {
|
||||
children: React.ReactNode;
|
||||
children?: React.ReactNode;
|
||||
height?: number;
|
||||
injectVanillaJS?: (parent: HTMLElement) => void;
|
||||
}) => {
|
||||
const ref = React.useRef<HTMLDivElement>(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!props.injectVanillaJS) {
|
||||
return;
|
||||
}
|
||||
|
||||
props.injectVanillaJS(ref.current);
|
||||
}, [props.injectVanillaJS]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
ref={ref}
|
||||
style={{
|
||||
height: props.height ? `${props.height}px` : '300px',
|
||||
}}
|
||||
|
Loading…
Reference in New Issue
Block a user