From 5571c8ff8a409548606d43b40337bf33957a7d6a Mon Sep 17 00:00:00 2001 From: Brandy Carney Date: Tue, 13 Jun 2017 15:22:30 -0400 Subject: [PATCH] feat(components): add core avatar and button components --- scripts/gulp/util.ts | 6 +- src/components/avatar/avatar.ios.scss | 6 + src/components/avatar/avatar.md.scss | 6 + src/components/avatar/avatar.scss | 9 + src/components/avatar/avatar.tsx | 27 +++ src/components/avatar/avatar.wp.scss | 6 + src/components/button/button-icon.scss | 22 +- src/components/button/button.ios.scss | 3 +- src/components/button/button.md.scss | 7 +- src/components/button/button.scss | 4 + src/components/button/button.tsx | 288 +++++++++++++++++++++++++ src/components/button/button.wp.scss | 5 +- src/index.ts | 2 - src/module.ts | 6 - 14 files changed, 365 insertions(+), 32 deletions(-) create mode 100644 src/components/avatar/avatar.ios.scss create mode 100644 src/components/avatar/avatar.md.scss create mode 100644 src/components/avatar/avatar.scss create mode 100644 src/components/avatar/avatar.tsx create mode 100644 src/components/avatar/avatar.wp.scss create mode 100644 src/components/button/button.tsx diff --git a/scripts/gulp/util.ts b/scripts/gulp/util.ts index 3091d17a7b..1edc62dbc1 100644 --- a/scripts/gulp/util.ts +++ b/scripts/gulp/util.ts @@ -57,16 +57,18 @@ export function createTempTsConfig(includeGlob: string[], target: string, module } config.include = includeGlob; const componentsToExclude = [ + 'avatar', 'badge', + 'button', 'card', 'card-content', 'card-header', 'card-title', + 'gesture', 'icon', 'scroll', 'slides', - 'toggle', - 'gesture' + 'toggle' ]; config.exclude = componentsToExclude.map(cmp => path.join(PROJECT_ROOT, `src/components/${cmp}`) + `/*.ts`) diff --git a/src/components/avatar/avatar.ios.scss b/src/components/avatar/avatar.ios.scss new file mode 100644 index 0000000000..f5bfb84c7d --- /dev/null +++ b/src/components/avatar/avatar.ios.scss @@ -0,0 +1,6 @@ +@import "../../themes/ionic.globals.ios"; +@import "./avatar"; + + +// iOS Avatar +// -------------------------------------------------- diff --git a/src/components/avatar/avatar.md.scss b/src/components/avatar/avatar.md.scss new file mode 100644 index 0000000000..4bbcd8cde6 --- /dev/null +++ b/src/components/avatar/avatar.md.scss @@ -0,0 +1,6 @@ +@import "../../themes/ionic.globals.md"; +@import "./avatar"; + + +// Material Design Avatar +// -------------------------------------------------- diff --git a/src/components/avatar/avatar.scss b/src/components/avatar/avatar.scss new file mode 100644 index 0000000000..951217f2bc --- /dev/null +++ b/src/components/avatar/avatar.scss @@ -0,0 +1,9 @@ +@import "../../themes/ionic.globals"; + + +// Avatar +// -------------------------------------------------- + +ion-avatar { + display: block; +} diff --git a/src/components/avatar/avatar.tsx b/src/components/avatar/avatar.tsx new file mode 100644 index 0000000000..d17f64dfa4 --- /dev/null +++ b/src/components/avatar/avatar.tsx @@ -0,0 +1,27 @@ +import { Component, h } from '../index'; + + +/** + * @name Avatar + * @module ionic + * @description + * An Avatar is a component that creates a circular image for an item. + * Avatars can be placed on the left or right side of an item with the `item-start` or `item-end` directive. + * @see {@link /docs/components/#avatar-list Avatar Component Docs} + */ +@Component({ + tag: 'ion-avatar', + styleUrls: { + ios: 'avatar.ios.scss', + md: 'avatar.md.scss', + wp: 'avatar.wp.scss' + }, + host: { + theme: 'avatar' + } +}) +export class Avatar { + render() { + return ; + } +} diff --git a/src/components/avatar/avatar.wp.scss b/src/components/avatar/avatar.wp.scss new file mode 100644 index 0000000000..73cb8e1155 --- /dev/null +++ b/src/components/avatar/avatar.wp.scss @@ -0,0 +1,6 @@ +@import "../../themes/ionic.globals.wp"; +@import "./avatar"; + + +// Windows Avatar +// -------------------------------------------------- diff --git a/src/components/button/button-icon.scss b/src/components/button/button-icon.scss index 9a603ff14c..fb80ffd82b 100644 --- a/src/components/button/button-icon.scss +++ b/src/components/button/button-icon.scss @@ -3,29 +3,19 @@ // Button Icons // -------------------------------------------------- -// Icons inside of buttons with text -@mixin button-icon { - font-size: 1.4em; - line-height: .67; - - pointer-events: none; -} - -[icon-left] ion-icon, // deprecated -[icon-start] ion-icon { - @include button-icon; +.button ion-icon[slot="start"] { + @include button-icon(); @include padding-horizontal(null, .3em); } -[icon-right] ion-icon, // deprecated -[icon-end] ion-icon { - @include button-icon; +.button ion-icon[slot="end"] { + @include button-icon(); @include padding-horizontal(.4em, null); } -.button[icon-only] { +[icon-only] .button { @include padding(0); min-width: .9em; @@ -38,4 +28,4 @@ line-height: .67; pointer-events: none; -} +} \ No newline at end of file diff --git a/src/components/button/button.ios.scss b/src/components/button/button.ios.scss index 0b53a53b3a..d531883f32 100644 --- a/src/components/button/button.ios.scss +++ b/src/components/button/button.ios.scss @@ -1,4 +1,5 @@ @import "../../themes/ionic.globals.ios"; +@import "./button"; // iOS Button // -------------------------------------------------- @@ -267,7 +268,7 @@ $button-ios-strong-font-weight: 600 !default; } } -.button-small-ios[icon-only] ion-icon { +[icon-only] .button-small-ios ion-icon { font-size: $button-ios-small-icon-font-size; } diff --git a/src/components/button/button.md.scss b/src/components/button/button.md.scss index dc4ca05fc5..874316649d 100644 --- a/src/components/button/button.md.scss +++ b/src/components/button/button.md.scss @@ -1,8 +1,10 @@ @import "../../themes/ionic.globals.md"; +@import "./button"; // Material Design Button // -------------------------------------------------- + // deprecated $button-md-margin: null !default; @@ -325,7 +327,7 @@ $button-md-strong-font-weight: bold !default; } } -.button-small-md[icon-only] ion-icon { +[icon-only] .button-small-md ion-icon { font-size: $button-md-small-icon-font-size; } @@ -459,7 +461,7 @@ $button-md-strong-font-weight: bold !default; } } -.button-md [icon-only] { +[icon-only] .button-md { @include padding(0); } @@ -487,7 +489,6 @@ $button-md-strong-font-weight: bold !default; @include multi-dir() { // scss-lint:disable PropertySpelling top: 0; - left: 0; } } diff --git a/src/components/button/button.scss b/src/components/button/button.scss index b806a5fc1f..c9461ca97c 100644 --- a/src/components/button/button.scss +++ b/src/components/button/button.scss @@ -1,4 +1,5 @@ @import "../../themes/ionic.globals"; +@import "button-icon"; // Buttons // -------------------------------------------------- @@ -26,6 +27,9 @@ $button-round-border-radius: 64px !default; @include text-align(center); @include appearance(none); + visibility: visible; + border: 0; + position: relative; z-index: 0; display: inline-block; diff --git a/src/components/button/button.tsx b/src/components/button/button.tsx new file mode 100644 index 0000000000..04d1382d76 --- /dev/null +++ b/src/components/button/button.tsx @@ -0,0 +1,288 @@ +import { Component, h, Prop } from '../index'; +import { CssClassObject } from '../../util/interfaces'; + +/** + * @name Button + * @module ionic + * @description + * Buttons are simple components in Ionic. They can consist of text and icons + * and be enhanced by a wide range of attributes. + * + * @usage + * + * ```html + * + * + * Default + * + * Secondary + * + * Danger + * + * Light + * + * Dark + * + * + * Full Button + * + * Block Button + * + * Round Button + * + * + * Outline + Full + * + * Outline + Block + * + * Outline + Round + * + * + * + * + * Left Icon + * + * + * + * Right Icon + * + * + * + * + * + * + * + * + * Large + * + * Default + * + * Small + * ``` + * + */ +@Component({ + tag: 'ion-button', + styleUrls: { + ios: 'button.ios.scss', + md: 'button.md.scss', + wp: 'button.wp.scss' + } +}) +export class Button { + @Prop() itemButton: boolean = false; + + @Prop() href: string; + + /** + * @Prop {string} The type of button. + * Possible values are: `"button"`, `"bar-button"`. + */ + @Prop() buttonType: string = 'button'; + + /** + * @Prop {boolean} If true, activates the large button size. + * Type: size + */ + @Prop() large: boolean = false; + + /** + * @Prop {boolean} If true, activates the small button size. + * Type: size + */ + @Prop() small: boolean = false; + + /** + * @Prop {boolean} If true, activates the default button size. Normally the default, useful for buttons in an item. + * Type: size + */ + @Prop() default: boolean = false; + + /** + * @Prop {boolean} If true, sets the button into a disabled state. + */ + @Prop() disabled: boolean = false; + + /** + * @Prop {boolean} If true, activates a transparent button style with a border. + * Type: style + */ + @Prop() outline: boolean = false; + + /** + * @Prop {boolean} If true, activates a transparent button style without a border. + * Type: style + */ + @Prop() clear: boolean = false; + + /** + * @Prop {boolean} If true, activates a solid button style. Normally the default, useful for buttons in a toolbar. + * Type: style + */ + @Prop() solid: boolean = false; + + /** + * @Prop {boolean} If true, activates a button with rounded corners. + * Type: shape + */ + @Prop() round: boolean = false; + + /** + * @Prop {boolean} If true, activates a button style that fills the available width. + * Type: display + */ + @Prop() block: boolean = false; + + /** + * @Prop {boolean} If true, activates a button style that fills the available width without + * a left and right border. + * Type: display + */ + @Prop() full: boolean = false; + + /** + * @Prop {boolean} If true, activates a button with a heavier font weight. + * Type: decorator + */ + @Prop() strong: boolean = false; + + /** + * @Prop {string} The mode determines which platform styles to use. + * Possible values are: `"ios"`, `"md"`, or `"wp"`. + * For more information, see [Platform Styles](/docs/theming/platform-specific-styles). + */ + @Prop() mode: 'ios' | 'md' | 'wp'; + + /** + * @Prop {string} The color to use from your Sass `$colors` map. + * Default options are: `"primary"`, `"secondary"`, `"danger"`, `"light"`, and `"dark"`. + * For more information, see [Theming your App](/docs/theming/theming-your-app). + */ + @Prop() color: string; + + /** + * @hidden + */ + getElementClassList(buttonType: string, mode: string): string[] { + if (!buttonType) { + return []; + } + return [ + buttonType, + `${buttonType}-${mode}` + ]; + } + + + /** + * @hidden + */ + getClassList(buttonType: string, type: string, mode: string): string[] { + if (!type) { + return []; + } + type = type.toLocaleLowerCase(); + return [ + `${buttonType}-${type}`, + `${buttonType}-${type}-${mode}` + ]; + } + + /** + * @hidden + */ + getColorClassList(color: string, buttonType: string, style: string, mode: string): string[] { + style = (buttonType !== 'bar-button' && style === 'solid') ? 'default' : style; + let className = + buttonType + + ((style && style !== 'default') ? + '-' + style.toLowerCase() : + ''); + + // special case for a default bar button + // if the bar button is default it should get the style + // but if a color is passed the style shouldn't be added + if (buttonType === 'bar-button' && style === 'default') { + className = buttonType; + if (!color) { + className += '-' + style.toLowerCase(); + } + } + + return [`${className}-${mode}`].concat( + color ? `${className}-${mode}-${color}` : [] + ); + } + + /** + * @hidden + */ + getStyleClassList(buttonType: string): string[] { + let classList = [].concat( + this.outline ? this.getColorClassList(this.color, buttonType, 'outline', this.mode) : [], + this.clear ? this.getColorClassList(this.color, buttonType, 'clear', this.mode) : [], + this.solid ? this.getColorClassList(this.color, buttonType, 'solid', this.mode) : [] + ); + + if (classList.length === 0) { + classList = this.getColorClassList(this.color, buttonType, 'default', this.mode); + } + + return classList; + } + + /** + * @hidden + * Whether or not to add the item-button class + */ + getItemClassList(size: string) { + let classList = [].concat( + this.itemButton && !size ? 'item-button' : [] + ); + + return classList; + } + + render() { + const size = + (this.large ? 'large' : null) || + (this.small ? 'small' : null) || + (this.default ? 'default' : null); + + const shape = (this.round ? 'round' : null); + + const display = + (this.block ? 'block' : null) || + (this.full ? 'full' : null); + + const decorator = (this.strong ? 'strong' : null); + + const buttonClasses: CssClassObject = [] + .concat( + this.getElementClassList(this.buttonType, this.mode), + this.getClassList(this.buttonType, shape, this.mode), + this.getClassList(this.buttonType, display, this.mode), + this.getClassList(this.buttonType, size, this.mode), + this.getClassList(this.buttonType, decorator, this.mode), + this.getStyleClassList(this.buttonType), + this.getItemClassList(size) + ) + .reduce((prevValue, cssClass) => { + prevValue[cssClass] = true; + return prevValue; + }, {}); + + const TagType = this.href ? 'a' : 'button'; + + return ( + + + + + + +
+
+ ); + } +} diff --git a/src/components/button/button.wp.scss b/src/components/button/button.wp.scss index d5b67f1610..e04a0ca0ef 100644 --- a/src/components/button/button.wp.scss +++ b/src/components/button/button.wp.scss @@ -1,4 +1,5 @@ @import "../../themes/ionic.globals.wp"; +@import "./button"; // Windows Button // -------------------------------------------------- @@ -265,7 +266,7 @@ $button-wp-strong-font-weight: bold !default; } } -.button-small-wp[icon-only] ion-icon { +[icon-only] .button-small-wp ion-icon { font-size: $button-wp-small-icon-font-size; } @@ -379,7 +380,7 @@ $button-wp-strong-font-weight: bold !default; } } -.button-wp [icon-only] { +[icon-only] .button-wp { @include padding(0); } diff --git a/src/index.ts b/src/index.ts index 174e41895d..78a487b12c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,9 +10,7 @@ export { AlertController } from './components/alert/alert-controller'; export { AlertOptions } from './components/alert/alert-options'; export { AlertCmp } from './components/alert/alert-component'; export { App } from './components/app/app'; -export { Avatar } from './components/avatar/avatar'; export { Backdrop } from './components/backdrop/backdrop'; -export { Button } from './components/button/button'; export { Checkbox } from './components/checkbox/checkbox'; export { Chip } from './components/chip/chip'; export { Content, ScrollEvent } from './components/content/content'; diff --git a/src/module.ts b/src/module.ts index 79152a01bf..af20b8d396 100644 --- a/src/module.ts +++ b/src/module.ts @@ -48,9 +48,7 @@ import { AlertController } from './components/alert/alert-controller'; import { ClickBlock } from './components/app/click-block'; import { IonicApp } from './components/app/app-root'; import { OverlayPortal } from './components/app/overlay-portal'; -import { Avatar } from './components/avatar/avatar'; import { Backdrop } from './components/backdrop/backdrop'; -import { Button } from './components/button/button'; import { Checkbox } from './components/checkbox/checkbox'; import { Chip } from './components/chip/chip'; import { Content } from './components/content/content'; @@ -180,9 +178,7 @@ import { BooleanInput } from './bindings/angular/components/boolean-input'; ClickBlock, IonicApp, OverlayPortal, - Avatar, Backdrop, - Button, Checkbox, Chip, Col, @@ -274,9 +270,7 @@ import { BooleanInput } from './bindings/angular/components/boolean-input'; ClickBlock, IonicApp, OverlayPortal, - Avatar, Backdrop, - Button, Checkbox, Chip, Col,