Compare commits

..

237 Commits

Author SHA1 Message Date
Liam DeBeasi
97123cd6c3 5.2.3 2020-07-01 13:28:43 -04:00
Brandy Carney
9413aa0bac docs(coc): add Contributor Covenant Code of Conduct (#21550) 2020-06-29 11:35:29 -04:00
Adam Bradley
ce6e637787 chore(deps): bump deps (#21632) 2020-06-29 10:21:06 -05:00
Adam Bradley
7a29e0e3c7 chore(ionicons): bump to ionicons 5.1.2, add package-lock.json (#21629) 2020-06-26 09:42:05 -05:00
Liam DeBeasi
8c79e2c5b5 fix(select): change role to listbox (#21609)
fixes https://github.com/ionic-team/ionic/issues/21601
2020-06-25 11:46:52 -04:00
Liam DeBeasi
26674f1dfa fix(slides): enable keyboard integration (#21608)
resolves #21554
2020-06-23 16:31:22 -04:00
Liam DeBeasi
88f23b1626 fix(textarea): add aria-labelledby to native textarea (#21606)
resolves #21600
2020-06-23 16:29:41 -04:00
Chris
a5b3750ee2 fix(angular): expose createAnimation in addition to AnimationController (#21616)
closes #21615
2020-06-23 16:23:22 -04:00
Liam DeBeasi
fbcd3f8c08 docs(select-option): clarify that disabled does not apply for action sheets (#21584)
resolves https://github.com/ionic-team/ionic/issues/21578
2020-06-19 13:45:49 -04:00
Liam DeBeasi
04ce642369 merge release-5.2.2
5.2.2
2020-06-17 12:46:28 -04:00
Liam DeBeasi
84c421a4b0 5.2.2 2020-06-17 12:03:58 -04:00
Liam DeBeasi
1decc13cb8 docs(modal): clarify backdrop usage for card modals (#21556) 2020-06-17 11:25:07 -04:00
Liam DeBeasi
17308f247f fix(segment): ensure checked classes get set after not having a value (#21547) 2020-06-16 11:22:17 -04:00
Liam DeBeasi
d8b377ffeb fix(input): add aria-label to clear button (#21538) 2020-06-15 13:36:11 -04:00
Liam DeBeasi
24cfdc308f fix(ios): respect toolbar opacity when doing nav transition (#21512) 2020-06-15 09:39:06 -04:00
Liam DeBeasi
bcccc217b8 fix(action-sheet, alert): resolve double click issue when running in iOS mode on chrome (#21506) 2020-06-12 10:36:09 -04:00
Liam DeBeasi
e968bd029a fix(angular): fix issue where navAnimation was being incorrectly overridden (#21508) 2020-06-11 13:30:58 -04:00
Masahiko Sakakibara
7c8f621536 chore(template): add v5.0 option to issue templates (#21498) 2020-06-11 11:21:18 -04:00
Liam DeBeasi
edceac0745 merge release-5.2.1
Release 5.2.1
2020-06-11 11:20:23 -04:00
Liam DeBeasi
2969f9f9f2 5.2.1 2020-06-11 10:43:55 -04:00
Liam DeBeasi
9223abc1f8 fix(angular): resolve issue when not using ngModel on components 2020-06-11 10:43:49 -04:00
Liam DeBeasi
b37c158eea merge release-5.2.0
Release 5.2.0
2020-06-10 13:26:16 -04:00
Liam DeBeasi
ce6448b068 chore(): add Silicon to version 5.2.0 2020-06-10 12:54:30 -04:00
Liam DeBeasi
fd65ceec84 5.2.0 2020-06-10 12:52:24 -04:00
Evgeniy
0bf9449ee1 fix(img): use setTimeout fallback on older versions of chrome (#21358) 2020-06-10 12:03:37 -04:00
Brandy Carney
cf3035778c chore(stencil): update to v1.14 (#21458) 2020-06-10 11:36:02 -04:00
Brandy Carney
17375d2325 feat(all): add shadow parts to missing components (#21436) 2020-06-10 09:58:33 -04:00
Stefanos Anagnostou
df408f91f1 feat(fab-button): add close icon font size css variable (#19628)
Co-authored-by: Brandy Carney <brandy@ionic.io>
2020-06-10 09:34:48 -04:00
Liam DeBeasi
e95b481a53 fix(angular): patch FormControl methods to properly sync Ionic form classes (#21429)
Co-authored-by: Mark Levy <MarkChrisLevy@users.noreply.github.com>
2020-06-09 11:54:40 -04:00
Stefanos Anagnostou
698e526b9f feat(fab-button): add closeIcon property (#19626) 2020-06-08 16:46:03 -04:00
Liam DeBeasi
f34d3752e3 feat(all): add support for configuring animations on a per-page basis (#21433) 2020-06-08 15:49:14 -04:00
Matthias Max
c8db0d5eeb fix(router): going back uses correct nav transition (#21301) 2020-06-08 12:23:27 -04:00
Liam DeBeasi
a4f0bdb4c3 fix(modal): set card-style modal height using the --height css variable (#21453) 2020-06-08 10:29:39 -04:00
Liam DeBeasi
187917c746 chore(): exempt bugs and feature requests from stale issues (#21435) 2020-06-05 09:45:27 -04:00
Liam DeBeasi
137c49d70b fix(scroll-assist): improve scroll detection accuracy (#21416) 2020-06-03 10:01:01 -04:00
Alexey Vinogradov
5bf83b80d7 feat(all): add optional generics typings for overlay component methods (#21393) 2020-06-03 09:08:27 -04:00
Niklas Merz
c7e94a1f23 docs(datetime): specify default value for dayShortNames (#21281) 2020-06-02 17:21:38 -04:00
Celilsemi Sam Erkiner
1ed81693f2 feat(alert): add support for custom input attributes (#21365) 2020-06-01 11:18:59 -04:00
Thomas Clark
5f2001c43c fix(reorder-group): revert item to original position when passing false to complete (#21396)
fixes #19128
2020-05-29 14:35:34 -04:00
Brandy Carney
882f8fef07 fix(item): inherit align-items from parent item (#19278)
inherits alignment in inner item, sets item alignment to center

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

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

* chore(angular): bump ng-packagr

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

references #17515

* style(input): fix lint error

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

* fix(item): adds delegatesFocus to shadow

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

closes #20993 closes #20743
2020-05-12 12:02:07 -04:00
Liam DeBeasi
85cc35ee91 fix(segment-button): screen readers now announce selected state properly (#21273) 2020-05-12 11:37:56 -04:00
Liam DeBeasi
7166a290cc fix(all): improve scroll assist reliability for below the fold inputs (#21206) 2020-05-11 15:44:59 -04:00
Liam DeBeasi
1e6f92377a fix(refresher): refresher completes even after switching to a new tab (#21236) 2020-05-11 15:21:26 -04:00
Liam DeBeasi
8e11ecc136 fix(picker): haptics now work properly (#21268) 2020-05-11 15:10:19 -04:00
Liam DeBeasi
1fbdb2255e fix(toggle): screen readers now announce toggle properly (#21168) 2020-05-08 11:59:04 -04:00
Liam DeBeasi
0c13f25bbb fix(header): do not error on collapsable header on devices that do not support IntersectionObserve (#21222) 2020-05-08 11:57:50 -04:00
Liam DeBeasi
9d0dcbbd31 fix(overlays): respect keyboardClose property when opening overlays (#21240) 2020-05-08 11:56:40 -04:00
Liam DeBeasi
f23f1cb37e fix(refresher): correctly select shadow root on older browsers (#21237) 2020-05-08 11:54:57 -04:00
Liam DeBeasi
f334e83a43 fix(md): do not hide page when swipe gesture is cancelled (#21247) 2020-05-08 10:16:42 -04:00
Liam DeBeasi
bb62023a0c fix(all): overlay components no longer display outline when focused (#21226) 2020-05-07 16:33:51 -04:00
Liam DeBeasi
cae389bd12 chore(): remove undocumented back button parts (#21223) 2020-05-07 16:32:18 -04:00
Liam DeBeasi
9308f0329c merge release-5.1.0
5.1.0
2020-04-30 18:25:49 -04:00
Liam DeBeasi
042686c7a4 5.1.0 2020-04-30 17:34:30 -04:00
Ely Lucas
43f9d24824 feat(react): Add IonTabsContext to add some missing element methods, closes #19935 (#21171) 2020-04-30 15:08:23 -06:00
Liam DeBeasi
ae5f1ddff0 feat(app): keyboard open and close events (#18478) 2020-04-30 16:07:44 -04:00
Liam DeBeasi
dea9248763 fix(all): gestures should use a passive listener (#21038) 2020-04-30 16:03:54 -04:00
Liam DeBeasi
eab3373213 fix(router): account for query string when pushing page (#21071) 2020-04-30 16:02:21 -04:00
Liam DeBeasi
bcf0fa17a9 docs(select): direct old controller links to component pages (#21167) 2020-04-30 12:10:08 -04:00
Liam DeBeasi
a261cb1f67 chore(select): make note about interfaceOptions and alert input/buttons clearer (#21166) 2020-04-30 11:12:54 -04:00
Brandy Carney
6bc62e1da5 docs(select): update headings to display properly in the docs (#21159) 2020-04-30 11:10:33 -04:00
Brandy Carney
04ace4c983 feat(toggle): improve customization with css vars and auto-adjust handle width and height (#21050)
- Updates Material Design toggle background & box-shadow to match spec
- Adds the following variables: --handle-box-shadow, --handle-height, --handle-max-height, --handle-transition, --handle-width, --handle-spacing
- Improves customization of toggle by inheriting properties where possible and auto-adjusting the handle height and position based on the width and height of the toggle

Closes #19868, closes #20474
2020-04-29 18:31:34 -04:00
Liam DeBeasi
83dcc7168a fix(refresher): properly calculate content dimensions in native ion-refresher (#21157) 2020-04-29 13:53:01 -04:00
Liam DeBeasi
c53b136dbe fix(all): use proper undefined check when using Haptics plugin (#21156)
fixes #21148
2020-04-29 13:13:28 -04:00
Liam DeBeasi
fc2be8d08b fix(overlays): focus overlay when presented (#20997)
fixes #19882, fixes #17126
2020-04-28 16:43:00 -04:00
Brandy Carney
c54911f451 docs(refresher): update usage to correct ionicons 5 icon (#21141)
closes ionic-team/ionic-docs#1263
2020-04-28 15:34:01 -04:00
Liam DeBeasi
fa9ddc91bc feat(all): add ability to eject from Ionic sanitizer (#20457)
resolves #18277
2020-04-27 16:03:39 -04:00
Liam DeBeasi
578ab93d29 feat(content): add parts support for background, scroll (#20929) 2020-04-27 16:01:39 -04:00
Liam DeBeasi
64144960b0 feat(item): add parts support for detail-icon (#20979) 2020-04-27 15:33:54 -04:00
Liam DeBeasi
3821c0463a feat(): add ability to continue processing hardware back button events (#20613)
fixes #17824
2020-04-27 12:58:37 -04:00
Liam DeBeasi
429edb053b feat(gesture): add option to run inside NgZone for Angular apps (#20685)
fixes #20529
2020-04-27 12:50:44 -04:00
Liam DeBeasi
15203de08b fix(angular): do not navigate to same tab if already active (#21085)
fixes #21074, fixes #19943
2020-04-27 12:19:23 -04:00
Liam DeBeasi
671802f9a2 fix(overlays): prevent accidental clicks when dismissing overlays (#21093)
fixes #21092
2020-04-27 11:33:23 -04:00
Liam DeBeasi
14c226ce75 fix(back-button): screen readers correctly announce the back button text (#21053)
fixes #21043
2020-04-27 11:31:32 -04:00
Liam DeBeasi
66e8e6404d fix(select): account for MutationObserver when performing SSR (#21068)
fixes #21063
2020-04-27 11:29:44 -04:00
Liam DeBeasi
4bd9134473 fix(modal): swipeToClose property is now reactive (#21073)
fixes #21072
2020-04-27 11:27:18 -04:00
EinfachHans
1b11ff7fb9 feat(back-button): add 'backButtonDefaultHref' property to Ionic Config (#20491)
closes #19305

Co-authored-by: Brandy Carney <brandy@ionic.io>
2020-04-27 10:57:43 -04:00
Liam DeBeasi
32ecdd6753 feat(gesture): add support for blurring active inputs on gesture start (#20638)
fixes #20588
2020-04-27 10:52:14 -04:00
Alex Currie-Clark
32ee040e3f fix(textarea): height is set correctly when using autoGrow in modals (#20971)
fixes #18993
2020-04-24 13:54:51 -04:00
Liam DeBeasi
1622d9bb3c feat(textarea): add support for inputmode and enterkeyhint (#21106) 2020-04-24 11:56:10 -04:00
Antoine
a75e8f34d6 fix(datetime): locale inputs are now reactive (#20826)
fixes #20367
2020-04-24 11:29:22 -04:00
Liam DeBeasi
e585a22ac9 chore(): change contributing link text (#21121) 2020-04-23 15:57:18 -04:00
Liam DeBeasi
395d7ec5a3 chore(): add extra lines for ionitron message (#21120) 2020-04-23 15:53:02 -04:00
Liam DeBeasi
71c7284ed5 chore(): update contributing docs, update ionitron bot (#21117) 2020-04-23 15:44:21 -04:00
Liam DeBeasi
0a33a095f1 chore(button): remove unreleased parts support (#21111) 2020-04-23 12:23:48 -04:00
Liam DeBeasi
50bc212d0b feat(menu): add parts support for backdrop, container (#20978) 2020-04-23 12:22:19 -04:00
Liam DeBeasi
76ca475734 feat(datetime): add parts support for placeholder, text (#20930) 2020-04-23 12:20:25 -04:00
Liam DeBeasi
63c75edd21 feat(img): add parts support for image (#20943) 2020-04-23 12:19:52 -04:00
Liam DeBeasi
d4b9151396 feat(checkbox): add parts support for container, mark (#20950) 2020-04-23 12:19:24 -04:00
Liam DeBeasi
228ca2b093 feat(radio): add parts support for container, mark (#20952) 2020-04-23 12:18:58 -04:00
Liam DeBeasi
ba20209604 feat(reorder): add parts support for icon (#20960) 2020-04-23 12:18:32 -04:00
Liam DeBeasi
619f67a00b feat(range): add parts support for bar, bar-active, knob, pin, tick, tick-active (#20961) 2020-04-23 12:18:04 -04:00
Liam DeBeasi
d2b772f19f feat(toggle): add parts support for handle, track (#20962) 2020-04-23 12:17:17 -04:00
Liam DeBeasi
15a603b397 fix(searchbar): screen readers correctly announce the cancel button text (#21049)
fixes #21013
2020-04-23 12:15:54 -04:00
Liam DeBeasi
30a1c89688 feat(select): add parts support for placeholder, icon, text (#21108) 2020-04-23 12:14:21 -04:00
Liam DeBeasi
63d8f6239c fix(loading): screen readers no longer incorrectly announce spinner (#21116)
fixes #21107
2020-04-23 12:07:43 -04:00
Brandy Carney
ae0a98924f chore(api): update api generator to include parts in the public API (#21110) 2020-04-22 15:41:44 -04:00
Liam DeBeasi
e442324753 fix(action-sheet): show correct cancel button background on dark mode (#21084)
fixes #21082
2020-04-22 14:27:18 -04:00
Liam DeBeasi
57b2a6b0cc docs(input): provide info regarding pattern used with date type (#21067)
fixes #21020
2020-04-17 10:09:21 -04:00
Liam DeBeasi
497380743d fix(md): do not display blank screen when using MD page transition and swipe gesture (#21058)
fixes #21056
2020-04-16 13:15:02 -04:00
Liam DeBeasi
6a167172ff chore(): update to swiper 5.3.7 (#21055) 2020-04-16 09:55:12 -04:00
Brandy Carney
fe175380d2 chore(github): remove weekly digest 2020-04-15 16:15:47 -04:00
Liam DeBeasi
e90683a713 feat(searchbar): add support for enterkeyhint (#21036)
fixes #21034
2020-04-15 15:08:43 -04:00
Liam DeBeasi
3efaf43821 feat(input): add support for enterkeyhint (#21035)
fixes #21034
2020-04-15 15:08:12 -04:00
Masanori Onoue
102a842bd2 fix(react): IonTabBar properly extends IonicReactProps (#21009)
fixes #21006
2020-04-10 13:09:06 -04:00
Ramez Atassi
7a21708d24 fix(split-pane): properly show border in rtl mode (#20995)
closes #20994

Co-authored-by: Ramez Atassi <ramez@al-salamah.net>
2020-04-08 15:27:24 -04:00
Liam DeBeasi
8a02b28efe fix(ios): properly animate content when navigating from a tabbed page (#20918)
fixes #20912
2020-04-08 15:16:10 -04:00
Liam DeBeasi
6f13b8c792 perf(all): improve scroll assist responsiveness (#20987)
resolves #20922
2020-04-07 12:19:58 -04:00
EinfachHans
acaa1d9ef7 feat(searchbar): add border-radius css variable (#20662)
fixes #17426
fixes #18247
2020-04-03 13:01:07 -04:00
Liam DeBeasi
5b9840508f feat(animation): add option to clean up old animation stylesheets (#20940)
fixes #20610
2020-04-03 09:28:41 -04:00
Liam DeBeasi
4e28445ecb feat(slides): update to swiper 5 (#20917)
fixes #20033
2020-04-02 16:19:28 -04:00
Liam DeBeasi
e23dec5eb9 fix(ios): account for nested tabs with page transition (#20955)
fixes #20948
2020-04-02 15:03:08 -04:00
Liam DeBeasi
e0f3c09bab chore(): update @stencil/core (#20945)
- also updated @stencil/sass
2020-04-01 17:45:26 -04:00
Mike Hartington
6fac5ff7fc docs(modal): remove navParams usage 2020-04-01 10:13:43 -04:00
Liam DeBeasi
3123a318b6 fix(slides): slides no longer breaks when Angular Ivy enabled (#20899)
fixes #20356
2020-03-31 13:07:25 -04:00
Liam DeBeasi
e5e02d4f88 feat(toast): add white-space variable for toast message (#20729)
fixes #20727
2020-03-30 12:02:46 -04:00
Liam DeBeasi
bd64509bae fix(modal): properly inherit border radius for modals on Safari (#20887)
fixes #20878
2020-03-30 11:56:46 -04:00
Liam DeBeasi
9b534bd43f chore(): generate correct change log (#20888) 2020-03-30 11:53:37 -04:00
Liam DeBeasi
8a161f053f merge release-5.0.7
Release 5.0.7
2020-03-26 11:48:51 -04:00
Liam DeBeasi
af1a6d6d6d 5.0.7 2020-03-26 11:30:32 -04:00
Liam DeBeasi
5816cf52a7 fix(modal): properly target card modal for iPadOS styles (#20884) 2020-03-26 11:19:47 -04:00
Liam DeBeasi
7c5661fcfb fix(modal): properly target card modal for iPadOS styles (#20884) 2020-03-26 11:19:23 -04:00
Liam DeBeasi
2b854ec2cc merge release-5.0.6
Release 5.0.6
2020-03-25 15:26:55 -04:00
Liam DeBeasi
3a269e27b6 merge release-5.0.6
Release 5.0.6
2020-03-25 15:26:00 -04:00
Liam DeBeasi
576da29ac6 5.0.6 2020-03-25 14:57:31 -04:00
Jakob Engelbrecht
6ed1c51321 fix(): only cascade mode from parent Ionic components (#20828)
fixes #20055
2020-03-25 14:39:38 -04:00
Liam DeBeasi
75bae403e9 fix(modal): respect card-style modal spec for iPadOS (#20750)
fixes #20700
2020-03-25 14:39:38 -04:00
Liam DeBeasi
321140ff73 fix(title): large title now inherits global color styling during nav transition (#20862) 2020-03-25 14:39:38 -04:00
Liam DeBeasi
d3d7de121b fix(): scroll assists now recognizes inputs on inner pages and modals (#20864)
fixes #20843
2020-03-25 14:39:38 -04:00
Liam DeBeasi
43fbd9d2f2 chore(): properly export ionic page transition functions (#20860) 2020-03-25 14:39:38 -04:00
Liam DeBeasi
dff3816c04 fix(modal): properly apply border radius on card-style modal (#20852)
fixes #20851
2020-03-25 14:39:38 -04:00
Liam DeBeasi
3bd6b5def2 fix(title): improve reliability of large title ios nav transition (#20861) 2020-03-25 14:38:46 -04:00
Liam DeBeasi
2707289b36 fix(content): apply --offset-top and --offset-bottom values correctly (#20790)
fixes #20735
2020-03-25 14:38:46 -04:00
Brandy Carney
d91e22d820 fix(item-divider): update design to match native iOS (#20854) 2020-03-25 14:38:45 -04:00
Manu MA
5a20f84aa4 refactor(): minor updates for next stencil version (#20787) 2020-03-25 14:38:45 -04:00
Liam DeBeasi
71f118201b fix(modal): properly remove safe area padding on card-modal (#20853)
fixes #20799
2020-03-25 14:38:45 -04:00
Hayden Braxton
8bd5bace73 fix(textarea): properly adjust auto-grow textarea in scrolled content (#19776)
fixes #19193
2020-03-25 14:38:45 -04:00
Hayden Braxton
a3fc77be91 fix(content): set overscroll-behavior based on the scroll direction (#20011)
resolves #20010
2020-03-25 14:38:08 -04:00
Liam DeBeasi
14ac8ae24c chore(): add show-modal in component not in animation (#20833)
resolves #20827
2020-03-25 14:38:08 -04:00
Liam DeBeasi
b1a87c8892 fix(refresher): properly dismiss refresher when completed synchronously (#20815)
fixes #20803
2020-03-25 14:38:08 -04:00
Liam DeBeasi
cdfd50b554 fix(segment): automatically expand width for scrollable segment buttons (#20763)
fixes #20566
2020-03-25 14:37:56 -04:00
Brandy Carney
7bc51911f6 fix(list): show bottom border on last item in a list followed by a list (#20798) 2020-03-25 14:37:50 -04:00
Liam DeBeasi
253cd96164 fix(modal): backdrop and box shadows no longer stack when opening multiple modals (#20801)
fixes #20800
2020-03-25 14:37:44 -04:00
Liam DeBeasi
12932dd202 fix(modal): backdrop is no longer tappable on card-style modal on smaller screens (#20802)
fixes #20783
2020-03-25 14:37:34 -04:00
Liam DeBeasi
f23ac44c9a fix(item-sliding): account for swipe to go back gesture when opening item-options (#20777)
fixes #20773
2020-03-25 14:37:22 -04:00
Brandy Carney
2d5d2515be fix(slides): check that mutation observer is defined for ssr (#20791) 2020-03-25 14:37:16 -04:00
Liam DeBeasi
e24060ecd9 fix(): properly scroll to input with scroll assist (#20742)
fixes #19589
2020-03-25 14:37:10 -04:00
Liam DeBeasi
0514b421ec docs(segment): clarify usage of scrollable segments (#20765)
resolves #20692
2020-03-25 14:37:03 -04:00
Liam DeBeasi
0897c3f9c2 fix(react): expose correct type for CreateAnimation (#20775)
fixes #20771
2020-03-25 14:36:58 -04:00
Liam DeBeasi
f2dbe1ff3b fix(angular): respect animation property for ion-router-outlet (#20767)
fixes #20764
2020-03-25 14:36:47 -04:00
Liam DeBeasi
2ece194a08 fix(angular): export Animation and Gesture related types (#20766) 2020-03-25 14:36:47 -04:00
Simon Hänisch
ab146c96ec fix(segment): scrollable segments only show scrollbar if they overflow (#20760)
fixes #20758
2020-03-25 14:36:24 -04:00
Jakob Engelbrecht
364a0a63da fix(): only cascade mode from parent Ionic components (#20828)
fixes #20055
2020-03-25 14:33:13 -04:00
Liam DeBeasi
ae7fe543fe fix(modal): respect card-style modal spec for iPadOS (#20750)
fixes #20700
2020-03-25 13:36:54 -04:00
Liam DeBeasi
794c3d4e96 fix(title): large title now inherits global color styling during nav transition (#20862) 2020-03-25 12:14:26 -04:00
Liam DeBeasi
e2cba41e32 fix(): scroll assists now recognizes inputs on inner pages and modals (#20864)
fixes #20843
2020-03-25 11:45:56 -04:00
Liam DeBeasi
f340cb64c8 chore(): properly export ionic page transition functions (#20860) 2020-03-25 11:43:02 -04:00
Liam DeBeasi
645578c66b fix(modal): properly apply border radius on card-style modal (#20852)
fixes #20851
2020-03-25 11:10:57 -04:00
Liam DeBeasi
df27793702 fix(title): improve reliability of large title ios nav transition (#20861) 2020-03-24 18:06:17 -04:00
Liam DeBeasi
8680c2e83b fix(content): apply --offset-top and --offset-bottom values correctly (#20790)
fixes #20735
2020-03-24 15:44:56 -04:00
Brandy Carney
8660e61b96 fix(item-divider): update design to match native iOS (#20854) 2020-03-24 12:03:41 -04:00
Manu MA
976e68da5b refactor(): minor updates for next stencil version (#20787) 2020-03-24 11:59:07 -04:00
Liam DeBeasi
7a4ddde5ce fix(modal): properly remove safe area padding on card-modal (#20853)
fixes #20799
2020-03-24 11:53:29 -04:00
Hayden Braxton
2796e9453f fix(textarea): properly adjust auto-grow textarea in scrolled content (#19776)
fixes #19193
2020-03-24 11:48:57 -04:00
Hayden Braxton
c68160ecd3 fix(content): set overscroll-behavior based on the scroll direction (#20011)
resolves #20010
2020-03-23 15:07:08 -04:00
Liam DeBeasi
879b90c3c4 chore(): add show-modal in component not in animation (#20833)
resolves #20827
2020-03-20 12:23:09 -04:00
Liam DeBeasi
dae1ce8526 fix(refresher): properly dismiss refresher when completed synchronously (#20815)
fixes #20803
2020-03-19 09:52:49 -04:00
Liam DeBeasi
f86c82639f fix(segment): automatically expand width for scrollable segment buttons (#20763)
fixes #20566
2020-03-18 16:14:06 -04:00
Brandy Carney
de28bd3b79 fix(list): show bottom border on last item in a list followed by a list (#20798) 2020-03-18 15:43:36 -04:00
Liam DeBeasi
0b134dfebf fix(modal): backdrop and box shadows no longer stack when opening multiple modals (#20801)
fixes #20800
2020-03-18 13:44:11 -04:00
Liam DeBeasi
8b6536098a fix(modal): backdrop is no longer tappable on card-style modal on smaller screens (#20802)
fixes #20783
2020-03-18 13:20:14 -04:00
Walter S
39e6c8f55b feat(angular): support multi-app for ng-add schematic (#20768)
* chore(angular): Add missing argument type information.

* chore(angular): Add missing semicolon.

* fix(angular): Properly detect the Angular project name for multi-app repositories.

* fix(angular): Fix generated angular.json when using ng-add  in multi-app repositories.

* chore(angular): Improve reported warnings when using ng-add with invalid workspace configuration.
2020-03-18 12:46:14 -04:00
Liam DeBeasi
3514dd8362 fix(item-sliding): account for swipe to go back gesture when opening item-options (#20777)
fixes #20773
2020-03-17 11:00:38 -04:00
Brandy Carney
e2df046eff fix(slides): check that mutation observer is defined for ssr (#20791) 2020-03-16 17:36:58 -04:00
Liam DeBeasi
0e91c6c502 fix(): properly scroll to input with scroll assist (#20742)
fixes #19589
2020-03-16 15:38:11 -04:00
Liam DeBeasi
cfc6773cb9 docs(segment): clarify usage of scrollable segments (#20765)
resolves #20692
2020-03-16 09:51:13 -04:00
Liam DeBeasi
2982c95993 fix(react): expose correct type for CreateAnimation (#20775)
fixes #20771
2020-03-13 10:10:38 -04:00
Liam DeBeasi
bfb78abda0 fix(angular): respect animation property for ion-router-outlet (#20767)
fixes #20764
2020-03-12 15:26:24 -04:00
Liam DeBeasi
5049d19917 fix(angular): export Animation and Gesture related types (#20766) 2020-03-12 14:56:36 -04:00
Simon Hänisch
13e4e5b03d fix(segment): scrollable segments only show scrollbar if they overflow (#20760)
fixes #20758
2020-03-12 11:01:42 -04:00
Liam DeBeasi
ac229528eb merge release-5.0.5
Release 5.0.5
2020-03-11 14:30:12 -04:00
Liam DeBeasi
f9f3095eb4 merge release-5.0.5
5.0.5
2020-03-11 14:29:29 -04:00
Liam DeBeasi
572f7b6934 5.0.5 2020-03-11 13:07:09 -04:00
Simon Hänisch
4d34ce6a31 fix(label): text overflow for slotted headings (#20690)
fixes #17087
2020-03-11 12:42:46 -04:00
Brandy Carney
d53595eb16 fix(item): apply proper margin left for slotted icon in RTL (#20684)
fixes #20653
2020-03-11 11:52:01 -04:00
Adam Bradley
a1bf2f5b8f chore(ionicons): bump ionicons version (#20704) 2020-03-11 11:36:04 -04:00
Brandy Carney
7ecde36f9d fix(button): allow overflow to be overridden by the CSS variable (#20738)
fixes #20726
2020-03-11 11:35:26 -04:00
Liam DeBeasi
87a27216d0 fix(header): collapsible header now works when navigating quickly (#20728)
fixes #20725
2020-03-11 10:58:26 -04:00
Liam DeBeasi
f6c3ba7e5a fix(header): collapsable header should default to using content background (#20736)
fixes #20691
2020-03-11 10:52:33 -04:00
Liam DeBeasi
f796074f33 chore(): set @nguniversal/builders dependency to exact version (#20734) 2020-03-10 11:22:36 -04:00
Liam DeBeasi
7d260b96a7 fix(modal): swipeable modal now works in firefox (#20714)
fixes #20706
2020-03-06 13:19:48 -05:00
Liam DeBeasi
22d5256810 fix(modal): leave animation transitions modal completely out of viewport on ipad (#20702)
fixes #20697
2020-03-06 10:12:21 -05:00
Liam DeBeasi
b6c2a77deb fix(overlays): prevent accidental dismiss of overlays when tapping screen twice (#20683)
fixes #20608
2020-03-06 10:11:20 -05:00
Liam DeBeasi
ec4878ac08 fix(ios): large title animation now works properly in a modal (#20703)
fixes #20696
2020-03-06 10:09:39 -05:00
Liam DeBeasi
314dbb1a4d fix(segment): allow routerLink to work on segment buttons (#20682)
fixes #20678
2020-03-05 12:38:51 -05:00
Liam DeBeasi
44993b7987 fix(segment): iOS mode segment now works on older Android devices (#20673)
fixes #20648
2020-03-05 11:56:54 -05:00
Mike Hartington
f64b1420ae fix(): exclude components from ssr (#20674) 2020-03-02 14:46:03 -05:00
Ni Tianzhen
21774612d8 fix(datetime): max property now works when hour, minute, or second set to 0 (#20665)
fixes #20652
2020-03-02 11:23:43 -05:00
Brandy Carney
a360ea6d19 merge release-5.0.4 2020-02-27 18:05:03 -05:00
Brandy Carney
36f98eda1b merge release-5.0.4 2020-02-27 18:04:44 -05:00
Brandy Carney
b11ae5da67 5.0.4 2020-02-27 17:32:17 -05:00
Mike Hartington
dff1ffd124 chore(): bump stencil version 2020-02-27 17:09:55 -05:00
Brandy Carney
c1d7bf229d fix(buttons): use proper button colors based on CSS variables when inside of a toolbar (#20633) 2020-02-27 16:22:39 -05:00
Liam DeBeasi
0e0e401d86 fix(animation): reset all temporary flags when interrupting an animation (#20627)
fixes #20602
2020-02-27 11:17:43 -05:00
Beeno Tung
b84822e674 docs(readme): update npm version on CDN example to latest (#20599) 2020-02-26 19:56:29 -05:00
Liam DeBeasi
8e71317de4 merge release-5.0.3
5.0.3
2020-02-26 18:52:13 -05:00
Liam DeBeasi
5a87a728e1 5.0.3 2020-02-26 16:00:07 -05:00
Liam DeBeasi
fe8d74d08c fix(menu): allow ssr to work properly with hardware back button updates (#20629) 2020-02-26 15:54:50 -05:00
Brandy Carney
e3364f283f merge release-5.0.0 2020-02-11 12:31:15 -05:00
511 changed files with 58063 additions and 9927 deletions

View File

@@ -4,6 +4,7 @@ Thanks for your interest in contributing to the Ionic Framework! :tada:
- [Contributing Etiquette](#contributing-etiquette)
- [Creating an Issue](#creating-an-issue)
* [Creating a Good Code Reproduction](#creating-a-good-code-reproduction)
- [Creating a Pull Request](#creating-a-pull-request)
* [Setup](#setup)
* [Core](#core)
@@ -40,13 +41,40 @@ Please see our [Contributor Code of Conduct](https://github.com/ionic-team/ionic
* The issue list of this repository is exclusively for bug reports and feature requests. Non-conforming issues will be closed immediately.
* Issues with no clear steps to reproduce will not be triaged. If an issue is labeled with "needs: reply" and receives no further replies from the author of the issue for more than 30 days, it will be closed.
* Issues with no clear steps to reproduce will not be triaged. If an issue is labeled with "needs: reply" and receives no further replies from the author of the issue for more than 14 days, it will be closed.
* If you think you have found a bug, or have a new feature idea, please start by making sure it hasn't already been [reported](https://github.com/ionic-team/ionic/issues?utf8=%E2%9C%93&q=is%3Aissue). You can search through existing issues to see if there is a similar one reported. Include closed issues as it may have been closed with a solution.
* Next, [create a new issue](https://github.com/ionic-team/ionic/issues/new/choose) that thoroughly explains the problem. Please fill out the populated issue form before submitting the issue.
## Creating a Good Code Reproduction
### What is a Code Reproduction?
A code reproduction is a small application that is built to demonstrate a particular issue. The code reproduction should contain the minimum amount of code needed to recreate the issue and should focus on a single issue.
### Why Should You Create a Reproduction?
A code reproduction of the issue you are experiencing helps us better isolate the cause of the problem. This is an important first step to getting any bug fixed!
Without a reliable code reproduction, it is unlikely we will be able to resolve the issue, leading to it being closed. In other words, creating a code reproduction of the issue helps us help you.
### How to Create a Reproduction
* Create a new Ionic application using one of our starter templates. The `blank` starter application is a great choice for this. You can create one using the following Ionic CLI command: `ionic start myApp blank`
* Add the minimum amount of code needed to recreate the issue you are experiencing. Do not include anything that is not required to reproduce the issue. This includes any 3rd party plugins you have installed.
* Publish the application on GitHub and include a link to it when [creating an issue](#creating-an-issue).
* Be sure to include steps to reproduce the issue. These steps should be clear and easy to follow.
### Benefits of Creating a Reproduction
* **Uses the latest version of Ionic:** By creating a new Ionic application, you are ensuring that you are testing against the latest version of the framework. Sometimes the issues you are experiencing have already been resolved in a newer version of the framework!
* **Minimal surface area:** By removing code that is not needed in order to reproduce the issue, it makes it easier to identify the cause of the issue.
* **No secret code needed:** Creating a minimal reproduction of the issue prevents you from having to publish any proprietary code used in your project.
* **Get help fixing the issue:** If we can reliably reproduce an issue, there is a good chance we will be able to address it.
## Creating a Pull Request
* We appreciate you taking the time to contribute! Before submitting a pull request, we ask that you please [create an issue](#creating-an-issue) that explains the bug or feature request and let us know that you plan on creating a pull request for it. If an issue already exists, please comment on that issue letting us know you would like to submit a pull request for it. This helps us to keep track of the pull request and make sure there isn't duplicated effort.

View File

@@ -19,7 +19,8 @@ assignees: ''
**Ionic version:**
<!-- (For Ionic 1.x issues, please use https://github.com/ionic-team/ionic-v1) -->
<!-- (For Ionic 2.x & 3.x issues, please use https://github.com/ionic-team/ionic-v3) -->
[x] **4.x**
[ ] **4.x**
[x] **5.x**
**Current behavior:**
<!-- Describe how the bug manifests. -->

View File

@@ -21,6 +21,16 @@ comment:
Thank you!
- label: "ionitron: needs reproduction"
message: >
Thanks for the issue! This issue has been labeled as `needs reproduction`. This label
is added to issues that need a code reproduction.
Please provide a reproduction with the minimum amount of code required to reproduce the issue. Without a reliable code reproduction, it is unlikely we will be able to resolve the issue, leading to it being closed.
For a guide on how to create a good reproduction, see our [Contributing Guide](https://ionicframework.com/docs/contributing/how-to-contribute#creating-a-good-code-reproduction).
dryRun: false
closeAndLock:
@@ -65,8 +75,10 @@ stale:
days: 365
maxIssuesPerRun: 100
exemptLabels:
- good first issue
- triage
- "good first issue"
- "triage"
- "type: bug"
- "type: feature request"
exemptAssigned: true
exemptProjects: true
exemptMilestones: true
@@ -83,7 +95,7 @@ stale:
dryRun: false
noReply:
days: 30
days: 14
maxIssuesPerRun: 100
label: "needs: reply"
responseLabel: triage
@@ -95,6 +107,24 @@ noReply:
template is fully filled out.
Thank you for using Ionic!
close: true
lock: true
dryRun: false
noReproduction:
days: 14
maxIssuesPerRun: 100
label: "ionitron: needs reproduction"
responseLabel: triage
exemptProjects: true
exemptMilestones: true
message: >
Thanks for the issue! This issue is being closed due to the lack of a code reproduction. If this is still
an issue with the latest version of Ionic, please create a new issue and ensure the
template is fully filled out.
Thank you for using Ionic!
close: true
lock: true

View File

@@ -1,7 +0,0 @@
# Configuration for weekly-digest - https://github.com/apps/weekly-digest
publishDay: wed
canPublishIssues: true
canPublishPullRequests: true
canPublishContributors: true
canPublishStargazers: true
canPublishCommits: true

1
.gitignore vendored
View File

@@ -64,3 +64,4 @@ core/loader/
core/www/
.stencil/
angular/build/
core/components/

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,243 @@
## [5.2.3](https://github.com/ionic-team/ionic/compare/v5.2.2...v5.2.3) (2020-07-01)
### Bug Fixes
* **angular:** expose createAnimation in addition to AnimationController ([#21616](https://github.com/ionic-team/ionic/issues/21616)) ([a5b3750](https://github.com/ionic-team/ionic/commit/a5b3750ee2a7c005f80f8453b03c67dd1a5622ca)), closes [#21615](https://github.com/ionic-team/ionic/issues/21615)
* **select:** change role to listbox ([#21609](https://github.com/ionic-team/ionic/issues/21609)) ([8c79e2c](https://github.com/ionic-team/ionic/commit/8c79e2c5b58ad562967f2d559c6b548e57536936))
* **slides:** enable keyboard integration ([#21608](https://github.com/ionic-team/ionic/issues/21608)) ([26674f1](https://github.com/ionic-team/ionic/commit/26674f1dfa8c9a28f5525f1b16070e8ec494c232)), closes [#21554](https://github.com/ionic-team/ionic/issues/21554)
* **textarea:** add aria-labelledby to native textarea ([#21606](https://github.com/ionic-team/ionic/issues/21606)) ([88f23b1](https://github.com/ionic-team/ionic/commit/88f23b1626eb400336f2f52a3e0d34ac3c161e64)), closes [#21600](https://github.com/ionic-team/ionic/issues/21600)
## [5.2.2](https://github.com/ionic-team/ionic/compare/v5.2.1...v5.2.2) (2020-06-17)
### Bug Fixes
* **action-sheet, alert:** resolve double click issue when running in iOS mode on chrome ([#21506](https://github.com/ionic-team/ionic/issues/21506)) ([bcccc21](https://github.com/ionic-team/ionic/commit/bcccc217b8833a284a1781e287db5e46043b3548)), closes [#21503](https://github.com/ionic-team/ionic/issues/21503)
* **angular:** fix issue where navAnimation was being incorrectly overridden ([#21508](https://github.com/ionic-team/ionic/issues/21508)) ([e968bd0](https://github.com/ionic-team/ionic/commit/e968bd029a4fb37b4001d96a490c6091a948785a)), closes [#21495](https://github.com/ionic-team/ionic/issues/21495)
* **input:** add aria-label to clear button ([#21538](https://github.com/ionic-team/ionic/issues/21538)) ([d8b377f](https://github.com/ionic-team/ionic/commit/d8b377ffeb88eaae23b33eadeae5c8e54e1bc77c)), closes [#21537](https://github.com/ionic-team/ionic/issues/21537)
* **ios:** respect toolbar opacity when doing nav transition ([#21512](https://github.com/ionic-team/ionic/issues/21512)) ([24cfdc3](https://github.com/ionic-team/ionic/commit/24cfdc308f63b7a55969ac58806eafd67116b017))
* **segment:** ensure checked classes get set after not having a value ([#21547](https://github.com/ionic-team/ionic/issues/21547)) ([17308f2](https://github.com/ionic-team/ionic/commit/17308f247f8750029ece39548c9f457e15326189)), closes [#21546](https://github.com/ionic-team/ionic/issues/21546)
## [5.2.1](https://github.com/ionic-team/ionic/compare/v5.2.0...v5.2.1) (2020-06-11)
### Bug Fixes
* **angular:** resolve error when not using ngModel on components ([4083e32](https://github.com/ionic-team/ionic/commit/4083e32e103db71f6db86ed1ecd398fda407c28b))
# [5.2.0 Silicon](https://github.com/ionic-team/ionic/compare/v5.1.1...v5.2.0) (2020-06-10)
### Bug Fixes
* **action-sheet, toast:** allow button handler to return `Promise<void>` ([#21259](https://github.com/ionic-team/ionic/issues/21259)) ([7703da2](https://github.com/ionic-team/ionic/commit/7703da28f8181b02390b97a7d4d02df99b2ad34c))
* **angular:** patch FormControl methods to properly sync Ionic form classes ([#21429](https://github.com/ionic-team/ionic/issues/21429)) ([e95b481](https://github.com/ionic-team/ionic/commit/e95b481a53191582bca635f322ad07eadbd62d64))
* **datetime:** ensure year-only values are not affected by timezone when parsing ([#21309](https://github.com/ionic-team/ionic/issues/21309)) ([3937101](https://github.com/ionic-team/ionic/commit/3937101e5c2b181a6b7926eb8386c22b0f887716))
* **header:** large title transition now works on older versions of iOS ([#21339](https://github.com/ionic-team/ionic/issues/21339)) ([2dac12c](https://github.com/ionic-team/ionic/commit/2dac12c577e0c7a5310857389dbda2b2b3dfadd1))
* **img:** use setTimeout fallback on older versions of chrome ([#21358](https://github.com/ionic-team/ionic/issues/21358)) ([0bf9449](https://github.com/ionic-team/ionic/commit/0bf9449ee1f9b2498e35f61511cb3e018814c6ca))
* **ios:** add haptic drag gesture for action sheet and alert components ([#21060](https://github.com/ionic-team/ionic/issues/21060)) ([33be1f0](https://github.com/ionic-team/ionic/commit/33be1f061ebbe27ee22e357c394f112af42ec360))
* **item:** inherit align-items from parent item ([#19278](https://github.com/ionic-team/ionic/issues/19278)) ([882f8fe](https://github.com/ionic-team/ionic/commit/882f8fef07dfb6ebda17ca09046d1af281075098)), closes [#18703](https://github.com/ionic-team/ionic/issues/18703)
* **item:** input-wrapper now inherits overflow ([#21282](https://github.com/ionic-team/ionic/issues/21282)) ([29d208d](https://github.com/ionic-team/ionic/commit/29d208de88f340e216e22badb6366bba4eda8bfb))
* **menu-button:** screen readers now properly announce menu button ([#21324](https://github.com/ionic-team/ionic/issues/21324)) ([eaf4fb6](https://github.com/ionic-team/ionic/commit/eaf4fb6b2a6d68f5c3d8d49ef41b4885f096070d))
* **modal:** card style modal no longer gets stuck when swiping quickly ([#21224](https://github.com/ionic-team/ionic/issues/21224)) ([448dfa0](https://github.com/ionic-team/ionic/commit/448dfa0a6955008ce4dc73354f5b8319ae1a1cc2))
* **modal:** set card-style modal height using the --height css variable ([#21453](https://github.com/ionic-team/ionic/issues/21453)) ([a4f0bdb](https://github.com/ionic-team/ionic/commit/a4f0bdb4c3ceeeaf902d520e9aa72e04a6ec2302))
* **reorder-group:** revert item to original position when passing false to complete ([#21396](https://github.com/ionic-team/ionic/issues/21396)) ([5f2001c](https://github.com/ionic-team/ionic/commit/5f2001c43c0846ec8973cbb8eb5662976ba7e31a)), closes [#19128](https://github.com/ionic-team/ionic/issues/19128)
* **router:** use correct nav transition when going back ([#21301](https://github.com/ionic-team/ionic/issues/21301)) ([c8db0d5](https://github.com/ionic-team/ionic/commit/c8db0d5eeba6f10d1492e95e6df6b4d871d43400))
* **scroll-assist:** improve scroll detection accuracy ([#21416](https://github.com/ionic-team/ionic/issues/21416)) ([137c49d](https://github.com/ionic-team/ionic/commit/137c49d70be45e1b0ee73d41fed6e9d69a2caa32))
* **slides:** update Swiper dependency to resolve error when doing SSR ([#21350](https://github.com/ionic-team/ionic/issues/21350)) ([3290604](https://github.com/ionic-team/ionic/commit/32906048a491961ec7340ba2e085807ea8a9c118))
* **textarea:** native textarea inherits max/min width and height ([#21333](https://github.com/ionic-team/ionic/issues/21333)) ([2377480](https://github.com/ionic-team/ionic/commit/237748049c7644ae8a7a74101ece5cfd7a160470))
### Features
* **alert:** add destructive role to alert buttons ([#21269](https://github.com/ionic-team/ionic/issues/21269)) ([e53f024](https://github.com/ionic-team/ionic/commit/e53f0241e2bf91461c55097fde271ae85ca644ea))
* **alert:** add support for custom input attributes ([#21365](https://github.com/ionic-team/ionic/issues/21365)) ([1ed8169](https://github.com/ionic-team/ionic/commit/1ed81693f225b6801a0897ef1a8314999c122484))
* **all:** add all autocomplete values to input and searchbar ([#21297](https://github.com/ionic-team/ionic/issues/21297)) ([4fd7c0c](https://github.com/ionic-team/ionic/commit/4fd7c0cc5a6c97100fa380e4ff1be0bb84c7006b))
* **all:** add optional generic typings for overlay component methods ([#21393](https://github.com/ionic-team/ionic/issues/21393)) ([5bf83b8](https://github.com/ionic-team/ionic/commit/5bf83b80d7d2749719dd1a280ae8e205fbc4b2a9))
* **all:** add shadow parts to missing components ([#21436](https://github.com/ionic-team/ionic/issues/21436)) ([17375d2](https://github.com/ionic-team/ionic/commit/17375d232500b47ef1cacd7c028c38990d307984))
* **all:** add support for configuring animations on a per-page basis ([#21433](https://github.com/ionic-team/ionic/issues/21433)) ([f34d375](https://github.com/ionic-team/ionic/commit/f34d3752e3462c9d81487fc86af5ec185cc3d1e3))
* **angular:** expose activatedView ([#21302](https://github.com/ionic-team/ionic/issues/21302)) ([829a0d9](https://github.com/ionic-team/ionic/commit/829a0d9be5a20c5fc96b5c5f18fedc4eb5e5b9ec))
* **angular:** expose getPlatforms and isPlatform ([#21308](https://github.com/ionic-team/ionic/issues/21308)) ([4af54a2](https://github.com/ionic-team/ionic/commit/4af54a2fea5d9cef843b1ebce849fb4a5c206f0b))
* **angular:** add strongly typed Ionic lifecycle hooks ([#18044](https://github.com/ionic-team/ionic/issues/18044)) ([53fc8e3](https://github.com/ionic-team/ionic/commit/53fc8e37c89cea793d0e00246d52805166730108)), closes [#18043](https://github.com/ionic-team/ionic/issues/18043)
* **fab-button:** add close icon font size css variable ([#19628](https://github.com/ionic-team/ionic/issues/19628)) ([df408f9](https://github.com/ionic-team/ionic/commit/df408f91f1aef903adaa5e635fef9bc7542e8739))
* **fab-button:** add closeIcon property ([#19626](https://github.com/ionic-team/ionic/issues/19626)) ([698e526](https://github.com/ionic-team/ionic/commit/698e526b9f882e98efc4bf160999182c645b772c))
* **select-option:** pass class from the option to the interface for individual styling ([#21304](https://github.com/ionic-team/ionic/issues/21304)) ([5285824](https://github.com/ionic-team/ionic/commit/5285824da5258ea638420fc60c50e0a19952f89c))
## [5.1.1](https://github.com/ionic-team/ionic/compare/v5.1.0...v5.1.1) (2020-05-13)
### Bug Fixes
* **all:** improve scroll assist reliability for below the fold inputs ([#21206](https://github.com/ionic-team/ionic/issues/21206)) ([7166a29](https://github.com/ionic-team/ionic/commit/7166a290cc1dd728e5bab2f7e39b8d41954e3808))
* **all:** overlay components no longer display outline when focused ([#21226](https://github.com/ionic-team/ionic/issues/21226)) ([bb62023](https://github.com/ionic-team/ionic/commit/bb62023a0cdc5a64e956766c7d1704797fc8c9ae))
* **display:** remove 1px gap between mutually exclusive breakpoints ([#21276](https://github.com/ionic-team/ionic/issues/21276)) ([703ef5c](https://github.com/ionic-team/ionic/commit/703ef5c99284f1e2b8d63c3af411c945dc756e20)), closes [#20993](https://github.com/ionic-team/ionic/issues/20993) [#20743](https://github.com/ionic-team/ionic/issues/20743)
* **header:** do not error on collapsible header on devices that do not support IntersectionObserve ([#21222](https://github.com/ionic-team/ionic/issues/21222)) ([0c13f25](https://github.com/ionic-team/ionic/commit/0c13f25bbb4d4674e76cd19b098900f698e7146e))
* **input:** check for tabindex and pass it properly to native input ([#21170](https://github.com/ionic-team/ionic/issues/21170)) ([dd4cb70](https://github.com/ionic-team/ionic/commit/dd4cb706ffeebc2069645ea03f0e7a96d6b14d43)), closes [#17515](https://github.com/ionic-team/ionic/issues/17515)
* **ios:** position page transition shadow properly under footer ([#21095](https://github.com/ionic-team/ionic/issues/21095)) ([50678c0](https://github.com/ionic-team/ionic/commit/50678c03c9829a87408633dabd77b21da1650a84))
* **md:** do not hide page when swipe gesture is cancelled ([#21247](https://github.com/ionic-team/ionic/issues/21247)) ([f334e83](https://github.com/ionic-team/ionic/commit/f334e83a43f855ac1e36eaf73954df6ee27a03af))
* **overlays:** respect keyboardClose property when opening overlays ([#21240](https://github.com/ionic-team/ionic/issues/21240)) ([9d0dcbb](https://github.com/ionic-team/ionic/commit/9d0dcbbd31fc34ad8952eacb9864ad1b31636113))
* **picker:** haptics now work properly ([#21268](https://github.com/ionic-team/ionic/issues/21268)) ([8e11ecc](https://github.com/ionic-team/ionic/commit/8e11ecc136c61e925e76c0e48ab21611e09b5898))
* **refresher:** correctly select shadow root on older browsers ([#21237](https://github.com/ionic-team/ionic/issues/21237)) ([f23f1cb](https://github.com/ionic-team/ionic/commit/f23f1cb37eef02307c357fbb48c0db729974cdc4))
* **refresher:** refresher completes even after switching to a new tab ([#21236](https://github.com/ionic-team/ionic/issues/21236)) ([1e6f923](https://github.com/ionic-team/ionic/commit/1e6f92377aaf0804cfd0ddb9b06da7b4c9dc355f))
* **segment-button:** screen readers now announce selected state properly ([#21273](https://github.com/ionic-team/ionic/issues/21273)) ([85cc35e](https://github.com/ionic-team/ionic/commit/85cc35ee9163a38c48c6df466a3c036906437804))
* **toggle:** screen readers now announce toggle properly ([#21168](https://github.com/ionic-team/ionic/issues/21168)) ([1fbdb22](https://github.com/ionic-team/ionic/commit/1fbdb2255e4ff7fccf22d9ccc12b7f9bb4c3a064))
# [5.1.0 Aluminum](https://github.com/ionic-team/ionic/compare/v5.0.7...v5.1.0) (2020-04-30)
### Bug Fixes
* **action-sheet:** show correct cancel button background on dark mode ([#21084](https://github.com/ionic-team/ionic/issues/21084)) ([e442324](https://github.com/ionic-team/ionic/commit/e4423247537cbcda174305ab9fdde4a57c50a88e)), closes [#21082](https://github.com/ionic-team/ionic/issues/21082)
* **all:** correctly default gestures to use a passive listener ([#21038](https://github.com/ionic-team/ionic/issues/21038)) ([dea9248](https://github.com/ionic-team/ionic/commit/dea9248763737164e17678119c775cdfc0e53ccd))
* **angular:** do not navigate to the same tab if already active ([#21085](https://github.com/ionic-team/ionic/issues/21085)) ([15203de](https://github.com/ionic-team/ionic/commit/15203de08bf97f27e33f35994444c2c4843b3a44)), closes [#21074](https://github.com/ionic-team/ionic/issues/21074) [#19943](https://github.com/ionic-team/ionic/issues/19943)
* **back-button:** announce back button text correctly by screen readers ([#21053](https://github.com/ionic-team/ionic/issues/21053)) ([14c226c](https://github.com/ionic-team/ionic/commit/14c226ce75958da14b66821028d6f3a6852d695c)), closes [#21043](https://github.com/ionic-team/ionic/issues/21043)
* **datetime:** locale inputs are now reactive ([#20826](https://github.com/ionic-team/ionic/issues/20826)) ([a75e8f3](https://github.com/ionic-team/ionic/commit/a75e8f34d608c167f8d429ddbf39e94173204a61)), closes [#20367](https://github.com/ionic-team/ionic/issues/20367)
* **ios:** account for nested tabs with page transition ([#20955](https://github.com/ionic-team/ionic/issues/20955)) ([e23dec5](https://github.com/ionic-team/ionic/commit/e23dec5eb9fbb58eedffabefca8d7d643f49f7b9)), closes [#20948](https://github.com/ionic-team/ionic/issues/20948)
* **ios:** properly animate content when navigating from a tabbed page ([#20918](https://github.com/ionic-team/ionic/issues/20918)) ([8a02b28](https://github.com/ionic-team/ionic/commit/8a02b28efeca81c25176ff52508b4005441e8314)), closes [#20912](https://github.com/ionic-team/ionic/issues/20912)
* **loading:** correctly announce spinner by screen readers ([#21116](https://github.com/ionic-team/ionic/issues/21116)) ([63d8f62](https://github.com/ionic-team/ionic/commit/63d8f6239cc39e6a111108bd1a2557c297a256ae)), closes [#21107](https://github.com/ionic-team/ionic/issues/21107)
* **md:** do not display blank screen when using MD page transition and swipe gesture ([#21058](https://github.com/ionic-team/ionic/issues/21058)) ([4973807](https://github.com/ionic-team/ionic/commit/497380743df4461688455bc8b8440d2f3cc7c247)), closes [#21056](https://github.com/ionic-team/ionic/issues/220800)
* **modal:** properly inherit border radius for modals on Safari ([#20887](https://github.com/ionic-team/ionic/issues/20887)) ([bd64509](https://github.com/ionic-team/ionic/commit/bd64509bae9dd4c960134d986ce8150dc1a9d3b4)), closes [#20878](https://github.com/ionic-team/ionic/issues/20878)
* **modal:** swipeToClose property is now reactive ([#21073](https://github.com/ionic-team/ionic/issues/21073)) ([4bd9134](https://github.com/ionic-team/ionic/commit/4bd91344730bd26c66a8d838436d94045dc21f78)), closes [#21072](https://github.com/ionic-team/ionic/issues/21072)
* **overlays:** focus overlay when presented ([#20997](https://github.com/ionic-team/ionic/issues/20997)) ([fc2be8d](https://github.com/ionic-team/ionic/commit/fc2be8d08bbb495df911783f808d7ca511942172)), closes [#19882](https://github.com/ionic-team/ionic/issues/19882) [#17126](https://github.com/ionic-team/ionic/issues/17126)
* **overlays:** prevent accidental clicks when dismissing overlays ([#21093](https://github.com/ionic-team/ionic/issues/21093)) ([671802f](https://github.com/ionic-team/ionic/commit/671802f9a2050d9942e9dfb2db9f9c58bdc58620)), closes [#21092](https://github.com/ionic-team/ionic/issues/21092)
* **react:** IonTabBar properly extends IonicReactProps ([#21009](https://github.com/ionic-team/ionic/issues/21009)) ([102a842](https://github.com/ionic-team/ionic/commit/102a842bd2a967c04a3cf42ed4e0811929bd4d99)), closes [#21006](https://github.com/ionic-team/ionic/issues/21006)
* **refresher:** properly check for Haptics plugin on web ([#21156](https://github.com/ionic-team/ionic/issues/21156)) ([c53b136](https://github.com/ionic-team/ionic/commit/c53b136dbe7ed7fc0fc298593f8b677a66c77910)), closes [#21148](https://github.com/ionic-team/ionic/issues/21148)
* **refresher:** properly calculate content dimensions in native ion-refresher ([#21157](https://github.com/ionic-team/ionic/issues/21157)) ([83dcc71](https://github.com/ionic-team/ionic/commit/83dcc7168a48bc5b05583fb7c01b5eff9d1a67f8))
* **router:** account for query string when pushing page ([#21071](https://github.com/ionic-team/ionic/issues/21071)) ([eab3373](https://github.com/ionic-team/ionic/commit/eab33732133bd43ca6788bba6e93a9b545ee058a))
* **searchbar:** correctly announce the cancel button text by screen readers ([#21049](https://github.com/ionic-team/ionic/issues/21049)) ([15a603b](https://github.com/ionic-team/ionic/commit/15a603b39797dee6baf7e33d58907f98ced7e86d)), closes [#21013](https://github.com/ionic-team/ionic/issues/21013)
* **select:** account for MutationObserver when performing SSR ([#21068](https://github.com/ionic-team/ionic/issues/21068)) ([66e8e64](https://github.com/ionic-team/ionic/commit/66e8e6404d87a2767e71b13bed19706b29ad1b9c)), closes [#21063](https://github.com/ionic-team/ionic/issues/21063)
* **slides:** slides no longer break with Angular Ivy enabled ([#20899](https://github.com/ionic-team/ionic/issues/20899)) ([3123a31](https://github.com/ionic-team/ionic/commit/3123a318b6755dbf8fde8476f81c37e6ffa9b70e)), closes [#20356](https://github.com/ionic-team/ionic/issues/20356)
* **split-pane:** properly show border in rtl mode ([#20995](https://github.com/ionic-team/ionic/issues/20995)) ([7a21708](https://github.com/ionic-team/ionic/commit/7a21708d24bab6a388e1b55c88337e3d0f7922eb)), closes [#20994](https://github.com/ionic-team/ionic/issues/20994)
* **textarea:** height is set correctly when using autoGrow in modals ([#20971](https://github.com/ionic-team/ionic/issues/20971)) ([32ee040](https://github.com/ionic-team/ionic/commit/32ee040e3f0d7012790f190856097d0c6fa0eaa2)), closes [#18993](https://github.com/ionic-team/ionic/issues/18993)
### Features
* **all:** add ability to continue processing hardware back button events ([#20613](https://github.com/ionic-team/ionic/issues/20613)) ([3821c04](https://github.com/ionic-team/ionic/commit/3821c0463ae9a02e67c835a221c4ea01fab306d1)), closes [#17824](https://github.com/ionic-team/ionic/issues/17824)
* **all:** add ability to eject from Ionic sanitizer ([#20457](https://github.com/ionic-team/ionic/issues/20457)) ([fa9ddc9](https://github.com/ionic-team/ionic/commit/fa9ddc91bc9fefc2bb247cfe7511384f77335476)), closes [#18277](https://github.com/ionic-team/ionic/issues/18277)
* **angular:** support multi-app for ng-add schematic ([#20768](https://github.com/ionic-team/ionic/issues/20768)) ([39e6c8f](https://github.com/ionic-team/ionic/commit/39e6c8f55b514b0c7330dd3a790c859bb3410404))
* **animation:** add option to clean up old animation stylesheets ([#20940](https://github.com/ionic-team/ionic/issues/20940)) ([5b98405](https://github.com/ionic-team/ionic/commit/5b9840508faf6a2c985726be889c1f2fca0e0733)), closes [#20610](https://github.com/ionic-team/ionic/issues/20610)
* **app:** add keyboard open and close events (ionKeyboardDidShow and ionKeyboardDidHide) ([#18478](https://github.com/ionic-team/ionic/issues/18478)) ([ae5f1dd](https://github.com/ionic-team/ionic/commit/ae5f1ddff0c0799167a154abbb418b2ad3434d47))
* **back-button:** add backButtonDefaultHref property to Ionic Config ([#20491](https://github.com/ionic-team/ionic/issues/20491)) ([1b11ff7](https://github.com/ionic-team/ionic/commit/1b11ff7fb92b75f5c869c79d5e0d5dfd8889597f)), closes [#19305](https://github.com/ionic-team/ionic/issues/19305)
* **checkbox:** add parts support for container, mark ([#20950](https://github.com/ionic-team/ionic/issues/20950)) ([d4b9151](https://github.com/ionic-team/ionic/commit/d4b9151396aed6d7a29d8f40d6e607bf6258b4ef))
* **content:** add parts support for background, scroll ([#20929](https://github.com/ionic-team/ionic/issues/20929)) ([578ab93](https://github.com/ionic-team/ionic/commit/578ab93d297f101ac899b6b6b099445ac679c71f))
* **datetime:** add parts support for placeholder, text ([#20930](https://github.com/ionic-team/ionic/issues/20930)) ([76ca475](https://github.com/ionic-team/ionic/commit/76ca475734e13404886bdf70117c0c39bbd7ce70))
* **gesture:** add option to run inside NgZone for Angular apps ([#20685](https://github.com/ionic-team/ionic/issues/20685)) ([429edb0](https://github.com/ionic-team/ionic/commit/429edb053bf2a5e778665770c373e31fc7d3bfd2)), closes [#20529](https://github.com/ionic-team/ionic/issues/20529)
* **gesture:** add support for blurring active inputs on gesture start ([#20638](https://github.com/ionic-team/ionic/issues/20638)) ([32ecdd6](https://github.com/ionic-team/ionic/commit/32ecdd67536f07f9d95e331e44661afb2cf7b470)), closes [#20588](https://github.com/ionic-team/ionic/issues/20588)
* **img:** add parts support for image ([#20943](https://github.com/ionic-team/ionic/issues/20943)) ([63c75ed](https://github.com/ionic-team/ionic/commit/63c75edd21387f28387c8a8529ba638317a9d9b8))
* **input:** add support for enterkeyhint ([#21035](https://github.com/ionic-team/ionic/issues/21035)) ([3efaf43](https://github.com/ionic-team/ionic/commit/3efaf4382175d40902968cabb7edd672ffc7cc2b)), closes [#21034](https://github.com/ionic-team/ionic/issues/21034)
* **item:** add parts support for detail-icon ([#20979](https://github.com/ionic-team/ionic/issues/20979)) ([6414496](https://github.com/ionic-team/ionic/commit/64144960b06e056a99aa3d352486a495b6bb43ed))
* **menu:** add parts support for backdrop, container ([#20978](https://github.com/ionic-team/ionic/issues/20978)) ([50bc212](https://github.com/ionic-team/ionic/commit/50bc212d0b30919c136d6be60a9d458ec7d50dde))
* **radio:** add parts support for container, mark ([#20952](https://github.com/ionic-team/ionic/issues/20952)) ([228ca2b](https://github.com/ionic-team/ionic/commit/228ca2b093215aba91fe925b301049471ffaa169))
* **range:** add parts support for bar, bar-active, knob, pin, tick, tick-active ([#20961](https://github.com/ionic-team/ionic/issues/20961)) ([619f67a](https://github.com/ionic-team/ionic/commit/619f67a00baa387d0f2bf3f6219e21bc87c03313))
* **react:** expose selectTab method and activeTab, closes [#19935](https://github.com/ionic-team/ionic/issues/19935) ([#21171](https://github.com/ionic-team/ionic/issues/21171)) ([43f9d24](https://github.com/ionic-team/ionic/commit/43f9d24824e4c1b679b350b3db05a6830d98fc0a))
* **reorder:** add parts support for icon ([#20960](https://github.com/ionic-team/ionic/issues/20960)) ([ba20209](https://github.com/ionic-team/ionic/commit/ba20209604666048619ae5f4358be0e65ef36e4f))
* **searchbar:** add border-radius css variable ([#20662](https://github.com/ionic-team/ionic/issues/20662)) ([acaa1d9](https://github.com/ionic-team/ionic/commit/acaa1d9ef7e4037913159c0d32829183ddc1860b)), closes [#17426](https://github.com/ionic-team/ionic/issues/17426) [#18247](https://github.com/ionic-team/ionic/issues/18247)
* **searchbar:** add support for enterkeyhint ([#21036](https://github.com/ionic-team/ionic/issues/21036)) ([e90683a](https://github.com/ionic-team/ionic/commit/e90683a713cb45d1e1283dd41343ea6b672a9e3a)), closes [#21034](https://github.com/ionic-team/ionic/issues/21034)
* **select:** add parts support for placeholder, icon, text ([#21108](https://github.com/ionic-team/ionic/issues/21108)) ([30a1c89](https://github.com/ionic-team/ionic/commit/30a1c896883e971ab87ef7d5d8790e9a60632fc2))
* **slides:** update to swiper 5 ([#20917](https://github.com/ionic-team/ionic/issues/20917)) ([4e28445](https://github.com/ionic-team/ionic/commit/4e28445ecb029f8d225acf9313209e5f61114dc4)), closes [#20033](https://github.com/ionic-team/ionic/issues/20033)
* **textarea:** add support for inputmode and enterkeyhint ([#21106](https://github.com/ionic-team/ionic/issues/21106)) ([1622d9b](https://github.com/ionic-team/ionic/commit/1622d9bb3c7f2aeed7dc823620204737619a5b0d))
* **toast:** add white-space variable for toast message ([#20729](https://github.com/ionic-team/ionic/issues/20729)) ([e5e02d4](https://github.com/ionic-team/ionic/commit/e5e02d4f88abbcc7dbc626db6d5adf4292d8e776)), closes [#20727](https://github.com/ionic-team/ionic/issues/20727)
* **toggle:** add parts support for handle, track ([#20962](https://github.com/ionic-team/ionic/issues/20962)) ([d2b772f](https://github.com/ionic-team/ionic/commit/d2b772f19fde71bcec72300cb4cf8234321b35bc))
* **toggle:** improve customization with css vars and auto-adjust handle width and height ([#21050](https://github.com/ionic-team/ionic/issues/21050)) ([04ace4c](https://github.com/ionic-team/ionic/commit/04ace4c98346fde5bad343224657f049beb3e868)), closes [#19868](https://github.com/ionic-team/ionic/issues/19868) [#20474](https://github.com/ionic-team/ionic/issues/20474)
### Performance Improvements
* **all:** improve scroll assist responsiveness ([#20987](https://github.com/ionic-team/ionic/issues/20987)) ([6f13b8c](https://github.com/ionic-team/ionic/commit/6f13b8c7922f638cac4eb3b111ff9643e6995491)), closes [#20922](https://github.com/ionic-team/ionic/issues/20922)
## [5.0.7](https://github.com/ionic-team/ionic/compare/v5.0.6...v5.0.7) (2020-03-26)
### Bug Fixes
* **modal:** properly target card modal for iPadOS styles ([#20884](https://github.com/ionic-team/ionic/issues/20884)) ([5816cf5](https://github.com/ionic-team/ionic/commit/5816cf52a779acc4613c2d2da28b97c511360cc2))
## [5.0.6](https://github.com/ionic-team/ionic/compare/v5.0.5...v5.0.6) (2020-03-25)
### Bug Fixes
* **all** only warn invalid mode if used on an ionic component ([#20828](https://github.com/ionic-team/ionic/issues/20828)) ([6ed1c51](https://github.com/ionic-team/ionic/commit/6ed1c51321d781ff92efbf623790af91cb16a5af)), closes [#20055](https://github.com/ionic-team/ionic/issues/20055)
* **all** properly scroll to input with scroll assist ([#20742](https://github.com/ionic-team/ionic/issues/20742)) ([e24060e](https://github.com/ionic-team/ionic/commit/e24060ecd9d803ece4bbb9c6beae23e761d7fb5e)), closes [#19589](https://github.com/ionic-team/ionic/issues/19589)
* **angular:** export Animation and Gesture related types ([#20766](https://github.com/ionic-team/ionic/issues/20766)) ([2ece194](https://github.com/ionic-team/ionic/commit/2ece194a085742b919cc68f643b1b365f7d85594))
* **angular:** respect animation property for ion-router-outlet ([#20767](https://github.com/ionic-team/ionic/issues/20767)) ([f2dbe1f](https://github.com/ionic-team/ionic/commit/f2dbe1ff3be44e6697b791de392a9ef46dbf27e8)), closes [#20764](https://github.com/ionic-team/ionic/issues/20764)
* **content:** apply --offset-top and --offset-bottom values correctly ([#20790](https://github.com/ionic-team/ionic/issues/20790)) ([2707289](https://github.com/ionic-team/ionic/commit/2707289b36883ae495f86cfb2f2b6c84e090551b)), closes [#20735](https://github.com/ionic-team/ionic/issues/20735)
* **content:** set overscroll-behavior based on the scroll direction ([#20011](https://github.com/ionic-team/ionic/issues/20011)) ([a3fc77b](https://github.com/ionic-team/ionic/commit/a3fc77be91ead6edc3f07c6127879753a063bd18)), closes [#20010](https://github.com/ionic-team/ionic/issues/20010)
* **item-divider:** update design to match native iOS ([#20854](https://github.com/ionic-team/ionic/issues/20854)) ([d91e22d](https://github.com/ionic-team/ionic/commit/d91e22d820f170ecfdfad835ca56701ad70e6f3d))
* **item-sliding:** account for swipe to go back gesture when opening item-options ([#20777](https://github.com/ionic-team/ionic/issues/20777)) ([f23ac44](https://github.com/ionic-team/ionic/commit/f23ac44c9a6646129762bb861cae6145690ca5a1)), closes [#20773](https://github.com/ionic-team/ionic/issues/20773)
* **list:** show bottom border on last item in a list followed by a list ([#20798](https://github.com/ionic-team/ionic/issues/20798)) ([7bc5191](https://github.com/ionic-team/ionic/commit/7bc51911f6c538be8b91d1e569675b19832cb000))
* **modal:** backdrop and box shadows no longer stack when opening multiple modals ([#20801](https://github.com/ionic-team/ionic/issues/20801)) ([253cd96](https://github.com/ionic-team/ionic/commit/253cd96164914a803f6bb42ff95ca74880c940d0)), closes [#20800](https://github.com/ionic-team/ionic/issues/20800)
* **modal:** backdrop is no longer tappable on card-style modal on smaller screens ([#20802](https://github.com/ionic-team/ionic/issues/20802)) ([12932dd](https://github.com/ionic-team/ionic/commit/12932dd20212bec7d780650166c70819d125f75a)), closes [#20783](https://github.com/ionic-team/ionic/issues/20783)
* **modal:** properly apply border radius on card-style modal ([#20852](https://github.com/ionic-team/ionic/issues/20852)) ([dff3816](https://github.com/ionic-team/ionic/commit/dff3816c049a1c051f94d3176c8b903a69603912)), closes [#20851](https://github.com/ionic-team/ionic/issues/20851)
* **modal:** properly remove safe area padding on card-modal ([#20853](https://github.com/ionic-team/ionic/issues/20853)) ([71f1182](https://github.com/ionic-team/ionic/commit/71f118201b0918f60c1a078d55afd10b39f17e86)), closes [#20799](https://github.com/ionic-team/ionic/issues/20799)
* **modal:** respect card-style modal spec for iPadOS ([#20750](https://github.com/ionic-team/ionic/issues/20750)) ([75bae40](https://github.com/ionic-team/ionic/commit/75bae403e917b20645675343734440ee95d31634)), closes [#20700](https://github.com/ionic-team/ionic/issues/20700)
* **react:** expose correct type for CreateAnimation ([#20775](https://github.com/ionic-team/ionic/issues/20775)) ([0897c3f](https://github.com/ionic-team/ionic/commit/0897c3f9c2591442b3f80d28a25ec4471da3c9d7)), closes [#20771](https://github.com/ionic-team/ionic/issues/20771)
* **refresher:** properly dismiss refresher when completed synchronously ([#20815](https://github.com/ionic-team/ionic/issues/20815)) ([b1a87c8](https://github.com/ionic-team/ionic/commit/b1a87c88923201fd0b31bf55d81b97acc09ddf1c)), closes [#20803](https://github.com/ionic-team/ionic/issues/20803)
* **segment:** automatically expand width for scrollable segment buttons ([#20763](https://github.com/ionic-team/ionic/issues/20763)) ([cdfd50b](https://github.com/ionic-team/ionic/commit/cdfd50b554d1d8f89c3d9948c7613ce75ede1e52)), closes [#20566](https://github.com/ionic-team/ionic/issues/20566)
* **segment:** scrollable segments only show scrollbar if they overflow ([#20760](https://github.com/ionic-team/ionic/issues/20760)) ([ab146c9](https://github.com/ionic-team/ionic/commit/ab146c96ec5cbc962eed629c30b2c5c446f3098d)), closes [#20758](https://github.com/ionic-team/ionic/issues/20758)
* **slides:** check that mutation observer is defined for ssr ([#20791](https://github.com/ionic-team/ionic/issues/20791)) ([2d5d251](https://github.com/ionic-team/ionic/commit/2d5d2515be86496a280d93847185ab332e5d47a2))
* **textarea:** properly adjust auto-grow textarea in scrolled content ([#19776](https://github.com/ionic-team/ionic/issues/19776)) ([8bd5bac](https://github.com/ionic-team/ionic/commit/8bd5bace73670dfe351b3734b51cbf3aa87517dc)), closes [#19193](https://github.com/ionic-team/ionic/issues/19193)
* **title:** improve reliability of large title ios nav transition ([#20861](https://github.com/ionic-team/ionic/issues/20861)) ([3bd6b5d](https://github.com/ionic-team/ionic/commit/3bd6b5def2877f6a918c587de25a10ccc82f88f1))
* **title:** large title now inherits global color styling during nav transition ([#20862](https://github.com/ionic-team/ionic/issues/20862)) ([321140f](https://github.com/ionic-team/ionic/commit/321140ff736b46d2631a9e87a7b070009c5e1b2c))
## [5.0.5](https://github.com/ionic-team/ionic/compare/v5.0.4...v5.0.5) (2020-03-11)
### Bug Fixes
* **button:** allow overflow to be overridden by the CSS variable ([#20738](https://github.com/ionic-team/ionic/issues/20738)) ([7ecde36](https://github.com/ionic-team/ionic/commit/7ecde36f9d31327a45f7b5023ed533edbb9cc709)), closes [#20726](https://github.com/ionic-team/ionic/issues/20726)
* **datetime:** account for max property when hour, minute, or second is set to 0 ([#20665](https://github.com/ionic-team/ionic/issues/20665)) ([2177461](https://github.com/ionic-team/ionic/commit/21774612d8d70ab7eda3eab0e6e9ac039b5c87d8)), closes [#20652](https://github.com/ionic-team/ionic/issues/20652)
* **header:** collapsable header should default to using content background ([#20736](https://github.com/ionic-team/ionic/issues/20736)) ([f6c3ba7](https://github.com/ionic-team/ionic/commit/f6c3ba7e5af2af9e32f75306cde7704509e82263)), closes [#20691](https://github.com/ionic-team/ionic/issues/20691)
* **header:** resolve undefined error on collapsible header when navigating quickly ([#20728](https://github.com/ionic-team/ionic/issues/20728)) ([87a2721](https://github.com/ionic-team/ionic/commit/87a27216d011f1d02ac0fc0aeb3ae0400ecfbd8c)), closes [#20725](https://github.com/ionic-team/ionic/issues/20725)
* **ios:** large title animation now works properly in a modal ([#20703](https://github.com/ionic-team/ionic/issues/20703)) ([ec4878a](https://github.com/ionic-team/ionic/commit/ec4878ac085d8ff92cb8b2ea0852523f174ab01b)), closes [#20696](https://github.com/ionic-team/ionic/issues/20696)
* **item:** apply proper margin left for slotted icon in RTL ([#20684](https://github.com/ionic-team/ionic/issues/20684)) ([d53595e](https://github.com/ionic-team/ionic/commit/d53595eb1629e0d60f7e832414e84c544e184346)), closes [#20653](https://github.com/ionic-team/ionic/issues/20653)
* **label:** text overflow for slotted headings ([#20690](https://github.com/ionic-team/ionic/issues/20690)) ([4d34ce6](https://github.com/ionic-team/ionic/commit/4d34ce6a31eaa19859699646cc614f5be6239e10)), closes [#17087](https://github.com/ionic-team/ionic/issues/17087)
* **modal:** leave animation transitions modal completely out of viewport on ipad ([#20702](https://github.com/ionic-team/ionic/issues/20702)) ([22d5256](https://github.com/ionic-team/ionic/commit/22d52568100d8096ee36e3a61a19614f0d63d45f)), closes [#20697](https://github.com/ionic-team/ionic/issues/20697)
* **angular** exclude components from ssr ([#20674](https://github.com/ionic-team/ionic/issues/20674)) ([f64b142](https://github.com/ionic-team/ionic/commit/f64b1420aead39b9056dc25cfdbcf95bc4f6f621))
* **modal:** swipeable modal now works in firefox ([#20714](https://github.com/ionic-team/ionic/issues/20714)) ([7d260b9](https://github.com/ionic-team/ionic/commit/7d260b96a73958709fa93a4fe58f816a445471ee)), closes [#20706](https://github.com/ionic-team/ionic/issues/20706)
* **overlays:** prevent accidental dismiss of overlays when tapping screen twice ([#20683](https://github.com/ionic-team/ionic/issues/20683)) ([b6c2a77](https://github.com/ionic-team/ionic/commit/b6c2a77deb1c09eb1fd414f7737794e208ab5081)), closes [#20608](https://github.com/ionic-team/ionic/issues/20608)
* **segment:** allow routerLink to work on segment buttons ([#20682](https://github.com/ionic-team/ionic/issues/20682)) ([314dbb1](https://github.com/ionic-team/ionic/commit/314dbb1a4d970327fcbb2f3fbdec0627c626fe4d)), closes [#20678](https://github.com/ionic-team/ionic/issues/20678)
* **segment:** iOS mode segment now works on older Android devices ([#20673](https://github.com/ionic-team/ionic/issues/20673)) ([44993b7](https://github.com/ionic-team/ionic/commit/44993b7987031b6618409675fdbb1f15ec4ea343)), closes [#20648](https://github.com/ionic-team/ionic/issues/20648)
## [5.0.4](https://github.com/ionic-team/ionic/compare/v5.0.3...v5.0.4) (2020-02-27)
### Bug Fixes
* **animation:** reset all temporary flags when interrupting an animation ([#20627](https://github.com/ionic-team/ionic/issues/20627)) ([0e0e401](https://github.com/ionic-team/ionic/commit/0e0e401d86dabaa1dc804656e4d384154d6fdd05)), closes [#20602](https://github.com/ionic-team/ionic/issues/20602)
* **buttons:** use proper button colors based on CSS variables when inside of a toolbar ([#20633](https://github.com/ionic-team/ionic/issues/20633)) ([c1d7bf2](https://github.com/ionic-team/ionic/commit/c1d7bf229d10d0a12f90b6d2730d6d8ac78b48cd))
## [5.0.3](https://github.com/ionic-team/ionic/compare/v5.0.2...v5.0.3) (2020-02-26)
### Bug Fixes
* **menu:** allow ssr to work properly with hardware back button updates ([#20629](https://github.com/ionic-team/ionic/issues/20629)) ([fe8d74d](https://github.com/ionic-team/ionic/commit/fe8d74d08cb919ed1c685262f0aed4a544c3a7e1))
## [5.0.2](https://github.com/ionic-team/ionic/compare/v5.0.1...v5.0.2) (2020-02-26)

View File

@@ -1,11 +1,129 @@
# Contributor Code of Conduct
As contributors and maintainers of the Ionic project, we pledge to respect everyone who contributes by posting issues, updating documentation, submitting pull requests, providing feedback in comments, and any other activities.
# Contributor Covenant Code of Conduct
Communication through any of Ionic's channels (GitHub, Slack, Forum, IRC, mailing lists, Twitter, etc.) must be constructive and never resort to personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
## Our Pledge
We promise to extend courtesy and respect to everyone involved in this project regardless of gender, gender identity, sexual orientation, disability, age, race, ethnicity, religion, or level of experience. We expect anyone contributing to the Ionic project to do the same.
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
If any member of the community violates this code of conduct, the maintainers of the Ionic project may take action, removing issues, comments, and PRs or blocking accounts as deemed appropriate.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
If you are subject to or witness unacceptable behavior, or have any other concerns, please email us at [hi@ionicframework.com](mailto:hi@ionicframework.com).
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
[contact@ionic.io](mailto:contact@ionic.io).
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

View File

@@ -31,6 +31,8 @@ Thanks for your interest in contributing! Read up on our guidelines for
and then look through our issues with a [help wanted](https://github.com/ionic-team/ionic/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22)
label.
Please note that this project is released with a [Contributor Code of Conduct](https://github.com/ionic-team/ionic/blob/master/CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.
### Examples

View File

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

View File

@@ -1,4 +1,4 @@
import resolve from 'rollup-plugin-node-resolve';
import resolve from '@rollup/plugin-node-resolve';
export default {
input: 'build/es2015/core.js',

View File

@@ -1,4 +1,4 @@
import { Directive, ElementRef, HostListener } from '@angular/core';
import { Directive, ElementRef, HostListener, Injector } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { ValueAccessor, setIonicClasses } from './value-accessor';
@@ -16,8 +16,8 @@ import { ValueAccessor, setIonicClasses } from './value-accessor';
})
export class BooleanValueAccessor extends ValueAccessor {
constructor(el: ElementRef) {
super(el);
constructor(injector: Injector, el: ElementRef) {
super(injector, el);
}
writeValue(value: any) {

View File

@@ -1,4 +1,4 @@
import { Directive, ElementRef, HostListener } from '@angular/core';
import { Directive, ElementRef, HostListener, Injector } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { ValueAccessor } from './value-accessor';
@@ -16,8 +16,8 @@ import { ValueAccessor } from './value-accessor';
})
export class NumericValueAccessor extends ValueAccessor {
constructor(el: ElementRef) {
super(el);
constructor(injector: Injector, el: ElementRef) {
super(injector, el);
}
@HostListener('ionChange', ['$event.target'])

View File

@@ -1,4 +1,4 @@
import { Directive, ElementRef, HostListener } from '@angular/core';
import { Directive, ElementRef, HostListener, Injector } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { ValueAccessor } from './value-accessor';
@@ -16,8 +16,8 @@ import { ValueAccessor } from './value-accessor';
})
export class RadioValueAccessor extends ValueAccessor {
constructor(el: ElementRef) {
super(el);
constructor(injector: Injector, el: ElementRef) {
super(injector, el);
}
@HostListener('ionSelect', ['$event.target'])

View File

@@ -1,4 +1,4 @@
import { Directive, ElementRef, HostListener } from '@angular/core';
import { Directive, ElementRef, HostListener, Injector } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { ValueAccessor } from './value-accessor';
@@ -16,8 +16,8 @@ import { ValueAccessor } from './value-accessor';
})
export class SelectValueAccessor extends ValueAccessor {
constructor(el: ElementRef) {
super(el);
constructor(injector: Injector, el: ElementRef) {
super(injector, el);
}
@HostListener('ionChange', ['$event.target'])

View File

@@ -1,4 +1,4 @@
import { Directive, ElementRef, HostListener } from '@angular/core';
import { Directive, ElementRef, HostListener, Injector } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { ValueAccessor } from './value-accessor';
@@ -16,8 +16,8 @@ import { ValueAccessor } from './value-accessor';
})
export class TextValueAccessor extends ValueAccessor {
constructor(el: ElementRef) {
super(el);
constructor(injector: Injector, el: ElementRef) {
super(injector, el);
}
@HostListener('ionChange', ['$event.target'])

View File

@@ -1,15 +1,17 @@
import { ElementRef, HostListener } from '@angular/core';
import { ControlValueAccessor } from '@angular/forms';
import { AfterViewInit, ElementRef, HostListener, Injector, OnDestroy, Type } from '@angular/core';
import { ControlValueAccessor, NgControl } from '@angular/forms';
import { Subscription } from 'rxjs';
import { raf } from '../../util/util';
export class ValueAccessor implements ControlValueAccessor {
export class ValueAccessor implements ControlValueAccessor, AfterViewInit, OnDestroy {
private onChange: (value: any) => void = () => {/**/};
private onTouched: () => void = () => {/**/};
protected lastValue: any;
private statusChanges?: Subscription;
constructor(protected el: ElementRef) {}
constructor(protected injector: Injector, protected el: ElementRef) {}
writeValue(value: any) {
/**
@@ -52,6 +54,50 @@ export class ValueAccessor implements ControlValueAccessor {
setDisabledState(isDisabled: boolean) {
this.el.nativeElement.disabled = isDisabled;
}
ngOnDestroy() {
if (this.statusChanges) {
this.statusChanges.unsubscribe();
}
}
ngAfterViewInit() {
let ngControl;
try {
ngControl = this.injector.get<NgControl>(NgControl as Type<NgControl>);
} catch { /* No FormControl or ngModel binding */ }
if (!ngControl) { return; }
// Listen for changes in validity, disabled, or pending states
if (ngControl.statusChanges) {
this.statusChanges = ngControl.statusChanges.subscribe(() => setIonicClasses(this.el));
}
/**
* TODO Remove this in favor of https://github.com/angular/angular/issues/10887
* whenever it is implemented. Currently, Ionic's form status classes
* do not react to changes when developers manually call
* Angular form control methods such as markAsTouched.
* This results in Ionic's form status classes being out
* of sync with the ng form status classes.
* This patches the methods to manually sync
* the classes until this feature is implemented in Angular.
*/
const formControl = ngControl.control;
if (formControl) {
const methodsToPatch = ['markAsTouched', 'markAllAsTouched', 'markAsUntouched', 'markAsDirty', 'markAsPristine'];
methodsToPatch.forEach(method => {
if (formControl[method]) {
const oldFn = formControl[method].bind(formControl);
formControl[method] = (...params) => {
oldFn(...params);
setIonicClasses(this.el);
};
}
});
}
}
}
export const setIonicClasses = (element: ElementRef) => {

View File

@@ -1,20 +1,24 @@
import { Directive, HostListener, Optional } from '@angular/core';
import { AnimationBuilder } from '@ionic/core';
import { Config } from '../../providers/config';
import { NavController } from '../../providers/nav-controller';
import { IonRouterOutlet } from './ion-router-outlet';
@Directive({
selector: 'ion-back-button',
inputs: ['defaultHref'],
inputs: ['defaultHref', 'routerAnimation'],
})
export class IonBackButtonDelegate {
defaultHref: string | undefined | null;
routerAnimation?: AnimationBuilder;
constructor(
@Optional() private routerOutlet: IonRouterOutlet,
private navCtrl: NavController
private navCtrl: NavController,
private config: Config
) {}
/**
@@ -22,11 +26,14 @@ export class IonBackButtonDelegate {
*/
@HostListener('click', ['$event'])
onClick(ev: Event) {
const defaultHref = this.defaultHref || this.config.get('backButtonDefaultHref');
if (this.routerOutlet && this.routerOutlet.canGoBack()) {
this.navCtrl.setDirection('back', undefined, undefined, this.routerAnimation);
this.routerOutlet.pop();
ev.preventDefault();
} else if (this.defaultHref != null) {
this.navCtrl.navigateBack(this.defaultHref);
} else if (defaultHref != null) {
this.navCtrl.navigateBack(defaultHref, { animation: this.routerAnimation });
ev.preventDefault();
}
}

View File

@@ -4,6 +4,7 @@ import { ActivatedRoute, ChildrenOutletContexts, OutletContext, PRIMARY_OUTLET,
import { BehaviorSubject, Observable } from 'rxjs';
import { distinctUntilChanged, filter, switchMap } from 'rxjs/operators';
import { AnimationBuilder } from '../../';
import { Config } from '../../providers/config';
import { NavController } from '../../providers/nav-controller';
@@ -13,13 +14,13 @@ import { RouteView, getUrl } from './stack-utils';
@Directive({
selector: 'ion-router-outlet',
exportAs: 'outlet',
inputs: ['animated', 'swipeGesture']
inputs: ['animated', 'animation', 'swipeGesture']
})
export class IonRouterOutlet implements OnDestroy, OnInit {
nativeEl: HTMLIonRouterOutletElement;
private activated: ComponentRef<any> | null = null;
private activatedView: RouteView | null = null;
activatedView: RouteView | null = null;
private _activatedRoute: ActivatedRoute | null = null;
private _swipeGesture?: boolean;
@@ -38,6 +39,10 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
@Output('activate') activateEvents = new EventEmitter<any>();
@Output('deactivate') deactivateEvents = new EventEmitter<any>();
set animation(animation: AnimationBuilder) {
this.nativeEl.animation = animation;
}
set animated(animated: boolean) {
this.nativeEl.animated = animated;
}

View File

@@ -91,6 +91,12 @@ export class IonTabs {
const alreadySelected = this.outlet.getActiveStackId() === tab;
const tabRootUrl = `${this.outlet.tabsPrefix}/${tab}`;
if (alreadySelected) {
const activeStackId = this.outlet.getActiveStackId();
const activeView = this.outlet.getLastRouteView(activeStackId);
// If on root tab, do not navigate to root tab again
if (activeView.url === tabRootUrl) { return; }
const rootView = this.outlet.getRootView(tab);
const navigationExtras = rootView && tabRootUrl === rootView.url && rootView.savedExtras;
return this.navCtrl.navigateRoot(tabRootUrl, {

View File

@@ -1,20 +1,21 @@
import { LocationStrategy } from '@angular/common';
import { Directive, ElementRef, HostListener, Optional } from '@angular/core';
import { Router, RouterLink } from '@angular/router';
import { RouterDirection } from '@ionic/core';
import { AnimationBuilder, RouterDirection } from '@ionic/core';
import { Subscription } from 'rxjs';
import { NavController } from '../../providers/nav-controller';
@Directive({
selector: '[routerLink]',
inputs: ['routerDirection']
inputs: ['routerDirection', 'routerAnimation']
})
export class RouterLinkDelegate {
private subscription?: Subscription;
routerDirection: RouterDirection = 'forward';
routerAnimation?: AnimationBuilder;
constructor(
private locationStrategy: LocationStrategy,
@@ -50,7 +51,7 @@ export class RouterLinkDelegate {
*/
@HostListener('click', ['$event'])
onClick(ev: UIEvent) {
this.navCtrl.setDirection(this.routerDirection);
this.navCtrl.setDirection(this.routerDirection, undefined, undefined, this.routerAnimation);
ev.preventDefault();
}
}

View File

@@ -1,7 +1,7 @@
import { Location } from '@angular/common';
import { ComponentRef, NgZone } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { RouterDirection } from '@ionic/core';
import { AnimationBuilder, RouterDirection } from '@ionic/core';
import { bindLifecycleEvents } from '../../providers/angular-delegate';
import { NavController } from '../../providers/nav-controller';
@@ -52,7 +52,8 @@ export class StackController {
}
setActive(enteringView: RouteView): Promise<StackEvent> {
let { direction, animation } = this.navCtrl.consumeTransition();
const consumeResult = this.navCtrl.consumeTransition();
let { direction, animation, animationBuilder } = consumeResult;
const leavingView = this.activeView;
const tabSwitch = isTabSwitch(enteringView, leavingView);
if (tabSwitch) {
@@ -105,6 +106,31 @@ export class StackController {
enteringView.ref.changeDetectorRef.detectChanges();
}
/**
* If we are going back from a page that
* was presented using a custom animation
* we should default to using that
* unless the developer explicitly
* provided another animation.
*/
const customAnimation = enteringView.animationBuilder;
if (
animationBuilder === undefined &&
direction === 'back' &&
!tabSwitch &&
customAnimation !== undefined
) {
animationBuilder = customAnimation;
}
/**
* Save any custom animation so that navigating
* back will use this custom animation by default.
*/
if (animationBuilder !== undefined && leavingView) {
leavingView.animationBuilder = animationBuilder;
}
// Wait until previous transitions finish
return this.zone.runOutsideAngular(() => {
return this.wait(() => {
@@ -116,7 +142,7 @@ export class StackController {
// In case the enteringView is the same as the leavingPage we need to reattach()
enteringView.ref.changeDetectorRef.reattach();
return this.transition(enteringView, leavingView, animation, this.canGoBack(1), false)
return this.transition(enteringView, leavingView, animation, this.canGoBack(1), false, animationBuilder)
.then(() => cleanupAsync(enteringView, views, viewsSnapshot, this.location))
.then(() => ({
enteringView,
@@ -154,8 +180,8 @@ export class StackController {
url = primaryOutlet.route._routerState.snapshot.url;
}
}
return this.navCtrl.navigateBack(url, view.savedExtras).then(() => true);
const { animationBuilder } = this.navCtrl.consumeTransition();
return this.navCtrl.navigateBack(url, { ...view.savedExtras, animation: animationBuilder }).then(() => true);
});
}
@@ -225,7 +251,8 @@ export class StackController {
leavingView: RouteView | undefined,
direction: 'forward' | 'back' | undefined,
showGoBack: boolean,
progressAnimation: boolean
progressAnimation: boolean,
animationBuilder?: AnimationBuilder
) {
if (this.skipTransition) {
this.skipTransition = false;
@@ -250,7 +277,8 @@ export class StackController {
duration: direction === undefined ? 0 : undefined,
direction,
showGoBack,
progressAnimation
progressAnimation,
animationBuilder
});
}
}

View File

@@ -1,6 +1,6 @@
import { ComponentRef } from '@angular/core';
import { ActivatedRoute, NavigationExtras, Router } from '@angular/router';
import { NavDirection, RouterDirection } from '@ionic/core';
import { AnimationBuilder, NavDirection, RouterDirection } from '@ionic/core';
export const insertView = (views: RouteView[], view: RouteView, direction: RouterDirection) => {
if (direction === 'root') {
@@ -96,4 +96,5 @@ export interface RouteView {
savedData?: any;
savedExtras?: NavigationExtras;
unlistenEvents: () => void;
animationBuilder?: AnimationBuilder;
}

View File

@@ -2,7 +2,7 @@
import * as d from './proxies';
export const DIRECTIVES = [
d.IonApp,
d.IonApp,
d.IonAvatar,
d.IonBackButton,
d.IonBackdrop,

View File

@@ -1,29 +1,30 @@
/* 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));
}
});
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)
);
};
Prototype[methodName] = function () {
const args = arguments;
return this.z.runOutsideAngular(() =>
this.el[methodName].apply(this.el, args)
);
};
});
};
@@ -31,16 +32,15 @@ export const proxyOutputs = (instance: any, el: any, events: string[]) => {
events.forEach(eventName => instance[eventName] = fromEvent(el, eventName));
}
// tslint:disable-next-line: only-arrow-functions
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;
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

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

View File

@@ -1,14 +1,24 @@
import { Injectable } from '@angular/core';
import { Injectable, NgZone } from '@angular/core';
import { Gesture, GestureConfig, createGesture } from '@ionic/core';
@Injectable({
providedIn: 'root',
})
export class GestureController {
constructor(private zone: NgZone) {}
/**
* Create a new gesture
*/
create(opts: GestureConfig): Gesture {
create(opts: GestureConfig, runInsideAngularZone = false): Gesture {
if (runInsideAngularZone) {
Object.getOwnPropertyNames(opts).forEach(key => {
if (typeof opts[key] === 'function') {
const fn = opts[key];
opts[key] = (...props) => this.zone.run(() => fn(...props));
}
});
}
return createGesture(opts);
}
}

View File

@@ -1,7 +1,7 @@
import { Location } from '@angular/common';
import { Injectable, Optional } from '@angular/core';
import { NavigationExtras, NavigationStart, Router, UrlSerializer, UrlTree } from '@angular/router';
import { NavDirection, RouterDirection } from '@ionic/core';
import { AnimationBuilder, NavDirection, RouterDirection } from '@ionic/core';
import { IonRouterOutlet } from '../directives/navigation/ion-router-outlet';
@@ -9,6 +9,7 @@ import { Platform } from './platform';
export interface AnimationOptions {
animated?: boolean;
animation?: AnimationBuilder;
animationDirection?: 'forward' | 'back';
}
@@ -22,6 +23,7 @@ export class NavController {
private topOutlet?: IonRouterOutlet;
private direction: 'forward' | 'back' | 'root' | 'auto' = DEFAULT_DIRECTION;
private animated?: NavDirection = DEFAULT_ANIMATED;
private animationBuilder?: AnimationBuilder;
private guessDirection: RouterDirection = 'forward';
private guessAnimation?: NavDirection;
private lastNavId = -1;
@@ -45,7 +47,10 @@ export class NavController {
}
// Subscribe to backButton events
platform.backButton.subscribeWithPriority(0, () => this.pop());
platform.backButton.subscribeWithPriority(0, processNextHandler => {
this.pop();
processNextHandler();
});
}
/**
@@ -62,7 +67,7 @@ export class NavController {
* ```
*/
navigateForward(url: string | UrlTree | any[], options: NavigationOptions = {}): Promise<boolean> {
this.setDirection('forward', options.animated, options.animationDirection);
this.setDirection('forward', options.animated, options.animationDirection, options.animation);
return this.navigate(url, options);
}
@@ -85,7 +90,7 @@ export class NavController {
* ```
*/
navigateBack(url: string | UrlTree | any[], options: NavigationOptions = {}): Promise<boolean> {
this.setDirection('back', options.animated, options.animationDirection);
this.setDirection('back', options.animated, options.animationDirection, options.animation);
return this.navigate(url, options);
}
@@ -108,7 +113,7 @@ export class NavController {
* ```
*/
navigateRoot(url: string | UrlTree | any[], options: NavigationOptions = {}): Promise<boolean> {
this.setDirection('root', options.animated, options.animationDirection);
this.setDirection('root', options.animated, options.animationDirection, options.animation);
return this.navigate(url, options);
}
@@ -118,7 +123,7 @@ export class NavController {
* by default.
*/
back(options: AnimationOptions = { animated: true, animationDirection: 'back' }) {
this.setDirection('back', options.animated, options.animationDirection);
this.setDirection('back', options.animated, options.animationDirection, options.animation);
return this.location.back();
}
@@ -147,9 +152,10 @@ export class NavController {
*
* It's recommended to use `navigateForward()`, `navigateBack()` and `navigateRoot()` instead of `setDirection()`.
*/
setDirection(direction: RouterDirection, animated?: boolean, animationDirection?: 'forward' | 'back') {
setDirection(direction: RouterDirection, animated?: boolean, animationDirection?: 'forward' | 'back', animationBuilder?: AnimationBuilder) {
this.direction = direction;
this.animated = getAnimation(direction, animated, animationDirection);
this.animationBuilder = animationBuilder;
}
/**
@@ -165,6 +171,7 @@ export class NavController {
consumeTransition() {
let direction: RouterDirection = 'root';
let animation: NavDirection | undefined;
const animationBuilder = this.animationBuilder;
if (this.direction === 'auto') {
direction = this.guessDirection;
@@ -175,10 +182,12 @@ export class NavController {
}
this.direction = DEFAULT_DIRECTION;
this.animated = DEFAULT_ANIMATED;
this.animationBuilder = undefined;
return {
direction,
animation
animation,
animationBuilder
};
}

View File

@@ -1,10 +1,10 @@
import { DOCUMENT } from '@angular/common';
import { Inject, Injectable, NgZone } from '@angular/core';
import { BackButtonEventDetail, Platforms, getPlatforms, isPlatform } from '@ionic/core';
import { BackButtonEventDetail, KeyboardEventDetail, Platforms, getPlatforms, isPlatform } from '@ionic/core';
import { Subject, Subscription } from 'rxjs';
export interface BackButtonEmitter extends Subject<BackButtonEventDetail> {
subscribeWithPriority(priority: number, callback: () => Promise<any> | void): Subscription;
subscribeWithPriority(priority: number, callback: (processNextHandler: () => void) => Promise<any> | void): Subscription;
}
@Injectable({
@@ -20,6 +20,18 @@ export class Platform {
*/
backButton: BackButtonEmitter = new Subject<BackButtonEventDetail>() as any;
/**
* The keyboardDidShow event emits when the
* on-screen keyboard is presented.
*/
keyboardDidShow = new Subject<KeyboardEventDetail>() as any;
/**
* The keyboardDidHide event emits when the
* on-screen keyboard is hidden.
*/
keyboardDidHide = new Subject<void>();
/**
* The pause event emits when the native platform puts the application
* into the background, typically when the user switches to a different
@@ -46,15 +58,17 @@ export class Platform {
zone.run(() => {
this.win = doc.defaultView;
this.backButton.subscribeWithPriority = function(priority, callback) {
return this.subscribe(ev => (
ev.register(priority, () => zone.run(callback))
));
return this.subscribe(ev => {
return ev.register(priority, processNextHandler => zone.run(() => callback(processNextHandler)));
});
};
proxyEvent(this.pause, doc, 'pause');
proxyEvent(this.resume, doc, 'resume');
proxyEvent(this.backButton, doc, 'ionBackButton');
proxyEvent(this.resize, this.win, 'resize');
proxyEvent(this.keyboardDidShow, this.win, 'ionKeyboardDidShow');
proxyEvent(this.keyboardDidHide, this.win, 'ionKeyboardDidHide');
let readyResolve: (value: string) => void;
this._readyPromise = new Promise(res => { readyResolve = res; });

View File

@@ -2,7 +2,7 @@ import { join, Path } from '@angular-devkit/core';
import { apply, chain, mergeWith, move, Rule, SchematicContext, SchematicsException, template, Tree, url } from '@angular-devkit/schematics';
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
import { addModuleImportToRootModule } from './../utils/ast';
import { addArchitectBuilder, addStyle, getWorkspace, addAsset, WorkspaceProject, WorkspaceSchema } from './../utils/config';
import { addArchitectBuilder, addAsset, addStyle, getDefaultAngularAppName, getWorkspace, WorkspaceProject, WorkspaceSchema } from './../utils/config';
import { addPackageToPackageJson } from './../utils/package';
import { Schema as IonAddOptions } from './schema';
@@ -37,7 +37,7 @@ function addIonicAngularModuleToAppModule(projectSourceRoot: Path): Rule {
};
}
function addIonicStyles(projectSourceRoot: Path): Rule {
function addIonicStyles(projectName: string, projectSourceRoot: Path): Rule {
return (host: Tree) => {
const ionicStyles = [
'node_modules/@ionic/angular/css/normalize.css',
@@ -51,27 +51,27 @@ function addIonicStyles(projectSourceRoot: Path): Rule {
'node_modules/@ionic/angular/css/flex-utils.css',
`${projectSourceRoot}/theme/variables.css`
].forEach(entry => {
addStyle(host, entry);
addStyle(host, projectName, entry);
});
return host;
};
}
function addIonicons(): Rule {
function addIonicons(projectName: string): Rule {
return (host: Tree) => {
const ioniconsGlob = {
glob: '**/*.svg',
input: 'node_modules/ionicons/dist/ionicons/svg',
output: './svg'
};
addAsset(host, ioniconsGlob);
addAsset(host, projectName, ioniconsGlob);
return host;
};
}
function addIonicBuilder(projectName: string): Rule {
return (host: Tree) => {
addArchitectBuilder(host, 'ionic-cordova-serve', {
addArchitectBuilder(host, projectName, 'ionic-cordova-serve', {
builder: '@ionic/angular-toolkit:cordova-serve',
options: {
cordovaBuildTarget: `${projectName}:ionic-cordova-build`,
@@ -84,7 +84,7 @@ function addIonicBuilder(projectName: string): Rule {
}
}
});
addArchitectBuilder(host, 'ionic-cordova-build', {
addArchitectBuilder(host, projectName, 'ionic-cordova-build', {
builder: '@ionic/angular-toolkit:cordova-build',
options: {
browserTarget: `${projectName}:build`
@@ -109,7 +109,7 @@ export default function ngAdd(options: IonAddOptions): Rule {
return (host: Tree) => {
const workspace: WorkspaceSchema = getWorkspace(host);
if (!options.project) {
options.project = Object.keys(workspace.projects)[0];
options.project = getDefaultAngularAppName(workspace);
}
const project: WorkspaceProject = workspace.projects[options.project];
if (project.projectType !== 'application') {
@@ -128,8 +128,8 @@ export default function ngAdd(options: IonAddOptions): Rule {
addIonicAngularToolkitToPackageJson(),
addIonicAngularModuleToAppModule(sourcePath),
addIonicBuilder(options.project),
addIonicStyles(sourcePath),
addIonicons(),
addIonicStyles(options.project, sourcePath),
addIonicons(options.project),
mergeWith(rootTemplateSource),
// install freshly added dependencies
installNodeDeps()

View File

@@ -27,7 +27,7 @@ export function getSourceFile(host: Tree, path: string): ts.SourceFile {
*/
export function addModuleImportToRootModule(
host: Tree,
projectSourceRoot,
projectSourceRoot: string,
moduleName: string,
importSrc: string
) {

View File

@@ -21,7 +21,7 @@ function isAngularBrowserProject(projectConfig: any) {
return false;
}
export function getAngularAppName(config: any): string | null {
export function getDefaultAngularAppName(config: any): string {
const projects = config.projects;
const projectNames = Object.keys(projects);
@@ -32,60 +32,48 @@ export function getAngularAppName(config: any): string | null {
}
}
return null;
return projectNames[0];
}
export function getAngularAppConfig(config: any): any | null {
const projects = config.projects;
const projectNames = Object.keys(projects);
for (const projectName of projectNames) {
const projectConfig = projects[projectName];
if (isAngularBrowserProject(projectConfig)) {
return projectConfig;
}
export function getAngularAppConfig(config: any, projectName: string): any | never {
if (!config.projects.hasOwnProperty(projectName)) {
throw new SchematicsException(`Could not find project: ${projectName}`);
}
return null;
}
const projectConfig = config.projects[projectName];
if (isAngularBrowserProject(projectConfig)) {
return projectConfig;
}
export function addStyle(host: Tree, stylePath: string) {
const config = readConfig(host);
const appConfig = getAngularAppConfig(config);
if (appConfig) {
appConfig.architect.build.options.styles.push({
input: stylePath
});
writeConfig(host, config);
if (config.projectType !== 'application') {
throw new SchematicsException(`Invalid projectType for ${projectName}: ${config.projectType}`);
} else {
throw new SchematicsException(`Cannot find valid app`);
const buildConfig = projectConfig.architect.build;
throw new SchematicsException(`Invalid builder for ${projectName}: ${buildConfig.builder}`);
}
}
export function addAsset(host: Tree, asset: string | {glob: string; input: string; output: string}) {
export function addStyle(host: Tree, projectName: string, stylePath: string) {
const config = readConfig(host);
const appConfig = getAngularAppConfig(config);
if (appConfig) {
appConfig.architect.build.options.assets.push(asset);
writeConfig(host, config);
} else {
throw new SchematicsException(`Cannot find valid app`);
}
const appConfig = getAngularAppConfig(config, projectName);
appConfig.architect.build.options.styles.push({
input: stylePath
});
writeConfig(host, config);
}
export function addArchitectBuilder(host: Tree, builderName: string, builderOpts: any){
export function addAsset(host: Tree, projectName: string, asset: string | {glob: string; input: string; output: string}) {
const config = readConfig(host);
const appConfig = getAngularAppConfig(config);
const appConfig = getAngularAppConfig(config, projectName);
appConfig.architect.build.options.assets.push(asset);
writeConfig(host, config);
}
if (appConfig) {
appConfig.architect[builderName] = builderOpts
writeConfig(host, config);
} else {
throw new SchematicsException(`Cannot find valid app`);
}
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;

View File

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

View File

@@ -1,5 +1,5 @@
import { browser, element, by } from 'protractor';
import { handleErrorMessages, setProperty, getText, waitTime } from './utils';
import { handleErrorMessages, getProperty, setProperty, getText, waitTime } from './utils';
describe('form', () => {
@@ -7,6 +7,20 @@ describe('form', () => {
return handleErrorMessages();
});
describe('status updates', () => {
beforeEach(async () => {
await browser.get('/form');
await waitTime(30);
});
it('should update Ionic form classes when calling form methods programatically', async () => {
await element(by.css('form #input-touched')).click();
await waitTime(100);
const classList = (await getProperty('#touched-input-test', 'classList')) as string[];
expect(classList.includes('ion-touched')).toEqual(true);
});
});
describe('change', () => {
beforeEach(async () => {
await browser.get('/form');

View File

@@ -41,7 +41,7 @@
"@angular/cli": "^9.0.0-rc.2",
"@angular/compiler-cli": "^9.0.0-rc.2",
"@angular/language-service": "^9.0.0-rc.2",
"@nguniversal/builders": "^9.0.0-next.9",
"@nguniversal/builders": "9.0.0-next.9",
"@types/express": "^4.17.0",
"@types/jasmine": "3.4.1",
"@types/node": "^12.11.1",

View File

@@ -1,5 +1,8 @@
<ion-header>
<ion-toolbar>
<ion-buttons>
<ion-back-button></ion-back-button>
</ion-buttons>
<ion-title>
Alert test
</ion-title>

View File

@@ -35,9 +35,11 @@
<ion-item>
<ion-label>Input (required)</ion-label>
<ion-input formControlName="input" class="required"></ion-input>
<ion-input formControlName="input" class="required" id="touched-input-test"></ion-input>
</ion-item>
<ion-button id="input-touched" (click)="setTouched()">Set Input Touched</ion-button>
<ion-item>
<ion-label>Input</ion-label>
<ion-input formControlName="input2"></ion-input>

View File

@@ -25,6 +25,11 @@ export class FormComponent {
});
}
setTouched() {
const formControl = this.profileForm.get('input');
formControl.markAsTouched();
}
onSubmit(_ev) {
this.submitted = 'true';
}

View File

@@ -7,7 +7,7 @@
</ion-header>
<ion-content>
<ion-list>
<ion-item routerLink="/alerts">
<ion-item routerLink="/alerts" [routerAnimation]="routerAnimation">
<ion-label>
Alerts test
</ion-label>

View File

@@ -1,9 +1,25 @@
import { Component } from '@angular/core';
import { AnimationBuilder, AnimationController } from '@ionic/angular';
@Component({
selector: 'app-home-page',
templateUrl: './home-page.component.html',
})
export class HomePageComponent {
routerAnimation: AnimationBuilder = (_, opts) => {
const { direction, enteringEl, leavingEl } = opts;
const animation = this.animationCtrl.create().duration(500).easing('ease-out');
const enteringAnimation = this.animationCtrl.create().addElement(enteringEl).beforeRemoveClass(['ion-page-invisible']);
const leavingAnimation = this.animationCtrl.create().addElement(leavingEl).beforeRemoveClass(['ion-page-invisible']);
if (direction === 'back') {
enteringAnimation.fromTo('transform', 'translateX(-100%)', 'translateX(0%)');
leavingAnimation.fromTo('transform', 'translateX(0%)', 'translateX(100%)');
} else {
enteringAnimation.fromTo('transform', 'translateX(100%)', 'translateX(0%)');
leavingAnimation.fromTo('transform', 'translateX(0%)', 'translateX(-100%)');
}
return animation.addAnimation([enteringAnimation, leavingAnimation]);
};
constructor(private animationCtrl: AnimationController) {}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,121 +0,0 @@
# Contribution guide
## Contribute to Ionic Core
Ionic Core is the fundation of Ionic v4. It's based in [Stencil](https://stenciljs.com) and consist in a set of web components a long of JS and CSS utils.
### Installing dependencies
Before you can build ionic, we assume the following list of software is already installed in your system
- Git
- Node 8 or higher
- Npm 6.0 or higher
### Fork repository
In order to contributo to Ionic, you must have a github account so you can push code and create a new Pull Request (PR).
Once you are all setup, following the Github's guide of how to fork a repository: https://guides.github.com/activities/forking/
### Build Ionic Core
```bash
# Clone your Github repository:
git clone https://github.com/<github username>/ionic.git
# Go to the core directory:
cd ionic/core
# Install npm dependencies
npm install
# Run Ionic dev server
npm start
```
### Development Workflow
#### 1. Run Dev Server
```bash
# Move to the core folder
cd core
# Run dev server
npm start
```
You should be able to navigate to `http://localhost:3333` which will look like a file browser.
E2E tests are located inside the `src/components` folder, in the following way: `http://localhost:3333/src/components/{COMPONENT}/test/`
**Path examples:**
- ActionSheet basic test: http://localhost:3333/src/components/action-sheet/test/basic
- Nav basic test: http://localhost:3333/src/components/nav/test/basic
- Button basic test:
http://localhost:3333/src/components/button/test/basic
**IMPORTANT**
Leave the dev server running in the background while you make changes. The dev server listen for changes and automatically recompile Ionic for you.
#### 2. Open `core` folder in your IDE
Components implementations live inside the `core/src/components` folder.
You can find each ionic component inside their directory.
#### 3. Run test suite
Before commiting your changes make sure tests are passing:
```
npm run validate
```
#### 4. Create a branch and commit
```bash
# Create a git branch
git checkout -b my-improvement
# Add changes
git add .
# Create commit
git commit -m "fix(component): message"
```
Create a PR:
https://guides.github.com/activities/forking/
### Summary
```bash
# Clone repo
git clone git@github.com:ionic-team/ionic.git
# Move to ionic/core folder
cd ionic/core
# Install npm dependencies
npm i
# Run dev server
npm start
# Run test suite
npm run validate
```

View File

@@ -23,9 +23,9 @@ The Ionic Core package contains the Web Components that make up the reusable UI
Easiest way to start using Ionic Core is by adding a script tag to the CDN:
```html
<script type="module" src="https://cdn.jsdelivr.net/npm/@ionic/core@4.6.2/dist/ionic/ionic.esm.js"></script>
<script nomodule src="https://cdn.jsdelivr.net/npm/@ionic/core@4.6.2/dist/ionic/ionic.js"></script>
<link href="https://cdn.jsdelivr.net/npm/@ionic/core@4.6.2/css/ionic.bundle.css" rel="stylesheet">
<script type="module" src="https://cdn.jsdelivr.net/npm/@ionic/core/dist/ionic/ionic.esm.js"></script>
<script nomodule src="https://cdn.jsdelivr.net/npm/@ionic/core/dist/ionic/ionic.js"></script>
<link href="https://cdn.jsdelivr.net/npm/@ionic/core/css/ionic.bundle.css" rel="stylesheet">
```
Any Ionic component added to the webpage will automatically load. This includes writing the component tag directly in HTML, or using JavaScript such as `document.createElement('ion-toggle')`.

View File

@@ -12,8 +12,8 @@ ion-action-sheet,prop,mode,"ios" | "md",undefined,false,false
ion-action-sheet,prop,subHeader,string | undefined,undefined,false,false
ion-action-sheet,prop,translucent,boolean,false,false,false
ion-action-sheet,method,dismiss,dismiss(data?: any, role?: string | undefined) => Promise<boolean>
ion-action-sheet,method,onDidDismiss,onDidDismiss() => Promise<OverlayEventDetail<any>>
ion-action-sheet,method,onWillDismiss,onWillDismiss() => Promise<OverlayEventDetail<any>>
ion-action-sheet,method,onDidDismiss,onDidDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-action-sheet,method,onWillDismiss,onWillDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-action-sheet,method,present,present() => Promise<void>
ion-action-sheet,event,ionActionSheetDidDismiss,OverlayEventDetail<any>,true
ion-action-sheet,event,ionActionSheetDidPresent,void,true
@@ -53,13 +53,13 @@ ion-alert,prop,header,string | undefined,undefined,false,false
ion-alert,prop,inputs,AlertInput[],[],false,false
ion-alert,prop,keyboardClose,boolean,true,false,false
ion-alert,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-alert,prop,message,string | undefined,undefined,false,false
ion-alert,prop,message,IonicSafeString | string | undefined,undefined,false,false
ion-alert,prop,mode,"ios" | "md",undefined,false,false
ion-alert,prop,subHeader,string | undefined,undefined,false,false
ion-alert,prop,translucent,boolean,false,false,false
ion-alert,method,dismiss,dismiss(data?: any, role?: string | undefined) => Promise<boolean>
ion-alert,method,onDidDismiss,onDidDismiss() => Promise<OverlayEventDetail<any>>
ion-alert,method,onWillDismiss,onWillDismiss() => Promise<OverlayEventDetail<any>>
ion-alert,method,onDidDismiss,onDidDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-alert,method,onWillDismiss,onWillDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-alert,method,present,present() => Promise<void>
ion-alert,event,ionAlertDidDismiss,OverlayEventDetail<any>,true
ion-alert,event,ionAlertDidPresent,void,true
@@ -85,6 +85,7 @@ ion-back-button,prop,defaultHref,string | undefined,undefined,false,false
ion-back-button,prop,disabled,boolean,false,false,true
ion-back-button,prop,icon,null | string | undefined,undefined,false,false
ion-back-button,prop,mode,"ios" | "md",undefined,false,false
ion-back-button,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-back-button,prop,text,null | string | undefined,undefined,false,false
ion-back-button,prop,type,"button" | "reset" | "submit",'button',false,false
ion-back-button,css-prop,--background
@@ -119,6 +120,9 @@ ion-back-button,css-prop,--padding-start
ion-back-button,css-prop,--padding-top
ion-back-button,css-prop,--ripple-color
ion-back-button,css-prop,--transition
ion-back-button,part,icon
ion-back-button,part,native
ion-back-button,part,text
ion-backdrop,shadow
ion-backdrop,prop,stopPropagation,boolean,true,false,false
@@ -146,6 +150,7 @@ ion-button,prop,fill,"clear" | "default" | "outline" | "solid" | undefined,undef
ion-button,prop,href,string | undefined,undefined,false,false
ion-button,prop,mode,"ios" | "md",undefined,false,false
ion-button,prop,rel,string | undefined,undefined,false,false
ion-button,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-button,prop,routerDirection,"back" | "forward" | "root",'forward',false,false
ion-button,prop,shape,"round" | undefined,undefined,false,true
ion-button,prop,size,"default" | "large" | "small" | undefined,undefined,false,true
@@ -177,6 +182,7 @@ ion-button,css-prop,--padding-start
ion-button,css-prop,--padding-top
ion-button,css-prop,--ripple-color
ion-button,css-prop,--transition
ion-button,part,native
ion-buttons,scoped
ion-buttons,prop,collapse,boolean,false,false,false
@@ -189,11 +195,13 @@ ion-card,prop,download,string | undefined,undefined,false,false
ion-card,prop,href,string | undefined,undefined,false,false
ion-card,prop,mode,"ios" | "md",undefined,false,false
ion-card,prop,rel,string | undefined,undefined,false,false
ion-card,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-card,prop,routerDirection,"back" | "forward" | "root",'forward',false,false
ion-card,prop,target,string | undefined,undefined,false,false
ion-card,prop,type,"button" | "reset" | "submit",'button',false,false
ion-card,css-prop,--background
ion-card,css-prop,--color
ion-card,part,native
ion-card-content,none
ion-card-content,prop,mode,"ios" | "md",undefined,false,false
@@ -235,6 +243,8 @@ ion-checkbox,css-prop,--checkmark-color
ion-checkbox,css-prop,--checkmark-width
ion-checkbox,css-prop,--size
ion-checkbox,css-prop,--transition
ion-checkbox,part,container
ion-checkbox,part,mark
ion-chip,shadow
ion-chip,prop,color,string | undefined,undefined,false,false
@@ -286,7 +296,7 @@ ion-content,prop,scrollY,boolean,true,false,false
ion-content,method,getScrollElement,getScrollElement() => Promise<HTMLElement>
ion-content,method,scrollByPoint,scrollByPoint(x: number, y: number, duration: number) => Promise<void>
ion-content,method,scrollToBottom,scrollToBottom(duration?: number) => Promise<void>
ion-content,method,scrollToPoint,scrollToPoint(x: number | null | undefined, y: number | null | undefined, duration?: number) => Promise<void>
ion-content,method,scrollToPoint,scrollToPoint(x: number | undefined | null, y: number | undefined | null, duration?: number) => Promise<void>
ion-content,method,scrollToTop,scrollToTop(duration?: number) => Promise<void>
ion-content,event,ionScroll,ScrollDetail,true
ion-content,event,ionScrollEnd,ScrollBaseDetail,true
@@ -300,6 +310,8 @@ ion-content,css-prop,--padding-bottom
ion-content,css-prop,--padding-end
ion-content,css-prop,--padding-start
ion-content,css-prop,--padding-top
ion-content,part,background
ion-content,part,scroll
ion-datetime,shadow
ion-datetime,prop,cancelText,string,'Cancel',false,false
@@ -335,6 +347,8 @@ ion-datetime,css-prop,--padding-end
ion-datetime,css-prop,--padding-start
ion-datetime,css-prop,--padding-top
ion-datetime,css-prop,--placeholder-color
ion-datetime,part,placeholder
ion-datetime,part,text
ion-fab,shadow
ion-fab,prop,activated,boolean,false,false,false
@@ -345,12 +359,14 @@ ion-fab,method,close,close() => Promise<void>
ion-fab-button,shadow
ion-fab-button,prop,activated,boolean,false,false,false
ion-fab-button,prop,closeIcon,string,'close',false,false
ion-fab-button,prop,color,string | undefined,undefined,false,false
ion-fab-button,prop,disabled,boolean,false,false,false
ion-fab-button,prop,download,string | undefined,undefined,false,false
ion-fab-button,prop,href,string | undefined,undefined,false,false
ion-fab-button,prop,mode,"ios" | "md",undefined,false,false
ion-fab-button,prop,rel,string | undefined,undefined,false,false
ion-fab-button,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-fab-button,prop,routerDirection,"back" | "forward" | "root",'forward',false,false
ion-fab-button,prop,show,boolean,false,false,false
ion-fab-button,prop,size,"small" | undefined,undefined,false,false
@@ -371,6 +387,7 @@ ion-fab-button,css-prop,--border-radius
ion-fab-button,css-prop,--border-style
ion-fab-button,css-prop,--border-width
ion-fab-button,css-prop,--box-shadow
ion-fab-button,css-prop,--close-icon-font-size
ion-fab-button,css-prop,--color
ion-fab-button,css-prop,--color-activated
ion-fab-button,css-prop,--color-focused
@@ -381,6 +398,8 @@ ion-fab-button,css-prop,--padding-start
ion-fab-button,css-prop,--padding-top
ion-fab-button,css-prop,--ripple-color
ion-fab-button,css-prop,--transition
ion-fab-button,part,close-icon
ion-fab-button,part,native
ion-fab-list,shadow
ion-fab-list,prop,activated,boolean,false,false,false
@@ -416,6 +435,7 @@ ion-img,prop,src,string | undefined,undefined,false,false
ion-img,event,ionError,void,true
ion-img,event,ionImgDidLoad,void,true
ion-img,event,ionImgWillLoad,void,true
ion-img,part,image
ion-infinite-scroll,none
ion-infinite-scroll,prop,disabled,boolean,false,false,false
@@ -426,12 +446,12 @@ ion-infinite-scroll,event,ionInfinite,void,true
ion-infinite-scroll-content,none
ion-infinite-scroll-content,prop,loadingSpinner,"bubbles" | "circles" | "circular" | "crescent" | "dots" | "lines" | "lines-small" | null | undefined,undefined,false,false
ion-infinite-scroll-content,prop,loadingText,string | undefined,undefined,false,false
ion-infinite-scroll-content,prop,loadingText,IonicSafeString | string | undefined,undefined,false,false
ion-input,scoped
ion-input,prop,accept,string | undefined,undefined,false,false
ion-input,prop,autocapitalize,string,'off',false,false
ion-input,prop,autocomplete,"off" | "on",'off',false,false
ion-input,prop,autocomplete,"on" | "off" | "name" | "honorific-prefix" | "given-name" | "additional-name" | "family-name" | "honorific-suffix" | "nickname" | "email" | "username" | "new-password" | "current-password" | "one-time-code" | "organization-title" | "organization" | "street-address" | "address-line1" | "address-line2" | "address-line3" | "address-level4" | "address-level3" | "address-level2" | "address-level1" | "country" | "country-name" | "postal-code" | "cc-name" | "cc-given-name" | "cc-additional-name" | "cc-family-name" | "cc-number" | "cc-exp" | "cc-exp-month" | "cc-exp-year" | "cc-csc" | "cc-type" | "transaction-currency" | "transaction-amount" | "language" | "bday" | "bday-day" | "bday-month" | "bday-year" | "sex" | "tel" | "tel-country-code" | "tel-national" | "tel-area-code" | "tel-local" | "tel-extension" | "impp" | "url" | "photo",'off',false,false
ion-input,prop,autocorrect,"off" | "on",'off',false,false
ion-input,prop,autofocus,boolean,false,false,false
ion-input,prop,clearInput,boolean,false,false,false
@@ -439,6 +459,7 @@ ion-input,prop,clearOnEdit,boolean | undefined,undefined,false,false
ion-input,prop,color,string | undefined,undefined,false,false
ion-input,prop,debounce,number,0,false,false
ion-input,prop,disabled,boolean,false,false,false
ion-input,prop,enterkeyhint,"done" | "enter" | "go" | "next" | "previous" | "search" | "send" | undefined,undefined,false,false
ion-input,prop,inputmode,"decimal" | "email" | "none" | "numeric" | "search" | "tel" | "text" | "url" | undefined,undefined,false,false
ion-input,prop,max,string | undefined,undefined,false,false
ion-input,prop,maxlength,number | undefined,undefined,false,false
@@ -484,6 +505,7 @@ ion-item,prop,href,string | undefined,undefined,false,false
ion-item,prop,lines,"full" | "inset" | "none" | undefined,undefined,false,false
ion-item,prop,mode,"ios" | "md",undefined,false,false
ion-item,prop,rel,string | undefined,undefined,false,false
ion-item,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-item,prop,routerDirection,"back" | "forward" | "root",'forward',false,false
ion-item,prop,target,string | undefined,undefined,false,false
ion-item,prop,type,"button" | "reset" | "submit",'button',false,false
@@ -522,6 +544,8 @@ ion-item,css-prop,--padding-start
ion-item,css-prop,--padding-top
ion-item,css-prop,--ripple-color
ion-item,css-prop,--transition
ion-item,part,detail-icon
ion-item,part,native
ion-item-divider,shadow
ion-item-divider,prop,color,string | undefined,undefined,false,false
@@ -552,6 +576,7 @@ ion-item-option,prop,target,string | undefined,undefined,false,false
ion-item-option,prop,type,"button" | "reset" | "submit",'button',false,false
ion-item-option,css-prop,--background
ion-item-option,css-prop,--color
ion-item-option,part,native
ion-item-options,none
ion-item-options,prop,side,"end" | "start",'end',false,false
@@ -563,7 +588,7 @@ ion-item-sliding,method,close,close() => Promise<void>
ion-item-sliding,method,closeOpened,closeOpened() => Promise<boolean>
ion-item-sliding,method,getOpenAmount,getOpenAmount() => Promise<number>
ion-item-sliding,method,getSlidingRatio,getSlidingRatio() => Promise<number>
ion-item-sliding,method,open,open(side: "start" | "end" | undefined) => Promise<void>
ion-item-sliding,method,open,open(side: Side | undefined) => Promise<void>
ion-item-sliding,event,ionDrag,any,true
ion-label,scoped
@@ -597,14 +622,14 @@ ion-loading,prop,duration,number,0,false,false
ion-loading,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-loading,prop,keyboardClose,boolean,true,false,false
ion-loading,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-loading,prop,message,string | undefined,undefined,false,false
ion-loading,prop,message,IonicSafeString | string | undefined,undefined,false,false
ion-loading,prop,mode,"ios" | "md",undefined,false,false
ion-loading,prop,showBackdrop,boolean,true,false,false
ion-loading,prop,spinner,"bubbles" | "circles" | "circular" | "crescent" | "dots" | "lines" | "lines-small" | null | undefined,undefined,false,false
ion-loading,prop,translucent,boolean,false,false,false
ion-loading,method,dismiss,dismiss(data?: any, role?: string | undefined) => Promise<boolean>
ion-loading,method,onDidDismiss,onDidDismiss() => Promise<OverlayEventDetail<any>>
ion-loading,method,onWillDismiss,onWillDismiss() => Promise<OverlayEventDetail<any>>
ion-loading,method,onDidDismiss,onDidDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-loading,method,onWillDismiss,onWillDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-loading,method,present,present() => Promise<void>
ion-loading,event,ionLoadingDidDismiss,OverlayEventDetail<any>,true
ion-loading,event,ionLoadingDidPresent,void,true
@@ -645,12 +670,15 @@ ion-menu,css-prop,--max-width
ion-menu,css-prop,--min-height
ion-menu,css-prop,--min-width
ion-menu,css-prop,--width
ion-menu,part,backdrop
ion-menu,part,container
ion-menu-button,shadow
ion-menu-button,prop,autoHide,boolean,true,false,false
ion-menu-button,prop,color,string | undefined,undefined,false,false
ion-menu-button,prop,disabled,boolean,false,false,false
ion-menu-button,prop,menu,string | undefined,undefined,false,false
ion-menu-button,prop,mode,"ios" | "md",undefined,false,false
ion-menu-button,prop,type,"button" | "reset" | "submit",'button',false,false
ion-menu-button,css-prop,--background
ion-menu-button,css-prop,--background-focused
@@ -665,6 +693,8 @@ ion-menu-button,css-prop,--padding-bottom
ion-menu-button,css-prop,--padding-end
ion-menu-button,css-prop,--padding-start
ion-menu-button,css-prop,--padding-top
ion-menu-button,part,icon
ion-menu-button,part,native
ion-menu-toggle,shadow
ion-menu-toggle,prop,autoHide,boolean,true,false,false
@@ -684,8 +714,8 @@ ion-modal,prop,presentingElement,HTMLElement | undefined,undefined,false,false
ion-modal,prop,showBackdrop,boolean,true,false,false
ion-modal,prop,swipeToClose,boolean,false,false,false
ion-modal,method,dismiss,dismiss(data?: any, role?: string | undefined) => Promise<boolean>
ion-modal,method,onDidDismiss,onDidDismiss() => Promise<OverlayEventDetail<any>>
ion-modal,method,onWillDismiss,onWillDismiss() => Promise<OverlayEventDetail<any>>
ion-modal,method,onDidDismiss,onDidDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-modal,method,onWillDismiss,onWillDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-modal,method,present,present() => Promise<void>
ion-modal,event,ionModalDidDismiss,OverlayEventDetail<any>,true
ion-modal,event,ionModalDidPresent,void,true
@@ -729,6 +759,7 @@ ion-nav,event,ionNavWillChange,void,false
ion-nav-link,none
ion-nav-link,prop,component,Function | HTMLElement | ViewController | null | string | undefined,undefined,false,false
ion-nav-link,prop,componentProps,undefined | { [key: string]: any; },undefined,false,false
ion-nav-link,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-nav-link,prop,routerDirection,"back" | "forward" | "root",'forward',false,false
ion-note,shadow
@@ -750,8 +781,8 @@ ion-picker,prop,mode,"ios" | "md",undefined,false,false
ion-picker,prop,showBackdrop,boolean,true,false,false
ion-picker,method,dismiss,dismiss(data?: any, role?: string | undefined) => Promise<boolean>
ion-picker,method,getColumn,getColumn(name: string) => Promise<PickerColumn | undefined>
ion-picker,method,onDidDismiss,onDidDismiss() => Promise<OverlayEventDetail<any>>
ion-picker,method,onWillDismiss,onWillDismiss() => Promise<OverlayEventDetail<any>>
ion-picker,method,onDidDismiss,onDidDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-picker,method,onWillDismiss,onWillDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-picker,method,present,present() => Promise<void>
ion-picker,event,ionPickerDidDismiss,OverlayEventDetail<any>,true
ion-picker,event,ionPickerDidPresent,void,true
@@ -785,8 +816,8 @@ ion-popover,prop,mode,"ios" | "md",undefined,false,false
ion-popover,prop,showBackdrop,boolean,true,false,false
ion-popover,prop,translucent,boolean,false,false,false
ion-popover,method,dismiss,dismiss(data?: any, role?: string | undefined) => Promise<boolean>
ion-popover,method,onDidDismiss,onDidDismiss() => Promise<OverlayEventDetail<any>>
ion-popover,method,onWillDismiss,onWillDismiss() => Promise<OverlayEventDetail<any>>
ion-popover,method,onDidDismiss,onDidDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-popover,method,onWillDismiss,onWillDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-popover,method,present,present() => Promise<void>
ion-popover,event,ionPopoverDidDismiss,OverlayEventDetail<any>,true
ion-popover,event,ionPopoverDidPresent,void,true
@@ -825,6 +856,8 @@ ion-radio,css-prop,--border-radius
ion-radio,css-prop,--color
ion-radio,css-prop,--color-checked
ion-radio,css-prop,--inner-border-radius
ion-radio,part,container
ion-radio,part,mark
ion-radio-group,none
ion-radio-group,prop,allowEmptySelection,boolean,false,false,false
@@ -860,6 +893,12 @@ ion-range,css-prop,--knob-box-shadow
ion-range,css-prop,--knob-size
ion-range,css-prop,--pin-background
ion-range,css-prop,--pin-color
ion-range,part,bar
ion-range,part,bar-active
ion-range,part,knob
ion-range,part,pin
ion-range,part,tick
ion-range,part,tick-active
ion-refresher,none
ion-refresher,prop,closeDuration,string,'280ms',false,false
@@ -877,11 +916,12 @@ ion-refresher,event,ionStart,void,true
ion-refresher-content,none
ion-refresher-content,prop,pullingIcon,null | string | undefined,undefined,false,false
ion-refresher-content,prop,pullingText,string | undefined,undefined,false,false
ion-refresher-content,prop,pullingText,IonicSafeString | string | undefined,undefined,false,false
ion-refresher-content,prop,refreshingSpinner,"bubbles" | "circles" | "circular" | "crescent" | "dots" | "lines" | "lines-small" | null | undefined,undefined,false,false
ion-refresher-content,prop,refreshingText,string | undefined,undefined,false,false
ion-refresher-content,prop,refreshingText,IonicSafeString | string | undefined,undefined,false,false
ion-reorder,shadow
ion-reorder,part,icon
ion-reorder-group,none
ion-reorder-group,prop,disabled,boolean,true,false,false
@@ -907,7 +947,7 @@ ion-router,none
ion-router,prop,root,string,'/',false,false
ion-router,prop,useHash,boolean,true,false,false
ion-router,method,back,back() => Promise<void>
ion-router,method,push,push(url: string, direction?: RouterDirection) => Promise<boolean>
ion-router,method,push,push(url: string, direction?: RouterDirection, animation?: AnimationBuilder | undefined) => Promise<boolean>
ion-router,event,ionRouteDidChange,RouterEventDetail,true
ion-router,event,ionRouteWillChange,RouterEventDetail,true
@@ -915,6 +955,7 @@ ion-router-link,shadow
ion-router-link,prop,color,string | undefined,undefined,false,false
ion-router-link,prop,href,string | undefined,undefined,false,false
ion-router-link,prop,rel,string | undefined,undefined,false,false
ion-router-link,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-router-link,prop,routerDirection,"back" | "forward" | "root",'forward',false,false
ion-router-link,prop,target,string | undefined,undefined,false,false
ion-router-link,css-prop,--background
@@ -929,7 +970,7 @@ ion-row,shadow
ion-searchbar,scoped
ion-searchbar,prop,animated,boolean,false,false,false
ion-searchbar,prop,autocomplete,"off" | "on",'off',false,false
ion-searchbar,prop,autocomplete,"on" | "off" | "name" | "honorific-prefix" | "given-name" | "additional-name" | "family-name" | "honorific-suffix" | "nickname" | "email" | "username" | "new-password" | "current-password" | "one-time-code" | "organization-title" | "organization" | "street-address" | "address-line1" | "address-line2" | "address-line3" | "address-level4" | "address-level3" | "address-level2" | "address-level1" | "country" | "country-name" | "postal-code" | "cc-name" | "cc-given-name" | "cc-additional-name" | "cc-family-name" | "cc-number" | "cc-exp" | "cc-exp-month" | "cc-exp-year" | "cc-csc" | "cc-type" | "transaction-currency" | "transaction-amount" | "language" | "bday" | "bday-day" | "bday-month" | "bday-year" | "sex" | "tel" | "tel-country-code" | "tel-national" | "tel-area-code" | "tel-local" | "tel-extension" | "impp" | "url" | "photo",'off',false,false
ion-searchbar,prop,autocorrect,"off" | "on",'off',false,false
ion-searchbar,prop,cancelButtonIcon,string,config.get('backButtonIcon', 'arrow-back-sharp') as string,false,false
ion-searchbar,prop,cancelButtonText,string,'Cancel',false,false
@@ -937,6 +978,7 @@ ion-searchbar,prop,clearIcon,string | undefined,undefined,false,false
ion-searchbar,prop,color,string | undefined,undefined,false,false
ion-searchbar,prop,debounce,number,250,false,false
ion-searchbar,prop,disabled,boolean,false,false,false
ion-searchbar,prop,enterkeyhint,"done" | "enter" | "go" | "next" | "previous" | "search" | "send" | undefined,undefined,false,false
ion-searchbar,prop,inputmode,"decimal" | "email" | "none" | "numeric" | "search" | "tel" | "text" | "url" | undefined,undefined,false,false
ion-searchbar,prop,mode,"ios" | "md",undefined,false,false
ion-searchbar,prop,placeholder,string,'Search',false,false
@@ -954,6 +996,7 @@ ion-searchbar,event,ionClear,void,true
ion-searchbar,event,ionFocus,void,true
ion-searchbar,event,ionInput,KeyboardEvent,true
ion-searchbar,css-prop,--background
ion-searchbar,css-prop,--border-radius
ion-searchbar,css-prop,--box-shadow
ion-searchbar,css-prop,--cancel-button-color
ion-searchbar,css-prop,--clear-button-color
@@ -1007,6 +1050,8 @@ ion-segment-button,css-prop,--padding-end
ion-segment-button,css-prop,--padding-start
ion-segment-button,css-prop,--padding-top
ion-segment-button,css-prop,--transition
ion-segment-button,part,indicator
ion-segment-button,part,native
ion-select,shadow
ion-select,prop,cancelText,string,'Cancel',false,false
@@ -1032,6 +1077,9 @@ ion-select,css-prop,--padding-start
ion-select,css-prop,--padding-top
ion-select,css-prop,--placeholder-color
ion-select,css-prop,--placeholder-opacity
ion-select,part,icon
ion-select,part,placeholder
ion-select,part,text
ion-select-option,shadow
ion-select-option,prop,disabled,boolean,false,false,false
@@ -1141,6 +1189,7 @@ ion-tab-button,css-prop,--padding-end
ion-tab-button,css-prop,--padding-start
ion-tab-button,css-prop,--padding-top
ion-tab-button,css-prop,--ripple-color
ion-tab-button,part,native
ion-tabs,shadow
ion-tabs,method,getSelected,getSelected() => Promise<string | undefined>
@@ -1162,6 +1211,8 @@ ion-textarea,prop,color,string | undefined,undefined,false,false
ion-textarea,prop,cols,number | undefined,undefined,false,false
ion-textarea,prop,debounce,number,0,false,false
ion-textarea,prop,disabled,boolean,false,false,false
ion-textarea,prop,enterkeyhint,"done" | "enter" | "go" | "next" | "previous" | "search" | "send" | undefined,undefined,false,false
ion-textarea,prop,inputmode,"decimal" | "email" | "none" | "numeric" | "search" | "tel" | "text" | "url" | undefined,undefined,false,false
ion-textarea,prop,maxlength,number | undefined,undefined,false,false
ion-textarea,prop,minlength,number | undefined,undefined,false,false
ion-textarea,prop,mode,"ios" | "md",undefined,false,false
@@ -1210,13 +1261,13 @@ ion-toast,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefin
ion-toast,prop,header,string | undefined,undefined,false,false
ion-toast,prop,keyboardClose,boolean,false,false,false
ion-toast,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-toast,prop,message,string | undefined,undefined,false,false
ion-toast,prop,message,IonicSafeString | string | undefined,undefined,false,false
ion-toast,prop,mode,"ios" | "md",undefined,false,false
ion-toast,prop,position,"bottom" | "middle" | "top",'bottom',false,false
ion-toast,prop,translucent,boolean,false,false,false
ion-toast,method,dismiss,dismiss(data?: any, role?: string | undefined) => Promise<boolean>
ion-toast,method,onDidDismiss,onDidDismiss() => Promise<OverlayEventDetail<any>>
ion-toast,method,onWillDismiss,onWillDismiss() => Promise<OverlayEventDetail<any>>
ion-toast,method,onDidDismiss,onDidDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-toast,method,onWillDismiss,onWillDismiss<T = any>() => Promise<OverlayEventDetail<T>>
ion-toast,method,present,present() => Promise<void>
ion-toast,event,ionToastDidDismiss,OverlayEventDetail<any>,true
ion-toast,event,ionToastDidPresent,void,true
@@ -1237,6 +1288,7 @@ ion-toast,css-prop,--max-width
ion-toast,css-prop,--min-height
ion-toast,css-prop,--min-width
ion-toast,css-prop,--start
ion-toast,css-prop,--white-space
ion-toast,css-prop,--width
ion-toggle,shadow
@@ -1255,6 +1307,14 @@ ion-toggle,css-prop,--border-radius
ion-toggle,css-prop,--handle-background
ion-toggle,css-prop,--handle-background-checked
ion-toggle,css-prop,--handle-border-radius
ion-toggle,css-prop,--handle-box-shadow
ion-toggle,css-prop,--handle-height
ion-toggle,css-prop,--handle-max-height
ion-toggle,css-prop,--handle-spacing
ion-toggle,css-prop,--handle-transition
ion-toggle,css-prop,--handle-width
ion-toggle,part,handle
ion-toggle,part,track
ion-toolbar,shadow
ion-toolbar,prop,color,string | undefined,undefined,false,false

11739
core/package-lock.json generated Normal file
View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/core",
"version": "5.0.2",
"version": "5.2.3",
"description": "Base components for Ionic",
"keywords": [
"ionic",
@@ -30,32 +30,32 @@
"loader/"
],
"dependencies": {
"ionicons": "^5.0.0",
"ionicons": "^5.1.2",
"tslib": "^1.10.0"
},
"devDependencies": {
"@stencil/core": "1.8.3",
"@stencil/sass": "1.0.1",
"@types/jest": "24.0.21",
"@types/node": "12.12.3",
"@types/puppeteer": "1.19.1",
"@types/swiper": "4.4.4",
"aws-sdk": "^2.497.0",
"@rollup/plugin-node-resolve": "^8.1.0",
"@rollup/plugin-virtual": "^2.0.3",
"@stencil/core": "1.14.0",
"@stencil/sass": "1.3.2",
"@types/jest": "26.0.3",
"@types/node": "14.0.14",
"@types/puppeteer": "3.0.0",
"@types/swiper": "5.3.1",
"aws-sdk": "^2.705.0",
"clean-css-cli": "^4.1.11",
"domino": "^2.1.3",
"fs-extra": "^8.0.1",
"jest": "24.9.0",
"jest-cli": "24.9.0",
"fs-extra": "^9.0.1",
"jest": "26.1.0",
"jest-cli": "26.1.0",
"np": "^5.0.3",
"pixelmatch": "4.0.2",
"puppeteer": "1.20.0",
"rollup": "1.19.4",
"rollup-plugin-node-resolve": "5.2.0",
"rollup-plugin-virtual": "^1.0.1",
"sass": "^1.22.9",
"rollup": "^2.18.1",
"sass": "^1.26.9",
"stylelint": "10.1.0",
"stylelint-order": "3.0.1",
"swiper": "4.5.1",
"swiper": "5.4.1",
"tslint": "^5.10.0",
"tslint-ionic-rules": "0.0.21",
"tslint-react": "^3.6.0"
@@ -65,6 +65,7 @@
"build.vendor": "rollup --config ./scripts/swiper.rollup.config.js",
"build.css": "npm run css.sass && npm run css.minify",
"build.debug": "npm run clean && stencil build --debug",
"build.docs": "stencil build --docs",
"build.docs.json": "stencil build --docs-json dist/docs.json",
"clean": "node scripts/clean.js",
"cdnloader": "node scripts/copy-cdn-loader.js",

View File

@@ -35,6 +35,9 @@ function generateComponent(component, content) {
component.styles.forEach(prop => {
content.push(`${component.tag},css-prop,${prop.name}`);
});
component.parts.forEach(part => {
content.push(`${component.tag},part,${part.name}`);
});
}
exports.apiSpecGenerator = apiSpecGenerator;

View File

@@ -1,4 +1,4 @@
import resolve from 'rollup-plugin-node-resolve';
import resolve from '@rollup/plugin-node-resolve';
export default {
input: 'src/components/slides/swiper/swiper.js',

View File

@@ -1,7 +1,7 @@
const path = require('path');
const { rollup } = require('rollup');
const virtual = require('rollup-plugin-virtual');
const virtual = require('@rollup/plugin-virtual');
const fs = require('fs');
function main() {

12156
core/src/components.d.ts vendored
View File

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -121,7 +121,7 @@ $action-sheet-ios-button-background: linear-gradien
$action-sheet-ios-button-background-activated: $text-color !default;
/// @prop - Background color of the selected action sheet button
$action-sheet-ios-button-background-selected: $background-color !default;
$action-sheet-ios-button-background-selected: var(--ion-color-step-150, $background-color) !default;
/// @prop - Destructive text color of the action sheet button
$action-sheet-ios-button-destructive-text-color: ion-color(danger, base) !default;

View File

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

View File

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

View File

@@ -11,7 +11,11 @@ export const iosEnterAnimation = (baseEl: HTMLElement): Animation => {
backdropAnimation
.addElement(baseEl.querySelector('ion-backdrop')!)
.fromTo('opacity', 0.01, 'var(--backdrop-opacity)');
.fromTo('opacity', 0.01, 'var(--backdrop-opacity)')
.beforeStyles({
'pointer-events': 'none'
})
.afterClearStyles(['pointer-events']);
wrapperAnimation
.addElement(baseEl.querySelector('.action-sheet-wrapper')!)

View File

@@ -11,7 +11,11 @@ export const mdEnterAnimation = (baseEl: HTMLElement): Animation => {
backdropAnimation
.addElement(baseEl.querySelector('ion-backdrop')!)
.fromTo('opacity', 0.01, 'var(--backdrop-opacity)');
.fromTo('opacity', 0.01, 'var(--backdrop-opacity)')
.beforeStyles({
'pointer-events': 'none'
})
.afterClearStyles(['pointer-events']);
wrapperAnimation
.addElement(baseEl.querySelector('.action-sheet-wrapper')!)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -11,7 +11,11 @@ export const iosEnterAnimation = (baseEl: HTMLElement): Animation => {
backdropAnimation
.addElement(baseEl.querySelector('ion-backdrop')!)
.fromTo('opacity', 0.01, 'var(--backdrop-opacity)');
.fromTo('opacity', 0.01, 'var(--backdrop-opacity)')
.beforeStyles({
'pointer-events': 'none'
})
.afterClearStyles(['pointer-events']);
wrapperAnimation
.addElement(baseEl.querySelector('.alert-wrapper')!)

View File

@@ -11,7 +11,11 @@ export const mdEnterAnimation = (baseEl: HTMLElement): Animation => {
backdropAnimation
.addElement(baseEl.querySelector('ion-backdrop')!)
.fromTo('opacity', 0.01, 'var(--backdrop-opacity)');
.fromTo('opacity', 0.01, 'var(--backdrop-opacity)')
.beforeStyles({
'pointer-events': 'none'
})
.afterClearStyles(['pointer-events']);
wrapperAnimation
.addElement(baseEl.querySelector('.alert-wrapper')!)

View File

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

View File

@@ -14,7 +14,7 @@
import { alertController } from '../../../../dist/ionic/index.esm.js';
window.alertController = alertController;
</script>
<body>
<ion-app>
@@ -75,7 +75,14 @@
header: 'Alert',
subHeader: 'Subtitle',
message: 'This is an alert message.',
buttons: ['Cancel', 'Open Modal', 'Delete']
buttons: [
'Open Modal',
{
text: 'Delete',
role: 'destructive',
},
'Cancel',
]
});
}
@@ -161,6 +168,16 @@
{
name: 'name7',
type: 'number'
},
{
name: 'name8',
type: 'text',
placeholder: 'Advanced Attributes',
cssClass: 'specialClass',
attributes: {
maxlength: 4,
inputmode: 'decimal'
}
}
],
buttons: [

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -239,6 +239,6 @@ ion-icon {
// Back Button in Toolbar: Global Theming
// --------------------------------------------------
:host(.in-toolbar) {
:host(.in-toolbar:not(.in-toolbar-color)) {
color: #{var(--ion-toolbar-color, var(--color))};
}

View File

@@ -2,12 +2,16 @@ import { Component, ComponentInterface, Element, Host, Prop, h } from '@stencil/
import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import { Color } from '../../interface';
import { AnimationBuilder, Color } from '../../interface';
import { ButtonInterface } from '../../utils/element-interface';
import { createColorClasses, hostContext, openURL } from '../../utils/theme';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @part native - The native HTML button element that wraps all child elements.
* @part icon - The back button icon (uses ion-icon).
* @part text - The back button text.
*/
@Component({
tag: 'ion-back-button',
@@ -19,7 +23,6 @@ import { createColorClasses, hostContext, openURL } from '../../utils/theme';
})
export class BackButton implements ComponentInterface, ButtonInterface {
mode = getIonMode(this);
@Element() el!: HTMLElement;
/**
@@ -32,7 +35,7 @@ export class BackButton implements ComponentInterface, ButtonInterface {
/**
* The url to navigate back to by default when there is no history.
*/
@Prop() defaultHref?: string;
@Prop({ mutable: true }) defaultHref?: string;
/**
* If `true`, the user cannot interact with the button.
@@ -54,6 +57,18 @@ export class BackButton implements ComponentInterface, ButtonInterface {
*/
@Prop() type: 'submit' | 'reset' | 'button' = 'button';
/**
* When using a router, it specifies the transition animation when navigating to
* another page.
*/
@Prop() routerAnimation: AnimationBuilder | undefined;
componentWillLoad() {
if (this.defaultHref === undefined) {
this.defaultHref = config.get('backButtonDefaultHref');
}
}
get backButtonIcon() {
const icon = this.icon;
if (icon != null) {
@@ -61,7 +76,7 @@ export class BackButton implements ComponentInterface, ButtonInterface {
return icon;
}
if (this.mode === 'ios') {
if (getIonMode(this) === 'ios') {
// default ios back button icon
return config.get('backButtonIcon', 'chevron-back');
}
@@ -71,7 +86,7 @@ export class BackButton implements ComponentInterface, ButtonInterface {
}
get backButtonText() {
const defaultBackButtonText = this.mode === 'ios' ? 'Back' : null;
const defaultBackButtonText = getIonMode(this) === 'ios' ? 'Back' : null;
return this.text != null ? this.text : config.get('backButtonText', defaultBackButtonText);
}
@@ -94,14 +109,15 @@ export class BackButton implements ComponentInterface, ButtonInterface {
ev.preventDefault();
if (nav && await nav.canGoBack()) {
return nav.pop({ skipIfBusy: true });
return nav.pop({ animationBuilder: this.routerAnimation, skipIfBusy: true });
}
return openURL(this.defaultHref, ev, 'back');
return openURL(this.defaultHref, ev, 'back', this.routerAnimation);
}
render() {
const { color, defaultHref, disabled, type, mode, hasIconOnly, backButtonIcon, backButtonText } = this;
const { color, defaultHref, disabled, type, hasIconOnly, backButtonIcon, backButtonText } = this;
const showBackButton = defaultHref !== undefined;
const mode = getIonMode(this);
return (
<Host
@@ -114,15 +130,22 @@ export class BackButton implements ComponentInterface, ButtonInterface {
'back-button-disabled': disabled,
'back-button-has-icon-only': hasIconOnly,
'in-toolbar': hostContext('ion-toolbar', this.el),
'in-toolbar-color': hostContext('ion-toolbar[color]', this.el),
'ion-activatable': true,
'ion-focusable': true,
'show-back-button': showBackButton
}}
>
<button type={type} disabled={disabled} class="button-native" part="button">
<button
type={type}
disabled={disabled}
class="button-native"
part="native"
aria-label={backButtonText || 'back'}
>
<span class="button-inner">
{backButtonIcon && <ion-icon icon={backButtonIcon} lazy={false} part="icon"></ion-icon>}
{backButtonText && <span class="button-text" part="text">{backButtonText}</span>}
{backButtonIcon && <ion-icon part="icon" icon={backButtonIcon} aria-hidden="true" lazy={false}></ion-icon>}
{backButtonText && <span part="text" aria-hidden="true" class="button-text">{backButtonText}</span>}
</span>
{mode === 'md' && <ion-ripple-effect type={this.rippleType}></ion-ripple-effect>}
</button>

View File

@@ -173,6 +173,75 @@ export const BackButtonExample: React.FC = () => (
```
### Stencil
```tsx
import { Component, h } from '@stencil/core';
@Component({
tag: 'back-button-example',
styleUrl: 'back-button-example.css'
})
export class BackButtonExample {
render() {
const buttonText = "Custom";
const buttonIcon = "add";
return [
// Default back button
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
</ion-buttons>
</ion-toolbar>
</ion-header>,
// Back button with a default href
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button defaultHref="home"></ion-back-button>
</ion-buttons>
</ion-toolbar>
</ion-header>,
// Back button with custom text and icon
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button
text={buttonText}
icon={buttonIcon}>
</ion-back-button>
</ion-buttons>
</ion-toolbar>
</ion-header>,
// Back button with no text and custom icon
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button text="" icon="add"></ion-back-button>
</ion-buttons>
</ion-toolbar>
</ion-header>,
// Danger back button next to a menu button
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-menu-button></ion-menu-button>
<ion-back-button color="danger"></ion-back-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
];
}
}
```
### Vue
```html
@@ -232,15 +301,25 @@ export const BackButtonExample: React.FC = () => (
## Properties
| Property | Attribute | Description | Type | Default |
| ------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | ----------- |
| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
| `defaultHref` | `default-href` | The url to navigate back to by default when there is no history. | `string \| undefined` | `undefined` |
| `disabled` | `disabled` | If `true`, the user cannot interact with the button. | `boolean` | `false` |
| `icon` | `icon` | The icon name to use for the back button. | `null \| string \| undefined` | `undefined` |
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
| `text` | `text` | The text to display in the back button. | `null \| string \| undefined` | `undefined` |
| `type` | `type` | The type of the button. | `"button" \| "reset" \| "submit"` | `'button'` |
| Property | Attribute | Description | Type | Default |
| ----------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----------- |
| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
| `defaultHref` | `default-href` | The url to navigate back to by default when there is no history. | `string \| undefined` | `undefined` |
| `disabled` | `disabled` | If `true`, the user cannot interact with the button. | `boolean` | `false` |
| `icon` | `icon` | The icon name to use for the back button. | `null \| string \| undefined` | `undefined` |
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
| `routerAnimation` | -- | When using a router, it specifies the transition animation when navigating to another page. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
| `text` | `text` | The text to display in the back button. | `null \| string \| undefined` | `undefined` |
| `type` | `type` | The type of the button. | `"button" \| "reset" \| "submit"` | `'button'` |
## Shadow Parts
| Part | Description |
| ---------- | ------------------------------------------------------------- |
| `"icon"` | The back button icon (uses ion-icon). |
| `"native"` | The native HTML button element that wraps all child elements. |
| `"text"` | The back button text. |
## CSS Custom Properties

View File

@@ -1,18 +1,28 @@
import { newSpecPage } from '@stencil/core/testing';
import { BackButton } from "../back-button";
import { config } from "../../../global/config";
import { setMode } from '@stencil/core';
describe('back button', () => {
let bb: BackButton;
beforeEach(() => {
config.reset({});
bb = new BackButton();
});
const newBackButton = async (mode: string = 'md'): Promise<BackButton> => {
setMode(() => mode);
const { rootInstance } = await newSpecPage({
components: [BackButton],
html: `<ion-back-button></ion-back-button>`
})
return rootInstance;
};
describe('backButtonIcon', () => {
it('set custom icon on the instance, override config', () => {
it('set custom icon on the instance, override config', async () => {
const bb = await newBackButton();
bb.icon = 'custom-icon-instance';
config.reset({
backButtonIcon: 'custom-icon-config'
@@ -20,24 +30,27 @@ describe('back button', () => {
expect(bb.backButtonIcon).toBe('custom-icon-instance');
});
it('set custom icon in the config', () => {
it('set custom icon in the config', async () => {
const bb = await newBackButton();
config.reset({
backButtonIcon: 'custom-icon-config'
});
expect(bb.backButtonIcon).toBe('custom-icon-config');
});
it('set custom icon on the instance', () => {
it('set custom icon on the instance', async () => {
const bb = await newBackButton();
bb.icon = 'custom-icon-instance';
expect(bb.backButtonIcon).toBe('custom-icon-instance');
});
it('default icon for ios mode', () => {
bb.mode = 'ios';
it('default icon for ios mode', async () => {
const bb = await newBackButton('ios');
expect(bb.backButtonIcon).toBe('chevron-back');
});
it('default icon', () => {
it('default icon', async () => {
const bb = await newBackButton();
expect(bb.backButtonIcon).toBe('arrow-back-sharp');
});
@@ -45,15 +58,49 @@ describe('back button', () => {
describe('backButtonText', () => {
it('default text for ios mode', () => {
bb.mode = 'ios';
it('default text for ios mode', async () => {
const bb = await newBackButton('ios');
expect(bb.backButtonText).toBe('Back');
});
it('default text', () => {
it('default text', async () => {
const bb = await newBackButton();
expect(bb.backButtonText).toBe(null);
});
});
describe('backButtonDefaultHref', () => {
it('set custom defaultHref in the config', async () => {
config.reset({
backButtonDefaultHref: 'custom-default-href-config'
});
const bb = await newBackButton();
expect(bb.defaultHref).toBe('custom-default-href-config');
});
it('set custom defaultHref on the instance', async () => {
const bb = await newBackButton();
bb.defaultHref = 'custom-default-href';
expect(bb.defaultHref).toBe('custom-default-href');
});
it('set custom defaultHref on the instance, override config', async () => {
const bb = await newBackButton();
bb.defaultHref = 'custom-default-href';
config.reset({
backButtonDefaultHref: 'custom-default-href-config'
});
expect(bb.defaultHref).toBe('custom-default-href');
const bb2 = await newBackButton();
bb2.defaultHref = 'custom-default-href-second';
expect(bb2.defaultHref).toBe('custom-default-href-second');
});
});
});

View File

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

View File

@@ -2,7 +2,6 @@ import { Component, ComponentInterface, Event, EventEmitter, Host, Listen, Prop,
import { getIonMode } from '../../global/ionic-global';
import { GESTURE_CONTROLLER } from '../../utils/gesture';
import { now } from '../../utils/helpers';
@Component({
tag: 'ion-backdrop',
@@ -14,7 +13,6 @@ import { now } from '../../utils/helpers';
})
export class Backdrop implements ComponentInterface {
private lastClick = -10000;
private blocker = GESTURE_CONTROLLER.createBlocker({
disableScroll: true
});
@@ -49,18 +47,9 @@ export class Backdrop implements ComponentInterface {
this.blocker.unblock();
}
@Listen('touchstart', { passive: false, capture: true })
protected onTouchStart(ev: TouchEvent) {
this.lastClick = now(ev);
this.emitTap(ev);
}
@Listen('click', { passive: false, capture: true })
@Listen('mousedown', { passive: false, capture: true })
protected onMouseDown(ev: TouchEvent) {
if (this.lastClick < now(ev) - 2500) {
this.emitTap(ev);
}
this.emitTap(ev);
}
private emitTap(ev: Event) {

View File

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

View File

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

View File

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

View File

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

View File

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

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