mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
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
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
// --------------------------------------------------
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
// --------------------------------------------------
|
||||
|
||||
@@ -32,6 +32,11 @@
|
||||
contain: content;
|
||||
}
|
||||
|
||||
.button:active,
|
||||
.button:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.button-inner {
|
||||
display: flex;
|
||||
|
||||
|
||||
@@ -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<FocusEvent>;
|
||||
|
||||
/**
|
||||
* Emitted when the button loses focus.
|
||||
*/
|
||||
@Event() ionBlur: EventEmitter<BlurEvent>;
|
||||
|
||||
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 (
|
||||
<TagType class={buttonClasses} disabled={this.disabled} href={this.href}>
|
||||
<span class='button-inner'>
|
||||
<slot name='icon-only'></slot>
|
||||
<slot name='start'></slot>
|
||||
<slot></slot>
|
||||
<slot name='end'></slot>
|
||||
</span>
|
||||
<div class='button-effect'></div>
|
||||
<TagType
|
||||
class={buttonClasses}
|
||||
disabled={this.disabled}
|
||||
href={this.href}
|
||||
onFocus={this.onFocus.bind(this)}
|
||||
onKeyUp={this.onKeyUp.bind(this)}
|
||||
onBlur={this.onBlur.bind(this)}>
|
||||
<span class='button-inner'>
|
||||
<slot name='icon-only'></slot>
|
||||
<slot name='start'></slot>
|
||||
<slot></slot>
|
||||
<slot name='end'></slot>
|
||||
</span>
|
||||
<div class='button-effect'></div>
|
||||
</TagType>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user