Skip to content

Commit

Permalink
feat(card): add button functionality (#17997)
Browse files Browse the repository at this point in the history
closes #17773
  • Loading branch information
jlbeard84 authored and brandyscarney committed May 7, 2019
1 parent ef98977 commit 669ec0d
Show file tree
Hide file tree
Showing 9 changed files with 266 additions and 9 deletions.
4 changes: 2 additions & 2 deletions angular/src/directives/proxies.ts
Expand Up @@ -85,15 +85,15 @@ export class IonButtons {
}

export declare interface IonCard extends StencilComponents<'IonCard'> {}
@Component({ selector: 'ion-card', changeDetection: 0, template: '<ng-content></ng-content>', inputs: ['color', 'mode'] })
@Component({ selector: 'ion-card', changeDetection: 0, template: '<ng-content></ng-content>', inputs: ['color', 'mode', 'button', 'type', 'disabled', 'href', 'routerDirection'] })
export class IonCard {
protected el: HTMLElement;
constructor(c: ChangeDetectorRef, r: ElementRef) {
c.detach();
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: '<ng-content></ng-content>', inputs: ['mode'] })
Expand Down
5 changes: 5 additions & 0 deletions core/api.txt
Expand Up @@ -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

Expand Down
40 changes: 40 additions & 0 deletions core/src/components.d.ts
Expand Up @@ -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 {
Expand Down
6 changes: 6 additions & 0 deletions core/src/components/card/card.ios.scss
Expand Up @@ -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};
}
6 changes: 6 additions & 0 deletions core/src/components/card/card.ios.vars.scss
Expand Up @@ -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;
51 changes: 51 additions & 0 deletions core/src/components/card/card.scss
Expand Up @@ -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);
}
68 changes: 65 additions & 3 deletions 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',
Expand All @@ -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"`.
Expand All @@ -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 [
<slot></slot>
];
}

const { href, mode, win, routerDirection, type } = this;
const TagType = clickable ? (href === undefined ? 'button' : 'a') : 'div' as any;
const attrs = TagType === 'button' ? { type } : { href };

return (
<TagType
{...attrs}
class="card-native"
disabled={this.disabled}
onClick={(ev: Event) => openURL(win, href, ev, routerDirection)}
>
<slot></slot>
{clickable && mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
</TagType>
);
}
}
13 changes: 9 additions & 4 deletions core/src/components/card/readme.md
Expand Up @@ -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
Expand Down
82 changes: 82 additions & 0 deletions core/src/components/card/test/button/index.html
@@ -0,0 +1,82 @@
<!DOCTYPE html>
<html dir="ltr">

<head>
<meta charset="UTF-8">
<title>Card - Basic</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet">
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet">
<script src="../../../../../scripts/testing/scripts.js"></script>
<script src="../../../../../dist/ionic.js"></script>
</head>

<body>
<ion-app>

<ion-header>
<ion-toolbar>
<ion-title>Card - Button</ion-title>
</ion-toolbar>
</ion-header>

<ion-content id="content">

<ion-card button>
<ion-card-header>
<ion-card-subtitle>
Subtitle
</ion-card-subtitle>
<ion-card-title>
Button Card
</ion-card-title>
</ion-card-header>

<ion-card-content>
This is content, inside of a card with a button attribute.
</ion-card-content>
</ion-card>

<ion-card href="#">
<ion-card-header>
<ion-card-title>
Anchor Card
</ion-card-title>
</ion-card-header>

<ion-card-content>
This is content, inside of a card with a href attribute.
</ion-card-content>
</ion-card>

<ion-card button>
<div style="position: absolute; top: 0; left:0; right:0; bottom:0;">
<img src="https://images.unsplash.com/photo-1483354483454-4cd359948304?dpr=1&auto=format&fit=crop&w=1000&q=80&cs=tinysrgb&ixid=dW5zcGxhc2guY29tOzs7Ozs%3D">
</div>

<ion-card-header>
<ion-card-subtitle>
Subtitle
</ion-card-subtitle>
<ion-card-title>
Title
</ion-card-title>
</ion-card-header>

<ion-card-content>
This button should have a background.
</ion-card-content>
</ion-card>

</ion-content>

</ion-app>
<style>
.content {
background: #e5e5e5;
}

</style>
</body>

</html>

0 comments on commit 669ec0d

Please sign in to comment.