feat(fab): add fab container and buttons

This commit is contained in:
Brandy Carney
2017-07-12 16:04:28 -04:00
parent 1ada75014e
commit db9e9d9159
9 changed files with 997 additions and 1 deletions

View File

@ -0,0 +1,107 @@
import { Component, h, Method } from '@stencil/core';
/**
* @name FabContainer
* @module ionic
*
* @description
* `<ion-fab>` is not a FAB button by itself but a container that assist the fab button (`<button ion-fab>`) allowing it
* to be placed in fixed position that does not scroll with the content. It is also used to implement "material design speed dial",
* ie. a FAB buttons displays a small lists of related actions when clicked.
*
* @property [top] - Places the container on the top of the content
* @property [bottom] - Places the container on the bottom of the content
* @property [left] - Places the container on the left
* @property [right] - Places the container on the right
* @property [middle] - Places the container on the middle vertically
* @property [center] - Places the container on the center horizontally
* @property [edge] - Used to place the container between the content and the header/footer
*
* @usage
*
* ```html
* <!-- this fab is placed at top right -->
* <ion-content>
* <ion-fab top right>
* <button ion-fab>Button</button>
* </ion-fab>
*
* <!-- this fab is placed at the center of the content viewport -->
* <ion-fab center middle>
* <button ion-fab>Button</button>
* </ion-fab>
* </ion-content>
* ```
*
* Ionic's FAB also supports "material design's fab speed dial". It is a normal fab button
* that shows a list of related actions when clicked.
*
* The same `ion-fab` container can contain several `ion-fab-list` with different side values:
* `top`, `bottom`, `left` and `right`. For example, if you want to have a list of button that are
* on the top of the main button, you should use `side="top"` and so on. By default, if side is ommited, `side="bottom"`.
*
* ```html
* <ion-content>
* <!-- this fab is placed at bottom right -->
* <ion-fab bottom right >
* <button ion-fab>Share</button>
* <ion-fab-list side="top">
* <button ion-fab>Facebook</button>
* <button ion-fab>Twitter</button>
* <button ion-fab>Youtube</button>
* </ion-fab-list>
* <ion-fab-list side="left">
* <button ion-fab>Vimeo</button>
* </ion-fab-list>
* </ion-fab>
* </ion-content>
* ```
*
* A FAB speed dial can also be closed programatically.
*
* ```html
* <ion-content>
* <ion-fab bottom right #fab>
* <button ion-fab>Share</button>
* <ion-fab-list side="top">
* <button ion-fab (click)="share('facebook', fab)">Facebook</button>
* <button ion-fab (click)="share('twitter', fab)">Twitter</button>
* </ion-fab-list>
* </ion-fab>
* </ion-content>
* ```
*
* ```ts
* share(socialNet: string, fab: FabContainer) {
* fab.close();
* console.log("Sharing in", socialNet);
* }
* ```
*
* @demo /docs/demos/src/fab/
* @see {@link /docs/components#fabs FAB Component Docs}
*/
@Component({
tag: 'ion-fab',
})
export class FabContainer {
$el: HTMLElement;
/**
* Close an active FAB list container
*/
@Method()
close() {
const fab: any = this.$el.querySelector('ion-fab-button');
fab.close();
}
render() {
return (
<slot></slot>
);
}
}

View File

@ -0,0 +1,63 @@
import { Component, h, PropDidChange, State, VNodeData } from '@stencil/core';
import { HostElement } from '../../utils/interfaces';
/**
* @name FabList
* @description
* `ion-fab-list` is a container for multiple FAB buttons. They are components of `ion-fab` and allow you to specificy the buttons position, left, right, top, bottom.
* @usage
*
* ```html
* <ion-fab bottom right>
* <button ion-fab>Share</button>
* <ion-fab-list side="top">
* <button ion-fab>Facebook</button>
* <button ion-fab>Twitter</button>
* <button ion-fab>Youtube</button>
* </ion-fab-list>
* <ion-fab-list side="left">
* <button ion-fab>Vimeo</button>
* </ion-fab-list>
* </ion-fab>
* ```
* @module ionic
*
* @demo /docs/demos/src/fab/
* @see {@link /docs/components#fab Fab Component Docs}
*/
@Component({
tag: 'ion-fab-list',
})
export class FabList {
$el: HTMLElement;
@State() activated: boolean = false;
@PropDidChange('activated')
activatedChange(activated: boolean) {
const fabs = this.$el.querySelectorAll('ion-fab-button') as NodeListOf<HostElement>;
// if showing the fabs add a timeout, else show immediately
var timeout = activated ? 30 : 0;
for (var i = 0; i < fabs.length; i++) {
const fab = fabs[i].$instance;
setTimeout(() => fab.show = activated, i * timeout);
}
}
hostData(): VNodeData {
return {
class: {
'fab-list-active': this.activated
}
};
}
render() {
return (
<slot></slot>
);
}
}

