import { Attribute, ChangeDetectionStrategy, Component, ElementRef, Input, Renderer, ViewEncapsulation } from '@angular/core'; import { Config } from '../../config/config'; import { isTrueProperty } from '../../util/util'; /** * @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. * * @property [outline] - A transparent button with a border. * @property [clear] - A transparent button without a border. * @property [round] - A button with rounded corners. * @property [block] - A button that fills its parent container with a border-radius. * @property [full] - A button that fills its parent container without a border-radius or borders on the left/right. * @property [small] - A button with size small. * @property [large] - A button with size large. * @property [disabled] - A disabled button. * @property [fab] - A floating action button. * @property [fab-left] - Position a fab button to the left. * @property [fab-right] - Position a fab button to the right. * @property [fab-center] - Position a fab button towards the center. * @property [fab-top] - Position a fab button towards the top. * @property [fab-bottom] - Position a fab button towards the bottom. * @property [fab-fixed] - Makes a fab button have a fixed position. * @property [color] - Dynamically set which predefined color this button should use (e.g. primary, secondary, danger, etc). * * @usage * * ```html * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ``` * * @demo /docs/v2/demos/button/ * @see {@link /docs/v2/components#buttons Button Component Docs} */ @Component({ selector: '[ion-button]', // NOTE: template must not contain spaces between elements template: '', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, }) export class Button { private _role: string = 'button'; // bar-button private _mt: boolean = false; // menutoggle private _size: string = null; // large/small/default private _style: string = 'default'; // outline/clear/solid private _shape: string = null; // round/fab private _display: string = null; // block/full private _color: string = null; // primary/secondary private _disabled: boolean = false; // disabled private _init: boolean; /** * @input {string} Large button. */ @Input() set large(val: boolean) { this._attr('_size', 'large', val); } /** * @input {string} Small button. */ @Input() set small(val: boolean) { this._attr('_size', 'small', val); } /** * @input {string} Default button. */ @Input() set default(val: boolean) { this._attr('_size', 'default', val); } /** * @input {string} A transparent button with a border. */ @Input() set outline(val: boolean) { this._attr('_style', 'outline', val); } /** * @input {string} A transparent button without a border. */ @Input() set clear(val: boolean) { this._attr('_style', 'clear', val); } /** * @input {string} Force a solid button. Useful for buttons within an item. */ @Input() set solid(val: boolean) { this._attr('_style', 'solid', val); } /** * @input {string} A button with rounded corners. */ @Input() set round(val: boolean) { this._attr('_shape', 'round', val); } /** * @input {string} A floating action button. */ @Input() set fab(val: boolean) { this._attr('_shape', 'fab', val); } /** * @input {string} A button that fills its parent container with a border-radius. */ @Input() set block(val: boolean) { this._attr('_display', 'block', val); } /** * @input {string} A button that fills its parent container without a border-radius or borders on the left/right. */ @Input() set full(val: boolean) { this._attr('_display', 'full', val); } _attr(type: string, attrName: string, attrValue: boolean) { if (type === '_style') { this._setColor(this._color, isTrueProperty(attrValue)); } this._setClass(this[type], false); if (isTrueProperty(attrValue)) { this[type] = attrName; this._setClass(attrName, true); } else { // Special handling for '_style' which defaults to 'default'. this[type] = (type === '_style' ? 'default' : null); this._setClass(this[type], true); } } /** * @input {string} Dynamically set which predefined color this button should use (e.g. primary, secondary, danger, etc). */ @Input() set color(val: string) { this._updateColor(val); } constructor( @Attribute('menuToggle') menuToggle: string, @Attribute('ion-button') ionButton: string, config: Config, private _elementRef: ElementRef, private _renderer: Renderer ) { let element = _elementRef.nativeElement; if (config.get('hoverCSS') === false) { _renderer.setElementClass(element, 'disable-hover', true); } if (element.hasAttribute('disabled')) { this._disabled = true; } if (ionButton.trim().length > 0) { this.setRole(ionButton); } // menuToggle can be added with or without a string // but if the attribute isn't added it will be null if (menuToggle !== null) { this._mt = true; } } /** * @private */ ngAfterContentInit() { this._init = true; this._assignCss(true); } /** * @internal */ _updateColor(newColor: string) { this._setColor(this._color, false); this._setColor(newColor, true); this._color = newColor; } /** * @private */ addClass(className: string) { this._renderer.setElementClass(this._elementRef.nativeElement, className, true); } /** * @private */ setRole(val: string) { this._assignCss(false); this._role = val; this._assignCss(true); } /** * @private */ private _assignCss(assignCssClass: boolean) { let role = this._role; if (role) { this._renderer.setElementClass(this._elementRef.nativeElement, role, assignCssClass); // button this._setClass('menutoggle', this._mt); // menutoggle this._setClass(this._style, assignCssClass); // button-clear this._setClass(this._shape, assignCssClass); // button-round this._setClass(this._display, assignCssClass); // button-full this._setClass(this._size, assignCssClass); // button-small this._setColor(this._color, assignCssClass); // button-secondary, bar-button-secondary } } /** * @internal */ _setClass(type: string, assignCssClass: boolean) { if (type && this._init) { this._renderer.setElementClass(this._elementRef.nativeElement, this._role + '-' + type.toLowerCase(), assignCssClass); } } /** * @internal */ _setColor(color: string, isAdd: boolean) { if (color && this._init) { // The class should begin with the button role // button, bar-button let className = this._role; // If the role is not a bar-button, don't apply the solid style let style = this._style; style = (this._role !== 'bar-button' && style === 'solid' ? 'default' : style); className += (style !== null && style !== '' && style !== 'default' ? '-' + style.toLowerCase() : ''); if (color !== null && color !== '') { this._renderer.setElementClass(this._elementRef.nativeElement, `${className}-${color}`, isAdd); } } } }