mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-15 17:42:15 +08:00
feat(react): add react hooks to control overlay components (#22484)
This commit is contained in:
@ -155,6 +155,59 @@ async function presentActionSheet() {
|
|||||||
### React
|
### React
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
|
/* Using with useIonActionSheet Hook */
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
IonButton,
|
||||||
|
IonContent,
|
||||||
|
IonPage,
|
||||||
|
useIonActionSheet,
|
||||||
|
} from '@ionic/react';
|
||||||
|
|
||||||
|
const ActionSheetExample: React.FC = () => {
|
||||||
|
const [present, dismiss] = useIonActionSheet();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IonPage>
|
||||||
|
<IonContent>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() =>
|
||||||
|
present({
|
||||||
|
buttons: [{ text: 'Ok' }, { text: 'Cancel' }],
|
||||||
|
header: 'Action Sheet'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Show ActionSheet
|
||||||
|
</IonButton>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() =>
|
||||||
|
present([{ text: 'Ok' }, { text: 'Cancel' }], 'Action Sheet')
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Show ActionSheet using params
|
||||||
|
</IonButton>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() => {
|
||||||
|
present([{ text: 'Ok' }, { text: 'Cancel' }], 'Action Sheet');
|
||||||
|
setTimeout(dismiss, 3000);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Show ActionSheet, hide after 3 seconds
|
||||||
|
</IonButton>
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
/* Using with IonActionSheet Component */
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { IonActionSheet, IonContent, IonButton } from '@ionic/react';
|
import { IonActionSheet, IonContent, IonButton } from '@ionic/react';
|
||||||
import { trash, share, caretForwardCircle, heart, close } from 'ionicons/icons';
|
import { trash, share, caretForwardCircle, heart, close } from 'ionicons/icons';
|
||||||
|
@ -1,4 +1,57 @@
|
|||||||
```tsx
|
```tsx
|
||||||
|
/* Using with useIonActionSheet Hook */
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
IonButton,
|
||||||
|
IonContent,
|
||||||
|
IonPage,
|
||||||
|
useIonActionSheet,
|
||||||
|
} from '@ionic/react';
|
||||||
|
|
||||||
|
const ActionSheetExample: React.FC = () => {
|
||||||
|
const [present, dismiss] = useIonActionSheet();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IonPage>
|
||||||
|
<IonContent>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() =>
|
||||||
|
present({
|
||||||
|
buttons: [{ text: 'Ok' }, { text: 'Cancel' }],
|
||||||
|
header: 'Action Sheet'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Show ActionSheet
|
||||||
|
</IonButton>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() =>
|
||||||
|
present([{ text: 'Ok' }, { text: 'Cancel' }], 'Action Sheet')
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Show ActionSheet using params
|
||||||
|
</IonButton>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() => {
|
||||||
|
present([{ text: 'Ok' }, { text: 'Cancel' }], 'Action Sheet');
|
||||||
|
setTimeout(dismiss, 3000);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Show ActionSheet, hide after 3 seconds
|
||||||
|
</IonButton>
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
/* Using with IonActionSheet Component */
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { IonActionSheet, IonContent, IonButton } from '@ionic/react';
|
import { IonActionSheet, IonContent, IonButton } from '@ionic/react';
|
||||||
import { trash, share, caretForwardCircle, heart, close } from 'ionicons/icons';
|
import { trash, share, caretForwardCircle, heart, close } from 'ionicons/icons';
|
||||||
|
@ -588,6 +588,48 @@ function presentAlertCheckbox() {
|
|||||||
### React
|
### React
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
|
/* Using with useIonAlert Hook */
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { IonButton, IonContent, IonPage, useIonAlert } from '@ionic/react';
|
||||||
|
|
||||||
|
const AlertExample: React.FC = () => {
|
||||||
|
const [present] = useIonAlert();
|
||||||
|
return (
|
||||||
|
<IonPage>
|
||||||
|
<IonContent fullscreen>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() =>
|
||||||
|
present({
|
||||||
|
cssClass: 'my-css',
|
||||||
|
header: 'Alert',
|
||||||
|
message: 'alert from hook',
|
||||||
|
buttons: [
|
||||||
|
'Cancel',
|
||||||
|
{ text: 'Ok', handler: (d) => console.log('ok pressed') },
|
||||||
|
],
|
||||||
|
onDidDismiss: (e) => console.log('did dismiss'),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Show Alert
|
||||||
|
</IonButton>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() => present('hello with params', [{ text: 'Ok' }])}
|
||||||
|
>
|
||||||
|
Show Alert using params
|
||||||
|
</IonButton>
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
/* Using with IonAlert Component */
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { IonAlert, IonButton, IonContent } from '@ionic/react';
|
import { IonAlert, IonButton, IonContent } from '@ionic/react';
|
||||||
|
|
||||||
|
@ -1,4 +1,46 @@
|
|||||||
```tsx
|
```tsx
|
||||||
|
/* Using with useIonAlert Hook */
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { IonButton, IonContent, IonPage, useIonAlert } from '@ionic/react';
|
||||||
|
|
||||||
|
const AlertExample: React.FC = () => {
|
||||||
|
const [present] = useIonAlert();
|
||||||
|
return (
|
||||||
|
<IonPage>
|
||||||
|
<IonContent fullscreen>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() =>
|
||||||
|
present({
|
||||||
|
cssClass: 'my-css',
|
||||||
|
header: 'Alert',
|
||||||
|
message: 'alert from hook',
|
||||||
|
buttons: [
|
||||||
|
'Cancel',
|
||||||
|
{ text: 'Ok', handler: (d) => console.log('ok pressed') },
|
||||||
|
],
|
||||||
|
onDidDismiss: (e) => console.log('did dismiss'),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Show Alert
|
||||||
|
</IonButton>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() => present('hello with params', [{ text: 'Ok' }])}
|
||||||
|
>
|
||||||
|
Show Alert using params
|
||||||
|
</IonButton>
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
/* Using with IonAlert Component */
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { IonAlert, IonButton, IonContent } from '@ionic/react';
|
import { IonAlert, IonButton, IonContent } from '@ionic/react';
|
||||||
|
|
||||||
|
@ -131,6 +131,43 @@ async function presentLoadingWithOptions() {
|
|||||||
### React
|
### React
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
|
/* Using with useIonLoading Hook */
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { IonButton, IonContent, IonPage, useIonLoading } from '@ionic/react';
|
||||||
|
|
||||||
|
interface LoadingProps {}
|
||||||
|
|
||||||
|
const LoadingExample: React.FC<LoadingProps> = () => {
|
||||||
|
const [present] = useIonLoading();
|
||||||
|
return (
|
||||||
|
<IonPage>
|
||||||
|
<IonContent>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() =>
|
||||||
|
present({
|
||||||
|
duration: 3000,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Show Loading
|
||||||
|
</IonButton>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() => present('Loading', 2000, 'dots')}
|
||||||
|
>
|
||||||
|
Show Loading using params
|
||||||
|
</IonButton>
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
/* Using with IonLoading Component */
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { IonLoading, IonButton, IonContent } from '@ionic/react';
|
import { IonLoading, IonButton, IonContent } from '@ionic/react';
|
||||||
|
|
||||||
|
@ -1,4 +1,41 @@
|
|||||||
```tsx
|
```tsx
|
||||||
|
/* Using with useIonLoading Hook */
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { IonButton, IonContent, IonPage, useIonLoading } from '@ionic/react';
|
||||||
|
|
||||||
|
interface LoadingProps {}
|
||||||
|
|
||||||
|
const LoadingExample: React.FC<LoadingProps> = () => {
|
||||||
|
const [present] = useIonLoading();
|
||||||
|
return (
|
||||||
|
<IonPage>
|
||||||
|
<IonContent>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() =>
|
||||||
|
present({
|
||||||
|
duration: 3000,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Show Loading
|
||||||
|
</IonButton>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() => present('Loading', 2000, 'dots')}
|
||||||
|
>
|
||||||
|
Show Loading using params
|
||||||
|
</IonButton>
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
/* Using with IonLoading Component */
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { IonLoading, IonButton, IonContent } from '@ionic/react';
|
import { IonLoading, IonButton, IonContent } from '@ionic/react';
|
||||||
|
|
||||||
|
@ -332,6 +332,70 @@ modalElement.presentingElement = await modalController.getTop(); // Get the top-
|
|||||||
### React
|
### React
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
|
/* Using with useIonModal Hook */
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { IonButton, IonContent, IonPage, useIonModal } from '@ionic/react';
|
||||||
|
|
||||||
|
const Body: React.FC<{
|
||||||
|
count: number;
|
||||||
|
onDismiss: () => void;
|
||||||
|
onIncrement: () => void;
|
||||||
|
}> = ({ count, onDismiss, onIncrement }) => (
|
||||||
|
<div>
|
||||||
|
count: {count}
|
||||||
|
<IonButton expand="block" onClick={() => onIncrement()}>
|
||||||
|
Increment Count
|
||||||
|
</IonButton>
|
||||||
|
<IonButton expand="block" onClick={() => onDismiss()}>
|
||||||
|
Close
|
||||||
|
</IonButton>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const ModalExample: React.FC = () => {
|
||||||
|
const [count, setCount] = useState(0);
|
||||||
|
|
||||||
|
const handleIncrement = () => {
|
||||||
|
setCount(count + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDismiss = () => {
|
||||||
|
dismiss();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* First parameter is the component to show, second is the props to pass
|
||||||
|
*/
|
||||||
|
const [present, dismiss] = useIonModal(Body, {
|
||||||
|
count,
|
||||||
|
onDismiss: handleDismiss,
|
||||||
|
onIncrement: handleIncrement,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IonPage>
|
||||||
|
<IonContent fullscreen>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() => {
|
||||||
|
present({
|
||||||
|
cssClass: 'my-class',
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Show Modal
|
||||||
|
</IonButton>
|
||||||
|
<div>Count: {count}</div>
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
/* Using with IonModal Component */
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { IonModal, IonButton, IonContent } from '@ionic/react';
|
import { IonModal, IonButton, IonContent } from '@ionic/react';
|
||||||
|
|
||||||
|
@ -1,4 +1,68 @@
|
|||||||
```tsx
|
```tsx
|
||||||
|
/* Using with useIonModal Hook */
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { IonButton, IonContent, IonPage, useIonModal } from '@ionic/react';
|
||||||
|
|
||||||
|
const Body: React.FC<{
|
||||||
|
count: number;
|
||||||
|
onDismiss: () => void;
|
||||||
|
onIncrement: () => void;
|
||||||
|
}> = ({ count, onDismiss, onIncrement }) => (
|
||||||
|
<div>
|
||||||
|
count: {count}
|
||||||
|
<IonButton expand="block" onClick={() => onIncrement()}>
|
||||||
|
Increment Count
|
||||||
|
</IonButton>
|
||||||
|
<IonButton expand="block" onClick={() => onDismiss()}>
|
||||||
|
Close
|
||||||
|
</IonButton>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const ModalExample: React.FC = () => {
|
||||||
|
const [count, setCount] = useState(0);
|
||||||
|
|
||||||
|
const handleIncrement = () => {
|
||||||
|
setCount(count + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDismiss = () => {
|
||||||
|
dismiss();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* First parameter is the component to show, second is the props to pass
|
||||||
|
*/
|
||||||
|
const [present, dismiss] = useIonModal(Body, {
|
||||||
|
count,
|
||||||
|
onDismiss: handleDismiss,
|
||||||
|
onIncrement: handleIncrement,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IonPage>
|
||||||
|
<IonContent fullscreen>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() => {
|
||||||
|
present({
|
||||||
|
cssClass: 'my-class',
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Show Modal
|
||||||
|
</IonButton>
|
||||||
|
<div>Count: {count}</div>
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
/* Using with IonModal Component */
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { IonModal, IonButton, IonContent } from '@ionic/react';
|
import { IonModal, IonButton, IonContent } from '@ionic/react';
|
||||||
|
|
||||||
|
@ -7,6 +7,95 @@ A Picker is a dialog that displays a row of buttons and columns underneath. It a
|
|||||||
<!-- Auto Generated Below -->
|
<!-- Auto Generated Below -->
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### React
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
/* Using with useIonPicker Hook */
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { IonButton, IonContent, IonPage, useIonPicker } from '@ionic/react';
|
||||||
|
|
||||||
|
const PickerExample: React.FC = () => {
|
||||||
|
const [present] = useIonPicker();
|
||||||
|
const [value, setValue] = useState('');
|
||||||
|
return (
|
||||||
|
<IonPage>
|
||||||
|
<IonContent>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() =>
|
||||||
|
present({
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
text: 'Confirm',
|
||||||
|
handler: (selected) => {
|
||||||
|
setValue(selected.animal.value)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'animal',
|
||||||
|
options: [
|
||||||
|
{ text: 'Dog', value: 'dog' },
|
||||||
|
{ text: 'Cat', value: 'cat' },
|
||||||
|
{ text: 'Bird', value: 'bird' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Show Picker
|
||||||
|
</IonButton>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() =>
|
||||||
|
present(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: 'animal',
|
||||||
|
options: [
|
||||||
|
{ text: 'Dog', value: 'dog' },
|
||||||
|
{ text: 'Cat', value: 'cat' },
|
||||||
|
{ text: 'Bird', value: 'bird' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'vehicle',
|
||||||
|
options: [
|
||||||
|
{ text: 'Car', value: 'car' },
|
||||||
|
{ text: 'Truck', value: 'truck' },
|
||||||
|
{ text: 'Bike', value: 'bike' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
text: 'Confirm',
|
||||||
|
handler: (selected) => {
|
||||||
|
setValue(`${selected.animal.value}, ${selected.vehicle.value}`)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Show Picker using params
|
||||||
|
</IonButton>
|
||||||
|
{value && (
|
||||||
|
<div>Selected Value: {value}</div>
|
||||||
|
)}
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
## Properties
|
||||||
|
|
||||||
| Property | Attribute | Description | Type | Default |
|
| Property | Attribute | Description | Type | Default |
|
||||||
|
82
core/src/components/picker/usage/react.md
Normal file
82
core/src/components/picker/usage/react.md
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
```tsx
|
||||||
|
/* Using with useIonPicker Hook */
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { IonButton, IonContent, IonPage, useIonPicker } from '@ionic/react';
|
||||||
|
|
||||||
|
const PickerExample: React.FC = () => {
|
||||||
|
const [present] = useIonPicker();
|
||||||
|
const [value, setValue] = useState('');
|
||||||
|
return (
|
||||||
|
<IonPage>
|
||||||
|
<IonContent>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() =>
|
||||||
|
present({
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
text: 'Confirm',
|
||||||
|
handler: (selected) => {
|
||||||
|
setValue(selected.animal.value)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'animal',
|
||||||
|
options: [
|
||||||
|
{ text: 'Dog', value: 'dog' },
|
||||||
|
{ text: 'Cat', value: 'cat' },
|
||||||
|
{ text: 'Bird', value: 'bird' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Show Picker
|
||||||
|
</IonButton>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() =>
|
||||||
|
present(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: 'animal',
|
||||||
|
options: [
|
||||||
|
{ text: 'Dog', value: 'dog' },
|
||||||
|
{ text: 'Cat', value: 'cat' },
|
||||||
|
{ text: 'Bird', value: 'bird' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'vehicle',
|
||||||
|
options: [
|
||||||
|
{ text: 'Car', value: 'car' },
|
||||||
|
{ text: 'Truck', value: 'truck' },
|
||||||
|
{ text: 'Bike', value: 'bike' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
text: 'Confirm',
|
||||||
|
handler: (selected) => {
|
||||||
|
setValue(`${selected.animal.value}, ${selected.vehicle.value}`)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Show Picker using params
|
||||||
|
</IonButton>
|
||||||
|
{value && (
|
||||||
|
<div>Selected Value: {value}</div>
|
||||||
|
)}
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
@ -114,6 +114,59 @@ function presentPopover(ev) {
|
|||||||
### React
|
### React
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
|
/* Using with useIonPopover Hook */
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
IonButton,
|
||||||
|
IonContent,
|
||||||
|
IonItem,
|
||||||
|
IonList,
|
||||||
|
IonListHeader,
|
||||||
|
IonPage,
|
||||||
|
useIonPopover,
|
||||||
|
} from '@ionic/react';
|
||||||
|
|
||||||
|
const PopoverList: React.FC<{
|
||||||
|
onHide: () => void;
|
||||||
|
}> = ({ onHide }) => (
|
||||||
|
<IonList>
|
||||||
|
<IonListHeader>Ionic</IonListHeader>
|
||||||
|
<IonItem button>Learn Ionic</IonItem>
|
||||||
|
<IonItem button>Documentation</IonItem>
|
||||||
|
<IonItem button>Showcase</IonItem>
|
||||||
|
<IonItem button>GitHub Repo</IonItem>
|
||||||
|
<IonItem lines="none" detail={false} button onClick={onHide}>
|
||||||
|
Close
|
||||||
|
</IonItem>
|
||||||
|
</IonList>
|
||||||
|
);
|
||||||
|
|
||||||
|
const PopoverExample: React.FC = () => {
|
||||||
|
const [present, dismiss] = useIonPopover(PopoverList, { onHide: () => dismiss() });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IonPage>
|
||||||
|
<IonContent>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={(e) =>
|
||||||
|
present({
|
||||||
|
event: e.nativeEvent,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Show Popover
|
||||||
|
</IonButton>
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
/* Using with IonPopover Component */
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { IonPopover, IonButton } from '@ionic/react';
|
import { IonPopover, IonButton } from '@ionic/react';
|
||||||
|
|
||||||
|
@ -1,4 +1,57 @@
|
|||||||
```tsx
|
```tsx
|
||||||
|
/* Using with useIonPopover Hook */
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
IonButton,
|
||||||
|
IonContent,
|
||||||
|
IonItem,
|
||||||
|
IonList,
|
||||||
|
IonListHeader,
|
||||||
|
IonPage,
|
||||||
|
useIonPopover,
|
||||||
|
} from '@ionic/react';
|
||||||
|
|
||||||
|
const PopoverList: React.FC<{
|
||||||
|
onHide: () => void;
|
||||||
|
}> = ({ onHide }) => (
|
||||||
|
<IonList>
|
||||||
|
<IonListHeader>Ionic</IonListHeader>
|
||||||
|
<IonItem button>Learn Ionic</IonItem>
|
||||||
|
<IonItem button>Documentation</IonItem>
|
||||||
|
<IonItem button>Showcase</IonItem>
|
||||||
|
<IonItem button>GitHub Repo</IonItem>
|
||||||
|
<IonItem lines="none" detail={false} button onClick={onHide}>
|
||||||
|
Close
|
||||||
|
</IonItem>
|
||||||
|
</IonList>
|
||||||
|
);
|
||||||
|
|
||||||
|
const PopoverExample: React.FC = () => {
|
||||||
|
const [present, dismiss] = useIonPopover(PopoverList, { onHide: () => dismiss() });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IonPage>
|
||||||
|
<IonContent>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={(e) =>
|
||||||
|
present({
|
||||||
|
event: e.nativeEvent,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Show Popover
|
||||||
|
</IonButton>
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
/* Using with IonPopover Component */
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { IonPopover, IonButton } from '@ionic/react';
|
import { IonPopover, IonButton } from '@ionic/react';
|
||||||
|
|
||||||
|
@ -111,6 +111,48 @@ async function presentToastWithOptions() {
|
|||||||
### React
|
### React
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
|
/* Using the useIonToast Hook */
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { IonButton, IonContent, IonPage, useIonToast } from '@ionic/react';
|
||||||
|
|
||||||
|
const ToastExample: React.FC = () => {
|
||||||
|
const [present, dismiss] = useIonToast();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IonPage>
|
||||||
|
<IonContent>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() =>
|
||||||
|
present({
|
||||||
|
buttons: [{ text: 'hide', handler: () => dismiss() }],
|
||||||
|
message: 'toast from hook, click hide to dismiss',
|
||||||
|
onDidDismiss: () => console.log('dismissed'),
|
||||||
|
onWillDismiss: () => console.log('will dismiss'),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Show Toast
|
||||||
|
</IonButton>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() => present('hello from hook', 3000)}
|
||||||
|
>
|
||||||
|
Show Toast using params, closes in 3 secs
|
||||||
|
</IonButton>
|
||||||
|
<IonButton expand="block" onClick={dismiss}>
|
||||||
|
Hide Toast
|
||||||
|
</IonButton>
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
/* Using the IonToast Component */
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { IonToast, IonContent, IonButton } from '@ionic/react';
|
import { IonToast, IonContent, IonButton } from '@ionic/react';
|
||||||
|
|
||||||
|
@ -1,4 +1,46 @@
|
|||||||
```tsx
|
```tsx
|
||||||
|
/* Using the useIonToast Hook */
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { IonButton, IonContent, IonPage, useIonToast } from '@ionic/react';
|
||||||
|
|
||||||
|
const ToastExample: React.FC = () => {
|
||||||
|
const [present, dismiss] = useIonToast();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IonPage>
|
||||||
|
<IonContent>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() =>
|
||||||
|
present({
|
||||||
|
buttons: [{ text: 'hide', handler: () => dismiss() }],
|
||||||
|
message: 'toast from hook, click hide to dismiss',
|
||||||
|
onDidDismiss: () => console.log('dismissed'),
|
||||||
|
onWillDismiss: () => console.log('will dismiss'),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Show Toast
|
||||||
|
</IonButton>
|
||||||
|
<IonButton
|
||||||
|
expand="block"
|
||||||
|
onClick={() => present('hello from hook', 3000)}
|
||||||
|
>
|
||||||
|
Show Toast using params, closes in 3 secs
|
||||||
|
</IonButton>
|
||||||
|
<IonButton expand="block" onClick={dismiss}>
|
||||||
|
Hide Toast
|
||||||
|
</IonButton>
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
/* Using the IonToast Component */
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { IonToast, IonContent, IonButton } from '@ionic/react';
|
import { IonToast, IonContent, IonButton } from '@ionic/react';
|
||||||
|
|
||||||
|
@ -69,6 +69,15 @@ export * from './hrefprops';
|
|||||||
// Ionic Animations
|
// Ionic Animations
|
||||||
export { CreateAnimation } from './CreateAnimation';
|
export { CreateAnimation } from './CreateAnimation';
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
export { useIonActionSheet, UseIonActionSheetResult } from '../hooks/useIonActionSheet';
|
||||||
|
export { useIonAlert, UseIonAlertResult } from '../hooks/useIonAlert';
|
||||||
|
export { useIonToast, UseIonToastResult } from '../hooks/useIonToast';
|
||||||
|
export { useIonModal, UseIonModalResult } from '../hooks/useIonModal';
|
||||||
|
export { useIonPopover, UseIonPopoverResult } from '../hooks/useIonPopover';
|
||||||
|
export { useIonPicker, UseIonPickerResult } from '../hooks/useIonPicker';
|
||||||
|
export { useIonLoading, UseIonLoadingResult } from '../hooks/useIonLoading';
|
||||||
|
|
||||||
// Icons that are used by internal components
|
// Icons that are used by internal components
|
||||||
addIcons({
|
addIcons({
|
||||||
'arrow-back-sharp': arrowBackSharp,
|
'arrow-back-sharp': arrowBackSharp,
|
||||||
|
8
packages/react/src/hooks/HookOverlayOptions.ts
Normal file
8
packages/react/src/hooks/HookOverlayOptions.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { OverlayEventDetail } from '@ionic/core';
|
||||||
|
|
||||||
|
export interface HookOverlayOptions {
|
||||||
|
onDidDismiss?: (event: CustomEvent<OverlayEventDetail>) => void;
|
||||||
|
onDidPresent?: (event: CustomEvent<OverlayEventDetail>) => void;
|
||||||
|
onWillDismiss?: (event: CustomEvent<OverlayEventDetail>) => void;
|
||||||
|
onWillPresent?: (event: CustomEvent<OverlayEventDetail>) => void;
|
||||||
|
}
|
83
packages/react/src/hooks/useController.ts
Normal file
83
packages/react/src/hooks/useController.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import { OverlayEventDetail } from '@ionic/core';
|
||||||
|
import { useMemo, useRef } from 'react';
|
||||||
|
|
||||||
|
import { attachProps } from '../components/utils';
|
||||||
|
|
||||||
|
import { HookOverlayOptions } from './HookOverlayOptions';
|
||||||
|
|
||||||
|
interface OverlayBase extends HTMLElement {
|
||||||
|
present: () => Promise<void>;
|
||||||
|
dismiss: (data?: any, role?: string | undefined) => Promise<boolean>;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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);
|
||||||
|
}
|
||||||
|
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,
|
||||||
|
dismiss,
|
||||||
|
};
|
||||||
|
}
|
53
packages/react/src/hooks/useIonActionSheet.ts
Normal file
53
packages/react/src/hooks/useIonActionSheet.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { ActionSheetButton, ActionSheetOptions, actionSheetController } from '@ionic/core';
|
||||||
|
|
||||||
|
import { HookOverlayOptions } from './HookOverlayOptions';
|
||||||
|
import { useController } from './useController';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A hook for presenting/dismissing an IonActionSheet component
|
||||||
|
* @returns Returns the present and dismiss methods in an array
|
||||||
|
*/
|
||||||
|
export function useIonActionSheet(): UseIonActionSheetResult {
|
||||||
|
const controller = useController<ActionSheetOptions, HTMLIonActionSheetElement>(
|
||||||
|
'IonActionSheet',
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
present,
|
||||||
|
controller.dismiss
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UseIonActionSheetResult = [
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Presents the action sheet
|
||||||
|
* @param buttons An array of buttons for the action sheet
|
||||||
|
* @param header Optional - Title for the action sheet
|
||||||
|
*/
|
||||||
|
(buttons: ActionSheetButton[], header?: string | undefined): void;
|
||||||
|
/**
|
||||||
|
* Presents the action sheet
|
||||||
|
* @param options The options to pass to the IonActionSheet
|
||||||
|
*/
|
||||||
|
(options: ActionSheetOptions & HookOverlayOptions): void;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Dismisses the action sheet
|
||||||
|
*/
|
||||||
|
() => void
|
||||||
|
];
|
53
packages/react/src/hooks/useIonAlert.ts
Normal file
53
packages/react/src/hooks/useIonAlert.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { AlertButton, AlertOptions, alertController } from '@ionic/core';
|
||||||
|
|
||||||
|
import { HookOverlayOptions } from './HookOverlayOptions';
|
||||||
|
import { useController } from './useController';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A hook for presenting/dismissing an IonAlert component
|
||||||
|
* @returns Returns the present and dismiss methods in an array
|
||||||
|
*/
|
||||||
|
export function useIonAlert(): UseIonAlertResult {
|
||||||
|
const controller = useController<AlertOptions, HTMLIonAlertElement>(
|
||||||
|
'IonAlert',
|
||||||
|
alertController
|
||||||
|
);
|
||||||
|
|
||||||
|
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
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UseIonAlertResult = [
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Presents the alert
|
||||||
|
* @param message The main message to be displayed in the alert
|
||||||
|
* @param buttons Optional - Array of buttons to be added to the alert
|
||||||
|
*/
|
||||||
|
(message: string, buttons?: AlertButton[]): void;
|
||||||
|
/**
|
||||||
|
* Presents the alert
|
||||||
|
* @param options The options to pass to the IonAlert
|
||||||
|
*/
|
||||||
|
(options: AlertOptions & HookOverlayOptions): void;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Dismisses the alert
|
||||||
|
*/
|
||||||
|
() => void
|
||||||
|
];
|
60
packages/react/src/hooks/useIonLoading.tsx
Normal file
60
packages/react/src/hooks/useIonLoading.tsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import { LoadingOptions, SpinnerTypes, loadingController } from '@ionic/core';
|
||||||
|
|
||||||
|
import { HookOverlayOptions } from './HookOverlayOptions';
|
||||||
|
import { useController } from './useController';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A hook for presenting/dismissing an IonLoading component
|
||||||
|
* @returns Returns the present and dismiss methods in an array
|
||||||
|
*/
|
||||||
|
export function useIonLoading(): UseIonLoadingResult {
|
||||||
|
const controller = useController<LoadingOptions, HTMLIonLoadingElement>(
|
||||||
|
'IonLoading',
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [present, controller.dismiss];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UseIonLoadingResult = [
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Presents the loading indicator
|
||||||
|
* @param message Optional - Text content to display in the loading indicator, defaults to blank string
|
||||||
|
* @param duration Optional - Number of milliseconds to wait before dismissing the loading indicator
|
||||||
|
* @param spinner Optional - The name of the spinner to display, defaults to "lines"
|
||||||
|
*/
|
||||||
|
(message?: string, duration?: number, spinner?: SpinnerTypes): void;
|
||||||
|
/**
|
||||||
|
* Presents the loading indicator
|
||||||
|
* @param options The options to pass to the IonLoading
|
||||||
|
*/
|
||||||
|
(options: LoadingOptions & HookOverlayOptions): void;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Dismisses the loading indicator
|
||||||
|
*/
|
||||||
|
() => void
|
||||||
|
];
|
36
packages/react/src/hooks/useIonModal.ts
Normal file
36
packages/react/src/hooks/useIonModal.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { ModalOptions, modalController } from '@ionic/core';
|
||||||
|
|
||||||
|
import { HookOverlayOptions } from './HookOverlayOptions';
|
||||||
|
import { ReactComponentOrElement, useOverlay } from './useOverlay';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A hook for presenting/dismissing an IonModal component
|
||||||
|
* @param component The component that the modal will show. Can be a React Component, a functional component, or a JSX Element
|
||||||
|
* @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 {
|
||||||
|
const controller = useOverlay<ModalOptions, HTMLIonModalElement>(
|
||||||
|
'IonModal',
|
||||||
|
modalController,
|
||||||
|
component,
|
||||||
|
componentProps
|
||||||
|
);
|
||||||
|
|
||||||
|
function present(options: Omit<ModalOptions, 'component' | 'componentProps'> & HookOverlayOptions = {}) {
|
||||||
|
controller.present(options as any);
|
||||||
|
};
|
||||||
|
|
||||||
|
return [
|
||||||
|
present,
|
||||||
|
controller.dismiss
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UseIonModalResult = [
|
||||||
|
(options?: Omit<ModalOptions, 'component' | 'componentProps'> & HookOverlayOptions) => void,
|
||||||
|
/**
|
||||||
|
* Dismisses the modal
|
||||||
|
*/
|
||||||
|
() => void
|
||||||
|
];
|
58
packages/react/src/hooks/useIonPicker.tsx
Normal file
58
packages/react/src/hooks/useIonPicker.tsx
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import {
|
||||||
|
PickerButton,
|
||||||
|
PickerColumn,
|
||||||
|
PickerOptions,
|
||||||
|
pickerController,
|
||||||
|
} from '@ionic/core';
|
||||||
|
|
||||||
|
import { HookOverlayOptions } from './HookOverlayOptions';
|
||||||
|
import { useController } from './useController';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A hook for presenting/dismissing an IonPicker component
|
||||||
|
* @returns Returns the present and dismiss methods in an array
|
||||||
|
*/
|
||||||
|
export function useIonPicker(): UseIonPickerResult {
|
||||||
|
const controller = useController<PickerOptions, HTMLIonPickerElement>(
|
||||||
|
'IonPicker',
|
||||||
|
pickerController
|
||||||
|
);
|
||||||
|
|
||||||
|
function present(columns: PickerColumn[], buttons?: PickerButton[]): void;
|
||||||
|
function present(options: PickerOptions & HookOverlayOptions): void;
|
||||||
|
function present(
|
||||||
|
columnsOrOptions: PickerColumn[] | (PickerOptions & HookOverlayOptions),
|
||||||
|
buttons?: PickerButton[]
|
||||||
|
) {
|
||||||
|
if (Array.isArray(columnsOrOptions)) {
|
||||||
|
controller.present({
|
||||||
|
columns: columnsOrOptions,
|
||||||
|
buttons: buttons ?? [{ text: 'Ok' }],
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
controller.present(columnsOrOptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [present, controller.dismiss];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UseIonPickerResult = [
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Presents the picker
|
||||||
|
* @param columns Array of columns to be displayed in the picker.
|
||||||
|
* @param buttons Optional - Array of buttons to be displayed at the top of the picker.
|
||||||
|
*/
|
||||||
|
(columns: PickerColumn[], buttons?: PickerButton[]): void;
|
||||||
|
/**
|
||||||
|
* Presents the picker
|
||||||
|
* @param options The options to pass to the IonPicker
|
||||||
|
*/
|
||||||
|
(options: PickerOptions & HookOverlayOptions): void;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Dismisses the picker
|
||||||
|
*/
|
||||||
|
() => void
|
||||||
|
];
|
36
packages/react/src/hooks/useIonPopover.ts
Normal file
36
packages/react/src/hooks/useIonPopover.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { PopoverOptions, popoverController } from '@ionic/core';
|
||||||
|
|
||||||
|
import { HookOverlayOptions } from './HookOverlayOptions';
|
||||||
|
import { ReactComponentOrElement, useOverlay } from './useOverlay';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A hook for presenting/dismissing an IonPicker component
|
||||||
|
* @param component The component that the popover will show. Can be a React Component, a functional component, or a JSX Element
|
||||||
|
* @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 useIonPopover(component: ReactComponentOrElement, componentProps?: any): UseIonPopoverResult {
|
||||||
|
const controller = useOverlay<PopoverOptions, HTMLIonPopoverElement>(
|
||||||
|
'IonPopover',
|
||||||
|
popoverController,
|
||||||
|
component,
|
||||||
|
componentProps
|
||||||
|
);
|
||||||
|
|
||||||
|
function present(options: Omit<PopoverOptions, 'component' | 'componentProps'> & HookOverlayOptions = {}) {
|
||||||
|
controller.present(options as any);
|
||||||
|
};
|
||||||
|
|
||||||
|
return [
|
||||||
|
present,
|
||||||
|
controller.dismiss
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UseIonPopoverResult = [
|
||||||
|
(options?: Omit<PopoverOptions, 'component' | 'componentProps'> & HookOverlayOptions) => void,
|
||||||
|
/**
|
||||||
|
* Dismisses the popover
|
||||||
|
*/
|
||||||
|
() => void
|
||||||
|
];
|
53
packages/react/src/hooks/useIonToast.ts
Normal file
53
packages/react/src/hooks/useIonToast.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { ToastOptions, toastController } from '@ionic/core';
|
||||||
|
|
||||||
|
import { HookOverlayOptions } from './HookOverlayOptions';
|
||||||
|
import { useController } from './useController';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A hook for presenting/dismissing an IonToast component
|
||||||
|
* @returns Returns the present and dismiss methods in an array
|
||||||
|
*/
|
||||||
|
export function useIonToast(): UseIonToastResult {
|
||||||
|
const controller = useController<ToastOptions, HTMLIonToastElement>(
|
||||||
|
'IonToast',
|
||||||
|
toastController
|
||||||
|
);
|
||||||
|
|
||||||
|
function present(message: string, duration?: number): void;
|
||||||
|
function present(options: ToastOptions & HookOverlayOptions): void;
|
||||||
|
function present(messageOrOptions: string | ToastOptions & HookOverlayOptions, duration?: number) {
|
||||||
|
if (typeof messageOrOptions === 'string') {
|
||||||
|
controller.present({
|
||||||
|
message: messageOrOptions,
|
||||||
|
duration
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
controller.present(messageOrOptions);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return [
|
||||||
|
present,
|
||||||
|
controller.dismiss
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UseIonToastResult = [
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Presents the toast
|
||||||
|
* @param message Message to be shown in the toast.
|
||||||
|
* @param duration Optional - How many milliseconds to wait before hiding the toast. By default, it will show until dismissToast() is called.
|
||||||
|
*/
|
||||||
|
(message: string, duration?: number): void;
|
||||||
|
/**
|
||||||
|
* Presents the Toast
|
||||||
|
* @param options The options to pass to the IonToast.
|
||||||
|
*/
|
||||||
|
(options: ToastOptions & HookOverlayOptions): void;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Dismisses the toast
|
||||||
|
*/
|
||||||
|
() => void
|
||||||
|
];
|
111
packages/react/src/hooks/useOverlay.ts
Normal file
111
packages/react/src/hooks/useOverlay.ts
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
import { OverlayEventDetail } from '@ionic/core';
|
||||||
|
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
|
||||||
|
import { attachProps } from '../components/utils';
|
||||||
|
|
||||||
|
import { HookOverlayOptions } from './HookOverlayOptions';
|
||||||
|
|
||||||
|
export type ReactComponentOrElement = React.ComponentClass<any, any> | React.FC<any> | JSX.Element;
|
||||||
|
|
||||||
|
interface OverlayBase extends HTMLElement {
|
||||||
|
present: () => Promise<void>;
|
||||||
|
dismiss: (data?: any, role?: string | undefined) => Promise<boolean>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useOverlay<
|
||||||
|
OptionsType,
|
||||||
|
OverlayType extends OverlayBase
|
||||||
|
>(
|
||||||
|
displayName: string,
|
||||||
|
controller: { create: (options: OptionsType) => Promise<OverlayType>; },
|
||||||
|
component: ReactComponentOrElement,
|
||||||
|
componentProps?: any
|
||||||
|
) {
|
||||||
|
const overlayRef = useRef<OverlayType>();
|
||||||
|
const containerElRef = useRef<HTMLDivElement>();
|
||||||
|
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 [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isOpen && component && containerElRef.current) {
|
||||||
|
if (React.isValidElement(component)) {
|
||||||
|
ReactDOM.render(component, containerElRef.current);
|
||||||
|
} else {
|
||||||
|
ReactDOM.render(React.createElement(component as React.ComponentClass, componentProps), containerElRef.current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [component, containerElRef.current, isOpen, componentProps]);
|
||||||
|
|
||||||
|
const present = async (options: OptionsType & HookOverlayOptions) => {
|
||||||
|
if (overlayRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
onDidDismiss,
|
||||||
|
onWillDismiss,
|
||||||
|
onDidPresent,
|
||||||
|
onWillPresent,
|
||||||
|
...rest
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
if (typeof document !== 'undefined') {
|
||||||
|
containerElRef.current = document.createElement('div');
|
||||||
|
}
|
||||||
|
|
||||||
|
overlayRef.current = await controller.create({
|
||||||
|
...(rest as any),
|
||||||
|
component: containerElRef.current
|
||||||
|
});
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
setIsOpen(true);
|
||||||
|
|
||||||
|
function handleDismiss(event: CustomEvent<OverlayEventDetail<any>>) {
|
||||||
|
if (onDidDismiss) {
|
||||||
|
onDidDismiss(event);
|
||||||
|
}
|
||||||
|
overlayRef.current = undefined;
|
||||||
|
containerElRef.current = undefined;
|
||||||
|
setIsOpen(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const dismiss = async () => {
|
||||||
|
overlayRef.current && await overlayRef.current.dismiss();
|
||||||
|
overlayRef.current = undefined;
|
||||||
|
containerElRef.current = undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
present,
|
||||||
|
dismiss,
|
||||||
|
};
|
||||||
|
}
|
Reference in New Issue
Block a user