diff --git a/core/api.txt b/core/api.txt index 56fc0d66ff..5bd30946f2 100644 --- a/core/api.txt +++ b/core/api.txt @@ -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 diff --git a/core/src/components/checkbox/checkbox.tsx b/core/src/components/checkbox/checkbox.tsx index fe6e1757e0..ff31cbcd86 100644 --- a/core/src/components/checkbox/checkbox.tsx +++ b/core/src/components/checkbox/checkbox.tsx @@ -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, diff --git a/core/src/components/item/item.ios.scss b/core/src/components/item/item.ios.scss index c4bfcde6cd..6e80302802 100644 --- a/core/src/components/item/item.ios.scss +++ b/core/src/components/item/item.ios.scss @@ -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 // -------------------------------------------------- diff --git a/core/src/components/item/item.md.scss b/core/src/components/item/item.md.scss index a89e222920..55dc5f5cd3 100644 --- a/core/src/components/item/item.md.scss +++ b/core/src/components/item/item.md.scss @@ -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 // -------------------------------------------------- diff --git a/core/src/components/item/item.scss b/core/src/components/item/item.scss index 290a6ea965..e8449a0711 100644 --- a/core/src/components/item/item.scss +++ b/core/src/components/item/item.scss @@ -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; diff --git a/core/src/components/item/item.tsx b/core/src/components/item/item.tsx index fb79706284..7c14b21eb0 100644 --- a/core/src/components/item/item.tsx +++ b/core/src/components/item/item.tsx @@ -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 && }
- {clickable && mode === 'md' && } + {canActivate && mode === 'md' && }
diff --git a/core/src/components/item/readme.md b/core/src/components/item/readme.md index 85a69b919f..12fcc3795e 100644 --- a/core/src/components/item/readme.md +++ b/core/src/components/item/readme.md @@ -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 | diff --git a/core/src/components/item/test/buttons/index.html b/core/src/components/item/test/buttons/index.html index 4f03b44ed5..b4ac9e209e 100644 --- a/core/src/components/item/test/buttons/index.html +++ b/core/src/components/item/test/buttons/index.html @@ -41,21 +41,21 @@ button[ion-item] type="submit" - + button[ion-item].activated - + button[ion-item] danger - + Default Inner Buttons Outline - + Left Icon diff --git a/core/src/themes/ionic.theme.default.ios.scss b/core/src/themes/ionic.theme.default.ios.scss index 5cdc0664de..bfb9c74c5d 100644 --- a/core/src/themes/ionic.theme.default.ios.scss +++ b/core/src/themes/ionic.theme.default.ios.scss @@ -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; +$item-ios-color: var(--ion-item-color, $text-color) !default; \ No newline at end of file diff --git a/core/src/themes/ionic.theme.default.md.scss b/core/src/themes/ionic.theme.default.md.scss index 5d5331595e..1402517543 100644 --- a/core/src/themes/ionic.theme.default.md.scss +++ b/core/src/themes/ionic.theme.default.md.scss @@ -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;