Compare commits

..

341 Commits

Author SHA1 Message Date
github-actions
5e448d9c74 v6.0.3 2022-01-19 15:01:39 +00:00
Liam DeBeasi
be022f7de8 fix(angular-server): use correct @ionic/angular dependency version (#24593)
resolves #24592
2022-01-18 16:25:25 -05:00
Zac Hayes
1a9be747f2 docs(datetime): fix typo in overview (#24577) 2022-01-14 12:58:29 -05:00
Sean Perkins
af01a8b307 fix(item): error slot visible in Safari (#24579)
Resolves #24575
2022-01-14 12:36:14 -05:00
Sean Perkins
e00c9cbd4c docs(textarea): available autocapitalize options (#24574) 2022-01-13 13:00:33 -05:00
Sean Perkins
e284d7a2c7 docs(menu-toggle): add usage examples and slot docs (#24570) 2022-01-13 11:38:56 -05:00
Amanda Smith
c8a392aef5 fix(react): prevent errors when dismissing inline popover after containing element is removed (#24569) 2022-01-12 14:51:50 -06:00
Sean Perkins
273ae2cc08 fix(angular): apply touch, dirty and pristine form control classes (#24558)
Resolves #24483
2022-01-12 14:48:01 -05:00
Sean Perkins
9a15753fd9 fix(modal): life cycle events for controller modals (#24508)
Resolves #24460
2022-01-12 13:46:01 -05:00
Sean Perkins
a753d3438a test(overlays): wait for modal events to fire (#24568) 2022-01-12 12:18:29 -05:00
Liam DeBeasi
7704ac3a37 fix(menu): remove main attribute that was supposed to removed in v5 (#24565)
resolves #24563
2022-01-12 11:52:37 -05:00
Liam DeBeasi
8c442059b5 docs(input): clarify intended placeholder behavior for certain input types (#24567)
resolves #24557
2022-01-12 11:44:52 -05:00
Liam DeBeasi
3d20959221 fix(datetime): showing calendar grid no longer causes month to switch on ios 15 (#24554)
resolves #24405
2022-01-12 10:24:29 -05:00
Liam DeBeasi
88602a9acf chore(dev-build): bump patch version for lerna dev builds (#24564) 2022-01-12 10:05:08 -05:00
Sean Perkins
f5b4382fd5 fix(overlays): getTop now returns the top-most presented overlay (#24547)
Resolves #19111
2022-01-11 15:13:35 -05:00
Liam DeBeasi
c4745d24ac chore(dev-build): use exact versioning so npm installs correct Ionic Core (#24555) 2022-01-11 15:04:10 -05:00
Amanda Smith
bce849c5f3 fix(react): add useRef wrapper to useIonOverlay state to avoid stale references (#24553) 2022-01-11 13:40:46 -06:00
Liam DeBeasi
bb9e5f68b4 merge release-6.0.2
Release 6.0.2
2022-01-11 12:32:30 -05:00
github-actions
3057afdf82 v6.0.2 2022-01-11 17:10:35 +00:00
Liam DeBeasi
d520f78d21 chore(build): create github release and generate changelog 2022-01-11 12:06:29 -05:00
Liam DeBeasi
d81c4f9a35 chore(build): fetch all history when building 2022-01-11 16:33:44 +00:00
Liam DeBeasi
2d9ec00745 chore(build): fix lerna version config 2022-01-11 16:33:34 +00:00
Liam DeBeasi
c90ce311a8 fix(datetime): wheel picker shows correct column order in rtl (#24546)
resolves #24378
2022-01-11 09:36:41 -05:00
Sean Perkins
5bb1414f7f fix(breadcrumb): support routerLink on breadcrumb (#24509)
Resolves #24493
2022-01-10 16:22:42 -05:00
Liam DeBeasi
90458da406 fix(vue): correct route is replaced when using router.replace (#24533)
resolves #24226
2022-01-10 11:58:35 -05:00
Liam DeBeasi
f539ff4788 chore(): end holiday triage 2021 (#24534)
This reverts commit 87c51c4a82.
2022-01-07 16:55:37 -05:00
Sean Perkins
77f8412b74 fix(react,vue): backdrop for inline modal/popover overlay (#24453)
Resolves #24449
2022-01-07 13:21:20 -05:00
Liam DeBeasi
388622f973 fix(refresher): import icons to avoid errors in react and vue (#24525)
resolves #24480
2022-01-06 16:06:17 -05:00
Sean Perkins
5c54593dde fix(angular): attach change detector ref for inline overlays (#24521)
Allow template bindings to update with inline overlays.

Resolves #24502
2022-01-06 15:43:51 -05:00
Sean Perkins
bd82b5dc1d fix(datetime): add top padding to MD calendar month grid (#24522)
Resolves #24408
2022-01-06 12:12:36 -05:00
Liam DeBeasi
987d46cfa6 fix(css): inline css source in source maps (#24514)
resolves #24441
2022-01-05 14:26:52 -05:00
Liam DeBeasi
32fad3d02c fix(react): building app for production now works correctly with vite (#24515)
resolves #24229
2022-01-05 14:25:49 -05:00
Sean Perkins
1462cef692 fix(react): scrolling to bottom of modal contents (#24510)
Resolves #24478
2022-01-05 13:32:46 -05:00
Sean Perkins
b39003a4c6 fix(popover): allow arrow configuration with controller approach (#24512)
Resolves #24487
2022-01-05 13:18:18 -05:00
Sean Perkins
a3724e6a56 fix(datetime): time picker format with hourCycle h23 (#24476)
Resolves #24474
2022-01-04 16:24:44 -05:00
Sean Perkins
8f000089c2 fix(datetime): RTL will no longer infinitely scroll (#24475)
Resolves #24472
2022-01-04 16:15:38 -05:00
Sean Perkins
430439191d fix(datetime): update active day styling when day is selected (#24454)
Resolves #24414, #24451
2022-01-04 14:32:19 -05:00
Sean Perkins
e6955a26b9 fix(angular): popover will respect side attribute value (#24470)
Resolves #24466
2022-01-04 14:26:12 -05:00
Sean Perkins
948a3b4914 chore(vue-router): update @ionic/vue dependencies to v6 latest (#24473)
Close #24467
2022-01-04 14:24:14 -05:00
Sean Perkins
ee488ff27a chore(): build modal docs formatting (#24471) 2021-12-22 12:24:49 -05:00
Malte
4aacccb112 docs(modal): fix styling issues in the slot table (#24468) 2021-12-22 12:01:07 -05:00
Sean Perkins
4715b83abb fix(overlays): define custom element children (#24439)
Closes #24393
2021-12-17 13:48:17 -05:00
Liam DeBeasi
87c51c4a82 chore(): start holiday triage 2021 (#24429) 2021-12-16 16:42:57 -05:00
Liam DeBeasi
fc64715e2a docs(datetime): add examples on formatting for time zones (#24425) 2021-12-16 13:17:13 -05:00
Amanda Smith
94a781cb6a fix(radio): fix radio not showing checked state when not in a group (#24423) 2021-12-16 12:08:11 -06:00
Liam DeBeasi
ac3b110248 build(lerna): split release and next builds out into separate tasks (#24422) 2021-12-16 10:13:09 -05:00
Liam DeBeasi
b8c3b49d70 chore(): update to stencil 2.12.0 (#24420) 2021-12-15 12:35:37 -05:00
Liam DeBeasi
77f13d5cbb merge release-6.0.1
Release 6.0.1
2021-12-15 12:00:45 -05:00
Liam DeBeasi
90b0fdc4eb 6.0.1 2021-12-15 16:06:54 +00:00
Liam DeBeasi
4d185404bd merge release-5.9.3 2021-12-15 15:41:56 +00:00
Liam DeBeasi
1405761d08 5.9.3 2021-12-15 10:41:19 -05:00
Sean Perkins
bf8e436ee3 fix(vue): tabs no longer get unmounted when navigating back to a tabs context (#24337)
resolves #24332

Co-authored-by: Liam DeBeasi <liamdebeasi@icloud.com>
2021-12-15 09:50:00 -05:00
Amanda Smith
732f8e10ce fix(modal): fix timing issue when rapidly closing and opening controller modal (#24380) 2021-12-14 13:21:33 -06:00
Amanda Smith
e7d06743ae fix(datetime): fix datetime-ready class sometimes not being added due to race condition (#24385) 2021-12-14 10:44:50 -06:00
Sean Perkins
a5d56b3d5a fix(vue): strongly typed controller methods (#24388)
Resolves #24387
2021-12-14 11:10:46 -05:00
Amanda Smith
412e5f168e chore(): revert "feat(select): add event for when overlay is dismissed (#24099)" (#24398)
This reverts commit c1ecf94e4e.
2021-12-14 09:05:06 -06:00
Hans Krywalsky
c1ecf94e4e feat(select): add event for when overlay is dismissed (#24099) 2021-12-14 08:39:25 -06:00
Sean Perkins
03dd372933 chore(README): update links from next to main (#24384) 2021-12-13 13:34:12 -05:00
Liam DeBeasi
223f36f6ad chore(): merge next into main post Ionic 6 launch
chore(): merge next into main post Ionic 6 launch
2021-12-13 12:16:49 -05:00
Liam DeBeasi
efbb37855c chore(): sync next with main
chore(): sync next with main
2021-12-13 12:00:51 -05:00
Liam DeBeasi
f6a6a1e92e build(angular-server): remove locally built deps 2021-12-13 16:46:20 +00:00
Liam DeBeasi
17ecff3fc5 build(lerna): bump version 2021-12-13 16:36:54 +00:00
Liam DeBeasi
8a74f875c3 chore(): fix package versions 2021-12-13 16:35:20 +00:00
Liam DeBeasi
75084fa61c build(angular-server): update package lock 2021-12-13 16:32:47 +00:00
Liam DeBeasi
c9f7909d62 chore(): sync with main 2021-12-13 11:31:44 -05:00
Liam DeBeasi
4a9e1ed247 build(lerna): add release script (#24374) 2021-12-13 11:12:02 -05:00
Liam DeBeasi
179cbd334b build(): add lerna for dev builds (#24358) 2021-12-10 17:17:53 -05:00
Sean Perkins
abd9a4b0a1 chore(README): logo url asset path (#24373) 2021-12-10 17:09:42 -05:00
Sean Perkins
3fc278a539 chore(README): update readme format (#24368) 2021-12-10 17:00:25 -05:00
Sean Perkins
7c700b4caa fix(overlays): define children custom elements (#24372)
Resolves #24366
2021-12-10 16:32:12 -05:00
Sean Perkins
4ff3477532 chore(CODEOWNERS): global owners for framework team (#24370) 2021-12-10 12:33:58 -05:00
Sean Perkins
24b4ff0d1c chore(tech-debt): codeowners rules (#24350) 2021-12-10 12:21:27 -05:00
Liam DeBeasi
1bfac52331 perf(content): remove global click listener to improve interaction performance (#24360)
resolves #24359
2021-12-10 10:34:44 -05:00
Liam DeBeasi
6309d5ddba fix(vue): improve query params handling in tabs (#24355)
resolves #24353
2021-12-09 10:42:43 -05:00
Sean Perkins
500985ce04 fix(item): remove empty padding space for item bottom (#24323)
* fix(item): remove empty padding space for item bottom

* test(item): padding CSS variable screenshot test

* fix(item): remove --bottom-padding-start CSS variable

Resolves #23892
2021-12-08 16:15:08 -05:00
Sean Perkins
63066bcb9c chore(deps): update puppeteer to v10 (#24342)
* chore(deps): update puppeteer to v10

* chore(item): disable nested-interactive axe rule temporarily

* chore(segment): disable nested-interactive axe rule temporarily

* chore(deps): update package-lock with puppeteer and axe-core update

* chore(): add TODO task references for axe nested-interactive rule

* chore(deps): remove @types/puppeteer dev dep
2021-12-08 16:13:17 -05:00
Liam DeBeasi
600885c16d merge release-6.0.0
6.0.0
2021-12-08 09:31:15 -05:00
Liam DeBeasi
290d7cbab9 6.0.0 2021-12-08 14:12:34 +00:00
Liam DeBeasi
04219fa061 merge release-6.0.0-rc.4
6.0.0-rc.4
2021-12-08 08:52:52 -05:00
Liam DeBeasi
521fc781c7 6.0.0-rc.4 2021-12-07 15:51:51 -05:00
Liam DeBeasi
108a3522f1 chore(): sync with main for RC4
chore(): sync with main for RC4
2021-12-07 15:38:04 -05:00
Liam DeBeasi
eb9bc8199d chore(): fix bad merge, update tests 2021-12-07 20:23:47 +00:00
Liam DeBeasi
c065d8b5d8 chore(): fix lint in angular 2021-12-07 20:13:37 +00:00
Liam DeBeasi
e4056f7945 chore(): sync with main 2021-12-07 14:57:29 -05:00
Liam DeBeasi
13d4418588 fix(react, vue): remove sideeffects to improve treeshaking (#24313) 2021-12-06 11:39:23 -05:00
Liam DeBeasi
0920797612 fix(accordion): improve functionality with nested accordions (#24302) 2021-12-06 10:28:10 -05:00
Sean Perkins
8bdcd3c6c9 fix(datetime): keyboard navigation of time picker columns (#24251) 2021-12-01 11:57:51 -05:00
Amanda Smith
c2bef8df14 fix(picker-column-internal): prevent multiple items from being highlighted at once (#24268) 2021-12-01 10:16:58 -06:00
Sean Perkins
b0eadfe229 refactor(datetime): e2e does not support components option (#24270) 2021-11-30 14:50:12 -05:00
Liam DeBeasi
ade21d3b19 docs(modal): add inline modal docs (#24269) 2021-11-30 14:22:45 -05:00
Liam DeBeasi
f61f356000 fix(item): counter defaults to false to make upgrade easier (#24263) 2021-11-30 09:44:46 -05:00
Liam DeBeasi
0d749923a8 docs(popover): add popover examples (#24267)
resolves #24266
2021-11-24 11:43:32 -05:00
Sean Perkins
ec3bc52ff1 fix(datetime): update active calendar display when value changes (#24244) 2021-11-24 11:23:13 -05:00
Amanda Smith
36a096c9b6 fix(content): ensure scrollEl is always available in scroll methods (#24255) 2021-11-24 08:40:36 -06:00
Liam DeBeasi
55db38ddc5 feat(react): add setupIonicReact function (#24254)
resolves #24139
2021-11-22 15:29:47 -05:00
Liam DeBeasi
3c4f9fd2d5 merge release-6.0.0-rc.3
6.0.0-rc.3
2021-11-17 19:31:06 -05:00
Liam DeBeasi
24f4e471aa 6.0.0-rc.3 2021-11-17 17:28:37 +00:00
Liam DeBeasi
ab7a4e3379 chore(): sync with main
chore(): sync with main
2021-11-17 12:20:01 -05:00
Liam DeBeasi
a3b7b45132 chore(): sync with main 2021-11-17 12:04:26 -05:00
Sean Perkins
3949a949df fix(item): allow click targets inside of label (#24225)
* fix(item): allow click targets inside of label

* docs(label): document z-index usage in label
2021-11-17 11:13:58 -05:00
Liam DeBeasi
5387bdb471 chore(): sync with main for RC 3
chore(): sync with main for RC 3
2021-11-17 11:06:28 -05:00
Liam DeBeasi
618271d1e2 chore(): sync with main 2021-11-17 10:40:04 -05:00
Sean Perkins
713f0f5526 fix(textarea): floating label with autogrow textareas (#24202)
* fix(textarea): floating label with autogrow textareas

* test(textarea): autogrow visual diff tests
2021-11-16 12:05:11 -05:00
Sean Perkins
9cf7c89704 fix(input): date type in ion-input now aligns correctly on iOS 15 (#24213) 2021-11-12 14:35:12 -05:00
Sean Perkins
fc1eae982d fix(angular): prevent duplicate event emissions (#24200)
* fix(angular-output-targets): prevent duplicate event emissions

* feat(angular-output-target): update package to ^0.2.1
2021-11-11 15:42:58 -05:00
Sean Perkins
0bb8e88582 test(tabs): skip tests for vue tabs (#24211) 2021-11-11 14:38:35 -05:00
Will Martin
5a2a335784 fix(all): Ionic components that use child Ionic components are now correctly defined (#24191)
resolves #23571, #24116, #24129

Co-authored-by: Liam DeBeasi <liamdebeasi@icloud.com>
2021-11-11 12:18:38 -05:00
Liam DeBeasi
5d4f5af360 fix(modal): card modal shadow now shows up correctly on ipad (#24203) 2021-11-11 10:59:18 -05:00
Liam DeBeasi
59e27bdcc6 chore(): sync with main branch
chore(): sync with main branch
2021-11-11 10:42:43 -05:00
Liam DeBeasi
2054690f54 chore(): sync with main 2021-11-11 10:19:05 -05:00
Liam DeBeasi
1f4f8eb6ca fix(modal): border radius is now correctly applied to card modals (#24204) 2021-11-11 10:01:53 -05:00
Sean Perkins
009dff5584 fix(md/label): apply error appearance when control is touched (#24072) 2021-11-09 12:42:44 -05:00
Liam DeBeasi
118c606703 fix(icon): update to ionicons 6 to resolve typescript 4.4 errors (#24185) 2021-11-08 16:59:30 -05:00
Sean Perkins
52cd5d0cce fix(input): ionInput event emits with type of InputEvent (#24111)
The ionInput event for both ion-input and ion-textarea will emit with a type of InputEvent.
2021-11-08 16:01:38 -05:00
Liam DeBeasi
da339a8a74 fix(modal, popover): opening modal and popover now works even if overlay was added to ion-app directly (#24174)
resolves #23728
2021-11-08 10:19:23 -05:00
Liam DeBeasi
b3759aed5b fix(overlays): declarative modals now work properly with the hardware back button (#24165) 2021-11-05 10:04:13 -04:00
Liam DeBeasi
5bd905d5e9 docs(angular): fix breaking change version typo (#24159) 2021-11-03 15:28:42 -04:00
Liam DeBeasi
e757e718c9 merge release-6.0.0-rc.2
Release 6.0.0-rc.2
2021-11-03 10:01:26 -04:00
Liam DeBeasi
15fc293d75 fix(react): improve component compatibility with preact (#24132)
resolves #23516
2021-11-03 09:25:08 -04:00
Liam DeBeasi
61be8aa140 6.0.0-rc.2 2021-11-03 09:16:27 -04:00
Liam DeBeasi
ff25ac14fa chore(): sync with main for GitHub Actions
chore(): sync with main for GitHub Actions
2021-11-02 17:14:00 -04:00
Liam DeBeasi
2ce8011805 chore(): fix react router test package-lock 2021-11-02 21:00:29 +00:00
Liam DeBeasi
27aef9343c fix(datetime): resolve month and year jumping issue on ios (#24142)
resolves #23910
2021-11-02 16:37:12 -04:00
Liam DeBeasi
3157005afe chore(): add webpack-cli to react and react router test apps 2021-11-02 20:36:38 +00:00
Liam DeBeasi
c39ef04373 chore(): fix sync paths 2021-11-02 20:03:20 +00:00
Liam DeBeasi
da66a2cf20 chore(all): update scripts for CE build and GitHub actions 2021-11-02 15:56:43 -04:00
Liam DeBeasi
6346011d62 Merge remote-tracking branch 'origin/next' into gha-next 2021-11-02 15:53:14 -04:00
Liam DeBeasi
8b940e505e chore(): update ionicons and stencil (#24152) 2021-11-02 13:15:49 -04:00
Liam DeBeasi
143b227d35 chore(): sync GitHub Actions with main 2021-11-02 09:21:41 -04:00
Liam DeBeasi
206cf40bf4 style(angular-server): add eslint and prettier (#24126) 2021-10-27 12:03:28 -04:00
Liam DeBeasi
76f7800253 ci(angular-server): add lint step (#24125) 2021-10-27 11:43:12 -04:00
Liam DeBeasi
3477e7b02f merge release-6.0.0-rc.1
Release 6.0.0 rc.1
2021-10-27 11:15:40 -04:00
Liam DeBeasi
f7cdee4189 chore(): fix angular server install 2021-10-27 11:01:31 -04:00
Liam DeBeasi
283ba60f2e 6.0.0-rc.1 2021-10-27 10:42:08 -04:00
Liam DeBeasi
51425e3b8e chore(): remove old metadata 2021-10-27 10:13:36 -04:00
Liam DeBeasi
b3d249f058 chore(): fix angular output test 2021-10-27 10:04:21 -04:00
Liam DeBeasi
26d20200dd chore(): temp disable linter 2021-10-27 09:52:00 -04:00
Liam DeBeasi
562a52a4dd chore(): sync with main for rc1
chore(): sync with main for rc1
2021-10-27 09:36:18 -04:00
Liam DeBeasi
3f52ebea6f chore(): add missing comma 2021-10-27 13:24:22 +00:00
Liam DeBeasi
9c540583b2 chore(): sync with main for rc1 2021-10-27 09:21:44 -04:00
Liam DeBeasi
7fed7bcb61 chore(): sync main changes into next
chore(): sync main changes into next
2021-10-22 17:28:19 -04:00
Liam DeBeasi
dd97c04d4d test(react): add react-scripts dependency 2021-10-22 21:10:35 +00:00
Liam DeBeasi
fdbf0950ef test(react): remove capacitor 2021-10-22 17:00:24 -04:00
Liam DeBeasi
48fbfa78e7 chore(): avoid ce build bug for now 2021-10-22 20:43:40 +00:00
Liam DeBeasi
264c42e63a test(react): update test for declarative modals 2021-10-22 20:40:08 +00:00
Liam DeBeasi
3e043e4952 test(react): ensure test app is getting latest CE build files 2021-10-22 20:35:29 +00:00
Liam DeBeasi
b2b87d24fc test(react): update test for inline modal 2021-10-22 20:21:07 +00:00
Liam DeBeasi
c425997cd8 chore(angular): lint 2021-10-22 19:47:02 +00:00
Liam DeBeasi
8d774de445 test(vue): fix incorrect test 2021-10-22 19:28:02 +00:00
Liam DeBeasi
cfd32aea30 chore(): sync with main 2021-10-22 15:25:23 -04:00
Liam DeBeasi
7ab50dda83 chore(): sync with main 2021-10-22 15:24:34 -04:00
Liam DeBeasi
71fab0fa12 fix(datetime): default sizing preserves shape of datetime (#24104) 2021-10-21 16:44:35 -04:00
Amanda Smith
4eb02ca776 docs(datetime): add usage examples for use in popovers (#24095) 2021-10-21 15:38:54 -05:00
Ely Lucas
f3e492c897 fix(react): overlays shown with useIonModal and useIonPopover no longer render outside of main react tree
closes #23516 and #23516
2021-10-15 15:29:25 -06:00
Mike Hartington
3451a34ad0 feat(angular): build for angular 12.0 (#23970) 2021-10-15 16:54:59 -04:00
Liam DeBeasi
e3996cfbd5 fix(datetime): clear button is now rendered even if showDefaultButtons is false (#24075) 2021-10-14 14:53:17 -04:00
Liam DeBeasi
61b99d13bf fix(accordion-group): ionChange is now fired properly in vue (#24063)
resolves #23762
2021-10-13 08:57:12 -04:00
Amanda Smith
49db6d0288 fix(modal): fix backdrop animation for sheets with off-center backdropBreakpoint (#24061) 2021-10-12 11:19:35 -05:00
Liam DeBeasi
8a86cfb705 fix(infinite-scroll): infinite scroll event now fired with custom elements build (#24043)
resolves #24034
2021-10-07 14:36:21 -04:00
Liam DeBeasi
b2dc338aeb merge release-6.0.0-rc.0
6.0.0-rc.0
2021-10-07 14:10:52 -04:00
Liam DeBeasi
1dc44c933e 6.0.0-rc.0 2021-10-07 09:25:28 -04:00
Liam DeBeasi
b37adacdcb merge release-6.0.0-beta.7
Release 6.0.0 beta.7
2021-10-06 16:15:12 -04:00
Liam DeBeasi
907996ce16 fix(angular): setup config properly (#24028) 2021-10-06 16:14:41 -04:00
Liam DeBeasi
24df1c22af 6.0.0-beta.7 2021-10-06 12:07:54 -04:00
Liam DeBeasi
a80c43cf79 6.0.0-beta.7 2021-10-06 16:06:49 +00:00
Liam DeBeasi
39c9ad2a29 chore(): sync with next for beta 7 2021-10-06 11:55:50 -04:00
Liam DeBeasi
5f31196fc1 chore(): fix tests again 2021-10-06 15:35:12 +00:00
Liam DeBeasi
b12422a4d9 chore(): fix tests 2021-10-06 15:14:47 +00:00
Liam DeBeasi
6951b7703c chore(): fix tests for now 2021-10-06 15:03:27 +00:00
Liam DeBeasi
0ade0a5f09 chore(all): sync with main for beta 7 2021-10-06 10:52:14 -04:00
Liam DeBeasi
03201643ba fix(datetime): change now emitted when picker is typed into (#24018) 2021-10-05 17:52:22 -04:00
Liam DeBeasi
7ce3959b66 feat(header, footer): add ios fading header style (#24011) 2021-10-05 16:44:23 -04:00
Will Martin
225a278740 fix(reorder-group): wait for content to render before getting scroll position (#24007)
resolves #23875
2021-10-05 16:15:08 -04:00
Will Martin
4715a57010 refactor(angular): use Stencil output target for Angular bindings (#23986) 2021-10-05 16:14:12 -04:00
Liam DeBeasi
0ab37b5061 fix(datetime): time picker uses new iOS 15 style (#23996)
resolves #23768
2021-10-05 09:14:52 -04:00
Amanda Smith
c20408369b fix(select): ensure popover options with number values are searched for correctly (#23998) 2021-10-04 11:19:49 -05:00
Liam DeBeasi
0ef4d68413 chore(): add base new picker component for datetime revisions (#23995) 2021-10-04 11:36:53 -04:00
Amanda Smith
2497a53255 fix(select): focus selected item in popovers (#23991) 2021-10-01 13:33:53 -05:00
Amanda Smith
86a77bd379 fix(datetime): add ionBlur/ionFocus events to whole component (#23980) 2021-09-27 10:01:03 -05:00
Liam DeBeasi
8708095111 feat(all): add CustomEvents types to components that emit events (#23956)
resolves #22925

BREAKING CHANGE: The `RadioChangeEventDetail` interface has been removed in favor of `RadioGroupChangeEventDetail`.
2021-09-24 16:28:49 -04:00
Amanda Smith
285a371101 fix(react): ensure inline modal content is visible (#23968) 2021-09-23 14:05:21 -05:00
Liam DeBeasi
ed455ab4c6 fix(modal): backdropBreakpoint is now an exclusive value (#23954) 2021-09-20 12:35:53 -04:00
Liam DeBeasi
ea39c6e5b3 fix(datetime): ionChange is no longer called for out of range dates (#23940)
resolves #23939
2021-09-16 10:44:20 -04:00
Liam DeBeasi
23994e211a merge release-6.0.0-beta.6
6.0.0-beta.6
2021-09-15 13:01:52 -04:00
Liam DeBeasi
67d81e2caa 6.0.0-beta.6 2021-09-15 12:37:54 -04:00
Liam DeBeasi
a64891c781 chore(): sync with main
chore(): sync with main for v6 beta 6
2021-09-15 12:25:29 -04:00
Liam DeBeasi
f69c90504e docs(popover): fix merge conflict with docs 2021-09-15 16:08:57 +00:00
Liam DeBeasi
ecb30af4d8 chore(): resolve merge conflicts for beta 2021-09-15 12:02:43 -04:00
William Martin
18765e7e39 feat(datetime): add clear button (#23920)
resolves #17482 

Co-authored-by: Liam DeBeasi <liamdebeasi@users.noreply.github.com>
2021-09-14 22:52:33 -04:00
William Martin
45cabae04b feat(platform): add ability to override platform detection methods (#23915)
resolves #19737
2021-09-14 15:49:04 -04:00
Liam DeBeasi
414f24685c fix(modal): sheet animation works correctly if breakpoints value does not include 1 (#23927) 2021-09-14 15:27:59 -04:00
Liam DeBeasi
497537ac73 chore(): bump react output target (#23926) 2021-09-14 12:01:56 -04:00
Liam DeBeasi
4ae44b7a23 feat(datetime): add ability to select only month, year, or month and year (#23913) 2021-09-14 09:10:43 -04:00
Liam DeBeasi
c50d895370 feat(react): add custom elements bundle (#23896) 2021-09-13 14:53:28 -04:00
Liam DeBeasi
d1763fc8b5 fix(modal): add sheet modal properties for angular (#23899) 2021-09-09 14:02:24 -04:00
Liam DeBeasi
e2d2ad6f8e fix(modal): handle on sheet modal can now be turned off (#23900) 2021-09-09 13:29:42 -04:00
Liam DeBeasi
58a4ba2853 fix(modal): sheet modal handle is now positioned correctly (#23901) 2021-09-09 13:24:32 -04:00
Liam DeBeasi
9d87028e81 fix(modal): modal displays in middle of screen on desktop (#23911) 2021-09-09 12:27:42 -04:00
Liam DeBeasi
195d817967 fix(modal): sheet modal now accounts for safe area (#23884)
resolves #23874
2021-09-08 09:15:45 -04:00
William Martin
879ab8ebda feat(menu): add console error for incorrect usage of contentId (#23871)
resolves #23810
2021-09-08 08:54:01 -04:00
William Martin
5fd80fd438 fix(modal): expose breakpoint props in ModalOptions interface (#23867)
resolves #23866
2021-09-07 10:55:50 -04:00
William Martin
6a89bd4c56 docs(accordion): update React usage (#23870) 2021-09-07 10:55:11 -04:00
Liam DeBeasi
a65e74ce3a docs(modal): fix breakpoints explanation (#23862) 2021-09-07 09:22:49 -04:00
Liam DeBeasi
9fa373c6ef merge release-6.0.0-beta.5
6.0.0-beta.5
2021-09-01 12:07:28 -04:00
Liam DeBeasi
51dae5a4d6 6.0.0-beta.5 2021-09-01 11:27:29 -04:00
Liam DeBeasi
00bae431d4 chore(): build vue with bottom sheet changes 2021-09-01 11:15:40 -04:00
Liam DeBeasi
7a50992cb0 chore(): sync with main
chore(): sync with main for v6 beta 5 release
2021-09-01 11:03:52 -04:00
Liam DeBeasi
c75951354b chore(): remove duplicate export 2021-09-01 10:33:27 -04:00
Liam DeBeasi
b211cf0236 chore(): sync with main for beta 5 release 2021-09-01 10:14:58 -04:00
William Martin
1680b0ce9f refactor(react): transition to Stencil React bindings (#23826) 2021-08-31 17:29:59 -04:00
Liam DeBeasi
5ca2ce9197 fix(item): form validation states are now properly shown (#23853)
resolves #23733 #23850

Co-authored-by: Will Martin <willmartindev@users.noreply.github.com>
2021-08-31 17:18:21 -04:00
Liam DeBeasi
12216d378d feat(modal): add bottom sheet functionality (#23828)
resolves #21039
2021-08-31 15:19:19 -04:00
Liam DeBeasi
c925274c3b fix(angular): overlay interfaces are now properly exported (#23847)
resolves #23846
2021-08-30 10:35:03 -04:00
Liam DeBeasi
a212eb5259 fix(overlays): thrown errors are no longer suppressed (#23831)
resolves #22724
2021-08-27 12:51:17 -04:00
Liam DeBeasi
1d2ee92ca0 feat(popover): add ability to pass event to present method (#23827)
resolves #23813
2021-08-26 16:22:04 -04:00
William Martin
950350a948 fix(datetime): prevent vertical page scroll on interaction (#23780)
resolves #23554
2021-08-26 09:18:51 -04:00
Liam DeBeasi
3d1ae0305d merge release-6.0.0-beta.4
6.0.0-beta.4
2021-08-18 11:51:10 -04:00
Liam DeBeasi
461390612d 6.0.0-beta.4 2021-08-18 11:28:35 -04:00
Liam DeBeasi
c2bd56bd4b chore(): sync next with main for beta 4
chore(): sync next with main for beta 4
2021-08-18 11:16:52 -04:00
Liam DeBeasi
71bf631863 chore(): fix vue e2e test 2021-08-18 10:38:59 -04:00
Liam DeBeasi
96790054f1 chore(): fix tests from merge 2021-08-18 10:23:09 -04:00
Liam DeBeasi
79e780e511 chore(): resolve merge conflict with vue test app 2021-08-18 09:44:34 -04:00
Liam DeBeasi
4c06814494 chore(): resolve merge conflict in vue 2021-08-18 09:43:32 -04:00
Liam DeBeasi
c8cbe9c1f3 chore(): sync with main for beta 4 2021-08-18 09:42:03 -04:00
Hans Krywalsky
ea348f005a feat(datetime): add firstDayOfWeek property (#23692)
resolves #23556

Co-authored-by: Liam DeBeasi <liamdebeasi@icloud.com>
2021-08-17 10:45:39 -04:00
William Martin
bc4e8267aa fix(datetime): reduce time presentation min height (#23771)
resolves #23690
2021-08-16 15:58:21 -04:00
Liam DeBeasi
578b9062dd fix(vue): modal and popover components now correctly pass properties (#23761)
resolves #23698
2021-08-16 09:09:41 -04:00
William Martin
2995e337c8 fix(item): highlight now appears above helper/error text (#23763)
resolves #23510
2021-08-12 10:51:36 -04:00
Hans Krywalsky
6342fde56c feat(datetime): add hourCycle property (#23686)
resolves #23661

Co-authored-by: Liam DeBeasi <liamdebeasi@icloud.com>
2021-08-10 13:20:17 -04:00
Liam DeBeasi
ea39c70b3e fix(vue): custom element internal properties are no longer overridden in vue 3.1.0 (#23738)
resolves #23539
2021-08-09 11:41:31 -04:00
Hans Krywalsky
30f8508296 feat(action-sheet): add data property to ActionSheetButton (#23744)
resolves #23700

Co-authored-by: Liam DeBeasi <liamdebeasi@icloud.com>
2021-08-09 11:32:57 -04:00
Liam DeBeasi
fbd32ffb26 fix(toast): ToastOptions interface now contains icon prop (#23737)
resolves #23736
2021-08-06 16:30:34 -04:00
Liam DeBeasi
3befdc32de merge release-6.0.0-beta.3
6.0.0-beta.3
2021-08-04 13:32:41 -04:00
Liam DeBeasi
5980db44e5 fix(datetime): text color on ios mode now accounts for color contrast (#23729)
resolves #23723
2021-08-04 12:26:55 -04:00
Liam DeBeasi
12aafd980c 6.0.0-beta.3 2021-08-04 12:20:50 -04:00
Liam DeBeasi
36eeb26db7 chore(): run build for vue (#23730) 2021-08-04 12:08:59 -04:00
Liam DeBeasi
7638f0986d chore(): sync next with main for v6 beta 3 release
chore(): sync next with main for v6 beta 3 release
2021-08-04 11:31:31 -04:00
Liam DeBeasi
7c0f9b73e8 chore(): fix extra merge conflict 2021-08-04 11:03:08 -04:00
Liam DeBeasi
c70a18ebc2 chore(): sync with main 2021-08-04 10:35:59 -04:00
William Martin
f2e7a26797 fix(popover): fix keyboard arrow navigation (#23709)
resolves #23512
2021-08-03 13:43:41 -04:00
William Martin
fe2810b227 fix(list): change inset border radius to match iOS 15 (#23711) 2021-08-02 09:56:08 -04:00
Liam DeBeasi
3a1a9cbce4 fix(vue): popover positioning is now correct with custom elements build (#23680) 2021-07-26 09:26:20 -04:00
Dominik Geng
df24c8c5ae feat(toast): add icon property to show icon at start of toast content (#23596)
resolves #23524

Co-authored-by: William Martin <contact@willmartin.dev>
Co-authored-by: Liam DeBeasi <liamdebeasi@users.noreply.github.com>
2021-07-23 12:46:01 -04:00
Liam DeBeasi
fffef8acd2 chore(): sync with main
chore(): sync with main
2021-07-23 11:27:33 -04:00
Liam DeBeasi
cf4d647ded merge release-6.0.0-beta.2
6.0.0-beta.2
2021-07-21 10:41:58 -04:00
Liam DeBeasi
4418f7a3cf 6.0.0-beta.2 2021-07-21 10:23:50 -04:00
Liam DeBeasi
3042301646 chore(): sync next with main in prep for beta 2
chore(): sync next with main in prep for beta 2
2021-07-21 10:10:52 -04:00
Liam DeBeasi
1e7696a0f1 chore(): fix additional conflicts 2021-07-21 09:46:04 -04:00
Liam DeBeasi
4377d27790 chore(): sync main in prep for beta 2 2021-07-21 09:44:01 -04:00
William Martin
b6c53e539b feat(segment): add keyboard navigation, add selectOnFocus property to control selection follow focus behavior (#23590)
resolves #23520
2021-07-20 16:45:17 -04:00
Liam DeBeasi
82d6275f3d chore(): sync with main branch
chore(): sync with main branch
2021-07-20 15:00:54 -04:00
Liam DeBeasi
b6cfc05b1f chore(): update disallowed list for label 2021-07-20 13:12:27 -04:00
Liam DeBeasi
d749d583e7 chore(): sync with main 2021-07-20 12:50:52 -04:00
William Martin
321341d97d feat(datetime): add size property (#23649)
resolves #23518
2021-07-20 12:31:38 -04:00
Brandy Carney
2c07a1566b feat(select): update popover interface to match MD spec on desktop, allow multiple values in popover interface (#23474)
resolves #23657
resolves #15500
resolves #12310
2021-07-20 11:23:00 -04:00
Liam DeBeasi
be219a2814 fix(datetime): years displayed now more consistent with v5 datetime, max and min are now accounted for in MD mode (#23616)
resolves #23615
2021-07-15 08:49:25 -04:00
Liam DeBeasi
9ce57d2efb feat(breadcrumbs): ionCollapsedClick event payload now contains references to collapsed breadcrumb elements (#23611)
resolves #23552
2021-07-13 11:21:36 -04:00
Victor Berchet
8f2c4f73db feat(range): add support for customizing pin format (#22972) 2021-07-09 10:57:52 -04:00
Liam DeBeasi
1c9435c3f5 docs(accordion): add usage on how to get and set the state programmatically (#23595) 2021-07-08 16:47:21 -04:00
Liam DeBeasi
259b1359db perf(): remove shims for legacy browsers no longer supported in v6 (#23592) 2021-07-08 11:01:40 -04:00
Hans Krywalsky
7ac010943b feat(datetime): add showDefaultTimeLabel property and time-label slot (#23577)
resolves #23555
2021-07-07 09:21:13 -04:00
William Martin
55bd1f749b fix(datetime): add keyboard year navigation (#23585)
resolves #21553 
resolves #18122
2021-07-06 15:56:50 -04:00
Liam DeBeasi
4188964dc8 fix(datetime): selecting time now works correctly on firefox (#23583)
resolves #23545
2021-07-06 14:27:27 -04:00
Liam DeBeasi
8f172de355 fix(accordion): value can now be set as string when using multiple is true (#23581)
resolves #23550
2021-07-06 12:24:20 -04:00
Liam DeBeasi
e5a7b34262 fix(angular): modal and popover now have correct props defined on angular component (#23565) 2021-07-01 18:55:48 -04:00
Liam DeBeasi
be4f89e6f4 docs(datetime): add correct angular usage example in a modal (#23564) 2021-07-01 17:04:11 -04:00
Liam DeBeasi
de6c024373 merge release-6.0.0-beta.1
6.0.0-beta.1
2021-07-01 17:01:21 -04:00
Liam DeBeasi
9037103083 6.0.0-beta.1 2021-07-01 13:22:12 -04:00
Liam DeBeasi
2e30ad8bce chore(): fix merge conflict 2021-07-01 13:09:04 -04:00
Liam DeBeasi
873284a8d6 chore(): sync next with 5.6.11 changes
chore(): sync next with 5.6.11 changes
2021-07-01 13:02:30 -04:00
Liam DeBeasi
1bb01c7634 fix merge conflicts 2021-07-01 12:08:32 -04:00
Liam DeBeasi
b735b587cd fix(datetime): scroll position no longer gets reset when using datetime in overlay (#23543) 2021-07-01 09:22:59 -04:00
Liam DeBeasi
bdb95b7b6d fix(popover): update animation to better match MD spec (#23541) 2021-06-30 14:27:02 -04:00
William Martin
b93eeeaff1 docs(datetime): fix typo 2021-06-30 13:58:20 -04:00
Liam DeBeasi
e30b17c5bb fix(vue): navigating between parameterized pages now results in page transition (#23525)
resolves #22662
2021-06-30 10:11:06 -04:00
William Martin
6ca17805b8 fix(content): add touch-action manipulation for a11y zoom and pan (#23534)
resolves #22805
2021-06-29 15:25:15 -04:00
Devin Shoemaker
9e24a0b493 feat(action-sheet, alert): add id to AlertButton and ActionSheetButton (#18992)
resolves #22959

Co-authored-by: Liam DeBeasi <liamdebeasi@icloud.com>
2021-06-29 14:17:19 -04:00
Liam DeBeasi
bdc1f2360d fix(popover): size property now works when providing only event (#23532)
resolves #23528
2021-06-29 13:21:39 -04:00
Liam DeBeasi
6fbd60b0df fix(accordion): improved reliability of accordion animations (#23531)
resolves #23504
2021-06-29 09:28:21 -04:00
Liam DeBeasi
9a60dd0ea7 feat(accordion-group): add animated property to disable animations (#23530) 2021-06-29 08:59:41 -04:00
Liam DeBeasi
fc9e1b4b36 feat(vue): extend useIonRouter hook for programmatic navigation with animation control (#23499)
resolves #23450
2021-06-28 10:33:32 -04:00
Lars Mikkelsen
79e3a26499 docs(virtual-scroll): fix ion-img link (#23508) 2021-06-24 19:20:21 -04:00
William Martin
f3ae4319bb fix(input, select, textarea): change type of placeholder prop to string only (#23500)
resolves #22976

BREAKING CHANGE: Updated the `placeholder` property on `ion-input`, `ion-textarea`, and `ion-select` to have a type of `string | undefined`.
2021-06-24 10:23:19 -04:00
Liam DeBeasi
ceabba154c docs(virtual-scroll, slides): add correct links to migration guides (#23502) 2021-06-23 18:32:38 -04:00
Liam DeBeasi
f00b452c1f docs(accordion-group): fix link to accordion (#23498) 2021-06-23 13:35:36 -04:00
Liam DeBeasi
a664d4268d fix(react): export accordion and accordion group components (#23497) 2021-06-23 12:14:55 -04:00
Liam DeBeasi
403e6d2c96 merge release-6.0.0-beta.0
6.0.0-beta.0
2021-06-23 10:23:11 -04:00
Liam DeBeasi
dac67b3a3b 6.0.0-beta.0 2021-06-23 09:28:54 -04:00
Liam DeBeasi
36d099d55a chore(): fix typos in v6 beta doc (#23489) 2021-06-22 17:14:07 -04:00
Liam DeBeasi
75dfc02afa chore(): add v6 beta note on starting a new app (#23488) 2021-06-22 16:33:34 -04:00
Liam DeBeasi
0164b829ec chore(): sync next with master before beta 0
chore(): sync next with master before beta 0
2021-06-22 16:05:15 -04:00
Liam DeBeasi
fa6e0a1254 Merge remote-tracking branch 'origin/master' into sync-with-master-b0 2021-06-22 15:34:38 -04:00
Liam DeBeasi
4f47261c03 chore(): add v6 beta instructions (#23486) 2021-06-22 15:30:04 -04:00
Liam DeBeasi
6dfbd89cf8 refactor(vue): remove auto-generated router outlet inside of ion-tabs (#23479) 2021-06-21 18:22:57 -04:00
Liam DeBeasi
c2eda6aee3 chore(): sync with master
chore(): sync with master
2021-06-21 17:49:28 -04:00
Liam DeBeasi
09da99b176 Merge remote-tracking branch 'origin/master' into sync-master
# Conflicts:
#	packages/vue/src/components/IonTabs.ts
#	packages/vue/test-app/src/router/index.ts
2021-06-21 21:26:49 +00:00
Liam DeBeasi
29d756f1fb chore(): sync with master 2021-06-21 14:18:47 -04:00
Liam DeBeasi
5db60d9697 chore(): resolve merge conflicts 2021-06-21 14:03:47 -04:00
Liam DeBeasi
80f181d484 fix(searchbar): showClearButton now defaults to 'always' for improved usability with screen readers (#23475)
BREAKING CHANGE: The `showClearButton` property on `ion-searchbar` now defaults to `'always'`.
2021-06-21 13:12:02 -04:00
Liam DeBeasi
ee3a00fde6 fix(vue): ensure webpack does not eliminate core css (#23465) 2021-06-18 16:03:55 -04:00
Liam DeBeasi
b0cce360c8 fix(datetime): changing time emits ionChange (#23463) 2021-06-18 09:23:19 -04:00
Brandy Carney
2f6b1e4eea feat(breadcrumbs): add breadcrumbs component (#22701)
resolves #22770
2021-06-17 18:19:10 -04:00
William Martin
faefe97da6 feat(item): add helper text, error text, counter, shape, and fill mode (#23354)
resolves #19619
2021-06-17 17:21:03 -04:00
Liam DeBeasi
dc48a9f1a2 feat(vue): add custom elements bundle (#23458) 2021-06-17 14:10:50 -04:00
Liam DeBeasi
bccb8ad5fb fix(modal): border radius is correctly set on card style modal (#23461) 2021-06-17 13:36:30 -04:00
Liam DeBeasi
0a700f9f6f docs(datetime): improve example tests with sizing (#23456) 2021-06-16 16:31:49 -04:00
Liam DeBeasi
932d3ca62f feat(datetime): add calendar picker (#23416)
resolves #19423

BREAKING CHANGE: The `ion-datetime` component has been revamped to use a new calendar style. As a result, some APIs have been removed. See https://github.com/ionic-team/ionic-framework/blob/master/BREAKING.md for more details.
2021-06-16 15:54:15 -04:00
Liam DeBeasi
c842dd88c9 refactor(all): update required browser, framework, and mobile platform versions for v6 (#23443)
BREAKING CHANGE: Browser, JS Framework, and mobile platform minimum required versions have been updated.
2021-06-14 09:12:43 -04:00
Liam DeBeasi
623c84ab08 feat(slides): add IonicSwiper modules, deprecate ion-slides, and add link to migration (#23447) 2021-06-11 12:56:32 -04:00
Liam DeBeasi
e1a96130eb fix(popover): shadow parts now correctly added (#23446) 2021-06-11 08:59:51 -04:00
Liam DeBeasi
42d133dac4 refactor(virtual-scroll): deprecate virtual scroll in favor of CDK Scroller (#23444)
Deprecates `ion-virtual-scroll` in favor of CDK Scroller. See PR for migration and docs information.
2021-06-10 16:25:18 -04:00
Liam DeBeasi
0e38d42761 feat(popover): account for ionShadowTarget elements (#23436) 2021-06-08 16:04:43 -04:00
Liam DeBeasi
8dbe8ba7bc fix(modal, popover): overlays now automatically determine if they are inline (#23434) 2021-06-08 14:25:06 -04:00
Liam DeBeasi
c716617945 fix(accordion): toggle icon now shows up in vue and react (#23426) 2021-06-07 16:30:46 -04:00
Liam DeBeasi
3be1c3dcd7 feat(modal): modals can now be used inline (#23341)
resolves #20117, resolves #20263
2021-06-01 11:09:40 -04:00
Liam DeBeasi
8c6163c5b6 chore(): update e2e structure for accordion tests so screenshots run (#23370) 2021-05-26 11:54:41 -04:00
Liam DeBeasi
7d47c91641 chore(): sync next with main branch 2021-05-26 10:14:38 -04:00
Liam DeBeasi
960778a36f fix(popover): update prop defaults, use correct delegate (#23340) 2021-05-21 11:11:22 -04:00
Liam DeBeasi
a67a0fabb8 feat(popover): add desktop support (#23258)
resolves #21599
2021-05-10 17:37:52 -04:00
William Martin
a037b65aad fix(modal): add additional padding to toolbars in iOS modal (#23262)
Resolves #22778
2021-05-03 16:43:11 -04:00
Liam DeBeasi
308fa1c0dd feat(popover): popover can now be used inline (#23231)
BREAKING CHANGE: Converted `ion-popover` to use the Shadow DOM.
2021-05-03 12:02:22 -04:00
Liam DeBeasi
6fcb3a62b1 refactor(vue): drop support for "on" prefixed overlay events and bump minimum required version of vue to 3.0.6 (#23229)
refactor(vue): drop support for "on" prefixed overlay events and bump minimum required version of vue to 3.0.6

BREAKING CHANGE:

- Dropped support for prefixed overlay events in favor of non prefixed events (I.e. `@onDidDismiss` becomes `@didDismiss`).
- Minimum required version of Vue is now Vue v3.0.6 or newer.
2021-04-23 13:06:22 -04:00
Liam DeBeasi
51c62fafe5 chore(): sync with master
chore(): sync with master
2021-04-23 12:03:51 -04:00
Liam DeBeasi
aede8e686f chore(): resolve merge conflicts 2021-04-23 11:41:46 -04:00
Liam DeBeasi
d4e773623f chore(): sync with master 2021-04-05 17:44:36 -04:00
Liam DeBeasi
4fb81b7450 chore(): sync with master 2021-04-05 16:40:39 -04:00
Liam DeBeasi
073883a098 feat(accordion): add accordion and accordion-group components (#22865)
resolves #17094
2021-03-24 09:17:54 -04:00
Liam DeBeasi
2c53363901 chore(): sync next with master 2021-03-04 16:03:12 -05:00
Liam DeBeasi
4cbf610e55 chore(): sync vue tabs changes with master 2021-03-04 15:31:42 -05:00
Liam DeBeasi
96abe22175 chore(): sync next with master
chore(): sync next with master
2021-02-26 15:14:28 -05:00
Hans Krywalsky
84d86397a7 refactor(refresher): add new ios 14 pull to refresh style (#22398)
resolves #22783

Co-authored-by: Liam DeBeasi <liamdebeasi@icloud.com>
2021-02-17 16:14:03 -05:00
Liam DeBeasi
75458ac7fb refactor(vue): remove support for child routes nested inside of tabs (#22919)
BREAKING CHANGE: Support for child routes nested inside of tabs has been removed to better conform to Vue Router's best practices. Additional routes should be written as sibling routes with the parent tab as the path prefix.
2021-02-12 14:43:29 -05:00
Liam DeBeasi
9e05891736 refactor(angular): remove Config.set() method (#22918)
BREAKING CHANGE: The `Config.set()` method has been removed. See https://ionicframework.com/docs/angular/config for examples on how to set config globally, per-component, and per-platform.
2021-02-12 13:54:34 -05:00
Liam DeBeasi
72466231fd chore(): sync with master 2021-02-11 15:42:25 -05:00
Hans Krywalsky
2a5b272a32 feat(spinner): add lines-sharp, lines-sharp-small, update styles for ios 14 (#22397)
Co-authored-by: Liam DeBeasi <liamdebeasi@icloud.com>
2021-02-11 14:21:56 -05:00
Liam DeBeasi
3d615cb3c7 refactor(ios): update toolbar and tabbar default background colors (#22852)
resolves #22780

BREAKING CHANGE: The tab bar and toolbar default background colors have been updated to better reflect the latest iOS styles.
2021-02-09 15:46:45 -05:00
Liam DeBeasi
acf0422ca9 chore(): sync with master branch 2021-02-08 14:13:43 -05:00
Liam DeBeasi
c72bc5dbd7 refactor(header): removed border from last toolbar when using collapsible large title (#22891)
resolves #22777

BREAKING CHANGE: The last toolbar in the header with a collapsible large title no longer has a border.
2021-02-08 10:34:08 -05:00
Liam DeBeasi
9b786899e5 refactor(toast): whitespace variable now defaults to normal (#22866)
BREAKING CHANGE: The `--white-space` CSS Variable now defaults to `normal`.
2021-02-05 11:10:22 -05:00
Liam DeBeasi
bfbc1f5420 chore(): update next with latest from main branch 2021-02-01 15:57:57 -05:00
Liam DeBeasi
6f2cbe6e59 breaking(config): remove experimentalTransitionShadow config option (#22797) 2021-01-20 14:02:56 -05:00
697 changed files with 129776 additions and 53394 deletions

15
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1,15 @@
# Lines starting with '#' are comments.
# Each line is a file pattern followed by one or more owners.
# More details are here: https://help.github.com/articles/about-codeowners/
# The '*' pattern is global owners.
# Order is important. The last matching pattern has the most precedence.
# The folders are ordered as follows:
# In each subsection folders are ordered first by depth, then alphabetically.
# This should make it easy to add new rules without breaking existing ones.
# Global owners
* @ionic-team/framework-core

View File

@@ -12,6 +12,7 @@
- [Accessibility](#accessibility)
* [Checkbox](#checkbox)
* [Switch](#switch)
* [Accordion](#accordion)
- [Rendering Anchor or Button](#rendering-anchor-or-button)
* [Example Components](#example-components-1)
* [Component Structure](#component-structure-1)
@@ -624,6 +625,19 @@ You are currently on a switch. To select or deselect this checkbox, press Contro
There is a WebKit bug open for this: https://bugs.webkit.org/show_bug.cgi?id=196354
### Accordion
#### Example Components
- [ion-accordion](https://github.com/ionic-team/ionic/tree/master/core/src/components/accordion)
- [ion-accordion-group](https://github.com/ionic-team/ionic/tree/master/core/src/components/accordion-group)
#### NVDA
In order to use the arrow keys to navigate the accordions, users must be in "Focus Mode". Typically, NVDA automatically switches between Browse and Focus modes when inside of a form, but not every accordion needs a form.
You can either wrap your `ion-accordion-group` in a form, or manually toggle Focus Mode using NVDA's keyboard shortcut.
## Rendering Anchor or Button

BIN
.github/assets/logo.png vendored Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -13,14 +13,14 @@ runs:
cache-name: core-node-modules
with:
path: ./core/node_modules
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json')}}-v1
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json')}}-v2
- name: Cache Angular Node Modules
uses: actions/cache@v2
env:
cache-name: angular-node-modules
with:
path: ./angular/node_modules
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./angular/package-lock.json')}}-v1
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./angular/package-lock.json')}}-v2
- uses: ./.github/workflows/actions/download-archive
with:
name: ionic-core

View File

@@ -14,7 +14,7 @@ runs:
cache-name: core-node-modules
with:
path: ./core/node_modules
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v1
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v2
- name: Install Dependencies
run: npm install
working-directory: ./core

View File

@@ -13,7 +13,16 @@ runs:
cache-name: core-node-modules
with:
path: ./core/node_modules
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v1
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v2
- name: Install Dependencies
run: npm install --legacy-peer-deps
shell: bash
working-directory: ./packages/react-router
- uses: ./.github/workflows/actions/download-archive
with:
name: ionic-react
path: ./packages/react
filename: ReactBuild.zip
- uses: ./.github/workflows/actions/download-archive
with:
name: ionic-core
@@ -40,10 +49,6 @@ runs:
run: npm run build
shell: bash
working-directory: ./packages/react-router
- name: Test Spec
run: npm run test.spec
shell: bash
working-directory: ./packages/react-router
- uses: ./.github/workflows/actions/upload-archive
with:
name: ionic-react-router

View File

@@ -13,7 +13,7 @@ runs:
cache-name: core-node-modules
with:
path: ./core/node_modules
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v1
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v2
- uses: ./.github/workflows/actions/download-archive
with:
name: ionic-core

View File

@@ -13,7 +13,7 @@ runs:
cache-name: core-node-modules
with:
path: ./core/node_modules
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v1
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v2
- uses: ./.github/workflows/actions/download-archive
with:
name: ionic-core

View File

@@ -13,7 +13,7 @@ runs:
cache-name: core-node-modules
with:
path: ./core/node_modules
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v1
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v2
- uses: ./.github/workflows/actions/download-archive
with:
name: ionic-core

View File

@@ -13,7 +13,7 @@ runs:
cache-name: core-node-modules
with:
path: ./core/node_modules
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v1
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v2
- uses: ./.github/workflows/actions/download-archive
with:
name: ionic-core
@@ -30,7 +30,7 @@ runs:
path: ./packages/angular-server
filename: AngularServerBuild.zip
- name: Install Dependencies
run: npm install --legacy-peer-deps
run: npm install
shell: bash
working-directory: ./angular/test/test-app
- name: Run Tests

View File

@@ -13,7 +13,7 @@ runs:
cache-name: core-node-modules
with:
path: ./core/node_modules
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v1
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v2
- uses: ./.github/workflows/actions/download-archive
with:
name: ionic-core

View File

@@ -13,7 +13,7 @@ runs:
cache-name: core-node-modules
with:
path: ./core/node_modules
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v1
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v2
- name: Lint
run: npm run lint
shell: bash

View File

@@ -18,7 +18,7 @@ runs:
cache-name: core-node-modules
with:
path: ./core/node_modules
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v1
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v2
- uses: ./.github/workflows/actions/download-archive
with:
name: ionic-core

View File

@@ -18,7 +18,7 @@ runs:
cache-name: core-node-modules
with:
path: ./core/node_modules
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v1
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v2
- uses: ./.github/workflows/actions/download-archive
with:
name: ionic-core

View File

@@ -13,7 +13,7 @@ runs:
cache-name: core-node-modules
with:
path: ./core/node_modules
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v1
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v2
- uses: ./.github/workflows/actions/download-archive
with:
name: ionic-core

View File

@@ -13,7 +13,7 @@ runs:
cache-name: core-node-modules
with:
path: ./core/node_modules
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v1
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v2
- uses: ./.github/workflows/actions/download-archive
with:
name: ionic-core

View File

@@ -13,7 +13,7 @@ runs:
cache-name: core-node-modules
with:
path: ./core/node_modules
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v1
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v2
- uses: ./.github/workflows/actions/download-archive
with:
name: ionic-core

View File

@@ -13,7 +13,7 @@ runs:
cache-name: core-node-modules
with:
path: ./core/node_modules
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v1
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v2
- uses: ./.github/workflows/actions/download-archive
with:
name: ionic-core

View File

@@ -6,13 +6,37 @@ on:
jobs:
dev-build:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.dev-build.outputs.version }}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
- uses: actions/setup-node@v2
with:
node-version: 15.x
- name: Create Dev Build
run: npm run release.dev -- --skip-prompt
node-version: 16
- name: Install Dependencies
run: npm ci --no-package-lock && lerna bootstrap --ignore-scripts -- --legacy-peer-deps
shell: bash
- name: Prepare NPM Token
run: echo //registry.npmjs.org/:_authToken=${NPM_TOKEN} > .npmrc
shell: bash
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Create Dev Hash
run: |
echo "HASH=$(git log -1 --format=%H | cut -c 1-7)" >> $GITHUB_ENV
echo "TIMESTAMP=$(date +%s)" >> $GITHUB_ENV
echo "CURRENT_VERSION=$(node ./.scripts/bump-version.js)" >> $GITHUB_ENV
shell: bash
- name: Create Dev Build
run: |
HUSKY_SKIP_HOOKS=1 lerna publish $(echo "${{ env.CURRENT_VERSION }}")-dev.$(echo "${{ env.TIMESTAMP }}").$(echo "${{ env.HASH }}") --no-verify-access --yes --force-publish='*' --dist-tag dev --no-git-tag-version --no-push --exact
shell: bash
- id: dev-build
run: echo "::set-output name=version::$(echo "${{ env.CURRENT_VERSION }}")-dev.$(echo "${{ env.TIMESTAMP }}").$(echo "${{ env.HASH }}")"
get-build:
name: Get your dev build!
runs-on: ubuntu-latest
needs: dev-build
steps:
- run: echo ${{ needs.dev-build.outputs.version }}

48
.github/workflows/pre-release.yml vendored Normal file
View File

@@ -0,0 +1,48 @@
name: 'Ionic Pre-Release'
on:
workflow_dispatch:
inputs:
version:
required: true
type: choice
description: Which version should be published?
options:
- prepatch
- preminor
- premajor
prefix:
required: true
type: choice
description: What kind of pre-release is this?
default: beta
options:
- alpha
- beta
- rc
jobs:
build-ionic:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 16
- name: Configure Identity
run: |
git config user.name github-actions
git config user.email github-actions@github.com
shell: bash
- name: Install Dependencies
run: npm ci --no-package-lock && lerna bootstrap --ignore-scripts -- --legacy-peer-deps
shell: bash
- name: Prepare NPM Token
run: echo //registry.npmjs.org/:_authToken=${NPM_TOKEN} > .npmrc
shell: bash
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Release
run: |
HUSKY_SKIP_HOOKS=1 lerna publish $(echo "${{ github.event.inputs.version }}") --no-verify-access --yes --force-publish='*' --dist-tag next --no-git-tag-version --no-push --skip-npm --preid $(echo "${{ github.events.inputs.prefix }}")
shell: bash

51
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,51 @@
name: 'Ionic Production Release'
on:
workflow_dispatch:
inputs:
version:
required: true
type: choice
description: Which version should be published?
options:
- patch
- minor
- major
tag:
required: true
type: choice
description: Which npm tag should this be published to?
options:
- latest
- v5-lts
- v4-lts
jobs:
build-ionic:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/setup-node@v2
with:
node-version: 16
- name: Configure Identity
run: |
git config user.name github-actions
git config user.email github-actions@github.com
shell: bash
- name: Install Dependencies
run: npm ci --no-package-lock && lerna bootstrap --ignore-scripts -- --legacy-peer-deps
shell: bash
- name: Prepare NPM Token
run: echo //registry.npmjs.org/:_authToken=${NPM_TOKEN} > .npmrc
shell: bash
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Release
run: |
HUSKY_SKIP_HOOKS=1 lerna publish $(echo "${{ github.event.inputs.version }}") --no-verify-access --yes --force-publish='*' --dist-tag $(echo "${{ github.event.inputs.tag }}") --conventional-commits --create-release github
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash

2
.gitignore vendored
View File

@@ -66,3 +66,5 @@ core/loader/
core/www/
.stencil/
angular/build/
.npmrc

1
.npmrc
View File

@@ -1 +0,0 @@
package-lock=false

10
.scripts/bump-version.js Normal file
View File

@@ -0,0 +1,10 @@
const semver = require('semver');
const getDevVersion = () => {
const originalVersion = require('../lerna.json').version;
const baseVersion = semver.inc(originalVersion, 'patch');
return baseVersion;
}
console.log(getDevVersion());

View File

@@ -8,15 +8,15 @@ const fs = require('fs');
// core
{
files: [
'../core/css/core.css',
'../core/css/core.css.map',
'../core/css/normalize.css',
'../core/css/normalize.css.map',
'../core/components/index.js',
'../core/components/index.d.ts',
'../core/css/core.css',
'../core/css/core.css.map',
'../core/css/normalize.css',
'../core/css/normalize.css.map',
'../core/components/index.js',
'../core/components/index.d.ts',
'../core/components/package.json',
'../core/dist/index.js',
'../core/dist/ionic/index.esm.js',
'../core/dist/index.js',
'../core/dist/ionic/index.esm.js',
]
},
// hydrate
@@ -31,19 +31,17 @@ const fs = require('fs');
{
files: [
'../angular/dist/schematics/collection.json',
'../angular/dist/fesm5/ionic-angular.js',
'../angular/dist/fesm2015/ionic-angular.js',
'../angular/dist/ionic-angular.d.ts',
'../angular/dist/ionic-angular.metadata.json'
'../angular/dist/esm2015/ionic-angular.js',
'../angular/dist/ionic-angular.d.ts'
]
},
// angular-server
{
files: [
'../packages/angular-server/dist/fesm5/ionic-angular-server.js',
'../packages/angular-server/dist/esm2015/ionic-angular-server.js',
'../packages/angular-server/dist/fesm2015/ionic-angular-server.js',
'../packages/angular-server/dist/ionic-angular-server.d.ts',
'../packages/angular-server/dist/ionic-angular-server.metadata.json'
'../packages/angular-server/dist/ionic-angular-server.d.ts'
]
},
// react

107
BETA.md Normal file
View File

@@ -0,0 +1,107 @@
# Ionic Framework v6 Beta
Thanks for your interest in trying out the Framework v6 beta! We are looking for developers to help test our new changes and provide feedback so that we can make Framework v6 the best release yet! Follow this guide to get setup with the beta.
## Installation
We have worked to make the Framework v6 migration as easy as possible, so the upgrade process should be a breeze!
Developers can follow the guide below to begin updating their existing apps to Framework v6. If you want to try out Framework v6 in a new app, you can create a starter application using `ionic start` with the Ionic CLI and then follow the guide below. See https://ionicframework.com/docs/intro/cli for information on how to get started with a new Ionic Framework application.
> Note: Framework v6 is currently in beta, so do not push any apps running v6 to production!
### Ionic Vue
Ionic Vue developers should first begin by upgrading to the latest version of `vue` and `vue-router`. As of Framework v6, `vue@3.0.6+` is required.
```shell
npm install vue@next vue-router@4
```
Ionic Vue users have access to the new Custom Elements build of Framework v6. To make the most out of this improvement, we recommend using Webpack 5. To do this, developers should first install the latest version of the Vue CLI:
```shell
npm install -g @vue/cli@next
```
From there, they can upgrade all Vue CLI plugins which will automatically migrate them to Webpack 5:
```shell
vue upgrade --next
```
The new Vue CLI will automatically generate two different bundles based on your `browserslist` configuration: one for modern browsers and one for legacy browsers. New Ionic Vue starter apps will only generate the bundle for modern browsers, but some older starter apps may need to have their `.browserslistrc` file updated. You can ensure your app only builds for modern browsers by setting `.browserlistrc` to have the following content:
```
> 1%, last 2 versions, not dead, not ie 11
```
From there, developers can install the Framework v6 beta:
```shell
npm install @ionic/vue@next @ionic/vue-router@next
```
Next, developers should review the breaking changes and make any changes necessary in their apps: https://github.com/ionic-team/ionic-framework/blob/next/BREAKING.md
After that, you should be good to go! Check out https://beta.ionicframework.com/docs for the Framework v6 documentation.
### Ionic React
Ionic React developers should first begin by upgrading to the latest version of `react` and `react-dom`. As of Framework v6, `react@17+` is required:
```shell
npm install react@latest react-dom@latest
```
From there, developers can install the Framework v6 beta:
```shell
npm install @ionic/react@next @ionic/react-router@next
```
Next, developers should review the breaking changes and make any changes necessary in their apps: https://github.com/ionic-team/ionic-framework/blob/next/BREAKING.md
After that, you should be good to go! Be sure to review the other breaking changes: https://github.com/ionic-team/ionic-framework/blob/next/BREAKING.md
Check out https://beta.ionicframework.com/docs for the Framework v6 documentation.
### Ionic Angular
Ionic Angular developers should first begin by upgrading to the latest version of Angular. As of Framework v6, Angular 11+ is required.
Please see https://update.angular.io/ for a guide on how to update to the latest version of Angular.
From there, developers can install the Framework v6 beta:
```shell
npm install @ionic/angular@next
```
Next, developers should review the breaking changes and make any changes necessary in their apps: https://github.com/ionic-team/ionic-framework/blob/next/BREAKING.md
After that, you should be good to go! Check out https://beta.ionicframework.com/docs for the Framework v6 documentation.
### Ionic Core
Developers using `@ionic/core` directly should install the Framework v6 beta directly:
```shell
npm install @ionic/core@next
```
If you are using Ionic Framework in a Stencil app, be sure to update to the latest version of Stencil as well:
```shell
npm install @stencil/core@latest
```
Next, developers should review the breaking changes and make any changes necessary in their apps: https://github.com/ionic-team/ionic-framework/blob/next/BREAKING.md
After that, you should be good to go! Check out https://beta.ionicframework.com/docs for the Framework v6 documentation.
## Providing Feedback
Feedback should be provided on our GitHub repo by creating a new issue: https://github.com/ionic-team/ionic-framework/issues/new/choose
Please note in the issue title that you are using the Framework v6 beta!

View File

@@ -4,11 +4,402 @@ This is a comprehensive list of the breaking changes introduced in the major ver
## Versions
- [Version 6.x](#version-6x)
- [Version 5.x](#version-5x)
- [Version 4.x](#version-4x)
- [Legacy](#legacy)
## Version 6.x
- [Components](#components)
* [Datetime](#datetime)
* [Header](#header)
* [Icons](#icons)
* [Input](#input)
* [Modal](#modal)
* [Popover](#popover)
* [Radio](#radio)
* [Searchbar](#searchbar)
* [Select](#select)
* [Tab Bar](#tab-bar)
* [Textarea](#textarea)
* [Toast](#toast)
* [Toolbar](#toolbar)
- [Config](#config)
* [Transition Shadow](#transition-shadow)
- [Angular](#angular)
* [Config](#config-1)
- [Vue](#vue)
* [Config](#config-2)
* [Tabs Config](#tabs-config)
* [Tabs Router Outlet](#tabs-router-outlet)
* [Overlay Events](#overlay-events)
* [Utility Function Types](#utility-function-types)
- [React](#react)
* [Config](#config-3)
- [Browser and Platform Support](#browser-and-platform-support)
### Components
#### Datetime
The `ion-datetime` component has undergone a complete rewrite and uses a new calendar style. As a result, some of the properties no longer apply and have been removed.
- `ion-datetime` now displays the calendar inline by default, allowing for more flexibility in presentation. As a result, the `placeholder` property has been removed. Additionally, the `text` and `placeholder` Shadow Parts have been removed.
- The `--padding-bottom`, `--padding-end`, `--padding-start`, `--padding-top`, and `--placeholder-color` CSS Variables have been removed since `ion-datetime` now displays inline by default.
- The `displayFormat` and `displayTimezone` properties have been removed since `ion-datetime` now displays inline with a calendar picker. To parse the UTC string provided in the payload of the `ionChange` event, we recommend using a 3rd-party date library like [date-fns](https://date-fns.org/). Here is an example of how you can take the UTC string from `ion-datetime` and format it to whatever style you prefer:
```typescript
import { format, parseISO } from 'date-fns';
/**
* This is provided in the event
* payload from the `ionChange` event.
*/
const dateFromIonDatetime = '2021-06-04T14:23:00-04:00';
const formattedString = format(parseISO(dateFromIonDatetime), 'MMM d, yyyy');
console.log(formattedString); // Jun 4, 2021
```
- The `pickerOptions` and `pickerFormat` properties have been removed since `ion-datetime` now uses a calendar style rather than a wheel picker style.
- The `monthNames`, `monthShortNames`, `dayNames`, and `dayShortNames` properties have been removed. `ion-datetime` can now automatically format these values according to your devices locale thanks to the [Intl.DateTimeFormat API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat). If you wish to force a specific locale, you can use the new `locale` property:
```html
<ion-datetime locale="fr-FR"></ion-datetime>
```
- The `open` method has been removed. To present the datetime in an overlay, you can pass it into an `ion-modal` or `ion-popover` component and call the `present` method on the overlay instance. Alternatively, you can use the `trigger` property on `ion-modal` or `ion-popover` to present the overlay on a button click:
```html
<ion-button id="open-modal">Open Datetime Modal</ion-button>
<ion-modal trigger="open-modal">
<ion-datetime></ion-datetime>
</ion-modal>
```
#### Header
When using a collapsible large title, the last toolbar in the header with `collapse="condense"` no longer has a border. This does not affect the toolbar when the large title is collapsed.
To get the old style back, add the following CSS to your global stylesheet:
```css
ion-header.header-collapse-condense ion-toolbar:last-of-type {
--border-width: 0 0 0.55px;
}
```
#### Icons
Ionic 6 now ships with Ionicons 6. Please be sure to review the [Ionicons 6.0.0 Changelog](https://github.com/ionic-team/ionicons/releases/tag/v6.0.0) and make any necessary changes.
#### Input
The `placeholder` property now has a type of `string | undefined` rather than `null | string | undefined`.
#### Modal
Converted `ion-modal` to use [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM).
If you were targeting the internals of `ion-modal` in your CSS, you will need to target the `backdrop` or `content` [Shadow Parts](https://ionicframework.com/docs/theming/css-shadow-parts) instead, or use the provided CSS Variables.
Developers dynamically creating modals using `document.createElement('ion-modal')` will now need to call `modal.remove()` after the modal has been dismissed if they want the modal to be removed from the DOM.
#### Popover
Converted `ion-popover` to use [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM).
If you were targeting the internals of `ion-popover` in your CSS, you will need to target the `backdrop`, `arrow`, or `content` [Shadow Parts](https://ionicframework.com/docs/theming/css-shadow-parts) instead, or use the provided CSS Variables.
Developers dynamically creating popovers using `document.createElement('ion-popover')` will now need to call `popover.remove()` after the popover has been dismissed if they want the popover to be removed from the DOM.
#### Radio
The `RadioChangeEventDetail` interface has been removed. Instead, listen for the `ionChange` event on `ion-radio-group` and use the `RadioGroupChangeEventDetail` interface.
#### Searchbar
The `showClearButton` property now defaults to `'always'` for improved usability with screen readers.
To get the old behavior, set `showClearButton` to `'focus'`.
#### Select
The `placeholder` property now has a type of `string | undefined` rather than `null | string | undefined`.
#### Tab Bar
The default iOS tab bar background color has been updated to better reflect the latest iOS styles. The new default value is:
```css
var(--ion-tab-bar-background, var(--ion-color-step-50, #f7f7f7));
```
#### Textarea
The `placeholder` property now has a type of `string | undefined` rather than `null | string | undefined`.
#### Toast
The `--white-space` CSS variable now defaults to `normal` instead of `pre-wrap`.
#### Toolbar
The default iOS toolbar background color has been updated to better reflect the latest iOS styles. The new default value is:
```css
var(--ion-toolbar-background, var(--ion-color-step-50, #f7f7f7));
```
### Config
#### Transition Shadow
The `experimentalTransitionShadow` config option has been removed. The transition shadow is now enabled when running in `ios` mode.
### Angular
#### Config
The `Config.set()` method has been removed. See https://ionicframework.com/docs/angular/config for examples on how to set config globally, per-component, and per-platform.
Additionally, the `setupConfig` function is no longer exported from `@ionic/angular`. Developers should use `IonicModule.forRoot` to set the config instead. See https://ionicframework.com/docs/angular/config for more information.
### React
#### Config
All Ionic React applications must now import `setupIonicReact` from `@ionic/react` and call it. If you are setting a custom config with `setupConfig`, pass your config directly to `setupIonicReact` instead:
**Old**
```javascript
import { setupConfig } from '@ionic/react';
setupConfig({
mode: 'md'
})
```
**New**
```javascript
import { setupIonicReact } from '@ionic/react';
setupIonicReact({
mode: 'md'
})
```
Note that all Ionic React applications must call `setupIonicReact` even if they are not setting custom configuration.
Additionally, the `setupConfig` function is no longer exported from `@ionic/react`.
### Vue
#### Config
The `setupConfig` function is no longer exported from `@ionic/vue`. Developers should pass their config into the `IonicVue` plugin. See https://ionicframework.com/docs/vue/config for more information.
#### Tabs Config
Support for child routes nested inside of tabs has been removed to better conform to Vue Router's best practices. Additional routes should be written as sibling routes with the parent tab as the path prefix:
**Old**
```typescript
const routes: Array<RouteRecordRaw> = [
{
path: '/',
redirect: '/tabs/tab1'
},
{
path: '/tabs/',
component: Tabs,
children: [
{
path: '',
redirect: 'tab1'
},
{
path: 'tab1',
component: () => import('@/views/Tab1.vue'),
children: {
{
path: 'view',
component: () => import('@/views/Tab1View.vue')
}
}
},
{
path: 'tab2',
component: () => import('@/views/Tab2.vue')
},
{
path: 'tab3',
component: () => import('@/views/Tab3.vue')
}
]
}
]
```
**New**
```typescript
const routes: Array<RouteRecordRaw> = [
{
path: '/',
redirect: '/tabs/tab1'
},
{
path: '/tabs/',
component: Tabs,
children: [
{
path: '',
redirect: 'tab1'
},
{
path: 'tab1',
component: () => import('@/views/Tab1.vue')
},
{
path: 'tab1/view',
component: () => import('@/views/Tab1View.vue')
},
{
path: 'tab2',
component: () => import('@/views/Tab2.vue')
},
{
path: 'tab3',
component: () => import('@/views/Tab3.vue')
}
]
}
]
```
In the example above `tabs/tab1/view` has been rewritten has a sibling route to `tabs/tab1`. The `path` field now includes the `tab1` prefix.
#### Tabs Router Outlet
Developers must now provide an `ion-router-outlet` inside of `ion-tabs`. Previously one was generated automatically, but this made it difficult for developers to access the properties on the generated `ion-router-outlet`.
**Old**
```html
<ion-tabs>
<ion-tab-bar slot="bottom">
...
</ion-tab-bar>
</ion-tabs>
<script>
import { IonTabs, IonTabBar } from '@ionic/vue';
import { defineComponent } from 'vue';
export default defineComponent({
components: { IonTabs, IonTabBar }
});
</script>
```
**New**
```html
<ion-tabs>
<ion-router-outlet></ion-router-outlet>
<ion-tab-bar slot="bottom">
...
</ion-tab-bar>
</ion-tabs>
<script>
import { IonTabs, IonTabBar, IonRouterOutlet } from '@ionic/vue';
import { defineComponent } from 'vue';
export default defineComponent({
components: { IonTabs, IonTabBar, IonRouterOutlet }
});
</script>
```
#### Overlay Events
Overlay events `onWillPresent`, `onDidPresent`, `onWillDismiss`, and `onDidDismiss` have been removed in favor of `willPresent`, `didPresent`, `willDismiss`, and `didDismiss`.
This applies to the following components: `ion-action-sheet`, `ion-alert`, `ion-loading`, `ion-modal`, `ion-picker`, `ion-popover`, and `ion-toast`.
**Old**
```html
<ion-modal
:is-open="modalOpenRef"
@onWillPresent="onModalWillPresentHandler"
@onDidPresent="onModalDidPresentHandler"
@onWillDismiss="onModalWillDismissHandler"
@onDidDismiss="onModalDidDismissHandler"
>
...
</ion-modal>
```
**New**
```html
<ion-modal
:is-open="modalOpenRef"
@willPresent="onModalWillPresentHandler"
@didPresent="onModalDidPresentHandler"
@willDismiss="onModalWillDismissHandler"
@didDismiss="onModalDidDismissHandler"
>
...
</ion-modal>
```
#### Utility Function Types
- The `IonRouter` type for `useIonRouter` has been renamed to `UseIonRouterResult`.
- The `IonKeyboardRef` type for `useKeyboard` has been renamed to `UseKeyboardResult`.
### Browser and Platform Support
This section details the desktop browser, JavaScript framework, and mobile platform versions that are supported by Ionic Framework v6.
**Minimum Browser Versions**
| Desktop Browser | Supported Versions |
| --------------- | ----------------- |
| Chrome | 60+ |
| Safari | 13+ |
| Firefox | 63+ |
| Edge | 79+ |
**Minimum JavaScript Framework Versions**
| Framework | Supported Version |
| --------- | --------------------- |
| Angular | 12+ |
| React | 17+ |
| Vue | 3.0.6+ |
**Minimum Mobile Platform Versions**
| Platform | Supported Version |
| -------- | --------------------------------------- |
| iOS | 13+ |
| Android | 5.0+ with Chromium 60+ (See note below) |
Starting with Android 5.0, the webview was moved to a separate application that can be updated independently of Android. This means that most Android 5.0+ devices are going to be running a modern version of Chromium. However, there are a still a subset of Android devices whose manufacturer has locked the webview version and does not allow the webview to update. These webviews are typically stuck at the version that was available when the device initially shipped.
As a result, Ionic Framework only supports Android devices and emulators running Android 5.0+ with a webview of Chromium 60 or newer. For context, this is the version that Stencil can support with no polyfills: https://stenciljs.com/docs/browser-support
## Version 5.x
- [CSS](#css)

View File

@@ -1,9 +1,71 @@
## [5.9.4](https://github.com/ionic-team/ionic/compare/v5.9.3...v5.9.4) (2022-04-27)
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [6.0.3](https://github.com/ionic-team/ionic-framework/compare/v6.0.2...v6.0.3) (2022-01-19)
### Bug Fixes
* **core:** inherit aria attributes on host elements ([#25156](https://github.com/ionic-team/ionic/issues/25156)) ([#25169](https://github.com/ionic-team/ionic/issues/25169)) ([ffb056d](https://github.com/ionic-team/ionic/commit/ffb056d50e126a1b89f5133de1e7516d0c29a61a))
* **angular-server:** use correct @ionic/angular dependency version ([#24593](https://github.com/ionic-team/ionic-framework/issues/24593)) ([be022f7](https://github.com/ionic-team/ionic-framework/commit/be022f7de8df85ae842b0e111722b03448d60387)), closes [#24592](https://github.com/ionic-team/ionic-framework/issues/24592)
* **angular:** apply touch, dirty and pristine form control classes ([#24558](https://github.com/ionic-team/ionic-framework/issues/24558)) ([273ae2c](https://github.com/ionic-team/ionic-framework/commit/273ae2cc087b2a5a30fb50a1b0eaeb0a221900fc)), closes [#24483](https://github.com/ionic-team/ionic-framework/issues/24483)
* **datetime:** showing calendar grid no longer causes month to switch on ios 15 ([#24554](https://github.com/ionic-team/ionic-framework/issues/24554)) ([3d20959](https://github.com/ionic-team/ionic-framework/commit/3d2095922147ea3763e977412977edd9586fec5d)), closes [#24405](https://github.com/ionic-team/ionic-framework/issues/24405)
* **item:** error slot visible in Safari ([#24579](https://github.com/ionic-team/ionic-framework/issues/24579)) ([af01a8b](https://github.com/ionic-team/ionic-framework/commit/af01a8b3073dce784cc042923d712b9492638d32)), closes [#24575](https://github.com/ionic-team/ionic-framework/issues/24575)
* **menu:** remove main attribute that was supposed to removed in v5 ([#24565](https://github.com/ionic-team/ionic-framework/issues/24565)) ([7704ac3](https://github.com/ionic-team/ionic-framework/commit/7704ac3a3710396248590daecb945b76825a0539)), closes [#24563](https://github.com/ionic-team/ionic-framework/issues/24563)
* **modal:** life cycle events for controller modals ([#24508](https://github.com/ionic-team/ionic-framework/issues/24508)) ([9a15753](https://github.com/ionic-team/ionic-framework/commit/9a15753fd95e32155abdeb490ec57cb72385ad1a)), closes [#24460](https://github.com/ionic-team/ionic-framework/issues/24460)
* **overlays:** getTop now returns the top-most presented overlay ([#24547](https://github.com/ionic-team/ionic-framework/issues/24547)) ([f5b4382](https://github.com/ionic-team/ionic-framework/commit/f5b4382fd5728365e4badf39bc1dd0c149b45c2c)), closes [#19111](https://github.com/ionic-team/ionic-framework/issues/19111)
* **react:** add useRef wrapper to useIonOverlay state to avoid stale references ([#24553](https://github.com/ionic-team/ionic-framework/issues/24553)) ([bce849c](https://github.com/ionic-team/ionic-framework/commit/bce849c5f324522002eff7f8a5e5023150e9201c))
* **react:** prevent errors when dismissing inline popover after containing element is removed ([#24569](https://github.com/ionic-team/ionic-framework/issues/24569)) ([c8a392a](https://github.com/ionic-team/ionic-framework/commit/c8a392aef5fbf25f59a573897d970c41abac04d2))
## [6.0.2](https://github.com/ionic-team/ionic-framework/compare/v6.0.1...v6.0.2) (2022-01-11)
### Bug Fixes
* **angular:** attach change detector ref for inline overlays ([#24521](https://github.com/ionic-team/ionic-framework/issues/24521)) ([5c54593](https://github.com/ionic-team/ionic-framework/commit/5c54593dde64ae61347568405ebf74502cfff370)), closes [#24502](https://github.com/ionic-team/ionic-framework/issues/24502)
* **angular:** popover will respect side attribute value ([#24470](https://github.com/ionic-team/ionic-framework/issues/24470)) ([e6955a2](https://github.com/ionic-team/ionic-framework/commit/e6955a26b92fc536c5c73b60b5943881c7d58ee1)), closes [#24466](https://github.com/ionic-team/ionic-framework/issues/24466)
* **breadcrumb:** support routerLink on breadcrumb ([#24509](https://github.com/ionic-team/ionic-framework/issues/24509)) ([5bb1414](https://github.com/ionic-team/ionic-framework/commit/5bb1414f7fa04ea07954cb3f68883ee2f162586a)), closes [#24493](https://github.com/ionic-team/ionic-framework/issues/24493)
* **css:** inline css source in source maps ([#24514](https://github.com/ionic-team/ionic-framework/issues/24514)) ([987d46c](https://github.com/ionic-team/ionic-framework/commit/987d46cfa6e48a932330f04f2e8eb7054b11baf8)), closes [#24441](https://github.com/ionic-team/ionic-framework/issues/24441)
* **datetime:** add top padding to MD calendar month grid ([#24522](https://github.com/ionic-team/ionic-framework/issues/24522)) ([bd82b5d](https://github.com/ionic-team/ionic-framework/commit/bd82b5dc1d06ba22a5410858802d57735fdcf450)), closes [#24408](https://github.com/ionic-team/ionic-framework/issues/24408)
* **datetime:** RTL will no longer infinitely scroll ([#24475](https://github.com/ionic-team/ionic-framework/issues/24475)) ([8f00008](https://github.com/ionic-team/ionic-framework/commit/8f000089c2986f292147c7f501f23c8c7d1df457)), closes [#24472](https://github.com/ionic-team/ionic-framework/issues/24472)
* **datetime:** time picker format with hourCycle h23 ([#24476](https://github.com/ionic-team/ionic-framework/issues/24476)) ([a3724e6](https://github.com/ionic-team/ionic-framework/commit/a3724e6a5662c5bc1b724d80540530472827506e)), closes [#24474](https://github.com/ionic-team/ionic-framework/issues/24474)
* **datetime:** update active day styling when day is selected ([#24454](https://github.com/ionic-team/ionic-framework/issues/24454)) ([4304391](https://github.com/ionic-team/ionic-framework/commit/430439191dba824c11290d7f8622fea10ced6c40)), closes [#24414](https://github.com/ionic-team/ionic-framework/issues/24414) [#24451](https://github.com/ionic-team/ionic-framework/issues/24451)
* **datetime:** wheel picker shows correct column order in rtl ([#24546](https://github.com/ionic-team/ionic-framework/issues/24546)) ([c90ce31](https://github.com/ionic-team/ionic-framework/commit/c90ce311a86ccb7c06b1cde91a4659f6682df04d)), closes [#24378](https://github.com/ionic-team/ionic-framework/issues/24378)
* **overlays:** define custom element children ([#24439](https://github.com/ionic-team/ionic-framework/issues/24439)) ([4715b83](https://github.com/ionic-team/ionic-framework/commit/4715b83abb30ec5930710d16e5bfe8fc88a940ce)), closes [#24393](https://github.com/ionic-team/ionic-framework/issues/24393)
* **popover:** allow arrow configuration with controller approach ([#24512](https://github.com/ionic-team/ionic-framework/issues/24512)) ([b39003a](https://github.com/ionic-team/ionic-framework/commit/b39003a4c67cd7e01d09be012c9e12d99ca1730a)), closes [#24487](https://github.com/ionic-team/ionic-framework/issues/24487)
* **radio:** fix radio not showing checked state when not in a group ([#24423](https://github.com/ionic-team/ionic-framework/issues/24423)) ([94a781c](https://github.com/ionic-team/ionic-framework/commit/94a781cb6a3d92c5e6cab1a7603bfe25826a753c))
* **react,vue:** backdrop for inline modal/popover overlay ([#24453](https://github.com/ionic-team/ionic-framework/issues/24453)) ([77f8412](https://github.com/ionic-team/ionic-framework/commit/77f8412b746222793cd9d17f12f50d512ab5e886)), closes [#24449](https://github.com/ionic-team/ionic-framework/issues/24449)
* **react:** building app for production now works correctly with vite ([#24515](https://github.com/ionic-team/ionic-framework/issues/24515)) ([32fad3d](https://github.com/ionic-team/ionic-framework/commit/32fad3d02cb6b012a772de03eafe3e3a6b1300e0)), closes [#24229](https://github.com/ionic-team/ionic-framework/issues/24229)
* **react:** scrolling to bottom of modal contents ([#24510](https://github.com/ionic-team/ionic-framework/issues/24510)) ([1462cef](https://github.com/ionic-team/ionic-framework/commit/1462cef69225e20582e2f9a0b8fd655ca2066b79)), closes [#24478](https://github.com/ionic-team/ionic-framework/issues/24478)
* **refresher:** import icons to avoid errors in react and vue ([#24525](https://github.com/ionic-team/ionic-framework/issues/24525)) ([388622f](https://github.com/ionic-team/ionic-framework/commit/388622f9734b7b832bca3ede99820a7124faa618)), closes [#24480](https://github.com/ionic-team/ionic-framework/issues/24480)
* **vue:** correct route is replaced when using router.replace ([#24533](https://github.com/ionic-team/ionic-framework/issues/24533)) ([90458da](https://github.com/ionic-team/ionic-framework/commit/90458da406e2f7a6675be185409ea78595a35128)), closes [#24226](https://github.com/ionic-team/ionic-framework/issues/24226)
## [6.0.1](https://github.com/ionic-team/ionic/compare/v6.0.0...v6.0.1) (2021-12-15)
### Bug Fixes
* **datetime:** datetime now appears correctly when presented in modal ([#24385](https://github.com/ionic-team/ionic/issues/24385)) ([e7d0674](https://github.com/ionic-team/ionic/commit/e7d06743ae2e09864510940bf8a97bc312ef1cf8)), closes [#24112](https://github.com/ionic-team/ionic-framework/issues/24112)
* **item:** remove empty padding space for item bottom ([#24323](https://github.com/ionic-team/ionic/issues/24323)) ([500985c](https://github.com/ionic-team/ionic/commit/500985ce04783f502a1f5c50fbd8b4c5e93294d7)), closes [#23892](https://github.com/ionic-team/ionic/issues/23892)
* **modal:** fix timing issue when rapidly closing and opening controller modal ([#24380](https://github.com/ionic-team/ionic/issues/24380)) ([732f8e1](https://github.com/ionic-team/ionic/commit/732f8e10ce604f1a3e98518ae9c3a4afd7803e9a)), closes [#24230](https://github.com/ionic-team/ionic-framework/issues/24230)
* **overlays:** define children custom elements for picker ([#24372](https://github.com/ionic-team/ionic/issues/24372)) ([7c700b4](https://github.com/ionic-team/ionic/commit/7c700b4caa35d7eb50c877d794f9db9fad6ed88b)), closes [#24366](https://github.com/ionic-team/ionic/issues/24366)
* **vue:** improve query params handling in tabs ([#24355](https://github.com/ionic-team/ionic/issues/24355)) ([6309d5d](https://github.com/ionic-team/ionic/commit/6309d5ddbaa7da5e37eda4e19866baf380069578)), closes [#24353](https://github.com/ionic-team/ionic/issues/24353)
* **vue:** strongly typed controller methods ([#24388](https://github.com/ionic-team/ionic/issues/24388)) ([a5d56b3](https://github.com/ionic-team/ionic/commit/a5d56b3d5a0a64fd4c62f4beab69a3a1681c0b70)), closes [#24387](https://github.com/ionic-team/ionic/issues/24387)
* **vue:** tabs no longer get unmounted when navigating back to a tabs context ([#24337](https://github.com/ionic-team/ionic/issues/24337)) ([bf8e436](https://github.com/ionic-team/ionic/commit/bf8e436ee3f7441ebbc7eaf53ec8d04545dab476)), closes [#24332](https://github.com/ionic-team/ionic/issues/24332)
### Performance Improvements
* **content:** remove global click listener to improve interaction performance ([#24360](https://github.com/ionic-team/ionic/issues/24360)) ([1bfac52](https://github.com/ionic-team/ionic/commit/1bfac52331d3f296e5721b2a6c3fd94a97450a1d)), closes [#24359](https://github.com/ionic-team/ionic/issues/24359)
@@ -22,6 +84,34 @@
# [6.0.0 Titanium](https://github.com/ionic-team/ionic/compare/v6.0.0-rc.4...v6.0.0) (2021-12-08)
Enjoy! 🚀
> We recommend updating to version `5.9.2` before updating to version `6.0.0` in order to see deprecation warnings related to your app [in the developer console](https://javascript.info/devtools).
Please see the [Ionic 6 Upgrade Guide](https://ionicframework.com/docs/next/intro/upgrading-to-ionic-6) for a step-by-step list of what you need to do to get started with Ionic 6.
# [6.0.0-rc.4](https://github.com/ionic-team/ionic/compare/v6.0.0-rc.3...v6.0.0-rc.4) (2021-12-07)
### Bug Fixes
* **accordion:** improve functionality with nested accordions ([#24302](https://github.com/ionic-team/ionic/issues/24302)) ([0920797](https://github.com/ionic-team/ionic/commit/0920797612a5ee3aac1c38d8bffe4fd1e80b6987))
* **content:** ensure scrollEl is always available in scroll methods ([#24255](https://github.com/ionic-team/ionic/issues/24255)) ([36a096c](https://github.com/ionic-team/ionic/commit/36a096c9b60bd6b3b086f2c966a1cd40dbc54473)), closes [#24168](https://github.com/ionic-team/ionic-framework/issues/24168)
* **datetime:** keyboard navigation now works in time picker ([#24251](https://github.com/ionic-team/ionic/issues/24251)) ([8bdcd3c](https://github.com/ionic-team/ionic/commit/8bdcd3c6c99d84a0a46b0f08dceca6b6929fd8f8)), closes [#24070](https://github.com/ionic-team/ionic-framework/issues/24070)
* **datetime:** prevent multiple items from being highlighted at once in month/year and time pickers ([#24268](https://github.com/ionic-team/ionic/issues/24268)) ([c2bef8d](https://github.com/ionic-team/ionic/commit/c2bef8df14111dc00c382a3ab36c27a08a92f0b7)), closes [#24067](https://github.com/ionic-team/ionic-framework/issues/24067)
* **datetime:** update active calendar display when value changes ([#24244](https://github.com/ionic-team/ionic/issues/24244)) ([ec3bc52](https://github.com/ionic-team/ionic/commit/ec3bc52ff194f1e4db4ce49548c1418c259b8795)), closes [#24241](https://github.com/ionic-team/ionic-framework/issues/24241)
* **item:** counter property now defaults to false to make upgrade easier ([#24263](https://github.com/ionic-team/ionic/issues/24263)) ([f61f356](https://github.com/ionic-team/ionic/commit/f61f35600072c5df069a24c3b24eb8f283d586f8))
* **react, vue:** remove side effects to improve treeshaking ([#24313](https://github.com/ionic-team/ionic/issues/24313)) ([13d4418](https://github.com/ionic-team/ionic/commit/13d4418588b98d301b05ebd94e0eac670163a553)), closes [#24280](https://github.com/ionic-team/ionic-framework/issues/24280)
### Features
* **react:** add setupIonicReact function ([#24254](https://github.com/ionic-team/ionic/issues/24254)) ([55db38d](https://github.com/ionic-team/ionic/commit/55db38ddc541c2632c7d3e4e4c9400ff5b5dfe8c)), closes [#24139](https://github.com/ionic-team/ionic/issues/24139)
## [5.9.2](https://github.com/ionic-team/ionic/compare/v5.9.1...v5.9.2) (2021-12-07)
@@ -39,6 +129,285 @@
# [6.0.0-rc.3](https://github.com/ionic-team/ionic/compare/v6.0.0-rc.2...v6.0.0-rc.3) (2021-11-17)
### Bug Fixes
* **all:** Ionic components that use child Ionic components are now correctly defined ([#24191](https://github.com/ionic-team/ionic/issues/24191)) ([5a2a335](https://github.com/ionic-team/ionic/commit/5a2a335784aab581cda90448193e48f687df6b15)), closes [#23571](https://github.com/ionic-team/ionic/issues/23571) [#24116](https://github.com/ionic-team/ionic/issues/24116) [#24129](https://github.com/ionic-team/ionic/issues/24129)
* **angular:** prevent duplicate event emissions ([#24200](https://github.com/ionic-team/ionic/issues/24200)) ([fc1eae9](https://github.com/ionic-team/ionic/commit/fc1eae982d7493f5b69fb18829f9c796f05a0d47))
* **icon:** update to ionicons 6 to resolve typescript 4.4 errors ([#24185](https://github.com/ionic-team/ionic/issues/24185)) ([118c606](https://github.com/ionic-team/ionic/commit/118c606703f792f830d92f1148882b5daa3f180f))
* **input:** date type in ion-input now aligns correctly on iOS 15 ([#24213](https://github.com/ionic-team/ionic/issues/24213)) ([9cf7c89](https://github.com/ionic-team/ionic/commit/9cf7c897043854a9d0db81d18ad6c016eb964de8))
* **input:** ionInput event emits with type of InputEvent ([#24111](https://github.com/ionic-team/ionic/issues/24111)) ([52cd5d0](https://github.com/ionic-team/ionic/commit/52cd5d0ccedb8013c860198fc69f6bc0d4e6d386))
* **item:** allow click targets inside of label ([#24225](https://github.com/ionic-team/ionic/issues/24225)) ([3949a94](https://github.com/ionic-team/ionic/commit/3949a949dfe112668c69a36d64e5f01a5aef1435))
* **label:** apply error appearance when control is touched ([#24072](https://github.com/ionic-team/ionic/issues/24072)) ([009dff5](https://github.com/ionic-team/ionic/commit/009dff5584fea6398bb99aa55760d25dafd7fbcc))
* **modal, popover:** opening modal and popover now works even if overlay was added to ion-app directly ([#24174](https://github.com/ionic-team/ionic/issues/24174)) ([da339a8](https://github.com/ionic-team/ionic/commit/da339a8a743548f9bde8b5a22f1a9d6b191f6e7b)), closes [#23728](https://github.com/ionic-team/ionic/issues/23728)
* **modal:** border radius is now correctly applied to card modals ([#24204](https://github.com/ionic-team/ionic/issues/24204)) ([1f4f8eb](https://github.com/ionic-team/ionic/commit/1f4f8eb6ca2b8adb543ade83c309177ac7f2044d))
* **modal:** card modal shadow now shows up correctly on ipad ([#24203](https://github.com/ionic-team/ionic/issues/24203)) ([5d4f5af](https://github.com/ionic-team/ionic/commit/5d4f5af36083eafcf7de91b22749ff307701087f))
* **overlays:** declarative modals now work properly with the hardware back button ([#24165](https://github.com/ionic-team/ionic/issues/24165)) ([b3759ae](https://github.com/ionic-team/ionic/commit/b3759aed5bd1ec6a7c744af03d0dac9c8055c5af))
* **react:** improve component compatibility with preact ([#24132](https://github.com/ionic-team/ionic/issues/24132)) ([15fc293](https://github.com/ionic-team/ionic/commit/15fc293d75aa21426616459c2596b46e2d460f49)), closes [#23516](https://github.com/ionic-team/ionic/issues/23516)
* **textarea:** floating label layout is correct with autogrow textareas ([#24202](https://github.com/ionic-team/ionic/issues/24202)) ([713f0f5](https://github.com/ionic-team/ionic/commit/713f0f55261205d3f7e25874939cb1f998f38d4a))
# [6.0.0-rc.2](https://github.com/ionic-team/ionic/compare/v6.0.0-rc.1...v6.0.0-rc.2) (2021-11-03)
### Bug Fixes
* **datetime:** resolve month and year jumping issue on ios ([#24142](https://github.com/ionic-team/ionic/issues/24142)) ([27aef93](https://github.com/ionic-team/ionic/commit/27aef9343cada9a83adec8fe00e8bc3bafa8e049)), closes [#23910](https://github.com/ionic-team/ionic/issues/23910)
# [6.0.0-rc.1](https://github.com/ionic-team/ionic/compare/v5.8.5...v6.0.0-rc.1) (2021-10-27)
### Bug Fixes
* **accordion-group:** ionChange is now fired properly in vue ([#24063](https://github.com/ionic-team/ionic/issues/24063)) ([61b99d1](https://github.com/ionic-team/ionic/commit/61b99d13bfab5c57617cbcdc7e54e43f88885f66)), closes [#23762](https://github.com/ionic-team/ionic/issues/23762)
* **datetime:** clear button is now rendered even if showDefaultButtons is false ([#24075](https://github.com/ionic-team/ionic/issues/24075)) ([e3996cf](https://github.com/ionic-team/ionic/commit/e3996cfbd50f5e9ae54ffcbe2594124e3b9969b0))
* **datetime:** default sizing preserves shape of datetime ([#24104](https://github.com/ionic-team/ionic/issues/24104)) ([71fab0f](https://github.com/ionic-team/ionic/commit/71fab0fa124254f8cdc3b513627aa7b045993f4e))
* **infinite-scroll:** infinite scroll event now fired with custom elements build ([#24043](https://github.com/ionic-team/ionic/issues/24043)) ([8a86cfb](https://github.com/ionic-team/ionic/commit/8a86cfb7050989e914fa85ccc1ea755d73f58c90)), closes [#24034](https://github.com/ionic-team/ionic/issues/24034)
* **modal:** fix backdrop animation for sheets with off-center backdropBreakpoint ([#24061](https://github.com/ionic-team/ionic/issues/24061)) ([49db6d0](https://github.com/ionic-team/ionic/commit/49db6d02883b11b5f179300e2eaa298002a381e8))
* **react:** overlays shown with useIonModal and useIonPopover no longer render outside of main react tree ([f3e492c](https://github.com/ionic-team/ionic/commit/f3e492c897c8cda2b98050156f130654f4d7014a)), closes [#23516](https://github.com/ionic-team/ionic/issues/23516) [#23516](https://github.com/ionic-team/ionic/issues/23516)
### Features
* **angular:** build for angular 12.0 ([#23970](https://github.com/ionic-team/ionic/issues/23970)) ([3451a34](https://github.com/ionic-team/ionic/commit/3451a34ad0c893be0b6c17dc91ac9a75d2b9b52c))
# [6.0.0-rc.0](https://github.com/ionic-team/ionic/compare/v6.0.0-beta.7...v6.0.0-rc.0) (2021-10-07)
### Bug Fixes
* **angular:** setup config properly ([#24028](https://github.com/ionic-team/ionic/issues/24028)) ([907996c](https://github.com/ionic-team/ionic/commit/907996ce16446d0dc12939da325b7b5dae09ebd9))
# [6.0.0-beta.7](https://github.com/ionic-team/ionic/compare/v5.8.2...v6.0.0-beta.7) (2021-10-06)
### Bug Fixes
* **datetime:** add ionBlur/ionFocus events to whole component ([#23980](https://github.com/ionic-team/ionic/issues/23980)) ([86a77bd](https://github.com/ionic-team/ionic/commit/86a77bd379c6dca57d5feb9694d18afe6d82934d))
* **datetime:** change now emitted when picker is typed into ([#24018](https://github.com/ionic-team/ionic/issues/24018)) ([0320164](https://github.com/ionic-team/ionic/commit/03201643ba9ae34fa969c1542742d9cd95298c81))
* **datetime:** ionChange is no longer called for out of range dates ([#23940](https://github.com/ionic-team/ionic/issues/23940)) ([ea39c6e](https://github.com/ionic-team/ionic/commit/ea39c6e5b3781ceb4c87277cf4a5e0be9c75bc20)), closes [#23939](https://github.com/ionic-team/ionic/issues/23939)
* **datetime:** time picker uses new iOS 15 style ([#23996](https://github.com/ionic-team/ionic/issues/23996)) ([0ab37b5](https://github.com/ionic-team/ionic/commit/0ab37b5061728bd60fd42781645b96add130a79f)), closes [#23768](https://github.com/ionic-team/ionic/issues/23768)
* **modal:** backdropBreakpoint is now an exclusive value ([#23954](https://github.com/ionic-team/ionic/issues/23954)) ([ed455ab](https://github.com/ionic-team/ionic/commit/ed455ab4c6df73f801a3c941da21261c205c9634))
* **react:** ensure inline modal content is visible ([#23968](https://github.com/ionic-team/ionic/issues/23968)) ([285a371](https://github.com/ionic-team/ionic/commit/285a371101e714e74d6df68701cbee9dfe23605e))
* **reorder-group:** wait for content to render before getting scroll position ([#24007](https://github.com/ionic-team/ionic/issues/24007)) ([225a278](https://github.com/ionic-team/ionic/commit/225a2787407c5ce68a953ee3448647d00af26517)), closes [#23875](https://github.com/ionic-team/ionic/issues/23875)
* **select:** ensure popover options with number values are searched for correctly ([#23998](https://github.com/ionic-team/ionic/issues/23998)) ([c204083](https://github.com/ionic-team/ionic/commit/c20408369bd332b5e225a3d50ec94978f6f5ec97))
* **select:** focus selected item in popovers ([#23991](https://github.com/ionic-team/ionic/issues/23991)) ([2497a53](https://github.com/ionic-team/ionic/commit/2497a53255dc43052755bba842dfcf556d930dcd))
### Features
* **all:** add CustomEvents types to components that emit events ([#23956](https://github.com/ionic-team/ionic/issues/23956)) ([8708095](https://github.com/ionic-team/ionic/commit/87080951112a409893a4bac2def1deca06642b16)), closes [#22925](https://github.com/ionic-team/ionic/issues/22925)
* **header, footer:** add ios fading header style ([#24011](https://github.com/ionic-team/ionic/issues/24011)) ([7ce3959](https://github.com/ionic-team/ionic/commit/7ce3959b66a08e980c7dac3bb7d7df6bf0ae874e))
### BREAKING CHANGES
* **all:** The `RadioChangeEventDetail` interface has been removed in favor of `RadioGroupChangeEventDetail`.
# [6.0.0-beta.6](https://github.com/ionic-team/ionic/compare/v5.8.0...v6.0.0-beta.6) (2021-09-15)
### Bug Fixes
* **modal:** add sheet modal properties for angular ([#23899](https://github.com/ionic-team/ionic/issues/23899)) ([d1763fc](https://github.com/ionic-team/ionic/commit/d1763fc8b56c8cb5272224ae0faaebfe3e516fdb))
* **modal:** expose breakpoint props in ModalOptions interface ([#23867](https://github.com/ionic-team/ionic/issues/23867)) ([5fd80fd](https://github.com/ionic-team/ionic/commit/5fd80fd43885a5d0cd65f0eef4e0ff15e82c4fe0)), closes [#23866](https://github.com/ionic-team/ionic/issues/23866)
* **modal:** handle on sheet modal can now be turned off ([#23900](https://github.com/ionic-team/ionic/issues/23900)) ([e2d2ad6](https://github.com/ionic-team/ionic/commit/e2d2ad6f8eaf798c6f4b4a69f2b8176f0ac22d32))
* **modal:** modal displays in middle of screen on desktop ([#23911](https://github.com/ionic-team/ionic/issues/23911)) ([9d87028](https://github.com/ionic-team/ionic/commit/9d87028e81723a0f1498c8cf231319676078eda0))
* **modal:** sheet animation works correctly if breakpoints value does not include 1 ([#23927](https://github.com/ionic-team/ionic/issues/23927)) ([414f246](https://github.com/ionic-team/ionic/commit/414f24685cbc67a7fff142b7786d33ce1cd67a0c))
* **modal:** sheet modal handle is now positioned correctly ([#23901](https://github.com/ionic-team/ionic/issues/23901)) ([58a4ba2](https://github.com/ionic-team/ionic/commit/58a4ba285389e45276df49a0b4a3412daa95e92c))
* **modal:** sheet modal now accounts for safe area ([#23884](https://github.com/ionic-team/ionic/issues/23884)) ([195d817](https://github.com/ionic-team/ionic/commit/195d8179676155315f8532636b6371dd2a63e4b9)), closes [#23874](https://github.com/ionic-team/ionic/issues/23874)
### Features
* **datetime:** add ability to select only month, year, or month and year ([#23913](https://github.com/ionic-team/ionic/issues/23913)) ([4ae44b7](https://github.com/ionic-team/ionic/commit/4ae44b7a236004738d593406d7b1236600bc6d95))
* **datetime:** add clear button ([#23920](https://github.com/ionic-team/ionic/issues/23920)) ([18765e7](https://github.com/ionic-team/ionic/commit/18765e7e39b9f205f47f394d26d6ecc4b53e17ef)), closes [#17482](https://github.com/ionic-team/ionic/issues/17482)
* **menu:** add console error for incorrect usage of contentId ([#23871](https://github.com/ionic-team/ionic/issues/23871)) ([879ab8e](https://github.com/ionic-team/ionic/commit/879ab8ebdacc1468ed206701c00b60100dbab9e4)), closes [#23810](https://github.com/ionic-team/ionic/issues/23810)
* **platform:** add ability to override platform detection methods ([#23915](https://github.com/ionic-team/ionic/issues/23915)) ([45cabae](https://github.com/ionic-team/ionic/commit/45cabae04bf9236cd069793fbf2ac8f68c372cc3)), closes [#19737](https://github.com/ionic-team/ionic/issues/19737)
* **react:** add custom elements bundle ([#23896](https://github.com/ionic-team/ionic/issues/23896)) ([c50d895](https://github.com/ionic-team/ionic/commit/c50d895370a56d0809019dc59fe32ec840b72f03))
# [6.0.0-beta.5](https://github.com/ionic-team/ionic/compare/v5.7.0...v6.0.0-beta.5) (2021-09-01)
### Bug Fixes
* **angular:** overlay interfaces are now properly exported ([#23847](https://github.com/ionic-team/ionic/issues/23847)) ([c925274](https://github.com/ionic-team/ionic/commit/c925274c3bb22532a323b2a07771d7448f7de542)), closes [#23846](https://github.com/ionic-team/ionic/issues/23846)
* **datetime:** prevent vertical page scroll on interaction ([#23780](https://github.com/ionic-team/ionic/issues/23780)) ([950350a](https://github.com/ionic-team/ionic/commit/950350a948320f889589a0c9d2ec9045637215e5)), closes [#23554](https://github.com/ionic-team/ionic/issues/23554)
* **item:** form validation states are now properly shown ([#23853](https://github.com/ionic-team/ionic/issues/23853)) ([5ca2ce9](https://github.com/ionic-team/ionic/commit/5ca2ce91971408218d7bdc52509ce61a6ebb46aa)), closes [#23733](https://github.com/ionic-team/ionic/issues/23733) [#23850](https://github.com/ionic-team/ionic/issues/23850)
* **overlays:** thrown errors are no longer suppressed ([#23831](https://github.com/ionic-team/ionic/issues/23831)) ([a212eb5](https://github.com/ionic-team/ionic/commit/a212eb52599e35d3706e2d3cef751e490e3a7259)), closes [#22724](https://github.com/ionic-team/ionic/issues/22724)
### Features
* **modal:** add bottom sheet functionality ([#23828](https://github.com/ionic-team/ionic/issues/23828)) ([12216d3](https://github.com/ionic-team/ionic/commit/12216d378df091e16fd77d271b107e819278481c)), closes [#21039](https://github.com/ionic-team/ionic/issues/21039)
* **popover:** add ability to pass event to present method ([#23827](https://github.com/ionic-team/ionic/issues/23827)) ([1d2ee92](https://github.com/ionic-team/ionic/commit/1d2ee92ca01b77bcf87c7783b50d59efcf0a402a)), closes [#23813](https://github.com/ionic-team/ionic/issues/23813)
# [6.0.0-beta.4](https://github.com/ionic-team/ionic/compare/v5.6.14...v6.0.0-beta.4) (2021-08-18)
### Bug Fixes
* **datetime:** reduce time presentation min height ([#23771](https://github.com/ionic-team/ionic/issues/23771)) ([bc4e826](https://github.com/ionic-team/ionic/commit/bc4e8267aa00e7f162cd01579d8d3adbf3cd7a83)), closes [#23690](https://github.com/ionic-team/ionic/issues/23690)
* **datetime:** text color on ios mode now accounts for color contrast ([#23729](https://github.com/ionic-team/ionic/issues/23729)) ([5980db4](https://github.com/ionic-team/ionic/commit/5980db44e5a765d15e681471325e916d566eca8d)), closes [#23723](https://github.com/ionic-team/ionic/issues/23723)
* **item:** highlight now appears above helper/error text ([#23763](https://github.com/ionic-team/ionic/issues/23763)) ([2995e33](https://github.com/ionic-team/ionic/commit/2995e337c8b4612a87eb7111224ec702494fd1d7)), closes [#23510](https://github.com/ionic-team/ionic/issues/23510)
* **toast:** ToastOptions interface now contains icon prop ([#23737](https://github.com/ionic-team/ionic/issues/23737)) ([fbd32ff](https://github.com/ionic-team/ionic/commit/fbd32ffb2633b17d71a34a8760386a319f2e2bca)), closes [#23736](https://github.com/ionic-team/ionic/issues/23736)
* **vue:** custom element internal properties are no longer overridden in vue 3.1.0 ([#23738](https://github.com/ionic-team/ionic/issues/23738)) ([ea39c70](https://github.com/ionic-team/ionic/commit/ea39c70b3ec78b2ea5ef64263e8528b543378784)), closes [#23539](https://github.com/ionic-team/ionic/issues/23539)
* **vue:** modal and popover components now correctly pass properties ([#23761](https://github.com/ionic-team/ionic/issues/23761)) ([578b906](https://github.com/ionic-team/ionic/commit/578b9062dd793c8526b80a769d94aa7aad8fe368)), closes [#23698](https://github.com/ionic-team/ionic/issues/23698)
### Features
* **action-sheet:** add data property to ActionSheetButton ([#23744](https://github.com/ionic-team/ionic/issues/23744)) ([30f8508](https://github.com/ionic-team/ionic/commit/30f8508296cfc8f8b1c03d04b24abfa184624200)), closes [#23700](https://github.com/ionic-team/ionic/issues/23700)
* **datetime:** add firstDayOfWeek property ([#23692](https://github.com/ionic-team/ionic/issues/23692)) ([ea348f0](https://github.com/ionic-team/ionic/commit/ea348f005aef7b2fda581a99338139f6fefcda63)), closes [#23556](https://github.com/ionic-team/ionic/issues/23556)
* **datetime:** add hourCycle property ([#23686](https://github.com/ionic-team/ionic/issues/23686)) ([6342fde](https://github.com/ionic-team/ionic/commit/6342fde56c7687703edd212b8383536c8b9a6400)), closes [#23661](https://github.com/ionic-team/ionic/issues/23661)
# [6.0.0-beta.3](https://github.com/ionic-team/ionic/compare/v5.6.13...v6.0.0-beta.3) (2021-08-04)
### Bug Fixes
* **list:** change inset border radius to match iOS 15 ([#23711](https://github.com/ionic-team/ionic/issues/23711)) ([fe2810b](https://github.com/ionic-team/ionic/commit/fe2810b227abc482e663b210cd89f29b76119ff5))
* **popover:** fix keyboard arrow navigation ([#23709](https://github.com/ionic-team/ionic/issues/23709)) ([f2e7a26](https://github.com/ionic-team/ionic/commit/f2e7a267973a06b50a0f6dcbba0a204930bccf69)), closes [#23512](https://github.com/ionic-team/ionic/issues/23512)
* **vue:** popover positioning is now correct with custom elements build ([#23680](https://github.com/ionic-team/ionic/issues/23680)) ([3a1a9cb](https://github.com/ionic-team/ionic/commit/3a1a9cbce45ad128c9ba87940535dabfa167fb9e))
### Features
* **toast:** add icon property to show icon at start of toast content ([#23596](https://github.com/ionic-team/ionic/issues/23596)) ([df24c8c](https://github.com/ionic-team/ionic/commit/df24c8c5ae0b493841c07c05e0d620fa4a90c05a)), closes [#23524](https://github.com/ionic-team/ionic/issues/23524)
# [6.0.0-beta.2](https://github.com/ionic-team/ionic/compare/v5.6.12...v6.0.0-beta.2) (2021-07-21)
### Bug Fixes
* **accordion:** value can now be set as string when using multiple is true ([#23581](https://github.com/ionic-team/ionic/issues/23581)) ([8f172de](https://github.com/ionic-team/ionic/commit/8f172de355bc7c910d600ce4d8446b04a6212545)), closes [#23550](https://github.com/ionic-team/ionic/issues/23550)
* **angular:** modal and popover now have correct props defined on angular component ([#23565](https://github.com/ionic-team/ionic/issues/23565)) ([e5a7b34](https://github.com/ionic-team/ionic/commit/e5a7b342623b159d41cc83e0a418fb3984ceb3a7))
* **datetime:** add keyboard year navigation ([#23585](https://github.com/ionic-team/ionic/issues/23585)) ([55bd1f7](https://github.com/ionic-team/ionic/commit/55bd1f749bac01cc691e16283728c42e755cc706)), closes [#21553](https://github.com/ionic-team/ionic/issues/21553) [#18122](https://github.com/ionic-team/ionic/issues/18122)
* **datetime:** selecting time now works correctly on firefox ([#23583](https://github.com/ionic-team/ionic/issues/23583)) ([4188964](https://github.com/ionic-team/ionic/commit/4188964dc8da2c46494245b81864ca6e305611f5)), closes [#23545](https://github.com/ionic-team/ionic/issues/23545)
* **datetime:** years displayed now more consistent with v5 datetime, max and min are now accounted for in MD mode ([#23616](https://github.com/ionic-team/ionic/issues/23616)) ([be219a2](https://github.com/ionic-team/ionic/commit/be219a2814800927e6328ff105616713003340b7)), closes [#23615](https://github.com/ionic-team/ionic/issues/23615)
### Features
* **breadcrumbs:** ionCollapsedClick event payload now contains references to collapsed breadcrumb elements ([#23611](https://github.com/ionic-team/ionic/issues/23611)) ([9ce57d2](https://github.com/ionic-team/ionic/commit/9ce57d2efb84130895a37e22e0fd7e5d713a9fa5)), closes [#23552](https://github.com/ionic-team/ionic/issues/23552)
* **datetime:** add showDefaultTimeLabel property and time-label slot ([#23577](https://github.com/ionic-team/ionic/issues/23577)) ([7ac0109](https://github.com/ionic-team/ionic/commit/7ac010943b2c9ad42a1833153ea16ccffd169b91)), closes [#23555](https://github.com/ionic-team/ionic/issues/23555)
* **datetime:** add size property ([#23649](https://github.com/ionic-team/ionic/issues/23649)) ([321341d](https://github.com/ionic-team/ionic/commit/321341d97dff98b76b69a1efce58923a80e92bc4)), closes [#23518](https://github.com/ionic-team/ionic/issues/23518)
* **range:** add support for customizing pin format ([#22972](https://github.com/ionic-team/ionic/issues/22972)) ([8f2c4f7](https://github.com/ionic-team/ionic/commit/8f2c4f73db167503cdf60222f42bcaadf905b401))
* **segment:** add keyboard navigation, add selectOnFocus property to control selection follow focus behavior ([#23590](https://github.com/ionic-team/ionic/issues/23590)) ([b6c53e5](https://github.com/ionic-team/ionic/commit/b6c53e539b0855fa95b0fe02e5fa74ce403b68b8)), closes [#23520](https://github.com/ionic-team/ionic/issues/23520)
* **select:** update popover interface to match MD spec on desktop, allow multiple values in popover interface ([#23474](https://github.com/ionic-team/ionic/issues/23474)) ([2c07a15](https://github.com/ionic-team/ionic/commit/2c07a1566b6f8570f7e12a55ca8f86d8fb8a968e)), closes [#23657](https://github.com/ionic-team/ionic/issues/23657) [#15500](https://github.com/ionic-team/ionic/issues/15500) [#12310](https://github.com/ionic-team/ionic/issues/12310)
### Performance Improvements
* remove shims for legacy browsers no longer supported in v6 ([#23592](https://github.com/ionic-team/ionic/issues/23592)) ([259b135](https://github.com/ionic-team/ionic/commit/259b1359dbd20d4f85036ae46901a051cd8fc98b))
# [6.0.0-beta.1](https://github.com/ionic-team/ionic/compare/v5.6.11...v6.0.0-beta.1) (2021-07-01)
### Bug Fixes
* **accordion:** improved reliability of accordion animations ([#23531](https://github.com/ionic-team/ionic/issues/23531)) ([6fbd60b](https://github.com/ionic-team/ionic/commit/6fbd60b0df56dc927226474a1ffa322d979c563e)), closes [#23504](https://github.com/ionic-team/ionic/issues/23504)
* **content:** add touch-action manipulation for a11y zoom and pan ([#23534](https://github.com/ionic-team/ionic/issues/23534)) ([6ca1780](https://github.com/ionic-team/ionic/commit/6ca17805b8b1ea38d7fc16d091324da16a4193c6)), closes [#22805](https://github.com/ionic-team/ionic/issues/22805)
* **datetime:** scroll position no longer gets reset when using datetime in overlay ([#23543](https://github.com/ionic-team/ionic/issues/23543)) ([b735b58](https://github.com/ionic-team/ionic/commit/b735b587cda777ac481bb580c883d9734145f31e))
* **input, select, textarea:** change type of placeholder prop to string only ([#23500](https://github.com/ionic-team/ionic/issues/23500)) ([f3ae431](https://github.com/ionic-team/ionic/commit/f3ae4319bb64debab304973856a33e422ac910a1)), closes [#22976](https://github.com/ionic-team/ionic/issues/22976)
* **popover:** size property now works when providing only event ([#23532](https://github.com/ionic-team/ionic/issues/23532)) ([bdc1f23](https://github.com/ionic-team/ionic/commit/bdc1f2360d7795472cc242a86eb4376d05fa0bb7)), closes [#23528](https://github.com/ionic-team/ionic/issues/23528)
* **popover:** update animation to better match MD spec ([#23541](https://github.com/ionic-team/ionic/issues/23541)) ([bdb95b7](https://github.com/ionic-team/ionic/commit/bdb95b7b6dd798cbc6d1786ae54fa95ac1dfd096))
* **react:** export accordion and accordion group components ([#23497](https://github.com/ionic-team/ionic/issues/23497)) ([a664d42](https://github.com/ionic-team/ionic/commit/a664d4268dea8e84ab9e3b150043ac8f87fb53c7))
* **vue:** navigating between parameterized pages now results in page transition ([#23525](https://github.com/ionic-team/ionic/issues/23525)) ([e30b17c](https://github.com/ionic-team/ionic/commit/e30b17c5bbd1af6936a8d7a98d1f7a115073e029)), closes [#22662](https://github.com/ionic-team/ionic/issues/22662)
### Features
* **accordion-group:** add animated property to disable animations ([#23530](https://github.com/ionic-team/ionic/issues/23530)) ([9a60dd0](https://github.com/ionic-team/ionic/commit/9a60dd0ea7c55acf0fdd1161433e5b4ed40778f2))
* **action-sheet, alert:** add id to AlertButton and ActionSheetButton ([#18992](https://github.com/ionic-team/ionic/issues/18992)) ([9e24a0b](https://github.com/ionic-team/ionic/commit/9e24a0b49357a3a39ca89f026ff23271a365d935)), closes [#22959](https://github.com/ionic-team/ionic/issues/22959)
* **vue:** extend useIonRouter hook for programmatic navigation with animation control ([#23499](https://github.com/ionic-team/ionic/issues/23499)) ([fc9e1b4](https://github.com/ionic-team/ionic/commit/fc9e1b4b361938e5644683c395a565be2de1eab9)), closes [#23450](https://github.com/ionic-team/ionic/issues/23450)
### BREAKING CHANGES
* **input, select, textarea:** Updated the `placeholder` property on `ion-input`, `ion-textarea`, and `ion-select` to have a type of `string | undefined`.
# [6.0.0-beta.0](https://github.com/ionic-team/ionic/compare/v5.6.10...v6.0.0-beta.0) (2021-06-23)
### Bug Fixes
* **accordion:** toggle icon now shows up in vue and react ([#23426](https://github.com/ionic-team/ionic/issues/23426)) ([c716617](https://github.com/ionic-team/ionic/commit/c7166179457a8e2c7e1702c5761bc6368dbd156f))
* **datetime:** changing time emits ionChange ([#23463](https://github.com/ionic-team/ionic/issues/23463)) ([b0cce36](https://github.com/ionic-team/ionic/commit/b0cce360c83ac564e053523cc31b32d1deaeda0c))
* **modal, popover:** overlays now automatically determine if they are inline ([#23434](https://github.com/ionic-team/ionic/issues/23434)) ([8dbe8ba](https://github.com/ionic-team/ionic/commit/8dbe8ba7bc26792c5024f81cf4752f5b78317492))
* **modal:** add additional padding to toolbars in iOS modal ([#23262](https://github.com/ionic-team/ionic/issues/23262)) ([a037b65](https://github.com/ionic-team/ionic/commit/a037b65aad5cfc0477322a8f36105b9009366ec2)), closes [#22778](https://github.com/ionic-team/ionic/issues/22778)
* **modal:** border radius is correctly set on card style modal ([#23461](https://github.com/ionic-team/ionic/issues/23461)) ([bccb8ad](https://github.com/ionic-team/ionic/commit/bccb8ad5fb5ec7f98a6cbfa62a403ecaca7fbdb6))
* **popover:** shadow parts now correctly added ([#23446](https://github.com/ionic-team/ionic/issues/23446)) ([e1a9613](https://github.com/ionic-team/ionic/commit/e1a96130ebab1e481e880f0f3876f421976f08d5))
* **popover:** update prop defaults, use correct delegate ([#23340](https://github.com/ionic-team/ionic/issues/23340)) ([960778a](https://github.com/ionic-team/ionic/commit/960778a36f6eb6318cc740c4f7a255107723b8fd))
* **searchbar:** showClearButton now defaults to 'always' for improved usability with screen readers ([#23475](https://github.com/ionic-team/ionic/issues/23475)) ([80f181d](https://github.com/ionic-team/ionic/commit/80f181d4846507ee6bd4150bb568fca9b6660428))
* **vue:** ensure webpack does not eliminate core css ([#23465](https://github.com/ionic-team/ionic/issues/23465)) ([ee3a00f](https://github.com/ionic-team/ionic/commit/ee3a00fde61b4d1d3168d34b3d23bb97dd154154))
### Code Refactoring
* **all:** update required browser, framework, and mobile platform versions for v6 ([#23443](https://github.com/ionic-team/ionic/issues/23443)) ([c842dd8](https://github.com/ionic-team/ionic/commit/c842dd88c98888b2afab08ac5e8bc57c2a4c2fbd))
* **angular:** remove Config.set() method ([#22918](https://github.com/ionic-team/ionic/issues/22918)) ([9e05891](https://github.com/ionic-team/ionic/commit/9e0589173607b3c0eff7794079123354c2eeaa1a))
* **header:** removed border from last toolbar when using collapsible large title ([#22891](https://github.com/ionic-team/ionic/issues/22891)) ([c72bc5d](https://github.com/ionic-team/ionic/commit/c72bc5dbd76cd3ce622a4b3cedcb7446a2819384)), closes [#22777](https://github.com/ionic-team/ionic/issues/22777)
* **ios:** update toolbar and tabbar default background colors ([#22852](https://github.com/ionic-team/ionic/issues/22852)) ([3d615cb](https://github.com/ionic-team/ionic/commit/3d615cb3c7b233b08b9da6ac04096e16bbb60bfc)), closes [#22780](https://github.com/ionic-team/ionic/issues/22780)
* **toast:** whitespace variable now defaults to normal ([#22866](https://github.com/ionic-team/ionic/issues/22866)) ([9b78689](https://github.com/ionic-team/ionic/commit/9b786899e550c391b9395c669f9bba8f39ac98aa))
* **vue:** drop support for "on" prefixed overlay events and bump minimum required version of vue to 3.0.6 ([#23229](https://github.com/ionic-team/ionic/issues/23229)) ([6fcb3a6](https://github.com/ionic-team/ionic/commit/6fcb3a62b1b12c5ded11179e83854592d4309bdf))
* **vue:** remove support for child routes nested inside of tabs ([#22919](https://github.com/ionic-team/ionic/issues/22919)) ([75458ac](https://github.com/ionic-team/ionic/commit/75458ac7fb95f56a6ec460f85cf7d7720ce0c070))
### Features
* **accordion:** add accordion and accordion-group components ([#22865](https://github.com/ionic-team/ionic/issues/22865)) ([073883a](https://github.com/ionic-team/ionic/commit/073883a0987149e9f6258ca43c46f5ed4bce0dc5)), closes [#17094](https://github.com/ionic-team/ionic/issues/17094)
* **breadcrumbs:** add breadcrumbs component ([#22701](https://github.com/ionic-team/ionic/issues/22701)) ([2f6b1e4](https://github.com/ionic-team/ionic/commit/2f6b1e4eea307c6f14345704e5824378ef079acb)), closes [#22770](https://github.com/ionic-team/ionic/issues/22770)
* **datetime:** add calendar picker ([#23416](https://github.com/ionic-team/ionic/issues/23416)) ([932d3ca](https://github.com/ionic-team/ionic/commit/932d3ca62f3e3ef08acb065ce6ec46faa3811f96)), closes [#19423](https://github.com/ionic-team/ionic/issues/19423)
* **item:** add helper text, error text, counter, shape, and fill mode ([#23354](https://github.com/ionic-team/ionic/issues/23354)) ([faefe97](https://github.com/ionic-team/ionic/commit/faefe97da6a9d5beff1183d10efd0df9c4e3ebd7)), closes [#19619](https://github.com/ionic-team/ionic/issues/19619)
* **modal:** modals can now be used inline ([#23341](https://github.com/ionic-team/ionic/issues/23341)) ([3be1c3d](https://github.com/ionic-team/ionic/commit/3be1c3dcd73e6039a89b19b409e63877cda37f6e)), closes [#20117](https://github.com/ionic-team/ionic/issues/20117) [#20263](https://github.com/ionic-team/ionic/issues/20263)
* **popover:** account for ionShadowTarget elements ([#23436](https://github.com/ionic-team/ionic/issues/23436)) ([0e38d42](https://github.com/ionic-team/ionic/commit/0e38d4276110dcd94db5adc3b6aee3b5b0befc5c))
* **popover:** add desktop support ([#23258](https://github.com/ionic-team/ionic/issues/23258)) ([a67a0fa](https://github.com/ionic-team/ionic/commit/a67a0fabb8249685bbe93ed862839e2b2e76cd5a)), closes [#21599](https://github.com/ionic-team/ionic/issues/21599)
* **popover:** popover can now be used inline ([#23231](https://github.com/ionic-team/ionic/issues/23231)) ([308fa1c](https://github.com/ionic-team/ionic/commit/308fa1c0dd054cfc2ea54d2edc99e7a4b549f6f0))
* **slides:** add IonicSwiper modules, deprecate ion-slides, and add link to migration ([#23447](https://github.com/ionic-team/ionic/issues/23447)) ([623c84a](https://github.com/ionic-team/ionic/commit/623c84ab082668a996c654e18ffc9768f68b85dd))
* **spinner:** add lines-sharp, lines-sharp-small, update styles for ios 14 ([#22397](https://github.com/ionic-team/ionic/issues/22397)) ([2a5b272](https://github.com/ionic-team/ionic/commit/2a5b272a329bbad1ca07705f84f0fd06e3ef32ad))
* **vue:** add custom elements bundle ([#23458](https://github.com/ionic-team/ionic/issues/23458)) ([dc48a9f](https://github.com/ionic-team/ionic/commit/dc48a9f1a2dff8a2d644112bbe1df8b0b6811848))
### BREAKING CHANGES
* **searchbar:** The `showClearButton` property on `ion-searchbar` now defaults to `'always'`.
* **datetime:** The `ion-datetime` component has been revamped to use a new calendar style. As a result, some APIs have been removed. See https://github.com/ionic-team/ionic-framework/blob/master/BREAKING.md for more details.
* **all:** Browser, JS Framework, and mobile platform minimum required versions have been updated.
* **popover:** Converted `ion-popover` to use the Shadow DOM.
* **vue:** - Dropped support for prefixed overlay events in favor of non prefixed events (I.e. `@onDidDismiss` becomes `@didDismiss`).
- Minimum required version of Vue is now Vue v3.0.6 or newer.
* **vue:** Support for child routes nested inside of tabs has been removed to better conform to Vue Router's best practices. Additional routes should be written as sibling routes with the parent tab as the path prefix.
* **angular:** The `Config.set()` method has been removed. See https://ionicframework.com/docs/angular/config for examples on how to set config globally, per-component, and per-platform.
* **ios:** The tab bar and toolbar default background colors have been updated to better reflect the latest iOS styles.
* **header:** The last toolbar in the header with a collapsible large title no longer has a border.
* **toast:** The `--white-space` CSS Variable now defaults to `normal`.
## [5.9.1](https://github.com/ionic-team/ionic/compare/v5.9.0...v5.9.1) (2021-11-17)
@@ -64,6 +433,31 @@
# [6.0.0-rc.2](https://github.com/ionic-team/ionic/compare/v6.0.0-rc.1...v6.0.0-rc.2) (2021-11-03)
### Bug Fixes
* **all:** resolve compilation issues with Stencil 2.10 ([#24152](https://github.com/ionic-team/ionic/issues/24152)) ([8b940e5](https://github.com/ionic-team/ionic-framework/commit/8b940e505e79bdf5da829850ed949847d5df8b90)), closes [#24153](https://github.com/ionic-team/ionic-framework/issues/24153)
* **datetime:** resolve month and year jumping issue on ios ([#24142](https://github.com/ionic-team/ionic/issues/24142)) ([27aef93](https://github.com/ionic-team/ionic/commit/27aef9343cada9a83adec8fe00e8bc3bafa8e049)), closes [#23910](https://github.com/ionic-team/ionic/issues/23910)
# [6.0.0-rc.1](https://github.com/ionic-team/ionic/compare/v6.0.0-rc.0...v6.0.0-rc.1) (2021-10-27)
### Bug Fixes
* **accordion-group:** ionChange is now fired properly in vue ([#24063](https://github.com/ionic-team/ionic/issues/24063)) ([61b99d1](https://github.com/ionic-team/ionic/commit/61b99d13bfab5c57617cbcdc7e54e43f88885f66)), closes [#23762](https://github.com/ionic-team/ionic/issues/23762)
* **angular:** resolve issues with ng add on angular 12 ([#23970](https://github.com/ionic-team/ionic/issues/23970)) ([3451a34](https://github.com/ionic-team/ionic/commit/3451a34ad0c893be0b6c17dc91ac9a75d2b9b52c))
* **datetime:** clear button is now rendered even if showDefaultButtons is false ([#24075](https://github.com/ionic-team/ionic/issues/24075)) ([e3996cf](https://github.com/ionic-team/ionic/commit/e3996cfbd50f5e9ae54ffcbe2594124e3b9969b0))
* **datetime:** default sizing preserves shape of datetime ([#24104](https://github.com/ionic-team/ionic/issues/24104)) ([71fab0f](https://github.com/ionic-team/ionic/commit/71fab0fa124254f8cdc3b513627aa7b045993f4e))
* **infinite-scroll:** infinite scroll event now fired with custom elements build ([#24043](https://github.com/ionic-team/ionic/issues/24043)) ([8a86cfb](https://github.com/ionic-team/ionic/commit/8a86cfb7050989e914fa85ccc1ea755d73f58c90)), closes [#24034](https://github.com/ionic-team/ionic/issues/24034)
* **modal:** fix backdrop animation for sheets with off-center backdropBreakpoint ([#24061](https://github.com/ionic-team/ionic/issues/24061)) ([49db6d0](https://github.com/ionic-team/ionic/commit/49db6d02883b11b5f179300e2eaa298002a381e8))
* **react:** overlays shown with useIonModal and useIonPopover no longer render outside of main react tree ([f3e492c](https://github.com/ionic-team/ionic/commit/f3e492c897c8cda2b98050156f130654f4d7014a)), closes [#23516](https://github.com/ionic-team/ionic/issues/23516) [#23516](https://github.com/ionic-team/ionic/issues/23516)
## [5.8.5](https://github.com/ionic-team/ionic/compare/v5.8.4...v5.8.5) (2021-10-27)
@@ -85,6 +479,15 @@
# [6.0.0-rc.0](https://github.com/ionic-team/ionic/compare/v6.0.0-beta.7...v6.0.0-rc.0) (2021-10-07)
### Bug Fixes
* **angular:** setup config properly ([#24028](https://github.com/ionic-team/ionic/issues/24028)) ([907996c](https://github.com/ionic-team/ionic/commit/907996ce16446d0dc12939da325b7b5dae09ebd9))
## [5.8.3](https://github.com/ionic-team/ionic/compare/v5.8.2...v5.8.3) (2021-10-07)
@@ -94,6 +497,33 @@
# [6.0.0-beta.7](https://github.com/ionic-team/ionic/compare/v6.0.0-beta.6...v6.0.0-beta.7) (2021-10-06)
### Bug Fixes
* **datetime:** ionBlur and ionFocus now fires correctly ([#23980](https://github.com/ionic-team/ionic/issues/23980)) ([86a77bd](https://github.com/ionic-team/ionic/commit/86a77bd379c6dca57d5feb9694d18afe6d82934d))
* **datetime:** ionChange is no longer called for out of range dates ([#23940](https://github.com/ionic-team/ionic/issues/23940)) ([ea39c6e](https://github.com/ionic-team/ionic/commit/ea39c6e5b3781ceb4c87277cf4a5e0be9c75bc20)), closes [#23939](https://github.com/ionic-team/ionic/issues/23939)
* **datetime:** time picker uses new iOS 15 style ([#23996](https://github.com/ionic-team/ionic/issues/23996)) ([0ab37b5](https://github.com/ionic-team/ionic/commit/0ab37b5061728bd60fd42781645b96add130a79f)), closes [#23768](https://github.com/ionic-team/ionic/issues/23768)
* **modal:** backdropBreakpoint is now an exclusive value ([#23954](https://github.com/ionic-team/ionic/issues/23954)) ([ed455ab](https://github.com/ionic-team/ionic/commit/ed455ab4c6df73f801a3c941da21261c205c9634))
* **react:** ensure inline modal content is visible ([#23968](https://github.com/ionic-team/ionic/issues/23968)) ([285a371](https://github.com/ionic-team/ionic/commit/285a371101e714e74d6df68701cbee9dfe23605e))
* **reorder-group:** wait for content to render before getting scroll position ([#24007](https://github.com/ionic-team/ionic/issues/24007)) ([225a278](https://github.com/ionic-team/ionic/commit/225a2787407c5ce68a953ee3448647d00af26517)), closes [#23875](https://github.com/ionic-team/ionic/issues/23875)
* **select:** ensure popover options with number values are searched for correctly ([#23998](https://github.com/ionic-team/ionic/issues/23998)) ([c204083](https://github.com/ionic-team/ionic/commit/c20408369bd332b5e225a3d50ec94978f6f5ec97))
* **select:** focus selected item in popovers ([#23991](https://github.com/ionic-team/ionic/issues/23991)) ([2497a53](https://github.com/ionic-team/ionic/commit/2497a53255dc43052755bba842dfcf556d930dcd))
### Features
* **all:** add CustomEvents types to components that emit events ([#23956](https://github.com/ionic-team/ionic/issues/23956)) ([8708095](https://github.com/ionic-team/ionic/commit/87080951112a409893a4bac2def1deca06642b16)), closes [#22925](https://github.com/ionic-team/ionic/issues/22925)
* **header, footer:** add ios fading header style ([#24011](https://github.com/ionic-team/ionic/issues/24011)) ([7ce3959](https://github.com/ionic-team/ionic/commit/7ce3959b66a08e980c7dac3bb7d7df6bf0ae874e))
### BREAKING CHANGES
* **radio:** The `RadioChangeEventDetail` interface has been removed in favor of `RadioGroupChangeEventDetail`.
## [5.8.2](https://github.com/ionic-team/ionic/compare/v5.8.1...v5.8.2) (2021-10-06)
@@ -119,6 +549,30 @@
# [6.0.0-beta.6](https://github.com/ionic-team/ionic/compare/v6.0.0-beta.5...v6.0.0-beta.6) (2021-09-15)
### Bug Fixes
* **menu:** add console error for incorrect usage of contentId ([#23871](https://github.com/ionic-team/ionic/issues/23871)) ([879ab8e](https://github.com/ionic-team/ionic/commit/879ab8ebdacc1468ed206701c00b60100dbab9e4)), closes [#23810](https://github.com/ionic-team/ionic/issues/23810)
* **modal:** add sheet modal properties for angular ([#23899](https://github.com/ionic-team/ionic/issues/23899)) ([d1763fc](https://github.com/ionic-team/ionic/commit/d1763fc8b56c8cb5272224ae0faaebfe3e516fdb))
* **modal:** expose breakpoint props in ModalOptions interface ([#23867](https://github.com/ionic-team/ionic/issues/23867)) ([5fd80fd](https://github.com/ionic-team/ionic/commit/5fd80fd43885a5d0cd65f0eef4e0ff15e82c4fe0)), closes [#23866](https://github.com/ionic-team/ionic/issues/23866)
* **modal:** handle on sheet modal can now be turned off ([#23900](https://github.com/ionic-team/ionic/issues/23900)) ([e2d2ad6](https://github.com/ionic-team/ionic/commit/e2d2ad6f8eaf798c6f4b4a69f2b8176f0ac22d32))
* **modal:** modal displays in middle of screen on desktop ([#23911](https://github.com/ionic-team/ionic/issues/23911)) ([9d87028](https://github.com/ionic-team/ionic/commit/9d87028e81723a0f1498c8cf231319676078eda0))
* **modal:** sheet animation works correctly if breakpoints value does not include 1 ([#23927](https://github.com/ionic-team/ionic/issues/23927)) ([414f246](https://github.com/ionic-team/ionic/commit/414f24685cbc67a7fff142b7786d33ce1cd67a0c))
* **modal:** sheet modal handle is now positioned correctly ([#23901](https://github.com/ionic-team/ionic/issues/23901)) ([58a4ba2](https://github.com/ionic-team/ionic/commit/58a4ba285389e45276df49a0b4a3412daa95e92c))
* **modal:** sheet modal now accounts for safe area ([#23884](https://github.com/ionic-team/ionic/issues/23884)) ([195d817](https://github.com/ionic-team/ionic/commit/195d8179676155315f8532636b6371dd2a63e4b9)), closes [#23874](https://github.com/ionic-team/ionic/issues/23874)
### Features
* **datetime:** add ability to select only month, year, or month and year ([#23913](https://github.com/ionic-team/ionic/issues/23913)) ([4ae44b7](https://github.com/ionic-team/ionic/commit/4ae44b7a236004738d593406d7b1236600bc6d95))
* **datetime:** add clear button ([#23920](https://github.com/ionic-team/ionic/issues/23920)) ([18765e7](https://github.com/ionic-team/ionic/commit/18765e7e39b9f205f47f394d26d6ecc4b53e17ef)), closes [#17482](https://github.com/ionic-team/ionic/issues/17482)
* **platform:** add ability to override platform detection methods ([#23915](https://github.com/ionic-team/ionic/issues/23915)) ([45cabae](https://github.com/ionic-team/ionic/commit/45cabae04bf9236cd069793fbf2ac8f68c372cc3)), closes [#19737](https://github.com/ionic-team/ionic/issues/19737)
* **react:** add custom elements bundle ([#23896](https://github.com/ionic-team/ionic/issues/23896)) ([c50d895](https://github.com/ionic-team/ionic/commit/c50d895370a56d0809019dc59fe32ec840b72f03))
# [5.8.0 Calcium](https://github.com/ionic-team/ionic/compare/v5.7.0...v5.8.0) (2021-09-15)
@@ -137,6 +591,24 @@
# [6.0.0-beta.5](https://github.com/ionic-team/ionic/compare/v6.0.0-beta.4...v6.0.0-beta.5) (2021-09-01)
### Bug Fixes
* **angular:** overlay interfaces are now properly exported ([#23847](https://github.com/ionic-team/ionic/issues/23847)) ([c925274](https://github.com/ionic-team/ionic/commit/c925274c3bb22532a323b2a07771d7448f7de542)), closes [#23846](https://github.com/ionic-team/ionic/issues/23846)
* **datetime:** prevent vertical page scroll on interaction ([#23780](https://github.com/ionic-team/ionic/issues/23780)) ([950350a](https://github.com/ionic-team/ionic/commit/950350a948320f889589a0c9d2ec9045637215e5)), closes [#23554](https://github.com/ionic-team/ionic/issues/23554)
* **item:** form validation states are now properly shown ([#23853](https://github.com/ionic-team/ionic/issues/23853)) ([5ca2ce9](https://github.com/ionic-team/ionic/commit/5ca2ce91971408218d7bdc52509ce61a6ebb46aa)), closes [#23733](https://github.com/ionic-team/ionic/issues/23733) [#23850](https://github.com/ionic-team/ionic/issues/23850)
* **overlays:** thrown errors are no longer suppressed ([#23831](https://github.com/ionic-team/ionic/issues/23831)) ([a212eb5](https://github.com/ionic-team/ionic/commit/a212eb52599e35d3706e2d3cef751e490e3a7259)), closes [#22724](https://github.com/ionic-team/ionic/issues/22724)
### Features
* **modal:** add bottom sheet functionality ([#23828](https://github.com/ionic-team/ionic/issues/23828)) ([12216d3](https://github.com/ionic-team/ionic/commit/12216d378df091e16fd77d271b107e819278481c)), closes [#21039](https://github.com/ionic-team/ionic/issues/21039)
* **popover:** add ability to pass event to present method ([#23827](https://github.com/ionic-team/ionic/issues/23827)) ([1d2ee92](https://github.com/ionic-team/ionic/commit/1d2ee92ca01b77bcf87c7783b50d59efcf0a402a)), closes [#23813](https://github.com/ionic-team/ionic/issues/23813)
# [5.7.0 Potassium](https://github.com/ionic-team/ionic/compare/v5.6.14...v5.7.0) (2021-09-01)
@@ -158,6 +630,27 @@
# [6.0.0-beta.4](https://github.com/ionic-team/ionic/compare/v6.0.0-beta.3...v6.0.0-beta.4) (2021-08-18)
### Bug Fixes
* **datetime:** reduce time presentation min height ([#23771](https://github.com/ionic-team/ionic/issues/23771)) ([bc4e826](https://github.com/ionic-team/ionic/commit/bc4e8267aa00e7f162cd01579d8d3adbf3cd7a83)), closes [#23690](https://github.com/ionic-team/ionic/issues/23690)
* **datetime:** text color on ios mode now accounts for color contrast ([#23729](https://github.com/ionic-team/ionic/issues/23729)) ([5980db4](https://github.com/ionic-team/ionic/commit/5980db44e5a765d15e681471325e916d566eca8d)), closes [#23723](https://github.com/ionic-team/ionic/issues/23723)
* **item:** highlight now appears above helper/error text ([#23763](https://github.com/ionic-team/ionic/issues/23763)) ([2995e33](https://github.com/ionic-team/ionic/commit/2995e337c8b4612a87eb7111224ec702494fd1d7)), closes [#23510](https://github.com/ionic-team/ionic/issues/23510)
* **toast:** ToastOptions interface now contains icon prop ([#23737](https://github.com/ionic-team/ionic/issues/23737)) ([fbd32ff](https://github.com/ionic-team/ionic/commit/fbd32ffb2633b17d71a34a8760386a319f2e2bca)), closes [#23736](https://github.com/ionic-team/ionic/issues/23736)
* **vue:** custom element internal properties are no longer overridden in vue 3.1.0 ([#23738](https://github.com/ionic-team/ionic/issues/23738)) ([ea39c70](https://github.com/ionic-team/ionic/commit/ea39c70b3ec78b2ea5ef64263e8528b543378784)), closes [#23539](https://github.com/ionic-team/ionic/issues/23539)
* **vue:** modal and popover components now correctly pass properties ([#23761](https://github.com/ionic-team/ionic/issues/23761)) ([578b906](https://github.com/ionic-team/ionic/commit/578b9062dd793c8526b80a769d94aa7aad8fe368)), closes [#23698](https://github.com/ionic-team/ionic/issues/23698)
### Features
* **action-sheet:** add data property to ActionSheetButton ([#23744](https://github.com/ionic-team/ionic/issues/23744)) ([30f8508](https://github.com/ionic-team/ionic/commit/30f8508296cfc8f8b1c03d04b24abfa184624200)), closes [#23700](https://github.com/ionic-team/ionic/issues/23700)
* **datetime:** add firstDayOfWeek property ([#23692](https://github.com/ionic-team/ionic/issues/23692)) ([ea348f0](https://github.com/ionic-team/ionic/commit/ea348f005aef7b2fda581a99338139f6fefcda63)), closes [#23556](https://github.com/ionic-team/ionic/issues/23556)
* **datetime:** add hourCycle property ([#23686](https://github.com/ionic-team/ionic/issues/23686)) ([6342fde](https://github.com/ionic-team/ionic/commit/6342fde56c7687703edd212b8383536c8b9a6400)), closes [#23661](https://github.com/ionic-team/ionic/issues/23661)
## [5.6.14](https://github.com/ionic-team/ionic/compare/v5.6.13...v5.6.14) (2021-08-18)
@@ -171,6 +664,22 @@
# [6.0.0-beta.3](https://github.com/ionic-team/ionic/compare/v6.0.0-beta.2...v6.0.0-beta.3) (2021-08-04)
### Bug Fixes
* **list:** change inset border radius to match iOS 15 ([#23711](https://github.com/ionic-team/ionic/issues/23711)) ([fe2810b](https://github.com/ionic-team/ionic/commit/fe2810b227abc482e663b210cd89f29b76119ff5))
* **popover:** fix keyboard arrow navigation ([#23709](https://github.com/ionic-team/ionic/issues/23709)) ([f2e7a26](https://github.com/ionic-team/ionic/commit/f2e7a267973a06b50a0f6dcbba0a204930bccf69)), closes [#23512](https://github.com/ionic-team/ionic/issues/23512)
* **vue:** popover positioning is now correct with custom elements build ([#23680](https://github.com/ionic-team/ionic/issues/23680)) ([3a1a9cb](https://github.com/ionic-team/ionic/commit/3a1a9cbce45ad128c9ba87940535dabfa167fb9e))
### Features
* **toast:** add icon property to show icon at start of toast content ([#23596](https://github.com/ionic-team/ionic/issues/23596)) ([df24c8c](https://github.com/ionic-team/ionic/commit/df24c8c5ae0b493841c07c05e0d620fa4a90c05a)), closes [#23524](https://github.com/ionic-team/ionic/issues/23524)
## [5.6.13](https://github.com/ionic-team/ionic/compare/v5.6.12...v5.6.13) (2021-08-04)
@@ -185,6 +694,34 @@
# [6.0.0-beta.2](https://github.com/ionic-team/ionic/compare/v6.0.0-beta.1...v6.0.0-beta.2) (2021-07-21)
### Bug Fixes
* **accordion:** value can now be set as string when using multiple is true ([#23581](https://github.com/ionic-team/ionic/issues/23581)) ([8f172de](https://github.com/ionic-team/ionic/commit/8f172de355bc7c910d600ce4d8446b04a6212545)), closes [#23550](https://github.com/ionic-team/ionic/issues/23550)
* **angular:** modal and popover now have correct props defined on angular component ([#23565](https://github.com/ionic-team/ionic/issues/23565)) ([e5a7b34](https://github.com/ionic-team/ionic/commit/e5a7b342623b159d41cc83e0a418fb3984ceb3a7))
* **datetime:** add keyboard year navigation ([#23585](https://github.com/ionic-team/ionic/issues/23585)) ([55bd1f7](https://github.com/ionic-team/ionic/commit/55bd1f749bac01cc691e16283728c42e755cc706)), closes [#21553](https://github.com/ionic-team/ionic/issues/21553) [#18122](https://github.com/ionic-team/ionic/issues/18122)
* **datetime:** selecting time now works correctly on firefox ([#23583](https://github.com/ionic-team/ionic/issues/23583)) ([4188964](https://github.com/ionic-team/ionic/commit/4188964dc8da2c46494245b81864ca6e305611f5)), closes [#23545](https://github.com/ionic-team/ionic/issues/23545)
* **datetime:** years displayed now more consistent with v5 datetime, max and min are now accounted for in MD mode ([#23616](https://github.com/ionic-team/ionic/issues/23616)) ([be219a2](https://github.com/ionic-team/ionic/commit/be219a2814800927e6328ff105616713003340b7)), closes [#23615](https://github.com/ionic-team/ionic/issues/23615)
### Features
* **breadcrumbs:** ionCollapsedClick event payload now contains references to collapsed breadcrumb elements ([#23611](https://github.com/ionic-team/ionic/issues/23611)) ([9ce57d2](https://github.com/ionic-team/ionic/commit/9ce57d2efb84130895a37e22e0fd7e5d713a9fa5)), closes [#23552](https://github.com/ionic-team/ionic/issues/23552)
* **datetime:** add showDefaultTimeLabel property and time-label slot ([#23577](https://github.com/ionic-team/ionic/issues/23577)) ([7ac0109](https://github.com/ionic-team/ionic/commit/7ac010943b2c9ad42a1833153ea16ccffd169b91)), closes [#23555](https://github.com/ionic-team/ionic/issues/23555)
* **datetime:** add size property ([#23649](https://github.com/ionic-team/ionic/issues/23649)) ([321341d](https://github.com/ionic-team/ionic/commit/321341d97dff98b76b69a1efce58923a80e92bc4)), closes [#23518](https://github.com/ionic-team/ionic/issues/23518)
* **range:** add support for customizing pin format ([#22972](https://github.com/ionic-team/ionic/issues/22972)) ([8f2c4f7](https://github.com/ionic-team/ionic/commit/8f2c4f73db167503cdf60222f42bcaadf905b401))
* **segment:** add keyboard navigation, add selectOnFocus property to control selection follow focus behavior ([#23590](https://github.com/ionic-team/ionic/issues/23590)) ([b6c53e5](https://github.com/ionic-team/ionic/commit/b6c53e539b0855fa95b0fe02e5fa74ce403b68b8)), closes [#23520](https://github.com/ionic-team/ionic/issues/23520)
* **select:** update popover interface to match MD spec on desktop, allow multiple values in popover interface ([#23474](https://github.com/ionic-team/ionic/issues/23474)) ([2c07a15](https://github.com/ionic-team/ionic/commit/2c07a1566b6f8570f7e12a55ca8f86d8fb8a968e)), closes [#23657](https://github.com/ionic-team/ionic/issues/23657) [#15500](https://github.com/ionic-team/ionic/issues/15500) [#12310](https://github.com/ionic-team/ionic/issues/12310)
### Performance Improvements
* remove shims for legacy browsers no longer supported in v6 ([#23592](https://github.com/ionic-team/ionic/issues/23592)) ([259b135](https://github.com/ionic-team/ionic/commit/259b1359dbd20d4f85036ae46901a051cd8fc98b))
## [5.6.12](https://github.com/ionic-team/ionic/compare/v5.6.11...v5.6.12) (2021-07-21)
@@ -199,9 +736,36 @@
## [5.6.11](https://github.com/ionic-team/ionic/compare/v5.6.10...v5.6.11) (2021-07-01)
# [6.0.0-beta.1](https://github.com/ionic-team/ionic/compare/v6.0.0-beta.0...v6.0.0-beta.1) (2021-07-01)
### Bug Fixes
* **accordion:** improved reliability of accordion animations ([#23531](https://github.com/ionic-team/ionic/issues/23531)) ([6fbd60b](https://github.com/ionic-team/ionic/commit/6fbd60b0df56dc927226474a1ffa322d979c563e)), closes [#23504](https://github.com/ionic-team/ionic/issues/23504)
* **content:** add touch-action manipulation for a11y zoom and pan ([#23534](https://github.com/ionic-team/ionic/issues/23534)) ([6ca1780](https://github.com/ionic-team/ionic/commit/6ca17805b8b1ea38d7fc16d091324da16a4193c6)), closes [#22805](https://github.com/ionic-team/ionic/issues/22805)
* **datetime:** scroll position no longer gets reset when using datetime in overlay ([#23543](https://github.com/ionic-team/ionic/issues/23543)) ([b735b58](https://github.com/ionic-team/ionic/commit/b735b587cda777ac481bb580c883d9734145f31e))
* **input, select, textarea:** change type of placeholder prop to string only ([#23500](https://github.com/ionic-team/ionic/issues/23500)) ([f3ae431](https://github.com/ionic-team/ionic/commit/f3ae4319bb64debab304973856a33e422ac910a1)), closes [#22976](https://github.com/ionic-team/ionic/issues/22976)
* **popover:** size property now works when providing only event ([#23532](https://github.com/ionic-team/ionic/issues/23532)) ([bdc1f23](https://github.com/ionic-team/ionic/commit/bdc1f2360d7795472cc242a86eb4376d05fa0bb7)), closes [#23528](https://github.com/ionic-team/ionic/issues/23528)
* **popover:** update animation to better match MD spec ([#23541](https://github.com/ionic-team/ionic/issues/23541)) ([bdb95b7](https://github.com/ionic-team/ionic/commit/bdb95b7b6dd798cbc6d1786ae54fa95ac1dfd096))
* **react:** export accordion and accordion group components ([#23497](https://github.com/ionic-team/ionic/issues/23497)) ([a664d42](https://github.com/ionic-team/ionic/commit/a664d4268dea8e84ab9e3b150043ac8f87fb53c7))
* **vue:** navigating between parameterized pages now results in page transition ([#23525](https://github.com/ionic-team/ionic/issues/23525)) ([e30b17c](https://github.com/ionic-team/ionic/commit/e30b17c5bbd1af6936a8d7a98d1f7a115073e029)), closes [#22662](https://github.com/ionic-team/ionic/issues/22662)
### Features
* **accordion-group:** add animated property to disable animations ([#23530](https://github.com/ionic-team/ionic/issues/23530)) ([9a60dd0](https://github.com/ionic-team/ionic/commit/9a60dd0ea7c55acf0fdd1161433e5b4ed40778f2))
* **action-sheet, alert:** add id to AlertButton and ActionSheetButton ([#18992](https://github.com/ionic-team/ionic/issues/18992)) ([9e24a0b](https://github.com/ionic-team/ionic/commit/9e24a0b49357a3a39ca89f026ff23271a365d935)), closes [#22959](https://github.com/ionic-team/ionic/issues/22959)
* **vue:** extend useIonRouter hook for programmatic navigation with animation control ([#23499](https://github.com/ionic-team/ionic/issues/23499)) ([fc9e1b4](https://github.com/ionic-team/ionic/commit/fc9e1b4b361938e5644683c395a565be2de1eab9)), closes [#23450](https://github.com/ionic-team/ionic/issues/23450)
### BREAKING CHANGES
* **input, select, textarea:** Updated the `placeholder` property on `ion-input`, `ion-textarea`, and `ion-select` to have a type of `string | undefined`.
## [5.6.11](https://github.com/ionic-team/ionic/compare/v5.6.10...v5.6.11) (2021-07-01)
### Bug Fixes
* **animation:** typescript interface has correct return value for progress methods ([#23536](https://github.com/ionic-team/ionic/issues/23536)) ([f3d6abb](https://github.com/ionic-team/ionic/commit/f3d6abbc1beeafe3b5e7f473d70d0b8ef4c79bc8))
@@ -209,6 +773,63 @@
# [6.0.0-beta.0](https://github.com/ionic-team/ionic/compare/v5.6.10...v6.0.0-beta.0) (2021-06-23)
### Bug Fixes
* **accordion:** toggle icon now shows up in vue and react ([#23426](https://github.com/ionic-team/ionic/issues/23426)) ([c716617](https://github.com/ionic-team/ionic/commit/c7166179457a8e2c7e1702c5761bc6368dbd156f))
* **datetime:** changing time emits ionChange ([#23463](https://github.com/ionic-team/ionic/issues/23463)) ([b0cce36](https://github.com/ionic-team/ionic/commit/b0cce360c83ac564e053523cc31b32d1deaeda0c))
* **modal:** add additional padding to toolbars in iOS modal ([#23262](https://github.com/ionic-team/ionic/issues/23262)) ([a037b65](https://github.com/ionic-team/ionic/commit/a037b65aad5cfc0477322a8f36105b9009366ec2)), closes [#22778](https://github.com/ionic-team/ionic/issues/22778)
* **modal:** border radius is correctly set on card style modal ([#23461](https://github.com/ionic-team/ionic/issues/23461)) ([bccb8ad](https://github.com/ionic-team/ionic/commit/bccb8ad5fb5ec7f98a6cbfa62a403ecaca7fbdb6))
* **modal, popover:** overlays now automatically determine if they are inline ([#23434](https://github.com/ionic-team/ionic/issues/23434)) ([8dbe8ba](https://github.com/ionic-team/ionic/commit/8dbe8ba7bc26792c5024f81cf4752f5b78317492))
* **popover:** shadow parts now correctly added ([#23446](https://github.com/ionic-team/ionic/issues/23446)) ([e1a9613](https://github.com/ionic-team/ionic/commit/e1a96130ebab1e481e880f0f3876f421976f08d5))
* **popover:** update prop defaults, use correct delegate ([#23340](https://github.com/ionic-team/ionic/issues/23340)) ([960778a](https://github.com/ionic-team/ionic/commit/960778a36f6eb6318cc740c4f7a255107723b8fd))
* **searchbar:** showClearButton now defaults to 'always' for improved usability with screen readers ([#23475](https://github.com/ionic-team/ionic/issues/23475)) ([80f181d](https://github.com/ionic-team/ionic/commit/80f181d4846507ee6bd4150bb568fca9b6660428))
* **vue:** ensure webpack does not eliminate core css ([#23465](https://github.com/ionic-team/ionic/issues/23465)) ([ee3a00f](https://github.com/ionic-team/ionic/commit/ee3a00fde61b4d1d3168d34b3d23bb97dd154154))
### Code Refactoring
* **all:** update required browser, framework, and mobile platform versions for v6 ([#23443](https://github.com/ionic-team/ionic/issues/23443)) ([c842dd8](https://github.com/ionic-team/ionic/commit/c842dd88c98888b2afab08ac5e8bc57c2a4c2fbd))
* **angular:** remove Config.set() method ([#22918](https://github.com/ionic-team/ionic/issues/22918)) ([9e05891](https://github.com/ionic-team/ionic/commit/9e0589173607b3c0eff7794079123354c2eeaa1a))
* **header:** removed border from last toolbar when using collapsible large title ([#22891](https://github.com/ionic-team/ionic/issues/22891)) ([c72bc5d](https://github.com/ionic-team/ionic/commit/c72bc5dbd76cd3ce622a4b3cedcb7446a2819384)), closes [#22777](https://github.com/ionic-team/ionic/issues/22777)
* **ios:** update toolbar and tabbar default background colors ([#22852](https://github.com/ionic-team/ionic/issues/22852)) ([3d615cb](https://github.com/ionic-team/ionic/commit/3d615cb3c7b233b08b9da6ac04096e16bbb60bfc)), closes [#22780](https://github.com/ionic-team/ionic/issues/22780)
* **toast:** whitespace variable now defaults to normal ([#22866](https://github.com/ionic-team/ionic/issues/22866)) ([9b78689](https://github.com/ionic-team/ionic/commit/9b786899e550c391b9395c669f9bba8f39ac98aa))
* **vue:** drop support for "on" prefixed overlay events and bump minimum required version of vue to 3.0.6 ([#23229](https://github.com/ionic-team/ionic/issues/23229)) ([6fcb3a6](https://github.com/ionic-team/ionic/commit/6fcb3a62b1b12c5ded11179e83854592d4309bdf))
* **vue:** remove support for child routes nested inside of tabs ([#22919](https://github.com/ionic-team/ionic/issues/22919)) ([75458ac](https://github.com/ionic-team/ionic/commit/75458ac7fb95f56a6ec460f85cf7d7720ce0c070))
### Features
* **accordion:** add accordion and accordion-group components ([#22865](https://github.com/ionic-team/ionic/issues/22865)) ([073883a](https://github.com/ionic-team/ionic/commit/073883a0987149e9f6258ca43c46f5ed4bce0dc5)), closes [#17094](https://github.com/ionic-team/ionic/issues/17094)
* **breadcrumbs:** add breadcrumbs component ([#22701](https://github.com/ionic-team/ionic/issues/22701)) ([2f6b1e4](https://github.com/ionic-team/ionic/commit/2f6b1e4eea307c6f14345704e5824378ef079acb)), closes [#22770](https://github.com/ionic-team/ionic/issues/22770)
* **datetime:** add calendar picker ([#23416](https://github.com/ionic-team/ionic/issues/23416)) ([932d3ca](https://github.com/ionic-team/ionic/commit/932d3ca62f3e3ef08acb065ce6ec46faa3811f96)), closes [#19423](https://github.com/ionic-team/ionic/issues/19423)
* **item:** add helper text, error text, counter, shape, and fill mode ([#23354](https://github.com/ionic-team/ionic/issues/23354)) ([faefe97](https://github.com/ionic-team/ionic/commit/faefe97da6a9d5beff1183d10efd0df9c4e3ebd7)), closes [#19619](https://github.com/ionic-team/ionic/issues/19619)
* **modal:** modals can now be used inline ([#23341](https://github.com/ionic-team/ionic/issues/23341)) ([3be1c3d](https://github.com/ionic-team/ionic/commit/3be1c3dcd73e6039a89b19b409e63877cda37f6e)), closes [#20117](https://github.com/ionic-team/ionic/issues/20117) [#20263](https://github.com/ionic-team/ionic/issues/20263)
* **popover:** account for ionShadowTarget elements ([#23436](https://github.com/ionic-team/ionic/issues/23436)) ([0e38d42](https://github.com/ionic-team/ionic/commit/0e38d4276110dcd94db5adc3b6aee3b5b0befc5c))
* **popover:** add desktop support ([#23258](https://github.com/ionic-team/ionic/issues/23258)) ([a67a0fa](https://github.com/ionic-team/ionic/commit/a67a0fabb8249685bbe93ed862839e2b2e76cd5a)), closes [#21599](https://github.com/ionic-team/ionic/issues/21599)
* **popover:** popover can now be used inline ([#23231](https://github.com/ionic-team/ionic/issues/23231)) ([308fa1c](https://github.com/ionic-team/ionic/commit/308fa1c0dd054cfc2ea54d2edc99e7a4b549f6f0))
* **slides:** add IonicSwiper modules, deprecate ion-slides, and add link to migration ([#23447](https://github.com/ionic-team/ionic/issues/23447)) ([623c84a](https://github.com/ionic-team/ionic/commit/623c84ab082668a996c654e18ffc9768f68b85dd))
* **spinner:** add lines-sharp, lines-sharp-small, update styles for ios 14 ([#22397](https://github.com/ionic-team/ionic/issues/22397)) ([2a5b272](https://github.com/ionic-team/ionic/commit/2a5b272a329bbad1ca07705f84f0fd06e3ef32ad))
* **vue:** add custom elements bundle ([#23458](https://github.com/ionic-team/ionic/issues/23458)) ([dc48a9f](https://github.com/ionic-team/ionic/commit/dc48a9f1a2dff8a2d644112bbe1df8b0b6811848))
### BREAKING CHANGES
* **searchbar:** The `showClearButton` property on `ion-searchbar` now defaults to `'always'`.
* **datetime:** The `ion-datetime` component has been revamped to use a new calendar style. As a result, some APIs have been removed. See https://github.com/ionic-team/ionic-framework/blob/master/BREAKING.md for more details.
* **all:** Browser, JS Framework, and mobile platform minimum required versions have been updated.
* **popover:** Converted `ion-popover` to use the Shadow DOM.
* **vue:** - Dropped support for prefixed overlay events in favor of non prefixed events (I.e. `@onDidDismiss` becomes `@didDismiss`).
- Minimum required version of Vue is now Vue v3.0.6 or newer.
* **vue:** Support for child routes nested inside of tabs has been removed to better conform to Vue Router's best practices. Additional routes should be written as sibling routes with the parent tab as the path prefix.
* **angular:** The `Config.set()` method has been removed. See https://ionicframework.com/docs/angular/config for examples on how to set config globally, per-component, and per-platform.
* **ios:** The tab bar and toolbar default background colors have been updated to better reflect the latest iOS styles.
* **header:** The last toolbar in the header with a collapsible large title no longer has a border.
* **toast:** The `--white-space` CSS Variable now defaults to `normal`.
## [5.6.10](https://github.com/ionic-team/ionic/compare/v5.6.9...v5.6.10) (2021-06-22)
@@ -4135,4 +4756,4 @@ The following dependencies need to be updated to resolve build errors
<a name="0.1.0"></a>
## [0.1.0](https://github.com/ionic-team/ionic/commit/43a8c4c7a719169336a84964fc1c737562d764a6) (2018-03-01)
## [0.1.0](https://github.com/ionic-team/ionic/commit/43a8c4c7a719169336a84964fc1c737562d764a6) (2018-03-01)

View File

@@ -1,22 +1,63 @@
# Ionic Framework
<p align="center">
<a href="#">
<img alt="Ionic" src="https://github.com/ionic-team/ionic-framework/blob/main/.github/assets/logo.png?raw=true" width="60" />
</a>
</p>
[Ionic Framework](https://ionicframework.com/) is the open-source mobile app development framework that makes it easy to
build top quality native and progressive web apps with web technologies.
<h1 align="center">
Ionic
</h1>
Ionic Framework is based on [Web Components](https://www.webcomponents.org/introduction) and comes with many significant performance, usability, and feature improvements over the past versions.
<p align="center">
Ionic is an open source app development toolkit for building modern, fast, top-quality cross-platform native and Progressive Web Apps from a single codebase with JavaScript and the Web.
</p>
<p align="center">
Ionic is based on <a href="https://www.webcomponents.org/introduction">Web Components</a>, which enables significant performance, usability, and feature improvements alongside support for popular web frameworks like <a href="https://angular.io/">Angular</a>, <a href="https://reactjs.com/">React</a>, and <a href="https://vuejs.org/">Vue</a>.
## Looking for the Ionic Framework v6 beta?
</p>
[Click here to get started!](https://github.com/ionic-team/ionic-framework/blob/next/BETA.md)
<p align="center">
<a href="https://github.com/ionic-team/ionic-framework/blob/main/LICENSE">
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="Ionic Framework is released under the MIT license." />
</a>
<a href="https://github.com/ionic-team/ionic/blob/main/.github/CONTRIBUTING.md">
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" alt="PRs welcome!" />
</a>
<a href="https://twitter.com/Ionicframework">
<img src="https://img.shields.io/twitter/follow/ionicframework.svg?label=Follow%20@IonicFramework" alt="Follow @IonicFramework">
</a>
<a href="https://ionic.link/discord">
<img src="https://img.shields.io/discord/520266681499779082?color=7289DA&label=%23ionic&logo=discord&logoColor=white" alt="Official Ionic Discord" />
</a>
</p>
<h2 align="center">
<a href="https://ionicframework.com/getting-started/">Quickstart</a>
<span> · </span>
<a href="https://ionicframework.com/docs/">
Documentation
</a>
<span> · </span>
<a href="https://github.com/ionic-team/ionic/blob/main/.github/CONTRIBUTING.md">Contribute</a>
<span> · </span>
<a href="https://blog.ionicframework.com/">Blog</a>
<br />
Community:
<a href="https://ionic.link/discord">Discord</a>
<span> · </span>
<a href="https://forum.ionicframework.com/">Forums</a>
<span> · </span>
<a href="https://twitter.com/Ionicframework">Twitter</a>
</h2>
### Packages
| Project | Package | Version | Links |
| ------- | ------- | ------- |:-----:|
| **Core** | [`@ionic/core`](https://www.npmjs.com/package/@ionic/core) | [![version](https://img.shields.io/npm/v/@ionic/core/latest.svg)](https://www.npmjs.com/package/@ionic/core) | [`README.md`](core/README.md)
| **Angular** | [`@ionic/angular`](https://www.npmjs.com/package/@ionic/angular) | [![version](https://img.shields.io/npm/v/@ionic/angular/latest.svg)](https://www.npmjs.com/package/@ionic/angular) | [`README.md`](angular/README.md)
| **Vue** | [`@ionic/vue`](https://www.npmjs.com/package/@ionic/vue) | [![version](https://img.shields.io/npm/v/@ionic/vue/latest.svg)](https://www.npmjs.com/package/@ionic/vue) | [`README.md`](packages/vue/README.md)
| **React** | [`@ionic/react`](https://www.npmjs.com/package/@ionic/react) | [![version](https://img.shields.io/npm/v/@ionic/react/latest.svg)](https://www.npmjs.com/package/@ionic/react) | [`README.md`](packages/react/README.md)
| Project | Package | Version | Downloads| Links |
| ------- | ------- | ------- | -------- |:-----:|
| **Core** | [`@ionic/core`](https://www.npmjs.com/package/@ionic/core) | [![version](https://img.shields.io/npm/v/@ionic/core/latest.svg)](https://www.npmjs.com/package/@ionic/core) | <a href="https://www.npmjs.com/package/@ionic/core" target="_blank"><img src="https://img.shields.io/npm/dm/@ionic/core.svg" alt="NPM Downloads" /></a> | [`README.md`](core/README.md)
| **Angular** | [`@ionic/angular`](https://www.npmjs.com/package/@ionic/angular) | [![version](https://img.shields.io/npm/v/@ionic/angular/latest.svg)](https://www.npmjs.com/package/@ionic/angular) | <a href="https://www.npmjs.com/package/@ionic/angular" target="_blank"><img src="https://img.shields.io/npm/dm/@ionic/angular.svg" alt="NPM Downloads" /></a> | [`README.md`](angular/README.md)
| **Vue** | [`@ionic/vue`](https://www.npmjs.com/package/@ionic/vue) | [![version](https://img.shields.io/npm/v/@ionic/vue/latest.svg)](https://www.npmjs.com/package/@ionic/vue) | <a href="https://www.npmjs.com/package/@ionic/vue" target="_blank"><img src="https://img.shields.io/npm/dm/@ionic/vue.svg" alt="NPM Downloads" /></a> | [`README.md`](packages/vue/README.md)
| **React** | [`@ionic/react`](https://www.npmjs.com/package/@ionic/react) | [![version](https://img.shields.io/npm/v/@ionic/react/latest.svg)](https://www.npmjs.com/package/@ionic/react) | <a href="https://www.npmjs.com/package/@ionic/react" target="_blank"><img src="https://img.shields.io/npm/dm/@ionic/react.svg" alt="NPM Downloads" /></a> |[`README.md`](packages/react/README.md)
Looking for the `ionic-angular` package? Ionic 3 has been moved to the [`ionic-v3`](https://github.com/ionic-team/ionic-v3) repo. See [Earlier Versions](#earlier-versions).
@@ -26,6 +67,18 @@ Start a new project by following our quick [Getting Started guide](https://ionic
We would love to hear from you! If you have any feedback or run into issues using our framework, please file
an [issue](https://github.com/ionic-team/ionic/issues/new) on this repository.
### Migration Guides
Already have an Ionic app? These guides will help you migrate to the latest versions.
* [Migrate from v5 to v6](https://ionicframework.com/docs/reference/migration#migrating-from-ionic-5x-to-ionic-6x)
* [Migrate from v4 to v5](https://ionicframework.com/docs/reference/migration#migrating-from-ionic-4x-to-ionic-5x)
* [Migrate from v3 to v4](https://ionicframework.com/docs/reference/migration#migrating-from-ionic-30-to-ionic-40)
### Examples
The [Ionic Conference App](https://github.com/ionic-team/ionic-conference-app) is a full featured Ionic app.
It is the perfect starting point for learning and building your own app.
### Contributing
@@ -36,13 +89,6 @@ label.
Please note that this project is released with a [Contributor Code of Conduct](https://github.com/ionic-team/ionic/blob/main/CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.
### Examples
The [Ionic Conference App](https://github.com/ionic-team/ionic-conference-app) is a full featured Ionic app.
It is the perfect starting point for learning and building your own app.
### Future Goals
As Ionic Framework components migrate to the web component standard, a goal of ours is to have Ionic Framework easily work within all of the popular frameworks.

4
angular/.eslintignore Normal file
View File

@@ -0,0 +1,4 @@
dist
virtual-scroll
scripts
proxies.ts

30
angular/.eslintrc.json Normal file
View File

@@ -0,0 +1,30 @@
{
"root": true,
"ignorePatterns": ["test/**/*", "src/directives/virtual-scroll/**/*"],
"overrides": [
{
"files": ["*.ts"],
"parserOptions": {
"project": ["tsconfig.json"],
"createDefaultProgram": true
},
"extends": [
"@ionic/eslint-config/recommended",
"plugin:@angular-eslint/recommended",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"@typescript-eslint/consistent-type-imports": "off",
"@angular-eslint/component-class-suffix": "off",
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": "ion",
"style": "kebab-case"
}
]
}
}
]
}

6
angular/.prettierignore Normal file
View File

@@ -0,0 +1,6 @@
dist
virtual-scroll
scripts
test
src/directives/proxies.ts
src/directives/angular-component-lib/utils.ts

23
angular/CHANGELOG.md Normal file
View File

@@ -0,0 +1,23 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [6.0.3](https://github.com/ionic-team/ionic/compare/v6.0.2...v6.0.3) (2022-01-19)
### Bug Fixes
* **angular:** apply touch, dirty and pristine form control classes ([#24558](https://github.com/ionic-team/ionic/issues/24558)) ([273ae2c](https://github.com/ionic-team/ionic/commit/273ae2cc087b2a5a30fb50a1b0eaeb0a221900fc)), closes [#24483](https://github.com/ionic-team/ionic/issues/24483)
## [6.0.2](https://github.com/ionic-team/ionic/compare/v6.0.1...v6.0.2) (2022-01-11)
### Bug Fixes
* **angular:** attach change detector ref for inline overlays ([#24521](https://github.com/ionic-team/ionic/issues/24521)) ([5c54593](https://github.com/ionic-team/ionic/commit/5c54593dde64ae61347568405ebf74502cfff370)), closes [#24502](https://github.com/ionic-team/ionic/issues/24502)
* **angular:** popover will respect side attribute value ([#24470](https://github.com/ionic-team/ionic/issues/24470)) ([e6955a2](https://github.com/ionic-team/ionic/commit/e6955a26b92fc536c5c73b60b5943881c7d58ee1)), closes [#24466](https://github.com/ionic-team/ionic/issues/24466)

15876
angular/package-lock.json generated
View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/angular",
"version": "5.9.4",
"version": "6.0.3",
"description": "Angular specific wrappers for @ionic/core",
"keywords": [
"ionic",
@@ -22,65 +22,76 @@
"bugs": {
"url": "https://github.com/ionic-team/ionic/issues"
},
"publishConfig": {
"directory": "dist"
},
"homepage": "https://ionicframework.com/",
"scripts": {
"prepublishOnly": "npm run build",
"build": "npm run clean && npm run build.ng && npm run build.core && npm run clean-generated",
"build.core": "node scripts/build-core.js",
"build.fesm": "rollup --config ./scripts/rollup.config.js",
"build.link": "npm run build && node scripts/link-copy.js",
"build.ng": "ng-packagr -p package.json",
"build.es2015": "ngc -p tsconfig.json && rollup --config ./scripts/rollup.config.js",
"build.es5": "ngc -p tsconfig.legacy.json && rollup --config ./scripts/rollup.config.legacy.js",
"build.ng": "ng-packagr -p package.json -c tsconfig.json",
"clean": "node scripts/clean.js",
"clean-generated": "node ./scripts/clean-generated.js",
"lint": "npm run lint.ts",
"lint.ts": "tslint --project .",
"lint.fix": "tslint --project . --fix",
"lint": "npm run eslint && npm run prettier -- --check",
"fmt": "npm run eslint -- --fix && npm run prettier -- --write",
"prettier": "prettier \"**/*.ts\"",
"eslint": "eslint . --ext .ts",
"prerelease": "npm run validate && np prerelease --yolo --any-branch --tag next",
"test": "echo 'angular no tests yet'",
"tsc": "tsc -p .",
"validate": "npm i && npm run lint && npm run test && npm run build"
},
"dependencies": {
"@ionic/core": "5.9.4",
"tslib": "^1.9.3"
"@ionic/core": "^6.0.3",
"jsonc-parser": "^3.0.0",
"tslib": "^2.0.0"
},
"peerDependencies": {
"@angular/core": ">=8.2.7",
"@angular/forms": ">=8.2.7",
"@angular/router": ">=8.2.7",
"rxjs": ">=6.2.0",
"zone.js": ">=0.8.26"
"@angular/core": ">=12.0.0",
"@angular/forms": ">=12.0.0",
"@angular/router": ">=12.0.0",
"rxjs": ">=6.6.0",
"zone.js": ">=0.11.0"
},
"devDependencies": {
"@angular-devkit/core": "8.3.17",
"@angular-devkit/schematics": "8.3.17",
"@angular/common": "8.2.13",
"@angular/compiler": "8.2.13",
"@angular/compiler-cli": "8.2.13",
"@angular/core": "8.2.13",
"@angular/forms": "8.2.13",
"@angular/router": "8.2.13",
"@angular-devkit/core": "^12.0.0",
"@angular-devkit/schematics": "^12.0.0",
"@angular-eslint/eslint-plugin": "^12.5.0",
"@angular-eslint/eslint-plugin-template": "^12.5.0",
"@angular-eslint/template-parser": "^12.5.0",
"@angular/common": "^12.0.0",
"@angular/compiler": "^12.0.0",
"@angular/compiler-cli": "^12.0.0",
"@angular/core": "^12.0.0",
"@angular/forms": "^12.0.0",
"@angular/router": "^12.0.0",
"@ionic/eslint-config": "^0.3.0",
"@ionic/prettier-config": "^2.0.0",
"@schematics/angular": "^12.2.9",
"@types/node": "12.12.5",
"@typescript-eslint/eslint-plugin": "^4.32.0",
"@typescript-eslint/parser": "^4.32.0",
"eslint": "^7.32.0",
"eslint-plugin-import": "^2.25.2",
"fs-extra": "^7.0.0",
"glob": "^7.1.4",
"ng-packagr": "^9.1.5",
"rollup": "~1.17.0",
"rollup-plugin-node-resolve": "~5.2.0",
"ng-packagr": "^12.0.0",
"prettier": "^2.4.1",
"rxjs": "^6.6.2",
"tsickle": "^0.39.1",
"tslint": "^5.12.1",
"tslint-ionic-rules": "0.0.21",
"typescript": "3.4.5",
"zone.js": "^0.11.1"
"typescript": "4.2.4",
"typescript-eslint-language-service": "^4.1.5",
"zone.js": "~0.11.4"
},
"prettier": "@ionic/prettier-config",
"schematics": "./schematics/collection.json",
"ngPackage": {
"lib": {
"entryFile": "src/index.ts"
},
"whitelistedNonPeerDependencies": [
"@ionic/core"
"allowedNonPeerDependencies": [
"@ionic/core",
"jsonc-parser"
]
}
}

View File

@@ -10,15 +10,13 @@ export const appInitialize = (config: Config, doc: Document, zone: NgZone) => {
return (): any => {
const win: IonicWindow | undefined = doc.defaultView as any;
if (win && typeof (window as any) !== 'undefined') {
setupConfig({
...config,
_zoneGate: (h: any) => zone.run(h)
_zoneGate: (h: any) => zone.run(h),
});
const aelFn = '__zone_symbol__addEventListener' in (doc.body as any)
? '__zone_symbol__addEventListener'
: 'addEventListener';
const aelFn =
'__zone_symbol__addEventListener' in (doc.body as any) ? '__zone_symbol__addEventListener' : 'addEventListener';
return applyPolyfills().then(() => {
return defineCustomElements(win, {
@@ -31,7 +29,7 @@ export const appInitialize = (config: Config, doc: Document, zone: NgZone) => {
},
rel(elm, eventName, cb, opts) {
elm.removeEventListener(eventName, cb, opts);
}
},
});
});
}

View File

@@ -0,0 +1,63 @@
/* eslint-disable */
/* tslint:disable */
import { fromEvent } from 'rxjs';
export const proxyInputs = (Cmp: any, inputs: string[]) => {
const Prototype = Cmp.prototype;
inputs.forEach(item => {
Object.defineProperty(Prototype, item, {
get() {
return this.el[item];
},
set(val: any) {
this.z.runOutsideAngular(() => (this.el[item] = val));
}
});
});
};
export const proxyMethods = (Cmp: any, methods: string[]) => {
const Prototype = Cmp.prototype;
methods.forEach(methodName => {
Prototype[methodName] = function () {
const args = arguments;
return this.z.runOutsideAngular(() =>
this.el[methodName].apply(this.el, args)
);
};
});
};
export const proxyOutputs = (instance: any, el: any, events: string[]) => {
events.forEach(eventName => instance[eventName] = fromEvent(el, eventName));
}
export const defineCustomElement = (tagName: string, customElement: any) => {
if (
customElement !== undefined &&
typeof customElements !== 'undefined' &&
!customElements.get(tagName)
) {
customElements.define(tagName, customElement);
}
}
// tslint:disable-next-line: only-arrow-functions
export function ProxyCmp(opts: { defineCustomElementFn?: () => void, inputs?: any; methods?: any }) {
const decorator = function (cls: any) {
const { defineCustomElementFn, inputs, methods } = opts;
if (defineCustomElementFn !== undefined) {
defineCustomElementFn();
}
if (inputs) {
proxyInputs(cls, inputs);
}
if (methods) {
proxyMethods(cls, methods);
}
return cls;
};
return decorator;
}

View File

@@ -1,32 +1,30 @@
import { Directive, ElementRef, HostListener, Injector } from '@angular/core';
import { Directive, HostListener, ElementRef, Injector } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { ValueAccessor, setIonicClasses } from './value-accessor';
@Directive({
/* tslint:disable-next-line:directive-selector */
selector: 'ion-checkbox,ion-toggle',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: BooleanValueAccessor,
multi: true
}
]
useExisting: BooleanValueAccessorDirective,
multi: true,
},
],
})
export class BooleanValueAccessor extends ValueAccessor {
export class BooleanValueAccessorDirective extends ValueAccessor {
constructor(injector: Injector, el: ElementRef) {
super(injector, el);
}
writeValue(value: any) {
writeValue(value: any): void {
this.el.nativeElement.checked = this.lastValue = value == null ? false : value;
setIonicClasses(this.el);
}
@HostListener('ionChange', ['$event.target'])
_handleIonChange(el: any) {
_handleIonChange(el: any): void {
this.handleChangeEvent(el, el.checked);
}
}

View File

@@ -1,32 +1,30 @@
import { Directive, ElementRef, HostListener, Injector } from '@angular/core';
import { Directive, HostListener, ElementRef, Injector } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { ValueAccessor } from './value-accessor';
@Directive({
/* tslint:disable-next-line:directive-selector */
selector: 'ion-input[type=number]',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: NumericValueAccessor,
multi: true
}
]
useExisting: NumericValueAccessorDirective,
multi: true,
},
],
})
export class NumericValueAccessor extends ValueAccessor {
export class NumericValueAccessorDirective extends ValueAccessor {
constructor(injector: Injector, el: ElementRef) {
super(injector, el);
}
@HostListener('ionChange', ['$event.target'])
_handleIonChange(el: any) {
_handleIonChange(el: any): void {
this.handleChangeEvent(el, el.value);
}
registerOnChange(fn: (_: number | null) => void) {
super.registerOnChange(value => {
registerOnChange(fn: (_: number | null) => void): void {
super.registerOnChange((value) => {
fn(value === '' ? null : parseFloat(value));
});
}

View File

@@ -1,4 +1,4 @@
import { Directive, ElementRef, HostListener, Injector } from '@angular/core';
import { ElementRef, Injector, Directive, HostListener } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { ValueAccessor } from './value-accessor';
@@ -9,19 +9,18 @@ import { ValueAccessor } from './value-accessor';
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: RadioValueAccessor,
multi: true
}
]
useExisting: RadioValueAccessorDirective,
multi: true,
},
],
})
export class RadioValueAccessor extends ValueAccessor {
export class RadioValueAccessorDirective extends ValueAccessor {
constructor(injector: Injector, el: ElementRef) {
super(injector, el);
}
@HostListener('ionSelect', ['$event.target'])
_handleIonSelect(el: any) {
_handleIonSelect(el: any): void {
this.handleChangeEvent(el, el.checked);
}
}

View File

@@ -1,4 +1,4 @@
import { Directive, ElementRef, HostListener, Injector } from '@angular/core';
import { ElementRef, Injector, Directive, HostListener } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { ValueAccessor } from './value-accessor';
@@ -9,19 +9,18 @@ import { ValueAccessor } from './value-accessor';
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: SelectValueAccessor,
multi: true
}
]
useExisting: SelectValueAccessorDirective,
multi: true,
},
],
})
export class SelectValueAccessor extends ValueAccessor {
export class SelectValueAccessorDirective extends ValueAccessor {
constructor(injector: Injector, el: ElementRef) {
super(injector, el);
}
@HostListener('ionChange', ['$event.target'])
_handleChangeEvent(el: any) {
_handleChangeEvent(el: any): void {
this.handleChangeEvent(el, el.value);
}
}

View File

@@ -1,4 +1,4 @@
import { Directive, ElementRef, HostListener, Injector } from '@angular/core';
import { ElementRef, Injector, Directive, HostListener } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { ValueAccessor } from './value-accessor';
@@ -9,19 +9,18 @@ import { ValueAccessor } from './value-accessor';
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: TextValueAccessor,
multi: true
}
]
useExisting: TextValueAccessorDirective,
multi: true,
},
],
})
export class TextValueAccessor extends ValueAccessor {
export class TextValueAccessorDirective extends ValueAccessor {
constructor(injector: Injector, el: ElementRef) {
super(injector, el);
}
@HostListener('ionChange', ['$event.target'])
_handleInputEvent(el: any) {
_handleInputEvent(el: any): void {
this.handleChangeEvent(el, el.value);
}
}

View File

@@ -1,19 +1,23 @@
import { AfterViewInit, ElementRef, HostListener, Injector, OnDestroy, Type } from '@angular/core';
import { AfterViewInit, ElementRef, Injector, OnDestroy, Directive, HostListener } from '@angular/core';
import { ControlValueAccessor, NgControl } from '@angular/forms';
import { Subscription } from 'rxjs';
import { raf } from '../../util/util';
@Directive()
export class ValueAccessor implements ControlValueAccessor, AfterViewInit, OnDestroy {
private onChange: (value: any) => void = () => {/**/};
private onTouched: () => void = () => {/**/};
private onChange: (value: any) => void = () => {
/**/
};
private onTouched: () => void = () => {
/**/
};
protected lastValue: any;
private statusChanges?: Subscription;
constructor(protected injector: Injector, protected el: ElementRef) {}
writeValue(value: any) {
writeValue(value: any): void {
/**
* TODO for Ionic 6:
* Change `value == null ? '' : value;`
@@ -25,7 +29,7 @@ export class ValueAccessor implements ControlValueAccessor, AfterViewInit, OnDes
setIonicClasses(this.el);
}
handleChangeEvent(el: HTMLElement, value: any) {
handleChangeEvent(el: HTMLElement, value: any): void {
if (el === this.el.nativeElement) {
if (value !== this.lastValue) {
this.lastValue = value;
@@ -36,38 +40,42 @@ export class ValueAccessor implements ControlValueAccessor, AfterViewInit, OnDes
}
@HostListener('ionBlur', ['$event.target'])
_handleBlurEvent(el: any) {
_handleBlurEvent(el: any): void {
if (el === this.el.nativeElement) {
this.onTouched();
setIonicClasses(this.el);
}
}
registerOnChange(fn: (value: any) => void) {
registerOnChange(fn: (value: any) => void): void {
this.onChange = fn;
}
registerOnTouched(fn: () => void) {
registerOnTouched(fn: () => void): void {
this.onTouched = fn;
}
setDisabledState(isDisabled: boolean) {
setDisabledState(isDisabled: boolean): void {
this.el.nativeElement.disabled = isDisabled;
}
ngOnDestroy() {
ngOnDestroy(): void {
if (this.statusChanges) {
this.statusChanges.unsubscribe();
}
}
ngAfterViewInit() {
ngAfterViewInit(): void {
let ngControl;
try {
ngControl = this.injector.get<NgControl>(NgControl as Type<NgControl>);
} catch { /* No FormControl or ngModel binding */ }
ngControl = this.injector.get<NgControl>(NgControl);
} catch {
/* No FormControl or ngModel binding */
}
if (!ngControl) { return; }
if (!ngControl) {
return;
}
// Listen for changes in validity, disabled, or pending states
if (ngControl.statusChanges) {
@@ -84,15 +92,15 @@ export class ValueAccessor implements ControlValueAccessor, AfterViewInit, OnDes
* This patches the methods to manually sync
* the classes until this feature is implemented in Angular.
*/
const formControl = ngControl.control;
const formControl = ngControl.control as any;
if (formControl) {
const methodsToPatch = ['markAsTouched', 'markAllAsTouched', 'markAsUntouched', 'markAsDirty', 'markAsPristine'] as const;
methodsToPatch.forEach(method => {
if (formControl[method]) {
const oldFn = formControl[method].bind(formControl);
formControl[method] = (...params: any[]) => {
oldFn(...params);
setIonicClasses(this.el);
const methodsToPatch = ['markAsTouched', 'markAllAsTouched', 'markAsUntouched', 'markAsDirty', 'markAsPristine'];
methodsToPatch.forEach((method) => {
if (typeof formControl[method] !== 'undefined') {
const oldFn = formControl[method].bind(formControl);
formControl[method] = (...params: any[]) => {
oldFn(...params);
setIonicClasses(this.el);
};
}
});
@@ -100,7 +108,7 @@ export class ValueAccessor implements ControlValueAccessor, AfterViewInit, OnDes
}
}
export const setIonicClasses = (element: ElementRef) => {
export const setIonicClasses = (element: ElementRef): void => {
raf(() => {
const input = element.nativeElement as HTMLElement;
const classes = getClasses(input);
@@ -127,16 +135,11 @@ const getClasses = (element: HTMLElement) => {
const setClasses = (element: HTMLElement, classes: string[]) => {
const classList = element.classList;
[
'ion-valid',
'ion-invalid',
'ion-touched',
'ion-untouched',
'ion-dirty',
'ion-pristine'
].forEach(c => classList.remove(c));
['ion-valid', 'ion-invalid', 'ion-touched', 'ion-untouched', 'ion-dirty', 'ion-pristine'].forEach((c) =>
classList.remove(c)
);
classes.forEach(c => classList.add(c));
classes.forEach((c) => classList.add(c));
};
const startsWith = (input: string, search: string): boolean => {

View File

@@ -1,4 +1,4 @@
import { Directive, HostListener, Optional } from '@angular/core';
import { Directive, HostListener, Input, Optional } from '@angular/core';
import { AnimationBuilder } from '@ionic/core';
import { Config } from '../../providers/config';
@@ -8,11 +8,12 @@ import { IonRouterOutlet } from './ion-router-outlet';
@Directive({
selector: 'ion-back-button',
inputs: ['defaultHref', 'routerAnimation'],
})
export class IonBackButtonDelegate {
export class IonBackButtonDelegateDirective {
@Input()
defaultHref: string | undefined | null;
@Input()
routerAnimation?: AnimationBuilder;
constructor(
@@ -25,10 +26,10 @@ export class IonBackButtonDelegate {
* @internal
*/
@HostListener('click', ['$event'])
onClick(ev: Event) {
onClick(ev: Event): void {
const defaultHref = this.defaultHref || this.config.get('backButtonDefaultHref');
if (this.routerOutlet && this.routerOutlet.canGoBack()) {
if (this.routerOutlet?.canGoBack()) {
this.navCtrl.setDirection('back', undefined, undefined, this.routerAnimation);
this.routerOutlet.pop();
ev.preventDefault();

View File

@@ -1,11 +1,26 @@
import { Location } from '@angular/common';
import { Attribute, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, EventEmitter, Injector, NgZone, OnDestroy, OnInit, Optional, Output, SkipSelf, ViewContainerRef } from '@angular/core';
import { ActivatedRoute, ChildrenOutletContexts, OutletContext, PRIMARY_OUTLET, Router } from '@angular/router';
import {
ComponentFactoryResolver,
ComponentRef,
ElementRef,
Injector,
NgZone,
OnDestroy,
OnInit,
ViewContainerRef,
Attribute,
Directive,
EventEmitter,
Optional,
Output,
SkipSelf,
} from '@angular/core';
import { OutletContext, Router, ActivatedRoute, ChildrenOutletContexts, PRIMARY_OUTLET } from '@angular/router';
import { componentOnReady } from '@ionic/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { Observable, BehaviorSubject } from 'rxjs';
import { distinctUntilChanged, filter, switchMap } from 'rxjs/operators';
import { AnimationBuilder } from '../../';
import { AnimationBuilder } from '../../ionic-core';
import { Config } from '../../providers/config';
import { NavController } from '../../providers/nav-controller';
@@ -15,8 +30,10 @@ import { RouteView, getUrl } from './stack-utils';
@Directive({
selector: 'ion-router-outlet',
exportAs: 'outlet',
inputs: ['animated', 'animation', 'swipeGesture']
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
inputs: ['animated', 'animation', 'swipeGesture'],
})
// eslint-disable-next-line @angular-eslint/directive-class-suffix
export class IonRouterOutlet implements OnDestroy, OnInit {
nativeEl: HTMLIonRouterOutletElement;
@@ -37,7 +54,9 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
tabsPrefix: string | undefined;
@Output() stackEvents = new EventEmitter<any>();
// eslint-disable-next-line @angular-eslint/no-output-rename
@Output('activate') activateEvents = new EventEmitter<any>();
// eslint-disable-next-line @angular-eslint/no-output-rename
@Output('deactivate') deactivateEvents = new EventEmitter<any>();
set animation(animation: AnimationBuilder) {
@@ -51,11 +70,13 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
set swipeGesture(swipe: boolean) {
this._swipeGesture = swipe;
this.nativeEl.swipeHandler = swipe ? {
canStart: () => this.stackCtrl.canGoBack(1) && !this.stackCtrl.hasRunningTask(),
onStart: () => this.stackCtrl.startBackTransition(),
onEnd: shouldContinue => this.stackCtrl.endBackTransition(shouldContinue)
} : undefined;
this.nativeEl.swipeHandler = swipe
? {
canStart: () => this.stackCtrl.canGoBack(1) && !this.stackCtrl.hasRunningTask(),
onStart: () => this.stackCtrl.startBackTransition(),
onEnd: (shouldContinue) => this.stackCtrl.endBackTransition(shouldContinue),
}
: undefined;
}
constructor(
@@ -93,12 +114,12 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
// If the outlet was not instantiated at the time the route got activated we need to populate
// the outlet when it is initialized (ie inside a NgIf)
const context = this.getContext();
if (context && context.route) {
if (context?.route) {
this.activateWith(context.route, context.resolver || null);
}
}
new Promise(resolve => componentOnReady(this.nativeEl, resolve)).then(() => {
new Promise((resolve) => componentOnReady(this.nativeEl, resolve)).then(() => {
if (this._swipeGesture === undefined) {
this.swipeGesture = this.config.getBoolean('swipeBackEnabled', (this.nativeEl as any).mode === 'ios');
}
@@ -109,7 +130,7 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
return !!this.activated;
}
get component(): object {
get component(): Record<string, unknown> {
if (!this.activated) {
throw new Error('Outlet is not activated');
}
@@ -140,13 +161,15 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
/**
* Called when the `RouteReuseStrategy` instructs to re-attach a previously detached subtree
*/
attach(_ref: ComponentRef<any>, _activatedRoute: ActivatedRoute) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
attach(_ref: ComponentRef<any>, _activatedRoute: ActivatedRoute): void {
throw new Error('incompatible reuse strategy');
}
deactivate(): void {
if (this.activated) {
if (this.activatedView) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const context = this.getContext()!;
this.activatedView.savedData = new Map(context.children['contexts']);
@@ -172,7 +195,7 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
const contextSnapshot = context.route.snapshot;
this.activatedView.savedExtras.queryParams = contextSnapshot.queryParams;
this.activatedView.savedExtras.fragment = contextSnapshot.fragment;
(this.activatedView.savedExtras.fragment as string | null) = contextSnapshot.fragment;
}
}
const c = this.component;
@@ -183,7 +206,7 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
}
}
activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver | null) {
activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver | null): void {
if (this.isActivated) {
throw new Error('Cannot activate an already activated outlet');
}
@@ -196,6 +219,7 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
const saved = enteringView.savedData;
if (saved) {
// self-restore
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const context = this.getContext()!;
context.children['contexts'] = saved;
}
@@ -203,6 +227,7 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
this.updateActivatedRouteProxy(cmpRef.instance, activatedRoute);
} else {
const snapshot = (activatedRoute as any)._futureSnapshot;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const component = snapshot.routeConfig!.component as any;
resolver = resolver || this.resolver;
@@ -230,7 +255,7 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
}
this.activatedView = enteringView;
this.stackCtrl.setActive(enteringView).then(data => {
this.stackCtrl.setActive(enteringView).then((data) => {
this.navCtrl.setTopOutlet(this);
this.activateEvents.emit(cmpRef.instance);
this.stackEvents.emit(data);
@@ -313,11 +338,11 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
private proxyObservable(component$: Observable<any>, path: string): Observable<any> {
return component$.pipe(
// First wait until the component instance is pushed
filter(component => !!component),
switchMap(component =>
filter((component) => !!component),
switchMap((component) =>
this.currentActivatedRoute$.pipe(
filter(current => current !== null && current.component === component),
switchMap(current => current && (current.activatedRoute as any)[path]),
filter((current) => current !== null && current.component === component),
switchMap((current) => current && (current.activatedRoute as any)[path]),
distinctUntilChanged()
)
)
@@ -344,11 +369,7 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
}
class OutletInjector implements Injector {
constructor(
private route: ActivatedRoute,
private childContexts: ChildrenOutletContexts,
private parent: Injector
) { }
constructor(private route: ActivatedRoute, private childContexts: ChildrenOutletContexts, private parent: Injector) {}
get(token: any, notFoundValue?: any): any {
if (token === ActivatedRoute) {
@@ -359,7 +380,6 @@ class OutletInjector implements Injector {
return this.childContexts;
}
// tslint:disable-next-line
return this.parent.get(token, notFoundValue);
}
}

View File

@@ -8,54 +8,53 @@ import { StackEvent } from './stack-utils';
@Component({
selector: 'ion-tabs',
template: `
<ng-content select="[slot=top]"></ng-content>
template: ` <ng-content select="[slot=top]"></ng-content>
<div class="tabs-inner">
<ion-router-outlet #outlet tabs="true" (stackEvents)="onPageSelected($event)"></ion-router-outlet>
</div>
<ng-content></ng-content>`,
styles: [`
:host {
display: flex;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
styles: [
`
:host {
display: flex;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
flex-direction: column;
flex-direction: column;
width: 100%;
height: 100%;
width: 100%;
height: 100%;
contain: layout size style;
z-index: $z-index-page-container;
}
.tabs-inner {
position: relative;
contain: layout size style;
z-index: $z-index-page-container;
}
.tabs-inner {
position: relative;
flex: 1;
flex: 1;
contain: layout size style;
}`
]
contain: layout size style;
}
`,
],
})
// eslint-disable-next-line @angular-eslint/component-class-suffix
export class IonTabs {
@ViewChild('outlet', { read: IonRouterOutlet, static: false }) outlet: IonRouterOutlet;
@ContentChild(IonTabBar, { static: false }) tabBar: IonTabBar | undefined;
@Output() ionTabsWillChange = new EventEmitter<{ tab: string }>();
@Output() ionTabsDidChange = new EventEmitter<{ tab: string }>();
constructor(
private navCtrl: NavController,
) { }
constructor(private navCtrl: NavController) {}
/**
* @internal
*/
onPageSelected(detail: StackEvent) {
onPageSelected(detail: StackEvent): void {
const stackId = detail.enteringView.stackId;
if (detail.tabSwitch && stackId !== undefined) {
if (this.tabBar) {
@@ -87,9 +86,9 @@ export class IonTabs {
* to the default tabRootUrl
*/
@HostListener('ionTabButtonClick', ['$event'])
select(tabOrEvent: string | CustomEvent) {
select(tabOrEvent: string | CustomEvent): Promise<boolean> | undefined {
const isTabString = typeof tabOrEvent === 'string';
const tab = (isTabString) ? tabOrEvent : (tabOrEvent as CustomEvent).detail.tab;
const tab = isTabString ? tabOrEvent : (tabOrEvent as CustomEvent).detail.tab;
const alreadySelected = this.outlet.getActiveStackId() === tab;
const tabRootUrl = `${this.outlet.tabsPrefix}/${tab}`;
@@ -108,12 +107,14 @@ export class IonTabs {
const activeView = this.outlet.getLastRouteView(activeStackId);
// If on root tab, do not navigate to root tab again
if (activeView.url === tabRootUrl) { return; }
if (activeView?.url === tabRootUrl) {
return;
}
const rootView = this.outlet.getRootView(tab);
const navigationExtras = rootView && tabRootUrl === rootView.url && rootView.savedExtras;
return this.navCtrl.navigateRoot(tabRootUrl, {
...(navigationExtras),
...navigationExtras,
animated: true,
animationDirection: 'back',
});
@@ -123,11 +124,11 @@ export class IonTabs {
* If there is a lastRoute, goto that, otherwise goto the fallback url of the
* selected tab
*/
const url = lastRoute && lastRoute.url || tabRootUrl;
const navigationExtras = lastRoute && lastRoute.savedExtras;
const url = lastRoute?.url || tabRootUrl;
const navigationExtras = lastRoute?.savedExtras;
return this.navCtrl.navigateRoot(url, {
...(navigationExtras),
...navigationExtras,
animated: true,
animationDirection: 'back',
});

View File

@@ -1,15 +1,30 @@
import { ComponentFactoryResolver, Directive, ElementRef, Injector, ViewContainerRef } from '@angular/core';
import { ComponentFactoryResolver, ElementRef, Injector, ViewContainerRef, Directive } from '@angular/core';
import { AngularDelegate } from '../../providers/angular-delegate';
import { ProxyCmp, proxyOutputs } from '../proxies-utils';
import { ProxyCmp, proxyOutputs } from '../angular-component-lib/utils';
@ProxyCmp({
inputs: ['animated', 'animation', 'root', 'rootParams', 'swipeGesture'],
methods: ['push', 'insert', 'insertPages', 'pop', 'popTo', 'popToRoot', 'removeIndex', 'setRoot', 'setPages', 'getActive', 'getByIndex', 'canGoBack', 'getPrevious']
methods: [
'push',
'insert',
'insertPages',
'pop',
'popTo',
'popToRoot',
'removeIndex',
'setRoot',
'setPages',
'getActive',
'getByIndex',
'canGoBack',
'getPrevious',
],
})
@Directive({
selector: 'ion-nav'
selector: 'ion-nav',
})
// eslint-disable-next-line @angular-eslint/directive-class-suffix
export class NavDelegate {
protected el: HTMLElement;
constructor(
@@ -21,6 +36,6 @@ export class NavDelegate {
) {
this.el = ref.nativeElement;
ref.nativeElement.delegate = angularDelegate.create(resolver, injector, location);
proxyOutputs(this, this.el, ['ionNavDidChange' , 'ionNavWillChange' ]);
proxyOutputs(this, this.el, ['ionNavDidChange', 'ionNavWillChange']);
}
}

View File

@@ -19,8 +19,7 @@
* ```
*/
export class NavParams {
constructor(public data: {[key: string]: any} = {}) {}
constructor(public data: { [key: string]: any } = {}) {}
/**
* Get the value of a nav-parameter for the current view

View File

@@ -1,5 +1,5 @@
import { LocationStrategy } from '@angular/common';
import { Directive, ElementRef, HostListener, Optional } from '@angular/core';
import { ElementRef, OnChanges, OnDestroy, OnInit, Directive, HostListener, Input, Optional } from '@angular/core';
import { Router, RouterLink } from '@angular/router';
import { AnimationBuilder, RouterDirection } from '@ionic/core';
import { Subscription } from 'rxjs';
@@ -8,13 +8,14 @@ import { NavController } from '../../providers/nav-controller';
@Directive({
selector: '[routerLink]',
inputs: ['routerDirection', 'routerAnimation']
})
export class RouterLinkDelegate {
export class RouterLinkDelegateDirective implements OnInit, OnChanges, OnDestroy {
private subscription?: Subscription;
@Input()
routerDirection: RouterDirection = 'forward';
@Input()
routerAnimation?: AnimationBuilder;
constructor(
@@ -22,18 +23,18 @@ export class RouterLinkDelegate {
private navCtrl: NavController,
private elementRef: ElementRef,
private router: Router,
@Optional() private routerLink?: RouterLink,
) { }
@Optional() private routerLink?: RouterLink
) {}
ngOnInit() {
ngOnInit(): void {
this.updateTargetUrlAndHref();
}
ngOnChanges(): any {
ngOnChanges(): void {
this.updateTargetUrlAndHref();
}
ngOnDestroy(): any {
ngOnDestroy(): void {
if (this.subscription) {
this.subscription.unsubscribe();
}
@@ -50,7 +51,7 @@ export class RouterLinkDelegate {
* @internal
*/
@HostListener('click', ['$event'])
onClick(ev: UIEvent) {
onClick(ev: UIEvent): void {
this.navCtrl.setDirection(this.routerDirection, undefined, undefined, this.routerAnimation);
ev.preventDefault();
}

View File

@@ -6,10 +6,18 @@ import { AnimationBuilder, RouterDirection } from '@ionic/core';
import { bindLifecycleEvents } from '../../providers/angular-delegate';
import { NavController } from '../../providers/nav-controller';
import { RouteView, StackEvent, computeStackId, destroyView, getUrl, insertView, isTabSwitch, toSegments } from './stack-utils';
import {
RouteView,
StackEvent,
computeStackId,
destroyView,
getUrl,
insertView,
isTabSwitch,
toSegments,
} from './stack-utils';
export class StackController {
private views: RouteView[] = [];
private runningTask?: Promise<any>;
private skipTransition = false;
@@ -30,7 +38,7 @@ export class StackController {
createView(ref: ComponentRef<any>, activatedRoute: ActivatedRoute): RouteView {
const url = getUrl(this.router, activatedRoute);
const element = (ref && ref.location && ref.location.nativeElement) as HTMLElement;
const element = ref?.location?.nativeElement as HTMLElement;
const unlistenEvents = bindLifecycleEvents(this.zone, ref.instance, element);
return {
id: this.nextId++,
@@ -44,7 +52,7 @@ export class StackController {
getExistingView(activatedRoute: ActivatedRoute): RouteView | undefined {
const activatedUrlKey = getUrl(this.router, activatedRoute);
const view = this.views.find(vw => vw.url === activatedUrlKey);
const view = this.views.find((vw) => vw.url === activatedUrlKey);
if (view) {
view.ref.changeDetectorRef.reattach();
}
@@ -65,17 +73,14 @@ export class StackController {
let currentNavigation;
const router = (this.router as any);
const router = this.router as any;
// Angular >= 7.2.0
if (router.getCurrentNavigation) {
currentNavigation = router.getCurrentNavigation();
// Angular < 7.2.0
} else if (
router.navigations &&
router.navigations.value
) {
} else if (router.navigations?.value) {
currentNavigation = router.navigations.value;
}
@@ -86,11 +91,7 @@ export class StackController {
* we remove the last item
* from our views stack
*/
if (
currentNavigation &&
currentNavigation.extras &&
currentNavigation.extras.replaceUrl
) {
if (currentNavigation?.extras?.replaceUrl) {
if (this.views.length > 0) {
this.views.splice(-1, 1);
}
@@ -114,12 +115,7 @@ export class StackController {
* provided another animation.
*/
const customAnimation = enteringView.animationBuilder;
if (
animationBuilder === undefined &&
direction === 'back' &&
!tabSwitch &&
customAnimation !== undefined
) {
if (animationBuilder === undefined && direction === 'back' && !tabSwitch && customAnimation !== undefined) {
animationBuilder = customAnimation;
}
@@ -148,7 +144,7 @@ export class StackController {
enteringView,
direction,
animation,
tabSwitch
tabSwitch,
}));
});
});
@@ -158,7 +154,7 @@ export class StackController {
return this.getStack(stackId).length > deep;
}
pop(deep: number, stackId = this.getActiveStackId()) {
pop(deep: number, stackId = this.getActiveStackId()): Promise<boolean> {
return this.zone.run(() => {
const views = this.getStack(stackId);
if (views.length <= deep) {
@@ -170,13 +166,7 @@ export class StackController {
const viewSavedData = view.savedData;
if (viewSavedData) {
const primaryOutlet = viewSavedData.get('primary');
if (
primaryOutlet &&
primaryOutlet.route &&
primaryOutlet.route._routerState &&
primaryOutlet.route._routerState.snapshot &&
primaryOutlet.route._routerState.snapshot.url
) {
if (primaryOutlet?.route?._routerState?.snapshot.url) {
url = primaryOutlet.route._routerState.snapshot.url;
}
}
@@ -185,7 +175,7 @@ export class StackController {
});
}
startBackTransition() {
startBackTransition(): Promise<boolean> | Promise<void> {
const leavingView = this.activeView;
if (leavingView) {
const views = this.getStack(leavingView.stackId);
@@ -206,7 +196,7 @@ export class StackController {
return Promise.resolve();
}
endBackTransition(shouldComplete: boolean) {
endBackTransition(shouldComplete: boolean): void {
if (shouldComplete) {
this.skipTransition = true;
this.pop(1);
@@ -215,7 +205,7 @@ export class StackController {
}
}
getLastUrl(stackId?: string) {
getLastUrl(stackId?: string): RouteView | undefined {
const views = this.getStack(stackId);
return views.length > 0 ? views[views.length - 1] : undefined;
}
@@ -223,7 +213,7 @@ export class StackController {
/**
* @internal
*/
getRootUrl(stackId?: string) {
getRootUrl(stackId?: string): RouteView | undefined {
const views = this.getStack(stackId);
return views.length > 0 ? views[0] : undefined;
}
@@ -236,7 +226,8 @@ export class StackController {
return this.runningTask !== undefined;
}
destroy() {
destroy(): void {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.containerEl = undefined!;
this.views.forEach(destroyView);
this.activeView = undefined;
@@ -244,7 +235,7 @@ export class StackController {
}
private getStack(stackId: string | undefined) {
return this.views.filter(v => v.stackId === stackId);
return this.views.filter((v) => v.stackId === stackId);
}
private insertView(enteringView: RouteView, direction: RouterDirection) {
@@ -285,7 +276,7 @@ export class StackController {
direction,
showGoBack,
progressAnimation,
animationBuilder
animationBuilder,
});
}
}
@@ -297,15 +288,15 @@ export class StackController {
await this.runningTask;
this.runningTask = undefined;
}
const promise = this.runningTask = task();
promise.finally(() => this.runningTask = undefined);
const promise = (this.runningTask = task());
promise.finally(() => (this.runningTask = undefined));
return promise;
}
}
const cleanupAsync = (activeRoute: RouteView, views: RouteView[], viewsSnapshot: RouteView[], location: Location) => {
if (typeof (requestAnimationFrame as any) === 'function') {
return new Promise<void>(resolve => {
return new Promise<void>((resolve) => {
requestAnimationFrame(() => {
cleanup(activeRoute, views, viewsSnapshot, location);
resolve();
@@ -316,11 +307,9 @@ const cleanupAsync = (activeRoute: RouteView, views: RouteView[], viewsSnapshot:
};
const cleanup = (activeRoute: RouteView, views: RouteView[], viewsSnapshot: RouteView[], location: Location) => {
viewsSnapshot
.filter(view => !views.includes(view))
.forEach(destroyView);
viewsSnapshot.filter((view) => !views.includes(view)).forEach(destroyView);
views.forEach(view => {
views.forEach((view) => {
/**
* In the event that a user navigated multiple
* times in rapid succession, we want to make sure

View File

@@ -2,7 +2,7 @@ import { ComponentRef } from '@angular/core';
import { ActivatedRoute, NavigationExtras, Router } from '@angular/router';
import { AnimationBuilder, NavDirection, RouterDirection } from '@ionic/core';
export const insertView = (views: RouteView[], view: RouteView, direction: RouterDirection) => {
export const insertView = (views: RouteView[], view: RouteView, direction: RouterDirection): RouteView[] => {
if (direction === 'root') {
return setRoot(views, view);
} else if (direction === 'forward') {
@@ -13,7 +13,7 @@ export const insertView = (views: RouteView[], view: RouteView, direction: Route
};
const setRoot = (views: RouteView[], view: RouteView) => {
views = views.filter(v => v.stackId !== view.stackId);
views = views.filter((v) => v.stackId !== view.stackId);
views.push(view);
return views;
};
@@ -21,7 +21,7 @@ const setRoot = (views: RouteView[], view: RouteView) => {
const setForward = (views: RouteView[], view: RouteView) => {
const index = views.indexOf(view);
if (index >= 0) {
views = views.filter(v => v.stackId !== view.stackId || v.id <= view.id);
views = views.filter((v) => v.stackId !== view.stackId || v.id <= view.id);
} else {
views.push(view);
}
@@ -31,25 +31,25 @@ const setForward = (views: RouteView[], view: RouteView) => {
const setBack = (views: RouteView[], view: RouteView) => {
const index = views.indexOf(view);
if (index >= 0) {
return views.filter(v => v.stackId !== view.stackId || v.id <= view.id);
return views.filter((v) => v.stackId !== view.stackId || v.id <= view.id);
} else {
return setRoot(views, view);
}
};
export const getUrl = (router: Router, activatedRoute: ActivatedRoute) => {
export const getUrl = (router: Router, activatedRoute: ActivatedRoute): string => {
const urlTree = router.createUrlTree(['.'], { relativeTo: activatedRoute });
return router.serializeUrl(urlTree);
};
export const isTabSwitch = (enteringView: RouteView, leavingView: RouteView | undefined) => {
export const isTabSwitch = (enteringView: RouteView, leavingView: RouteView | undefined): boolean => {
if (!leavingView) {
return true;
}
return enteringView.stackId !== leavingView.stackId;
};
export const computeStackId = (prefixUrl: string[] | undefined, url: string) => {
export const computeStackId = (prefixUrl: string[] | undefined, url: string): string | undefined => {
if (!prefixUrl) {
return undefined;
}
@@ -65,14 +65,14 @@ export const computeStackId = (prefixUrl: string[] | undefined, url: string) =>
return undefined;
};
export const toSegments = (path: string) => {
export const toSegments = (path: string): string[] => {
return path
.split('/')
.map(s => s.trim())
.filter(s => s !== '');
.map((s) => s.trim())
.filter((s) => s !== '');
};
export const destroyView = (view: RouteView | undefined) => {
export const destroyView = (view: RouteView | undefined): void => {
if (view) {
// TODO lifecycle event
view.ref.destroy();

View File

@@ -0,0 +1,128 @@
/* eslint-disable */
/* tslint:disable */
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ContentChild,
ElementRef,
EventEmitter,
NgZone,
TemplateRef,
} from '@angular/core';
import { ProxyCmp, proxyOutputs } from '../angular-component-lib/utils';
import { Components } from '@ionic/core';
export declare interface IonModal extends Components.IonModal {
/**
* Emitted after the modal has presented.
**/
ionModalDidPresent: EventEmitter<CustomEvent>;
/**
* Emitted before the modal has presented.
*/
ionModalWillPresent: EventEmitter<CustomEvent>;
/**
* Emitted before the modal has dismissed.
*/
ionModalWillDismiss: EventEmitter<CustomEvent>;
/**
* Emitted after the modal has dismissed.
*/
ionModalDidDismiss: EventEmitter<CustomEvent>;
/**
* Emitted after the modal has presented. Shorthand for ionModalWillDismiss.
*/
didPresent: EventEmitter<CustomEvent>;
/**
* Emitted before the modal has presented. Shorthand for ionModalWillPresent.
*/
willPresent: EventEmitter<CustomEvent>;
/**
* Emitted before the modal has dismissed. Shorthand for ionModalWillDismiss.
*/
willDismiss: EventEmitter<CustomEvent>;
/**
* Emitted after the modal has dismissed. Shorthand for ionModalDidDismiss.
*/
didDismiss: EventEmitter<CustomEvent>;
}
@ProxyCmp({
inputs: [
'animated',
'backdropBreakpoint',
'backdropDismiss',
'breakpoints',
'cssClass',
'enterAnimation',
'event',
'handle',
'initialBreakpoint',
'isOpen',
'keyboardClose',
'leaveAnimation',
'mode',
'presentingElement',
'showBackdrop',
'swipeToClose',
'translucent',
'trigger',
],
methods: ['present', 'dismiss', 'onDidDismiss', 'onWillDismiss'],
})
@Component({
selector: 'ion-modal',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `<ng-container [ngTemplateOutlet]="template" *ngIf="isCmpOpen"></ng-container>`,
inputs: [
'animated',
'backdropBreakpoint',
'backdropDismiss',
'breakpoints',
'cssClass',
'enterAnimation',
'event',
'handle',
'initialBreakpoint',
'isOpen',
'keyboardClose',
'leaveAnimation',
'mode',
'presentingElement',
'showBackdrop',
'swipeToClose',
'translucent',
'trigger',
],
})
export class IonModal {
@ContentChild(TemplateRef, { static: false }) template: TemplateRef<any>;
isCmpOpen: boolean = false;
protected el: HTMLElement;
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
this.el = r.nativeElement;
this.el.addEventListener('willPresent', () => {
this.isCmpOpen = true;
c.detectChanges();
});
this.el.addEventListener('didDismiss', () => {
this.isCmpOpen = false;
c.detectChanges();
});
proxyOutputs(this, this.el, [
'ionModalDidPresent',
'ionModalWillPresent',
'ionModalWillDismiss',
'ionModalDidDismiss',
'didPresent',
'willPresent',
'willDismiss',
'didDismiss',
]);
}
}

View File

@@ -0,0 +1,128 @@
/* eslint-disable */
/* tslint:disable */
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ContentChild,
ElementRef,
EventEmitter,
NgZone,
TemplateRef,
} from '@angular/core';
import { ProxyCmp, proxyOutputs } from '../angular-component-lib/utils';
import { Components } from '@ionic/core';
export declare interface IonPopover extends Components.IonPopover {
/**
* Emitted after the popover has presented.
*/
ionPopoverDidPresent: EventEmitter<CustomEvent>;
/**
* Emitted before the popover has presented.
*/
ionPopoverWillPresent: EventEmitter<CustomEvent>;
/**
* Emitted after the popover has dismissed.
*/
ionPopoverWillDismiss: EventEmitter<CustomEvent>;
/**
* Emitted after the popover has dismissed.
*/
ionPopoverDidDismiss: EventEmitter<CustomEvent>;
/**
* Emitted after the popover has presented. Shorthand for ionPopoverWillDismiss.
*/
didPresent: EventEmitter<CustomEvent>;
/**
* Emitted before the popover has presented. Shorthand for ionPopoverWillPresent.
*/
willPresent: EventEmitter<CustomEvent>;
/**
* Emitted after the popover has presented. Shorthand for ionPopoverWillDismiss.
*/
willDismiss: EventEmitter<CustomEvent>;
/**
* Emitted after the popover has dismissed. Shorthand for ionPopoverDidDismiss.
*/
didDismiss: EventEmitter<CustomEvent>;
}
@ProxyCmp({
inputs: [
'alignment',
'animated',
'arrow',
'backdropDismiss',
'cssClass',
'dismissOnSelect',
'enterAnimation',
'event',
'isOpen',
'keyboardClose',
'leaveAnimation',
'mode',
'showBackdrop',
'translucent',
'trigger',
'triggerAction',
'reference',
'size',
'side',
],
methods: ['present', 'dismiss', 'onDidDismiss', 'onWillDismiss'],
})
@Component({
selector: 'ion-popover',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `<ng-container [ngTemplateOutlet]="template" *ngIf="isCmpOpen"></ng-container>`,
inputs: [
'alignment',
'animated',
'arrow',
'backdropDismiss',
'cssClass',
'dismissOnSelect',
'enterAnimation',
'event',
'isOpen',
'keyboardClose',
'leaveAnimation',
'mode',
'showBackdrop',
'translucent',
'trigger',
'triggerAction',
'reference',
'size',
'side',
],
})
export class IonPopover {
@ContentChild(TemplateRef, { static: false }) template: TemplateRef<any>;
isCmpOpen: boolean = false;
protected el: HTMLElement;
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
this.el = r.nativeElement;
this.el.addEventListener('willPresent', () => {
this.isCmpOpen = true;
c.detectChanges();
});
this.el.addEventListener('didDismiss', () => {
this.isCmpOpen = false;
c.detectChanges();
});
proxyOutputs(this, this.el, [
'ionPopoverDidPresent',
'ionPopoverWillPresent',
'ionPopoverWillDismiss',
'ionPopoverDidDismiss',
'didPresent',
'willPresent',
'willDismiss',
'didDismiss',
]);
}
}

View File

@@ -1,12 +1,16 @@
import type * as d from './proxies';
import * as d from './proxies';
export const DIRECTIVES = [
d.IonAccordion,
d.IonAccordionGroup,
d.IonApp,
d.IonAvatar,
d.IonBackButton,
d.IonBackdrop,
d.IonBadge,
d.IonBreadcrumb,
d.IonBreadcrumbs,
d.IonButton,
d.IonButtons,
d.IonCard,

View File

@@ -1,46 +0,0 @@
/* eslint-disable */
/* tslint:disable */
import { fromEvent } from 'rxjs';
export const proxyInputs = (Cmp: any, inputs: string[]) => {
const Prototype = Cmp.prototype;
inputs.forEach(item => {
Object.defineProperty(Prototype, item, {
get() {
return this.el[item];
},
set(val: any) {
this.z.runOutsideAngular(() => (this.el[item] = val));
}
});
});
};
export const proxyMethods = (Cmp: any, methods: string[]) => {
const Prototype = Cmp.prototype;
methods.forEach(methodName => {
Prototype[methodName] = function () {
const args = arguments;
return this.z.runOutsideAngular(() =>
this.el[methodName].apply(this.el, args)
);
};
});
};
export const proxyOutputs = (instance: any, el: any, events: string[]) => {
events.forEach(eventName => instance[eventName] = fromEvent(el, eventName));
}
export function ProxyCmp(opts: { inputs?: any; methods?: any }) {
const decorator = function(cls: any){
if (opts.inputs) {
proxyInputs(cls, opts.inputs);
}
if (opts.methods) {
proxyMethods(cls, opts.methods);
}
return cls;
};
return decorator;
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
import { ChangeDetectionStrategy, Component, ContentChild, ElementRef, EmbeddedViewRef, IterableDiffer, IterableDiffers, NgZone, SimpleChanges, TrackByFunction } from '@angular/core';
import { Cell, CellType, FooterHeightFn, HeaderFn, HeaderHeightFn, ItemHeightFn } from '@ionic/core';
import { ProxyCmp } from '../proxies-utils';
import { ProxyCmp } from '../angular-component-lib/utils';
import { VirtualFooter } from './virtual-footer';
import { VirtualHeader } from './virtual-header';
@@ -205,8 +205,8 @@ export class IonVirtualScroll {
case 'item': return this.itmTmp.templateRef;
case 'header': return this.hdrTmp.templateRef;
case 'footer': return this.ftrTmp.templateRef;
default: throw new Error('template for virtual item was not provided');
}
throw new Error('template for virtual item was not provided');
}
}

View File

@@ -1,19 +1,21 @@
// DIRECTIVES
export { BooleanValueAccessor } from './directives/control-value-accessors/boolean-value-accessor';
export { NumericValueAccessor } from './directives/control-value-accessors/numeric-value-accesssor';
export { RadioValueAccessor } from './directives/control-value-accessors/radio-value-accessor';
export { SelectValueAccessor } from './directives/control-value-accessors/select-value-accessor';
export { TextValueAccessor } from './directives/control-value-accessors/text-value-accessor';
export { BooleanValueAccessorDirective as BooleanValueAccessor } from './directives/control-value-accessors/boolean-value-accessor';
export { NumericValueAccessorDirective as NumericValueAccessor } from './directives/control-value-accessors/numeric-value-accesssor';
export { RadioValueAccessorDirective as RadioValueAccessor } from './directives/control-value-accessors/radio-value-accessor';
export { SelectValueAccessorDirective as SelectValueAccessor } from './directives/control-value-accessors/select-value-accessor';
export { TextValueAccessorDirective as TextValueAccessor } from './directives/control-value-accessors/text-value-accessor';
export { IonTabs } from './directives/navigation/ion-tabs';
export { IonBackButtonDelegate } from './directives/navigation/ion-back-button';
export { IonBackButtonDelegateDirective as IonBackButtonDelegate } from './directives/navigation/ion-back-button';
export { NavDelegate } from './directives/navigation/nav-delegate';
export { IonRouterOutlet } from './directives/navigation/ion-router-outlet';
export { RouterLinkDelegate } from './directives/navigation/router-link-delegate';
export { RouterLinkDelegateDirective as RouterLinkDelegate } from './directives/navigation/router-link-delegate';
export { NavParams } from './directives/navigation/nav-params';
export { IonVirtualScroll } from './directives/virtual-scroll/virtual-scroll';
export { VirtualItem } from './directives/virtual-scroll/virtual-item';
export { VirtualHeader } from './directives/virtual-scroll/virtual-header';
export { VirtualFooter } from './directives/virtual-scroll/virtual-footer';
export { IonModal } from './directives/overlays/modal';
export { IonPopover } from './directives/overlays/popover';
export * from './directives/proxies';
// PROVIDERS
@@ -42,11 +44,18 @@ export * from './types/ionic-lifecycle-hooks';
// PACKAGE MODULE
export { IonicModule } from './ionic-module';
// UTILS
export { IonicSafeString, getPlatforms, isPlatform, createAnimation, IonicSwiper, IonicSlides } from '@ionic/core';
// CORE TYPES
export {
// UTILS
createAnimation,
createGesture,
iosTransitionAnimation,
mdTransitionAnimation,
IonicSwiper,
IonicSlides,
getPlatforms,
isPlatform,
getTimeGivenProgression,
// TYPES
Animation,
AnimationBuilder,
AnimationCallbackOptions,
@@ -57,33 +66,62 @@ export {
Gesture,
GestureConfig,
GestureDetail,
mdTransitionAnimation,
iosTransitionAnimation,
NavComponentWithProps,
SpinnerTypes,
AccordionGroupCustomEvent,
AccordionGroupChangeEventDetail,
BreadcrumbCustomEvent,
BreadcrumbCollapsedClickEventDetail,
ActionSheetOptions,
ActionSheetButton,
AlertOptions,
AlertInput,
AlertTextareaAttributes,
AlertInputAttributes,
AlertButton,
BackButtonEvent,
CheckboxCustomEvent,
CheckboxChangeEventDetail,
DatetimeCustomEvent,
DatetimeChangeEventDetail,
InfiniteScrollCustomEvent,
InputCustomEvent,
InputChangeEventDetail,
ItemReorderEventDetail,
ItemReorderCustomEvent,
ItemSlidingCustomEvent,
IonicSafeString,
LoadingOptions,
MenuCustomEvent,
ModalOptions,
NavCustomEvent,
PickerOptions,
PickerButton,
PickerColumn,
PickerColumnOption,
PlatformConfig,
PopoverOptions,
RadioGroupCustomEvent,
RadioGroupChangeEventDetail,
RefresherCustomEvent,
RefresherEventDetail,
RouterEventDetail,
RouterCustomEvent,
ScrollBaseCustomEvent,
ScrollBaseDetail,
ScrollDetail,
ScrollCustomEvent,
SearchbarCustomEvent,
SearchbarChangeEventDetail,
SegmentChangeEventDetail,
SegmentCustomEvent,
SelectChangeEventDetail,
SelectCustomEvent,
TabsCustomEvent,
TextareaChangeEventDetail,
TextareaCustomEvent,
ToastOptions,
ToastButton
ToastButton,
ToggleChangeEventDetail,
ToggleCustomEvent,
} from '@ionic/core';

21
angular/src/ionic-core.ts Normal file
View File

@@ -0,0 +1,21 @@
// Re-exports from ionic/core
// UTILS
export { IonicSafeString, getPlatforms, isPlatform, createAnimation } from '@ionic/core';
// CORE TYPES
export {
Animation,
AnimationBuilder,
AnimationCallbackOptions,
AnimationDirection,
AnimationFill,
AnimationKeyFrames,
AnimationLifecycle,
Gesture,
GestureConfig,
GestureDetail,
mdTransitionAnimation,
iosTransitionAnimation,
NavComponentWithProps,
} from '@ionic/core';

View File

@@ -1,35 +1,30 @@
import { CommonModule, DOCUMENT } from '@angular/common';
import { APP_INITIALIZER, ModuleWithProviders, NgModule, NgZone } from '@angular/core';
import { ModuleWithProviders, APP_INITIALIZER, NgModule, NgZone } from '@angular/core';
import { IonicConfig } from '@ionic/core';
import { appInitialize } from './app-initialize';
import { BooleanValueAccessor } from './directives/control-value-accessors/boolean-value-accessor';
import { NumericValueAccessor } from './directives/control-value-accessors/numeric-value-accesssor';
import { RadioValueAccessor } from './directives/control-value-accessors/radio-value-accessor';
import { SelectValueAccessor } from './directives/control-value-accessors/select-value-accessor';
import { TextValueAccessor } from './directives/control-value-accessors/text-value-accessor';
import { IonBackButtonDelegate } from './directives/navigation/ion-back-button';
import { BooleanValueAccessorDirective } from './directives/control-value-accessors/boolean-value-accessor';
import { NumericValueAccessorDirective } from './directives/control-value-accessors/numeric-value-accesssor';
import { RadioValueAccessorDirective } from './directives/control-value-accessors/radio-value-accessor';
import { SelectValueAccessorDirective } from './directives/control-value-accessors/select-value-accessor';
import { TextValueAccessorDirective } from './directives/control-value-accessors/text-value-accessor';
import { IonBackButtonDelegateDirective } from './directives/navigation/ion-back-button';
import { IonRouterOutlet } from './directives/navigation/ion-router-outlet';
import { IonTabs } from './directives/navigation/ion-tabs';
import { NavDelegate } from './directives/navigation/nav-delegate';
import { RouterLinkDelegate } from './directives/navigation/router-link-delegate';
import { IonApp, IonAvatar, IonBackButton, IonBackdrop, IonBadge, IonButton, IonButtons, IonCard, IonCardContent, IonCardHeader, IonCardSubtitle, IonCardTitle, IonCheckbox, IonChip, IonCol, IonContent, IonDatetime, IonFab, IonFabButton, IonFabList, IonFooter, IonGrid, IonHeader, IonIcon, IonImg, IonInfiniteScroll, IonInfiniteScrollContent, IonInput, IonItem, IonItemDivider, IonItemGroup, IonItemOption, IonItemOptions, IonItemSliding, IonLabel, IonList, IonListHeader, IonMenu, IonMenuButton, IonMenuToggle, IonNav, IonNavLink, IonNote, IonProgressBar, IonRadio, IonRadioGroup, IonRange, IonRefresher, IonRefresherContent, IonReorder, IonReorderGroup, IonRippleEffect, IonRow, IonSearchbar, IonSegment, IonSegmentButton, IonSelect, IonSelectOption, IonSkeletonText, IonSlide, IonSlides, IonSpinner, IonSplitPane, IonTabBar, IonTabButton, IonText, IonTextarea, IonThumbnail, IonTitle, IonToggle, IonToolbar } from './directives/proxies';
import { VirtualFooter } from './directives/virtual-scroll/virtual-footer';
import { VirtualHeader } from './directives/virtual-scroll/virtual-header';
import { VirtualItem } from './directives/virtual-scroll/virtual-item';
import { IonVirtualScroll } from './directives/virtual-scroll/virtual-scroll';
import { AngularDelegate } from './providers/angular-delegate';
import { ConfigToken } from './providers/config';
import { ModalController } from './providers/modal-controller';
import { PopoverController } from './providers/popover-controller';
const DECLARATIONS = [
// proxies
import { RouterLinkDelegateDirective } from './directives/navigation/router-link-delegate';
import { IonModal } from './directives/overlays/modal';
import { IonPopover } from './directives/overlays/popover';
import {
IonAccordion,
IonAccordionGroup,
IonApp,
IonAvatar,
IonBackButton,
IonBackdrop,
IonBadge,
IonBreadcrumb,
IonBreadcrumbs,
IonButton,
IonButtons,
IonCard,
@@ -93,6 +88,95 @@ const DECLARATIONS = [
IonText,
IonTextarea,
IonThumbnail,
IonTitle,
IonToggle,
IonToolbar,
} from './directives/proxies';
import { VirtualFooter } from './directives/virtual-scroll/virtual-footer';
import { VirtualHeader } from './directives/virtual-scroll/virtual-header';
import { VirtualItem } from './directives/virtual-scroll/virtual-item';
import { IonVirtualScroll } from './directives/virtual-scroll/virtual-scroll';
import { AngularDelegate } from './providers/angular-delegate';
import { ConfigToken } from './providers/config';
import { ModalController } from './providers/modal-controller';
import { PopoverController } from './providers/popover-controller';
const DECLARATIONS = [
// proxies
IonAccordion,
IonAccordionGroup,
IonApp,
IonAvatar,
IonBackButton,
IonBackdrop,
IonBadge,
IonBreadcrumb,
IonBreadcrumbs,
IonButton,
IonButtons,
IonCard,
IonCardContent,
IonCardHeader,
IonCardSubtitle,
IonCardTitle,
IonCheckbox,
IonChip,
IonCol,
IonContent,
IonDatetime,
IonFab,
IonFabButton,
IonFabList,
IonFooter,
IonGrid,
IonHeader,
IonIcon,
IonImg,
IonInfiniteScroll,
IonInfiniteScrollContent,
IonInput,
IonItem,
IonItemDivider,
IonItemGroup,
IonItemOption,
IonItemOptions,
IonItemSliding,
IonLabel,
IonList,
IonListHeader,
IonMenu,
IonMenuButton,
IonMenuToggle,
IonModal,
IonNav,
IonNavLink,
IonNote,
IonPopover,
IonProgressBar,
IonRadio,
IonRadioGroup,
IonRange,
IonRefresher,
IonRefresherContent,
IonReorder,
IonReorderGroup,
IonRippleEffect,
IonRow,
IonSearchbar,
IonSegment,
IonSegmentButton,
IonSelect,
IonSelectOption,
IonSkeletonText,
IonSlide,
IonSlides,
IonSpinner,
IonSplitPane,
IonTabBar,
IonTabButton,
IonText,
IonTextarea,
IonThumbnail,
IonToggle,
IonToolbar,
IonTitle,
@@ -100,30 +184,30 @@ const DECLARATIONS = [
IonTabs,
// ngModel accessors
BooleanValueAccessor,
NumericValueAccessor,
RadioValueAccessor,
SelectValueAccessor,
TextValueAccessor,
BooleanValueAccessorDirective,
NumericValueAccessorDirective,
RadioValueAccessorDirective,
SelectValueAccessorDirective,
TextValueAccessorDirective,
// navigation
IonRouterOutlet,
IonBackButtonDelegate,
IonBackButtonDelegateDirective,
NavDelegate,
RouterLinkDelegate,
RouterLinkDelegateDirective,
// virtual scroll
VirtualFooter,
VirtualHeader,
VirtualItem,
IonVirtualScroll
IonVirtualScroll,
];
@NgModule({
declarations: DECLARATIONS,
exports: DECLARATIONS,
providers: [AngularDelegate, ModalController, PopoverController],
imports: [CommonModule]
imports: [CommonModule],
})
export class IonicModule {
static forRoot(config?: IonicConfig): ModuleWithProviders<IonicModule> {
@@ -132,19 +216,15 @@ export class IonicModule {
providers: [
{
provide: ConfigToken,
useValue: config
useValue: config,
},
{
provide: APP_INITIALIZER,
useFactory: appInitialize,
multi: true,
deps: [
ConfigToken,
DOCUMENT,
NgZone
]
}
]
deps: [ConfigToken, DOCUMENT, NgZone],
},
],
};
}
}

View File

@@ -1,27 +1,37 @@
import { ApplicationRef, ComponentFactoryResolver, Injectable, InjectionToken, Injector, NgZone, ViewContainerRef } from '@angular/core';
import { FrameworkDelegate, LIFECYCLE_DID_ENTER, LIFECYCLE_DID_LEAVE, LIFECYCLE_WILL_ENTER, LIFECYCLE_WILL_LEAVE, LIFECYCLE_WILL_UNLOAD } from '@ionic/core';
import {
ApplicationRef,
ComponentFactoryResolver,
NgZone,
ViewContainerRef,
Injectable,
InjectionToken,
Injector,
} from '@angular/core';
import {
FrameworkDelegate,
LIFECYCLE_DID_ENTER,
LIFECYCLE_DID_LEAVE,
LIFECYCLE_WILL_ENTER,
LIFECYCLE_WILL_LEAVE,
LIFECYCLE_WILL_UNLOAD,
} from '@ionic/core';
import { NavParams } from '../directives/navigation/nav-params';
@Injectable()
export class AngularDelegate {
constructor(
private zone: NgZone,
private appRef: ApplicationRef
) {}
constructor(private zone: NgZone, private appRef: ApplicationRef) {}
create(
resolver: ComponentFactoryResolver,
injector: Injector,
location?: ViewContainerRef,
) {
location?: ViewContainerRef
): AngularFrameworkDelegate {
return new AngularFrameworkDelegate(resolver, injector, location, this.appRef, this.zone);
}
}
export class AngularFrameworkDelegate implements FrameworkDelegate {
private elRefMap = new WeakMap<HTMLElement, any>();
private elEventsMap = new WeakMap<HTMLElement, () => void>();
@@ -30,16 +40,24 @@ export class AngularFrameworkDelegate implements FrameworkDelegate {
private injector: Injector,
private location: ViewContainerRef | undefined,
private appRef: ApplicationRef,
private zone: NgZone,
private zone: NgZone
) {}
attachViewToDom(container: any, component: any, params?: any, cssClasses?: string[]): Promise<any> {
return this.zone.run(() => {
return new Promise(resolve => {
return new Promise((resolve) => {
const el = attachView(
this.zone, this.resolver, this.injector, this.location, this.appRef,
this.elRefMap, this.elEventsMap,
container, component, params, cssClasses
this.zone,
this.resolver,
this.injector,
this.location,
this.appRef,
this.elRefMap,
this.elEventsMap,
container,
component,
params,
cssClasses
);
resolve(el);
});
@@ -48,7 +66,7 @@ export class AngularFrameworkDelegate implements FrameworkDelegate {
removeViewFromDom(_container: any, component: any): Promise<void> {
return this.zone.run(() => {
return new Promise(resolve => {
return new Promise((resolve) => {
const componentRef = this.elRefMap.get(component);
if (componentRef) {
componentRef.destroy();
@@ -73,14 +91,17 @@ export const attachView = (
appRef: ApplicationRef,
elRefMap: WeakMap<HTMLElement, any>,
elEventsMap: WeakMap<HTMLElement, () => void>,
container: any, component: any, params: any, cssClasses: string[] | undefined
) => {
container: any,
component: any,
params: any,
cssClasses: string[] | undefined
): any => {
const factory = resolver.resolveComponentFactory(component);
const childInjector = Injector.create({
providers: getProviders(params),
parent: injector
parent: injector,
});
const componentRef = (location)
const componentRef = location
? location.createComponent(factory, location.length, childInjector)
: factory.create(childInjector);
@@ -111,35 +132,36 @@ const LIFECYCLES = [
LIFECYCLE_DID_ENTER,
LIFECYCLE_WILL_LEAVE,
LIFECYCLE_DID_LEAVE,
LIFECYCLE_WILL_UNLOAD
LIFECYCLE_WILL_UNLOAD,
];
export const bindLifecycleEvents = (zone: NgZone, instance: any, element: HTMLElement) => {
export const bindLifecycleEvents = (zone: NgZone, instance: any, element: HTMLElement): (() => void) => {
return zone.run(() => {
const unregisters = LIFECYCLES
.filter(eventName => typeof instance[eventName] === 'function')
.map(eventName => {
const handler = (ev: any) => instance[eventName](ev.detail);
element.addEventListener(eventName, handler);
return () => element.removeEventListener(eventName, handler);
});
return () => unregisters.forEach(fn => fn());
const unregisters = LIFECYCLES.filter((eventName) => typeof instance[eventName] === 'function').map((eventName) => {
const handler = (ev: any) => instance[eventName](ev.detail);
element.addEventListener(eventName, handler);
return () => element.removeEventListener(eventName, handler);
});
return () => unregisters.forEach((fn) => fn());
});
};
const NavParamsToken = new InjectionToken<any>('NavParamsToken');
const getProviders = (params: {[key: string]: any}) => {
const getProviders = (params: { [key: string]: any }) => {
return [
{
provide: NavParamsToken, useValue: params
provide: NavParamsToken,
useValue: params,
},
{
provide: NavParams, useFactory: provideNavParamsInjectable, deps: [NavParamsToken]
}
provide: NavParams,
useFactory: provideNavParamsInjectable,
deps: [NavParamsToken],
},
];
};
const provideNavParamsInjectable = (params: {[key: string]: any}) => {
const provideNavParamsInjectable = (params: { [key: string]: any }) => {
return new NavParams(params);
};

View File

@@ -4,10 +4,9 @@ import { Config as CoreConfig, IonicConfig } from '@ionic/core';
import { IonicWindow } from '../types/interfaces';
@Injectable({
providedIn: 'root'
providedIn: 'root',
})
export class Config {
get(key: keyof IonicConfig, fallback?: any): any {
const c = getConfig();
if (c) {
@@ -31,14 +30,6 @@ export class Config {
}
return 0;
}
set(key: keyof IonicConfig, value?: any) {
console.warn(`[DEPRECATION][Config]: The Config.set() method is deprecated and will be removed in Ionic Framework 6.0. Please see https://ionicframework.com/docs/angular/config for alternatives.`);
const c = getConfig();
if (c) {
c.set(key, value);
}
}
}
export const ConfigToken = new InjectionToken<any>('USERCONFIG');
@@ -46,7 +37,7 @@ export const ConfigToken = new InjectionToken<any>('USERCONFIG');
const getConfig = (): CoreConfig | null => {
if (typeof (window as any) !== 'undefined') {
const Ionic = (window as any as IonicWindow).Ionic;
if (Ionic && Ionic.config) {
if (Ionic?.config) {
return Ionic.config;
}
}

View File

@@ -4,12 +4,11 @@ import { Injectable } from '@angular/core';
providedIn: 'root',
})
export class DomController {
/**
* Schedules a task to run during the READ phase of the next frame.
* This task should only read the DOM, but never modify it.
*/
read(cb: RafCallback) {
read(cb: RafCallback): void {
getQueue().read(cb);
}
@@ -17,29 +16,29 @@ export class DomController {
* Schedules a task to run during the WRITE phase of the next frame.
* This task should write the DOM, but never READ it.
*/
write(cb: RafCallback) {
write(cb: RafCallback): void {
getQueue().write(cb);
}
}
const getQueue = () => {
const win = typeof (window as any) !== 'undefined' ? window : null as any;
const win = typeof (window as any) !== 'undefined' ? window : (null as any);
if (win != null) {
const Ionic = win.Ionic;
if (Ionic && Ionic.queue) {
if (Ionic?.queue) {
return Ionic.queue;
}
return {
read: (cb: any) => win.requestAnimationFrame(cb),
write: (cb: any) => win.requestAnimationFrame(cb)
write: (cb: any) => win.requestAnimationFrame(cb),
};
}
return {
read: (cb: any) => cb(),
write: (cb: any) => cb()
write: (cb: any) => cb(),
};
};

View File

@@ -1,4 +1,4 @@
import { Injectable, NgZone } from '@angular/core';
import { NgZone, Injectable } from '@angular/core';
import { Gesture, GestureConfig, createGesture } from '@ionic/core';
@Injectable({
@@ -11,10 +11,10 @@ export class GestureController {
*/
create(opts: GestureConfig, runInsideAngularZone = false): Gesture {
if (runInsideAngularZone) {
Object.getOwnPropertyNames(opts).forEach(key => {
Object.getOwnPropertyNames(opts).forEach((key) => {
if (typeof opts[key] === 'function') {
const fn = opts[key];
opts[key] = (...props) => this.zone.run(() => fn(...props));
opts[key] = (...props: any[]) => this.zone.run(() => fn(...props));
}
});
}

View File

@@ -5,13 +5,12 @@ import { menuController } from '@ionic/core';
providedIn: 'root',
})
export class MenuController {
/**
* Programmatically open the Menu.
* @param [menuId] Optionally get the menu by its id, or side.
* @return returns a promise when the menu is fully opened
*/
open(menuId?: string) {
open(menuId?: string): Promise<boolean> {
return menuController.open(menuId);
}
@@ -22,7 +21,7 @@ export class MenuController {
* @param [menuId] Optionally get the menu by its id, or side.
* @return returns a promise when the menu is fully closed
*/
close(menuId?: string) {
close(menuId?: string): Promise<boolean> {
return menuController.close(menuId);
}
@@ -32,7 +31,7 @@ export class MenuController {
* @param [menuId] Optionally get the menu by its id, or side.
* @return returns a promise when the menu has been toggled
*/
toggle(menuId?: string) {
toggle(menuId?: string): Promise<boolean> {
return menuController.toggle(menuId);
}
@@ -44,7 +43,7 @@ export class MenuController {
* @param [menuId] Optionally get the menu by its id, or side.
* @return Returns the instance of the menu, which is useful for chaining.
*/
enable(shouldEnable: boolean, menuId?: string) {
enable(shouldEnable: boolean, menuId?: string): Promise<HTMLIonMenuElement | undefined> {
return menuController.enable(shouldEnable, menuId);
}
@@ -54,7 +53,7 @@ export class MenuController {
* @param [menuId] Optionally get the menu by its id, or side.
* @return Returns the instance of the menu, which is useful for chaining.
*/
swipeGesture(shouldEnable: boolean, menuId?: string) {
swipeGesture(shouldEnable: boolean, menuId?: string): Promise<HTMLIonMenuElement | undefined> {
return menuController.swipeGesture(shouldEnable, menuId);
}
@@ -63,7 +62,7 @@ export class MenuController {
* @return Returns true if the specified menu is currently open, otherwise false.
* If the menuId is not specified, it returns true if ANY menu is currenly open.
*/
isOpen(menuId?: string) {
isOpen(menuId?: string): Promise<boolean> {
return menuController.isOpen(menuId);
}
@@ -71,7 +70,7 @@ export class MenuController {
* @param [menuId] Optionally get the menu by its id, or side.
* @return Returns true if the menu is currently enabled, otherwise false.
*/
isEnabled(menuId?: string) {
isEnabled(menuId?: string): Promise<boolean> {
return menuController.isEnabled(menuId);
}
@@ -84,21 +83,21 @@ export class MenuController {
* @param [menuId] Optionally get the menu by its id, or side.
* @return Returns the instance of the menu if found, otherwise `null`.
*/
get(menuId?: string) {
get(menuId?: string): Promise<HTMLIonMenuElement | undefined> {
return menuController.get(menuId);
}
/**
* @return Returns the instance of the menu already opened, otherwise `null`.
*/
getOpen() {
getOpen(): Promise<HTMLIonMenuElement | undefined> {
return menuController.getOpen();
}
/**
* @return Returns an array of all menu instances.
*/
getMenus() {
getMenus(): Promise<HTMLIonMenuElement[]> {
return menuController.getMenus();
}
}

View File

@@ -1,4 +1,4 @@
import { ComponentFactoryResolver, Injectable, Injector } from '@angular/core';
import { ComponentFactoryResolver, Injector, Injectable } from '@angular/core';
import { ModalOptions, modalController } from '@ionic/core';
import { OverlayBaseController } from '../util/overlay';
@@ -7,11 +7,10 @@ import { AngularDelegate } from './angular-delegate';
@Injectable()
export class ModalController extends OverlayBaseController<ModalOptions, HTMLIonModalElement> {
constructor(
private angularDelegate: AngularDelegate,
private resolver: ComponentFactoryResolver,
private injector: Injector,
private injector: Injector
) {
super(modalController);
}
@@ -19,7 +18,7 @@ export class ModalController extends OverlayBaseController<ModalOptions, HTMLIon
create(opts: ModalOptions): Promise<HTMLIonModalElement> {
return super.create({
...opts,
delegate: this.angularDelegate.create(this.resolver, this.injector)
delegate: this.angularDelegate.create(this.resolver, this.injector),
});
}
}

View File

@@ -1,6 +1,6 @@
import { Location } from '@angular/common';
import { Injectable, Optional } from '@angular/core';
import { NavigationExtras, NavigationStart, Router, UrlSerializer, UrlTree } from '@angular/router';
import { NavigationExtras, Router, UrlSerializer, UrlTree, NavigationStart } from '@angular/router';
import { AnimationBuilder, NavDirection, RouterDirection } from '@ionic/core';
import { IonRouterOutlet } from '../directives/navigation/ion-router-outlet';
@@ -19,7 +19,6 @@ export interface NavigationOptions extends NavigationExtras, AnimationOptions {}
providedIn: 'root',
})
export class NavController {
private topOutlet?: IonRouterOutlet;
private direction: 'forward' | 'back' | 'root' | 'auto' = DEFAULT_DIRECTION;
private animated?: NavDirection = DEFAULT_ANIMATED;
@@ -32,13 +31,13 @@ export class NavController {
platform: Platform,
private location: Location,
private serializer: UrlSerializer,
@Optional() private router?: Router,
@Optional() private router?: Router
) {
// Subscribe to router events to detect direction
if (router) {
router.events.subscribe(ev => {
router.events.subscribe((ev) => {
if (ev instanceof NavigationStart) {
const id = (ev.restoredState) ? ev.restoredState.navigationId : ev.id;
const id = ev.restoredState ? ev.restoredState.navigationId : ev.id;
this.guessDirection = id < this.lastNavId ? 'back' : 'forward';
this.guessAnimation = !ev.restoredState ? this.guessDirection : undefined;
this.lastNavId = this.guessDirection === 'forward' ? ev.id : id;
@@ -47,7 +46,7 @@ export class NavController {
}
// Subscribe to backButton events
platform.backButton.subscribeWithPriority(0, processNextHandler => {
platform.backButton.subscribeWithPriority(0, (processNextHandler) => {
this.pop();
processNextHandler();
});
@@ -122,7 +121,7 @@ export class NavController {
* It will use the standard `window.history.back()` under the hood, but featuring a `back` animation
* by default.
*/
back(options: AnimationOptions = { animated: true, animationDirection: 'back' }) {
back(options: AnimationOptions = { animated: true, animationDirection: 'back' }): void {
this.setDirection('back', options.animated, options.animationDirection, options.animation);
return this.location.back();
}
@@ -133,7 +132,7 @@ export class NavController {
* It recursively finds the top active `ion-router-outlet` and calls `pop()`.
* This is the recommended way to go back when you are using `ion-router-outlet`.
*/
async pop() {
async pop(): Promise<void> {
let outlet = this.topOutlet;
while (outlet) {
@@ -152,7 +151,12 @@ export class NavController {
*
* It's recommended to use `navigateForward()`, `navigateBack()` and `navigateRoot()` instead of `setDirection()`.
*/
setDirection(direction: RouterDirection, animated?: boolean, animationDirection?: 'forward' | 'back', animationBuilder?: AnimationBuilder) {
setDirection(
direction: RouterDirection,
animated?: boolean,
animationDirection?: 'forward' | 'back',
animationBuilder?: AnimationBuilder
): void {
this.direction = direction;
this.animated = getAnimation(direction, animated, animationDirection);
this.animationBuilder = animationBuilder;
@@ -161,14 +165,18 @@ export class NavController {
/**
* @internal
*/
setTopOutlet(outlet: IonRouterOutlet) {
setTopOutlet(outlet: IonRouterOutlet): void {
this.topOutlet = outlet;
}
/**
* @internal
*/
consumeTransition() {
consumeTransition(): {
direction: RouterDirection;
animation: NavDirection | undefined;
animationBuilder: AnimationBuilder | undefined;
} {
let direction: RouterDirection = 'root';
let animation: NavDirection | undefined;
const animationBuilder = this.animationBuilder;
@@ -187,15 +195,15 @@ export class NavController {
return {
direction,
animation,
animationBuilder
animationBuilder,
};
}
private navigate(url: string | UrlTree | any[], options: NavigationOptions) {
if (Array.isArray(url)) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return this.router!.navigate(url, options);
} else {
/**
* navigateByUrl ignores any properties that
* would change the url, so things like queryParams
@@ -217,12 +225,17 @@ export class NavController {
* that do not modify the url, such as `replaceUrl` which is why
* `options` is passed in here.
*/
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return this.router!.navigateByUrl(urlTree, options);
}
}
}
const getAnimation = (direction: RouterDirection, animated: boolean | undefined, animationDirection: 'forward' | 'back' | undefined): NavDirection | undefined => {
const getAnimation = (
direction: RouterDirection,
animated: boolean | undefined,
animationDirection: 'forward' | 'back' | undefined
): NavDirection | undefined => {
if (animated === false) {
return undefined;
}

View File

@@ -1,17 +1,19 @@
import { DOCUMENT } from '@angular/common';
import { Inject, Injectable, NgZone } from '@angular/core';
import { NgZone, Inject, Injectable } from '@angular/core';
import { BackButtonEventDetail, KeyboardEventDetail, Platforms, getPlatforms, isPlatform } from '@ionic/core';
import { Subject, Subscription } from 'rxjs';
import { Subscription, Subject } from 'rxjs';
export interface BackButtonEmitter extends Subject<BackButtonEventDetail> {
subscribeWithPriority(priority: number, callback: (processNextHandler: () => void) => Promise<any> | void): Subscription;
subscribeWithPriority(
priority: number,
callback: (processNextHandler: () => void) => Promise<any> | void
): Subscription;
}
@Injectable({
providedIn: 'root',
})
export class Platform {
private _readyPromise: Promise<string>;
private win: any;
@@ -57,9 +59,9 @@ export class Platform {
constructor(@Inject(DOCUMENT) private doc: any, zone: NgZone) {
zone.run(() => {
this.win = doc.defaultView;
this.backButton.subscribeWithPriority = function(priority, callback) {
return this.subscribe(ev => {
return ev.register(priority, processNextHandler => zone.run(() => callback(processNextHandler)));
this.backButton.subscribeWithPriority = function (priority, callback) {
return this.subscribe((ev) => {
return ev.register(priority, (processNextHandler) => zone.run(() => callback(processNextHandler)));
});
};
@@ -71,12 +73,19 @@ export class Platform {
proxyEvent(this.keyboardDidHide, this.win, 'ionKeyboardDidHide');
let readyResolve: (value: string) => void;
this._readyPromise = new Promise(res => { readyResolve = res; });
if (this.win && this.win['cordova']) {
doc.addEventListener('deviceready', () => {
readyResolve('cordova');
}, { once: true });
this._readyPromise = new Promise((res) => {
readyResolve = res;
});
if (this.win?.['cordova']) {
doc.addEventListener(
'deviceready',
() => {
readyResolve('cordova');
},
{ once: true }
);
} else {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
readyResolve!('dom');
}
});
@@ -213,25 +222,25 @@ export class Platform {
* Returns `true` if the app is in portrait mode.
*/
isPortrait(): boolean {
return this.win.matchMedia && this.win.matchMedia('(orientation: portrait)').matches;
return this.win.matchMedia?.('(orientation: portrait)').matches;
}
testUserAgent(expression: string): boolean {
const nav = this.win.navigator;
return !!(nav && nav.userAgent && nav.userAgent.indexOf(expression) >= 0);
return !!(nav?.userAgent && nav.userAgent.indexOf(expression) >= 0);
}
/**
* Get the current url.
*/
url() {
url(): string {
return this.win.location.href;
}
/**
* Gets the width of the platform's viewport using `window.innerWidth`.
*/
width() {
width(): number {
return this.win.innerWidth;
}
@@ -244,17 +253,17 @@ export class Platform {
}
const readQueryParam = (url: string, key: string) => {
key = key.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
key = key.replace(/[[]/, '\\[').replace(/[\]]/, '\\]');
const regex = new RegExp('[\\?&]' + key + '=([^&#]*)');
const results = regex.exec(url);
return results ? decodeURIComponent(results[1].replace(/\+/g, ' ')) : null;
};
const proxyEvent = <T>(emitter: Subject<T>, el: EventTarget, eventName: string) => {
if ((el as any)) {
if (el as any) {
el.addEventListener(eventName, (ev: Event | undefined | null) => {
// ?? cordova might emit "null" events
emitter.next(ev != null ? (ev as any).detail as T : undefined);
emitter.next(ev != null ? ((ev as any).detail as T) : undefined);
});
}
};

View File

@@ -1,4 +1,4 @@
import { ComponentFactoryResolver, Injectable, Injector } from '@angular/core';
import { ComponentFactoryResolver, Injector, Injectable } from '@angular/core';
import { PopoverOptions, popoverController } from '@ionic/core';
import { OverlayBaseController } from '../util/overlay';
@@ -7,11 +7,10 @@ import { AngularDelegate } from './angular-delegate';
@Injectable()
export class PopoverController extends OverlayBaseController<PopoverOptions, HTMLIonPopoverElement> {
constructor(
private angularDelegate: AngularDelegate,
private resolver: ComponentFactoryResolver,
private injector: Injector,
private injector: Injector
) {
super(popoverController);
}
@@ -19,7 +18,7 @@ export class PopoverController extends OverlayBaseController<PopoverOptions, HTM
create(opts: PopoverOptions): Promise<HTMLIonPopoverElement> {
return super.create({
...opts,
delegate: this.angularDelegate.create(this.resolver, this.injector)
delegate: this.angularDelegate.create(this.resolver, this.injector),
});
}
}

View File

@@ -1,8 +1,21 @@
import { join, Path } from '@angular-devkit/core';
import { apply, chain, mergeWith, move, Rule, SchematicContext, SchematicsException, template, Tree, url } from '@angular-devkit/schematics';
import { Path, join } from '@angular-devkit/core';
import {
Rule,
SchematicContext,
Tree,
apply,
chain,
mergeWith,
move,
SchematicsException,
template,
url,
} from '@angular-devkit/schematics';
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
import { getWorkspace } from '@schematics/angular/utility/workspace';
import { addModuleImportToRootModule } from './../utils/ast';
import { addArchitectBuilder, addAsset, addStyle, getDefaultAngularAppName, getWorkspace, WorkspaceProject, WorkspaceSchema } from './../utils/config';
import { addArchitectBuilder, addAsset, addStyle, getDefaultAngularAppName } from './../utils/config';
import { addPackageToPackageJson } from './../utils/package';
import { Schema as IonAddOptions } from './schema';
@@ -15,24 +28,14 @@ function addIonicAngularToPackageJson(): Rule {
function addIonicAngularToolkitToPackageJson(): Rule {
return (host: Tree) => {
addPackageToPackageJson(
host,
'devDependencies',
'@ionic/angular-toolkit',
'latest'
);
addPackageToPackageJson(host, 'devDependencies', '@ionic/angular-toolkit', 'latest');
return host;
};
}
function addIonicAngularModuleToAppModule(projectSourceRoot: Path): Rule {
return (host: Tree) => {
addModuleImportToRootModule(
host,
projectSourceRoot,
'IonicModule.forRoot()',
'@ionic/angular'
);
addModuleImportToRootModule(host, projectSourceRoot, 'IonicModule.forRoot()', '@ionic/angular');
return host;
};
}
@@ -50,13 +53,13 @@ function addIonicStyles(projectName: string, projectSourceRoot: Path): Rule {
'node_modules/@ionic/angular/css/text-alignment.css',
'node_modules/@ionic/angular/css/text-transformation.css',
'node_modules/@ionic/angular/css/flex-utils.css',
`${projectSourceRoot}/theme/variables.css`
]
`${projectSourceRoot}/theme/variables.css`,
];
ionicStyles.forEach(entry => {
ionicStyles.forEach((entry) => {
addStyle(host, projectName, entry);
});
return host;
return host;
};
}
@@ -65,7 +68,7 @@ function addIonicons(projectName: string): Rule {
const ioniconsGlob = {
glob: '**/*.svg',
input: 'node_modules/ionicons/dist/ionicons/svg',
output: './svg'
output: './svg',
};
addAsset(host, projectName, 'build', ioniconsGlob);
addAsset(host, projectName, 'test', ioniconsGlob);
@@ -79,25 +82,25 @@ function addIonicBuilder(projectName: string): Rule {
builder: '@ionic/angular-toolkit:cordova-serve',
options: {
cordovaBuildTarget: `${projectName}:ionic-cordova-build`,
devServerTarget: `${projectName}:serve`
devServerTarget: `${projectName}:serve`,
},
configurations: {
production: {
cordovaBuildTarget: `${projectName}:ionic-cordova-build:production`,
devServerTarget: `${projectName}:serve:production`
}
}
devServerTarget: `${projectName}:serve:production`,
},
},
});
addArchitectBuilder(host, projectName, 'ionic-cordova-build', {
builder: '@ionic/angular-toolkit:cordova-build',
options: {
browserTarget: `${projectName}:build`
browserTarget: `${projectName}:build`,
},
configurations: {
production: {
browserTarget: `${projectName}:build:production`
}
}
browserTarget: `${projectName}:build:production`,
},
},
});
return host;
};
@@ -110,22 +113,18 @@ function installNodeDeps() {
}
export default function ngAdd(options: IonAddOptions): Rule {
return (host: Tree) => {
const workspace: WorkspaceSchema = getWorkspace(host);
return async (host: Tree) => {
const workspace = await getWorkspace(host);
if (!options.project) {
options.project = getDefaultAngularAppName(workspace);
}
const project: WorkspaceProject = workspace.projects[options.project];
if (project.projectType !== 'application') {
throw new SchematicsException(
`Ionic Add requires a project type of "application".`
);
const project = workspace.projects.get(options.project);
if (!project || project.extensions.projectType !== 'application') {
throw new SchematicsException(`Ionic Add requires a project type of "application".`);
}
const sourcePath: Path = join(project.sourceRoot as Path);
const rootTemplateSource = apply(url('./files/root'), [
template({ ...options }),
move(sourcePath)
]);
const rootTemplateSource = apply(url('./files/root'), [template({ ...options }), move(sourcePath)]);
return chain([
// @ionic/angular
addIonicAngularToPackageJson(),
@@ -136,7 +135,7 @@ export default function ngAdd(options: IonAddOptions): Rule {
addIonicons(options.project),
mergeWith(rootTemplateSource),
// install freshly added dependencies
installNodeDeps()
installNodeDeps(),
]);
};
}

View File

@@ -1,6 +1,6 @@
{
"$schema": "http://json-schema.org/schema",
"id": "ionicNgAdd",
"$id": "ionicNgAdd",
"title": "Ionic Add options",
"type": "object",
"properties": {

View File

@@ -1,6 +1,7 @@
import { SchematicsException, Tree } from '@angular-devkit/schematics';
import { normalize } from '@angular-devkit/core';
import { Tree, SchematicsException } from '@angular-devkit/schematics';
import * as ts from 'typescript';
import { addImportToModule } from './devkit-utils/ast-utils';
import { InsertChange } from './devkit-utils/change';
@@ -13,12 +14,7 @@ export function getSourceFile(host: Tree, path: string): ts.SourceFile {
throw new SchematicsException(`Could not find file for path: ${path}`);
}
const content = buffer.toString();
const source = ts.createSourceFile(
path,
content,
ts.ScriptTarget.Latest,
true
);
const source = ts.createSourceFile(path, content, ts.ScriptTarget.Latest, true);
return source;
}
@@ -30,13 +26,8 @@ export function addModuleImportToRootModule(
projectSourceRoot: string,
moduleName: string,
importSrc: string
) {
addModuleImportToModule(
host,
normalize(`${projectSourceRoot}/app/app.module.ts`),
moduleName,
importSrc
);
): void {
addModuleImportToModule(host, normalize(`${projectSourceRoot}/app/app.module.ts`), moduleName, importSrc);
}
/**
@@ -46,17 +37,12 @@ export function addModuleImportToRootModule(
* @param moduleName name of module to import
* @param src src location to import
*/
export function addModuleImportToModule(
host: Tree,
modulePath: string,
moduleName: string,
src: string
) {
export function addModuleImportToModule(host: Tree, modulePath: string, moduleName: string, src: string): void {
const moduleSource = getSourceFile(host, modulePath);
const changes = addImportToModule(moduleSource, modulePath, moduleName, src);
const recorder = host.beginUpdate(modulePath);
changes.forEach(change => {
changes.forEach((change) => {
if (change instanceof InsertChange) {
recorder.insertLeft(change.pos, change.toAdd);
}

View File

@@ -1,18 +1,19 @@
import { SchematicsException, Tree } from '@angular-devkit/schematics';
import { experimental, parseJson, JsonParseMode } from '@angular-devkit/core';
import { WorkspaceDefinition } from '@angular-devkit/core/src/workspace';
import { Tree, SchematicsException } from '@angular-devkit/schematics';
import { parse } from 'jsonc-parser';
const CONFIG_PATH = 'angular.json';
export function readConfig(host: Tree) {
const sourceText = host.read(CONFIG_PATH)!.toString('utf-8');
export function readConfig(host: Tree): any {
const sourceText = host.read(CONFIG_PATH)?.toString('utf-8');
return JSON.parse(sourceText);
}
export function writeConfig(host: Tree, config: JSON) {
export function writeConfig(host: Tree, config: JSON): void {
host.overwrite(CONFIG_PATH, JSON.stringify(config, null, 2));
}
function isAngularBrowserProject(projectConfig: any) {
function isAngularBrowserProject(projectConfig: any): boolean {
if (projectConfig.projectType === 'application') {
const buildConfig = projectConfig.architect.build;
return buildConfig.builder === '@angular-devkit/build-angular:browser';
@@ -36,6 +37,7 @@ export function getDefaultAngularAppName(config: any): string {
}
export function getAngularAppConfig(config: any, projectName: string): any | never {
// eslint-disable-next-line no-prototype-builtins
if (!config.projects.hasOwnProperty(projectName)) {
throw new SchematicsException(`Could not find project: ${projectName}`);
}
@@ -53,40 +55,50 @@ export function getAngularAppConfig(config: any, projectName: string): any | nev
}
}
export function addStyle(host: Tree, projectName: string, stylePath: string) {
export function addStyle(host: Tree, projectName: string, stylePath: string): void {
const config = readConfig(host);
const appConfig = getAngularAppConfig(config, projectName);
appConfig.architect.build.options.styles.push({
input: stylePath
input: stylePath,
});
writeConfig(host, config);
}
export function addAsset(host: Tree, projectName: string, architect: string, asset: string | {glob: string; input: string; output: string}) {
export function addAsset(
host: Tree,
projectName: string,
architect: string,
asset: string | { glob: string; input: string; output: string }
): void {
const config = readConfig(host);
const appConfig = getAngularAppConfig(config, projectName);
appConfig.architect[architect].options.assets.push(asset);
writeConfig(host, config);
const target = appConfig.architect[architect];
if (target) {
target.options.assets.push(asset);
writeConfig(host, config);
}
}
export function addArchitectBuilder(host: Tree, projectName: string, builderName: string, builderOpts: any): void | never {
export function addArchitectBuilder(
host: Tree,
projectName: string,
builderName: string,
builderOpts: any
): void | never {
const config = readConfig(host);
const appConfig = getAngularAppConfig(config, projectName);
appConfig.architect[builderName] = builderOpts;
writeConfig(host, config);
}
export type WorkspaceSchema = experimental.workspace.WorkspaceSchema;
export type WorkspaceProject = experimental.workspace.WorkspaceProject;
export function getWorkspacePath(host: Tree): string {
const possibleFiles = ['/angular.json', '/.angular.json'];
const path = possibleFiles.filter(path => host.exists(path))[0];
const path = possibleFiles.filter((path) => host.exists(path))[0];
return path;
}
export function getWorkspace(host: Tree): WorkspaceSchema {
export function getWorkspace(host: Tree): WorkspaceDefinition {
const path = getWorkspacePath(host);
const configBuffer = host.read(path);
if (configBuffer === null) {
@@ -94,5 +106,5 @@ export function getWorkspace(host: Tree): WorkspaceSchema {
}
const content = configBuffer.toString();
return (parseJson(content, JsonParseMode.Loose) as {}) as WorkspaceSchema;
return parse(content) as WorkspaceDefinition;
}

View File

@@ -6,8 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import * as ts from 'typescript';
import { Change, InsertChange, NoopChange } from './change';
import { Change, InsertChange, NoopChange } from './change';
/**
* Add Import `import { symbolName } from fileName` if the import doesn't exit
@@ -18,26 +18,32 @@ import { Change, InsertChange, NoopChange } from './change';
* @param isDefault (if true, import follows style for importing default exports)
* @return Change
*/
export function insertImport(source: ts.SourceFile, fileToEdit: string, symbolName: string,
fileName: string, isDefault = false): Change {
export function insertImport(
source: ts.SourceFile,
fileToEdit: string,
symbolName: string,
fileName: string,
isDefault = false
): Change {
const rootNode = source;
const allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration);
// get nodes that map to import statements from the file fileName
const relevantImports = allImports.filter(node => {
const relevantImports = allImports.filter((node) => {
// StringLiteral of the ImportDeclaration is the import file (fileName in this case).
const importFiles = node.getChildren()
.filter(child => child.kind === ts.SyntaxKind.StringLiteral)
.map(n => (n as ts.StringLiteral).text);
const importFiles = node
.getChildren()
.filter((child) => child.kind === ts.SyntaxKind.StringLiteral)
.map((n) => (n as ts.StringLiteral).text);
return importFiles.filter(file => file === fileName).length === 1;
return importFiles.filter((file) => file === fileName).length === 1;
});
if (relevantImports.length > 0) {
let importsAsterisk = false;
// imports from import file
const imports: ts.Node[] = [];
relevantImports.forEach(n => {
relevantImports.forEach((n) => {
Array.prototype.push.apply(imports, findNodes(n, ts.SyntaxKind.Identifier));
if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) {
importsAsterisk = true;
@@ -49,7 +55,7 @@ export function insertImport(source: ts.SourceFile, fileToEdit: string, symbolNa
return new NoopChange();
}
const importTextNodes = imports.filter(n => (n as ts.Identifier).text === symbolName);
const importTextNodes = imports.filter((n) => (n as ts.Identifier).text === symbolName);
// insert import if it's not there
if (importTextNodes.length === 0) {
@@ -64,8 +70,9 @@ export function insertImport(source: ts.SourceFile, fileToEdit: string, symbolNa
}
// no such import declaration exists
const useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral)
.filter((n: ts.StringLiteral) => n.text === 'use strict');
const useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral).filter(
(n: ts.StringLiteral) => n.text === 'use strict'
);
let fallbackPos = 0;
if (useStrict.length > 0) {
fallbackPos = useStrict[0].end;
@@ -75,19 +82,12 @@ export function insertImport(source: ts.SourceFile, fileToEdit: string, symbolNa
// if there are no imports or 'use strict' statement, insert import at beginning of file
const insertAtBeginning = allImports.length === 0 && useStrict.length === 0;
const separator = insertAtBeginning ? '' : ';\n';
const toInsert = `${separator}import ${open}${symbolName}${close}` +
` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`;
const toInsert =
`${separator}import ${open}${symbolName}${close}` + ` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`;
return insertAfterLastOccurrence(
allImports,
toInsert,
fileToEdit,
fallbackPos,
ts.SyntaxKind.StringLiteral,
);
return insertAfterLastOccurrence(allImports, toInsert, fileToEdit, fallbackPos, ts.SyntaxKind.StringLiteral);
}
/**
* Find all nodes from the AST in the subtree of node of SyntaxKind kind.
* @param node
@@ -107,7 +107,7 @@ export function findNodes(node: ts.Node, kind: ts.SyntaxKind, max = Infinity): t
}
if (max > 0) {
for (const child of node.getChildren()) {
findNodes(child, kind, max).forEach(node => {
findNodes(child, kind, max).forEach((node) => {
if (max > 0) {
arr.push(node);
}
@@ -123,7 +123,6 @@ export function findNodes(node: ts.Node, kind: ts.SyntaxKind, max = Infinity): t
return arr;
}
/**
* Get all the nodes from a source.
* @param sourceFile The source file object.
@@ -154,14 +153,13 @@ export function findNode(node: ts.Node, kind: ts.SyntaxKind, text: string): ts.N
}
let foundNode: ts.Node | null = null;
ts.forEachChild(node, childNode => {
ts.forEachChild(node, (childNode) => {
foundNode = foundNode || findNode(childNode, kind, text);
});
return foundNode;
}
/**
* Helper for sorting nodes.
* @return function to sort nodes in increasing order of position in sourceFile
@@ -170,7 +168,6 @@ function nodesByPosition(first: ts.Node, second: ts.Node): number {
return first.getStart() - second.getStart();
}
/**
* Insert `toInsert` after the last occurence of `ts.SyntaxKind[nodes[i].kind]`
* or after the last of occurence of `syntaxKind` if the last occurence is a sub child
@@ -184,11 +181,13 @@ function nodesByPosition(first: ts.Node, second: ts.Node): number {
* @return Change instance
* @throw Error if toInsert is first occurence but fall back is not set
*/
export function insertAfterLastOccurrence(nodes: ts.Node[],
toInsert: string,
file: string,
fallbackPos: number,
syntaxKind?: ts.SyntaxKind): Change {
export function insertAfterLastOccurrence(
nodes: ts.Node[],
toInsert: string,
file: string,
fallbackPos: number,
syntaxKind?: ts.SyntaxKind
): Change {
// sort() has a side effect, so make a copy so that we won't overwrite the parent's object.
let lastItem = [...nodes].sort(nodesByPosition).pop();
if (!lastItem) {
@@ -205,7 +204,6 @@ export function insertAfterLastOccurrence(nodes: ts.Node[],
return new InsertChange(file, lastItemPosition, toInsert);
}
export function getContentOfKeyLiteral(_source: ts.SourceFile, node: ts.Node): string | null {
if (node.kind == ts.SyntaxKind.Identifier) {
return (node as ts.Identifier).text;
@@ -216,9 +214,11 @@ export function getContentOfKeyLiteral(_source: ts.SourceFile, node: ts.Node): s
}
}
function _angularImportsFromNode(node: ts.ImportDeclaration,
_sourceFile: ts.SourceFile): {[name: string]: string} {
function _angularImportsFromNode(
node: ts.ImportDeclaration,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_sourceFile: ts.SourceFile
): { [name: string]: string } {
const ms = node.moduleSpecifier;
let modulePath: string;
switch (ms.kind) {
@@ -249,8 +249,8 @@ function _angularImportsFromNode(node: ts.ImportDeclaration,
const namedImports = nb as ts.NamedImports;
return namedImports.elements
.map((is: ts.ImportSpecifier) => is.propertyName ? is.propertyName.text : is.name.text)
.reduce((acc: {[name: string]: string}, curr: string) => {
.map((is: ts.ImportSpecifier) => (is.propertyName ? is.propertyName.text : is.name.text))
.reduce((acc: { [name: string]: string }, curr: string) => {
acc[curr] = modulePath;
return acc;
@@ -265,13 +265,10 @@ function _angularImportsFromNode(node: ts.ImportDeclaration,
}
}
export function getDecoratorMetadata(source: ts.SourceFile, identifier: string,
module: string): ts.Node[] {
const angularImports: {[name: string]: string}
= findNodes(source, ts.SyntaxKind.ImportDeclaration)
export function getDecoratorMetadata(source: ts.SourceFile, identifier: string, module: string): ts.Node[] {
const angularImports: { [name: string]: string } = findNodes(source, ts.SyntaxKind.ImportDeclaration)
.map((node: ts.ImportDeclaration) => _angularImportsFromNode(node, source))
.reduce((acc: {[name: string]: string}, current: {[name: string]: string}) => {
.reduce((acc: { [name: string]: string }, current: { [name: string]: string }) => {
for (const key of Object.keys(current)) {
acc[key] = current[key];
}
@@ -280,17 +277,17 @@ export function getDecoratorMetadata(source: ts.SourceFile, identifier: string,
}, {});
return getSourceNodes(source)
.filter(node => {
return node.kind == ts.SyntaxKind.Decorator
&& (node as ts.Decorator).expression.kind == ts.SyntaxKind.CallExpression;
.filter((node) => {
return (
node.kind == ts.SyntaxKind.Decorator && (node as ts.Decorator).expression.kind == ts.SyntaxKind.CallExpression
);
})
.map(node => (node as ts.Decorator).expression as ts.CallExpression)
.filter(expr => {
.map((node) => (node as ts.Decorator).expression as ts.CallExpression)
.filter((expr) => {
if (expr.expression.kind == ts.SyntaxKind.Identifier) {
const id = expr.expression as ts.Identifier;
return id.getFullText(source) == identifier
&& angularImports[id.getFullText(source)] === module;
return id.getFullText(source) == identifier && angularImports[id.getFullText(source)] === module;
} else if (expr.expression.kind == ts.SyntaxKind.PropertyAccessExpression) {
// This covers foo.NgModule when importing * as foo.
const paExpr = expr.expression as ts.PropertyAccessExpression;
@@ -302,17 +299,16 @@ export function getDecoratorMetadata(source: ts.SourceFile, identifier: string,
const id = paExpr.name.text;
const moduleId = (paExpr.expression as ts.Identifier).getText(source);
return id === identifier && (angularImports[moduleId + '.'] === module);
return id === identifier && angularImports[moduleId + '.'] === module;
}
return false;
})
.filter(expr => expr.arguments[0]
&& expr.arguments[0].kind == ts.SyntaxKind.ObjectLiteralExpression)
.map(expr => expr.arguments[0] as ts.ObjectLiteralExpression);
.filter((expr) => expr.arguments[0] && expr.arguments[0].kind == ts.SyntaxKind.ObjectLiteralExpression)
.map((expr) => expr.arguments[0] as ts.ObjectLiteralExpression);
}
function findClassDeclarationParent(node: ts.Node): ts.ClassDeclaration|undefined {
function findClassDeclarationParent(node: ts.Node): ts.ClassDeclaration | undefined {
if (ts.isClassDeclaration(node)) {
return node;
}
@@ -326,7 +322,7 @@ function findClassDeclarationParent(node: ts.Node): ts.ClassDeclaration|undefine
* @param source source file containing one or more @NgModule
* @returns the name of the first @NgModule, or `undefined` if none is found
*/
export function getFirstNgModuleName(source: ts.SourceFile): string|undefined {
export function getFirstNgModuleName(source: ts.SourceFile): string | undefined {
// First, find the @NgModule decorators.
const ngModulesMetadata = getDecoratorMetadata(source, 'NgModule', '@angular/core');
if (ngModulesMetadata.length === 0) {
@@ -349,10 +345,10 @@ export function addSymbolToNgModuleMetadata(
ngModulePath: string,
metadataField: string,
symbolName: string,
importPath: string | null = null,
importPath: string | null = null
): Change[] {
const nodes = getDecoratorMetadata(source, 'NgModule', '@angular/core');
let node: any = nodes[0]; // tslint:disable-line:no-any
let node: any = nodes[0]; // tslint:disable-line:no-any
// Find the decorator declaration.
if (!node) {
@@ -360,9 +356,8 @@ export function addSymbolToNgModuleMetadata(
}
// Get all the children property assignment of object literals.
const matchingProperties: ts.ObjectLiteralElement[] =
(node as ts.ObjectLiteralExpression).properties
.filter(prop => prop.kind == ts.SyntaxKind.PropertyAssignment)
const matchingProperties: ts.ObjectLiteralElement[] = (node as ts.ObjectLiteralExpression).properties
.filter((prop) => prop.kind == ts.SyntaxKind.PropertyAssignment)
// Filter out every fields that's not "metadataField". Also handles string literals
// (but not expressions).
.filter((prop: ts.PropertyAssignment) => {
@@ -432,8 +427,9 @@ export function addSymbolToNgModuleMetadata(
}
if (Array.isArray(node)) {
const nodeArray = node as {} as Array<ts.Node>;
const symbolsArray = nodeArray.map(node => node.getText());
// eslint-disable-next-line @typescript-eslint/ban-types
const nodeArray = node as {} as ts.Node[];
const symbolsArray = nodeArray.map((node) => node.getText());
if (symbolsArray.includes(symbolName)) {
return [];
}
@@ -488,81 +484,93 @@ export function addSymbolToNgModuleMetadata(
* Custom function to insert a declaration (component, pipe, directive)
* into NgModule declarations. It also imports the component.
*/
export function addDeclarationToModule(source: ts.SourceFile,
modulePath: string, classifiedName: string,
importPath: string): Change[] {
return addSymbolToNgModuleMetadata(
source, modulePath, 'declarations', classifiedName, importPath);
export function addDeclarationToModule(
source: ts.SourceFile,
modulePath: string,
classifiedName: string,
importPath: string
): Change[] {
return addSymbolToNgModuleMetadata(source, modulePath, 'declarations', classifiedName, importPath);
}
/**
* Custom function to insert an NgModule into NgModule imports. It also imports the module.
*/
export function addImportToModule(source: ts.SourceFile,
modulePath: string, classifiedName: string,
importPath: string): Change[] {
export function addImportToModule(
source: ts.SourceFile,
modulePath: string,
classifiedName: string,
importPath: string
): Change[] {
return addSymbolToNgModuleMetadata(source, modulePath, 'imports', classifiedName, importPath);
}
/**
* Custom function to insert a provider into NgModule. It also imports it.
*/
export function addProviderToModule(source: ts.SourceFile,
modulePath: string, classifiedName: string,
importPath: string): Change[] {
export function addProviderToModule(
source: ts.SourceFile,
modulePath: string,
classifiedName: string,
importPath: string
): Change[] {
return addSymbolToNgModuleMetadata(source, modulePath, 'providers', classifiedName, importPath);
}
/**
* Custom function to insert an export into NgModule. It also imports it.
*/
export function addExportToModule(source: ts.SourceFile,
modulePath: string, classifiedName: string,
importPath: string): Change[] {
export function addExportToModule(
source: ts.SourceFile,
modulePath: string,
classifiedName: string,
importPath: string
): Change[] {
return addSymbolToNgModuleMetadata(source, modulePath, 'exports', classifiedName, importPath);
}
/**
* Custom function to insert an export into NgModule. It also imports it.
*/
export function addBootstrapToModule(source: ts.SourceFile,
modulePath: string, classifiedName: string,
importPath: string): Change[] {
export function addBootstrapToModule(
source: ts.SourceFile,
modulePath: string,
classifiedName: string,
importPath: string
): Change[] {
return addSymbolToNgModuleMetadata(source, modulePath, 'bootstrap', classifiedName, importPath);
}
/**
* Custom function to insert an entryComponent into NgModule. It also imports it.
*/
export function addEntryComponentToModule(source: ts.SourceFile,
modulePath: string, classifiedName: string,
importPath: string): Change[] {
return addSymbolToNgModuleMetadata(
source, modulePath,
'entryComponents', classifiedName, importPath,
);
export function addEntryComponentToModule(
source: ts.SourceFile,
modulePath: string,
classifiedName: string,
importPath: string
): Change[] {
return addSymbolToNgModuleMetadata(source, modulePath, 'entryComponents', classifiedName, importPath);
}
/**
* Determine if an import already exists.
*/
export function isImported(source: ts.SourceFile,
classifiedName: string,
importPath: string): boolean {
export function isImported(source: ts.SourceFile, classifiedName: string, importPath: string): boolean {
const allNodes = getSourceNodes(source);
const matchingNodes = allNodes
.filter(node => node.kind === ts.SyntaxKind.ImportDeclaration)
.filter((node) => node.kind === ts.SyntaxKind.ImportDeclaration)
.filter((imp: ts.ImportDeclaration) => imp.moduleSpecifier.kind === ts.SyntaxKind.StringLiteral)
.filter((imp: ts.ImportDeclaration) => {
return (<ts.StringLiteral> imp.moduleSpecifier).text === importPath;
return (imp.moduleSpecifier as ts.StringLiteral).text === importPath;
})
.filter((imp: ts.ImportDeclaration) => {
if (!imp.importClause) {
return false;
}
const nodes = findNodes(imp.importClause, ts.SyntaxKind.ImportSpecifier)
.filter(n => n.getText() === classifiedName);
const nodes = findNodes(imp.importClause, ts.SyntaxKind.ImportSpecifier).filter(
(n) => n.getText() === classifiedName
);
return nodes.length > 0;
});

View File

@@ -10,7 +10,6 @@ export interface Host {
read(path: string): Promise<string>;
}
export interface Change {
apply(host: Host): Promise<void>;
@@ -26,7 +25,6 @@ export interface Change {
readonly description: string;
}
/**
* An operation that does nothing.
*/
@@ -34,15 +32,15 @@ export class NoopChange implements Change {
description = 'No operation.';
order = Infinity;
path = null;
apply() { return Promise.resolve(); }
apply(): Promise<void> {
return Promise.resolve();
}
}
/**
* Will add text to the source code.
*/
export class InsertChange implements Change {
order: number;
description: string;
@@ -57,8 +55,8 @@ export class InsertChange implements Change {
/**
* This method does not insert spaces if there is none in the original string.
*/
apply(host: Host) {
return host.read(this.path).then(content => {
apply(host: Host): Promise<void> {
return host.read(this.path).then((content) => {
const prefix = content.substring(0, this.pos);
const suffix = content.substring(this.pos);
@@ -71,7 +69,6 @@ export class InsertChange implements Change {
* Will remove text from the source code.
*/
export class RemoveChange implements Change {
order: number;
description: string;
@@ -84,7 +81,7 @@ export class RemoveChange implements Change {
}
apply(host: Host): Promise<void> {
return host.read(this.path).then(content => {
return host.read(this.path).then((content) => {
const prefix = content.substring(0, this.pos);
const suffix = content.substring(this.pos + this.toRemove.length);
@@ -101,8 +98,7 @@ export class ReplaceChange implements Change {
order: number;
description: string;
constructor(public path: string, private pos: number, private oldText: string,
private newText: string) {
constructor(public path: string, private pos: number, private oldText: string, private newText: string) {
if (pos < 0) {
throw new Error('Negative positions are invalid');
}
@@ -111,7 +107,7 @@ export class ReplaceChange implements Change {
}
apply(host: Host): Promise<void> {
return host.read(this.path).then(content => {
return host.read(this.path).then((content) => {
const prefix = content.substring(0, this.pos);
const suffix = content.substring(this.pos + this.oldText.length);
const text = content.substring(this.pos, this.pos + this.oldText.length);

View File

@@ -3,5 +3,3 @@
These are utility files copied over from `@angular-devkit`.
They are not exported so they need to be manually copied over.
Please do not edit directly.

View File

@@ -6,6 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import * as ts from 'typescript';
import { findNodes, insertAfterLastOccurrence } from './ast-utils';
import { Change, NoopChange } from './change';
@@ -30,25 +31,22 @@ export function insertImport(
const allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration);
// get nodes that map to import statements from the file fileName
const relevantImports = allImports.filter(node => {
const relevantImports = allImports.filter((node) => {
// StringLiteral of the ImportDeclaration is the import file (fileName in this case).
const importFiles = node
.getChildren()
.filter(child => child.kind === ts.SyntaxKind.StringLiteral)
.map(n => (n as ts.StringLiteral).text);
.filter((child) => child.kind === ts.SyntaxKind.StringLiteral)
.map((n) => (n as ts.StringLiteral).text);
return importFiles.filter(file => file === fileName).length === 1;
return importFiles.filter((file) => file === fileName).length === 1;
});
if (relevantImports.length > 0) {
let importsAsterisk = false;
// imports from import file
const imports: ts.Node[] = [];
relevantImports.forEach(n => {
Array.prototype.push.apply(
imports,
findNodes(n, ts.SyntaxKind.Identifier)
);
relevantImports.forEach((n) => {
Array.prototype.push.apply(imports, findNodes(n, ts.SyntaxKind.Identifier));
if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) {
importsAsterisk = true;
}
@@ -59,25 +57,15 @@ export function insertImport(
return new NoopChange();
}
const importTextNodes = imports.filter(
n => (n as ts.Identifier).text === symbolName
);
const importTextNodes = imports.filter((n) => (n as ts.Identifier).text === symbolName);
// insert import if it's not there
if (importTextNodes.length === 0) {
const fallbackPos =
findNodes(
relevantImports[0],
ts.SyntaxKind.CloseBraceToken
)[0].getStart() ||
findNodes(relevantImports[0], ts.SyntaxKind.CloseBraceToken)[0].getStart() ||
findNodes(relevantImports[0], ts.SyntaxKind.FromKeyword)[0].getStart();
return insertAfterLastOccurrence(
imports,
`, ${symbolName}`,
fileToEdit,
fallbackPos
);
return insertAfterLastOccurrence(imports, `, ${symbolName}`, fileToEdit, fallbackPos);
}
return new NoopChange();
@@ -97,14 +85,7 @@ export function insertImport(
const insertAtBeginning = allImports.length === 0 && useStrict.length === 0;
const separator = insertAtBeginning ? '' : ';\n';
const toInsert =
`${separator}import ${open}${symbolName}${close}` +
` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`;
`${separator}import ${open}${symbolName}${close}` + ` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`;
return insertAfterLastOccurrence(
allImports,
toInsert,
fileToEdit,
fallbackPos,
ts.SyntaxKind.StringLiteral
);
return insertAfterLastOccurrence(allImports, toInsert, fileToEdit, fallbackPos, ts.SyntaxKind.StringLiteral);
}

View File

@@ -1,11 +1,11 @@
import {Tree} from '@angular-devkit/schematics';
import { Tree } from '@angular-devkit/schematics';
/**
* Adds a package to the package.json
*/
export function addPackageToPackageJson(host: Tree, type: string, pkg: string, version: string) {
export function addPackageToPackageJson(host: Tree, type: string, pkg: string, version: string): Tree {
if (host.exists('package.json')) {
const sourceText = host.read('package.json')!.toString('utf-8');
const sourceText = host.read('package.json')?.toString('utf-8');
const json = JSON.parse(sourceText);
if (!json[type]) {
json[type] = {};

View File

@@ -1,4 +1,3 @@
export interface IonicGlobal {
config?: any;
asyncQueue?: boolean;

View File

@@ -1,27 +1,31 @@
import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router';
export class IonicRouteStrategy implements RouteReuseStrategy {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
shouldDetach(_route: ActivatedRouteSnapshot): boolean {
return false;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
shouldAttach(_route: ActivatedRouteSnapshot): boolean {
return false;
}
store(_route: ActivatedRouteSnapshot, _detachedTree: DetachedRouteHandle): void {
store(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_route: ActivatedRouteSnapshot,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_detachedTree: DetachedRouteHandle
): void {
return;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
retrieve(_route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
return null;
}
shouldReuseRoute(
future: ActivatedRouteSnapshot,
curr: ActivatedRouteSnapshot
): boolean {
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
if (future.routeConfig !== curr.routeConfig) {
return false;
}

View File

@@ -1,4 +1,3 @@
interface ControllerShape<Opts, HTMLElm> {
create(options: Opts): Promise<HTMLElm>;
dismiss(data?: any, role?: string, id?: string): Promise<boolean>;
@@ -11,7 +10,7 @@ export class OverlayBaseController<Opts, Overlay> implements ControllerShape<Opt
/**
* Creates a new overlay
*/
create(opts?: Opts) {
create(opts?: Opts): Promise<Overlay> {
// TODO: next major release opts is not optional
return this.ctrl.create((opts || {}) as any);
}
@@ -19,14 +18,14 @@ export class OverlayBaseController<Opts, Overlay> implements ControllerShape<Opt
/**
* When `id` is not provided, it dismisses the top overlay.
*/
dismiss(data?: any, role?: string, id?: string) {
dismiss(data?: any, role?: string, id?: string): Promise<boolean> {
return this.ctrl.dismiss(data, role, id);
}
/**
* Returns the top overlay.
*/
getTop() {
getTop(): Promise<Overlay | undefined> {
return this.ctrl.getTop();
}
}

View File

@@ -1,8 +1,7 @@
declare const __zone_symbol__requestAnimationFrame: any;
declare const requestAnimationFrame: any;
export const raf = (h: any) => {
export const raf = (h: any): any => {
if (typeof __zone_symbol__requestAnimationFrame === 'function') {
return __zone_symbol__requestAnimationFrame(h);
}

View File

@@ -0,0 +1,51 @@
{
"root": true,
"ignorePatterns": [
"projects/**/*"
],
"overrides": [
{
"files": [
"*.ts"
],
"parserOptions": {
"project": [
"tsconfig.json",
"e2e/tsconfig.json"
],
"createDefaultProgram": true
},
"extends": [
"plugin:@angular-eslint/recommended",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"@angular-eslint/component-selector": [
"error",
{
"prefix": "app",
"style": "kebab-case",
"type": "element"
}
],
"@angular-eslint/directive-selector": [
"error",
{
"prefix": "app",
"style": "camelCase",
"type": "attribute"
}
]
}
},
{
"files": [
"*.html"
],
"extends": [
"plugin:@angular-eslint/template/recommended"
],
"rules": {}
}
]
}

View File

@@ -33,7 +33,9 @@
"output": "./svg"
}
],
"styles": ["src/styles.css"],
"styles": [
"src/styles.css"
],
"scripts": []
},
"configurations": {
@@ -47,7 +49,6 @@
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"progress": false,
@@ -86,10 +87,12 @@
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"builder": "@angular-eslint/builder:lint",
"options": {
"tsConfig": ["tsconfig.app.json", "tsconfig.spec.json"],
"exclude": ["**/node_modules/**"]
"lintFilePatterns": [
"src/**/*.ts",
"src/**/*.html"
]
}
},
"server": {
@@ -137,5 +140,8 @@
}
}
},
"defaultProject": "test-app"
"defaultProject": "test-app",
"cli": {
"defaultCollection": "@angular-eslint/schematics"
}
}

View File

@@ -8,6 +8,16 @@ describe('Form', () => {
cy.get('#input-touched').click();
cy.get('#touched-input-test').should('have.class', 'ion-touched');
});
describe('markAllAsTouched', () => {
it('should apply .ion-touched to nearest ion-item', () => {
cy.get('#mark-all-touched-button').click();
cy.get('form ion-item').each(item => {
cy.wrap(item).should('have.class', 'ion-touched');
});
});
});
});
describe('change', () => {

View File

@@ -41,3 +41,23 @@ describe('Modals', () => {
});
});
describe('Modals: Inline', () => {
beforeEach(() => {
cy.visit('/modal-inline');
});
it('should initially have no items', () => {
cy.get('ion-list ion-item').should('not.exist');
});
it('should have items after 1500ms', () => {
cy.wait(1500);
cy.get('ion-list ion-item:nth-child(1)').should('have.text', 'A');
cy.get('ion-list ion-item:nth-child(2)').should('have.text', 'B');
cy.get('ion-list ion-item:nth-child(3)').should('have.text', 'C');
cy.get('ion-list ion-item:nth-child(4)').should('have.text', 'D');
});
});

View File

@@ -0,0 +1,18 @@
describe('Popovers: Inline', () => {
beforeEach(() => {
cy.visit('/popover-inline');
});
it('should initially have no items', () => {
cy.get('ion-list ion-item').should('not.exist');
});
it('should have items after 1500ms', () => {
cy.wait(1500);
cy.get('ion-list ion-item:nth-child(1)').should('have.text', 'A');
cy.get('ion-list ion-item:nth-child(2)').should('have.text', 'B');
cy.get('ion-list ion-item:nth-child(3)').should('have.text', 'C');
cy.get('ion-list ion-item:nth-child(4)').should('have.text', 'D');
});
});

View File

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@
"start": "npm run sync && ng serve",
"sync:build": "sh scripts/build-ionic.sh",
"sync": "sh scripts/sync.sh",
"build": "npm run sync && ng build --prod --no-progress",
"build": "npm run sync && ng build --configuration production --no-progress",
"lint": "ng lint",
"postinstall": "npm run sync && ngcc",
"serve:ssr": "node dist/test-app/server/main.js",
@@ -20,41 +20,49 @@
"test.watch": "concurrently \"npm run start\" \"wait-on http-get://localhost:4200 && npm run cy.open\" --kill-others --success first"
},
"dependencies": {
"@angular/animations": "^11.2.11",
"@angular/common": "^11.2.11",
"@angular/compiler": "^11.2.11",
"@angular/core": "^11.2.11",
"@angular/forms": "^11.2.11",
"@angular/platform-browser": "^11.2.11",
"@angular/platform-browser-dynamic": "^11.2.11",
"@angular/platform-server": "^11.2.11",
"@angular/router": "^11.2.11",
"@angular/animations": "^12.2.8",
"@angular/common": "^12.2.8",
"@angular/compiler": "^12.2.8",
"@angular/core": "^12.2.8",
"@angular/forms": "^12.2.8",
"@angular/platform-browser": "^12.2.8",
"@angular/platform-browser-dynamic": "^12.2.8",
"@angular/platform-server": "^12.2.8",
"@angular/router": "^12.2.8",
"@ionic/angular": "^5.3.1",
"@ionic/angular-server": "^5.3.1",
"@nguniversal/express-engine": "^11.2.1",
"@nguniversal/express-engine": "^12.1.1",
"angular-in-memory-web-api": "^0.11.0",
"core-js": "^2.6.11",
"express": "^4.15.2",
"rxjs": "^6.5.5",
"tslib": "^2.0.0",
"zone.js": "^0.10.3"
"typescript-eslint-language-service": "^4.1.5",
"zone.js": "^0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "^0.1102.10",
"@angular/cli": "^11.2.10",
"@angular/compiler-cli": "^11.2.11",
"@angular/language-service": "^11.2.11",
"@nguniversal/builders": "^11.2.1",
"@angular-devkit/build-angular": "^12.2.8",
"@angular-eslint/builder": "12.5.0",
"@angular-eslint/eslint-plugin": "12.5.0",
"@angular-eslint/eslint-plugin-template": "12.5.0",
"@angular-eslint/schematics": "12.5.0",
"@angular-eslint/template-parser": "12.5.0",
"@angular/cli": "^12.2.8",
"@angular/compiler-cli": "^12.2.8",
"@angular/language-service": "^12.2.8",
"@nguniversal/builders": "^12.1.1",
"@types/express": "^4.17.7",
"@types/node": "^12.12.54",
"codelyzer": "^6.0.1",
"@typescript-eslint/eslint-plugin": "4.28.2",
"@typescript-eslint/parser": "4.28.2",
"concurrently": "^6.0.0",
"cypress": "^6.7.1",
"eslint": "^7.26.0",
"ts-loader": "^6.2.2",
"ts-node": "^8.3.0",
"tslint": "~6.1.0",
"typescript": "^4.0.7",
"typescript": "^4.3.5",
"wait-on": "^5.2.1",
"webpack": "^5.61.0",
"webpack-cli": "^3.3.12"
}
}

View File

@@ -27,7 +27,9 @@ const routes: Routes = [
{ path: 'inputs', component: InputsComponent },
{ path: 'form', component: FormComponent },
{ path: 'modals', component: ModalComponent },
{ path: 'modal-inline', loadChildren: () => import('./modal-inline').then(m => m.ModalInlineModule) },
{ path: 'view-child', component: ViewChildComponent },
{ path: 'popover-inline', loadChildren: () => import('./popover-inline').then(m => m.PopoverInlineModule) },
{ path: 'providers', component: ProvidersComponent },
{ path: 'router-link', component: RouterLinkComponent },
{ path: 'router-link-page', component: RouterLinkPageComponent },

View File

@@ -63,7 +63,7 @@ import { AlertComponent } from './alert/alert.component';
AppRoutingModule,
FormsModule,
ReactiveFormsModule,
IonicModule.forRoot(),
IonicModule.forRoot({ keyboardHeight: 12345 }),
],
entryComponents: [
ModalExampleComponent,

View File

@@ -12,7 +12,8 @@
<ion-item>
<ion-label>DateTime</ion-label>
<ion-datetime formControlName="datetime" min="1994-03-14" max="2017-12-09" display-format="MM/DD/YYYY"></ion-datetime>
<ion-datetime formControlName="datetime" min="1994-03-14" max="2017-12-09" display-format="MM/DD/YYYY">
</ion-datetime>
</ion-item>
<ion-item>
@@ -65,6 +66,7 @@
<p>
Form Submit: <span id="submit">{{submitted}}</span>
</p>
<ion-button id="mark-all-touched-button" (click)="markAllAsTouched()">Mark all as touched</ion-button>
<ion-button id="submit-button" type="submit" [disabled]="!profileForm.valid">Submit</ion-button>
</form>

View File

@@ -46,4 +46,8 @@ export class FormComponent {
});
}
markAllAsTouched() {
this.profileForm.markAllAsTouched();
}
}

View File

@@ -0,0 +1,2 @@
export * from './modal-inline.component';
export * from './modal-inline.module';

View File

@@ -0,0 +1,16 @@
import { NgModule } from "@angular/core";
import { RouterModule } from "@angular/router";
import { ModalInlineComponent } from ".";
@NgModule({
imports: [
RouterModule.forChild([
{
path: '',
component: ModalInlineComponent
}
])
],
exports: [RouterModule]
})
export class ModalInlineRoutingModule { }

View File

@@ -0,0 +1,11 @@
<ion-modal [isOpen]="true" [breakpoints]="[0.1, 0.5, 1]" [initialBreakpoint]="0.5">
<ng-template>
<ion-content>
<ion-list>
<ion-item *ngFor="let item of items">
<ion-label>{{ item }}</ion-label>
</ion-item>
</ion-list>
</ion-content>
</ng-template>
</ion-modal>

View File

@@ -0,0 +1,21 @@
import { AfterViewInit, Component } from "@angular/core";
/**
* Validates that inline modals will correctly display
* dynamic contents that are updated after the modal is
* display.
*/
@Component({
selector: 'app-modal-inline',
templateUrl: 'modal-inline.component.html'
})
export class ModalInlineComponent implements AfterViewInit {
items: string[] = [];
ngAfterViewInit(): void {
setTimeout(() => {
this.items = ['A', 'B', 'C', 'D'];
}, 1000);
}
}

View File

@@ -0,0 +1,12 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { IonicModule } from "@ionic/angular";
import { ModalInlineRoutingModule } from "./modal-inline-routing.module";
import { ModalInlineComponent } from "./modal-inline.component";
@NgModule({
imports: [CommonModule, IonicModule, ModalInlineRoutingModule],
declarations: [ModalInlineComponent],
exports: [ModalInlineComponent]
})
export class ModalInlineModule { }

View File

@@ -0,0 +1 @@
export * from './popover-inline.module';

View File

@@ -0,0 +1,14 @@
import { NgModule } from "@angular/core";
import { RouterModule } from "@angular/router";
import { PopoverInlineComponent } from "./popover-inline.component";
@NgModule({
imports: [RouterModule.forChild([
{
path: '',
component: PopoverInlineComponent
}
])],
exports: [RouterModule]
})
export class PopoverInlineRoutingModule { }

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