-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
[Core] Add panel stack component #2642
Conversation
Thanks for your interest in palantir/blueprint, @kadhirvelm! Before we can accept your pull request, you need to sign our contributor license agreement - just visit https://cla.palantir.com/ and follow the instructions. Once you sign, I'll automatically update this pull request. |
Made lower casePreview: documentation | landing | table |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
needs dark theme and style love
`Panel Stack` is a component designed to render multiple panels from a stack, but only display the | ||
top most panel at any given time. | ||
|
||
It will render each panel with a header and uses [`CSSTransitionGroup`](https://facebook.github.io/react/docs/animation.html) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's just CSSTransition
now and link to docs directly http://reactcommunity.org/react-transition-group/css-transition
@## Props | ||
|
||
The `Panel Stack` component is available in the __@blueprintjs/core__ package. | ||
Make sure to review the [general usage docs for JS components](#blueprint.usage). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove this paragraph, we don't do this anymore.
position: relative; | ||
overflow: hidden; | ||
|
||
.push-#{$ns}-panel-stack-transition-enter { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$ns must be the first thing in the class. #{$ns}-panel-stack-transition-push-*
transform: translateX(100%); | ||
} | ||
|
||
.push-#{$ns}-panel-stack-transition-enter-active { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: use the mixin
|
||
export interface IPanelStackProps extends IProps { | ||
/** The panel to show when initially rendering the component */ | ||
initialPanel: IPanel; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
must this be required?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@giladgray I think it must. The only way to open a panel (after the initial panel becomes the stack) is from a panel. If there are no more panels, the stack will stay empty, forever. I don't think there's a valid use case for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh yeah that makes a lot of sense. probably worth calling that out in some usage docs.
margin: 0 10px; | ||
// aligns title with back button | ||
line-height: 28px; | ||
color: $pt-text-color; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is the default, why must it be reset? if so, needs dark theme
} | ||
|
||
.#{$ns}-panel-stack-chevron { | ||
font-size: $pt-font-size; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
font-size has no effect on svg icons. please remove.
right: 0; | ||
bottom: 0; | ||
left: 0; | ||
background-color: $white; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
needs dark theme
top: 0; | ||
right: 0; | ||
bottom: 0; | ||
left: 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@include position-all(absolute, 0)
return null; | ||
} | ||
return ( | ||
<div className={Classes.PANELSTACK_HEADER_BACK} onClick={this.props.back.onClick}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎨 i feel like we should just use a small minimal button here instead of all this custom style
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tried to remove whatever I could, now it's just flex + cursor + color
So I tried to add the But on the plus side, changing the duration to |
Dark theme addedPreview: documentation | landing | table |
Linting fixedPreview: documentation | landing | table |
export class PanelStack extends React.PureComponent<IPanelStackProps, IPanelStackState> { | ||
public constructor(props: IPanelStackProps, context?: any) { | ||
super(props, context); | ||
this.state = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pull this out to member, remove constructor. you can access this.props
in member definitions.
timeout={{ | ||
enter: 400, | ||
exit: 400, | ||
}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
timeout={400}
?
return ( | ||
<CSSTransition | ||
classNames={`${Classes.PANELSTACK_TRANSITION}-${this.state.direction}`} | ||
key={stack.length} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this does not feel safe to use as a key. the size of the stack is not a unique identifier of the panel. not really sure what to do tho, needs investigation.
}} | ||
> | ||
<PanelView | ||
key={stack.length} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need for key here, it's not in an array.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure about transition group 2.x, but in 1.x the key was required for their bookkeeping, not react's. Maybe it needs to be on the transition now?
// Prevent the last panel from being closed. | ||
state.stack.length > 1; | ||
if (allowed && this.props.onClose !== undefined) { | ||
this.props.onClose(state.stack[0]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Utils.safeInvoke
instead of undefined check
} | ||
|
||
export interface IPanelHeaderProps { | ||
back?: IBackButton; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prefer to avoid objects as props as it often breaks the pure behavior by creating new objects every render (you do this below). spell them out as backTitle
and onBackClick
.
|
||
export interface IPanelHeaderProps { | ||
back?: IBackButton; | ||
title: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not use children
for this? <PanelHeader>content</PanelHeader>
}} | ||
> | ||
<PanelView | ||
key={stack.length} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure about transition group 2.x, but in 1.x the key was required for their bookkeeping, not react's. Maybe it needs to be on the transition now?
// otherwise rapidly clicking the back link will close multiple panels. | ||
state.stack.length === stackSize && | ||
// Prevent the last panel from being closed. | ||
state.stack.length > 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this can be refactored to just if (condition) { return null }
I initially wrote it this way because I had problems with setState
typings, but returning null
should work and allows you to remove the allowed
variable entirely.
* The name of the previous panel header in the stack. Will not render unless an onBackClick | ||
* handler is defined. | ||
*/ | ||
backTitle?: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh hum, should this ever be undefined? title
Should we allow a panel to be defined without a title?
Review items fixed, transitions revertedPreview: documentation | landing | table |
> | ||
<PanelView | ||
key={stack.length} | ||
panelClassName={this.props.className} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kadhirvelm why is this prop passed down here? it gets rendered on two elements, which seems undesirable.
Removed extra panelClassNamePreview: documentation | landing | table |
Merge branch 'develop' of github.com:palantir/blueprint into km/panel-stackPreview: documentation | landing | table |
minor docsPreview: documentation | landing | table |
Adjusted transition to include opacity and -50% left movementPreview: documentation | landing | table |
Removed useless type checkingPreview: documentation | landing | table |
Fixed opacityPreview: documentation | landing | table |
OpacityPreview: documentation | landing | table |
Removed 0Preview: documentation | landing | table |
Reversed opacitiesPreview: documentation | landing | table |
One more attemptPreview: documentation | landing | table |
* merge PanelHeader into PanelView * panelProps file with more docs * panelProps.ts * export panelProps, more docs * example key * docs * safeInvoke
[PanelStack] merge some files (#2719)Preview: documentation | landing | table |
changed easing settingsPreview: documentation | landing | table |
onClose/Open param namesPreview: documentation | landing | table |
* openPanel accepts IPanel instead of three args * PanelView onClose/Open props skips getPanelProps() step * fix tests * remove IPanelPptions
[PanelStack] use IPanel in openPanel() public API (#2738)Preview: documentation | landing | table |
* PanelStack docs * more docs refactors * adjust docs-modifiers margins * remove "pop the stack"
[PanelStack] documentation (#2737)Preview: documentation | landing | table |
Bugs
There's a strange bug that if you smash the
Open new panel
button rapidly, it spits out the panels incorrectly in theonOpen
callback handler.The panel stack isn't really meant to be used like that, but either way I don't think the component should be merged with a bug like that. Wanted to get the PR up in the meantime and get some feedback while I continue to figure this out.
Checklist
Changes proposed in this pull request:
Adds the panel stack component to blueprint core:
Reviewers should focus on:
The core component was already reviewed, so best to focus on the example, documentation, and that overall the component was properly integrated into blueprint.
Also I've been having issues getting the transition to work correctly, so any thoughts on how to fix that nicely would be very appreciated.
GIF