diff --git a/core/src/components/action-sheet/action-sheet.tsx b/core/src/components/action-sheet/action-sheet.tsx index b691cab313..99d55b4021 100644 --- a/core/src/components/action-sheet/action-sheet.tsx +++ b/core/src/components/action-sheet/action-sheet.tsx @@ -53,7 +53,7 @@ export class ActionSheet implements OverlayInterface { * Additional classes to apply for custom CSS. If multiple classes are * provided they should be separated by spaces. */ - @Prop() cssClass: string; + @Prop() cssClass: string | string[]; /** * If true, the action sheet will be dismissed when the backdrop is clicked. Defaults to `true`. diff --git a/core/src/components/alert/alert.tsx b/core/src/components/alert/alert.tsx index 18577ad31d..64a2663eda 100644 --- a/core/src/components/alert/alert.tsx +++ b/core/src/components/alert/alert.tsx @@ -51,7 +51,7 @@ export class Alert implements OverlayInterface { * Additional classes to apply for custom CSS. If multiple classes are * provided they should be separated by spaces. */ - @Prop() cssClass: string; + @Prop() cssClass: string | string[]; /** * The main title in the heading of the alert. @@ -455,7 +455,7 @@ export interface AlertOptions { title?: string; subTitle?: string; message?: string; - cssClass?: string; + cssClass?: string | string[]; mode?: string; inputs?: AlertInput[]; buttons?: (AlertButton|string)[]; @@ -480,6 +480,6 @@ export interface AlertInput { export interface AlertButton { text: string; role?: string; - cssClass?: string; + cssClass?: string | string[]; handler?: (value: any) => boolean|void; } diff --git a/core/src/components/loading/loading.tsx b/core/src/components/loading/loading.tsx index bd45bdad01..85553f1993 100644 --- a/core/src/components/loading/loading.tsx +++ b/core/src/components/loading/loading.tsx @@ -54,7 +54,7 @@ export class Loading implements OverlayInterface { * Additional classes to apply for custom CSS. If multiple classes are * provided they should be separated by spaces. */ - @Prop() cssClass: string; + @Prop() cssClass: string | string[]; /** * If true, the loading indicator will dismiss when the page changes. Defaults to `false`. @@ -222,7 +222,7 @@ export class Loading implements OverlayInterface { export interface LoadingOptions { spinner?: string; content?: string; - cssClass?: string; + cssClass?: string | string[]; showBackdrop?: boolean; dismissOnPageChange?: boolean; duration?: number; diff --git a/core/src/components/modal/modal.tsx b/core/src/components/modal/modal.tsx index 46d0f88e49..e21047185d 100644 --- a/core/src/components/modal/modal.tsx +++ b/core/src/components/modal/modal.tsx @@ -1,5 +1,5 @@ import { Component, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core'; -import { Animation, AnimationBuilder, Config, FrameworkDelegate } from '../../index'; +import { Animation, AnimationBuilder, ComponentProps, ComponentRef, Config, FrameworkDelegate } from '../../index'; import { createThemedClasses, getClassList } from '../../utils/theme'; import { BACKDROP, OverlayEventDetail, OverlayInterface, dismiss, eventMethod, present } from '../../utils/overlays'; @@ -64,18 +64,18 @@ export class Modal implements OverlayInterface { /** * The component to display inside of the modal. */ - @Prop() component: any; + @Prop() component: ComponentRef; /** * The data to pass to the modal component. */ - @Prop() data: any = {}; + @Prop() componentProps: ComponentProps; /** * Additional classes to apply for custom CSS. If multiple classes are * provided they should be separated by spaces. */ - @Prop() cssClass: string; + @Prop() cssClass: string | string[]; /** * If true, the modal will be dismissed when the backdrop is clicked. Defaults to `true`. @@ -169,15 +169,15 @@ export class Modal implements OverlayInterface { return Promise.resolve(); } const container = this.el.querySelector(`.modal-wrapper`); - const data = { - ...this.data, + const componentProps = { + ...this.componentProps, modal: this.el }; const classes = [ ...getClassList(this.cssClass), 'ion-page' ]; - this.usersElement = await attachComponent(this.delegate, container, this.component, classes, data); + this.usersElement = await attachComponent(this.delegate, container, this.component, classes, componentProps); return present(this, 'modalEnter', iosEnterAnimation, mdEnterAnimation); } @@ -243,12 +243,12 @@ const LIFECYCLE_MAP: any = { }; export interface ModalOptions { - component: any; - data?: any; + component: ComponentRef; + componentProps?: ComponentProps; showBackdrop?: boolean; enableBackdropDismiss?: boolean; enterAnimation?: AnimationBuilder; leaveAnimation?: AnimationBuilder; - cssClass?: string; + cssClass?: string | string[]; delegate?: FrameworkDelegate; } diff --git a/core/src/components/nav-push/nav-push.tsx b/core/src/components/nav-push/nav-push.tsx index 1d5cfbbb1a..5e652cce1f 100644 --- a/core/src/components/nav-push/nav-push.tsx +++ b/core/src/components/nav-push/nav-push.tsx @@ -1,5 +1,6 @@ import { Component, Element, Listen, Prop } from '@stencil/core'; -// import { NavResult } from '../../index'; +import { ComponentProps } from '../..'; +import { NavComponent } from '../nav/nav-util'; @Component({ tag: 'ion-nav-push', @@ -7,16 +8,16 @@ import { Component, Element, Listen, Prop } from '@stencil/core'; export class NavPush { @Element() el: HTMLElement; - @Prop() component: any; + @Prop() component: NavComponent; + @Prop() componentProps: ComponentProps; @Prop() url: string; - @Prop() data: any; @Listen('child:click') push(): Promise { const nav = this.el.closest('ion-nav'); const toPush = this.url || this.component; if (nav && toPush) { - return nav.push(toPush, this.data); + return nav.push(toPush, this.componentProps); } return Promise.resolve(null); } diff --git a/core/src/components/nav-set-root/nav-set-root.tsx b/core/src/components/nav-set-root/nav-set-root.tsx index 8354f25ad2..897177ebfc 100644 --- a/core/src/components/nav-set-root/nav-set-root.tsx +++ b/core/src/components/nav-set-root/nav-set-root.tsx @@ -1,4 +1,6 @@ import { Component, Element, Listen, Prop } from '@stencil/core'; +import { ComponentProps } from '../..'; +import { NavComponent } from '../nav/nav-util'; @Component({ tag: 'ion-nav-set-root', @@ -6,16 +8,16 @@ import { Component, Element, Listen, Prop } from '@stencil/core'; export class NavSetRoot { @Element() el: HTMLElement; - @Prop() component: any; + @Prop() component: NavComponent; + @Prop() componentProps: ComponentProps; @Prop() url: string; - @Prop() data: any; @Listen('child:click') push(): Promise { const nav = this.el.closest('ion-nav'); if (nav) { const toPush = this.url || this.component; - return nav.setRoot(toPush, this.data); + return nav.setRoot(toPush, this.componentProps); } return Promise.resolve(null); } diff --git a/core/src/components/nav/nav-util.ts b/core/src/components/nav/nav-util.ts index d37946927c..b087fe6b38 100644 --- a/core/src/components/nav/nav-util.ts +++ b/core/src/components/nav/nav-util.ts @@ -1,5 +1,5 @@ import { ViewController, isViewController } from './view-controller'; -import { Animation, FrameworkDelegate } from '../..'; +import { Animation, ComponentRef, FrameworkDelegate } from '../..'; export function convertToView(page: any, params: any): ViewController|null { if (!page) { @@ -38,7 +38,7 @@ export const enum NavDirection { Forward = 'forward' } -export type NavParams = {[key: string]: any}; +export type NavComponent = ComponentRef | ViewController | Function; export interface NavResult { hasCompleted: boolean; diff --git a/core/src/components/nav/nav.tsx b/core/src/components/nav/nav.tsx index 7022d77ea9..c0d70966ef 100644 --- a/core/src/components/nav/nav.tsx +++ b/core/src/components/nav/nav.tsx @@ -1,8 +1,8 @@ import { Build, Component, Element, Event, EventEmitter, Method, Prop, Watch } from '@stencil/core'; import { + NavComponent, NavDirection, NavOptions, - NavParams, NavResult, TransitionDoneFn, TransitionInstruction, @@ -12,7 +12,7 @@ import { } from './nav-util'; import { ViewController, isViewController } from './view-controller'; -import { Animation, Config, DomController, FrameworkDelegate, GestureDetail, NavOutlet } from '../..'; +import { Animation, ComponentProps, Config, DomController, FrameworkDelegate, GestureDetail, NavOutlet } from '../..'; import { RouteID, RouteWrite, RouterDirection } from '../router/utils/interfaces'; import { AnimationOptions, ViewLifecycle, lifecycle, transition } from '../../utils/transition'; import { assert } from '../../utils/helpers'; @@ -25,22 +25,16 @@ import mdTransitionAnimation from './animations/md.transition'; }) export class NavControllerBase implements NavOutlet { - private _ids = -1; private _init = false; private _queue: TransitionInstruction[] = []; private _sbTrns: Animation; private useRouter = false; isTransitioning = false; private _destroyed = false; + private _views: ViewController[] = []; - _views: ViewController[] = []; - - id: string; - name: string; mode: string; - parent: any; - @Element() el: HTMLElement; @Prop({context: 'dom'}) dom: DomController; @@ -50,8 +44,8 @@ export class NavControllerBase implements NavOutlet { @Prop({ mutable: true }) swipeBackEnabled: boolean; @Prop({ mutable: true }) animated: boolean; @Prop() delegate: FrameworkDelegate; - @Prop() rootParams: any; - @Prop() root: any; + @Prop() rootParams: ComponentProps; + @Prop() root: NavComponent; @Watch('root') rootChanged() { if (this.root) { @@ -66,7 +60,6 @@ export class NavControllerBase implements NavOutlet { @Event() ionNavChanged: EventEmitter; componentWillLoad() { - this.id = 'n' + (++ctrlIds); this.useRouter = !!document.querySelector('ion-router') && !this.el.closest('[no-router]'); if (this.swipeBackEnabled === undefined) { this.swipeBackEnabled = this.config.getBoolean('swipeBackEnabled', this.mode === 'ios'); @@ -81,32 +74,44 @@ export class NavControllerBase implements NavOutlet { } componentDidUnload() { - this.destroy(); + const views = this._views; + let view: ViewController; + for (let i = 0; i < views.length; i++) { + view = views[i]; + lifecycle(view.element, ViewLifecycle.WillUnload); + view._destroy(); + } + + // release swipe back gesture and transition + this._sbTrns && this._sbTrns.destroy(); + this._queue = this._views = this._sbTrns = null; + + this._destroyed = true; } @Method() - push(page: any, params?: NavParams, opts?: NavOptions, done?: TransitionDoneFn): Promise { + push(component: NavComponent, componentProps?: ComponentProps, opts?: NavOptions, done?: TransitionDoneFn): Promise { return this._queueTrns({ insertStart: -1, - insertViews: [{ page: page, params: params }], + insertViews: [{ page: component, params: componentProps }], opts: opts, }, done); } @Method() - insert(insertIndex: number, page: any, params?: NavParams, opts?: NavOptions, done?: TransitionDoneFn): Promise { + insert(insertIndex: number, component: NavComponent, componentProps?: ComponentProps, opts?: NavOptions, done?: TransitionDoneFn): Promise { return this._queueTrns({ insertStart: insertIndex, - insertViews: [{ page: page, params: params }], + insertViews: [{ page: component, params: componentProps }], opts: opts, }, done); } @Method() - insertPages(insertIndex: number, insertPages: any[], opts?: NavOptions, done?: TransitionDoneFn): Promise { + insertPages(insertIndex: number, insertComponents: NavComponent[], opts?: NavOptions, done?: TransitionDoneFn): Promise { return this._queueTrns({ insertStart: insertIndex, - insertViews: insertPages, + insertViews: insertComponents, opts: opts, }, done); } @@ -121,7 +126,7 @@ export class NavControllerBase implements NavOutlet { } @Method() - popTo(indexOrViewCtrl: any, opts?: NavOptions, done?: TransitionDoneFn): Promise { + popTo(indexOrViewCtrl: number | ViewController, opts?: NavOptions, done?: TransitionDoneFn): Promise { const config: TransitionInstruction = { removeStart: -1, removeCount: -1, @@ -174,12 +179,12 @@ export class NavControllerBase implements NavOutlet { } @Method() - setRoot(pageOrViewCtrl: any, params?: any, opts?: NavOptions, done?: TransitionDoneFn): Promise { - return this.setPages([{ page: pageOrViewCtrl, params: params }], opts, done); + setRoot(component: NavComponent, componentProps?: ComponentProps, opts?: NavOptions, done?: TransitionDoneFn): Promise { + return this.setPages([{ page: component, params: componentProps }], opts, done); } @Method() - setPages(pages: any[], opts?: NavOptions, done?: TransitionDoneFn): Promise { + setPages(views: any[], opts?: NavOptions, done?: TransitionDoneFn): Promise { if (!opts) { opts = {}; } @@ -189,7 +194,7 @@ export class NavControllerBase implements NavOutlet { } return this._queueTrns({ insertStart: 0, - insertViews: pages, + insertViews: views, removeStart: 0, removeCount: -1, opts: opts @@ -252,12 +257,12 @@ export class NavControllerBase implements NavOutlet { } @Method() - getActive(): ViewController { + getActive(): ViewController|undefined { return this._views[this._views.length - 1]; } @Method() - getByIndex(index: number): ViewController { + getByIndex(index: number): ViewController|undefined { return this._views[index]; } @@ -269,18 +274,10 @@ export class NavControllerBase implements NavOutlet { } @Method() - getViews(): Array { + getViews(): ViewController[] { return this._views.slice(); } - /** - * Return a view controller - */ - @Method() - getViewById(id: string): ViewController|undefined { - return this._views.find(vc => vc.id === id); - } - indexOf(viewController: ViewController) { return this._views.indexOf(viewController); } @@ -674,12 +671,6 @@ export class NavControllerBase implements NavOutlet { // create the new entering view view._setNav(this); - // give this inserted view an ID - this._ids++; - if (!view.id) { - view.id = `${this.id}-${this._ids}`; - } - // insert the entering view into the correct index in the stack this._views.splice(index, 0, view); } @@ -729,28 +720,6 @@ export class NavControllerBase implements NavOutlet { } } - destroy() { - const views = this._views; - let view: ViewController; - for (let i = 0; i < views.length; i++) { - view = views[i]; - lifecycle(view.element, ViewLifecycle.WillUnload); - view._destroy(); - } - - // release swipe back gesture and transition - this._sbTrns && this._sbTrns.destroy(); - this._queue = this._views = this._sbTrns = null; - - // Unregister navcontroller - if (this.parent && this.parent.unregisterChildNav) { - // TODO: event - this.parent.unregisterChildNav(this); - } - - this._destroyed = true; - } - private swipeBackStart() { if (this.isTransitioning || this._queue.length > 0) { return; @@ -837,5 +806,3 @@ export class NavControllerBase implements NavOutlet { return dom; } } - -let ctrlIds = -1; diff --git a/core/src/components/nav/test/nav-controller.spec.ts b/core/src/components/nav/test/nav-controller.spec.ts index 93f8ab0b1a..035c57deb4 100644 --- a/core/src/components/nav/test/nav-controller.spec.ts +++ b/core/src/components/nav/test/nav-controller.spec.ts @@ -207,8 +207,8 @@ describe('NavController', () => { hasCompleted, requiresTransition, undefined, undefined, undefined ); expect(nav.length()).toEqual(4); - expect(nav._views[0].component).toEqual(MockView4); - expect(nav._views[nav._views.length - 1].component).toEqual(MockView3); + expect(nav.getByIndex(0).component).toEqual(MockView4); + expect(nav.getByIndex(nav.length() - 1).component).toEqual(MockView3); }, 10000); @@ -226,7 +226,7 @@ describe('NavController', () => { hasCompleted, requiresTransition, view2, view1, NavDirection.Forward ); expect(nav.length()).toEqual(2); - expect(nav._views[nav._views.length - 1].component).toEqual(MockView2); + expect(nav.getByIndex(nav.length() - 1).component).toEqual(MockView2); }, 10000); @@ -242,7 +242,7 @@ describe('NavController', () => { hasCompleted, requiresTransition, view2, view1, NavDirection.Forward ); expect(nav.length()).toEqual(2); - expect(nav._views[nav._views.length - 1].component).toEqual(MockView2); + expect(nav.getByIndex(nav.length() - 1).component).toEqual(MockView2); }, 10000); @@ -260,7 +260,7 @@ describe('NavController', () => { expect(err).toEqual(rejectReason); expect(trnsDone).toHaveBeenCalledWith(hasCompleted, requiresTransition, rejectReason); expect(nav.length()).toEqual(1); - expect(nav._views[nav._views.length - 1].component).toEqual(MockView1); + expect(nav.getByIndex(nav.length() - 1).component).toEqual(MockView1); done(); }); }, 10000); @@ -980,7 +980,7 @@ describe('NavController', () => { }); - describe('destroy', () => { + describe('componentDidUnload', () => { it('should not crash when destroyed while transitioning', (done) => { const view1 = mockView(MockView1); @@ -991,7 +991,7 @@ describe('NavController', () => { fail('should never get here'); done(); }); - nav.destroy(); + nav.componentDidUnload(); }, 10000); }); @@ -1092,7 +1092,7 @@ function mockView(component ?: any, data ?: any) { } function mockViews(nav: NavControllerBase, views: ViewController[]) { - nav._views = views; + nav['_views'] = views; views.forEach(v => { v._setNav(nav); }); diff --git a/core/src/components/picker/picker.tsx b/core/src/components/picker/picker.tsx index 88acabb0dd..332276a12a 100644 --- a/core/src/components/picker/picker.tsx +++ b/core/src/components/picker/picker.tsx @@ -59,7 +59,7 @@ export class Picker implements OverlayInterface { * Additional classes to apply for custom CSS. If multiple classes are * provided they should be separated by spaces. */ - @Prop() cssClass: string; + @Prop() cssClass: string | string[]; /** * Number of milliseconds to wait before dismissing the picker. @@ -341,14 +341,14 @@ function buttonClass(button: PickerButton): CssClassMap { export interface PickerButton { text?: string; role?: string; - cssClass?: string; + cssClass?: string | string[]; handler?: (value: any) => boolean|void; } export interface PickerOptions { buttons?: PickerButton[]; columns?: PickerColumn[]; - cssClass?: string; + cssClass?: string | string[]; enableBackdropDismiss?: boolean; } @@ -360,7 +360,7 @@ export interface PickerColumn { prefix?: string; suffix?: string; options: PickerColumnOption[]; - cssClass?: string; + cssClass?: string | string[]; columnWidth?: string; prefixWidth?: string; suffixWidth?: string; diff --git a/core/src/components/popover/popover.tsx b/core/src/components/popover/popover.tsx index 858d1dda98..c18680a199 100644 --- a/core/src/components/popover/popover.tsx +++ b/core/src/components/popover/popover.tsx @@ -1,5 +1,5 @@ import { Component, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core'; -import { Animation, AnimationBuilder, Config, FrameworkDelegate } from '../../index'; +import { Animation, AnimationBuilder, ComponentProps, ComponentRef, Config, FrameworkDelegate } from '../../index'; import { createThemedClasses, getClassList } from '../../utils/theme'; import { BACKDROP, OverlayEventDetail, OverlayInterface, dismiss, eventMethod, present } from '../../utils/overlays'; @@ -63,18 +63,18 @@ export class Popover implements OverlayInterface { /** * The component to display inside of the popover. */ - @Prop() component: string; + @Prop() component: ComponentRef; /** * The data to pass to the popover component. */ - @Prop() data: any = {}; + @Prop() componentProps: ComponentProps; /** * Additional classes to apply for custom CSS. If multiple classes are * provided they should be separated by spaces. */ - @Prop() cssClass: string; + @Prop() cssClass: string | string[]; /** * If true, the popover will be dismissed when the backdrop is clicked. Defaults to `true`. @@ -180,7 +180,7 @@ export class Popover implements OverlayInterface { } const container = this.el.querySelector('.popover-content'); const data = { - ...this.data, + ...this.componentProps, popover: this.el }; const classes = [ @@ -254,14 +254,14 @@ export class Popover implements OverlayInterface { } export interface PopoverOptions { - component: any; - data?: any; + component: ComponentRef; + componentProps?: ComponentProps; showBackdrop?: boolean; enableBackdropDismiss?: boolean; translucent?: boolean; enterAnimation?: AnimationBuilder; leaveAnimation?: AnimationBuilder; - cssClass?: string; + cssClass?: string | string[]; ev: Event; delegate?: FrameworkDelegate; } diff --git a/core/src/components/select/select.tsx b/core/src/components/select/select.tsx index 8391cf5efe..48a0abeac6 100644 --- a/core/src/components/select/select.tsx +++ b/core/src/components/select/select.tsx @@ -310,7 +310,7 @@ export class Select { const popoverOpts: PopoverOptions = Object.assign(interfaceOptions, { component: 'ion-select-popover', - data: { + componentProps: { title: interfaceOptions.title, subTitle: interfaceOptions.subTitle, message: interfaceOptions.message, diff --git a/core/src/components/toast/toast.tsx b/core/src/components/toast/toast.tsx index 796effe3a6..b970e2e755 100644 --- a/core/src/components/toast/toast.tsx +++ b/core/src/components/toast/toast.tsx @@ -56,7 +56,7 @@ export class Toast implements OverlayInterface { * Additional classes to apply for custom CSS. If multiple classes are * provided they should be separated by spaces. */ - @Prop() cssClass: string; + @Prop() cssClass: string | string[]; /** * If true, the toast will dismiss when the page changes. Defaults to `false`. @@ -226,7 +226,7 @@ export class Toast implements OverlayInterface { export interface ToastOptions { message?: string; - cssClass?: string; + cssClass?: string | string[]; duration?: number; showCloseButton?: boolean; closeButtonText?: string; diff --git a/core/src/index.d.ts b/core/src/index.d.ts index cb2156d350..7ef725b1f9 100644 --- a/core/src/index.d.ts +++ b/core/src/index.d.ts @@ -59,7 +59,7 @@ export * from './components/modal/modal'; export { ModalController } from './components/modal-controller/modal-controller'; export * from './components/nav/nav'; export { ViewController } from './components/nav/view-controller'; -export { NavParams, NavOptions, TransitionDoneFn} from './components/nav/nav-util'; +export { NavOptions, TransitionDoneFn} from './components/nav/nav-util'; export { Note } from './components/note/note'; export { PickerColumnCmp } from './components/picker-column/picker-column'; export * from './components/picker/picker'; @@ -110,6 +110,9 @@ export { DomController, RafCallback } from './global/dom-controller'; export { FrameworkDelegate } from './utils/framework-delegate'; export { OverlayEventDetail } from './utils/overlays'; +export type ComponentRef = HTMLElement | string; +export type ComponentProps = {[key: string]: any}; + export interface Config { get: (key: string, fallback?: any) => any; getBoolean: (key: string, fallback?: boolean) => boolean; diff --git a/core/src/utils/framework-delegate.ts b/core/src/utils/framework-delegate.ts index 214c50bde5..71150d198e 100644 --- a/core/src/utils/framework-delegate.ts +++ b/core/src/utils/framework-delegate.ts @@ -1,17 +1,18 @@ +import { ComponentRef } from '..'; export interface FrameworkDelegate { attachViewToDom(container: any, component: any, propsOrDataObj?: any, cssClasses?: string[]): Promise; removeViewFromDom(container: any, component: any): Promise; } -export function attachComponent(delegate: FrameworkDelegate, container: Element, component: string|HTMLElement, cssClasses?: string[], params?: {[key: string]: any}): Promise { +export function attachComponent(delegate: FrameworkDelegate, container: Element, component: ComponentRef, cssClasses?: string[], componentProps?: {[key: string]: any}): Promise { if (delegate) { - return delegate.attachViewToDom(container, component, params, cssClasses); + return delegate.attachViewToDom(container, component, componentProps, cssClasses); } const el = (typeof component === 'string') ? document.createElement(component) : component; cssClasses && cssClasses.forEach(c => el.classList.add(c)); - params && Object.assign(el, params); + componentProps && Object.assign(el, componentProps); container.appendChild(el); if ((el as any).componentOnReady) { diff --git a/core/src/utils/lazy.ts b/core/src/utils/lazy.ts new file mode 100644 index 0000000000..5807a73341 --- /dev/null +++ b/core/src/utils/lazy.ts @@ -0,0 +1,19 @@ + +export function waitUntilVisible(el: HTMLElement, callback?: Function) { + return new Promise((resolve) => { + if ('IntersectionObserver' in window) { + const io = new IntersectionObserver(data => { + if (data[0].isIntersecting) { + resolve(); + io.disconnect(); + } + }); + io.observe(el); + } else { + // fall back to setTimeout for Safari and IE + setTimeout(() => resolve(), 300); + } + }).then(() => { + callback && callback(); + }); +} diff --git a/core/src/utils/theme.ts b/core/src/utils/theme.ts index 713eebb0dc..8f0d006a5d 100644 --- a/core/src/utils/theme.ts +++ b/core/src/utils/theme.ts @@ -50,8 +50,11 @@ export function getButtonClassMap(buttonType: string, mode: string): CssClassMap }; } -export function getClassList(classes: string | undefined): string[] { +export function getClassList(classes: string | string[] | undefined): string[] { if (classes) { + if (Array.isArray(classes)) { + return classes; + } return classes .split(' ') .filter(c => c.trim() !== ''); @@ -59,7 +62,7 @@ export function getClassList(classes: string | undefined): string[] { return []; } -export function getClassMap(classes: string | undefined): CssClassMap { +export function getClassMap(classes: string | string[] | undefined): CssClassMap { const map: CssClassMap = {}; getClassList(classes).forEach(c => map[c] = true); return map;