View File

@ -0,0 +1,75 @@
@import "../../themes/ionic.globals.ios";
@import "./fab";
// iOS FAB Button
// --------------------------------------------------
/// @prop - Background color of the button
$fab-ios-background-color: color($colors-ios, primary) !default;
/// @prop - Text color of the button
$fab-ios-text-color: color-contrast($colors-ios, $fab-ios-background-color) !default;
/// @prop - Background color of the activated button
$fab-ios-background-color-activated: color-shade($fab-ios-background-color) !default;
/// @prop - Background color of the button in a list
$fab-ios-list-button-background-color: $fab-list-button-background-color !default;
/// @prop - Text color of the button in a list
$fab-ios-list-button-text-color: color-contrast($colors-ios, $fab-ios-list-button-background-color) !default;
/// @prop - Background color of the activated button in a list
$fab-ios-list-button-background-color-activated: color-shade($fab-ios-list-button-background-color) !default;
/// @prop - Transition duration of the transform and opacity of the button in a list
$fab-ios-list-button-transition-duration: 200ms !default;
/// @prop - Speed curve of the transition of the transform and opacity of the button in a list
$fab-ios-list-button-transition-timing-function: ease !default;
/// @prop - Transition delay of the transform and opacity of the button in a list
$fab-ios-list-button-transition-delay: 10ms !default;
.fab-ios {
color: $fab-ios-text-color;
background-color: $fab-ios-background-color;
}
.fab-ios.activated {
background-color: $fab-ios-background-color-activated;
}
.fab-ios-in-list {
color: $fab-ios-list-button-text-color;
background-color: $fab-ios-list-button-background-color;
transition: transform $fab-ios-list-button-transition-duration $fab-ios-list-button-transition-timing-function $fab-ios-list-button-transition-delay,
opacity $fab-ios-list-button-transition-duration $fab-ios-list-button-transition-timing-function $fab-ios-list-button-transition-delay;
}
.fab-ios-in-list.activated {
background-color: $fab-ios-list-button-background-color-activated;
}
// Generate iOS FAB colors
// --------------------------------------------------
@each $color-name, $color-base, $color-contrast in get-colors($colors-ios) {
$bg-color: $color-base;
$bg-color-activated: color-shade($bg-color);
$fg-color: $color-contrast;
.fab-ios-#{$color-name} {
color: $fg-color;
background-color: $bg-color;
}
.fab-ios-#{$color-name}.activated {
background-color: $bg-color-activated;
}
}

View File

