@lanxuexing/vue2toast 0.0.7 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +151 -29
- package/README.zh-CN.md +168 -0
- package/dist/index.d.ts +64 -0
- package/dist/vue2toast.css +1 -0
- package/dist/vue2toast.es.js +166 -0
- package/dist/vue2toast.umd.js +1 -0
- package/package.json +57 -24
- package/.babelrc +0 -3
- package/dist/vue2toast.js +0 -947
- package/postcss.config.js +0 -5
- package/src/index.html +0 -65
- package/src/lib/index.js +0 -53
- package/src/lib/vue2toast.vue +0 -75
- package/webpack.config.js +0 -33
package/README.md
CHANGED
|
@@ -1,48 +1,170 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# vue2toast
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
A lightweight, high-performance Toast notification plugin for Vue 3, built with TypeScript and Vite.
|
|
6
6
|
|
|
7
|
+
[](https://npmjs.org/package/@lanxuexing/vue2toast)
|
|
8
|
+
[](https://github.com/lanxuexing/vue2toast/releases)
|
|
9
|
+
[](https://github.com/lanxuexing/vue2toast)
|
|
10
|
+
[](https://github.com/lanxuexing/vue2toast/stargazers)
|
|
11
|
+
[](https://npmjs.org/package/@lanxuexing/vue2toast)
|
|
12
|
+
[](https://github.com/lanxuexing/vue2toast/actions)
|
|
13
|
+
[](https://github.com/lanxuexing/vue2toast/blob/main/LICENSE)
|
|
14
|
+
[](https://vuejs.org)
|
|
15
|
+
[](https://www.typescriptlang.org/)
|
|
16
|
+
[](https://github.com/prettier/prettier)
|
|
17
|
+
[](http://makeapullrequest.com)
|
|
7
18
|
|
|
8
|
-
|
|
19
|
+
[中文版](./README.zh-CN.md) | English
|
|
9
20
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
duration | 200 | Number | The duration of the toast
|
|
13
|
-
callback | null | Number | The callback of the toast
|
|
21
|
+
## 🔗 Live Demo
|
|
22
|
+
Check out the component in action: **[https://lanxuexing.github.io/vue2toast/](https://lanxuexing.github.io/vue2toast/)**
|
|
14
23
|
|
|
15
|
-
|
|
24
|
+
</div>
|
|
16
25
|
|
|
17
|
-
|
|
26
|
+
---
|
|
18
27
|
|
|
19
|
-
|
|
28
|
+
## ✨ Features
|
|
20
29
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
30
|
+
- 🚀 **Vue 3 Optimized**: Built with `createVNode` and `render` for minimal overhead.
|
|
31
|
+
- 📐 **TypeScript Ready**: Full type definitions included.
|
|
32
|
+
- 📚 **Stackable**: Multiple toasts stack automatically without overlapping.
|
|
33
|
+
- 📱 **Responsive**: Auto-resizing width to fit content comfortably.
|
|
34
|
+
- 🎨 **Modern Design**: Clean and accessible UI with smooth animations.
|
|
35
|
+
- 🔄 **Updateable Toasts**: Update message content programmatically (e.g., for progress bars).
|
|
36
|
+
- 📦 **Lightweight**: Zero dependencies, tiny bundle size.
|
|
37
|
+
- 🛠 **Customizable**: Control duration and styling easily.
|
|
38
|
+
|
|
39
|
+
## 📦 Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install @lanxuexing/vue2toast
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 🚀 Usage
|
|
46
|
+
|
|
47
|
+
### 1. Register Plugin
|
|
48
|
+
|
|
49
|
+
Register the plugin in your main application file (`main.ts` or `main.js`).
|
|
24
50
|
|
|
25
|
-
|
|
26
|
-
|
|
51
|
+
```typescript
|
|
52
|
+
import { createApp } from 'vue';
|
|
53
|
+
import App from './App.vue';
|
|
54
|
+
import Toast from '@lanxuexing/vue2toast';
|
|
55
|
+
import '@lanxuexing/vue2toast/style.css'; // Import styles
|
|
27
56
|
|
|
28
|
-
|
|
29
|
-
|
|
57
|
+
const app = createApp(App);
|
|
58
|
+
app.use(Toast); // Installs $toast globally and provides useToast
|
|
59
|
+
app.mount('#app');
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
3. **SSR Support**: Safe for Server-Side Rendering (Nuxt, Vite SSR).
|
|
63
|
+
|
|
64
|
+
### 2. Usage in Components
|
|
65
|
+
|
|
66
|
+
You can access the toast instance via the `useToast` composable (Recommended) or the global `$toast` property.
|
|
30
67
|
|
|
31
|
-
|
|
32
|
-
this.$toast.show("Hello, Toast", {
|
|
33
|
-
duration: 500
|
|
34
|
-
});
|
|
68
|
+
**Composition API (Recommended):**
|
|
35
69
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
});
|
|
70
|
+
```typescript
|
|
71
|
+
<script setup lang="ts">
|
|
72
|
+
import { useToast } from '@lanxuexing/vue2toast';
|
|
40
73
|
|
|
74
|
+
// Best practice: Typesafe & Clean
|
|
75
|
+
const toast = useToast();
|
|
76
|
+
|
|
77
|
+
const showToast = () => {
|
|
78
|
+
toast('Hello World');
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const showLongToast = () => {
|
|
82
|
+
toast('This stays for 5 seconds', {
|
|
83
|
+
duration: 5000,
|
|
84
|
+
position: 'top',
|
|
85
|
+
style: { fontWeight: 'bold' }
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
</script>
|
|
41
89
|
```
|
|
42
90
|
|
|
43
|
-
|
|
91
|
+
**Options API:**
|
|
92
|
+
|
|
93
|
+
```javascript
|
|
94
|
+
export default {
|
|
95
|
+
methods: {
|
|
96
|
+
showToast() {
|
|
97
|
+
// Fully typed via module augmentation
|
|
98
|
+
this.$toast('Hello World');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
44
103
|
|
|
104
|
+
### 3. Updateable Toasts
|
|
105
|
+
|
|
106
|
+
You can update a toast message while it's still visible. This is perfect for loading states or countdowns.
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
const showDynamic = () => {
|
|
110
|
+
// Set duration to 0 to keep it open indefinitely (until closed manually)
|
|
111
|
+
const instance = toast('Loading... 0%', { duration: 0 });
|
|
112
|
+
|
|
113
|
+
let progress = 0;
|
|
114
|
+
const timer = setInterval(() => {
|
|
115
|
+
progress += 10;
|
|
116
|
+
instance.update(`Loading... ${progress}%`); // Update text
|
|
117
|
+
|
|
118
|
+
if (progress >= 100) {
|
|
119
|
+
clearInterval(timer);
|
|
120
|
+
instance.close(); // Close programmatically
|
|
121
|
+
toast('Done!');
|
|
122
|
+
}
|
|
123
|
+
}, 300);
|
|
124
|
+
};
|
|
45
125
|
```
|
|
46
|
-
|
|
47
|
-
|
|
126
|
+
|
|
127
|
+
### 4. Manual Close (Persistent Toast)
|
|
128
|
+
|
|
129
|
+
Set `duration` to `0` to keep the toast open indefinitely until you call the `close()` method on the returned instance.
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
const showPersist = () => {
|
|
133
|
+
const instance = toast('I will not close automatically...', { duration: 0 });
|
|
134
|
+
|
|
135
|
+
// Close manually after some action
|
|
136
|
+
setTimeout(() => {
|
|
137
|
+
instance.close();
|
|
138
|
+
}, 5000);
|
|
139
|
+
};
|
|
48
140
|
```
|
|
141
|
+
|
|
142
|
+
### 5. SSR & Best Practices
|
|
143
|
+
|
|
144
|
+
- **SSR Safe**: The plugin automatically detects the environment and returns a no-op instance on the server, preventing hydration mismatches or node errors.
|
|
145
|
+
- **Context Inheritance**: Toasts inherit the `appContext` of your application, meaning they can access global plugins (like `i18n`, `router`, `pinia`) and provided values.
|
|
146
|
+
|
|
147
|
+
## ⚙️ Configuration
|
|
148
|
+
|
|
149
|
+
| Option | Type | Default | Description |
|
|
150
|
+
| :--- | :--- | :--- | :--- |
|
|
151
|
+
| `duration` | `number` | `3000` | Duration in ms. Set to `0` to persist indefinitely. |
|
|
152
|
+
| `pauseOnHover` | `boolean` | `true` | Pauses timer when hovering over the toast. |
|
|
153
|
+
| `position` | `'top' \| 'bottom' \| 'center'` | `'top'` | Vertical position of the toast. |
|
|
154
|
+
| `zIndex` | `number` | `9999` | Z-Index of the toast container. |
|
|
155
|
+
| `className` | `string` | `''` | Custom CSS class name for the toast content. |
|
|
156
|
+
| `style` | `CSSProperties` | `{}` | Custom inline styles (Vue CSS object). |
|
|
157
|
+
| `useHtml` | `boolean` | `false` | **Warning**: Enables HTML rendering (XSS Risk). |
|
|
158
|
+
|
|
159
|
+
## 🛠 Development
|
|
160
|
+
|
|
161
|
+
This repository is powered by Vite.
|
|
162
|
+
|
|
163
|
+
- **Node.js**: >= 18.0.0 (Required for Vite 6+ / Tailwind 4)
|
|
164
|
+
- **Dev Server**: `npm run dev`
|
|
165
|
+
- **Build Lib**: `npm run build`
|
|
166
|
+
- **Build Demo**: `npm run build:demo`
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
Built with ❤️ for the Vue Community.
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# vue2toast
|
|
4
|
+
|
|
5
|
+
一个轻量、高性能的 Vue 3 Toast 提示插件,基于 TypeScript 和 Vite 构建。
|
|
6
|
+
|
|
7
|
+
[](https://npmjs.org/package/@lanxuexing/vue2toast)
|
|
8
|
+
[](https://github.com/lanxuexing/vue2toast/releases)
|
|
9
|
+
[](https://github.com/lanxuexing/vue2toast)
|
|
10
|
+
[](https://github.com/lanxuexing/vue2toast/stargazers)
|
|
11
|
+
[](https://npmjs.org/package/@lanxuexing/vue2toast)
|
|
12
|
+
[](https://github.com/lanxuexing/vue2toast/actions)
|
|
13
|
+
[](https://github.com/lanxuexing/vue2toast/blob/main/LICENSE)
|
|
14
|
+
[](https://vuejs.org)
|
|
15
|
+
[](https://www.typescriptlang.org/)
|
|
16
|
+
[](https://github.com/prettier/prettier)
|
|
17
|
+
[](http://makeapullrequest.com)
|
|
18
|
+
|
|
19
|
+
[中文版](./README.zh-CN.md) | [English](./README.md)
|
|
20
|
+
|
|
21
|
+
## 🔗 在线演示
|
|
22
|
+
查看组件效果: **[https://lanxuexing.github.io/vue2toast/](https://lanxuexing.github.io/vue2toast/)**
|
|
23
|
+
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## ✨ 特性
|
|
29
|
+
|
|
30
|
+
- 🚀 **Vue 3 优化**: 使用 `createVNode` 和 `render` 函数构建,性能极致。
|
|
31
|
+
- 📐 **TypeScript 支持**: 内置完整的类型定义 (d.ts)。
|
|
32
|
+
- 📚 **堆叠显示**: 支持多个 Toast 自动垂直堆叠,不重叠。
|
|
33
|
+
- 📱 **响应式**: 宽度随内容自动调整,适应长文本。
|
|
34
|
+
- 🎨 **现代设计**: 简洁美观的 UI,流畅的动画。
|
|
35
|
+
- 🔄 **支持更新**: 可编程更新 Toast 内容 (适用于进度条、倒计时等)。
|
|
36
|
+
- 📦 **轻量级**: 零依赖,体积极小。
|
|
37
|
+
- 🛠 **易定制**: 轻松控制时长和样式。
|
|
38
|
+
|
|
39
|
+
## 📦 安装
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install @lanxuexing/vue2toast
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 🚀 使用方法
|
|
46
|
+
|
|
47
|
+
### 1. 注册插件
|
|
48
|
+
|
|
49
|
+
在你的主入口文件 (`main.ts` 或 `main.js`) 中注册插件。
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import { createApp } from 'vue';
|
|
53
|
+
import App from './App.vue';
|
|
54
|
+
import Toast from '@lanxuexing/vue2toast';
|
|
55
|
+
import '@lanxuexing/vue2toast/style.css'; // 记得引入样式文件
|
|
56
|
+
|
|
57
|
+
const app = createApp(App);
|
|
58
|
+
app.use(Toast); // 全局注册 $toast 并提供 useToast
|
|
59
|
+
app.mount('#app');
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 2. 在组件中使用
|
|
63
|
+
|
|
64
|
+
推荐使用 `useToast` 组合式函数,也可以继续使用全局 `$toast`。
|
|
65
|
+
|
|
66
|
+
**Composition API (推荐):**
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
<script setup lang="ts">
|
|
70
|
+
import { useToast } from '@lanxuexing/vue2toast';
|
|
71
|
+
|
|
72
|
+
// 最佳实践:类型安全且简洁
|
|
73
|
+
const toast = useToast();
|
|
74
|
+
|
|
75
|
+
const showToast = () => {
|
|
76
|
+
toast('Hello World');
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const showLongToast = () => {
|
|
80
|
+
toast('这条消息会显示 5 秒', {
|
|
81
|
+
duration: 5000,
|
|
82
|
+
position: 'top',
|
|
83
|
+
style: { fontWeight: 'bold' }
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
</script>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Options API:**
|
|
90
|
+
|
|
91
|
+
```javascript
|
|
92
|
+
export default {
|
|
93
|
+
methods: {
|
|
94
|
+
showToast() {
|
|
95
|
+
// 这里的 this.$toast 现在有完善的类型提示
|
|
96
|
+
this.$toast('Hello World');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 3. 可更新的 Toast
|
|
103
|
+
|
|
104
|
+
你可以在 Toast 显示期间更新其内容,这非常适合加载状态或倒计时场景。
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
const showDynamic = () => {
|
|
108
|
+
// 设置 duration 为 0,使其一直显示,直到手动关闭
|
|
109
|
+
const instance = toast('加载中... 0%', { duration: 0 });
|
|
110
|
+
|
|
111
|
+
let progress = 0;
|
|
112
|
+
const timer = setInterval(() => {
|
|
113
|
+
progress += 10;
|
|
114
|
+
instance.update(`加载中... ${progress}%`); // 更新内容
|
|
115
|
+
|
|
116
|
+
if (progress >= 100) {
|
|
117
|
+
clearInterval(timer);
|
|
118
|
+
instance.close(); // 手动关闭
|
|
119
|
+
toast('加载完成!');
|
|
120
|
+
}
|
|
121
|
+
}, 300);
|
|
122
|
+
};
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 4. 手动关闭 (持久化 Toast)
|
|
126
|
+
|
|
127
|
+
将 `duration` 设置为 `0`,Toast 将不会自动消失,直到你调用返回实例的 `close()` 方法。
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
const showPersist = () => {
|
|
131
|
+
const instance = toast('我不会自动消失...', { duration: 0 });
|
|
132
|
+
|
|
133
|
+
// 模拟异步操作后关闭
|
|
134
|
+
setTimeout(() => {
|
|
135
|
+
instance.close();
|
|
136
|
+
}, 5000);
|
|
137
|
+
};
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### 5. SSR 与最佳实践
|
|
141
|
+
|
|
142
|
+
- **SSR 安全**: 插件会自动检测环境,在服务端返回空实例,避免水合不匹配或 Node 报错。
|
|
143
|
+
- **上下文继承**: Toast 会自动继承应用的 `appContext`,这意味着你可以在 Toast 组件内部正常访问全局插件 (如 `i18n`, `router`, `pinia`)。
|
|
144
|
+
|
|
145
|
+
## ⚙️ 配置选项
|
|
146
|
+
|
|
147
|
+
| 选项名 | 类型 | 默认值 | 描述 |
|
|
148
|
+
| :--- | :--- | :--- | :--- |
|
|
149
|
+
| `duration` | `number` | `3000` | 显示时长 (ms)。设置为 `0` 则永久显示。 |
|
|
150
|
+
| `pauseOnHover` | `boolean` | `true` | 鼠标悬停时是否暂停倒计时。 |
|
|
151
|
+
| `position` | `'top' \| 'bottom' \| 'center'` | `'top'` | Toast 的垂直显示位置。 |
|
|
152
|
+
| `zIndex` | `number` | `9999` | Toast 容器的层级 (z-index)。 |
|
|
153
|
+
| `className` | `string` | `''` | 自定义 CSS 类名。 |
|
|
154
|
+
| `style` | `CSSProperties` | `{}` | 自定义内联样式对象 (Vue CSS)。 |
|
|
155
|
+
| `useHtml` | `boolean` | `false` | **警告**: 是否解析 HTML (注意 XSS 风险)。 |
|
|
156
|
+
|
|
157
|
+
## 🛠 本地开发
|
|
158
|
+
|
|
159
|
+
本项目使用 Vite 构建。
|
|
160
|
+
|
|
161
|
+
- **Node.js**: >= 18.0.0 (Vite 6+ / Tailwind 4 需要)
|
|
162
|
+
- **启动开发服务器**: `npm run dev`
|
|
163
|
+
- **构建库**: `npm run build`
|
|
164
|
+
- **构建 Demo**: `npm run build:demo`
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
Built with ❤️ for the Vue Community.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { App } from 'vue';
|
|
2
|
+
import { CSSProperties } from 'vue';
|
|
3
|
+
|
|
4
|
+
export declare type ShowToast = (message: string, options?: ToastOptions | (() => void)) => ToastInstance;
|
|
5
|
+
|
|
6
|
+
declare const Toast: {
|
|
7
|
+
install(app: App, options?: ToastOptions): void;
|
|
8
|
+
};
|
|
9
|
+
export default Toast;
|
|
10
|
+
|
|
11
|
+
export declare interface ToastInstance {
|
|
12
|
+
close: () => void;
|
|
13
|
+
update: (message: string) => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export declare interface ToastOptions {
|
|
17
|
+
/**
|
|
18
|
+
* Duration in milliseconds before the toast automatically closes.
|
|
19
|
+
* Set to 0 to disable auto-close.
|
|
20
|
+
* @default 3000
|
|
21
|
+
*/
|
|
22
|
+
duration?: number;
|
|
23
|
+
/**
|
|
24
|
+
* Whether to pause the auto-close timer when mouse hovers over the toast.
|
|
25
|
+
* @default true
|
|
26
|
+
*/
|
|
27
|
+
pauseOnHover?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Custom CSS class name(s) to apply to the toast element.
|
|
30
|
+
*/
|
|
31
|
+
className?: string | object | string[];
|
|
32
|
+
/**
|
|
33
|
+
* Custom inline styles to apply to the toast element.
|
|
34
|
+
*/
|
|
35
|
+
style?: CSSProperties;
|
|
36
|
+
/**
|
|
37
|
+
* Z-index of the toast container.
|
|
38
|
+
* @default 9999
|
|
39
|
+
*/
|
|
40
|
+
zIndex?: number;
|
|
41
|
+
/**
|
|
42
|
+
* Position of the toast on the screen.
|
|
43
|
+
* @default 'center'
|
|
44
|
+
*/
|
|
45
|
+
position?: 'top' | 'bottom' | 'center';
|
|
46
|
+
/**
|
|
47
|
+
* Whether to interpret the message property as HTML content.
|
|
48
|
+
* ⚠️ Be careful with XSS vulnerabilities when enabling this.
|
|
49
|
+
* @default false
|
|
50
|
+
*/
|
|
51
|
+
useHtml?: boolean;
|
|
52
|
+
[key: string]: any;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export declare const useToast: () => ShowToast;
|
|
56
|
+
|
|
57
|
+
export { }
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
declare module '@vue/runtime-core' {
|
|
61
|
+
interface ComponentCustomProperties {
|
|
62
|
+
$toast: ShowToast;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.toast[data-v-c8a446fe]{display:flex;align-items:center;justify-content:center;min-width:200px;max-width:400px;padding:12px 24px;background-color:#000c;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);border-radius:8px;color:#fff;pointer-events:auto;box-shadow:0 4px 12px #00000026;cursor:default;font-size:14px;line-height:1.5;text-align:center;word-break:break-word}.toast[data-v-c8a446fe]:hover{transform:translateY(-1px);box-shadow:0 6px 16px #0003}.toast .message[data-v-c8a446fe]{color:#fff}.toast-container[data-v-39f2ff69]{position:fixed;left:0;right:0;display:flex;justify-content:center;pointer-events:none;padding:20px}.toast-container.is-top[data-v-39f2ff69]{top:0;align-items:flex-start}.toast-container.is-bottom[data-v-39f2ff69]{bottom:0;align-items:flex-end}.toast-container.is-center[data-v-39f2ff69]{top:50%;transform:translateY(-50%);align-items:center}.toast-list[data-v-39f2ff69]{display:flex;flex-direction:column;align-items:center;gap:10px}.toast-list-enter-active[data-v-39f2ff69],.toast-list-leave-active[data-v-39f2ff69]{transition:all .3s ease}.toast-list-enter-from[data-v-39f2ff69],.toast-list-leave-to[data-v-39f2ff69]{opacity:0;transform:translateY(-20px)}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { defineComponent as T, createElementBlock as f, openBlock as d, normalizeStyle as x, normalizeClass as C, toDisplayString as O, ref as h, createVNode as $, TransitionGroup as H, withCtx as S, Fragment as k, renderList as z, createBlock as _, inject as w, render as j } from "vue";
|
|
2
|
+
const B = ["innerHTML"], E = {
|
|
3
|
+
key: 1,
|
|
4
|
+
class: "message"
|
|
5
|
+
}, L = /* @__PURE__ */ T({
|
|
6
|
+
__name: "Toast",
|
|
7
|
+
props: {
|
|
8
|
+
message: {
|
|
9
|
+
type: String,
|
|
10
|
+
required: !0
|
|
11
|
+
},
|
|
12
|
+
useHtml: {
|
|
13
|
+
type: Boolean,
|
|
14
|
+
default: !1
|
|
15
|
+
},
|
|
16
|
+
customClass: {
|
|
17
|
+
type: [String, Object, Array],
|
|
18
|
+
default: ""
|
|
19
|
+
},
|
|
20
|
+
customStyle: {
|
|
21
|
+
type: Object,
|
|
22
|
+
default: () => ({})
|
|
23
|
+
},
|
|
24
|
+
type: {
|
|
25
|
+
type: String,
|
|
26
|
+
default: "info"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
emits: ["mouseenter", "mouseleave", "close"],
|
|
30
|
+
setup(o) {
|
|
31
|
+
return (i, n) => (d(), f("div", {
|
|
32
|
+
class: C(["toast", o.customClass]),
|
|
33
|
+
style: x(o.customStyle),
|
|
34
|
+
onMouseenter: n[0] || (n[0] = (s) => i.$emit("mouseenter")),
|
|
35
|
+
onMouseleave: n[1] || (n[1] = (s) => i.$emit("mouseleave"))
|
|
36
|
+
}, [
|
|
37
|
+
o.useHtml ? (d(), f("div", {
|
|
38
|
+
key: 0,
|
|
39
|
+
innerHTML: o.message,
|
|
40
|
+
class: "message-html"
|
|
41
|
+
}, null, 8, B)) : (d(), f("span", E, O(o.message), 1))
|
|
42
|
+
], 38));
|
|
43
|
+
}
|
|
44
|
+
}), b = (o, i) => {
|
|
45
|
+
const n = o.__vccOpts || o;
|
|
46
|
+
for (const [s, u] of i)
|
|
47
|
+
n[s] = u;
|
|
48
|
+
return n;
|
|
49
|
+
}, N = /* @__PURE__ */ b(L, [["__scopeId", "data-v-c8a446fe"]]), D = /* @__PURE__ */ T({
|
|
50
|
+
__name: "ToastContainer",
|
|
51
|
+
props: {
|
|
52
|
+
zIndex: {
|
|
53
|
+
type: Number,
|
|
54
|
+
default: 9999
|
|
55
|
+
},
|
|
56
|
+
position: {
|
|
57
|
+
type: String,
|
|
58
|
+
default: "top"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
setup(o, { expose: i }) {
|
|
62
|
+
const n = o, s = h([]);
|
|
63
|
+
let u = 0;
|
|
64
|
+
const y = (t, r) => {
|
|
65
|
+
const e = `toast-${Date.now()}-${u++}`, l = {
|
|
66
|
+
id: e,
|
|
67
|
+
message: t,
|
|
68
|
+
options: r
|
|
69
|
+
};
|
|
70
|
+
return n.position.includes("bottom") ? s.value.unshift(l) : s.value.push(l), r.duration > 0 && c(l), {
|
|
71
|
+
close: () => a(e),
|
|
72
|
+
update: (m) => {
|
|
73
|
+
const g = s.value.find((M) => M.id === e);
|
|
74
|
+
g && (g.message = m);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}, a = (t) => {
|
|
78
|
+
const r = s.value.findIndex((e) => e.id === t);
|
|
79
|
+
if (r !== -1) {
|
|
80
|
+
const e = s.value[r];
|
|
81
|
+
e.timer && clearTimeout(e.timer), s.value.splice(r, 1), e.options.onClose && e.options.onClose();
|
|
82
|
+
}
|
|
83
|
+
}, c = (t) => {
|
|
84
|
+
t.timer = setTimeout(() => {
|
|
85
|
+
a(t.id);
|
|
86
|
+
}, t.options.duration);
|
|
87
|
+
}, v = (t) => {
|
|
88
|
+
t.timer && (clearTimeout(t.timer), t.timer = null);
|
|
89
|
+
}, p = (t) => {
|
|
90
|
+
t.options.duration > 0 && c(t);
|
|
91
|
+
};
|
|
92
|
+
return i({
|
|
93
|
+
add: y,
|
|
94
|
+
remove: a
|
|
95
|
+
}), (t, r) => (d(), f("div", {
|
|
96
|
+
class: C(["toast-container", [`is-${o.position}`]]),
|
|
97
|
+
style: x({ zIndex: o.zIndex })
|
|
98
|
+
}, [
|
|
99
|
+
$(H, {
|
|
100
|
+
name: "toast-list",
|
|
101
|
+
tag: "div",
|
|
102
|
+
class: "toast-list"
|
|
103
|
+
}, {
|
|
104
|
+
default: S(() => [
|
|
105
|
+
(d(!0), f(k, null, z(s.value, (e) => (d(), _(N, {
|
|
106
|
+
key: e.id,
|
|
107
|
+
message: e.message,
|
|
108
|
+
type: e.options.type,
|
|
109
|
+
"use-html": e.options.useHtml,
|
|
110
|
+
"custom-class": e.options.className,
|
|
111
|
+
"custom-style": e.options.style,
|
|
112
|
+
onClose: (l) => a(e.id),
|
|
113
|
+
onMouseenter: (l) => e.options.pauseOnHover && v(e),
|
|
114
|
+
onMouseleave: (l) => e.options.pauseOnHover && p(e)
|
|
115
|
+
}, null, 8, ["message", "type", "use-html", "custom-class", "custom-style", "onClose", "onMouseenter", "onMouseleave"]))), 128))
|
|
116
|
+
]),
|
|
117
|
+
_: 1
|
|
118
|
+
})
|
|
119
|
+
], 6));
|
|
120
|
+
}
|
|
121
|
+
}), q = /* @__PURE__ */ b(D, [["__scopeId", "data-v-39f2ff69"]]), I = Symbol("Toast"), F = {
|
|
122
|
+
install(o, i = {}) {
|
|
123
|
+
let n = {
|
|
124
|
+
duration: 3e3,
|
|
125
|
+
pauseOnHover: !0,
|
|
126
|
+
zIndex: 9999,
|
|
127
|
+
position: "top",
|
|
128
|
+
// Changed default to top as it's more standard for stacks, but center is fine too. Let's stick to center to match old default if possible, but stack usually implies top/bottom. Let's use 'top' as default for modern feel.
|
|
129
|
+
useHtml: !1
|
|
130
|
+
};
|
|
131
|
+
Object.assign(n, i);
|
|
132
|
+
const s = /* @__PURE__ */ new Map(), u = (y, a) => {
|
|
133
|
+
var e;
|
|
134
|
+
let c = { ...n }, v = null;
|
|
135
|
+
if (typeof a == "object" ? Object.assign(c, a) : typeof a == "function" && (v = a), typeof document > "u")
|
|
136
|
+
return { close: () => {
|
|
137
|
+
}, update: () => {
|
|
138
|
+
} };
|
|
139
|
+
const p = c.position || "top";
|
|
140
|
+
let t = s.get(p);
|
|
141
|
+
if (!t) {
|
|
142
|
+
const l = document.createElement("div");
|
|
143
|
+
document.body.appendChild(l);
|
|
144
|
+
const m = $(q, {
|
|
145
|
+
position: p,
|
|
146
|
+
zIndex: c.zIndex
|
|
147
|
+
});
|
|
148
|
+
m.appContext = o._context, j(m, l), t = (e = m.component) == null ? void 0 : e.exposed, s.set(p, t);
|
|
149
|
+
}
|
|
150
|
+
return t.add(y, {
|
|
151
|
+
...c,
|
|
152
|
+
onClose: v
|
|
153
|
+
});
|
|
154
|
+
};
|
|
155
|
+
o.config.globalProperties.$toast = u, o.provide(I, u);
|
|
156
|
+
}
|
|
157
|
+
}, G = () => {
|
|
158
|
+
const o = w(I);
|
|
159
|
+
if (!o)
|
|
160
|
+
throw new Error("Toast plugin not installed");
|
|
161
|
+
return o;
|
|
162
|
+
};
|
|
163
|
+
export {
|
|
164
|
+
F as default,
|
|
165
|
+
G as useToast
|
|
166
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(c,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(c=typeof globalThis<"u"?globalThis:c||self,e(c.vue2toast={},c.Vue))})(this,(function(c,e){"use strict";const x=["innerHTML"],b={key:1,class:"message"},B=e.defineComponent({__name:"Toast",props:{message:{type:String,required:!0},useHtml:{type:Boolean,default:!1},customClass:{type:[String,Object,Array],default:""},customStyle:{type:Object,default:()=>({})},type:{type:String,default:"info"}},emits:["mouseenter","mouseleave","close"],setup(n){return(r,a)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["toast",n.customClass]),style:e.normalizeStyle(n.customStyle),onMouseenter:a[0]||(a[0]=s=>r.$emit("mouseenter")),onMouseleave:a[1]||(a[1]=s=>r.$emit("mouseleave"))},[n.useHtml?(e.openBlock(),e.createElementBlock("div",{key:0,innerHTML:n.message,class:"message-html"},null,8,x)):(e.openBlock(),e.createElementBlock("span",b,e.toDisplayString(n.message),1))],38))}}),T=(n,r)=>{const a=n.__vccOpts||n;for(const[s,p]of r)a[s]=p;return a},M=T(B,[["__scopeId","data-v-c8a446fe"]]),$=T(e.defineComponent({__name:"ToastContainer",props:{zIndex:{type:Number,default:9999},position:{type:String,default:"top"}},setup(n,{expose:r}){const a=n,s=e.ref([]);let p=0;const g=(o,u)=>{const t=`toast-${Date.now()}-${p++}`,i={id:t,message:o,options:u};return a.position.includes("bottom")?s.value.unshift(i):s.value.push(i),u.duration>0&&d(i),{close:()=>l(t),update:f=>{const C=s.value.find(_=>_.id===t);C&&(C.message=f)}}},l=o=>{const u=s.value.findIndex(t=>t.id===o);if(u!==-1){const t=s.value[u];t.timer&&clearTimeout(t.timer),s.value.splice(u,1),t.options.onClose&&t.options.onClose()}},d=o=>{o.timer=setTimeout(()=>{l(o.id)},o.options.duration)},y=o=>{o.timer&&(clearTimeout(o.timer),o.timer=null)},m=o=>{o.options.duration>0&&d(o)};return r({add:g,remove:l}),(o,u)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["toast-container",[`is-${n.position}`]]),style:e.normalizeStyle({zIndex:n.zIndex})},[e.createVNode(e.TransitionGroup,{name:"toast-list",tag:"div",class:"toast-list"},{default:e.withCtx(()=>[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(s.value,t=>(e.openBlock(),e.createBlock(M,{key:t.id,message:t.message,type:t.options.type,"use-html":t.options.useHtml,"custom-class":t.options.className,"custom-style":t.options.style,onClose:i=>l(t.id),onMouseenter:i=>t.options.pauseOnHover&&y(t),onMouseleave:i=>t.options.pauseOnHover&&m(t)},null,8,["message","type","use-html","custom-class","custom-style","onClose","onMouseenter","onMouseleave"]))),128))]),_:1})],6))}}),[["__scopeId","data-v-39f2ff69"]]),k=Symbol("Toast"),h={install(n,r={}){let a={duration:3e3,pauseOnHover:!0,zIndex:9999,position:"top",useHtml:!1};Object.assign(a,r);const s=new Map,p=(g,l)=>{var t;let d={...a},y=null;if(typeof l=="object"?Object.assign(d,l):typeof l=="function"&&(y=l),typeof document>"u")return{close:()=>{},update:()=>{}};const m=d.position||"top";let o=s.get(m);if(!o){const i=document.createElement("div");document.body.appendChild(i);const f=e.createVNode($,{position:m,zIndex:d.zIndex});f.appContext=n._context,e.render(f,i),o=(t=f.component)==null?void 0:t.exposed,s.set(m,o)}return o.add(g,{...d,onClose:y})};n.config.globalProperties.$toast=p,n.provide(k,p)}},S=()=>{const n=e.inject(k);if(!n)throw new Error("Toast plugin not installed");return n};c.default=h,c.useToast=S,Object.defineProperties(c,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
|