feat(item): add hover and focused states (#18606)

references #18279 references #17624
This commit is contained in:
Brandy Carney
2019-06-25 17:29:14 -04:00
committed by GitHub
parent ad00679da9
commit 8a88dd25b6
10 changed files with 139 additions and 27 deletions

View File

@ -483,12 +483,17 @@ ion-item,prop,target,string | undefined,undefined,false,false
ion-item,prop,type,"button" | "reset" | "submit",'button',false,false
ion-item,css-prop,--background
ion-item,css-prop,--background-activated
ion-item,css-prop,--background-focused
ion-item,css-prop,--background-hover
ion-item,css-prop,--border-color
ion-item,css-prop,--border-radius
ion-item,css-prop,--border-style
ion-item,css-prop,--border-width
ion-item,css-prop,--box-shadow
ion-item,css-prop,--color
ion-item,css-prop,--color-activated
ion-item,css-prop,--color-focused
ion-item,css-prop,--color-hover
ion-item,css-prop,--detail-icon-color
ion-item,css-prop,--detail-icon-font-size
ion-item,css-prop,--detail-icon-opacity

View File

@ -94,7 +94,11 @@ export class Checkbox implements ComponentInterface {
}
@Watch('disabled')
emitStyle() {
disabledChanged() {
this.emitStyle();
}
private emitStyle() {
this.ionStyle.emit({
'checkbox-checked': this.checked,
'interactive-disabled': this.disabled,

View File

@ -12,7 +12,8 @@
--inner-border-width: #{0px 0px $item-ios-border-bottom-width 0px};
--background: #{$item-ios-background};
--background-activated: #{$item-ios-background-activated};
--background-focused: #{$item-ios-background-activated};
--background-focused: #{$item-ios-background-focused};
--background-hover: #{$item-ios-background-hover};
--border-color: #{$item-ios-border-bottom-color};
--color: #{$item-ios-color};
--highlight-height: 0;
@ -23,10 +24,31 @@
font-size: $item-ios-font-size;
}
// iOS Activated
// --------------------------------------------------
:host(.activated) {
--transition: none;
}
:host(.ion-color.activated) .item-native {
background: current-color(shade);
color: current-color(contrast);
}
@media (any-hover: hover) {
:host(.activated.ion-activatable:hover) .item-native {
background: var(--background-activated);
color: var(--color-activated);
}
:host(.activated.ion-color.ion-activatable:hover) .item-native {
background: #{current-color(shade)};
color: #{current-color(contrast)};
}
}
// iOS Item Lines
// --------------------------------------------------

View File

@ -9,7 +9,8 @@
--min-height: #{$item-md-min-height};
--background: #{$item-md-background};
--background-activated: var(--background);
--background-focused: #{$item-md-background-activated};
--background-focused: #{$item-md-background-focused};
--background-hover: #{$item-md-background-hover};
--border-color: #{$item-md-border-bottom-color};
--color: #{$item-md-color};
--transition: background-color 300ms cubic-bezier(.4, 0, .2, 1);
@ -30,6 +31,25 @@
}
// Material Design Item: Focused & Activated
// --------------------------------------------------
:host(.ion-focused.activated) .item-native {
background: var(--background-focused);
color: var(--color-focused);
}
:host(.ion-color.activated) .item-native {
background: current-color(base);
color: current-color(contrast);
}
:host(.ion-color.ion-focused.activated) .item-native {
background: current-color(shade);
color: current-color(contrast);
}
// Material Design Item Lines
// --------------------------------------------------

View File

@ -7,6 +7,8 @@
/**
* @prop --background: Background of the item
* @prop --background-activated: Background of the item when pressed
* @prop --background-focused: Background of the item when focused with the tab key
* @prop --background-hover: Background of the item on hover
*
* @prop --border-color: Color of the item border
* @prop --border-radius: Radius of the item border
@ -16,6 +18,9 @@
* @prop --box-shadow: Box shadow of the item
*
* @prop --color: Color of the item
* @prop --color-activated: Color of the item when pressed
* @prop --color-focused: Color of the item when focused with the tab key
* @prop --color-hover: Color of the item on hover
*
* @prop --detail-icon-color: Color of the item detail icon
* @prop --detail-icon-opacity: Opacity of the item detail icon
@ -63,6 +68,9 @@
--detail-icon-color: initial;
--detail-icon-font-size: 20px;
--detail-icon-opacity: 0.25;
--color-activated: var(--color);
--color-focused: var(--color);
--color-hover: var(--color);
--ripple-color: var(--ion-item-background-activated, currentColor);
@include font-smoothing();
@ -85,7 +93,7 @@
}
// Item with Color
// Item: Color
// --------------------------------------------------
:host(.ion-color) .item-native {
@ -99,25 +107,53 @@
}
// Activated Item
// Item: Focused
// --------------------------------------------------
:host(.ion-focused) .item-native {
background: var(--background-focused);
color: var(--color-focused);
}
:host(.ion-color.ion-focused) .item-native {
background: current-color(shade);
color: current-color(contrast);
}
// Item: Hover
// --------------------------------------------------
@media (any-hover: hover) {
:host(.ion-activatable:hover) .item-native {
background: var(--background-hover);
color: var(--color-hover);
}
:host(.ion-color.ion-activatable:hover) .item-native {
background: #{current-color(tint)};
color: #{current-color(contrast)};
}
}
// Item: Activated
// --------------------------------------------------
:host(.activated) .item-native {
background: var(--background-activated);
}
:host(.ion-color.activated) .item-native {
background: current-color(tint);
color: var(--color-activated);
}
// Disabled Item
// Item: Disabled
// --------------------------------------------------
:host(.item-interactive-disabled) {
cursor: default;
pointer-events: none;
}
:host(.item-disabled) {
cursor: default;
opacity: .3;
@ -209,7 +245,7 @@ button, a {
}
// Item Detail Icon
// -----------------------------------------
// --------------------------------------------------
.item-detail-icon {
color: var(--detail-icon-color);
@ -221,7 +257,7 @@ button, a {
// Item Slots
// -----------------------------------------
// --------------------------------------------------
::slotted(ion-icon) {
font-size: 1.6em;
@ -242,7 +278,7 @@ button, a {
// Item Input
// -----------------------------------------
// --------------------------------------------------
:host([vertical-align-top]),
:host(.item-input) {
@ -331,7 +367,7 @@ button, a {
// Item Select
// -----------------------------------------
// --------------------------------------------------
:host(.item-label-stacked) ::slotted(ion-select),
:host(.item-label-floating) ::slotted(ion-select) {
@ -346,7 +382,7 @@ button, a {
// Item Datetime
// -----------------------------------------
// --------------------------------------------------
:host(.item-label-stacked) ::slotted(ion-datetime),
:host(.item-label-floating) ::slotted(ion-datetime) {
@ -357,9 +393,9 @@ button, a {
// Item w/ Multiple Inputs
// -----------------------------------------
// Multiple inputs in an item should have the input cover
// relative to them instead of the item
// --------------------------------------------------
// Multiple inputs in an item should have the input
// cover relative to themselves instead of the item
:host(.item-multiple-inputs) ::slotted(ion-datetime),
:host(.item-multiple-inputs) ::slotted(ion-select) {
@ -368,7 +404,7 @@ button, a {
// Item Textarea
// -----------------------------------------
// --------------------------------------------------
:host(.item-textarea) {
align-items: stretch;

View File

@ -133,15 +133,31 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
this.multipleInputs = inputs.length > 1 ? true : false;
}
// If the item contains an input including a radio, checkbox, datetime, etc.
// then the item will have a clickable input cover that should
// get the hover, focused and activated states UNLESS it has multiple
// inputs, then those need to individually get the click
private hasCover(): boolean {
const inputs = this.el.querySelectorAll('ion-checkbox, ion-datetime, ion-select, ion-radio');
return inputs.length > 0 && !this.multipleInputs;
}
// If the item has an href or button property it will render a native
// anchor or button that is clickable
private isClickable(): boolean {
return (this.href !== undefined || this.button);
}
private canActivate(): boolean {
return (this.isClickable() || this.hasCover());
}
render() {
const { detail, detailIcon, download, lines, disabled, href, rel, target, routerDirection } = this;
const childStyles = {};
const mode = getIonMode(this);
const clickable = this.isClickable();
const canActivate = this.canActivate();
const TagType = clickable ? (href === undefined ? 'button' : 'a') : 'div' as any;
const attrs = (TagType === 'button')
? { type: this.type }
@ -168,7 +184,7 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
'item-disabled': disabled,
'in-list': hostContext('ion-list', this.el),
'item-multiple-inputs': this.multipleInputs,
'ion-activatable': this.isClickable(),
'ion-activatable': canActivate,
'ion-focusable': true,
}}
>
@ -187,7 +203,7 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
{showDetail && <ion-icon icon={detailIcon} lazy={false} class="item-detail-icon"></ion-icon>}
<div class="item-inner-highlight"></div>
</div>
{clickable && mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
{canActivate && mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
</TagType>
<div class="item-highlight"></div>
</Host>

View File

@ -1396,12 +1396,17 @@ Item Inputs
| --------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `--background` | Background of the item |
| `--background-activated` | Background of the item when pressed |
| `--background-focused` | Background of the item when focused with the tab key |
| `--background-hover` | Background of the item on hover |
| `--border-color` | Color of the item border |
| `--border-radius` | Radius of the item border |
| `--border-style` | Style of the item border |
| `--border-width` | Width of the item border |
| `--box-shadow` | Box shadow of the item |
| `--color` | Color of the item |
| `--color-activated` | Color of the item when pressed |
| `--color-focused` | Color of the item when focused with the tab key |
| `--color-hover` | Color of the item on hover |
| `--detail-icon-color` | Color of the item detail icon |
| `--detail-icon-font-size` | Font size of the item detail icon |
| `--detail-icon-opacity` | Opacity of the item detail icon |

View File

@ -41,21 +41,21 @@
<ion-label>button[ion-item] type="submit"</ion-label>
</ion-item>
<ion-item class="activated" onClick="testClick(event)">
<ion-item button class="activated" onClick="testClick(event)">
<ion-label>button[ion-item].activated</ion-label>
</ion-item>
<ion-item color="danger" onclick="testClick(event)">
<ion-item button color="danger" onClick="testClick(event)">
<ion-label>button[ion-item] danger</ion-label>
</ion-item>
<ion-item onclick="testClickOutsize(event)">
<ion-item button onclick="testClickOutsize(event)">
<ion-button slot="start" onclick="testClick(event)">Default</ion-button>
<ion-label>Inner Buttons</ion-label>
<ion-button fill="outline" slot="end" onclick="testClick(event)">Outline</ion-button>
</ion-item>
<ion-item disabled>
<ion-item button disabled>
<ion-button slot="start" onclick="testClick(event)">
<ion-icon slot="start" name="home"></ion-icon>
Left Icon

View File

@ -30,5 +30,7 @@ $toolbar-ios-color-activated: var(--ion-toolbar-color-activated, i
// --------------------------------------------------
$item-ios-background: var(--ion-item-background, $background-color) !default;
$item-ios-background-activated: var(--ion-item-background-activated, var(--ion-color-step-150, #d9d9d9)) !default;
$item-ios-background-focused: var(--ion-item-background-focused, var(--ion-color-step-100, #e1e1e1)) !default;
$item-ios-background-hover: var(--ion-item-background-hover, var(--ion-color-step-50, #f5f5f5)) !default;
$item-ios-border-color: var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-150, #c8c7cc))) !default;
$item-ios-color: var(--ion-item-color, $text-color) !default;

View File

@ -30,6 +30,8 @@ $toolbar-md-color-activated: var(--ion-toolbar-color-activated, #
// Material Design List & List Items
// --------------------------------------------------
$item-md-background: var(--ion-item-background, $background-color) !default;
$item-md-background-activated: var(--ion-item-background-activated, var(--ion-color-step-50, #f1f1f1)) !default;
// activated item background does not exist in MD as it uses the ripple color
$item-md-background-focused: var(--ion-item-background-focused, var(--ion-color-step-100, #e1e1e1)) !default;
$item-md-background-hover: var(--ion-item-background-hover, var(--ion-color-step-50, #f5f5f5)) !default;
$item-md-border-color: var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-150, rgba(0, 0, 0, .13)))) !default;
$item-md-color: var(--ion-item-color, $text-color) !default;