@ -0,0 +1,106 @@
@import "../../themes/ionic.globals.md";
@import "./fab";
// Material Design FAB Button
// --------------------------------------------------
/// @prop - Box shadow of the FAB button
$fab-md-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
$fab-md-box-shadow-activated: 0 5px 15px 0 rgba(0, 0, 0, .4), 0 4px 7px 0 rgba(0, 0, 0, .1) !default;
/// @prop - Background color of the button
$fab-md-background-color: color($colors-md, primary) !default;
/// @prop - Text color of the button
$fab-md-text-color: color-contrast($colors-md, $fab-md-background-color) !default;
/// @prop - Background color of the activated button
$fab-md-background-color-activated: color-shade($fab-md-background-color) !default;
/// @prop - Background color of the button in a list
$fab-md-list-button-background-color: $fab-list-button-background-color !default;
/// @prop - Text color of the button in a list
$fab-md-list-button-text-color: color-contrast($colors-md, $fab-md-list-button-background-color) !default;
/// @prop - Background color of the activated button in a list
$fab-md-list-button-background-color-activated: color-shade($fab-md-list-button-background-color) !default;
/// @prop - Transition duration of the transform and opacity of the button in a list
$fab-md-list-button-transition-duration: 200ms !default;
/// @prop - Speed curve of the transition of the transform and opacity of the button in a list
$fab-md-list-button-transition-timing-function: ease !default;
/// @prop - Transition delay of the transform and opacity of the button in a list
$fab-md-list-button-transition-delay: 10ms !default;
$fab-button-md-transition-duration: 300ms !default;
$fab-button-md-transition-timing-function: cubic-bezier(.4, 0, .2, 1) !default;
.fab-md {
color: $fab-md-text-color;
background-color: $fab-md-background-color;
box-shadow: $fab-md-box-shadow;
transition: box-shadow $fab-button-md-transition-duration $fab-button-md-transition-timing-function,
background-color $fab-button-md-transition-duration $fab-button-md-transition-timing-function,
color $fab-button-md-transition-duration $fab-button-md-transition-timing-function;
}
.fab-md.activated {
background-color: $fab-md-background-color-activated;
box-shadow: $fab-md-box-shadow-activated;
}
.fab-md-in-list {
color: $fab-md-list-button-text-color;
background-color: $fab-md-list-button-background-color;
transition: transform $fab-md-list-button-transition-duration $fab-md-list-button-transition-timing-function $fab-md-list-button-transition-delay,
opacity $fab-md-list-button-transition-duration $fab-md-list-button-transition-timing-function $fab-md-list-button-transition-delay,
box-shadow $fab-button-md-transition-duration $fab-button-md-transition-timing-function,
background-color $fab-button-md-transition-duration $fab-button-md-transition-timing-function,
color $fab-button-md-transition-duration $fab-button-md-transition-timing-function;
}
.fab-md-in-list.activated {
background-color: $fab-md-list-button-background-color-activated;
}
// Material Design FAB Ripple
// --------------------------------------------------
.fab-md .button-effect {
background-color: color-contrast($colors-md, $fab-md-background-color);
}
// Generate MD FAB colors
// --------------------------------------------------
@each $color-name, $color-base, $color-contrast in get-colors($colors-md) {
$bg-color: $color-base;
$bg-color-activated: color-shade($bg-color);
$fg-color: $color-contrast;
.fab-md-#{$color-name} {
color: $fg-color;
background-color: $bg-color;
}
.fab-md-#{$color-name}.activated {
background-color: $bg-color-activated;
}
.fab-md-#{$color-name} .button-effect {
background-color: $fg-color;
}
}

View File

