From 490a06dd3e04807c392b0ef402f6879b5c012127 Mon Sep 17 00:00:00 2001 From: "Manu Mtz.-Almeida" Date: Wed, 21 Sep 2016 16:42:07 +0200 Subject: [PATCH] feat(fab): update floating action buttons --- src/components/button/button-fab.scss | 58 ------ src/components/button/button.ios.scss | 8 - src/components/button/button.md.scss | 17 -- src/components/button/button.wp.scss | 8 - src/components/button/test/fab/app-module.ts | 30 --- src/components/button/test/fab/e2e.ts | 1 - src/components/button/test/fab/main.html | 25 --- src/components/content/content.scss | 33 +-- src/components/content/content.ts | 110 +++++----- src/components/fab/fab.ios.scss | 32 +++ src/components/fab/fab.md.scss | 48 +++++ src/components/fab/fab.scss | 202 +++++++++++++++++++ src/components/fab/fab.ts | 168 +++++++++++++++ src/components/fab/fab.wp.scss | 32 +++ src/components/fab/test/basic/app-module.ts | 45 +++++ src/components/fab/test/basic/main.html | 73 +++++++ src/components/fab/test/fab.spec.ts | 0 src/components/nav/test/basic/app-module.ts | 7 +- src/directives.ts | 5 + src/themes/ionic.components.scss | 7 +- src/themes/ionic.globals.scss | 2 +- src/util/ui-event-manager.ts | 15 +- 22 files changed, 703 insertions(+), 223 deletions(-) delete mode 100644 src/components/button/button-fab.scss delete mode 100644 src/components/button/test/fab/app-module.ts delete mode 100644 src/components/button/test/fab/e2e.ts delete mode 100644 src/components/button/test/fab/main.html create mode 100755 src/components/fab/fab.ios.scss create mode 100755 src/components/fab/fab.md.scss create mode 100755 src/components/fab/fab.scss create mode 100755 src/components/fab/fab.ts create mode 100755 src/components/fab/fab.wp.scss create mode 100755 src/components/fab/test/basic/app-module.ts create mode 100755 src/components/fab/test/basic/main.html create mode 100755 src/components/fab/test/fab.spec.ts diff --git a/src/components/button/button-fab.scss b/src/components/button/button-fab.scss deleted file mode 100644 index ccdf30e26c..0000000000 --- a/src/components/button/button-fab.scss +++ /dev/null @@ -1,58 +0,0 @@ -@import "../../themes/ionic.globals"; - -// Floating Action Buttons -// -------------------------------------------------- - -/// @prop - Width and height of the FAB button -$button-fab-size: 56px !default; - - -.button-fab { - position: absolute; - overflow: hidden; - - line-height: $button-fab-size; - vertical-align: middle; - - background-clip: padding-box; -} - -.button-fab.button { - width: $button-fab-size; - min-width: 0; - height: $button-fab-size; - - font-size: 14px; -} - -.button-fab ion-icon { - flex: 1; - - font-size: 2.8rem; -} - -.button-fab[fab-center] { - left: 50%; - - margin-left: -$button-fab-size / 2; -} - -.button-fab[fab-top] { - top: 16px; -} - -.button-fab[fab-right] { - right: 16px; -} - -.button-fab[fab-bottom] { - bottom: 16px; -} - -.button-fab[fab-left] { - left: 16px; -} - -.button-fab[fab-fixed] { - position: fixed; -} diff --git a/src/components/button/button.ios.scss b/src/components/button/button.ios.scss index 5b6289b3bf..1d1734c7c3 100644 --- a/src/components/button/button.ios.scss +++ b/src/components/button/button.ios.scss @@ -311,14 +311,6 @@ $button-ios-fab-border-radius: 50% !default; } -// iOS FAB Button -// -------------------------------------------------- - -.button-fab-ios { - border-radius: $button-ios-fab-border-radius; -} - - // Generate iOS Button Colors // -------------------------------------------------- diff --git a/src/components/button/button.md.scss b/src/components/button/button.md.scss index d80d54131c..882d62cd28 100644 --- a/src/components/button/button.md.scss +++ b/src/components/button/button.md.scss @@ -394,23 +394,6 @@ $button-md-fab-box-shadow-activated: 0 5px 15px 0 rgba(0, 0, 0, .4), border-radius: $button-md-round-border-radius; } - -// Material Design FAB Button -// -------------------------------------------------- - -.button-fab-md { - border-radius: $button-md-fab-border-radius; - box-shadow: $button-md-fab-box-shadow; - - transition: box-shadow $button-md-transition-duration $button-md-transition-timing-function, - background-color $button-md-transition-duration $button-md-transition-timing-function, - color $button-md-transition-duration $button-md-transition-timing-function; -} - -.button-fab-md.activated { - box-shadow: $button-md-fab-box-shadow-activated; -} - .button-md [icon-only] { padding: 0; } diff --git a/src/components/button/button.wp.scss b/src/components/button/button.wp.scss index 1aaa40bf43..334ee0cc11 100644 --- a/src/components/button/button.wp.scss +++ b/src/components/button/button.wp.scss @@ -309,14 +309,6 @@ $button-wp-fab-border-radius: 50% !default; border-radius: $button-wp-round-border-radius; } - -// Windows FAB Button -// -------------------------------------------------- - -.button-fab-wp { - border-radius: $button-wp-fab-border-radius; -} - .button-wp [icon-only] { padding: 0; } diff --git a/src/components/button/test/fab/app-module.ts b/src/components/button/test/fab/app-module.ts deleted file mode 100644 index 0bf1cc361b..0000000000 --- a/src/components/button/test/fab/app-module.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Component, NgModule } from '@angular/core'; -import { IonicApp, IonicModule } from '../../../..'; - - -@Component({ - templateUrl: 'main.html' -}) -export class E2EPage {} - -@Component({ - template: '' -}) -export class E2EApp { - rootPage = E2EPage; -} - -@NgModule({ - declarations: [ - E2EApp, - E2EPage - ], - imports: [ - IonicModule.forRoot(E2EApp) - ], - bootstrap: [IonicApp], - entryComponents: [ - E2EPage - ] -}) -export class AppModule {} diff --git a/src/components/button/test/fab/e2e.ts b/src/components/button/test/fab/e2e.ts deleted file mode 100644 index 8b13789179..0000000000 --- a/src/components/button/test/fab/e2e.ts +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/components/button/test/fab/main.html b/src/components/button/test/fab/main.html deleted file mode 100644 index b2f30c33e9..0000000000 --- a/src/components/button/test/fab/main.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - diff --git a/src/components/content/content.scss b/src/components/content/content.scss index 3cdd0cd3f9..dc7f5040d2 100644 --- a/src/components/content/content.scss +++ b/src/components/content/content.scss @@ -57,6 +57,27 @@ ion-content.js-scroll > .scroll-content { } +// Fixed Content (ion-fixed and ion-fab) +// -------------------------------------------------- + +.fixed-content { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + display: block; +} + +[ion-fixed] { + position: absolute; + + z-index: $z-index-fixed-content; + + transform: translateZ(0); +} + + // Content Padding // -------------------------------------------------- @@ -151,15 +172,3 @@ ion-content.js-scroll > .scroll-content { margin-left: $content-margin; } } - - -// Content Fixed -// -------------------------------------------------- - -ion-fixed { - position: absolute; - - z-index: $z-index-fixed-content; - - transform: translateZ(0); -} diff --git a/src/components/content/content.ts b/src/components/content/content.ts index e9e023f801..77d97f3419 100644 --- a/src/components/content/content.ts +++ b/src/components/content/content.ts @@ -103,10 +103,12 @@ import { isTrueProperty } from '../../util/util'; @Component({ selector: 'ion-content', template: + '
' + + '' + + '
' + '
' + '' + '
' + - '' + '', host: { '[class.statusbar-padding]': '_sbPadding' @@ -136,6 +138,11 @@ export class Content extends Ion { */ _scrollEle: HTMLElement; + /* + * @private + */ + _fixedEle: HTMLElement; + /** * A number representing how many pixels the top of the content has been * adjusted, which could be by either padding or margin. @@ -175,7 +182,8 @@ export class Content extends Ion { * @private */ ngOnInit() { - this._scrollEle = this._elementRef.nativeElement.children[0]; + this._fixedEle = this._elementRef.nativeElement.children[0]; + this._scrollEle = this._elementRef.nativeElement.children[1]; this._zone.runOutsideAngular(() => { this._scroll = new ScrollView(this._scrollEle); @@ -530,63 +538,61 @@ export class Content extends Ion { * DOM WRITE */ writeDimensions() { - let newVal: number; - let scrollEle = this._scrollEle; + let scrollEle = this._scrollEle as any; + if (!scrollEle) { + return; + } - if (!scrollEle) return; + let fixedEle = this._fixedEle; + if (!fixedEle) { + return; + } - // only write when it has changed + // Toolbar height + let contentTop = this._headerHeight; + let contentBottom = this._footerHeight; + + // Tabs height + if (this._tabsPlacement === 'top') { + contentTop += this._tabbarHeight; + + } else if (this._tabsPlacement === 'bottom') { + contentBottom += this._tabbarHeight; + + // Update footer position + if (contentBottom > 0 && this._footerEle) { + this._footerEle.style.bottom = cssFormat(contentBottom - this._footerHeight); + } + } + + // Handle fullscreen viewport (padding vs margin) + let topProperty = 'marginTop'; + let bottomProperty = 'marginBottom'; + let fixedTop: number = contentTop; + let fixedBottom: number = contentBottom; if (this._fullscreen) { // adjust the content with padding, allowing content to scroll under headers/footers // however, on iOS you cannot control the margins of the scrollbar (last tested iOS9.2) // only add inline padding styles if the computed padding value, which would // have come from the app's css, is different than the new padding value + contentTop += this._paddingTop; + contentBottom += this._paddingBottom; + topProperty = 'paddingTop'; + bottomProperty = 'paddingBottom'; + } - newVal = this._headerHeight + this._paddingTop; - if (this._tabsPlacement === 'top') { - newVal += this._tabbarHeight; - } - if (newVal !== this.contentTop) { - scrollEle.style.paddingTop = (newVal > 0 ? newVal + 'px' : ''); - this.contentTop = newVal; - } + // Only update top margin if value changed + if (contentTop !== this.contentTop) { + scrollEle.style[topProperty] = cssFormat(contentTop); + fixedEle.style.marginTop = cssFormat(fixedTop); + this.contentTop = contentTop; + } - newVal = this._footerHeight + this._paddingBottom; - if (this._tabsPlacement === 'bottom') { - newVal += this._tabbarHeight; - - if (newVal > 0 && this._footerEle) { - this._footerEle.style.bottom = (newVal - this._footerHeight - this._paddingBottom) + 'px'; - } - } - if (newVal !== this.contentBottom) { - scrollEle.style.paddingBottom = (newVal > 0 ? newVal + 'px' : ''); - this.contentBottom = newVal; - } - - } else { - // adjust the content with margins - newVal = this._headerHeight; - if (this._tabsPlacement === 'top') { - newVal += this._tabbarHeight; - } - if (newVal !== this.contentTop) { - scrollEle.style.marginTop = (newVal > 0 ? newVal + 'px' : ''); - this.contentTop = newVal; - } - - newVal = this._footerHeight; - if (this._tabsPlacement === 'bottom') { - newVal += this._tabbarHeight; - } - if (newVal !== this.contentBottom) { - scrollEle.style.marginBottom = (newVal > 0 ? newVal + 'px' : ''); - this.contentBottom = newVal; - - if (newVal > 0 && this._footerEle) { - this._footerEle.style.bottom = (newVal - this._footerHeight) + 'px'; - } - } + // Only update bottom margin if value changed + if (contentBottom !== this.contentBottom) { + scrollEle.style[bottomProperty] = cssFormat(contentBottom); + fixedEle.style.marginBottom = cssFormat(fixedBottom); + this.contentBottom = contentBottom; } @@ -606,3 +612,7 @@ export class Content extends Ion { function parsePxUnit(val: string): number { return (val.indexOf('px') > 0) ? parseInt(val, 10) : 0; } + +function cssFormat(val: number): string { + return (val > 0 ? val + 'px' : ''); +} diff --git a/src/components/fab/fab.ios.scss b/src/components/fab/fab.ios.scss new file mode 100755 index 0000000000..1fed6c3766 --- /dev/null +++ b/src/components/fab/fab.ios.scss @@ -0,0 +1,32 @@ +@import "../../themes/ionic.globals.ios"; + +// iOS FAB Button +// -------------------------------------------------- + +/// @prop - Border radius of the FAB button +$button-ios-fab-border-radius: 50% !default; + +.fab-button { + border-radius: $button-ios-fab-border-radius; +} + + +// Generate iOS FAB colors +// -------------------------------------------------- + +@each $color-name, $color-base, $color-contrast in get-colors($colors-ios) { + + $background-color: $color-base; + $background-color-activated: color-shade($background-color); + $fg-color: $color-contrast; + + .fab-ios-#{$color-name} { + color: $fg-color; + background-color: $background-color; + } + + .fab-ios-#{$color-name}.activated { + background-color: $background-color-activated; + } +} + diff --git a/src/components/fab/fab.md.scss b/src/components/fab/fab.md.scss new file mode 100755 index 0000000000..beb6c3634b --- /dev/null +++ b/src/components/fab/fab.md.scss @@ -0,0 +1,48 @@ +@import "../../themes/ionic.globals.md"; + +// Material Design FAB Button +// -------------------------------------------------- + +/// @prop - Border radius of the FAB button +$button-md-fab-border-radius: 50% !default; + +/// @prop - Box shadow of the FAB button +$button-md-fab-box-shadow: 0 4px 6px 0 rgba(0, 0, 0, .14), 0 4px 5px rgba(0, 0, 0, .1) !default; + +/// @prop - Box shadow of the activated FAB button +$button-md-fab-box-shadow-activated: 0 5px 15px 0 rgba(0, 0, 0, .4), 0 4px 7px 0 rgba(0, 0, 0, .1) !default; + + +.fab-button { + border-radius: $button-md-fab-border-radius; + box-shadow: $button-md-fab-box-shadow; + + transition: box-shadow $button-md-transition-duration $button-md-transition-timing-function, + background-color $button-md-transition-duration $button-md-transition-timing-function, + color $button-md-transition-duration $button-md-transition-timing-function; + + &.activated { + box-shadow: $button-md-fab-box-shadow-activated; + } +} + + +// Generate iOS FAB colors +// -------------------------------------------------- + +@each $color-name, $color-base, $color-contrast in get-colors($colors-md) { + + $background-color: $color-base; + $background-color-activated: color-shade($background-color); + $fg-color: $color-contrast; + + .fab-md-#{$color-name} { + color: $fg-color; + background-color: $background-color; + } + + .fab-md-#{$color-name}.activated { + background-color: $background-color-activated; + } +} + diff --git a/src/components/fab/fab.scss b/src/components/fab/fab.scss new file mode 100755 index 0000000000..df4dc5a334 --- /dev/null +++ b/src/components/fab/fab.scss @@ -0,0 +1,202 @@ +@import "../../themes/ionic.globals"; + +// Floating Action Buttons +// -------------------------------------------------- + +/// @prop - Width and height of the FAB button +$button-fab-size: 56px !default; +$button-fab-mini-size: 40px !default; +$button-fab-content-margin: 10px !default; +$button-fab-list-margin: 10px !default; + + +.fab-button { + position: relative; + z-index: 0; + display: block; + overflow: hidden; + + width: $button-fab-size; + height: $button-fab-size; + + font-size: 14px; + line-height: $button-fab-size; + text-align: center; + text-overflow: ellipsis; + text-transform: none; + white-space: nowrap; + color: #fff; + background-color: #327eff; + cursor: pointer; + transition: background-color, opacity 100ms linear; + + -moz-appearance: none; + -webkit-appearance: none; + background-clip: padding-box; + font-kerning: none; + user-select: none; + + ion-icon { + flex: 1; + + font-size: 2.4rem; + } +} + +// FAB mini +// -------------------------------------------------- + +.fab-button[mini] { + margin: ($button-fab-size - $button-fab-mini-size) / 2; + + width: $button-fab-mini-size; + height: $button-fab-mini-size; + + line-height: $button-fab-mini-size; + + .fab-close-icon { + line-height: $button-fab-mini-size; + } +} + + +// FAB container +// -------------------------------------------------- + +ion-fab { + position: absolute; + z-index: $z-index-fixed-content; + + &[center] { + left: 50%; + + margin-left: -$button-fab-size / 2; + } + + &[middle] { + top: 50%; + + margin-top: -$button-fab-size / 2; + } + + &[top] { + top: $button-fab-content-margin; + } + + &[right] { + right: $button-fab-content-margin; + } + + &[bottom] { + bottom: $button-fab-content-margin; + } + + &[left] { + left: $button-fab-content-margin; + } + + &[top][edge] { + top: -$button-fab-size / 2; + } + + &[bottom][edge] { + bottom: -$button-fab-size / 2; + } +} + + +// FAB list (speed dial) +// -------------------------------------------------- + +ion-fab-list { + position: absolute; + top: 0; + display: none; + + flex-direction: column; + align-items: center; + + margin: $button-fab-size + $button-fab-list-margin 0; + + min-width: $button-fab-size; + min-height: $button-fab-size; + + .fab-button { + margin: 8px; + + width: $button-fab-mini-size; + height: $button-fab-mini-size; + + color: #797979; + background: #fff; + opacity: 0; + visibility: hidden; + transform: scale(0); + transition: all 200ms ease; + transition-delay: 10ms; + transition-property: transform, opacity; + + &.fab-dial-button-visible { + opacity: 1; + visibility: visible; + transform: scale(1); + } + } +} + +ion-fab-list[side=top] { + top: initial; + bottom: 0; + + flex-direction: column-reverse; +} + +ion-fab-list[side=left] { + right: 0; + + flex-direction: row-reverse; + + margin: 0 $button-fab-size + $button-fab-list-margin; +} + +ion-fab-list[side=right] { + left: 0; + + flex-direction: row; + + margin: 0 $button-fab-size + $button-fab-list-margin; +} + + +// FAB animation +// -------------------------------------------------- + +.fab-list-active { + display: flex; +} + +.fab-close-icon { + position: absolute; + top: 0; + right: 0; + left: 0; + + line-height: $button-fab-size; + opacity: 0; + transform: scale(.4) rotateZ(-45deg); + transition: all ease-in-out 300ms; +} + +.fab-button .button-inner { + transition: all ease-in-out 300ms; +} + +.fab-close-active .fab-close-icon { + opacity: 1; + transform: scale(1) rotateZ(0deg); +} + +.fab-close-active .button-inner { + opacity: 0; + transform: scale(.4) rotateZ(45deg); +} diff --git a/src/components/fab/fab.ts b/src/components/fab/fab.ts new file mode 100755 index 0000000000..b2883f11f6 --- /dev/null +++ b/src/components/fab/fab.ts @@ -0,0 +1,168 @@ +import { Component, ContentChild, Input, ContentChildren, QueryList, ChangeDetectionStrategy, Directive, ElementRef, Renderer, ViewEncapsulation } from '@angular/core'; + +import { Config } from '../../config/config'; +import { Ion } from '../ion'; + +import { UIEventManager } from '../../util/ui-event-manager'; +import { isTrueProperty } from '../../util/util'; + +@Component({ + selector: '[ion-fab]', + template: + '' + + '' + + '' + + '' + + '
', + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, +}) +export class FabButton extends Ion { + + ngAfterContentInit() { + this.setElementClass('fab-button', true); // set role + } + /** + * @input {string} The predefined color to use. For example: `"primary"`, `"secondary"`, `"danger"`. + */ + @Input() + set color(val: string) { + this._setColor('fab', val); + } + + /** + * @input {string} The mode to apply to this component. + */ + @Input() + set mode(val: string) { + this._setMode('fab', val); + } + + constructor( + config: Config, + elementRef: ElementRef, + renderer: Renderer, + ) { + super(config, elementRef, renderer); + this.mode = config.get('mode'); + } + + + setActiveClose(closeVisible: boolean) { + this.setElementClass('fab-close-active', closeVisible); + } +} + +/** + * @name Fab + * @module ionic + * + * @demo /docs/v2/demos/fab/ + * @see {@link /docs/v2/components#fab Fab Component Docs} + */ + +@Directive({ + selector: 'ion-fab-list', + host: { + '[class.fab-list-active]': '_visible' + } +}) +export class FabList { + _visible: boolean = false; + + @ContentChildren(FabButton) _buttons: QueryList; + + /** + * @private + */ + setVisible(val: boolean) { + let visible = isTrueProperty(val); + if (visible === this._visible) { + return; + } + + let buttons = this._buttons.toArray(); + let i = 1; + if (visible) { + buttons.forEach(fab => { + setTimeout(() => fab.setElementClass('fab-dial-button-visible', true), i * 30); + i++; + }); + } else { + buttons.forEach(fab => fab.setElementClass('fab-dial-button-visible', false)); + } + this._visible = visible; + } + +} + +@Component({ + selector: 'ion-fab', + template: '' +}) +export class Fab { + _events: UIEventManager = new UIEventManager(); + _listsActive: boolean = false; + + @ContentChild(FabButton) _mainButton: FabButton; + @ContentChildren(FabList) _fabLists: QueryList; + + constructor(private _elementRef: ElementRef) { } + + /** + * @private + */ + ngAfterContentInit() { + this._events.listen(this._mainButton.getNativeElement(), 'click', this.pointerUp.bind(this)); + } + + /** + * @private + */ + pointerUp(ev: any) { + if (this.canActivateList(ev)) { + this.toggleList(); + } + } + + /** + * @private + */ + canActivateList(ev: any): boolean { + if (this._fabLists.length > 0 && this._mainButton && ev.target) { + let ele = ev.target.closest('ion-fab>button'); + return (ele && ele === this._mainButton.getNativeElement()); + } + return false; + } + + /** + * @private + */ + toggleList() { + this.setActiveLists(!this._listsActive); + } + + setActiveLists(isActive: boolean) { + if (isActive === this._listsActive) { + return; + } + let lists = this._fabLists.toArray(); + for (let list of lists) { + list.setVisible(isActive); + } + this._mainButton.setActiveClose(isActive); + this._listsActive = isActive; + } + + close() { + this.setActiveLists(false); + } + + /** + * @private + */ + ngOnDestroy() { + this._events.unlistenAll(); + } +} diff --git a/src/components/fab/fab.wp.scss b/src/components/fab/fab.wp.scss new file mode 100755 index 0000000000..2bff374db1 --- /dev/null +++ b/src/components/fab/fab.wp.scss @@ -0,0 +1,32 @@ +@import "../../themes/ionic.globals.wp"; + +// Windows FAB Button +// -------------------------------------------------- + +/// @prop - Border radius of the FAB button +$button-wp-fab-border-radius: 50% !default; + + +.fab-button { + border-radius: $button-wp-fab-border-radius; +} + + +// Generate iOS FAB colors +// -------------------------------------------------- + +@each $color-name, $color-base, $color-contrast in get-colors($colors-wp) { + + $background-color: $color-base; + $background-color-activated: color-shade($background-color); + $fg-color: $color-contrast; + + .fab-wp-#{$color-name} { + color: $fg-color; + background-color: $background-color; + } + + .fab-wp-#{$color-name}.activated { + background-color: $background-color-activated; + } +} diff --git a/src/components/fab/test/basic/app-module.ts b/src/components/fab/test/basic/app-module.ts new file mode 100755 index 0000000000..a3d3921d85 --- /dev/null +++ b/src/components/fab/test/basic/app-module.ts @@ -0,0 +1,45 @@ +import { Component, NgModule } from '@angular/core'; +import { IonicApp, IonicModule, Fab } from '../../../..'; + +@Component({ + templateUrl: 'main.html' +}) +export class E2EPage { + array: number[] = []; + + add() { + this.array.push(1); + } + + clickMainFAB() { + console.log('Clicked open social menu'); + } + + openSocial(network: string, fab: Fab) { + console.log('Share in ' + network); + fab.close(); + } +} + + +@Component({ + template: '' +}) +export class E2EApp { + root: any = E2EPage; +} + +@NgModule({ + declarations: [ + E2EApp, + E2EPage + ], + imports: [ + IonicModule.forRoot(E2EApp) + ], + bootstrap: [IonicApp], + entryComponents: [ + E2EPage + ] +}) +export class AppModule {} diff --git a/src/components/fab/test/basic/main.html b/src/components/fab/test/basic/main.html new file mode 100755 index 0000000000..4e80f717bb --- /dev/null +++ b/src/components/fab/test/basic/main.html @@ -0,0 +1,73 @@ + + + Floating Action Buttons + + + + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/src/components/fab/test/fab.spec.ts b/src/components/fab/test/fab.spec.ts new file mode 100755 index 0000000000..e69de29bb2 diff --git a/src/components/nav/test/basic/app-module.ts b/src/components/nav/test/basic/app-module.ts index 08f1367751..75fe264b63 100644 --- a/src/components/nav/test/basic/app-module.ts +++ b/src/components/nav/test/basic/app-module.ts @@ -290,10 +290,9 @@ export class FullPage {

