refactor: internal refactoring

This commit is contained in:
mathuo 2023-03-21 17:25:37 +01:00
parent 5b1aa4221f
commit 6aca089685
No known key found for this signature in database
GPG Key ID: C6EEDEFD6CA07281
24 changed files with 119 additions and 93 deletions

View File

@ -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);

View File

@ -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]);
});
});

View File

@ -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

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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) => {

View File

@ -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;
}

View File

@ -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
);

View File

@ -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;

View File

@ -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 {

View File

@ -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;

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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,

View File

@ -1,4 +1,4 @@
import { FrameworkFactory } from '../types';
import { FrameworkFactory } from '../panel/componentFactory';
import { PaneviewDndOverlayEvent } from './paneviewComponent';
import { IPaneBodyPart, IPaneHeaderPart, PaneviewPanel } from './paneviewPanel';

View File

@ -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;

View File

@ -120,6 +120,7 @@
position: relative;
height: 100%;
width: 100%;
background-color: var(--dv-background-color);
.view {
height: 100%;

View File

@ -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 {

View File

@ -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',

View File

@ -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;

View File

@ -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>;

View File

@ -16,7 +16,7 @@ export class ReactPanelView extends SplitviewPanel {
super(id, component);
}
getComponent() {
getComponent(): ReactPart<ISplitviewPanelProps> {
return new ReactPart(
this.element,
this.reactPortalStore,

View File

@ -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} /> -->

View File

@ -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',
}}