Skip to content

Commit

Permalink
[core] feat: PanelStack2 component (#4541)
Browse files Browse the repository at this point in the history
  • Loading branch information
adidahiya authored Feb 25, 2021
1 parent f2264b6 commit f959561
Show file tree
Hide file tree
Showing 22 changed files with 896 additions and 4 deletions.
2 changes: 1 addition & 1 deletion packages/core/karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ module.exports = function (config) {

if (REACT === "15") {
// features require React 16.8+
coverageExcludes.push("src/context/*", "src/hooks/*");
coverageExcludes.push("src/context/*", "src/hooks/*", "src/components/panel-stack2/*");
}

const baseConfig = createKarmaConfig({
Expand Down
5 changes: 5 additions & 0 deletions packages/core/src/common/classes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,11 @@ export const PANEL_STACK_HEADER = `${PANEL_STACK}-header`;
export const PANEL_STACK_HEADER_BACK = `${PANEL_STACK}-header-back`;
export const PANEL_STACK_VIEW = `${PANEL_STACK}-view`;

export const PANEL_STACK2 = `${NS}-panel-stack2`;
export const PANEL_STACK2_HEADER = `${PANEL_STACK}-header`;
export const PANEL_STACK2_HEADER_BACK = `${PANEL_STACK}-header-back`;
export const PANEL_STACK2_VIEW = `${PANEL_STACK}-view`;

export const POPOVER = `${NS}-popover`;
export const POPOVER_ARROW = `${POPOVER}-arrow`;
export const POPOVER_BACKDROP = `${POPOVER}-backdrop`;
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/components/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
@import "overflow-list/overflow-list";
@import "overlay/overlay";
@import "panel-stack/panel-stack";
@import "panel-stack2/panel-stack2";
@import "popover/popover";
@import "portal/portal";
@import "progress-bar/progress-bar";
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/components/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
@page non-ideal-state
@page overflow-list
@page panel-stack
@page panel-stack2
@page progress-bar
@page resize-sensor
@page skeleton
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ export * from "./overlay/overlay";
export * from "./text/text";
export * from "./panel-stack/panelProps";
export * from "./panel-stack/panelStack";
export { PanelStack2, PanelStack2Props } from "./panel-stack2/panelStack2";
export { Panel, PanelProps } from "./panel-stack2/panelTypes";
export * from "./popover/popover";
export * from "./popover/popoverSharedProps";
export * from "./portal/portal";
Expand Down
16 changes: 14 additions & 2 deletions packages/core/src/components/panel-stack/panel-stack.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
@# Panel stack

<div class="@ns-callout @ns-intent-danger @ns-icon-error">
<h4 class="@ns-heading">

Deprecated: use [PanelStack2](#core/components/panel-stack2)

</h4>

This API is **deprecated since @blueprintjs/core v3.40.0** in favor of the new
PanelStack2 component available to React 16.8+ users. You should migrate to the
new API which will become the standard in Blueprint v4.

</div>

`PanelStack` manages a stack of panels and displays only the topmost panel.

Each panel appears with a header containing a "back" button to return to the
Expand Down Expand Up @@ -59,8 +72,7 @@ class SettingsPanel extends React.Component<IPanelProps & { enabled: boolean }>

@## Props

The panel stack cannot be controlled but `onClose` and `onOpen` callbacks are
available to listen for changes.
PanelStack can be operated as a controlled or uncontrolled component.

@interface IPanelStackProps

6 changes: 6 additions & 0 deletions packages/core/src/components/panel-stack/panelProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@

import * as React from "react";

/* eslint-disable deprecation/deprecation */

/**
* An object describing a panel in a `PanelStack`.
*
* @deprecated use `Panel<T>`
*/
// eslint-disable-next-line @typescript-eslint/ban-types
export interface IPanel<P = {}> {
Expand Down Expand Up @@ -54,6 +58,8 @@ export interface IPanel<P = {}> {
* import { IPanelProps } from "@blueprintjs/core";
* export class SettingsPanel extends React.Component<IPanelProps & ISettingsPanelProps> {...}
* ```
*
* @deprecated use `PanelActions<T>`
*/
export interface IPanelProps {
/**
Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/components/panel-stack/panelStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import { IProps } from "../../common/props";
import { IPanel } from "./panelProps";
import { PanelView } from "./panelView";

/* eslint-disable deprecation/deprecation */

export interface IPanelStackProps extends IProps {
/**
* The initial panel to show on mount. This panel cannot be removed from the
Expand Down Expand Up @@ -77,6 +79,7 @@ export interface IPanelStackState {
stack: IPanel[];
}

/** @deprecated use `PanelStack2<T>` */
@polyfill
export class PanelStack extends AbstractPureComponent2<IPanelStackProps, IPanelStackState> {
public state: IPanelStackState = {
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/components/panel-stack/panelView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import { Button } from "../button/buttons";
import { Text } from "../text/text";
import { IPanel } from "./panelProps";

/* eslint-disable deprecation/deprecation */

export interface IPanelViewProps {
/**
* Callback invoked when the user presses the back button or a panel invokes
Expand Down
103 changes: 103 additions & 0 deletions packages/core/src/components/panel-stack2/_panel-stack2.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Copyright 2021 Palantir Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0.

@import "../../common/variables";
@import "~@blueprintjs/core/src/common/react-transition";

.#{$ns}-panel-stack2 {
overflow: hidden;
position: relative;
}

.#{$ns}-panel-stack2-header {
align-items: center;
box-shadow: 0 1px $pt-divider-black;
display: flex;
flex-shrink: 0;
height: $pt-grid-size * 3;
z-index: 1;

.#{$ns}-dark & {
box-shadow: 0 1px $pt-dark-divider-white;
}

// two span children act as spacers to keep the title centered.
> span {
align-items: stretch;
display: flex;
flex: 1;
}

.#{$ns}-heading {
margin: 0 ($pt-grid-size / 2);
}
}

.#{$ns}-button.#{$ns}-panel-stack2-header-back {
margin-left: $pt-grid-size / 2;
padding-left: 0;
white-space: nowrap;

.#{$ns}-icon {
// reduce margins around icon so it fits better in tight header
margin: 0 2px;
}
}

.#{$ns}-panel-stack2-view {
@include position-all(absolute, 0);

background-color: $white;
border-right: 1px solid $pt-divider-black;
display: flex;
flex-direction: column;

// border between panels, visible during transition
margin-right: -1px;
overflow-y: auto;
z-index: 1;

.#{$ns}-dark & {
background-color: $dark-gray4;
}

&:nth-last-child(n + 4) {
display: none;
}
}

// PUSH transition: enter from right (100%), existing panel moves off left.
.#{$ns}-panel-stack2-push {
@include react-transition-phase(
"#{$ns}-panel-stack2",
"enter",
(transform: translateX(100%) translate(0%), opacity: 0 1),
$easing: ease,
$duration: $pt-transition-duration * 4
);
@include react-transition-phase(
"#{$ns}-panel-stack2",
"exit",
(transform: translateX(-50%) translate(0%), opacity: 0 1),
$easing: ease,
$duration: $pt-transition-duration * 4
);
}

// POP transition: enter from left (-50%), existing panel moves off right.
.#{$ns}-panel-stack2-pop {
@include react-transition-phase(
"#{$ns}-panel-stack2",
"enter",
(transform: translateX(-50%) translate(0%), opacity: 0 1),
$easing: ease,
$duration: $pt-transition-duration * 4
);
@include react-transition-phase(
"#{$ns}-panel-stack2",
"exit",
(transform: translateX(100%) translate(0%), opacity: 0 1),
$easing: ease,
$duration: $pt-transition-duration * 4
);
}
75 changes: 75 additions & 0 deletions packages/core/src/components/panel-stack2/panel-stack2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
tag: new
---

@# Panel stack (v2)

<div class="@ns-callout @ns-intent-warning @ns-icon-warning-sign">
<h4 class="@ns-heading">This API requires React 16.8+</h4>
</div>

<div class="@ns-callout @ns-intent-primary @ns-icon-info-sign">
<h4 class="@ns-heading">

Migrating from [PanelStack](#core/components/panel-stack)?

</h4>

PanelStack2 is a replacement for PanelStack. It will become the standard
API in Blueprint core v4. You are encouraged to use this new API now to ease the
transition to the next major version of Blueprint. See the full
[migration guide](https://github.com/palantir/blueprint/wiki/PanelStack2-migration) on the wiki.

</div>


`PanelStack2` manages a stack of panels and displays only the topmost panel.

Each panel appears with a header containing a "back" button to return to the
previous panel. The bottom-most `initialPanel` cannot be closed or removed from
the stack. Panels use
[`CSSTransition`](http://reactcommunity.org/react-transition-group/css-transition)
for seamless transitions.

By default, only the currently active panel is rendered to the DOM. This means
that other panels are unmounted and can lose their component state as a user
transitions between the panels. You can notice this in the example below as
the numeric counter is reset. To render all panels to the DOM and keep their
React trees mounted, change the `renderActivePanelOnly` prop.

@reactExample PanelStack2Example

@## Panels

Panels are supplied as `Panel<T>` objects, where `renderPanel` and `props` are
used to render the panel element and `title` will appear in the header and back button.
This breakdown allows the component to avoid cloning elements.
Note that each panel is only mounted when it is atop the stack and is unmounted when
it is closed or when a panel opens above it.

`PanelStack2` injects panel action callbacks into each panel renderer in addition to
the `props` defined by `Panel<T>`. These allow you to close the current panel or open a
new one on top of it during the panel's lifecycle. For example:

```tsx
import { PanelProps } from "@blueprintjs/core";

type SettingsPanelInfo = {
// ...
};

const SettingsPanel: React.FC<PanelProps<SettingsPanelInfo>> = props => {
const { openPanel, closePanel, ...info } = props;
// ...
}
```

@interface Panel

@interface PanelActions

@## Props

PanelStack2 can be operated as a controlled or uncontrolled component.

@interface PanelStack2Props
Loading

1 comment on commit f959561

@blueprint-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[core] feat: PanelStack2 component (#4541)

Previews: documentation | landing | table

Please sign in to comment.