diff --git a/ionic/components/app/mixins/util.scss b/ionic/components/app/mixins/util.scss index aff8701216..cdd3ecae80 100644 --- a/ionic/components/app/mixins/util.scss +++ b/ionic/components/app/mixins/util.scss @@ -1,6 +1,14 @@ // Util Mixins/Functions +// Appearance (not a CSS standard, does not autoprefix) +// -------------------------------------------------- + +@mixin appearance($val) { + -webkit-appearance: $val; + -moz-appearance: $val; +} + // String Replace Function // -------------------------------------------------- diff --git a/ionic/components/app/util.scss b/ionic/components/app/util.scss index dceacc0671..999889577c 100644 --- a/ionic/components/app/util.scss +++ b/ionic/components/app/util.scss @@ -95,6 +95,6 @@ $content-padding: 10px !default; // http://davidwalsh.name/detect-node-insertion @keyframes nodeInserted { - from { opacity: 0.99; } - to { opacity: 1; } + from { transform: scale(0.999); } + to { transform: scale(1); } } diff --git a/ionic/components/button/button.scss b/ionic/components/button/button.scss index cb8bc7592b..3d69de2a61 100644 --- a/ionic/components/button/button.scss +++ b/ionic/components/button/button.scss @@ -36,7 +36,7 @@ $button-small-icon-size: 2.1rem !default; margin: $button-margin; line-height: 1; - appearance: none; + @include appearance(none); vertical-align: top; // the better option for most scenarios vertical-align: -webkit-baseline-middle; // the best for those that support it diff --git a/ionic/components/form/form.scss b/ionic/components/form/form.scss index e7a11c5486..0f228b9cde 100644 --- a/ionic/components/form/form.scss +++ b/ionic/components/form/form.scss @@ -48,7 +48,7 @@ textarea { input { border-radius: 0; flex: 1 220px; - appearance: none; + @include appearance(none); margin: 0; padding-right: 24px; background-color: transparent; @@ -66,7 +66,7 @@ textarea { .button-bar { border-radius: 0; flex: 1 0 220px; - appearance: none; + @include appearance(none); } .icon { diff --git a/ionic/components/form/input/input.scss b/ionic/components/form/input/input.scss index 949cf88867..86ca69285e 100644 --- a/ionic/components/form/input/input.scss +++ b/ionic/components/form/input/input.scss @@ -21,7 +21,7 @@ ion-input { border-radius: 0; flex: 1 220px; - appearance: none; + @include appearance(none); margin: 0; padding-right: 24px; diff --git a/ionic/components/search-bar/search-bar.scss b/ionic/components/search-bar/search-bar.scss index a7fd54f96a..8de79daff5 100644 --- a/ionic/components/search-bar/search-bar.scss +++ b/ionic/components/search-bar/search-bar.scss @@ -26,7 +26,7 @@ $search-bar-min-height: 44px !default; height: 100%; border: none; font-family: inherit; - appearance: none; + @include appearance(none); } .search-bar-cancel { diff --git a/ionic/components/toolbar/toolbar.js b/ionic/components/toolbar/toolbar.js index 9c4f089c62..0102da822d 100644 --- a/ionic/components/toolbar/toolbar.js +++ b/ionic/components/toolbar/toolbar.js @@ -36,10 +36,10 @@ export class Toolbar { this.config = Toolbar.config.invoke(this); // http://davidwalsh.name/detect-node-insertion - this.domElement.addEventListener("animationstart", (ev) => { - ev.stopPropagation(); + dom.animationStart(this.domElement, 'nodeInserted').then(() => { this.alignTitle(); }); + } alignTitle() { diff --git a/ionic/components/toolbar/toolbar.scss b/ionic/components/toolbar/toolbar.scss index a4361af4f6..ae32a38738 100644 --- a/ionic/components/toolbar/toolbar.scss +++ b/ionic/components/toolbar/toolbar.scss @@ -51,7 +51,7 @@ ion-title { display: block; // used to notify JS when the title has been rendered - animation-duration: 0.001s; + animation-duration: 1ms; animation-name: nodeInserted; } diff --git a/ionic/util/dom.js b/ionic/util/dom.js index 9ad765b2af..083f52f611 100644 --- a/ionic/util/dom.js +++ b/ionic/util/dom.js @@ -30,34 +30,63 @@ export function rafPromise() { export const isSVG = val => window.SVGElement && (val instanceof window.SVGElement); -// We only need to test for webkit in our supported browsers. Webkit is the only browser still -// using prefixes. -// Code adapted from angular-animate.js -export let css = {}; +// We only need to test for webkit in our supported browsers. Webkit is the +// only browser still using prefixes. Code adapted from angular-animate.js +export let CSS = {}; if (window.ontransitionend === undefined && window.onwebkittransitionend !== undefined) { - css.prefix = 'webkit'; - css.transition = 'webkitTransition'; - css.transform = 'webkitTransform'; - css.transitionEnd = 'webkitTransitionEnd transitionend'; + CSS.prefix = '-webkit-'; + CSS.transition = 'webkitTransition'; + CSS.transform = 'webkitTransform'; + CSS.transitionEnd = 'webkitTransitionEnd transitionend'; } else { - css.prefix = ''; - css.transform = 'transform'; - css.transition = 'transition'; - css.transitionEnd = 'transitionend'; + CSS.prefix = ''; + CSS.transform = 'transform'; + CSS.transition = 'transition'; + CSS.transitionEnd = 'transitionend'; } -export function transitionEndPromise(el:Element) { +if (window.onanimationend === undefined && window.onwebkitanimationend !== undefined) { + CSS.animation = 'WebkitAnimation'; + CSS.animationStart = 'webkitAnimationStart animationstart'; + CSS.animationEnd = 'webkitAnimationEnd animationend'; +} else { + CSS.animation = 'animation'; + CSS.animationStart = 'animationstart'; + CSS.animationEnd = 'animationend'; +} + +export function transitionEnd(el:Element) { + return cssPromise(el, CSS.transitionEnd); +} + +export function animationStart(el:Element, animationName) { + return cssPromise(el, CSS.animationStart, animationName); +} + +export function animationEnd(el:Element, animationName) { + return cssPromise(el, CSS.animationEnd, animationName); +} + +function cssPromise(el:Element, eventNames, animationName) { return new Promise(resolve => { - css.transitionEnd.split(' ').forEach(eventName => { - el.addEventListener(eventName, onTransitionEnd); + eventNames.split(' ').forEach(eventName => { + el.addEventListener(eventName, onEvent); }) - function onTransitionEnd(ev) { - // Don't allow bubbled transitionend events - if (ev.target !== el) { + function onEvent(ev) { + if (ev.animationName && animationName) { + // do not resolve if a bubbled up ev.animationName + // is not the same as the passed in animationName arg + if (ev.animationName !== animationName) { + return; + } + } else if (ev.target !== el) { + // do not resolve if the event's target element is not + // the same as the element the listener was added to return; } - css.transitionEnd.split(' ').forEach(eventName => { - el.removeEventListener(css.transitionEnd, onTransitionEnd) + ev.stopPropagation(); + eventNames.split(' ').forEach(eventName => { + el.removeEventListener(eventName, onEvent); }) resolve(ev); }