mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-17 02:31:34 +08:00
chore(all): sync with main for beta 7
This commit is contained in:
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -4,7 +4,7 @@ title: 'bug: '
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Prequisites
|
||||
label: Prerequisites
|
||||
description: Please ensure you have completed all of the following.
|
||||
options:
|
||||
- label: I have read the [Contributing Guidelines](https://github.com/ionic-team/ionic-framework/blob/main/.github/CONTRIBUTING.md#creating-an-issue).
|
||||
|
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@ -4,7 +4,7 @@ title: 'feat: '
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Prequisites
|
||||
label: Prerequisites
|
||||
description: Please ensure you have completed all of the following.
|
||||
options:
|
||||
- label: I have read the [Contributing Guidelines](https://github.com/ionic-team/ionic-framework/blob/main/.github/CONTRIBUTING.md#creating-an-issue).
|
||||
|
25
CHANGELOG.md
25
CHANGELOG.md
@ -1,3 +1,28 @@
|
||||
## [5.8.2](https://github.com/ionic-team/ionic/compare/v5.8.1...v5.8.2) (2021-10-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **alert:** made it easier to tell if alert is scrollable in MD mode ([#23976](https://github.com/ionic-team/ionic/issues/23976)) ([a262753](https://github.com/ionic-team/ionic/commit/a26275378f10835343ad8a6cdea50303e6c10a14))
|
||||
* **angular:** use initialize function when setting up ionic angular to avoid config errors ([#24004](https://github.com/ionic-team/ionic/issues/24004)) ([f112ad4](https://github.com/ionic-team/ionic/commit/f112ad4490dc4a179dc3feab495530e14e655e5a)), closes [#22853](https://github.com/ionic-team/ionic/issues/22853)
|
||||
* **item-sliding:** closing an item can no longer be interrupted ([#23973](https://github.com/ionic-team/ionic/issues/23973)) ([3ca0419](https://github.com/ionic-team/ionic/commit/3ca04197a4186c85d04cdf04fa9cb2689ca1bbfb)), closes [#23969](https://github.com/ionic-team/ionic/issues/23969)
|
||||
* **react:** overlay hooks memorised properly to prevent re-renders ([#24010](https://github.com/ionic-team/ionic/issues/24010)) ([2c97712](https://github.com/ionic-team/ionic/commit/2c977126012ae0231d4e4fa63cc76a528bde699b)), closes [#23741](https://github.com/ionic-team/ionic/issues/23741)
|
||||
* **select-popover:** non-scrollable popovers no longer have forced overscroll ([#23972](https://github.com/ionic-team/ionic/issues/23972)) ([aa4ba89](https://github.com/ionic-team/ionic/commit/aa4ba890e9c18e8a911c5188b3e2e85433658be9)), closes [#23971](https://github.com/ionic-team/ionic/issues/23971)
|
||||
* **status-bar:** tapping status bar correctly scrolls content to top ([#24001](https://github.com/ionic-team/ionic/issues/24001)) ([25eb8cd](https://github.com/ionic-team/ionic/commit/25eb8cdf98fe455433ca6185e89d9e1223a6d3ae)), closes [#20423](https://github.com/ionic-team/ionic/issues/20423)
|
||||
|
||||
|
||||
|
||||
## [5.8.1](https://github.com/ionic-team/ionic/compare/v5.8.0...v5.8.1) (2021-09-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **angular:** select method now has correct types ([#23953](https://github.com/ionic-team/ionic/issues/23953)) ([3c1be89](https://github.com/ionic-team/ionic/commit/3c1be89112d464e77d65c875223138aaedf350cd)), closes [#23952](https://github.com/ionic-team/ionic/issues/23952)
|
||||
* **item-sliding:** item-sliding accounts for multiple ion-item elements ([#23943](https://github.com/ionic-team/ionic/issues/23943)) ([8108edd](https://github.com/ionic-team/ionic/commit/8108edd876b10834015016385dc3cd5b8f31fbfa)), closes [#19312](https://github.com/ionic-team/ionic/issues/19312)
|
||||
* **label:** only inherit color if color property is set on ion-item ([#23944](https://github.com/ionic-team/ionic/issues/23944)) ([ae1325c](https://github.com/ionic-team/ionic/commit/ae1325cee698066a71aae4e7deb953c4185c0926)), closes [#20125](https://github.com/ionic-team/ionic/issues/20125)
|
||||
|
||||
|
||||
|
||||
# [6.0.0-beta.6](https://github.com/ionic-team/ionic/compare/v6.0.0-beta.5...v6.0.0-beta.6) (2021-09-15)
|
||||
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { NgZone } from '@angular/core';
|
||||
import { initialize } from '@ionic/core';
|
||||
import { applyPolyfills, defineCustomElements } from '@ionic/core/loader';
|
||||
|
||||
import { Config } from './providers/config';
|
||||
@ -9,12 +10,11 @@ export const appInitialize = (config: Config, doc: Document, zone: NgZone) => {
|
||||
return (): any => {
|
||||
const win: IonicWindow | undefined = doc.defaultView as any;
|
||||
if (win && typeof (window as any) !== 'undefined') {
|
||||
const Ionic = win.Ionic = win.Ionic || {};
|
||||
|
||||
Ionic.config = {
|
||||
initialize({
|
||||
...config,
|
||||
_zoneGate: (h: any) => zone.run(h)
|
||||
};
|
||||
});
|
||||
|
||||
const aelFn = '__zone_symbol__addEventListener' in (doc.body as any)
|
||||
? '__zone_symbol__addEventListener'
|
||||
|
@ -87,8 +87,9 @@ export class IonTabs {
|
||||
* to the default tabRootUrl
|
||||
*/
|
||||
@HostListener('ionTabButtonClick', ['$event'])
|
||||
select(ev: CustomEvent) {
|
||||
const tab = ev.detail.tab;
|
||||
select(tabOrEvent: string | CustomEvent) {
|
||||
const isTabString = typeof tabOrEvent === 'string';
|
||||
const tab = (isTabString) ? tabOrEvent : (tabOrEvent as CustomEvent).detail.tab;
|
||||
const alreadySelected = this.outlet.getActiveStackId() === tab;
|
||||
const tabRootUrl = `${this.outlet.tabsPrefix}/${tab}`;
|
||||
|
||||
@ -98,7 +99,9 @@ export class IonTabs {
|
||||
* will respond to this event too, causing
|
||||
* the app to get directed to the wrong place.
|
||||
*/
|
||||
ev.stopPropagation();
|
||||
if (!isTabString) {
|
||||
(tabOrEvent as CustomEvent).stopPropagation();
|
||||
}
|
||||
|
||||
if (alreadySelected) {
|
||||
const activeStackId = this.outlet.getActiveStackId();
|
||||
|
@ -60,7 +60,7 @@ Notice how `IonBadge` is imported from `@ionic/core/components/ion-badge` rather
|
||||
|
||||
## How to contribute
|
||||
|
||||
[Check out the CONTRIBUTE guide](CONTRIBUTING.md)
|
||||
[Check out the CONTRIBUTE guide](/.github/CONTRIBUTING.md)
|
||||
|
||||
## Related
|
||||
|
||||
|
8
core/src/components.d.ts
vendored
8
core/src/components.d.ts
vendored
@ -2105,7 +2105,7 @@ export namespace Components {
|
||||
*/
|
||||
"pullMin": number;
|
||||
/**
|
||||
* Time it takes the refresher to to snap back to the `refreshing` state. Does not apply when the refresher content uses a spinner, enabling the native refresher.
|
||||
* Time it takes the refresher to snap back to the `refreshing` state. Does not apply when the refresher content uses a spinner, enabling the native refresher.
|
||||
*/
|
||||
"snapbackDuration": string;
|
||||
}
|
||||
@ -2199,7 +2199,7 @@ export namespace Components {
|
||||
*/
|
||||
"push": (url: string, direction?: RouterDirection, animation?: AnimationBuilder | undefined) => Promise<boolean>;
|
||||
/**
|
||||
* By default `ion-router` will match the routes at the root path ("/"). That can be changed when
|
||||
* The root path to use when matching URLs. By default, this is set to "/", but you can specify an alternate prefix for all URL paths.
|
||||
*/
|
||||
"root": string;
|
||||
/**
|
||||
@ -5777,7 +5777,7 @@ declare namespace LocalJSX {
|
||||
*/
|
||||
"pullMin"?: number;
|
||||
/**
|
||||
* Time it takes the refresher to to snap back to the `refreshing` state. Does not apply when the refresher content uses a spinner, enabling the native refresher.
|
||||
* Time it takes the refresher to snap back to the `refreshing` state. Does not apply when the refresher content uses a spinner, enabling the native refresher.
|
||||
*/
|
||||
"snapbackDuration"?: string;
|
||||
}
|
||||
@ -5867,7 +5867,7 @@ declare namespace LocalJSX {
|
||||
*/
|
||||
"onIonRouteWillChange"?: (event: CustomEvent<RouterEventDetail>) => void;
|
||||
/**
|
||||
* By default `ion-router` will match the routes at the root path ("/"). That can be changed when
|
||||
* The root path to use when matching URLs. By default, this is set to "/", but you can specify an alternate prefix for all URL paths.
|
||||
*/
|
||||
"root"?: string;
|
||||
/**
|
||||
|
@ -80,7 +80,7 @@ $alert-md-message-empty-padding-bottom: $alert-md-message-empty-padding-to
|
||||
$alert-md-message-empty-padding-start: $alert-md-message-empty-padding-end !default;
|
||||
|
||||
/// @prop - Maximum height of the alert content
|
||||
$alert-md-content-max-height: 240px !default;
|
||||
$alert-md-content-max-height: 266px !default;
|
||||
|
||||
/// @prop - Border width of the alert input
|
||||
$alert-md-input-border-width: 1px !default;
|
||||
|
@ -270,6 +270,13 @@ export class ItemSliding implements ComponentInterface {
|
||||
}
|
||||
|
||||
private onStart() {
|
||||
/**
|
||||
* We need to query for the ion-item
|
||||
* every time the gesture starts. Developers
|
||||
* may toggle ion-item elements via *ngIf.
|
||||
*/
|
||||
this.item = this.el.querySelector('ion-item');
|
||||
|
||||
// Prevent scrolling during gesture
|
||||
this.disableContentScrollY();
|
||||
|
||||
@ -387,16 +394,28 @@ export class ItemSliding implements ComponentInterface {
|
||||
? SlidingState.Start | SlidingState.SwipeStart
|
||||
: SlidingState.Start;
|
||||
} else {
|
||||
/**
|
||||
* Item sliding cannot be interrupted
|
||||
* while closing the item. If it did,
|
||||
* it would allow the item to get into an
|
||||
* inconsistent state where multiple
|
||||
* items are then open at the same time.
|
||||
*/
|
||||
if (this.gesture) {
|
||||
this.gesture.enable(false);
|
||||
}
|
||||
this.tmr = setTimeout(() => {
|
||||
this.state = SlidingState.Disabled;
|
||||
this.tmr = undefined;
|
||||
if (this.gesture) {
|
||||
this.gesture.enable(true);
|
||||
}
|
||||
}, 600) as any;
|
||||
|
||||
openSlidingItem = undefined;
|
||||
style.transform = '';
|
||||
return;
|
||||
}
|
||||
|
||||
style.transform = `translate3d(${-openAmount}px,0,0)`;
|
||||
this.ionDrag.emit({
|
||||
amount: openAmount,
|
||||
|
@ -41,6 +41,7 @@
|
||||
<ion-button expand="block" onclick="openItem('start')">Open Item Start</ion-button>
|
||||
<ion-button expand="block" onclick="openItem('end')">Open Item End</ion-button>
|
||||
<ion-button expand="block" onclick="openItemOneSide()">Open Item with only one side</ion-button>
|
||||
<ion-button expand="block" onclick="setDynaicItem()">Swap dynamic item</ion-button>
|
||||
</div>
|
||||
|
||||
<ion-list id="list">
|
||||
@ -369,6 +370,17 @@
|
||||
</ion-item-options>
|
||||
</ion-item-sliding>
|
||||
|
||||
<ion-item-sliding id="dynamic-item">
|
||||
<ion-item>
|
||||
<ion-label>Dynamic First Item</ion-label>
|
||||
</ion-item>
|
||||
<ion-item-options side="end">
|
||||
<ion-item-option color="tertiary" expandable>
|
||||
First Item Options
|
||||
</ion-item-option>
|
||||
</ion-item-options>
|
||||
</ion-item-sliding>
|
||||
|
||||
<ion-item>
|
||||
<ion-label class="ion-text-wrap">
|
||||
<h2>Normal ion-item (no sliding)</h2>
|
||||
@ -387,6 +399,20 @@
|
||||
</ion-list>
|
||||
|
||||
<script>
|
||||
const setDynaicItem = () => {
|
||||
const sliding = document.querySelector('#dynamic-item');
|
||||
sliding.innerHTML = `
|
||||
<ion-item>
|
||||
<ion-label>Dynamic Second Item</ion-label>
|
||||
</ion-item>
|
||||
<ion-item-options side="end">
|
||||
<ion-item-option color="tertiary" expandable>
|
||||
Second Item Options
|
||||
</ion-item-option>
|
||||
</ion-item-options>
|
||||
`
|
||||
}
|
||||
|
||||
var dynamicSlidingEnabled = document.getElementsByClassName('sliding-enabled');
|
||||
|
||||
// Toggle the dynamic options
|
||||
|
@ -89,11 +89,10 @@
|
||||
color: #{$item-ios-paragraph-text-color};
|
||||
}
|
||||
|
||||
:host-context(.ion-color)::slotted(p) {
|
||||
:host(.in-item-color)::slotted(p) {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
|
||||
::slotted(*) h2:last-child,
|
||||
::slotted(*) h3:last-child,
|
||||
::slotted(*) h4:last-child,
|
||||
|
@ -188,6 +188,6 @@
|
||||
color: $item-md-paragraph-text-color;
|
||||
}
|
||||
|
||||
:host-context(.ion-color)::slotted(p) {
|
||||
:host(.in-item-color)::slotted(p) {
|
||||
color: inherit;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Prop
|
||||
|
||||
import { getIonMode } from '../../global/ionic-global';
|
||||
import { Color, StyleEventDetail } from '../../interface';
|
||||
import { createColorClasses } from '../../utils/theme';
|
||||
import { createColorClasses, hostContext } from '../../utils/theme';
|
||||
|
||||
/**
|
||||
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
|
||||
@ -101,6 +101,7 @@ export class Label implements ComponentInterface {
|
||||
<Host
|
||||
class={createColorClasses(this.color, {
|
||||
[mode]: true,
|
||||
'in-item-color': hostContext('ion-item.ion-color', this.el),
|
||||
[`label-${position}`]: position !== undefined,
|
||||
[`label-no-animate`]: (this.noAnimate),
|
||||
'label-rtl': document.dir === 'rtl'
|
||||
|
10
core/src/components/label/test/color/e2e.ts
Normal file
10
core/src/components/label/test/color/e2e.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { newE2EPage } from '@stencil/core/testing';
|
||||
|
||||
test('label: color', async () => {
|
||||
const page = await newE2EPage({
|
||||
url: '/src/components/label/test/color?ionic:_testing=true'
|
||||
});
|
||||
|
||||
const compare = await page.compareScreenshot();
|
||||
expect(compare).toMatchScreenshot();
|
||||
});
|
29
core/src/components/label/test/color/index.html
Normal file
29
core/src/components/label/test/color/index.html
Normal file
@ -0,0 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Label - Color</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">
|
||||
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet">
|
||||
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet">
|
||||
<script src="../../../../../scripts/testing/scripts.js"></script>
|
||||
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
|
||||
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ion-app>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Label - Color</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content color="light">
|
||||
<ion-item>
|
||||
<ion-label>Label Text<p>This paragraph should not inherit the color from content</p></ion-label>
|
||||
</ion-item>
|
||||
</ion-content>
|
||||
</ion-app>
|
||||
</body>
|
||||
</html>
|
@ -299,7 +299,7 @@ export default defineComponent({
|
||||
| `pullFactor` | `pull-factor` | How much to multiply the pull speed by. To slow the pull animation down, pass a number less than `1`. To speed up the pull, pass a number greater than `1`. The default value is `1` which is equal to the speed of the cursor. If a negative value is passed in, the factor will be `1` instead. For example: If the value passed is `1.2` and the content is dragged by `10` pixels, instead of `10` pixels the content will be pulled by `12` pixels (an increase of 20 percent). If the value passed is `0.8`, the dragged amount will be `8` pixels, less than the amount the cursor has moved. Does not apply when the refresher content uses a spinner, enabling the native refresher. | `number` | `1` |
|
||||
| `pullMax` | `pull-max` | The maximum distance of the pull until the refresher will automatically go into the `refreshing` state. Defaults to the result of `pullMin + 60`. Does not apply when the refresher content uses a spinner, enabling the native refresher. | `number` | `this.pullMin + 60` |
|
||||
| `pullMin` | `pull-min` | The minimum distance the user must pull down until the refresher will go into the `refreshing` state. Does not apply when the refresher content uses a spinner, enabling the native refresher. | `number` | `60` |
|
||||
| `snapbackDuration` | `snapback-duration` | Time it takes the refresher to to snap back to the `refreshing` state. Does not apply when the refresher content uses a spinner, enabling the native refresher. | `string` | `'280ms'` |
|
||||
| `snapbackDuration` | `snapback-duration` | Time it takes the refresher to snap back to the `refreshing` state. Does not apply when the refresher content uses a spinner, enabling the native refresher. | `string` | `'280ms'` |
|
||||
|
||||
|
||||
## Events
|
||||
|
@ -82,7 +82,7 @@ export class Refresher implements ComponentInterface {
|
||||
@Prop() closeDuration = '280ms';
|
||||
|
||||
/**
|
||||
* Time it takes the refresher to to snap back to the `refreshing` state.
|
||||
* Time it takes the refresher to snap back to the `refreshing` state.
|
||||
* Does not apply when the refresher content uses a spinner,
|
||||
* enabling the native refresher.
|
||||
*/
|
||||
|
@ -76,7 +76,7 @@ interface RouterCustomEvent extends CustomEvent {
|
||||
|
||||
| Property | Attribute | Description | Type | Default |
|
||||
| --------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------- |
|
||||
| `root` | `root` | By default `ion-router` will match the routes at the root path ("/"). That can be changed when | `string` | `'/'` |
|
||||
| `root` | `root` | The root path to use when matching URLs. By default, this is set to "/", but you can specify an alternate prefix for all URL paths. | `string` | `'/'` |
|
||||
| `useHash` | `use-hash` | The router can work in two "modes": - With hash: `/index.html#/path/to/page` - Without hash: `/path/to/page` Using one or another might depend in the requirements of your app and/or where it's deployed. Usually "hash-less" navigation works better for SEO and it's more user friendly too, but it might requires additional server-side configuration in order to properly work. On the other side hash-navigation is much easier to deploy, it even works over the file protocol. By default, this property is `true`, change to `false` to allow hash-less URLs. | `boolean` | `true` |
|
||||
|
||||
|
||||
|
@ -25,9 +25,8 @@ export class Router implements ComponentInterface {
|
||||
@Element() el!: HTMLElement;
|
||||
|
||||
/**
|
||||
* By default `ion-router` will match the routes at the root path ("/").
|
||||
* That can be changed when
|
||||
*
|
||||
* The root path to use when matching URLs. By default, this is set to "/", but you can specify
|
||||
* an alternate prefix for all URL paths.
|
||||
*/
|
||||
@Prop() root = '/';
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
@import "./select-popover.vars";
|
||||
@import "../../themes/ionic.globals";
|
||||
|
||||
ion-list {
|
||||
@include margin($select-popover-list-margin-top, $select-popover-list-margin-end, $select-popover-list-margin-bottom, $select-popover-list-margin-start);
|
||||
:host ion-list {
|
||||
@include margin(0);
|
||||
}
|
||||
|
||||
ion-list-header,
|
||||
|
@ -1,16 +0,0 @@
|
||||
@import "../../themes/ionic.globals";
|
||||
|
||||
// Select
|
||||
// --------------------------------------------------
|
||||
|
||||
/// @prop - Margin top of the select popover list
|
||||
$select-popover-list-margin-top: -1px !default;
|
||||
|
||||
/// @prop - Margin end of the select popover list
|
||||
$select-popover-list-margin-end: 0 !default;
|
||||
|
||||
/// @prop - Margin bottom of the select popover list
|
||||
$select-popover-list-margin-bottom: -1px !default;
|
||||
|
||||
/// @prop - Margin start of the select popover list
|
||||
$select-popover-list-margin-start: 0 !default;
|
@ -102,7 +102,7 @@ You can change the background color of the toolbar with the standard title by se
|
||||
When styling the text color of the large title, you should target the large title globally as opposed to within the context of a particular page or tab, otherwise its styles will not be applied during the navigation animation.
|
||||
|
||||
```css
|
||||
ion-title.large-title {
|
||||
ion-title.title-large {
|
||||
color: purple;
|
||||
font-size: 30px;
|
||||
}
|
||||
@ -240,7 +240,7 @@ You can change the background color of the toolbar with the standard title by se
|
||||
When styling the text color of the large title, you should target the large title globally as opposed to within the context of a particular page or tab, otherwise its styles will not be applied during the navigation animation.
|
||||
|
||||
```css
|
||||
ion-title.large-title {
|
||||
ion-title.title-large {
|
||||
color: purple;
|
||||
font-size: 30px;
|
||||
}
|
||||
@ -381,7 +381,7 @@ You can change the background color of the toolbar with the standard title by se
|
||||
When styling the text color of the large title, you should target the large title globally as opposed to within the context of a particular page or tab, otherwise its styles will not be applied during the navigation animation.
|
||||
|
||||
```css
|
||||
ion-title.large-title {
|
||||
ion-title.title-large {
|
||||
color: purple;
|
||||
font-size: 30px;
|
||||
}
|
||||
@ -544,7 +544,7 @@ You can change the background color of the toolbar with the standard title by se
|
||||
When styling the text color of the large title, you should target the large title globally as opposed to within the context of a particular page or tab, otherwise its styles will not be applied during the navigation animation.
|
||||
|
||||
```css
|
||||
ion-title.large-title {
|
||||
ion-title.title-large {
|
||||
color: purple;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ You can change the background color of the toolbar with the standard title by se
|
||||
When styling the text color of the large title, you should target the large title globally as opposed to within the context of a particular page or tab, otherwise its styles will not be applied during the navigation animation.
|
||||
|
||||
```css
|
||||
ion-title.large-title {
|
||||
ion-title.title-large {
|
||||
color: purple;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ You can change the background color of the toolbar with the standard title by se
|
||||
When styling the text color of the large title, you should target the large title globally as opposed to within the context of a particular page or tab, otherwise its styles will not be applied during the navigation animation.
|
||||
|
||||
```css
|
||||
ion-title.large-title {
|
||||
ion-title.title-large {
|
||||
color: purple;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ You can change the background color of the toolbar with the standard title by se
|
||||
When styling the text color of the large title, you should target the large title globally as opposed to within the context of a particular page or tab, otherwise its styles will not be applied during the navigation animation.
|
||||
|
||||
```css
|
||||
ion-title.large-title {
|
||||
ion-title.title-large {
|
||||
color: purple;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ You can change the background color of the toolbar with the standard title by se
|
||||
When styling the text color of the large title, you should target the large title globally as opposed to within the context of a particular page or tab, otherwise its styles will not be applied during the navigation animation.
|
||||
|
||||
```css
|
||||
ion-title.large-title {
|
||||
ion-title.title-large {
|
||||
color: purple;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ You can change the background color of the toolbar with the standard title by se
|
||||
When styling the text color of the large title, you should target the large title globally as opposed to within the context of a particular page or tab, otherwise its styles will not be applied during the navigation animation.
|
||||
|
||||
```css
|
||||
ion-title.large-title {
|
||||
ion-title.title-large {
|
||||
color: purple;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
@ -15,7 +15,21 @@ export const startStatusTap = () => {
|
||||
const contentEl = el.closest('ion-content');
|
||||
if (contentEl) {
|
||||
new Promise(resolve => componentOnReady(contentEl, resolve)).then(() => {
|
||||
writeTask(() => contentEl.scrollToTop(300));
|
||||
writeTask(async () => {
|
||||
|
||||
/**
|
||||
* If scrolling and user taps status bar,
|
||||
* only calling scrollToTop is not enough
|
||||
* as engines like WebKit will jump the
|
||||
* scroll position back down and complete
|
||||
* any in-progress momentum scrolling.
|
||||
*/
|
||||
contentEl.style.setProperty('--overflow', 'hidden');
|
||||
|
||||
await contentEl.scrollToTop(300);
|
||||
|
||||
contentEl.style.removeProperty('--overflow');
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -52,6 +52,7 @@
|
||||
"@rollup/plugin-virtual": "^2.0.3",
|
||||
"@testing-library/jest-dom": "^5.11.6",
|
||||
"@testing-library/react": "^11.2.2",
|
||||
"@testing-library/react-hooks": "^7.0.1",
|
||||
"@types/jest": "^26.0.15",
|
||||
"@types/node": "^14.0.14",
|
||||
"@types/react": "16.14.0",
|
||||
|
153
packages/react/src/hooks/__tests__/hooks.spec.tsx
Normal file
153
packages/react/src/hooks/__tests__/hooks.spec.tsx
Normal file
@ -0,0 +1,153 @@
|
||||
import { alertController, modalController } from '@ionic/core';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { useController } from '../useController';
|
||||
import { useOverlay } from '../useOverlay';
|
||||
|
||||
import { useIonActionSheet } from '../useIonActionSheet';
|
||||
import type { UseIonActionSheetResult } from '../useIonActionSheet';
|
||||
import { useIonAlert } from '../useIonAlert';
|
||||
import type { UseIonAlertResult } from '../useIonAlert';
|
||||
import { useIonLoading } from '../useIonLoading';
|
||||
import type { UseIonLoadingResult } from '../useIonLoading';
|
||||
import { useIonModal } from '../useIonModal';
|
||||
import type { UseIonModalResult } from '../useIonModal';
|
||||
import { useIonPicker } from '../useIonPicker';
|
||||
import type { UseIonPickerResult } from '../useIonPicker';
|
||||
import { useIonPopover } from '../useIonPopover';
|
||||
import type { UseIonPopoverResult } from '../useIonPopover';
|
||||
import { useIonToast } from '../useIonToast';
|
||||
import type { UseIonToastResult } from '../useIonToast';
|
||||
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
|
||||
describe('useController', () => {
|
||||
it('should be memorised', () => {
|
||||
const { result, rerender } = renderHook(() =>
|
||||
useController('AlertController', alertController)
|
||||
);
|
||||
|
||||
rerender();
|
||||
|
||||
const [
|
||||
{ present: firstPresent, dismiss: firstDismiss },
|
||||
{ present: secondPresent, dismiss: secondDismiss },
|
||||
] = result.all as ReturnType<typeof useController>[];
|
||||
|
||||
expect(firstPresent).toBe(secondPresent);
|
||||
expect(firstDismiss).toBe(secondDismiss);
|
||||
});
|
||||
});
|
||||
|
||||
describe('useIonActionSheet', () => {
|
||||
it('should be memorised', () => {
|
||||
const { result, rerender } = renderHook(() => useIonActionSheet());
|
||||
|
||||
rerender();
|
||||
|
||||
const [[firstPresent, firstDismiss], [secondPresent, secondDismiss]] =
|
||||
result.all as UseIonActionSheetResult[];
|
||||
expect(firstPresent).toBe(secondPresent);
|
||||
expect(firstDismiss).toBe(secondDismiss);
|
||||
});
|
||||
});
|
||||
|
||||
describe('useIonAlert', () => {
|
||||
it('should be memorised', () => {
|
||||
const { result, rerender } = renderHook(() => useIonAlert());
|
||||
|
||||
rerender();
|
||||
|
||||
const [[firstPresent, firstDismiss], [secondPresent, secondDismiss]] =
|
||||
result.all as UseIonAlertResult[];
|
||||
expect(firstPresent).toBe(secondPresent);
|
||||
expect(firstDismiss).toBe(secondDismiss);
|
||||
});
|
||||
});
|
||||
|
||||
describe('useIonLoading', () => {
|
||||
it('should be memorised', () => {
|
||||
const { result, rerender } = renderHook(() => useIonLoading());
|
||||
|
||||
rerender();
|
||||
|
||||
const [[firstPresent, firstDismiss], [secondPresent, secondDismiss]] =
|
||||
result.all as UseIonLoadingResult[];
|
||||
expect(firstPresent).toBe(secondPresent);
|
||||
expect(firstDismiss).toBe(secondDismiss);
|
||||
});
|
||||
});
|
||||
|
||||
describe('useIonModal', () => {
|
||||
it('should be memorised', () => {
|
||||
const ModalComponent = () => <div />;
|
||||
const { result, rerender } = renderHook(() => useIonModal(ModalComponent, {}));
|
||||
|
||||
rerender();
|
||||
|
||||
const [[firstPresent, firstDismiss], [secondPresent, secondDismiss]] =
|
||||
result.all as UseIonModalResult[];
|
||||
expect(firstPresent).toBe(secondPresent);
|
||||
expect(firstDismiss).toBe(secondDismiss);
|
||||
});
|
||||
});
|
||||
|
||||
describe('useIonPicker', () => {
|
||||
it('should be memorised', () => {
|
||||
const { result, rerender } = renderHook(() => useIonPicker());
|
||||
|
||||
rerender();
|
||||
|
||||
const [[firstPresent, firstDismiss], [secondPresent, secondDismiss]] =
|
||||
result.all as UseIonPickerResult[];
|
||||
expect(firstPresent).toBe(secondPresent);
|
||||
expect(firstDismiss).toBe(secondDismiss);
|
||||
});
|
||||
});
|
||||
|
||||
describe('useIonPopover', () => {
|
||||
it('should be memorised', () => {
|
||||
const PopoverComponent = () => <div />;
|
||||
const { result, rerender } = renderHook(() => useIonPopover(PopoverComponent, {}));
|
||||
|
||||
rerender();
|
||||
|
||||
const [[firstPresent, firstDismiss], [secondPresent, secondDismiss]] =
|
||||
result.all as UseIonPopoverResult[];
|
||||
expect(firstPresent).toBe(secondPresent);
|
||||
expect(firstDismiss).toBe(secondDismiss);
|
||||
});
|
||||
});
|
||||
|
||||
describe('useIonToast', () => {
|
||||
it('should be memorised', () => {
|
||||
const { result, rerender } = renderHook(() => useIonToast());
|
||||
|
||||
rerender();
|
||||
|
||||
const [[firstPresent, firstDismiss], [secondPresent, secondDismiss]] =
|
||||
result.all as UseIonToastResult[];
|
||||
expect(firstPresent).toBe(secondPresent);
|
||||
expect(firstDismiss).toBe(secondDismiss);
|
||||
});
|
||||
});
|
||||
|
||||
describe('useOverlay', () => {
|
||||
it('should be memorised', () => {
|
||||
const OverlayComponent = () => <div />;
|
||||
const { result, rerender } = renderHook(() =>
|
||||
useOverlay('IonModal', modalController, OverlayComponent, {})
|
||||
);
|
||||
|
||||
rerender();
|
||||
|
||||
const [
|
||||
{ present: firstPresent, dismiss: firstDismiss },
|
||||
{ present: secondPresent, dismiss: secondDismiss },
|
||||
] = result.all as ReturnType<typeof useOverlay>[];
|
||||
|
||||
expect(firstPresent).toBe(secondPresent);
|
||||
expect(firstDismiss).toBe(secondDismiss);
|
||||
});
|
||||
});
|
@ -1,5 +1,5 @@
|
||||
import { OverlayEventDetail } from '@ionic/core/components';
|
||||
import { useMemo, useRef } from 'react';
|
||||
import { useCallback, useMemo, useRef } from 'react';
|
||||
|
||||
import { attachProps } from '../components/react-component-lib/utils';
|
||||
|
||||
@ -10,71 +10,53 @@ interface OverlayBase extends HTMLElement {
|
||||
dismiss: (data?: any, role?: string | undefined) => Promise<boolean>;
|
||||
}
|
||||
|
||||
export function useController<
|
||||
OptionsType,
|
||||
OverlayType extends OverlayBase
|
||||
>(
|
||||
export function useController<OptionsType, OverlayType extends OverlayBase>(
|
||||
displayName: string,
|
||||
controller: { create: (options: OptionsType) => Promise<OverlayType> }
|
||||
) {
|
||||
const overlayRef = useRef<OverlayType>();
|
||||
const didDismissEventName = useMemo(
|
||||
() => `on${displayName}DidDismiss`,
|
||||
[displayName]
|
||||
);
|
||||
const didPresentEventName = useMemo(
|
||||
() => `on${displayName}DidPresent`,
|
||||
[displayName]
|
||||
);
|
||||
const willDismissEventName = useMemo(
|
||||
() => `on${displayName}WillDismiss`,
|
||||
[displayName]
|
||||
);
|
||||
const willPresentEventName = useMemo(
|
||||
() => `on${displayName}WillPresent`,
|
||||
[displayName]
|
||||
);
|
||||
const didDismissEventName = useMemo(() => `on${displayName}DidDismiss`, [displayName]);
|
||||
const didPresentEventName = useMemo(() => `on${displayName}DidPresent`, [displayName]);
|
||||
const willDismissEventName = useMemo(() => `on${displayName}WillDismiss`, [displayName]);
|
||||
const willPresentEventName = useMemo(() => `on${displayName}WillPresent`, [displayName]);
|
||||
|
||||
const present = async (options: OptionsType & HookOverlayOptions) => {
|
||||
if (overlayRef.current) {
|
||||
return;
|
||||
}
|
||||
const {
|
||||
onDidDismiss,
|
||||
onWillDismiss,
|
||||
onDidPresent,
|
||||
onWillPresent,
|
||||
...rest
|
||||
} = options;
|
||||
|
||||
const handleDismiss = (event: CustomEvent<OverlayEventDetail<any>>) => {
|
||||
if (onDidDismiss) {
|
||||
onDidDismiss(event);
|
||||
const present = useCallback(
|
||||
async (options: OptionsType & HookOverlayOptions) => {
|
||||
if (overlayRef.current) {
|
||||
return;
|
||||
}
|
||||
const { onDidDismiss, onWillDismiss, onDidPresent, onWillPresent, ...rest } = options;
|
||||
|
||||
const handleDismiss = (event: CustomEvent<OverlayEventDetail<any>>) => {
|
||||
if (onDidDismiss) {
|
||||
onDidDismiss(event);
|
||||
}
|
||||
overlayRef.current = undefined;
|
||||
};
|
||||
|
||||
overlayRef.current = await controller.create({
|
||||
...(rest as any),
|
||||
});
|
||||
|
||||
attachProps(overlayRef.current, {
|
||||
[didDismissEventName]: handleDismiss,
|
||||
[didPresentEventName]: (e: CustomEvent) => onDidPresent && onDidPresent(e),
|
||||
[willDismissEventName]: (e: CustomEvent) => onWillDismiss && onWillDismiss(e),
|
||||
[willPresentEventName]: (e: CustomEvent) => onWillPresent && onWillPresent(e),
|
||||
});
|
||||
|
||||
overlayRef.current.present();
|
||||
},
|
||||
[controller]
|
||||
);
|
||||
|
||||
const dismiss = useCallback(
|
||||
() => async () => {
|
||||
overlayRef.current && (await overlayRef.current.dismiss());
|
||||
overlayRef.current = undefined;
|
||||
}
|
||||
|
||||
overlayRef.current = await controller.create({
|
||||
...(rest as any),
|
||||
});
|
||||
|
||||
attachProps(overlayRef.current, {
|
||||
[didDismissEventName]: handleDismiss,
|
||||
[didPresentEventName]: (e: CustomEvent) =>
|
||||
onDidPresent && onDidPresent(e),
|
||||
[willDismissEventName]: (e: CustomEvent) =>
|
||||
onWillDismiss && onWillDismiss(e),
|
||||
[willPresentEventName]: (e: CustomEvent) =>
|
||||
onWillPresent && onWillPresent(e),
|
||||
});
|
||||
|
||||
overlayRef.current.present();
|
||||
};
|
||||
|
||||
const dismiss = async () => {
|
||||
overlayRef.current && await overlayRef.current.dismiss();
|
||||
overlayRef.current = undefined;
|
||||
};
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
return {
|
||||
present,
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { ActionSheetButton, ActionSheetOptions, actionSheetController } from '@ionic/core/components';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { HookOverlayOptions } from './HookOverlayOptions';
|
||||
import { useController } from './useController';
|
||||
@ -13,23 +14,24 @@ export function useIonActionSheet(): UseIonActionSheetResult {
|
||||
actionSheetController
|
||||
);
|
||||
|
||||
function present(buttons: ActionSheetButton[], header?: string): void;
|
||||
function present(options: ActionSheetOptions & HookOverlayOptions): void;
|
||||
function present(buttonsOrOptions: ActionSheetButton[] | ActionSheetOptions & HookOverlayOptions, header?: string) {
|
||||
if (Array.isArray(buttonsOrOptions)) {
|
||||
controller.present({
|
||||
buttons: buttonsOrOptions,
|
||||
header
|
||||
});
|
||||
} else {
|
||||
controller.present(buttonsOrOptions);
|
||||
}
|
||||
}
|
||||
const present = useCallback(
|
||||
(
|
||||
buttonsOrOptions: ActionSheetButton[] | (ActionSheetOptions & HookOverlayOptions),
|
||||
header?: string
|
||||
) => {
|
||||
if (Array.isArray(buttonsOrOptions)) {
|
||||
controller.present({
|
||||
buttons: buttonsOrOptions,
|
||||
header,
|
||||
});
|
||||
} else {
|
||||
controller.present(buttonsOrOptions);
|
||||
}
|
||||
},
|
||||
[controller.present]
|
||||
);
|
||||
|
||||
return [
|
||||
present,
|
||||
controller.dismiss
|
||||
];
|
||||
return [present, controller.dismiss];
|
||||
}
|
||||
|
||||
export type UseIonActionSheetResult = [
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { AlertButton, AlertOptions, alertController } from '@ionic/core/components';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { HookOverlayOptions } from './HookOverlayOptions';
|
||||
import { useController } from './useController';
|
||||
@ -8,28 +9,23 @@ import { useController } from './useController';
|
||||
* @returns Returns the present and dismiss methods in an array
|
||||
*/
|
||||
export function useIonAlert(): UseIonAlertResult {
|
||||
const controller = useController<AlertOptions, HTMLIonAlertElement>(
|
||||
'IonAlert',
|
||||
alertController
|
||||
const controller = useController<AlertOptions, HTMLIonAlertElement>('IonAlert', alertController);
|
||||
|
||||
const present = useCallback(
|
||||
(messageOrOptions: string | (AlertOptions & HookOverlayOptions), buttons?: AlertButton[]) => {
|
||||
if (typeof messageOrOptions === 'string') {
|
||||
controller.present({
|
||||
message: messageOrOptions,
|
||||
buttons: buttons ?? [{ text: 'Ok' }],
|
||||
});
|
||||
} else {
|
||||
controller.present(messageOrOptions);
|
||||
}
|
||||
},
|
||||
[controller.present]
|
||||
);
|
||||
|
||||
function present(message: string, buttons?: AlertButton[]): void;
|
||||
function present(options: AlertOptions & HookOverlayOptions): void;
|
||||
function present(messageOrOptions: string | AlertOptions & HookOverlayOptions, buttons?: AlertButton[]) {
|
||||
if (typeof messageOrOptions === 'string') {
|
||||
controller.present({
|
||||
message: messageOrOptions,
|
||||
buttons: buttons ?? [{ text: 'Ok' }]
|
||||
});
|
||||
} else {
|
||||
controller.present(messageOrOptions);
|
||||
}
|
||||
};
|
||||
|
||||
return [
|
||||
present,
|
||||
controller.dismiss
|
||||
];
|
||||
return [present, controller.dismiss];
|
||||
}
|
||||
|
||||
export type UseIonAlertResult = [
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { LoadingOptions, SpinnerTypes, loadingController } from '@ionic/core/components';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { HookOverlayOptions } from './HookOverlayOptions';
|
||||
import { useController } from './useController';
|
||||
@ -13,27 +14,24 @@ export function useIonLoading(): UseIonLoadingResult {
|
||||
loadingController
|
||||
);
|
||||
|
||||
function present(
|
||||
message?: string,
|
||||
duration?: number,
|
||||
spinner?: SpinnerTypes
|
||||
): void;
|
||||
function present(options: LoadingOptions & HookOverlayOptions): void;
|
||||
function present(
|
||||
messageOrOptions: string | (LoadingOptions & HookOverlayOptions) = '',
|
||||
duration?: number,
|
||||
spinner?: SpinnerTypes
|
||||
) {
|
||||
if (typeof messageOrOptions === 'string') {
|
||||
controller.present({
|
||||
message: messageOrOptions,
|
||||
duration,
|
||||
spinner: spinner ?? 'lines',
|
||||
});
|
||||
} else {
|
||||
controller.present(messageOrOptions);
|
||||
}
|
||||
}
|
||||
const present = useCallback(
|
||||
(
|
||||
messageOrOptions: string | (LoadingOptions & HookOverlayOptions) = '',
|
||||
duration?: number,
|
||||
spinner?: SpinnerTypes
|
||||
) => {
|
||||
if (typeof messageOrOptions === 'string') {
|
||||
controller.present({
|
||||
message: messageOrOptions,
|
||||
duration,
|
||||
spinner: spinner ?? 'lines',
|
||||
});
|
||||
} else {
|
||||
controller.present(messageOrOptions);
|
||||
}
|
||||
},
|
||||
[controller.present]
|
||||
);
|
||||
|
||||
return [present, controller.dismiss];
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { ModalOptions, modalController } from '@ionic/core/components';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { HookOverlayOptions } from './HookOverlayOptions';
|
||||
import { ReactComponentOrElement, useOverlay } from './useOverlay';
|
||||
@ -9,7 +10,10 @@ import { ReactComponentOrElement, useOverlay } from './useOverlay';
|
||||
* @param componentProps The props that will be passed to the component, if required
|
||||
* @returns Returns the present and dismiss methods in an array
|
||||
*/
|
||||
export function useIonModal(component: ReactComponentOrElement, componentProps?: any): UseIonModalResult {
|
||||
export function useIonModal(
|
||||
component: ReactComponentOrElement,
|
||||
componentProps?: any
|
||||
): UseIonModalResult {
|
||||
const controller = useOverlay<ModalOptions, HTMLIonModalElement>(
|
||||
'IonModal',
|
||||
modalController,
|
||||
@ -17,14 +21,14 @@ export function useIonModal(component: ReactComponentOrElement, componentProps?:
|
||||
componentProps
|
||||
);
|
||||
|
||||
function present(options: Omit<ModalOptions, 'component' | 'componentProps'> & HookOverlayOptions = {}) {
|
||||
controller.present(options as any);
|
||||
};
|
||||
const present = useCallback(
|
||||
(options: Omit<ModalOptions, 'component' | 'componentProps'> & HookOverlayOptions = {}) => {
|
||||
controller.present(options as any);
|
||||
},
|
||||
[controller.present]
|
||||
);
|
||||
|
||||
return [
|
||||
present,
|
||||
controller.dismiss
|
||||
];
|
||||
return [present, controller.dismiss];
|
||||
}
|
||||
|
||||
export type UseIonModalResult = [
|
||||
|
@ -4,6 +4,7 @@ import {
|
||||
PickerOptions,
|
||||
pickerController,
|
||||
} from '@ionic/core/components';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { HookOverlayOptions } from './HookOverlayOptions';
|
||||
import { useController } from './useController';
|
||||
@ -18,12 +19,10 @@ export function useIonPicker(): UseIonPickerResult {
|
||||
pickerController
|
||||
);
|
||||
|
||||
function present(columns: PickerColumn[], buttons?: PickerButton[]): void;
|
||||
function present(options: PickerOptions & HookOverlayOptions): void;
|
||||
function present(
|
||||
const present = useCallback((
|
||||
columnsOrOptions: PickerColumn[] | (PickerOptions & HookOverlayOptions),
|
||||
buttons?: PickerButton[]
|
||||
) {
|
||||
) => {
|
||||
if (Array.isArray(columnsOrOptions)) {
|
||||
controller.present({
|
||||
columns: columnsOrOptions,
|
||||
@ -32,7 +31,7 @@ export function useIonPicker(): UseIonPickerResult {
|
||||
} else {
|
||||
controller.present(columnsOrOptions);
|
||||
}
|
||||
}
|
||||
}, [controller.present]);
|
||||
|
||||
return [present, controller.dismiss];
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { PopoverOptions, popoverController } from '@ionic/core/components';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { HookOverlayOptions } from './HookOverlayOptions';
|
||||
import { ReactComponentOrElement, useOverlay } from './useOverlay';
|
||||
@ -17,9 +18,9 @@ export function useIonPopover(component: ReactComponentOrElement, componentProps
|
||||
componentProps
|
||||
);
|
||||
|
||||
function present(options: Omit<PopoverOptions, 'component' | 'componentProps'> & HookOverlayOptions = {}) {
|
||||
const present = useCallback((options: Omit<PopoverOptions, 'component' | 'componentProps'> & HookOverlayOptions = {}) => {
|
||||
controller.present(options as any);
|
||||
};
|
||||
}, [controller.present]);
|
||||
|
||||
return [
|
||||
present,
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { ToastOptions, toastController } from '@ionic/core/components';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { HookOverlayOptions } from './HookOverlayOptions';
|
||||
import { useController } from './useController';
|
||||
@ -13,9 +14,7 @@ export function useIonToast(): UseIonToastResult {
|
||||
toastController
|
||||
);
|
||||
|
||||
function present(message: string, duration?: number): void;
|
||||
function present(options: ToastOptions & HookOverlayOptions): void;
|
||||
function present(messageOrOptions: string | ToastOptions & HookOverlayOptions, duration?: number) {
|
||||
const present = useCallback((messageOrOptions: string | ToastOptions & HookOverlayOptions, duration?: number) => {
|
||||
if (typeof messageOrOptions === 'string') {
|
||||
controller.present({
|
||||
message: messageOrOptions,
|
||||
@ -24,7 +23,7 @@ export function useIonToast(): UseIonToastResult {
|
||||
} else {
|
||||
controller.present(messageOrOptions);
|
||||
}
|
||||
};
|
||||
}, [controller.present]);
|
||||
|
||||
return [
|
||||
present,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { OverlayEventDetail } from '@ionic/core/components';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import { attachProps } from '../components/react-component-lib/utils';
|
||||
@ -52,7 +52,7 @@ export function useOverlay<
|
||||
}
|
||||
}, [component, containerElRef.current, isOpen, componentProps]);
|
||||
|
||||
const present = async (options: OptionsType & HookOverlayOptions) => {
|
||||
const present = useCallback(async (options: OptionsType & HookOverlayOptions) => {
|
||||
if (overlayRef.current) {
|
||||
return;
|
||||
}
|
||||
@ -96,13 +96,13 @@ export function useOverlay<
|
||||
containerElRef.current = undefined;
|
||||
setIsOpen(false);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
const dismiss = async () => {
|
||||
const dismiss = useCallback(async () => {
|
||||
overlayRef.current && await overlayRef.current.dismiss();
|
||||
overlayRef.current = undefined;
|
||||
containerElRef.current = undefined;
|
||||
};
|
||||
}, []);
|
||||
|
||||
return {
|
||||
present,
|
||||
|
Reference in New Issue
Block a user