remove gluestackk-ui
This commit is contained in:
409
MODAL_USAGE.md
Normal file
409
MODAL_USAGE.md
Normal file
@@ -0,0 +1,409 @@
|
||||
# Modal Component
|
||||
|
||||
Modal component tương tự như Modal của Ant Design, được tạo cho React Native/Expo.
|
||||
|
||||
## Cài đặt
|
||||
|
||||
Component này sử dụng `@expo/vector-icons` cho các icon. Đảm bảo bạn đã cài đặt:
|
||||
|
||||
```bash
|
||||
npx expo install @expo/vector-icons
|
||||
```
|
||||
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import Modal from "@/components/ui/modal";
|
||||
```
|
||||
|
||||
## Các tính năng chính
|
||||
|
||||
### 1. Basic Modal
|
||||
|
||||
```tsx
|
||||
import React, { useState } from "react";
|
||||
import { View, Text, Button } from "react-native";
|
||||
import Modal from "@/components/ui/modal";
|
||||
|
||||
export default function BasicExample() {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Button title="Open Modal" onPress={() => setOpen(true)} />
|
||||
|
||||
<Modal
|
||||
open={open}
|
||||
title="Basic Modal"
|
||||
onOk={() => {
|
||||
console.log("OK clicked");
|
||||
setOpen(false);
|
||||
}}
|
||||
onCancel={() => setOpen(false)}
|
||||
>
|
||||
<Text>Some contents...</Text>
|
||||
<Text>Some contents...</Text>
|
||||
<Text>Some contents...</Text>
|
||||
</Modal>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Async Close (với confirmLoading)
|
||||
|
||||
```tsx
|
||||
import React, { useState } from "react";
|
||||
import { View, Text, Button } from "react-native";
|
||||
import Modal from "@/components/ui/modal";
|
||||
|
||||
export default function AsyncExample() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleOk = async () => {
|
||||
setLoading(true);
|
||||
// Giả lập API call
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
setLoading(false);
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Button title="Open Modal" onPress={() => setOpen(true)} />
|
||||
|
||||
<Modal
|
||||
open={open}
|
||||
title="Async Modal"
|
||||
confirmLoading={loading}
|
||||
onOk={handleOk}
|
||||
onCancel={() => setOpen(false)}
|
||||
>
|
||||
<Text>Modal will be closed after 2 seconds when you click OK.</Text>
|
||||
</Modal>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Customized Footer
|
||||
|
||||
```tsx
|
||||
import React, { useState } from "react";
|
||||
import { View, Text, Button, TouchableOpacity, StyleSheet } from "react-native";
|
||||
import Modal from "@/components/ui/modal";
|
||||
|
||||
export default function CustomFooterExample() {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Button title="Open Modal" onPress={() => setOpen(true)} />
|
||||
|
||||
<Modal
|
||||
open={open}
|
||||
title="Custom Footer Modal"
|
||||
onCancel={() => setOpen(false)}
|
||||
footer={
|
||||
<View style={styles.customFooter}>
|
||||
<TouchableOpacity
|
||||
style={styles.customButton}
|
||||
onPress={() => setOpen(false)}
|
||||
>
|
||||
<Text style={styles.buttonText}>Return</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[styles.customButton, styles.submitButton]}
|
||||
onPress={() => {
|
||||
console.log("Submit");
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
<Text style={[styles.buttonText, styles.submitText]}>Submit</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
}
|
||||
>
|
||||
<Text>Custom footer buttons</Text>
|
||||
</Modal>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
customFooter: {
|
||||
flexDirection: "row",
|
||||
gap: 8,
|
||||
},
|
||||
customButton: {
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 8,
|
||||
borderRadius: 6,
|
||||
borderWidth: 1,
|
||||
borderColor: "#d9d9d9",
|
||||
},
|
||||
submitButton: {
|
||||
backgroundColor: "#1890ff",
|
||||
borderColor: "#1890ff",
|
||||
},
|
||||
buttonText: {
|
||||
fontSize: 14,
|
||||
color: "#000",
|
||||
},
|
||||
submitText: {
|
||||
color: "#fff",
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### 4. No Footer
|
||||
|
||||
```tsx
|
||||
<Modal
|
||||
open={open}
|
||||
title="Modal Without Footer"
|
||||
footer={null}
|
||||
onCancel={() => setOpen(false)}
|
||||
>
|
||||
<Text>Modal content without footer buttons</Text>
|
||||
</Modal>
|
||||
```
|
||||
|
||||
### 5. Centered Modal
|
||||
|
||||
```tsx
|
||||
<Modal
|
||||
open={open}
|
||||
title="Centered Modal"
|
||||
centered
|
||||
onOk={() => setOpen(false)}
|
||||
onCancel={() => setOpen(false)}
|
||||
>
|
||||
<Text>This modal is centered on the screen</Text>
|
||||
</Modal>
|
||||
```
|
||||
|
||||
### 6. Custom Width
|
||||
|
||||
```tsx
|
||||
<Modal
|
||||
open={open}
|
||||
title="Custom Width Modal"
|
||||
width={700}
|
||||
onOk={() => setOpen(false)}
|
||||
onCancel={() => setOpen(false)}
|
||||
>
|
||||
<Text>This modal has custom width</Text>
|
||||
</Modal>
|
||||
```
|
||||
|
||||
### 7. Confirm Modal với useModal Hook
|
||||
|
||||
**Đây là cách khuyến nghị sử dụng trong React Native để có context đầy đủ:**
|
||||
|
||||
```tsx
|
||||
import React from "react";
|
||||
import { View, Button } from "react-native";
|
||||
import Modal from "@/components/ui/modal";
|
||||
|
||||
export default function HookExample() {
|
||||
const [modal, contextHolder] = Modal.useModal();
|
||||
|
||||
const showConfirm = () => {
|
||||
modal.confirm({
|
||||
title: "Do you want to delete these items?",
|
||||
content:
|
||||
"When clicked the OK button, this dialog will be closed after 1 second",
|
||||
onOk: async () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
console.log("OK");
|
||||
},
|
||||
onCancel: () => {
|
||||
console.log("Cancel");
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const showInfo = () => {
|
||||
modal.info({
|
||||
title: "This is a notification message",
|
||||
content: "Some additional information...",
|
||||
});
|
||||
};
|
||||
|
||||
const showSuccess = () => {
|
||||
modal.success({
|
||||
title: "Success",
|
||||
content: "Operation completed successfully!",
|
||||
});
|
||||
};
|
||||
|
||||
const showError = () => {
|
||||
modal.error({
|
||||
title: "Error",
|
||||
content: "Something went wrong!",
|
||||
});
|
||||
};
|
||||
|
||||
const showWarning = () => {
|
||||
modal.warning({
|
||||
title: "Warning",
|
||||
content: "This is a warning message!",
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={{ padding: 20, gap: 10 }}>
|
||||
{/* contextHolder phải được đặt trong component */}
|
||||
{contextHolder}
|
||||
|
||||
<Button title="Confirm" onPress={showConfirm} />
|
||||
<Button title="Info" onPress={showInfo} />
|
||||
<Button title="Success" onPress={showSuccess} />
|
||||
<Button title="Error" onPress={showError} />
|
||||
<Button title="Warning" onPress={showWarning} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 8. Update Modal Instance
|
||||
|
||||
```tsx
|
||||
import React from "react";
|
||||
import { View, Button } from "react-native";
|
||||
import Modal from "@/components/ui/modal";
|
||||
|
||||
export default function UpdateExample() {
|
||||
const [modal, contextHolder] = Modal.useModal();
|
||||
|
||||
const showModal = () => {
|
||||
const instance = modal.success({
|
||||
title: "Loading...",
|
||||
content: "Please wait...",
|
||||
});
|
||||
|
||||
// Update after 2 seconds
|
||||
setTimeout(() => {
|
||||
instance.update({
|
||||
title: "Success!",
|
||||
content: "Operation completed successfully!",
|
||||
});
|
||||
}, 2000);
|
||||
|
||||
// Close after 4 seconds
|
||||
setTimeout(() => {
|
||||
instance.destroy();
|
||||
}, 4000);
|
||||
};
|
||||
|
||||
return (
|
||||
<View>
|
||||
{contextHolder}
|
||||
<Button title="Show Updating Modal" onPress={showModal} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Modal Props
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| --------------- | ----------------------------- | --------- | ------------------------------------------------------------ |
|
||||
| open | boolean | false | Whether the modal dialog is visible or not |
|
||||
| title | ReactNode | - | The modal dialog's title |
|
||||
| closable | boolean | true | Whether a close (x) button is visible on top right or not |
|
||||
| closeIcon | ReactNode | - | Custom close icon |
|
||||
| maskClosable | boolean | true | Whether to close the modal dialog when the mask is clicked |
|
||||
| centered | boolean | false | Centered Modal |
|
||||
| width | number \| string | 520 | Width of the modal dialog |
|
||||
| confirmLoading | boolean | false | Whether to apply loading visual effect for OK button |
|
||||
| okText | string | 'OK' | Text of the OK button |
|
||||
| cancelText | string | 'Cancel' | Text of the Cancel button |
|
||||
| okType | 'primary' \| 'default' | 'primary' | Button type of the OK button |
|
||||
| footer | ReactNode \| null | - | Footer content, set as footer={null} to hide default buttons |
|
||||
| mask | boolean | true | Whether show mask or not |
|
||||
| zIndex | number | 1000 | The z-index of the Modal |
|
||||
| onOk | (e?) => void \| Promise<void> | - | Callback when clicking OK button |
|
||||
| onCancel | (e?) => void | - | Callback when clicking cancel button or close icon |
|
||||
| afterOpenChange | (open: boolean) => void | - | Callback when animation ends |
|
||||
| afterClose | () => void | - | Callback when modal is closed completely |
|
||||
| destroyOnClose | boolean | false | Whether to unmount child components on close |
|
||||
| keyboard | boolean | true | Whether support press back button to close (Android) |
|
||||
|
||||
### Modal.useModal()
|
||||
|
||||
Khi bạn cần sử dụng Context, bạn có thể dùng `Modal.useModal()` để tạo `contextHolder` và chèn vào children. Modal được tạo bởi hooks sẽ có tất cả context nơi `contextHolder` được đặt.
|
||||
|
||||
**Returns:** `[modalMethods, contextHolder]`
|
||||
|
||||
- `modalMethods`: Object chứa các methods
|
||||
|
||||
- `info(config)`: Show info modal
|
||||
- `success(config)`: Show success modal
|
||||
- `error(config)`: Show error modal
|
||||
- `warning(config)`: Show warning modal
|
||||
- `confirm(config)`: Show confirm modal
|
||||
|
||||
- `contextHolder`: React element cần được render trong component tree
|
||||
|
||||
### Modal Methods Config
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| ---------- | -------------------------------------------------------- | --------- | ----------------------------- |
|
||||
| type | 'info' \| 'success' \| 'error' \| 'warning' \| 'confirm' | 'confirm' | Type of the modal |
|
||||
| title | ReactNode | - | Title |
|
||||
| content | ReactNode | - | Content |
|
||||
| icon | ReactNode | - | Custom icon |
|
||||
| okText | string | 'OK' | Text of the OK button |
|
||||
| cancelText | string | 'Cancel' | Text of the Cancel button |
|
||||
| onOk | (e?) => void \| Promise<void> | - | Callback when clicking OK |
|
||||
| onCancel | (e?) => void | - | Callback when clicking Cancel |
|
||||
|
||||
### Modal Instance
|
||||
|
||||
Modal instance được trả về bởi `Modal.useModal()`:
|
||||
|
||||
```tsx
|
||||
interface ModalInstance {
|
||||
destroy: () => void;
|
||||
update: (config: ConfirmModalProps) => void;
|
||||
}
|
||||
```
|
||||
|
||||
## Lưu ý
|
||||
|
||||
1. **React Native Limitations**: Các static methods như `Modal.info()`, `Modal.confirm()` gọi trực tiếp (không qua hook) không được hỗ trợ đầy đủ trong React Native do không thể render imperatively. Hãy sử dụng `Modal.useModal()` hook thay thế.
|
||||
|
||||
2. **Context Support**: Khi cần sử dụng Context (như Redux, Theme Context), bắt buộc phải dùng `Modal.useModal()` hook và đặt `contextHolder` trong component tree.
|
||||
|
||||
3. **Animation**: Modal sử dụng React Native's built-in Modal với `animationType="fade"`.
|
||||
|
||||
4. **Icons**: Component sử dụng `@expo/vector-icons` (Ionicons). Đảm bảo đã cài đặt package này.
|
||||
|
||||
5. **Keyboard**: Prop `keyboard` trong React Native chỉ hoạt động với nút back của Android (không có ESC key như web).
|
||||
|
||||
## So sánh với Ant Design Modal
|
||||
|
||||
| Feature | Ant Design (Web) | This Component (RN) |
|
||||
| --------------------------- | ---------------- | --------------------------- |
|
||||
| Basic Modal | ✅ | ✅ |
|
||||
| Centered | ✅ | ✅ |
|
||||
| Custom Footer | ✅ | ✅ |
|
||||
| Confirm Dialog | ✅ | ✅ (via useModal) |
|
||||
| Info/Success/Error/Warning | ✅ | ✅ (via useModal) |
|
||||
| Async close | ✅ | ✅ |
|
||||
| Custom width | ✅ | ✅ |
|
||||
| Mask closable | ✅ | ✅ |
|
||||
| Keyboard close | ✅ (ESC) | ✅ (Back button on Android) |
|
||||
| Static methods without hook | ✅ | ⚠️ (Limited support) |
|
||||
| useModal hook | ✅ | ✅ (Recommended) |
|
||||
| Draggable | ✅ | ❌ (Not applicable) |
|
||||
| destroyAll() | ✅ | ❌ |
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
Reference in New Issue
Block a user