diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3e7458c4f0..cb0cdc73c2 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -11,11 +11,46 @@ permissions:
name: PR Testing
jobs:
- ci:
+ build:
runs-on: ubuntu-latest
steps:
- name: Checkout Sources
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
+
+ - name: Install NodeJS
+ uses: actions/setup-node@v6
+ with:
+ node-version: 22
+ registry-url: "https://registry.npmjs.org"
+ scope: "@hpcc-js"
+
+ - name: Install Dependencies
+ run: |
+ npm ci
+
+ - name: Build
+ run: |
+ npm run build
+
+ - name: Upload build artifacts
+ uses: actions/upload-artifact@v7
+ with:
+ name: build-output
+ path: |
+ packages/*/dist/
+ packages/*/types/
+
+ - name: Upload error logs
+ if: ${{ failure() || cancelled() }}
+ uses: actions/upload-artifact@v7
+ with:
+ name: all-logs
+ path: ./**/*.log
+ lint:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout Sources
+ uses: actions/checkout@v6
- name: Install NodeJS
uses: actions/setup-node@v6
@@ -32,9 +67,29 @@ jobs:
run: |
npm run lint
- - name: Build
+ test:
+ needs: build
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout Sources
+ uses: actions/checkout@v6
+
+ - name: Install NodeJS
+ uses: actions/setup-node@v6
+ with:
+ node-version: 22
+ registry-url: "https://registry.npmjs.org"
+ scope: "@hpcc-js"
+
+ - name: Install Dependencies
run: |
- npm run build
+ npm ci
+
+ - name: Download build artifacts
+ uses: actions/download-artifact@v8
+ with:
+ name: build-output
+ path: packages
- name: Install Test Dependencies
run: |
@@ -61,7 +116,7 @@ jobs:
- name: Upload error logs
if: ${{ failure() || cancelled() }}
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v7
with:
name: all-logs
path: ./**/*.log
diff --git a/package-lock.json b/package-lock.json
index a3aec37cc5..131ecebd56 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19112,7 +19112,6 @@
"os": [
"darwin"
],
- "peer": true,
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
diff --git a/packages/eclwatch/tests/eclwatch.browser.spec.ts b/packages/eclwatch/tests/eclwatch.browser.spec.ts
index d63d707c8b..134d11b23f 100644
--- a/packages/eclwatch/tests/eclwatch.browser.spec.ts
+++ b/packages/eclwatch/tests/eclwatch.browser.spec.ts
@@ -57,6 +57,16 @@ describe("@hpcc-js/eclwatch", async () => {
;
break;
+ case eclwatchMod.WUGraphLegend:
+ const graph = new eclwatchMod.WUGraph()
+ .baseUrl(ESP_URL)
+ .wuid(WUID)
+ .graphID("graph1")
+ ;
+ new eclwatchMod.WUGraphLegend(graph)
+ ;
+ break;
+
default:
it("Has render test", () => {
expect(false).to.be.true;
diff --git a/packages/marshaller/src/dashy.ts b/packages/marshaller/src/dashy.ts
index 8582ca5da3..07853f02a3 100644
--- a/packages/marshaller/src/dashy.ts
+++ b/packages/marshaller/src/dashy.ts
@@ -434,7 +434,9 @@ export class Dashy extends SplitPanel {
this.loadGraph();
break;
case this._lhsDebugSheet:
- this._lhsDebugSheet.childActivation(this._lhsDebugSheet.active());
+ const w = this._lhsDebugSheet.active();
+ const wa = this._lhsDebugSheet.getWidgetAdapter(w);
+ this._lhsDebugSheet.childActivation(w, wa);
break;
}
})
diff --git a/packages/phosphor/index.html b/packages/phosphor/index.html
index 97d2c6f883..d021fac10c 100644
--- a/packages/phosphor/index.html
+++ b/packages/phosphor/index.html
@@ -2,36 +2,65 @@
- Home
+
+ @hpcc-js/phosphor — Panel Demos
-
-
-
- ESM Quick Test
-
-
+
- const area = new Area()
- .columns(twoD.columns)
- .data(twoD.data);
- const line = new Line()
- .columns(twoD.columns)
- .data(twoD.data);
- const bubble = new Bubble()
- .columns(twoD.columns)
- .data(twoD.data)
- .paletteID("Dark2");
+
+ @hpcc-js/phosphor
+ Docking, splitting & tabbing panels with size constraints
+
+
+
+
DockPanel — defaultSize / relative sizes
+
Left sidebar defaults to ~200px via defaultSize; remaining two panels split equally via setSizes().
+
+
+
+
+
+
+
DockPanel — min/max constraints
+
Left panel constrained to min 150px. Try resizing — it won't shrink below 150px.
+
+
+
+
+
+
+
SplitPanel — horizontal with defaultSize
+
Three columns: left clamped at 180px, center flexible, right default and min at 250px.
+
+
+
+
+
+
+
SplitPanel — vertical with defaultSize
+
Top panel gets 100px default size, with min 80px and max 120px; bottom fills remaining space.
+
+
+
+
diff --git a/packages/phosphor/src/BasePanel.ts b/packages/phosphor/src/BasePanel.ts
new file mode 100644
index 0000000000..a2a3377909
--- /dev/null
+++ b/packages/phosphor/src/BasePanel.ts
@@ -0,0 +1,87 @@
+import { HTMLWidget, Widget, Utility } from "@hpcc-js/common";
+import { Widget as PWidget, IMessageHandler, IMessageHook, Message, MessageLoop } from "./phosphor-shim.ts";
+import { Msg, WidgetAdapter, WidgetAdapterArray } from "./WidgetAdapter.ts";
+
+export namespace BasePanel {
+ export interface IAddWidgetOptions {
+ /** Minimum size in pixels */
+ minSize?: number;
+ /** Preferred/default size in pixels — used as initial size hint */
+ defaultSize?: number;
+ /** Inner padding in pixels (default 8) */
+ padding?: number;
+
+ /** Reference widget for split/tab positioning */
+ refWidget?: Widget;
+ }
+}
+
+export abstract class BasePanel extends HTMLWidget implements IMessageHandler, IMessageHook {
+
+ protected abstract _content: WidgetAdapterArray;
+
+ constructor() {
+ super();
+ this._tag = "div";
+ MessageLoop.installMessageHook(this, this);
+ }
+
+ getWidget(wa: PWidget): Widget | undefined {
+ if (wa instanceof WidgetAdapter) {
+ return wa.widget;
+ }
+ }
+
+ getWidgetAdapter(widget: Widget): WidgetAdapter | null {
+ let retVal = null;
+ this._content.some(wa => {
+ if (wa.widget === widget) {
+ retVal = wa;
+ return true;
+ }
+ return false;
+ });
+ return retVal;
+ }
+
+ protected _prevActive: Widget;
+ active(): Widget {
+ return this._prevActive;
+ }
+
+ // Phosphor Messaging ---
+ protected _lazyLayoutChanged = Utility.debounce(async () => {
+ this.layoutChanged();
+ }, 1000);
+
+ processMessage(msg: Message): void {
+ switch (msg.type) {
+ case Msg.WAActivateRequest.type:
+ const wa = (msg as Msg.WAActivateRequest).wa;
+ const widget = wa.widget;
+ if (this._prevActive !== widget) {
+ this._prevActive = widget;
+ this.childActivation(widget, wa);
+ }
+ break;
+ case Msg.WALayoutChanged.type:
+ this._lazyLayoutChanged();
+ break;
+ }
+ }
+
+ messageHook(handler: IMessageHandler, msg: Message): boolean {
+ if (handler === this) {
+ this.processMessage(msg);
+ }
+ return true;
+ }
+
+ // Events ---
+ childActivation(w: Widget, wa: WidgetAdapter) {
+ }
+
+ layoutChanged() {
+ }
+
+}
diff --git a/packages/phosphor/src/DockPanel.ts b/packages/phosphor/src/DockPanel.ts
index ecd6f72084..c26bb17857 100644
--- a/packages/phosphor/src/DockPanel.ts
+++ b/packages/phosphor/src/DockPanel.ts
@@ -1,43 +1,144 @@
-import { HTMLWidget, Widget, Utility, select as d3Select } from "@hpcc-js/common";
-import { DockPanel as PhosphorDockPanel, IMessageHandler, IMessageHook, Message, MessageLoop, Widget as PWidget } from "./phosphor-shim.ts";
+import { Widget, select as d3Select } from "@hpcc-js/common";
+import { BasePanel } from "./BasePanel.ts";
+import { DockLayout, DockPanel as PhosphorDockPanel, MessageLoop, Widget as PWidget } from "./phosphor-shim.ts";
+import { IClosable, WidgetAdapter } from "./WidgetAdapter.ts";
import { PDockPanel } from "./PDockPanel.ts";
-import { IClosable, Msg, WidgetAdapter } from "./WidgetAdapter.ts";
import "../src/DockPanel.css";
-export class DockPanel extends HTMLWidget implements IMessageHandler, IMessageHook {
+export namespace DockPanel {
+ export interface IAddWidgetOptions extends BasePanel.IAddWidgetOptions {
+ /** Tab title */
+ title?: string;
+ /** Insertion mode relative to refWidget */
+ location?: PhosphorDockPanel.InsertMode;
+ /** Whether the tab can be closed */
+ closable?: boolean | IClosable;
+ }
+}
+
+export class DockPanel extends BasePanel {
private _dock = new PDockPanel({ mode: "multiple-document" });
+ protected _content = this._dock.content();
constructor() {
super();
- this._tag = "div";
this._dock.id = "p" + this.id();
- MessageLoop.installMessageHook(this, this);
}
- protected getWidgetAdapter(widget: Widget): WidgetAdapter | null {
- let retVal = null;
- this._dock.content().some(wa => {
- if (wa.widget === widget) {
- retVal = wa;
- return true;
- }
- return false;
- });
- return retVal;
- }
+ private _pendingDefaults: Map = new Map();
+ addWidget(widget: Widget, options: DockPanel.IAddWidgetOptions): this;
+ /** @deprecated Use options object form instead */
+ addWidget(widget: Widget, title: string, location?: PhosphorDockPanel.InsertMode, refWidget?: Widget, closable?: boolean | IClosable, padding?: number): this;
+ addWidget(widget: Widget, titleOrOptions: string | DockPanel.IAddWidgetOptions, location: PhosphorDockPanel.InsertMode = "split-right", refWidget?: Widget, closable?: boolean | IClosable, padding: number = 8) {
+ const opts: DockPanel.IAddWidgetOptions = typeof titleOrOptions === "string"
+ ? { title: titleOrOptions, location, refWidget, closable, padding }
+ : titleOrOptions;
- addWidget(widget: Widget, title: string, location: PhosphorDockPanel.InsertMode = "split-right", refWidget?: Widget, closable?: boolean | IClosable, padding: number = 8) {
- const addMode: PhosphorDockPanel.IAddOptions = { mode: location, ref: this.getWidgetAdapter(refWidget) };
- const wa = new WidgetAdapter(this, widget, {}, closable);
+ const {
+ title = "",
+ location: loc = "split-right",
+ refWidget: ref,
+ closable: canClose,
+ padding: pad = 8,
+ minSize,
+ defaultSize
+ } = opts;
+
+ const addMode: PhosphorDockPanel.IAddOptions = { mode: loc, ref: this.getWidgetAdapter(ref) };
+ const wa = new WidgetAdapter(this, widget, {}, canClose);
wa.title.label = title;
- wa.padding = padding;
+ wa.padding = pad;
+
+ if (minSize != null) {
+ const style = wa.node.style;
+ if (loc === "split-left" || loc === "split-right") {
+ style.minWidth = `${minSize}px`;
+ } else {
+ style.minHeight = `${minSize}px`;
+ }
+ }
+
this._dock.addWidget(wa, addMode);
this._dock.appendContent(wa);
this._dock.tabsMovable = true;
+
+ if (defaultSize != null) {
+ this._pendingDefaults.set(wa, { defaultSize });
+ }
+
return this;
}
+ private _applyPendingDefaults() {
+ if (this._pendingDefaults.size === 0) return;
+
+ const config = this._dock.saveLayout() as DockLayout.ILayoutConfig;
+ if (!config.main) {
+ this._pendingDefaults.clear();
+ return;
+ }
+
+ // Build a lookup: widgetId → { defaultSize }
+ const lookup = new Map();
+ for (const [wa, defaults] of this._pendingDefaults) {
+ lookup.set(wa.widget.id(), defaults);
+ }
+ this._pendingDefaults.clear();
+
+ const containerWidth = this.width();
+ const containerHeight = this.height();
+
+ const applySizes = (area: DockLayout.AreaConfig, availWidth: number, availHeight: number): void => {
+ if (!area || area.type !== "split-area") return;
+
+ const isHorizontal = area.orientation === "horizontal";
+ const totalSpace = isHorizontal ? availWidth : availHeight;
+ const n = area.children.length;
+
+ // Collect requested pixel sizes per child
+ let usedSpace = 0;
+ let flexCount = 0;
+ const pixelSizes: (number | null)[] = area.children.map((child, i) => {
+ if (child.type === "tab-area") {
+ for (const w of (child as any).widgets) {
+ const defaults = lookup.get(w?.__id);
+ if (defaults) {
+ const size = defaults.defaultSize;
+ if (size != null) {
+ usedSpace += size;
+ return size;
+ }
+ }
+ }
+ }
+ flexCount++;
+ return null;
+ });
+
+ // Only apply if at least one child has a default
+ if (flexCount < n) {
+ const remainingSpace = Math.max(0, totalSpace - usedSpace);
+ const flexSize = flexCount > 0 ? remainingSpace / flexCount : 0;
+ area.sizes = pixelSizes.map(px => px != null ? px : flexSize);
+ }
+
+ // Recurse into nested split areas with their allocated portion
+ for (let i = 0; i < area.children.length; i++) {
+ const child = area.children[i];
+ if (child.type === "split-area") {
+ const ratio = area.sizes[i] / (area.sizes.reduce((a, b) => a + b, 0) || 1);
+ const childW = isHorizontal ? availWidth * ratio : availWidth;
+ const childH = isHorizontal ? availHeight : availHeight * ratio;
+ applySizes(child, childW, childH);
+ }
+ }
+ };
+
+ applySizes(config.main, containerWidth, containerHeight);
+ this._dock.restoreLayout(config as any);
+ }
+
removeWidget(widget: Widget) {
const wa = this.getWidgetAdapter(widget);
if (wa) {
@@ -74,25 +175,16 @@ export class DockPanel extends HTMLWidget implements IMessageHandler, IMessageHo
return this;
}
- private _pPlaceholder;
enter(domNode, element) {
super.enter(domNode, element);
- this._pPlaceholder = element.append("div");
- PWidget.attach(this._dock, this._pPlaceholder.node());
+ PWidget.attach(this._dock, domNode);
}
_prevHideSingleTabs;
update(domNode, element) {
super.update(domNode, element);
-
- this._pPlaceholder
- .style("width", this.width() + "px")
- .style("height", this.height() + "px")
- .style("overflow", "hidden")
- ;
-
element.select(".lm-Widget")
- .style("width", this._pPlaceholder.node().clientWidth + "px")
+ .style("width", this.width() + "px")
.style("height", this.height() + "px")
;
@@ -125,6 +217,7 @@ export class DockPanel extends HTMLWidget implements IMessageHandler, IMessageHo
this.layoutObj(null);
}
return super.render((w) => {
+ this._applyPendingDefaults();
this._dock.content().watchRendered(this, callback);
this._dock.update();
setTimeout(() => {
@@ -150,39 +243,6 @@ export class DockPanel extends HTMLWidget implements IMessageHandler, IMessageHo
this._dock.fit();
}
- // Phosphor Messaging ---
- messageHook(handler: IMessageHandler, msg: Message): boolean {
- if (handler === this) {
- this.processMessage(msg);
- }
- return true;
- }
-
- private _lazyLayoutChanged = Utility.debounce(async () => {
- this.layoutChanged();
- }, 1000);
-
- _prevActive: Widget;
- processMessage(msg: Message): void {
- switch (msg.type) {
- case Msg.WAActivateRequest.type:
- const wa = (msg as Msg.WAActivateRequest).wa;
- const widget = wa.widget;
- if (this._prevActive !== widget) {
- this._prevActive = widget;
- this.childActivation(widget, wa);
- }
- break;
- case Msg.WALayoutChanged.type:
- this._lazyLayoutChanged();
- break;
- }
- }
-
- active(): Widget {
- return this._prevActive;
- }
-
// Events ---
childActivation(w: Widget, wa: WidgetAdapter) {
}
diff --git a/packages/phosphor/src/SplitPanel.ts b/packages/phosphor/src/SplitPanel.ts
index 1ddb3e8f3b..2187ea8ab1 100644
--- a/packages/phosphor/src/SplitPanel.ts
+++ b/packages/phosphor/src/SplitPanel.ts
@@ -1,36 +1,61 @@
import { HTMLWidget, SVGWidget, Widget } from "@hpcc-js/common";
-import { Message, SplitPanel as PSplitPanel, Widget as PWidget } from "./phosphor-shim.ts";
-import { Msg, WidgetAdapter, WidgetAdapterArray } from "./WidgetAdapter.ts";
+import { BasePanel } from "./BasePanel.ts";
+import { SplitPanel as PSplitPanel, Widget as PWidget } from "./phosphor-shim.ts";
+import { WidgetAdapter, WidgetAdapterArray } from "./WidgetAdapter.ts";
import "../src/DockPanel.css";
-export class SplitPanel extends HTMLWidget {
+export namespace SplitPanel {
+
+ export interface IAddWidgetOptions extends BasePanel.IAddWidgetOptions {
+ /** Maximum size in pixels */
+ maxSize?: number;
+ }
+}
+
+export class SplitPanel extends BasePanel {
private _split: PSplitPanel;
- private content = WidgetAdapterArray.create();
+ protected _content = WidgetAdapterArray.create();
- constructor(orientation: "horizontal" | "vertical" = "vertical") {
+ constructor(readonly _orientation: "horizontal" | "vertical" = "vertical") {
super();
- this._split = new PSplitPanel({ orientation });
- this._tag = "div";
+ this._split = new PSplitPanel({ orientation: _orientation });
this._split.id = "p" + this.id();
}
- protected getWidgetAdapter(widget: Widget): WidgetAdapter | null {
- let retVal = null;
- this.content.some(wa => {
- if (wa.widget === widget) {
- retVal = wa;
- return true;
+ private _pendingDefaults: Map = new Map();
+ addWidget(widget: SVGWidget | HTMLWidget, options?: SplitPanel.IAddWidgetOptions): this {
+ const opts = options || {};
+ const wa = new WidgetAdapter(this, widget);
+ wa.padding = opts.padding ?? 0;
+
+ if (opts.minSize != null || opts.maxSize != null) {
+ const style = wa.node.style;
+ if (opts.minSize != null) {
+ if (this._orientation === "horizontal") {
+ style.minWidth = `${opts.minSize}px`;
+ } else {
+ style.minHeight = `${opts.minSize}px`;
+ }
}
- return false;
- });
- return retVal;
- }
+ if (opts.maxSize != null) {
+ if (this._orientation === "horizontal") {
+ style.maxWidth = `${opts.maxSize}px`;
+ } else {
+ style.maxHeight = `${opts.maxSize}px`;
+ }
+ }
+ }
- addWidget(widget: SVGWidget | HTMLWidget) {
- const wa = new WidgetAdapter(this, widget);
this._split.addWidget(wa);
- this.content.push(wa);
+ this._content.push(wa);
+
+ if (opts.defaultSize != null) {
+ this._pendingDefaults.set(this._content.length - 1, {
+ defaultSize: opts.defaultSize
+ });
+ }
+
return this;
}
@@ -62,26 +87,51 @@ export class SplitPanel extends HTMLWidget {
render(callback?: (w: Widget) => void): this {
return super.render(w => {
- this.content.watchRendered(this, callback);
+ this._applyPendingDefaults();
+ this._content.watchRendered(this, callback);
this._split.update();
});
}
- private _prevActive: Widget;
- processMessage(msg: Message): void {
- switch (msg.type) {
- case "wa-activate-request":
- const widget = (msg as Msg.WAActivateRequest).wa.widget;
- if (this._prevActive !== widget) {
- this._prevActive = widget;
- this.childActivation(widget);
+ private _applyPendingDefaults() {
+ if (this._pendingDefaults.size === 0) return;
+
+ const isHorizontal = this._orientation === "horizontal";
+ const totalSpace = isHorizontal ? this.width() : this.height();
+ const n = this._content.length;
+
+ let usedSpace = 0;
+ let flexCount = 0;
+ const pixelSizes: (number | null)[] = [];
+
+ for (let i = 0; i < n; i++) {
+ const defaults = this._pendingDefaults.get(i);
+ if (defaults) {
+ const size = defaults.defaultSize;
+ if (size != null) {
+ pixelSizes.push(size);
+ usedSpace += size;
+ continue;
}
- break;
+ }
+ pixelSizes.push(null);
+ flexCount++;
}
+
+ this._pendingDefaults.clear();
+
+ const remainingSpace = Math.max(0, totalSpace - usedSpace);
+ const flexSize = flexCount > 0 ? remainingSpace / flexCount : 0;
+ const sizes = pixelSizes.map(px => px != null ? px : flexSize);
+ this._split.setRelativeSizes(sizes);
}
- // Events ---
- childActivation(w: Widget) {
+ // Events ---
+ childActivation(w: Widget, wa: WidgetAdapter) {
+ }
+
+ layoutChanged() {
}
}
SplitPanel.prototype._class += " phosphor_SplitPanel";
+
diff --git a/packages/phosphor/src/TabPanel.ts b/packages/phosphor/src/TabPanel.ts
index 059369f2d8..9a7a80a4b0 100644
--- a/packages/phosphor/src/TabPanel.ts
+++ b/packages/phosphor/src/TabPanel.ts
@@ -1,55 +1,63 @@
import { HTMLWidget, SVGWidget, Widget } from "@hpcc-js/common";
-import { IMessageHandler, Message, TabPanel as PTabPanel, Widget as PWidget } from "./phosphor-shim.ts";
-import { Msg, WidgetAdapter, WidgetAdapterArray, WidgetAdapterExt } from "./WidgetAdapter.ts";
+import { BasePanel } from "./BasePanel.ts";
+import { TabPanel as PTabPanel, Widget as PWidget } from "./phosphor-shim.ts";
+import { WidgetAdapter, WidgetAdapterArray, WidgetAdapterExt } from "./WidgetAdapter.ts";
import "../src/DockPanel.css";
-export class TabPanel extends HTMLWidget {
+export namespace TabPanel {
+
+ export interface IAddWidgetOptions {
+ /** Inner padding in pixels (default 8) */
+ padding?: number;
+ /** Tab title */
+ title?: string;
+ /** Widget adapter extensions (overflow settings) */
+ ext?: WidgetAdapterExt;
+ }
+}
+
+export class TabPanel extends BasePanel {
private _tab = new PTabPanel({ tabPlacement: "top" });
- protected content = WidgetAdapterArray.create();
+ protected _content = WidgetAdapterArray.create();
constructor() {
super();
- this._tag = "div";
this._tab.id = "p" + this.id();
}
- protected getWidget(wa: PWidget): Widget | undefined {
- if (wa instanceof WidgetAdapter) {
- return wa.widget;
- }
- }
+ addWidget(widget: SVGWidget | HTMLWidget, options: TabPanel.IAddWidgetOptions): this;
+ /** @deprecated Use options object form instead */
+ addWidget(widget: SVGWidget | HTMLWidget, title: string, ext?: WidgetAdapterExt): this;
+ addWidget(widget: SVGWidget | HTMLWidget, titleOrOptions: string | TabPanel.IAddWidgetOptions, ext: WidgetAdapterExt = {}) {
+ const opts: TabPanel.IAddWidgetOptions = typeof titleOrOptions === "string"
+ ? { title: titleOrOptions, ext }
+ : titleOrOptions;
- protected getWidgetAdapter(widget: Widget): WidgetAdapter | null {
- let retVal = null;
- this.content.some(wa => {
- if (wa.widget === widget) {
- retVal = wa;
- return true;
- }
- return false;
- });
- return retVal;
- }
+ const {
+ title = "",
+ ext: widgetExt = {},
+ padding = 8
+ } = opts;
- addWidget(widget: SVGWidget | HTMLWidget, title: string, ext: WidgetAdapterExt = {}) {
if (!this._prevActive) {
this._prevActive = widget;
}
- const wa = new WidgetAdapter(this, widget, undefined, undefined, ext);
+ const wa = new WidgetAdapter(this, widget, undefined, undefined, widgetExt);
wa.title.label = title;
- wa.padding = 8;
+ wa.padding = padding;
+
this._tab.addWidget(wa);
- this.content.push(wa);
+ this._content.push(wa);
return this;
}
removeWidget(widget: SVGWidget | HTMLWidget) {
const wa = this.getWidgetAdapter(widget);
if (wa) {
- const found = this.content.indexOf(wa);
+ const found = this._content.indexOf(wa);
if (found >= 0) {
- this.content.splice(found, 1);
+ this._content.splice(found, 1);
}
widget.target(null);
wa.dispose();
@@ -77,35 +85,11 @@ export class TabPanel extends HTMLWidget {
render(callback?: (w: Widget) => void): this {
return super.render(w => {
- this.content.watchRendered(this, callback);
+ this._content.watchRendered(this, callback);
this._tab.update();
});
}
- // Phosphor Messaging ---
- messageHook(handler: IMessageHandler, msg: Message): boolean {
- if (handler === this) {
- this.processMessage(msg);
- }
- return true;
- }
-
- private _prevActive: Widget;
- processMessage(msg: Message): void {
- switch (msg.type) {
- case "wa-activate-request":
- const widget = (msg as Msg.WAActivateRequest).wa.widget;
- if (this._prevActive !== widget) {
- this._prevActive = widget;
- this.childActivation(widget);
- }
- break;
- }
- }
-
- childActivation(w: Widget) {
- }
-
active(): Widget;
active(_: Widget);
active(_?: Widget): Widget | this {
@@ -113,5 +97,12 @@ export class TabPanel extends HTMLWidget {
this._tab.currentWidget = this.getWidgetAdapter(_);
return this;
}
+
+ // Events ---
+ childActivation(w: Widget, wa: WidgetAdapter) {
+ }
+
+ layoutChanged() {
+ }
}
TabPanel.prototype._class += " phosphor_TabPanel";
diff --git a/packages/phosphor/src/WidgetAdapter.css b/packages/phosphor/src/WidgetAdapter.css
index 3e0cdb8fe8..186d0d0b3f 100644
--- a/packages/phosphor/src/WidgetAdapter.css
+++ b/packages/phosphor/src/WidgetAdapter.css
@@ -13,5 +13,6 @@
}
.phosphor_WidgetAdapter.lm-SplitPanel-child {
- border: none;
+ border-top: none;
+ box-shadow: 0px -1px 0px rgba(0, 0, 0, 0.2), 1px 1px 2px rgba(0, 0, 0, 0.2);
}
\ No newline at end of file