From c6170fc1be237d688dc180d9cd1c031e49fbfa96 Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Mon, 1 May 2017 11:54:57 -0500 Subject: [PATCH] fix(toggle): update toggle js --- src/components/toggle/toggle.scss | 5 + src/components/toggle/toggle.ts | 237 +++++++++++++++++------------- 2 files changed, 138 insertions(+), 104 deletions(-) diff --git a/src/components/toggle/toggle.scss b/src/components/toggle/toggle.scss index c539e5ba7c..a9860eeb39 100644 --- a/src/components/toggle/toggle.scss +++ b/src/components/toggle/toggle.scss @@ -4,12 +4,17 @@ // Toggle // -------------------------------------------------- +ion-toggle, :host { display: inline-block; visibility: inherit !important; contain: content; } +ion-gesture { + display: block; + visibility: inherit !important; +} .toggle-cover { position: absolute; diff --git a/src/components/toggle/toggle.ts b/src/components/toggle/toggle.ts index bca1457c37..286bc26d15 100644 --- a/src/components/toggle/toggle.ts +++ b/src/components/toggle/toggle.ts @@ -1,117 +1,146 @@ -import { Component, h, Ionic } from '../index'; +import { BooleanInputComponent, GestureDetail } from '../../util/interfaces'; +import { Component, h, Ionic, Listen, Prop, Watch } from '../index'; -/** - * @name Toolbar - * @description - * A Toolbar is a generic bar that is positioned above or below content. - * Unlike a [Navbar](../../navbar/Navbar), a toolbar can be used as a subheader. - * When toolbars are placed within an `` or ``, - * the toolbars stay fixed in their respective location. When placed within - * ``, toolbars will scroll with the content. - * - * - * ### Buttons in a Toolbar - * Buttons placed in a toolbar should be placed inside of the `` - * element. An exception to this is a [menuToggle](../../menu/MenuToggle) button. - * It should not be placed inside of the `` element. Both the - * `` element and the `menuToggle` can be positioned inside of the - * toolbar using different properties. The below chart has a description of each - * property. - * - * | Property | Description | - * |-------------|-----------------------------------------------------------------------------------------------------------------------| - * | `start` | Positions element to the left of the content in `ios` mode, and directly to the right in `md` and `wp` mode. | - * | `end` | Positions element to the right of the content in `ios` mode, and to the far right in `md` and `wp` mode. | - * | `left` | Positions element to the left of all other elements. | - * | `right` | Positions element to the right of all other elements. | - * - * - * ### Header / Footer Box Shadow and Border - * In `md` mode, the `` will receive a box-shadow on the bottom, and the - * `` will receive a box-shadow on the top. In `ios` mode, the `` - * will receive a border on the bottom, and the `` will receive a border on the - * top. Both the `md` box-shadow and the `ios` border can be removed by adding the `no-border` - * attribute to the element. - * - * ```html - * - * - * Header - * - * - * - * - * - * - * - * - * Footer - * - * - * ``` - * - * @usage - * - * ```html - * - * - * - * - * My Toolbar Title - * - * - * - * I'm a subheader - * - * - * - * - * - * - * - * - * Scrolls with the content - * - * - * - * - * - * - * - * - * I'm a footer - * - * - * - * ``` - * - * @demo /docs/demos/src/toolbar/ - * @see {@link ../../navbar/Navbar/ Navbar API Docs} - */ @Component({ - tag: 'ion-toolbar', + tag: 'ion-toggle', styleUrls: { - ios: 'toolbar.ios.scss', - md: 'toolbar.md.scss', - wp: 'toolbar.wp.scss' + ios: 'toggle.ios.scss', + md: 'toggle.md.scss', + wp: 'toggle.wp.scss' } }) -export class Toolbar { - private sbPadding: boolean; +export class Toggle implements BooleanInputComponent { + activated: boolean; + hasFocus: boolean; + id: string; + labelId: string; + startX: number; - constructor() { - this.sbPadding = Ionic.config.getBoolean('statusbarPadding'); + @Prop() checked: boolean; + @Prop() disabled: boolean; + @Prop() value: string; + + + @Watch('checked') + changed(val: boolean) { + Ionic.emit(this, 'ionChange', { detail: { checked: val } }); } + + canStart() { + return !this.disabled; + } + + + onDragStart(detail: GestureDetail) { + this.startX = detail.startX; + this.fireFocus(); + } + + + onDragMove(detail: GestureDetail) { + if (this.checked) { + if (detail.currentX + 15 < this.startX) { + this.checked = false; + this.activated = true; + this.startX = detail.currentX; + } + + } else if (detail.currentX - 15 > this.startX) { + this.checked = true; + this.activated = (detail.currentX < this.startX + 5); + this.startX = detail.currentX; + } + } + + + onDragEnd(detail: GestureDetail) { + if (this.checked) { + if (detail.startX + 4 > detail.currentX) { + this.checked = false; + } + + } else if (detail.startX - 4 < detail.currentX) { + this.checked = true; + } + + this.activated = false; + this.fireBlur(); + this.startX = null; + } + + + @Listen('keydown.space') + onSpace(ev: KeyboardEvent) { + this.toggle(); + ev.stopPropagation(); + ev.preventDefault(); + } + + + toggle() { + if (!this.disabled) { + this.checked = !this.checked; + this.fireFocus(); + } + } + + + fireFocus() { + if (!this.hasFocus) { + this.hasFocus = true; + Ionic.emit(this, 'ionFocus'); + } + } + + + fireBlur() { + if (this.hasFocus) { + this.hasFocus = false; + Ionic.emit(this, 'ionBlur'); + } + } + + render() { - return h(this, { class: { 'statusbar-padding': this.sbPadding } }, - h('div', Ionic.theme(this, 'toolbar'), [ - h('div', Ionic.theme(this, 'toolbar-background')), - h('div', Ionic.theme(this, 'toolbar-content'), - h('slot') - ), - ]) + return h(this, + h('ion-gesture', Ionic.theme(this, 'toggle', { + class: { + 'toggle-activated': this.activated, + 'toggle-checked': this.checked, + 'toggle-disabled': this.disabled, + }, + props: { + 'canStart': this.canStart.bind(this), + 'onStart': this.onDragStart.bind(this), + 'onMove': this.onDragMove.bind(this), + 'onEnd': this.onDragEnd.bind(this), + 'onPress': this.toggle.bind(this), + 'gestureName': 'toggle', + 'gesturePriority': 30, + 'type': 'pan,press', + 'direction': 'x', + 'threshold': 20, + 'listenOn': 'parent' + } + }), + [ + h('div.toggle-icon', + h('div.toggle-inner') + ), + h('div.toggle-cover', { + attrs: { + 'id': this.id, + 'aria-checked': this.checked ? 'true' : false, + 'aria-disabled': this.disabled ? 'true' : false, + 'aria-labelledby': this.labelId, + 'role': 'checkbox', + 'tabindex': 0 + } + }) + ] + ) ); }