feat(translucent): add translucent property to core components (#13475)

* refactor(components): add translucent property

* feat(toast): add translucent property to toast

* refactor(toolbar): get translucency working with colored toolbars

* refactor(fab): get colored fab and list fab working with translucent

* feat(loading): add translucent property for loading

* feat(popover): add translucent option to popover

* feat(card): add translucent property to card header

* refactor(components): default translucent to false

* refactor(card): use white for card header background

* refactor(tabs): update translucency values and add test for it

* feat(translucent): add translucent options to alert and action sheet

* refactor(translucent): update values for transucency

* feat(tabs): add translucent color styles
This commit is contained in:
Brandy Carney
2017-11-22 11:38:22 -05:00
committed by GitHub
parent 1530c9085d
commit 9599981723
43 changed files with 2187 additions and 201 deletions

View File

@ -101,6 +101,7 @@ declare global {
subTitle?: string,
buttons?: ActionSheetButton[],
enableBackdropDismiss?: boolean,
translucent?: boolean,
enterAnimation?: AnimationBuilder,
exitAnimation?: AnimationBuilder,
actionSheetId?: string
@ -171,6 +172,7 @@ declare global {
buttons?: AlertButton[],
inputs?: AlertInput[],
enableBackdropDismiss?: boolean,
translucent?: boolean,
enterAnimation?: AnimationBuilder,
exitAnimation?: AnimationBuilder,
alertId?: string
@ -465,7 +467,8 @@ declare global {
export interface IonCardHeaderAttributes extends HTMLAttributes {
color?: string,
mode?: 'ios' | 'md'
mode?: 'ios' | 'md',
translucent?: boolean
}
}
}
@ -842,6 +845,7 @@ declare global {
color?: string,
mode?: 'ios' | 'md',
href?: string,
translucent?: boolean,
activated?: boolean,
toggleActive?: Function,
show?: boolean,
@ -876,6 +880,7 @@ declare global {
namespace JSXElements {
export interface IonFooterAttributes extends HTMLAttributes {
translucent?: boolean
}
}
}
@ -1074,6 +1079,7 @@ declare global {
namespace JSXElements {
export interface IonHeaderAttributes extends HTMLAttributes {
translucent?: boolean
}
}
}
@ -1592,6 +1598,7 @@ declare global {
content?: string,
dismissOnPageChange?: boolean,
duration?: number,
translucent?: boolean,
enterAnimation?: AnimationBuilder,
exitAnimation?: AnimationBuilder,
loadingId?: string,
@ -2152,7 +2159,8 @@ declare global {
exitAnimation?: AnimationBuilder,
ev?: Event,
popoverId?: string,
showBackdrop?: boolean
showBackdrop?: boolean,
translucent?: boolean
}
}
}
@ -2886,71 +2894,6 @@ declare global {
}
import {
PageTab as PageTab
} from './components/tabs/page-tab';
declare global {
interface HTMLPageTabElement extends PageTab, HTMLElement {
}
var HTMLPageTabElement: {
prototype: HTMLPageTabElement;
new (): HTMLPageTabElement;
};
interface HTMLElementTagNameMap {
"page-tab": HTMLPageTabElement;
}
interface ElementTagNameMap {
"page-tab": HTMLPageTabElement;
}
namespace JSX {
interface IntrinsicElements {
"page-tab": JSXElements.PageTabAttributes;
}
}
namespace JSXElements {
export interface PageTabAttributes extends HTMLAttributes {
}
}
}
import {
TabBar as IonTabbar
} from './components/tabs/tab-bar';
declare global {
interface HTMLIonTabbarElement extends IonTabbar, HTMLElement {
}
var HTMLIonTabbarElement: {
prototype: HTMLIonTabbarElement;
new (): HTMLIonTabbarElement;
};
interface HTMLElementTagNameMap {
"ion-tabbar": HTMLIonTabbarElement;
}
interface ElementTagNameMap {
"ion-tabbar": HTMLIonTabbarElement;
}
namespace JSX {
interface IntrinsicElements {
"ion-tabbar": JSXElements.IonTabbarAttributes;
}
}
namespace JSXElements {
export interface IonTabbarAttributes extends HTMLAttributes {
placement?: string,
tabs?: HTMLIonTabElement[],
selectedTab?: HTMLIonTabElement,
layout?: string,
highlight?: boolean
}
}
}
import {
TabbarButton as IonTabButton
} from './components/tabs/tab-button';
@ -3054,6 +2997,42 @@ declare global {
}
import {
Tabbar as IonTabbar
} from './components/tabs/tabbar';
declare global {
interface HTMLIonTabbarElement extends IonTabbar, HTMLElement {
}
var HTMLIonTabbarElement: {
prototype: HTMLIonTabbarElement;
new (): HTMLIonTabbarElement;
};
interface HTMLElementTagNameMap {
"ion-tabbar": HTMLIonTabbarElement;
}
interface ElementTagNameMap {
"ion-tabbar": HTMLIonTabbarElement;
}
namespace JSX {
interface IntrinsicElements {
"ion-tabbar": JSXElements.IonTabbarAttributes;
}
}
namespace JSXElements {
export interface IonTabbarAttributes extends HTMLAttributes {
placement?: string,
tabs?: HTMLIonTabElement[],
selectedTab?: HTMLIonTabElement,
layout?: string,
highlight?: boolean,
translucent?: boolean
}
}
}
import {
Tabs as IonTabs
} from './components/tabs/tabs';
@ -3083,7 +3062,68 @@ declare global {
tabbarHidden?: boolean,
tabbarLayout?: string,
tabbarPlacement?: string,
tabbarHighlight?: boolean
tabbarHighlight?: boolean,
translucent?: boolean
}
}
}
import {
PageTab as PageTab
} from './components/tabs/test/basic/page-tab';
declare global {
interface HTMLPageTabElement extends PageTab, HTMLElement {
}
var HTMLPageTabElement: {
prototype: HTMLPageTabElement;
new (): HTMLPageTabElement;
};
interface HTMLElementTagNameMap {
"page-tab": HTMLPageTabElement;
}
interface ElementTagNameMap {
"page-tab": HTMLPageTabElement;
}
namespace JSX {
interface IntrinsicElements {
"page-tab": JSXElements.PageTabAttributes;
}
}
namespace JSXElements {
export interface PageTabAttributes extends HTMLAttributes {
}
}
}
import {
TranslucentPageTab as TranslucentPageTab
} from './components/tabs/test/translucent/translucent-page-tab';
declare global {
interface HTMLTranslucentPageTabElement extends TranslucentPageTab, HTMLElement {
}
var HTMLTranslucentPageTabElement: {
prototype: HTMLTranslucentPageTabElement;
new (): HTMLTranslucentPageTabElement;
};
interface HTMLElementTagNameMap {
"translucent-page-tab": HTMLTranslucentPageTabElement;
}
interface ElementTagNameMap {
"translucent-page-tab": HTMLTranslucentPageTabElement;
}
namespace JSX {
interface IntrinsicElements {
"translucent-page-tab": JSXElements.TranslucentPageTabAttributes;
}
}
namespace JSXElements {
export interface TranslucentPageTabAttributes extends HTMLAttributes {
}
}
}
@ -3211,6 +3251,7 @@ declare global {
closeButtonText?: string,
dismissOnPageChange?: boolean,
position?: string,
translucent?: boolean,
enterAnimation?: AnimationBuilder,
exitAnimation?: AnimationBuilder,
toastId?: string
@ -3315,7 +3356,8 @@ declare global {
export interface IonToolbarAttributes extends HTMLAttributes {
color?: string,
mode?: 'ios' | 'md'
mode?: 'ios' | 'md',
translucent?: boolean
}
}
}

View File

