Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport PR #497 on branch 1.x (Add content-visibility hide mode) #500

Merged
merged 2 commits into from
Dec 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/widgets/src/cssPatch.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
declare interface CSSStyleDeclaration {
contentVisibility: string;
}
19 changes: 11 additions & 8 deletions packages/widgets/src/docklayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -852,18 +852,21 @@ export class DockLayout extends Layout {

// Using transform create an additional layer in the pixel pipeline
// to limit the number of layer, it is set only if there is more than one widget.
if (
this._hiddenMode === Widget.HiddenMode.Scale &&
refNode.tabBar.titles.length > 0
) {
if (refNode.tabBar.titles.length == 1) {
if (this._hiddenMode === Widget.HiddenMode.Scale) {
if (refNode.tabBar.titles.length === 0) {
// Singular tab should use display mode to limit number of layers.
widget.hiddenMode = Widget.HiddenMode.Display;
} else if (refNode.tabBar.titles.length == 1) {
// If we are adding a second tab, switch the existing tab back to scale.
const existingWidget = refNode.tabBar.titles[0].owner;
existingWidget.hiddenMode = Widget.HiddenMode.Scale;
} else {
// For the third and subsequent tabs no special action is needed.
widget.hiddenMode = Widget.HiddenMode.Scale;
}

widget.hiddenMode = Widget.HiddenMode.Scale;
} else {
widget.hiddenMode = Widget.HiddenMode.Display;
// For all other modes just propagate the current mode.
widget.hiddenMode = this._hiddenMode;
}

// Insert the widget's tab relative to the target index.
Expand Down
96 changes: 58 additions & 38 deletions packages/widgets/src/widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,30 +183,23 @@ export class Widget implements IMessageHandler, IObservableDisposable {
if (this._hiddenMode === value) {
return;
}
this._hiddenMode = value;
switch (value) {
case Widget.HiddenMode.Display:
this.node.style.willChange = 'auto';
break;
case Widget.HiddenMode.Scale:
this.node.style.willChange = 'transform';
break;

if (this.isHidden) {
// Reset styles set by previous mode.
this._toggleHidden(false);
}

if (value == Widget.HiddenMode.Scale) {
this.node.style.willChange = 'transform';
} else {
this.node.style.willChange = 'auto';
}

this._hiddenMode = value;

if (this.isHidden) {
if (value === Widget.HiddenMode.Display) {
this.addClass('lm-mod-hidden');
/* <DEPRECATED> */
this.addClass('p-mod-hidden');
/* </DEPRECATED> */
this.node.style.transform = '';
} else {
this.node.style.transform = 'scale(0)';
this.removeClass('lm-mod-hidden');
/* <DEPRECATED> */
this.removeClass('p-mod-hidden');
/* </DEPRECATED> */
}
// Set styles for new mode.
this._toggleHidden(true);
}
}

Expand Down Expand Up @@ -434,14 +427,7 @@ export class Widget implements IMessageHandler, IObservableDisposable {
}
this.clearFlag(Widget.Flag.IsHidden);
this.node.removeAttribute('aria-hidden');
if (this.hiddenMode === Widget.HiddenMode.Display) {
this.removeClass('lm-mod-hidden');
/* <DEPRECATED> */
this.removeClass('p-mod-hidden');
/* </DEPRECATED> */
} else {
this.node.style.transform = '';
}
this._toggleHidden(false);

if (this.isAttached && (!this.parent || this.parent.isVisible)) {
MessageLoop.sendMessage(this, Widget.Msg.AfterShow);
Expand Down Expand Up @@ -469,14 +455,7 @@ export class Widget implements IMessageHandler, IObservableDisposable {
}
this.setFlag(Widget.Flag.IsHidden);
this.node.setAttribute('aria-hidden', 'true');
if (this.hiddenMode === Widget.HiddenMode.Display) {
this.addClass('lm-mod-hidden');
/* <DEPRECATED> */
this.addClass('p-mod-hidden');
/* </DEPRECATED> */
} else {
this.node.style.transform = 'scale(0)';
}
this._toggleHidden(true);

if (this.isAttached && (!this.parent || this.parent.isVisible)) {
MessageLoop.sendMessage(this, Widget.Msg.AfterHide);
Expand Down Expand Up @@ -759,6 +738,42 @@ export class Widget implements IMessageHandler, IObservableDisposable {
*/
protected onChildRemoved(msg: Widget.ChildMessage): void {}

private _toggleHidden(hidden: boolean) {
if (hidden) {
switch (this._hiddenMode) {
case Widget.HiddenMode.Display:
this.addClass('lm-mod-hidden');
/* <DEPRECATED> */
this.addClass('p-mod-hidden');
/* </DEPRECATED> */
break;
case Widget.HiddenMode.Scale:
this.node.style.transform = 'scale(0)';
break;
case Widget.HiddenMode.ContentVisibility:
this.node.style.contentVisibility = 'hidden';
this.node.style.zIndex = '-1';
break;
}
} else {
switch (this._hiddenMode) {
case Widget.HiddenMode.Display:
this.removeClass('lm-mod-hidden');
/* <DEPRECATED> */
this.removeClass('p-mod-hidden');
/* </DEPRECATED> */
break;
case Widget.HiddenMode.Scale:
this.node.style.transform = '';
break;
case Widget.HiddenMode.ContentVisibility:
this.node.style.contentVisibility = '';
this.node.style.zIndex = '';
break;
}
}
}

private _flags = 0;
private _layout: Layout | null = null;
private _parent: Widget | null = null;
Expand Down Expand Up @@ -819,7 +834,12 @@ export namespace Widget {
/**
* Hide the widget by setting the `transform` to `'scale(0)'`.
*/
Scale
Scale,

/**
*Hide the widget by setting the `content-visibility` to `'hidden'`.
*/
ContentVisibility
}

/**
Expand Down
3 changes: 3 additions & 0 deletions packages/widgets/tests/src/cssPatch.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
declare interface CSSStyleDeclaration {
contentVisibility: string;
}
32 changes: 30 additions & 2 deletions packages/widgets/tests/src/widget.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -740,10 +740,38 @@ describe('@lumino/widgets', () => {
widget.dispose();
});

it('should add class when switching from scale to display', () => {
for (const fromMode of [
Widget.HiddenMode.Scale,
Widget.HiddenMode.ContentVisibility
]) {
it(`should add class when switching from ${fromMode} to display`, () => {
let widget = new Widget();
Widget.attach(widget, document.body);
widget.hiddenMode = fromMode;
widget.hide();
widget.hiddenMode = Widget.HiddenMode.Display;
expect(widget.hasClass('lm-mod-hidden')).to.equal(true);
expect(widget.node.style.transform).to.equal('');
expect(widget.node.style.willChange).to.equal('auto');
widget.dispose();
});
}

it('should use content-visibility in relevant mode', () => {
let widget = new Widget();
Widget.attach(widget, document.body);
widget.hiddenMode = Widget.HiddenMode.Scale;
widget.hiddenMode = Widget.HiddenMode.ContentVisibility;
widget.hide();
expect(widget.hasClass('lm-mod-hidden')).to.equal(false);
expect(widget.node.style.contentVisibility).to.equal('hidden');
expect(widget.node.style.willChange).to.equal('auto');
widget.dispose();
});

it('should add class when switching from content-visibility to display', () => {
let widget = new Widget();
Widget.attach(widget, document.body);
widget.hiddenMode = Widget.HiddenMode.ContentVisibility;
widget.hide();
widget.hiddenMode = Widget.HiddenMode.Display;
expect(widget.hasClass('lm-mod-hidden')).to.equal(true);
Expand Down
1 change: 1 addition & 0 deletions review/api/widgets.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1267,6 +1267,7 @@ export namespace Widget {
IsVisible = 8
}
export enum HiddenMode {
ContentVisibility = 2,
Display = 0,
Scale = 1
}
Expand Down