- - - - + + +
diff --git a/src/directives.ts b/src/directives.ts index b047ab2085..d94d2d3ede 100644 --- a/src/directives.ts +++ b/src/directives.ts @@ -11,6 +11,7 @@ import { Checkbox } from './components/checkbox/checkbox'; import { Chip } from './components/chip/chip'; import { Content } from './components/content/content'; import { DateTime } from './components/datetime/datetime'; +import { Fab, FabButton, FabList } from './components/fab/fab'; import { Fixed } from './components/fixed/fixed'; import { Grid, Row, Col } from './components/grid/grid'; import { Icon } from './components/icon/icon'; @@ -79,6 +80,7 @@ export { Checkbox } from './components/checkbox/checkbox'; export { Chip } from './components/chip/chip'; export { Content } from './components/content/content'; export { DateTime } from './components/datetime/datetime'; +export { Fab, FabButton, FabList } from './components/fab/fab'; export { Fixed } from './components/fixed/fixed'; export { Grid, Row, Col } from './components/grid/grid'; export { Icon } from './components/icon/icon'; @@ -171,6 +173,9 @@ export const IONIC_DIRECTIVES: any[] = [ Col, Content, DateTime, + Fab, + FabButton, + FabList, Fixed, Footer, Grid, diff --git a/src/themes/ionic.components.scss b/src/themes/ionic.components.scss index e089b4f360..23a9ac8185 100644 --- a/src/themes/ionic.components.scss +++ b/src/themes/ionic.components.scss @@ -31,7 +31,6 @@ @import "../components/button/button", -"../components/button/button-fab", "../components/button/button-icon", "../components/button/button.ios", "../components/button/button.md", @@ -66,6 +65,12 @@ "../components/datetime/datetime.md", "../components/datetime/datetime.wp"; +@import +"../components/fab/fab", +"../components/fab/fab.ios", +"../components/fab/fab.md", +"../components/fab/fab.wp"; + @import "../components/grid/grid"; diff --git a/src/themes/ionic.globals.scss b/src/themes/ionic.globals.scss index 2d6a2a8aa5..3a2fbbcc01 100644 --- a/src/themes/ionic.globals.scss +++ b/src/themes/ionic.globals.scss @@ -32,7 +32,7 @@ $z-index-menu-backdrop: 79; $z-index-overlay: 1000; $z-index-click-block: 9999; -$z-index-fixed-content: 2; +$z-index-fixed-content: 100; $z-index-scroll-content: 1; $z-index-refresher: 0; diff --git a/src/util/ui-event-manager.ts b/src/util/ui-event-manager.ts index ac9a80914c..0b8305c856 100644 --- a/src/util/ui-event-manager.ts +++ b/src/util/ui-event-manager.ts @@ -4,8 +4,8 @@ export interface PointerEventsConfig { element?: HTMLElement; elementRef?: ElementRef; pointerDown: (ev: any) => boolean; - pointerMove: (ev: any) => void; - pointerUp: (ev: any) => void; + pointerMove?: (ev: any) => void; + pointerUp?: (ev: any) => void; nativeOptions?: any; zone?: boolean; } @@ -37,7 +37,6 @@ export class PointerEvents { private zone: boolean, private option: any ) { - this.bindTouchEnd = this.handleTouchEnd.bind(this); this.bindMouseUp = this.handleMouseUp.bind(this); @@ -50,7 +49,7 @@ export class PointerEvents { if (!this.pointerDown(ev)) { return; } - if (!this.rmTouchMove) { + if (!this.rmTouchMove && this.pointerMove) { this.rmTouchMove = listenEvent(this.ele, 'touchmove', this.zone, this.option, this.pointerMove); } if (!this.rmTouchEnd) { @@ -69,7 +68,7 @@ export class PointerEvents { if (!this.pointerDown(ev)) { return; } - if (!this.rmMouseMove) { + if (!this.rmMouseMove && this.pointerMove) { this.rmMouseMove = listenEvent(document, 'mousemove', this.zone, this.option, this.pointerMove); } if (!this.rmMouseUp) { @@ -79,12 +78,12 @@ export class PointerEvents { private handleTouchEnd(ev: any) { this.stopTouch(); - this.pointerUp(ev); + this.pointerUp && this.pointerUp(ev); } private handleMouseUp(ev: any) { this.stopMouse(); - this.pointerUp(ev); + this.pointerUp && this.pointerUp(ev); } private stopTouch() { @@ -147,7 +146,7 @@ export class UIEventManager { element = config.elementRef.nativeElement; } - if (!element || !config.pointerDown || !config.pointerMove || !config.pointerUp) { + if (!element || !config.pointerDown) { console.error('PointerEvents config is invalid'); return; }