From 14f7b4977f49d025b7a69caf200db2305726c259 Mon Sep 17 00:00:00 2001 From: Cam Wiegert Date: Thu, 21 Dec 2017 16:00:22 -0600 Subject: [PATCH] feat(button) localize focus management and styles (#13690) * feat(button) handle button focus locally * chore() remove global focus styles * feat(button) add button md focus styles * feat(button) add ios focus styles * fix(button) adjust ios clear focus styles --- .../src/components/button/button.ios.scss | 36 +++++++++++++ .../components/button/button.ios.vars.scss | 9 ++++ .../core/src/components/button/button.md.scss | 27 ++++++++++ .../src/components/button/button.md.vars.scss | 9 ++++ .../core/src/components/button/button.scss | 5 ++ .../core/src/components/button/button.tsx | 53 +++++++++++++++---- packages/core/src/components/button/readme.md | 12 +++++ packages/core/src/themes/util.scss | 40 +++++++------- 8 files changed, 160 insertions(+), 31 deletions(-) diff --git a/packages/core/src/components/button/button.ios.scss b/packages/core/src/components/button/button.ios.scss index 1d0facd2ed..76e97a4529 100644 --- a/packages/core/src/components/button/button.ios.scss +++ b/packages/core/src/components/button/button.ios.scss @@ -25,6 +25,10 @@ opacity: $button-ios-opacity-activated; } +.button-ios.focused { + background-color: $button-ios-background-color-focused; +} + .button-ios:hover:not(.disable-hover) { opacity: $button-ios-opacity-hover; } @@ -40,6 +44,7 @@ @mixin ios-button-default($color-name, $color-base, $color-contrast) { $bg-color: $color-base; $bg-color-activated: color-shade($bg-color); + $bg-color-focused: color-shade($color-base, 12%); $fg-color: $color-contrast; .button-ios-#{$color-name} { @@ -50,6 +55,10 @@ .button-ios-#{$color-name}.activated { background-color: $bg-color-activated; } + + .button-ios-#{$color-name}.focused { + background-color: $bg-color-focused; + } } @@ -109,10 +118,20 @@ opacity: $button-ios-outline-opacity-activated; } +.button-outline-ios.focused { + background-color: $button-ios-outline-background-color-focused; +} + +.button-outline-ios.activated.focused { + background-color: color-shade($button-ios-background-color, 12%); + border-color: color-shade($button-ios-background-color, 12%); +} + // iOS Outline Button Color Mixin // -------------------------------------------------- @mixin ios-button-outline($color-name, $color-base, $color-contrast) { + $bg-color-focused: rgba($color-base, 0.12); .button-outline-ios-#{$color-name} { border-color: $color-base; @@ -125,6 +144,14 @@ background-color: $color-base; } + .button-outline-ios-#{$color-name}.focused { + background-color: $bg-color-focused; + } + + .button-outline-ios-#{$color-name}.activated.focused { + background-color: color-shade($color-base, 12%); + border-color: color-shade($color-base, 12%); + } } @@ -142,6 +169,10 @@ opacity: $button-ios-clear-opacity-activated; } +.button-clear-ios.focused { + background-color: $button-ios-clear-background-color-focused; +} + .button-clear-ios:hover:not(.disable-hover) { color: $button-ios-clear-text-color-hover; opacity: $button-ios-clear-opacity-hover; @@ -153,6 +184,7 @@ @mixin ios-button-clear($color-name, $color-base, $color-contrast) { $fg-color: $color-base; + $bg-color-focused: rgba($color-base, 0.12); .button-clear-ios-#{$color-name} { border-color: $button-ios-clear-border-color; @@ -164,6 +196,10 @@ opacity: $button-ios-clear-opacity-activated; } + .button-clear-ios-#{$color-name}.focused { + background-color: $bg-color-focused; + } + .button-clear-ios-#{$color-name}:hover:not(.disable-hover) { color: $fg-color; } diff --git a/packages/core/src/components/button/button.ios.vars.scss b/packages/core/src/components/button/button.ios.vars.scss index 112147c7a4..491085810f 100644 --- a/packages/core/src/components/button/button.ios.vars.scss +++ b/packages/core/src/components/button/button.ios.vars.scss @@ -54,6 +54,9 @@ $button-ios-opacity-activated: 1 !default; /// @prop - Opacity of the button on hover $button-ios-opacity-hover: .8 !default; +/// @prop - Background color of the focused button +$button-ios-background-color-focused: color-shade($button-ios-background-color, 12%) !default; + // iOS Large Button // -------------------------------------------------- @@ -129,6 +132,9 @@ $button-ios-outline-background-color-activated: $button-ios-background-color /// @prop - Opacity of the activated outline button $button-ios-outline-opacity-activated: 1 !default; +/// @prop - Background color of the focused outline button +$button-ios-outline-background-color-focused: rgba($button-ios-background-color, 0.12) !default; + // iOS Clear Button // -------------------------------------------------- @@ -151,6 +157,9 @@ $button-ios-clear-text-color-hover: $button-ios-background-color /// @prop - Opacity of the clear button on hover $button-ios-clear-opacity-hover: .6 !default; +/// @prop - Background color of the focused clear button +$button-ios-clear-background-color-focused: rgba($button-ios-background-color, 0.12) !default; + // iOS Round Button // -------------------------------------------------- diff --git a/packages/core/src/components/button/button.md.scss b/packages/core/src/components/button/button.md.scss index ff637ce780..96791ae585 100644 --- a/packages/core/src/components/button/button.md.scss +++ b/packages/core/src/components/button/button.md.scss @@ -37,6 +37,10 @@ box-shadow: $button-md-box-shadow-activated; } +.button-md.focused { + background-color: $button-md-background-color-focused; +} + .button-md .button-effect { background-color: $button-md-text-color; } @@ -52,6 +56,7 @@ @mixin md-button-default($color-name, $color-base, $color-contrast) { $bg-color: $color-base; $bg-color-activated: color-shade($bg-color); + $bg-color-focused: color-shade($bg-color, 12%); $fg-color: $color-contrast; .button-md-#{$color-name} { @@ -68,6 +73,10 @@ opacity: $button-md-opacity-activated; } + .button-md-#{$color-name}.focused { + background-color: $bg-color-focused; + } + .button-md-#{$color-name} .button-effect { background-color: $fg-color; } @@ -133,6 +142,10 @@ opacity: $button-md-outline-opacity-activated; } +.button-outline-md.focused { + background-color: $button-md-outline-background-color-focused; +} + .button-outline-md .button-effect { background-color: $button-md-outline-ripple-background-color; } @@ -143,6 +156,7 @@ @mixin md-button-outline($color-name, $color-base, $color-contrast) { $fg-color: color-shade($color-base, 5%); + $bg-color-focused: rgba($color-base, 0.12); .button-outline-md-#{$color-name} { border-color: $fg-color; @@ -158,6 +172,10 @@ background-color: $button-md-outline-background-color-activated; } + .button-outline-md-#{$color-name}.focused { + background-color: $bg-color-focused; + } + .button-outline-md-#{$color-name} .button-effect { background-color: $fg-color; } @@ -180,6 +198,10 @@ box-shadow: $button-md-clear-box-shadow-activated; } +.button-clear-md.focused { + background-color: $button-md-clear-background-color-focused; +} + .button-clear-md:hover:not(.disable-hover) { background-color: $button-md-clear-background-color-hover; } @@ -194,6 +216,7 @@ @mixin md-button-clear($color-name, $color-base, $color-contrast) { $fg-color: $color-base; + $bg-color-focused: rgba($color-base, 0.12); .button-clear-md-#{$color-name} { border-color: $button-md-clear-border-color; @@ -206,6 +229,10 @@ box-shadow: $button-md-clear-box-shadow-activated; } + .button-clear-md-#{$color-name}.focused { + background-color: $bg-color-focused; + } + .button-clear-md-#{$color-name}:hover:not(.disable-hover) { color: $fg-color; } diff --git a/packages/core/src/components/button/button.md.vars.scss b/packages/core/src/components/button/button.md.vars.scss index 445ffd1669..b33eb1a086 100644 --- a/packages/core/src/components/button/button.md.vars.scss +++ b/packages/core/src/components/button/button.md.vars.scss @@ -75,6 +75,9 @@ $button-md-box-shadow-activated: 0 3px 5px rgba(0, 0, 0, .14), 0 3px 5 /// @prop - Background color of the ripple on the button $button-md-ripple-background-color: #555 !default; +/// @prop - Background color of the focused button +$button-md-background-color-focused: color-shade($button-md-background-color, 12%) !default; + // Material Design Large Button // -------------------------------------------------- @@ -156,6 +159,9 @@ $button-md-outline-opacity-activated: 1 !default; /// @prop - Background color of the ripple on the outline button $button-md-outline-ripple-background-color: $button-md-background-color !default; +/// @prop - Background color of the focused outline button +$button-md-outline-background-color-focused: rgba($button-md-background-color, 0.12) !default; + // Material Design Clear Button // -------------------------------------------------- @@ -187,6 +193,9 @@ $button-md-clear-background-color-hover: rgba(158, 158, 158, .1) !default /// @prop - Background color of the ripple on the clear button $button-md-clear-ripple-background-color: #999 !default; +/// @props - Background color of the focused clear button +$button-md-clear-background-color-focused: rgba($button-md-background-color, 0.12) !default; + // Material Design Round Button // -------------------------------------------------- diff --git a/packages/core/src/components/button/button.scss b/packages/core/src/components/button/button.scss index 79de9eef54..108dcc05c6 100644 --- a/packages/core/src/components/button/button.scss +++ b/packages/core/src/components/button/button.scss @@ -32,6 +32,11 @@ contain: content; } +.button:active, +.button:focus { + outline: none; +} + .button-inner { display: flex; diff --git a/packages/core/src/components/button/button.tsx b/packages/core/src/components/button/button.tsx index a2c9d1722a..3007c6df3e 100644 --- a/packages/core/src/components/button/button.tsx +++ b/packages/core/src/components/button/button.tsx @@ -1,4 +1,5 @@ -import { Component, Element, Prop } from '@stencil/core'; +import { BlurEvent, FocusEvent } from '../../utils/input-interfaces'; +import { Component, Element, Event, EventEmitter, Prop, State } from '@stencil/core'; import { getElementClassObject } from '../../utils/theme'; @@ -12,6 +13,8 @@ import { getElementClassObject } from '../../utils/theme'; export class Button { @Element() private el: HTMLElement; + @State() keyFocus: boolean; + /** * Contains a URL or a URL fragment that the hyperlink points to. * If this property is set, an anchor tag will be rendered. @@ -72,6 +75,29 @@ export class Button { */ @Prop() mode: 'ios' | 'md'; + /** + * Emitted when the button has focus. + */ + @Event() ionFocus: EventEmitter; + + /** + * Emitted when the button loses focus. + */ + @Event() ionBlur: EventEmitter; + + onFocus() { + this.ionFocus.emit(); + } + + onKeyUp() { + this.keyFocus = true; + } + + onBlur() { + this.keyFocus = false; + this.ionBlur.emit(); + } + protected render() { const { @@ -99,18 +125,25 @@ export class Button { const buttonClasses = { ...getElementClassObject(this.el.classList), - ...getElementClassObject(elementClasses) + ...getElementClassObject(elementClasses), + 'focused': this.keyFocus }; return ( - - - - - - - -
+ + + + + + + +
); } diff --git a/packages/core/src/components/button/readme.md b/packages/core/src/components/button/readme.md index 3bb671fc45..d75ac8869e 100644 --- a/packages/core/src/components/button/readme.md +++ b/packages/core/src/components/button/readme.md @@ -240,6 +240,18 @@ boolean If true, activates a button with a heavier font weight. +## Events + +#### ionBlur + +Emitted when the button loses focus. + + +#### ionFocus + +Emitted when the button has focus. + + ---------------------------------------------- diff --git a/packages/core/src/themes/util.scss b/packages/core/src/themes/util.scss index 5fcc789661..fa7ce592a1 100755 --- a/packages/core/src/themes/util.scss +++ b/packages/core/src/themes/util.scss @@ -12,31 +12,29 @@ template { } -// Focus Outline +// Click Block // -------------------------------------------------- +// Fill the screen to block clicks (a better pointer-events: none) +// to avoid full-page reflows and paints which can cause flickers -$focus-outline-border-color: #51a7e8 !default; -$focus-outline-border-width: 2px !default; -$focus-outline-box-shadow: 0 0 8px 1px $focus-outline-border-color !default; - - -:focus, -:active { - outline: none; +.click-block { + display: none; } -.focus-outline :focus { - outline: thin dotted; - outline-offset: -1px; +.click-block-enabled { + @include position(0, 0, 0, 0); + @include transform(translate3d(0, -100%, 0), translateY(1px)); + + position: absolute; + + z-index: $z-index-click-block; + display: block; + + opacity: 0; + + contain: strict; } -.focus-outline button:focus, -.focus-outline [ion-button]:focus { - border-color: $focus-outline-border-color; - outline: $focus-outline-border-width solid $focus-outline-border-color; - box-shadow: $focus-outline-box-shadow; -} - -ion-input :focus { - outline: none; +.click-block-active { + @include transform(translate3d(0, 0, 0)); }