From 04b2ecf65b64971cd9307dac687b9a7d5fc86790 Mon Sep 17 00:00:00 2001 From: jeroenransijn Date: Wed, 14 Feb 2018 16:21:22 -0800 Subject: [PATCH 1/8] improved dialog and docs + button loading --- docs/src/components/ComponentReadme.js | 29 ++- docs/src/components/ComponentsSidebar.js | 4 + docs/src/css/appearance-option.css | 2 +- docs/src/css/component-readme.css | 29 +-- docs/src/css/content.css | 20 ++ docs/src/css/main-layout.css | 2 +- docs/src/utils/getComponent.js | 5 +- src/buttons/docs/LoadingManager.js | 29 +++ src/buttons/docs/examples/loading.example | 13 ++ src/buttons/docs/index.js | 10 +- src/buttons/src/Button.js | 23 +++ src/buttons/stories/index.stories.js | 50 +++++ src/dialog/docs/DialogManager.js | 40 ++++ src/dialog/docs/examples/hide-header.example | 19 ++ .../docs/examples/internal-scrolling.example | 20 ++ .../primary-button-confirmation.example | 23 +++ .../docs/examples/primary-button-only.example | 20 ++ .../docs/examples/primary-button-red.example | 21 ++ .../docs/examples/primary-button.example | 20 ++ .../docs/examples/self-managed-close.example | 21 ++ .../docs/examples/without-buttons.example | 16 ++ src/dialog/docs/index.js | 183 +++++++++++++++++ src/dialog/src/Dialog.js | 155 ++++++++++++--- src/dialog/stories/index.stories.js | 187 +++++++++++++++--- src/spinner/src/Spinner.js | 13 +- src/table/docs/index.js | 20 +- 26 files changed, 857 insertions(+), 117 deletions(-) create mode 100644 src/buttons/docs/LoadingManager.js create mode 100644 src/buttons/docs/examples/loading.example create mode 100644 src/dialog/docs/DialogManager.js create mode 100644 src/dialog/docs/examples/hide-header.example create mode 100644 src/dialog/docs/examples/internal-scrolling.example create mode 100644 src/dialog/docs/examples/primary-button-confirmation.example create mode 100644 src/dialog/docs/examples/primary-button-only.example create mode 100644 src/dialog/docs/examples/primary-button-red.example create mode 100644 src/dialog/docs/examples/primary-button.example create mode 100644 src/dialog/docs/examples/self-managed-close.example create mode 100644 src/dialog/docs/examples/without-buttons.example create mode 100644 src/dialog/docs/index.js diff --git a/docs/src/components/ComponentReadme.js b/docs/src/components/ComponentReadme.js index efbec2306..c32ab2210 100644 --- a/docs/src/components/ComponentReadme.js +++ b/docs/src/components/ComponentReadme.js @@ -1,3 +1,4 @@ +/* eslint-disable react/no-danger */ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import ComponentBlock from './ComponentBlock' @@ -32,19 +33,17 @@ export default class ComponentReadme extends PureComponent {
-

{title}

-

{subTitle}

-
-
Links
-
- - GitHub - -
-
+

{title}

+

+ {subTitle}{' '} + + View on GitHub + . +

{designGuidelines && ( @@ -99,8 +98,8 @@ export default class ComponentReadme extends PureComponent {

Component Examples

- The {name} package exports the following - documented components: + The following components are exported by Evergreen for this + UI pattern:

    {components.map(component => { diff --git a/docs/src/components/ComponentsSidebar.js b/docs/src/components/ComponentsSidebar.js index 92c731427..28ebb246d 100644 --- a/docs/src/components/ComponentsSidebar.js +++ b/docs/src/components/ComponentsSidebar.js @@ -18,6 +18,10 @@ export default class ComponentsSidebar extends PureComponent { label: 'Buttons', to: '/components/buttons' }, + { + label: 'Dialog', + to: '/components/dialog' + }, { label: 'Table', to: '/components/table' diff --git a/docs/src/css/appearance-option.css b/docs/src/css/appearance-option.css index d717343f9..6cee4ceba 100644 --- a/docs/src/css/appearance-option.css +++ b/docs/src/css/appearance-option.css @@ -1,6 +1,6 @@ .AppearanceOption { background-color: white; - box-shadow: inset 0 0 0 1px var(--color-border-muted); + box-shadow: inset 0 0 0 1px var(--color-border-default); padding: 16px; margin-bottom: 16px; } diff --git a/docs/src/css/component-readme.css b/docs/src/css/component-readme.css index 806b4e8a7..ff30aa4c8 100644 --- a/docs/src/css/component-readme.css +++ b/docs/src/css/component-readme.css @@ -23,32 +23,15 @@ .ComponentReadme-header { border-bottom: 1px solid var(--neutral-20A); - /* padding-bottom: 16px; */ + padding-bottom: 16px; margin-bottom: 24px; +} - & dl { - font-size: 14px; - margin-top: 16px; - margin-bottom: px; - - & dt { - color: var(--neutral-200); - width: 72px; - display: inline-block; - } - - & dd { - width: calc(100% - 72px); - margin-left: 0; - margin-bottom: 16px; - display: inline-block; +.ComponentReadme-githubLink { + color: var(--blue-500); - & a { - &:hover { - text-decoration: underline; - } - } - } + &:hover { + text-decoration: underline; } } diff --git a/docs/src/css/content.css b/docs/src/css/content.css index acc79d988..2d3dd2645 100644 --- a/docs/src/css/content.css +++ b/docs/src/css/content.css @@ -67,14 +67,34 @@ } } + & p { + margin-top: 1em; + margin-bottom: 1em; + } + + & li { + margin-top: 0.2em; + margin-bottom: 0.2em; + } + & p, & li { font-size: 14px; font-weight: 400; line-height: 22px; letter-spacing: -0.05px; + } + + & blockquote { + font-size: 14px; + font-weight: 400; + line-height: 22px; + letter-spacing: -0.05px; margin-top: 1em; margin-bottom: 1em; + border-left: 2px solid var(--green-100A); + padding: 12px; + background-color: var(--green-7A); } & strong { diff --git a/docs/src/css/main-layout.css b/docs/src/css/main-layout.css index 3c38cbc30..f4fef5ce8 100644 --- a/docs/src/css/main-layout.css +++ b/docs/src/css/main-layout.css @@ -9,7 +9,7 @@ .MainLayout-main { flex: 1; display: flex; - background-color: var(--neutral-3); + /* background-color: var(--neutral-3); */ @media (--range-palm), (--range-hand), (--range-lap) { flex-direction: column; diff --git a/docs/src/utils/getComponent.js b/docs/src/utils/getComponent.js index 7faf9aa70..9d4ae7214 100644 --- a/docs/src/utils/getComponent.js +++ b/docs/src/utils/getComponent.js @@ -24,13 +24,14 @@ import buttonsDocs from '../../../src/buttons/docs' import tableDocs from '../../../src/table/docs/' // import sideSheetDocs from '../../src/side-sheet/docs/' // import radioDocs from '../../src/radio/docs/' -// import dialogDocs from '../../src/dialog/docs/' +import dialogDocs from '../../../src/dialog/docs/' // import cornerDialogDocs from '../../src/corner-dialog/docs/' // import alertDocs from '../../src/alert/docs/' const map = { buttons: buttonsDocs, - table: tableDocs + table: tableDocs, + dialog: dialogDocs } export default function getComponent(name) { diff --git a/src/buttons/docs/LoadingManager.js b/src/buttons/docs/LoadingManager.js new file mode 100644 index 000000000..39c2a88ac --- /dev/null +++ b/src/buttons/docs/LoadingManager.js @@ -0,0 +1,29 @@ +import React from 'react' +import PropTypes from 'prop-types' + +export default class LoadingManager extends React.PureComponent { + static propTypes = { + children: PropTypes.func + } + + state = { + isLoading: false + } + + render() { + return this.props.children({ + isLoading: this.state.isLoading, + setLoading: () => { + this.setState({ + isLoading: true + }) + + window.setTimeout(() => { + this.setState({ + isLoading: false + }) + }, 2000) + } + }) + } +} diff --git a/src/buttons/docs/examples/loading.example b/src/buttons/docs/examples/loading.example new file mode 100644 index 000000000..3baf22423 --- /dev/null +++ b/src/buttons/docs/examples/loading.example @@ -0,0 +1,13 @@ + + {({ isLoading, setLoading }) => { + return ( + + ) + }} + diff --git a/src/buttons/docs/index.js b/src/buttons/docs/index.js index bf5bdf2d8..3aab1e7a6 100644 --- a/src/buttons/docs/index.js +++ b/src/buttons/docs/index.js @@ -1,4 +1,5 @@ import React from 'react' +import LoadingManager from './LoadingManager' import { BackButton, IconButton, Button } from '..' /* eslint-disable import/no-unresolved, import/no-webpack-loader-syntax */ import sourceBackButton from '!raw-loader!../src/BackButton' @@ -10,6 +11,7 @@ import sourceButton from '!raw-loader!../src/Button' * Code examples */ import basicExample from './examples/basic.example' +import loadingExample from './examples/loading.example' import basicWithIconsExample from './examples/basic-with-icons.example' import backButtonExample from './examples/back-button.example' import triangleExample from './examples/triangle.example' @@ -17,7 +19,7 @@ import arrowExample from './examples/arrow.example' import iconButtonBasicExample from './examples/icon-button-basic.example' const title = 'Buttons' -const subTitle = 'A package exporting multiple types of buttons.' +const subTitle = 'A set of buttons with multiple appearances.' const designGuidelines = (
    @@ -129,6 +131,11 @@ const components = [ codeText: basicExample, scope: { Button } }, + { + title: 'Loading button', + codeText: loadingExample, + scope: { Button, LoadingManager } + }, { title: 'Buttons with an icon', codeText: basicWithIconsExample, @@ -136,6 +143,7 @@ const components = [ } ] }, + { name: 'BackButton', source: sourceBackButton, diff --git a/src/buttons/src/Button.js b/src/buttons/src/Button.js index 2bf9ea383..25300a1be 100644 --- a/src/buttons/src/Button.js +++ b/src/buttons/src/Button.js @@ -7,6 +7,7 @@ import { getTextStyleForControlHeight, getIconSizeForControlHeight } from '../../shared-styles' +import { Spinner } from '../../spinner' import ButtonAppearances from './styles/ButtonAppearances' export default class Button extends PureComponent { @@ -21,6 +22,12 @@ export default class Button extends PureComponent { */ appearance: PropTypes.oneOf(Object.keys(ButtonAppearances)).isRequired, + /** + * When true, show a loading spinner before the children. + * This also disables the button. + */ + isLoading: PropTypes.bool, + /** * Forcefully set the active state of a button. * Useful in conjuction with a Popover. @@ -47,6 +54,12 @@ export default class Button extends PureComponent { */ iconAfterAim: PropTypes.oneOf(Object.keys(IconAim)), + /** + * When true, the button is disabled. + * isLoading also sets the button to disabled. + */ + disabled: PropTypes.bool, + /** * A JavaScript object to override css styling */ @@ -77,7 +90,9 @@ export default class Button extends PureComponent { height, isActive, children, + disabled, appearance, + isLoading, // Paddings paddingRight, @@ -145,7 +160,15 @@ export default class Button extends PureComponent { lineHeight={`${height}px`} {...(isActive ? { 'data-active': true } : {})} {...props} + disabled={disabled || isLoading} > + {isLoading && ( + + )} {iconBefore || null} {children} {iconAfter || null} diff --git a/src/buttons/stories/index.stories.js b/src/buttons/stories/index.stories.js index a5d872c7c..19fdd788a 100644 --- a/src/buttons/stories/index.stories.js +++ b/src/buttons/stories/index.stories.js @@ -154,6 +154,56 @@ buttonsStory.add('Button + icons', () => ( )) +class LoadingManager extends React.PureComponent { + static propTypes = { + children: PropTypes.func + } + + state = { + isLoading: false + } + + render() { + return this.props.children({ + isLoading: this.state.isLoading, + setLoading: () => { + this.setState({ + isLoading: true + }) + + window.setTimeout(() => { + this.setState({ + isLoading: false + }) + }, 2000) + } + }) + } +} + +buttonsStory.add('Button isLoading', () => ( + + {Object.keys(ButtonAppearances).map(appearance => { + return ( + + {({ isLoading, setLoading }) => { + return ( + + ) + }} + + ) + })} + +)) + function IconButtonIcon({ appearance, height, iconKey }) { const iconProps = { appearance, diff --git a/src/dialog/docs/DialogManager.js b/src/dialog/docs/DialogManager.js new file mode 100644 index 000000000..7a7897514 --- /dev/null +++ b/src/dialog/docs/DialogManager.js @@ -0,0 +1,40 @@ +import React from 'react' +import PropTypes from 'prop-types' + +export default class DialogManager extends React.PureComponent { + static propTypes = { + children: PropTypes.func + } + + state = { + isShown: false, + isLoading: false + } + + render() { + return this.props.children({ + isShown: this.state.isShown, + isLoading: this.state.isLoading, + confirmLoading: () => { + this.setState({ + isLoading: true + }) + + window.setTimeout(() => { + this.setState({ + isShown: false + }) + }, 2000) + }, + show: () => + this.setState({ + isShown: true + }), + hide: () => + this.setState({ + isShown: false, + isLoading: false + }) + }) + } +} diff --git a/src/dialog/docs/examples/hide-header.example b/src/dialog/docs/examples/hide-header.example new file mode 100644 index 000000000..f6c599e35 --- /dev/null +++ b/src/dialog/docs/examples/hide-header.example @@ -0,0 +1,19 @@ + + {({ isShown, show, hide }) => ( + + + {({ close }) => ( + + + Manage your own header, buttons and interactions. + + + + )} + + + + )} + diff --git a/src/dialog/docs/examples/internal-scrolling.example b/src/dialog/docs/examples/internal-scrolling.example new file mode 100644 index 000000000..3a4048a23 --- /dev/null +++ b/src/dialog/docs/examples/internal-scrolling.example @@ -0,0 +1,20 @@ + + {({ isShown, show, hide }) => ( + + { + close() + }, + children: 'Primary Button', + }} + > + + + + + )} + diff --git a/src/dialog/docs/examples/primary-button-confirmation.example b/src/dialog/docs/examples/primary-button-confirmation.example new file mode 100644 index 000000000..5ea5e1b15 --- /dev/null +++ b/src/dialog/docs/examples/primary-button-confirmation.example @@ -0,0 +1,23 @@ + + {({ isShown, isLoading, confirmLoading, show, hide }) => ( + + + + This is useful when you need to process something before closing + the dialog. + + + + + )} + diff --git a/src/dialog/docs/examples/primary-button-only.example b/src/dialog/docs/examples/primary-button-only.example new file mode 100644 index 000000000..7e493dd5f --- /dev/null +++ b/src/dialog/docs/examples/primary-button-only.example @@ -0,0 +1,20 @@ + + {({ isShown, show, hide }) => ( + + + + This is useful for product updates and onboarding content. + + + + + )} + diff --git a/src/dialog/docs/examples/primary-button-red.example b/src/dialog/docs/examples/primary-button-red.example new file mode 100644 index 000000000..6d135eaee --- /dev/null +++ b/src/dialog/docs/examples/primary-button-red.example @@ -0,0 +1,21 @@ + + {({ isShown, show, hide }) => ( + + { + close() + }, + appearance: 'red', + children: 'Primary Button', + }} + > + Dialog content + + + + )} + diff --git a/src/dialog/docs/examples/primary-button.example b/src/dialog/docs/examples/primary-button.example new file mode 100644 index 000000000..16e5597e8 --- /dev/null +++ b/src/dialog/docs/examples/primary-button.example @@ -0,0 +1,20 @@ + + {({ isShown, show, hide }) => ( + + { + close() + }, + children: 'Primary Button', + }} + > + Dialog content. + + + + )} + diff --git a/src/dialog/docs/examples/self-managed-close.example b/src/dialog/docs/examples/self-managed-close.example new file mode 100644 index 000000000..823886154 --- /dev/null +++ b/src/dialog/docs/examples/self-managed-close.example @@ -0,0 +1,21 @@ + + {({ isShown, show, hide }) => ( + + + {({ close }) => ( + + Manage Your Own Buttons and Interactions. + + + )} + + + + )} + diff --git a/src/dialog/docs/examples/without-buttons.example b/src/dialog/docs/examples/without-buttons.example new file mode 100644 index 000000000..b1d314d73 --- /dev/null +++ b/src/dialog/docs/examples/without-buttons.example @@ -0,0 +1,16 @@ + + {({ isShown, show, hide }) => ( + + + + Manage your own buttons and interactions. + + + + + )} + diff --git a/src/dialog/docs/index.js b/src/dialog/docs/index.js new file mode 100644 index 000000000..8ee633e1a --- /dev/null +++ b/src/dialog/docs/index.js @@ -0,0 +1,183 @@ +import React from 'react' +import Box from 'ui-box' +import Dialog from '../src/Dialog' +import { Button } from '../../buttons' +import { Paragraph } from '../../typography' +import DialogManager from './DialogManager' + +/* eslint-disable import/no-unresolved, import/no-webpack-loader-syntax */ +import sourceDialog from '!raw-loader!../src/Dialog' +/* eslint-enable import/no-unresolved, import/no-webpack-loader-syntax */ + +/** + * Code examples + */ +import examplePrimaryButton from './examples/primary-button.example' +import examplePrimaryButtonRed from './examples/primary-button-red.example' +import examplePrimaryButtonOnly from './examples/primary-button-only.example' +import examplePrimaryButtonConfirmation from './examples/primary-button-confirmation.example' +import exampleWithoutButtons from './examples/without-buttons.example' +import exampleSelfManagedClose from './examples/self-managed-close.example' +import exampleHideHeader from './examples/hide-header.example' +import exampleInternalScrolling from './examples/internal-scrolling.example' + +const title = 'Dialog' +const subTitle = 'A component that displays content on top of an overlay.' + +const designGuidelines = ( +
    +

    + The Dialog component is used to show content on top of an + overlay. It blocks any interaction with the page — until the overlay + is clicked, or a close action is triggered. +

    +

    When To Use

    +

    + When you require your user to interact with you app, but don’t want + your users to jump to a different page and break their workflow. +

    +

    + You should also use a dialog in cases where you need to ask for + confirmation from the user before doing a lengthy or dangerous action. + This could be a deletion of some sorts or initiating a lengthy download. +

    +

    Terminology

    +

    + + BlueprintJS + {' '} + pointed out in their documentation that “modal” is a misnomer + for “dialog”. +

    +
    + The term “modal” is sometimes used to mean + “dialog”, but this is a misnomer. Modal is an adjective that + describes parts of a UI. An element is considered modal if it{' '} + + blocks interaction with the rest of the application + . We use the term “dialog” to avoid confusion with the + adjective. +
    +
    +) + +const appearanceOptions = null + +const scope = { + Box, + Dialog, + DialogManager, + Paragraph, + Button +} + +const components = [ + { + name: 'Dialog', + source: sourceDialog, + description: ( +

    + This is the component responsible for all interactions and properties. +

    + ), + examples: [ + { + title: 'Primary button and cancel button', + description: ( +

    + By passing in the primary button, the cancel button also shows. + Primary button is an object which is passed through to the{' '} + Button component. +

    + ), + codeText: examplePrimaryButton, + scope + }, + { + title: 'Primary button with a custom appearance', + description: ( +

    + You can pass all properties through to the primary button. In this + example the red appearance is passed. +

    + ), + codeText: examplePrimaryButtonRed, + scope + }, + { + title: 'Primary button with loading confirmation', + description: ( +

    + You can pass all properties through to the primary button. Including + the isLoading prop. +

    + ), + codeText: examplePrimaryButtonConfirmation, + scope + }, + { + title: 'Primary button only', + description: ( +

    Hide the cancel button, useful in onboarding dialogs.

    + ), + codeText: examplePrimaryButtonOnly, + scope + }, + { + title: 'Internal scrolling', + description: ( +

    + When you pass in content that is greater than the available space, + the content area will become scrollable. It will add a symmetric + offset on the top and bottom — based on the topOffset{' '} + prop. +

    + ), + codeText: exampleInternalScrolling, + scope + }, + { + title: 'Without buttons', + description: ( +

    + If you don’t pass the primaryButton prop — you + wont’t see any footer at all. Clicks on the overlay will still + close your dialog. +

    + ), + codeText: exampleWithoutButtons, + scope + }, + { + title: 'Self managed close', + description: ( +

    + Pass in a function as children to accept a close{' '} + function you can use to manually close your dialog. +

    + ), + codeText: exampleSelfManagedClose, + scope + }, + { + title: 'Hidden header', + description: ( +

    + Hide the header by passing the hideHeader prop. This + will hide both the close icon button as the title. +

    + ), + codeText: exampleHideHeader, + scope + } + ] + } +] + +export default { + title, + subTitle, + designGuidelines, + appearanceOptions, + components +} diff --git a/src/dialog/src/Dialog.js b/src/dialog/src/Dialog.js index a974214c0..b88b965e6 100644 --- a/src/dialog/src/Dialog.js +++ b/src/dialog/src/Dialog.js @@ -4,7 +4,7 @@ import { css } from 'ui-box' import { Pane } from '../../layers' import { Heading } from '../../typography' import { Overlay } from '../../overlay' -import { IconButton } from '../../buttons' +import { Button, IconButton } from '../../buttons' const animationEasing = { deceleration: `cubic-bezier(0.0, 0.0, 0.2, 1)`, @@ -50,28 +50,88 @@ const animationStyles = { class Dialog extends React.Component { static propTypes = { + /** + * Composes the Overlay component as the base. + */ ...Overlay.propTypes, + + /** + * Children can be a node or a function accepting `({ close })`. + * See an example to understand how this works. + */ + children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]), + + /** + * Title of the Dialog. Titles should use Title Case. + */ title: PropTypes.node, + + /** + * Props passed through to the primary button. + * Passing this object will show the button and cancel button. + * You should pass `children` and `onClick`. + */ + primaryButton: PropTypes.object, + + /** + * Label of the cancel button, shown when primaryButton is passed. + * You should not have to change this in most cases. + */ + cancelLabel: PropTypes.node, + + /** + * Only effective when when passing primaryButton. + */ + hideCancelButton: PropTypes.bool, + + /** + * Width of the Dialog. + */ width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - hasCloseIcon: PropTypes.bool, + + /** + * The space above the Dialog. + * This offset is also used at the bottom when there is not enough space + * available on screen — and the Dialog scrolls internally. + */ + topOffset: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + + /** + * The min height of the body content. + * Makes it less weird when only showing little content. + */ + minHeightContent: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + + /** + * When true, hide the header containing the title and close button. + */ + hideHeader: PropTypes.bool, + + /** + * Props that are passed to the Dialog container. + */ containerProps: PropTypes.object } static defaultProps = { - width: 567, - height: 240, - hasCloseIcon: true + width: 560, + topOffset: '12vh', + minHeightContent: 80, + cancelLabel: 'Cancel' } render() { const { - children, + title, width, - height, - hasCloseIcon, + children, + topOffset, + hideHeader, + cancelLabel, + primaryButton, + minHeightContent, + hideCancelButton, containerProps, - title, ...props } = this.props @@ -81,8 +141,8 @@ class Dialog extends React.Component { + {!hideHeader && ( + + + {title} + + + + )} + - - {title} - - {hasCloseIcon && ( - - )} - + + {typeof children === 'function' + ? children({ + close + }) + : children} + - - {typeof children === 'function' - ? children({ - close - }) - : children} + {primaryButton && ( + + + )} + + )} diff --git a/src/dialog/stories/index.stories.js b/src/dialog/stories/index.stories.js index 7c5c69b3c..3a0586b99 100644 --- a/src/dialog/stories/index.stories.js +++ b/src/dialog/stories/index.stories.js @@ -1,34 +1,11 @@ import { storiesOf } from '@storybook/react' -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' +import React from 'react' import Box from 'ui-box' +import DialogManager from '../docs/DialogManager' +import { Paragraph } from '../../typography' import { Dialog } from '../../dialog' import { Button } from '../../buttons' -class DialogManager extends PureComponent { - static propTypes = { - children: PropTypes.func - } - - state = { - isShown: true - } - - render() { - return this.props.children({ - isShown: this.state.isShown, - show: () => - this.setState({ - isShown: true - }), - hide: () => - this.setState({ - isShown: false - }) - }) - } -} - storiesOf('dialog', module).add('Dialog', () => ( {(() => { @@ -37,11 +14,161 @@ storiesOf('dialog', module).add('Dialog', () => ( })()} {({ isShown, show, hide }) => ( - - - Dialog content + + { + close() + }, + children: 'Primary Button' + }} + > + Dialog content + + + + )} + + + {({ isShown, show, hide }) => ( + + { + close() + }, + appearance: 'red', + children: 'Primary Button' + }} + > + Dialog content + + + + )} + + + {({ isShown, isLoading, confirmLoading, show, hide }) => ( + + + + This is useful when you need to process something before closing + the dialog. + + + + + )} + + + {({ isShown, show, hide }) => ( + + + + This is useful for product updates and onboarding content. + + + + + )} + + + {({ isShown, show, hide }) => ( + + + + Manage your own buttons and interactions. + + + + + )} + + + {({ isShown, show, hide }) => ( + + + {({ close }) => ( + + Manage Your Own Buttons and Interactions. + + + )} + + + + )} + + + {({ isShown, show, hide }) => ( + + + {({ close }) => ( + + + Manage your own header, buttons and interactions. + + + + )} + + + + )} + + + {({ isShown, show, hide }) => ( + + { + close() + }, + children: 'Primary Button' + }} + > + - + )} diff --git a/src/spinner/src/Spinner.js b/src/spinner/src/Spinner.js index 359bd4296..4aa5271d8 100644 --- a/src/spinner/src/Spinner.js +++ b/src/spinner/src/Spinner.js @@ -22,7 +22,7 @@ const loadingCircleKeyframes = css.keyframes('loading-circle', { }) const outer = { - animation: `${loadingKeyframes} 3s linear infinite` + animation: `${loadingKeyframes} 2s linear infinite` } const inner = { @@ -31,14 +31,21 @@ const inner = { strokeWidth: 12, strokeMiterlimit: 10, strokeLinecap: 'round', - animation: `${loadingCircleKeyframes} 2s cubic-bezier(0.4, 0.15, 0.6, 0.85) infinite`, + animation: `${loadingCircleKeyframes} 1.6s cubic-bezier(0.4, 0.15, 0.6, 0.85) infinite`, stroke: colors.neutral['500'], fill: 'transparent' } export default class Spinner extends PureComponent { static propTypes = { + /** + * Composes the Box component as the base. + */ ...Box.propTypes, + + /** + * The size of the spinner. + */ size: PropTypes.number } @@ -49,7 +56,7 @@ export default class Spinner extends PureComponent { render() { const { size, ...props } = this.props return ( - + diff --git a/src/table/docs/index.js b/src/table/docs/index.js index e652a9964..ed1911e9a 100644 --- a/src/table/docs/index.js +++ b/src/table/docs/index.js @@ -37,33 +37,29 @@ import exampleTableBody from './examples/TableBody.example' import exampleTableHead from './examples/TableHead.example' const title = 'Table' -const subTitle = 'A package exporting the building blocks of a table.' +const subTitle = 'A set of components for building a table.' const designGuidelines = (

    - This package exports the building blocks for tables. This package is also - used in places such as the options list in the SelectMenu{' '} - component. Currently this package does not use real tables under the hood. - There is a{' '} - - discussion on GitHub - {' '} - going on to potentially change this in the future. + Evergreen exports a set of building blocks for building tables. This + package is also used in places such as the options list in the{' '} + SelectMenu component. Currently this package does not use + real tables under the hood.

    Implementation details

    • None of these components implement HTML table elements such as: {` `} - table, th or tr + table, th or tr.
    • Most components are basic Pane components combined with {` `} - Text + Text.
    • -
    • All components are presentational, no sorting build in
    • +
    • All components are presentational, no sorting build in.
    ) From 994caecb41982c43a614651a15cf43d5580a5c98 Mon Sep 17 00:00:00 2001 From: jeroenransijn Date: Wed, 14 Feb 2018 18:20:00 -0800 Subject: [PATCH 2/8] fixes --- docs/src/components/ComponentReadme.js | 1 - docs/src/css/component-readme.css | 4 ++++ docs/src/css/content.css | 5 +++++ docs/src/css/main-layout.css | 1 - docs/src/css/nav-group.css | 4 ++++ docs/src/css/top-bar.css | 6 +++++- src/buttons/docs/LoadingManager.js | 24 ++++++++++++---------- src/buttons/stories/index.stories.js | 28 +------------------------- src/dialog/docs/index.js | 23 ++++++++++----------- src/dialog/src/Dialog.js | 13 +++++++++--- 10 files changed, 53 insertions(+), 56 deletions(-) diff --git a/docs/src/components/ComponentReadme.js b/docs/src/components/ComponentReadme.js index c32ab2210..14335d9f7 100644 --- a/docs/src/components/ComponentReadme.js +++ b/docs/src/components/ComponentReadme.js @@ -1,4 +1,3 @@ -/* eslint-disable react/no-danger */ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import ComponentBlock from './ComponentBlock' diff --git a/docs/src/css/component-readme.css b/docs/src/css/component-readme.css index ff30aa4c8..07a682aff 100644 --- a/docs/src/css/component-readme.css +++ b/docs/src/css/component-readme.css @@ -33,6 +33,10 @@ &:hover { text-decoration: underline; } + + &:focus { + outline: 1px solid var(--blue-500); + } } /** diff --git a/docs/src/css/content.css b/docs/src/css/content.css index 2d3dd2645..d838555be 100644 --- a/docs/src/css/content.css +++ b/docs/src/css/content.css @@ -14,9 +14,14 @@ & a { color: var(--blue-500); + &:hover { text-decoration: underline; } + + &:focus { + outline: 1px solid var(--blue-500); + } } & h1 { diff --git a/docs/src/css/main-layout.css b/docs/src/css/main-layout.css index f4fef5ce8..39b2f7aae 100644 --- a/docs/src/css/main-layout.css +++ b/docs/src/css/main-layout.css @@ -9,7 +9,6 @@ .MainLayout-main { flex: 1; display: flex; - /* background-color: var(--neutral-3); */ @media (--range-palm), (--range-hand), (--range-lap) { flex-direction: column; diff --git a/docs/src/css/nav-group.css b/docs/src/css/nav-group.css index b11adb1b5..35f9499ae 100644 --- a/docs/src/css/nav-group.css +++ b/docs/src/css/nav-group.css @@ -12,6 +12,10 @@ background-color: var(--neutral-5A); } + &:focus { + box-shadow: inset 0 0 0 1px var(--blue-100A); + } + &:active, &.is-active { background-color: var(--blue-10A); diff --git a/docs/src/css/top-bar.css b/docs/src/css/top-bar.css index b0da351b1..8cb9ce575 100644 --- a/docs/src/css/top-bar.css +++ b/docs/src/css/top-bar.css @@ -46,10 +46,10 @@ display: inline-flex; align-items: center; letter-spacing: 0.4px; + border-radius: 3px; &:hover { background-color: var(--neutral-7A); - border-radius: 3px; } &:active, @@ -58,6 +58,10 @@ color: var(--blue-500); } + &:focus { + box-shadow: inset 0 0 0 1px var(--blue-100A); + } + & .icon-holder { width: 16px; height: 16px; diff --git a/src/buttons/docs/LoadingManager.js b/src/buttons/docs/LoadingManager.js index 39c2a88ac..bff3feccf 100644 --- a/src/buttons/docs/LoadingManager.js +++ b/src/buttons/docs/LoadingManager.js @@ -10,20 +10,22 @@ export default class LoadingManager extends React.PureComponent { isLoading: false } + setLoading = () => { + this.setState({ + isLoading: true + }) + + window.setTimeout(() => { + this.setState({ + isLoading: false + }) + }, 2000) + } + render() { return this.props.children({ isLoading: this.state.isLoading, - setLoading: () => { - this.setState({ - isLoading: true - }) - - window.setTimeout(() => { - this.setState({ - isLoading: false - }) - }, 2000) - } + setLoading: this.setLoading }) } } diff --git a/src/buttons/stories/index.stories.js b/src/buttons/stories/index.stories.js index 19fdd788a..a8de87ee6 100644 --- a/src/buttons/stories/index.stories.js +++ b/src/buttons/stories/index.stories.js @@ -10,6 +10,7 @@ import { } from '../../buttons' import { Heading } from '../../typography' import { IconMap } from '../../icons' +import LoadingManager from '../docs/LoadingManager' const baseStyles = { margin: 16 @@ -154,33 +155,6 @@ buttonsStory.add('Button + icons', () => (
    )) -class LoadingManager extends React.PureComponent { - static propTypes = { - children: PropTypes.func - } - - state = { - isLoading: false - } - - render() { - return this.props.children({ - isLoading: this.state.isLoading, - setLoading: () => { - this.setState({ - isLoading: true - }) - - window.setTimeout(() => { - this.setState({ - isLoading: false - }) - }, 2000) - } - }) - } -} - buttonsStory.add('Button isLoading', () => ( {Object.keys(ButtonAppearances).map(appearance => { diff --git a/src/dialog/docs/index.js b/src/dialog/docs/index.js index 8ee633e1a..0b36ffd96 100644 --- a/src/dialog/docs/index.js +++ b/src/dialog/docs/index.js @@ -33,8 +33,8 @@ const designGuidelines = (

    When To Use

    - When you require your user to interact with you app, but don’t want - your users to jump to a different page and break their workflow. + When you require your user to interact with you app, but don’t want your + users to jump to a different page and break their workflow.

    You should also use a dialog in cases where you need to ask for @@ -46,17 +46,16 @@ const designGuidelines = ( BlueprintJS {' '} - pointed out in their documentation that “modal” is a misnomer - for “dialog”. + pointed out in their documentation that “modal” is a misnomer for + “dialog”.

    - The term “modal” is sometimes used to mean - “dialog”, but this is a misnomer. Modal is an adjective that - describes parts of a UI. An element is considered modal if it{' '} + The term “modal” is sometimes used to mean “dialog”, but this is a + misnomer. Modal is an adjective that describes parts of a UI. An element + is considered modal if it{' '} blocks interaction with the rest of the application - . We use the term “dialog” to avoid confusion with the - adjective. + . We use the term “dialog” to avoid confusion with the adjective.
    ) @@ -140,9 +139,9 @@ const components = [ title: 'Without buttons', description: (

    - If you don’t pass the primaryButton prop — you - wont’t see any footer at all. Clicks on the overlay will still - close your dialog. + If you don’t pass the primaryButton prop — you wont’t + see any footer at all. Clicks on the overlay will still close your + dialog.

    ), codeText: exampleWithoutButtons, diff --git a/src/dialog/src/Dialog.js b/src/dialog/src/Dialog.js index b88b965e6..7fd192671 100644 --- a/src/dialog/src/Dialog.js +++ b/src/dialog/src/Dialog.js @@ -59,7 +59,7 @@ class Dialog extends React.Component { * Children can be a node or a function accepting `({ close })`. * See an example to understand how this works. */ - children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]), + children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired, /** * Title of the Dialog. Titles should use Title Case. @@ -135,6 +135,13 @@ class Dialog extends React.Component { ...props } = this.props + let maxHeight + if (Number.isInteger(topOffset)) { + maxHeight = `calc(100% - ${topOffset}px - ${topOffset}px)` + } else { + maxHeight = `calc(100% - ${topOffset} - ${topOffset})` + } + return ( {({ state, close }) => ( @@ -142,7 +149,7 @@ class Dialog extends React.Component { display="flex" justifyContent="center" paddingTop={topOffset} - maxHeight={`calc(100% - ${topOffset} - ${topOffset})`} + maxHeight={maxHeight} > - {hideCancelButton ? null : ( + {!hideCancelButton && ( )} From b7409dd9ff917a2053fcb1d8020f7405a2b743ef Mon Sep 17 00:00:00 2001 From: jeroenransijn Date: Wed, 14 Feb 2018 18:28:02 -0800 Subject: [PATCH 3/8] fix build --- docs/gatsby-node.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/gatsby-node.js b/docs/gatsby-node.js index ad4cb4a04..1fd82947a 100644 --- a/docs/gatsby-node.js +++ b/docs/gatsby-node.js @@ -1,18 +1,15 @@ const path = require('path') const webpack = require('webpack') // eslint-disable-line import/no-extraneous-dependencies -const globby = require('globby') const componentTemplate = path.resolve(`src/templates/component.js`) -const componentNames = globby - .sync(`${__dirname}/../src/*/`, { nodir: false }) - .map(pathname => path.basename(pathname)) +const componentNames = ['buttons', 'dialog', 'table'] // Implement the Gatsby API “createPages”. This is called once the // data layer is bootstrapped to let plugins create pages from data. exports.createPages = ({ boundActionCreators }) => { const { createPage } = boundActionCreators - for (const componentName of componentNames) { + componentNames.forEach(componentName => { const componentPath = `/components/${componentName}` createPage({ @@ -27,7 +24,7 @@ exports.createPages = ({ boundActionCreators }) => { name: componentName } }) - } + }) } exports.modifyWebpackConfig = ({ config }) => { From bd184c350ce26554e989509903cf627628fc7a5f Mon Sep 17 00:00:00 2001 From: jeroenransijn Date: Thu, 15 Feb 2018 13:15:55 -0800 Subject: [PATCH 4/8] more explicit API --- docs/src/components/prop-types-table/index.js | 26 +-- src/dialog/docs/examples/hide-header.example | 7 +- .../docs/examples/internal-scrolling.example | 8 +- .../primary-button-confirmation.example | 13 +- .../docs/examples/primary-button-only.example | 10 +- .../docs/examples/primary-button-red.example | 15 +- .../docs/examples/primary-button.example | 15 +- .../docs/examples/self-managed-close.example | 3 +- .../docs/examples/without-buttons.example | 3 +- src/dialog/docs/index.js | 58 +++---- src/dialog/src/Dialog.js | 157 +++++++++++++----- src/dialog/stories/index.stories.js | 70 ++++---- 12 files changed, 220 insertions(+), 165 deletions(-) diff --git a/docs/src/components/prop-types-table/index.js b/docs/src/components/prop-types-table/index.js index 97a585253..f5fd65e4c 100644 --- a/docs/src/components/prop-types-table/index.js +++ b/docs/src/components/prop-types-table/index.js @@ -31,23 +31,23 @@ export default class PropTypesTable extends PureComponent { render() { const { componentDocs } = this.state const propTypes = Object.keys(componentDocs.props) - console.log('componentDocs', componentDocs) return (

    Props

    - {componentDocs.composes.length > 0 && ( -
    -

    - This component composes - {componentDocs.composes.map(filePath => ( - - {filePath.substring(filePath.indexOf('/') + 1)} - - ))} -

    -
    - )} + {componentDocs.composes && + componentDocs.composes.length > 0 && ( +
    +

    + This component composes + {componentDocs.composes.map(filePath => ( + + {filePath.substring(filePath.indexOf('/') + 1)} + + ))} +

    +
    + )}
    {propTypes.map(propName => { diff --git a/src/dialog/docs/examples/hide-header.example b/src/dialog/docs/examples/hide-header.example index f6c599e35..fc155ffc8 100644 --- a/src/dialog/docs/examples/hide-header.example +++ b/src/dialog/docs/examples/hide-header.example @@ -1,7 +1,12 @@ {({ isShown, show, hide }) => ( - + {({ close }) => ( diff --git a/src/dialog/docs/examples/internal-scrolling.example b/src/dialog/docs/examples/internal-scrolling.example index 3a4048a23..db1ff8d48 100644 --- a/src/dialog/docs/examples/internal-scrolling.example +++ b/src/dialog/docs/examples/internal-scrolling.example @@ -4,13 +4,7 @@ { - close() - }, - children: 'Primary Button', - }} + onCloseComplete={hide} > diff --git a/src/dialog/docs/examples/primary-button-confirmation.example b/src/dialog/docs/examples/primary-button-confirmation.example index 5ea5e1b15..2c02b299e 100644 --- a/src/dialog/docs/examples/primary-button-confirmation.example +++ b/src/dialog/docs/examples/primary-button-confirmation.example @@ -3,14 +3,11 @@ This is useful when you need to process something before closing diff --git a/src/dialog/docs/examples/primary-button-only.example b/src/dialog/docs/examples/primary-button-only.example index 7e493dd5f..960f7e484 100644 --- a/src/dialog/docs/examples/primary-button-only.example +++ b/src/dialog/docs/examples/primary-button-only.example @@ -3,12 +3,10 @@ This is useful for product updates and onboarding content. diff --git a/src/dialog/docs/examples/primary-button-red.example b/src/dialog/docs/examples/primary-button-red.example index 6d135eaee..7011694a5 100644 --- a/src/dialog/docs/examples/primary-button-red.example +++ b/src/dialog/docs/examples/primary-button-red.example @@ -3,19 +3,14 @@ { - close() - }, - appearance: 'red', - children: 'Primary Button', - }} + title="Dialog with Danger Intent" + onCloseComplete={hide} + intent="danger" + confirmLabel="Dangerous Action" > Dialog content - + )} diff --git a/src/dialog/docs/examples/primary-button.example b/src/dialog/docs/examples/primary-button.example index 16e5597e8..e98441520 100644 --- a/src/dialog/docs/examples/primary-button.example +++ b/src/dialog/docs/examples/primary-button.example @@ -3,18 +3,13 @@ { - close() - }, - children: 'Primary Button', - }} + title="Dialog Title" + onCloseComplete={hide} + confirmLabel="Custom Label" > - Dialog content. + Dialog content - + )} diff --git a/src/dialog/docs/examples/self-managed-close.example b/src/dialog/docs/examples/self-managed-close.example index 823886154..6b0824edd 100644 --- a/src/dialog/docs/examples/self-managed-close.example +++ b/src/dialog/docs/examples/self-managed-close.example @@ -4,7 +4,8 @@ {({ close }) => ( diff --git a/src/dialog/docs/examples/without-buttons.example b/src/dialog/docs/examples/without-buttons.example index b1d314d73..9b6b31bab 100644 --- a/src/dialog/docs/examples/without-buttons.example +++ b/src/dialog/docs/examples/without-buttons.example @@ -4,7 +4,8 @@ Manage your own buttons and interactions. diff --git a/src/dialog/docs/index.js b/src/dialog/docs/index.js index 0b36ffd96..3b97a474f 100644 --- a/src/dialog/docs/index.js +++ b/src/dialog/docs/index.js @@ -81,88 +81,90 @@ const components = [ ), examples: [ { - title: 'Primary button and cancel button', + title: 'Default Behavior', description: (

    - By passing in the primary button, the cancel button also shows. - Primary button is an object which is passed through to the{' '} - Button component. + The default behavior of the dialog is to show a header with a title + and close button —  and a footer with a confirm and cancel button.

    ), codeText: examplePrimaryButton, scope }, { - title: 'Primary button with a custom appearance', + title: 'Dialog with a Danger Intent', description: (

    - You can pass all properties through to the primary button. In this - example the red appearance is passed. + The intent prop determines the appearance of the confirm button. + danger is red. In the future, more intent types might + be added.

    ), codeText: examplePrimaryButtonRed, scope }, { - title: 'Primary button with loading confirmation', + title: 'Confirm Button with Loading Confirmation', description: (

    - You can pass all properties through to the primary button. Including - the isLoading prop. + Pass the isConfirmLoading to set the loading state on + the confirm button.

    ), codeText: examplePrimaryButtonConfirmation, scope }, { - title: 'Primary button only', + title: 'Confirm Button Only', description: ( -

    Hide the cancel button, useful in onboarding dialogs.

    +

    + Sometimes you only need a confirm button and not a cancel button. + For example in onboarding use cases. +

    ), codeText: examplePrimaryButtonOnly, scope }, { - title: 'Internal scrolling', + title: 'Internal Scrolling', description: (

    - When you pass in content that is greater than the available space, - the content area will become scrollable. It will add a symmetric - offset on the top and bottom — based on the topOffset{' '} - prop. + When content makes the dialog height greater than the available + space in the viewport, the content area will become scrollable. It + will add a symmetric offset on the top and bottom — based on the{' '} + topOffset prop.

    ), codeText: exampleInternalScrolling, scope }, { - title: 'Without buttons', + title: 'Self Managed Close', description: (

    - If you don’t pass the primaryButton prop — you wont’t - see any footer at all. Clicks on the overlay will still close your - dialog. + Pass in a function as children to accept a close{' '} + function you can use to manually close your dialog.

    ), - codeText: exampleWithoutButtons, + codeText: exampleSelfManagedClose, scope }, { - title: 'Self managed close', + title: 'Without Footer', description: (

    - Pass in a function as children to accept a close{' '} - function you can use to manually close your dialog. + Use the hasFooter props to show or hide the footer. + This will hide the confirm and cancel buttons.

    ), - codeText: exampleSelfManagedClose, + codeText: exampleWithoutButtons, scope }, { - title: 'Hidden header', + title: 'Without Header', description: (

    - Hide the header by passing the hideHeader prop. This + Use the hasHeader props to show or hide the heaer. This will hide both the close icon button as the title.

    ), diff --git a/src/dialog/src/Dialog.js b/src/dialog/src/Dialog.js index 7fd192671..d2f278bcf 100644 --- a/src/dialog/src/Dialog.js +++ b/src/dialog/src/Dialog.js @@ -50,39 +50,94 @@ const animationStyles = { class Dialog extends React.Component { static propTypes = { - /** - * Composes the Overlay component as the base. - */ - ...Overlay.propTypes, - /** * Children can be a node or a function accepting `({ close })`. * See an example to understand how this works. */ children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired, + /** + * When true, the dialog is shown. + */ + isShown: PropTypes.bool, + /** * Title of the Dialog. Titles should use Title Case. */ title: PropTypes.node, /** - * Props passed through to the primary button. - * Passing this object will show the button and cancel button. - * You should pass `children` and `onClick`. + * When true, the header with the title and close icon button is shown. */ - primaryButton: PropTypes.object, + hasHeader: PropTypes.bool, /** - * Label of the cancel button, shown when primaryButton is passed. - * You should not have to change this in most cases. + * When true, the footer with the cancel and confirm button is shown. */ - cancelLabel: PropTypes.node, + hasFooter: PropTypes.bool, + + /** + * When true, the cancel button is shown. + */ + hasCancel: PropTypes.bool, /** - * Only effective when when passing primaryButton. + * Function that will be called when the exit transition is complete. */ - hideCancelButton: PropTypes.bool, + onCloseComplete: PropTypes.func, + + /** + * Function that will be called when the enter transition is complete. + */ + onOpenComplete: PropTypes.func, + + /** + * Function that will be called when the confirm button is clicked. + * This does not close the Dialog. A close function will be passed + * as a paramater you can use to close the dialog. + * + * `onConfirm={(close) => close()}` + */ + onConfirm: PropTypes.func, + + /** + * Label that is used inside of the confirm button. + */ + confirmLabel: PropTypes.string, + + /** + * The intent of the message. + */ + intent: PropTypes.oneOf(['neutral', 'danger']), + + /** + * When true, the confirm button is set to loading. + */ + isConfirmLoading: PropTypes.bool, + + /** + * When true, the confirm button is set to disabled. + */ + isConfirmDisabled: PropTypes.bool, + + /** + * When true, the cancel button is shown. + */ + showCancel: PropTypes.bool, + + /** + * Function that will be called when the cancel button is clicked. + * This closes the Dialog by default. + * + * `onCancel={(close) => close()}` + */ + onCancel: PropTypes.func, + + /** + * Label of the cancel button, shown when primaryButton is passed. + * You should not have to change this in most cases. + */ + cancelLabel: PropTypes.node, /** * Width of the Dialog. @@ -102,11 +157,6 @@ class Dialog extends React.Component { */ minHeightContent: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - /** - * When true, hide the header containing the title and close button. - */ - hideHeader: PropTypes.bool, - /** * Props that are passed to the Dialog container. */ @@ -114,38 +164,70 @@ class Dialog extends React.Component { } static defaultProps = { + isShown: false, + hasHeader: true, + hasFooter: true, + hasCancel: true, + intent: 'neutral', width: 560, topOffset: '12vh', minHeightContent: 80, - cancelLabel: 'Cancel' + confirmLabel: 'Confirm', + isConfirmLoading: false, + isConfirmDisabled: false, + cancelLabel: 'Cancel', + onCancel: close => close(), + onConfirm: close => close() } render() { const { title, width, + intent, + isShown, children, topOffset, - hideHeader, + hasHeader, + hasFooter, + hasCancel, + onCloseComplete, + onOpenComplete, + onConfirm, + confirmLabel, + isConfirmLoading, + isConfirmDisabled, + onCancel, cancelLabel, - primaryButton, - minHeightContent, - hideCancelButton, containerProps, + minHeightContent, ...props } = this.props let maxHeight if (Number.isInteger(topOffset)) { - maxHeight = `calc(100% - ${topOffset}px - ${topOffset}px)` + maxHeight = `calc(100% - ${topOffset}px)` } else { - maxHeight = `calc(100% - ${topOffset} - ${topOffset})` + maxHeight = `calc(100% - ${topOffset})` + } + + let buttonAppearance + if (intent === 'neutral') { + buttonAppearance = 'green' + } else if (intent === 'danger') { + buttonAppearance = 'red' } return ( - + {({ state, close }) => ( - {!hideHeader && ( + {hasHeader && ( - {primaryButton && ( + {hasFooter && ( + {hasCancel && ( )} diff --git a/src/dialog/stories/index.stories.js b/src/dialog/stories/index.stories.js index 3a0586b99..a7a1f0794 100644 --- a/src/dialog/stories/index.stories.js +++ b/src/dialog/stories/index.stories.js @@ -18,17 +18,12 @@ storiesOf('dialog', module).add('Dialog', () => ( { - close() - }, - children: 'Primary Button' - }} + onCloseComplete={hide} + confirmLabel="Custom Label" > Dialog content - +
    )} @@ -37,19 +32,14 @@ storiesOf('dialog', module).add('Dialog', () => ( { - close() - }, - appearance: 'red', - children: 'Primary Button' - }} + title="Dialog with Danger Intent" + onCloseComplete={hide} + intent="danger" + confirmLabel="Dangerous Action" > Dialog content - + )} @@ -58,14 +48,11 @@ storiesOf('dialog', module).add('Dialog', () => ( This is useful when you need to process something before closing @@ -81,12 +68,10 @@ storiesOf('dialog', module).add('Dialog', () => ( This is useful for product updates and onboarding content. @@ -102,7 +87,8 @@ storiesOf('dialog', module).add('Dialog', () => ( Manage your own buttons and interactions. @@ -118,7 +104,8 @@ storiesOf('dialog', module).add('Dialog', () => ( {({ close }) => ( @@ -136,7 +123,12 @@ storiesOf('dialog', module).add('Dialog', () => ( {({ isShown, show, hide }) => ( - + {({ close }) => ( @@ -158,13 +150,7 @@ storiesOf('dialog', module).add('Dialog', () => ( { - close() - }, - children: 'Primary Button' - }} + onCloseComplete={hide} > From 849b595795d7986b18e585a8dd68790ef0284e3e Mon Sep 17 00:00:00 2001 From: jeroenransijn Date: Thu, 15 Feb 2018 13:23:47 -0800 Subject: [PATCH 5/8] intent => type keep consistent with Alert --- src/dialog/src/Dialog.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/dialog/src/Dialog.js b/src/dialog/src/Dialog.js index d2f278bcf..998d2a050 100644 --- a/src/dialog/src/Dialog.js +++ b/src/dialog/src/Dialog.js @@ -106,9 +106,9 @@ class Dialog extends React.Component { confirmLabel: PropTypes.string, /** - * The intent of the message. + * The type of the message. */ - intent: PropTypes.oneOf(['neutral', 'danger']), + type: PropTypes.oneOf(['default', 'danger']), /** * When true, the confirm button is set to loading. @@ -168,7 +168,7 @@ class Dialog extends React.Component { hasHeader: true, hasFooter: true, hasCancel: true, - intent: 'neutral', + type: 'default', width: 560, topOffset: '12vh', minHeightContent: 80, @@ -184,7 +184,7 @@ class Dialog extends React.Component { const { title, width, - intent, + type, isShown, children, topOffset, @@ -212,9 +212,9 @@ class Dialog extends React.Component { } let buttonAppearance - if (intent === 'neutral') { + if (type === 'default') { buttonAppearance = 'green' - } else if (intent === 'danger') { + } else if (type === 'danger') { buttonAppearance = 'red' } From 5f87fddc223aa25a128b0445c091bc74986facf9 Mon Sep 17 00:00:00 2001 From: jeroenransijn Date: Thu, 15 Feb 2018 13:25:35 -0800 Subject: [PATCH 6/8] update story and docs --- src/dialog/docs/examples/primary-button-red.example | 2 +- src/dialog/stories/index.stories.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dialog/docs/examples/primary-button-red.example b/src/dialog/docs/examples/primary-button-red.example index 7011694a5..12927b507 100644 --- a/src/dialog/docs/examples/primary-button-red.example +++ b/src/dialog/docs/examples/primary-button-red.example @@ -5,7 +5,7 @@ isShown={isShown} title="Dialog with Danger Intent" onCloseComplete={hide} - intent="danger" + type="danger" confirmLabel="Dangerous Action" > Dialog content diff --git a/src/dialog/stories/index.stories.js b/src/dialog/stories/index.stories.js index a7a1f0794..52a2f6839 100644 --- a/src/dialog/stories/index.stories.js +++ b/src/dialog/stories/index.stories.js @@ -34,7 +34,7 @@ storiesOf('dialog', module).add('Dialog', () => ( isShown={isShown} title="Dialog with Danger Intent" onCloseComplete={hide} - intent="danger" + type="danger" confirmLabel="Dangerous Action" > Dialog content From f90980368fdb9ab1985d3ac4e257cfcde4aa8ecf Mon Sep 17 00:00:00 2001 From: jeroenransijn Date: Thu, 15 Feb 2018 13:26:43 -0800 Subject: [PATCH 7/8] removed old showCancel --- src/dialog/src/Dialog.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/dialog/src/Dialog.js b/src/dialog/src/Dialog.js index 998d2a050..74393a505 100644 --- a/src/dialog/src/Dialog.js +++ b/src/dialog/src/Dialog.js @@ -120,11 +120,6 @@ class Dialog extends React.Component { */ isConfirmDisabled: PropTypes.bool, - /** - * When true, the cancel button is shown. - */ - showCancel: PropTypes.bool, - /** * Function that will be called when the cancel button is clicked. * This closes the Dialog by default. From e3b65c6a71e1f42eab7061cedb7f998f56356ee1 Mon Sep 17 00:00:00 2001 From: jeroenransijn Date: Thu, 15 Feb 2018 13:30:00 -0800 Subject: [PATCH 8/8] docs fixes --- src/dialog/src/Dialog.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/dialog/src/Dialog.js b/src/dialog/src/Dialog.js index 74393a505..bad5493af 100644 --- a/src/dialog/src/Dialog.js +++ b/src/dialog/src/Dialog.js @@ -101,7 +101,7 @@ class Dialog extends React.Component { onConfirm: PropTypes.func, /** - * Label that is used inside of the confirm button. + * Label of the confirm button. */ confirmLabel: PropTypes.string, @@ -129,10 +129,9 @@ class Dialog extends React.Component { onCancel: PropTypes.func, /** - * Label of the cancel button, shown when primaryButton is passed. - * You should not have to change this in most cases. + * Label of the cancel button. */ - cancelLabel: PropTypes.node, + cancelLabel: PropTypes.string, /** * Width of the Dialog. @@ -140,9 +139,9 @@ class Dialog extends React.Component { width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** - * The space above the Dialog. + * The space above the dialog. * This offset is also used at the bottom when there is not enough space - * available on screen — and the Dialog scrolls internally. + * available on screen — and the dialog scrolls internally. */ topOffset: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), @@ -153,7 +152,7 @@ class Dialog extends React.Component { minHeightContent: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** - * Props that are passed to the Dialog container. + * Props that are passed to the dialog container. */ containerProps: PropTypes.object }