Compare commits

..

8 Commits

Author SHA1 Message Date
Liam DeBeasi
926b119231 remove old lines 2019-11-18 15:03:42 -05:00
Liam DeBeasi
256c7de469 only fire pressUp if press was fired; allow overriding of other gesture params 2019-11-18 15:02:38 -05:00
Liam DeBeasi
b7b5b94cce add angular integration 2019-11-12 11:39:21 -05:00
Liam DeBeasi
5e1e883585 sync with master 2019-11-12 11:33:42 -05:00
Liam DeBeasi
ad747b05f1 add press up handler 2019-11-07 15:20:49 -05:00
Liam DeBeasi
3b52074a10 fix typo 2019-11-07 15:17:26 -05:00
Liam DeBeasi
9eac7266a0 Fix 2019-11-07 15:04:18 -05:00
Liam DeBeasi
12a4c974b4 add press recognizer 2019-11-07 15:03:05 -05:00
170 changed files with 1380 additions and 4500 deletions

View File

@@ -1,90 +1,3 @@
# [5.0.0-beta.2](https://github.com/ionic-team/ionic/compare/v5.0.0-beta.1...v5.0.0-beta.2) (2019-12-11)
### Bug Fixes
* **animation:** convert hyphenated properties to camel case when using Web Animations ([#20059](https://github.com/ionic-team/ionic/issues/20059)) ([56f67bd](https://github.com/ionic-team/ionic/commit/56f67bd9a5c8c81768e310560b2605e44bf7a9f0)), closes [#20058](https://github.com/ionic-team/ionic/issues/20058)
* **animation:** properly update Web Animation object ([#19964](https://github.com/ionic-team/ionic/issues/19964)) ([e766194](https://github.com/ionic-team/ionic/commit/e76619478c3c49469fcc22e264cc831d498abf8d))
* **picker:** pass selected value to handler on dismiss ([#20042](https://github.com/ionic-team/ionic/issues/20042)) ([6e0b9c4](https://github.com/ionic-team/ionic/commit/6e0b9c45489889266620ee2ca38c33fdf8ce3f3b)), closes [#20036](https://github.com/ionic-team/ionic/issues/20036)
* **tabs:** preserve route navigation extras when changing tabs ([#18493](https://github.com/ionic-team/ionic/issues/18493)) ([4c8f32f](https://github.com/ionic-team/ionic/commit/4c8f32fae99db4022aa9dc75187e2f161e8e678e)), closes [#18717](https://github.com/ionic-team/ionic/issues/18717)
* **title:** add correct safe area to large title nav transition ([#20029](https://github.com/ionic-team/ionic/issues/20029)) ([300d543](https://github.com/ionic-team/ionic/commit/300d54356df925bb94f22b6805e48c88d1e56a26)), closes [#20028](https://github.com/ionic-team/ionic/issues/20028)
### Features
* **modal:** add card-style presentation with swipe to close gesture ([#19428](https://github.com/ionic-team/ionic/issues/19428)) ([b3b3312](https://github.com/ionic-team/ionic/commit/b3b33127115bb966980a1288a0005dfb09306881)), closes [#18660](https://github.com/ionic-team/ionic/issues/18660)
## [4.11.6](https://github.com/ionic-team/ionic/compare/v4.11.5...v4.11.6) (2019-12-11)
### Bug Fixes
* **react:** don't show back button when not appropriate ([684293d](https://github.com/ionic-team/ionic/commit/684293ddbf1ad4edce590d56f7ff66fcd6c817a5))
* **react:** first render performance improvements ([1c7d1e5](https://github.com/ionic-team/ionic/commit/1c7d1e5cf1ad7e53ebbee2566e8fa89f567f7fb5))
* **react:** fix refs for controllers, overlays, ionpage, and ionrouteroutlet, fixes [#19924](https://github.com/ionic-team/ionic/issues/19924) ([#20012](https://github.com/ionic-team/ionic/issues/20012)) ([eef55bb](https://github.com/ionic-team/ionic/commit/eef55bb0072a9e54b1fd7d1c8c69e7fd43b2a5c5))
* **react:** support for 'root' router direction, fixes [#19982](https://github.com/ionic-team/ionic/issues/19982) ([#20052](https://github.com/ionic-team/ionic/issues/20052)) ([e116712](https://github.com/ionic-team/ionic/commit/e1167122758b23221935e897bcd65839b75c59aa))
* **react:** support navigating to same page and route updates in IonRouterOutlet, fixes [#19891](https://github.com/ionic-team/ionic/issues/19891), [#19892](https://github.com/ionic-team/ionic/issues/19892), [#19986](https://github.com/ionic-team/ionic/issues/19986) ([f9bf8db](https://github.com/ionic-team/ionic/commit/f9bf8dbe6f952ee53b6b213a4c0d043d25f49b93))
### Upgrade Note
If you run into a "Property 'translate' is missing in type" error building after updating to 4.11.6, update your React Typings library to the latest:
npm i @types/react@latest @types/react-dom@latest
# [5.0.0-beta.1](https://github.com/ionic-team/ionic/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2019-11-20)
### Bug Fixes
* **animation:** track correctly when updating CSS Animation ([#19813](https://github.com/ionic-team/ionic/issues/19813)) ([7bd4412](https://github.com/ionic-team/ionic/commit/7bd44128895b9fa4992142c0cc30cf75092cb794))
* **card:** update background to use the same as item ([#19602](https://github.com/ionic-team/ionic/issues/19602)) ([1a8b7a4](https://github.com/ionic-team/ionic/commit/1a8b7a4559860b3efa4778a78c905e30f18587bf))
* **content:** set fixed content to position absolute ([#19867](https://github.com/ionic-team/ionic/issues/19867)) ([fce3e24](https://github.com/ionic-team/ionic/commit/fce3e24600be6f04b285cda62fe2f21c49d809e2)), closes [#17754](https://github.com/ionic-team/ionic/issues/17754)
* **gesture:** release gesture when disabling ([#19855](https://github.com/ionic-team/ionic/issues/19855)) ([21484f1](https://github.com/ionic-team/ionic/commit/21484f1f3a9ebe46096c979fe3f2035892a53a62)), closes [#19848](https://github.com/ionic-team/ionic/issues/19848)
* **header:** avoid flicker on collapsible header load ([#19682](https://github.com/ionic-team/ionic/issues/19682)) ([0a7aae2](https://github.com/ionic-team/ionic/commit/0a7aae28a7eb0270cdcd100933c01850403b66db))
* **header:** avoid flicker when collapsing ([#19850](https://github.com/ionic-team/ionic/issues/19850)) ([a3666dd](https://github.com/ionic-team/ionic/commit/a3666ddf0ccc44c696121a8d6107015dbe7aeabb)), closes [#19839](https://github.com/ionic-team/ionic/issues/19839)
* **header:** support collapsible header with multiple toolbars ([#19909](https://github.com/ionic-team/ionic/issues/19909)) ([fc4bb2d](https://github.com/ionic-team/ionic/commit/fc4bb2db5c5715841347135bdfa1bf66718d647d))
* **header:** translucent toolbars now work with collapsible header ([#19774](https://github.com/ionic-team/ionic/issues/19774)) ([b642b53](https://github.com/ionic-team/ionic/commit/b642b532e8846042f1317dc936191d0934b23945)), closes [#19773](https://github.com/ionic-team/ionic/issues/19773)
* **title:** only animate large title if back button is in start slot ([#19846](https://github.com/ionic-team/ionic/issues/19846)) ([cace1b3](https://github.com/ionic-team/ionic/commit/cace1b357e5acd54d49f2b662ecee5de90add708)), closes [#19840](https://github.com/ionic-team/ionic/issues/19840)
* **nav-params:** set generic type on navigation parameters get() ([#19195](https://github.com/ionic-team/ionic/issues/19195)) ([504051d](https://github.com/ionic-team/ionic/commit/504051d709c8afe08d588747866d2ee924baf804))
* **picker:** pass data and role to dismiss ([#19787](https://github.com/ionic-team/ionic/issues/19787)) ([7988720](https://github.com/ionic-team/ionic/commit/7988720b1cf46a651d9c140f0fe95726d3feb48c)), closes [#18454](https://github.com/ionic-team/ionic/issues/18454)
* **searchbar:** use back button config value for cancel icon ([#19353](https://github.com/ionic-team/ionic/issues/19353)) ([3d6f3b9](https://github.com/ionic-team/ionic/commit/ed6f3b9f3f42ef85f3f2d083fa7fe37a69b491c8))
* **textarea:** remove padding from textarea placeholder ([#19694](https://github.com/ionic-team/ionic/issues/19694)) ([f63d37a](https://github.com/ionic-team/ionic/commit/f63d37a4c506801a19b9bf6e5ef05d415d680b0c)), closes [#19616](https://github.com/ionic-team/ionic/issues/19616)
* **toast:** call button handler on cancel ([#19793](https://github.com/ionic-team/ionic/issues/19793)) ([420aa66](https://github.com/ionic-team/ionic/commit/420aa6639214e7d2e7b7413e699ace3d7fd35e40)), closes [#19791](https://github.com/ionic-team/ionic/issues/19791)
### Features
* **animation:** animation identifiers ([#19771](https://github.com/ionic-team/ionic/issues/19771)) ([7d41715](https://github.com/ionic-team/ionic/commit/7d417154c5f1ba89e0a30084807ff7e164dd6eba)), closes [#19550](https://github.com/ionic-team/ionic/issues/19550)
* **animation:** cubic-bezier easing conversion utility (experimental) ([#19788](https://github.com/ionic-team/ionic/issues/19788)) ([96a5e60](https://github.com/ionic-team/ionic/commit/96a5e600e563489d93a26d5956d210f246f6fea5)), closes [#19789](https://github.com/ionic-team/ionic/issues/19789)
* **alert:** add support for textarea inputs ([#16851](https://github.com/ionic-team/ionic/issues/16851)) ([b28cf02](https://github.com/ionic-team/ionic/commit/b28cf02ef3979c844c498a8e30ee977937984828)), closes [#14153](https://github.com/ionic-team/ionic/issues/14153)
* **angular:** expose Ionic Animations via AnimationController ([#19745](https://github.com/ionic-team/ionic/issues/19745)) ([67a7e23](https://github.com/ionic-team/ionic/commit/67a7e232b9058620653feec5ed99e0ebf22b6620))
* **angular:** expose Ionic Gestures via GestureController ([#19864](https://github.com/ionic-team/ionic/issues/19864)) ([48a7662](https://github.com/ionic-team/ionic/commit/48a766246d08170c709345bba235275eef0bd020))
* **searchbar:** add --box-shadow variable to style searchbar input ([#19838](https://github.com/ionic-team/ionic/issues/19838)) ([1ab7066](https://github.com/ionic-team/ionic/commit/1ab7066aa085bc0185a6dd3d162439f7f82415fa))
* **select:** add --placeholder-opacity and --placeholder-color, expose shadow parts ([#19893](https://github.com/ionic-team/ionic/issues/19893)) ([bef0f53](https://github.com/ionic-team/ionic/commit/bef0f53d0dcb15c58221c2dec8c4c274d3b5c77e)), closes [#17446](https://github.com/ionic-team/ionic/issues/17446)
* **split-pane:** convert to shadow component, add width, max-width, and min-width vars ([#19754](https://github.com/ionic-team/ionic/issues/19754)) ([d80f455](https://github.com/ionic-team/ionic/commit/d80f45516d5dca62b77db1773206ef274d42f3ef)), closes [#17088](https://github.com/ionic-team/ionic/issues/17088)
### Breaking Changes
> We recommend updating to the latest version of 4.x before trying out version 5 in order to see deprecation warnings related to your app in the console.
* **back-button:** convert back button to shadow ([#19411](https://github.com/ionic-team/ionic/pull/19411)) ([0d40d3f](https://github.com/ionic-team/ionic/commit/0d40d3f3b72aac7932ac71e6573d8bbb65a01515))
* **ionicons:** update to Ionicons v5. See https://ionicons.com for more information. ([#19670](https://github.com/ionic-team/ionic/pull/19670)) ([69e10de](https://github.com/ionic-team/ionic/commit/69e10de718dcba4d43e82bd37aeacd2585dd9a79))
* **list-header:** redesign list header to match latest iOS spec ([#19915](https://github.com/ionic-team/ionic/issues/19915)) ([5bbb95f](https://github.com/ionic-team/ionic/commit/5bbb95fae1e371021d6a0edc17fbb021a598b285))
* **split-pane:** convert split-pane to shadow ([#19754](https://github.com/ionic-team/ionic/issues/19754)) ([d80f455](https://github.com/ionic-team/ionic/commit/d80f45516d5dca62b77db1773206ef274d42f3ef))
## [4.11.5](https://github.com/ionic-team/ionic/compare/v4.11.0...v4.11.5) (2019-11-14)
### Bug Fixes
* **react:** improved lifecycle hooks to deal with stale closures, fixes [#19873](https://github.com/ionic-team/ionic/issues/19873) ([#19874](https://github.com/ionic-team/ionic/issues/19874)) ([5ff786a](https://github.com/ionic-team/ionic/commit/5ff786a23d5aa32281bbf5daaa7f8156de39caca))
## [4.11.4](https://github.com/ionic-team/ionic/compare/v4.11.1...v4.11.4) (2019-11-07)

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/angular",
"version": "5.0.0-beta.2",
"version": "5.0.0-beta.0",
"description": "Angular specific wrappers for @ionic/core",
"keywords": [
"ionic",
@@ -49,7 +49,7 @@
"css/"
],
"dependencies": {
"@ionic/core": "5.0.0-beta.2",
"@ionic/core": "5.0.0-beta.0",
"tslib": "^1.9.3"
},
"peerDependencies": {

View File

@@ -16,8 +16,6 @@ import { RouteView, getUrl } from './stack-utils';
inputs: ['animated', 'swipeGesture']
})
export class IonRouterOutlet implements OnDestroy, OnInit {
nativeEl: HTMLIonRouterOutletElement;
private activated: ComponentRef<any> | null = null;
private activatedView: RouteView | null = null;
@@ -25,6 +23,7 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
private _swipeGesture?: boolean;
private name: string;
private stackCtrl: StackController;
private nativeEl: HTMLIonRouterOutletElement;
// Maintain map of activated route proxies for each component instance
private proxyMap = new WeakMap<any, ActivatedRoute>();
@@ -242,22 +241,6 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
return active ? active.url : undefined;
}
/**
* Returns the RouteView of the active page of each stack.
* @internal
*/
getLastRouteView(stackId?: string): RouteView | undefined {
return this.stackCtrl.getLastUrl(stackId);
}
/**
* Returns the root view in the tab stack.
* @internal
*/
getRootView(stackId?: string): RouteView | undefined {
return this.stackCtrl.getRootUrl(stackId);
}
/**
* Returns the active stack ID. In the context of ion-tabs, it means the active tab.
*/
@@ -331,7 +314,7 @@ class OutletInjector implements Injector {
private route: ActivatedRoute,
private childContexts: ChildrenOutletContexts,
private parent: Injector
) { }
) {}
get(token: any, notFoundValue?: any): any {
if (token === ActivatedRoute) {

View File

@@ -66,53 +66,18 @@ export class IonTabs {
}
}
/**
* When a tab button is clicked, there are several scenarios:
* 1. If the selected tab is currently active (the tab button has been clicked
* again), then it should go to the root view for that tab.
*
* a. Get the saved root view from the router outlet. If the saved root view
* matches the tabRootUrl, set the route view to this view including the
* navigation extras.
* b. If the saved root view from the router outlet does
* not match, navigate to the tabRootUrl. No navigation extras are
* included.
*
* 2. If the current tab tab is not currently selected, get the last route
* view from the router outlet.
*
* a. If the last route view exists, navigate to that view including any
* navigation extras
* b. If the last route view doesn't exist, then navigate
* to the default tabRootUrl
*/
@HostListener('ionTabButtonClick', ['$event.detail.tab'])
select(tab: string) {
const alreadySelected = this.outlet.getActiveStackId() === tab;
const tabRootUrl = `${this.outlet.tabsPrefix}/${tab}`;
if (alreadySelected) {
const rootView = this.outlet.getRootView(tab);
const navigationExtras = rootView && tabRootUrl === rootView.url && rootView.savedExtras;
return this.navCtrl.navigateRoot(tabRootUrl, {
...(navigationExtras),
animated: true,
animationDirection: 'back',
});
} else {
const lastRoute = this.outlet.getLastRouteView(tab);
/**
* If there is a lastRoute, goto that, otherwise goto the fallback url of the
* selected tab
*/
const url = lastRoute && lastRoute.url || tabRootUrl;
const navigationExtras = lastRoute && lastRoute.savedExtras;
const href = `${this.outlet.tabsPrefix}/${tab}`;
const url = alreadySelected
? href
: this.outlet.getLastUrl(tab) || href;
return this.navCtrl.navigateRoot(url, {
...(navigationExtras),
animated: true,
animationDirection: 'back',
});
}
return this.navCtrl.navigateRoot(url, {
animated: true,
animationDirection: 'back'
});
}
getSelected(): string | undefined {

View File

@@ -70,7 +70,7 @@ export class StackController {
if (router.getCurrentNavigation) {
currentNavigation = router.getCurrentNavigation();
// Angular < 7.2.0
// Angular < 7.2.0
} else if (
router.navigations &&
router.navigations.value
@@ -191,14 +191,6 @@ export class StackController {
return views.length > 0 ? views[views.length - 1] : undefined;
}
/**
* @internal
*/
getRootUrl(stackId?: string) {
const views = this.getStack(stackId);
return views.length > 0 ? views[0] : undefined;
}
getActiveStackId(): string | undefined {
return this.activeView ? this.activeView.stackId : undefined;
}

View File

@@ -442,7 +442,7 @@ proxyMethods(IonList, ['closeSlidingItems']);
proxyInputs(IonList, ['inset', 'lines', 'mode']);
export declare interface IonListHeader extends Components.IonListHeader {}
@Component({ selector: 'ion-list-header', changeDetection: ChangeDetectionStrategy.OnPush, template: '<ng-content></ng-content>', inputs: ['color', 'lines', 'mode'] })
@Component({ selector: 'ion-list-header', changeDetection: ChangeDetectionStrategy.OnPush, template: '<ng-content></ng-content>', inputs: ['color', 'mode'] })
export class IonListHeader {
protected el: HTMLElement;
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
@@ -450,7 +450,7 @@ export class IonListHeader {
this.el = r.nativeElement;
}
}
proxyInputs(IonListHeader, ['color', 'lines', 'mode']);
proxyInputs(IonListHeader, ['color', 'mode']);
export declare interface IonMenu extends Components.IonMenu {}
@Component({ selector: 'ion-menu', changeDetection: ChangeDetectionStrategy.OnPush, template: '<ng-content></ng-content>', inputs: ['contentId', 'disabled', 'maxEdgeStart', 'menuId', 'side', 'swipeGesture', 'type'] })

View File

@@ -33,7 +33,7 @@ export class Config {
}
set(key: keyof IonicConfig, value?: any) {
console.warn(`[DEPRECATION][Config]: The Config.set() method is deprecated and will be removed in Ionic Framework 6.0. Please see https://ionicframework.com/docs/angular/config for alternatives.`);
console.warn(`[DEPRECATION][Config]: The Config.set() method is deprecated and will be removed in the next major release.`);
const c = getConfig();
if (c) {
c.set(key, value);

View File

@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { Gesture, GestureConfig, createGesture } from '@ionic/core';
import { Gesture, GestureConfig, PressRecognizerOptions, createGesture, createPressRecognizer } from '@ionic/core';
@Injectable({
providedIn: 'root',
@@ -11,4 +11,11 @@ export class GestureController {
create(opts: GestureConfig): Gesture {
return createGesture(opts);
}
/**
* Create a new Press recognizer gesture
*/
pressRecognizer(opts: PressRecognizerOptions): Gesture {
return createPressRecognizer(opts);
}
}

View File

@@ -1,5 +1,5 @@
import { browser, by, element, ElementFinder, ExpectedConditions } from 'protractor';
import { handleErrorMessages, testStack, waitTime } from './utils';
import { browser, element, by, ElementFinder } from 'protractor';
import { waitTime, testStack, handleErrorMessages } from './utils';
describe('tabs', () => {
afterEach(() => {
@@ -131,94 +131,6 @@ describe('tabs', () => {
await testTabTitle('Tab 3 - Page 1');
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab3']);
});
it('should preserve navigation extras when switching tabs', async () => {
const expectUrlToContain = 'search=hello#fragment';
let tab = await getSelectedTab() as ElementFinder;
await tab.$('#goto-nested-page1-with-query-params').click();
await testTabTitle('Tab 1 - Page 2 (1)');
await testUrlContains(expectUrlToContain);
await element(by.css('#tab-button-contact')).click();
await testTabTitle('Tab 2 - Page 1');
await element(by.css('#tab-button-account')).click();
tab = await testTabTitle('Tab 1 - Page 2 (1)');
await testUrlContains(expectUrlToContain);
});
it('should set root when clicking on an active tab to navigate to the root', async () => {
const expectNestedTabUrlToContain = 'search=hello#fragment';
let tab = await getSelectedTab() as ElementFinder;
const initialUrl = await browser.getCurrentUrl();
await tab.$('#goto-nested-page1-with-query-params').click();
await testTabTitle('Tab 1 - Page 2 (1)');
await testUrlContains(expectNestedTabUrlToContain);
await element(by.css('#tab-button-account')).click();
await testTabTitle('Tab 1 - Page 1');
await testUrlEquals(initialUrl);
});
});
describe('entry tab contains navigation extras', () => {
const expectNestedTabUrlToContain = 'search=hello#fragment';
const rootUrlParams = 'test=123#rootFragment';
const rootUrl = `/tabs/account?${rootUrlParams}`;
beforeEach(async () => {
await browser.get(rootUrl);
await waitTime(30);
});
it('should preserve root url navigation extras when clicking on an active tab to navigate to the root', async () => {
await browser.get(rootUrl);
let tab = await getSelectedTab() as ElementFinder;
await tab.$('#goto-nested-page1-with-query-params').click();
await testTabTitle('Tab 1 - Page 2 (1)');
await testUrlContains(expectNestedTabUrlToContain);
await element(by.css('#tab-button-account')).click();
await testTabTitle('Tab 1 - Page 1');
await testUrlContains(rootUrl);
});
it('should preserve root url navigation extras when changing tabs', async () => {
await browser.get(rootUrl);
let tab = await getSelectedTab() as ElementFinder;
await element(by.css('#tab-button-contact')).click();
tab = await testTabTitle('Tab 2 - Page 1');
await element(by.css('#tab-button-account')).click();
await testTabTitle('Tab 1 - Page 1');
await testUrlContains(rootUrl);
});
it('should navigate deep then go home and preserve navigation extras', async () => {
let tab = await getSelectedTab();
await tab.$('#goto-tab1-page2').click();
tab = await testTabTitle('Tab 1 - Page 2 (1)');
await tab.$('#goto-next').click();
tab = await testTabTitle('Tab 1 - Page 2 (2)');
await element(by.css('#tab-button-contact')).click();
tab = await testTabTitle('Tab 2 - Page 1');
await element(by.css('#tab-button-account')).click();
await testTabTitle('Tab 1 - Page 2 (2)');
await element(by.css('#tab-button-account')).click();
await testTabTitle('Tab 1 - Page 1');
await testUrlContains(rootUrl);
});
});
describe('entry url - /tabs/account/nested/1', () => {
@@ -247,7 +159,7 @@ describe('tabs', () => {
await tab.$('#goto-next').click();
tab = await testTabTitle('Tab 1 - Page 2 (3)');
await testStack('ion-tabs ion-router-outlet', [
await testStack('ion-tabs ion-router-outlet',[
'app-tabs-tab1-nested',
'app-tabs-tab1-nested',
'app-tabs-tab1-nested'
@@ -314,18 +226,6 @@ async function testTabTitle(title: string) {
return tab;
}
async function testUrlContains(urlFragment: string) {
await browser.wait(ExpectedConditions.urlContains(urlFragment),
5000,
`expected ${browser.getCurrentUrl()} to contain ${urlFragment}`);
}
async function testUrlEquals(url: string) {
await browser.wait(ExpectedConditions.urlIs(url),
5000,
`expected ${browser.getCurrentUrl()} to equal ${url}`);
}
async function getSelectedTab(): Promise<ElementFinder> {
const tabs = element.all(by.css('ion-tabs ion-router-outlet > *:not(.ion-page-hidden)'));
expect(await tabs.count()).toEqual(1);

View File

@@ -15,8 +15,6 @@
</p>
<p>
<ion-button routerLink="/tabs/account/nested/1" id="goto-tab1-page2">Go to Page 2</ion-button>
<ion-button routerLink="/tabs/account/nested/1" [queryParams]="{search:'hello'}" fragment="fragment"
id="goto-nested-page1-with-query-params">Go to Page 2 with Query Params</ion-button>
<ion-button routerLink="/tabs/lazy/nested" id="goto-tab3-page2">Go to Tab 3 - Page 2</ion-button>
<ion-button routerLink="/nested-outlet/page" id="goto-nested-page1">Go to nested</ion-button>
</p>

View File

@@ -77,7 +77,7 @@ ion-app,none
ion-avatar,shadow
ion-avatar,css-prop,--border-radius
ion-back-button,shadow
ion-back-button,scoped
ion-back-button,prop,color,string | undefined,undefined,false,false
ion-back-button,prop,defaultHref,string | undefined,undefined,false,false
ion-back-button,prop,disabled,boolean,false,false,true
@@ -465,7 +465,7 @@ ion-item,shadow
ion-item,prop,button,boolean,false,false,false
ion-item,prop,color,string | undefined,undefined,false,false
ion-item,prop,detail,boolean | undefined,undefined,false,false
ion-item,prop,detailIcon,string,'chevron-forward',false,false
ion-item,prop,detailIcon,string,'ios-arrow-forward',false,false
ion-item,prop,disabled,boolean,false,false,false
ion-item,prop,download,string | undefined,undefined,false,false
ion-item,prop,href,string | undefined,undefined,false,false
@@ -566,14 +566,9 @@ ion-list,method,closeSlidingItems,closeSlidingItems() => Promise<boolean>
ion-list-header,shadow
ion-list-header,prop,color,string | undefined,undefined,false,false
ion-list-header,prop,lines,"full" | "inset" | "none" | undefined,undefined,false,false
ion-list-header,prop,mode,"ios" | "md",undefined,false,false
ion-list-header,css-prop,--background
ion-list-header,css-prop,--border-color
ion-list-header,css-prop,--border-style
ion-list-header,css-prop,--border-width
ion-list-header,css-prop,--color
ion-list-header,css-prop,--inner-border-width
ion-loading,scoped
ion-loading,prop,animated,boolean,true,false,false
@@ -683,9 +678,7 @@ ion-modal,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefin
ion-modal,prop,keyboardClose,boolean,true,false,false
ion-modal,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-modal,prop,mode,"ios" | "md",undefined,false,false
ion-modal,prop,presentingElement,HTMLElement | undefined,undefined,false,false
ion-modal,prop,showBackdrop,boolean,true,false,false
ion-modal,prop,swipeToClose,boolean,false,false,false
ion-modal,method,dismiss,dismiss(data?: any, role?: string | undefined) => Promise<boolean>
ion-modal,method,onDidDismiss,onDidDismiss() => Promise<OverlayEventDetail<any>>
ion-modal,method,onWillDismiss,onWillDismiss() => Promise<OverlayEventDetail<any>>
@@ -949,7 +942,7 @@ ion-searchbar,scoped
ion-searchbar,prop,animated,boolean,false,false,false
ion-searchbar,prop,autocomplete,"off" | "on",'off',false,false
ion-searchbar,prop,autocorrect,"off" | "on",'off',false,false
ion-searchbar,prop,cancelButtonIcon,string,config.get('backButtonIcon', 'arrow-back-sharp') as string,false,false
ion-searchbar,prop,cancelButtonIcon,string,config.get('backButtonIcon', 'md-arrow-back') as string,false,false
ion-searchbar,prop,cancelButtonText,string,'Cancel',false,false
ion-searchbar,prop,clearIcon,string | undefined,undefined,false,false
ion-searchbar,prop,color,string | undefined,undefined,false,false
@@ -958,7 +951,7 @@ ion-searchbar,prop,disabled,boolean,false,false,false
ion-searchbar,prop,inputmode,"decimal" | "email" | "none" | "numeric" | "search" | "tel" | "text" | "url",'search',false,false
ion-searchbar,prop,mode,"ios" | "md",undefined,false,false
ion-searchbar,prop,placeholder,string,'Search',false,false
ion-searchbar,prop,searchIcon,string | undefined,undefined,false,false
ion-searchbar,prop,searchIcon,string,'search',false,false
ion-searchbar,prop,showCancelButton,"always" | "focus" | "never",'never',false,false
ion-searchbar,prop,spellcheck,boolean,false,false,false
ion-searchbar,prop,type,"email" | "number" | "password" | "search" | "tel" | "text" | "url",'search',false,false

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/core",
"version": "5.0.0-beta.2",
"version": "5.0.0-beta.0",
"description": "Base components for Ionic",
"keywords": [
"ionic",
@@ -30,7 +30,7 @@
"loader/"
],
"dependencies": {
"ionicons": "^5.0.0-13",
"ionicons": "^4.6.3",
"tslib": "^1.10.0"
},
"devDependencies": {

View File

@@ -1199,10 +1199,6 @@ export namespace Components {
*/
'color'?: Color;
/**
* How the bottom border should be displayed on the list header.
*/
'lines'?: 'full' | 'inset' | 'none';
/**
* The mode determines which platform styles to use.
*/
'mode'?: "ios" | "md";
@@ -1500,17 +1496,9 @@ export namespace Components {
*/
'present': () => Promise<void>;
/**
* The element that presented the modal. This is used for card presentation effects and for stacking multiple modals on top of each other. Only applies in iOS mode.
*/
'presentingElement'?: HTMLElement;
/**
* If `true`, a backdrop will be displayed behind the modal.
*/
'showBackdrop': boolean;
/**
* If `true`, the modal can be swiped to dismiss. Only applies in iOS mode.
*/
'swipeToClose': boolean;
}
interface IonModalController {
/**
@@ -2149,7 +2137,7 @@ export namespace Components {
*/
'autocorrect': 'on' | 'off';
/**
* Set the cancel button icon. Only applies to `md` mode. Defaults to `"arrow-back-sharp"`.
* Set the cancel button icon. Only applies to `md` mode.
*/
'cancelButtonIcon': string;
/**
@@ -2157,7 +2145,7 @@ export namespace Components {
*/
'cancelButtonText': string;
/**
* Set the clear icon. Defaults to `"close-circle"` for `ios` and `"close-sharp"` for `md`.
* Set the clear icon. Defaults to `"close-circle"` for `ios` and `"close"` for `md`.
*/
'clearIcon'?: string;
/**
@@ -2189,9 +2177,9 @@ export namespace Components {
*/
'placeholder': string;
/**
* The icon to use as the search icon. Defaults to `"search-outline"` in `ios` mode and `"search-sharp"` in `md` mode.
* The icon to use as the search icon.
*/
'searchIcon'?: string;
'searchIcon': string;
/**
* Sets focus on the specified `ion-searchbar`. Use this method instead of the global `input.focus()`.
*/
@@ -4452,7 +4440,7 @@ declare namespace LocalJSX {
*/
'onIonFocus'?: (event: CustomEvent<void>) => void;
/**
* Emitted when a keyboard input occurred.
* Emitted when a keyboard input ocurred.
*/
'onIonInput'?: (event: CustomEvent<KeyboardEvent>) => void;
/**
@@ -4653,10 +4641,6 @@ declare namespace LocalJSX {
*/
'color'?: Color;
/**
* How the bottom border should be displayed on the list header.
*/
'lines'?: 'full' | 'inset' | 'none';
/**
* The mode determines which platform styles to use.
*/
'mode'?: "ios" | "md";
@@ -4861,17 +4845,9 @@ declare namespace LocalJSX {
*/
'onIonModalWillPresent'?: (event: CustomEvent<void>) => void;
/**
* The element that presented the modal. This is used for card presentation effects and for stacking multiple modals on top of each other. Only applies in iOS mode.
*/
'presentingElement'?: HTMLElement;
/**
* If `true`, a backdrop will be displayed behind the modal.
*/
'showBackdrop'?: boolean;
/**
* If `true`, the modal can be swiped to dismiss. Only applies in iOS mode.
*/
'swipeToClose'?: boolean;
}
interface IonModalController {}
interface IonNav {
@@ -5386,7 +5362,7 @@ declare namespace LocalJSX {
*/
'autocorrect'?: 'on' | 'off';
/**
* Set the cancel button icon. Only applies to `md` mode. Defaults to `"arrow-back-sharp"`.
* Set the cancel button icon. Only applies to `md` mode.
*/
'cancelButtonIcon'?: string;
/**
@@ -5394,7 +5370,7 @@ declare namespace LocalJSX {
*/
'cancelButtonText'?: string;
/**
* Set the clear icon. Defaults to `"close-circle"` for `ios` and `"close-sharp"` for `md`.
* Set the clear icon. Defaults to `"close-circle"` for `ios` and `"close"` for `md`.
*/
'clearIcon'?: string;
/**
@@ -5438,7 +5414,7 @@ declare namespace LocalJSX {
*/
'onIonFocus'?: (event: CustomEvent<void>) => void;
/**
* Emitted when a keyboard input occurred.
* Emitted when a keyboard input ocurred.
*/
'onIonInput'?: (event: CustomEvent<KeyboardEvent>) => void;
/**
@@ -5446,7 +5422,7 @@ declare namespace LocalJSX {
*/
'placeholder'?: string;
/**
* The icon to use as the search icon. Defaults to `"search-outline"` in `ios` mode and `"search-sharp"` in `md` mode.
* The icon to use as the search icon.
*/
'searchIcon'?: string;
/**
@@ -5893,7 +5869,7 @@ declare namespace LocalJSX {
*/
'onIonFocus'?: (event: CustomEvent<void>) => void;
/**
* Emitted when a keyboard input occurred.
* Emitted when a keyboard input ocurred.
*/
'onIonInput'?: (event: CustomEvent<KeyboardEvent>) => void;
/**

View File

@@ -79,7 +79,7 @@
}
}, {
text: 'Play (open modal)',
icon: 'chevron-forward-circle',
icon: 'arrow-dropright-circle',
handler: () => {
console.log('Play clicked');
}
@@ -221,7 +221,7 @@
}
}, {
text: 'Play (open modal)',
icon: 'chevron-forward-circle',
icon: 'arrow-dropright-circle',
handler: () => {
console.log('Play clicked');
}

View File

@@ -55,7 +55,7 @@
}
}, {
text: 'Play (open modal)',
icon: 'chevron-forward-circle',
icon: 'arrow-dropright-circle',
handler: () => {
console.log('Play clicked');
}
@@ -98,7 +98,7 @@
}
}, {
text: 'Play (open modal)',
icon: 'chevron-forward-circle',
icon: 'arrow-dropright-circle',
handler: () => {
console.log('Play clicked');
}

View File

@@ -68,7 +68,7 @@
}
}, {
text: 'Play (open modal)',
icon: 'chevron-forward-circle',
icon: 'arrow-dropright-circle',
handler: () => {
console.log('Play clicked');
}

View File

@@ -1,7 +1,7 @@
import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Method, Prop, Watch, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { AlertButton, AlertInput, AnimationBuilder, CssClassMap, OverlayEventDetail, OverlayInterface } from '../../interface';
import { AlertButton, AlertInput, Animation, AnimationBuilder, CssClassMap, OverlayEventDetail, OverlayInterface } from '../../interface';
import { BACKDROP, dismiss, eventMethod, isCancel, prepareOverlay, present, safeCall } from '../../utils/overlays';
import { sanitizeDOMString } from '../../utils/sanitization';
import { getClassMap } from '../../utils/theme';
@@ -30,6 +30,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
private processedButtons: AlertButton[] = [];
presented = false;
animation?: Animation;
mode = getIonMode(this);
@Element() el!: HTMLIonAlertElement;

View File

@@ -60,7 +60,7 @@
const toast = Object.assign(document.createElement('ion-toast'), {
message: 'Hello world!',
buttons: [
{ text: 'Close', role: 'cancel' }
{ text: 'Close', role: 'close' }
]
});
document.body.appendChild(toast);

View File

@@ -102,6 +102,7 @@
// Back Button States
// --------------------------------------------------
:host-context(.can-go-back > ion-header),
:host(.show-back-button) {
display: block;
}

View File

@@ -15,11 +15,11 @@ import { createColorClasses, openURL } from '../../utils/theme';
ios: 'back-button.ios.scss',
md: 'back-button.md.scss'
},
shadow: true
scoped: true
})
export class BackButton implements ComponentInterface, ButtonInterface {
mode = getIonMode(this);
private mode = getIonMode(this);
@Element() el!: HTMLElement;
/**
@@ -54,32 +54,20 @@ export class BackButton implements ComponentInterface, ButtonInterface {
*/
@Prop() type: 'submit' | 'reset' | 'button' = 'button';
get backButtonIcon() {
const icon = this.icon;
if (icon != null) {
// icon is set on the component or by the config
return icon;
}
if (this.mode === 'ios') {
// default ios back button icon
return config.get('backButtonIcon', 'chevron-back');
}
// default md back button icon
return config.get('backButtonIcon', 'arrow-back-sharp');
private get backButtonIcon() {
return this.icon != null ? this.icon : config.get('backButtonIcon', 'arrow-back');
}
get backButtonText() {
private get backButtonText() {
const defaultBackButtonText = this.mode === 'ios' ? 'Back' : null;
return this.text != null ? this.text : config.get('backButtonText', defaultBackButtonText);
}
get hasIconOnly() {
private get hasIconOnly() {
return this.backButtonIcon && !this.backButtonText;
}
get rippleType() {
private get rippleType() {
// If the button only has an icon we use the unbounded
// "circular" ripple effect
if (this.hasIconOnly) {
@@ -118,10 +106,10 @@ export class BackButton implements ComponentInterface, ButtonInterface {
'show-back-button': showBackButton
}}
>
<button type={type} disabled={disabled} class="button-native" part="button">
<button type={type} disabled={disabled} class="button-native">
<span class="button-inner">
{backButtonIcon && <ion-icon icon={backButtonIcon} lazy={false} part="icon"></ion-icon>}
{backButtonText && <span class="button-text" part="text">{backButtonText}</span>}
{backButtonIcon && <ion-icon icon={backButtonIcon} lazy={false}></ion-icon>}
{backButtonText && <span class="button-text">{backButtonText}</span>}
</span>
{mode === 'md' && <ion-ripple-effect type={this.rippleType}></ion-ripple-effect>}
</button>

View File

@@ -1,59 +0,0 @@
import { BackButton } from "../back-button";
import { config } from "../../../global/config";
describe('back button', () => {
let bb: BackButton;
beforeEach(() => {
config.reset({});
bb = new BackButton();
});
describe('backButtonIcon', () => {
it('set custom icon on the instance, override config', () => {
bb.icon = 'custom-icon-instance';
config.reset({
backButtonIcon: 'custom-icon-config'
});
expect(bb.backButtonIcon).toBe('custom-icon-instance');
});
it('set custom icon in the config', () => {
config.reset({
backButtonIcon: 'custom-icon-config'
});
expect(bb.backButtonIcon).toBe('custom-icon-config');
});
it('set custom icon on the instance', () => {
bb.icon = 'custom-icon-instance';
expect(bb.backButtonIcon).toBe('custom-icon-instance');
});
it('default icon for ios mode', () => {
bb.mode = 'ios';
expect(bb.backButtonIcon).toBe('chevron-back');
});
it('default icon', () => {
expect(bb.backButtonIcon).toBe('arrow-back-sharp');
});
});
describe('backButtonText', () => {
it('default text for ios mode', () => {
bb.mode = 'ios';
expect(bb.backButtonText).toBe('Back');
});
it('default text', () => {
expect(bb.backButtonText).toBe(null);
});
});
});

View File

@@ -22,11 +22,7 @@
<ion-content id="content">
<ion-list>
<ion-list-header>
<ion-label>
Badges Right
</ion-label>
</ion-list-header>
<ion-list-header>Badges Right</ion-list-header>
<ion-item>
<ion-label>Default Badge</ion-label>
<ion-badge slot="end">00</ion-badge>
@@ -74,11 +70,7 @@
</ion-list>
<ion-list>
<ion-list-header>
<ion-label>
Badges Left
</ion-label>
</ion-list-header>
<ion-list-header>Badges Left</ion-list-header>
<ion-item>
<ion-label>Default Badge</ion-label>
<ion-badge slot="start">00</ion-badge>

View File

@@ -68,11 +68,6 @@
--background-focused: #{ion-color(primary, base, .1)};
--color-activated: #{ion-color(primary, base)};
--color-focused: #{ion-color(primary, base)};
font-size: #{$button-ios-clear-font-size};
font-weight: #{$button-ios-clear-font-weight};
letter-spacing: #{$button-ios-clear-letter-spacing};
}

View File

@@ -153,15 +153,6 @@ $button-ios-outline-background-color-focused: ion-color(primary, base, $
// iOS Clear Button
// --------------------------------------------------
/// @prop - Font size of the clear button
$button-ios-clear-font-size: 17px !default;
/// @prop - Font weight of the clear button
$button-ios-clear-font-weight: normal !default;
/// @prop - Letter spacing of the clear button
$button-ios-clear-letter-spacing: 0 !default;
/// @prop - Border color of the clear button
$button-ios-clear-border-color: transparent !default;

View File

@@ -23,9 +23,9 @@ import { createColorClasses, openURL } from '../../utils/theme';
shadow: true,
})
export class Button implements ComponentInterface, AnchorInterface, ButtonInterface {
private inItem = false;
private inListHeader = false;
private inToolbar = false;
private inItem = false;
@Element() el!: HTMLElement;
@@ -124,7 +124,6 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
componentWillLoad() {
this.inToolbar = !!this.el.closest('ion-buttons');
this.inListHeader = !!this.el.closest('ion-list-header');
this.inItem = !!this.el.closest('ion-item') || !!this.el.closest('ion-item-divider');
}
@@ -190,7 +189,7 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
let fill = this.fill;
if (fill === undefined) {
fill = this.inToolbar || this.inListHeader ? 'clear' : 'solid';
fill = this.inToolbar ? 'clear' : 'solid';
}
return (
<Host

View File

@@ -32,7 +32,7 @@
<ion-toolbar>
<ion-buttons slot="secondary">
<ion-button>
<ion-icon slot="icon-only" name="person-circle"></ion-icon>
<ion-icon slot="icon-only" name="contact"></ion-icon>
</ion-button>
<ion-button>
<ion-icon slot="icon-only" name="search"></ion-icon>
@@ -83,7 +83,7 @@
<ion-toolbar>
<ion-buttons slot="secondary">
<ion-button>
<ion-icon slot="icon-only" name="person-circle"></ion-icon>
<ion-icon slot="icon-only" name="contact"></ion-icon>
</ion-button>
<ion-button>
<ion-icon slot="icon-only" name="search"></ion-icon>
@@ -100,7 +100,7 @@
<ion-toolbar>
<ion-buttons slot="secondary">
<ion-button class="activated">
<ion-icon slot="icon-only" name="person-circle"></ion-icon>
<ion-icon slot="icon-only" name="contact"></ion-icon>
</ion-button>
<ion-button class="activated">
<ion-icon slot="icon-only" name="search"></ion-icon>
@@ -117,10 +117,10 @@
<ion-toolbar>
<ion-buttons slot="secondary">
<ion-button fill="solid">
<ion-icon slot="icon-only" name="person-circle"></ion-icon>
<ion-icon slot="icon-only" name="contact"></ion-icon>
</ion-button>
<ion-button fill="solid">
<ion-icon name="person-circle" slot="start"></ion-icon>
<ion-icon name="contact" slot="start"></ion-icon>
Solid
</ion-button>
</ion-buttons>
@@ -136,10 +136,10 @@
<ion-toolbar>
<ion-buttons slot="secondary">
<ion-button fill="solid" class="activated">
<ion-icon slot="icon-only" name="person-circle"></ion-icon>
<ion-icon slot="icon-only" name="contact"></ion-icon>
</ion-button>
<ion-button fill="solid" class="activated">
<ion-icon name="person-circle" slot="start"></ion-icon>
<ion-icon name="contact" slot="start"></ion-icon>
Solid
</ion-button>
</ion-buttons>
@@ -155,7 +155,7 @@
<ion-toolbar>
<ion-buttons slot="secondary">
<ion-button fill="outline">
<ion-icon slot="icon-only" name="person-circle"></ion-icon>
<ion-icon slot="icon-only" name="contact"></ion-icon>
</ion-button>
<ion-button fill="outline">
<ion-icon name="star" slot="start"></ion-icon>
@@ -164,7 +164,7 @@
</ion-buttons>
<ion-buttons slot="primary">
<ion-button color="secondary" fill="outline">
<ion-icon slot="icon-only" name="person-circle"></ion-icon>
<ion-icon slot="icon-only" name="contact"></ion-icon>
</ion-button>
</ion-buttons>
<ion-title>Outline</ion-title>
@@ -173,7 +173,7 @@
<ion-toolbar>
<ion-buttons slot="secondary">
<ion-button fill="outline" class="activated">
<ion-icon slot="icon-only" name="person-circle"></ion-icon>
<ion-icon slot="icon-only" name="contact"></ion-icon>
</ion-button>
<ion-button fill="outline" class="activated">
<ion-icon name="star" slot="start"></ion-icon>
@@ -182,7 +182,7 @@
</ion-buttons>
<ion-buttons slot="primary">
<ion-button color="secondary" fill="outline" class="activated">
<ion-icon slot="icon-only" name="person-circle"></ion-icon>
<ion-icon slot="icon-only" name="contact"></ion-icon>
</ion-button>
</ion-buttons>
<ion-title>Outline.activated</ion-title>
@@ -191,7 +191,7 @@
<ion-toolbar>
<ion-buttons slot="secondary">
<ion-button>
<ion-icon name="person-circle" slot="start"></ion-icon>
<ion-icon name="contact" slot="start"></ion-icon>
Clear
</ion-button>
</ion-buttons>

View File

@@ -23,9 +23,7 @@
<ion-content id="content">
<ion-list-header>
<ion-label>
Native
</ion-label>
Native
</ion-list-header>
<div class="ion-padding-start">
@@ -51,9 +49,7 @@
</div>
<ion-list-header>
<ion-label>
Ionic
</ion-label>
Ionic
</ion-list-header>
<ion-item>
<ion-label>Unchecked</ion-label>
@@ -76,9 +72,7 @@
</ion-item>
<ion-list-header>
<ion-label>
Colors
</ion-label>
Colors
</ion-list-header>
<div class="ion-padding-start">
<ion-checkbox indeterminate></ion-checkbox>
@@ -93,9 +87,7 @@
</div>
<ion-list-header>
<ion-label>
Parent
</ion-label>
Parent
</ion-list-header>
<ul>

View File

@@ -120,8 +120,6 @@
}
.transition-effect {
display: none;
position: absolute;
/* stylelint-disable property-blacklist */

View File

@@ -50,7 +50,7 @@
<ion-fab vertical="bottom" horizontal="end" edge id="fab2" slot="fixed">
<ion-fab-button onclick="clickMainFAB('fab2')" color="dark" class="e2eFabBottomRight" disabled>
<ion-icon name="arrow-back-circle"></ion-icon>
<ion-icon name="arrow-dropleft"></ion-icon>
</ion-fab-button>
<ion-fab-list side="start">
<ion-fab-button onclick="openSocial('facebook', 'fab2')">
@@ -70,7 +70,7 @@
<ion-fab vertical="top" horizontal="start" id="fab3" slot="fixed">
<ion-fab-button onclick="clickMainFAB('fab3')" color="secondary" class="e2eFabTopLeft">
<ion-icon name="arrow-forward-circle"></ion-icon>
<ion-icon name="arrow-dropright"></ion-icon>
</ion-fab-button>
<ion-fab-list side="end">
<ion-fab-button onclick="openSocial('facebook', 'fab3')">
@@ -90,7 +90,7 @@
<ion-fab vertical="bottom" horizontal="start" id="fab4" slot="fixed">
<ion-fab-button onclick="clickMainFAB('fab4')" color="light" class="e2eFabBottomLeft">
<ion-icon name="arrow-up-circle"></ion-icon>
<ion-icon name="arrow-dropup"></ion-icon>
</ion-fab-button>
<ion-fab-list side="top">
<ion-fab-button onclick="openSocial('facebook', 'fab4')">
@@ -110,7 +110,7 @@
<ion-fab vertical="center" horizontal="center" id="fab5" slot="fixed">
<ion-fab-button onclick="clickMainFAB('fab5')" class="e2eFabCenter">
<ion-icon name="share"></ion-icon>
<ion-icon name="md-share"></ion-icon>
</ion-fab-button>
<ion-fab-list side="top">
<ion-fab-button onclick="openSocial('vimeo', 'fab5')" color="primary">

View File

@@ -48,7 +48,7 @@
</ion-fab>
<ion-fab vertical="bottom" horizontal="end" edge id="fab2" slot="fixed">
<ion-fab-button translucent onclick="clickMainFAB('fab2')" color="dark" class="e2eFabBottomRight"><ion-icon name="arrow-back-circle"></ion-icon></ion-fab-button>
<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="start">
<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>
@@ -58,7 +58,7 @@
</ion-fab>
<ion-fab vertical="top" horizontal="start" id="fab3" slot="fixed">
<ion-fab-button translucent onclick="clickMainFAB('fab3')" color="secondary" class="e2eFabTopLeft"><ion-icon name="arrow-forward-circle"></ion-icon></ion-fab-button>
<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="end">
<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>
@@ -68,7 +68,7 @@
</ion-fab>
<ion-fab vertical="bottom" horizontal="start" id="fab4" slot="fixed">
<ion-fab-button translucent onclick="clickMainFAB('fab4')" color="light" class="e2eFabBottomLeft"><ion-icon name="arrow-up-circle"></ion-icon></ion-fab-button>
<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>
@@ -78,7 +78,7 @@
</ion-fab>
<ion-fab horizontal="center" vertical="center" id="fab5" slot="fixed">
<ion-fab-button translucent onclick="clickMainFAB('fab5')" class="e2eFabCenter"><ion-icon name="share"></ion-icon></ion-fab-button>
<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>

View File

@@ -101,10 +101,7 @@ export class Header implements ComponentInterface {
if (!mainHeaderIndex || !scrollHeaderIndex) { return; }
setHeaderActive(mainHeaderIndex, false);
mainHeaderIndex.toolbars.forEach(toolbar => {
setToolbarBackgroundOpacity(toolbar, 0);
});
setToolbarBackgroundOpacity(mainHeaderIndex.toolbars[0], 0);
readTask(() => {
const mainHeaderHeight = mainHeaderIndex.el.clientHeight;
@@ -117,7 +114,7 @@ export class Header implements ComponentInterface {
*/
const toolbarIntersection = (ev: any) => { handleToolbarIntersection(ev, mainHeaderIndex, scrollHeaderIndex); };
this.intersectionObserver = new IntersectionObserver(toolbarIntersection, { threshold: [0.25, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1], rootMargin: `-${mainHeaderHeight}px 0px 0px 0px` });
this.intersectionObserver.observe(scrollHeaderIndex.toolbars[scrollHeaderIndex.toolbars.length - 1].el);
this.intersectionObserver.observe(scrollHeaderIndex.toolbars[0].el);
/**
* Handle scaling of large iOS titles and

View File

@@ -72,10 +72,7 @@ const handleToolbarBorderIntersection = (ev: any, mainHeaderIndex: HeaderIndex)
if (!ev[0].isIntersecting) { return; }
const scale = ((1 - ev[0].intersectionRatio) * 100) / 75;
mainHeaderIndex.toolbars.forEach(toolbar => {
setToolbarBackgroundOpacity(toolbar, (scale === 1) ? undefined : scale);
});
setToolbarBackgroundOpacity(mainHeaderIndex.toolbars[0], (scale === 1) ? undefined : scale);
};
/**

View File

@@ -4,15 +4,9 @@
Icons can be used on their own as a standalone component, or inside of another component.
By default, Ionicons will use the same icon for each platform (iOS or Material Design). In previous versions of Ionicons, icons would automatically update based on the platform. As of Ionicons 5.0, apps will have to handle this on a per-icon basis, if needed.
Ionicons provide platform continuity out of the box in Ionic by rendering a different icon based on the device the app is running on. For example, by setting the icon `name` to `alarm` the icon will automatically use the `ios-alarm` on an iOS device, and the `md-alarm` for any device running Material Design. This allows the developer to write the markup once while Ionic handles displaying the appropriate icon based on the mode.
To use different icons depending on platform, set the `ios` and `md` properties or attributes. In the example below, when the app has the `ios` mode applied, it'll show the `logo-apple` icon. When using `md`, it'll show the `logo-android` icon.
```
<ion-icon ios="logo-apple" md="logo-android"></ion-icon>
```
For a full list of available icons and more usage explanations, please check out the [Ionicons documentation](https://ionicons.com/).
For a full list of available icons and more usage explanations, check out the [Ionicons documentation](https://ionicons.com/).
<!-- Auto Generated Below -->

View File

@@ -50,19 +50,55 @@
</ion-item>
<ion-item>
<ion-icon name="STAR" slot="end"></ion-icon>
<ion-icon name="md-home" slot="start"></ion-icon>
<ion-label>
<code>
name="STAR"
name="md-home"
</code>
</ion-label>
</ion-item>
<ion-item>
<ion-icon icon="home" color="primary" slot="start"></ion-icon>
<ion-icon name="ios-home" slot="start"></ion-icon>
<ion-label>
<code>
icon="home"
name="ios-home"
</code>
</ion-label>
</ion-item>
<ion-item>
<ion-icon name="ios-home" slot="end"></ion-icon>
<ion-label>
<code>
name="ios-home"
</code>
</ion-label>
</ion-item>
<ion-item>
<ion-icon name="ios-star-outline" slot="start"></ion-icon>
<ion-label>
<code>
name="ios-star-outline"
</code>
</ion-label>
</ion-item>
<ion-item>
<ion-icon name="IOS-STAR-OUTLINE" slot="end"></ion-icon>
<ion-label>
<code>
name="IOS-STAR-OUTLINE"
</code>
</ion-label>
</ion-item>
<ion-item>
<ion-icon name="md-home" color="primary" slot="start"></ion-icon>
<ion-label>
<code>
name="md-home"
</code>
</ion-label>
</ion-item>
@@ -94,6 +130,24 @@
</ion-label>
</ion-item>
<ion-item>
<ion-icon ios="ios-color-filter" md="md-color-filter" slot="start"></ion-icon>
<ion-label>
<code>
ios="ios-color-filter" md="md-color-filter"
</code>
</ion-label>
</ion-item>
<ion-item>
<ion-icon ios="MD-COLOR-FILTER" md="IOS-COLOR-FILTER" slot="start"></ion-icon>
<ion-label>
<code>
ios="MD-COLOR-FILTER" md="IOS-COLOR-FILTER"
</code>
</ion-label>
</ion-item>
<ion-item>
<ion-icon slot="start"></ion-icon>
<ion-label>

View File

@@ -51,17 +51,25 @@
<ion-grid>
<ion-row class="ion-align-items-center">
<ion-col size="auto"><code>null</code></ion-col>
<ion-col><ion-icon name="arrow-dropright"></ion-icon></ion-col>
<ion-col><ion-icon name="arrow-dropright-circle"></ion-icon></ion-col>
<ion-col><ion-icon name="arrow-forward"></ion-icon></ion-col>
<ion-col><ion-icon name="arrow-forward-circle"></ion-icon></ion-col>
<ion-col><ion-icon name="arrow-round-forward"></ion-icon></ion-col>
<ion-col><ion-icon name="arrow-dropleft"></ion-icon></ion-col>
<ion-col><ion-icon name="arrow-dropleft-circle"></ion-icon></ion-col>
<ion-col><ion-icon name="arrow-back"></ion-icon></ion-col>
<ion-col><ion-icon name="arrow-back-circle"></ion-icon></ion-col>
<ion-col><ion-icon name="arrow-round-back"></ion-icon></ion-col>
</ion-row>
<ion-row class="ion-align-items-center">
<ion-col size="auto"><code>false</code></ion-col>
<ion-col><ion-icon name="arrow-dropright" flip-rtl="false"></ion-icon></ion-col>
<ion-col><ion-icon name="arrow-dropright-circle" flip-rtl="false"></ion-icon></ion-col>
<ion-col><ion-icon name="arrow-forward" flip-rtl="false"></ion-icon></ion-col>
<ion-col><ion-icon name="arrow-forward-circle" flip-rtl="false"></ion-icon></ion-col>
<ion-col><ion-icon name="arrow-round-forward" flip-rtl="false"></ion-icon></ion-col>
<ion-col><ion-icon name="arrow-dropleft" flip-rtl="false"></ion-icon></ion-col>
<ion-col><ion-icon name="arrow-dropleft-circle" flip-rtl="false"></ion-icon></ion-col>
<ion-col><ion-icon name="arrow-back" flip-rtl="false"></ion-icon></ion-col>
<ion-col><ion-icon name="arrow-back-circle" flip-rtl="false"></ion-icon></ion-col>
<ion-col><ion-icon name="arrow-round-back" flip-rtl="false"></ion-icon></ion-col>
</ion-row>
</ion-grid>

View File

@@ -56,16 +56,30 @@
</ion-item>
<ion-item>
<ion-icon name="home" is-active="true" slot="start"></ion-icon>
<ion-icon name="md-home" is-active="true" slot="start"></ion-icon>
<code>
name="home" is-active="true"
name="md-home" is-active="true"
</code>
</ion-item>
<ion-item>
<ion-icon name="home" color="primary" slot="start"></ion-icon>
<ion-icon name="ios-home" is-active="true" slot="start"></ion-icon>
<code>
name="home"
name="ios-home" is-active="true"
</code>
</ion-item>
<ion-item>
<ion-icon name="ios-home" slot="start"></ion-icon>
<code>
name="ios-home"
</code>
</ion-item>
<ion-item>
<ion-icon name="md-home" color="primary" slot="start"></ion-icon>
<code>
name="md-home"
</code>
</ion-item>
@@ -82,11 +96,18 @@
ios="logo-apple" md="logo-android"
</code>
</ion-item>
<ion-item>
<ion-icon ios="logo-apple" md="logo-android" slot="start" id-active="false"></ion-icon>
<ion-icon ios="md-color-filter" md="ios-color-filter" slot="start"></ion-icon>
<code>
ios="logo-apple" md="logo-android" is-active="false"
ios="md-color-filter" md="ios-color-filter"
</code>
</ion-item>
<ion-item>
<ion-icon ios="md-color-filter" md="ios-color-filter" is-active="false" slot="start"></ion-icon>
<code>
ios="md-color-filter" md="ios-color-filter" is-active="false"
</code>
</ion-item>

View File

@@ -20,12 +20,12 @@
<ion-icon name="happy" color="warning"></ion-icon>
<ion-icon name="people"></ion-icon>
<ion-icon name="person" color="tertiary"></ion-icon>
<ion-icon name="person-circle"></ion-icon>
<ion-icon name="contact"></ion-icon>
<ion-icon name="apps"></ion-icon>
<ion-icon name="lock-closed"></ion-icon>
<ion-icon name="lock"></ion-icon>
<ion-icon name="key" color="success"></ion-icon>
<ion-icon name="lock-open"></ion-icon>
<ion-icon name="unlock"></ion-icon>
<ion-icon name="map" color="secondary"></ion-icon>
<ion-icon name="navigate"></ion-icon>
@@ -35,6 +35,7 @@
<ion-icon name="mic"></ion-icon>
<ion-icon name="musical-notes" color="warning"></ion-icon>
<ion-icon name="volume-high"></ion-icon>
<ion-icon name="microphone" color="tertiary"></ion-icon>
<ion-icon name="cafe" color="success"></ion-icon>
<ion-icon name="calculator"></ion-icon>
@@ -46,9 +47,9 @@
<ion-icon name="star" color="success"></ion-icon>
<ion-icon name="pin"></ion-icon>
<ion-icon name="arrow-up-circle" color="warning"></ion-icon>
<ion-icon name="arrow-dropup-circle" color="warning"></ion-icon>
<ion-icon name="arrow-back"></ion-icon>
<ion-icon name="arrow-down-circle"></ion-icon>
<ion-icon name="arrow-dropdown"></ion-icon>
<ion-icon name="arrow-forward"></ion-icon>
<ion-icon name="cloud"></ion-icon>

View File

@@ -181,7 +181,7 @@ export class Input implements ComponentInterface {
}
/**
* Emitted when a keyboard input occurred.
* Emitted when a keyboard input ocurred.
*/
@Event() ionInput!: EventEmitter<KeyboardEvent>;

View File

@@ -243,12 +243,12 @@ export const InputExample: React.FC = () => (
## Events
| Event | Description | Type |
| ----------- | --------------------------------------- | ------------------------------------- |
| `ionBlur` | Emitted when the input loses focus. | `CustomEvent<void>` |
| `ionChange` | Emitted when the value has changed. | `CustomEvent<InputChangeEventDetail>` |
| `ionFocus` | Emitted when the input has focus. | `CustomEvent<void>` |
| `ionInput` | Emitted when a keyboard input occurred. | `CustomEvent<KeyboardEvent>` |
| Event | Description | Type |
| ----------- | -------------------------------------- | ------------------------------------- |
| `ionBlur` | Emitted when the input loses focus. | `CustomEvent<void>` |
| `ionChange` | Emitted when the value has changed. | `CustomEvent<InputChangeEventDetail>` |
| `ionFocus` | Emitted when the input has focus. | `CustomEvent<void>` |
| `ionInput` | Emitted when a keyboard input ocurred. | `CustomEvent<KeyboardEvent>` |
## Methods

View File

@@ -22,38 +22,22 @@
<ion-content>
<ion-list>
<ion-list-header>
<ion-label>
Default List
</ion-label>
</ion-list-header>
<ion-list-header>Default List</ion-list-header>
<!-- Sliding items are generated below -->
</ion-list>
<ion-list lines="full">
<ion-list-header>
<ion-label>
Full List
</ion-label>
</ion-list-header>
<ion-list-header>Full List</ion-list-header>
<!-- Sliding items are generated below -->
</ion-list>
<ion-list lines="inset">
<ion-list-header>
<ion-label>
Inset List
</ion-label>
</ion-list-header>
<ion-list-header>Inset List</ion-list-header>
<!-- Sliding items are generated below -->
</ion-list>
<ion-list lines="none">
<ion-list-header>
<ion-label>
No Lines List
</ion-label>
</ion-list-header>
<ion-list-header>No Lines List</ion-list-header>
<!-- Sliding items are generated below -->
</ion-list>
</ion-content>

View File

@@ -86,7 +86,7 @@
</ion-item>
<ion-item-options>
<ion-item-option color="primary">
<ion-icon slot="start" ios="ellipsis-horizontal" md="ellipsis-vertical"></ion-icon>
<ion-icon slot="start" name="more"></ion-icon>
More
</ion-item-option>
<ion-item-option color="secondary">
@@ -105,7 +105,7 @@
</ion-item>
<ion-item-options>
<ion-item-option color="primary">
<ion-icon slot="end" ios="ellipsis-horizontal" md="ellipsis-vertical"></ion-icon>
<ion-icon slot="end" name="more"></ion-icon>
More
</ion-item-option>
<ion-item-option color="secondary">
@@ -124,7 +124,7 @@
</ion-item>
<ion-item-options>
<ion-item-option color="primary">
<ion-icon slot="top" ios="ellipsis-horizontal" md="ellipsis-vertical"></ion-icon>
<ion-icon slot="top" name="more"></ion-icon>
More
</ion-item-option>
<ion-item-option color="secondary">
@@ -143,7 +143,7 @@
</ion-item>
<ion-item-options>
<ion-item-option color="primary">
<ion-icon slot="bottom" ios="ellipsis-horizontal" md="ellipsis-vertical"></ion-icon>
<ion-icon slot="bottom" name="more"></ion-icon>
More
</ion-item-option>
<ion-item-option color="secondary">

View File

@@ -46,13 +46,13 @@ $item-ios-detail-icon-color: $item-ios-border-color !default;
$item-ios-padding-top: 10px !default;
/// @prop - Padding end for the item content
$item-ios-padding-end: 20px !default;
$item-ios-padding-end: 16px !default;
/// @prop - Padding bottom for the item content
$item-ios-padding-bottom: 10px !default;
/// @prop - Padding start for the item content
$item-ios-padding-start: 20px !default;
$item-ios-padding-start: 16px !default;
/// @prop - Border bottom width for the item when lines are displayed
$item-ios-border-bottom-width: $hairlines-width !default;

View File

@@ -404,6 +404,7 @@ button, a {
position: relative;
}
// Item Textarea
// --------------------------------------------------

View File

@@ -49,7 +49,7 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
/**
* The icon to use when `detail` is set to `true`.
*/
@Prop() detailIcon = 'chevron-forward';
@Prop() detailIcon = 'ios-arrow-forward';
/**
* If `true`, the user cannot interact with the item.
@@ -136,14 +136,9 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
// input cover on top of those interfering with their clicks
const inputs = this.el.querySelectorAll('ion-input, ion-range, ion-searchbar, ion-segment, ion-textarea, ion-toggle');
// The following elements should also stay clickable when an input with cover is present
const clickables = this.el.querySelectorAll('ion-anchor, ion-button, a, button');
// Check for multiple inputs to change the position of the input cover to relative
// for all of the covered inputs above
this.multipleInputs = covers.length + inputs.length > 1
|| covers.length + clickables.length > 1
|| covers.length > 0 && this.isClickable();
this.multipleInputs = covers.length + inputs.length > 1;
}
// If the item contains an input including a checkbox, datetime, select, or radio

View File

@@ -1364,21 +1364,21 @@ Item Inputs
## Properties
| Property | Attribute | Description | Type | Default |
| ----------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | ------------------- |
| `button` | `button` | If `true`, a button tag will be rendered and the item will be tappable. | `boolean` | `false` |
| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
| `detail` | `detail` | If `true`, a detail arrow will appear on the item. Defaults to `false` unless the `mode` is `ios` and an `href` or `button` property is present. | `boolean \| undefined` | `undefined` |
| `detailIcon` | `detail-icon` | The icon to use when `detail` is set to `true`. | `string` | `'chevron-forward'` |
| `disabled` | `disabled` | If `true`, the user cannot interact with the item. | `boolean` | `false` |
| `download` | `download` | This attribute instructs browsers to download a URL instead of navigating to it, so the user will be prompted to save it as a local file. If the attribute has a value, it is used as the pre-filled file name in the Save prompt (the user can still change the file name if they want). | `string \| undefined` | `undefined` |
| `href` | `href` | Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. | `string \| undefined` | `undefined` |
| `lines` | `lines` | How the bottom border should be displayed on the item. | `"full" \| "inset" \| "none" \| undefined` | `undefined` |
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
| `rel` | `rel` | Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). | `string \| undefined` | `undefined` |
| `routerDirection` | `router-direction` | When using a router, it specifies the transition direction when navigating to another page using `href`. | `"back" \| "forward" \| "root"` | `'forward'` |
| `target` | `target` | Specifies where to display the linked URL. Only applies when an `href` is provided. Special keywords: `"_blank"`, `"_self"`, `"_parent"`, `"_top"`. | `string \| undefined` | `undefined` |
| `type` | `type` | The type of the button. Only used when an `onclick` or `button` property is present. | `"button" \| "reset" \| "submit"` | `'button'` |
| Property | Attribute | Description | Type | Default |
| ----------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | --------------------- |
| `button` | `button` | If `true`, a button tag will be rendered and the item will be tappable. | `boolean` | `false` |
| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
| `detail` | `detail` | If `true`, a detail arrow will appear on the item. Defaults to `false` unless the `mode` is `ios` and an `href` or `button` property is present. | `boolean \| undefined` | `undefined` |
| `detailIcon` | `detail-icon` | The icon to use when `detail` is set to `true`. | `string` | `'ios-arrow-forward'` |
| `disabled` | `disabled` | If `true`, the user cannot interact with the item. | `boolean` | `false` |
| `download` | `download` | This attribute instructs browsers to download a URL instead of navigating to it, so the user will be prompted to save it as a local file. If the attribute has a value, it is used as the pre-filled file name in the Save prompt (the user can still change the file name if they want). | `string \| undefined` | `undefined` |
| `href` | `href` | Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. | `string \| undefined` | `undefined` |
| `lines` | `lines` | How the bottom border should be displayed on the item. | `"full" \| "inset" \| "none" \| undefined` | `undefined` |
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
| `rel` | `rel` | Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). | `string \| undefined` | `undefined` |
| `routerDirection` | `router-direction` | When using a router, it specifies the transition direction when navigating to another page using `href`. | `"back" \| "forward" \| "root"` | `'forward'` |
| `target` | `target` | Specifies where to display the linked URL. Only applies when an `href` is provided. Special keywords: `"_blank"`, `"_self"`, `"_parent"`, `"_top"`. | `string \| undefined` | `undefined` |
| `type` | `type` | The type of the button. Only used when an `onclick` or `button` property is present. | `"button" \| "reset" \| "submit"` | `'button'` |
## Slots

View File

@@ -2,15 +2,12 @@ import { E2EPage, newE2EPage } from '@stencil/core/testing';
test('item: inputs', async () => {
const page = await newE2EPage({
url: '/src/components/item/test/inputs?ionic:_testing=true',
url: '/src/components/item/test/inputs?ionic:_testing=true'
});
// check form
await page.click('#submit');
await checkFormResult(
page,
'{"date":"","select":"n64","toggle":"","input":"","input2":"","checkbox":"","range":"10"}'
);
await checkFormResult(page, '{"date":"","select":"n64","toggle":"","input":"","input2":"","checkbox":"","range":"10"}');
await page.waitFor(100);
// Default case, enabled and no value
@@ -25,7 +22,6 @@ test('item: inputs', async () => {
// check form
await page.click('#submit');
await page.waitFor(100);
await checkFormResult(page, '{}');
await page.waitFor(100);
@@ -40,10 +36,7 @@ test('item: inputs', async () => {
// check form
await page.click('#submit');
await checkFormResult(
page,
'{"date":"2016-12-09","select":"nes","toggle":"on","input":"Some text","input2":"Some text","checkbox":"on","range":"20"}'
);
await checkFormResult(page, '{"date":"2016-12-09","select":"nes","toggle":"on","input":"Some text","input2":"Some text","checkbox":"on","range":"20"}');
await page.waitFor(100);
compare = await page.compareScreenshot('should reenable and set value');
@@ -69,22 +62,6 @@ test('item: inputs', async () => {
compare = await page.compareScreenshot('should set empty');
expect(compare).toMatchScreenshot();
// Test multiple
await page.click('#checkbox-start');
await page.click('#datetime-end');
await page.waitFor(300);
compare = await page.compareScreenshot(
'should check checkbox and open datepicker'
);
expect(compare).toMatchScreenshot();
await page.click('#button-end');
await page.waitFor(100);
compare = await page.compareScreenshot('should change button color to red');
expect(compare).toMatchScreenshot();
});
const checkFormResult = async (page: E2EPage, content: string) => {

View File

@@ -22,69 +22,65 @@
<ion-content class="ion-padding-vertical">
<form onsubmit="return onSubmit(event)">
<ion-list class="basic">
<ion-item>
<ion-label>Simple item</ion-label>
</ion-item>
<ion-list>
<ion-item>
<ion-label>Simple item</ion-label>
</ion-item>
<ion-item id="item" button onclick="testClick(event)">
<ion-label>Item Button</ion-label>
</ion-item>
<ion-item id="item" button onclick="testClick(event)">
<ion-label>Item Button</ion-label>
</ion-item>
<ion-item>
<ion-label>DateTime</ion-label>
<ion-datetime name="date" id="datetime" min="1994-03-14" max="2017-12-09" display-format="MM/DD/YYYY"></ion-datetime>
</ion-item>
<ion-item>
<ion-label>DateTime</ion-label>
<ion-datetime name="date" id="datetime" min="1994-03-14" max="2017-12-09" display-format="MM/DD/YYYY"></ion-datetime>
</ion-item>
<ion-item>
<ion-label>Select</ion-label>
<ion-select name="select" id="select">
<ion-select-option value="">No Game Console</ion-select-option>
<ion-select-option value="nes">NES</ion-select-option>
<ion-select-option value="n64" selected>Nintendo64</ion-select-option>
<ion-select-option value="ps">PlayStation</ion-select-option>
<ion-select-option value="genesis">Sega Genesis</ion-select-option>
<ion-select-option value="saturn">Sega Saturn</ion-select-option>
<ion-select-option value="snes">SNES</ion-select-option>
</ion-select>
</ion-item>
<ion-item>
<ion-label>Select</ion-label>
<ion-select name="select" id="select">
<ion-select-option value="">No Game Console</ion-select-option>
<ion-select-option value="nes">NES</ion-select-option>
<ion-select-option value="n64" selected>Nintendo64</ion-select-option>
<ion-select-option value="ps">PlayStation</ion-select-option>
<ion-select-option value="genesis">Sega Genesis</ion-select-option>
<ion-select-option value="saturn">Sega Saturn</ion-select-option>
<ion-select-option value="snes">SNES</ion-select-option>
</ion-select>
</ion-item>
<ion-item>
<ion-label>Toggle</ion-label>
<ion-toggle name="toggle" id="toggle" name="Actually" slot="end"></ion-toggle>
</ion-item>
<ion-item>
<ion-label>Toggle</ion-label>
<ion-toggle name="toggle" id="toggle" name="Actually" slot="end"></ion-toggle>
</ion-item>
<ion-item>
<ion-label>Input (text)</ion-label>
<ion-input name="input" id="text"></ion-input>
</ion-item>
<ion-item>
<ion-label>Input (text)</ion-label>
<ion-input name="input" id="text"></ion-input>
</ion-item>
<ion-item>
<ion-label>Input (placeholder)</ion-label>
<ion-input name="input2" id="placeholder" placeholder="Placeholder"></ion-input>
</ion-item>
<ion-item>
<ion-label>Input (placeholder)</ion-label>
<ion-input name="input2" id="placeholder" placeholder="Placeholder"></ion-input>
</ion-item>
<ion-item>
<ion-label>Checkbox</ion-label>
<ion-checkbox name="checkbox" id="checkbox" slot="start"></ion-checkbox>
</ion-item>
<ion-item>
<ion-label>Checkbox</ion-label>
<ion-checkbox name="checkbox" id="checkbox" slot="start"></ion-checkbox>
</ion-item>
<ion-item>
<ion-label>Range</ion-label>
<ion-range name="range" id="range" value="10"></ion-range>
</ion-item>
</ion-list>
<ion-item>
<ion-label>Range</ion-label>
<ion-range name="range" id="range" value="10"></ion-range>
</ion-item>
</ion-list>
<ion-button id="submit" type="submit">Submit</ion-button>
<p id="form-result"></p>
</form>
<ion-button id="submit" type="submit">Submit</ion-button>
<p id="form-result"></p>
</form>
<ion-list>
<ion-list-header>
<ion-label>
Controls
</ion-label>
</ion-list-header>
<ion-list-header>Controls</ion-list-header>
<ion-item-divider>Value Controls</ion-item-divider>
<ion-item button onClick="toggleDisabled()" id="btnDisabled">
@@ -116,70 +112,14 @@
Fixed
</ion-item>
</ion-list>
<ion-list-header>
<ion-label>
Multiple inputs/clickables
</ion-label>
</ion-list-header>
<ion-list class="multiple">
<ion-item>
<ion-checkbox slot="start" id="checkbox-start"></ion-checkbox>
<ion-label>Multiple inputs w/ cover</ion-label>
<ion-datetime placeholder="startTime" display-format="HH:mm" id="datetime-end"></ion-datetime>
<ion-checkbox slot="end" id="checkbox-end"></ion-checkbox>
</ion-item>
<ion-item>
<ion-select slot="start" placeholder="month" id="select-start">
<ion-select-option value="1">January</ion-select-option>
<ion-select-option value="2">February</ion-select-option>
<ion-select-option value="3">March</ion-select-option>
</ion-select>
<ion-label>Input w/ clickable</ion-label>
<ion-button slot="end" id="button-end" onclick="setButtonColorRed()">Button</ion-button>
</ion-item>
<ion-item>
<ion-radio slot="start" id="radio-start"></ion-radio>
<ion-label>Input w/ cover + input</ion-label>
<ion-range value="45" id="range-end"></ion-range>
</ion-item>
<ion-item>
<ion-range value="60" id="range-start"></ion-range>
<ion-label>Multiple inputs w/o cover</ion-label>
<ion-toggle id="toggle-1-end"></ion-toggle>
<ion-toggle id="toggle-2-end"></ion-toggle>
</ion-item>
<ion-item button id="clickableItem">
<ion-label>Clickable item</ion-label>
<ion-checkbox slot="end"></ion-checkbox>
</ion-item>
<ion-item>
<ion-checkbox slot="start"></ion-checkbox>
<ion-label>Checkbox w/ disabled button</ion-label>
<ion-button slot="end" onclick="setButtonColorRed()" disabled>Button</ion-button>
</ion-item>
</ion-list>
</ion-content>
</ion-app>
<script>
var ids = ['item', 'datetime', 'select', 'toggle', 'text', 'placeholder', 'checkbox', 'toggle', 'range'];
var ids = ['item', 'datetime', 'select', 'toggle', 'text', 'placeholder', 'checkbox', 'toggle', 'range']
var isDisabled = false;
const clickableItem = document.querySelector('#clickableItem')
clickableItem.addEventListener('click', function() {
console.log('Clicked item', clickableItem);
const color = clickableItem.color;
clickableItem.color = color === undefined ? 'primary' : undefined;
});
function toggleDisabled() {
isDisabled = !isDisabled;
Object.values(getInputs()).forEach(el => el.disabled = isDisabled);
@@ -231,7 +171,7 @@
}
function setLabelPosition(position) {
Array.from(document.querySelectorAll('ion-list.basic ion-label'))
Array.from(document.querySelectorAll('ion-label'))
.forEach(label => label.position = position);
}
@@ -257,11 +197,6 @@
return false;
}
function setButtonColorRed() {
const button = document.getElementById('button-end');
button.style.setProperty('--background', '#ff0000');
}
</script>
</html>

View File

@@ -70,11 +70,7 @@
<!-- List Lines Full -->
<ion-list lines="full">
<ion-list-header>
<ion-label>
List Full Lines
</ion-label>
</ion-list-header>
<ion-list-header>List Full Lines</ion-list-header>
<ion-item>
<ion-label>Item</ion-label>
</ion-item>
@@ -88,9 +84,7 @@
<ion-list lines="inset">
<ion-list-header>
<ion-label>
List Inset Lines
</ion-label>
List Inset Lines
</ion-list-header>
<ion-item>
<ion-label>Item</ion-label>
@@ -105,9 +99,7 @@
<ion-list lines="none">
<ion-list-header>
<ion-label>
List No Lines
</ion-label>
List No Lines
</ion-list-header>
<ion-item>
<ion-label>Item</ion-label>
@@ -173,11 +165,7 @@
<!-- List Lines Full -->
<ion-list lines="full">
<ion-list-header>
<ion-label>
List Full Lines
</ion-label>
</ion-list-header>
<ion-list-header>List Full Lines</ion-list-header>
<ion-item color="light">
<ion-label>Item</ion-label>
</ion-item>
@@ -191,9 +179,7 @@
<ion-list lines="inset">
<ion-list-header>
<ion-label>
List Inset Lines
</ion-label>
List Inset Lines
</ion-list-header>
<ion-item color="dark">
<ion-label>Item</ion-label>
@@ -208,9 +194,7 @@
<ion-list lines="none">
<ion-list-header>
<ion-label>
List No Lines
</ion-label>
List No Lines
</ion-list-header>
<ion-item color="tertiary">
<ion-label>Item</ion-label>

View File

@@ -28,20 +28,12 @@
</ion-list>
<ion-list>
<ion-list-header>
<ion-label>
Start
</ion-label>
</ion-list-header>
<ion-list-header>start</ion-list-header>
<ion-reorder-group id="startGroup"></ion-reorder-group>
</ion-list>
<ion-list>
<ion-list-header>
<ion-label>
End
</ion-label>
</ion-list-header>
<ion-list-header>end</ion-list-header>
<ion-reorder-group id="endGroup"></ion-reorder-group>
</ion-list>
</ion-content>

View File

@@ -45,9 +45,9 @@
// --------------------------------------------------
::slotted(*) h1 {
@include margin(3px, 0, 2px);
@include margin(0, 0, 2px);
font-size: 22px;
font-size: 24px;
font-weight: normal;
}

View File

@@ -5,46 +5,17 @@
// --------------------------------------------------
:host {
--background: #{$list-header-ios-background-color};
--color: #{$list-header-ios-color};
--border-color: #{$item-ios-border-bottom-color};
--background: #{$list-ios-header-background-color};
--color: #{$list-ios-header-color};
@include padding-horizontal(calc(var(--ion-safe-area-left, 0px) + #{$list-header-ios-padding-start}), null);
@include padding-horizontal(calc(var(--ion-safe-area-left, 0px) + #{$list-ios-header-padding-start}), null);
position: relative;
align-items: flex-end;
font-size: $list-ios-header-font-size;
font-weight: $list-ios-header-font-weight;
font-size: $list-header-ios-font-size;
font-weight: $list-header-ios-font-weight;
letter-spacing: $list-ios-header-letter-spacing;
letter-spacing: $list-header-ios-letter-spacing;
}
// List Header: Slotted Components
// --------------------------------------------------
::slotted(ion-button),
::slotted(ion-label) {
@include margin(29px, null, 6px);
}
::slotted(ion-button) {
@include margin(null, 3px);
height: 1.4em;
}
// List Header Lines
// --------------------------------------------------
// Full lines - apply the border to the list header
// Inset lines - apply the border to the list header inner
:host(.list-header-lines-full) {
--border-width: #{0 0 $item-ios-border-bottom-width 0};
}
:host(.list-header-lines-inset) {
--inner-border-width: #{0 0 $item-ios-border-bottom-width 0};
text-transform: $list-ios-header-text-transform;
}

View File

@@ -4,20 +4,23 @@
// iOS List Header
// --------------------------------------------------
/// @prop - Padding start of the list header
$list-header-ios-padding-start: $item-ios-padding-start !default;
/// @prop - Padding start of the header in a list
$list-ios-header-padding-start: $item-ios-padding-start !default;
/// @prop - Font size of the list header
$list-header-ios-font-size: 22px !default;
/// @prop - Font size of the header in a list
$list-ios-header-font-size: 12px !default;
/// @prop - Font weight of the list header
$list-header-ios-font-weight: 700 !default;
/// @prop - Font weight of the header in a list
$list-ios-header-font-weight: 500 !default;
/// @prop - Letter spacing of the list header
$list-header-ios-letter-spacing: 0 !default;
/// @prop - Letter spacing of the header in a list
$list-ios-header-letter-spacing: 1px !default;
/// @prop - Text color of the list header
$list-header-ios-color: $text-color-step-150 !default;
/// @prop - Text transform of the header in a list
$list-ios-header-text-transform: uppercase !default;
/// @prop - Background color of the list header
$list-header-ios-background-color: transparent !default;
/// @prop - Text color of the header in a list
$list-ios-header-color: $text-color-step-150 !default;
/// @prop - Background color of the header in a list
$list-ios-header-background-color: transparent !default;

View File

@@ -6,25 +6,11 @@
:host {
--background: transparent;
--color: #{$list-header-md-color};
--border-color: #{$item-md-border-bottom-color};
--color: #{$list-md-header-color};
@include padding-horizontal(calc(var(--ion-safe-area-left, 0) + #{$list-header-md-padding-start}), null);
@include padding-horizontal(calc(var(--ion-safe-area-left, 0px) + #{$list-md-header-padding-start}), null);
min-height: $list-header-md-min-height;
min-height: $list-md-header-min-height;
font-size: $list-header-md-font-size;
}
// List Header Lines
// --------------------------------------------------
// Full lines - apply the border to the list header
// Inset lines - apply the border to the list header inner
:host(.list-header-lines-full) {
--border-width: #{0 0 $item-md-border-bottom-width 0};
}
:host(.list-header-lines-inset) {
--inner-border-width: #{0 0 $item-md-border-bottom-width 0};
font-size: $list-md-header-font-size;
}

View File

@@ -4,14 +4,14 @@
// Material Design List Header
// --------------------------------------------------
/// @prop - Padding start of the list header
$list-header-md-padding-start: $item-md-padding-start !default;
/// @prop - Padding start of the header in a list
$list-md-header-padding-start: $item-md-padding-start !default;
/// @prop - Minimum height of the list header
$list-header-md-min-height: 45px !default;
/// @prop - Minimum height of the header in a list
$list-md-header-min-height: 45px !default;
/// @prop - Font size of the list header
$list-header-md-font-size: 14px !default;
/// @prop - Font size of the header in a list
$list-md-header-font-size: 14px !default;
/// @prop - Text color of the list header
$list-header-md-color: $text-color !default;
/// @prop - Text color of the header in a list
$list-md-header-color: $text-color !default;

View File

@@ -8,16 +8,7 @@
/**
* @prop --background: Background of the list header
* @prop --color: Color of the list header text
*
* @prop --border-color: Color of the list header border
* @prop --border-width: Width of the list header border
* @prop --border-style: Style of the list header border
*
* @prop --inner-border-width: Width of the inner list header border
*/
--border-style: solid;
--border-width: 0;
--inner-border-width: 0;
@include font-smoothing();
@include margin(0);
@@ -31,10 +22,6 @@
width: 100%;
min-height: 40px;
border-width: var(--border-width);
border-style: var(--border-style);
border-color: var(--border-color);
background: var(--background);
color: var(--color);
@@ -45,47 +32,3 @@
background: current-color(base);
color: current-color(contrast);
}
// Inner List Header
// --------------------------------------------------
.list-header-inner {
display: flex;
// This is required to work with an inset highlight
position: relative;
flex: 1;
flex-direction: inherit;
align-items: inherit;
align-self: stretch;
min-height: inherit;
border-width: var(--inner-border-width);
border-style: var(--border-style);
border-color: var(--border-color);
overflow: inherit;
box-sizing: border-box;
}
::slotted(ion-label) {
flex: 1 1 auto;
}
// List Header Lines
// --------------------------------------------------
// Full lines - remove the border from the item inner (inset list items)
// Inset lines - remove the border on the item (full list items)
// No lines - remove the border on both (full / inset list items)
:host(.list-header-lines-inset),
:host(.list-header-lines-none) {
--border-width: 0;
}
:host(.list-header-lines-full),
:host(.list-header-lines-none) {
--inner-border-width: 0;
}

View File

@@ -24,26 +24,16 @@ export class ListHeader implements ComponentInterface {
*/
@Prop() color?: Color;
/**
* How the bottom border should be displayed on the list header.
*/
@Prop() lines?: 'full' | 'inset' | 'none';
render() {
const { lines } = this;
const mode = getIonMode(this);
return (
<Host
class={{
...createColorClasses(this.color),
[mode]: true,
[`list-header-lines-${lines}`]: lines !== undefined,
}}
>
<div class="list-header-inner">
<slot></slot>
</div>
<slot></slot>
</Host>
);
}

View File

@@ -51,23 +51,18 @@ export const ListHeaderExample: React.FC = () => (
## Properties
| Property | Attribute | Description | Type | Default |
| -------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | ----------- |
| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
| `lines` | `lines` | How the bottom border should be displayed on the list header. | `"full" \| "inset" \| "none" \| undefined` | `undefined` |
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
| Property | Attribute | Description | Type | Default |
| -------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | ----------- |
| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
## CSS Custom Properties
| Name | Description |
| ---------------------- | ------------------------------------- |
| `--background` | Background of the list header |
| `--border-color` | Color of the list header border |
| `--border-style` | Style of the list header border |
| `--border-width` | Width of the list header border |
| `--color` | Color of the list header text |
| `--inner-border-width` | Width of the inner list header border |
| Name | Description |
| -------------- | ----------------------------- |
| `--background` | Background of the list header |
| `--color` | Color of the list header text |
## Dependencies

View File

@@ -1,10 +0,0 @@
import { newE2EPage } from '@stencil/core/testing';
test('list-header: spec', async () => {
const page = await newE2EPage({
url: '/src/components/list-header/test/spec?ionic:_testing=true'
});
const compare = await page.compareScreenshot();
expect(compare).toMatchScreenshot();
});

View File

@@ -1,80 +0,0 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="UTF-8">
<title>List Header - Spec</title>
<meta name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet">
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet">
<script src="../../../../../scripts/testing/scripts.js"></script>
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
</head>
<body>
<ion-app>
<ion-header>
<ion-toolbar>
<ion-title>List Header - Spec</ion-title>
</ion-toolbar>
</ion-header>
<ion-content id="content">
<ion-list>
<ion-list-header lines="inset">
<ion-label>Recent</ion-label>
<ion-button>Clear</ion-button>
</ion-list-header>
<ion-item lines="none">
<ion-label color="primary">
<h1>I got you babe</h1>
</ion-label>
</ion-item>
</ion-list>
<ion-list>
<ion-list-header lines="inset">
<ion-label>Trending</ion-label>
</ion-list-header>
<ion-item>
<ion-label color="primary">
<h1>harry styles</h1>
</ion-label>
</ion-item>
<ion-item>
<ion-label color="primary">
<h1>christmas</h1>
</ion-label>
</ion-item>
<ion-item lines="none">
<ion-label color="primary">
<h1>falling</h1>
</ion-label>
</ion-item>
</ion-list>
<ion-list>
<ion-list-header>
<ion-label>New This Week</ion-label>
<ion-button>See All</ion-button>
</ion-list-header>
<ion-list-header lines="full">
<ion-label>New This Week</ion-label>
<ion-button>See All</ion-button>
</ion-list-header>
<ion-list-header lines="inset">
<ion-label>New This Week</ion-label>
<ion-button>See All</ion-button>
</ion-list-header>
</ion-list>
</ion-content>
</ion-app>
<style>
</style>
</body>
</html>

View File

@@ -11,7 +11,7 @@ $list-ios-margin-top: 10px !default;
$list-ios-margin-end: 0 !default;
/// @prop - Margin bottom of the list
$list-ios-margin-bottom: 0 !default;
$list-ios-margin-bottom: 32px !default;
/// @prop - Margin start of the list
$list-ios-margin-start: 0 !default;

View File

@@ -22,92 +22,64 @@
<ion-content>
<ion-list lines="full">
<ion-list-header>
<ion-label>
Lines: full
</ion-label>
</ion-list-header>
<ion-item><ion-label>Pokémon Yellow</ion-label></ion-item>
<ion-item><ion-label>Super Metroid</ion-label></ion-item>
<ion-item><ion-label>Mega Man X</ion-label></ion-item>
<ion-item><ion-label>The Legend of Zelda</ion-label></ion-item>
<ion-item><ion-label>Pac-Man</ion-label></ion-item>
<ion-list-header>Lines: full</ion-list-header>
<ion-item>Pokémon Yellow</ion-item>
<ion-item>Super Metroid</ion-item>
<ion-item>Mega Man X</ion-item>
<ion-item>The Legend of Zelda</ion-item>
<ion-item>Pac-Man</ion-item>
</ion-list>
<ion-list lines="inset">
<ion-list-header>
<ion-label>
Lines: inset
</ion-label>
</ion-list-header>
<ion-item><ion-label>Super Mario World</ion-label></ion-item>
<ion-item><ion-label>Street Fighter II</ion-label></ion-item>
<ion-item><ion-label>Half Life</ion-label></ion-item>
<ion-item><ion-label>Portal</ion-label></ion-item>
<ion-list-header>Lines: inset</ion-list-header>
<ion-item>Super Mario World</ion-item>
<ion-item>Street Fighter II</ion-item>
<ion-item>Half Life</ion-item>
<ion-item>Portal</ion-item>
</ion-list>
<ion-list lines="none">
<ion-list-header>
<ion-label>
Lines: none
</ion-label>
</ion-list-header>
<ion-item><ion-label>Star Fox</ion-label></ion-item>
<ion-item><ion-label>Tetris</ion-label></ion-item>
<ion-item><ion-label>Donkey Kong III</ion-label></ion-item>
<ion-item><ion-label>Goldeneye 007</ion-label></ion-item>
<ion-list-header>Lines: none</ion-list-header>
<ion-item>Star Fox</ion-item>
<ion-item>Tetris</ion-item>
<ion-item>Donkey Kong III</ion-item>
<ion-item>Goldeneye 007</ion-item>
</ion-list>
<ion-list>
<ion-list-header>
<ion-label>
Lines: Default
</ion-label>
</ion-list-header>
<ion-item><ion-label>Fallout</ion-label></ion-item>
<ion-item><ion-label>GTA</ion-label></ion-item>
<ion-item><ion-label>Halo</ion-label></ion-item>
<ion-item><ion-label>Doom</ion-label></ion-item>
<ion-item><ion-label>Final Fantasy VII</ion-label></ion-item>
<ion-list-header>Lines: Default</ion-list-header>
<ion-item>Fallout</ion-item>
<ion-item>GTA</ion-item>
<ion-item>Halo</ion-item>
<ion-item>Doom</ion-item>
<ion-item>Final Fantasy VII</ion-item>
</ion-list>
<ion-list>
<ion-list-header>
<ion-label>
Wrapper item: default
</ion-label>
</ion-list-header>
<div><ion-item><ion-label>Pokémon Yellow</ion-item></ion-label></div>
<div><ion-item><ion-label>Super Metroid</ion-item></ion-label></div>
<div><ion-item><ion-label>Mega Man X</ion-item></ion-label></div>
<div><ion-item><ion-label>The Legend of Zelda</ion-item></ion-label></div>
<div><ion-item><ion-label>Pac-Man</ion-item></ion-label></div>
<ion-list-header>Wrapper item: default</ion-list-header>
<div><ion-item>Pokémon Yellow</ion-item></div>
<div><ion-item>Super Metroid</ion-item></div>
<div><ion-item>Mega Man X</ion-item></div>
<div><ion-item>The Legend of Zelda</ion-item></div>
<div><ion-item>Pac-Man</ion-item></div>
</ion-list>
<ion-list lines="none">
<ion-list-header>
<ion-label>
Wrapper list lines: none
</ion-label>
</ion-list-header>
<div><ion-item><ion-label>Pokémon Yellow</ion-item></ion-label></div>
<div><ion-item><ion-label>Super Metroid</ion-item></ion-label></div>
<div><ion-item><ion-label>Mega Man X</ion-item></ion-label></div>
<div><ion-item><ion-label>The Legend of Zelda</ion-item></ion-label></div>
<div><ion-item><ion-label>Pac-Man</ion-item></ion-label></div>
<ion-list-header>Wrapper list lines: none</ion-list-header>
<div><ion-item>Pokémon Yellow</ion-item></div>
<div><ion-item>Super Metroid</ion-item></div>
<div><ion-item>Mega Man X</ion-item></div>
<div><ion-item>The Legend of Zelda</ion-item></div>
<div><ion-item>Pac-Man</ion-item></div>
</ion-list>
<ion-list>
<ion-list-header>
<ion-label>
Wrapper w/ item lines: none
</ion-label>
</ion-list-header>
<div><ion-item lines="none"><ion-label>Pokémon Yellow</ion-label></ion-item></div>
<div><ion-item lines="none"><ion-label>Super Metroid</ion-label></ion-item></div>
<div><ion-item lines="none"><ion-label>Mega Man X</ion-label></ion-item></div>
<div><ion-item lines="none"><ion-label>The Legend of Zelda</ion-label></ion-item></div>
<div><ion-item lines="none"><ion-label>Pac-Man</ion-label></ion-item></div>
<ion-list-header>Wrapper w/ item lines: none</ion-list-header>
<div><ion-item lines="none">Pokémon Yellow</ion-item></div>
<div><ion-item lines="none">Super Metroid</ion-item></div>
<div><ion-item lines="none">Mega Man X</ion-item></div>
<div><ion-item lines="none">The Legend of Zelda</ion-item></div>
<div><ion-item lines="none">Pac-Man</ion-item></div>
</ion-list>
</ion-content>

View File

@@ -2,7 +2,7 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Meth
import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import { AnimationBuilder, OverlayEventDetail, OverlayInterface, SpinnerTypes } from '../../interface';
import { Animation, AnimationBuilder, OverlayEventDetail, OverlayInterface, SpinnerTypes } from '../../interface';
import { BACKDROP, dismiss, eventMethod, prepareOverlay, present } from '../../utils/overlays';
import { sanitizeDOMString } from '../../utils/sanitization';
import { getClassMap } from '../../utils/theme';
@@ -27,6 +27,7 @@ export class Loading implements ComponentInterface, OverlayInterface {
private durationTimeout: any;
presented = false;
animation?: Animation;
mode = getIonMode(this);
@Element() el!: HTMLIonLoadingElement;

View File

@@ -64,7 +64,7 @@ export class MenuButton implements ComponentInterface, ButtonInterface {
render() {
const { color, disabled } = this;
const mode = getIonMode(this);
const menuIcon = config.get('menuIcon', mode === 'ios' ? 'menu-outline' : 'menu-sharp');
const menuIcon = config.get('menuIcon', 'menu');
const hidden = this.autoHide && !this.visible;
const attrs = {

View File

@@ -1,53 +1,90 @@
import { Animation } from '../../../interface';
import { createAnimation } from '../../../utils/animation/animation';
import { SwipeToCloseDefaults } from '../gestures/swipe-to-close';
/**
* iOS Modal Enter Animation for the Card presentation style
* iOS Modal Enter Animation
*/
export const iosEnterAnimation = (
baseEl: HTMLElement,
presentingEl?: HTMLElement,
): Animation => {
// The top translate Y for the presenting element
const backdropAnimation = createAnimation()
export const iosEnterAnimation = (baseEl: HTMLElement): Animation => {
const baseAnimation = createAnimation();
const backdropAnimation = createAnimation();
const wrapperAnimation = createAnimation();
backdropAnimation
.addElement(baseEl.querySelector('ion-backdrop')!)
.fromTo('opacity', 0.01, 'var(--backdrop-opacity)');
const wrapperAnimation = createAnimation()
wrapperAnimation
.addElement(baseEl.querySelector('.modal-wrapper')!)
.beforeStyles({ 'opacity': 1 })
.fromTo('transform', 'translateY(100%)', 'translateY(0%)');
const baseAnimation = createAnimation()
return baseAnimation
.addElement(baseEl)
.easing('cubic-bezier(0.32,0.72,0,1)')
.duration(500)
.easing('cubic-bezier(0.36,0.66,0.04,1)')
.duration(400)
.beforeAddClass('show-modal')
.addAnimation([backdropAnimation, wrapperAnimation]);
if (presentingEl) {
const modalTransform = (presentingEl.tagName === 'ION-MODAL' && (presentingEl as HTMLIonModalElement).presentingElement !== undefined) ? 40 : 0;
const bodyEl = document.body;
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
const finalTransform = `translateY(${-modalTransform}px) scale(${toPresentingScale})`;
const presentingAnimation = createAnimation()
.beforeStyles({
'transform': 'translateY(0)'
})
.afterStyles({
'transform': finalTransform
})
.beforeAddWrite(() => bodyEl.style.setProperty('background-color', 'black'))
.addElement(presentingEl)
.keyframes([
{ offset: 0, transform: 'translateY(0px) scale(1)', 'border-radius': '0px' },
{ offset: 1, transform: finalTransform, 'border-radius': '10px 10px 0 0' }
]);
baseAnimation.addAnimation(presentingAnimation);
}
return baseAnimation;
};
/**
* Animations for modals
*/
// export function modalSlideIn(rootEl: HTMLElement) {
// }
// export class ModalSlideOut {
// constructor(el: HTMLElement) {
// let backdrop = new Animation(this.plt, el.querySelector('ion-backdrop'));
// let wrapperEle = <HTMLElement>el.querySelector('.modal-wrapper');
// let wrapperEleRect = wrapperEle.getBoundingClientRect();
// let wrapper = new Animation(this.plt, wrapperEle);
// // height of the screen - top of the container tells us how much to scoot it down
// // so it's off-screen
// wrapper.fromTo('translateY', '0px', `${this.plt.height() - wrapperEleRect.top}px`);
// backdrop.fromTo('opacity', 0.4, 0.0);
// this
// .element(this.leavingView.pageRef())
// .easing('ease-out')
// .duration(250)
// .add(backdrop)
// .add(wrapper);
// }
// }
// export class ModalMDSlideIn {
// constructor(el: HTMLElement) {
// const backdrop = new Animation(this.plt, el.querySelector('ion-backdrop'));
// const wrapper = new Animation(this.plt, el.querySelector('.modal-wrapper'));
// backdrop.fromTo('opacity', 0.01, 0.4);
// wrapper.fromTo('translateY', '40px', '0px');
// wrapper.fromTo('opacity', 0.01, 1);
// const DURATION = 280;
// const EASING = 'cubic-bezier(0.36,0.66,0.04,1)';
// this.element(this.enteringView.pageRef()).easing(EASING).duration(DURATION)
// .add(backdrop)
// .add(wrapper);
// }
// }
// export class ModalMDSlideOut {
// constructor(el: HTMLElement) {
// const backdrop = new Animation(this.plt, el.querySelector('ion-backdrop'));
// const wrapper = new Animation(this.plt, el.querySelector('.modal-wrapper'));
// backdrop.fromTo('opacity', 0.4, 0.0);
// wrapper.fromTo('translateY', '0px', '40px');
// wrapper.fromTo('opacity', 0.99, 0);
// this
// .element(this.leavingView.pageRef())
// .duration(200)
// .easing('cubic-bezier(0.47,0,0.745,0.715)')
// .add(wrapper)
// .add(backdrop);
// }
// }

View File

@@ -1,55 +1,28 @@
import { Animation } from '../../../interface';
import { createAnimation } from '../../../utils/animation/animation';
import { SwipeToCloseDefaults } from '../gestures/swipe-to-close';
/**
* iOS Modal Leave Animation
*/
export const iosLeaveAnimation = (
baseEl: HTMLElement,
presentingEl?: HTMLElement,
duration = 500
): Animation => {
export const iosLeaveAnimation = (baseEl: HTMLElement): Animation => {
const baseAnimation = createAnimation();
const backdropAnimation = createAnimation();
const wrapperAnimation = createAnimation();
const wrapperEl = baseEl.querySelector('.modal-wrapper');
const wrapperElRect = wrapperEl!.getBoundingClientRect();
const backdropAnimation = createAnimation()
backdropAnimation
.addElement(baseEl.querySelector('ion-backdrop')!)
.fromTo('opacity', 'var(--backdrop-opacity)', 0.0);
const wrapperAnimation = createAnimation()
.addElement(baseEl.querySelector('.modal-wrapper')!)
wrapperAnimation
.addElement(wrapperEl!)
.beforeStyles({ 'opacity': 1 })
.fromTo('transform', `translateY(0%)`, 'translateY(100%)');
.fromTo('transform', 'translateY(0%)', `translateY(${(baseEl.ownerDocument as any).defaultView.innerHeight - wrapperElRect.top}px)`);
const baseAnimation = createAnimation()
return baseAnimation
.addElement(baseEl)
.easing('cubic-bezier(0.32,0.72,0,1)')
.duration(duration)
.easing('ease-out')
.duration(250)
.addAnimation([backdropAnimation, wrapperAnimation]);
if (presentingEl) {
const modalTransform = (presentingEl.tagName === 'ION-MODAL' && (presentingEl as HTMLIonModalElement).presentingElement !== undefined) ? 40 : 0;
const bodyEl = document.body;
const currentPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
const presentingAnimation = createAnimation()
.addElement(presentingEl)
.beforeClearStyles(['transform'])
.afterClearStyles(['transform'])
.onFinish(currentStep => {
// only reset background color if this is the last card-style modal
if (currentStep !== 1) { return; }
const numModals = Array.from(bodyEl.querySelectorAll('ion-modal')).filter(m => m.presentingElement !== undefined).length;
if (numModals <= 1) {
bodyEl.style.setProperty('background-color', '');
}
})
.keyframes([
{ offset: 0, transform: `translateY(${-modalTransform}px) scale(${currentPresentingScale})`, 'border-radius': '10px 10px 0 0' },
{ offset: 1, transform: 'translateY(0px) scale(1)', 'border-radius': '0px' }
]);
baseAnimation.addAnimation(presentingAnimation);
}
return baseAnimation;
};

View File

@@ -1,97 +0,0 @@
import { Animation } from '../../../interface';
import { getTimeGivenProgression } from '../../../utils/animation/cubic-bezier';
import { GestureDetail, createGesture } from '../../../utils/gesture';
import { clamp } from '../../../utils/helpers';
// Defaults for the card swipe animation
export const SwipeToCloseDefaults = {
MIN_BACKDROP_OPACITY: 0.4,
MIN_PRESENTING_SCALE: 0.95,
MIN_Y_CARD: 44,
MIN_Y_FULLSCREEN: 0,
MIN_PRESENTING_Y: 0
};
export const createSwipeToCloseGesture = (
el: HTMLIonModalElement,
animation: Animation,
onDismiss: () => void
) => {
const height = el.offsetHeight;
let isOpen = false;
const canStart = (detail: GestureDetail) => {
const target = detail.event.target as HTMLElement | null;
if (target === null ||
!(target as any).closest) {
return true;
}
const content = target.closest('ion-content');
if (content === null) {
return true;
}
// Target is in the content so we don't start the gesture.
// We could be more nuanced here and allow it for content that
// does not need to scroll.
return false;
};
const onStart = () => {
animation.progressStart(true, (isOpen) ? 1 : 0);
};
const onMove = (detail: GestureDetail) => {
const step = detail.deltaY / height;
if (step < 0) { return; }
animation.progressStep(step);
};
const onEnd = (detail: GestureDetail) => {
const velocity = detail.velocityY;
const step = detail.deltaY / height;
if (step < 0) { return; }
const threshold = (detail.deltaY + velocity * 1000) / height;
const shouldComplete = threshold >= 0.5;
let newStepValue = (shouldComplete) ? -0.001 : 0.001;
if (!shouldComplete) {
animation.easing('cubic-bezier(1, 0, 0.68, 0.28)');
newStepValue += getTimeGivenProgression([0, 0], [1, 0], [0.68, 0.28], [1, 1], step)[0];
} else {
animation.easing('cubic-bezier(0.32, 0.72, 0, 1)');
newStepValue += getTimeGivenProgression([0, 0], [0.32, 0.72], [0, 1], [1, 1], step)[0];
}
const duration = (shouldComplete) ? computeDuration(step * height, velocity) : computeDuration((1 - step) * height, velocity);
isOpen = shouldComplete;
animation
.onFinish(() => {
if (shouldComplete) {
onDismiss();
}
})
.progressEnd((shouldComplete) ? 1 : 0, newStepValue, duration);
};
return createGesture({
el,
gestureName: 'modalSwipeToClose',
gesturePriority: 40,
direction: 'y',
threshold: 10,
canStart,
onStart,
onMove,
onEnd
});
};
const computeDuration = (remaining: number, velocity: number) => {
return clamp(100, remaining / Math.abs(velocity * 1.1), 400);
};

View File

@@ -3,13 +3,11 @@ import { AnimationBuilder, ComponentProps, ComponentRef, FrameworkDelegate, Mode
export interface ModalOptions<T extends ComponentRef = ComponentRef> {
component: T;
componentProps?: ComponentProps<T>;
presentingElement?: HTMLElement;
showBackdrop?: boolean;
backdropDismiss?: boolean;
cssClass?: string | string[];
delegate?: FrameworkDelegate;
animated?: boolean;
swipeToClose?: boolean;
mode?: Mode;
keyboardClose?: boolean;

View File

@@ -18,12 +18,3 @@
// hidden by default to prevent flickers, the animation will show it
@include transform(translate3d(0, 100%, 0));
}
:host(.modal-card) {
align-items: flex-end;
}
:host(.modal-card) .modal-wrapper {
@include border-radius($modal-ios-border-radius, $modal-ios-border-radius, 0, 0);
height: calc(100% - 40px);
}

View File

@@ -8,5 +8,3 @@ $modal-ios-background-color: $background-color !default;
/// @prop - Border radius for the modal
$modal-ios-border-radius: 10px !default;
$modal-ios-card-border-radius: 10px !default;

View File

@@ -20,4 +20,4 @@
@include transform(translate3d(0, 40px, 0));
opacity: .01;
}
}

View File

@@ -1,9 +1,9 @@
import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Method, Prop, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { Animation, AnimationBuilder, ComponentProps, ComponentRef, FrameworkDelegate, Gesture, OverlayEventDetail, OverlayInterface } from '../../interface';
import { Animation, AnimationBuilder, ComponentProps, ComponentRef, FrameworkDelegate, OverlayEventDetail, OverlayInterface } from '../../interface';
import { attachComponent, detachComponent } from '../../utils/framework-delegate';
import { BACKDROP, activeAnimations, dismiss, eventMethod, prepareOverlay, present } from '../../utils/overlays';
import { BACKDROP, dismiss, eventMethod, prepareOverlay, present } from '../../utils/overlays';
import { getClassMap } from '../../utils/theme';
import { deepReady } from '../../utils/transition';
@@ -11,7 +11,6 @@ import { iosEnterAnimation } from './animations/ios.enter';
import { iosLeaveAnimation } from './animations/ios.leave';
import { mdEnterAnimation } from './animations/md.enter';
import { mdLeaveAnimation } from './animations/md.leave';
import { createSwipeToCloseGesture } from './gestures/swipe-to-close';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
@@ -25,13 +24,11 @@ import { createSwipeToCloseGesture } from './gestures/swipe-to-close';
scoped: true
})
export class Modal implements ComponentInterface, OverlayInterface {
private gesture?: Gesture;
// Reference to the user's provided modal content
private usersElement?: HTMLElement;
presented = false;
animation?: Animation;
animation: Animation | undefined;
mode = getIonMode(this);
@Element() el!: HTMLIonModalElement;
@@ -88,17 +85,6 @@ export class Modal implements ComponentInterface, OverlayInterface {
*/
@Prop() animated = true;
/**
* If `true`, the modal can be swiped to dismiss. Only applies in iOS mode.
*/
@Prop() swipeToClose = false;
/**
* The element that presented the modal. This is used for card presentation effects
* and for stacking multiple modals on top of each other. Only applies in iOS mode.
*/
@Prop() presentingElement?: HTMLElement;
/**
* Emitted after the modal has presented.
*/
@@ -141,21 +127,7 @@ export class Modal implements ComponentInterface, OverlayInterface {
};
this.usersElement = await attachComponent(this.delegate, container, this.component, ['ion-page'], componentProps);
await deepReady(this.usersElement);
await present(this, 'modalEnter', iosEnterAnimation, mdEnterAnimation, this.presentingElement);
const mode = getIonMode(this);
if (this.swipeToClose && mode === 'ios') {
// All of the elements needed for the swipe gesture
// should be in the DOM and referenced by now, except
// for the presenting el
const ani = this.animation = iosLeaveAnimation(this.el, this.presentingElement);
this.gesture = createSwipeToCloseGesture(
this.el,
ani,
() => this.dismiss(undefined, 'gesture')
);
this.gesture.enable(true);
}
return present(this, 'modalEnter', iosEnterAnimation, mdEnterAnimation);
}
/**
@@ -166,21 +138,10 @@ export class Modal implements ComponentInterface, OverlayInterface {
*/
@Method()
async dismiss(data?: any, role?: string): Promise<boolean> {
const iosAni = (this.animation === undefined || (role === BACKDROP || role === undefined)) ? iosLeaveAnimation : undefined;
const enteringAnimation = activeAnimations.get(this) || [];
const dismissed = await dismiss(this, data, role, 'modalLeave', iosAni, mdLeaveAnimation, this.presentingElement);
const dismissed = await dismiss(this, data, role, 'modalLeave', iosLeaveAnimation, mdLeaveAnimation);
if (dismissed) {
await detachComponent(this.delegate, this.usersElement);
if (this.animation) {
this.animation.destroy();
}
enteringAnimation.forEach(ani => ani.destroy());
}
this.animation = undefined;
return dismissed;
}
@@ -233,7 +194,6 @@ export class Modal implements ComponentInterface, OverlayInterface {
aria-modal="true"
class={{
[mode]: true,
[`modal-card`]: this.presentingElement !== undefined,
...getClassMap(this.cssClass)
}}
style={{
@@ -249,7 +209,10 @@ export class Modal implements ComponentInterface, OverlayInterface {
<ion-backdrop visible={this.showBackdrop} tappable={this.backdropDismiss}/>
<div
role="dialog"
class="modal-wrapper"
class={{
[`modal-wrapper`]: true,
[mode]: true,
}}
>
</div>
</Host>

View File

@@ -153,42 +153,6 @@ import { EventModalModule } from '../modals/event/event.module';
export class CalendarComponentModule {}
```
### Swipeable Modals
Modals in iOS mode have the ability to be presented in a card-style and swiped to close. The card-style presentation and swipe to close gesture are not mutually exclusive, meaning you can pick and choose which features you want to use. For example, you can have a card-style modal that cannot be swiped or a full sized modal that can be swiped.
```javascript
import { IonRouterOutlet } from '@ionic/angular';
constructor(private routerOutlet: IonRouterOutlet) {}
async presentModal() {
const modal = await this.modalController.create({
component: ModalPage,
swipeToClose: true,
presentingElement: this.routerOutlet.nativeEl
});
return await modal.present();
}
```
In most scenarios, using the `ion-router-outlet` element as the `presentingElement` is fine. In cases where you are presenting a card-style modal from within another modal, you should pass in the top-most `ion-modal` element as the `presentingElement`.
```javascript
import { ModalController } from '@ionic/angular';
constructor(private modalCtrl: ModalController) {}
async presentModal() {
const modal = await this.modalController.create({
component: ModalPage,
swipeToClose: true,
presentingElement: await this.modalCtrl.getTop() // Get the top-most ion-modal
});
return await modal.present();
}
```
### Javascript
@@ -271,27 +235,6 @@ console.log(data);
```
### Swipeable Modals
Modals in iOS mode have the ability to be presented in a card-style and swiped to close. The card-style presentation and swipe to close gesture are not mutually exclusive, meaning you can pick and choose which features you want to use. For example, you can have a card-style modal that cannot be swiped or a full sized modal that can be swiped.
```javascript
const modalElement = document.createElement('ion-modal');
modalElement.component = 'modal-page';
modalElement.swipeToClose = true;
modalElement.presentingElement = document.querySelector('ion-nav');
```
In most scenarios, using the `ion-nav` element as the `presentingElement` is fine. In cases where you are presenting a card-style modal from within a modal, you should pass in the top-most `ion-modal` element as the `presentingElement`.
```javascript
const modalElement = document.createElement('ion-modal');
modalElement.component = 'modal-page';
modalElement.swipeToClose = true;
modalElement.presentingElement = await modalController.getTop(); // Get the top-most ion-modal
```
### React
```tsx
@@ -313,43 +256,6 @@ export const ModalExample: React.FC = () => {
};
```
### Swipeable Modals
Modals in iOS mode have the ability to be presented in a card-style and swiped to close. The card-style presentation and swipe to close gesture are not mutually exclusive, meaning you can pick and choose which features you want to use. For example, you can have a card-style modal that cannot be swiped or a full sized modal that can be swiped.
```tsx
<IonModal
isOpen={showModal}
swipeToClose={true}
presentingElement={pageRef.current}
onDidDismiss={() => setShowModal(false)}>
<p>This is modal content</p>
<IonButton onClick={() => setShowModal(false)}>Close Modal</IonButton>
</IonModal>
```
In most scenarios, setting a ref on `IonPage` and passing that ref's `current` value to `presentingElement` is fine. In cases where you are presenting a card-style modal from within another modal, you should pass in the top-most `ion-modal` ref as the `presentingElement`.
```tsx
<IonModal
ref={firstModalRef}
isOpen={showModal}
swipeToClose={true}
presentingElement={pageRef.current}
onDidDismiss={() => setShowModal(false)}>
<p>This is modal content</p>
<IonButton onClick={() => setShow2ndModal(true)}>Show 2nd Modal</IonButton>
<IonButton onClick={() => setShowModal(false)}>Close Modal</IonButton>
</IonModal>
<IonModal
isOpen={show2ndModal}
presentingElement={firstModalRef.current}
onDidDismiss={() => setShow2ndModal(false)}>
<p>This is more modal content</p>
<IonButton onClick={() => setShow2ndModal(false)}>Close Modal</IonButton>
</IonModal>
```
### Vue
@@ -420,20 +326,18 @@ export default {
## Properties
| Property | Attribute | Description | Type | Default |
| ------------------------ | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----------- |
| `animated` | `animated` | If `true`, the modal will animate. | `boolean` | `true` |
| `backdropDismiss` | `backdrop-dismiss` | If `true`, the modal will be dismissed when the backdrop is clicked. | `boolean` | `true` |
| `component` _(required)_ | `component` | The component to display inside of the modal. | `Function \| HTMLElement \| null \| string` | `undefined` |
| `componentProps` | -- | The data to pass to the modal component. | `undefined \| { [key: string]: any; }` | `undefined` |
| `cssClass` | `css-class` | Additional classes to apply for custom CSS. If multiple classes are provided they should be separated by spaces. | `string \| string[] \| undefined` | `undefined` |
| `enterAnimation` | -- | Animation to use when the modal is presented. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
| `keyboardClose` | `keyboard-close` | If `true`, the keyboard will be automatically dismissed when the overlay is presented. | `boolean` | `true` |
| `leaveAnimation` | -- | Animation to use when the modal is dismissed. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
| `presentingElement` | -- | The element that presented the modal. This is used for card presentation effects and for stacking multiple modals on top of each other. Only applies in iOS mode. | `HTMLElement \| undefined` | `undefined` |
| `showBackdrop` | `show-backdrop` | If `true`, a backdrop will be displayed behind the modal. | `boolean` | `true` |
| `swipeToClose` | `swipe-to-close` | If `true`, the modal can be swiped to dismiss. Only applies in iOS mode. | `boolean` | `false` |
| Property | Attribute | Description | Type | Default |
| ------------------------ | ------------------ | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----------- |
| `animated` | `animated` | If `true`, the modal will animate. | `boolean` | `true` |
| `backdropDismiss` | `backdrop-dismiss` | If `true`, the modal will be dismissed when the backdrop is clicked. | `boolean` | `true` |
| `component` _(required)_ | `component` | The component to display inside of the modal. | `Function \| HTMLElement \| null \| string` | `undefined` |
| `componentProps` | -- | The data to pass to the modal component. | `undefined \| { [key: string]: any; }` | `undefined` |
| `cssClass` | `css-class` | Additional classes to apply for custom CSS. If multiple classes are provided they should be separated by spaces. | `string \| string[] \| undefined` | `undefined` |
| `enterAnimation` | -- | Animation to use when the modal is presented. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
| `keyboardClose` | `keyboard-close` | If `true`, the keyboard will be automatically dismissed when the overlay is presented. | `boolean` | `true` |
| `leaveAnimation` | -- | Animation to use when the modal is dismissed. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
| `showBackdrop` | `show-backdrop` | If `true`, a backdrop will be displayed behind the modal. | `boolean` | `true` |
## Events

View File

@@ -23,26 +23,23 @@
<body>
<ion-app>
<div class="ion-page">
<ion-header>
<ion-toolbar>
<ion-title>Modal - Basic</ion-title>
</ion-toolbar>
</ion-header>
<ion-header>
<ion-toolbar>
<ion-title>Modal - Basic</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<p>
<ion-button id="basic-modal" onclick="presentModal()">Present modal</ion-button>
</p>
<p>
<ion-button id="presentModal" class="e2ePresentModal" onclick="presentCloseModal()">Present and close modal</ion-button>
</p>
<p>
<ion-button id="presentModal" class="e2ePresentModal" onclick="presentCloseModal2()">Present and close modal (crash)</ion-button>
</p>
</ion-content>
</div>
<ion-modal-controller></ion-modal-controller>
<ion-content class="ion-padding">
<p>
<ion-button id="basic-modal" onclick="presentModal()">Present modal</ion-button>
</p>
<p>
<ion-button id="presentModal" class="e2ePresentModal" onclick="presentCloseModal()">Present and close modal</ion-button>
</p>
<p>
<ion-button id="presentModal" class="e2ePresentModal" onclick="presentCloseModal2()">Present and close modal (crash)</ion-button>
</p>
</ion-content>
</ion-app>
@@ -80,9 +77,8 @@
}
async function presentModal() {
const presentingEl = document.querySelectorAll('.ion-page')[1];
const modal = createModal();
await modal.present(presentingEl);
await modal.present();
}
async function presentCloseModal() {
const modal = createModal();

View File

@@ -1,11 +0,0 @@
import { testModal } from '../test.utils';
const DIRECTORY = 'spec';
test('modal: card', async () => {
await testModal(DIRECTORY, '#card-modal');
});
test('modal:rtl: card', async () => {
await testModal(DIRECTORY, '#card-modal', true);
});

View File

@@ -1,478 +0,0 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="UTF-8">
<title>Modal - Spec</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet">
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet">
<script src="../../../../../scripts/testing/scripts.js"></script>
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
<style>
:root {
--ion-safe-area-top: 20px;
--ion-safe-area-bottom: 20px;
}
#modal-header {
padding-top: 5px !important;
height: 55px;
}
#modal-header ion-title {
padding-top: 5px;
}
#modal-header ion-note {
display: block;
width: 100%;
height: 15px;
text-align: center;
font-size: 11px;
color: #111;
}
ion-list ion-icon {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<ion-app>
<div class="ion-page">
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-button id="card-modal" onclick="presentModal(document.querySelectorAll('.ion-page')[1])">
<ion-icon name="add" slot="icon-only"></ion-icon>
</ion-button>
</ion-buttons>
<ion-title>Favorites</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list id="list"></ion-list>
</ion-content>
</div>
<ion-modal-controller></ion-modal-controller>
</ion-app>
<script>
window.addEventListener("ionModalDidDismiss", function (e) { console.log('DidDismiss', e) })
window.addEventListener("ionModalWillDismiss", function (e) { console.log('WillDismiss', e) })
const people = [
{
"name": "Miyah Myles",
"email": "miyah.myles@gmail.com",
"position": "Business Analyst",
},
{
"name": "June Cha",
"email": "june.cha@gmail.com",
"position": "Data Entry Clerk",
},
{
"name": "Iida Niskanen",
"email": "iida.niskanen@gmail.com",
"position": "Business Analyst",
},
{
"name": "Renee Sims",
"email": "renee.sims@gmail.com",
"position": "Lead Developer",
},
{
"name": "Jonathan Nu\u00f1ez",
"email": "jonathan.nu\u00f1ez@gmail.com",
"position": "Receptionist",
},
{
"name": "Sasha Ho",
"email": "sasha.ho@gmail.com",
"position": "Sales",
},
{
"name": "Abdullah Hadley",
"email": "abdullah.hadley@gmail.com",
"position": "Sales Manager",
},
{
"name": "Veeti Seppanen",
"email": "veeti.seppanen@gmail.com",
"position": "Marketing",
},
{
"name": "Thomas Stock",
"email": "thomas.stock@gmail.com",
"position": "Clerical",
},
{
"name": "Bonnie Riley",
"email": "bonnie.riley@gmail.com",
"position": "Medical Assistant",
}
];
const allContacts = [
{
"name": "Miyah Myles",
"email": "miyah.myles@gmail.com",
"position": "Office Assistant",
},
{
"name": "June Cha",
"email": "june.cha@gmail.com",
"position": "Administrative Assistant",
},
{
"name": "Iida Niskanen",
"email": "iida.niskanen@gmail.com",
"position": "Customer Service Representative",
},
{
"name": "Renee Sims",
"email": "renee.sims@gmail.com",
"position": "Customer Service Representative",
},
{
"name": "Jonathan Nu\u00f1ez",
"email": "jonathan.nu\u00f1ez@gmail.com",
"position": "Sales",
},
{
"name": "Sasha Ho",
"email": "sasha.ho@gmail.com",
"position": "Marketing",
},
{
"name": "Abdullah Hadley",
"email": "abdullah.hadley@gmail.com",
"position": "Marketing",
},
{
"name": "Veeti Seppanen",
"email": "veeti.seppanen@gmail.com",
"position": "Project Manager",
},
{
"name": "Thomas Stock",
"email": "thomas.stock@gmail.com",
"position": "Customer Service",
},
{
"name": "Bonnie Riley",
"email": "bonnie.riley@gmail.com",
"position": "Executive Assistant",
},
{
"name": "Steve T. Scaife",
"email": "steve.t..scaife@gmail.com",
"position": "Receptionist",
},
{
"name": "Andreas Brixen",
"email": "andreas.brixen@gmail.com",
"position": "Director",
},
{
"name": "Lilja Peltola",
"email": "lilja.peltola@gmail.com",
"position": "Sales Manager",
},
{
"name": "Sean PJPGR Doran",
"email": "sean.pjpgr.doran@gmail.com",
"position": "Lead Developer",
},
{
"name": "Elliana Palacios",
"email": "elliana.palacios@gmail.com",
"position": "Marketing",
},
{
"name": "Eduard Franz",
"email": "eduard.franz@gmail.com",
"position": "Manager",
},
{
"name": "Leah Stevens",
"email": "leah.stevens@gmail.com",
"position": "Attorney",
},
{
"name": "Britney Cooper",
"email": "britney.cooper@gmail.com",
"position": "Data Entry Clerk",
},
{
"name": "Chrishell Stause",
"email": "chrishell.stause@gmail.com",
"position": "Receptionist",
},
{
"name": "Ana De Armas",
"email": "ana.de.armas@gmail.com",
"position": "Administrative Assistant",
},
{
"name": "Jennifer Fritz",
"email": "jennifer.fritz@gmail.com",
"position": "Graphic Designer",
},
{
"name": "Wyatt Morris",
"email": "wyatt.morris@gmail.com",
"position": "Executive Assistant",
},
{
"name": "Lourdes Browning",
"email": "lourdes.browning@gmail.com",
"position": "Sales",
},
{
"name": "Tim Schoch",
"email": "tim.schoch@gmail.com",
"position": "Product Designer",
},
{
"name": "Nykyta Korotkevych",
"email": "nykyta.korotkevych@gmail.com",
"position": "Lead Developer",
},
{
"name": "Carys Metz",
"email": "carys.metz@gmail.com",
"position": "Administrative Assistant",
},
{
"name": "Loki Bright",
"email": "loki.bright@gmail.com",
"position": "Data Entry",
},
{
"name": "Ferdinand Karl",
"email": "ferdinand.karl@gmail.com",
"position": "Medical Assistant",
},
{
"name": "Andrew Kumar",
"email": "andrew.kumar@gmail.com",
"position": "Accounting",
},
{
"name": "Mario Palmer",
"email": "mario.palmer@gmail.com",
"position": "Attorney",
},
{
"name": "Zechariah Burrell",
"email": "zechariah.burrell@gmail.com",
"position": "Part Time",
},
{
"name": "Lucr\u00e9cia Caldeira",
"email": "lucr\u00e9cia.caldeira@gmail.com",
"position": "Human Resources",
},
{
"name": "Love Grayson",
"email": "love.grayson@gmail.com",
"position": "Office Assistant",
},
{
"name": "Elizabeth Olsen",
"email": "elizabeth.olsen@gmail.com",
"position": "Accounting",
},
{
"name": "Layton Diament",
"email": "layton.diament@gmail.com",
"position": "Receptionist",
},
{
"name": "Sophie French",
"email": "sophie.french@gmail.com",
"position": "Medical Assistant",
},
{
"name": "Mia Denys",
"email": "mia.denys@gmail.com",
"position": "Data Entry Clerk",
},
{
"name": "Christine M. Maldonado",
"email": "christine.m..maldonado@gmail.com",
"position": "Director",
},
{
"name": "Line Rolland",
"email": "line.rolland@gmail.com",
"position": "Project Manager",
},
{
"name": "Micheal Murphy",
"email": "micheal.murphy@gmail.com",
"position": "Software Engineer",
},
{
"name": "Jacob Ginnish",
"email": "jacob.ginnish@gmail.com",
"position": "Sales",
},
{
"name": "Erwan Gauthier",
"email": "erwan.gauthier@gmail.com",
"position": "Marketing",
},
{
"name": "Derrick Wells",
"email": "derrick.wells@gmail.com",
"position": "Office Assistant",
},
{
"name": "Emre Topalo\u011flu",
"email": "emre.topalo\u011flu@gmail.com",
"position": "Project Manager",
},
{
"name": "Lucy Walker",
"email": "lucy.walker@gmail.com",
"position": "Business Analyst",
},
{
"name": "Ece Akman",
"email": "ece.akman@gmail.com",
"position": "Accounting",
},
{
"name": "Sophie Louise Hart",
"email": "sophie.louise.hart@gmail.com",
"position": "Attorney",
},
{
"name": "Carmen Velasco",
"email": "carmen.velasco@gmail.com",
"position": "Executive Assistant",
}
]
const list = document.querySelector('#list');
const addFavorite = (p) => {
const item = document.createElement('ion-item');
item.innerHTML = `
<ion-avatar slot="start"><ion-icon name="person"></ion-icon></ion-avatar>
<ion-label>
<h2>${p.name}</h2>
<h3>${p.position}</h3>
</ion-label>
`;
list.appendChild(item);
}
people.forEach(p => addFavorite(p));
function handleAddFavorite (email) {
const modalController = document.querySelector('ion-modal-controller');
modalController.dismiss(email);
}
async function createModal(presentingEl) {
// initialize controller
const modalController = document.querySelector('ion-modal-controller');
await modalController.componentOnReady();
const contactGroups = allContacts
.sort((a, b) => {
const aSplit = a.name.split(' ');
const bSplit = b.name.split(' ');
return aSplit[1].localeCompare(bSplit[1]);
}).reduce((groups, contact) => {
const firstLast = contact.name.split(' ')[1].charAt(0);
if (!groups.hasOwnProperty(firstLast)) {
groups[firstLast] = [];
}
groups[firstLast].push(contact);
return groups;
}, {});
const sortedGroups = Object.keys(contactGroups)
.map(k => { return { letter: k, contacts: contactGroups[k] }})
.sort((a, b) => a.letter.localeCompare(b.letter))
const items = new Array(20).fill(0).map((item, i) => {
return {
title: `Person ${i}`
}
});
// create component to open
const element = document.createElement('div');
element.innerHTML = `
<ion-header id="modal-header">
<ion-note>Choose a contact to add to Favorites</ion-note>
<ion-toolbar>
<ion-title>Contacts</ion-title>
<ion-buttons slot="end">
<ion-button class="add">
<ion-icon name="add" slot="icon-only"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
${sortedGroups.map(group => {
return `<ion-item-divider sticky="true">
<ion-label>
${group.letter}
</ion-label>
</ion-item-divider>
${group.contacts.map(item => `<ion-item onclick="handleAddFavorite('${item.email}')"><ion-label>${item.name}</ion-label></ion-item>`).join('')}
`;
}).join('')}
</ion-list>
<ion-button class="dismiss">Dismiss Modal</ion-button>
</ion-content>
`;
// listen for close event
const button = element.querySelector('ion-button.dismiss');
button.addEventListener('click', () => {
modalController.dismiss();
});
const create = element.querySelector('ion-button.add');
create.addEventListener('click', async () => {
const topModal = await modalController.getTop();
presentModal(topModal);
});
// present the modal
const modalElement = await modalController.create({
presentingElement: presentingEl,
component: element,
swipeToClose: true
});
return modalElement;
}
async function presentModal(presentingEl) {
const modal = await createModal(presentingEl);
await modal.present();
const data = await modal.onWillDismiss();
const person = allContacts.find(c => c.email === data.data);
person && addFavorite(person);
}
</script>
</body>
</html>

View File

@@ -129,40 +129,4 @@ import { EventModalModule } from '../modals/event/event.module';
})
export class CalendarComponentModule {}
```
### Swipeable Modals
Modals in iOS mode have the ability to be presented in a card-style and swiped to close. The card-style presentation and swipe to close gesture are not mutually exclusive, meaning you can pick and choose which features you want to use. For example, you can have a card-style modal that cannot be swiped or a full sized modal that can be swiped.
```javascript
import { IonRouterOutlet } from '@ionic/angular';
constructor(private routerOutlet: IonRouterOutlet) {}
async presentModal() {
const modal = await this.modalController.create({
component: ModalPage,
swipeToClose: true,
presentingElement: this.routerOutlet.nativeEl
});
return await modal.present();
}
```
In most scenarios, using the `ion-router-outlet` element as the `presentingElement` is fine. In cases where you are presenting a card-style modal from within another modal, you should pass in the top-most `ion-modal` element as the `presentingElement`.
```javascript
import { ModalController } from '@ionic/angular';
constructor(private modalCtrl: ModalController) {}
async presentModal() {
const modal = await this.modalController.create({
component: ModalPage,
swipeToClose: true,
presentingElement: await this.modalCtrl.getTop() // Get the top-most ion-modal
});
return await modal.present();
}
```
```

View File

@@ -75,25 +75,4 @@ After being dismissed, the data can be read in through the `onWillDismiss` or `o
```javascript
const { data } = await modalElement.onWillDismiss();
console.log(data);
```
### Swipeable Modals
Modals in iOS mode have the ability to be presented in a card-style and swiped to close. The card-style presentation and swipe to close gesture are not mutually exclusive, meaning you can pick and choose which features you want to use. For example, you can have a card-style modal that cannot be swiped or a full sized modal that can be swiped.
```javascript
const modalElement = document.createElement('ion-modal');
modalElement.component = 'modal-page';
modalElement.swipeToClose = true;
modalElement.presentingElement = document.querySelector('ion-nav');
```
In most scenarios, using the `ion-nav` element as the `presentingElement` is fine. In cases where you are presenting a card-style modal from within a modal, you should pass in the top-most `ion-modal` element as the `presentingElement`.
```javascript
const modalElement = document.createElement('ion-modal');
modalElement.component = 'modal-page';
modalElement.swipeToClose = true;
modalElement.presentingElement = await modalController.getTop(); // Get the top-most ion-modal
```
```

View File

@@ -16,40 +16,3 @@ export const ModalExample: React.FC = () => {
);
};
```
### Swipeable Modals
Modals in iOS mode have the ability to be presented in a card-style and swiped to close. The card-style presentation and swipe to close gesture are not mutually exclusive, meaning you can pick and choose which features you want to use. For example, you can have a card-style modal that cannot be swiped or a full sized modal that can be swiped.
```tsx
<IonModal
isOpen={showModal}
swipeToClose={true}
presentingElement={pageRef.current}
onDidDismiss={() => setShowModal(false)}>
<p>This is modal content</p>
<IonButton onClick={() => setShowModal(false)}>Close Modal</IonButton>
</IonModal>
```
In most scenarios, setting a ref on `IonPage` and passing that ref's `current` value to `presentingElement` is fine. In cases where you are presenting a card-style modal from within another modal, you should pass in the top-most `ion-modal` ref as the `presentingElement`.
```tsx
<IonModal
ref={firstModalRef}
isOpen={showModal}
swipeToClose={true}
presentingElement={pageRef.current}
onDidDismiss={() => setShowModal(false)}>
<p>This is modal content</p>
<IonButton onClick={() => setShow2ndModal(true)}>Show 2nd Modal</IonButton>
<IonButton onClick={() => setShowModal(false)}>Close Modal</IonButton>
</IonModal>
<IonModal
isOpen={show2ndModal}
presentingElement={firstModalRef.current}
onDidDismiss={() => setShow2ndModal(false)}>
<p>This is more modal content</p>
<IonButton onClick={() => setShow2ndModal(false)}>Close Modal</IonButton>
</IonModal>
```

View File

@@ -986,7 +986,7 @@ export class Nav implements NavOutlet {
newStepValue += getTimeGivenProgression([0, 0], [0.32, 0.72], [0, 1], [1, 1], stepValue)[0];
}
this.sbAni.progressEnd(shouldComplete ? 1 : 0, newStepValue, dur);
(this.sbAni as Animation).progressEnd(shouldComplete ? 1 : 0, newStepValue, dur);
}
}

View File

@@ -22,11 +22,7 @@
<ion-content>
<ion-list>
<ion-list-header>
<ion-label>
Notes Right
</ion-label>
</ion-list-header>
<ion-list-header>Notes Right</ion-list-header>
<ion-item>
<ion-label>Default Note</ion-label>
<ion-note slot="end">99</ion-note>
@@ -84,11 +80,7 @@
</ion-list>
<ion-list>
<ion-list-header>
<ion-label>
Notes Left
</ion-label>
</ion-list-header>
<ion-list-header>Notes Left</ion-list-header>
<ion-item>
<ion-label>Default Note</ion-label>
<ion-note slot="start">99</ion-note>

View File

@@ -1,7 +1,7 @@
import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Method, Prop, State, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { AnimationBuilder, CssClassMap, OverlayEventDetail, OverlayInterface, PickerButton, PickerColumn } from '../../interface';
import { Animation, AnimationBuilder, CssClassMap, OverlayEventDetail, OverlayInterface, PickerButton, PickerColumn } from '../../interface';
import { BACKDROP, dismiss, eventMethod, isCancel, prepareOverlay, present, safeCall } from '../../utils/overlays';
import { getClassMap } from '../../utils/theme';
@@ -24,6 +24,8 @@ export class Picker implements ComponentInterface, OverlayInterface {
mode = getIonMode(this);
animation?: Animation;
@Element() el!: HTMLIonPickerElement;
@State() presented = false;
@@ -177,7 +179,7 @@ export class Picker implements ComponentInterface, OverlayInterface {
if (button) {
// a handler has been provided, execute it
// pass the handler the values from the inputs
const rtn = await safeCall(button.handler, this.getSelected());
const rtn = await safeCall(button.handler);
if (rtn === false) {
// if the return value of the handler is false then do not dismiss
return false;

View File

@@ -1,7 +1,7 @@
import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Method, Prop, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { AnimationBuilder, ComponentProps, ComponentRef, FrameworkDelegate, OverlayEventDetail, OverlayInterface } from '../../interface';
import { Animation, AnimationBuilder, ComponentProps, ComponentRef, FrameworkDelegate, OverlayEventDetail, OverlayInterface } from '../../interface';
import { attachComponent, detachComponent } from '../../utils/framework-delegate';
import { BACKDROP, dismiss, eventMethod, prepareOverlay, present } from '../../utils/overlays';
import { getClassMap } from '../../utils/theme';
@@ -28,6 +28,7 @@ export class Popover implements ComponentInterface, OverlayInterface {
private usersElement?: HTMLElement;
presented = false;
animation?: Animation;
mode = getIonMode(this);
@Element() el!: HTMLIonPopoverElement;

View File

@@ -74,7 +74,7 @@
this.innerHTML = `
<ion-content>
<ion-list>
<ion-list-header><ion-label>Ionic</ion-label></ion-list-header>
<ion-list-header>Ionic</ion-list-header>
<ion-item><ion-label>Item 0</ion-label></ion-item>
<ion-item><ion-label>Item 1</ion-label></ion-item>
<ion-item><ion-label>Item 2</ion-label></ion-item>
@@ -101,7 +101,7 @@
this.innerHTML = `
<ion-content>
<ion-list>
<ion-list-header><ion-label>Ionic</ion-label></ion-list-header>
<ion-list-header>Ionic</ion-list-header>
` + items + `
</ion-list>
</ion-content>

View File

@@ -49,7 +49,7 @@
this.innerHTML = `
<ion-content>
<ion-list>
<ion-list-header><ion-label>Ionic</ion-label></ion-list-header>
<ion-list-header>Ionic</ion-list-header>
<ion-item><ion-label>Item 0</ion-label></ion-item>
<ion-item><ion-label>Item 1</ion-label></ion-item>
<ion-item><ion-label>Item 2</ion-label></ion-item>
@@ -76,7 +76,7 @@
this.innerHTML = `
<ion-content>
<ion-list>
<ion-list-header><ion-label>Ionic</ion-label></ion-list-header>
<ion-list-header>Ionic</ion-list-header>
` + items + `
</ion-list>
</ion-content>

View File

@@ -8,7 +8,7 @@ ion-progress-bar is a horizontal progress bar to visualize the progression of an
If the percentage of an operation is known, you should use the determinate type. This is the default type and the progress is represented by the `value` property.
A buffer shows circles as animation to indicate some activity. If the `buffer` property is smaller than 1 you can show the additional buffering progress.
A buffer shows circles as animation to indicate some activity. If the `buffer` property is smaller than 1 you can show the addditional buffering progress.
### Indeterminate

View File

@@ -19,9 +19,7 @@ radio button within the same group.
<ion-list>
<ion-radio-group>
<ion-list-header>
<ion-label>
Auto Manufacturers
</ion-label>
Auto Manufacturers
</ion-list-header>
<ion-item>
@@ -63,11 +61,7 @@ export const RadioGroupExample: React.FC = () => (
<IonContent>
<IonList>
<IonRadioGroup>
<IonListHeader>
<IonLabel>
Auto Manufacturers
</IonLabel>
</IonListHeader>
<IonListHeader>Auto Manufacturers</IonListHeader>
<IonItem>
<IonLabel>Cord</IonLabel>
@@ -107,9 +101,7 @@ export const RadioGroupExample: React.FC = () => (
<ion-list>
<ion-radio-group>
<ion-list-header>
<ion-label>
Auto Manufacturers
</ion-label>
Auto Manufacturers
</ion-list-header>
<ion-item>

View File

@@ -2,9 +2,7 @@
<ion-list>
<ion-radio-group>
<ion-list-header>
<ion-label>
Auto Manufacturers
</ion-label>
Auto Manufacturers
</ion-list-header>
<ion-item>

View File

@@ -2,9 +2,7 @@
<ion-list>
<ion-radio-group>
<ion-list-header>
<ion-label>
Auto Manufacturers
</ion-label>
Auto Manufacturers
</ion-list-header>
<ion-item>

View File

@@ -6,11 +6,7 @@ export const RadioGroupExample: React.FC = () => (
<IonContent>
<IonList>
<IonRadioGroup>
<IonListHeader>
<IonLabel>
Auto Manufacturers
</IonLabel>
</IonListHeader>
<IonListHeader>Auto Manufacturers</IonListHeader>
<IonItem>
<IonLabel>Cord</IonLabel>

View File

@@ -3,9 +3,7 @@
<ion-list>
<ion-radio-group>
<ion-list-header>
<ion-label>
Auto Manufacturers
</ion-label>
Auto Manufacturers
</ion-list-header>
<ion-item>

View File

@@ -89,9 +89,7 @@
<ion-list>
<ion-list-header>
<ion-label>
No Radio Group
</ion-label>
No Radio Group
</ion-list-header>
<ion-item>
<ion-label>Kiwi, (ionChange) Secondary color</ion-label>

View File

@@ -23,9 +23,7 @@
<ion-content id="content">
<ion-list>
<ion-list-header>
<ion-label>
Range color
</ion-label>
Range color
</ion-list-header>
<ion-item>
<ion-range value="20"></ion-range>
@@ -56,9 +54,7 @@
<ion-list>
<ion-list-header>
<ion-label>
Dynamic Value
</ion-label>
Dynamic Value
</ion-list-header>
<ion-item>
<ion-range pin="true" step="0" color="secondary" id="progressValue"></ion-range>
@@ -79,9 +75,7 @@
<ion-list>
<ion-list-header>
<ion-label>
Mode
</ion-label>
Mode
</ion-list-header>
<ion-item>
<ion-range value="50" mode="md"></ion-range>
@@ -93,9 +87,7 @@
<ion-list>
<ion-list-header>
<ion-label>
Options
</ion-label>
Options
</ion-list-header>
<ion-item>
<ion-range pin="true"></ion-range>
@@ -121,9 +113,7 @@
<ion-list>
<ion-list-header>
<ion-label>
Coupled sliders
</ion-label>
Coupled sliders
</ion-list-header>
<ion-item>
<ion-range min="0" value="0" max="50" id="minRange"></ion-range>

View File

@@ -19,12 +19,10 @@ export class Reorder implements ComponentInterface {
}
render() {
const mode = getIonMode(this);
const reorderIcon = mode === 'ios' ? 'reorder-three-outline' : 'reorder-two-sharp';
return (
<Host class={mode}>
<Host class={getIonMode(this)}>
<slot>
<ion-icon name={reorderIcon} lazy={false} class="reorder-icon" />
<ion-icon name="reorder" lazy={false} class="reorder-icon" />
</slot>
</Host>
);

View File

@@ -96,7 +96,7 @@ export class RouterOutlet implements ComponentInterface, NavOutlet {
newStepValue += getTimeGivenProgression([0, 0], [0.32, 0.72], [0, 1], [1, 1], step)[0];
}
this.ani.progressEnd(shouldComplete ? 1 : 0, newStepValue, dur);
(this.ani as Animation).progressEnd(shouldComplete ? 1 : 0, newStepValue, dur);
}
}

View File

@@ -219,25 +219,25 @@ export const SearchbarExample: React.FC = () => (
## Properties
| Property | Attribute | Description | Type | Default |
| ------------------ | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| `animated` | `animated` | If `true`, enable searchbar animation. | `boolean` | `false` |
| `autocomplete` | `autocomplete` | Set the input's autocomplete property. | `"off" \| "on"` | `'off'` |
| `autocorrect` | `autocorrect` | Set the input's autocorrect property. | `"off" \| "on"` | `'off'` |
| `cancelButtonIcon` | `cancel-button-icon` | Set the cancel button icon. Only applies to `md` mode. Defaults to `"arrow-back-sharp"`. | `string` | `config.get('backButtonIcon', 'arrow-back-sharp') as string` |
| `cancelButtonText` | `cancel-button-text` | Set the the cancel button text. Only applies to `ios` mode. | `string` | `'Cancel'` |
| `clearIcon` | `clear-icon` | Set the clear icon. Defaults to `"close-circle"` for `ios` and `"close-sharp"` for `md`. | `string \| undefined` | `undefined` |
| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
| `debounce` | `debounce` | Set the amount of time, in milliseconds, to wait to trigger the `ionChange` event after each keystroke. | `number` | `250` |
| `disabled` | `disabled` | If `true`, the user cannot interact with the input. | `boolean` | `false` |
| `inputmode` | `inputmode` | A hint to the browser for which keyboard to display. Possible values: `"none"`, `"text"`, `"tel"`, `"url"`, `"email"`, `"numeric"`, `"decimal"`, and `"search"`. | `"decimal" \| "email" \| "none" \| "numeric" \| "search" \| "tel" \| "text" \| "url"` | `'search'` |
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
| `placeholder` | `placeholder` | Set the input's placeholder. `placeholder` can accept either plaintext or HTML as a string. To display characters normally reserved for HTML, they must be escaped. For example `<Ionic>` would become `&lt;Ionic&gt;` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security) | `string` | `'Search'` |
| `searchIcon` | `search-icon` | The icon to use as the search icon. Defaults to `"search-outline"` in `ios` mode and `"search-sharp"` in `md` mode. | `string \| undefined` | `undefined` |
| `showCancelButton` | `show-cancel-button` | Sets the behavior for the cancel button. Defaults to `"never"`. Setting to `"focus"` shows the cancel button on focus. Setting to `"never"` hides the cancel button. Setting to `"always"` shows the cancel button regardless of focus state. | `"always" \| "focus" \| "never"` | `'never'` |
| `spellcheck` | `spellcheck` | If `true`, enable spellcheck on the input. | `boolean` | `false` |
| `type` | `type` | Set the type of the input. | `"email" \| "number" \| "password" \| "search" \| "tel" \| "text" \| "url"` | `'search'` |
| `value` | `value` | the value of the searchbar. | `null \| string \| undefined` | `''` |
| Property | Attribute | Description | Type | Default |
| ------------------ | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | --------------------------------------------------------- |
| `animated` | `animated` | If `true`, enable searchbar animation. | `boolean` | `false` |
| `autocomplete` | `autocomplete` | Set the input's autocomplete property. | `"off" \| "on"` | `'off'` |
| `autocorrect` | `autocorrect` | Set the input's autocorrect property. | `"off" \| "on"` | `'off'` |
| `cancelButtonIcon` | `cancel-button-icon` | Set the cancel button icon. Only applies to `md` mode. | `string` | `config.get('backButtonIcon', 'md-arrow-back') as string` |
| `cancelButtonText` | `cancel-button-text` | Set the the cancel button text. Only applies to `ios` mode. | `string` | `'Cancel'` |
| `clearIcon` | `clear-icon` | Set the clear icon. Defaults to `"close-circle"` for `ios` and `"close"` for `md`. | `string \| undefined` | `undefined` |
| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
| `debounce` | `debounce` | Set the amount of time, in milliseconds, to wait to trigger the `ionChange` event after each keystroke. | `number` | `250` |
| `disabled` | `disabled` | If `true`, the user cannot interact with the input. | `boolean` | `false` |
| `inputmode` | `inputmode` | A hint to the browser for which keyboard to display. Possible values: `"none"`, `"text"`, `"tel"`, `"url"`, `"email"`, `"numeric"`, `"decimal"`, and `"search"`. | `"decimal" \| "email" \| "none" \| "numeric" \| "search" \| "tel" \| "text" \| "url"` | `'search'` |
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
| `placeholder` | `placeholder` | Set the input's placeholder. `placeholder` can accept either plaintext or HTML as a string. To display characters normally reserved for HTML, they must be escaped. For example `<Ionic>` would become `&lt;Ionic&gt;` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security) | `string` | `'Search'` |
| `searchIcon` | `search-icon` | The icon to use as the search icon. | `string` | `'search'` |
| `showCancelButton` | `show-cancel-button` | Sets the behavior for the cancel button. Defaults to `"never"`. Setting to `"focus"` shows the cancel button on focus. Setting to `"never"` hides the cancel button. Setting to `"always"` shows the cancel button regardless of focus state. | `"always" \| "focus" \| "never"` | `'never'` |
| `spellcheck` | `spellcheck` | If `true`, enable spellcheck on the input. | `boolean` | `false` |
| `type` | `type` | Set the type of the input. | `"email" \| "number" \| "password" \| "search" \| "tel" \| "text" \| "url"` | `'search'` |
| `value` | `value` | the value of the searchbar. | `null \| string \| undefined` | `''` |
## Events
@@ -249,7 +249,7 @@ export const SearchbarExample: React.FC = () => (
| `ionChange` | Emitted when the value has changed. | `CustomEvent<SearchbarChangeEventDetail>` |
| `ionClear` | Emitted when the clear input button is clicked. | `CustomEvent<void>` |
| `ionFocus` | Emitted when the input has focus. | `CustomEvent<void>` |
| `ionInput` | Emitted when a keyboard input occurred. | `CustomEvent<KeyboardEvent>` |
| `ionInput` | Emitted when a keyboard input ocurred. | `CustomEvent<KeyboardEvent>` |
## Methods

View File

@@ -53,9 +53,8 @@ export class Searchbar implements ComponentInterface {
/**
* Set the cancel button icon. Only applies to `md` mode.
* Defaults to `"arrow-back-sharp"`.
*/
@Prop() cancelButtonIcon = config.get('backButtonIcon', 'arrow-back-sharp') as string;
@Prop() cancelButtonIcon = config.get('backButtonIcon', 'md-arrow-back') as string;
/**
* Set the the cancel button text. Only applies to `ios` mode.
@@ -63,7 +62,7 @@ export class Searchbar implements ComponentInterface {
@Prop() cancelButtonText = 'Cancel';
/**
* Set the clear icon. Defaults to `"close-circle"` for `ios` and `"close-sharp"` for `md`.
* Set the clear icon. Defaults to `"close-circle"` for `ios` and `"close"` for `md`.
*/
@Prop() clearIcon?: string;
@@ -101,10 +100,9 @@ export class Searchbar implements ComponentInterface {
@Prop() placeholder = 'Search';
/**
* The icon to use as the search icon. Defaults to `"search-outline"` in
* `ios` mode and `"search-sharp"` in `md` mode.
* The icon to use as the search icon.
*/
@Prop() searchIcon?: string;
@Prop() searchIcon = 'search';
/**
* Sets the behavior for the cancel button. Defaults to `"never"`.
@@ -131,7 +129,7 @@ export class Searchbar implements ComponentInterface {
@Prop({ mutable: true }) value?: string | null = '';
/**
* Emitted when a keyboard input occurred.
* Emitted when a keyboard input ocurred.
*/
@Event() ionInput!: EventEmitter<KeyboardEvent>;
@@ -414,8 +412,8 @@ export class Searchbar implements ComponentInterface {
render() {
const animated = this.animated && config.getBoolean('animated', true);
const mode = getIonMode(this);
const clearIcon = this.clearIcon || (mode === 'ios' ? 'close-circle' : 'close-sharp');
const searchIcon = this.searchIcon || (mode === 'ios' ? 'search-outline' : 'search-sharp');
const clearIcon = this.clearIcon || (mode === 'ios' ? 'ios-close-circle' : 'md-close');
const searchIcon = this.searchIcon;
const cancelButton = (this.showCancelButton !== 'never') && (
<button

View File

@@ -55,11 +55,7 @@ Note: `interfaceOptions` will not override `inputs` or `buttons` with the `alert
```html
<ion-list>
<ion-list-header>
<ion-label>
Single Selection
</ion-label>
</ion-list-header>
<ion-list-header>Single Selection</ion-list-header>
<ion-item>
<ion-label>Gender</ion-label>
@@ -86,11 +82,7 @@ Note: `interfaceOptions` will not override `inputs` or `buttons` with the `alert
```html
<ion-list>
<ion-list-header>
<ion-label>
Multiple Selection
</ion-label>
</ion-list-header>
<ion-list-header>Multiple Selection</ion-list-header>
<ion-item>
<ion-label>Toppings</ion-label>
@@ -124,12 +116,8 @@ Note: `interfaceOptions` will not override `inputs` or `buttons` with the `alert
```html
<ion-list>
<ion-list-header>
<ion-label>
Objects as Values (compareWith)
</ion-label>
</ion-list-header>
<ion-list-header>Objects as Values (compareWith)</ion-list-header>
<ion-item>
<ion-label>Users</ion-label>
<ion-select [compareWith]="compareWith">
@@ -178,11 +166,7 @@ export class SelectExample {
```html
<ion-list>
<ion-list-header>
<ion-label>
Interface Options
</ion-label>
</ion-list-header>
<ion-list-header>Interface Options</ion-list-header>
<ion-item>
<ion-label>Alert</ion-label>
@@ -260,11 +244,7 @@ export class SelectExample {
```html
<ion-list>
<ion-list-header>
<ion-label>
Single Selection
</ion-label>
</ion-list-header>
<ion-list-header>Single Selection</ion-list-header>
<ion-item>
<ion-label>Gender</ion-label>
@@ -291,11 +271,7 @@ export class SelectExample {
```html
<ion-list>
<ion-list-header>
<ion-label>
Multiple Selection
</ion-label>
</ion-list-header>
<ion-list-header>Multiple Selection</ion-list-header>
<ion-item>
<ion-label>Toppings</ion-label>
@@ -329,11 +305,7 @@ export class SelectExample {
```html
<ion-list>
<ion-list-header>
<ion-label>
Objects as Values (compareWith)
</ion-label>
</ion-list-header>
<ion-list-header>Objects as Values (compareWith)</ion-list-header>
<ion-item>
<ion-label>Users</ion-label>
@@ -367,13 +339,13 @@ export class SelectExample {
let objectSelectElement = document.getElementById('objectSelectCompareWith');
objectSelectElement.compareWith = compareWithFn;
objectOptions.forEach((option, i) => {
let selectOption = document.createElement('ion-select-option');
selectOption.value = option;
selectOption.textContent = option.first + ' ' + option.last;
selectOption.selected = (i === 0);
objectSelectElement.appendChild(selectOption)
});
}
@@ -383,11 +355,7 @@ export class SelectExample {
```html
<ion-list>
<ion-list-header>
<ion-label>
Interface Options
</ion-label>
</ion-list-header>
<ion-list-header>Interface Options</ion-list-header>
<ion-item>
<ion-label>Alert</ion-label>
@@ -514,11 +482,7 @@ export const SelectExample: React.FC = () => (
<IonContent>
## Single Selection
<IonList>
<IonListHeader>
<IonLabel>
Single Selection
</IonLabel>
</IonListHeader>
<IonListHeader>Single Selection</IonListHeader>
<IonItem>
<IonLabel>Gender</IonLabel>
@@ -540,11 +504,7 @@ export const SelectExample: React.FC = () => (
</IonList>
## Multiple Selection
<IonList>
<IonListHeader>
<IonLabel>
Multiple Selection
</IonLabel>
</IonListHeader>
<IonListHeader>Multiple Selection</IonListHeader>
<IonItem>
<IonLabel>Toppings</IonLabel>
@@ -578,11 +538,7 @@ export const SelectExample: React.FC = () => (
</IonList>
## Objects as Values
<IonList>
<IonListHeader>
<IonLabel>
Objects as Values (compareWith)
</IonLabel>
</IonListHeader>
<IonListHeader>Objects as Values (compareWith)</IonListHeader>
<IonItem>
<IonLabel>Users</IonLabel>
<IonSelect compareWith={compareWith}>
@@ -598,11 +554,7 @@ export const SelectExample: React.FC = () => (
</IonList>
## Interface Options
<IonList>
<IonListHeader>
<IonLabel>
Interface Options
</IonLabel>
</IonListHeader>
<IonListHeader>Interface Options</IonListHeader>
<IonItem>
<IonLabel>Alert</IonLabel>
@@ -662,11 +614,7 @@ export const SelectExample: React.FC = () => (
```html
<template>
<ion-list>
<ion-list-header>
<ion-label>
Single Selection
</ion-label>
</ion-list-header>
<ion-list-header>Single Selection</ion-list-header>
<ion-item>
<ion-label>Gender</ion-label>
@@ -695,11 +643,7 @@ export const SelectExample: React.FC = () => (
```html
<template>
<ion-list>
<ion-list-header>
<ion-label>
Multiple Selection
</ion-label>
</ion-list-header>
<ion-list-header>Multiple Selection</ion-list-header>
<ion-item>
<ion-label>Toppings</ion-label>
@@ -735,11 +679,7 @@ export const SelectExample: React.FC = () => (
```html
<template>
<ion-list>
<ion-list-header>
<ion-label>
Interface Options
</ion-label>
</ion-list-header>
<ion-list-header>Interface Options</ion-list-header>
<ion-item>
<ion-label>Alert</ion-label>

View File

@@ -22,11 +22,7 @@
<ion-content class="outer-content test-content">
<ion-list>
<ion-list-header>
<ion-label>
Single Value Select
</ion-label>
</ion-list-header>
<ion-list-header>Single Value Select</ion-list-header>
<ion-item>
<ion-label>Gender</ion-label>
@@ -60,11 +56,7 @@
</ion-list>
<ion-list>
<ion-list-header>
<ion-label>
Object Values with trackBy
</ion-label>
</ion-list-header>
<ion-list-header>Object Values with trackBy</ion-list-header>
<ion-item>
<ion-label>Users</ion-label>
@@ -73,11 +65,7 @@
</ion-list>
<ion-list>
<ion-list-header>
<ion-label>
Select - Custom Interface Options
</ion-label>
</ion-list-header>
<ion-list-header>Select - Custom Interface Options</ion-list-header>
<ion-item color="danger">
<ion-label>Alert</ion-label>
@@ -119,11 +107,7 @@
</ion-list>
<ion-list>
<ion-list-header>
<ion-label>
Popover Interface Select
</ion-label>
</ion-list-header>
<ion-list-header>Popover Interface Select</ion-list-header>
<ion-item>
<ion-label>Gender</ion-label>
@@ -180,11 +164,7 @@
<ion-list>
<ion-list-header>
<ion-label>
Action Sheet Interface Select
</ion-label>
</ion-list-header>
<ion-list-header>Action Sheet Interface Select</ion-list-header>
<ion-item>
<ion-label>Mute Notifications</ion-label>
@@ -210,11 +190,7 @@
</ion-list>
<ion-list>
<ion-list-header>
<ion-label>
Multiple Value Select
</ion-label>
</ion-list-header>
<ion-list-header>Multiple Value Select</ion-list-header>
<ion-item>
<ion-label>Toppings</ion-label>

View File

@@ -2,11 +2,7 @@
```html
<ion-list>
<ion-list-header>
<ion-label>
Single Selection
</ion-label>
</ion-list-header>
<ion-list-header>Single Selection</ion-list-header>
<ion-item>
<ion-label>Gender</ion-label>
@@ -33,11 +29,7 @@
```html
<ion-list>
<ion-list-header>
<ion-label>
Multiple Selection
</ion-label>
</ion-list-header>
<ion-list-header>Multiple Selection</ion-list-header>
<ion-item>
<ion-label>Toppings</ion-label>
@@ -71,12 +63,8 @@
```html
<ion-list>
<ion-list-header>
<ion-label>
Objects as Values (compareWith)
</ion-label>
</ion-list-header>
<ion-list-header>Objects as Values (compareWith)</ion-list-header>
<ion-item>
<ion-label>Users</ion-label>
<ion-select [compareWith]="compareWith">
@@ -125,11 +113,7 @@ export class SelectExample {
```html
<ion-list>
<ion-list-header>
<ion-label>
Interface Options
</ion-label>
</ion-list-header>
<ion-list-header>Interface Options</ion-list-header>
<ion-item>
<ion-label>Alert</ion-label>

View File

@@ -2,11 +2,7 @@
```html
<ion-list>
<ion-list-header>
<ion-label>
Single Selection
</ion-label>
</ion-list-header>
<ion-list-header>Single Selection</ion-list-header>
<ion-item>
<ion-label>Gender</ion-label>
@@ -33,11 +29,7 @@
```html
<ion-list>
<ion-list-header>
<ion-label>
Multiple Selection
</ion-label>
</ion-list-header>
<ion-list-header>Multiple Selection</ion-list-header>
<ion-item>
<ion-label>Toppings</ion-label>
@@ -71,11 +63,7 @@
```html
<ion-list>
<ion-list-header>
<ion-label>
Objects as Values (compareWith)
</ion-label>
</ion-list-header>
<ion-list-header>Objects as Values (compareWith)</ion-list-header>
<ion-item>
<ion-label>Users</ion-label>
@@ -109,13 +97,13 @@
let objectSelectElement = document.getElementById('objectSelectCompareWith');
objectSelectElement.compareWith = compareWithFn;
objectOptions.forEach((option, i) => {
let selectOption = document.createElement('ion-select-option');
selectOption.value = option;
selectOption.textContent = option.first + ' ' + option.last;
selectOption.selected = (i === 0);
objectSelectElement.appendChild(selectOption)
});
}
@@ -125,11 +113,7 @@
```html
<ion-list>
<ion-list-header>
<ion-label>
Interface Options
</ion-label>
</ion-list-header>
<ion-list-header>Interface Options</ion-list-header>
<ion-item>
<ion-label>Alert</ion-label>

Some files were not shown because too many files have changed in this diff Show More