-
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
Add a multistep dialog component #4462
Changes from all commits
3c1a376
aed6c90
3ad28bc
a5c2d05
368f935
017cb65
53f6c3c
6e8def9
17c9744
6187de0
69fd270
90d6c8a
931f069
9027e98
8104acf
29d0f1d
9fb304d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
// Copyright 2020 Palantir Technologies, Inc. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. | ||
|
||
@import "~@blueprintjs/icons/src/icons"; | ||
@import "../../common/mixins"; | ||
@import "../../common/react-transition"; | ||
@import "../../common/variables"; | ||
|
||
$dialog-border-radius: $pt-border-radius * 2 !default; | ||
$step-radius: $pt-border-radius * 2 !default; | ||
|
||
.#{$ns}-multistep-dialog-panels { | ||
display: flex; | ||
} | ||
|
||
.#{$ns}-multistep-dialog-left-panel { | ||
display: flex; | ||
flex: 1; | ||
flex-direction: column; | ||
|
||
.#{$ns}-dark & { | ||
background: $dark-gray2; | ||
} | ||
} | ||
|
||
.#{$ns}-multistep-dialog-right-panel { | ||
background-color: $light-gray5; | ||
border-left: 1px solid $pt-divider-black; | ||
border-radius: 0 0 $dialog-border-radius 0; | ||
flex: 2; | ||
|
||
.#{$ns}-dark & { | ||
background-color: $dark-gray3; | ||
border-left: 1px solid $pt-dark-divider-black; | ||
} | ||
} | ||
|
||
.#{$ns}-multistep-dialog-footer { | ||
background-color: $white; | ||
border-radius: 0 0 $dialog-border-radius 0; | ||
border-top: 1px solid $pt-divider-black; | ||
padding: 10px; | ||
|
||
.#{$ns}-dark & { | ||
background: $dark-gray4; | ||
border-top: 1px solid $pt-dark-divider-black; | ||
} | ||
} | ||
|
||
.#{$ns}-dialog-step-container { | ||
background-color: $light-gray5; | ||
border-bottom: 1px solid $pt-divider-black; | ||
|
||
.#{$ns}-dark & { | ||
background: $dark-gray3; | ||
border-bottom: 1px solid $pt-dark-divider-black; | ||
} | ||
|
||
&.#{$ns}-active { | ||
background-color: $white; | ||
.#{$ns}-dark & { | ||
background: $dark-gray4; | ||
} | ||
} | ||
} | ||
|
||
.#{$ns}-dialog-step { | ||
align-items: center; | ||
background-color: $light-gray5; | ||
border-radius: $step-radius; | ||
cursor: not-allowed; | ||
display: flex; | ||
margin: 4px; | ||
padding: 6px 14px; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed padding to better align with the title icon. |
||
|
||
.#{$ns}-dark & { | ||
background: $dark-gray3; | ||
} | ||
|
||
// by default, steps are inactive until they are visited | ||
.#{$ns}-active & { | ||
background-color: $white; | ||
cursor: pointer; | ||
|
||
.#{$ns}-dark & { | ||
background: $dark-gray4; | ||
} | ||
} | ||
|
||
&:hover { | ||
background-color: $light-gray5; | ||
|
||
.#{$ns}-dark & { | ||
background: $dark-gray3; | ||
} | ||
} | ||
} | ||
|
||
.#{$ns}-dialog-step-icon { | ||
align-items: center; | ||
background-color: $light-gray1; | ||
border-radius: 50%; | ||
color: $white; | ||
display: flex; | ||
height: 25px; | ||
justify-content: center; | ||
width: 25px; | ||
|
||
.#{$ns}-dark & { | ||
background-color: $pt-dark-icon-color-disabled; | ||
} | ||
|
||
.#{$ns}-active & { | ||
background-color: $blue4; | ||
} | ||
} | ||
|
||
.#{$ns}-dialog-step-title { | ||
color: $gray1; | ||
padding-left: 10px; | ||
|
||
.#{$ns}-dark & { | ||
color: $pt-dark-text-color-disabled; | ||
} | ||
|
||
// by default, step title is active only when the step is selected | ||
&.#{$ns}-active { | ||
color: $blue4; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
@# Dialog | ||
@# Dialogs | ||
|
||
Dialogs present content overlaid over other parts of the UI. | ||
|
||
|
@@ -13,9 +13,16 @@ We use the term "dialog" to avoid confusion with the adjective. | |
|
||
</div> | ||
|
||
Blueprint provides two types of dialogs: | ||
|
||
1. Standard dialog: use the `Dialog` component for a dialog that only requires one view. | ||
1. Multistep dialog: use the `MultistepDialog` component for a dialog with multiple sequential views. | ||
|
||
@## Dialog | ||
|
||
@reactExample DialogExample | ||
|
||
@## Props | ||
@### Props | ||
|
||
`Dialog` is a stateless React component controlled by the `isOpen` prop. | ||
|
||
|
@@ -26,7 +33,7 @@ The children you provide to this component are rendered as contents inside the | |
|
||
@interface IDialogProps | ||
|
||
@## CSS | ||
@### CSS | ||
|
||
You can create dialogs manually using the HTML markup and `@ns-dialog-*` classes below. | ||
However, you should use the [`Dialog` component](#core/components/dialog.props) | ||
|
@@ -35,3 +42,29 @@ whenever possible, as they automatically generate some of this markup. | |
More examples of dialog content are shown below. | ||
|
||
@css dialog | ||
|
||
@## Multistep dialog | ||
|
||
@reactExample MultistepDialogExample | ||
|
||
@### Multistep dialog props | ||
|
||
`MultistepDialog` is a wrapper around `Dialog` that displays a dialog with multiple steps, each of which maps to a specific panel. | ||
|
||
The children you provide to this component are rendered as contents inside the | ||
`Classes.DIALOG` element. Typically, you will want to render a panel with | ||
`Classes.DIALOG_BODY` that contains the body content for each step. | ||
Comment on lines
+54
to
+56
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should explain a little more about the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good, I added info under line 54. |
||
|
||
Children of the `MultistepDialog` are filtered down to only `Step` components and rendered in order. | ||
`Step` children are managed by the component; clicking one will change selection. | ||
|
||
@interface IMultistepDialogProps | ||
|
||
@### Step | ||
|
||
`Step` is a minimal wrapper with no functionality of its own—it is managed entirely by its | ||
parent `MultistepDialog` wrapper. Step title text can be set via the `title` prop. | ||
|
||
The associated step panel will be visible when the `Step` is selected. | ||
|
||
@interface IStepProps |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/* | ||
* Copyright 2020 Palantir Technologies, Inc. All rights reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
import classNames from "classnames"; | ||
import * as React from "react"; | ||
import { polyfill } from "react-lifecycles-compat"; | ||
|
||
import { AbstractPureComponent2, Classes } from "../../common"; | ||
import { DISPLAYNAME_PREFIX, HTMLDivProps, IProps } from "../../common/props"; | ||
|
||
export type DialogStepId = string | number; | ||
|
||
export interface IDialogStepProps extends IProps, Omit<HTMLDivProps, "id" | "title" | "onClick"> { | ||
/** | ||
* Unique identifier used to identify which step is selected. | ||
*/ | ||
id: DialogStepId; | ||
|
||
/** | ||
* Panel content, rendered by the parent `MultistepDialog` when this step is active. | ||
*/ | ||
panel: JSX.Element; | ||
|
||
/** | ||
* Space-delimited string of class names applied to multistep dialog panel container. | ||
*/ | ||
panelClassName?: string; | ||
|
||
/** | ||
* Content of step title element, rendered in a list left of the active panel. | ||
*/ | ||
title?: React.ReactNode; | ||
} | ||
|
||
@polyfill | ||
export class DialogStep extends AbstractPureComponent2<IDialogStepProps> { | ||
public static displayName = `${DISPLAYNAME_PREFIX}.DialogStep`; | ||
|
||
// this component is never rendered directly; see MultistepDialog#renderDialogStepPanel() | ||
/* istanbul ignore next */ | ||
public render() { | ||
const { className } = this.props; | ||
return ( | ||
<div className={Classes.DIALOG_STEP_CONTAINER}> | ||
<div className={classNames(Classes.DIALOG_STEP, className)} role="dialogsteplist" /> | ||
</div> | ||
); | ||
} | ||
} |
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 don't think this is strictly necessary, it can just be grayed out and have a normal pointer with no hover state. Also, what about previous steps? Can't you click on those?
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.
On further review, I realized the semantics of "active" here are a little different from what I expected. That's fine, I think what you have works. but I think it would help to leave a code comment along the lines of "by default, steps are inactive until they are visited"