@ -29,7 +29,7 @@ $action-sheet-ios-group-margin-bottom: 10px !default;
$action-sheet-ios-background: #f9f9f9 !default;
/// @prop - Border color of the action sheet
$action-sheet-ios-border-color: #d6d6da !default;
$action-sheet-ios-border-color: rgba(0, 0, 0, .1) !default;
/// @prop - Border radius of the action sheet
$action-sheet-ios-border-radius: 13px !default;
@ -89,7 +89,7 @@ $action-sheet-ios-button-border-color: #d1d3d6 !default;
$action-sheet-ios-button-background: transparent !default;
/// @prop - Background color of the activated action sheet button
$action-sheet-ios-button-background-activated: #ebebeb !default;
$action-sheet-ios-button-background-activated: rgba(115, 115, 115, .1) !default;
/// @prop - Destructive text color of the action sheet button
$action-sheet-ios-button-destructive-text-color: #f53d3d !default;
@ -103,6 +103,12 @@ $action-sheet-ios-button-cancel-background: #fff !default;
/// @prop - Font weight of the action sheet cancel button
$action-sheet-ios-button-cancel-font-weight: 600 !default;
/// @prop - Filter of the translucent action-sheet
$action-sheet-ios-translucent-filter: saturate(180%) blur(20px) !default;
/// @prop - Opacity of the translucent action-sheet
$action-sheet-ios-translucent-opacity: .88 !default;
.action-sheet-ios {
@include text-align($action-sheet-ios-text-align);
@ -113,20 +119,23 @@ $action-sheet-ios-button-cancel-font-weight: 600 !default;
@include margin(env(safe-area-inset-top), auto, env(safe-area-inset-bottom), auto);
}
// iOS Action Sheet Container
// -----------------------------------------
.action-sheet-ios .action-sheet-container {
@include padding($action-sheet-ios-padding-top, $action-sheet-ios-padding-end, $action-sheet-ios-padding-bottom, $action-sheet-ios-padding-start);
}
// iOS Action Sheet Group
// -----------------------------------------
.action-sheet-ios .action-sheet-group {
@include border-radius($action-sheet-ios-border-radius);
@include margin(null, null, $action-sheet-ios-group-margin-bottom - 2, null);
background: $action-sheet-ios-background;
// scss-lint:disable VendorPrefix
-webkit-overflow-scrolling: touch;
// Prevents borders from going outside of the container
-webkit-mask-image: -webkit-radial-gradient(circle, #fff, #000);
}
.action-sheet-ios .action-sheet-group:first-child {
@ -137,6 +146,21 @@ $action-sheet-ios-button-cancel-font-weight: 600 !default;
@include margin(null, null, $action-sheet-ios-group-margin-bottom, null);
}
// iOS Translucent Action Sheet
// -----------------------------------------
.action-sheet-translucent-ios .action-sheet-group {
background: rgba($action-sheet-ios-background, $action-sheet-ios-translucent-opacity);
backdrop-filter: $action-sheet-ios-translucent-filter;
-webkit-backdrop-filter: $action-sheet-ios-translucent-filter;
}
// iOS Action Sheet Title
// -----------------------------------------
.action-sheet-ios .action-sheet-title {
@include border-radius($action-sheet-ios-title-border-radius);
@ -151,6 +175,10 @@ $action-sheet-ios-button-cancel-font-weight: 600 !default;
color: $action-sheet-ios-title-color;
}
// iOS Action Sheet Buttons
// -----------------------------------------
.action-sheet-ios .action-sheet-button {
@include margin(0);

View File

@ -86,6 +86,10 @@ $action-sheet-md-icon-margin-bottom: 0 !default;
$action-sheet-md-icon-margin-start: 0 !default;
// Material Design Action Sheet Title
// -----------------------------------------
.action-sheet-md .action-sheet-title,
.action-sheet-md .action-sheet-sub-title {
@include padding($action-sheet-md-title-padding-top, $action-sheet-md-title-padding-end, $action-sheet-md-title-padding-bottom, $action-sheet-md-title-padding-start);
@ -96,6 +100,26 @@ $action-sheet-md-icon-margin-start: 0 !default;
color: $action-sheet-md-title-color;
}
// Material Design Action Sheet Group
// -----------------------------------------
.action-sheet-md .action-sheet-group {
background: $action-sheet-md-background;
}
.action-sheet-md .action-sheet-group:first-child {
@include padding($action-sheet-md-padding-top, null, null, null);
}
.action-sheet-md .action-sheet-group:last-child {
@include padding(null, null, $action-sheet-md-padding-bottom, null);
}
// Material Design Action Sheet Buttons
// -----------------------------------------
.action-sheet-md .action-sheet-button {
@include padding($action-sheet-md-button-padding-top, $action-sheet-md-button-padding-end, $action-sheet-md-button-padding-bottom, $action-sheet-md-button-padding-start);
@ -128,18 +152,6 @@ $action-sheet-md-icon-margin-start: 0 !default;
vertical-align: $action-sheet-md-icon-vertical-align;
}
.action-sheet-md .action-sheet-group {
background: $action-sheet-md-background;
}
.action-sheet-md .action-sheet-group:first-child {
@include padding($action-sheet-md-padding-top, null, null, null);
}
.action-sheet-md .action-sheet-group:last-child {
@include padding(null, null, $action-sheet-md-padding-bottom, null);
}
.action-sheet-md .action-sheet-group .button-inner {
justify-content: flex-start;
}

View File

@ -1,6 +1,8 @@
import { Component, CssClassMap, Element, Event, EventEmitter, Listen, Prop } from '@stencil/core';
import { Animation, AnimationBuilder, AnimationController, Config } from '../../index';
import { createThemedClasses } from '../../utils/theme';
import iOSEnterAnimation from './animations/ios.enter';
import iOSLeaveAnimation from './animations/ios.leave';
@ -15,6 +17,9 @@ import iOSLeaveAnimation from './animations/ios.leave';
}
})
export class ActionSheet {
mode: string;
color: string;
private animation: Animation;
@Element() private el: HTMLElement;
@ -57,6 +62,7 @@ export class ActionSheet {
@Prop() subTitle: string;
@Prop() buttons: ActionSheetButton[];
@Prop() enableBackdropDismiss: boolean = true;
@Prop() translucent: boolean = false;
@Prop() enterAnimation: AnimationBuilder;
@Prop() exitAnimation: AnimationBuilder;
@ -160,6 +166,16 @@ export class ActionSheet {
}
}
buttonClass(button: ActionSheetButton): CssClassMap {
let buttonClass: string[] = !button.role
? ['action-sheet-button']
: [`action-sheet-button`, `action-sheet-${button.role}`];
return buttonClass.reduce((prevValue: any, cssClass: any) => {
prevValue[cssClass] = true;
return prevValue;
}, {});
}
protected buttonClick(button: ActionSheetButton) {
let shouldDismiss = true;
if (button.handler) {
@ -172,6 +188,18 @@ export class ActionSheet {
}
}
hostData() {
const themedClasses = this.translucent ? createThemedClasses(this.mode, this.color, 'action-sheet-translucent') : {};
const hostClasses = {
...themedClasses
};
return {
class: hostClasses
};
}
render() {
let userCssClass = 'action-sheet-content';
if (this.cssClass) {
@ -241,16 +269,6 @@ export class ActionSheet {
</div>
];
}
buttonClass(button: ActionSheetButton): CssClassMap {
let buttonClass: string[] = !button.role
? ['action-sheet-button']
: [`action-sheet-button`, `action-sheet-${button.role}`];
return buttonClass.reduce((prevValue: any, cssClass: any) => {
prevValue[cssClass] = true;
return prevValue;
}, {});
}
}
export interface ActionSheetOptions {
@ -259,6 +277,7 @@ export interface ActionSheetOptions {
cssClass?: string;
buttons?: (ActionSheetButton | string)[];
enableBackdropDismiss?: boolean;
translucent?: boolean;
}
export interface ActionSheetButton {

View File

@ -0,0 +1,368 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="UTF-8">
<title>Action Sheet - Translucent</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<script src="/dist/ionic.js"></script>
</head>
<body>
<ion-app>
<ion-page>
<ion-header>
<ion-toolbar>
<ion-title>Action Sheet - Translucent</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding>
<ion-action-sheet-controller></ion-action-sheet-controller>
<ion-button id="basic" block onclick="presentBasic()">Basic</ion-button>
<ion-button id="noBackdropDismiss" block onclick="presentNoBackdropDismiss()">No Backdrop Dismiss</ion-button>
<ion-button id="alertFromActionSheet" block onclick="presentAlert()">Alert from Action Sheet</ion-button>
<ion-button id="scrollableOptions" block onclick="presentScroll()">Scrollable Options</ion-button>
<ion-button id="scrollWithoutCancel" block onclick="presentScrollNoCancel()">Scroll Without Cancel</ion-button>
<ion-button id="cancelOnly" block onclick="presentCancelOnly()">Cancel Only</ion-button>
<ion-grid>
<ion-row>
<ion-col col-4><f class="red"></f></ion-col>
<ion-col col-4><f class="green"></f></ion-col>
<ion-col col-4><f class="blue"></f></ion-col>
<ion-col col-4><f class="yellow"></f></ion-col>
<ion-col col-4><f class="pink"></f></ion-col>
<ion-col col-4><f class="purple"></f></ion-col>
<ion-col col-4><f class="black"></f></ion-col>
<ion-col col-4><f class="fuchsia"></f></ion-col>
<ion-col col-4><f class="orange"></f></ion-col>
</ion-row>
</ion-grid>
</ion-content>
</ion-page>
</ion-app>
<script>
function presentBasic() {
var mode = Ionic.mode;
var actionSheetController = document.querySelector('ion-action-sheet-controller');
actionSheetController.create({
title: "Albums",
buttons: [{
text: 'Delete',
role: 'destructive',
icon: 'trash',
handler: () => {
console.log('Delete clicked');
}
}, {
text: 'Share',
icon: 'share',
handler: () => {
console.log('Share clicked');
}
}, {
text: 'Play (open modal)',
icon: 'arrow-dropright-circle',
handler: () => {
console.log('Play clicked');
}
}, {
text: 'Favorite',
icon: mode !== 'ios' ? 'heart' : null,
handler: () => {
console.log('Favorite clicked');
}
}, {
text: 'Cancel',
role: 'cancel',
icon: mode !== 'ios' ? 'close' : null,
handler: () => {
console.log('Cancel clicked');
}
}],
translucent: true
})
.then(actionSheet => {
actionSheet.present()
});
}
function presentNoBackdropDismiss() {
var actionSheetController = document.querySelector('ion-action-sheet-controller');
actionSheetController.create({
buttons: [{
text: 'Archive',
handler: () => {
console.log('Archive clicked');
}
}, {
text: 'Destructive',
role: 'destructive',
handler: () => {
console.log('Destructive clicked');
}
}, {
text: 'Cancel',
role: 'cancel',
handler: () => {
console.log('Cancel clicked');
}
}],
translucent: true
})
.then(actionSheet => {
actionSheet.present()
});
}
function presentAlert() {
var actionSheetController = document.querySelector('ion-action-sheet-controller');
actionSheetController.create({
buttons: [{
text: 'Open Alert',
handler: () => {
console.log('Open Alert clicked');
}
}, {
text: 'Cancel',
role: 'cancel',
handler: () => {
console.log('Cancel clicked');
}
}],
translucent: true
})
.then(actionSheet => {
actionSheet.present()
});
}
function presentScroll() {
var actionSheetController = document.querySelector('ion-action-sheet-controller');
actionSheetController.create({
buttons: [
{
text: 'Add Reaction',
handler: () => {
console.log('Add Reaction clicked');
}
}, {
text: 'Copy Text',
handler: () => {
console.log('Copy Text clicked');
}
}, {
text: 'Share Text',
handler: () => {
console.log('Share Text clicked');
}
}, {
text: 'Copy Link to Message',
handler: () => {
console.log('Copy Link to Message clicked');
}
}, {
text: 'Remind Me',
handler: () => {
console.log('Remind Me clicked');
}
}, {
text: 'Pin File',
handler: () => {
console.log('Pin File clicked');
}
}, {
text: 'Star File',
handler: () => {
console.log('Star File clicked');
}
}, {
text: 'Mark Unread',
handler: () => {
console.log('Mark Unread clicked');
}
}, {
text: 'Edit Title',
handler: () => {
console.log('Edit Title clicked');
}
}, {
text: 'Save Image',
handler: () => {
console.log('Save Image clicked');
}
}, {
text: 'Copy Image',
handler: () => {
console.log('Copy Image clicked');
}
}, {
text: 'Delete File',
role: 'destructive',
handler: () => {
console.log('Delete File clicked');
}
}, {
text: 'Cancel',
role: 'cancel', // will always sort to be on the bottom
handler: () => {
console.log('Cancel clicked');
}
}
],
translucent: true
})
.then(actionSheet => {
actionSheet.present()
});
}
function presentScrollNoCancel() {
var actionSheetController = document.querySelector('ion-action-sheet-controller');
actionSheetController.create({
buttons: [
{
text: 'Add Reaction',
handler: () => {
console.log('Add Reaction clicked');
}
}, {
text: 'Copy Text',
handler: () => {
console.log('Copy Text clicked');
}
}, {
text: 'Share Text',
handler: () => {
console.log('Share Text clicked');
}
}, {
text: 'Copy Link to Message',
handler: () => {
console.log('Copy Link to Message clicked');
}
}, {
text: 'Remind Me',
handler: () => {
console.log('Remind Me clicked');
}
}, {
text: 'Pin File',
handler: () => {
console.log('Pin File clicked');
}
}, {
text: 'Star File',
handler: () => {
console.log('Star File clicked');
}
}, {
text: 'Mark Unread',
handler: () => {
console.log('Mark Unread clicked');
}
}, {
text: 'Edit Title',
handler: () => {
console.log('Edit Title clicked');
}
}, {
text: 'Save Image',
handler: () => {
console.log('Save Image clicked');
}
}, {
text: 'Copy Image',
handler: () => {
console.log('Copy Image clicked');
}
}, {
text: 'Delete File',
role: 'destructive',
handler: () => {
console.log('Delete File clicked');
}
}
],
translucent: true
})
.then(actionSheet => {
actionSheet.present()
});
}
function presentCancelOnly() {
var actionSheetController = document.querySelector('ion-action-sheet-controller');
actionSheetController.create({
buttons: [
{
text: 'Cancel',
role: 'cancel', // will always sort to be on the bottom
handler: () => {
console.log('Cancel clicked');
}
}
],
translucent: true
})
.then(actionSheet => {
actionSheet.present()
});
}
</script>
<style>
f {
display: block;
width: 100%;
height: 150px;
}
.red {
background-color: #ea445a;
}
.green {
background-color: #76d672;
}
.blue {
background-color: #3478f6;
}
.yellow {
background-color: #ffff80;
}
.pink {
background-color: #ff6b86;
}
.purple {
background-color: #7e34f6;
}
.black {
background-color: #000;
}
.fuchsia {
background-color: #cc00ff;
}
.orange {
background-color: #f69234;
}
</style>
</body>
</html>

View File

@ -58,7 +58,6 @@ $alert-ios-message-padding-bottom: 21px !default;
/// @prop - Padding start of the alert message
$alert-ios-message-padding-start: $alert-ios-message-padding-end !default;
/// @prop - Font size of the alert message
$alert-ios-message-font-size: 13px !default;
@ -135,7 +134,7 @@ $alert-ios-button-text-color: color($colors-ios, primary) !def
$alert-ios-button-background-color: transparent !default;
/// @prop - Background color of the alert activated button
$alert-ios-button-background-color-activated: #e9e9e9 !default;
$alert-ios-button-background-color-activated: rgba(115, 115, 115, .1) !default;
/// @prop - Border width of the alert button
$alert-ios-button-border-width: $hairlines-width !default;
@ -144,7 +143,7 @@ $alert-ios-button-border-width: $hairlines-width !default;
$alert-ios-button-border-style: solid !default;
/// @prop - Border color of the alert button
$alert-ios-button-border-color: #dbdbdf !default;
$alert-ios-button-border-color: rgba(0, 0, 0, .1) !default;
/// @prop - Border radius of the alert button
$alert-ios-button-border-radius: 0 !default;
@ -278,6 +277,12 @@ $alert-ios-checkbox-icon-border-color: $background-ios-color !default;
/// @prop - Transform of the icon in the checkbox alert
$alert-ios-checkbox-icon-transform: rotate(45deg) !default;
/// @prop - Filter of the translucent alert
$alert-ios-translucent-filter: saturate(180%) blur(20px) !default;
/// @prop - Opacity of the translucent alert
$alert-ios-translucent-opacity: .88 !default;
.alert-ios .alert-wrapper {
@include border-radius($alert-ios-border-radius);
@ -292,6 +297,17 @@ $alert-ios-checkbox-icon-transform: rotate(45deg) !default;
}
// iOS Translucent Alert
// -----------------------------------------
.alert-translucent-ios .alert-wrapper {
background: rgba($alert-ios-background, $alert-ios-translucent-opacity);
backdrop-filter: $alert-ios-translucent-filter;
-webkit-backdrop-filter: $alert-ios-translucent-filter;
}
// iOS Alert Header
// --------------------------------------------------

View File

@ -3,6 +3,8 @@ import { Component, CssClassMap, Element, Event, EventEmitter, Listen, Method, P
import { Animation, AnimationBuilder, AnimationController, Config } from '../../index';
import { playAnimationAsync } from '../../utils/helpers';
import { createThemedClasses } from '../../utils/theme';
import iOSEnterAnimation from './animations/ios.enter';
import iOSLeaveAnimation from './animations/ios.leave';
@ -17,6 +19,9 @@ import iOSLeaveAnimation from './animations/ios.leave';
}
})
export class Alert {
mode: string;
color: string;
private animation: Animation;
private activeId: string;
private inputType: string;
@ -64,6 +69,7 @@ export class Alert {
@Prop() buttons: AlertButton[] = [];
@Prop({ mutable: true }) inputs: AlertInput[] = [];
@Prop() enableBackdropDismiss: boolean = true;
@Prop() translucent: boolean = false;
@Prop() enterAnimation: AnimationBuilder;
@Prop() exitAnimation: AnimationBuilder;
@ -146,7 +152,7 @@ export class Alert {
this.dismiss();
}
protected backdropClick() {
if (this.enableBackdropDismiss) {
// const opts: NavOptions = {
@ -310,6 +316,19 @@ export class Alert {
);
}
hostData() {
const themedClasses = this.translucent ? createThemedClasses(this.mode, this.color, 'alert-translucent') : {};
const hostClasses = {
...themedClasses
};
return {
class: hostClasses,
id: this.alertId
};
}
render() {
const hdrId = `${this.alertId}-hdr`;
const subHdrId = `${this.alertId}-sub-hdr`;
@ -413,12 +432,6 @@ export class Alert {
];
}
hostData() {
return {
id: this.alertId
};
}
}
@ -431,6 +444,7 @@ export interface AlertOptions {
inputs?: AlertInput[];
buttons?: (AlertButton|string)[];
enableBackdropDismiss?: boolean;
translucent?: boolean;
}
export interface AlertInput {

View File

@ -0,0 +1,361 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="UTF-8">
<title>Alert - Translucent</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-page>
<ion-header>
<ion-toolbar>
<ion-title>Alert - Translucent</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding>
<ion-alert-controller></ion-alert-controller>
<ion-button block onclick="presentAlert()">Alert</ion-button>
<ion-button block color="secondary" onclick="presentAlertLongMessage()">Alert Long Message</ion-button>
<ion-button block color="danger" onclick="presentAlertMultipleButtons()">Multiple Buttons (>2)</ion-button>
<ion-button block color="light" onclick="presentAlertNoMessage()">Alert No Message</ion-button>
<ion-grid>
<ion-row>
<ion-col col-4><f class="red"></f></ion-col>
<ion-col col-4><f class="green"></f></ion-col>
<ion-col col-4><f class="blue"></f></ion-col>
<ion-col col-4><f class="yellow"></f></ion-col>
<ion-col col-4><f class="pink"></f></ion-col>
<ion-col col-4><f class="purple"></f></ion-col>
<ion-col col-4><f class="black"></f></ion-col>
<ion-col col-4><f class="fuchsia"></f></ion-col>
<ion-col col-4><f class="orange"></f></ion-col>
</ion-row>
</ion-grid>
<ion-button block color="dark" onclick="presentAlertConfirm()">Confirm</ion-button>
<ion-button block color="primary" onclick="presentAlertPrompt()">Prompt</ion-button>
<ion-button block color="secondary" onclick="presentAlertRadio()">Radio</ion-button>
<ion-button block color="danger" onclick="presentAlertCheckbox()">Checkbox</ion-button>
</ion-content>
</ion-page>
</ion-app>
<script>
async function presentAlert() {
var alertController = document.querySelector('ion-alert-controller');
await alertController.componentOnReady();
const alert = await alertController.create({
title: 'Alert',
subTitle: 'Subtitle',
message: 'This is an alert message.',
buttons: ['OK'],
translucent: true
});
return await alert.present();
}
async function presentAlertLongMessage() {
var alertController = document.querySelector('ion-alert-controller');
await alertController.componentOnReady();
const alert = await alertController.create({
title: 'Alert',
message: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum hendrerit diam lorem, a faucibus turpis sagittis eu. In finibus augue in dui varius convallis. Donec vulputate nibh gravida odio vulputate commodo. Suspendisse imperdiet consequat egestas. Nulla feugiat consequat urna eu tincidunt. Cras nec blandit turpis, eu auctor nunc. Pellentesque finibus, magna eu vestibulum imperdiet, arcu ex lacinia massa, eget volutpat quam leo a orci. Etiam mauris est, elementum at feugiat at, dictum in sapien. Mauris efficitur eros sodales convallis egestas. Phasellus eu faucibus nisl. In eu diam vitae libero egestas lacinia. Integer sed convallis metus, nec commodo felis. Duis libero augue, ornare at tempus non, posuere vel augue. Cras mattis dui at tristique aliquam. Phasellus fermentum nibh ligula, porta hendrerit ligula elementum eu. Suspendisse sollicitudin enim at libero iaculis pulvinar. Donec ac massa id purus laoreet rutrum quis eu urna. Mauris luctus erat vel magna porttitor, vel varius erat rhoncus. Donec eu turpis vestibulum, feugiat urna id, gravida mauris. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer at lobortis tortor. Nam ultrices volutpat elit, sed pharetra nulla suscipit at. Nunc eu accumsan eros, id auctor libero. Suspendisse potenti. Nam vitae dapibus metus. Maecenas nisi dui, sagittis et condimentum eu, bibendum vel eros. Vivamus malesuada, tortor in accumsan iaculis, urna velit consectetur ante, nec semper sem diam a diam. In et semper ante. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus blandit, velit vel porttitor euismod, neque risus blandit nulla, non laoreet libero dolor et odio. Nulla enim risus, feugiat eu urna sed, ultrices semper felis. Sed blandit mi diam. Nunc quis mi ligula. Pellentesque a elit eu orci volutpat egestas. Aenean fermentum eleifend quam, ut tincidunt eros tristique et. Nam dapibus tincidunt ligula, id faucibus felis sodales quis. Donec tincidunt lectus ipsum, ac semper tellus cursus ac. Vestibulum nec dui a lectus accumsan vestibulum quis et velit. Aliquam finibus justo et odio euismod, viverra condimentum eros tristique. Sed eget luctus risus. Pellentesque lorem magna, dictum non congue sodales, laoreet eget quam. In sagittis vulputate dolor a ultricies. Donec viverra leo sed ex maximus, in finibus elit gravida. Aliquam posuere vulputate mi. Suspendisse potenti. Nunc consectetur congue arcu, at pharetra dui varius non. Etiam vestibulum congue felis, id ullamcorper neque convallis ultrices. Aenean congue, diam a iaculis mollis, nisl eros maximus arcu, nec hendrerit purus felis porta diam. Nullam vitae ultrices dui, ac dictum sapien. Phasellus eu magna luctus, varius urna id, molestie quam. Nulla in semper tellus. Curabitur lacinia tellus sit amet lacinia dapibus. Sed id condimentum tellus, nec aliquam sapien. Vivamus luctus at ante a tincidunt.',
buttons: ['Cancel', 'OK'],
translucent: true
});
return await alert.present();
}
async function presentAlertMultipleButtons() {
var alertController = document.querySelector('ion-alert-controller');
await alertController.componentOnReady();
const alert = await alertController.create({
title: 'Alert',
subTitle: 'Subtitle',
message: 'This is an alert message.',
buttons: ['Cancel', 'Open Modal', 'Delete'],
translucent: true
});
return await alert.present();
}
async function presentAlertNoMessage() {
var alertController = document.querySelector('ion-alert-controller');
await alertController.componentOnReady();
const alert = await alertController.create({
title: 'Alert',
buttons: ['OK'],
translucent: true
});
return await alert.present();
}
async function presentAlertConfirm() {
var alertController = document.querySelector('ion-alert-controller');
await alertController.componentOnReady();
const alert = await alertController.create({
title: 'Confirm!',
message: 'Message <strong>text</strong>!!!',
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'secondary',
handler: (blah) => {
console.log('Confirm Cancel: blah');
}
}, {
text: 'Okay',
handler: () => {
console.log('Confirm Okay')
}
}
],
translucent: true
});
return await alert.present();
}
async function presentAlertPrompt() {
var alertController = document.querySelector('ion-alert-controller');
await alertController.componentOnReady();
const alert = await alertController.create({
title: 'Prompt!',
inputs: [
{
placeholder: 'Placeholder 1'
},
{
name: 'name2',
id: 'name2-id',
value: 'hello',
placeholder: 'Placeholder 2'
},
{
name: 'name3',
value: 'http://ionicframework.com',
type: 'url',
placeholder: 'Favorite site ever'
},
// input date with min & max
{
name: 'name4',
type: 'date',
min: '2017-03-01',
max: '2018-01-12'
},
// input date without min nor max
{
name: 'name5',
type: 'date'
},
{
name: 'name6',
type: 'number',
min: -5,
max: 10
},
{
name: 'name7',
type: 'number'
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'secondary',
handler: () => {
console.log('Confirm Cancel')
}
}, {
text: 'Ok',
handler: () => {
console.log('Confirm Ok')
}
}
],
translucent: true
});
return await alert.present();
}
async function presentAlertRadio() {
var alertController = document.querySelector('ion-alert-controller');
await alertController.componentOnReady();
const alert = await alertController.create({
title: 'Radio',
inputs: [
{
type: 'radio',
label: 'Radio 1',
value: 'value1',
checked: true
},
{
type: 'radio',
label: 'Radio 2',
value: 'value2'
},
{
type: 'radio',
label: 'Radio 3',
value: 'value3'
},
{
type: 'radio',
label: 'Radio 4',
value: 'value4'
},
{
type: 'radio',
label: 'Radio 5',
value: 'value5'
},
{
type: 'radio',
label: 'Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 ',
value: 'value6'
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'secondary',
handler: () => {
console.log('Confirm Cancel')
}
}, {
text: 'Ok',
handler: () => {
console.log('Confirm Ok')
}
}
],
translucent: true
});
return await alert.present();
}
async function presentAlertCheckbox() {
var alertController = document.querySelector('ion-alert-controller');
await alertController.componentOnReady();
const alert = await alertController.create({
title: 'Checkbox',
inputs: [
{
type: 'checkbox',
label: 'Checkbox 1',
value: 'value1',
checked: true
},
{
type: 'checkbox',
label: 'Checkbox 2',
value: 'value2'
},
{
type: 'checkbox',
label: 'Checkbox 3',
value: 'value3'
},
{
type: 'checkbox',
label: 'Checkbox 4',
value: 'value4'
},
{
type: 'checkbox',
label: 'Checkbox 5',
value: 'value5'
},
{
type: 'checkbox',
label: 'Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6',
value: 'value6'
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'secondary',
handler: () => {
console.log('Confirm Cancel')
}
}, {
text: 'Ok',
handler: () => {
console.log('Confirm Ok')
}
}
],
translucent: true
});
return await alert.present();
}
</script>
<style>
f {
display: block;
width: 100%;
height: 50px;
}
.red {
background-color: #ea445a;
}
.green {
background-color: #76d672;
}
.blue {
background-color: #3478f6;
}
.yellow {
background-color: #ffff80;
}
.pink {
background-color: #ff6b86;
}
.purple {
background-color: #7e34f6;
}
.black {
background-color: #000;
}
.fuchsia {
background-color: #cc00ff;
}
.orange {
background-color: #f69234;
}
</style>
</body>
</html>

View File

@ -6,18 +6,34 @@
// --------------------------------------------------
/// @prop - Padding top of the card header
$card-ios-header-padding-top: 20px !default;
$card-ios-header-padding-top: 20px !default;
/// @prop - Padding end of the card header
$card-ios-header-padding-end: $card-ios-header-padding-top !default;
$card-ios-header-padding-end: $card-ios-header-padding-top !default;
/// @prop - Padding bottom of the card header
$card-ios-header-padding-bottom: 16px !default;
$card-ios-header-padding-bottom: 16px !default;
/// @prop - Padding start of the card header
$card-ios-header-padding-start: $card-ios-header-padding-end !default;
$card-ios-header-padding-start: $card-ios-header-padding-end !default;
/// @prop - Filter of the translucent card header
$card-ios-header-translucent-background: #fff !default;
/// @prop - Filter of the translucent card header
$card-ios-header-translucent-filter: saturate(180%) blur(30px) !default;
/// @prop - Opacity of the translucent cardheader
$card-ios-header-translucent-opacity: .88 !default;
.card-header-ios {
@include padding($card-ios-header-padding-top, $card-ios-header-padding-end, $card-ios-header-padding-bottom, $card-ios-header-padding-start);
}
.card-header-translucent-ios {
background-color: rgba($card-ios-header-translucent-background, $card-ios-header-translucent-opacity);
-webkit-backdrop-filter: $card-ios-header-translucent-filter;
backdrop-filter: $card-ios-header-translucent-filter;
}

View File

@ -1,5 +1,6 @@
import { Component, Prop } from '@stencil/core';
import { createThemedClasses } from '../../utils/theme';
@Component({
tag: 'ion-card-header',
@ -26,6 +27,24 @@ export class CardHeader {
*/
@Prop() mode: 'ios' | 'md';
/**
* @input {boolean} If true, adds transparency to the card header.
* Only affects `ios` mode. Defaults to `false`.
*/
@Prop() translucent: boolean = false;
hostData() {
const themedClasses = this.translucent ? createThemedClasses(this.mode, this.color, 'card-header-translucent') : {};
const hostClasses = {
...themedClasses
};
return {
class: hostClasses
};
}
render() {
return <slot></slot>;
}

View File

@ -52,6 +52,8 @@ $card-ios-text-color: #666 !default;
background: $card-ios-background-color;
box-shadow: $card-ios-box-shadow;
transform: translateZ(0);
}
.card-ios ion-list {

View File

@ -17,7 +17,7 @@
</ion-toolbar>
</ion-header>
<ion-content>
<ion-content fullscreen="true">
<ion-card>
<ion-card-content>
This is just your basic card with some text to boot. Like it? Keep scrolling...
@ -41,10 +41,9 @@
<ion-card>
<div style="position: absolute; top: 0; left:0; right:0; bottom:0;">
<img src="https://images.unsplash.com/photo-1483354483454-4cd359948304?dpr=1&auto=format&fit=crop&w=1000&q=80&cs=tinysrgb&ixid=dW5zcGxhc2guY29tOzs7Ozs%3D">
<img style="transform: rotate(145deg) scale(1.5)" src="http://images.all-free-download.com/images/graphiclarge/travel_icons_6813629.jpg">
</div>
<ion-card-header>
<ion-card-header translucent>
<ion-card-subtitle>
Subtitle
</ion-card-subtitle>
@ -53,21 +52,38 @@
</ion-card-title>
</ion-card-header>
<ion-card-content>
<ion-card-content style="min-height: 200px">
</ion-card-content>
</ion-card>
<ion-card style="color: white;">
<div style="position: absolute; top: 0; left:0; right:0; bottom:0;">
<img style="transform: scale(2)" src="https://images.unsplash.com/photo-1500531279542-fc8490c8ea4d?auto=format&fit=crop&w=1502&q=60&ixid=dW5zcGxhc2guY29tOzs7Ozs%3D">
</div>
<ion-card-header translucent>
<ion-card-subtitle>
Subtitle
</ion-card-subtitle>
<ion-card-title>
Title
</ion-card-title>
</ion-card-header>
<ion-card-content style="padding-top: 100px">
The British use the term "header", but the American term "head-shot" the English simply refuse to adopt.
</ion-card-content>
</ion-card>
<ion-card style="color: white">
<ion-card>
<div style="position: absolute; top: 0; left:0; right:0; bottom:0;">
<img src="https://images.unsplash.com/photo-1500531279542-fc8490c8ea4d?auto=format&fit=crop&w=1502&q=60&ixid=dW5zcGxhc2guY29tOzs7Ozs%3D">
<img src="https://images.unsplash.com/photo-1483354483454-4cd359948304?dpr=1&auto=format&fit=crop&w=1000&q=80&cs=tinysrgb&ixid=dW5zcGxhc2guY29tOzs7Ozs%3D">
</div>
<ion-card-header style="background-color: rgba(255, 255, 255, 0.4)">
<ion-card-subtitle color="light">
<ion-card-header>
<ion-card-subtitle>
Subtitle
</ion-card-subtitle>
<ion-card-title color="light">
<ion-card-title>
Title
</ion-card-title>
</ion-card-header>

View File

@ -37,6 +37,12 @@ $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;
/// @prop - Filter of the translucent fab
$fab-ios-translucent-filter: saturate(180%) blur(20px) !default;
/// @prop - Opacity of the translucent fab
$fab-ios-translucent-opacity: .88 !default;
.fab-ios {
color: $fab-ios-text-color;
@ -70,6 +76,20 @@ $fab-ios-list-button-transition-delay: 10ms !default;
fill: $fab-ios-list-button-icon-fill-color;
}
// Translucent FAB buttons
// --------------------------------------------------
.fab-translucent-ios {
background-color: rgba($fab-ios-background-color, $fab-ios-translucent-opacity);
-webkit-backdrop-filter: $fab-ios-translucent-filter;
backdrop-filter: $fab-ios-translucent-filter;
}
.fab-translucent-ios-in-list {
background-color: rgba($fab-ios-list-button-background-color, $fab-ios-translucent-opacity);
}
// Generate iOS FAB colors
// --------------------------------------------------
@ -92,5 +112,13 @@ $fab-ios-list-button-transition-delay: 10ms !default;
.fab-ios-#{$color-name}.activated {
background-color: $bg-color-activated;
}
.fab-translucent-ios-#{$color-name} {
background-color: rgba($bg-color, $fab-ios-translucent-opacity);
}
.fab-translucent-ios-#{$color-name}.activated {
background-color: rgba($bg-color-activated, $fab-ios-translucent-opacity);
}
}

View File

@ -77,6 +77,12 @@ export class FabButton {
*/
@Prop() href: string;
/**
* @input {boolean} If true, adds transparency to the fab.
* Only affects `ios` mode. Defaults to `false`.
*/
@Prop() translucent: boolean = false;
@Prop() activated: boolean = false;
@Prop() toggleActive: Function = () => {};
@ -112,10 +118,16 @@ export class FabButton {
if (!this.inList) {
return [];
}
return [
let listClasses = [
`fab-in-list`,
`fab-${this.mode}-in-list`
];
if (this.translucent) {
listClasses.push(`fab-translucent-${this.mode}-in-list`);
}
return listClasses;
}
/**
@ -146,6 +158,7 @@ export class FabButton {
render() {
const themedClasses = createThemedClasses(this.mode, this.color, 'fab');
const translucentClasses = this.translucent ? createThemedClasses(this.mode, this.color, 'fab-translucent') : {};
const hostClasses = getElementClassObject(this.el.classList);
const elementClasses: CssClassMap = []
@ -163,6 +176,7 @@ export class FabButton {
const fabClasses = {
...themedClasses,
...translucentClasses,
...hostClasses,
...elementClasses
};

View File

@ -23,7 +23,7 @@
<ion-button>Test</ion-button>
<ion-fab top right edge id="fab1" slot="fixed">
<ion-fab-button onclick="clickMainFAB()" mini class="e2eFabTopRight"><ion-icon name="add"></ion-icon></ion-fab-button>
<ion-fab-button onclick="clickMainFAB('fab1')" 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>
@ -33,7 +33,7 @@
</ion-fab>
<ion-fab bottom right edge id="fab2" slot="fixed">
<ion-fab-button onclick="clickMainFAB()" color="dark" class="e2eFabBottomRight"><ion-icon name="arrow-dropleft"></ion-icon></ion-fab-button>
<ion-fab-button onclick="clickMainFAB('fab2')" 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>
@ -43,7 +43,7 @@
</ion-fab>
<ion-fab top left id="fab3" slot="fixed">
<ion-fab-button onclick="clickMainFAB()" color="secondary" class="e2eFabTopLeft"><ion-icon name="arrow-dropright"></ion-icon></ion-fab-button>
<ion-fab-button onclick="clickMainFAB('fab3')" 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>
@ -53,7 +53,7 @@
</ion-fab>
<ion-fab bottom left id="fab4" slot="fixed">
<ion-fab-button onclick="clickMainFAB()" color="light" class="e2eFabBottomLeft"><ion-icon name="arrow-dropup"></ion-icon></ion-fab-button>
<ion-fab-button onclick="clickMainFAB('fab4')" 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>
@ -63,7 +63,7 @@
</ion-fab>
<ion-fab center middle id="fab5" slot="fixed">
<ion-fab-button onclick="clickMainFAB()" color="danger" class="e2eFabCenter"><ion-icon name="md-share"></ion-icon></ion-fab-button>
<ion-fab-button onclick="clickMainFAB('fab5')" 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>
@ -109,17 +109,26 @@
insertLog('add');
}
function clickMainFAB() {
function clickMainFAB(container) {
let message = 'Clicked open social menu';
insertLog(message);
openLists(container);
}
function openSocial(network, container) {
let message = 'Share in ' + network;
insertLog(message);
var fab = document.getElementById(container);
fab.close();
openLists(container);
}
function openLists(container) {
var fabLists = document.getElementById(container).querySelectorAll('ion-fab-list');
for (var i = 0; i < fabLists.length; i++) {
fabLists[i].activated = true;
}
}
</script>
@ -138,4 +147,4 @@
</style>
</ion-app>
</body>
</html>
</html>

View File

@ -0,0 +1,189 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="UTF-8">
<title>Floating Action Button - Translucent</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<script src="/dist/ionic.js"></script>
</head>
<body>
<ion-app>
<ion-page>
<ion-header>
<ion-toolbar>
<ion-title>Floating Action Button - Translucent</ion-title>
</ion-toolbar>
</ion-header>
<ion-content fullscreen>
<ion-grid>
<ion-row>
<ion-col col-6><f class="red"></f></ion-col>
<ion-col col-6><f class="green"></f></ion-col>
<ion-col col-6><f class="blue"></f></ion-col>
<ion-col col-6><f class="yellow"></f></ion-col>
<ion-col col-6><f class="pink"></f></ion-col>
<ion-col col-6><f class="purple"></f></ion-col>
<ion-col col-6><f class="black"></f></ion-col>
<ion-col col-6><f class="orange"></f></ion-col>
</ion-row>
</ion-grid>
<pre id="log" style="right:10px; bottom:50px; text-shadow: 0 0 2px rgba(0, 0, 0, 0.24);" slot="fixed">log</pre>
<ion-button>Test</ion-button>
<ion-fab top right edge id="fab1" slot="fixed">
<ion-fab-button translucent onclick="clickMainFAB('fab1')" mini class="e2eFabTopRight"><ion-icon name="add"></ion-icon></ion-fab-button>
<ion-fab-list>
<ion-fab-button translucent onclick="openSocial('facebook', 'fab1')"><ion-icon name="logo-facebook"></ion-icon></ion-fab-button>
<ion-fab-button translucent onclick="openSocial('twitter', 'fab1')"><ion-icon name="logo-twitter"></ion-icon></ion-fab-button>
<ion-fab-button translucent onclick="openSocial('vimeo', 'fab1')"><ion-icon name="logo-vimeo"></ion-icon></ion-fab-button>
<ion-fab-button translucent onclick="openSocial('googleplus', 'fab1')"><ion-icon name="logo-googleplus"></ion-icon></ion-fab-button>
</ion-fab-list>
</ion-fab>
<ion-fab bottom right edge id="fab2" slot="fixed">
<ion-fab-button translucent onclick="clickMainFAB('fab2')" color="dark" class="e2eFabBottomRight"><ion-icon name="arrow-dropleft"></ion-icon></ion-fab-button>
<ion-fab-list side="left">
<ion-fab-button translucent onclick="openSocial('facebook', 'fab2')"><ion-icon name="logo-facebook"></ion-icon></ion-fab-button>
<ion-fab-button translucent onclick="openSocial('twitter', 'fab2')"><ion-icon name="logo-twitter"></ion-icon></ion-fab-button>
<ion-fab-button translucent onclick="openSocial('vimeo', 'fab2')"><ion-icon name="logo-vimeo"></ion-icon></ion-fab-button>
<ion-fab-button translucent 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" slot="fixed">
<ion-fab-button translucent onclick="clickMainFAB('fab3')" color="secondary" class="e2eFabTopLeft"><ion-icon name="arrow-dropright"></ion-icon></ion-fab-button>
<ion-fab-list side="right">
<ion-fab-button translucent onclick="openSocial('facebook', 'fab3')"><ion-icon name="logo-facebook"></ion-icon></ion-fab-button>
<ion-fab-button translucent onclick="openSocial('twitter', 'fab3')"><ion-icon name="logo-twitter"></ion-icon></ion-fab-button>
<ion-fab-button translucent onclick="openSocial('vimeo', 'fab3')"><ion-icon name="logo-vimeo"></ion-icon></ion-fab-button>
<ion-fab-button translucent 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" slot="fixed">
<ion-fab-button translucent onclick="clickMainFAB('fab4')" color="light" class="e2eFabBottomLeft"><ion-icon name="arrow-dropup"></ion-icon></ion-fab-button>
<ion-fab-list side="top">
<ion-fab-button translucent onclick="openSocial('facebook', 'fab4')"><ion-icon name="logo-facebook"></ion-icon></ion-fab-button>
<ion-fab-button translucent onclick="openSocial('twitter', 'fab4')"><ion-icon name="logo-twitter"></ion-icon></ion-fab-button>
<ion-fab-button translucent onclick="openSocial('vimeo', 'fab4')"><ion-icon name="logo-vimeo"></ion-icon></ion-fab-button>
<ion-fab-button translucent 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" slot="fixed">
<ion-fab-button translucent onclick="clickMainFAB('fab5')" class="e2eFabCenter"><ion-icon name="md-share"></ion-icon></ion-fab-button>
<ion-fab-list side="top">
<ion-fab-button translucent 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 translucent 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 translucent 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 translucent 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 slot="fixed">
<ion-fab-button translucent color="danger" onclick="add()"><ion-icon name="add"></ion-icon></ion-fab-button>
</ion-fab>
</ion-content>
<ion-footer>
<ion-toolbar>
<ion-title>Footer</ion-title>
</ion-toolbar>
</ion-footer>
</ion-page>
<script>
function insertAfter(el, referenceNode) {
referenceNode.parentNode.insertBefore(el, referenceNode.nextSibling);
}
function insertLog(message) {
console.log(message);
var el = document.querySelector('#log');
const oldHTML = el.innerHTML;
el.innerHTML = oldHTML + '\n' + message;
}
function add() {
var newEle = document.createElement('f');
var ref = document.querySelector('f');
insertAfter(newEle, ref);
insertLog('add');
}
function clickMainFAB(container) {
let message = 'Clicked open social menu';
insertLog(message);
openLists(container);
}
function openSocial(network, container) {
let message = 'Share in ' + network;
insertLog(message);
openLists(container);
}
function openLists(container) {
var fabLists = document.getElementById(container).querySelectorAll('ion-fab-list');
for (var i = 0; i < fabLists.length; i++) {
fabLists[i].activated = true;
}
}
</script>
<style>
f {
display: block;
background: blue;
width: 100%;
height: 200px;
margin: 20px auto;
}
.red {
background-color: #ea445a;
}
.green {
background-color: #76d672;
}
.blue {
background-color: #3478f6;
}
.yellow {
background-color: #ffff80;
}
.pink {
background-color: #ff6b86;
}
.purple {
background-color: #7e34f6;
}
.black {
background-color: #000;
}
.orange {
background-color: #f69234;
}
</style>
</ion-app>
</body>
</html>

View File

@ -0,0 +1,11 @@
@import "../../themes/ionic.globals.ios";
// iOS Footer
// --------------------------------------------------
$footer-ios-translucent-filter: saturate(180%) blur(20px) !default;
.footer-translucent-ios {
-webkit-backdrop-filter: $footer-ios-translucent-filter;
backdrop-filter: $footer-ios-translucent-filter;
}

View File

@ -1,5 +1,6 @@
import { Component } from '@stencil/core';
import { Component, Prop } from '@stencil/core';
import { createThemedClasses } from '../../utils/theme';
@Component({
tag: 'ion-footer',
@ -8,6 +9,29 @@ import { Component } from '@stencil/core';
}
})
export class Footer {
mode: string;
color: string;
/**
* @input {boolean} If true, adds transparency to the footer.
* Note: In order to scroll content behind the footer, the `fullscreen`
* attribute needs to be set on the content.
* Only affects `ios` mode. Defaults to `false`.
*/
@Prop() translucent: boolean = false;
hostData() {
const themedClasses = this.translucent ? createThemedClasses(this.mode, this.color, 'header-translucent') : {};
const hostClasses = {
...themedClasses
};
return {
class: hostClasses
};
}
render() {
return <slot></slot>;
}

View File

@ -0,0 +1,11 @@
@import "../../themes/ionic.globals.ios";
// iOS Header
// --------------------------------------------------
$header-ios-translucent-filter: saturate(180%) blur(20px) !default;
.header-translucent-ios {
-webkit-backdrop-filter: $header-ios-translucent-filter;
backdrop-filter: $header-ios-translucent-filter;
}

View File

@ -1,13 +1,40 @@
import { Component } from '@stencil/core';
import { Component, Prop } from '@stencil/core';
import { createThemedClasses } from '../../utils/theme';
@Component({
tag: 'ion-header',
styleUrls: {
ios: 'header.ios.scss'
},
host: {
theme: 'header'
}
})
export class Header {
mode: string;
color: string;
/**
* @input {boolean} If true, adds transparency to the header.
* Note: In order to scroll content behind the header, the `fullscreen`
* attribute needs to be set on the content.
* Only affects `ios` mode. Defaults to `false`.
*/
@Prop() translucent: boolean = false;
hostData() {
const themedClasses = this.translucent ? createThemedClasses(this.mode, this.color, 'header-translucent') : {};
const hostClasses = {
...themedClasses
};
return {
class: hostClasses
};
}
render() {
return <slot></slot>;
}

View File

@ -53,6 +53,12 @@ $loading-ios-spinner-crescent-color: $loading-ios-spinner-color !default;
/// @prop - Color of the dots loading spinner
$loading-ios-spinner-dots-color: $loading-ios-spinner-color !default;
/// @prop - Filter of the translucent loading
$loading-ios-translucent-filter: saturate(180%) blur(20px) !default;
/// @prop - Opacity of the translucent loading
$loading-ios-translucent-opacity: .88 !default;
.loading-ios .loading-wrapper {
@include border-radius($loading-ios-border-radius);
@ -67,6 +73,17 @@ $loading-ios-spinner-dots-color: $loading-ios-spinner-color !default;
}
// iOS Translucent Loading
// -----------------------------------------
.loading-translucent-ios .loading-wrapper {
background: rgba($loading-ios-background, $loading-ios-translucent-opacity);
backdrop-filter: $loading-ios-translucent-filter;
-webkit-backdrop-filter: $loading-ios-translucent-filter;
}
// iOS Loading Content
// -----------------------------------------

View File

@ -1,6 +1,8 @@
import { Animation, AnimationBuilder, AnimationController, Config } from '../../index';
import { Component, Element, Event, EventEmitter, Listen, Prop, State } from '@stencil/core';
import { createThemedClasses } from '../../utils/theme';
import iOSEnterAnimation from './animations/ios.enter';
import iOSLeaveAnimation from './animations/ios.leave';
@ -15,9 +17,11 @@ import iOSLeaveAnimation from './animations/ios.leave';
}
})
export class Loading {
color: string;
mode: string;
private animation: Animation;
private durationTimeout: any;
private mode: string;
@Element() private el: HTMLElement;
@ -60,6 +64,7 @@ export class Loading {
@Prop() content: string;
@Prop() dismissOnPageChange: boolean = false;
@Prop() duration: number;
@Prop() translucent: boolean = false;
@Prop() enterAnimation: AnimationBuilder;
@Prop() exitAnimation: AnimationBuilder;
@Prop() loadingId: string;
@ -182,6 +187,18 @@ export class Loading {
this.dismiss();
}
hostData() {
const themedClasses = this.translucent ? createThemedClasses(this.mode, this.color, 'loading-translucent') : {};
const hostClasses = {
...themedClasses
};
return {
class: hostClasses
};
}
render() {
// TODO: cssClass
@ -227,6 +244,7 @@ export interface LoadingOptions {
showBackdrop?: boolean;
dismissOnPageChange?: boolean;
duration?: number;
translucent?: boolean;
}

View File

@ -0,0 +1,17 @@
const { register, navigate, Page } = require('../../../../../scripts/e2e');
const testPageURL = 'http://localhost:3333/src/components/loading/test/basic';
describe('loading: basic', () => {
register('navigates', navigate(testPageURL));
describe('present', () => {
register('shows loading', driver => {
const page = new Page(driver, testPageURL);
return page.present('.e2eShowLoading', { waitFor: 'ion-loading' });
});
});
});

View File

@ -0,0 +1,122 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="UTF-8">
<title>Loading - Basic</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-page>
<ion-header>
<ion-toolbar>
<ion-title>Loading - Basic</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding>
<ion-button block onclick="presentLoading()" class="e2eShowLoading">Show Loading</ion-button>
<ion-button block onclick="presentLoadingWithOptions({duration: 2000, content: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea voluptatibus quibusdam eum nihil optio, ullam accusamus magni, nobis suscipit reprehenderit, sequi quam amet impedit. Accusamus dolorem voluptates laborum dolor obcaecati.'})">Show Loading with long content</ion-button>
<ion-button block onclick="presentLoadingWithOptions({duration: 2000, message: 'Loading Please Wait...', spinner: 'hide'})">Show Loading with no spinner</ion-button>
<ion-button block onclick="presentLoadingWithOptions({duration: 5000, message: 'Loading Please Wait...', translucent: true})">Show Loading with translucent</ion-button>
<ion-loading-controller></ion-loading-controller>
<ion-grid>
<ion-row>
<ion-col col-6>
<f class="red"></f>
</ion-col>
<ion-col col-6>
<f class="green"></f>
</ion-col>
<ion-col col-6>
<f class="blue"></f>
</ion-col>
<ion-col col-6>
<f class="yellow"></f>
</ion-col>
<ion-col col-6>
<f class="pink"></f>
</ion-col>
<ion-col col-6>
<f class="purple"></f>
</ion-col>
<ion-col col-6>
<f class="black"></f>
</ion-col>
<ion-col col-6>
<f class="orange"></f>
</ion-col>
</ion-row>
</ion-grid>
</ion-content>
</ion-page>
</ion-app>
<script>
function presentLoading() {
var loadingController = document.querySelector('ion-loading-controller');
loadingController.create({
message: 'Hellooo',
duration: 2000
}).then(loading => {
loading.present();
});
}
function presentLoadingWithOptions(opts) {
var loadingController = document.querySelector('ion-loading-controller');
loadingController.create(opts).then(loading => {
loading.present();
});
}
</script>
<style>
f {
display: block;
background: blue;
width: 100%;
height: 200px;
margin: 20px auto;
}
.red {
background-color: #ea445a;
}
.green {
background-color: #76d672;
}
.blue {
background-color: #3478f6;
}
.yellow {
background-color: #ffff80;
}
.pink {
background-color: #ff6b86;
}
.purple {
background-color: #7e34f6;
}
.black {
background-color: #000;
}
.orange {
background-color: #f69234;
}
</style>
</body>
</html>

View File

@ -28,6 +28,12 @@ $popover-ios-background: $background-ios-color !default;
/// @prop - Background of the popover arrow
$popover-ios-arrow-background: $popover-ios-background !default;
/// @prop - Filter of the translucent popover
$popover-ios-translucent-filter: saturate(180%) blur(20px) !default;
/// @prop - Opacity of the translucent popover
$popover-ios-translucent-opacity: .88 !default;
.popover-ios .popover-content {
@include border-radius($popover-ios-border-radius);
@ -79,3 +85,14 @@ $popover-ios-arrow-background: $popover-ios-background !default;
.popover-ios.popover-bottom .popover-arrow::after {
top: -6px;
}
// Translucent Popover
// -----------------------------------------
.popover-translucent-ios .popover-content,
.popover-translucent-ios .popover-arrow::after {
background: rgba($popover-ios-background, $popover-ios-translucent-opacity);
-webkit-backdrop-filter: $popover-ios-translucent-filter;
backdrop-filter: $popover-ios-translucent-filter;
}

View File

@ -67,6 +67,7 @@ export class Popover {
@Prop() ev: Event;
@Prop() popoverId: string;
@Prop() showBackdrop: boolean = true;
@Prop() translucent: boolean = false;
present() {
@ -288,6 +289,18 @@ export class Popover {
}
}
hostData() {
const themedClasses = this.translucent ? createThemedClasses(this.mode, this.color, 'popover-translucent') : {};
const hostClasses = {
...themedClasses
};
return {
class: hostClasses
};
}
render() {
const ThisComponent = this.component;
@ -320,6 +333,7 @@ export interface PopoverOptions {
componentProps?: any;
showBackdrop?: boolean;
enableBackdropDismiss?: boolean;
translucent?: boolean;
enterAnimation?: AnimationBuilder;
exitAnimation?: AnimationBuilder;
cssClass?: string;

View File

@ -23,9 +23,10 @@
</ion-header>
<ion-content padding>
<ion-button class="e2eShowPopover" block onclick="presentPopover('profile-page', event)">Show Popover</ion-button>
<ion-button block onclick="presentPopover('list-page', event)">Show Long List Popover</ion-button>
<ion-button block onclick="presentPopover('profile-page')">No Event Popover</ion-button>
<ion-button class="e2eShowPopover" block onclick="presentPopover({ component: 'profile-page', ev: event })">Show Popover</ion-button>
<ion-button block onclick="presentPopover({ component: 'translucent-page', ev: event, translucent: true })">Show Translucent Popover</ion-button>
<ion-button block color="secondary" onclick="presentPopover({ component: 'list-page', ev: event })">Show Long List Popover</ion-button>
<ion-button block color="danger" onclick="presentPopover({ component: 'profile-page' })">No Event Popover</ion-button>
<ion-popover-controller></ion-popover-controller>
</ion-content>
@ -43,12 +44,9 @@
</ion-page>
</ion-app>
<script>
function presentPopover(componentName, event) {
function presentPopover(opts) {
var popoverController = document.querySelector('ion-popover-controller');
popoverController.create({
component: componentName,
ev: event
}).then(popover => {
popoverController.create(opts).then(popover => {
popover.present();
});
}
@ -98,6 +96,22 @@
}
customElements.define('list-page', ListPage);
class TranslucentPage extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
this.innerHTML = `
<div padding>
<h1>Translucent Popover</h1>
</div>
`;
}
}
customElements.define('translucent-page', TranslucentPage);
</script>
</body>

View File

@ -19,9 +19,18 @@
</ion-header>
<ion-content fullscreen>
<div class="block red"></div>
<div class="block green"></div>
<div class="block blue"></div>
<ion-grid>
<ion-row>
<ion-col col-6><f class="red"></f></ion-col>
<ion-col col-6><f class="green"></f></ion-col>
<ion-col col-6><f class="blue"></f></ion-col>
<ion-col col-6><f class="yellow"></f></ion-col>
<ion-col col-6><f class="pink"></f></ion-col>
<ion-col col-6><f class="purple"></f></ion-col>
<ion-col col-6><f class="black"></f></ion-col>
<ion-col col-6><f class="orange"></f></ion-col>
</ion-row>
</ion-grid>
<h5 padding-left padding-top> Search - Transparent Toolbar </h5>
<ion-toolbar transparent>
@ -52,7 +61,7 @@
</ion-app>
<style>
.block {
f {
width: 100%;
height: 200px;
margin: 20px auto;
@ -69,6 +78,26 @@
.blue {
background-color: #3478f6;
}
.yellow {
background-color: #ffff80;
}
.pink {
background-color: #ff6b86;
}
.purple {
background-color: #7e34f6;
}
.black {
background-color: #000;
}
.orange {
background-color: #f69234;
}
</style>
</body>
</html>

View File

@ -1,12 +1,16 @@
import { Component, Listen, Prop, State } from '@stencil/core';
import { createThemedClasses } from '../../utils/theme';
@Component({
tag: 'ion-tabbar',
host: {
theme: 'tabbar'
}
})
export class TabBar {
export class Tabbar {
mode: string;
color: string;
@State() hidden = false;
@ -15,6 +19,7 @@ export class TabBar {
@Prop() selectedTab: HTMLIonTabElement;
@Prop() layout: string = 'icon-top';
@Prop() highlight: boolean = false;
@Prop() translucent: boolean = false;
@Listen('body:keyboardWillHide')
protected onKeyboardWillHide() {
@ -28,16 +33,23 @@ export class TabBar {
}
}
hostData() {
const themedClasses = this.translucent ? createThemedClasses(this.mode, this.color, 'tabbar-translucent') : {};
const layoutClass = `layout-${this.layout}`;
const placementClass = `placement-${this.placement}`;
const hostClasses = {
...themedClasses,
'tabbar-hidden': this.hidden,
[layoutClass]: true,
[placementClass]: true
};
return {
'role': 'tablist',
'class': {
'tabbar-hidden': this.hidden,
[layoutClass]: true,
[placementClass]: true
}
role: 'tablist',
class: hostClasses
};
}

View File

@ -43,6 +43,12 @@ $tabs-ios-tab-font-size: 10px !default;
/// @prop - Size of the tab button icon
$tabs-ios-tab-icon-size: 30px !default;
/// @prop - Filter of the translucent tabbar
$tabbar-ios-translucent-filter: saturate(210%) blur(20px) !default;
/// @prop - Opacity of the translucent tabbar
$tabbar-ios-translucent-opacity: .8 !default;
.tabbar-ios {
justify-content: center;
@ -140,6 +146,16 @@ $tabs-ios-tab-icon-size: 30px !default;
// min-height: $tabs-ios-tab-min-height - 8;
// }
// iOS Translucent Tabbar
// --------------------------------------------------
.tabbar-translucent-ios {
background-color: rgba($tabs-ios-background, $tabbar-ios-translucent-opacity);
-webkit-backdrop-filter: $tabbar-ios-translucent-filter;
backdrop-filter: $tabbar-ios-translucent-filter;
}
// iOS Tabbar Color Mixin
// --------------------------------------------------
@ -160,6 +176,10 @@ $tabs-ios-tab-icon-size: 30px !default;
fill: $color-contrast;
}
.tabbar-translucent-ios-#{$color-name} {
background-color: rgba($color-base, $tabbar-ios-translucent-opacity);
}
}
// iOS Tabbar Color Generation

View File

@ -144,7 +144,6 @@ export interface NavOptions { }
}
})
export class Tabs {
private ids: number = -1;
private tabsId: number = (++tabIds);
@ -180,6 +179,14 @@ export class Tabs {
*/
@Prop({ mutable: true }) tabbarHighlight: boolean;
/**
* @input {boolean} If true, adds transparency to the tabbar.
* Note: In order to scroll content behind the tabbar, the `fullscreen`
* attribute needs to be set on the content.
* Only affects `ios` mode. Defaults to `false`.
*/
@Prop() translucent: boolean = false;
/**
* @output {any} Emitted when the tab changes.
*/
@ -342,7 +349,9 @@ export class Tabs {
const dom = [
<div class='tabs-inner'>
<slot></slot>
</div>];
</div>
];
if (!this.tabbarHidden) {
dom.push(
<ion-tabbar
@ -350,7 +359,8 @@ export class Tabs {
selectedTab={this.selectedTab}
highlight={this.tabbarHighlight}
placement={this.tabbarPlacement}
layout={this.tabbarLayout}>
layout={this.tabbarLayout}
translucent={this.translucent}>
</ion-tabbar>
);
}

View File

@ -42,17 +42,46 @@
</ion-app>
<style>
f {
display: block;
margin: 15px auto;
max-width: 150px;
height: 150px;
background: blue;
}
f {
display: block;
background: blue;
f:last-of-type {
background: yellow;
}
width: 100%;
height: 200px;
margin: 20px auto;
}
.red {
background-color: #ea445a;
}
.green {
background-color: #76d672;
}
.blue {
background-color: #3478f6;
}
.yellow {
background-color: #ffff80;
}
.pink {
background-color: #ff6b86;
}
.purple {
background-color: #7e34f6;
}
.black {
background-color: #000;
}
.orange {
background-color: #f69234;
}
</style>
</body>
</html>

View File

@ -70,11 +70,18 @@ export class PageTab {
<p><a href='#/tab3'>/tab3</a></p>
<p><a href='#/tab4'>/tab4</a></p>
<p><a href='#/tab4/paginaaaa-two'>/tab4/paginaaaa-two</a></p>
<f></f>
<f></f>
<f></f>
<f></f>
<f></f>
<ion-grid>
<ion-row>
<ion-col col-6><f class='red'></f></ion-col>
<ion-col col-6><f class='green'></f></ion-col>
<ion-col col-6><f class='blue'></f></ion-col>
<ion-col col-6><f class='yellow'></f></ion-col>
<ion-col col-6><f class='pink'></f></ion-col>
<ion-col col-6><f class='purple'></f></ion-col>
<ion-col col-6><f class='black'></f></ion-col>
<ion-col col-6><f class='orange'></f></ion-col>
</ion-row>
</ion-grid>
</ion-content>
];
}

View File

@ -0,0 +1,91 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="UTF-8">
<title>Tab - Basic</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>
<script type="text/javascript">
window.Ionic.config = {useRouter: true};
</script>
</head>
<body>
<ion-app>
<ion-tabs color="primary" translucent>
<ion-tab title="Today" icon="calendar" path="">
<translucent-page-tab class="ion-page"></translucent-page-tab>
</ion-tab>
<ion-tab title="Games" icon="planet" path="tab2">
<ion-nav root="page-two">
<ion-route path="" component="page-two"></ion-route>
<ion-route path="path/to/page/three" component="page-three"></ion-route>
</ion-nav>
</ion-tab>
<ion-tab title="Apps" icon="logo-buffer" path="tab3">
<ion-nav root="page-three">
<ion-route path="/" component="page-three"></ion-route>
</ion-nav>
</ion-tab>
<ion-tab title="Updates" icon="download" path="tab4" badge="7" badge-style="danger">
<ion-nav root="translucent-page-tab">
<ion-route component="page-one"></ion-route>
<ion-route path="paginaaaa-two" component="page-two"></ion-route>
</ion-nav>
</ion-tab>
<ion-tab title="Search" icon="search" path="tab5">
<translucent-page-tab class="ion-page"></translucent-page-tab>
</ion-tab>
</ion-tabs>
<ion-nav-controller></ion-nav-controller>
</ion-app>
<style>
f {
display: block;
background: blue;
width: 100%;
height: 200px;
margin: 20px auto;
}
.red {
background-color: #ea445a;
}
.green {
background-color: #76d672;
}
.blue {
background-color: #3478f6;
}
.yellow {
background-color: #ffff80;
}
.pink {
background-color: #ff6b86;
}
.purple {
background-color: #7e34f6;
}
.black {
background-color: #000;
}
.orange {
background-color: #f69234;
}
</style>
</body>
</html>

View File

@ -0,0 +1,58 @@
import { Component, Element } from '@stencil/core';
export interface Route {
path: string | null;
component: string;
}
@Component({
tag: 'translucent-page-tab'
})
export class TranslucentPageTab {
@Element() element: HTMLElement;
getTabs() {
return this.element.closest('ion-tabs') as HTMLIonTabsElement;
}
setLayout(value: string) {
this.getTabs().tabbarLayout = value;
}
setPlacement(value: string) {
this.getTabs().tabbarPlacement = value;
}
setHidden(value: boolean) {
this.getTabs().tabbarHidden = value;
}
setHighlight(value: boolean) {
this.getTabs().tabbarHighlight = value;
}
render() {
return [
<ion-header>
<ion-toolbar>
<ion-title>Tab Translucent</ion-title>
</ion-toolbar>
</ion-header>,
<ion-content fullscreen={true}>
<ion-grid>
<ion-row>
<ion-col col-6><f class='red'></f></ion-col>
<ion-col col-6><f class='green'></f></ion-col>
<ion-col col-6><f class='blue'></f></ion-col>
<ion-col col-6><f class='yellow'></f></ion-col>
<ion-col col-6><f class='pink'></f></ion-col>
<ion-col col-6><f class='purple'></f></ion-col>
<ion-col col-6><f class='black'></f></ion-col>
<ion-col col-6><f class='orange'></f></ion-col>
</ion-row>
</ion-grid>
</ion-content>
];
}
}

View File

@ -22,9 +22,39 @@
<ion-button block onclick="presentToast('top')">Show Toast Top</ion-button>
<ion-button block onclick="presentToast('middle')">Show Toast Middle</ion-button>
<ion-button block onclick="presentToastWithOptions({message: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea voluptatibus quibusdam eum nihil optio, ullam accusamus magni, nobis suscipit reprehenderit, sequi quam amet impedit. Accusamus dolorem voluptates laborum dolor obcaecati.', duration: 2000})">Show Toast with long message</ion-button>
<ion-button block onclick="presentToastWithOptions({message: 'click to close', showCloseButton: true})">Show Toast with close button</ion-button>
<ion-button block onclick="presentToastWithOptions({message: 'click to close', showCloseButton: true, closeButtonText: 'closing time'})">Show Toast with close button and custom text</ion-button>
<ion-button block onclick="presentToastWithOptions({message: 'click to close', showCloseButton: true})">Show Toast with Close Button</ion-button>
<ion-button block onclick="presentToastWithOptions({message: 'click to close', showCloseButton: true, closeButtonText: 'closing time'})">Show Toast with Custom Close Button Text</ion-button>
<ion-button block onclick="presentToastWithOptions({message: 'click to close', showCloseButton: true, translucent: true})">Show Translucent Toast</ion-button>
<ion-toast-controller></ion-toast-controller>
<ion-grid>
<ion-row>
<ion-col col-6>
<f class="red"></f>
</ion-col>
<ion-col col-6>
<f class="green"></f>
</ion-col>
<ion-col col-6>
<f class="blue"></f>
</ion-col>
<ion-col col-6>
<f class="yellow"></f>
</ion-col>
<ion-col col-6>
<f class="pink"></f>
</ion-col>
<ion-col col-6>
<f class="purple"></f>
</ion-col>
<ion-col col-6>
<f class="black"></f>
</ion-col>
<ion-col col-6>
<f class="orange"></f>
</ion-col>
</ion-row>
</ion-grid>
</ion-content>
</ion-page>
</ion-app>
@ -32,23 +62,65 @@
function presentToast(position) {
var toastController = document.querySelector('ion-toast-controller');
toastController.create({
message: 'Hellooo',
position,
duration: 2000
})
.then(toast => {
toast.present();
});
message: 'Hellooo',
position,
duration: 2000
}).then(toast => {
toast.present();
});
}
function presentToastWithOptions(opts) {
var toastController = document.querySelector('ion-toast-controller');
toastController.create(opts)
.then(toast => {
toast.present();
});
toastController.create(opts).then(toast => {
toast.present();
});
}
</script>
<style>
f {
display: block;
background: blue;
width: 100%;
height: 200px;
margin: 20px auto;
}
.red {
background-color: #ea445a;
}
.green {
background-color: #76d672;
}
.blue {
background-color: #3478f6;
}
.yellow {
background-color: #ffff80;
}
.pink {
background-color: #ff6b86;
}
.purple {
background-color: #7e34f6;
}
.black {
background-color: #000;
}
.orange {
background-color: #f69234;
}
</style>
</body>
</html>

View File

@ -31,6 +31,12 @@ $toast-ios-title-padding-start: $toast-ios-title-padding-end !
/// @prop - Color of the toast button
$toast-ios-button-color: rgba(71, 71, 71, 1) !default;
/// @prop - Filter of the translucent toast
$toast-ios-translucent-filter: saturate(180%) blur(20px) !default;
/// @prop - Opacity of the translucent toast
$toast-ios-translucent-opacity: .88 !default;
.toast-ios .toast-wrapper {
@include position-horizontal(10px, 10px);
@ -47,6 +53,13 @@ $toast-ios-button-color: rgba(71, 71, 71, 1) !default;
background: $toast-ios-background;
}
.toast-translucent-ios .toast-wrapper {
background: rgba($toast-ios-background, $toast-ios-translucent-opacity);
backdrop-filter: $toast-ios-translucent-filter;
-webkit-backdrop-filter: $toast-ios-translucent-filter;
}
.toast-ios .toast-wrapper.toast-top {
@include transform(translate3d(0, -100%, 0));

View File

@ -1,6 +1,8 @@
import { Component, Element, Event, EventEmitter, Listen, Prop } from '@stencil/core';
import { Animation, AnimationBuilder, AnimationController, Config, CssClassMap } from '../../index';
import { createThemedClasses } from '../../utils/theme';
import iOSEnterAnimation from './animations/ios.enter';
import iOSLeaveAnimation from './animations/ios.leave';
@ -15,6 +17,9 @@ import iOSLeaveAnimation from './animations/ios.leave';
}
})
export class Toast {
mode: string;
color: string;
private animation: Animation;
@Element() private el: HTMLElement;
@ -59,6 +64,7 @@ export class Toast {
@Prop() closeButtonText: string;
@Prop() dismissOnPageChange: boolean;
@Prop() position: string;
@Prop() translucent: boolean = false;
@Prop() enterAnimation: AnimationBuilder;
@Prop() exitAnimation: AnimationBuilder;
@Prop() toastId: string;
@ -156,6 +162,28 @@ export class Toast {
this.dismiss();
}
wrapperClass(): CssClassMap {
let wrapperClass: string[] = !this.position
? ['toast-wrapper', 'toast-bottom']
: [`toast-wrapper`, `toast-${this.position}`];
return wrapperClass.reduce((prevValue: any, cssClass: any) => {
prevValue[cssClass] = true;
return prevValue;
}, {});
}
hostData() {
const themedClasses = this.translucent ? createThemedClasses(this.mode, this.color, 'toast-translucent') : {};
const hostClasses = {
...themedClasses
};
return {
class: hostClasses
};
}
render() {
let userCssClass = 'toast-content';
if (this.cssClass) {
@ -178,16 +206,6 @@ export class Toast {
);
}
wrapperClass(): CssClassMap {
let wrapperClass: string[] = !this.position
? ['toast-wrapper', 'toast-bottom']
: [`toast-wrapper`, `toast-${this.position}`];
return wrapperClass.reduce((prevValue: any, cssClass: any) => {
prevValue[cssClass] = true;
return prevValue;
}, {});
}
}
export interface ToastOptions {
@ -198,6 +216,7 @@ export interface ToastOptions {
closeButtonText?: string;
dismissOnPageChange?: boolean;
position?: string;
translucent?: boolean;
enterAnimation?: AnimationBuilder;
exitAnimation?: AnimationBuilder;
}

View File

@ -15,7 +15,13 @@
</ion-toolbar>
</ion-header>
<ion-content></ion-content>
<ion-content padding>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec vitae lobortis felis, eu sodales enim. Nam risus nibh, placerat at rutrum ac, vehicula vel velit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum quis elementum ligula, ac aliquet nulla. Mauris non placerat mauris. Aenean dignissim lacinia porttitor. Praesent fringilla at est et ullamcorper. In ac ante ac massa porta venenatis ut id nibh. Fusce felis neque, aliquet in velit vitae, venenatis euismod libero. Donec vulputate, urna sed sagittis tempor, mi arcu tristique lacus, eget fringilla urna sem eget felis. Fusce dignissim lacus a scelerisque vehicula. Nulla nec enim nunc.
Quisque nec dui eu nibh pulvinar bibendum quis ut nunc. Duis ex odio, sollicitudin ac mollis nec, fringilla non lacus. Maecenas sed tincidunt urna. Nunc feugiat maximus venenatis. Donec porttitor, felis eget porttitor tempor, quam nulla dapibus nisl, sit amet posuere sapien sapien malesuada tortor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Quisque luctus, sapien nec tincidunt efficitur, nibh turpis faucibus felis, in sodales massa augue nec erat. Morbi sollicitudin nisi ex, et gravida nisi euismod eu. Suspendisse hendrerit dapibus orci, non viverra neque vestibulum id. Quisque vitae interdum ligula, quis consectetur nibh.
Phasellus in mi at erat ultrices semper. Fusce sollicitudin at dolor ac lobortis. Morbi sit amet sem quis nulla pellentesque imperdiet. Nullam eu sem a enim maximus eleifend non vulputate leo. Proin quis congue lacus. Pellentesque placerat, quam at tempus pulvinar, nisl ligula tempor risus, quis pretium arcu odio et nulla. Nullam mollis consequat pharetra. Phasellus dictum velit sed purus mattis maximus. In molestie eget massa ut dignissim. In a interdum elit. In finibus nibh a mauris lobortis aliquet. Proin rutrum varius consequat. In mollis dapibus nisl, eu finibus urna viverra ac. Quisque scelerisque nisl eu suscipit consectetur.
</ion-content>
<ion-footer>
<ion-toolbar>

View File

@ -0,0 +1,130 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="UTF-8">
<title>Toolbar - Translucent</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-page>
<ion-header translucent>
<ion-toolbar>
<ion-title>Toolbar - Translucent</ion-title>
</ion-toolbar>
<ion-toolbar color="primary">
<ion-title>Toolbar - Primary Translucent</ion-title>
</ion-toolbar>
<ion-toolbar color="secondary">
<ion-title>Toolbar - Secondary Translucent</ion-title>
</ion-toolbar>
<ion-toolbar color="light">
<ion-title>Toolbar - Light Translucent</ion-title>
</ion-toolbar>
<ion-toolbar color="danger">
<ion-title>Toolbar - Danger Translucent</ion-title>
</ion-toolbar>
<ion-toolbar color="dark">
<ion-title>Toolbar - Dark Translucent</ion-title>
</ion-toolbar>
</ion-header>
<ion-toolbar translucent color="danger">
<ion-title>Toolbar - Danger Translucent</ion-title>
</ion-toolbar>
<ion-toolbar translucent color="dark">
<ion-title>Toolbar - Dark Translucent</ion-title>
</ion-toolbar>
<ion-content fullscreen>
<ion-grid>
<ion-row>
<ion-col col-6><f class="red"></f></ion-col>
<ion-col col-6><f class="green"></f></ion-col>
<ion-col col-6><f class="blue"></f></ion-col>
<ion-col col-6><f class="yellow"></f></ion-col>
<ion-col col-6><f class="pink"></f></ion-col>
<ion-col col-6><f class="purple"></f></ion-col>
<ion-col col-6><f class="black"></f></ion-col>
<ion-col col-6><f class="orange"></f></ion-col>
</ion-row>
</ion-grid>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec vitae lobortis felis, eu sodales enim. Nam risus nibh, placerat at rutrum ac, vehicula vel velit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum quis elementum ligula, ac aliquet nulla. Mauris non placerat mauris. Aenean dignissim lacinia porttitor. Praesent fringilla at est et ullamcorper. In ac ante ac massa porta venenatis ut id nibh. Fusce felis neque, aliquet in velit vitae, venenatis euismod libero. Donec vulputate, urna sed sagittis tempor, mi arcu tristique lacus, eget fringilla urna sem eget felis. Fusce dignissim lacus a scelerisque vehicula. Nulla nec enim nunc.
Quisque nec dui eu nibh pulvinar bibendum quis ut nunc. Duis ex odio, sollicitudin ac mollis nec, fringilla non lacus. Maecenas sed tincidunt urna. Nunc feugiat maximus venenatis. Donec porttitor, felis eget porttitor tempor, quam nulla dapibus nisl, sit amet posuere sapien sapien malesuada tortor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Quisque luctus, sapien nec tincidunt efficitur, nibh turpis faucibus felis, in sodales massa augue nec erat. Morbi sollicitudin nisi ex, et gravida nisi euismod eu. Suspendisse hendrerit dapibus orci, non viverra neque vestibulum id. Quisque vitae interdum ligula, quis consectetur nibh.
Phasellus in mi at erat ultrices semper. Fusce sollicitudin at dolor ac lobortis. Morbi sit amet sem quis nulla pellentesque imperdiet. Nullam eu sem a enim maximus eleifend non vulputate leo. Proin quis congue lacus. Pellentesque placerat, quam at tempus pulvinar, nisl ligula tempor risus, quis pretium arcu odio et nulla. Nullam mollis consequat pharetra. Phasellus dictum velit sed purus mattis maximus. In molestie eget massa ut dignissim. In a interdum elit. In finibus nibh a mauris lobortis aliquet. Proin rutrum varius consequat. In mollis dapibus nisl, eu finibus urna viverra ac. Quisque scelerisque nisl eu suscipit consectetur.
</p>
<ion-grid>
<ion-row>
<ion-col col-6><f class="red"></f></ion-col>
<ion-col col-6><f class="green"></f></ion-col>
<ion-col col-6><f class="blue"></f></ion-col>
<ion-col col-6><f class="yellow"></f></ion-col>
<ion-col col-6><f class="pink"></f></ion-col>
<ion-col col-6><f class="purple"></f></ion-col>
<ion-col col-6><f class="black"></f></ion-col>
<ion-col col-6><f class="orange"></f></ion-col>
</ion-row>
</ion-grid>
</ion-content>
<ion-footer translucent>
<ion-toolbar color="danger">
<ion-title>Footer Toolbar - Danger</ion-title>
</ion-toolbar>
<ion-toolbar color="primary">
<ion-title>Footer Toolbar - Primary</ion-title>
</ion-toolbar>
<ion-toolbar>
<ion-title>Footer Toolbar - Translucent</ion-title>
</ion-toolbar>
</ion-footer>
</ion-page>
</ion-app>
<style>
f {
height: 200px;
}
.red {
background-color: #ea445a;
}
.green {
background-color: #76d672;
}
.blue {
background-color: #3478f6;
}
.yellow {
background-color: #ffff80;
}
.pink {
background-color: #ff6b86;
}
.purple {
background-color: #7e34f6;
}
.black {
background-color: #000;
}
.orange {
background-color: #f69234;
}
</style>
</body>
</html>

View File

@ -33,6 +33,12 @@ $toolbar-ios-button-strong-font-weight: 600 !default;
/// @prop - Height of the navigation bar
$navbar-ios-height: $toolbar-ios-height !default;
/// @prop - Filter of the translucent toolbar
$toolbar-ios-translucent-filter: saturate(180%) blur(20px) !default;
/// @prop - Opacity of the translucent toolbar
$toolbar-ios-translucent-opacity: .88 !default;
.toolbar-ios {
@include padding($toolbar-ios-padding);
@ -76,6 +82,21 @@ $navbar-ios-height: $toolbar-ios-height !default;
}
// iOS Translucent Toolbar
// --------------------------------------------------
.header-translucent-ios .toolbar-background-ios,
.footer-translucent-ios .toolbar-background-ios,
.toolbar-translucent-ios .toolbar-background-ios {
background: rgba($toolbar-ios-background, $toolbar-ios-translucent-opacity);
}
.toolbar-translucent-ios .toolbar-background-ios {
-webkit-backdrop-filter: $toolbar-ios-translucent-filter;
backdrop-filter: $toolbar-ios-translucent-filter;
}
// iOS Toolbar Content
// --------------------------------------------------
@ -104,6 +125,17 @@ $navbar-ios-height: $toolbar-ios-height !default;
@include ios-bar-button-solid($color-name, $color-base, $color-contrast);
}
}
// Colored toolbars with translucency
.header-translucent-ios .toolbar-ios-#{$color-name},
.footer-translucent-ios .toolbar-ios-#{$color-name},
.toolbar-translucent-ios-#{$color-name} {
.toolbar-background-ios {
background: rgba($color-base, $toolbar-ios-translucent-opacity);
}
}
}

View File

@ -32,6 +32,14 @@ export class Toolbar {
*/
@Prop() mode: 'ios' | 'md';
/**
* @input {boolean} If true, adds transparency to the header.
* Note: In order to scroll content behind the header, the `fullscreen`
* attribute needs to be set on the content.
* Only affects `ios` mode. Defaults to `false`.
*/
@Prop() translucent: boolean = false;
componentDidLoad() {
const buttons = this.el.querySelectorAll('ion-button') as any;
for (var i = 0; i < buttons.length; i++) {
@ -40,10 +48,15 @@ export class Toolbar {
}
hostData() {
const themedClasses = this.translucent ? createThemedClasses(this.mode, this.color, 'toolbar-translucent') : {};
const hostClasses = {
...themedClasses,
'statusbar-padding': this.config.getBoolean('statusbarPadding')
};
return {
class: {
'statusbar-padding': this.config.getBoolean('statusbarPadding')
}
class: hostClasses
};
}

View File

@ -23,7 +23,7 @@ $content-ios-margin: $content-margin !default;
$toolbar-ios-height: 44px !default;
$toolbar-ios-padding: 4px !default;
$toolbar-ios-background: $toolbar-background !default;
$toolbar-ios-border-color: rgba(0, 0, 0, .3) !default;
$toolbar-ios-border-color: rgba(0, 0, 0, .2) !default;
$toolbar-ios-text-color: $toolbar-text-color !default;
$toolbar-ios-active-color: $toolbar-active-color !default;
$toolbar-ios-inactive-color: $toolbar-inactive-color !default;
@ -33,7 +33,7 @@ $toolbar-ios-inactive-color: $toolbar-inactive-color !default;
// --------------------------------------------------
$tabs-ios-background: $tabs-background !default;
$tabs-ios-border-color: rgba(0, 0, 0, .3) !default;
$tabs-ios-border-color: rgba(0, 0, 0, .2) !default;
$tabs-ios-tab-color-inactive: $tabs-tab-color-inactive !default;
$tabs-ios-tab-color-active: $tabs-tab-color-active !default;