@ -0,0 +1,224 @@
@import "../../themes/ionic.globals";
// Floating Action Buttons
// --------------------------------------------------
/// @prop - Width and height of the FAB button
$fab-size: 56px !default;
/// @prop - Width and height of the FAB button mini
$fab-mini-size: 40px !default;
/// @prop - Margin of the FAB Container
$fab-content-margin: 10px !default;
/// @prop - Margin of the FAB List
$fab-list-margin: 10px !default;
/// @prop - Background color of the button in a list
$fab-list-button-background-color: #f4f4f4 !default;
.fab {
@include text-align(center);
@include appearance(none);
@include border-radius(50%);
position: relative;
z-index: 0;
display: block;
overflow: hidden;
width: $fab-size;
height: $fab-size;
font-size: 14px;
line-height: $fab-size;
text-overflow: ellipsis;
text-transform: none;
white-space: nowrap;
cursor: pointer;
transition: background-color, opacity 100ms linear;
background-clip: padding-box;
font-kerning: none;
user-select: none;
contain: strict;
}
.fab ion-icon {
flex: 1;
font-size: 2.4rem;
}
// FAB mini
// --------------------------------------------------
.fab[mini] {
@include margin(($fab-size - $fab-mini-size) / 2);
width: $fab-mini-size;
height: $fab-mini-size;
line-height: $fab-mini-size;
}
.fab[mini] .fab-close-icon {
line-height: $fab-mini-size;
}
// FAB container
// --------------------------------------------------
ion-fab {
position: absolute;
z-index: $z-index-fixed-content;
&[center] {
@include position(null, null, null, 50%);
@include margin-horizontal(-$fab-size / 2, null);
}
&[middle] {
@include margin(-$fab-size / 2, null, null, null);
top: 50%;
}
&[top] {
top: $fab-content-margin;
}
&[right] {
// scss-lint:disable PropertySpelling
@include multi-dir() {
right: $fab-content-margin;
}
}
&[end] {
@include position-horizontal(null, $fab-content-margin);
}
&[bottom] {
bottom: $fab-content-margin;
}
&[left] {
// scss-lint:disable PropertySpelling
@include multi-dir() {
left: $fab-content-margin;
}
}
&[start] {
@include position-horizontal($fab-content-margin, null);
}
&[top][edge] {
top: -$fab-size / 2;
}
&[bottom][edge] {
bottom: -$fab-size / 2;
}
}
// FAB list (speed dial)
// --------------------------------------------------
ion-fab-list {
@include margin($fab-size + $fab-list-margin, 0);
position: absolute;
top: 0;
display: none;
flex-direction: column;
align-items: center;
min-width: $fab-size;
min-height: $fab-size;
}
.fab-in-list {
@include margin(8px, 0);
width: $fab-mini-size;
height: $fab-mini-size;
opacity: 0;
visibility: hidden;
transform: scale(0);
}
.fab-in-list.show {
opacity: 1;
visibility: visible;
transform: scale(1);
}
ion-fab-list[side=left] .fab-in-list,
ion-fab-list[side=right] .fab-in-list {
@include margin(0, 8px);
}
ion-fab-list[side=top] {
top: auto;
bottom: 0;
flex-direction: column-reverse;
}
ion-fab-list[side=left] {
@include margin(0, $fab-size + $fab-list-margin);
@include position-horizontal(null, 0);
flex-direction: row-reverse;
}
ion-fab-list[side=right] {
@include margin(0, $fab-size + $fab-list-margin);
@include position(null, null, null, 0);
flex-direction: row;
}
// FAB animation
// --------------------------------------------------
.fab-list-active {
display: flex;
}
.fab-close-icon {
@include position(0, 0, null, 0);
position: absolute;
line-height: $fab-size;
opacity: 0;
transform: scale(.4) rotateZ(-45deg);
transition: all ease-in-out 300ms;
transition-property: transform, opacity;
}
.fab .button-inner {
transition: all ease-in-out 300ms;
transition-property: transform, opacity;
}
.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);
}

View File

