Compare commits

..

58 Commits

Author SHA1 Message Date
Liam DeBeasi
ede6289bc6 remove package lock 2020-06-05 16:08:10 -04:00
Liam DeBeasi
f077f0aac7 sync with master 2020-06-05 16:06:40 -04:00
Liam DeBeasi
9c64308f0d add generic wrapper class 2020-06-05 16:05:43 -04:00
Liam DeBeasi
795783311a clean up animations: 2020-06-05 14:55:58 -04:00
Liam DeBeasi
f3e8d4c31d typo 2020-06-05 14:04:51 -04:00
Liam DeBeasi
7fb38d1e12 add support for backdrop to fade anim 2020-06-05 14:04:04 -04:00
Liam DeBeasi
9f9ba235ee add fade and fade through animations 2020-06-05 13:54:56 -04:00
Liam DeBeasi
187917c746 chore(): exempt bugs and feature requests from stale issues (#21435) 2020-06-05 09:45:27 -04:00
Liam DeBeasi
137c49d70b fix(scroll-assist): improve scroll detection accuracy (#21416) 2020-06-03 10:01:01 -04:00
Alexey Vinogradov
5bf83b80d7 feat(all): add optional generics typings for overlay component methods (#21393) 2020-06-03 09:08:27 -04:00
Niklas Merz
c7e94a1f23 docs(datetime): specify default value for dayShortNames (#21281) 2020-06-02 17:21:38 -04:00
Celilsemi Sam Erkiner
1ed81693f2 feat(alert): add support for custom input attributes (#21365) 2020-06-01 11:18:59 -04:00
Thomas Clark
5f2001c43c fix(reorder-group): revert item to original position when passing false to complete (#21396)
fixes #19128
2020-05-29 14:35:34 -04:00
Brandy Carney
882f8fef07 fix(item): inherit align-items from parent item (#19278)
inherits alignment in inner item, sets item alignment to center

fixes #18703
2020-05-29 11:30:19 -04:00
Adam Bradley
323e15003f chore: internal import updates to improve bundling (#21400)
* chore: internal import updates to improve bundling

- Rename keyboard.ts so it has a good filename after custom element bundling
- Import util fns directly instead of from top level index
- Do not export with *

* chore(angular): bump ng-packagr

Co-authored-by: Mike Hartington <mikehartington@gmail.com>
2020-05-29 10:04:12 -05:00
Haidar Zeineddine
53fc8e37c8 feat(angular): strongly type Ionic lifecycle hooks (#18044)
closes #18043
2020-05-27 16:42:34 -04:00
Alex Currie-Clark
29d208de88 fix(item): input-wrapper now inherits overflow (#21282) 2020-05-27 12:56:11 -04:00
Brandy Carney
5285824da5 feat(select-option): pass class from the option to the interface for individual styling (#21304)
Co-authored-by: Robb Wright <audaxion@gmail.com>
2020-05-27 12:12:01 -04:00
David
2dac12c577 fix(header): large title transition works on older versions of iOS (#21339) 2020-05-27 10:34:01 -04:00
Simon Hänisch
7703da28f8 fix(toast, action-sheet): allow button handler to return Promise<void> (#21259) 2020-05-26 15:27:14 -04:00
Brandy Carney
1ea5ce5839 chore(stencil): update to latest stencil version (#21378)
references ionic-team/ionic-docs#1343
2020-05-26 15:05:36 -04:00
Liam DeBeasi
33be1f061e fix(ios): add haptic drag gesture for action sheet and alert components (#21060) 2020-05-26 11:33:51 -04:00
Manu MA
e53f0241e2 feat(alert): add destructive role to alert buttons (#21269) 2020-05-22 15:32:12 -04:00
Liam DeBeasi
4af54a2fea feat(angular): expose getPlatforms and isPlatform (#21308) 2020-05-22 10:27:03 -04:00
Manu MA
4fd7c0cc5a feat(all): add all autocomplete values to input and searchbar (#21297) 2020-05-22 09:23:44 -04:00
Liam DeBeasi
32906048a4 fix(slides): update Swiper dependency to resolve error when doing SSR (#21350) 2020-05-20 15:54:02 -04:00
Liam DeBeasi
829a0d9be5 feat(angular): expose activatedView (#21302) 2020-05-20 15:24:30 -04:00
Liam DeBeasi
c680705162 chore(): update scripts to use colorette instead of turbocolor (#21349) 2020-05-20 13:33:53 -04:00
Liam DeBeasi
60be68ca6d docs(title): clarify background-color styling with collapsible large title (#21348) 2020-05-20 12:58:24 -04:00
Liam DeBeasi
28c5e14434 add multi axis anim 2020-05-20 11:25:30 -04:00
Liam DeBeasi
237748049c fix(textarea): native textarea inherits max/min width and heights (#21333)
Co-authored-by: Stefanos Anagnostou <anagstef@users.noreply.github.com>
2020-05-19 12:38:03 -04:00
Liam DeBeasi
a4be67aeb8 add axis support 2020-05-18 17:39:12 -04:00
Liam DeBeasi
ec4c0fe5bd chore(): revert changes until bot is updated (#21332)
This reverts commit cc780c80b2.
2020-05-18 13:48:39 -04:00
Liam DeBeasi
cc780c80b2 chore(): update bot template to properly close issues (#21330) 2020-05-18 13:40:37 -04:00
Liam DeBeasi
eaf4fb6b2a fix(menu-button): screen readers now properly announce menu button (#21324) 2020-05-18 12:43:02 -04:00
Liam DeBeasi
94c3d481e9 Add base motion package 2020-05-15 15:57:55 -04:00
Liam DeBeasi
3937101e5c fix(datetime): ensure year-only values are not affected by timezone when parsing (#21309) 2020-05-15 11:36:01 -04:00
Brandy Carney
16a03d58ec docs(headings): update readme headings to be correct level 2020-05-14 17:26:44 -04:00
Julian Baumann
448dfa0a69 fix(modal): card style modal no longer gets stuck when swiping quickly (#21224) 2020-05-14 11:50:31 -04:00
Liam DeBeasi
39bfaeaa79 merge release-5.1.1
5.1.1
2020-05-13 14:22:45 -04:00
Liam DeBeasi
f954d40453 5.1.1 2020-05-13 14:19:55 -04:00
Brandy Carney
dd4cb706ff fix(input): check for tabindex and pass it properly to native input (#21170)
* fix(input): check for tabindex and pass it properly to native input

references #17515

* style(input): fix lint error

* test(input): update test for more use cases (inside item)

* fix(item): adds delegatesFocus to shadow

* style(input): add comment block on what the code does
2020-05-13 12:18:03 -04:00
Liam DeBeasi
50678c03c9 fix(ios): transition shadow properly sized regardless of footer (#21095) 2020-05-13 12:17:45 -04:00
Brandy Carney
898401a7e0 docs(overlays): add documentation on customization in scoped overlays (#21283)
- improves the documentation on customizing scoped overlays using cssClass and/or CSS variables
- includes a section in the Angular usage with information on where the CSS needs to be styled (globally) in order to work for an overlay
2020-05-13 11:54:11 -04:00
Brandy Carney
687122127c docs(stencil): add stencil usage to components (#21261) 2020-05-12 20:35:48 -04:00
Brandy Carney
703ef5c992 fix(display): remove 1px gap between mutually exclusive breakpoints (#21276)
updates breakpoint max to reduce the max width by 0.02px

closes #20993 closes #20743
2020-05-12 12:02:07 -04:00
Liam DeBeasi
85cc35ee91 fix(segment-button): screen readers now announce selected state properly (#21273) 2020-05-12 11:37:56 -04:00
Liam DeBeasi
7166a290cc fix(all): improve scroll assist reliability for below the fold inputs (#21206) 2020-05-11 15:44:59 -04:00
Liam DeBeasi
1e6f92377a fix(refresher): refresher completes even after switching to a new tab (#21236) 2020-05-11 15:21:26 -04:00
Liam DeBeasi
8e11ecc136 fix(picker): haptics now work properly (#21268) 2020-05-11 15:10:19 -04:00
Liam DeBeasi
1fbdb2255e fix(toggle): screen readers now announce toggle properly (#21168) 2020-05-08 11:59:04 -04:00
Liam DeBeasi
0c13f25bbb fix(header): do not error on collapsable header on devices that do not support IntersectionObserve (#21222) 2020-05-08 11:57:50 -04:00
Liam DeBeasi
9d0dcbbd31 fix(overlays): respect keyboardClose property when opening overlays (#21240) 2020-05-08 11:56:40 -04:00
Liam DeBeasi
f23f1cb37e fix(refresher): correctly select shadow root on older browsers (#21237) 2020-05-08 11:54:57 -04:00
Liam DeBeasi
f334e83a43 fix(md): do not hide page when swipe gesture is cancelled (#21247) 2020-05-08 10:16:42 -04:00
Liam DeBeasi
bb62023a0c fix(all): overlay components no longer display outline when focused (#21226) 2020-05-07 16:33:51 -04:00
Liam DeBeasi
cae389bd12 chore(): remove undocumented back button parts (#21223) 2020-05-07 16:32:18 -04:00
Liam DeBeasi
9308f0329c merge release-5.1.0
5.1.0
2020-04-30 18:25:49 -04:00
301 changed files with 14588 additions and 1483 deletions

View File

@@ -75,8 +75,10 @@ stale:
days: 365
maxIssuesPerRun: 100
exemptLabels:
- good first issue
- triage
- "good first issue"
- "triage"
- "type: bug"
- "type: feature request"
exemptAssigned: true
exemptProjects: true
exemptMilestones: true

View File

@@ -4,7 +4,7 @@ const execa = require('execa');
const inquirer = require('inquirer');
const Listr = require('listr');
const semver = require('semver');
const tc = require('turbocolor');
const { bold, cyan, dim } = require('colorette');
const rootDir = path.join(__dirname, '../');
@@ -55,7 +55,7 @@ async function askNpmTag(version) {
type: 'confirm',
name: 'confirm',
message: answers => {
return `Will publish ${tc.cyan(version)} to ${tc.cyan(answers.npmTag)}. Continue?`;
return `Will publish ${cyan(version)} to ${cyan(answers.npmTag)}. Continue?`;
}
}
];
@@ -192,7 +192,7 @@ function preparePackage(tasks, package, version, install) {
// Add project tasks
tasks.push({
title: `Prepare ${tc.bold(pkg.name)}`,
title: `Prepare ${bold(pkg.name)}`,
task: () => new Listr(projectTasks)
});
}
@@ -234,7 +234,7 @@ function prepareDevPackage(tasks, package, version) {
// Add project tasks
tasks.push({
title: `Prepare dev build: ${tc.bold(pkg.name)}`,
title: `Prepare dev build: ${bold(pkg.name)}`,
task: () => new Listr(projectTasks)
});
}
@@ -244,7 +244,7 @@ function updatePackageVersions(tasks, packages, version) {
updatePackageVersion(tasks, package, version);
tasks.push({
title: `${package} update @ionic/core dependency, if present ${tc.dim(`(${version})`)}`,
title: `${package} update @ionic/core dependency, if present ${dim(`(${version})`)}`,
task: async () => {
if (package !== 'core') {
const pkg = readPkg(package);
@@ -261,7 +261,7 @@ function updatePackageVersions(tasks, packages, version) {
updatePackageVersion(tasks, distPackage, version);
tasks.push({
title: `${package} update @ionic/core dependency, if present ${tc.dim(`(${version})`)}`,
title: `${package} update @ionic/core dependency, if present ${dim(`(${version})`)}`,
task: async () => {
const pkg = readPkg(distPackage);
updateDependency(pkg, '@ionic/core', version);
@@ -272,7 +272,7 @@ function updatePackageVersions(tasks, packages, version) {
if (package === 'packages/react-router') {
tasks.push({
title: `${package} update @ionic/react dependency, if present ${tc.dim(`(${version})`)}`,
title: `${package} update @ionic/react dependency, if present ${dim(`(${version})`)}`,
task: async () => {
const pkg = readPkg(package);
updateDependency(pkg, '@ionic/react', version);
@@ -287,7 +287,7 @@ function updatePackageVersion(tasks, package, version) {
const projectRoot = projectPath(package);
tasks.push({
title: `${package}: update package.json ${tc.dim(`(${version})`)}`,
title: `${package}: update package.json ${dim(`(${version})`)}`,
task: async () => {
await execa('npm', ['version', version], { cwd: projectRoot });
}

View File

@@ -2,7 +2,7 @@
* Deploy script adopted from https://github.com/sindresorhus/np
* MIT License (c) Sindre Sorhus (sindresorhus.com)
*/
const tc = require('turbocolor');
const { cyan, dim, red, reset } = require('colorette');
const execa = require('execa');
const inquirer = require('inquirer');
const Listr = require('listr');
@@ -34,7 +34,7 @@ async function main() {
console.log(` npm run release\n`);
} catch(err) {
console.log('\n', tc.red(err), '\n');
console.log('\n', red(err), '\n');
process.exit(1);
}
}
@@ -84,7 +84,7 @@ async function askVersion() {
type: 'confirm',
name: 'confirm',
message: answers => {
return `Will bump from ${tc.cyan(oldVersion)} to ${tc.cyan(answers.version)}. Continue?`;
return `Will bump from ${cyan(oldVersion)} to ${cyan(answers.version)}. Continue?`;
}
}
];
@@ -131,7 +131,7 @@ async function preparePackages(packages, version, install) {
function validateGit(tasks, version) {
tasks.push(
{
title: `Validate git tag ${tc.dim(`(v${version})`)}`,
title: `Validate git tag ${dim(`(v${version})`)}`,
task: () => execa('git', ['fetch'])
.then(() => {
return execa.stdout('npm', ['config', 'get', 'tag-version-prefix']);
@@ -198,17 +198,17 @@ function prettyVersionDiff(oldVersion, inc) {
for (let i = 0; i < newVersion.length; i++) {
if ((newVersion[i] !== oldVersion[i] && !firstVersionChange)) {
output.push(`${tc.dim.cyan(newVersion[i])}`);
output.push(`${dim(cyan(newVersion[i]))}`);
firstVersionChange = true;
} else if (newVersion[i].indexOf('-') >= 1) {
let preVersion = [];
preVersion = newVersion[i].split('-');
output.push(`${tc.dim.cyan(`${preVersion[0]}-${preVersion[1]}`)}`);
output.push(`${dim(cyan(`${preVersion[0]}-${preVersion[1]}`))}`);
} else {
output.push(tc.reset.dim(newVersion[i]));
output.push(reset(dim(newVersion[i])));
}
}
return output.join(tc.reset.dim('.'));
return output.join(reset(dim('.')));
}
main();

View File

@@ -1,4 +1,4 @@
const tc = require('turbocolor');
const { cyan, red } = require('colorette');
const semver = require('semver');
const execa = require('execa');
const inquirer = require('inquirer');
@@ -47,7 +47,7 @@ async function main() {
console.log(`\nionic ${devVersion} published!! 🎉\n`);
} catch (err) {
console.log('\n', tc.red(err), '\n');
console.log('\n', red(err), '\n');
process.exit(1);
}
@@ -64,7 +64,7 @@ async function askDevVersion(devVersion) {
name: 'confirm',
value: true,
message: () => {
return `Publish the dev build ${tc.cyan(devVersion)}?`;
return `Publish the dev build ${cyan(devVersion)}?`;
}
}
];

View File

@@ -2,7 +2,7 @@
* Deploy script adopted from https://github.com/sindresorhus/np
* MIT License (c) Sindre Sorhus (sindresorhus.com)
*/
const tc = require('turbocolor');
const { cyan, dim, green, red, yellow } = require('colorette');
const execa = require('execa');
const Listr = require('listr');
const path = require('path');
@@ -48,14 +48,14 @@ async function main() {
// Dry run doesn't publish to npm or git
if (dryRun) {
console.log(`
\n${tc.yellow('Did not publish. Remove the "--dry-run" flag to publish:')}\n${tc.green(version)} to ${tc.cyan(npmTag)}\n
\n${yellow('Did not publish. Remove the "--dry-run" flag to publish:')}\n${green(version)} to ${cyan(npmTag)}\n
`);
} else {
console.log(`\nionic ${version} published to ${npmTag}!! 🎉\n`);
}
} catch (err) {
console.log('\n', tc.red(err), '\n');
console.log('\n', red(err), '\n');
process.exit(1);
}
}
@@ -75,7 +75,7 @@ function publishGit(tasks, version, changelog, npmTag) {
tasks.push(
{
title: `Tag latest commit ${tc.dim(`(${gitTag})`)}`,
title: `Tag latest commit ${dim(`(${gitTag})`)}`,
task: () => execa('git', ['tag', `${gitTag}`], { cwd: common.rootDir })
},
{

View File

@@ -1,3 +1,24 @@
## [5.1.1](https://github.com/ionic-team/ionic/compare/v5.1.0...v5.1.1) (2020-05-13)
### Bug Fixes
* **all:** improve scroll assist reliability for below the fold inputs ([#21206](https://github.com/ionic-team/ionic/issues/21206)) ([7166a29](https://github.com/ionic-team/ionic/commit/7166a290cc1dd728e5bab2f7e39b8d41954e3808))
* **all:** overlay components no longer display outline when focused ([#21226](https://github.com/ionic-team/ionic/issues/21226)) ([bb62023](https://github.com/ionic-team/ionic/commit/bb62023a0cdc5a64e956766c7d1704797fc8c9ae))
* **display:** remove 1px gap between mutually exclusive breakpoints ([#21276](https://github.com/ionic-team/ionic/issues/21276)) ([703ef5c](https://github.com/ionic-team/ionic/commit/703ef5c99284f1e2b8d63c3af411c945dc756e20)), closes [#20993](https://github.com/ionic-team/ionic/issues/20993) [#20743](https://github.com/ionic-team/ionic/issues/20743)
* **header:** do not error on collapsible header on devices that do not support IntersectionObserve ([#21222](https://github.com/ionic-team/ionic/issues/21222)) ([0c13f25](https://github.com/ionic-team/ionic/commit/0c13f25bbb4d4674e76cd19b098900f698e7146e))
* **input:** check for tabindex and pass it properly to native input ([#21170](https://github.com/ionic-team/ionic/issues/21170)) ([dd4cb70](https://github.com/ionic-team/ionic/commit/dd4cb706ffeebc2069645ea03f0e7a96d6b14d43)), closes [#17515](https://github.com/ionic-team/ionic/issues/17515)
* **ios:** position page transition shadow properly under footer ([#21095](https://github.com/ionic-team/ionic/issues/21095)) ([50678c0](https://github.com/ionic-team/ionic/commit/50678c03c9829a87408633dabd77b21da1650a84))
* **md:** do not hide page when swipe gesture is cancelled ([#21247](https://github.com/ionic-team/ionic/issues/21247)) ([f334e83](https://github.com/ionic-team/ionic/commit/f334e83a43f855ac1e36eaf73954df6ee27a03af))
* **overlays:** respect keyboardClose property when opening overlays ([#21240](https://github.com/ionic-team/ionic/issues/21240)) ([9d0dcbb](https://github.com/ionic-team/ionic/commit/9d0dcbbd31fc34ad8952eacb9864ad1b31636113))
* **picker:** haptics now work properly ([#21268](https://github.com/ionic-team/ionic/issues/21268)) ([8e11ecc](https://github.com/ionic-team/ionic/commit/8e11ecc136c61e925e76c0e48ab21611e09b5898))
* **refresher:** correctly select shadow root on older browsers ([#21237](https://github.com/ionic-team/ionic/issues/21237)) ([f23f1cb](https://github.com/ionic-team/ionic/commit/f23f1cb37eef02307c357fbb48c0db729974cdc4))
* **refresher:** refresher completes even after switching to a new tab ([#21236](https://github.com/ionic-team/ionic/issues/21236)) ([1e6f923](https://github.com/ionic-team/ionic/commit/1e6f92377aaf0804cfd0ddb9b06da7b4c9dc355f))
* **segment-button:** screen readers now announce selected state properly ([#21273](https://github.com/ionic-team/ionic/issues/21273)) ([85cc35e](https://github.com/ionic-team/ionic/commit/85cc35ee9163a38c48c6df466a3c036906437804))
* **toggle:** screen readers now announce toggle properly ([#21168](https://github.com/ionic-team/ionic/issues/21168)) ([1fbdb22](https://github.com/ionic-team/ionic/commit/1fbdb2255e4ff7fccf22d9ccc12b7f9bb4c3a064))
# [5.1.0 Aluminum](https://github.com/ionic-team/ionic/compare/v5.0.7...v5.1.0) (2020-04-30)

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/angular",
"version": "5.1.0",
"version": "5.1.1",
"description": "Angular specific wrappers for @ionic/core",
"keywords": [
"ionic",
@@ -42,7 +42,7 @@
"validate": "npm i && npm run lint && npm run test && npm run build"
},
"dependencies": {
"@ionic/core": "5.1.0",
"@ionic/core": "5.1.1",
"tslib": "^1.9.3"
},
"peerDependencies": {
@@ -64,7 +64,7 @@
"@types/node": "12.12.5",
"fs-extra": "^7.0.0",
"glob": "^7.1.4",
"ng-packagr": "5.7.1",
"ng-packagr": "^9.1.5",
"rollup": "~1.17.0",
"rollup-plugin-node-resolve": "~5.2.0",
"rxjs": "^6.5.2",

View File

@@ -20,7 +20,7 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
nativeEl: HTMLIonRouterOutletElement;
private activated: ComponentRef<any> | null = null;
private activatedView: RouteView | null = null;
activatedView: RouteView | null = null;
private _activatedRoute: ActivatedRoute | null = null;
private _swipeGesture?: boolean;

View File

@@ -36,11 +36,14 @@ export { GestureController } from './providers/gesture-controller';
// ROUTER STRATEGY
export { IonicRouteStrategy } from './util/ionic-router-reuse-strategy';
// TYPES
export * from './types/ionic-lifecycle-hooks';
// PACKAGE MODULE
export { IonicModule } from './ionic-module';
// UTILS
export { IonicSafeString } from '@ionic/core';
export { IonicSafeString, getPlatforms, isPlatform } from '@ionic/core';
// CORE TYPES
export { Animation, AnimationBuilder, AnimationCallbackOptions, AnimationDirection, AnimationFill, AnimationKeyFrames, AnimationLifecycle, Gesture, GestureConfig, GestureDetail, mdTransitionAnimation, iosTransitionAnimation } from '@ionic/core';

View File

@@ -0,0 +1,31 @@
/**
* https://ionicframework.com/docs/api/router-outlet#life-cycle-hooks
*/
export interface ViewWillEnter {
/**
* Fired when the component routing to is about to animate into view.
*/
ionViewWillEnter(): void;
}
export interface ViewDidEnter {
/**
* Fired when the component routing to has finished animating.
*/
ionViewDidEnter(): void;
}
export interface ViewWillLeave {
/**
* Fired when the component routing from is about to animate.
*/
ionViewWillLeave(): void;
}
export interface ViewDidLeave {
/**
* Fired when the component routing to has finished animating.
*/
ionViewDidLeave(): void;
}

View File

@@ -1,11 +1,11 @@
import { Component, Input, NgZone, OnInit, Optional } from '@angular/core';
import { ModalController, NavParams, IonNav } from '@ionic/angular';
import { ModalController, NavParams, IonNav, ViewWillLeave, ViewDidEnter, ViewDidLeave } from '@ionic/angular';
@Component({
selector: 'app-modal-example',
templateUrl: './modal-example.component.html',
})
export class ModalExampleComponent implements OnInit {
export class ModalExampleComponent implements OnInit, ViewWillLeave, ViewDidEnter, ViewWillLeave, ViewDidLeave {
@Input() value: string;

View File

@@ -1,11 +1,11 @@
import { Component, OnInit, NgZone } from '@angular/core';
import { IonRouterOutlet } from '@ionic/angular';
import { IonRouterOutlet, ViewDidEnter, ViewDidLeave, ViewWillLeave } from '@ionic/angular';
@Component({
selector: 'app-router-link-page',
templateUrl: './router-link-page.component.html',
})
export class RouterLinkPageComponent implements OnInit {
export class RouterLinkPageComponent implements OnInit, ViewWillLeave, ViewDidEnter, ViewWillLeave, ViewDidLeave {
onInit = 0;
willEnter = 0;

View File

@@ -1,12 +1,12 @@
import { Component, NgZone, OnInit } from '@angular/core';
import { NavController } from '@ionic/angular';
import { NavController, ViewDidEnter, ViewDidLeave, ViewWillEnter, ViewWillLeave } from '@ionic/angular';
import { Router } from '@angular/router';
@Component({
selector: 'app-router-link',
templateUrl: './router-link.component.html',
})
export class RouterLinkComponent implements OnInit {
export class RouterLinkComponent implements OnInit, ViewWillEnter, ViewDidEnter, ViewWillLeave, ViewDidLeave {
onInit = 0;
willEnter = 0;

View File

@@ -1,11 +1,12 @@
import { Component, NgZone, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ViewDidEnter, ViewDidLeave, ViewWillEnter, ViewWillLeave } from '@ionic/angular';
@Component({
selector: 'app-virtual-scroll-detail',
templateUrl: './virtual-scroll-detail.component.html',
})
export class VirtualScrollDetailComponent implements OnInit {
export class VirtualScrollDetailComponent implements OnInit, ViewWillEnter, ViewDidEnter, ViewWillLeave, ViewDidLeave {
onInit = 0;
willEnter = 0;

View File

@@ -12,8 +12,8 @@ ion-action-sheet,prop,mode,"ios" | "md",undefined,false,false
ion-action-sheet,prop,subHeader,string | undefined,undefined,false,false
ion-action-sheet,prop,translucent,boolean,false,false,false
ion-action-sheet,method,dismiss,dismiss(data?: any, role?: string | undefined) => Promise<boolean>
ion-action-sheet,method,onDidDismiss,onDidDismiss() => Promise<OverlayEventDetail<any>>
ion-action-sheet,method,onWillDismiss,onWillDismiss() => Promise<OverlayEventDetail<any>>
ion-action-sheet,method,onDidDismiss,onDidDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-action-sheet,method,onWillDismiss,onWillDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-action-sheet,method,present,present() => Promise<void>
ion-action-sheet,event,ionActionSheetDidDismiss,OverlayEventDetail<any>,true
ion-action-sheet,event,ionActionSheetDidPresent,void,true
@@ -58,8 +58,8 @@ ion-alert,prop,mode,"ios" | "md",undefined,false,false
ion-alert,prop,subHeader,string | undefined,undefined,false,false
ion-alert,prop,translucent,boolean,false,false,false
ion-alert,method,dismiss,dismiss(data?: any, role?: string | undefined) => Promise<boolean>
ion-alert,method,onDidDismiss,onDidDismiss() => Promise<OverlayEventDetail<any>>
ion-alert,method,onWillDismiss,onWillDismiss() => Promise<OverlayEventDetail<any>>
ion-alert,method,onDidDismiss,onDidDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-alert,method,onWillDismiss,onWillDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-alert,method,present,present() => Promise<void>
ion-alert,event,ionAlertDidDismiss,OverlayEventDetail<any>,true
ion-alert,event,ionAlertDidPresent,void,true
@@ -438,7 +438,7 @@ ion-infinite-scroll-content,prop,loadingText,IonicSafeString | string | undefine
ion-input,scoped
ion-input,prop,accept,string | undefined,undefined,false,false
ion-input,prop,autocapitalize,string,'off',false,false
ion-input,prop,autocomplete,"off" | "on",'off',false,false
ion-input,prop,autocomplete,"on" | "off" | "name" | "honorific-prefix" | "given-name" | "additional-name" | "family-name" | "honorific-suffix" | "nickname" | "email" | "username" | "new-password" | "current-password" | "one-time-code" | "organization-title" | "organization" | "street-address" | "address-line1" | "address-line2" | "address-line3" | "address-level4" | "address-level3" | "address-level2" | "address-level1" | "country" | "country-name" | "postal-code" | "cc-name" | "cc-given-name" | "cc-additional-name" | "cc-family-name" | "cc-number" | "cc-exp" | "cc-exp-month" | "cc-exp-year" | "cc-csc" | "cc-type" | "transaction-currency" | "transaction-amount" | "language" | "bday" | "bday-day" | "bday-month" | "bday-year" | "sex" | "tel" | "tel-country-code" | "tel-national" | "tel-area-code" | "tel-local" | "tel-extension" | "impp" | "url" | "photo",'off',false,false
ion-input,prop,autocorrect,"off" | "on",'off',false,false
ion-input,prop,autofocus,boolean,false,false,false
ion-input,prop,clearInput,boolean,false,false,false
@@ -612,8 +612,8 @@ ion-loading,prop,showBackdrop,boolean,true,false,false
ion-loading,prop,spinner,"bubbles" | "circles" | "circular" | "crescent" | "dots" | "lines" | "lines-small" | null | undefined,undefined,false,false
ion-loading,prop,translucent,boolean,false,false,false
ion-loading,method,dismiss,dismiss(data?: any, role?: string | undefined) => Promise<boolean>
ion-loading,method,onDidDismiss,onDidDismiss() => Promise<OverlayEventDetail<any>>
ion-loading,method,onWillDismiss,onWillDismiss() => Promise<OverlayEventDetail<any>>
ion-loading,method,onDidDismiss,onDidDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-loading,method,onWillDismiss,onWillDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-loading,method,present,present() => Promise<void>
ion-loading,event,ionLoadingDidDismiss,OverlayEventDetail<any>,true
ion-loading,event,ionLoadingDidPresent,void,true
@@ -695,8 +695,8 @@ 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>>
ion-modal,method,onDidDismiss,onDidDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-modal,method,onWillDismiss,onWillDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-modal,method,present,present() => Promise<void>
ion-modal,event,ionModalDidDismiss,OverlayEventDetail<any>,true
ion-modal,event,ionModalDidPresent,void,true
@@ -761,8 +761,8 @@ ion-picker,prop,mode,"ios" | "md",undefined,false,false
ion-picker,prop,showBackdrop,boolean,true,false,false
ion-picker,method,dismiss,dismiss(data?: any, role?: string | undefined) => Promise<boolean>
ion-picker,method,getColumn,getColumn(name: string) => Promise<PickerColumn | undefined>
ion-picker,method,onDidDismiss,onDidDismiss() => Promise<OverlayEventDetail<any>>
ion-picker,method,onWillDismiss,onWillDismiss() => Promise<OverlayEventDetail<any>>
ion-picker,method,onDidDismiss,onDidDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-picker,method,onWillDismiss,onWillDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-picker,method,present,present() => Promise<void>
ion-picker,event,ionPickerDidDismiss,OverlayEventDetail<any>,true
ion-picker,event,ionPickerDidPresent,void,true
@@ -796,8 +796,8 @@ ion-popover,prop,mode,"ios" | "md",undefined,false,false
ion-popover,prop,showBackdrop,boolean,true,false,false
ion-popover,prop,translucent,boolean,false,false,false
ion-popover,method,dismiss,dismiss(data?: any, role?: string | undefined) => Promise<boolean>
ion-popover,method,onDidDismiss,onDidDismiss() => Promise<OverlayEventDetail<any>>
ion-popover,method,onWillDismiss,onWillDismiss() => Promise<OverlayEventDetail<any>>
ion-popover,method,onDidDismiss,onDidDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-popover,method,onWillDismiss,onWillDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-popover,method,present,present() => Promise<void>
ion-popover,event,ionPopoverDidDismiss,OverlayEventDetail<any>,true
ion-popover,event,ionPopoverDidPresent,void,true
@@ -949,7 +949,7 @@ ion-row,shadow
ion-searchbar,scoped
ion-searchbar,prop,animated,boolean,false,false,false
ion-searchbar,prop,autocomplete,"off" | "on",'off',false,false
ion-searchbar,prop,autocomplete,"on" | "off" | "name" | "honorific-prefix" | "given-name" | "additional-name" | "family-name" | "honorific-suffix" | "nickname" | "email" | "username" | "new-password" | "current-password" | "one-time-code" | "organization-title" | "organization" | "street-address" | "address-line1" | "address-line2" | "address-line3" | "address-level4" | "address-level3" | "address-level2" | "address-level1" | "country" | "country-name" | "postal-code" | "cc-name" | "cc-given-name" | "cc-additional-name" | "cc-family-name" | "cc-number" | "cc-exp" | "cc-exp-month" | "cc-exp-year" | "cc-csc" | "cc-type" | "transaction-currency" | "transaction-amount" | "language" | "bday" | "bday-day" | "bday-month" | "bday-year" | "sex" | "tel" | "tel-country-code" | "tel-national" | "tel-area-code" | "tel-local" | "tel-extension" | "impp" | "url" | "photo",'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,cancelButtonText,string,'Cancel',false,false
@@ -1242,8 +1242,8 @@ ion-toast,prop,mode,"ios" | "md",undefined,false,false
ion-toast,prop,position,"bottom" | "middle" | "top",'bottom',false,false
ion-toast,prop,translucent,boolean,false,false,false
ion-toast,method,dismiss,dismiss(data?: any, role?: string | undefined) => Promise<boolean>
ion-toast,method,onDidDismiss,onDidDismiss() => Promise<OverlayEventDetail<any>>
ion-toast,method,onWillDismiss,onWillDismiss() => Promise<OverlayEventDetail<any>>
ion-toast,method,onDidDismiss,onDidDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-toast,method,onWillDismiss,onWillDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-toast,method,present,present() => Promise<void>
ion-toast,event,ionToastDidDismiss,OverlayEventDetail<any>,true
ion-toast,event,ionToastDidPresent,void,true

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/core",
"version": "5.1.0",
"version": "5.1.1",
"description": "Base components for Ionic",
"keywords": [
"ionic",
@@ -34,12 +34,12 @@
"tslib": "^1.10.0"
},
"devDependencies": {
"@stencil/core": "1.12.4",
"@stencil/core": "1.13.0",
"@stencil/sass": "1.3.1",
"@types/jest": "24.9.1",
"@types/node": "12.12.3",
"@types/puppeteer": "1.19.1",
"@types/swiper": "5.2.1",
"@types/swiper": "5.3.1",
"aws-sdk": "^2.497.0",
"clean-css-cli": "^4.1.11",
"domino": "^2.1.3",
@@ -55,7 +55,7 @@
"sass": "^1.22.9",
"stylelint": "10.1.0",
"stylelint-order": "3.0.1",
"swiper": "5.3.7",
"swiper": "5.4.1",
"tslint": "^5.10.0",
"tslint-ionic-rules": "0.0.21",
"tslint-react": "^3.6.0"
@@ -65,6 +65,7 @@
"build.vendor": "rollup --config ./scripts/swiper.rollup.config.js",
"build.css": "npm run css.sass && npm run css.minify",
"build.debug": "npm run clean && stencil build --debug",
"build.docs": "stencil build --docs",
"build.docs.json": "stencil build --docs-json dist/docs.json",
"clean": "node scripts/clean.js",
"cdnloader": "node scripts/copy-cdn-loader.js",

View File

@@ -5,8 +5,8 @@
* It contains typing information for all components that exist in this project.
*/
import { HTMLStencilElement, JSXBase } from "@stencil/core/internal";
import { ActionSheetButton, AlertButton, AlertInput, AnimationBuilder, CheckboxChangeEventDetail, Color, ComponentProps, ComponentRef, DatetimeChangeEventDetail, DatetimeOptions, DomRenderFn, FooterHeightFn, FrameworkDelegate, HeaderFn, HeaderHeightFn, InputChangeEventDetail, ItemHeightFn, ItemRenderFn, ItemReorderEventDetail, MenuChangeEventDetail, NavComponent, NavOptions, OverlayEventDetail, PickerButton, PickerColumn, RadioGroupChangeEventDetail, RangeChangeEventDetail, RangeValue, RefresherEventDetail, RouteID, RouterDirection, RouterEventDetail, RouterOutletOptions, RouteWrite, ScrollBaseDetail, ScrollDetail, SearchbarChangeEventDetail, SegmentButtonLayout, SegmentChangeEventDetail, SelectChangeEventDetail, SelectInterface, SelectPopoverOption, Side, SpinnerTypes, StyleEventDetail, SwipeGestureHandler, TabBarChangedEventDetail, TabButtonClickEventDetail, TabButtonLayout, TextareaChangeEventDetail, TextFieldTypes, ToastButton, ToggleChangeEventDetail, TransitionDoneFn, TransitionInstruction, ViewController, } from "./interface";
import { IonicSafeString, } from ".";
import { ActionSheetButton, AlertButton, AlertInput, AnimationBuilder, AutocompleteTypes, CheckboxChangeEventDetail, Color, ComponentProps, ComponentRef, DatetimeChangeEventDetail, DatetimeOptions, DomRenderFn, FooterHeightFn, FrameworkDelegate, HeaderFn, HeaderHeightFn, InputChangeEventDetail, ItemHeightFn, ItemRenderFn, ItemReorderEventDetail, MenuChangeEventDetail, NavComponent, NavOptions, OverlayEventDetail, PickerButton, PickerColumn, RadioGroupChangeEventDetail, RangeChangeEventDetail, RangeValue, RefresherEventDetail, RouteID, RouterDirection, RouterEventDetail, RouterOutletOptions, RouteWrite, ScrollBaseDetail, ScrollDetail, SearchbarChangeEventDetail, SegmentButtonLayout, SegmentChangeEventDetail, SelectChangeEventDetail, SelectInterface, SelectPopoverOption, Side, SpinnerTypes, StyleEventDetail, SwipeGestureHandler, TabBarChangedEventDetail, TabButtonClickEventDetail, TabButtonLayout, TextareaChangeEventDetail, TextFieldTypes, ToastButton, ToggleChangeEventDetail, TransitionDoneFn, TransitionInstruction, ViewController, } from "./interface";
import { IonicSafeString, } from "./utils/sanitization";
import { SelectCompareFn, } from "./components/select/select-interface";
export namespace Components {
interface IonActionSheet {
@@ -55,11 +55,11 @@ export namespace Components {
/**
* Returns a promise that resolves when the action sheet did dismiss.
*/
"onDidDismiss": () => Promise<OverlayEventDetail<any>>;
"onDidDismiss": <T = any>() => Promise<OverlayEventDetail<T>>;
/**
* Returns a promise that resolves when the action sheet will dismiss.
*/
"onWillDismiss": () => Promise<OverlayEventDetail<any>>;
"onWillDismiss": <T = any>() => Promise<OverlayEventDetail<T>>;
"overlayIndex": number;
/**
* Present the action sheet overlay after it has been created.
@@ -128,11 +128,11 @@ export namespace Components {
/**
* Returns a promise that resolves when the alert did dismiss.
*/
"onDidDismiss": () => Promise<OverlayEventDetail<any>>;
"onDidDismiss": <T = any>() => Promise<OverlayEventDetail<T>>;
/**
* Returns a promise that resolves when the alert will dismiss.
*/
"onWillDismiss": () => Promise<OverlayEventDetail<any>>;
"onWillDismiss": <T = any>() => Promise<OverlayEventDetail<T>>;
"overlayIndex": number;
/**
* Present the alert overlay after it has been created.
@@ -561,7 +561,7 @@ export namespace Components {
*/
"dayNames"?: string[] | string;
/**
* Short abbreviated day of the week names. This can be used to provide locale names for each day in the week. Defaults to English.
* Short abbreviated day of the week names. This can be used to provide locale names for each day in the week. Defaults to English. Defaults to: `['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']`
*/
"dayShortNames"?: string[] | string;
/**
@@ -815,7 +815,7 @@ export namespace Components {
/**
* Indicates whether the value of the control can be automatically completed by the browser.
*/
"autocomplete": "on" | "off";
"autocomplete": AutocompleteTypes;
/**
* Whether auto correction should be enabled when the user is entering/editing the text value.
*/
@@ -1159,11 +1159,11 @@ export namespace Components {
/**
* Returns a promise that resolves when the loading did dismiss.
*/
"onDidDismiss": () => Promise<OverlayEventDetail<any>>;
"onDidDismiss": <T = any>() => Promise<OverlayEventDetail<T>>;
/**
* Returns a promise that resolves when the loading will dismiss.
*/
"onWillDismiss": () => Promise<OverlayEventDetail<any>>;
"onWillDismiss": <T = any>() => Promise<OverlayEventDetail<T>>;
"overlayIndex": number;
/**
* Present the loading overlay after it has been created.
@@ -1315,11 +1315,11 @@ export namespace Components {
/**
* Returns a promise that resolves when the modal did dismiss.
*/
"onDidDismiss": () => Promise<OverlayEventDetail<any>>;
"onDidDismiss": <T = any>() => Promise<OverlayEventDetail<T>>;
/**
* Returns a promise that resolves when the modal will dismiss.
*/
"onWillDismiss": () => Promise<OverlayEventDetail<any>>;
"onWillDismiss": <T = any>() => Promise<OverlayEventDetail<T>>;
"overlayIndex": number;
/**
* Present the modal overlay after it has been created.
@@ -1528,11 +1528,11 @@ export namespace Components {
/**
* Returns a promise that resolves when the picker did dismiss.
*/
"onDidDismiss": () => Promise<OverlayEventDetail<any>>;
"onDidDismiss": <T = any>() => Promise<OverlayEventDetail<T>>;
/**
* Returns a promise that resolves when the picker will dismiss.
*/
"onWillDismiss": () => Promise<OverlayEventDetail<any>>;
"onWillDismiss": <T = any>() => Promise<OverlayEventDetail<T>>;
"overlayIndex": number;
/**
* Present the picker overlay after it has been created.
@@ -1600,11 +1600,11 @@ export namespace Components {
/**
* Returns a promise that resolves when the popover did dismiss.
*/
"onDidDismiss": () => Promise<OverlayEventDetail<any>>;
"onDidDismiss": <T = any>() => Promise<OverlayEventDetail<T>>;
/**
* Returns a promise that resolves when the popover will dismiss.
*/
"onWillDismiss": () => Promise<OverlayEventDetail<any>>;
"onWillDismiss": <T = any>() => Promise<OverlayEventDetail<T>>;
"overlayIndex": number;
/**
* Present the popover overlay after it has been created.
@@ -1915,7 +1915,7 @@ export namespace Components {
/**
* Set the input's autocomplete property.
*/
"autocomplete": "on" | "off";
"autocomplete": AutocompleteTypes;
/**
* Set the input's autocorrect property.
*/
@@ -2510,11 +2510,11 @@ export namespace Components {
/**
* Returns a promise that resolves when the toast did dismiss.
*/
"onDidDismiss": () => Promise<OverlayEventDetail<any>>;
"onDidDismiss": <T = any>() => Promise<OverlayEventDetail<T>>;
/**
* Returns a promise that resolves when the toast will dismiss.
*/
"onWillDismiss": () => Promise<OverlayEventDetail<any>>;
"onWillDismiss": <T = any>() => Promise<OverlayEventDetail<T>>;
"overlayIndex": number;
/**
* The position of the toast on the screen.
@@ -3801,7 +3801,7 @@ declare namespace LocalJSX {
*/
"dayNames"?: string[] | string;
/**
* Short abbreviated day of the week names. This can be used to provide locale names for each day in the week. Defaults to English.
* Short abbreviated day of the week names. This can be used to provide locale names for each day in the week. Defaults to English. Defaults to: `['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']`
*/
"dayShortNames"?: string[] | string;
/**
@@ -4083,7 +4083,7 @@ declare namespace LocalJSX {
/**
* Indicates whether the value of the control can be automatically completed by the browser.
*/
"autocomplete"?: "on" | "off";
"autocomplete"?: AutocompleteTypes;
/**
* Whether auto correction should be enabled when the user is entering/editing the text value.
*/
@@ -5081,7 +5081,7 @@ declare namespace LocalJSX {
/**
* Set the input's autocomplete property.
*/
"autocomplete"?: "on" | "off";
"autocomplete"?: AutocompleteTypes;
/**
* Set the input's autocorrect property.
*/

View File

@@ -21,5 +21,5 @@ export interface ActionSheetButton {
role?: 'cancel' | 'destructive' | 'selected' | string;
icon?: string;
cssClass?: string | string[];
handler?: () => boolean | void | Promise<boolean>;
handler?: () => boolean | void | Promise<boolean | void>;
}

View File

@@ -134,6 +134,8 @@
@include margin-horizontal(null, $action-sheet-ios-button-icon-padding-right);
font-size: $action-sheet-ios-button-icon-font-size;
pointer-events: none;
}
.action-sheet-button:last-child {

View File

@@ -52,6 +52,8 @@
display: block;
position: fixed;
outline: none;
font-family: $font-family-base;
touch-action: none;
@@ -110,6 +112,7 @@
flex-shrink: 0;
align-items: center;
justify-content: center;
pointer-events: none;
width: 100%;
height: 100%;
@@ -210,4 +213,4 @@
opacity: var(--button-background-hover-opacity);
}
}
}
}

View File

@@ -1,7 +1,9 @@
import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Method, Prop, h } from '@stencil/core';
import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Method, Prop, h, readTask } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { ActionSheetButton, AnimationBuilder, CssClassMap, OverlayEventDetail, OverlayInterface } from '../../interface';
import { Gesture } from '../../utils/gesture';
import { createButtonActiveGesture } from '../../utils/gesture/button-active';
import { BACKDROP, dismiss, eventMethod, isCancel, prepareOverlay, present, safeCall } from '../../utils/overlays';
import { getClassMap } from '../../utils/theme';
@@ -25,6 +27,9 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
presented = false;
animation?: any;
private wrapperEl?: HTMLElement;
private groupEl?: HTMLElement;
private gesture?: Gesture;
@Element() el!: HTMLIonActionSheetElement;
@@ -134,7 +139,7 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
* Returns a promise that resolves when the action sheet did dismiss.
*/
@Method()
onDidDismiss(): Promise<OverlayEventDetail> {
onDidDismiss<T = any>(): Promise<OverlayEventDetail<T>> {
return eventMethod(this.el, 'ionActionSheetDidDismiss');
}
@@ -143,7 +148,7 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
*
*/
@Method()
onWillDismiss(): Promise<OverlayEventDetail> {
onWillDismiss<T = any>(): Promise<OverlayEventDetail<T>> {
return eventMethod(this.el, 'ionActionSheetWillDismiss');
}
@@ -192,6 +197,35 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
}
}
componentDidUnload() {
if (this.gesture) {
this.gesture.destroy();
this.gesture = undefined;
}
}
componentDidLoad() {
/**
* Do not create gesture if:
* 1. A gesture already exists
* 2. App is running in MD mode
* 3. A wrapper ref does not exist
*/
const { groupEl, wrapperEl } = this;
if (this.gesture || getIonMode(this) === 'md' || !wrapperEl || !groupEl) { return; }
readTask(() => {
const isScrollable = groupEl.scrollHeight > groupEl.clientHeight;
if (!isScrollable) {
this.gesture = createButtonActiveGesture(
wrapperEl,
(refEl: HTMLElement) => refEl.classList.contains('action-sheet-button')
);
this.gesture.enable(true);
}
});
}
render() {
const mode = getIonMode(this);
const allButtons = this.getButtons();
@@ -216,9 +250,9 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
onIonBackdropTap={this.onBackdropTap}
>
<ion-backdrop tappable={this.backdropDismiss}/>
<div class="action-sheet-wrapper" role="dialog">
<div class="action-sheet-wrapper ion-wrapper" role="dialog" ref={el => this.wrapperEl = el}>
<div class="action-sheet-container">
<div class="action-sheet-group">
<div class="action-sheet-group" ref={el => this.groupEl = el}>
{this.header !== undefined &&
<div class="action-sheet-title">
{this.header}

View File

@@ -2,10 +2,38 @@
An Action Sheet is a dialog that displays a set of options. It appears on top of the app's content, and must be manually dismissed by the user before they can resume interaction with the app. Destructive options are made obvious in `ios` mode. There are multiple ways to dismiss the action sheet, including tapping the backdrop or hitting the escape key on desktop.
### Buttons
## Buttons
A button's `role` property can either be `destructive` or `cancel`. Buttons without a role property will have the default look for the platform. Buttons with the `cancel` role will always load as the bottom button, no matter where they are in the array. All other buttons will be displayed in the order they have been added to the `buttons` array. Note: We recommend that `destructive` buttons are always the first button in the array, making them the top button. Additionally, if the action sheet is dismissed by tapping the backdrop, then it will fire the handler from the button with the cancel role.
## Customization
Action Sheet uses scoped encapsulation, which means it will automatically scope its CSS by appending each of the styles with an additional class at runtime. Overriding scoped selectors in CSS requires a [higher specificity](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity) selector.
We recommend passing a custom class to `cssClass` in the `create` method and using that to add custom styles to the host and inner elements. This property can also accept multiple classes separated by spaces. View the [Usage](#usage) section for an example of how to pass a class using `cssClass`.
```css
/* DOES NOT WORK - not specific enough */
.action-sheet-group {
background: #e5e5e5;
}
/* Works - pass "my-custom-class" in cssClass to increase specificity */
.my-custom-class .action-sheet-group {
background: #e5e5e5;
}
```
Any of the defined [CSS Custom Properties](#css-custom-properties) can be used to style the Action Sheet without needing to target individual elements:
```css
.my-custom-class {
--background: #e5e5e5;
}
```
> If you are building an Ionic Angular app, the styles need to be added to a global stylesheet file. Read [Style Placement](#style-placement) in the Angular section below for more information.
<!-- Auto Generated Below -->
@@ -30,6 +58,7 @@ export class ActionSheetExample {
async presentActionSheet() {
const actionSheet = await this.actionSheetController.create({
header: 'Albums',
cssClass: 'my-custom-class',
buttons: [{
text: 'Delete',
role: 'destructive',
@@ -45,7 +74,7 @@ export class ActionSheetExample {
}
}, {
text: 'Play (open modal)',
icon: 'arrow-dropright-circle',
icon: 'caret-forward-circle',
handler: () => {
console.log('Play clicked');
}
@@ -71,14 +100,19 @@ export class ActionSheetExample {
```
### Style Placement
In Angular, the CSS of a specific page is scoped only to elements of that page. Even though the Action Sheet can be presented from within a page, the `ion-action-sheet` element is appended outside of the current page. This means that any custom styles need to go in a global stylesheet file. In an Ionic Angular starter this can be the `src/global.scss` file or you can register a new global style file by [adding to the `styles` build option in `angular.json`](https://angular.io/guide/workspace-config#style-script-config).
### Javascript
```javascript
async function presentActionSheet() {
const actionSheet = document.createElement('ion-action-sheet');
actionSheet.header = "Albums";
actionSheet.header = 'Albums';
actionSheet.cssClass = 'my-custom-class';
actionSheet.buttons = [{
text: 'Delete',
role: 'destructive',
@@ -94,7 +128,7 @@ async function presentActionSheet() {
}
}, {
text: 'Play (open modal)',
icon: 'arrow-dropright-circle',
icon: 'caret-forward-circle',
handler: () => {
console.log('Play clicked');
}
@@ -120,21 +154,23 @@ async function presentActionSheet() {
### React
```typescript
import React, { useState } from 'react'
```tsx
import React, { useState } from 'react';
import { IonActionSheet, IonContent, IonButton } from '@ionic/react';
import { trash, share, playCircleOutline, heart, close } from 'ionicons/icons';
import { trash, share, caretForwardCircle, heart, close } from 'ionicons/icons';
export const ActionSheetExample: React.FC = () => {
const [showActionSheet, setShowActionSheet] = useState(false);
return (
<IonContent>
<IonButton onClick={() => setShowActionSheet(true)} expand="block">Show Action Sheet</IonButton>
<IonButton onClick={() => setShowActionSheet(true)} expand="block">
Show Action Sheet
</IonButton>
<IonActionSheet
isOpen={showActionSheet}
onDidDismiss={() => setShowActionSheet(false)}
cssClass='my-custom-class'
buttons={[{
text: 'Delete',
role: 'destructive',
@@ -150,7 +186,7 @@ export const ActionSheetExample: React.FC = () => {
}
}, {
text: 'Play (open modal)',
icon: playCircleOutline,
icon: caretForwardCircle,
handler: () => {
console.log('Play clicked');
}
@@ -171,11 +207,72 @@ export const ActionSheetExample: React.FC = () => {
>
</IonActionSheet>
</IonContent>
);
}
```
### Stencil
```tsx
import { Component, h } from '@stencil/core';
import { actionSheetController } from '@ionic/core';
@Component({
tag: 'action-sheet-example',
styleUrl: 'action-sheet-example.css'
})
export class ActionSheetExample {
async presentActionSheet() {
const actionSheet = await actionSheetController.create({
header: 'Albums',
cssClass: 'my-custom-class',
buttons: [{
text: 'Delete',
role: 'destructive',
icon: 'trash',
handler: () => {
console.log('Delete clicked');
}
}, {
text: 'Share',
icon: 'share',
handler: () => {
console.log('Share clicked');
}
}, {
text: 'Play (open modal)',
icon: 'caret-forward-circle',
handler: () => {
console.log('Play clicked');
}
}, {
text: 'Favorite',
icon: 'heart',
handler: () => {
console.log('Favorite clicked');
}
}, {
text: 'Cancel',
icon: 'close',
role: 'cancel',
handler: () => {
console.log('Cancel clicked');
}
}]
});
await actionSheet.present();
}
render() {
return [
<ion-content>
<ion-button onClick={() => this.presentActionSheet()}>Present Action Sheet</ion-button>
</ion-content>
];
}
}
```
@@ -195,6 +292,7 @@ export default {
return this.$ionic.actionSheetController
.create({
header: 'Albums',
cssClass: 'my-custom-class',
buttons: [
{
text: 'Delete',
@@ -213,7 +311,7 @@ export default {
},
{
text: 'Play (open modal)',
icon: 'arrow-dropright-circle',
icon: 'caret-forward-circle',
handler: () => {
console.log('Play clicked')
},
@@ -283,23 +381,23 @@ Type: `Promise<boolean>`
### `onDidDismiss() => Promise<OverlayEventDetail<any>>`
### `onDidDismiss<T = any>() => Promise<OverlayEventDetail<T>>`
Returns a promise that resolves when the action sheet did dismiss.
#### Returns
Type: `Promise<OverlayEventDetail<any>>`
Type: `Promise<OverlayEventDetail<T>>`
### `onWillDismiss() => Promise<OverlayEventDetail<any>>`
### `onWillDismiss<T = any>() => Promise<OverlayEventDetail<T>>`
Returns a promise that resolves when the action sheet will dismiss.
#### Returns
Type: `Promise<OverlayEventDetail<any>>`
Type: `Promise<OverlayEventDetail<T>>`

View File

@@ -14,6 +14,7 @@ export class ActionSheetExample {
async presentActionSheet() {
const actionSheet = await this.actionSheetController.create({
header: 'Albums',
cssClass: 'my-custom-class',
buttons: [{
text: 'Delete',
role: 'destructive',
@@ -29,7 +30,7 @@ export class ActionSheetExample {
}
}, {
text: 'Play (open modal)',
icon: 'arrow-dropright-circle',
icon: 'caret-forward-circle',
handler: () => {
console.log('Play clicked');
}
@@ -53,3 +54,8 @@ export class ActionSheetExample {
}
```
### Style Placement
In Angular, the CSS of a specific page is scoped only to elements of that page. Even though the Action Sheet can be presented from within a page, the `ion-action-sheet` element is appended outside of the current page. This means that any custom styles need to go in a global stylesheet file. In an Ionic Angular starter this can be the `src/global.scss` file or you can register a new global style file by [adding to the `styles` build option in `angular.json`](https://angular.io/guide/workspace-config#style-script-config).

View File

@@ -1,9 +1,9 @@
```javascript
async function presentActionSheet() {
const actionSheet = document.createElement('ion-action-sheet');
actionSheet.header = "Albums";
actionSheet.header = 'Albums';
actionSheet.cssClass = 'my-custom-class';
actionSheet.buttons = [{
text: 'Delete',
role: 'destructive',
@@ -19,7 +19,7 @@ async function presentActionSheet() {
}
}, {
text: 'Play (open modal)',
icon: 'arrow-dropright-circle',
icon: 'caret-forward-circle',
handler: () => {
console.log('Play clicked');
}

View File

@@ -1,18 +1,20 @@
```typescript
import React, { useState } from 'react'
```tsx
import React, { useState } from 'react';
import { IonActionSheet, IonContent, IonButton } from '@ionic/react';
import { trash, share, playCircleOutline, heart, close } from 'ionicons/icons';
import { trash, share, caretForwardCircle, heart, close } from 'ionicons/icons';
export const ActionSheetExample: React.FC = () => {
const [showActionSheet, setShowActionSheet] = useState(false);
return (
<IonContent>
<IonButton onClick={() => setShowActionSheet(true)} expand="block">Show Action Sheet</IonButton>
<IonButton onClick={() => setShowActionSheet(true)} expand="block">
Show Action Sheet
</IonButton>
<IonActionSheet
isOpen={showActionSheet}
onDidDismiss={() => setShowActionSheet(false)}
cssClass='my-custom-class'
buttons={[{
text: 'Delete',
role: 'destructive',
@@ -28,7 +30,7 @@ export const ActionSheetExample: React.FC = () => {
}
}, {
text: 'Play (open modal)',
icon: playCircleOutline,
icon: caretForwardCircle,
handler: () => {
console.log('Play clicked');
}
@@ -49,9 +51,6 @@ export const ActionSheetExample: React.FC = () => {
>
</IonActionSheet>
</IonContent>
);
}
```

View File

@@ -0,0 +1,60 @@
```tsx
import { Component, h } from '@stencil/core';
import { actionSheetController } from '@ionic/core';
@Component({
tag: 'action-sheet-example',
styleUrl: 'action-sheet-example.css'
})
export class ActionSheetExample {
async presentActionSheet() {
const actionSheet = await actionSheetController.create({
header: 'Albums',
cssClass: 'my-custom-class',
buttons: [{
text: 'Delete',
role: 'destructive',
icon: 'trash',
handler: () => {
console.log('Delete clicked');
}
}, {
text: 'Share',
icon: 'share',
handler: () => {
console.log('Share clicked');
}
}, {
text: 'Play (open modal)',
icon: 'caret-forward-circle',
handler: () => {
console.log('Play clicked');
}
}, {
text: 'Favorite',
icon: 'heart',
handler: () => {
console.log('Favorite clicked');
}
}, {
text: 'Cancel',
icon: 'close',
role: 'cancel',
handler: () => {
console.log('Cancel clicked');
}
}]
});
await actionSheet.present();
}
render() {
return [
<ion-content>
<ion-button onClick={() => this.presentActionSheet()}>Present Action Sheet</ion-button>
</ion-content>
];
}
}
```

View File

@@ -12,6 +12,7 @@ export default {
return this.$ionic.actionSheetController
.create({
header: 'Albums',
cssClass: 'my-custom-class',
buttons: [
{
text: 'Delete',
@@ -30,7 +31,7 @@ export default {
},
{
text: 'Play (open modal)',
icon: 'arrow-dropright-circle',
icon: 'caret-forward-circle',
handler: () => {
console.log('Play clicked')
},

View File

@@ -1,5 +1,7 @@
import { IonicSafeString } from '../../';
import { JSXBase } from '@stencil/core/internal';
import { AnimationBuilder, Mode, TextFieldTypes } from '../../interface';
import { IonicSafeString } from '../../utils/sanitization';
export interface AlertOptions {
header?: string;
@@ -32,8 +34,13 @@ export interface AlertInput {
handler?: (input: AlertInput) => void;
min?: string | number;
max?: string | number;
cssClass?: string | string[];
attributes?: AlertInputAttributes | AlertTextareaAttributes;
}
export interface AlertTextareaAttributes extends JSXBase.TextareaHTMLAttributes<HTMLTextAreaElement> {}
export interface AlertInputAttributes extends JSXBase.InputHTMLAttributes<HTMLInputElement> {}
export interface AlertButton {
text: string;
role?: string;

View File

@@ -19,6 +19,10 @@
overflow: hidden;
}
.alert-button .alert-button-inner {
pointer-events: none;
}
// iOS Translucent Alert
// -----------------------------------------
@@ -301,3 +305,12 @@
.alert-button.ion-activated {
background-color: $alert-ios-button-background-color-activated;
}
// iOS Action Sheet Button: Destructive
// ---------------------------------------------------
.alert-button-role-destructive,
.alert-button-role-destructive.ion-activated,
.alert-button-role-destructive.ion-focused {
color: $alert-ios-button-destructive-text-color;
}

View File

@@ -145,6 +145,9 @@ $alert-ios-button-font-size: 17px !default;
/// @prop - Color of the text in the alert button
$alert-ios-button-text-color: ion-color(primary, base) !default;
/// @prop - Destructive text color of the alert button
$alert-ios-button-destructive-text-color: ion-color(danger, base) !default;
/// @prop - Background color of the alert button
$alert-ios-button-background-color: transparent !default;

View File

@@ -32,6 +32,8 @@
align-items: center;
justify-content: center;
outline: none;
font-family: $font-family-base;
contain: strict;

View File

@@ -1,10 +1,11 @@
import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Method, Prop, Watch, forceUpdate, h } from '@stencil/core';
import { IonicSafeString } from '../../';
import { getIonMode } from '../../global/ionic-global';
import { AlertButton, AlertInput, AnimationBuilder, CssClassMap, OverlayEventDetail, OverlayInterface } from '../../interface';
import { AlertButton, AlertInput, AlertInputAttributes, AlertTextareaAttributes, AnimationBuilder, CssClassMap, OverlayEventDetail, OverlayInterface } from '../../interface';
import { Gesture } from '../../utils/gesture';
import { createButtonActiveGesture } from '../../utils/gesture/button-active';
import { BACKDROP, dismiss, eventMethod, isCancel, prepareOverlay, present, safeCall } from '../../utils/overlays';
import { sanitizeDOMString } from '../../utils/sanitization';
import { IonicSafeString, sanitizeDOMString } from '../../utils/sanitization';
import { getClassMap } from '../../utils/theme';
import { iosEnterAnimation } from './animations/ios.enter';
@@ -29,6 +30,8 @@ export class Alert implements ComponentInterface, OverlayInterface {
private inputType?: string;
private processedInputs: AlertInput[] = [];
private processedButtons: AlertButton[] = [];
private wrapperEl?: HTMLElement;
private gesture?: Gesture;
presented = false;
@@ -158,7 +161,9 @@ export class Alert implements ComponentInterface, OverlayInterface {
id: i.id || `alert-input-${this.overlayIndex}-${index}`,
handler: i.handler,
min: i.min,
max: i.max
max: i.max,
cssClass: i.cssClass || '',
attributes: i.attributes || {},
}) as AlertInput);
}
@@ -171,6 +176,29 @@ export class Alert implements ComponentInterface, OverlayInterface {
this.buttonsChanged();
}
componentDidUnload() {
if (this.gesture) {
this.gesture.destroy();
this.gesture = undefined;
}
}
componentDidLoad() {
/**
* Do not create gesture if:
* 1. A gesture already exists
* 2. App is running in MD mode
* 3. A wrapper ref does not exist
*/
if (this.gesture || getIonMode(this) === 'md' || !this.wrapperEl) { return; }
this.gesture = createButtonActiveGesture(
this.wrapperEl,
(refEl: HTMLElement) => refEl.classList.contains('alert-button')
);
this.gesture.enable(true);
}
/**
* Present the alert overlay after it has been created.
*/
@@ -197,7 +225,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
* Returns a promise that resolves when the alert did dismiss.
*/
@Method()
onDidDismiss(): Promise<OverlayEventDetail> {
onDidDismiss<T = any>(): Promise<OverlayEventDetail<T>> {
return eventMethod(this.el, 'ionAlertDidDismiss');
}
@@ -205,7 +233,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
* Returns a promise that resolves when the alert will dismiss.
*/
@Method()
onWillDismiss(): Promise<OverlayEventDetail> {
onWillDismiss<T = any>(): Promise<OverlayEventDetail<T>> {
return eventMethod(this.el, 'ionAlertWillDismiss');
}
@@ -307,6 +335,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
tabIndex={0}
role="checkbox"
class={{
...getClassMap(i.cssClass),
'alert-tappable': true,
'alert-checkbox': true,
'alert-checkbox-button': true,
@@ -345,6 +374,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
id={i.id}
tabIndex={0}
class={{
...getClassMap(i.cssClass),
'alert-radio-button': true,
'alert-tappable': true,
'alert-radio': true,
@@ -379,13 +409,14 @@ export class Alert implements ComponentInterface, OverlayInterface {
<textarea
placeholder={i.placeholder}
value={i.value}
onInput={e => i.value = (e.target as any).value}
id={i.id}
disabled={i.disabled}
tabIndex={0}
class={{
'alert-input': true,
'alert-input-disabled': i.disabled || false
{...i.attributes as AlertTextareaAttributes}
disabled={i.attributes?.disabled ?? i.disabled}
class={inputClass(i)}
onInput={e => {
i.value = (e.target as any).value;
if (i.attributes?.onInput) { i.attributes.onInput(e); }
}}
/>
</div>
@@ -395,17 +426,18 @@ export class Alert implements ComponentInterface, OverlayInterface {
<div class="alert-input-wrapper">
<input
placeholder={i.placeholder}
value={i.value}
type={i.type}
min={i.min}
max={i.max}
onInput={e => i.value = (e.target as any).value}
value={i.value}
id={i.id}
disabled={i.disabled}
tabIndex={0}
class={{
'alert-input': true,
'alert-input-disabled': i.disabled || false
{...i.attributes as AlertInputAttributes}
disabled={i.attributes?.disabled ?? i.disabled}
class={inputClass(i)}
onInput={e => {
i.value = (e.target as any).value;
if (i.attributes?.onInput) { i.attributes.onInput(e); }
}}
/>
</div>
@@ -482,7 +514,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
<ion-backdrop tappable={this.backdropDismiss}/>
<div class="alert-wrapper">
<div class="alert-wrapper ion-wrapper" ref={el => this.wrapperEl = el}>
<div class="alert-head">
{header && <h2 id={hdrId} class="alert-title">{header}</h2>}
@@ -500,11 +532,21 @@ export class Alert implements ComponentInterface, OverlayInterface {
}
}
const inputClass = (input: AlertInput): CssClassMap => {
return {
'alert-input': true,
'alert-input-disabled': (input.attributes?.disabled ?? input.disabled) || false,
...getClassMap(input.cssClass),
...getClassMap(input.attributes ? input.attributes.class?.toString() : ''),
};
};
const buttonClass = (button: AlertButton): CssClassMap => {
return {
'alert-button': true,
'ion-focusable': true,
'ion-activatable': true,
[`alert-button-role-${button.role}`]: button.role !== undefined,
...getClassMap(button.cssClass)
};
};

View File

@@ -2,17 +2,45 @@
An Alert is a dialog that presents users with information or collects information from the user using inputs. An alert appears on top of the app's content, and must be manually dismissed by the user before they can resume interaction with the app. It can also optionally have a `header`, `subHeader` and `message`.
### Buttons
## Buttons
In the array of `buttons`, each button includes properties for its `text`, and optionally a `handler`. If a handler returns `false` then the alert will not automatically be dismissed when the button is clicked. All buttons will show up in the order they have been added to the `buttons` array from left to right. Note: The right most button (the last one in the array) is the main button.
Optionally, a `role` property can be added to a button, such as `cancel`. If a `cancel` role is on one of the buttons, then if the alert is dismissed by tapping the backdrop, then it will fire the handler from the button with a cancel role.
### Inputs
## Inputs
Alerts can also include several different inputs whose data can be passed back to the app. Inputs can be used as a simple way to prompt users for information. Radios, checkboxes and text inputs are all accepted, but they cannot be mixed. For example, an alert could have all radio button inputs, or all checkbox inputs, but the same alert cannot mix radio and checkbox inputs. Do note however, different types of "text" inputs can be mixed, such as `url`, `email`, `text`, `textarea` etc. If you require a complex form UI which doesn't fit within the guidelines of an alert then we recommend building the form within a modal instead.
## Customization
Alert uses scoped encapsulation, which means it will automatically scope its CSS by appending each of the styles with an additional class at runtime. Overriding scoped selectors in CSS requires a [higher specificity](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity) selector.
We recommend passing a custom class to `cssClass` in the `create` method and using that to add custom styles to the host and inner elements. This property can also accept multiple classes separated by spaces. View the [Usage](#usage) section for an example of how to pass a class using `cssClass`.
```css
/* DOES NOT WORK - not specific enough */
.alert-wrapper {
background: #e5e5e5;
}
/* Works - pass "my-custom-class" in cssClass to increase specificity */
.my-custom-class .alert-wrapper {
background: #e5e5e5;
}
```
Any of the defined [CSS Custom Properties](#css-custom-properties) can be used to style the Alert without needing to target individual elements:
```css
.my-custom-class {
--background: #e5e5e5;
}
```
> If you are building an Ionic Angular app, the styles need to be added to a global stylesheet file. Read [Style Placement](#style-placement) in the Angular section below for more information.
<!-- Auto Generated Below -->
@@ -36,6 +64,7 @@ export class AlertExample {
async presentAlert() {
const alert = await this.alertController.create({
cssClass: 'my-custom-class',
header: 'Alert',
subHeader: 'Subtitle',
message: 'This is an alert message.',
@@ -47,6 +76,7 @@ export class AlertExample {
async presentAlertMultipleButtons() {
const alert = await this.alertController.create({
cssClass: 'my-custom-class',
header: 'Alert',
subHeader: 'Subtitle',
message: 'This is an alert message.',
@@ -58,6 +88,7 @@ export class AlertExample {
async presentAlertConfirm() {
const alert = await this.alertController.create({
cssClass: 'my-custom-class',
header: 'Confirm!',
message: 'Message <strong>text</strong>!!!',
buttons: [
@@ -82,6 +113,7 @@ export class AlertExample {
async presentAlertPrompt() {
const alert = await this.alertController.create({
cssClass: 'my-custom-class',
header: 'Prompt!',
inputs: [
{
@@ -130,6 +162,16 @@ export class AlertExample {
{
name: 'name7',
type: 'number'
},
{
name: 'name8',
type: 'password',
placeholder: 'Advanced Attributes',
cssClass: 'specialClass',
attributes: {
maxlength: 4,
inputmode: 'decimal'
}
}
],
buttons: [
@@ -154,6 +196,7 @@ export class AlertExample {
async presentAlertRadio() {
const alert = await this.alertController.create({
cssClass: 'my-custom-class',
header: 'Radio',
inputs: [
{
@@ -216,6 +259,7 @@ export class AlertExample {
async presentAlertCheckbox() {
const alert = await this.alertController.create({
cssClass: 'my-custom-class',
header: 'Checkbox',
inputs: [
{
@@ -280,16 +324,21 @@ export class AlertExample {
await alert.present();
}
}
```
### Style Placement
In Angular, the CSS of a specific page is scoped only to elements of that page. Even though the Alert can be presented from within a page, the `ion-alert` element is appended outside of the current page. This means that any custom styles need to go in a global stylesheet file. In an Ionic Angular starter this can be the `src/global.scss` file or you can register a new global style file by [adding to the `styles` build option in `angular.json`](https://angular.io/guide/workspace-config#style-script-config).
### Javascript
```javascript
function presentAlert() {
const alert = document.createElement('ion-alert');
alert.cssClass = 'my-custom-class';
alert.header = 'Alert';
alert.subHeader = 'Subtitle';
alert.message = 'This is an alert message.';
@@ -301,6 +350,7 @@ function presentAlert() {
function presentAlertMultipleButtons() {
const alert = document.createElement('ion-alert');
alert.cssClass = 'my-custom-class';
alert.header = 'Alert';
alert.subHeader = 'Subtitle';
alert.message = 'This is an alert message.';
@@ -312,6 +362,7 @@ function presentAlertMultipleButtons() {
function presentAlertConfirm() {
const alert = document.createElement('ion-alert');
alert.cssClass = 'my-custom-class';
alert.header = 'Confirm!';
alert.message = 'Message <strong>text</strong>!!!';
alert.buttons = [
@@ -336,6 +387,7 @@ function presentAlertConfirm() {
function presentAlertPrompt() {
const alert = document.createElement('ion-alert');
alert.cssClass = 'my-custom-class';
alert.header = 'Prompt!';
alert.inputs = [
{
@@ -381,6 +433,16 @@ function presentAlertPrompt() {
{
name: 'name7',
type: 'number'
},
{
name: 'name8',
type: 'password',
placeholder: 'Advanced Attributes',
cssClass: 'specialClass',
attributes: {
maxlength: 4,
inputmode: 'decimal'
}
}
];
alert.buttons = [
@@ -405,6 +467,7 @@ function presentAlertPrompt() {
function presentAlertRadio() {
const alert = document.createElement('ion-alert');
alert.cssClass = 'my-custom-class';
alert.header = 'Radio';
alert.inputs = [
{
@@ -460,6 +523,7 @@ function presentAlertRadio() {
function presentAlertCheckbox() {
const alert = document.createElement('ion-alert');
alert.cssClass = 'my-custom-class';
alert.header = 'Checkbox';
alert.inputs = [
{
@@ -547,6 +611,7 @@ export const AlertExample: React.FC = () => {
<IonAlert
isOpen={showAlert1}
onDidDismiss={() => setShowAlert1(false)}
cssClass='my-custom-class'
header={'Alert'}
subHeader={'Subtitle'}
message={'This is an alert message.'}
@@ -556,6 +621,7 @@ export const AlertExample: React.FC = () => {
<IonAlert
isOpen={showAlert2}
onDidDismiss={() => setShowAlert2(false)}
cssClass='my-custom-class'
header={'Alert'}
subHeader={'Subtitle'}
message={'This is an alert message.'}
@@ -565,6 +631,7 @@ export const AlertExample: React.FC = () => {
<IonAlert
isOpen={showAlert3}
onDidDismiss={() => setShowAlert3(false)}
cssClass='my-custom-class'
header={'Confirm!'}
message={'Message <strong>text</strong>!!!'}
buttons={[
@@ -588,6 +655,7 @@ export const AlertExample: React.FC = () => {
<IonAlert
isOpen={showAlert4}
onDidDismiss={() => setShowAlert4(false)}
cssClass='my-custom-class'
header={'Prompt!'}
inputs={[
{
@@ -629,6 +697,16 @@ export const AlertExample: React.FC = () => {
{
name: 'name7',
type: 'number'
},
{
name: 'name8',
type: 'password',
placeholder: 'Advanced Attributes',
cssClass: 'specialClass',
attributes: {
maxlength: 4,
inputmode: 'decimal'
}
}
]}
buttons={[
@@ -652,6 +730,7 @@ export const AlertExample: React.FC = () => {
<IonAlert
isOpen={showAlert5}
onDidDismiss={() => setShowAlert5(false)}
cssClass='my-custom-class'
header={'Radio'}
inputs={[
{
@@ -713,6 +792,7 @@ export const AlertExample: React.FC = () => {
<IonAlert
isOpen={showAlert6}
onDidDismiss={() => setShowAlert6(false)}
cssClass='my-custom-class'
header={'Checkbox'}
inputs={[
{
@@ -779,6 +859,298 @@ export default AlertExample;
```
### Stencil
```tsx
import { Component, h } from '@stencil/core';
import { alertController } from '@ionic/core';
@Component({
tag: 'alert-example',
styleUrl: 'alert-example.css'
})
export class AlertExample {
async presentAlert() {
const alert = await alertController.create({
cssClass: 'my-custom-class',
header: 'Alert',
subHeader: 'Subtitle',
message: 'This is an alert message.',
buttons: ['OK']
});
await alert.present();
}
async presentAlertMultipleButtons() {
const alert = await alertController.create({
cssClass: 'my-custom-class',
header: 'Alert',
subHeader: 'Subtitle',
message: 'This is an alert message.',
buttons: ['Cancel', 'Open Modal', 'Delete']
});
await alert.present();
}
async presentAlertConfirm() {
const alert = await alertController.create({
cssClass: 'my-custom-class',
header: 'Confirm!',
message: 'Message <strong>text</strong>!!!',
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'secondary',
handler: (blah) => {
console.log('Confirm Cancel: blah');
}
}, {
text: 'Okay',
handler: () => {
console.log('Confirm Okay');
}
}
]
});
await alert.present();
}
async presentAlertPrompt() {
const alert = await alertController.create({
cssClass: 'my-custom-class',
header: 'Prompt!',
inputs: [
{
name: 'name1',
type: 'text',
placeholder: 'Placeholder 1'
},
{
name: 'name2',
type: 'text',
id: 'name2-id',
value: 'hello',
placeholder: 'Placeholder 2'
},
// multiline input.
{
name: 'paragraph',
id: 'paragraph',
type: 'textarea',
placeholder: 'Placeholder 3'
},
{
name: 'name3',
value: 'http://ionicframework.com',
type: 'url',
placeholder: 'Favorite site ever'
},
// input date with min & max
{
name: 'name4',
type: 'date',
min: '2017-03-01',
max: '2018-01-12'
},
// input date without min nor max
{
name: 'name5',
type: 'date'
},
{
name: 'name6',
type: 'number',
min: -5,
max: 10
},
{
name: 'name7',
type: 'number'
},
{
name: 'name8',
type: 'password',
placeholder: 'Advanced Attributes',
cssClass: 'specialClass',
attributes: {
maxlength: 4,
inputmode: 'decimal'
}
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'secondary',
handler: () => {
console.log('Confirm Cancel');
}
}, {
text: 'Ok',
handler: () => {
console.log('Confirm Ok');
}
}
]
});
await alert.present();
}
async presentAlertRadio() {
const alert = await alertController.create({
cssClass: 'my-custom-class',
header: 'Radio',
inputs: [
{
name: 'radio1',
type: 'radio',
label: 'Radio 1',
value: 'value1',
checked: true
},
{
name: 'radio2',
type: 'radio',
label: 'Radio 2',
value: 'value2'
},
{
name: 'radio3',
type: 'radio',
label: 'Radio 3',
value: 'value3'
},
{
name: 'radio4',
type: 'radio',
label: 'Radio 4',
value: 'value4'
},
{
name: 'radio5',
type: 'radio',
label: 'Radio 5',
value: 'value5'
},
{
name: 'radio6',
type: 'radio',
label: 'Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 ',
value: 'value6'
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'secondary',
handler: () => {
console.log('Confirm Cancel');
}
}, {
text: 'Ok',
handler: () => {
console.log('Confirm Ok');
}
}
]
});
await alert.present();
}
async presentAlertCheckbox() {
const alert = await alertController.create({
cssClass: 'my-custom-class',
header: 'Checkbox',
inputs: [
{
name: 'checkbox1',
type: 'checkbox',
label: 'Checkbox 1',
value: 'value1',
checked: true
},
{
name: 'checkbox2',
type: 'checkbox',
label: 'Checkbox 2',
value: 'value2'
},
{
name: 'checkbox3',
type: 'checkbox',
label: 'Checkbox 3',
value: 'value3'
},
{
name: 'checkbox4',
type: 'checkbox',
label: 'Checkbox 4',
value: 'value4'
},
{
name: 'checkbox5',
type: 'checkbox',
label: 'Checkbox 5',
value: 'value5'
},
{
name: 'checkbox6',
type: 'checkbox',
label: 'Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6',
value: 'value6'
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'secondary',
handler: () => {
console.log('Confirm Cancel');
}
}, {
text: 'Ok',
handler: () => {
console.log('Confirm Ok');
}
}
]
});
await alert.present();
}
render() {
return [
<ion-content>
<ion-button onClick={() => this.presentAlert()}>Present Alert</ion-button>
<ion-button onClick={() => this.presentAlertMultipleButtons()}>Present Alert: Multiple Buttons</ion-button>
<ion-button onClick={() => this.presentAlertConfirm()}>Present Alert: Confirm</ion-button>
<ion-button onClick={() => this.presentAlertPrompt()}>Present Alert: Prompt</ion-button>
<ion-button onClick={() => this.presentAlertRadio()}>Present Alert: Radio</ion-button>
<ion-button onClick={() => this.presentAlertCheckbox()}>Present Alert: Checkbox</ion-button>
</ion-content>
];
}
}
```
### Vue
```html
@@ -799,6 +1171,7 @@ export default {
presentAlert() {
return this.$ionic.alertController
.create({
cssClass: 'my-custom-class',
header: 'Alert',
subHeader: 'Subtitle',
message: 'This is an alert message.',
@@ -810,6 +1183,7 @@ export default {
presentAlertMultipleButtons() {
return this.$ionic.alertController
.create({
cssClass: 'my-custom-class',
header: 'Alert',
subHeader: 'Subtitle',
message: 'This is an alert message.',
@@ -821,6 +1195,7 @@ export default {
presentAlertConfirm() {
return this.$ionic.alertController
.create({
cssClass: 'my-custom-class',
header: 'Confirm!',
message: 'Message <strong>text</strong>!!!',
buttons: [
@@ -846,6 +1221,7 @@ export default {
presentAlertPrompt() {
return this.$ionic.alertController
.create({
cssClass: 'my-custom-class',
header: 'Prompt!',
inputs: [
{
@@ -885,6 +1261,16 @@ export default {
name: 'name7',
type: 'number',
},
{
name: 'name8',
type: 'password',
placeholder: 'Advanced Attributes',
cssClass: 'specialClass',
attributes: {
maxlength: 4,
inputmode: 'decimal'
}
}
],
buttons: [
{
@@ -909,6 +1295,7 @@ export default {
presentAlertRadio() {
return this.$ionic.alertController
.create({
cssClass: 'my-custom-class',
header: 'Radio',
inputs: [
{
@@ -966,6 +1353,7 @@ export default {
presentAlertCheckbox() {
return this.$ionic.alertController
.create({
cssClass: 'my-custom-class',
header: 'Checkbox',
inputs: [
{
@@ -1072,23 +1460,23 @@ Type: `Promise<boolean>`
### `onDidDismiss() => Promise<OverlayEventDetail<any>>`
### `onDidDismiss<T = any>() => Promise<OverlayEventDetail<T>>`
Returns a promise that resolves when the alert did dismiss.
#### Returns
Type: `Promise<OverlayEventDetail<any>>`
Type: `Promise<OverlayEventDetail<T>>`
### `onWillDismiss() => Promise<OverlayEventDetail<any>>`
### `onWillDismiss<T = any>() => Promise<OverlayEventDetail<T>>`
Returns a promise that resolves when the alert will dismiss.
#### Returns
Type: `Promise<OverlayEventDetail<any>>`
Type: `Promise<OverlayEventDetail<T>>`

View File

@@ -75,7 +75,14 @@
header: 'Alert',
subHeader: 'Subtitle',
message: 'This is an alert message.',
buttons: ['Cancel', 'Open Modal', 'Delete']
buttons: [
'Open Modal',
{
text: 'Delete',
role: 'destructive',
},
'Cancel',
]
});
}
@@ -161,6 +168,16 @@
{
name: 'name7',
type: 'number'
},
{
name: 'name8',
type: 'text',
placeholder: 'Advanced Attributes',
cssClass: 'specialClass',
attributes: {
maxlength: 4,
inputmode: 'decimal'
}
}
],
buttons: [

View File

@@ -13,6 +13,7 @@ export class AlertExample {
async presentAlert() {
const alert = await this.alertController.create({
cssClass: 'my-custom-class',
header: 'Alert',
subHeader: 'Subtitle',
message: 'This is an alert message.',
@@ -24,6 +25,7 @@ export class AlertExample {
async presentAlertMultipleButtons() {
const alert = await this.alertController.create({
cssClass: 'my-custom-class',
header: 'Alert',
subHeader: 'Subtitle',
message: 'This is an alert message.',
@@ -35,6 +37,7 @@ export class AlertExample {
async presentAlertConfirm() {
const alert = await this.alertController.create({
cssClass: 'my-custom-class',
header: 'Confirm!',
message: 'Message <strong>text</strong>!!!',
buttons: [
@@ -59,6 +62,7 @@ export class AlertExample {
async presentAlertPrompt() {
const alert = await this.alertController.create({
cssClass: 'my-custom-class',
header: 'Prompt!',
inputs: [
{
@@ -107,6 +111,16 @@ export class AlertExample {
{
name: 'name7',
type: 'number'
},
{
name: 'name8',
type: 'password',
placeholder: 'Advanced Attributes',
cssClass: 'specialClass',
attributes: {
maxlength: 4,
inputmode: 'decimal'
}
}
],
buttons: [
@@ -131,6 +145,7 @@ export class AlertExample {
async presentAlertRadio() {
const alert = await this.alertController.create({
cssClass: 'my-custom-class',
header: 'Radio',
inputs: [
{
@@ -193,6 +208,7 @@ export class AlertExample {
async presentAlertCheckbox() {
const alert = await this.alertController.create({
cssClass: 'my-custom-class',
header: 'Checkbox',
inputs: [
{
@@ -257,6 +273,10 @@ export class AlertExample {
await alert.present();
}
}
```
### Style Placement
In Angular, the CSS of a specific page is scoped only to elements of that page. Even though the Alert can be presented from within a page, the `ion-alert` element is appended outside of the current page. This means that any custom styles need to go in a global stylesheet file. In an Ionic Angular starter this can be the `src/global.scss` file or you can register a new global style file by [adding to the `styles` build option in `angular.json`](https://angular.io/guide/workspace-config#style-script-config).

View File

@@ -1,6 +1,7 @@
```javascript
function presentAlert() {
const alert = document.createElement('ion-alert');
alert.cssClass = 'my-custom-class';
alert.header = 'Alert';
alert.subHeader = 'Subtitle';
alert.message = 'This is an alert message.';
@@ -12,6 +13,7 @@ function presentAlert() {
function presentAlertMultipleButtons() {
const alert = document.createElement('ion-alert');
alert.cssClass = 'my-custom-class';
alert.header = 'Alert';
alert.subHeader = 'Subtitle';
alert.message = 'This is an alert message.';
@@ -23,6 +25,7 @@ function presentAlertMultipleButtons() {
function presentAlertConfirm() {
const alert = document.createElement('ion-alert');
alert.cssClass = 'my-custom-class';
alert.header = 'Confirm!';
alert.message = 'Message <strong>text</strong>!!!';
alert.buttons = [
@@ -47,6 +50,7 @@ function presentAlertConfirm() {
function presentAlertPrompt() {
const alert = document.createElement('ion-alert');
alert.cssClass = 'my-custom-class';
alert.header = 'Prompt!';
alert.inputs = [
{
@@ -92,6 +96,16 @@ function presentAlertPrompt() {
{
name: 'name7',
type: 'number'
},
{
name: 'name8',
type: 'password',
placeholder: 'Advanced Attributes',
cssClass: 'specialClass',
attributes: {
maxlength: 4,
inputmode: 'decimal'
}
}
];
alert.buttons = [
@@ -116,6 +130,7 @@ function presentAlertPrompt() {
function presentAlertRadio() {
const alert = document.createElement('ion-alert');
alert.cssClass = 'my-custom-class';
alert.header = 'Radio';
alert.inputs = [
{
@@ -171,6 +186,7 @@ function presentAlertRadio() {
function presentAlertCheckbox() {
const alert = document.createElement('ion-alert');
alert.cssClass = 'my-custom-class';
alert.header = 'Checkbox';
alert.inputs = [
{

View File

@@ -22,6 +22,7 @@ export const AlertExample: React.FC = () => {
<IonAlert
isOpen={showAlert1}
onDidDismiss={() => setShowAlert1(false)}
cssClass='my-custom-class'
header={'Alert'}
subHeader={'Subtitle'}
message={'This is an alert message.'}
@@ -31,6 +32,7 @@ export const AlertExample: React.FC = () => {
<IonAlert
isOpen={showAlert2}
onDidDismiss={() => setShowAlert2(false)}
cssClass='my-custom-class'
header={'Alert'}
subHeader={'Subtitle'}
message={'This is an alert message.'}
@@ -40,6 +42,7 @@ export const AlertExample: React.FC = () => {
<IonAlert
isOpen={showAlert3}
onDidDismiss={() => setShowAlert3(false)}
cssClass='my-custom-class'
header={'Confirm!'}
message={'Message <strong>text</strong>!!!'}
buttons={[
@@ -63,6 +66,7 @@ export const AlertExample: React.FC = () => {
<IonAlert
isOpen={showAlert4}
onDidDismiss={() => setShowAlert4(false)}
cssClass='my-custom-class'
header={'Prompt!'}
inputs={[
{
@@ -104,6 +108,16 @@ export const AlertExample: React.FC = () => {
{
name: 'name7',
type: 'number'
},
{
name: 'name8',
type: 'password',
placeholder: 'Advanced Attributes',
cssClass: 'specialClass',
attributes: {
maxlength: 4,
inputmode: 'decimal'
}
}
]}
buttons={[
@@ -127,6 +141,7 @@ export const AlertExample: React.FC = () => {
<IonAlert
isOpen={showAlert5}
onDidDismiss={() => setShowAlert5(false)}
cssClass='my-custom-class'
header={'Radio'}
inputs={[
{
@@ -188,6 +203,7 @@ export const AlertExample: React.FC = () => {
<IonAlert
isOpen={showAlert6}
onDidDismiss={() => setShowAlert6(false)}
cssClass='my-custom-class'
header={'Checkbox'}
inputs={[
{

View File

@@ -0,0 +1,288 @@
```tsx
import { Component, h } from '@stencil/core';
import { alertController } from '@ionic/core';
@Component({
tag: 'alert-example',
styleUrl: 'alert-example.css'
})
export class AlertExample {
async presentAlert() {
const alert = await alertController.create({
cssClass: 'my-custom-class',
header: 'Alert',
subHeader: 'Subtitle',
message: 'This is an alert message.',
buttons: ['OK']
});
await alert.present();
}
async presentAlertMultipleButtons() {
const alert = await alertController.create({
cssClass: 'my-custom-class',
header: 'Alert',
subHeader: 'Subtitle',
message: 'This is an alert message.',
buttons: ['Cancel', 'Open Modal', 'Delete']
});
await alert.present();
}
async presentAlertConfirm() {
const alert = await alertController.create({
cssClass: 'my-custom-class',
header: 'Confirm!',
message: 'Message <strong>text</strong>!!!',
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'secondary',
handler: (blah) => {
console.log('Confirm Cancel: blah');
}
}, {
text: 'Okay',
handler: () => {
console.log('Confirm Okay');
}
}
]
});
await alert.present();
}
async presentAlertPrompt() {
const alert = await alertController.create({
cssClass: 'my-custom-class',
header: 'Prompt!',
inputs: [
{
name: 'name1',
type: 'text',
placeholder: 'Placeholder 1'
},
{
name: 'name2',
type: 'text',
id: 'name2-id',
value: 'hello',
placeholder: 'Placeholder 2'
},
// multiline input.
{
name: 'paragraph',
id: 'paragraph',
type: 'textarea',
placeholder: 'Placeholder 3'
},
{
name: 'name3',
value: 'http://ionicframework.com',
type: 'url',
placeholder: 'Favorite site ever'
},
// input date with min & max
{
name: 'name4',
type: 'date',
min: '2017-03-01',
max: '2018-01-12'
},
// input date without min nor max
{
name: 'name5',
type: 'date'
},
{
name: 'name6',
type: 'number',
min: -5,
max: 10
},
{
name: 'name7',
type: 'number'
},
{
name: 'name8',
type: 'password',
placeholder: 'Advanced Attributes',
cssClass: 'specialClass',
attributes: {
maxlength: 4,
inputmode: 'decimal'
}
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'secondary',
handler: () => {
console.log('Confirm Cancel');
}
}, {
text: 'Ok',
handler: () => {
console.log('Confirm Ok');
}
}
]
});
await alert.present();
}
async presentAlertRadio() {
const alert = await alertController.create({
cssClass: 'my-custom-class',
header: 'Radio',
inputs: [
{
name: 'radio1',
type: 'radio',
label: 'Radio 1',
value: 'value1',
checked: true
},
{
name: 'radio2',
type: 'radio',
label: 'Radio 2',
value: 'value2'
},
{
name: 'radio3',
type: 'radio',
label: 'Radio 3',
value: 'value3'
},
{
name: 'radio4',
type: 'radio',
label: 'Radio 4',
value: 'value4'
},
{
name: 'radio5',
type: 'radio',
label: 'Radio 5',
value: 'value5'
},
{
name: 'radio6',
type: 'radio',
label: 'Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 ',
value: 'value6'
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'secondary',
handler: () => {
console.log('Confirm Cancel');
}
}, {
text: 'Ok',
handler: () => {
console.log('Confirm Ok');
}
}
]
});
await alert.present();
}
async presentAlertCheckbox() {
const alert = await alertController.create({
cssClass: 'my-custom-class',
header: 'Checkbox',
inputs: [
{
name: 'checkbox1',
type: 'checkbox',
label: 'Checkbox 1',
value: 'value1',
checked: true
},
{
name: 'checkbox2',
type: 'checkbox',
label: 'Checkbox 2',
value: 'value2'
},
{
name: 'checkbox3',
type: 'checkbox',
label: 'Checkbox 3',
value: 'value3'
},
{
name: 'checkbox4',
type: 'checkbox',
label: 'Checkbox 4',
value: 'value4'
},
{
name: 'checkbox5',
type: 'checkbox',
label: 'Checkbox 5',
value: 'value5'
},
{
name: 'checkbox6',
type: 'checkbox',
label: 'Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6',
value: 'value6'
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'secondary',
handler: () => {
console.log('Confirm Cancel');
}
}, {
text: 'Ok',
handler: () => {
console.log('Confirm Ok');
}
}
]
});
await alert.present();
}
render() {
return [
<ion-content>
<ion-button onClick={() => this.presentAlert()}>Present Alert</ion-button>
<ion-button onClick={() => this.presentAlertMultipleButtons()}>Present Alert: Multiple Buttons</ion-button>
<ion-button onClick={() => this.presentAlertConfirm()}>Present Alert: Confirm</ion-button>
<ion-button onClick={() => this.presentAlertPrompt()}>Present Alert: Prompt</ion-button>
<ion-button onClick={() => this.presentAlertRadio()}>Present Alert: Radio</ion-button>
<ion-button onClick={() => this.presentAlertCheckbox()}>Present Alert: Checkbox</ion-button>
</ion-content>
];
}
}
```

View File

@@ -16,6 +16,7 @@ export default {
presentAlert() {
return this.$ionic.alertController
.create({
cssClass: 'my-custom-class',
header: 'Alert',
subHeader: 'Subtitle',
message: 'This is an alert message.',
@@ -27,6 +28,7 @@ export default {
presentAlertMultipleButtons() {
return this.$ionic.alertController
.create({
cssClass: 'my-custom-class',
header: 'Alert',
subHeader: 'Subtitle',
message: 'This is an alert message.',
@@ -38,6 +40,7 @@ export default {
presentAlertConfirm() {
return this.$ionic.alertController
.create({
cssClass: 'my-custom-class',
header: 'Confirm!',
message: 'Message <strong>text</strong>!!!',
buttons: [
@@ -63,6 +66,7 @@ export default {
presentAlertPrompt() {
return this.$ionic.alertController
.create({
cssClass: 'my-custom-class',
header: 'Prompt!',
inputs: [
{
@@ -102,6 +106,16 @@ export default {
name: 'name7',
type: 'number',
},
{
name: 'name8',
type: 'password',
placeholder: 'Advanced Attributes',
cssClass: 'specialClass',
attributes: {
maxlength: 4,
inputmode: 'decimal'
}
}
],
buttons: [
{
@@ -126,6 +140,7 @@ export default {
presentAlertRadio() {
return this.$ionic.alertController
.create({
cssClass: 'my-custom-class',
header: 'Radio',
inputs: [
{
@@ -183,6 +198,7 @@ export default {
presentAlertCheckbox() {
return this.$ionic.alertController
.create({
cssClass: 'my-custom-class',
header: 'Checkbox',
inputs: [
{

View File

@@ -6,10 +6,9 @@ import { isPlatform } from '../../utils/platform';
@Component({
tag: 'ion-app',
styleUrl: 'app.scss'
styleUrl: 'app.scss',
})
export class App implements ComponentInterface {
@Element() el!: HTMLElement;
componentDidLoad() {
@@ -29,7 +28,7 @@ export class App implements ComponentInterface {
import('../../utils/hardware-back-button').then(module => module.startHardwareBackButton());
}
if (typeof (window as any) !== 'undefined') {
import('../../utils/keyboard').then(module => module.startKeyboardAssist(window));
import('../../utils/keyboard/keyboard').then(module => module.startKeyboardAssist(window));
}
import('../../utils/focus-visible').then(module => module.startFocusVisible());
});
@@ -43,7 +42,7 @@ export class App implements ComponentInterface {
class={{
[mode]: true,
'ion-page': true,
'force-statusbar-padding': config.getBoolean('_forceStatusbarPadding')
'force-statusbar-padding': config.getBoolean('_forceStatusbarPadding'),
}}
>
</Host>

View File

@@ -36,7 +36,7 @@ Avatars can be used by themselves or inside of any element. If placed inside of
### React
```tsx
import React from 'react'
import React from 'react';
import { IonAvatar, IonChip, IonItem, IonLabel, IonContent } from '@ionic/react';
export const AvatarExample: React.FC = () => (
@@ -63,6 +63,41 @@ export const AvatarExample: React.FC = () => (
```
### Stencil
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'avatar-example',
styleUrl: 'avatar-example.css'
})
export class AvatarExample {
render() {
return [
<ion-avatar>
<img src="https://gravatar.com/avatar/dba6bae8c566f9d4041fb9cd9ada7741?d=identicon&f=y"/>
</ion-avatar>,
<ion-chip>
<ion-avatar>
<img src="https://gravatar.com/avatar/dba6bae8c566f9d4041fb9cd9ada7741?d=identicon&f=y"/>
</ion-avatar>
<ion-label>Chip Avatar</ion-label>
</ion-chip>,
<ion-item>
<ion-avatar slot="start">
<img src="https://gravatar.com/avatar/dba6bae8c566f9d4041fb9cd9ada7741?d=identicon&f=y"/>
</ion-avatar>
<ion-label>Item Avatar</ion-label>
</ion-item>
];
}
}
```
### Vue
```html

View File

@@ -1,5 +1,5 @@
```tsx
import React from 'react'
import React from 'react';
import { IonAvatar, IonChip, IonItem, IonLabel, IonContent } from '@ionic/react';
export const AvatarExample: React.FC = () => (

View File

@@ -0,0 +1,31 @@
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'avatar-example',
styleUrl: 'avatar-example.css'
})
export class AvatarExample {
render() {
return [
<ion-avatar>
<img src="https://gravatar.com/avatar/dba6bae8c566f9d4041fb9cd9ada7741?d=identicon&f=y"/>
</ion-avatar>,
<ion-chip>
<ion-avatar>
<img src="https://gravatar.com/avatar/dba6bae8c566f9d4041fb9cd9ada7741?d=identicon&f=y"/>
</ion-avatar>
<ion-label>Chip Avatar</ion-label>
</ion-chip>,
<ion-item>
<ion-avatar slot="start">
<img src="https://gravatar.com/avatar/dba6bae8c566f9d4041fb9cd9ada7741?d=identicon&f=y"/>
</ion-avatar>
<ion-label>Item Avatar</ion-label>
</ion-item>
];
}
}
```

View File

@@ -126,10 +126,10 @@ export class BackButton implements ComponentInterface, ButtonInterface {
'show-back-button': showBackButton
}}
>
<button type={type} disabled={disabled} class="button-native" part="button" aria-label={backButtonText || 'back'}>
<button type={type} disabled={disabled} class="button-native" aria-label={backButtonText || 'back'}>
<span class="button-inner">
{backButtonIcon && <ion-icon icon={backButtonIcon} aria-hidden="true" lazy={false} part="icon"></ion-icon>}
{backButtonText && <span aria-hidden="true" class="button-text" part="text">{backButtonText}</span>}
{backButtonIcon && <ion-icon icon={backButtonIcon} aria-hidden="true" lazy={false}></ion-icon>}
{backButtonText && <span aria-hidden="true" class="button-text">{backButtonText}</span>}
</span>
{mode === 'md' && <ion-ripple-effect type={this.rippleType}></ion-ripple-effect>}
</button>

View File

@@ -173,6 +173,75 @@ export const BackButtonExample: React.FC = () => (
```
### Stencil
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'back-button-example',
styleUrl: 'back-button-example.css'
})
export class BackButtonExample {
render() {
const buttonText = "Custom";
const buttonIcon = "add";
return [
// Default back button
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
</ion-buttons>
</ion-toolbar>
</ion-header>,
// Back button with a default href
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button defaultHref="home"></ion-back-button>
</ion-buttons>
</ion-toolbar>
</ion-header>,
// Back button with custom text and icon
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button
text={buttonText}
icon={buttonIcon}>
</ion-back-button>
</ion-buttons>
</ion-toolbar>
</ion-header>,
// Back button with no text and custom icon
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button text="" icon="add"></ion-back-button>
</ion-buttons>
</ion-toolbar>
</ion-header>,
// Danger back button next to a menu button
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-menu-button></ion-menu-button>
<ion-back-button color="danger"></ion-back-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
];
}
}
```
### Vue
```html

View File

@@ -0,0 +1,65 @@
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'back-button-example',
styleUrl: 'back-button-example.css'
})
export class BackButtonExample {
render() {
const buttonText = "Custom";
const buttonIcon = "add";
return [
// Default back button
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
</ion-buttons>
</ion-toolbar>
</ion-header>,
// Back button with a default href
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button defaultHref="home"></ion-back-button>
</ion-buttons>
</ion-toolbar>
</ion-header>,
// Back button with custom text and icon
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button
text={buttonText}
icon={buttonIcon}>
</ion-back-button>
</ion-buttons>
</ion-toolbar>
</ion-header>,
// Back button with no text and custom icon
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button text="" icon="add"></ion-back-button>
</ion-buttons>
</ion-toolbar>
</ion-header>,
// Danger back button next to a menu button
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-menu-button></ion-menu-button>
<ion-back-button color="danger"></ion-back-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
];
}
}
```

View File

@@ -40,7 +40,7 @@ import { Component } from '@angular/core';
styleUrls: ['./backdrop-example.css'],
})
export class BackdropExample {
backdropDismiss = false;
enableBackdropDismiss = false;
showBackdrop = false;
shouldPropagate = false;
}
@@ -100,6 +100,46 @@ export const BackdropExample: React.FC = () => (
```
### Stencil
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'backdrop-example',
styleUrl: 'backdrop-example.css'
})
export class BackdropExample {
render() {
const enableBackdropDismiss = false;
const showBackdrop = false;
const shouldPropagate = false;
return [
// Default backdrop
<ion-backdrop></ion-backdrop>,
// Backdrop that is not tappable
<ion-backdrop tappable={false}></ion-backdrop>,
// Backdrop that is not visible
<ion-backdrop visible={false}></ion-backdrop>,
// Backdrop with propagation
<ion-backdrop stopPropagation={false}></ion-backdrop>,
// Backdrop that sets dynamic properties
<ion-backdrop
tappable={enableBackdropDismiss}
visible={showBackdrop}
stopPropagation={shouldPropagate}>
</ion-backdrop>
];
}
}
```
### Vue
```html
@@ -129,7 +169,7 @@ export const BackdropExample: React.FC = () => (
@Component()
export default class Example extends Vue {
backdropDismiss = false;
enableBackdropDismiss = false;
showBackdrop = false;
shouldPropagate = false;
}

View File

@@ -28,7 +28,7 @@ import { Component } from '@angular/core';
styleUrls: ['./backdrop-example.css'],
})
export class BackdropExample {
backdropDismiss = false;
enableBackdropDismiss = false;
showBackdrop = false;
shouldPropagate = false;
}

View File

@@ -0,0 +1,36 @@
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'backdrop-example',
styleUrl: 'backdrop-example.css'
})
export class BackdropExample {
render() {
const enableBackdropDismiss = false;
const showBackdrop = false;
const shouldPropagate = false;
return [
// Default backdrop
<ion-backdrop></ion-backdrop>,
// Backdrop that is not tappable
<ion-backdrop tappable={false}></ion-backdrop>,
// Backdrop that is not visible
<ion-backdrop visible={false}></ion-backdrop>,
// Backdrop with propagation
<ion-backdrop stopPropagation={false}></ion-backdrop>,
// Backdrop that sets dynamic properties
<ion-backdrop
tappable={enableBackdropDismiss}
visible={showBackdrop}
stopPropagation={shouldPropagate}>
</ion-backdrop>
];
}
}
```

View File

@@ -25,7 +25,7 @@
@Component()
export default class Example extends Vue {
backdropDismiss = false;
enableBackdropDismiss = false;
showBackdrop = false;
shouldPropagate = false;
}

View File

@@ -67,6 +67,44 @@ export const BadgeExample: React.FC = () => (
```
### Stencil
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'badge-example',
styleUrl: 'badge-example.css'
})
export class BadgeExample {
render() {
return [
// Default
<ion-badge>99</ion-badge>,
// Colors
<ion-badge color="primary">11</ion-badge>,
<ion-badge color="secondary">22</ion-badge>,
<ion-badge color="tertiary">33</ion-badge>,
<ion-badge color="success">44</ion-badge>,
<ion-badge color="warning">55</ion-badge>,
<ion-badge color="danger">66</ion-badge>,
<ion-badge color="light">77</ion-badge>,
<ion-badge color="medium">88</ion-badge>,
<ion-badge color="dark">99</ion-badge>,
// Item with badge on left and right
<ion-item>
<ion-badge slot="start">11</ion-badge>
<ion-label>My Item</ion-label>
<ion-badge slot="end">22</ion-badge>
</ion-item>
];
}
}
```
### Vue
```html

View File

@@ -0,0 +1,34 @@
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'badge-example',
styleUrl: 'badge-example.css'
})
export class BadgeExample {
render() {
return [
// Default
<ion-badge>99</ion-badge>,
// Colors
<ion-badge color="primary">11</ion-badge>,
<ion-badge color="secondary">22</ion-badge>,
<ion-badge color="tertiary">33</ion-badge>,
<ion-badge color="success">44</ion-badge>,
<ion-badge color="warning">55</ion-badge>,
<ion-badge color="danger">66</ion-badge>,
<ion-badge color="light">77</ion-badge>,
<ion-badge color="medium">88</ion-badge>,
<ion-badge color="dark">99</ion-badge>,
// Item with badge on left and right
<ion-item>
<ion-badge slot="start">11</ion-badge>
<ion-label>My Item</ion-label>
<ion-badge slot="end">22</ion-badge>
</ion-item>
];
}
}
```

View File

@@ -155,6 +155,72 @@ export const ButtonExample: React.FC = () => (
```
### Stencil
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'button-example',
styleUrl: 'button-example.css'
})
export class ButtonExample {
render() {
return [
// Default
<ion-button>Default</ion-button>,
// Anchor
<ion-button href="#">Anchor</ion-button>,
// Colors
<ion-button color="primary">Primary</ion-button>,
<ion-button color="secondary">Secondary</ion-button>,
<ion-button color="tertiary">Tertiary</ion-button>,
<ion-button color="success">Success</ion-button>,
<ion-button color="warning">Warning</ion-button>,
<ion-button color="danger">Danger</ion-button>,
<ion-button color="light">Light</ion-button>,
<ion-button color="medium">Medium</ion-button>,
<ion-button color="dark">Dark</ion-button>,
// Expand
<ion-button expand="full">Full Button</ion-button>,
<ion-button expand="block">Block Button</ion-button>,
// Round
<ion-button shape="round">Round Button</ion-button>,
// Fill
<ion-button expand="full" fill="outline">Outline + Full</ion-button>,
<ion-button expand="block" fill="outline">Outline + Block</ion-button>,
<ion-button shape="round" fill="outline">Outline + Round</ion-button>,
// Icons
<ion-button>
<ion-icon slot="start" name="star"></ion-icon>
Left Icon
</ion-button>,
<ion-button>
Right Icon
<ion-icon slot="end" name="star"></ion-icon>
</ion-button>,
<ion-button>
<ion-icon slot="icon-only" name="star"></ion-icon>
</ion-button>,
// Sizes
<ion-button size="large">Large</ion-button>,
<ion-button>Default</ion-button>,
<ion-button size="small">Small</ion-button>
];
}
}
```
### Vue
```html

View File

@@ -0,0 +1,62 @@
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'button-example',
styleUrl: 'button-example.css'
})
export class ButtonExample {
render() {
return [
// Default
<ion-button>Default</ion-button>,
// Anchor
<ion-button href="#">Anchor</ion-button>,
// Colors
<ion-button color="primary">Primary</ion-button>,
<ion-button color="secondary">Secondary</ion-button>,
<ion-button color="tertiary">Tertiary</ion-button>,
<ion-button color="success">Success</ion-button>,
<ion-button color="warning">Warning</ion-button>,
<ion-button color="danger">Danger</ion-button>,
<ion-button color="light">Light</ion-button>,
<ion-button color="medium">Medium</ion-button>,
<ion-button color="dark">Dark</ion-button>,
// Expand
<ion-button expand="full">Full Button</ion-button>,
<ion-button expand="block">Block Button</ion-button>,
// Round
<ion-button shape="round">Round Button</ion-button>,
// Fill
<ion-button expand="full" fill="outline">Outline + Full</ion-button>,
<ion-button expand="block" fill="outline">Outline + Block</ion-button>,
<ion-button shape="round" fill="outline">Outline + Round</ion-button>,
// Icons
<ion-button>
<ion-icon slot="start" name="star"></ion-icon>
Left Icon
</ion-button>,
<ion-button>
Right Icon
<ion-icon slot="end" name="star"></ion-icon>
</ion-button>,
<ion-button>
<ion-icon slot="icon-only" name="star"></ion-icon>
</ion-button>,
// Sizes
<ion-button size="large">Large</ion-button>,
<ion-button>Default</ion-button>,
<ion-button size="small">Small</ion-button>
];
}
}
```

View File

@@ -125,16 +125,8 @@ The `<ion-buttons>` element can be positioned inside of the toolbar using a name
```tsx
import React from 'react';
import {
IonButtons,
IonToolbar,
IonBackButton,
IonTitle,
IonButton,
IonIcon,
IonMenuButton,
IonContent
} from '@ionic/react';
import { IonButtons, IonToolbar, IonBackButton, IonTitle, IonButton, IonIcon, IonMenuButton, IonContent } from '@ionic/react';
import { personCircle, search, star, ellipsisHorizontal, ellipsisVertical } from 'ionicons/icons';
export const ButtonsExample: React.FC = () => (
<IonContent>
@@ -148,16 +140,16 @@ export const ButtonsExample: React.FC = () => (
<IonToolbar>
<IonButtons slot="secondary">
<IonButton>
<IonIcon slot="icon-only" name="person-circle" />
<IonIcon slot="icon-only" icon={personCircle} />
</IonButton>
<IonButton>
<IonIcon slot="icon-only" name="search" />
<IonIcon slot="icon-only" icon={search} />
</IonButton>
</IonButtons>
<IonTitle>Default Buttons</IonTitle>
<IonButtons slot="primary">
<IonButton color="secondary">
<IonIcon slot="icon-only" ios="ellipsis-horizontal" md="ellipsis-vertical" />
<IonIcon slot="icon-only" ios={ellipsisHorizontal} md={ellipsisVertical} />
</IonButton>
</IonButtons>
</IonToolbar>
@@ -165,7 +157,7 @@ export const ButtonsExample: React.FC = () => (
<IonToolbar>
<IonButtons slot="primary">
<IonButton onClick={() => {}}>
<IonIcon slot="icon-only" name="star" />
<IonIcon slot="icon-only" icon={star} />
</IonButton>
</IonButtons>
<IonTitle>Right side menu toggle</IonTitle>
@@ -177,7 +169,7 @@ export const ButtonsExample: React.FC = () => (
<IonToolbar>
<IonButtons collapse="true">
<IonButton>
<IonIcon slot="icon-only" name="star" />
<IonIcon slot="icon-only" icon={star} />
</IonButton>
</IonButtons>
<IonTitle>Collapsible Buttons</IonTitle>
@@ -187,6 +179,73 @@ export const ButtonsExample: React.FC = () => (
```
### Stencil
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'buttons-example',
styleUrl: 'buttons-example.css'
})
export class ButtonsExample {
clickedStar() {
console.log("Clicked star button");
}
render() {
return [
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
</ion-buttons>
<ion-title>Back Button</ion-title>
</ion-toolbar>,
<ion-toolbar>
<ion-buttons slot="secondary">
<ion-button>
<ion-icon slot="icon-only" name="person-circle"></ion-icon>
</ion-button>
<ion-button>
<ion-icon slot="icon-only" name="search"></ion-icon>
</ion-button>
</ion-buttons>
<ion-title>Default Buttons</ion-title>
<ion-buttons slot="primary">
<ion-button color="secondary">
<ion-icon slot="icon-only" ios="ellipsis-horizontal" md="ellipsis-vertical"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>,
<ion-toolbar>
<ion-buttons slot="primary">
<ion-button onClick={() => this.clickedStar()}>
<ion-icon slot="icon-only" name="star"></ion-icon>
</ion-button>
</ion-buttons>
<ion-title>Right side menu toggle</ion-title>
<ion-buttons slot="end">
<ion-menu-button autoHide={false}></ion-menu-button>
</ion-buttons>
</ion-toolbar>,
<ion-toolbar>
<ion-buttons collapse={true}>
<ion-button>
<ion-icon slot="icon-only" name="star"></ion-icon>
</ion-button>
</ion-buttons>
<ion-title>Collapsible Buttons</ion-title>
</ion-toolbar>
];
}
}
```
### Vue
```html

View File

@@ -1,15 +1,7 @@
```tsx
import React from 'react';
import {
IonButtons,
IonToolbar,
IonBackButton,
IonTitle,
IonButton,
IonIcon,
IonMenuButton,
IonContent
} from '@ionic/react';
import { IonButtons, IonToolbar, IonBackButton, IonTitle, IonButton, IonIcon, IonMenuButton, IonContent } from '@ionic/react';
import { personCircle, search, star, ellipsisHorizontal, ellipsisVertical } from 'ionicons/icons';
export const ButtonsExample: React.FC = () => (
<IonContent>
@@ -23,16 +15,16 @@ export const ButtonsExample: React.FC = () => (
<IonToolbar>
<IonButtons slot="secondary">
<IonButton>
<IonIcon slot="icon-only" name="person-circle" />
<IonIcon slot="icon-only" icon={personCircle} />
</IonButton>
<IonButton>
<IonIcon slot="icon-only" name="search" />
<IonIcon slot="icon-only" icon={search} />
</IonButton>
</IonButtons>
<IonTitle>Default Buttons</IonTitle>
<IonButtons slot="primary">
<IonButton color="secondary">
<IonIcon slot="icon-only" ios="ellipsis-horizontal" md="ellipsis-vertical" />
<IonIcon slot="icon-only" ios={ellipsisHorizontal} md={ellipsisVertical} />
</IonButton>
</IonButtons>
</IonToolbar>
@@ -40,7 +32,7 @@ export const ButtonsExample: React.FC = () => (
<IonToolbar>
<IonButtons slot="primary">
<IonButton onClick={() => {}}>
<IonIcon slot="icon-only" name="star" />
<IonIcon slot="icon-only" icon={star} />
</IonButton>
</IonButtons>
<IonTitle>Right side menu toggle</IonTitle>
@@ -52,7 +44,7 @@ export const ButtonsExample: React.FC = () => (
<IonToolbar>
<IonButtons collapse="true">
<IonButton>
<IonIcon slot="icon-only" name="star" />
<IonIcon slot="icon-only" icon={star} />
</IonButton>
</IonButtons>
<IonTitle>Collapsible Buttons</IonTitle>

View File

@@ -0,0 +1,63 @@
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'buttons-example',
styleUrl: 'buttons-example.css'
})
export class ButtonsExample {
clickedStar() {
console.log("Clicked star button");
}
render() {
return [
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
</ion-buttons>
<ion-title>Back Button</ion-title>
</ion-toolbar>,
<ion-toolbar>
<ion-buttons slot="secondary">
<ion-button>
<ion-icon slot="icon-only" name="person-circle"></ion-icon>
</ion-button>
<ion-button>
<ion-icon slot="icon-only" name="search"></ion-icon>
</ion-button>
</ion-buttons>
<ion-title>Default Buttons</ion-title>
<ion-buttons slot="primary">
<ion-button color="secondary">
<ion-icon slot="icon-only" ios="ellipsis-horizontal" md="ellipsis-vertical"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>,
<ion-toolbar>
<ion-buttons slot="primary">
<ion-button onClick={() => this.clickedStar()}>
<ion-icon slot="icon-only" name="star"></ion-icon>
</ion-button>
</ion-buttons>
<ion-title>Right side menu toggle</ion-title>
<ion-buttons slot="end">
<ion-menu-button autoHide={false}></ion-menu-button>
</ion-buttons>
</ion-toolbar>,
<ion-toolbar>
<ion-buttons collapse={true}>
<ion-button>
<ion-icon slot="icon-only" name="star"></ion-icon>
</ion-button>
</ion-buttons>
<ion-title>Collapsible Buttons</ion-title>
</ion-toolbar>
];
}
}
```

View File

@@ -133,6 +133,70 @@ export const CardExamples: React.FC = () => {
```
### Stencil
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'card-example',
styleUrl: 'card-example.css'
})
export class CardExample {
render() {
return [
<ion-card>
<ion-card-header>
<ion-card-subtitle>Card Subtitle</ion-card-subtitle>
<ion-card-title>Card Title</ion-card-title>
</ion-card-header>
<ion-card-content>
Keep close to Nature's heart... and break clear away, once in awhile,
and climb a mountain or spend a week in the woods. Wash your spirit clean.
</ion-card-content>
</ion-card>,
<ion-card>
<ion-item>
<ion-icon name="pin" slot="start"></ion-icon>
<ion-label>ion-item in a card, icon left, button right</ion-label>
<ion-button fill="outline" slot="end">View</ion-button>
</ion-item>
<ion-card-content>
This is content, without any paragraph or header tags,
within an ion-card-content element.
</ion-card-content>
</ion-card>,
<ion-card>
<ion-item href="#" class="ion-activated">
<ion-icon name="wifi" slot="start"></ion-icon>
<ion-label>Card Link Item 1 activated</ion-label>
</ion-item>
<ion-item href="#">
<ion-icon name="wine" slot="start"></ion-icon>
<ion-label>Card Link Item 2</ion-label>
</ion-item>
<ion-item class="ion-activated">
<ion-icon name="warning" slot="start"></ion-icon>
<ion-label>Card Button Item 1 activated</ion-label>
</ion-item>
<ion-item>
<ion-icon name="walk" slot="start"></ion-icon>
<ion-label>Card Button Item 2</ion-label>
</ion-item>
</ion-card>
];
}
}
```
### Vue
```html

View File

@@ -0,0 +1,60 @@
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'card-example',
styleUrl: 'card-example.css'
})
export class CardExample {
render() {
return [
<ion-card>
<ion-card-header>
<ion-card-subtitle>Card Subtitle</ion-card-subtitle>
<ion-card-title>Card Title</ion-card-title>
</ion-card-header>
<ion-card-content>
Keep close to Nature's heart... and break clear away, once in awhile,
and climb a mountain or spend a week in the woods. Wash your spirit clean.
</ion-card-content>
</ion-card>,
<ion-card>
<ion-item>
<ion-icon name="pin" slot="start"></ion-icon>
<ion-label>ion-item in a card, icon left, button right</ion-label>
<ion-button fill="outline" slot="end">View</ion-button>
</ion-item>
<ion-card-content>
This is content, without any paragraph or header tags,
within an ion-card-content element.
</ion-card-content>
</ion-card>,
<ion-card>
<ion-item href="#" class="ion-activated">
<ion-icon name="wifi" slot="start"></ion-icon>
<ion-label>Card Link Item 1 activated</ion-label>
</ion-item>
<ion-item href="#">
<ion-icon name="wine" slot="start"></ion-icon>
<ion-label>Card Link Item 2</ion-label>
</ion-item>
<ion-item class="ion-activated">
<ion-icon name="warning" slot="start"></ion-icon>
<ion-label>Card Button Item 1 activated</ion-label>
</ion-item>
<ion-item>
<ion-icon name="walk" slot="start"></ion-icon>
<ion-label>Card Button Item 2</ion-label>
</ion-item>
</ion-card>
];
}
}
```

View File

@@ -153,6 +153,55 @@ export const CheckboxExamples: React.FC = () => {
```
### Stencil
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'checkbox-example',
styleUrl: 'checkbox-example.css'
})
export class CheckboxExample {
private form = [
{ val: 'Pepperoni', isChecked: true },
{ val: 'Sausage', isChecked: false },
{ val: 'Mushroom', isChecked: false }
];
render() {
return [
// Default Checkbox
<ion-checkbox></ion-checkbox>,
// Disabled Checkbox
<ion-checkbox disabled={true}></ion-checkbox>,
// Checked Checkbox
<ion-checkbox checked={true}></ion-checkbox>,
// Checkbox Colors
<ion-checkbox color="primary"></ion-checkbox>,
<ion-checkbox color="secondary"></ion-checkbox>,
<ion-checkbox color="danger"></ion-checkbox>,
<ion-checkbox color="light"></ion-checkbox>,
<ion-checkbox color="dark"></ion-checkbox>,
// Checkboxes in a List
<ion-list>
{this.form.map(entry =>
<ion-item>
<ion-label>{entry.val}</ion-label>
<ion-checkbox slot="end" checked={entry.isChecked}></ion-checkbox>
</ion-item>
)}
</ion-list>
];
}
}
```
### Vue
```html

View File

@@ -0,0 +1,45 @@
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'checkbox-example',
styleUrl: 'checkbox-example.css'
})
export class CheckboxExample {
private form = [
{ val: 'Pepperoni', isChecked: true },
{ val: 'Sausage', isChecked: false },
{ val: 'Mushroom', isChecked: false }
];
render() {
return [
// Default Checkbox
<ion-checkbox></ion-checkbox>,
// Disabled Checkbox
<ion-checkbox disabled={true}></ion-checkbox>,
// Checked Checkbox
<ion-checkbox checked={true}></ion-checkbox>,
// Checkbox Colors
<ion-checkbox color="primary"></ion-checkbox>,
<ion-checkbox color="secondary"></ion-checkbox>,
<ion-checkbox color="danger"></ion-checkbox>,
<ion-checkbox color="light"></ion-checkbox>,
<ion-checkbox color="dark"></ion-checkbox>,
// Checkboxes in a List
<ion-list>
{this.form.map(entry =>
<ion-item>
<ion-label>{entry.val}</ion-label>
<ion-checkbox slot="end" checked={entry.isChecked}></ion-checkbox>
</ion-item>
)}
</ion-list>
];
}
}
```

View File

@@ -117,6 +117,64 @@ export const ChipExamples: React.FC = () => {
```
### Stencil
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'chip-example',
styleUrl: 'chip-example.css'
})
export class ChipExample {
render() {
return [
<ion-chip>
<ion-label>Default</ion-label>
</ion-chip>,
<ion-chip>
<ion-label color="secondary">Secondary Label</ion-label>
</ion-chip>,
<ion-chip color="secondary">
<ion-label color="dark">Secondary w/ Dark label</ion-label>
</ion-chip>,
<ion-chip>
<ion-icon name="pin"></ion-icon>
<ion-label>Default</ion-label>
</ion-chip>,
<ion-chip>
<ion-icon name="heart" color="dark"></ion-icon>
<ion-label>Default</ion-label>
</ion-chip>,
<ion-chip>
<ion-label>Button Chip</ion-label>
<ion-icon name="close-circle"></ion-icon>
</ion-chip>,
<ion-chip>
<ion-icon name="pin" color="primary"></ion-icon>
<ion-label>Icon Chip</ion-label>
<ion-icon name="close"></ion-icon>
</ion-chip>,
<ion-chip>
<ion-avatar>
<img src="https://gravatar.com/avatar/dba6bae8c566f9d4041fb9cd9ada7741?d=identicon&f=y"/>
</ion-avatar>
<ion-label>Avatar Chip</ion-label>
<ion-icon name="close-circle"></ion-icon>
</ion-chip>
];
}
}
```
### Vue
```html

View File

@@ -0,0 +1,54 @@
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'chip-example',
styleUrl: 'chip-example.css'
})
export class ChipExample {
render() {
return [
<ion-chip>
<ion-label>Default</ion-label>
</ion-chip>,
<ion-chip>
<ion-label color="secondary">Secondary Label</ion-label>
</ion-chip>,
<ion-chip color="secondary">
<ion-label color="dark">Secondary w/ Dark label</ion-label>
</ion-chip>,
<ion-chip>
<ion-icon name="pin"></ion-icon>
<ion-label>Default</ion-label>
</ion-chip>,
<ion-chip>
<ion-icon name="heart" color="dark"></ion-icon>
<ion-label>Default</ion-label>
</ion-chip>,
<ion-chip>
<ion-label>Button Chip</ion-label>
<ion-icon name="close-circle"></ion-icon>
</ion-chip>,
<ion-chip>
<ion-icon name="pin" color="primary"></ion-icon>
<ion-label>Icon Chip</ion-label>
<ion-icon name="close"></ion-icon>
</ion-chip>,
<ion-chip>
<ion-avatar>
<img src="https://gravatar.com/avatar/dba6bae8c566f9d4041fb9cd9ada7741?d=identicon&f=y"/>
</ion-avatar>
<ion-label>Avatar Chip</ion-label>
<ion-icon name="close-circle"></ion-icon>
</ion-chip>
];
}
}
```

View File

@@ -137,7 +137,7 @@
/* stylelint-enable property-blacklist */
width: 100%;
height: 100%;
height: 100vh;
opacity: 0;

View File

@@ -77,6 +77,47 @@ const ContentExample: React.FC = () => (
```
### Stencil
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'content-example',
styleUrl: 'content-example.css'
})
export class ContentExample {
logScrollStart() {
console.log('Scroll start');
}
logScrolling(ev) {
console.log('Scrolling', ev);
}
logScrollEnd() {
console.log('Scroll end');
}
render() {
return [
<ion-content
scrollEvents={true}
onIonScrollStart={() => this.logScrollStart()}
onIonScroll={(ev) => this.logScrolling(ev)}
onIonScrollEnd={() => this.logScrollEnd()}>
<h1>Main Content</h1>
<div slot="fixed">
<h1>Fixed Content</h1>
</div>
</ion-content>
];
}
}
```
### Vue
```html

View File

@@ -0,0 +1,37 @@
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'content-example',
styleUrl: 'content-example.css'
})
export class ContentExample {
logScrollStart() {
console.log('Scroll start');
}
logScrolling(ev) {
console.log('Scrolling', ev);
}
logScrollEnd() {
console.log('Scroll end');
}
render() {
return [
<ion-content
scrollEvents={true}
onIonScrollStart={() => this.logScrollStart()}
onIonScroll={(ev) => this.logScrolling(ev)}
onIonScrollEnd={() => this.logScrollEnd()}>
<h1>Main Content</h1>
<div slot="fixed">
<h1>Fixed Content</h1>
</div>
</ion-content>
];
}
}
```

View File

@@ -262,13 +262,14 @@ export const getDateTime = (dateString: any = '', timeZone: any = ''): Date => {
/**
* Ensures that YYYY-MM-DD, YYYY-MM,
* YYYY-DD, etc does not get affected
* YYYY-DD, YYYY, etc does not get affected
* by timezones and stays on the day/month
* that the user provided
*/
if (
dateString.length === 10 ||
dateString.length === 7
dateString.length === 7 ||
dateString.length === 4
) {
dateString += ' ';
}

View File

@@ -179,6 +179,7 @@ export class Datetime implements ComponentInterface {
/**
* Short abbreviated day of the week names. This can be used to provide
* locale names for each day in the week. Defaults to English.
* Defaults to: `['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']`
*/
@Prop() dayShortNames?: string[] | string;

View File

@@ -555,6 +555,116 @@ export const DateTimeExamples: React.FC = () => {
```
### Stencil
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'datetime-example',
styleUrl: 'datetime-example.css'
})
export class DatetimeExample {
private customYearValues = [2020, 2016, 2008, 2004, 2000, 1996];
private customDayShortNames = ['s\u00f8n', 'man', 'tir', 'ons', 'tor', 'fre', 'l\u00f8r'];
private customPickerOptions = {
buttons: [{
text: 'Save',
handler: () => console.log('Clicked Save!')
}, {
text: 'Log',
handler: () => {
console.log('Clicked Log. Do not Dismiss.');
return false;
}
}]
}
render() {
return [
<ion-item>
<ion-label>MMMM</ion-label>
<ion-datetime displayFormat="MMMM" value="2012-12-15T13:47:20.789"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label>MM DD YY</ion-label>
<ion-datetime displayFormat="MM DD YY" placeholder="Select Date"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label>Disabled</ion-label>
<ion-datetime id="dynamicDisabled" displayFormat="MM DD YY" disabled value="1994-12-15"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label>YYYY</ion-label>
<ion-datetime pickerOptions={this.customPickerOptions} placeholder="Custom Options" displayFormat="YYYY" min="1981" max="2002"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label position="stacked">MMMM YY</ion-label>
<ion-datetime displayFormat="MMMM YY" min="1989-06-04" max="2004-08-23" value="1994-12-15T13:47:20.789"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label position="floating">MM/DD/YYYY</ion-label>
<ion-datetime displayFormat="MM/DD/YYYY" min="1994-03-14" max="2012-12-09" value="2002-09-23T15:03:46.789"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label position="floating">MM/DD/YYYY</ion-label>
<ion-datetime displayFormat="MM/DD/YYYY" min="1994-03-14" max="2012-12-09"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label>DDD. MMM DD, YY (custom locale)</ion-label>
<ion-datetime value="1995-04-15" min="1990-02" max="2000"
dayShortNames={this.customDayShortNames}
displayFormat="DDD. MMM DD, YY"
monthShortNames="jan, feb, mar, apr, mai, jun, jul, aug, sep, okt, nov, des"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label>D MMM YYYY H:mm</ion-label>
<ion-datetime displayFormat="D MMM YYYY H:mm" min="1997" max="2010" value="2005-06-17T11:06Z"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label>DDDD MMM D, YYYY</ion-label>
<ion-datetime displayFormat="DDDD MMM D, YYYY" min="2005" max="2016" value="2008-09-02"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label>HH:mm</ion-label>
<ion-datetime displayFormat="HH:mm"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label>h:mm a</ion-label>
<ion-datetime displayFormat="h:mm a"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label>hh:mm A (15 min steps)</ion-label>
<ion-datetime displayFormat="h:mm A" minuteValues="0,15,30,45"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label>Leap years, summer months</ion-label>
<ion-datetime displayFormat="MM/YYYY" pickerFormat="MMMM YYYY" monthValues="6,7,8" yearValues={this.customYearValues}></ion-datetime>
</ion-item>,
<ion-item>
<ion-label>Specific days/months/years</ion-label>
<ion-datetime monthValues="6,7,8" yearValues="2014,2015" dayValues="01,02,03,04,05,06,08,09,10, 11, 12, 13, 14" displayFormat="DD/MMM/YYYY"></ion-datetime>
</ion-item>
];
}
}
```
### Vue
```html
@@ -679,7 +789,7 @@ export const DateTimeExamples: React.FC = () => {
| ----------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- |
| `cancelText` | `cancel-text` | The text to display on the picker's cancel button. | `string` | `'Cancel'` |
| `dayNames` | `day-names` | Full day of the week names. This can be used to provide locale names for each day in the week. Defaults to English. | `string \| string[] \| undefined` | `undefined` |
| `dayShortNames` | `day-short-names` | Short abbreviated day of the week names. This can be used to provide locale names for each day in the week. Defaults to English. | `string \| string[] \| undefined` | `undefined` |
| `dayShortNames` | `day-short-names` | Short abbreviated day of the week names. This can be used to provide locale names for each day in the week. Defaults to English. Defaults to: `['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']` | `string \| string[] \| undefined` | `undefined` |
| `dayValues` | `day-values` | Values used to create the list of selectable days. By default every day is shown for the given month. However, to control exactly which days of the month to display, the `dayValues` input can take a number, an array of numbers, or a string of comma separated numbers. Note that even if the array days have an invalid number for the selected month, like `31` in February, it will correctly not show days which are not valid for the selected month. | `number \| number[] \| string \| undefined` | `undefined` |
| `disabled` | `disabled` | If `true`, the user cannot interact with the datetime. | `boolean` | `false` |
| `displayFormat` | `display-format` | The display format of the date and time as text that shows within the item. When the `pickerFormat` input is not used, then the `displayFormat` is used for both display the formatted text, and determining the datetime picker's columns. See the `pickerFormat` input description for more info. Defaults to `MMM D, YYYY`. | `string` | `'MMM D, YYYY'` |

View File

@@ -64,7 +64,7 @@
<ion-item>
<ion-label>YYYY</ion-label>
<ion-datetime id="customPickerOptions" placeholder="Custom Options" display-format="YYYY" min="1981" max="2002"></ion-datetime>
<ion-datetime id="customPickerOptions" placeholder="Custom Options" display-format="YYYY" min="1981" max="2002" value="2000"></ion-datetime>
</ion-item>
<ion-item>
@@ -242,10 +242,10 @@
var selectedLang = "en";
var customDayShortNames = document.getElementById('customMonthShortNames');
customDayShortNames.monthShortNames = monthShortNamesEnglish;
function toggleLanguage() {
selectedLang = selectedLang === 'en' ? 'fr' : 'en';
var customMonthShortNames = document.getElementById('customMonthShortNames');
var el = document.getElementById('selectedLang');

View File

@@ -0,0 +1,106 @@
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'datetime-example',
styleUrl: 'datetime-example.css'
})
export class DatetimeExample {
private customYearValues = [2020, 2016, 2008, 2004, 2000, 1996];
private customDayShortNames = ['s\u00f8n', 'man', 'tir', 'ons', 'tor', 'fre', 'l\u00f8r'];
private customPickerOptions = {
buttons: [{
text: 'Save',
handler: () => console.log('Clicked Save!')
}, {
text: 'Log',
handler: () => {
console.log('Clicked Log. Do not Dismiss.');
return false;
}
}]
}
render() {
return [
<ion-item>
<ion-label>MMMM</ion-label>
<ion-datetime displayFormat="MMMM" value="2012-12-15T13:47:20.789"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label>MM DD YY</ion-label>
<ion-datetime displayFormat="MM DD YY" placeholder="Select Date"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label>Disabled</ion-label>
<ion-datetime id="dynamicDisabled" displayFormat="MM DD YY" disabled value="1994-12-15"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label>YYYY</ion-label>
<ion-datetime pickerOptions={this.customPickerOptions} placeholder="Custom Options" displayFormat="YYYY" min="1981" max="2002"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label position="stacked">MMMM YY</ion-label>
<ion-datetime displayFormat="MMMM YY" min="1989-06-04" max="2004-08-23" value="1994-12-15T13:47:20.789"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label position="floating">MM/DD/YYYY</ion-label>
<ion-datetime displayFormat="MM/DD/YYYY" min="1994-03-14" max="2012-12-09" value="2002-09-23T15:03:46.789"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label position="floating">MM/DD/YYYY</ion-label>
<ion-datetime displayFormat="MM/DD/YYYY" min="1994-03-14" max="2012-12-09"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label>DDD. MMM DD, YY (custom locale)</ion-label>
<ion-datetime value="1995-04-15" min="1990-02" max="2000"
dayShortNames={this.customDayShortNames}
displayFormat="DDD. MMM DD, YY"
monthShortNames="jan, feb, mar, apr, mai, jun, jul, aug, sep, okt, nov, des"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label>D MMM YYYY H:mm</ion-label>
<ion-datetime displayFormat="D MMM YYYY H:mm" min="1997" max="2010" value="2005-06-17T11:06Z"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label>DDDD MMM D, YYYY</ion-label>
<ion-datetime displayFormat="DDDD MMM D, YYYY" min="2005" max="2016" value="2008-09-02"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label>HH:mm</ion-label>
<ion-datetime displayFormat="HH:mm"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label>h:mm a</ion-label>
<ion-datetime displayFormat="h:mm a"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label>hh:mm A (15 min steps)</ion-label>
<ion-datetime displayFormat="h:mm A" minuteValues="0,15,30,45"></ion-datetime>
</ion-item>,
<ion-item>
<ion-label>Leap years, summer months</ion-label>
<ion-datetime displayFormat="MM/YYYY" pickerFormat="MMMM YYYY" monthValues="6,7,8" yearValues={this.customYearValues}></ion-datetime>
</ion-item>,
<ion-item>
<ion-label>Specific days/months/years</ion-label>
<ion-datetime monthValues="6,7,8" yearValues="2014,2015" dayValues="01,02,03,04,05,06,08,09,10, 11, 12, 13, 14" displayFormat="DD/MMM/YYYY"></ion-datetime>
</ion-item>
];
}
}
```

View File

@@ -15,7 +15,7 @@ If the FAB button is not wrapped with `<ion-fab>`, it will scroll with the conte
<ion-content>
<!-- Fixed Floating Action Button that does not scroll with the content -->
<ion-fab>
<ion-fab slot="fixed">
<ion-fab-button>Button</ion-fab-button>
</ion-fab>
@@ -45,7 +45,7 @@ import { IonContent, IonFab, IonFabButton } from '@ionic/react';
export const FabButtonExample: React.FC = () => (
<IonContent>
{/*-- Fixed Floating Action Button that does not scroll with the content --*/}
<IonFab>
<IonFab slot="fixed">
<IonFabButton>Button</IonFabButton>
</IonFab>
@@ -66,6 +66,45 @@ export const FabButtonExample: React.FC = () => (
```
### Stencil
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'fab-button-example',
styleUrl: 'fab-button-example.css'
})
export class FabButtonExample {
render() {
return [
<ion-content>
{/* Fixed Floating Action Button that does not scroll with the content */}
<ion-fab slot="fixed">
<ion-fab-button>Button</ion-fab-button>
</ion-fab>
{/* Default Floating Action Button that scrolls with the content */}
<ion-fab-button>Default</ion-fab-button>
{/* Mini */}
<ion-fab-button size="small">Mini</ion-fab-button>
{/* Colors */}
<ion-fab-button color="primary">Primary</ion-fab-button>
<ion-fab-button color="secondary">Secondary</ion-fab-button>
<ion-fab-button color="danger">Danger</ion-fab-button>
<ion-fab-button color="light">Light</ion-fab-button>
<ion-fab-button color="dark">Dark</ion-fab-button>
</ion-content>
];
}
}
```
### Vue
```html
@@ -73,7 +112,7 @@ export const FabButtonExample: React.FC = () => (
<ion-content>
<!-- Fixed Floating Action Button that does not scroll with the content -->
<ion-fab>
<ion-fab slot="fixed">
<ion-fab-button>Button</ion-fab-button>
</ion-fab>

View File

@@ -2,7 +2,7 @@
<ion-content>
<!-- Fixed Floating Action Button that does not scroll with the content -->
<ion-fab>
<ion-fab slot="fixed">
<ion-fab-button>Button</ion-fab-button>
</ion-fab>

View File

@@ -2,7 +2,7 @@
<ion-content>
<!-- Fixed Floating Action Button that does not scroll with the content -->
<ion-fab>
<ion-fab slot="fixed">
<ion-fab-button>Button</ion-fab-button>
</ion-fab>

View File

@@ -5,7 +5,7 @@ import { IonContent, IonFab, IonFabButton } from '@ionic/react';
export const FabButtonExample: React.FC = () => (
<IonContent>
{/*-- Fixed Floating Action Button that does not scroll with the content --*/}
<IonFab>
<IonFab slot="fixed">
<IonFabButton>Button</IonFabButton>
</IonFab>

View File

@@ -0,0 +1,35 @@
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'fab-button-example',
styleUrl: 'fab-button-example.css'
})
export class FabButtonExample {
render() {
return [
<ion-content>
{/* Fixed Floating Action Button that does not scroll with the content */}
<ion-fab slot="fixed">
<ion-fab-button>Button</ion-fab-button>
</ion-fab>
{/* Default Floating Action Button that scrolls with the content */}
<ion-fab-button>Default</ion-fab-button>
{/* Mini */}
<ion-fab-button size="small">Mini</ion-fab-button>
{/* Colors */}
<ion-fab-button color="primary">Primary</ion-fab-button>
<ion-fab-button color="secondary">Secondary</ion-fab-button>
<ion-fab-button color="danger">Danger</ion-fab-button>
<ion-fab-button color="light">Light</ion-fab-button>
<ion-fab-button color="dark">Dark</ion-fab-button>
</ion-content>
];
}
}
```

View File

@@ -3,7 +3,7 @@
<ion-content>
<!-- Fixed Floating Action Button that does not scroll with the content -->
<ion-fab>
<ion-fab slot="fixed">
<ion-fab-button>Button</ion-fab-button>
</ion-fab>

View File

@@ -10,19 +10,55 @@ The `ion-fab-list` element is a container for multiple fab buttons. This collect
### Angular / javascript
```html
<ion-fab vertical="bottom" horizontal="end">
<ion-fab vertical="center" horizontal="center">
<ion-fab-button>Share</ion-fab-button>
<ion-fab-list side="top">
<ion-fab-button>Facebook</ion-fab-button>
<ion-fab-button>Twitter</ion-fab-button>
<ion-fab-button>Youtube</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-facebook"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-twitter"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-youtube"></ion-icon>
</ion-fab-button>
</ion-fab-list>
<ion-fab-list side="end">
<ion-fab-button>
<ion-icon name="logo-pwa"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-npm"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-ionic"></ion-icon>
</ion-fab-button>
</ion-fab-list>
<ion-fab-list side="bottom">
<ion-fab-button>
<ion-icon name="logo-github"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-javascript"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-angular"></ion-icon>
</ion-fab-button>
</ion-fab-list>
<ion-fab-list side="start">
<ion-fab-button>Vimeo</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-vimeo"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-chrome"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-react"></ion-icon>
</ion-fab-button>
</ion-fab-list>
</ion-fab>
```
@@ -32,29 +68,57 @@ The `ion-fab-list` element is a container for multiple fab buttons. This collect
```tsx
import React from 'react';
import { IonFab, IonFabButton, IonFabList, IonContent, IonIcon } from '@ionic/react';
import { logoFacebook, logoTwitter, logoYoutube, logoPwa, logoNpm, logoIonic, logoGithub, logoJavascript, logoAngular, logoVimeo, logoChrome, logoReact } from 'ionicons/icons';
export const FabListExample: React.FC = () => (
<IonContent>
<IonFab vertical="bottom" horizontal="end">
<IonFabButton>
<IonIcon icon="share" />
</IonFabButton>
<IonFab vertical="center" horizontal="center">
<IonFabButton>Share</IonFabButton>
<IonFabList side="top">
<IonFabButton color="primary">
<IonIcon icon="logo-facebook" />
<IonFabButton>
<IonIcon icon={logoFacebook} />
</IonFabButton>
<IonFabButton color="primary">
<IonIcon icon="logo-twitter" />
<IonFabButton>
<IonIcon icon={logoTwitter} />
</IonFabButton>
<IonFabButton color="primary">
<IonIcon icon="logo-youtube" />
<IonFabButton>
<IonIcon icon={logoYoutube} />
</IonFabButton>
</IonFabList>
<IonFabList side="end">
<IonFabButton>
<IonIcon icon={logoPwa} />
</IonFabButton>
<IonFabButton>
<IonIcon icon={logoNpm} />
</IonFabButton>
<IonFabButton>
<IonIcon icon={logoIonic} />
</IonFabButton>
</IonFabList>
<IonFabList side="bottom">
<IonFabButton>
<IonIcon icon={logoGithub} />
</IonFabButton>
<IonFabButton>
<IonIcon icon={logoJavascript} />
</IonFabButton>
<IonFabButton>
<IonIcon icon={logoAngular} />
</IonFabButton>
</IonFabList>
<IonFabList side="start">
<IonFabButton color="primary">
<IonIcon icon="logo-vimeo" />
<IonFabButton>
<IonIcon icon={logoVimeo} />
</IonFabButton>
<IonFabButton>
<IonIcon icon={logoChrome} />
</IonFabButton>
<IonFabButton>
<IonIcon icon={logoReact} />
</IonFabButton>
</IonFabList>
</IonFab>
@@ -64,6 +128,74 @@ export const FabListExample: React.FC = () => (
```
### Stencil
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'fab-list-example',
styleUrl: 'fab-list-example.css'
})
export class FabListExample {
render() {
return [
<ion-fab vertical="center" horizontal="center">
<ion-fab-button>Share</ion-fab-button>
<ion-fab-list side="top">
<ion-fab-button>
<ion-icon name="logo-facebook"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-twitter"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-youtube"></ion-icon>
</ion-fab-button>
</ion-fab-list>
<ion-fab-list side="end">
<ion-fab-button>
<ion-icon name="logo-pwa"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-npm"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-ionic"></ion-icon>
</ion-fab-button>
</ion-fab-list>
<ion-fab-list side="bottom">
<ion-fab-button>
<ion-icon name="logo-github"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-javascript"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-angular"></ion-icon>
</ion-fab-button>
</ion-fab-list>
<ion-fab-list side="start">
<ion-fab-button>
<ion-icon name="logo-vimeo"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-chrome"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-react"></ion-icon>
</ion-fab-button>
</ion-fab-list>
</ion-fab>
];
}
}
```
### Vue
```html

View File

@@ -1,16 +1,52 @@
```html
<ion-fab vertical="bottom" horizontal="end">
<ion-fab vertical="center" horizontal="center">
<ion-fab-button>Share</ion-fab-button>
<ion-fab-list side="top">
<ion-fab-button>Facebook</ion-fab-button>
<ion-fab-button>Twitter</ion-fab-button>
<ion-fab-button>Youtube</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-facebook"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-twitter"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-youtube"></ion-icon>
</ion-fab-button>
</ion-fab-list>
<ion-fab-list side="end">
<ion-fab-button>
<ion-icon name="logo-pwa"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-npm"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-ionic"></ion-icon>
</ion-fab-button>
</ion-fab-list>
<ion-fab-list side="bottom">
<ion-fab-button>
<ion-icon name="logo-github"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-javascript"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-angular"></ion-icon>
</ion-fab-button>
</ion-fab-list>
<ion-fab-list side="start">
<ion-fab-button>Vimeo</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-vimeo"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-chrome"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-react"></ion-icon>
</ion-fab-button>
</ion-fab-list>
</ion-fab>
```

View File

@@ -1,16 +1,52 @@
```html
<ion-fab vertical="bottom" horizontal="end">
<ion-fab vertical="center" horizontal="center">
<ion-fab-button>Share</ion-fab-button>
<ion-fab-list side="top">
<ion-fab-button>Facebook</ion-fab-button>
<ion-fab-button>Twitter</ion-fab-button>
<ion-fab-button>Youtube</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-facebook"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-twitter"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-youtube"></ion-icon>
</ion-fab-button>
</ion-fab-list>
<ion-fab-list side="end">
<ion-fab-button>
<ion-icon name="logo-pwa"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-npm"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-ionic"></ion-icon>
</ion-fab-button>
</ion-fab-list>
<ion-fab-list side="bottom">
<ion-fab-button>
<ion-icon name="logo-github"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-javascript"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-angular"></ion-icon>
</ion-fab-button>
</ion-fab-list>
<ion-fab-list side="start">
<ion-fab-button>Vimeo</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-vimeo"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-chrome"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-react"></ion-icon>
</ion-fab-button>
</ion-fab-list>
</ion-fab>
```

View File

@@ -1,29 +1,57 @@
```tsx
import React from 'react';
import { IonFab, IonFabButton, IonFabList, IonContent, IonIcon } from '@ionic/react';
import { logoFacebook, logoTwitter, logoYoutube, logoPwa, logoNpm, logoIonic, logoGithub, logoJavascript, logoAngular, logoVimeo, logoChrome, logoReact } from 'ionicons/icons';
export const FabListExample: React.FC = () => (
<IonContent>
<IonFab vertical="bottom" horizontal="end">
<IonFabButton>
<IonIcon icon="share" />
</IonFabButton>
<IonFab vertical="center" horizontal="center">
<IonFabButton>Share</IonFabButton>
<IonFabList side="top">
<IonFabButton color="primary">
<IonIcon icon="logo-facebook" />
<IonFabButton>
<IonIcon icon={logoFacebook} />
</IonFabButton>
<IonFabButton color="primary">
<IonIcon icon="logo-twitter" />
<IonFabButton>
<IonIcon icon={logoTwitter} />
</IonFabButton>
<IonFabButton color="primary">
<IonIcon icon="logo-youtube" />
<IonFabButton>
<IonIcon icon={logoYoutube} />
</IonFabButton>
</IonFabList>
<IonFabList side="end">
<IonFabButton>
<IonIcon icon={logoPwa} />
</IonFabButton>
<IonFabButton>
<IonIcon icon={logoNpm} />
</IonFabButton>
<IonFabButton>
<IonIcon icon={logoIonic} />
</IonFabButton>
</IonFabList>
<IonFabList side="bottom">
<IonFabButton>
<IonIcon icon={logoGithub} />
</IonFabButton>
<IonFabButton>
<IonIcon icon={logoJavascript} />
</IonFabButton>
<IonFabButton>
<IonIcon icon={logoAngular} />
</IonFabButton>
</IonFabList>
<IonFabList side="start">
<IonFabButton color="primary">
<IonIcon icon="logo-vimeo" />
<IonFabButton>
<IonIcon icon={logoVimeo} />
</IonFabButton>
<IonFabButton>
<IonIcon icon={logoChrome} />
</IonFabButton>
<IonFabButton>
<IonIcon icon={logoReact} />
</IonFabButton>
</IonFabList>
</IonFab>

View File

@@ -0,0 +1,64 @@
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'fab-list-example',
styleUrl: 'fab-list-example.css'
})
export class FabListExample {
render() {
return [
<ion-fab vertical="center" horizontal="center">
<ion-fab-button>Share</ion-fab-button>
<ion-fab-list side="top">
<ion-fab-button>
<ion-icon name="logo-facebook"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-twitter"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-youtube"></ion-icon>
</ion-fab-button>
</ion-fab-list>
<ion-fab-list side="end">
<ion-fab-button>
<ion-icon name="logo-pwa"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-npm"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-ionic"></ion-icon>
</ion-fab-button>
</ion-fab-list>
<ion-fab-list side="bottom">
<ion-fab-button>
<ion-icon name="logo-github"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-javascript"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-angular"></ion-icon>
</ion-fab-button>
</ion-fab-list>
<ion-fab-list side="start">
<ion-fab-button>
<ion-icon name="logo-vimeo"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-chrome"></ion-icon>
</ion-fab-button>
<ion-fab-button>
<ion-icon name="logo-react"></ion-icon>
</ion-fab-button>
</ion-fab-list>
</ion-fab>
];
}
}
```

View File

@@ -10,6 +10,12 @@ Fabs are container elements that contain one or more fab buttons. They should be
### Angular / javascript
```html
<ion-header>
<ion-toolbar>
<ion-title>Header</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<!-- fab placed to the top end -->
<ion-fab vertical="top" horizontal="end" slot="fixed">
@@ -89,6 +95,12 @@ Fabs are container elements that contain one or more fab buttons. They should be
</ion-fab-list>
</ion-fab>
</ion-content>
<ion-footer>
<ion-toolbar>
<ion-title>Footer</ion-title>
</ion-toolbar>
</ion-footer>
```
@@ -96,7 +108,7 @@ Fabs are container elements that contain one or more fab buttons. They should be
```tsx
import React from 'react';
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonFab, IonFabButton, IonIcon, IonFabList } from '@ionic/react';
import { IonContent, IonHeader, IonFooter, IonPage, IonTitle, IonToolbar, IonFab, IonFabButton, IonIcon, IonFabList } from '@ionic/react';
import { add, settings, share, person, arrowForwardCircle, arrowBackCircle, arrowUpCircle, logoVimeo, logoFacebook, logoInstagram, logoTwitter } from 'ionicons/icons';
export const FabExamples: React.FC = () => {
@@ -104,7 +116,7 @@ export const FabExamples: React.FC = () => {
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>FabExamples</IonTitle>
<IonTitle>Header</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>
@@ -186,16 +198,138 @@ export const FabExamples: React.FC = () => {
</IonFabList>
</IonFab>
</IonContent>
<IonFooter>
<IonToolbar>
<IonTitle>Footer</IonTitle>
</IonToolbar>
</IonFooter>
</IonPage>
);
};
```
### Stencil
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'fab-example',
styleUrl: 'fab-example.css'
})
export class FabExample {
render() {
return [
<ion-header>
<ion-toolbar>
<ion-title>Header</ion-title>
</ion-toolbar>
</ion-header>,
<ion-content>
{/* fab placed to the top end */}
<ion-fab vertical="top" horizontal="end" slot="fixed">
<ion-fab-button>
<ion-icon name="add"></ion-icon>
</ion-fab-button>
</ion-fab>
{/* fab placed to the bottom end */}
<ion-fab vertical="bottom" horizontal="end" slot="fixed">
<ion-fab-button>
<ion-icon name="arrow-forward-circle"></ion-icon>
</ion-fab-button>
</ion-fab>
{/* fab placed to the top start */}
<ion-fab vertical="top" horizontal="start" slot="fixed">
<ion-fab-button>
<ion-icon name="arrow-back-circle"></ion-icon>
</ion-fab-button>
</ion-fab>
{/* fab placed to the bottom start */}
<ion-fab vertical="bottom" horizontal="start" slot="fixed">
<ion-fab-button>
<ion-icon name="arrow-up-circle"></ion-icon>
</ion-fab-button>
</ion-fab>
{/* fab placed to the (vertical) center and start */}
<ion-fab vertical="center" horizontal="start" slot="fixed">
<ion-fab-button>
<ion-icon name="share"></ion-icon>
</ion-fab-button>
</ion-fab>
{/* fab placed to the (vertical) center and end */}
<ion-fab vertical="center" horizontal="end" slot="fixed">
<ion-fab-button>
<ion-icon name="add"></ion-icon>
</ion-fab-button>
</ion-fab>
{/* fab placed to the top and end and on the top edge of the content overlapping header */}
<ion-fab vertical="top" horizontal="end" edge slot="fixed">
<ion-fab-button>
<ion-icon name="person"></ion-icon>
</ion-fab-button>
</ion-fab>
{/* fab placed to the bottom and start and on the bottom edge of content overlapping footer with a list to the right */}
<ion-fab vertical="bottom" horizontal="start" edge slot="fixed">
<ion-fab-button>
<ion-icon name="settings"></ion-icon>
</ion-fab-button>
<ion-fab-list side="end">
<ion-fab-button><ion-icon name="logo-vimeo"></ion-icon></ion-fab-button>
</ion-fab-list>
</ion-fab>
{/* fab placed in the center of the content with a list on each side */}
<ion-fab vertical="center" horizontal="center" slot="fixed">
<ion-fab-button>
<ion-icon name="share"></ion-icon>
</ion-fab-button>
<ion-fab-list side="top">
<ion-fab-button><ion-icon name="logo-vimeo"></ion-icon></ion-fab-button>
</ion-fab-list>
<ion-fab-list side="bottom">
<ion-fab-button><ion-icon name="logo-facebook"></ion-icon></ion-fab-button>
</ion-fab-list>
<ion-fab-list side="start">
<ion-fab-button><ion-icon name="logo-instagram"></ion-icon></ion-fab-button>
</ion-fab-list>
<ion-fab-list side="end">
<ion-fab-button><ion-icon name="logo-twitter"></ion-icon></ion-fab-button>
</ion-fab-list>
</ion-fab>
</ion-content>,
<ion-footer>
<ion-toolbar>
<ion-title>
Footer
</ion-title>
</ion-toolbar>
</ion-footer>
];
}
}
```
### Vue
```html
<template>
<ion-header>
<ion-toolbar>
<ion-title>Header</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<!-- fab placed to the top end -->
<ion-fab vertical="top" horizontal="end" slot="fixed">
@@ -275,6 +409,12 @@ export const FabExamples: React.FC = () => {
</ion-fab-list>
</ion-fab>
</ion-content>
<ion-footer>
<ion-toolbar>
<ion-title>Footer</ion-title>
</ion-toolbar>
</ion-footer>
</template>
```

View File

@@ -1,4 +1,10 @@
```html
<ion-header>
<ion-toolbar>
<ion-title>Header</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<!-- fab placed to the top end -->
<ion-fab vertical="top" horizontal="end" slot="fixed">
@@ -78,4 +84,10 @@
</ion-fab-list>
</ion-fab>
</ion-content>
<ion-footer>
<ion-toolbar>
<ion-title>Footer</ion-title>
</ion-toolbar>
</ion-footer>
```

View File

@@ -1,4 +1,10 @@
```html
<ion-header>
<ion-toolbar>
<ion-title>Header</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<!-- fab placed to the top end -->
<ion-fab vertical="top" horizontal="end" slot="fixed">
@@ -78,4 +84,10 @@
</ion-fab-list>
</ion-fab>
</ion-content>
<ion-footer>
<ion-toolbar>
<ion-title>Footer</ion-title>
</ion-toolbar>
</ion-footer>
```

View File

@@ -1,6 +1,6 @@
```tsx
import React from 'react';
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonFab, IonFabButton, IonIcon, IonFabList } from '@ionic/react';
import { IonContent, IonHeader, IonFooter, IonPage, IonTitle, IonToolbar, IonFab, IonFabButton, IonIcon, IonFabList } from '@ionic/react';
import { add, settings, share, person, arrowForwardCircle, arrowBackCircle, arrowUpCircle, logoVimeo, logoFacebook, logoInstagram, logoTwitter } from 'ionicons/icons';
export const FabExamples: React.FC = () => {
@@ -8,7 +8,7 @@ export const FabExamples: React.FC = () => {
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>FabExamples</IonTitle>
<IonTitle>Header</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>
@@ -90,6 +90,11 @@ export const FabExamples: React.FC = () => {
</IonFabList>
</IonFab>
</IonContent>
<IonFooter>
<IonToolbar>
<IonTitle>Footer</IonTitle>
</IonToolbar>
</IonFooter>
</IonPage>
);
};

View File

@@ -0,0 +1,107 @@
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'fab-example',
styleUrl: 'fab-example.css'
})
export class FabExample {
render() {
return [
<ion-header>
<ion-toolbar>
<ion-title>Header</ion-title>
</ion-toolbar>
</ion-header>,
<ion-content>
{/* fab placed to the top end */}
<ion-fab vertical="top" horizontal="end" slot="fixed">
<ion-fab-button>
<ion-icon name="add"></ion-icon>
</ion-fab-button>
</ion-fab>
{/* fab placed to the bottom end */}
<ion-fab vertical="bottom" horizontal="end" slot="fixed">
<ion-fab-button>
<ion-icon name="arrow-forward-circle"></ion-icon>
</ion-fab-button>
</ion-fab>
{/* fab placed to the top start */}
<ion-fab vertical="top" horizontal="start" slot="fixed">
<ion-fab-button>
<ion-icon name="arrow-back-circle"></ion-icon>
</ion-fab-button>
</ion-fab>
{/* fab placed to the bottom start */}
<ion-fab vertical="bottom" horizontal="start" slot="fixed">
<ion-fab-button>
<ion-icon name="arrow-up-circle"></ion-icon>
</ion-fab-button>
</ion-fab>
{/* fab placed to the (vertical) center and start */}
<ion-fab vertical="center" horizontal="start" slot="fixed">
<ion-fab-button>
<ion-icon name="share"></ion-icon>
</ion-fab-button>
</ion-fab>
{/* fab placed to the (vertical) center and end */}
<ion-fab vertical="center" horizontal="end" slot="fixed">
<ion-fab-button>
<ion-icon name="add"></ion-icon>
</ion-fab-button>
</ion-fab>
{/* fab placed to the top and end and on the top edge of the content overlapping header */}
<ion-fab vertical="top" horizontal="end" edge slot="fixed">
<ion-fab-button>
<ion-icon name="person"></ion-icon>
</ion-fab-button>
</ion-fab>
{/* fab placed to the bottom and start and on the bottom edge of content overlapping footer with a list to the right */}
<ion-fab vertical="bottom" horizontal="start" edge slot="fixed">
<ion-fab-button>
<ion-icon name="settings"></ion-icon>
</ion-fab-button>
<ion-fab-list side="end">
<ion-fab-button><ion-icon name="logo-vimeo"></ion-icon></ion-fab-button>
</ion-fab-list>
</ion-fab>
{/* fab placed in the center of the content with a list on each side */}
<ion-fab vertical="center" horizontal="center" slot="fixed">
<ion-fab-button>
<ion-icon name="share"></ion-icon>
</ion-fab-button>
<ion-fab-list side="top">
<ion-fab-button><ion-icon name="logo-vimeo"></ion-icon></ion-fab-button>
</ion-fab-list>
<ion-fab-list side="bottom">
<ion-fab-button><ion-icon name="logo-facebook"></ion-icon></ion-fab-button>
</ion-fab-list>
<ion-fab-list side="start">
<ion-fab-button><ion-icon name="logo-instagram"></ion-icon></ion-fab-button>
</ion-fab-list>
<ion-fab-list side="end">
<ion-fab-button><ion-icon name="logo-twitter"></ion-icon></ion-fab-button>
</ion-fab-list>
</ion-fab>
</ion-content>,
<ion-footer>
<ion-toolbar>
<ion-title>
Footer
</ion-title>
</ion-toolbar>
</ion-footer>
];
}
}
```

View File

@@ -1,5 +1,11 @@
```html
<template>
<ion-header>
<ion-toolbar>
<ion-title>Header</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<!-- fab placed to the top end -->
<ion-fab vertical="top" horizontal="end" slot="fixed">
@@ -79,5 +85,11 @@
</ion-fab-list>
</ion-fab>
</ion-content>
<ion-footer>
<ion-toolbar>
<ion-title>Footer</ion-title>
</ion-toolbar>
</ion-footer>
</template>
```

View File

@@ -55,6 +55,38 @@ export const FooterExample: React.FC = () => (
```
### Stencil
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'footer-example',
styleUrl: 'footer-example.css'
})
export class FooterExample {
render() {
return [
<ion-content></ion-content>,
// Footer without a border
<ion-footer class="ion-no-border">
<ion-toolbar>
<ion-title>Footer - No Border</ion-title>
</ion-toolbar>
</ion-footer>,
<ion-footer>
<ion-toolbar>
<ion-title>Footer</ion-title>
</ion-toolbar>
</ion-footer>
];
}
}
```
### Vue
```html

View File

@@ -0,0 +1,28 @@
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'footer-example',
styleUrl: 'footer-example.css'
})
export class FooterExample {
render() {
return [
<ion-content></ion-content>,
// Footer without a border
<ion-footer class="ion-no-border">
<ion-toolbar>
<ion-title>Footer - No Border</ion-title>
</ion-toolbar>
</ion-footer>,
<ion-footer>
<ion-toolbar>
<ion-title>Footer</ion-title>
</ion-toolbar>
</ion-footer>
];
}
}
```

View File

@@ -337,6 +337,201 @@ export const GridExample: React.FC = () => (
```
### Stencil
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'grid-example',
styleUrl: 'grid-example.css'
})
export class GridExample {
render() {
return [
<ion-grid>
<ion-row>
<ion-col>
ion-col
</ion-col>
<ion-col>
ion-col
</ion-col>
<ion-col>
ion-col
</ion-col>
<ion-col>
ion-col
</ion-col>
</ion-row>
<ion-row>
<ion-col size="6">
ion-col [size="6"]
</ion-col>
<ion-col>
ion-col
</ion-col>
<ion-col>
ion-col
</ion-col>
</ion-row>
<ion-row>
<ion-col size="3">
ion-col [size="3"]
</ion-col>
<ion-col>
ion-col
</ion-col>
<ion-col size="3">
ion-col [size="3"]
</ion-col>
</ion-row>
<ion-row>
<ion-col size="3">
ion-col [size="3"]
</ion-col>
<ion-col size="3" offset="3">
ion-col [size="3"] [offset="3"]
</ion-col>
</ion-row>
<ion-row>
<ion-col>
ion-col
</ion-col>
<ion-col>
ion-col
<br/>#
</ion-col>
<ion-col>
ion-col
<br/>#
<br/>#
</ion-col>
<ion-col>
ion-col
<br/>#
<br/>#
<br/>#
</ion-col>
</ion-row>
<ion-row>
<ion-col class="ion-align-self-start">
ion-col [start]
</ion-col>
<ion-col class="ion-align-self-center">
ion-col [center]
</ion-col>
<ion-col class="ion-align-self-end">
ion-col [end]
</ion-col>
<ion-col>
ion-col
<br/>#
<br/>#
</ion-col>
</ion-row>
<ion-row class="ion-align-items-start">
<ion-col>
[start] ion-col
</ion-col>
<ion-col>
[start] ion-col
</ion-col>
<ion-col class="ion-align-self-end">
[start] ion-col [end]
</ion-col>
<ion-col>
ion-col
<br/>#
<br/>#
</ion-col>
</ion-row>
<ion-row class="ion-align-items-center">
<ion-col>
[center] ion-col
</ion-col>
<ion-col>
[center] ion-col
</ion-col>
<ion-col>
[center] ion-col
</ion-col>
<ion-col>
ion-col
<br/>#
<br/>#
</ion-col>
</ion-row>
<ion-row class="ion-align-items-end">
<ion-col>
[end] ion-col
</ion-col>
<ion-col class="ion-align-self-start">
[end] ion-col [start]
</ion-col>
<ion-col>
[end] ion-col
</ion-col>
<ion-col>
ion-col
<br/>#
<br/>#
</ion-col>
</ion-row>
<ion-row>
<ion-col size="12" sizeSm="">
ion-col [size="12"] [sizeSm]
</ion-col>
<ion-col size="12" sizeSm="">
ion-col [size="12"] [sizeSm]
</ion-col>
<ion-col size="12" sizeSm="">
ion-col [size="12"] [sizeSm]
</ion-col>
<ion-col size="12" sizeSm="">
ion-col [size="12"] [sizeSm]
</ion-col>
</ion-row>
<ion-row>
<ion-col size="12" sizeMd="">
ion-col [size="12"] [sizeMd]
</ion-col>
<ion-col size="12" sizeMd="">
ion-col [size="12"] [sizeMd]
</ion-col>
<ion-col size="12" sizeMd="">
ion-col [size="12"] [sizeMd]
</ion-col>
<ion-col size="12" sizeMd="">
ion-col [size="12"] [sizeMd]
</ion-col>
</ion-row>
<ion-row>
<ion-col size="6" sizeLg="" offset="3">
ion-col [size="6"] [sizeLg] [offset="3"]
</ion-col>
<ion-col size="3" sizeLg="">
ion-col [size="3"] [sizeLg]
</ion-col>
</ion-row>
</ion-grid>
];
}
}
```
### Vue
```html

View File

@@ -0,0 +1,191 @@
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'grid-example',
styleUrl: 'grid-example.css'
})
export class GridExample {
render() {
return [
<ion-grid>
<ion-row>
<ion-col>
ion-col
</ion-col>
<ion-col>
ion-col
</ion-col>
<ion-col>
ion-col
</ion-col>
<ion-col>
ion-col
</ion-col>
</ion-row>
<ion-row>
<ion-col size="6">
ion-col [size="6"]
</ion-col>
<ion-col>
ion-col
</ion-col>
<ion-col>
ion-col
</ion-col>
</ion-row>
<ion-row>
<ion-col size="3">
ion-col [size="3"]
</ion-col>
<ion-col>
ion-col
</ion-col>
<ion-col size="3">
ion-col [size="3"]
</ion-col>
</ion-row>
<ion-row>
<ion-col size="3">
ion-col [size="3"]
</ion-col>
<ion-col size="3" offset="3">
ion-col [size="3"] [offset="3"]
</ion-col>
</ion-row>
<ion-row>
<ion-col>
ion-col
</ion-col>
<ion-col>
ion-col
<br/>#
</ion-col>
<ion-col>
ion-col
<br/>#
<br/>#
</ion-col>
<ion-col>
ion-col
<br/>#
<br/>#
<br/>#
</ion-col>
</ion-row>
<ion-row>
<ion-col class="ion-align-self-start">
ion-col [start]
</ion-col>
<ion-col class="ion-align-self-center">
ion-col [center]
</ion-col>
<ion-col class="ion-align-self-end">
ion-col [end]
</ion-col>
<ion-col>
ion-col
<br/>#
<br/>#
</ion-col>
</ion-row>
<ion-row class="ion-align-items-start">
<ion-col>
[start] ion-col
</ion-col>
<ion-col>
[start] ion-col
</ion-col>
<ion-col class="ion-align-self-end">
[start] ion-col [end]
</ion-col>
<ion-col>
ion-col
<br/>#
<br/>#
</ion-col>
</ion-row>
<ion-row class="ion-align-items-center">
<ion-col>
[center] ion-col
</ion-col>
<ion-col>
[center] ion-col
</ion-col>
<ion-col>
[center] ion-col
</ion-col>
<ion-col>
ion-col
<br/>#
<br/>#
</ion-col>
</ion-row>
<ion-row class="ion-align-items-end">
<ion-col>
[end] ion-col
</ion-col>
<ion-col class="ion-align-self-start">
[end] ion-col [start]
</ion-col>
<ion-col>
[end] ion-col
</ion-col>
<ion-col>
ion-col
<br/>#
<br/>#
</ion-col>
</ion-row>
<ion-row>
<ion-col size="12" sizeSm="">
ion-col [size="12"] [sizeSm]
</ion-col>
<ion-col size="12" sizeSm="">
ion-col [size="12"] [sizeSm]
</ion-col>
<ion-col size="12" sizeSm="">
ion-col [size="12"] [sizeSm]
</ion-col>
<ion-col size="12" sizeSm="">
ion-col [size="12"] [sizeSm]
</ion-col>
</ion-row>
<ion-row>
<ion-col size="12" sizeMd="">
ion-col [size="12"] [sizeMd]
</ion-col>
<ion-col size="12" sizeMd="">
ion-col [size="12"] [sizeMd]
</ion-col>
<ion-col size="12" sizeMd="">
ion-col [size="12"] [sizeMd]
</ion-col>
<ion-col size="12" sizeMd="">
ion-col [size="12"] [sizeMd]
</ion-col>
</ion-row>
<ion-row>
<ion-col size="6" sizeLg="" offset="3">
ion-col [size="6"] [sizeLg] [offset="3"]
</ion-col>
<ion-col size="3" sizeLg="">
ion-col [size="3"] [sizeLg]
</ion-col>
</ion-row>
</ion-grid>
];
}
}
```

View File

@@ -64,6 +64,13 @@ export class Header implements ComponentInterface {
const pageEl = this.el.closest('ion-app,ion-page,.ion-page,page-inner');
const contentEl = (pageEl) ? pageEl.querySelector('ion-content') : null;
// Cloned elements are always needed in iOS transition
writeTask(() => {
const title = cloneElement('ion-title') as HTMLIonTitleElement;
title.size = 'large';
cloneElement('ion-back-button');
});
await this.setupCollapsibleHeader(contentEl, pageEl);
}
}
@@ -87,6 +94,7 @@ export class Header implements ComponentInterface {
private async setupCollapsibleHeader(contentEl: HTMLIonContentElement | null, pageEl: Element | null) {
if (!contentEl || !pageEl) { console.error('ion-header requires a content to collapse, make sure there is an ion-content.'); return; }
if (typeof (IntersectionObserver as any) === 'undefined') { return; }
this.scrollEl = await contentEl.getScrollElement();
@@ -126,10 +134,6 @@ export class Header implements ComponentInterface {
this.scrollEl!.addEventListener('scroll', this.contentScrollCallback);
writeTask(() => {
const title = cloneElement('ion-title') as HTMLIonTitleElement;
title.size = 'large';
cloneElement('ion-back-button');
if (this.collapsibleMainHeader !== undefined) {
this.collapsibleMainHeader.classList.add('header-collapse-main');
}

View File

@@ -83,6 +83,51 @@ export const HeaderExample: React.FC = () => (
```
### Stencil
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'header-example',
styleUrl: 'header-example.css'
})
export class HeaderExample {
render() {
return [
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
</ion-buttons>
<ion-title>My Navigation Bar</ion-title>
</ion-toolbar>
<ion-toolbar>
<ion-title>Subheader</ion-title>
</ion-toolbar>
</ion-header>,
// Header without a border
<ion-header class="ion-no-border">
<ion-toolbar>
<ion-title>Header - No Border</ion-title>
</ion-toolbar>
</ion-header>,
<ion-content>
<ion-header collapse="condense">
<ion-toolbar>
<ion-title size="large">My Navigation Bar</ion-title>
</ion-toolbar>
</ion-header>
</ion-content>
];
}
}
```
### Vue
```html

View File

@@ -0,0 +1,41 @@
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'header-example',
styleUrl: 'header-example.css'
})
export class HeaderExample {
render() {
return [
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
</ion-buttons>
<ion-title>My Navigation Bar</ion-title>
</ion-toolbar>
<ion-toolbar>
<ion-title>Subheader</ion-title>
</ion-toolbar>
</ion-header>,
// Header without a border
<ion-header class="ion-no-border">
<ion-toolbar>
<ion-title>Header - No Border</ion-title>
</ion-toolbar>
</ion-header>,
<ion-content>
<ion-header collapse="condense">
<ion-toolbar>
<ion-title size="large">My Navigation Bar</ion-title>
</ion-toolbar>
</ion-header>
</ion-content>
];
}
}
```

View File

@@ -0,0 +1,26 @@
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'icon-example',
styleUrl: 'icon-example.css'
})
export class IconExample {
render() {
return [
// uses "star" icon for both modes
<ion-icon name="star"></ion-icon>,
// explicitly set the icon for each mode
<ion-icon ios="home" md="star"></ion-icon>,
// use a custom svg icon
<ion-icon src="/path/to/external/file.svg"></ion-icon>,
// set the icon size
<ion-icon size="small" name="heart"></ion-icon>,
<ion-icon size="large" name="heart"></ion-icon>
];
}
}
```

View File

@@ -51,6 +51,45 @@ export const ImgExample: React.FC = () => (
```
### Stencil
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'img-example',
styleUrl: 'img-example.css'
})
export class ImgExample {
private items = [{
'text': 'Item 1',
'src': '/path/to/external/file.png'
}, {
'text': 'Item 2',
'src': '/path/to/external/file.png'
}, {
'text': 'Item 3',
'src': '/path/to/external/file.png'
}];
render() {
return [
<ion-list>
{this.items.map(item =>
<ion-item>
<ion-thumbnail slot="start">
<ion-img src={item.src}></ion-img>
</ion-thumbnail>
<ion-label>{item.text}</ion-label>
</ion-item>
)}
</ion-list>
];
}
}
```
### Vue
```html

View File

@@ -0,0 +1,35 @@
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'img-example',
styleUrl: 'img-example.css'
})
export class ImgExample {
private items = [{
'text': 'Item 1',
'src': '/path/to/external/file.png'
}, {
'text': 'Item 2',
'src': '/path/to/external/file.png'
}, {
'text': 'Item 3',
'src': '/path/to/external/file.png'
}];
render() {
return [
<ion-list>
{this.items.map(item =>
<ion-item>
<ion-thumbnail slot="start">
<ion-img src={item.src}></ion-img>
</ion-thumbnail>
<ion-label>{item.text}</ion-label>
</ion-item>
)}
</ion-list>
];
}
}
```

View File

@@ -1,10 +1,9 @@
import { Component, ComponentInterface, Host, Prop, h } from '@stencil/core';
import { IonicSafeString } from '../../';
import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import { SpinnerTypes } from '../../interface';
import { sanitizeDOMString } from '../../utils/sanitization';
import { IonicSafeString, sanitizeDOMString } from '../../utils/sanitization';
@Component({
tag: 'ion-infinite-scroll-content',

View File

@@ -39,6 +39,32 @@ The `ion-infinite-scroll-content` component is not supported in React.
```
### Stencil
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'infinite-scroll-content-example',
styleUrl: 'infinite-scroll-content-example.css'
})
export class InfiniteScrollContentExample {
render() {
return [
<ion-content>
<ion-infinite-scroll>
<ion-infinite-scroll-content
loadingSpinner="bubbles"
loadingText="Loading more data...">
</ion-infinite-scroll-content>
</ion-infinite-scroll>
</ion-content>
];
}
}
```
### Vue
```html

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