UNPKG

@ionic/core

Version:

Base components for Ionic

445 lines (444 loc) • 14.1 kB
import { Component, Element, Event, Host, Prop, h } from '@stencil/core'; import { getIonMode } from '../../global/ionic-global'; import { hasShadowDom, inheritAttributes } from '../../utils/helpers'; import { createColorClasses, hostContext, openURL } from '../../utils/theme'; /** * @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use. * * @slot - Content is placed between the named slots if provided without a slot. * @slot icon-only - Should be used on an icon in a button that has no text. * @slot start - Content is placed to the left of the button text in LTR, and to the right in RTL. * @slot end - Content is placed to the right of the button text in LTR, and to the left in RTL. * * @part native - The native HTML button or anchor element that wraps all child elements. */ export class Button { constructor() { this.inItem = false; this.inListHeader = false; this.inToolbar = false; this.inheritedAttributes = {}; /** * The type of button. */ this.buttonType = 'button'; /** * If `true`, the user cannot interact with the button. */ this.disabled = false; /** * When using a router, it specifies the transition direction when navigating to * another page using `href`. */ this.routerDirection = 'forward'; /** * If `true`, activates a button with a heavier font weight. */ this.strong = false; /** * The type of the button. */ this.type = 'button'; this.handleClick = (ev) => { if (this.type === 'button') { openURL(this.href, ev, this.routerDirection, this.routerAnimation); } else if (hasShadowDom(this.el)) { // this button wants to specifically submit a form // climb up the dom to see if we're in a <form> // and if so, then use JS to submit it const form = this.el.closest('form'); if (form) { ev.preventDefault(); const fakeButton = document.createElement('button'); fakeButton.type = this.type; fakeButton.style.display = 'none'; form.appendChild(fakeButton); fakeButton.click(); fakeButton.remove(); } } }; this.onFocus = () => { this.ionFocus.emit(); }; this.onBlur = () => { this.ionBlur.emit(); }; } componentWillLoad() { this.inToolbar = !!this.el.closest('ion-buttons'); this.inListHeader = !!this.el.closest('ion-list-header'); this.inItem = !!this.el.closest('ion-item') || !!this.el.closest('ion-item-divider'); this.inheritedAttributes = inheritAttributes(this.el, ['aria-label']); } get hasIconOnly() { return !!this.el.querySelector('[slot="icon-only"]'); } get rippleType() { const hasClearFill = this.fill === undefined || this.fill === 'clear'; // If the button is in a toolbar, has a clear fill (which is the default) // and only has an icon we use the unbounded "circular" ripple effect if (hasClearFill && this.hasIconOnly && this.inToolbar) { return 'unbounded'; } return 'bounded'; } render() { const mode = getIonMode(this); const { buttonType, type, disabled, rel, target, size, href, color, expand, hasIconOnly, shape, strong, inheritedAttributes } = this; const finalSize = size === undefined && this.inItem ? 'small' : size; const TagType = href === undefined ? 'button' : 'a'; const attrs = (TagType === 'button') ? { type } : { download: this.download, href, rel, target }; let fill = this.fill; if (fill === undefined) { fill = this.inToolbar || this.inListHeader ? 'clear' : 'solid'; } return (h(Host, { onClick: this.handleClick, "aria-disabled": disabled ? 'true' : null, class: createColorClasses(color, { [mode]: true, [buttonType]: true, [`${buttonType}-${expand}`]: expand !== undefined, [`${buttonType}-${finalSize}`]: finalSize !== undefined, [`${buttonType}-${shape}`]: shape !== undefined, [`${buttonType}-${fill}`]: true, [`${buttonType}-strong`]: strong, 'in-toolbar': hostContext('ion-toolbar', this.el), 'in-toolbar-color': hostContext('ion-toolbar[color]', this.el), 'button-has-icon-only': hasIconOnly, 'button-disabled': disabled, 'ion-activatable': true, 'ion-focusable': true, }) }, h(TagType, Object.assign({}, attrs, { class: "button-native", part: "native", disabled: disabled, onFocus: this.onFocus, onBlur: this.onBlur }, inheritedAttributes), h("span", { class: "button-inner" }, h("slot", { name: "icon-only" }), h("slot", { name: "start" }), h("slot", null), h("slot", { name: "end" })), mode === 'md' && h("ion-ripple-effect", { type: this.rippleType })))); } static get is() { return "ion-button"; } static get encapsulation() { return "shadow"; } static get originalStyleUrls() { return { "ios": ["button.ios.scss"], "md": ["button.md.scss"] }; } static get styleUrls() { return { "ios": ["button.ios.css"], "md": ["button.md.css"] }; } static get properties() { return { "color": { "type": "string", "mutable": false, "complexType": { "original": "Color", "resolved": "string | undefined", "references": { "Color": { "location": "import", "path": "../../interface" } } }, "required": false, "optional": true, "docs": { "tags": [], "text": "The color to use from your application's color palette.\nDefault options are: `\"primary\"`, `\"secondary\"`, `\"tertiary\"`, `\"success\"`, `\"warning\"`, `\"danger\"`, `\"light\"`, `\"medium\"`, and `\"dark\"`.\nFor more information on colors, see [theming](/docs/theming/basics)." }, "attribute": "color", "reflect": true }, "buttonType": { "type": "string", "mutable": true, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "The type of button." }, "attribute": "button-type", "reflect": false, "defaultValue": "'button'" }, "disabled": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "If `true`, the user cannot interact with the button." }, "attribute": "disabled", "reflect": true, "defaultValue": "false" }, "expand": { "type": "string", "mutable": false, "complexType": { "original": "'full' | 'block'", "resolved": "\"block\" | \"full\" | undefined", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "Set to `\"block\"` for a full-width button or to `\"full\"` for a full-width button\nwithout left and right borders." }, "attribute": "expand", "reflect": true }, "fill": { "type": "string", "mutable": true, "complexType": { "original": "'clear' | 'outline' | 'solid' | 'default'", "resolved": "\"clear\" | \"default\" | \"outline\" | \"solid\" | undefined", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "Set to `\"clear\"` for a transparent button, to `\"outline\"` for a transparent\nbutton with a border, or to `\"solid\"`. The default style is `\"solid\"` except inside of\na toolbar, where the default is `\"clear\"`." }, "attribute": "fill", "reflect": true }, "routerDirection": { "type": "string", "mutable": false, "complexType": { "original": "RouterDirection", "resolved": "\"back\" | \"forward\" | \"root\"", "references": { "RouterDirection": { "location": "import", "path": "../../interface" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "When using a router, it specifies the transition direction when navigating to\nanother page using `href`." }, "attribute": "router-direction", "reflect": false, "defaultValue": "'forward'" }, "routerAnimation": { "type": "unknown", "mutable": false, "complexType": { "original": "AnimationBuilder | undefined", "resolved": "((baseEl: any, opts?: any) => Animation) | undefined", "references": { "AnimationBuilder": { "location": "import", "path": "../../interface" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "When using a router, it specifies the transition animation when navigating to\nanother page using `href`." } }, "download": { "type": "string", "mutable": false, "complexType": { "original": "string | undefined", "resolved": "string | undefined", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "This attribute instructs browsers to download a URL instead of navigating to\nit, so the user will be prompted to save it as a local file. If the attribute\nhas a value, it is used as the pre-filled file name in the Save prompt\n(the user can still change the file name if they want)." }, "attribute": "download", "reflect": false }, "href": { "type": "string", "mutable": false, "complexType": { "original": "string | undefined", "resolved": "string | undefined", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Contains a URL or a URL fragment that the hyperlink points to.\nIf this property is set, an anchor tag will be rendered." }, "attribute": "href", "reflect": false }, "rel": { "type": "string", "mutable": false, "complexType": { "original": "string | undefined", "resolved": "string | undefined", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Specifies the relationship of the target object to the link object.\nThe value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types)." }, "attribute": "rel", "reflect": false }, "shape": { "type": "string", "mutable": false, "complexType": { "original": "'round'", "resolved": "\"round\" | undefined", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "The button shape." }, "attribute": "shape", "reflect": true }, "size": { "type": "string", "mutable": false, "complexType": { "original": "'small' | 'default' | 'large'", "resolved": "\"default\" | \"large\" | \"small\" | undefined", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "The button size." }, "attribute": "size", "reflect": true }, "strong": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "If `true`, activates a button with a heavier font weight." }, "attribute": "strong", "reflect": false, "defaultValue": "false" }, "target": { "type": "string", "mutable": false, "complexType": { "original": "string | undefined", "resolved": "string | undefined", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Specifies where to display the linked URL.\nOnly applies when an `href` is provided.\nSpecial keywords: `\"_blank\"`, `\"_self\"`, `\"_parent\"`, `\"_top\"`." }, "attribute": "target", "reflect": false }, "type": { "type": "string", "mutable": false, "complexType": { "original": "'submit' | 'reset' | 'button'", "resolved": "\"button\" | \"reset\" | \"submit\"", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "The type of the button." }, "attribute": "type", "reflect": false, "defaultValue": "'button'" } }; } static get events() { return [{ "method": "ionFocus", "name": "ionFocus", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Emitted when the button has focus." }, "complexType": { "original": "void", "resolved": "void", "references": {} } }, { "method": "ionBlur", "name": "ionBlur", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Emitted when the button loses focus." }, "complexType": { "original": "void", "resolved": "void", "references": {} } }]; } static get elementRef() { return "el"; } }