Update 4.0.x with 4.0.1 and 4.0.2 (#18156)

* docs(ng): update angular test readme
Closes #17212

* docs(breaking): add breaking changes and copy editing (#17214)

- adds col auto to grid
- updates overlays to point to the same usage
- copy editing
- adds more info on the tabs changes
- documents event changes closes ionic-team/ionic-docs#258
- update nav event documentation

references #16819

* fix(build): modify rollup.config.js to work with Windows (#17231)

* docs(react): fix typo
Closes #17243

* fix(reorder): capture click event (#17244)

fixes #17241

* fix(grid): add flex to ion-grid to allow it to properly render in an ion-item (#17258)

fixes #17075

* docs(segment) add example for default Value
Closes #17275

* docs(alert): correct alert-controller link path (#17294)

references ionic-team/ionic-docs#254

* docs(loading): correct loading-controller link path (#17295)

closes ionic-team/ionic-docs#254

* fix(range): chrome bug with will-change

* docs(): update links
Ref #17256

* docs(): rebuild docs

* docs(): rebuilding

* docs(): update incorrect links

* fix(searchbar): hide search icon when focused with cancel button (#17260)

fixes #17252

* fix(react): duplicate events being fired in ionic/react (#17321)

* docs(modal): fix typo with returning header (#17333)

* test(searchbar): update searchbar tests to take focused ss (#17318)

- gets focus test working properly
- adds a no cancel button focus test

this should prevent the regression in #17252 in the future

* Merge branch 'master' into update-pwa-check

merge:

* Merge branch 'master' into add-mobileweb-platform

merge

* Merge pull request #17356 from ionic-team/add-mobileweb-platform

feat(platform): add mobileweb platform

* Merge branch 'master' into update-pwa-check

merge

* Merge pull request #17355 from ionic-team/update-pwa-check

fix(platform): add additional check for safari PWA

* Merge branch 'master' into add-mobileweb-platform

merge

* Merge pull request #17356 from ionic-team/add-mobileweb-platform

feat(platform): add mobileweb platform

merge

* Merge branch 'master' into update-pwa-check

merge and try again.

* Merge pull request #17355 from ionic-team/update-pwa-check

fix(platform): add additional check for safari PWA

merge

* docs(rtl): Fix small typo in item docs (#17365)

* docs(datetime): fix typo (#17360)

* docs(loading): remove dismissOnPageChange, add ionLoadingDidDismiss (#17357)

* docs(loading): remove dismissOnPageChange, change onDidDismiss to ionLoadingDidDismiss

* docs(loading): add usage showing events

* docs(loading): update example to show proper usage

* docs(rtl): Fix small typo in item docs (#17365)
merge

* docs(loading): update example to show proper usage

docs(loading): update example to show proper usage
merge and try again.

* test(platform): Add Platform tests (#17354)

* test(platform): add base platform tests

* test(platform): add isPlatform test, clean up test file

* test(platform): do not export matchMedia

* test(platform): change window to win to avoid confusion

* fix(menu): fix content shadow when revealed in iOS (#17383)

* fix(popover): originate animation from right in RTL/MD (#17381)

* fix(popover): apply fixed position to keep backdrop in viewport (#17352)

fixes #17337

* 4.0.1

* fix(tab-bar): add translucent tab-bar styles back (#17376)

- updates css to allow for translucent tab-bar
- adds translucent test

* docs(datetime): usage typos and clean up (#17415)

Fix some typos, clean up a code snippet, reword slightly to use clearer language (in consideration of ESL readers).

* docs(reorder): Update incomplete reorder docs (#17417)

* add base reorder doc updates

* update doc wording

* remove extra sentence

* clear up explanation sentence

* fix typo

* run build

* fix doc definition for ionitemReorder

* make requested changes

* remove prop table

* chore(github): update issue template

* docs(loading): update breaking doc to show new loading usage (#17431)

* docs(loading): add missing async to new loading example (#17432)

* update loading example

* add async

* chore(react): release of ionic react 0.0.4 (#17442)

* chore(github): update issue templates (#17433)

* fix(searchbar): allow setting of toolbar color and searchbar color (#17474)

* fix(searchbar): allow setting of toolbar color and searchbar color

* fix test label typo

* docs(popover): add missing comma in example (#17401)

* fix(range): implement RTL (from PR 17157) (#17384)

- MD PIN fixes not committed because they depend on mixin changes

references #17012

* docs(): Add documentation for slots (#17441)

* add button slot

* add component slot docs

* update content default slot description

* run npm build

* fix typos

* update md files

* docs(slots): update slot components and the build files

* chore(stencil): updates stencil to build readmes

* chore(build): update the swiper bundle file to match master

* update default slot doc wording

* revert changes

* Revert "update default slot doc wording"

This reverts commit e18401491e.

merge

* docs(slots): update default slot doc wording

* docs(avatar): update angular usage for img src (#16884)

* fix(config): update types for scrollPadding, inputBlurring and hideCaretOnScroll to boolean (#17302)

* feat(range): add neutral point (#17400)

* feat(Range): add neutral point

* feat(Range): generate proxies and api

* fix(): check positive case in neutralPointChanged

* fix(Range): neutralPoint to min if neutralPoint < min

* fix(Range): active bar style

* fix(Range): tick styling

* fix(range): improved rtl support (#17479)

* fix(Range): rtl support

* fix(Range): knob position in rtl

* fix(select): Account for when options are not loaded immediately (#17405)

* Added logging to begin debugging issue

* identify potential fix, add test

* fix(select): render when options are loaded after a delay

* fix linter issues

* fix e2e test

* fix edge case with if statement

* fix(item-sliding): Sliding no longer breaks after removing an item (#17492)

* fix(item-sliding): Sliding no longer breaks after removing an item

* run linter

* fix(datetime): default to current date when no value given (#17443)

* fix(datetime): default to current date when no value given

* test(datetime): add spec test

* move getDateValue to utils

* docs(process): update process documentation

* fix(button): show proper shade for activated button on ios (#17508)

fixes #17436

* 4.0.2

* chore(range): revert neutral point (#17550)

* Revert "fix(range): improved rtl support (#17479)"

This reverts commit f832de5f4a.

revert range rtl support

* Revert "feat(range): add neutral point (#17400)"

This reverts commit 15acb4be37.

revert neutral point

* sync in 4.0.1 and 4.0.2

* docs(): Add documentation for slots (#17441)

* add button slot

* add component slot docs

* update content default slot description

* run npm build

* fix typos

* update md files

* docs(slots): update slot components and the build files

* chore(stencil): updates stencil to build readmes

* chore(build): update the swiper bundle file to match master

* update default slot doc wording

* revert changes

* Revert "update default slot doc wording"

This reverts commit e18401491e.

merge

* docs(slots): update default slot doc wording
This commit is contained in:
Liam DeBeasi 2019-04-26 16:31:10 -04:00 committed by GitHub
parent b33d940513
commit c6bd7be763
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
101 changed files with 1506 additions and 374 deletions

View File

@ -1,55 +1,57 @@
---
name: Bug Report
about: Create a report to help us improve
---
<!-- Before submitting an issue, please consult our docs (https://beta.ionicframework.com/docs/) and API reference (https://beta.ionicframework.com/docs/api/) -->
<!-- Please make sure you are posting an issue pertaining to the Ionic Framework. If you are having an issue with the Ionic Appflow services (Ionic View, Ionic Deploy, etc.) please consult the Ionic Appflow support portal (https://ionic.zendesk.com/hc/en-us) -->
<!-- Please do not submit support requests or "How to" questions here. Instead, please use one of these channels: https://forum.ionicframework.com/ or http://ionicworldwide.herokuapp.com/ -->
<!-- ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION. -->
# Bug Report
**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**
**Current behavior:**
<!-- Describe how the bug manifests. -->
**Expected behavior:**
<!-- Describe what the behavior would be without the bug. -->
**Steps to reproduce:**
<!-- Please explain the steps required to duplicate the issue, especially if you are able to provide a sample application. -->
**Related code:**
<!-- If you are able to illustrate the bug or feature request with an example, please provide a sample application via one of the following means:
A sample application via GitHub
StackBlitz (https://stackblitz.com)
Plunker (http://plnkr.co/edit/cpeRJs?p=preview)
-->
```
insert short code snippets here
```
**Other information:**
<!-- List any other information that is relevant to your issue. Stack traces, related issues, suggestions on how to fix, Stack Overflow links, forum links, etc. -->
**Ionic info:**
<!-- (run `ionic info` from a terminal/cmd prompt and paste output below): -->
```
insert the output from ionic info here
```
---
name: Bug Report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
<!-- Before submitting an issue, please consult our docs (https://ionicframework.com/docs/). -->
<!-- Please make sure you are posting an issue pertaining to the Ionic Framework. If you are having an issue with the Ionic Appflow services (Ionic View, Ionic Deploy, etc.) please consult the Ionic Appflow support portal (https://ionic.zendesk.com/hc/en-us) -->
<!-- Please do not submit support requests or "How to" questions here. Instead, please use one of these channels: https://forum.ionicframework.com/ or http://ionicworldwide.herokuapp.com/ -->
<!-- ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION. -->
# Bug Report
**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**
**Current behavior:**
<!-- Describe how the bug manifests. -->
**Expected behavior:**
<!-- Describe what the behavior would be without the bug. -->
**Steps to reproduce:**
<!-- Please explain the steps required to duplicate the issue, especially if you are able to provide a sample application. -->
**Related code:**
<!-- If you are able to illustrate the bug or feature request with an example, please provide a sample application via one of the following means:
A sample application via GitHub
StackBlitz (https://stackblitz.com)
Plunker (http://plnkr.co/edit/cpeRJs?p=preview)
-->
```
insert short code snippets here
```
**Other information:**
<!-- List any other information that is relevant to your issue. Stack traces, related issues, suggestions on how to fix, Stack Overflow links, forum links, etc. -->
**Ionic info:**
<!-- (run `ionic info` from a terminal/cmd prompt and paste output below): -->
```
insert the output from ionic info here
```

11
.github/ISSUE_TEMPLATE/cli.md vendored Normal file
View File

@ -0,0 +1,11 @@
---
name: CLI
about: Suggest an improvement for the CLI
title: ''
labels: 'ionitron: cli'
assignees: ''
---
# CLI
Please do not submit bug reports or feature requests related to the Ionic CLI. Instead, please submit an issue to the [Ionic CLI Repository](https://github.com/ionic-team/ionic-cli/issues/new/choose).

11
.github/ISSUE_TEMPLATE/documentation.md vendored Normal file
View File

@ -0,0 +1,11 @@
---
name: Documentation
about: Suggest an improvement for the documentation of this project
title: ''
labels: 'ionitron: docs'
assignees: ''
---
# Documentation
Please do not submit issues on how to improve or fix the documentation. Instead, please submit an issue to the [Ionic Docs Repository](https://github.com/ionic-team/ionic-docs/issues/new/choose).

View File

@ -1,37 +1,37 @@
---
name: Feature Request
about: Suggest an idea for this project
---
<!-- Please make sure you are posting an feature request pertaining to the Ionic Framework. -->
<!-- Before submitting an issue, please consult our docs (https://beta.ionicframework.com/docs/) and API reference (https://beta.ionicframework.com/docs/api/) -->
<!-- Please make sure you are posting an issue pertaining to the Ionic Framework. If you are having an issue with the Ionic Appflow services (Ionic View, Ionic Deploy, etc.) please consult the Ionic Appflow support portal (https://ionic.zendesk.com/hc/en-us) -->
<!-- Please do not submit support requests or "How to" questions here. Instead, please use one of these channels: https://forum.ionicframework.com/ or http://ionicworldwide.herokuapp.com/ -->
<!-- ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION. -->
# Feature Request
**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**
**Describe the Feature Request**
<!-- A clear and concise description of what the feature request is. Please include if your feature request is related to a problem. -->
**Describe Preferred Solution**
<!-- A clear and concise description of what you want to happen. -->
**Describe Alternatives**
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
**Related Code**
<!-- If you are able to illustrate the feature request with an example, please provide a sample application via an online code collaborator such as [StackBlitz](https://stackblitz.com), or [GitHub](https://github.com). -->
**Additional Context**
<!-- List any other information that is relevant to your issue. Stack traces, related issues, suggestions on how to add, use case, Stack Overflow links, forum links, screenshots, OS if applicable, etc. -->
---
name: Feature Request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
<!-- Before submitting an issue, please consult our docs (https://ionicframework.com/docs/). -->
<!-- Please make sure you are posting an issue pertaining to the Ionic Framework. If you are having an issue with the Ionic Appflow services (Ionic View, Ionic Deploy, etc.) please consult the Ionic Appflow support portal (https://ionic.zendesk.com/hc/en-us) -->
<!-- Please do not submit support requests or "How to" questions here. Instead, please use one of these channels: https://forum.ionicframework.com/ or http://ionicworldwide.herokuapp.com/ -->
<!-- ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION. -->
# Feature Request
**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**
**Describe the Feature Request**
<!-- A clear and concise description of what the feature request is. Please include if your feature request is related to a problem. -->
**Describe Preferred Solution**
<!-- A clear and concise description of what you want to happen. -->
**Describe Alternatives**
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
**Related Code**
<!-- If you are able to illustrate the feature request with an example, please provide a sample application via an online code collaborator such as [StackBlitz](https://stackblitz.com), or [GitHub](https://github.com). -->
**Additional Context**
<!-- List any other information that is relevant to your issue. Stack traces, related issues, suggestions on how to add, use case, Stack Overflow links, forum links, screenshots, OS if applicable, etc. -->

View File

@ -1,9 +1,11 @@
---
name: Support Question
about: Question on how to use this project
---
# Support Question
Please do not submit support requests or "How to" questions here. Instead, please use one of these channels: https://forum.ionicframework.com/ or http://ionicworldwide.herokuapp.com/
---
name: Support Question
about: Question on how to use this project
title: ''
labels: 'ionitron: support'
assignees: ''
---
# Support Question
Please do not submit support requests or "How to" questions here. Instead, please use one of these channels: https://forum.ionicframework.com/ or http://ionicworldwide.herokuapp.com/

17
.github/PROCESS.md vendored
View File

@ -35,26 +35,27 @@ Issues and pull requests that need review. Pull requests will automatically move
Issues and pull requests that are completed. Issues will automatically move here when they are closed. Pull requests will automatically moved here when they are merged or closed with unmerged commits.
## Managing Issues
### Issues to Triage
The issues that need to be triaged all have the `triage` label. In many cases the issue can be automatically processed by the Ionic Issue Bot by applying a specific label.
Once another label is applied to the issue, the `triage` label is automatically be removed by the bot.
Once another label is applied to the issue, the `triage` label is automatically removed by the bot.
### Wrong Repo
### Wrong Repository
If an issue does not pertain to the Ionic Framework but does pertain to another repo, it should be moved to that repo. The bot has been set up to automatically create the issue in other repositories while closing and locking the issue in this repository. Use one of the following labels to perform that action:
If an issue does not pertain to the Ionic Framework but does pertain to another repository, it should be moved to that repository. The bot has been set up to automatically create the issue in other repositories while closing and locking the issue in this repository. Use one of the following labels to perform that action:
- ionitron: cli
- ionitron: docs
- ionitron: stencil
- ionitron: native
### Ionic Pro Issues
### Ionic Appflow Issues
If the issue is associated with Ionic Pro the submitter should be told to use the [Ionic Pro Support Forum](https://ionic.zendesk.com/hc/en-us/requests/new). The issue should be closed and locked. Use the `ionitron: ionic pro` label to accomplish this.
If the issue is associated with Ionic Appflow the submitter should be told to use the [Ionic Appflow Support Forum](https://ionic.zendesk.com/hc/en-us/requests/new). The issue should be closed and locked. Use the `ionitron: ionic appflow` label to accomplish this.
### Support Questions
@ -68,12 +69,12 @@ If the issue template has not been filled out completely, the issue should be cl
In many cases, the template is mostly filled out but just missing a thing or two or you may have a question or need clarification. In such a case, the submitter should be asked to supply that information.
1. create a comment requesting the additional information or clarification
1. add the `needs reply` label to the task
1. add a comment requesting the additional information or clarification
1. add the `needs: reply` label to the task
NOTE: be sure to perform those actions in the order stated. If you add the comment second it will trigger the removal of the label.
If there is a response to the question, the bot will remove the `needs reply` and apply the `triage` label. The issue will then go through the triage handling again.
If there is a response to the question, the bot will remove the `needs: reply` and apply the `triage` label. The issue will then go through the triage handling again.
if there is no response within 30 days, the issue will be closed and locked.

View File

@ -1,3 +1,37 @@
## [4.0.2](https://github.com/ionic-team/ionic/compare/v4.0.1...v4.0.2) (2019-02-20)
### Bug Fixes
* **button:** show proper shade for activated button on ios ([#17508](https://github.com/ionic-team/ionic/issues/17508)) ([3a9b679](https://github.com/ionic-team/ionic/commit/3a9b679)), closes [#17436](https://github.com/ionic-team/ionic/issues/17436)
* **config:** update types for scrollPadding, inputBlurring and hideCaretOnScroll to boolean ([#17302](https://github.com/ionic-team/ionic/issues/17302)) ([39fbc32](https://github.com/ionic-team/ionic/commit/39fbc32))
* **datetime:** default to current date when no value given ([#17443](https://github.com/ionic-team/ionic/issues/17443)) ([644f9f4](https://github.com/ionic-team/ionic/commit/644f9f4))
* **item-sliding:** Sliding no longer breaks after removing an item ([#17492](https://github.com/ionic-team/ionic/issues/17492)) ([e27bb2e](https://github.com/ionic-team/ionic/commit/e27bb2e))
* **range:** implement RTL (from PR 17157) ([#17384](https://github.com/ionic-team/ionic/issues/17384)) ([4f203bc](https://github.com/ionic-team/ionic/commit/4f203bc)), closes [#17012](https://github.com/ionic-team/ionic/issues/17012)
* **searchbar:** allow setting of toolbar color and searchbar color ([#17474](https://github.com/ionic-team/ionic/issues/17474)) ([ba4e117](https://github.com/ionic-team/ionic/commit/ba4e117))
* **select:** Account for when options are not loaded immediately ([#17405](https://github.com/ionic-team/ionic/issues/17405)) ([f9f1775](https://github.com/ionic-team/ionic/commit/f9f1775))
* **tab-bar:** add translucent tab-bar styles back ([#17376](https://github.com/ionic-team/ionic/issues/17376)) ([374bd77](https://github.com/ionic-team/ionic/commit/374bd77))
## [4.0.1](https://github.com/ionic-team/ionic/compare/v4.0.0...v4.0.1) (2019-02-06)
### Bug Fixes
* **build:** modify rollup.config.js to work with Windows ([#17231](https://github.com/ionic-team/ionic/issues/17231)) ([d26d43d](https://github.com/ionic-team/ionic/commit/d26d43d))
* **grid:** add flex to ion-grid to allow it to properly render in an ion-item ([#17258](https://github.com/ionic-team/ionic/issues/17258)) ([40c6955](https://github.com/ionic-team/ionic/commit/40c6955)), closes [#17075](https://github.com/ionic-team/ionic/issues/17075)
* **menu:** fix content shadow when revealed in iOS ([#17383](https://github.com/ionic-team/ionic/issues/17383)) ([fc43faa](https://github.com/ionic-team/ionic/commit/fc43faa))
* **platform:** add additional check for safari PWA ([a584f6e](https://github.com/ionic-team/ionic/commit/a584f6e))
* **platform:** add mobileweb platform back ([cf2b2b3](https://github.com/ionic-team/ionic/commit/cf2b2b3))
* **popover:** apply fixed position to keep backdrop in viewport ([#17352](https://github.com/ionic-team/ionic/issues/17352)) ([ee3b04a](https://github.com/ionic-team/ionic/commit/ee3b04a)), closes [#17337](https://github.com/ionic-team/ionic/issues/17337)
* **popover:** originate animation from right in RTL/MD ([#17381](https://github.com/ionic-team/ionic/issues/17381)) ([bc3aa21](https://github.com/ionic-team/ionic/commit/bc3aa21))
* **range:** chrome bug with will-change ([74ce34f](https://github.com/ionic-team/ionic/commit/74ce34f))
* **react:** duplicate events being fired in ionic/react ([#17321](https://github.com/ionic-team/ionic/issues/17321)) ([a415001](https://github.com/ionic-team/ionic/commit/a415001))
* **reorder:** capture click event ([#17244](https://github.com/ionic-team/ionic/issues/17244)) ([986e67b](https://github.com/ionic-team/ionic/commit/986e67b)), closes [#17241](https://github.com/ionic-team/ionic/issues/17241)
* **searchbar:** hide search icon when focused with cancel button ([#17260](https://github.com/ionic-team/ionic/issues/17260)) ([c87867c](https://github.com/ionic-team/ionic/commit/c87867c)), closes [#17252](https://github.com/ionic-team/ionic/issues/17252)
# [4.0.0 Neutronium](https://github.com/ionic-team/ionic/compare/v4.0.0-rc.3...v4.0.0) (2019-01-23)
Enjoy! 🎈

View File

@ -21,6 +21,7 @@ A list of the breaking changes introduced to each component in Ionic Angular v4.
- [Back Button](#back-button)
- [Button](#button)
- [Colors](#colors)
- [Component Imports](#component-imports)
- [Content](#content)
- [Datetime](#datetime)
- [Dynamic Mode](#dynamic-mode)
@ -43,6 +44,7 @@ A list of the breaking changes introduced to each component in Ionic Angular v4.
- [Navbar](#navbar)
- [Option](#option)
- [Overlays](#overlays)
- [Popover](#popover)
- [Radio](#radio)
- [Range](#range)
- [Refresher](#refresher)
@ -54,6 +56,7 @@ A list of the breaking changes introduced to each component in Ionic Angular v4.
- [Tabs](#tabs)
- [Text / Typography](#text--typography)
- [Theming](#theming)
- [Toast](#toast)
- [Toolbar](#toolbar)
@ -86,7 +89,7 @@ await actionSheet.present();
## Alert
The `title`, `subTitle` and `enableBackdropDismiss` properties has been renamed to `header`, `subHeader` and `backdropDismiss` respectivelly.
The `title`, `subTitle` and `enableBackdropDismiss` properties has been renamed to `header`, `subHeader` and `backdropDismiss` respectively.
**Old Usage Example:**
@ -263,7 +266,7 @@ light: #f4f4f4
dark: #222
```
Some of their values have changed and we now include more colors by default:
Some of their values have changed, and we now include more colors by default:
```
primary: #3880ff
@ -280,13 +283,24 @@ dark: #222428
The `secondary` color saw the largest change. If you were previously using our `secondary` color we recommend switching to `success` instead.
## Component Imports
For consistency with other frameworks and the rest of APIs and tooling, the exported
Ionic components are now prefixed with `Ion`:
```diff
- import { Input, List, Slides } from 'ionic-angular';
+ import { IonInput, IonList, IonSlides } from '@ionic/angular';
```
## Content
Content is now a drop-in replacement for `ion-scroll`, that means `ion-content` is much more flexible today, they can be used anywhere, even in a nested fashion.
Content is now a drop-in replacement for `ion-scroll`. This makes `ion-content` much more flexible. It can be used anywhere, even nested.
### resize() was removed
### Method Removed
In Ionic 4, `ion-content` layout is based in flex, that means their size will automatically adjust without requiring to call resize() programmatically.
The `resize` method has been removed from Content. In Ionic 4, the `ion-content` is based on a flex layout. This means the content size will automatically adjust without requiring a call to `resize()`.
### Attributes Renamed
@ -319,6 +333,35 @@ import { Datetime } from '@ionic/angular';
Components are no longer able to have their mode changed dynamically. You can change the mode before the first render, but after that it will not style properly because only the initial mode's styles are included.
## Events
Events now emit as a [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent) interface that extends the [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event) interface. This interface includes a `detail` property that holds any data passed when the event is triggered.
This allows you to still get the details of the event. For example, to get the target where the event was dispatched, such as a button that was clicked, you can read in the value of `event.target`.
**Old Usage Example:**
```html
<ion-select (ionChange)="onSelectChange($event)">
```
```typescript
onSelectChange(event) {
const value = event.value;
console.log('Select value is', value);
}
```
**New Usage Example:**
```typescript
onSelectChange(event: CustomEvent) {
const value = event.detail.value;
console.log('Select value is', value);
}
```
## FAB
### Markup Changed
@ -381,8 +424,8 @@ The attributes to align the fab horizontally are now combined under the `horizon
| Old Property | New Property | Property Behavior |
|--------------|----------------------|-------------------------------------------------------------------------|
| left | Removed | |
| right | Removed | |
| left | Removed, see `start` | |
| right | Removed, see `end` | |
| center | `horizontal="center"`| Positions to the center of the viewport. |
| start | `horizontal="start"` | Positions to the left of the viewport in LTR, and to the right in RTL. |
| end | `horizontal="end"` | Positions to the right of the viewport in LTR, and to the left in RTL. |
@ -448,7 +491,7 @@ The `<ion-fab>` container was previously placed inside of the fixed content by d
The Grid has been refactored in order to support css variables and a dynamic number of columns. The following column attributes have been changed.
_In the following examples, `{breakpoint}` refers to the optional screen breakpoint (xs, sm, md, lg, xl) and `{value}` refers to the number of columns._
_In the following examples, `{breakpoint}` refers to the optional screen breakpoint (xs, sm, md, lg, xl) and `{value}` refers to the number of columns (`auto` or a number between `1` and `12`)._
- `col-{breakpoint}-{value}` attributes have been renamed to `size-{breakpoint}=“{value}”`
- `offset-{breakpoint}-{value}` attributes have been renamed to `offset-{breakpoint}=“{value}”`
@ -585,7 +628,7 @@ Item should now be written as an `<ion-item>` element. Ionic will determine when
### Label Required
Previously an `ion-label` would automatically get added to an `ion-item` if one wasn't provided. Now an `ion-label` should always be added if the component is used to display text.
Previously an `ion-label` would automatically get added to an `ion-item` if one wasn't provided. Now an `ion-label` should always be added in the item component.
```html
<ion-item>
@ -667,7 +710,7 @@ By default, items that render buttons or anchor tags will show the arrow in `ios
### Label Required
Previously an `ion-label` would automatically get added to an `ion-item-divider` if one wasn't provided. Now an `ion-label` should always be added if the component is used to display text.
Previously an `ion-label` would automatically get added to an `ion-item-divider` if one wasn't provided. Now an `ion-label` should always be added around the text.
```html
<ion-item-divider>
@ -695,7 +738,7 @@ These values have been renamed to `"start"` and `"end"` to better align with our
### Markup Changed
The option component should not be written as a `button` with an `ion-button` directive anymore. It should be written as an `ion-item-option`. This will render a native button element inside of it.
The option component should now be written as an `ion-item-option`. Previously it was written as a `button` with an `ion-button` directive. The `ion-item-option` element will render a native button element inside of it.
**Old Usage Example:**
@ -736,7 +779,7 @@ The `getSlidingPercent` method has been renamed to `getSlidingRatio` since the f
### Attributes Renamed
The attributes to set label position for input are now combined under the `position` attribute:
The attributes to set label position in an item are now combined under the `position` attribute:
| Old Property | New Property | Property Behavior |
|--------------|----------------------|------------------------------------------------------------------------------|
@ -777,7 +820,7 @@ The attributes to set label position for input are now combined under the `posit
### Label Required
Previously an `ion-label` would automatically get added to an `ion-list-header` if one wasn't provided. Now an `ion-label` should always be added if the component is used to display text.
Previously an `ion-label` would automatically get added to an `ion-list-header` if one wasn't provided. Now an `ion-label` should always be added around the text.
```html
<ion-list-header>
@ -787,38 +830,39 @@ Previously an `ion-label` would automatically get added to an `ion-list-header`
## Loading
`dismissOnPageChange` was removed. Fortunately all the navigation API is promise based and there are global events (`ionNavWillChange`) you can listen in order to detect when navigation occurs.
You should take advantage of these APIs in order to dismiss your loading overlay explicitally.
See [Overlays](#overlays).
## Menu
### Prop renamed
### Properties Renamed
The `swipeEnabled` prop has been renamed to `swipeGesture`.
The `content` prop has been renamed to `contentId` and it points to the DOM id of the content:
- The `swipeEnabled` property has been renamed to `swipeGesture`.
- The `content` prop has been renamed to `contentId` and it points to the DOM id of the content.
**Old Usage Example:**
```html
<ion-menu swipeEnabled="false" content="nav"> </ion-menu>
<ion-nav #nav></ion-nav>
```
### Events renamed
- `ionClose` was renamed to `ionDidClose`
- `ionOpen` was renamed to `ionDidOpen`
**New Usage Example:**
```html
<ion-menu swipeGesture="false" contentId="nav"> </ion-menu>
<ion-nav id="nav"></ion-nav>
```
### Events Renamed
- `ionClose` was renamed to `ionDidClose`
- `ionOpen` was renamed to `ionDidOpen`
## Menu Toggle
### Markup Changed
@ -897,19 +941,19 @@ export class MyPage {
## Nav
### Method renamed
### Method Renamed
The `remove` method has been renamed to `removeIndex` to avoid conflicts with HTML and be more descriptive as to what it does.
The `getActiveChildNavs` method has been renamed to `getChildNavs`.
- The `remove` method has been renamed to `removeIndex` to avoid conflicts with HTML and be more descriptive as to what it does.
- The `getActiveChildNavs` method has been renamed to `getChildNavs`.
### Prop renamed
### Prop Renamed
The `swipeBackEnabled` prop has been renamed to `swipeGesture`.
- The `swipeBackEnabled` prop has been renamed to `swipeGesture`.
## Navbar
The `<ion-navbar>` component has been removed in favor of always using an `<ion-toolbar>` with an added back button:
The `<ion-navbar>` component has been removed in favor of always using an `<ion-toolbar>` with an explicit back button:
**Old Usage Example:**
@ -932,6 +976,7 @@ The `<ion-navbar>` component has been removed in favor of always using an `<ion-
See the [back button](#back-button) changes for more information.
## Option
### Markup Changed
@ -958,19 +1003,16 @@ Select's option element should now be written as `<ion-select-option>`. This mak
</ion-select>
```
### Class Changed
### Class Renamed
The class has been renamed from `Option` to `SelectOption` to keep it consistent with the element tag name.
## Overlays
### Markup Changed
Action Sheet, Alert, Loading, Modal, Popover, and Toast:
- Should now use `async`/`await`
- `enableBackdropDismiss` has been renamed to `backdropDismiss`.
All overlays should now use `async`/`await`. This includes Action Sheet, Alert, Loading, Modal, Popover, and Toast. In addition, the `enableBackdropDismiss` property has been renamed to `backdropDismiss`.
**Old Usage Example:**
@ -1001,12 +1043,48 @@ async presentPopover(ev: any) {
```
### Property Removed
The `dismissOnPageChange` property of the create was removed from Loading & Toast. All of the navigation API is promise based and there are global events (`ionNavWillChange`, `ionNavDidChange`) that you can listen to in order to detect when navigation occurs.
**Old Usage Example:**
```javascript
openLoading() {
let loading = this.loadingCtrl.create({
content: 'Loading...',
dismissOnPageChange: true
});
}
```
**New Usage Example:**
```javascript
async openLoading() {
let loading = this.loadingCtrl.create({
content: 'Loading...'
});
await loading.present();
const { role, data } = await loading.onDidDismiss();
console.log('Loading dismissed!');
}
```
## Popover
See [Overlays](#overlays).
## Radio
### Slot Required
Previously radio was positioned inside of an item automatically or by using `item-left`/`item-right`. It is now required to have a `slot` to be positioned properly.
Previously radio was positioned inside of an item automatically or by using `item-left`/`item-right`. It is now required to have a `slot` to be positioned properly in an item.
**Old Usage Example:**
@ -1155,7 +1233,7 @@ The `enabled` property (with a default value of `true`) has been renamed to `dis
## Scroll
`ion-scroll` has been removed, fortunately `ion-content` can work as a drop-in replacement:
`ion-scroll` has been removed in favor of using `ion-content`:
```diff
- <ion-scroll scrollX="true">
@ -1440,11 +1518,18 @@ The `ios` and `ios-small` spinner's have been renamed to `lines` and `lines-smal
## Tabs
### Breaking changes
Tabs has been completely refactored for Ionic 4. In Ionic 3 there was a lot of magic going on behind the scenes to style and generate the tab bar and buttons. While this made it easy to get up and running using tabs in Ionic, it made it more difficult to customize the tabs.
#### `ion-tabs`
We decided to rethink the tabs implementation to make it more flexible and easier to theme for your application. In order to accomplish this, there had to be some changes to the markup.
The attributes to position the tabs, change the tab layout, enable the tab highlight and hide the tabs have been removed. Instead use [ion-tab-button](#ion-tab-button)
### `ion-tabs`
The general usage of the `ion-tabs` element hasn't changed too drastically. Its purpose is still mostly the same - it wraps the entire layout.
#### Properties Removed
The attributes to position the tabs, change the tab layout, enable the tab highlight and hide the tabs have been removed. Instead customize this content in the [ion-tab-button](#ion-tab-button).
**Old Usage Example:**
@ -1463,21 +1548,99 @@ The attributes to position the tabs, change the tab layout, enable the tab highl
```
#### `ion-tab`
### `ion-tab`
`ion-tab` was removed. Instead you have to use [ion-tab-button](#ion-tab-button).
The `ion-tab` has been removed in the Angular version of Ionic 4. You should use the Angular router with an [ion-tab-button](#ion-tab-button) that has a `tab` property.
#### `ion-tab-button`
```typescript
import { RouterModule, Routes } from '@angular/router';
You can add `<ion-label>` and `<ion-icon>` inside `ion-tab-button`. `ion-tab-button` has to be wrapped by `<ion-tab-bar>`.
import { TabsPage } from './tabs.page';
The tab attribute defines the route (which should be shown on switching to this tab).
const routes: Routes = [
{
path: 'tabs',
component: TabsPage,
children: [
{
path: 'tab1',
children: [
{
path: '',
loadChildren: '../tab1/tab1.module#Tab1PageModule'
}
]
},
{
path: 'tab2',
children: [
{
path: '',
loadChildren: '../tab2/tab2.module#Tab2PageModule'
}
]
},
{
path: 'tab3',
children: [
{
path: '',
loadChildren: '../tab3/tab3.module#Tab3PageModule'
}
]
},
{
path: '',
redirectTo: '/tabs/tab1',
pathMatch: 'full'
}
]
},
{
path: '',
redirectTo: '/tabs/tab1',
pathMatch: 'full'
}
];
```
```html
<ion-tabs>
<ion-tab-bar slot="bottom">
<ion-tab-button tab="tab1">
<ion-icon name="flash"></ion-icon>
<ion-label>Tab One</ion-label>
</ion-tab-button>
<ion-tab-button tab="tab2">
<ion-icon name="apps"></ion-icon>
<ion-label>Tab Two</ion-label>
</ion-tab-button>
<ion-tab-button tab="tab3">
<ion-icon name="send"></ion-icon>
<ion-label>Tab Three</ion-label>
</ion-tab-button>
</ion-tab-bar>
</ion-tabs>
```
### `ion-tab-bar`
A new element, `ion-tab-bar`, creates the tab bar that will contain the tab buttons and allow for full customization. It requires `slot` to be placed properly above or below the content.
### `ion-tab-button`
A new element, `ion-tab-button`, is used to create each button in the tab bar. These could be static links to different routes, buttons with click handlers on them, or link to whole tab views.
You can add `<ion-label>` and `<ion-icon>` inside of an `<ion-tab-button>`. An `<ion-tab-button>` should be wrapped by an `<ion-tab-bar>`.
The tab attribute defines the route to be shown upon clicking on this tab.
**Old Usage Example:**
```html
<ion-tabs>
<ion-tab tabTitle="Schedule" tabIcon="add"></ion-tab>
<ion-tab tabTitle="Map" tabIcon="map" tabBadge="2" tabBadgeStyle="danger" enabled="false"></ion-tab>
</ion-tabs>
```
@ -1493,16 +1656,12 @@ The tab attribute defines the route (which should be shown on switching to this
<ion-label>Map</ion-label>
<ion-badge color="danger">2</ion-badge>
</ion-tab-button>
<!-- No ion-tab, just a button that looks like a tab -->
<ion-tab-button (click)="schedule()">
<ion-icon name="add"></ion-icon>
<ion-label>Schedule</ion-label>
</ion-tab-button>
</ion-tab-bar>
</ion-tabs>
```
See more usage examples in the [Tabs](https://github.com/ionic-team/ionic/blob/master/core/src/components/tabs) documentation.
## Text / Typography
@ -1675,6 +1834,11 @@ Sass variables should no longer be used to change Ionic components. We have buil
For more information on theming, check out the [theming documentation](https://beta.ionicframework.com/docs/theming/basics).
## Toast
See [Overlays](#overlays).
## Toolbar
### Menu Toggle

View File

@ -1,6 +1,6 @@
{
"name": "@ionic/angular",
"version": "4.0.0",
"version": "4.0.2",
"description": "Angular specific wrappers for @ionic/core",
"keywords": [
"ionic",
@ -45,7 +45,7 @@
"css/"
],
"dependencies": {
"@ionic/core": "4.0.0",
"@ionic/core": "4.0.2",
"tslib": "^1.9.3"
},
"peerDependencies": {

View File

@ -12,7 +12,9 @@ export default {
return false;
}
// anything else is external
return !(id.startsWith('.') || id.startsWith('/'));
// Windows: C:\xxxxxx\xxx
const colonPosition = 1;
return !(id.startsWith('.') || id.startsWith('/') || id.charAt(colonPosition) === ':');
},
plugins: [
resolve({

View File

@ -98,8 +98,9 @@ export class Platform {
* | phablet | on a phablet device. |
* | tablet | on a tablet device. |
* | electron | in Electron on a desktop device. |
* | pwa | as a PWA app. |
* | pwa | as a PWA app. |
* | mobile | on a mobile device. |
* | mobileweb | on a mobile device in a browser. |
* | desktop | on a desktop device. |
* | hybrid | is a cordova or capacitor app. |
*

View File

@ -1,23 +1,7 @@
# TestApp
# Ionic Angular Test App
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 7.1.0.
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
```
npm install
npm run sync:build
npm start
```

View File

@ -23,8 +23,8 @@ 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
<link href="https://unpkg.com/@ionic/core@4.0.0/css/ionic.bundle.css" rel="stylesheet">
<script src="https://unpkg.com/@ionic/core@4.0.0/dist/ionic.js"></script>
<link href="https://unpkg.com/@ionic/core@4.0.2/css/ionic.bundle.css" rel="stylesheet">
<script src="https://unpkg.com/@ionic/core@4.0.2/dist/ionic.js"></script>
```
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

@ -1,6 +1,6 @@
{
"name": "@ionic/core",
"version": "4.0.0",
"version": "4.0.2",
"description": "Base components for Ionic",
"keywords": [
"ionic",
@ -33,7 +33,7 @@
"ionicons": "4.5.5"
},
"devDependencies": {
"@stencil/core": "0.17.0",
"@stencil/core": "0.17.3-0",
"@stencil/sass": "0.1.1",
"@stencil/utils": "latest",
"@types/jest": "^23.3.13",

View File

@ -2776,7 +2776,7 @@ export namespace Components {
*/
'onIonNavDidChange'?: (event: CustomEvent<void>) => void;
/**
* Event fired when the nav will components
* Event fired when the nav will change components
*/
'onIonNavWillChange'?: (event: CustomEvent<void>) => void;
/**
@ -3510,7 +3510,7 @@ export namespace Components {
*/
'disabled'?: boolean;
/**
* Event that needs to be listen to in order to respond to reorder action. `ion-reorder-group` uses this event to delegate to the user the reordering of data array. The complete() method exposed as
* Event that needs to be listened to in order to complete the reorder action. Once the event has been emitted, the `complete()` method then needs to be called in order to finalize the reorder action.
*/
'onIonItemReorder'?: (event: CustomEvent<ItemReorderEventDetail>) => void;
}

View File

@ -4,7 +4,7 @@ An Action Sheet is a dialog that displays a set of options. It appears on top of
### Creating
An action sheet can be created by the [Action Sheet Controller](../../action-sheet-controller/ActionSheetController) from an array of `buttons`, with each button including properties for its `text`, and optionally a `handler` and `role`. If a handler returns `false` then the action sheet will not be dismissed. An action sheet can also optionally have a `title`, `subTitle` and an `icon`.
An action sheet can be created by the [Action Sheet Controller](../action-sheet-controller) from an array of `buttons`, with each button including properties for its `text`, and optionally a `handler` and `role`. If a handler returns `false` then the action sheet will not be dismissed. An action sheet can also optionally have a `title`, `subTitle` and an `icon`.
### Buttons

View File

@ -5,7 +5,7 @@ An Alert is a dialog that presents users with information or collects informatio
### Creating
Alerts can be created using a [Alert Controller](../../alert-controller/AlertController). They can be customized by passing alert options in the alert controller's create method.
Alerts can be created using an [Alert Controller](../alert-controller). They can be customized by passing alert options in the alert controller's create method.
### Buttons

View File

@ -10,30 +10,7 @@ Avatars can be used by themselves or inside of any element. If placed inside of
## Usage
### Angular
```html
<ion-avatar>
<img [src]="user.img">
</ion-avatar>
<ion-chip>
<ion-avatar>
<img [src]="user.img">
</ion-avatar>
<ion-label>Chip Avatar</ion-label>
</ion-chip>
<ion-item>
<ion-avatar slot="start">
<img [src]="user.img">
</ion-avatar>
<ion-label>Item Avatar</ion-label>
</ion-item>
```
### Javascript
### Angular / javascript
```html
<ion-avatar>

View File

@ -1,18 +1,18 @@
```html
<ion-avatar>
<img [src]="user.img">
<img src="https://gravatar.com/avatar/dba6bae8c566f9d4041fb9cd9ada7741?d=identicon&f=y">
</ion-avatar>
<ion-chip>
<ion-avatar>
<img [src]="user.img">
<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]="user.img">
<img src="https://gravatar.com/avatar/dba6bae8c566f9d4041fb9cd9ada7741?d=identicon&f=y">
</ion-avatar>
<ion-label>Item Avatar</ion-label>
</ion-item>

View File

@ -34,6 +34,10 @@
--opacity: #{$button-ios-opacity-activated};
}
:host(.button-solid.activated.ion-color) .button-native {
background: current-color(shade);
}
// iOS Outline Button
// --------------------------------------------------

View File

@ -4,6 +4,12 @@ import { Color, Mode, RouterDirection } from '../../interface';
import { hasShadowDom } from '../../utils/helpers';
import { createColorClasses, openURL } from '../../utils/theme';
/**
* @slot - Content is placed between the named slots if provided without a slot.
* @slot icon-only - Should be used on an icon in a button that has no text.
* @slot start - Content is placed to the left of the button text in LTR, and to the right in RTL.
* @slot end - Content is placed to the right of the button text in LTR, and to the left in RTL.
*/
@Component({
tag: 'ion-button',
styleUrls: {

View File

@ -118,6 +118,16 @@ This attribute specifies the size of the button. Setting this attribute will cha
| `ionFocus` | Emitted when the button has focus. | `CustomEvent<void>` |
## Slots
| Slot | Description |
| ------------- | --------------------------------------------------------------------------------- |
| | Content is placed between the named slots if provided without a slot. |
| `"end"` | Content is placed to the right of the button text in LTR, and to the left in RTL. |
| `"icon-only"` | Should be used on an icon in a button that has no text. |
| `"start"` | Content is placed to the left of the button text in LTR, and to the right in RTL. |
## CSS Custom Properties
| Name | Description |

View File

@ -4,6 +4,10 @@ import { Color, Config, Mode, ScrollBaseDetail, ScrollDetail } from '../../inter
import { isPlatform } from '../../utils/platform';
import { createColorClasses, hostContext } from '../../utils/theme';
/**
* @slot - Content is placed in the scrollable area if provided without a slot.
* @slot fixed - Should be used for fixed content that should not scroll.
*/
@Component({
tag: 'ion-content',
styleUrl: 'content.scss',

View File

@ -144,6 +144,14 @@ Type: `Promise<void>`
## Slots
| Slot | Description |
| --------- | -------------------------------------------------------------------- |
| | Content is placed in the scrollable area if provided without a slot. |
| `"fixed"` | Should be used for fixed content that should not scroll. |
## CSS Custom Properties
| Name | Description |

View File

@ -1,3 +1,16 @@
/**
* Gets a date value given a format
* Defaults to the current date if
* no date given
*/
export function getDateValue(date: DatetimeData, format: string): number {
const getValue = getValueFromFormat(date, format);
if (getValue) { return getValue; }
const defaultDate = parseDate(new Date().toISOString());
return getValueFromFormat((defaultDate as DatetimeData), format);
}
export function renderDatetime(template: string, value: DatetimeData | undefined, locale: LocaleData): string | undefined {
if (value === undefined) {

View File

@ -4,7 +4,7 @@ import { DatetimeChangeEventDetail, DatetimeOptions, Mode, PickerColumn, PickerC
import { clamp, findItemLabel, renderHiddenInput } from '../../utils/helpers';
import { hostContext } from '../../utils/theme';
import { DatetimeData, LocaleData, convertDataToISO, convertFormatToKey, convertToArrayOfNumbers, convertToArrayOfStrings, dateDataSortValue, dateSortValue, dateValueRange, daysInMonth, getValueFromFormat, parseDate, parseTemplate, renderDatetime, renderTextFormat, updateDate } from './datetime-util';
import { DatetimeData, LocaleData, convertDataToISO, convertFormatToKey, convertToArrayOfNumbers, convertToArrayOfStrings, dateDataSortValue, dateSortValue, dateValueRange, daysInMonth, getDateValue, parseDate, parseTemplate, renderDatetime, renderTextFormat, updateDate } from './datetime-util';
@Component({
tag: 'ion-datetime',
@ -359,7 +359,7 @@ export class Datetime implements ComponentInterface {
// cool, we've loaded up the columns with options
// preselect the option for this column
const optValue = getValueFromFormat(this.datetimeValue, format);
const optValue = getDateValue(this.datetimeValue, format);
const selectedIndex = colOptions.findIndex(opt => opt.value === optValue);
return {

View File

@ -151,18 +151,20 @@ selection between the beginning of 2016, and October 31st of 2020:
At this time, there is no one-size-fits-all standard to automatically choose the
correct language/spelling for a month name, or day of the week name, depending
on the language or locale. Good news is that there is an
[Intl.DatetimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DatetimeFormat)
standard whichmost* browsers have adopted. However, at this time the standard
has not been fully implemented by all popular browsers so Ionic is unavailable
to take advantage of ityet*. Additionally, Angular also provides an
internationalization service, but it is still under heavy development so Ionic
does not depend on it at this time.
on the language or locale.
All things considered, the by far easiest solution is to just provide an array
of names if the app needs to use names other than the default English version of
month and day names. The month names and day names can be either configured at
the app level, or individual `ion-datetime` level.
The good news is that there is an [Intl.DatetimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DatetimeFormat)
standard which [most browsers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DatetimeFormat#Browser_compatibility) have adopted.
However, at this time the standard has not been fully implemented by all popular browsers
so Ionic is unavailable to take advantage of it yet.
Additionally, Angular also provides an internationalization service, but it is still
under heavy development so Ionic does not depend on it at this time.
The current best practice is to provide an array of names if the app needs to use names other
than the default English version of month and day names. The month names and day names can be
either configured at the app level, or individual `ion-datetime` level.
### Component Input Level
@ -194,8 +196,7 @@ dates in JavaScript.
```html
<ion-item>
<ion-label>Date</ion-label>
<ion-datetime display-format="MM/DD/YYYY" >
</ion-datetime>
<ion-datetime display-format="MM/DD/YYYY"></ion-datetime>
</ion-item>
```

View File

@ -0,0 +1,35 @@
import { DatetimeOptions } from '../datetime-interface';
import { DatetimeData, getDateValue } from '../datetime-util';
describe('Datetime', () => {
describe('getDateValue()', () => {
it('it should return the date value for the current day', () => {
const today = new Date();
const dayValue = getDateValue({}, 'DD');
const monthvalue = getDateValue({}, 'MM');
const yearValue = getDateValue({}, 'YYYY');
expect(dayValue).toEqual(today.getDate());
expect(monthvalue).toEqual(today.getMonth() + 1);
expect(yearValue).toEqual(today.getFullYear());
});
it('it should return the date value for a given day', () => {
const date = new Date('15 October 1995');
const dateTimeData: DatetimeData = {
year: date.getFullYear(),
month: date.getMonth() + 1,
day: date.getDate()
}
const dayValue = getDateValue(dateTimeData, 'DD');
const monthvalue = getDateValue(dateTimeData, 'MM');
const yearValue = getDateValue(dateTimeData, 'YYYY');
expect(dayValue).toEqual(date.getDate());
expect(monthvalue).toEqual(date.getMonth() + 1);
expect(yearValue).toEqual(date.getFullYear());
});
});
});

View File

@ -1,6 +1,6 @@
# ion-fab
Fabs are container elements that contain one or more fab buttons. They should be placed in a fixed position that does not scroll with the content. Fab should have one main fab-button. Fabs can also contain fab-lists which contain related buttons that show when the main fab button is clicked. The same fab container can contain several [fab-list](../../fab-list/FabList) elements with different side values.
Fabs are container elements that contain one or more fab buttons. They should be placed in a fixed position that does not scroll with the content. Fab should have one main fab-button. Fabs can also contain fab-lists which contain related buttons that show when the main fab button is clicked. The same fab container can contain several [fab-list](../fab-list) elements with different side values.
<!-- Auto Generated Below -->

View File

@ -24,6 +24,8 @@
@include margin-horizontal(auto);
display: block;
flex: 1;
}
// Fixed Grid

View File

@ -3,6 +3,11 @@ import { Component, ComponentInterface, Element, Prop } from '@stencil/core';
import { Color, Mode } from '../../interface';
import { createColorClasses } from '../../utils/theme';
/**
* @slot - Content is placed between the named slots if provided without a slot.
* @slot start - Content is placed to the left of the divider text in LTR, and to the right in RTL.
* @slot end - Content is placed to the right of the divider text in LTR, and to the left in RTL.
*/
@Component({
tag: 'ion-item-divider',
styleUrls: {

View File

@ -61,6 +61,15 @@ Item Dividers are block elements that can be used to separate items in a list. T
| `sticky` | `sticky` | When it's set to `true`, the item-divider will stay visible when it reaches the top of the viewport until the next `ion-item-divider` replaces it. This feature relies in `position:sticky`: https://caniuse.com/#feat=css-sticky | `boolean` | `false` |
## Slots
| Slot | Description |
| --------- | ---------------------------------------------------------------------------------- |
| | Content is placed between the named slots if provided without a slot. |
| `"end"` | Content is placed to the right of the divider text in LTR, and to the left in RTL. |
| `"start"` | Content is placed to the left of the divider text in LTR, and to the right in RTL. |
## CSS Custom Properties
| Name | Description |

View File

@ -3,6 +3,14 @@ import { Component, ComponentInterface, Element, Listen, Prop } from '@stencil/c
import { Color, Mode } from '../../interface';
import { createColorClasses } from '../../utils/theme';
/**
* @slot - Content is placed between the named slots if provided without a slot.
* @slot start - Content is placed to the left of the option text in LTR, and to the right in RTL.
* @slot top - Content is placed above the option text.
* @slot icon-only - Should be used on an icon in an option that has no text.
* @slot bottom - Content is placed below the option text.
* @slot end - Content is placed to the right of the option text in LTR, and to the left in RTL.
*/
@Component({
tag: 'ion-item-option',
styleUrls: {

View File

@ -18,6 +18,18 @@ action for the item.
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
## Slots
| Slot | Description |
| ------------- | --------------------------------------------------------------------------------- |
| | Content is placed between the named slots if provided without a slot. |
| `"bottom"` | Content is placed below the option text. |
| `"end"` | Content is placed to the right of the option text in LTR, and to the left in RTL. |
| `"icon-only"` | Should be used on an icon in an option that has no text. |
| `"start"` | Content is placed to the left of the option text in LTR, and to the right in RTL. |
| `"top"` | Content is placed above the option text. |
## CSS Custom Properties
| Name | Description |

View File

@ -66,7 +66,6 @@ export class ItemSliding implements ComponentInterface {
async componentDidLoad() {
this.item = this.el.querySelector('ion-item');
await this.updateOptions();
this.gesture = (await import('../../utils/gesture')).createGesture({
@ -91,6 +90,7 @@ export class ItemSliding implements ComponentInterface {
this.item = null;
this.leftOptions = this.rightOptions = undefined;
this.closeOpened();
}
/**
@ -128,6 +128,7 @@ export class ItemSliding implements ComponentInterface {
async closeOpened(): Promise<boolean> {
if (openSlidingItem !== undefined) {
openSlidingItem.close();
openSlidingItem = undefined;
return true;
}
return false;
@ -162,6 +163,7 @@ export class ItemSliding implements ComponentInterface {
this.closeOpened();
return false;
}
return !!(this.rightOptions || this.leftOptions);
}

View File

@ -0,0 +1,49 @@
import { newE2EPage } from '@stencil/core/testing';
test('item-sliding: interactive', async () => {
const page = await newE2EPage({
url: '/src/components/item-sliding/test/interactive?ionic:_testing=true'
});
const compare = await page.compareScreenshot();
expect(compare).toMatchScreenshot();
const items = await page.$$('ion-item-sliding');
expect(items.length).toEqual(3);
await slideAndDelete(items[0], page);
const itemsAfterFirstSlide = await page.$$('ion-item-sliding');
expect(itemsAfterFirstSlide.length).toEqual(2);
await slideAndDelete(items[1], page);
const itemsAfterSecondSlide = await page.$$('ion-item-sliding');
expect(itemsAfterSecondSlide.length).toEqual(1);
});
async function slideAndDelete(item: any, page: any) {
try {
// Get the element's ID
const id = await(await item.getProperty('id')).jsonValue();
// Simulate a drag
const boundingBox = await item.boundingBox();
const centerX = parseFloat(boundingBox.x + boundingBox.width / 2);
const centerY = parseFloat(boundingBox.y + boundingBox.height / 2);
await page.mouse.move(centerX, centerY);
await page.mouse.down();
await page.mouse.move(0, centerY);
await page.mouse.up();
// Click the "delete" option
const options = await item.$$('ion-item-option');
await options[0].click();
// Wait for element to be removed from DOM
await page.waitForSelector(id, { hidden: true });
} catch (err) {
throw err;
}
}

View File

@ -0,0 +1,54 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="UTF-8">
<title>Item Sliding - Standalone</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link href="../../../../../css/core.css" rel="stylesheet">
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet">
<script src="../../../../../scripts/testing/scripts.js"></script>
<script src="../../../../../dist/ionic.js"></script>
</head>
<body>
<ion-list></ion-list>
<script>
let lists = document.getElementsByTagName('ion-list');
for (var i = 0; i < lists.length; i++) {
for (var j = 0; j < 3; j++) {
addSlidingItem(lists[i]);
}
}
function addSlidingItem(list) {
const slidingItem = document.createElement('ion-item-sliding');
slidingItem.innerHTML = `
<ion-item>
<ion-label>
<h2>Item Options Both Sides</h2>
</ion-label>
</ion-item>
<ion-item-options side="end">
<ion-item-option color="danger" expandable onclick="remove(this)">
<ion-icon name="trash"></ion-icon>
Delete
</ion-item-option>
</ion-item-options>
`;
slidingItem.id = `item-${list.childElementCount}`;
list.appendChild(slidingItem);
}
function remove(optionElement) {
const slidingElement = optionElement.parentNode.parentNode;
lists[0].removeChild(slidingElement);
}
</script>
</body>
</html>

View File

@ -3,6 +3,11 @@ import { Component, ComponentInterface, Element, Listen, Prop, State } from '@st
import { Color, CssClassMap, Mode, RouterDirection, StyleEventDetail } from '../../interface';
import { createColorClasses, hostContext, openURL } from '../../utils/theme';
/**
* @slot - Content is placed between the named slots if provided without a slot.
* @slot start - Content is placed to the left of the item text in LTR, and to the right in RTL.
* @slot end - Content is placed to the right of the item text in LTR, and to the left in RTL.
*/
@Component({
tag: 'ion-item',
styleUrls: {

View File

@ -31,7 +31,7 @@ The below chart details the item slots and where it will place the element insid
| Slot | Description |
|---------|-----------------------------------------------------------------------------|
| `start` | Placed to the left of all other content in LTR, and to the `right` in RTL. |
| `end` | Placed to the right of all other content in LTR, and to the `right` in RTL. |
| `end` | Placed to the right of all other content in LTR, and to the `left` in RTL. |
| none | Placed inside of the input wrapper. |
@ -721,6 +721,15 @@ Item Inputs
| `type` | `type` | The type of the button. Only used when an `onclick` or `button` property is present. | `"button" \| "reset" \| "submit"` | `'button'` |
## Slots
| Slot | Description |
| --------- | ------------------------------------------------------------------------------- |
| | Content is placed between the named slots if provided without a slot. |
| `"end"` | Content is placed to the right of the item text in LTR, and to the left in RTL. |
| `"start"` | Content is placed to the left of the item text in LTR, and to the right in RTL. |
## CSS Custom Properties
| Name | Description |

View File

@ -5,12 +5,12 @@ An overlay that can be used to indicate activity while blocking user interaction
### Creating
Loading indicators can be created using a [Loading Controller](../../loading-controller/LoadingController). They can be customized by passing loading options in the loading controller's create method. The spinner name should be passed in the `spinner` property, and any optional HTML can be passed in the `content` property. If a value is not passed to `spinner` the loading indicator will use the spinner specified by the platform.
Loading indicators can be created using a [Loading Controller](../loading-controller). They can be customized by passing loading options in the loading controller's create method. The spinner name should be passed in the `spinner` property, and any optional HTML can be passed in the `content` property. If a value is not passed to `spinner` the loading indicator will use the spinner specified by the platform.
### Dismissing
The loading indicator can be dismissed automatically after a specific amount of time by passing the number of milliseconds to display it in the `duration` of the loading options. By default the loading indicator will show even during page changes, but this can be disabled by setting `dismissOnPageChange` to `true`. To dismiss the loading indicator after creation, call the `dismiss()` method on the loading instance. The `onDidDismiss` function can be called to perform an action after the loading indicator is dismissed.
The loading indicator can be dismissed automatically after a specific amount of time by passing the number of milliseconds to display it in the `duration` of the loading options. To dismiss the loading indicator after creation, call the `dismiss()` method on the loading instance. The `onDidDismiss` function can be called to perform an action after the loading indicator is dismissed.
<!-- Auto Generated Below -->
@ -37,7 +37,11 @@ export class LoadingExample {
message: 'Hellooo',
duration: 2000
});
return await loading.present();
await loading.present();
const { role, data } = await loading.onDidDismiss();
console.log('Loading dismissed!');
}
async presentLoadingWithOptions() {
@ -65,7 +69,12 @@ async function presentLoading() {
message: 'Hellooo',
duration: 2000
});
return await loading.present();
await loading.present();
const { role, data } = await loading.onDidDismiss();
console.log('Loading dismissed!');
}
async function presentLoadingWithOptions() {

View File

@ -15,7 +15,11 @@ export class LoadingExample {
message: 'Hellooo',
duration: 2000
});
return await loading.present();
await loading.present();
const { role, data } = await loading.onDidDismiss();
console.log('Loading dismissed!');
}
async presentLoadingWithOptions() {

View File

@ -7,7 +7,12 @@ async function presentLoading() {
message: 'Hellooo',
duration: 2000
});
return await loading.present();
await loading.present();
const { role, data } = await loading.onDidDismiss();
console.log('Loading dismissed!');
}
async function presentLoadingWithOptions() {

View File

@ -18,6 +18,10 @@
box-shadow: $menu-ios-box-shadow-reveal;
}
[dir=rtl].ios .menu-content-reveal {
box-shadow: $menu-ios-box-shadow-reveal-rtl;
}
.ios .menu-content-push {
box-shadow: $menu-ios-box-shadow-push;
}

View File

@ -12,9 +12,15 @@ $menu-ios-box-shadow-color: rgba(0, 0, 0, .08) !default;
/// @prop - Box shadow of the menu
$menu-ios-box-shadow: -8px 0 42px $menu-ios-box-shadow-color !default;
/// @prop - Box shadow of the menu in rtl mode
$menu-ios-box-shadow-rtl: 8px 0 42px $menu-ios-box-shadow-color !default;
/// @prop - Box shadow of the reveal menu
$menu-ios-box-shadow-reveal: $menu-ios-box-shadow !default;
/// @prop - Box shadow of the reveal menu
$menu-ios-box-shadow-reveal-rtl: $menu-ios-box-shadow-rtl !default;
/// @prop - Box shadow of the push menu
$menu-ios-box-shadow-push: null !default;

View File

@ -5,7 +5,7 @@ A Modal is a dialog that appears on top of the app's content, and must be dismis
### Creating
Modals can be created using a [Modal Controller](../../modal-controller/ModalController). They can be customized by passing modal options in the modal controller's create method.
Modals can be created using a [Modal Controller](../modal-controller). They can be customized by passing modal options in the modal controller's create method.
### Passing paramaters
@ -36,7 +36,7 @@ instance.prop2 = value2;
This way, your component can access the passed params, check the "Usage" section for further code example for each frameworks.
### Retuning data
### Returning data
Modals can also return data back to the controller when they are dismissed.

View File

@ -85,7 +85,7 @@ export class Nav implements NavOutlet {
*/
@Event() ionNavWillLoad!: EventEmitter<void>;
/**
* Event fired when the nav will components
* Event fired when the nav will change components
*/
@Event({ bubbles: false }) ionNavWillChange!: EventEmitter<void>;
/**

View File

@ -23,7 +23,7 @@ Unlike RouterOutlet, Nav is not tied to a particular router. Meaning that if we
| Event | Description | Type |
| ------------------ | ----------------------------------------------- | ------------------- |
| `ionNavDidChange` | Event fired when the nav has changed components | `CustomEvent<void>` |
| `ionNavWillChange` | Event fired when the nav will components | `CustomEvent<void>` |
| `ionNavWillChange` | Event fired when the nav will change components | `CustomEvent<void>` |
## Methods

View File

@ -4,8 +4,10 @@ import { Animation } from '../../../interface';
* Md Popover Enter Animation
*/
export function mdEnterAnimation(AnimationC: Animation, baseEl: HTMLElement, ev?: Event): Promise<Animation> {
const isRTL = document.dir === 'rtl';
let originY = 'top';
let originX = 'left';
let originX = isRTL ? 'right' : 'left';
const contentEl = baseEl.querySelector('.popover-content') as HTMLElement;
const contentDimentions = contentEl.getBoundingClientRect();
@ -24,7 +26,6 @@ export function mdEnterAnimation(AnimationC: Animation, baseEl: HTMLElement, ev?
? targetDim.top
: bodyHeight / 2 - contentHeight / 2;
const isRTL = document.dir === 'rtl';
const targetLeft =
targetDim != null && 'left' in targetDim
? isRTL
@ -49,7 +50,7 @@ export function mdEnterAnimation(AnimationC: Animation, baseEl: HTMLElement, ev?
bodyWidth
) {
popoverCSS.left = bodyWidth - contentWidth - POPOVER_MD_BODY_PADDING;
originX = 'right';
originX = isRTL ? 'left' : 'right';
}
// If the popover when popped down stretches past bottom of screen,

View File

@ -25,7 +25,7 @@
@include position(0, 0, 0, 0);
display: flex;
position: absolute;
position: fixed;
align-items: center;
justify-content: center;

View File

@ -4,7 +4,7 @@ A Popover is a dialog that appears on top of the current page. It can be used fo
### Creating
Popovers can be created using a [Popover Controller](https://beta.ionicframework.com/docs/api/popover-controller). They can be customized by passing popover options in the popover controller's create method.
Popovers can be created using a [Popover Controller](../popover-controller). They can be customized by passing popover options in the popover controller's create method.
### Presenting
@ -52,8 +52,8 @@ async function presentPopover(ev) {
const popover = await popoverController.create({
component: 'popover-example-page',
translucent: true
event: ev,
translucent: true
});
return await popover.present();
}

View File

@ -5,8 +5,8 @@ async function presentPopover(ev) {
const popover = await popoverController.create({
component: 'popover-example-page',
translucent: true
event: ev,
translucent: true
});
return await popover.present();
}

View File

@ -105,6 +105,11 @@
@include border-radius(50%, 50%, 50%, 0);
@include margin-horizontal(-13px, null);
@include rtl() {
/* stylelint-disable-next-line property-blacklist */
left: unset;
}
position: absolute;
width: 26px;

View File

@ -79,6 +79,11 @@
null
);
@include rtl() {
/* stylelint-disable-next-line property-blacklist */
left: unset;
}
position: absolute;
width: var(--knob-handle-size);
@ -95,6 +100,12 @@
.range-bar {
@include border-radius(var(--bar-border-radius));
@include position(calc((var(--height) - var(--bar-height)) / 2), null, null, 0);
@include rtl() {
/* stylelint-disable-next-line property-blacklist */
left: unset;
}
position: absolute;
width: 100%;
@ -113,6 +124,11 @@
calc(50% - var(--knob-size) / 2)
);
@include rtl() {
/* stylelint-disable-next-line property-blacklist */
left: unset;
}
position: absolute;
width: var(--knob-size);
@ -129,9 +145,6 @@
will-change: left, right;
}
:host(.range-pressed) .range-knob-handle {
will-change: left;
}
// Range in Item
// ----------------------------

View File

@ -4,6 +4,10 @@ import { Color, Gesture, GestureDetail, KnobName, Mode, RangeChangeEventDetail,
import { clamp, debounceEvent } from '../../utils/helpers';
import { createColorClasses, hostContext } from '../../utils/theme';
/**
* @slot start - Content is placed to the left of the range slider in LTR, and to the right in RTL.
* @slot end - Content is placed to the right of the range slider in LTR, and to the left in RTL.
*/
@Component({
tag: 'ion-range',
styleUrls: {
@ -235,7 +239,11 @@ export class Range implements ComponentInterface {
const currentX = detail.currentX;
// figure out which knob they started closer to
const ratio = clamp(0, (currentX - rect.left) / rect.width, 1);
let ratio = clamp(0, (currentX - rect.left) / rect.width, 1);
if (document.dir === 'rtl') {
ratio = 1 - ratio;
}
this.pressedKnob =
!this.dualKnobs ||
Math.abs(this.ratioA - ratio) < Math.abs(this.ratioB - ratio)
@ -262,6 +270,10 @@ export class Range implements ComponentInterface {
// update the knob being interacted with
const rect = this.rect;
let ratio = clamp(0, (currentX - rect.left) / rect.width, 1);
if (document.dir === 'rtl') {
ratio = 1 - ratio;
}
if (this.snaps) {
// snaps the ratio to the current value
ratio = valueToRatio(
@ -353,31 +365,56 @@ export class Range implements ComponentInterface {
render() {
const { min, max, step, ratioLower, ratioUpper } = this;
const barL = `${ratioLower * 100}%`;
const barR = `${100 - ratioUpper * 100}%`;
const barStart = `${ratioLower * 100}%`;
const barEnd = `${100 - ratioUpper * 100}%`;
const isRTL = document.dir === 'rtl';
const start = isRTL ? 'right' : 'left';
const end = isRTL ? 'left' : 'right';
const ticks = [];
if (this.snaps) {
for (let value = min; value <= max; value += step) {
const ratio = valueToRatio(value, min, max);
ticks.push({
const tick: any = {
ratio,
active: ratio >= ratioLower && ratio <= ratioUpper,
left: `${ratio * 100}%`
});
};
tick[start] = `${ratio * 100}%`;
ticks.push(tick);
}
}
const tickStyle = (tick: any) => {
const style: any = {};
style[start] = tick[start];
return style;
};
const barStyle = () => {
const style: any = {};
style[start] = barStart;
style[end] = barEnd;
return style;
};
return [
<slot name="start"></slot>,
<div class="range-slider" ref={el => this.rangeSlider = el}>
{ticks.map(t => (
{ticks.map(tick => (
<div
style={{ left: t.left }}
style={tickStyle(tick)}
role="presentation"
class={{
'range-tick': true,
'range-tick-active': t.active
'range-tick-active': tick.active
}}
/>
))}
@ -386,10 +423,7 @@ export class Range implements ComponentInterface {
<div
class="range-bar range-bar-active"
role="presentation"
style={{
left: barL,
right: barR
}}
style={barStyle()}
/>
{ renderKnob({
@ -435,6 +469,17 @@ interface RangeKnob {
}
function renderKnob({ knob, value, ratio, min, max, disabled, pressed, pin, handleKeyboard }: RangeKnob) {
const isRTL = document.dir === 'rtl';
const start = isRTL ? 'right' : 'left';
const knobStyle = () => {
const style: any = {};
style[start] = `${ratio * 100}%`;
return style;
};
return (
<div
onKeyDown={(ev: KeyboardEvent) => {
@ -458,9 +503,7 @@ function renderKnob({ knob, value, ratio, min, max, disabled, pressed, pin, hand
'range-knob-min': value === min,
'range-knob-max': value === max
}}
style={{
'left': `${ratio * 100}%`
}}
style={knobStyle()}
role="slider"
tabindex={disabled ? -1 : 0}
aria-valuemin={min}

View File

@ -111,6 +111,14 @@ left or right of the range.
| `ionFocus` | Emitted when the range has focus. | `CustomEvent<void>` |
## Slots
| Slot | Description |
| --------- | ---------------------------------------------------------------------------------- |
| `"end"` | Content is placed to the right of the range slider in LTR, and to the left in RTL. |
| `"start"` | Content is placed to the left of the range slider in LTR, and to the right in RTL. |
## CSS Custom Properties
| Name | Description |

View File

@ -13,7 +13,7 @@ reorderGroup.addEventListener('ionItemReorder', (ev) => {
});
```
The event's detail includes all the relevant information about the reorder operation, including the `from` and `to` indexes. The meaning of this indexes are pretty self-explanatory, the item **from** index X, moved **to** the index Y.
The event's detail includes all the relevant information about the reorder operation, including the `from` and `to` indexes. In the context of reordering, an item moves `from` index X `to` index Y.
For example, in this list we move the item at index `0` to the index `3`:
@ -42,10 +42,6 @@ Fortunately this `complete()` method can optionally accept an array as input and
this.dataList = reorderGroup.complete(this.dataList);
```
This utility is really handy when
<!-- Auto Generated Below -->
@ -178,9 +174,9 @@ reorderGroup.addEventListener('ionItemReorder', ({detail}) => {
## Events
| Event | Description | Type |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- |
| `ionItemReorder` | Event that needs to be listen to in order to respond to reorder action. `ion-reorder-group` uses this event to delegate to the user the reordering of data array. The complete() method exposed as | `CustomEvent<ItemReorderEventDetail>` |
| Event | Description | Type |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- |
| `ionItemReorder` | Event that needs to be listened to in order to complete the reorder action. Once the event has been emitted, the `complete()` method then needs to be called in order to finalize the reorder action. | `CustomEvent<ItemReorderEventDetail>` |
## Methods

View File

@ -50,11 +50,9 @@ export class ReorderGroup implements ComponentInterface {
}
/**
* Event that needs to be listen to in order to respond to reorder action.
* `ion-reorder-group` uses this event to delegate to the user the reordering of data array.
*
*
* The complete() method exposed as
* Event that needs to be listened to in order to complete the reorder action.
* Once the event has been emitted, the `complete()` method then needs
* to be called in order to finalize the reorder action.
*/
@Event() ionItemReorder!: EventEmitter<ItemReorderEventDetail>;

View File

@ -27,35 +27,35 @@
<ion-list>
<ion-reorder-group id="reorder">
<ion-item>
<ion-item button onclick="openAlert()">
<ion-label>
Item 1 (default ion-reorder)
</ion-label>
<ion-reorder slot="end"></ion-reorder>
</ion-item>
<ion-item>
<ion-item button onclick="openAlert()">
<ion-label>
Item 2 (default ion-reorder)
</ion-label>
<ion-reorder slot="end"></ion-reorder>
</ion-item>
<ion-item>
<ion-item button onclick="openAlert()">
<ion-label>
Item 3 (default ion-reorder slot="start")
</ion-label>
<ion-reorder slot="start"></ion-reorder>
</ion-item>
<ion-item color="secondary">
<ion-item button color="secondary">
<ion-label>
Item 4 (default ion-reorder slot="start")
</ion-label>
<ion-reorder slot="start"></ion-reorder>
</ion-item>
<ion-item>
<ion-item button onclick="openAlert()">
<ion-label>
Item 5 (custom ion-reorder)
</ion-label>
@ -64,7 +64,7 @@
</ion-reorder>
</ion-item>
<ion-item>
<ion-item button onclick="openAlert()">
<ion-label>
Item 6 (custom ion-reorder)
</ion-label>
@ -73,7 +73,7 @@
</ion-reorder>
</ion-item>
<ion-item>
<ion-item button onclick="openAlert()">
<ion-label>
Item 7 (custom ion-reorder slot="start")
</ion-label>
@ -83,7 +83,7 @@
</ion-item>
<ion-reorder>
<ion-item>
<ion-item button onclick="openAlert()">
<ion-label>
Item 8 (the whole item can be dragged)
</ion-label>
@ -91,7 +91,7 @@
</ion-reorder>
<ion-reorder>
<ion-item>
<ion-item button onclick="openAlert()">
<ion-label>
Item 9 (the whole item can be dragged)
</ion-label>
@ -99,7 +99,7 @@
</ion-reorder>
<ion-reorder>
<ion-item>
<ion-item button onclick="openAlert()">
<ion-label>
Item 10 (the whole item can be dragged)
</ion-label>
@ -113,6 +113,9 @@
</ion-app>
<script>
function openAlert() {
alert('click');
}
function toggleEdit() {
const reorderGroup = document.getElementById('reorder');
reorderGroup.disabled = !reorderGroup.disabled;

View File

@ -2,7 +2,7 @@
Reorder is a component that allows an item to be dragged to change its order. It must be used within an `ion-reorder-group` to provide a visual drag and drop interface.
`ion-reorder` is the anchor users will use to drag and drop items inside the `ion-reorder-group`. It must be added to `ion-item` in order for them to be draggable.
`ion-reorder` is the anchor users will use to drag and drop items inside the `ion-reorder-group`.
```html
<ion-item>
@ -13,9 +13,6 @@ Reorder is a component that allows an item to be dragged to change its order. It
</ion-item>
```
The position of the
<!-- Auto Generated Below -->

View File

@ -1,4 +1,4 @@
import { Component, ComponentInterface } from '@stencil/core';
import { Component, ComponentInterface, Listen } from '@stencil/core';
import { Mode } from '../../interface';
@ -14,6 +14,12 @@ export class Reorder implements ComponentInterface {
mode!: Mode;
@Listen('click', { capture: true })
onClick(ev: Event) {
ev.preventDefault();
ev.stopImmediatePropagation();
}
render() {
return (
<slot>

View File

@ -156,11 +156,11 @@
// Searchbar in Toolbar Color
// -----------------------------------------
:host-context(ion-toolbar.ion-color) {
:host-context(ion-toolbar.ion-color):not(.ion-color) {
color: inherit;
}
:host-context(ion-toolbar.ion-color) .searchbar-cancel-button {
:host-context(ion-toolbar.ion-color):not(.ion-color) .searchbar-cancel-button {
color: currentColor;
}
@ -170,13 +170,13 @@
opacity: $searchbar-ios-input-icon-opacity;
}
:host-context(ion-toolbar.ion-color) .searchbar-input {
:host-context(ion-toolbar.ion-color):not(.ion-color) .searchbar-input {
background: rgba(var(--ion-color-contrast-rgb), $searchbar-ios-input-background-color-alpha);
color: currentColor;
}
:host-context(ion-toolbar.ion-color) .searchbar-clear-button {
:host-context(ion-toolbar.ion-color):not(.ion-color) .searchbar-clear-button {
color: currentColor;
opacity: $searchbar-ios-input-icon-opacity;
}
}

View File

@ -109,6 +109,10 @@
display: block;
}
:host(.searchbar-has-focus) .searchbar-cancel-button + .searchbar-search-icon {
display: none;
}
// Searchbar in Toolbar
// -----------------------------------------

View File

@ -7,10 +7,29 @@ test('searchbar: basic', async () => {
await page.waitFor(250);
const compare = await page.compareScreenshot();
expect(compare).toMatchScreenshot();
const compares = [];
compares.push(await page.compareScreenshot());
const searchbar = await page.find('ion-searchbar');
let searchbar = await page.find('#basic');
await searchbar.callMethod('setFocus');
expect(await page.compareScreenshot('focused')).toMatchScreenshot();
await page.waitFor(250);
searchbar = await page.find('#basic');
expect(searchbar).toHaveClass('searchbar-has-focus');
compares.push(await page.compareScreenshot('focused'));
// No Cancel Button Searchbar
searchbar = await page.find('#noCancel');
await searchbar.callMethod('setFocus');
await page.waitFor(250);
searchbar = await page.find('#noCancel');
expect(searchbar).toHaveClass('searchbar-has-focus');
compares.push(await page.compareScreenshot('no cancel button, focused'));
for (const compare of compares) {
expect(compare).toMatchScreenshot();
}
});

View File

@ -22,7 +22,11 @@
<ion-content id="content">
<h5 padding-start padding-top> Search - Default </h5>
<ion-searchbar value="test" type="tel" show-cancel-button debounce="500">
<ion-searchbar id="basic" value="test" type="tel" show-cancel-button debounce="500">
</ion-searchbar>
<h5 padding-start padding-top> Search - No Cancel Button </h5>
<ion-searchbar id="noCancel" value="after view" autocorrect="off" autocomplete="off" spellcheck="true" type="text" show-cancel-button="false">
</ion-searchbar>
<h5 padding-start padding-top> Search - Danger </h5>
@ -42,10 +46,6 @@
type="number" placeholder="Filter Schedules">
</ion-searchbar>
<h5 padding-start padding-top> Search - No Cancel Button </h5>
<ion-searchbar value="after view" autocorrect="off" autocomplete="off" spellcheck="true" type="text" show-cancel-button="false">
</ion-searchbar>
<h5 padding-start padding-top> Search - Custom Cancel Button Danger </h5>
<ion-searchbar show-cancel-button cancel-button-text="Really Long Cancel" color="danger">
</ion-searchbar>

View File

@ -78,6 +78,11 @@
<ion-toolbar color="dark">
<ion-searchbar show-cancel-button placeholder="Filter Schedules"></ion-searchbar>
</ion-toolbar>
<h5 padding-start padding-top> Search - Dark Toolbar, Primary Search </h5>
<ion-toolbar color="dark">
<ion-searchbar show-cancel-button color="primary" placeholder="Filter Schedules"></ion-searchbar>
</ion-toolbar>
<ion-grid>
<ion-row>
@ -138,4 +143,4 @@
</style>
</body>
</html>
</html>

View File

@ -1,6 +1,6 @@
# ion-segment-button
Segment buttons are groups of related buttons inside of a [Segment](../../segment/Segment). They are displayed in a horizontal row. A segment button can be checked by default by adding the `checked` attribute or by setting the `value` of the segment to the `value` of the segment button. Only one segment button should be selected at a time.
Segment buttons are groups of related buttons inside of a [Segment](../segment). They are displayed in a horizontal row. A segment button can be checked by default by adding the `checked` attribute or by setting the `value` of the segment to the `value` of the segment button. Only one segment button should be selected at a time.
<!-- Auto Generated Below -->

View File

@ -92,6 +92,16 @@ Their functionality is similar to tabs, where selecting one will deselect all ot
</ion-segment-button>
</ion-segment>
</ion-toolbar>
<!-- Segment with default selection -->
<ion-segment (ionChange)="segmentChanged($event)" value="javascript">
<ion-segment-button value="python">
<ion-label>Python</ion-label>
</ion-segment-button>
<ion-segment-button value="javascript">
<ion-label>Javascript</ion-label>
</ion-segment-button>
</ion-segment>
```
```typescript
@ -192,6 +202,16 @@ export class SegmentExample {
</ion-segment-button>
</ion-segment>
</ion-toolbar>
<!-- Segment with default selection -->
<ion-segment value="javascript">
<ion-segment-button value="python">
<ion-label>Python</ion-label>
</ion-segment-button>
<ion-segment-button value="javascript">
<ion-label>Javascript</ion-label>
</ion-segment-button>
</ion-segment>
```
```javascript

View File

@ -78,6 +78,16 @@
</ion-segment-button>
</ion-segment>
</ion-toolbar>
<!-- Segment with default selection -->
<ion-segment (ionChange)="segmentChanged($event)" value="javascript">
<ion-segment-button value="python">
<ion-label>Python</ion-label>
</ion-segment-button>
<ion-segment-button value="javascript">
<ion-label>Javascript</ion-label>
</ion-segment-button>
</ion-segment>
```
```typescript

View File

@ -78,6 +78,16 @@
</ion-segment-button>
</ion-segment>
</ion-toolbar>
<!-- Segment with default selection -->
<ion-segment value="javascript">
<ion-segment-button value="python">
<ion-label>Python</ion-label>
</ion-segment-button>
<ion-segment-button value="javascript">
<ion-label>Javascript</ion-label>
</ion-segment-button>
</ion-segment>
```
```javascript

View File

@ -9,7 +9,7 @@ If `value` is set on the `<ion-select>`, the selected option will be chosen base
## Interfaces
By default, select uses the [AlertController API](../../alert/AlertController) to open up the overlay of options in an alert. The interface can be changed to use the [ActionSheetController API](../../action-sheet/ActionSheetController) or [PopoverController API](../../popover/PopoverController) by passing `action-sheet` or `popover`, respectively, to the `interface` property. Read on to the other sections for the limitations of the different interfaces.
By default, select uses the [AlertController API](../alert-controller) to open up the overlay of options in an alert. The interface can be changed to use the [ActionSheetController API](../action-sheet-controller) or [PopoverController API](../popover-controller) by passing `action-sheet` or `popover`, respectively, to the `interface` property. Read on to the other sections for the limitations of the different interfaces.
## Single Selection
@ -33,7 +33,7 @@ The `action-sheet` and `popover` interfaces do not have an `OK` button, clicking
## Interface Options
Since select uses the alert, action sheet and popover interfaces, options can be passed to these components through the `interfaceOptions` property. This can be used to pass a custom header, subheader, css class, and more. See the [AlertController API docs](../../alert/AlertController/#create), [ActionSheetController API docs](../../action-sheet/ActionSheetController/#create), and [PopoverController API docs](../../popover/PopoverController/#create) for the properties that each interface accepts.
Since select uses the alert, action sheet and popover interfaces, options can be passed to these components through the `interfaceOptions` property. This can be used to pass a custom header, subheader, css class, and more. See the [AlertController API docs](../alert-controller), [ActionSheetController API docs](../action-sheet-controller), and [PopoverController API docs](../popover-controller) for the properties that each interface accepts.
<!-- Auto Generated Below -->

View File

@ -133,8 +133,21 @@ export class Select implements ComponentInterface {
@Listen('ionSelectOptionDidUnload')
async selectOptionChanged() {
await this.loadOptions();
if (this.didInit) {
this.updateOptions();
/**
* In the event that options
* are not loaded at component load
* this ensures that any value that is
* set is properly rendered once
* options have been loaded
*/
if (this.value !== undefined) {
this.el.forceUpdate();
}
}
}

View File

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

View File

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="UTF-8">
<title>Select - Async</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link href="../../../../../css/core.css" rel="stylesheet">
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet">
<script src="../../../../../scripts/testing/scripts.js"></script>
<script src="../../../../../dist/ionic.js"></script>
</head>
<body>
<ion-select id="animals" placeholder="Select One"></ion-select>
<script>
let select = document.getElementById('animals');
const options = ['bird', 'dog', 'shark', 'lizard'];
setTimeout(() => {
options.forEach(option => {
let o = document.createElement('ion-select-option');
o.value = option;
o.textContent = option;
select.appendChild(o);
});
select.value = options[0];
}, 500);
</script>
</body>
</html>

View File

@ -12,6 +12,11 @@
</head>
<body>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tristique ipsum ipsum, eget hendrerit erat gravida vitae. Cras condimentum aliquam diam faucibus facilisis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Suspendisse potenti. Duis libero quam, varius ac quam et, pulvinar pretium libero. Suspendisse mollis eros a vehicula pellentesque. Sed viverra eros vel lorem lacinia, lobortis congue dolor dignissim. In congue tincidunt massa, sit amet elementum turpis eleifend in. Nullam laoreet condimentum pharetra. Donec cursus viverra eros nec lacinia. Sed dapibus nulla vel augue efficitur tincidunt. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Fusce suscipit auctor sem et eleifend. Nullam vitae magna ex. Quisque dolor arcu, congue in nisi eu, ullamcorper tincidunt sapien. Praesent sed molestie ante, vitae tincidunt odio.</p>
<p>Duis quis rhoncus libero, vitae mollis tortor. Phasellus mollis tellus in auctor ullamcorper. Vivamus eget sagittis arcu, sed egestas dolor. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer mi sapien, pharetra ut sapien vulputate, congue dictum libero. Integer dapibus, arcu at ullamcorper tempus, nulla dolor vestibulum arcu, sit amet laoreet libero leo eu turpis. Nulla varius maximus molestie.</p>
<p>Phasellus interdum sem ut viverra bibendum. Vivamus vel turpis arcu. Maecenas ultricies pretium dolor id blandit. In nibh sapien, tristique quis purus vitae, placerat sollicitudin ante. Suspendisse venenatis libero rutrum odio ultricies blandit. Proin a fringilla sem. Etiam pretium metus sem, eu lacinia tellus blandit id.</p>
<p>Vestibulum aliquam sapien elementum hendrerit viverra. Vivamus vulputate ligula id dui accumsan, at pulvinar mauris lobortis. Integer a ultrices nulla. Cras ultricies sollicitudin erat. Nam nec dolor a enim vestibulum egestas id non dui. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer sodales libero congue magna dictum auctor. Duis vitae tellus tempor, tempus dolor semper, dictum eros. Etiam at suscipit lacus. Proin magna ipsum, pulvinar rhoncus vulputate vel, finibus nec nisi. Praesent felis neque, porttitor ac pellentesque et, mattis non lorem. Etiam et ex ultrices, posuere purus id, vestibulum massa.</p>
<ion-select id="gender" placeholder="Select One">
<ion-select-option value="f">Female</ion-select-option>
<ion-select-option value="m">Male</ion-select-option>
@ -24,7 +29,8 @@
<ion-select-option value="red">Red</ion-select-option>
</ion-select>
<ion-select id="gaming" ok-text="Okay" cancel-text="Dismiss">
<ion-select id="gaming" interface="popover" value="popover" ok-text="Okay" cancel-text="Dismiss">
<ion-select-option value="popover">Popover</ion-select-option>
<ion-select-option value="nes">NES</ion-select-option>
<ion-select-option value="n64">Nintendo64</ion-select-option>
<ion-select-option value="ps">PlayStation</ion-select-option>

View File

@ -1,7 +1,7 @@
# ion-slides
The Slides component is a multi-section container. Each section can be swiped
or dragged between. It contains any number of [Slide](../Slide) components.
or dragged between. It contains any number of [Slide](../slide) components.
Adopted from Swiper.js:

View File

@ -1,6 +1,5 @@
@import "./tab-bar";
@import "../../themes/ionic.globals.ios";
@import "../tab-button/tab-button.ios.vars";
@import "./tab-bar.ios.vars";
// iOS Tabs
// --------------------------------------------------
@ -20,6 +19,16 @@
// --------------------------------------------------
:host(.tab-bar-translucent) {
background-color: #{current-color(base, .8)};
backdrop-filter: saturate(210%) blur(20px);
--background: #{$tab-bar-ios-translucent-background-color};
backdrop-filter: $tab-bar-ios-translucent-filter;
}
// iOS Translucent Tab bar with Color
:host(.ion-color.tab-bar-translucent) {
background: #{current-color(base, $tab-bar-ios-translucent-background-color-alpha)};
}
// iOS Translucent Tab bar button
:host(.tab-bar-translucent) ::slotted(ion-tab-button) {
background: transparent;
}

View File

@ -0,0 +1,14 @@
@import "../../themes/ionic.globals.ios";
@import "../tab-button/tab-button.ios.vars";
// iOS Tab Bar
// --------------------------------------------------
/// @prop - Alpha of translucent tab bar background color
$tab-bar-ios-translucent-background-color-alpha: .8 !default;
/// @prop - Translucent tab bar background color
$tab-bar-ios-translucent-background-color: rgba($background-color-rgb, $tab-bar-ios-translucent-background-color-alpha) !default;
/// @prop - Filter of the translucent tab bar background color
$tab-bar-ios-translucent-filter: saturate(210%) blur(20px) !default;

View File

@ -12,3 +12,7 @@
height: 56px;
}
:host(.tab-bar-translucent) ::slotted(ion-tab-button) {
background: transparent;
}

View File

@ -146,6 +146,44 @@
<ion-icon name="calendar"></ion-icon>
</ion-tab-button>
</ion-tab-bar>
<!-- Translucent -->
<ion-tab-bar translucent>
<ion-tab-button tab="1">
<ion-icon name="heart"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="2">
<ion-icon name="musical-note"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="3">
<ion-icon name="today"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="4">
<ion-icon name="calendar"></ion-icon>
</ion-tab-button>
</ion-tab-bar>
<!-- Translucent / Custom Color -->
<ion-tab-bar translucent color="dark">
<ion-tab-button tab="1">
<ion-icon name="heart"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="2">
<ion-icon name="musical-note"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="3">
<ion-icon name="today"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="4">
<ion-icon name="calendar"></ion-icon>
</ion-tab-button>
</ion-tab-bar>
<style>
body {

View File

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

View File

@ -0,0 +1,213 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="UTF-8">
<title>Tab Bar - Spec</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<script src="../../../../../scripts/testing/scripts.js"></script>
<script src="../../../../../dist/ionic.js"></script>
<link rel="stylesheet" href="../../../../../css/ionic.bundle.css">
<link rel="stylesheet" href="../../../../../scripts/testing/styles.css">
</head>
<body>
<!-- Default -->
<ion-tab-bar translucent selected-tab="1">
<ion-tab-button tab="1">
<ion-label>Recents</ion-label>
</ion-tab-button>
<ion-tab-button tab="2">
<ion-label>Favorites</ion-label>
<ion-badge>6</ion-badge>
</ion-tab-button>
<ion-tab-button tab="3">
<ion-label>Settings</ion-label>
</ion-tab-button>
</ion-tab-bar>
<!-- Badges -->
<ion-tab-bar translucent selected-tab="1">
<ion-tab-button tab="1">
<ion-icon name="heart"></ion-icon>
<ion-label>Item One Max</ion-label>
<ion-badge color="danger"></ion-badge>
</ion-tab-button>
<ion-tab-button tab="2">
<ion-icon name="musical-note"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="3">
<ion-icon name="today"></ion-icon>
<ion-badge color="danger">88</ion-badge>
</ion-tab-button>
<ion-tab-button tab="4">
<ion-icon name="calendar"></ion-icon>
<ion-badge color="danger">888+</ion-badge>
</ion-tab-button>
</ion-tab-bar>
<ion-tab-bar translucent selected-tab="1">
<ion-tab-button tab="1">
<ion-icon name="musical-note"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="2" layout="icon-bottom">
<ion-icon name="heart"></ion-icon>
<ion-label>Item One Max</ion-label>
<ion-badge color="danger"></ion-badge>
</ion-tab-button>
<ion-tab-button tab="3">
<ion-icon name="today"></ion-icon>
<ion-badge color="danger">88</ion-badge>
</ion-tab-button>
<ion-tab-button tab="4">
<ion-icon name="calendar"></ion-icon>
<ion-badge color="danger">888+</ion-badge>
</ion-tab-button>
</ion-tab-bar>
<ion-tab-bar translucent selected-tab="1">
<ion-tab-button tab="1">
<ion-icon name="heart"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="2">
<ion-icon name="musical-note"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="3">
<ion-icon name="today"></ion-icon>
</ion-tab-button>
</ion-tab-bar>
<ion-tab-bar translucent selected-tab="1">
<ion-tab-button tab="1">
<ion-icon name="musical-note"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="2" layout="icon-bottom">
<ion-icon name="heart"></ion-icon>
<ion-label>Item One Max</ion-label>
<ion-badge color="danger">88</ion-badge>
</ion-tab-button>
<ion-tab-button tab="3">
<ion-icon name="today"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="4">
<ion-icon name="calendar"></ion-icon>
</ion-tab-button>
</ion-tab-bar>
<!-- Custom Height -->
<ion-tab-bar translucent color="danger" selected-tab="3" class="custom-height">
<ion-tab-button tab="1">
<ion-icon name="heart"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="2">
<ion-icon name="musical-note"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="3">
<ion-icon name="today"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="4">
<ion-icon name="calendar"></ion-icon>
</ion-tab-button>
</ion-tab-bar>
<!-- Custom Height / Alignment -->
<ion-tab-bar translucent color="tertiary" selected-tab="3" class="custom-height custom-top">
<ion-tab-button tab="1">
<ion-icon name="heart"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="2">
<ion-icon name="musical-note"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="3">
<ion-icon name="today"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="4">
<ion-icon name="calendar"></ion-icon>
</ion-tab-button>
</ion-tab-bar>
<!-- Translucent -->
<ion-tab-bar translucent>
<ion-tab-button tab="1">
<ion-icon name="heart"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="2">
<ion-icon name="musical-note"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="3">
<ion-icon name="today"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="4">
<ion-icon name="calendar"></ion-icon>
</ion-tab-button>
</ion-tab-bar>
<!-- Translucent / Custom Color -->
<ion-tab-bar translucent class="custom-background">
<ion-tab-button tab="1">
<ion-icon name="heart"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="2">
<ion-icon name="musical-note"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="3">
<ion-icon name="today"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="4">
<ion-icon name="calendar"></ion-icon>
</ion-tab-button>
</ion-tab-bar>
<style>
body {
background: linear-gradient(
to right, orange , yellow, green, cyan, blue, violet
);
}
ion-tab-bar {
margin-bottom: 5px;
}
.custom-height {
height: 80px;
}
.custom-top ion-tab-button {
justify-content: start;
}
.custom-background {
--background: rgba(124, 243, 217, 0.6);
}
</style>
</body>
</html>

View File

@ -217,6 +217,15 @@ Type: `Promise<boolean>`
## Slots
| Slot | Description |
| ---------- | --------------------------------------------------------------------- |
| | Content is placed between the named slots if provided without a slot. |
| `"bottom"` | Content is placed at the bottom of the screen. |
| `"top"` | Content is placed at the top of the screen. |
----------------------------------------------
*Built with [StencilJS](https://stenciljs.com/)*

View File

@ -2,6 +2,11 @@ import { Component, Element, Event, EventEmitter, Listen, Method, Prop, State }
import { Config, NavOutlet, RouteID, RouteWrite, TabButtonClickEventDetail } from '../../interface';
/**
* @slot - Content is placed between the named slots if provided without a slot.
* @slot top - Content is placed at the top of the screen.
* @slot bottom - Content is placed at the bottom of the screen.
*/
@Component({
tag: 'ion-tabs',
styleUrl: 'tabs.scss',

View File

@ -351,6 +351,17 @@ In `md` mode, the `<ion-header>` will receive a box-shadow on the bottom, and th
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
## Slots
| Slot | Description |
| ------------- | -------------------------------------------------------------------------------------------------------- |
| | Content is placed between the named slots if provided without a slot. |
| `"end"` | Content is placed to the left of the toolbar text in LTR, and to the right in RTL. |
| `"primary"` | Content is placed to the right of the toolbar text in `ios` mode, and to the far right in `md` mode. |
| `"secondary"` | Content is placed to the left of the toolbar text in `ios` mode, and directly to the right in `md` mode. |
| `"start"` | Content is placed to the left of the toolbar text in LTR, and to the right in RTL. |
## CSS Custom Properties
| Name | Description |

View File

@ -3,6 +3,13 @@ import { Component, ComponentInterface, Element, Listen, Prop } from '@stencil/c
import { Color, Config, CssClassMap, Mode, StyleEventDetail } from '../../interface';
import { createColorClasses } from '../../utils/theme';
/**
* @slot - Content is placed between the named slots if provided without a slot.
* @slot start - Content is placed to the left of the toolbar text in LTR, and to the right in RTL.
* @slot secondary - Content is placed to the left of the toolbar text in `ios` mode, and directly to the right in `md` mode.
* @slot primary - Content is placed to the right of the toolbar text in `ios` mode, and to the far right in `md` mode.
* @slot end - Content is placed to the left of the toolbar text in LTR, and to the right in RTL.
*/
@Component({
tag: 'ion-toolbar',
styleUrls: {

View File

@ -83,7 +83,7 @@ scrolling. In order to better control images, Ionic provides `<ion-img>`
to manage HTTP requests and image rendering. While scrolling through items
quickly, `<ion-img>` knows when and when not to make requests, when and
when not to render images, and only loads the images that are viewable
after scrolling. [Read more about `ion-img`.](../../img/Img/)
after scrolling. [Read more about `ion-img`.](../img)
It's also important for app developers to ensure image sizes are locked in,
and after images have fully loaded they do not change size and affect any
@ -132,7 +132,7 @@ dimensions are measured correctly.
#### iOS Cordova WKWebView
When deploying to iOS with Cordova, it's highly recommended to use the
[WKWebView plugin](http://blog.ionic.io/cordova-ios-performance-improvements-drop-in-speed-with-wkwebview/)
[WKWebView plugin](https://blog.ionicframework.com/cordova-ios-performance-improvements-drop-in-speed-with-wkwebview/)
in order to take advantage of iOS's higher performing webview. Additionally,
WKWebView is superior at scrolling efficiently in comparison to the older
UIWebView.

View File

@ -168,10 +168,10 @@ export interface IonicConfig {
// PRIVATE configs
keyboardHeight?: number;
inputShims?: boolean;
scrollPadding?: string;
inputBlurring?: string;
scrollPadding?: boolean;
inputBlurring?: boolean;
scrollAssist?: boolean;
hideCaretOnScroll?: string;
hideCaretOnScroll?: boolean;
// INTERNAL configs
persistConfig?: boolean;

View File

@ -11,6 +11,7 @@ export const PLATFORMS_MAP = {
'electron': isElectron,
'pwa': isPWA,
'mobile': isMobile,
'mobileweb': isMobileWeb,
'desktop': isDesktop,
'hybrid': isHybrid
};
@ -37,6 +38,10 @@ export function setupPlatforms(win: any) {
return platforms;
}
function isMobileWeb(win: Window): boolean {
return isMobile(win) && !isHybrid(win);
}
function detectPlatforms(win: Window): string[] {
return Object.keys(PLATFORMS_MAP).filter(p => (PLATFORMS_MAP as any)[p](win));
}
@ -104,10 +109,10 @@ function isElectron(win: Window): boolean {
}
function isPWA(win: Window): boolean {
return win.matchMedia('(display-mode: standalone)').matches;
return win.matchMedia('(display-mode: standalone)').matches || (win.navigator as any).standalone;
}
function testUserAgent(win: Window, expr: RegExp) {
export function testUserAgent(win: Window, expr: RegExp) {
return expr.test(win.navigator.userAgent);
}

View File

@ -0,0 +1,121 @@
import { testUserAgent, getPlatforms, isPlatform } from '../platform';
enum PlatformConfiguration {
AndroidTablet = {
navigator: {
userAgent: 'Mozilla/5.0 (Linux; Android 7.0; Pixel C Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/52.0.2743.98 Safari/537.36'
},
innerWidth: 800,
innerHeight: 1200
},
Capacitor = {
Capacitor: {
isNative: true
}
},
Cordova = {
cordova: true
},
DesktopSafari = {
navigator: {
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/601.3.9 (KHTML, like Gecko) Version/9.0.2 Safari/601.3.9'
},
innerWidth: 1920,
innerHeight: 1080
},
iPhone = {
navigator: {
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1'
},
innerWidth: 375,
innerHeight: 812
}
}
describe('Platform Tests', () => {
/**
* The `window` object is not reset
* after each test, so we need to do
* that manually otherwise tests will
* interefere with each other
*/
let sharedWindow;
beforeEach(() => {
sharedWindow = Object.create(window);
});
describe('testUserAgent()', () => {
it('should return true when testing if user agent is an iPhone', () => {
configureBrowser(sharedWindow, PlatformConfiguration.iPhone);
expect(testUserAgent(sharedWindow, /iPhone/)).toEqual(true);
})
it('should return false when testing if user agent is an iPad', () => {
configureBrowser(sharedWindow, PlatformConfiguration.iPhone);
expect(testUserAgent(sharedWindow, /iPad/)).toEqual(false);
})
it('should return false when testing if user agent is an Android', () => {
configureBrowser(sharedWindow, PlatformConfiguration.iPhone);
expect(testUserAgent(sharedWindow, /android|sink/i)).toEqual(false);
})
it('should return true when testing if user agent is an Android', () => {
configureBrowser(sharedWindow, PlatformConfiguration.AndroidTablet);
expect(testUserAgent(sharedWindow, /android|sink/i)).toEqual(true);
})
});
describe('getPlatforms()', () => {
it('should contain "desktop" platform', () => {
configureBrowser(sharedWindow, PlatformConfiguration.DesktopSafari);
expect(getPlatforms(sharedWindow)).toContain('desktop');
});
it('should contain "android" and "tablet" platforms', () => {
configureBrowser(sharedWindow, PlatformConfiguration.AndroidTablet);
const platforms = getPlatforms(sharedWindow);
expect(platforms).toContain('android');
expect(platforms).toContain('tablet');
})
it('should contain "capacitor" platform', () => {
configureBrowser(sharedWindow, PlatformConfiguration.Capacitor);
expect(getPlatforms(sharedWindow)).toContain('capacitor');
})
});
describe('isPlatform()', () => {
it('should return true for "capacitor" and "hybrid" in a Capacitor app', () => {
configureBrowser(sharedWindow, PlatformConfiguration.Capacitor);
expect(isPlatform(sharedWindow, 'capacitor')).toEqual(true);
expect(isPlatform(sharedWindow, 'hybrid')).toEqual(true);
});
it('should return false for "capacitor" on desktop safari', () => {
configureBrowser(sharedWindow, PlatformConfiguration.DesktopSafari);
expect(isPlatform(sharedWindow, 'capacitor')).toEqual(false);
});
it('should return true for "android" and "tablet" on an android tablet', () => {
configureBrowser(sharedWindow, PlatformConfiguration.AndroidTablet);
expect(isPlatform(sharedWindow, 'android')).toEqual(true);
expect(isPlatform(sharedWindow, 'tablet')).toEqual(true);
});
it('should return true for "cordova" and "hybrid" in a Cordova app', () => {
configureBrowser(sharedWindow, PlatformConfiguration.Cordova);
expect(isPlatform(sharedWindow, 'cordova')).toEqual(true);
expect(isPlatform(sharedWindow, 'hybrid')).toEqual(true);
});
})
});
function configureBrowser(win: Window, config: PlatformConfiguration): void {
for (let attributeKey in config) {
win[attributeKey] = config[attributeKey];
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@ionic/docs",
"version": "4.0.0",
"version": "4.0.2",
"description": "Pre-packaged API documentation for the Ionic docs.",
"main": "core.json",
"files": [

View File

@ -6,7 +6,7 @@ To get started simply install `@ionic/react` and `@ionic/core` with npm into you
and to use TypeScript for the best experience.
We are currently working on providing more detailed documentation on usage but please refer to our example application for now.
If you would like to see a example app of the implementation please go to our [react conference app](https://github.com/ionic-team/ionic-react-conference-app)
If you would like to see an example app of the implementation please go to our [react conference app](https://github.com/ionic-team/ionic-react-conference-app)
```ts

View File

@ -1,6 +1,6 @@
{
"name": "@ionic/react",
"version": "0.0.3",
"version": "0.0.4",
"description": "React specific wrapper for @ionic/core",
"keywords": [
"ionic",
@ -46,7 +46,7 @@
"np": "^3.1.0"
},
"dependencies": {
"@ionic/core": "4.0.0-rc.2"
"@ionic/core": "4.0.1"
},
"peerDependencies": {
"react": "^16.7.0",

View File

@ -1,6 +1,6 @@
import { Components } from '@ionic/core';
import { createOverlayComponent } from './createOverlayComponent';
import { Omit } from './types';
import { Omit } from '../types';
export type ModalOptions = Omit<Components.IonModalAttributes, 'component' | 'componentProps'> & {
children: React.ReactNode;

View File

@ -1,6 +1,6 @@
import { Components } from '@ionic/core';
import { createOverlayComponent } from './createOverlayComponent';
import { Omit } from './types';
import { Omit } from '../types';
export type PopoverOptions = Omit<Components.IonPopoverAttributes, 'component' | 'componentProps'> & {
children: React.ReactNode;

View File

@ -1,7 +1,7 @@
import React from 'react';
import { attachEventProps } from './utils'
import { ensureElementInBody, dashToPascalCase } from './utils';
import { OverlayComponentElement, OverlayControllerComponentElement } from './types';
import { OverlayComponentElement, OverlayControllerComponentElement } from '../types';
export function createControllerComponent<T extends object, E extends OverlayComponentElement, C extends OverlayControllerComponentElement<E>>(tagName: string, controllerTagName: string) {
const displayName = dashToPascalCase(tagName);

View File

@ -2,7 +2,7 @@ import React from 'react';
import ReactDOM from 'react-dom';
import { attachEventProps } from './utils'
import { ensureElementInBody, dashToPascalCase } from './utils';
import { OverlayComponentElement, OverlayControllerComponentElement } from './types';
import { OverlayComponentElement, OverlayControllerComponentElement } from '../types';
export function createOverlayComponent<T extends object, E extends OverlayComponentElement, C extends OverlayControllerComponentElement<E>>(tagName: string, controllerTagName: string) {
const displayName = dashToPascalCase(tagName);

View File

@ -64,7 +64,11 @@ class IonTabBar extends Component<Props, State> {
onTabButtonClick = (e: CustomEvent<{ href: string, selected: boolean, tab: string }>) => {
this.props.history.push(e.detail.href);
const targetUrl = (this.state.activeTab === e.detail.tab) ?
this.state.tabs[e.detail.tab].originalHref :
this.state.tabs[e.detail.tab].currentHref;
this.props.history.push(targetUrl);
}
renderChild = (activeTab: string) => (child: React.ReactElement<Components.IonTabButtonAttributes & { onIonTabButtonClick: (e: CustomEvent) => void }>) => {

View File

@ -1,17 +1,32 @@
/**
* Checks if an event is supported in the current execution environment.
* @license Modernizr 3.0.0pre (Custom Build) | MIT
*/
function isCoveredByReact(eventNameSuffix: string) {
const eventName = 'on' + eventNameSuffix;
let isSupported = eventName in document;
if (!isSupported) {
const element = document.createElement('div');
element.setAttribute(eventName, 'return;');
isSupported = typeof (<any>element)[eventName] === 'function';
}
return isSupported;
}
function syncEvent(node: Element, eventName: string, newEventHandler: (e: Event) => any) {
const eventNameLc = eventName[0].toLowerCase() + eventName.substring(1);
const eventStore = (node as any).__events || ((node as any).__events = {});
const oldEventHandler = eventStore[eventNameLc];
const oldEventHandler = eventStore[eventName];
// Remove old listener so they don't double up.
if (oldEventHandler) {
node.removeEventListener(eventNameLc, oldEventHandler);
node.removeEventListener(eventName, oldEventHandler);
}
// Bind new listener.
if (newEventHandler) {
node.addEventListener(eventNameLc, eventStore[eventNameLc] = function handler(e: Event) {
node.addEventListener(eventName, eventStore[eventName] = function handler(e: Event) {
newEventHandler.call(this, e);
});
}
@ -35,7 +50,12 @@ export function attachEventProps<E extends HTMLElement>(node: E, props: any) {
}
if (name.indexOf('on') === 0 && name[2] === name[2].toUpperCase()) {
syncEvent(node, name.substring(2), props[name]);
const eventName = name.substring(2);
const eventNameLc = eventName[0].toLowerCase() + eventName.substring(1);
if (!isCoveredByReact(eventNameLc)) {
syncEvent(node, eventNameLc, props[name]);
}
} else {
(node as any)[name] = props[name];
}

View File

@ -1,26 +1,5 @@
import { addIcons } from 'ionicons';
import { ICON_PATHS } from 'ionicons/icons';
import { IonicConfig } from '@ionic/core';
import { defineCustomElements } from '@ionic/core/loader';
export * from './components';
export interface IonicGlobal {
config?: any;
ael?: (elm: any, eventName: string, cb: (ev: Event) => void, opts: any) => void;
raf?: (ts: number) => void;
rel?: (elm: any, eventName: string, cb: (ev: Event) => void, opts: any) => void;
}
export * from './types';
export interface IonicWindow extends Window {
Ionic: IonicGlobal;
}
export function registerIonic(config: IonicConfig = {}) {
const win: IonicWindow = window as any;
const Ionic = (win.Ionic = win.Ionic || {});
addIcons(ICON_PATHS);
Ionic.config = config;
defineCustomElements(window);
}
export * from './register';

14
react/src/register.ts Normal file
View File

@ -0,0 +1,14 @@
import { addIcons } from 'ionicons';
import { ICON_PATHS } from 'ionicons/icons';
import { IonicConfig } from '@ionic/core';
import { defineCustomElements } from '@ionic/core/loader';
import { IonicWindow } from './types';
export function registerIonic(config: IonicConfig = {}) {
const win: IonicWindow = window as any;
const Ionic = (win.Ionic = win.Ionic || {});
addIcons(ICON_PATHS);
Ionic.config = config;
defineCustomElements(window);
}

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