diff --git a/packages/core/src/common/classes.ts b/packages/core/src/common/classes.ts index 14740fab0a..b46f668bf0 100644 --- a/packages/core/src/common/classes.ts +++ b/packages/core/src/common/classes.ts @@ -35,6 +35,7 @@ export const INTERACTIVE = `${NS}-interactive`; export const LARGE = `${NS}-large`; export const LOADING = `${NS}-loading`; export const MINIMAL = `${NS}-minimal`; +export const OUTLINED = `${NS}-outlined`; export const MULTILINE = `${NS}-multiline`; export const ROUND = `${NS}-round`; export const SMALL = `${NS}-small`; diff --git a/packages/core/src/components/button/_button.scss b/packages/core/src/components/button/_button.scss index 15f9d78745..d674046e3e 100644 --- a/packages/core/src/components/button/_button.scss +++ b/packages/core/src/components/button/_button.scss @@ -19,6 +19,7 @@ Markup: .#{$ns}-intent-warning - Warning intent .#{$ns}-intent-danger - Danger intent .#{$ns}-minimal - More subtle appearance +.#{$ns}-outlined - Subtle yet structured appearance .#{$ns}-large - Larger size .#{$ns}-small - Smaller size .#{$ns}-fill - Fill parent container @@ -163,6 +164,12 @@ Styleguide button &.#{$ns}-minimal { @include pt-button-minimal(); } + + // outline is based on the styles of minimal + &.#{$ns}-outlined { + @include pt-button-minimal(); + @include pt-button-outlined(); + } } a.#{$ns}-button { diff --git a/packages/core/src/components/button/_common.scss b/packages/core/src/components/button/_common.scss index 10c82fbbfc..af8c0f8810 100644 --- a/packages/core/src/components/button/_common.scss +++ b/packages/core/src/components/button/_common.scss @@ -85,6 +85,10 @@ $dark-minimal-button-background-color: none !default; $dark-minimal-button-background-color-hover: rgba($gray3, 0.15) !default; $dark-minimal-button-background-color-active: rgba($gray3, 0.3) !default; +$button-outlined-width: 1px !default; +$button-outlined-border-intent-opacity: 0.6 !default; +$button-outlined-border-disabled-intent-opacity: 0.2 !default; + // "intent": (default, hover, active colors) $button-intents: ( "primary": ($pt-intent-primary, $blue2, $blue1), @@ -448,3 +452,56 @@ $button-intents: ( } } +@mixin pt-button-outlined() { + border: $button-outlined-width solid rgba($pt-text-color, 0.2); + box-sizing: border-box; + + &:disabled, + &.#{$ns}-disabled, + &:disabled:hover, + &.#{$ns}-disabled:hover { + border-color: rgba($pt-text-color-disabled, 0.1); + } + + .#{$ns}-dark & { + @include pt-dark-button-outlined(); + } + + @each $intent, $colors in $button-intents { + &.#{$ns}-intent-#{$intent} { + @include pt-button-outlined-intent( + map-get($pt-intent-text-colors, $intent), + map-get($pt-dark-intent-text-colors, $intent) + ); + } + } +} + +@mixin pt-dark-button-outlined() { + border-color: rgba($white, 0.4); + + &:disabled, + &:disabled:hover, + &.#{$ns}-disabled, + &.#{$ns}-disabled:hover { + border-color: rgba($white, 0.2); + } +} + +@mixin pt-button-outlined-intent($text-color, $dark-text-color) { + border-color: rgba($text-color, $button-outlined-border-intent-opacity); + + &:disabled, + &.#{$ns}-disabled { + border-color: rgba($text-color, $button-outlined-border-disabled-intent-opacity); + } + + .#{$ns}-dark & { + border-color: rgba($dark-text-color, $button-outlined-border-intent-opacity); + + &:disabled, + &.#{$ns}-disabled { + border-color: rgba($dark-text-color, $button-outlined-border-disabled-intent-opacity); + } + } +} diff --git a/packages/core/src/components/button/abstractButton.tsx b/packages/core/src/components/button/abstractButton.tsx index 36b31324be..0dc9e3c5d9 100644 --- a/packages/core/src/components/button/abstractButton.tsx +++ b/packages/core/src/components/button/abstractButton.tsx @@ -57,6 +57,9 @@ export interface IButtonProps extends IActionProps { /** Whether this button should use minimal styles. */ minimal?: boolean; + /** Whether this button should use outlined styles. */ + outlined?: boolean; + /** Name of a Blueprint UI icon (or an icon element) to render after the text. */ rightIcon?: IconName | MaybeElement; @@ -96,7 +99,7 @@ export abstract class AbstractButton> extend public abstract render(): JSX.Element; protected getCommonButtonProps() { - const { alignText, fill, large, loading, minimal, small, tabIndex } = this.props; + const { alignText, fill, large, loading, outlined, minimal, small, tabIndex } = this.props; const disabled = this.props.disabled || loading; const className = classNames( @@ -108,6 +111,7 @@ export abstract class AbstractButton> extend [Classes.LARGE]: large, [Classes.LOADING]: loading, [Classes.MINIMAL]: minimal, + [Classes.OUTLINED]: outlined, [Classes.SMALL]: small, }, Classes.alignmentClass(alignText), diff --git a/packages/docs-app/src/examples/core-examples/buttonsExample.tsx b/packages/docs-app/src/examples/core-examples/buttonsExample.tsx index d756f8537b..c5d9ac8120 100644 --- a/packages/docs-app/src/examples/core-examples/buttonsExample.tsx +++ b/packages/docs-app/src/examples/core-examples/buttonsExample.tsx @@ -29,6 +29,7 @@ export interface IButtonsExampleState { loading: boolean; large: boolean; minimal: boolean; + outlined: boolean; wiggling: boolean; } @@ -41,6 +42,7 @@ export class ButtonsExample extends React.PureComponent this.setState({ large })); private handleLoadingChange = handleBooleanChange(loading => this.setState({ loading })); private handleMinimalChange = handleBooleanChange(minimal => this.setState({ minimal })); + private handleOutlinedChange = handleBooleanChange(outlined => this.setState({ outlined })); private handleIntentChange = handleStringChange((intent: Intent) => this.setState({ intent })); private wiggleTimeoutId: number; @@ -69,6 +72,7 @@ export class ButtonsExample extends React.PureComponent +
Example