From 062669f65a0cb03ee92e398ce32e2f007094f231 Mon Sep 17 00:00:00 2001 From: Gordon Smith Date: Sun, 31 May 2026 11:29:07 +0100 Subject: [PATCH] feat: enhance panel components with new sizing options and layout features Signed-off-by: Gordon Smith --- .github/workflows/ci.yml | 65 +++++- package-lock.json | 1 - .../eclwatch/tests/eclwatch.browser.spec.ts | 10 + packages/marshaller/src/dashy.ts | 4 +- packages/phosphor/index.html | 174 ++++++++++++---- packages/phosphor/src/BasePanel.ts | 87 ++++++++ packages/phosphor/src/DockPanel.ts | 190 ++++++++++++------ packages/phosphor/src/SplitPanel.ts | 114 ++++++++--- packages/phosphor/src/TabPanel.ts | 95 ++++----- packages/phosphor/src/WidgetAdapter.css | 3 +- 10 files changed, 552 insertions(+), 191 deletions(-) create mode 100644 packages/phosphor/src/BasePanel.ts 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