@ -0,0 +1,201 @@
import { Component, CssClassObject, h, Method, Prop, State } from '@stencil/core';
import { createThemedClasses } from '../../utils/theme';
import { HostElement } from '../../utils/interfaces';
/**
* @name FabButton
* @module ionic
*
* @description
* FABs (Floating Action Buttons) are standard material design components. They are shaped as a circle that represents a promoted action. When pressed, it may contain more related actions.
* FABs as its name suggests are floating over the content in a fixed position. This is not achieved exclusively with `<button ion-fab>Button</button>` but it has to wrapped with the `<ion-fab>` component, like this:
*
* ```html
* <ion-content>
* <!-- Real floating action button, fixed. It will not scroll with the content -->
* <ion-fab>
* <button ion-fab>Button</button>
* </ion-fab>
*
* <!-- Button shaped as a circle that just like a normal button scrolls with the content -->
* <button ion-fab>Button</button>
* </ion-content>
*
* ```
*
* In case the button is not wrapped with `<ion-fab>`, the fab button will behave like a normal button, scrolling with the content.
*
* See [ion-fab] to learn more information about how to position the fab button.
*
* @property [mini] - Makes a fab button with a reduced size.
*
* @usage
*
* ```html
*
* <!-- Colors -->
* <ion-fab>
* <button ion-fab color="primary">Button</button>
* </ion-fab>
*
* <!-- Mini -->
* <ion-fab>
* <button ion-fab mini>Small</button>
* </ion-fab>
* ```
*
* @demo /docs/demos/src/fab/
* @see {@link /docs/components#fabs FAB Component Docs}
*/
@Component({
tag: 'ion-fab-button',
styleUrls: {
ios: 'fab.ios.scss',
md: 'fab.md.scss',
wp: 'fab.wp.scss'
}
})
export class FabButton {
$el: HTMLElement;
mode: string;
color: string;
@State() activated: boolean = false;
@State() closeActivated: boolean = false;
@State() show: boolean = false;
@State() inContainer: boolean = false;
@State() inList: boolean = false;
@Prop() href: string;
/**
* @Prop {boolean} If true, sets the button into a disabled state.
*/
@Prop() disabled: boolean = false;
ionViewDidLoad() {
const parentNode = this.$el.parentNode.nodeName;
this.inList = (parentNode === 'ION-FAB-LIST');
this.inContainer = (parentNode === 'ION-FAB');
}
clickedFab() {
if (this.inContainer) {
const activated = !this.activated;
this.setActiveLists(activated);
}
}
/**
* @hidden
*/
setActiveLists(activated: boolean) {
const lists = this.$el.parentElement.querySelectorAll('ion-fab-list') as NodeListOf<HostElement>;
if (lists.length > 0) {
this.activated = activated;
}
for (var i = 0; i < lists.length; i++) {
const list = lists[i].$instance;
list.activated = activated;
}
}
/**
* Close an active FAB list container
*/
@Method()
close() {
this.setActiveLists(false);
}
/**
* @hidden
* Get the element classes to add to the child element
*/
getElementClassList() {
let classList = [].concat(
this.$el.className.length ? this.$el.className.split(' ') : []
);
return classList;
}
/**
* @hidden
* Get the classes for fab buttons in lists
*/
getFabListClassList() {
if (!this.inList) {
return [];
}
return [
`fab-in-list`,
`fab-${this.mode}-in-list`
];
}
/**
* @hidden
* Get the close active class for fab buttons
*/
getFabActiveClassList() {
if (!this.activated) {
return [];
}
return [
`fab-close-active`
];
}
/**
* @hidden
* Get the show class for fab buttons
*/
getFabShowClassList() {
if (!this.show) {
return [];
}
return [
`show`
];
}
render() {
const themedClasses = createThemedClasses(this.mode, this.color, 'fab');
var fabClasses: CssClassObject = []
.concat(
this.getElementClassList(),
this.getFabListClassList(),
this.getFabActiveClassList(),
this.getFabShowClassList()
)
.reduce((prevValue, cssClass) => {
prevValue[cssClass] = true;
return prevValue;
}, {});
const TagType = this.href ? 'a' : 'button';
fabClasses = Object.assign(fabClasses, themedClasses);
return (
<TagType class={fabClasses} onclick={this.clickedFab.bind(this)} disabled={this.disabled}>
<ion-icon name="close" class="fab-close-icon"></ion-icon>
<span class='button-inner'>
<slot></slot>
</span>
<div class='button-effect'></div>
</TagType>
);
}
}

View File

@ -0,0 +1,74 @@
@import "../../themes/ionic.globals.wp";
@import "./fab";
// Windows FAB Button
// --------------------------------------------------
/// @prop - Background color of the button
$fab-wp-background-color: color($colors-wp, primary) !default;
/// @prop - Text color of the button
$fab-wp-text-color: color-contrast($colors-wp, $fab-wp-background-color) !default;
/// @prop - Background color of the activated button
$fab-wp-background-color-activated: color-shade($fab-wp-background-color) !default;
/// @prop - Background color of the button in a list
$fab-wp-list-button-background-color: $fab-list-button-background-color !default;
/// @prop - Text color of the button in a list
$fab-wp-list-button-text-color: color-contrast($colors-wp, $fab-wp-list-button-background-color) !default;
/// @prop - Background color of the activated button in a list
$fab-wp-list-button-background-color-activated: color-shade($fab-wp-list-button-background-color) !default;
/// @prop - Transition duration of the transform and opacity of the button in a list
$fab-wp-list-button-transition-duration: 200ms !default;
/// @prop - Speed curve of the transition of the transform and opacity of the button in a list
$fab-wp-list-button-transition-timing-function: ease !default;
/// @prop - Transition delay of the transform and opacity of the button in a list
$fab-wp-list-button-transition-delay: 10ms !default;
.fab-wp {
color: $fab-wp-text-color;
background-color: $fab-wp-background-color;
}
.fab-wp.activated {
background-color: $fab-wp-background-color-activated;
}
.fab-wp-in-list {
color: $fab-wp-list-button-text-color;
background-color: $fab-wp-list-button-background-color;
transition: transform $fab-wp-list-button-transition-duration $fab-wp-list-button-transition-timing-function $fab-wp-list-button-transition-delay,
opacity $fab-wp-list-button-transition-duration $fab-wp-list-button-transition-timing-function $fab-wp-list-button-transition-delay;
}
.fab-wp-in-list.activated {
background-color: $fab-wp-list-button-background-color-activated;
}
// Generate WP FAB colors
// --------------------------------------------------
@each $color-name, $color-base, $color-contrast in get-colors($colors-wp) {
$bg-color: $color-base;
$bg-color-activated: color-shade($bg-color);
$fg-color: $color-contrast;
.fab-wp-#{$color-name} {
color: $fg-color;
background-color: $bg-color;
}
.fab-wp-#{$color-name}.activated {
background-color: $bg-color-activated;
}
}

