diff --git a/angular/src/directives/proxies.ts b/angular/src/directives/proxies.ts index c31884b84d..4f286be95e 100644 --- a/angular/src/directives/proxies.ts +++ b/angular/src/directives/proxies.ts @@ -85,7 +85,7 @@ export class IonButtons { } export declare interface IonCard extends StencilComponents<'IonCard'> {} -@Component({ selector: 'ion-card', changeDetection: 0, template: '', inputs: ['color', 'mode'] }) +@Component({ selector: 'ion-card', changeDetection: 0, template: '', inputs: ['color', 'mode', 'button', 'type', 'disabled', 'href', 'routerDirection'] }) export class IonCard { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef) { @@ -93,7 +93,7 @@ export class IonCard { this.el = r.nativeElement; } } -proxyInputs(IonCard, ['color', 'mode']); +proxyInputs(IonCard, ['color', 'mode', 'button', 'type', 'disabled', 'href', 'routerDirection']); export declare interface IonCardContent extends StencilComponents<'IonCardContent'> {} @Component({ selector: 'ion-card-content', changeDetection: 0, template: '', inputs: ['mode'] }) diff --git a/core/api.txt b/core/api.txt index 5d841143ec..5fc7051bf9 100644 --- a/core/api.txt +++ b/core/api.txt @@ -186,8 +186,13 @@ ion-card-title,prop,mode,"ios" | "md",undefined,false,false ion-card-title,css-prop,--color ion-card,scoped +ion-card,prop,button,boolean,false,false,false ion-card,prop,color,string | undefined,undefined,false,false +ion-card,prop,disabled,boolean,false,false,false +ion-card,prop,href,string | undefined,undefined,false,false ion-card,prop,mode,"ios" | "md",undefined,false,false +ion-card,prop,routerDirection,"back" | "forward" | "root",'forward',false,false +ion-card,prop,type,"button" | "reset" | "submit",'button',false,false ion-card,css-prop,--background ion-card,css-prop,--color diff --git a/core/src/components.d.ts b/core/src/components.d.ts index f9cc3daaaa..328d4bb28b 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -716,24 +716,64 @@ export namespace Components { } interface IonCard { + /** + * If `true`, a button tag will be rendered and the card will be tappable. + */ + 'button': boolean; /** * The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). */ 'color'?: Color; /** + * If `true`, the user cannot interact with the card. + */ + 'disabled': boolean; + /** + * Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. + */ + 'href'?: string; + /** * The mode determines which platform styles to use. */ 'mode': Mode; + /** + * When using a router, it specifies the transition direction when navigating to another page using `href`. + */ + 'routerDirection': RouterDirection; + /** + * The type of the button. Only used when an `onclick` or `button` property is present. + */ + 'type': 'submit' | 'reset' | 'button'; } interface IonCardAttributes extends StencilHTMLAttributes { + /** + * If `true`, a button tag will be rendered and the card will be tappable. + */ + 'button'?: boolean; /** * The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). */ 'color'?: Color; /** + * If `true`, the user cannot interact with the card. + */ + 'disabled'?: boolean; + /** + * Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. + */ + 'href'?: string; + /** * The mode determines which platform styles to use. */ 'mode'?: Mode; + /** + * When using a router, it specifies the transition direction when navigating to another page using `href`. + */ + 'routerDirection'?: RouterDirection; + /** + * The type of the button. Only used when an `onclick` or `button` property is present. + */ + 'type'?: 'submit' | 'reset' | 'button'; } interface IonCheckbox { diff --git a/core/src/components/card/card.ios.scss b/core/src/components/card/card.ios.scss index f4bec1e7fd..4e2a85df91 100755 --- a/core/src/components/card/card.ios.scss +++ b/core/src/components/card/card.ios.scss @@ -13,7 +13,13 @@ transform: translateZ(0); + transition: transform 500ms $card-ios-transition-timing-function; + font-size: $card-ios-font-size; box-shadow: $card-ios-box-shadow; } + +:host(.activated) { + transform: #{$card-ios-transform-activated}; +} \ No newline at end of file diff --git a/core/src/components/card/card.ios.vars.scss b/core/src/components/card/card.ios.vars.scss index 27fb5a9e0b..9fc5f3b07e 100755 --- a/core/src/components/card/card.ios.vars.scss +++ b/core/src/components/card/card.ios.vars.scss @@ -32,3 +32,9 @@ $card-ios-font-size: 14px !default; /// @prop - Color of the card text $card-ios-text-color: $text-color-step-400 !default; + +/// @prop - Transition timing function of the card +$card-ios-transition-timing-function: cubic-bezier(0.12, 0.72, 0.29, 1) !default; + +/// @prop - Transform of the card on activate +$card-ios-transform-activated: scale3d(.97, .97, 1) !default; \ No newline at end of file diff --git a/core/src/components/card/card.scss b/core/src/components/card/card.scss index 6cbf8fc76e..50207bb83c 100755 --- a/core/src/components/card/card.scss +++ b/core/src/components/card/card.scss @@ -50,3 +50,54 @@ ::slotted(*) ion-list { @include margin(0); } + + +// Disabled Card +// -------------------------------------------------- + +:host(.card-disabled) { + cursor: default; + opacity: .3; + pointer-events: none; +} + + +// Native +// -------------------------------------------------- + +.card-native { + @include text-inherit(); + @include padding(0); + @include margin(0); + + width: 100%; + min-height: var(--min-height); + + transition: var(--transition); + + border-width: var(--border-width); + border-style: var(--border-style); + border-color: var(--border-color); + + outline: none; + + background: var(--background); +} + +.card-native::-moz-focus-inner { + border: 0; +} + +button, a { + cursor: pointer; + user-select: none; + + -webkit-user-drag: none; +} + +// Card Button Ripple effect +// -------------------------------------------------- + +ion-ripple-effect { + color: var(--ripple-color); +} \ No newline at end of file diff --git a/core/src/components/card/card.tsx b/core/src/components/card/card.tsx index a140e5e54e..adf532cc31 100644 --- a/core/src/components/card/card.tsx +++ b/core/src/components/card/card.tsx @@ -1,7 +1,7 @@ import { Component, ComponentInterface, Prop } from '@stencil/core'; -import { Color, Mode } from '../../interface'; -import { createColorClasses } from '../../utils/theme'; +import { Color, Mode, RouterDirection } from '../../interface'; +import { createColorClasses, openURL } from '../../utils/theme'; @Component({ tag: 'ion-card', @@ -13,6 +13,8 @@ import { createColorClasses } from '../../utils/theme'; }) export class Card implements ComponentInterface { + @Prop({ context: 'window' }) win!: Window; + /** * The color to use from your application's color palette. * Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. @@ -25,12 +27,72 @@ export class Card implements ComponentInterface { */ @Prop() mode!: Mode; + /** + * If `true`, a button tag will be rendered and the card will be tappable. + */ + @Prop() button = false; + + /** + * The type of the button. Only used when an `onclick` or `button` property is present. + */ + @Prop() type: 'submit' | 'reset' | 'button' = 'button'; + + /** + * If `true`, the user cannot interact with the card. + */ + @Prop() disabled = false; + + /** + * Contains a URL or a URL fragment that the hyperlink points to. + * If this property is set, an anchor tag will be rendered. + */ + @Prop() href?: string; + + /** + * When using a router, it specifies the transition direction when navigating to + * another page using `href`. + */ + @Prop() routerDirection: RouterDirection = 'forward'; + + private isClickable(): boolean { + return (this.href !== undefined || this.button); + } + hostData() { return { class: { + [`${this.mode}`]: true, + ...createColorClasses(this.color), - [`${this.mode}`]: true + 'card-disabled': this.disabled, + 'ion-activatable': this.isClickable() } }; } + + render() { + const clickable = this.isClickable(); + + if (!clickable) { + return [ + + ]; + } + + const { href, mode, win, routerDirection, type } = this; + const TagType = clickable ? (href === undefined ? 'button' : 'a') : 'div' as any; + const attrs = TagType === 'button' ? { type } : { href }; + + return ( + openURL(win, href, ev, routerDirection)} + > + + {clickable && mode === 'md' && } + + ); + } } diff --git a/core/src/components/card/readme.md b/core/src/components/card/readme.md index 4cf5f8d0f6..808c40ef77 100644 --- a/core/src/components/card/readme.md +++ b/core/src/components/card/readme.md @@ -182,10 +182,15 @@ export default Example; ## Properties -| Property | Attribute | Description | Type | Default | -| -------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | ----------- | -| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` | -| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` | +| Property | Attribute | Description | Type | Default | +| ----------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | ----------- | +| `button` | `button` | If `true`, a button tag will be rendered and the card will be tappable. | `boolean` | `false` | +| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` | +| `disabled` | `disabled` | If `true`, the user cannot interact with the card. | `boolean` | `false` | +| `href` | `href` | Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. | `string \| undefined` | `undefined` | +| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` | +| `routerDirection` | `router-direction` | When using a router, it specifies the transition direction when navigating to another page using `href`. | `"back" \| "forward" \| "root"` | `'forward'` | +| `type` | `type` | The type of the button. Only used when an `onclick` or `button` property is present. | `"button" \| "reset" \| "submit"` | `'button'` | ## CSS Custom Properties diff --git a/core/src/components/card/test/button/index.html b/core/src/components/card/test/button/index.html new file mode 100644 index 0000000000..abdc9a930a --- /dev/null +++ b/core/src/components/card/test/button/index.html @@ -0,0 +1,82 @@ + + + + + + Card - Basic + + + + + + + + + + + + + Card - Button + + + + + + + + + Subtitle + + + Button Card + + + + + This is content, inside of a card with a button attribute. + + + + + + + Anchor Card + + + + + This is content, inside of a card with a href attribute. + + + + +
+ +
+ + + + Subtitle + + + Title + + + + + This button should have a background. + +
+ +
+ +
+ + + +