mirror of
https://github.com/mathuo/dockview
synced 2025-03-15 10:22:03 +00:00
code
This commit is contained in:
parent
4033489e38
commit
47f27633da
@ -2,7 +2,7 @@ import * as React from "react";
|
||||
import { LoadFromConfig } from "./loadFromConfig";
|
||||
import { FromApi } from "./fromApi";
|
||||
import { PaneDemo } from "./pane";
|
||||
import { TestGrid } from "./reactgrid";
|
||||
import { TestGrid } from "./layout-grid/reactgrid";
|
||||
|
||||
const options = [
|
||||
{ id: "config", component: LoadFromConfig },
|
||||
|
6
packages/splitview-demo/src/layout-grid/customTab.tsx
Normal file
6
packages/splitview-demo/src/layout-grid/customTab.tsx
Normal file
@ -0,0 +1,6 @@
|
||||
import * as React from "react";
|
||||
import { IPanelProps } from "splitview";
|
||||
|
||||
export const CustomTab = (props: IPanelProps) => {
|
||||
return <div>hello</div>;
|
||||
};
|
@ -9,6 +9,39 @@ import {
|
||||
CompositeDisposable,
|
||||
GroupChangeKind,
|
||||
} from "splitview";
|
||||
import { CustomTab } from "./customTab";
|
||||
import { SplitPanel } from "./splitPanel";
|
||||
|
||||
const Editor = (props: IPanelProps & { layoutApi: Api }) => {
|
||||
const [tabHeight, setTabHeight] = React.useState<number>(0);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (props.layoutApi) {
|
||||
setTabHeight(props.layoutApi.getTabHeight());
|
||||
}
|
||||
}, [props.layoutApi]);
|
||||
|
||||
const onTabHeightChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = Number(event.target.value);
|
||||
if (!Number.isNaN(value)) {
|
||||
setTabHeight(value);
|
||||
}
|
||||
};
|
||||
|
||||
const onClick = () => {
|
||||
props.layoutApi.setTabHeight(tabHeight);
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ height: "100%", backgroundColor: "white", color: "black" }}>
|
||||
<label>
|
||||
Tab height
|
||||
<input onChange={onTabHeightChange} value={tabHeight} type="number" />
|
||||
<button onClick={onClick}>Apply</button>
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const components = {
|
||||
inner_component: (props: IPanelProps) => {
|
||||
@ -122,6 +155,7 @@ const components = {
|
||||
|
||||
const backgroundColor = React.useMemo(
|
||||
() =>
|
||||
// "#1e1e1e",
|
||||
`rgb(${Math.floor(Math.random() * 256)},${Math.floor(
|
||||
Math.random() * 256
|
||||
)},${Math.floor(Math.random() * 256)})`,
|
||||
@ -143,6 +177,12 @@ const components = {
|
||||
</div>
|
||||
);
|
||||
},
|
||||
editor: Editor,
|
||||
split_panel: SplitPanel,
|
||||
};
|
||||
|
||||
const tabComponents = {
|
||||
default: CustomTab,
|
||||
};
|
||||
|
||||
const nextGuid = (() => {
|
||||
@ -177,7 +217,7 @@ export const TestGrid = () => {
|
||||
title: "Item 2",
|
||||
});
|
||||
api.addPanelFromComponent({
|
||||
componentName: "test_component",
|
||||
componentName: "split_panel",
|
||||
id: nextGuid(),
|
||||
title: "Item 3 with a long title",
|
||||
});
|
||||
@ -202,6 +242,18 @@ export const TestGrid = () => {
|
||||
componentName: "test_component",
|
||||
};
|
||||
});
|
||||
|
||||
api.addDndHandle("Files", (ev) => {
|
||||
const { event } = ev;
|
||||
|
||||
ev.event.event.preventDefault();
|
||||
|
||||
return {
|
||||
id: Date.now().toString(),
|
||||
title: event.event.dataTransfer.files[0].name,
|
||||
componentName: "test_component",
|
||||
};
|
||||
});
|
||||
}, [api]);
|
||||
|
||||
const onAdd = () => {
|
||||
@ -224,6 +276,7 @@ export const TestGrid = () => {
|
||||
_api.current?.layout(width, height);
|
||||
};
|
||||
window.addEventListener("resize", callback);
|
||||
callback(undefined);
|
||||
|
||||
const dis = _api.current.onDidLayoutChange((event) => {
|
||||
console.log(event.kind);
|
||||
@ -280,7 +333,6 @@ export const TestGrid = () => {
|
||||
if (!api) {
|
||||
return;
|
||||
}
|
||||
console.log("create drag refs");
|
||||
api.createDragTarget(
|
||||
{ element: dragRef.current, content: "drag me" },
|
||||
() => ({
|
||||
@ -294,10 +346,25 @@ export const TestGrid = () => {
|
||||
event.dataTransfer.setData("text/plain", "Panel2");
|
||||
};
|
||||
|
||||
const onAddEditor = () => {
|
||||
api.addPanelFromComponent({
|
||||
id: "editor",
|
||||
componentName: "editor",
|
||||
tabComponentName: "default",
|
||||
params: { layoutApi: api },
|
||||
});
|
||||
};
|
||||
|
||||
const onTabContextMenu = (event: MouseEvent) => {};
|
||||
|
||||
return (
|
||||
<div style={{ width: "100%" }}>
|
||||
<div
|
||||
// className="visual-studio-theme"
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
<div style={{ height: "20px", display: "flex" }}>
|
||||
<button onClick={onAdd}>Add</button>
|
||||
<button onClick={onAddEditor}>Expr</button>
|
||||
<button onClick={onAddEmpty}>Add empty</button>
|
||||
<button onClick={onConfig}>Save</button>
|
||||
<button onClick={onLoad}>Load</button>
|
||||
@ -335,9 +402,12 @@ export const TestGrid = () => {
|
||||
// autoSizeToFitContainer={true}
|
||||
onReady={onReady}
|
||||
components={components}
|
||||
tabComponents={tabComponents}
|
||||
debug={true}
|
||||
// tabHeight={30}
|
||||
enableExternalDragEvents={true}
|
||||
// serializedLayout={data}
|
||||
// onTabContextMenu={onTabContextMenu}
|
||||
/>
|
||||
</div>
|
||||
);
|
43
packages/splitview-demo/src/layout-grid/splitPanel.tsx
Normal file
43
packages/splitview-demo/src/layout-grid/splitPanel.tsx
Normal file
@ -0,0 +1,43 @@
|
||||
import * as React from "react";
|
||||
import {
|
||||
IPanelProps,
|
||||
Orientation,
|
||||
SplitviewFacade,
|
||||
SplitviewReadyEvent,
|
||||
} from "splitview";
|
||||
import { SplitViewComponent } from "splitview";
|
||||
|
||||
const components = {
|
||||
default1: (props) => {
|
||||
return <div style={{ height: "100%", width: "100%" }}>hiya</div>;
|
||||
},
|
||||
};
|
||||
|
||||
export const SplitPanel = (props: IPanelProps) => {
|
||||
const api = React.useRef<SplitviewFacade>();
|
||||
|
||||
React.useEffect(() => {
|
||||
props.api.onDidPanelDimensionChange((event) => {
|
||||
// const [height,width] = [event.height, event.width]
|
||||
// const [size, orthogonalSize] =
|
||||
// props.orientation === Orientation.HORIZONTAL
|
||||
// ? [width, height]
|
||||
// : [height, width];
|
||||
api.current?.layout(event.width, event.height);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const onReady = (event: SplitviewReadyEvent) => {
|
||||
event.api.addFromComponent({ id: "1", component: "default1" });
|
||||
event.api.addFromComponent({ id: "2", component: "default1" });
|
||||
api.current = event.api;
|
||||
};
|
||||
|
||||
return (
|
||||
<SplitViewComponent
|
||||
components={components}
|
||||
onReady={onReady}
|
||||
orientation={Orientation.VERTICAL}
|
||||
/>
|
||||
);
|
||||
};
|
@ -16,7 +16,7 @@ export interface IPaneComponentRef {
|
||||
layout: (size: number, orthogonalSize: number) => void;
|
||||
}
|
||||
|
||||
export type PaneComponent = React.RefForwardingComponent<
|
||||
export type PaneComponent = React.ForwardRefRenderFunction<
|
||||
IPaneComponentRef,
|
||||
IPaneComponentProps
|
||||
>;
|
||||
@ -27,7 +27,7 @@ export interface IPaneHeaderComponentProps extends IViewWithReactComponent {
|
||||
userprops?: { [index: string]: any };
|
||||
}
|
||||
|
||||
export type PaneHeaderComponent = React.RefForwardingComponent<
|
||||
export type PaneHeaderComponent = React.ForwardRefRenderFunction<
|
||||
{},
|
||||
IPaneHeaderComponentProps
|
||||
>;
|
||||
|
@ -12,7 +12,7 @@ export interface IViewComponentRef {
|
||||
layout: (size: number, orthogonalSize: number) => void;
|
||||
}
|
||||
|
||||
export type ViewComponent = React.RefForwardingComponent<
|
||||
export type ViewComponent = React.ForwardRefRenderFunction<
|
||||
IViewComponentRef,
|
||||
IViewComponentProps
|
||||
>;
|
||||
|
@ -24,19 +24,19 @@ export interface IPaneViewReactProps {
|
||||
initialLayout?: PaneViewSerializedConfig;
|
||||
}
|
||||
|
||||
export type PaneViewReadyEvent = {
|
||||
export interface PaneViewReadyEvent {
|
||||
api: PaneviewApi;
|
||||
};
|
||||
}
|
||||
|
||||
export type PaneViewSerializedConfig = {
|
||||
export interface PaneViewSerializedConfig {
|
||||
views: Array<
|
||||
Omit<IPaneWithReactComponent, "component" | "headerComponent"> & {
|
||||
size?: number;
|
||||
}
|
||||
>;
|
||||
};
|
||||
}
|
||||
|
||||
export type PaneviewApi = {
|
||||
export interface PaneviewApi {
|
||||
add: (
|
||||
options: Omit<IPaneWithReactComponent, "component" | "headerComponent"> & {
|
||||
size?: number;
|
||||
@ -45,7 +45,7 @@ export type PaneviewApi = {
|
||||
) => void;
|
||||
moveView: (from: number, to: number) => void;
|
||||
toJSON: () => {};
|
||||
};
|
||||
}
|
||||
|
||||
export interface IPaneViewComponentRef {
|
||||
layout: (size: number, orthogonalSize: number) => void;
|
||||
|
@ -9,15 +9,15 @@ export interface IViewWithReactComponent extends IBaseView {
|
||||
component: ViewComponent;
|
||||
}
|
||||
|
||||
export type OnReadyEvent = {
|
||||
export interface OnReadyEvent {
|
||||
api: SplitviewApi;
|
||||
};
|
||||
}
|
||||
|
||||
export type SerializedConfig = {
|
||||
export interface SerializedConfig {
|
||||
views: Array<Omit<IViewWithReactComponent, "component"> & { size?: number }>;
|
||||
};
|
||||
}
|
||||
|
||||
export type SplitviewApi = {
|
||||
export interface SplitviewApi {
|
||||
add: (
|
||||
options: Omit<IViewWithReactComponent, "component"> & {
|
||||
size?: number;
|
||||
@ -26,7 +26,7 @@ export type SplitviewApi = {
|
||||
) => void;
|
||||
moveView: (from: number, to: number) => void;
|
||||
toJSON: () => {};
|
||||
};
|
||||
}
|
||||
|
||||
export interface ISplitViewReactProps {
|
||||
orientation: Orientation;
|
||||
|
@ -6,7 +6,7 @@
|
||||
"types": "dist/esm/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "gulp run",
|
||||
"docs": "typedoc --excludeNotExported --excludePrivate true --mode file --out typedocs/ src/"
|
||||
"docs": "typedoc"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Orientation, Sizing } from "../splitview/splitview";
|
||||
import { Target } from "../groupview/droptarget/droptarget";
|
||||
import { Position } from "../groupview/droptarget/droptarget";
|
||||
import { tail } from "../array";
|
||||
import { LeafNode } from "./leafNode";
|
||||
import { BranchNode } from "./branchNode";
|
||||
@ -91,7 +91,7 @@ export function getGridLocation(element: HTMLElement): number[] {
|
||||
export function getRelativeLocation(
|
||||
rootOrientation: Orientation,
|
||||
location: number[],
|
||||
direction: Target
|
||||
direction: Position
|
||||
): number[] {
|
||||
const orientation = getLocationOrientation(rootOrientation, location);
|
||||
const directionOrientation = getDirectionOrientation(direction);
|
||||
@ -99,20 +99,20 @@ export function getRelativeLocation(
|
||||
if (orientation === directionOrientation) {
|
||||
let [rest, index] = tail(location);
|
||||
|
||||
if (direction === Target.Right || direction === Target.Bottom) {
|
||||
if (direction === Position.Right || direction === Position.Bottom) {
|
||||
index += 1;
|
||||
}
|
||||
|
||||
return [...rest, index];
|
||||
} else {
|
||||
const index =
|
||||
direction === Target.Right || direction === Target.Bottom ? 1 : 0;
|
||||
direction === Position.Right || direction === Position.Bottom ? 1 : 0;
|
||||
return [...location, index];
|
||||
}
|
||||
}
|
||||
|
||||
export function getDirectionOrientation(direction: Target): Orientation {
|
||||
return direction === Target.Top || direction === Target.Bottom
|
||||
export function getDirectionOrientation(direction: Position): Orientation {
|
||||
return direction === Position.Top || direction === Position.Bottom
|
||||
? Orientation.VERTICAL
|
||||
: Orientation.HORIZONTAL;
|
||||
}
|
||||
@ -193,9 +193,9 @@ export interface INodeDescriptor {
|
||||
visible?: boolean;
|
||||
}
|
||||
|
||||
export type IViewDeserializer = {
|
||||
export interface IViewDeserializer {
|
||||
fromJSON: (data: {}) => IGridView;
|
||||
};
|
||||
}
|
||||
|
||||
export class Gridview {
|
||||
private _root: BranchNode;
|
||||
|
@ -11,12 +11,12 @@ export enum DragType {
|
||||
EXTERNAL = "external_group_drag",
|
||||
}
|
||||
|
||||
export type DragItem = {
|
||||
export interface DragItem {
|
||||
itemId: string;
|
||||
groupId: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type ExternalDragItem = PanelOptions;
|
||||
export interface ExternalDragItem extends PanelOptions {}
|
||||
|
||||
export type DataObject = DragItem | ExternalDragItem;
|
||||
|
||||
|
@ -20,18 +20,18 @@
|
||||
transition-duration: 0.15s;
|
||||
transition-timing-function: ease-out;
|
||||
|
||||
&.left {
|
||||
&.left,
|
||||
&.right {
|
||||
width: 50%;
|
||||
}
|
||||
&.right {
|
||||
left: 50%;
|
||||
width: 50%;
|
||||
transform: translate(100%, 0%);
|
||||
}
|
||||
&.bottom {
|
||||
top: 50%;
|
||||
height: 50%;
|
||||
transform: translate(0%, 100%);
|
||||
}
|
||||
&.top {
|
||||
&.top,
|
||||
&.bottom {
|
||||
height: 50%;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Emitter, Event } from "../../events";
|
||||
import { DataTransferSingleton } from "./dataTransfer";
|
||||
|
||||
export enum Target {
|
||||
export enum Position {
|
||||
Top = "Top",
|
||||
Left = "Left",
|
||||
Bottom = "Bottom",
|
||||
@ -9,10 +9,10 @@ export enum Target {
|
||||
Center = "Center",
|
||||
}
|
||||
|
||||
export type DroptargetEvent = {
|
||||
target: Target;
|
||||
export interface DroptargetEvent {
|
||||
position: Position;
|
||||
event: DragEvent;
|
||||
};
|
||||
}
|
||||
|
||||
const HAS_PROCESSED_KEY = "__drop_target_processed__";
|
||||
|
||||
@ -39,7 +39,7 @@ const toggleClassName = (
|
||||
export class Droptarget {
|
||||
private target: HTMLElement;
|
||||
private overlay: HTMLElement;
|
||||
private state: Target;
|
||||
private state: Position | undefined;
|
||||
|
||||
private readonly _onDidChange = new Emitter<DroptargetEvent>();
|
||||
readonly onDidChange: Event<DroptargetEvent> = this._onDidChange.event;
|
||||
@ -106,7 +106,7 @@ export class Droptarget {
|
||||
this.removeDropTarget();
|
||||
|
||||
if (!hasProcessed(event)) {
|
||||
this._onDidChange.fire({ target: this.state, event });
|
||||
this._onDidChange.fire({ position: this.state, event });
|
||||
} else {
|
||||
console.debug("[dragtarget] already processed");
|
||||
}
|
||||
@ -140,15 +140,15 @@ export class Droptarget {
|
||||
toggleClassName(this.overlay, "bottom", isBottom);
|
||||
|
||||
if (isRight) {
|
||||
this.state = Target.Right;
|
||||
this.state = Position.Right;
|
||||
} else if (isLeft) {
|
||||
this.state = Target.Left;
|
||||
this.state = Position.Left;
|
||||
} else if (isTop) {
|
||||
this.state = Target.Top;
|
||||
this.state = Position.Top;
|
||||
} else if (isBottom) {
|
||||
this.state = Target.Bottom;
|
||||
this.state = Position.Bottom;
|
||||
} else {
|
||||
this.state = Target.Center;
|
||||
this.state = Position.Center;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,11 +1,6 @@
|
||||
import { DroptargetEvent } from "./droptarget/droptarget";
|
||||
|
||||
export enum TabChangedEventType {
|
||||
CLICK,
|
||||
}
|
||||
|
||||
export type TabChangedEvent = { type: TabChangedEventType };
|
||||
export type TabDropEvent = {
|
||||
export interface TabDropEvent {
|
||||
event: DroptargetEvent;
|
||||
index?: number;
|
||||
};
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { IDisposable, CompositeDisposable, Disposable } from "../lifecycle";
|
||||
import { ITabContainer, TabContainer } from "./tabs/tabContainer";
|
||||
import { IContentContainer, ContentContainer } from "./content";
|
||||
import { ITabContainer, TabContainer } from "./titlebar/tabContainer";
|
||||
import { IContentContainer, ContentContainer } from "./panel/content/content";
|
||||
import { IGridView } from "../gridview/gridview";
|
||||
import { Target, Droptarget, DroptargetEvent } from "./droptarget/droptarget";
|
||||
import { Position, Droptarget, DroptargetEvent } from "./droptarget/droptarget";
|
||||
import { Event, Emitter, addDisposableListener } from "../events";
|
||||
import { IGroupAccessor, Layout } from "../layout";
|
||||
import { toggleClass } from "../dom";
|
||||
@ -44,12 +44,12 @@ export interface IGroupItem {
|
||||
body: { element: HTMLElement };
|
||||
}
|
||||
|
||||
type GroupMoveEvent = {
|
||||
interface GroupMoveEvent {
|
||||
groupId: string;
|
||||
itemId: string;
|
||||
target: Target;
|
||||
target: Position;
|
||||
index?: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface GroupOptions {
|
||||
panels: IPanel[];
|
||||
@ -88,11 +88,11 @@ export interface IGroupview extends IDisposable, IGridView {
|
||||
moveToPrevious(options?: { panel?: IPanel; suppressRoll?: boolean }): void;
|
||||
}
|
||||
|
||||
export type GroupDropEvent = {
|
||||
export interface GroupDropEvent {
|
||||
event: DragEvent;
|
||||
target: Target;
|
||||
target: Position;
|
||||
index?: number;
|
||||
};
|
||||
}
|
||||
|
||||
export class Groupview extends CompositeDisposable implements IGroupview {
|
||||
private _element: HTMLElement;
|
||||
@ -129,6 +129,7 @@ export class Groupview extends CompositeDisposable implements IGroupview {
|
||||
|
||||
set tabHeight(height: number) {
|
||||
this.tabContainer.height = height;
|
||||
this.layout(this._width, this._height);
|
||||
}
|
||||
|
||||
get isActive() {
|
||||
@ -290,7 +291,7 @@ export class Groupview extends CompositeDisposable implements IGroupview {
|
||||
this.dropTarget.onDidChange((event) => {
|
||||
// if we've center dropped on ourself then ignore
|
||||
if (
|
||||
event.target === Target.Center &&
|
||||
event.position === Position.Center &&
|
||||
this.tabContainer.hasActiveDragEvent
|
||||
) {
|
||||
return;
|
||||
@ -531,18 +532,18 @@ export class Groupview extends CompositeDisposable implements IGroupview {
|
||||
|
||||
private handleDropEvent(event: DroptargetEvent, index?: number) {
|
||||
if (isPanelTransferEvent(event.event)) {
|
||||
this.handlePanelDropEvent(event.event, event.target, index);
|
||||
this.handlePanelDropEvent(event.event, event.position, index);
|
||||
return;
|
||||
}
|
||||
|
||||
this._onDrop.fire({ event: event.event, target: event.target, index });
|
||||
this._onDrop.fire({ event: event.event, target: event.position, index });
|
||||
|
||||
console.debug("[customDropEvent]");
|
||||
}
|
||||
|
||||
private handlePanelDropEvent(
|
||||
event: DragEvent,
|
||||
target: Target,
|
||||
target: Position,
|
||||
index?: number
|
||||
) {
|
||||
const dataObject = extractData(event);
|
||||
@ -550,10 +551,10 @@ export class Groupview extends CompositeDisposable implements IGroupview {
|
||||
if (isTabDragEvent(dataObject)) {
|
||||
const { groupId, itemId } = dataObject;
|
||||
const isSameGroup = this.id === groupId;
|
||||
if (isSameGroup) {
|
||||
const index = this.tabContainer.indexOf(itemId);
|
||||
if (index > -1 && index === this.panels.length - 1) {
|
||||
console.debug("[tabs] dropped in empty space");
|
||||
if (isSameGroup && !target) {
|
||||
const oldIndex = this.tabContainer.indexOf(itemId);
|
||||
if (oldIndex === index) {
|
||||
console.debug("[tabs] drop indicates no change in position");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -4,15 +4,15 @@ import { ClosePanelResult } from "./parts";
|
||||
import { IPanel } from "./types";
|
||||
import { CompositeDisposable, IDisposable } from "../../lifecycle";
|
||||
|
||||
export type PanelStateChangeEvent = {
|
||||
export interface PanelStateChangeEvent {
|
||||
isPanelVisible: boolean;
|
||||
isGroupActive: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export type PanelDimensionChangeEvent = {
|
||||
export interface PanelDimensionChangeEvent {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface PanelApi extends IDisposable {
|
||||
onDidPanelStateChange: Event<PanelStateChangeEvent>;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { CompositeDisposable, IDisposable } from "../lifecycle";
|
||||
import { Emitter, Event } from "../events";
|
||||
import { trackFocus } from "../dom";
|
||||
import { CompositeDisposable, IDisposable } from "../../../lifecycle";
|
||||
import { Emitter, Event } from "../../../events";
|
||||
import { trackFocus } from "../../../dom";
|
||||
|
||||
export interface IContentContainer extends IDisposable {
|
||||
onDidFocus: Event<void>;
|
@ -149,7 +149,11 @@ export class DefaultPanel extends CompositeDisposable implements IPanel {
|
||||
}
|
||||
|
||||
public layout(width: number, height: number) {
|
||||
this._onDidPanelDimensionsChange.fire({ width, height });
|
||||
// thw height of the panel excluded the height of the title/tab
|
||||
this._onDidPanelDimensionsChange.fire({
|
||||
width,
|
||||
height: height - (this.group?.tabHeight || 0),
|
||||
});
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
|
@ -14,13 +14,13 @@ interface Methods extends IDisposable {
|
||||
setVisible(isPanelVisible: boolean, isGroupVisible: boolean): void;
|
||||
}
|
||||
|
||||
export type WatermarkPartInitParameters = {
|
||||
export interface WatermarkPartInitParameters {
|
||||
accessor: IGroupAccessor;
|
||||
};
|
||||
}
|
||||
|
||||
export type PartInitParameters = {
|
||||
export interface PartInitParameters extends PanelInitParameters {
|
||||
api: PanelApi;
|
||||
} & PanelInitParameters;
|
||||
}
|
||||
|
||||
export interface PanelHeaderPart extends Methods {
|
||||
id: string;
|
||||
|
@ -1,23 +1,31 @@
|
||||
import { addDisposableListener, Emitter, Event } from "../../events";
|
||||
import { Droptarget, DroptargetEvent } from "../droptarget/droptarget";
|
||||
import { CompositeDisposable } from "../../lifecycle";
|
||||
import { TabChangedEvent, TabDropEvent, TabChangedEventType } from "../events";
|
||||
import { IGroupview } from "../groupview";
|
||||
import { addDisposableListener, Emitter, Event } from "../../../events";
|
||||
import { Droptarget, DroptargetEvent } from "../../droptarget/droptarget";
|
||||
import { CompositeDisposable } from "../../../lifecycle";
|
||||
import { IGroupview } from "../../groupview";
|
||||
import {
|
||||
DataTransferSingleton,
|
||||
DATA_KEY,
|
||||
DragType,
|
||||
extractData,
|
||||
} from "../droptarget/dataTransfer";
|
||||
import { IGroupAccessor } from "../../layout";
|
||||
import { toggleClass } from "../../dom";
|
||||
} from "../../droptarget/dataTransfer";
|
||||
// import { IGroupAccessor } from "../../layout";
|
||||
import { toggleClass } from "../../../dom";
|
||||
import { IGroupAccessor } from "../../../layout";
|
||||
|
||||
export enum TabInteractionKind {
|
||||
CLICK = "CLICK",
|
||||
CONTEXT_MENU = "CONTEXT_MEU",
|
||||
}
|
||||
|
||||
export interface TabInteractionEvent {
|
||||
kind: TabInteractionKind;
|
||||
}
|
||||
|
||||
export interface ITab {
|
||||
id: string;
|
||||
element: HTMLElement;
|
||||
hasActiveDragEvent: boolean;
|
||||
setContent: (element: HTMLElement) => void;
|
||||
onChanged: Event<TabChangedEvent>;
|
||||
onChanged: Event<TabInteractionEvent>;
|
||||
onDropped: Event<DroptargetEvent>;
|
||||
setActive(isActive: boolean): void;
|
||||
startDragEvent(): void;
|
||||
@ -32,8 +40,8 @@ export class Tab extends CompositeDisposable implements ITab {
|
||||
private droptarget: Droptarget;
|
||||
private content: HTMLElement;
|
||||
|
||||
private readonly _onChanged = new Emitter<TabChangedEvent>();
|
||||
readonly onChanged: Event<TabChangedEvent> = this._onChanged.event;
|
||||
private readonly _onChanged = new Emitter<TabInteractionEvent>();
|
||||
readonly onChanged: Event<TabInteractionEvent> = this._onChanged.event;
|
||||
|
||||
private readonly _onDropped = new Emitter<DroptargetEvent>();
|
||||
readonly onDropped: Event<DroptargetEvent> = this._onDropped.event;
|
||||
@ -72,7 +80,10 @@ export class Tab extends CompositeDisposable implements ITab {
|
||||
if (ev.defaultPrevented) {
|
||||
return;
|
||||
}
|
||||
this._onChanged.fire({ type: TabChangedEventType.CLICK });
|
||||
this._onChanged.fire({ kind: TabInteractionKind.CLICK });
|
||||
}),
|
||||
addDisposableListener(this._element, "contextmenu", (ev) => {
|
||||
this._onChanged.fire({ kind: TabInteractionKind.CONTEXT_MENU });
|
||||
}),
|
||||
addDisposableListener(this._element, "dragstart", (event) => {
|
||||
this.dragInPlayDetails = { isDragging: true, id: this.accessor.id };
|
@ -5,18 +5,18 @@ import { PanelHeaderPart, PanelContentPart, ClosePanelResult } from "./parts";
|
||||
|
||||
// objects
|
||||
|
||||
export type PanelUpdateEvent = {
|
||||
export interface PanelUpdateEvent {
|
||||
params: { [key: string]: any };
|
||||
};
|
||||
}
|
||||
|
||||
// init parameters
|
||||
|
||||
export type PanelInitParameters = {
|
||||
export interface PanelInitParameters {
|
||||
title: string;
|
||||
suppressClosable?: boolean;
|
||||
params: { [index: string]: any };
|
||||
state?: { [index: string]: any };
|
||||
};
|
||||
}
|
||||
|
||||
// constructors
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { IDisposable, CompositeDisposable } from "../../lifecycle";
|
||||
import { addDisposableListener, Emitter, Event } from "../../events";
|
||||
import { ITab, Tab } from "./tab";
|
||||
import { ITab, Tab, TabInteractionKind } from "../panel/tab/tab";
|
||||
import { removeClasses, addClasses, toggleClass } from "../../dom";
|
||||
import { hasProcessed } from "../droptarget/droptarget";
|
||||
import { hasProcessed, Position } from "../droptarget/droptarget";
|
||||
import { TabDropEvent } from "../events";
|
||||
|
||||
import { IGroupview } from "../groupview";
|
||||
@ -144,7 +144,8 @@ export class TabContainer extends CompositeDisposable implements ITabContainer {
|
||||
}
|
||||
|
||||
this._onDropped.fire({
|
||||
event: { event, target: undefined },
|
||||
event: { event, position: Position.Center },
|
||||
index: this.tabs.length - 1,
|
||||
});
|
||||
})
|
||||
);
|
||||
@ -195,7 +196,13 @@ export class TabContainer extends CompositeDisposable implements ITabContainer {
|
||||
// TODO - dispose of resources
|
||||
const disposables = CompositeDisposable.from(
|
||||
tab.onChanged((event) => {
|
||||
this.group.openPanel(panel);
|
||||
switch (event.kind) {
|
||||
case TabInteractionKind.CLICK:
|
||||
this.group.openPanel(panel);
|
||||
break;
|
||||
case TabInteractionKind.CONTEXT_MENU:
|
||||
// TODO finish
|
||||
}
|
||||
}),
|
||||
tab.onDropped((event) => {
|
||||
this._onDropped.fire({ event, index: this.indexOf(tab) });
|
@ -2,8 +2,8 @@ export * from "./splitview/splitview";
|
||||
export * from "./splitview/paneview";
|
||||
export * from "./gridview/gridview";
|
||||
export * from "./groupview/groupview";
|
||||
export * from "./groupview/content";
|
||||
export * from "./groupview/tabs/tab";
|
||||
export * from "./groupview/panel/content/content";
|
||||
export * from "./groupview/panel/tab/tab";
|
||||
export * from "./events";
|
||||
export * from "./lifecycle";
|
||||
export * from "./groupview/panel/panel";
|
||||
@ -12,6 +12,7 @@ export * from "./react/react";
|
||||
export * from "./groupview/panel/types";
|
||||
export * from "./groupview/panel/parts";
|
||||
export * from "./react/layout";
|
||||
export * from "./react/splitview";
|
||||
export * from "./react/reactContentPart";
|
||||
export * from "./react/reactHeaderPart";
|
||||
|
||||
|
@ -1,67 +1,17 @@
|
||||
.groupview {
|
||||
&.active-group {
|
||||
> .title-container > .tab-container > .tab {
|
||||
&.active-tab {
|
||||
.default-tab {
|
||||
background-color: var(--tab-background-visible);
|
||||
color: var(--active-group-visible-panel-color);
|
||||
}
|
||||
.tab-action {
|
||||
background-color: var(--active-group-visible-panel-color);
|
||||
}
|
||||
}
|
||||
&.inactive-tab {
|
||||
.default-tab {
|
||||
background-color: var(--tab-background-hidden);
|
||||
color: var(--active-group-hidden-panel-color);
|
||||
}
|
||||
.tab-action {
|
||||
background-color: var(--active-group-hidden-panel-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&.inactive-group {
|
||||
> .title-container > .tab-container > .tab {
|
||||
&.active-tab {
|
||||
.default-tab {
|
||||
background-color: var(--tab-background-visible);
|
||||
color: var(--inactive-group-visible-panel-color);
|
||||
}
|
||||
.tab-action {
|
||||
background-color: var(--inactive-group-visible-panel-color);
|
||||
}
|
||||
}
|
||||
&.inactive-tab {
|
||||
.default-tab {
|
||||
background-color: var(--tab-background-hidden);
|
||||
color: var(--inactive-group-hidden-panel-color);
|
||||
}
|
||||
.tab-action {
|
||||
background-color: var(--inactive-group-hidden-panel-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tab {
|
||||
&.dragging {
|
||||
color: var(--active-group-visible-panel-color);
|
||||
.tab-action {
|
||||
background-color: var(--active-group-visible-panel-color);
|
||||
}
|
||||
}
|
||||
|
||||
&.active-tab > .default-tab {
|
||||
background-color: var(--tab-background-visible);
|
||||
.tab-action {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
&.inactive-tab > .default-tab {
|
||||
background-color: var(--tab-background-hidden);
|
||||
.tab-action:not(.dirty) {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
@ -9,3 +9,55 @@
|
||||
position: absolute;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.groupview {
|
||||
&.active-group {
|
||||
> .title-container > .tab-container > .tab {
|
||||
&.active-tab {
|
||||
background-color: var(--active-tab-background-visible);
|
||||
color: var(--active-group-visible-panel-color);
|
||||
|
||||
.tab-action {
|
||||
background-color: var(--active-group-visible-panel-color);
|
||||
}
|
||||
}
|
||||
&.inactive-tab {
|
||||
background-color: var(--active-tab-background-hidden);
|
||||
color: var(--active-group-hidden-panel-color);
|
||||
|
||||
.tab-action {
|
||||
background-color: var(--active-group-hidden-panel-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&.inactive-group {
|
||||
> .title-container > .tab-container > .tab {
|
||||
&.active-tab {
|
||||
background-color: var(--inactive-tab-background-visible);
|
||||
color: var(--inactive-group-visible-panel-color);
|
||||
|
||||
.tab-action {
|
||||
background-color: var(--inactive-group-visible-panel-color);
|
||||
}
|
||||
}
|
||||
&.inactive-tab {
|
||||
background-color: var(--inactive-tab-background-hidden);
|
||||
color: var(--inactive-group-hidden-panel-color);
|
||||
|
||||
.tab-action {
|
||||
background-color: var(--inactive-group-hidden-panel-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// when a tab is dragged we loss the above stylings because they are conditional on parent elements
|
||||
// there we also set some stylings for the dragging event
|
||||
.tab {
|
||||
&.dragging {
|
||||
background-color: var(--active-tab-background-visible);
|
||||
color: var(--active-group-visible-panel-color);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Gridview, getRelativeLocation } from "../gridview/gridview";
|
||||
import { Target } from "../groupview/droptarget/droptarget";
|
||||
import { Position } from "../groupview/droptarget/droptarget";
|
||||
import { getGridLocation } from "../gridview/gridview";
|
||||
import { tail, sequenceEquals } from "../array";
|
||||
import {
|
||||
@ -45,10 +45,10 @@ import {
|
||||
const nextGroupId = sequentialNumberGenerator();
|
||||
const nextLayoutId = sequentialNumberGenerator();
|
||||
|
||||
export type PanelReference = {
|
||||
export interface PanelReference {
|
||||
update: (event: { params: { [key: string]: any } }) => void;
|
||||
remove: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Api {
|
||||
layout(width: number, height: number): void;
|
||||
@ -56,6 +56,7 @@ export interface Api {
|
||||
setAutoResizeToFit(enabled: boolean): void;
|
||||
resizeToFit(): void;
|
||||
setTabHeight(height: number): void;
|
||||
getTabHeight(): number;
|
||||
size: number;
|
||||
totalPanels: number;
|
||||
// lifecycle
|
||||
@ -90,7 +91,7 @@ export interface IGroupAccessor {
|
||||
referenceGroup: IGroupview,
|
||||
groupId: string,
|
||||
itemId: string,
|
||||
target: Target,
|
||||
target: Position,
|
||||
index?: number
|
||||
): void;
|
||||
doSetGroupActive: (group: IGroupview) => void;
|
||||
@ -399,11 +400,16 @@ export class Layout extends CompositeDisposable implements ILayout {
|
||||
}
|
||||
|
||||
public setTabHeight(height: number) {
|
||||
this.options.tabHeight = height;
|
||||
this.groups.forEach((value) => {
|
||||
value.value.tabHeight = height;
|
||||
});
|
||||
}
|
||||
|
||||
public getTabHeight() {
|
||||
return this.options.tabHeight;
|
||||
}
|
||||
|
||||
public setAutoResizeToFit(enabled: boolean) {
|
||||
if (this.resizeTimer) {
|
||||
clearInterval(this.resizeTimer);
|
||||
@ -435,7 +441,7 @@ export class Layout extends CompositeDisposable implements ILayout {
|
||||
const referenceGroup = this.findGroup(referencePanel);
|
||||
|
||||
const target = this.toTarget(options.position.direction);
|
||||
if (target === Target.Center) {
|
||||
if (target === Position.Center) {
|
||||
referenceGroup.openPanel(panel);
|
||||
} else {
|
||||
const location = getGridLocation(referenceGroup.element);
|
||||
@ -597,13 +603,13 @@ export class Layout extends CompositeDisposable implements ILayout {
|
||||
referenceGroup: IGroupview,
|
||||
groupId: string,
|
||||
itemId: string,
|
||||
target: Target,
|
||||
target: Position,
|
||||
index?: number
|
||||
) {
|
||||
const sourceGroup = groupId ? this.groups.get(groupId).value : undefined;
|
||||
|
||||
switch (target) {
|
||||
case Target.Center:
|
||||
case Position.Center:
|
||||
case undefined:
|
||||
const groupItem =
|
||||
sourceGroup?.removePanel(itemId) || this.panels.get(itemId).value;
|
||||
@ -699,7 +705,7 @@ export class Layout extends CompositeDisposable implements ILayout {
|
||||
}
|
||||
this.moveGroup(
|
||||
group,
|
||||
panel?.group.id,
|
||||
panel?.group?.id,
|
||||
panel.id,
|
||||
event.target,
|
||||
event.index
|
||||
@ -774,16 +780,16 @@ export class Layout extends CompositeDisposable implements ILayout {
|
||||
private toTarget(direction: "left" | "right" | "above" | "below" | "within") {
|
||||
switch (direction) {
|
||||
case "left":
|
||||
return Target.Left;
|
||||
return Position.Left;
|
||||
case "right":
|
||||
return Target.Right;
|
||||
return Position.Right;
|
||||
case "above":
|
||||
return Target.Top;
|
||||
return Position.Top;
|
||||
case "below":
|
||||
return Target.Bottom;
|
||||
return Position.Bottom;
|
||||
case "within":
|
||||
default:
|
||||
return Target.Center;
|
||||
return Position.Center;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { IGroupview } from "../groupview/groupview";
|
||||
import { PanelApi } from "../groupview/panel/api";
|
||||
import {
|
||||
PanelContentPart,
|
||||
PanelContentPartConstructor,
|
||||
@ -6,11 +7,20 @@ import {
|
||||
PanelHeaderPartConstructor,
|
||||
WatermarkConstructor,
|
||||
} from "../groupview/panel/parts";
|
||||
import { IPanel } from "../groupview/panel/types";
|
||||
import { Api } from "./layout";
|
||||
|
||||
export type FrameworkPanelWrapper = {
|
||||
export interface FrameworkPanelWrapper {
|
||||
createContentWrapper: (id: string, component: any) => PanelContentPart;
|
||||
createTabWrapper: (id: string, component: any) => PanelHeaderPart;
|
||||
};
|
||||
}
|
||||
|
||||
export interface TabContextMenuEvent {
|
||||
event: MouseEvent;
|
||||
api: Api;
|
||||
panelApi: PanelApi;
|
||||
panel: IPanel;
|
||||
}
|
||||
|
||||
export interface LayoutOptions {
|
||||
tabComponents?: {
|
||||
@ -31,6 +41,7 @@ export interface LayoutOptions {
|
||||
tabHeight?: number;
|
||||
debug?: boolean;
|
||||
enableExternalDragEvents?: boolean;
|
||||
onTabContextMenu?: (event: TabContextMenuEvent) => void;
|
||||
}
|
||||
|
||||
export interface PanelOptions {
|
||||
|
@ -6,9 +6,9 @@ import { ReactPanelHeaderPart } from "./reactHeaderPart";
|
||||
import { IPanelProps } from "./react";
|
||||
import { ReactPanelDeserialzier } from "./deserializer";
|
||||
|
||||
export type OnReadyEvent = {
|
||||
export interface OnReadyEvent {
|
||||
api: Api;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ReactLayout {
|
||||
addPortal: (portal: React.ReactPortal) => IDisposable;
|
||||
|
57
packages/splitview/src/react/reactView.ts
Normal file
57
packages/splitview/src/react/reactView.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import { Emitter } from "../events";
|
||||
import { IView } from "../splitview/splitview";
|
||||
import { ReactLayout } from "./layout";
|
||||
import { ReactPart } from "./react";
|
||||
|
||||
export class ReactView implements IView {
|
||||
private _element: HTMLElement;
|
||||
private part: ReactPart;
|
||||
|
||||
private _onDidChange: Emitter<number | undefined> = new Emitter<
|
||||
number | undefined
|
||||
>();
|
||||
public onDidChange = this._onDidChange.event;
|
||||
|
||||
get element() {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
get minimumSize() {
|
||||
return 100;
|
||||
}
|
||||
// get snapSize() {
|
||||
// return 100;
|
||||
// }
|
||||
|
||||
get maximumSize() {
|
||||
return Number.MAX_SAFE_INTEGER;
|
||||
}
|
||||
|
||||
constructor(
|
||||
public readonly id: string,
|
||||
private readonly component: React.FunctionComponent<{}>,
|
||||
private readonly parent: ReactLayout
|
||||
) {
|
||||
if (!this.component) {
|
||||
throw new Error("React.FunctionalComponent cannot be undefined");
|
||||
}
|
||||
|
||||
this._element = document.createElement("div");
|
||||
}
|
||||
|
||||
layout(size: number, orthogonalSize: number) {}
|
||||
|
||||
init(parameters: { params: any }): void {
|
||||
this.part = new ReactPart(
|
||||
this.element,
|
||||
{} as any,
|
||||
this.parent.addPortal,
|
||||
this.component,
|
||||
parameters.params
|
||||
);
|
||||
}
|
||||
|
||||
update(params: {}) {
|
||||
this.part.update(params);
|
||||
}
|
||||
}
|
95
packages/splitview/src/react/splitview.tsx
Normal file
95
packages/splitview/src/react/splitview.tsx
Normal file
@ -0,0 +1,95 @@
|
||||
import * as React from "react";
|
||||
import { Orientation, SplitView } from "../splitview/splitview";
|
||||
import { ReactView } from "./reactView";
|
||||
|
||||
export interface SplitviewFacade {
|
||||
addFromComponent(options: { id: string; component: string }): void;
|
||||
layout(size: number, orthogonalSize: number): void;
|
||||
}
|
||||
|
||||
export interface SplitviewReadyEvent {
|
||||
api: SplitviewFacade;
|
||||
}
|
||||
|
||||
export interface ISplitviewComponentProps {
|
||||
orientation: Orientation;
|
||||
onReady?: (event: SplitviewReadyEvent) => void;
|
||||
components: { [index: string]: React.FunctionComponent<{}> };
|
||||
}
|
||||
|
||||
export const SplitViewComponent = (props: ISplitviewComponentProps) => {
|
||||
const domReference = React.useRef<HTMLDivElement>();
|
||||
const splitview = React.useRef<SplitView>();
|
||||
const [portals, setPortals] = React.useState<React.ReactPortal[]>([]);
|
||||
|
||||
const addPortal = React.useCallback((p: React.ReactPortal) => {
|
||||
setPortals((portals) => [...portals, p]);
|
||||
return {
|
||||
dispose: () => {
|
||||
setPortals((portals) => portals.filter((portal) => portal !== p));
|
||||
},
|
||||
};
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
splitview.current = new SplitView(domReference.current, {
|
||||
orientation: props.orientation,
|
||||
});
|
||||
|
||||
const createViewWrapper = (
|
||||
id: string,
|
||||
component: React.FunctionComponent<{}>
|
||||
) => {
|
||||
return new ReactView(id, component, { addPortal });
|
||||
};
|
||||
|
||||
const facade: SplitviewFacade = {
|
||||
addFromComponent: (options) => {
|
||||
const component = props.components[options.component];
|
||||
const view = createViewWrapper(options.id, component);
|
||||
|
||||
splitview.current.addView(view, { type: "distribute" });
|
||||
view.init({ params: {} });
|
||||
return {
|
||||
dispose: () => {
|
||||
//
|
||||
},
|
||||
};
|
||||
},
|
||||
layout: (width, height) => {
|
||||
const [size, orthogonalSize] =
|
||||
props.orientation === Orientation.HORIZONTAL
|
||||
? [width, height]
|
||||
: [height, width];
|
||||
splitview.current.layout(size, orthogonalSize);
|
||||
},
|
||||
};
|
||||
|
||||
const { width, height } = domReference.current.getBoundingClientRect();
|
||||
const [size, orthogonalSize] =
|
||||
props.orientation === Orientation.HORIZONTAL
|
||||
? [width, height]
|
||||
: [height, width];
|
||||
splitview.current.layout(size, orthogonalSize);
|
||||
|
||||
if (props.onReady) {
|
||||
props.onReady({ api: facade });
|
||||
}
|
||||
|
||||
return () => {
|
||||
splitview.current.dispose();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
}}
|
||||
ref={domReference}
|
||||
>
|
||||
{portals}
|
||||
</div>
|
||||
);
|
||||
};
|
@ -4,11 +4,13 @@
|
||||
--title-bar-background-color: #252526;
|
||||
--title-bar-scroll-bar-color: #888;
|
||||
//
|
||||
--tab-background-visible: #1e1e1e;
|
||||
--tab-background-hidden: #2d2d2d;
|
||||
--active-tab-background-visible: #1e1e1e;
|
||||
--active-tab-background-hidden: #2d2d2d;
|
||||
--inactive-tab-background-visible: #1e1e1e;
|
||||
--inactive-tab-background-hidden: #2d2d2d;
|
||||
--tab-divider-color: #1e1e1e;
|
||||
//
|
||||
--drag-over-background-color: rgba(255, 0, 0, 0.5);
|
||||
--drag-over-background-color: rgba(83, 89, 93, 0.5);
|
||||
//
|
||||
--active-group-visible-panel-color: white;
|
||||
--active-group-hidden-panel-color: #969696;
|
||||
@ -20,3 +22,20 @@
|
||||
//
|
||||
--splitview-divider-color: rgb(68, 68, 68);
|
||||
}
|
||||
|
||||
.visual-studio-theme {
|
||||
--active-tab-background-visible: dodgerblue;
|
||||
|
||||
.groupview {
|
||||
&.active-group {
|
||||
> .title-container {
|
||||
border-bottom: 2px solid var(--active-tab-background-visible);
|
||||
}
|
||||
}
|
||||
&.inactive-group {
|
||||
> .title-container {
|
||||
border-bottom: 2px solid var(--inactive-tab-background-visible);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
11
packages/splitview/typedoc.json
Normal file
11
packages/splitview/typedoc.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"out": "typedocs",
|
||||
"mode": "file",
|
||||
"inputFiles": ["./src"],
|
||||
"exclude": ["**/_test/**/*.*", "**/index.ts"],
|
||||
"ignoreCompilerErrors": true,
|
||||
"disableOutputCheck": true,
|
||||
"excludeExternals": true,
|
||||
"excludePrivate": true,
|
||||
"excludeNotExported": true
|
||||
}
|
Loading…
Reference in New Issue
Block a user