View File

@ -0,0 +1,145 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="UTF-8">
<title>Ionic FAB</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<script src="/dist/ionic.js"></script>
</head>
<body>
<ion-app>
<ion-header>
<ion-toolbar>
<ion-title>Header</ion-title>
</ion-toolbar>
</ion-header>
<ion-fixed>
<ion-fab top right edge id="fab1">
<ion-fab-button onclick="clickMainFAB()" mini class="e2eFabTopRight"><ion-icon name="add"></ion-icon></ion-fab-button>
<ion-fab-list>
<ion-fab-button onclick="openSocial('facebook', 'fab1')"><ion-icon name="logo-facebook"></ion-icon></ion-fab-button>
<ion-fab-button onclick="openSocial('twitter', 'fab1')"><ion-icon name="logo-twitter"></ion-icon></ion-fab-button>
<ion-fab-button onclick="openSocial('vimeo', 'fab1')"><ion-icon name="logo-vimeo"></ion-icon></ion-fab-button>
<ion-fab-button onclick="openSocial('googleplus', 'fab1')"><ion-icon name="logo-googleplus"></ion-icon></ion-fab-button>
</ion-fab-list>
</ion-fab>
<ion-fab bottom right edge if="fab2">
<ion-fab-button onclick="clickMainFAB()" color="dark" class="e2eFabBottomRight"><ion-icon name="arrow-dropleft"></ion-icon></ion-fab-button>
<ion-fab-list side="left">
<ion-fab-button onclick="openSocial('facebook', 'fab2')"><ion-icon name="logo-facebook"></ion-icon></ion-fab-button>
<ion-fab-button onclick="openSocial('twitter', 'fab2')"><ion-icon name="logo-twitter"></ion-icon></ion-fab-button>
<ion-fab-button onclick="openSocial('vimeo', 'fab2')"><ion-icon name="logo-vimeo"></ion-icon></ion-fab-button>
<ion-fab-button onclick="openSocial('googleplus', 'fab2')"><ion-icon name="logo-googleplus"></ion-icon></ion-fab-button>
</ion-fab-list>
</ion-fab>
<ion-fab top left id="fab3">
<ion-fab-button onclick="clickMainFAB()" color="secondary" class="e2eFabTopLeft"><ion-icon name="arrow-dropright"></ion-icon></ion-fab-button>
<ion-fab-list side="right">
<ion-fab-button onclick="openSocial('facebook', 'fab3')"><ion-icon name="logo-facebook"></ion-icon></ion-fab-button>
<ion-fab-button onclick="openSocial('twitter', 'fab3')"><ion-icon name="logo-twitter"></ion-icon></ion-fab-button>
<ion-fab-button onclick="openSocial('vimeo', 'fab3')"><ion-icon name="logo-vimeo"></ion-icon></ion-fab-button>
<ion-fab-button onclick="openSocial('googleplus', 'fab3')"><ion-icon name="logo-googleplus"></ion-icon></ion-fab-button>
</ion-fab-list>
</ion-fab>
<ion-fab bottom left id="fab4">
<ion-fab-button onclick="clickMainFAB()" color="light" class="e2eFabBottomLeft"><ion-icon name="arrow-dropup"></ion-icon></ion-fab-button>
<ion-fab-list side="top">
<ion-fab-button onclick="openSocial('facebook', 'fab4')"><ion-icon name="logo-facebook"></ion-icon></ion-fab-button>
<ion-fab-button onclick="openSocial('twitter', 'fab4')"><ion-icon name="logo-twitter"></ion-icon></ion-fab-button>
<ion-fab-button onclick="openSocial('vimeo', 'fab4')"><ion-icon name="logo-vimeo"></ion-icon></ion-fab-button>
<ion-fab-button onclick="openSocial('googleplus', 'fab4')"><ion-icon name="logo-googleplus"></ion-icon></ion-fab-button>
</ion-fab-list>
</ion-fab>
<ion-fab center middle id="fab5">
<ion-fab-button onclick="clickMainFAB()" color="danger" class="e2eFabCenter"><ion-icon name="md-share"></ion-icon></ion-fab-button>
<ion-fab-list side="top">
<ion-fab-button onclick="openSocial('vimeo', 'fab5')" color="primary"><ion-icon name="logo-vimeo"></ion-icon></ion-fab-button>
</ion-fab-list>
<ion-fab-list side="bottom">
<ion-fab-button onclick="openSocial('facebook', 'fab5')" color="secondary"><ion-icon name="logo-facebook"></ion-icon></ion-fab-button>
</ion-fab-list>
<ion-fab-list side="left">
<ion-fab-button onclick="openSocial('googleplus', 'fab5')" color="light"><ion-icon name="logo-googleplus"></ion-icon></ion-fab-button>
</ion-fab-list>
<ion-fab-list side="right">
<ion-fab-button onclick="openSocial('twitter', 'fab5')" color="dark"><ion-icon name="logo-twitter"></ion-icon></ion-fab-button>
</ion-fab-list>
</ion-fab>
<ion-fab right middle>
<ion-fab-button color="danger" onclick="add()"><ion-icon name="add"></ion-icon></ion-fab-button>
</ion-fab>
</ion-fixed>
<ion-content padding fullscreen>
<f></f>
<f></f>
<pre id="log" ion-fixed style="right:10px; bottom:50px; text-shadow: 0 0 2px rgba(0, 0, 0, 0.24);">log</pre>
<ion-button>Test</ion-button>
</ion-content>
<ion-footer>
<ion-toolbar>
<ion-title>Footer</ion-title>
</ion-toolbar>
</ion-footer>
<script>
function insertAfter(el, referenceNode) {
referenceNode.parentNode.insertBefore(el, referenceNode.nextSibling);
}
function insertLog(message) {
console.log(message);
var ele = document.querySelector('#log');
const oldHTML = ele.innerHTML;
ele.innerHTML = oldHTML + '\n' + message;
}
function add() {
var newEle = document.createElement('f');
var ref = document.querySelector('f');
insertAfter(newEle, ref);
insertLog('add');
}
function clickMainFAB() {
let message = 'Clicked open social menu';
insertLog(message);
}
function openSocial(network, container) {
let message = 'Share in ' + network;
insertLog(message);
var fab = document.getElementById(container);
fab.close();
}
</script>
<style>
[ion-fixed] {
position: absolute;
}
f {
display: block;
margin: 15px auto;
max-width: 150px;
height: 150px;
background: blue;
}
f:last-of-type {
background: yellow;
}
</style>
</ion-app>
</body>
</html>

View File

@ -4,10 +4,11 @@ exports.config = {
publicPath: '/dist',
generateCollection: true,
bundles: [
{ components: ['ion-app', 'ion-content', 'ion-footer', 'ion-header', 'ion-navbar', 'ion-page', 'ion-title', 'ion-toolbar'] },
{ components: ['ion-app', 'ion-content', 'ion-fixed', 'ion-footer', 'ion-header', 'ion-navbar', 'ion-page', 'ion-title', 'ion-toolbar'] },
{ components: ['ion-avatar', 'ion-badge', 'ion-thumbnail'] },
{ components: ['ion-button', 'ion-buttons', 'ion-icon'] },
{ components: ['ion-card', 'ion-card-content', 'ion-card-header', 'ion-card-title'] },
{ components: ['ion-fab', 'ion-fab-button', 'ion-fab-list'] },
{ components: ['ion-gesture', 'ion-scroll'], priority: 'low' },
{ components: ['ion-item', 'ion-item-divider', 'ion-label', 'ion-list', 'ion-list-header', 'ion-skeleton-text'] },
{ components: ['ion-loading', 'ion-loading-controller'] },