@rayhanbapari/vue-toastr 0.1.0

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/LICENCE ADDED
@@ -0,0 +1,21 @@
1
+ # MIT License
2
+
3
+ Copyright (c) 2025 Rayhan Bapari
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,170 @@
1
+ # @rayhanbapari/vue-toastr
2
+
3
+ > Elegant toast notifications for **Vue 3**, inspired by Toastr.
4
+
5
+ ---
6
+
7
+ ## ✨ Features
8
+
9
+ - ⚡ Simple API: `toastr.success('Title')`
10
+ - 🎨 Clean, modern design
11
+ - 📍 6 positions: top/bottom left/center/right
12
+ - ⏳ Auto-close + bottom progress bar
13
+ - ⚙️ Customizable global options
14
+ - 🧩 Written in TypeScript + Vue 3
15
+
16
+ ---
17
+
18
+ ## 📦 Installation
19
+
20
+ ```bash
21
+ npm install @rayhanbapari/vue-toastr
22
+ # or
23
+ yarn add @rayhanbapari/vue-toastr
24
+ ```
25
+
26
+ ## Register the plugin
27
+
28
+ ```javascript
29
+ import { createApp } from 'vue';
30
+ import App from './App.vue';
31
+
32
+ import Toastr from '@rayhanbapari/vue-toastr';
33
+ import '@rayhanbapari/vue-toastr/style.css';
34
+
35
+ createApp(App)
36
+ .use(Toastr)
37
+ .mount('#app');
38
+
39
+
40
+ // Add the container once
41
+ <script setup lang="ts">
42
+ import { ToastrContainer } from '@rayhanbapari/vue-toastr';
43
+ </script>
44
+
45
+ <template>
46
+ <RouterView />
47
+ <ToastrContainer />
48
+ </template>
49
+ ```
50
+
51
+ ## 💬 Triggering Notifications
52
+
53
+ ```javascript
54
+ // Basic usage
55
+ toastr.success('Operation successful!');
56
+ toastr.error('Something went wrong!');
57
+ toastr.warning('Please check your input.');
58
+ toastr.info('New update available.');
59
+
60
+ // With custom options
61
+ toastr.success('Custom toast', {
62
+ position: 'bottom-right',
63
+ autoClose: 5000,
64
+ progress: false,
65
+ });
66
+
67
+ // Set global defaults
68
+ toastr.options({
69
+ position: 'top-right',
70
+ autoClose: 4000,
71
+ progress: true,
72
+ });
73
+
74
+ // Using the composable
75
+ import { useToastr } from '@rayhanbapari/vue-toastr';
76
+ const toastr = useToastr();
77
+ toastr.success('Data saved!');
78
+ ```
79
+
80
+ ## 🔧 Framework Integrations
81
+
82
+ ### Nuxt 3
83
+
84
+ Register the plugin in `nuxt.config.ts`:
85
+
86
+ ```javascript
87
+ export default defineNuxtConfig({
88
+ modules: [
89
+ // ... other modules
90
+ ],
91
+ css: ['@rayhanbapari/vue-toastr/style.css'],
92
+ plugins: [
93
+ '~/plugins/toastr.client.js', // Create this file
94
+ ],
95
+ });
96
+ ```
97
+
98
+ Create `plugins/toastr.client.js`:
99
+
100
+ ```javascript
101
+ import Toastr from '@rayhanbapari/vue-toastr';
102
+
103
+ export default defineNuxtPlugin((nuxtApp) => {
104
+ nuxtApp.vueApp.use(Toastr);
105
+ });
106
+ ```
107
+
108
+ Add the container in your `app.vue` or layout:
109
+
110
+ ```vue
111
+ <template>
112
+ <div>
113
+ <NuxtPage />
114
+ <ClientOnly>
115
+ <ToastrContainer />
116
+ </ClientOnly>
117
+ </div>
118
+ </template>
119
+
120
+ <script setup>
121
+ import { ToastrContainer } from '@rayhanbapari/vue-toastr';
122
+ </script>
123
+ ```
124
+
125
+ ### Vue Inertia
126
+
127
+ Register the plugin in your main app file:
128
+
129
+ ```javascript
130
+ import { createApp, h } from 'vue';
131
+ import { createInertiaApp } from '@inertiajs/vue3';
132
+ import Toastr from '@rayhanbapari/vue-toastr';
133
+ import '@rayhanbapari/vue-toastr/style.css';
134
+
135
+ createInertiaApp({
136
+ resolve: (name) => require(`./Pages/${name}`),
137
+ setup({ el, App, props, plugin }) {
138
+ createApp({ render: () => h(App, props) })
139
+ .use(plugin)
140
+ .use(Toastr)
141
+ .mount(el);
142
+ },
143
+ });
144
+ ```
145
+
146
+ Add the container in your main layout:
147
+
148
+ ```vue
149
+ <template>
150
+ <main>
151
+ <slot />
152
+ </main>
153
+ <ToastrContainer />
154
+ </template>
155
+
156
+ <script setup>
157
+ import { ToastrContainer } from '@rayhanbapari/vue-toastr';
158
+ </script>
159
+ ```
160
+
161
+ ## ⚙️ Available Options
162
+
163
+ | Option | Type | Default | Description |
164
+ | ----------- | ------------------------------------------------------------------------------------------------- | -------------- | ------------------------------------------- |
165
+ | `position` | `"top-left" \| "top-center" \| "top-right" \| "bottom-left" \| "bottom-center" \| "bottom-right"` | `"top-center"` | Toast placement |
166
+ | `autoClose` | `number \| false` | `3000` | Auto close delay (ms) or `false` to disable |
167
+ | `progress` | `boolean` | `true` | Show bottom progress bar |
168
+
169
+ # vue-toastr
170
+ # vue-toastr
package/dist/index.cjs ADDED
Binary file
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/core/service.ts","../src/plugin/index.ts","../src/components/ToastrContainer.vue","unplugin-vue:\u0000/plugin-vue/export-helper"],"sourcesContent":["import Plugin from '@/plugin/index';\nexport * from '@/core/types';\nexport { toastr } from '@/plugin/index';\nexport { default as ToastrContainer } from '@/components/ToastrContainer.vue';\nimport './styles/style.css';\n\nexport default Plugin;\n","import { reactive } from 'vue';\nimport type { NotyItem, NotyOptions, NotyType } from '@/core/types';\n\nconst defaults: Required<NotyOptions> = {\n position: 'top-center',\n autoClose: 3000,\n progress: true,\n};\n\nlet idCounter = 1;\n\nexport const store = reactive({\n options: { ...defaults } as Required<NotyOptions>,\n items: [] as NotyItem[],\n});\n\nfunction makeOptions(opts?: NotyOptions): Required<NotyOptions> {\n return { ...store.options, ...(opts || {}) };\n}\n\nfunction push(type: NotyType, title: string, opts?: NotyOptions) {\n const options = makeOptions(opts);\n const item: NotyItem = {\n id: idCounter++,\n type,\n title,\n options,\n createdAt: Date.now(),\n };\n store.items.push(item);\n\n if (options.autoClose !== false && typeof window !== 'undefined') {\n setTimeout(() => remove(item.id), options.autoClose);\n }\n}\n\nexport function remove(id: number) {\n const i = store.items.findIndex((t) => t.id === id);\n if (i !== -1) store.items.splice(i, 1);\n}\n\nexport function clear() {\n store.items.splice(0, store.items.length);\n}\n\nexport function setDefaults(opts: NotyOptions) {\n store.options = { ...store.options, ...opts };\n}\n\nexport const api = {\n success: (title: string, opts?: NotyOptions) => push('success', title, opts),\n error: (title: string, opts?: NotyOptions) => push('error', title, opts),\n warning: (title: string, opts?: NotyOptions) => push('warning', title, opts),\n info: (title: string, opts?: NotyOptions) => push('info', title, opts),\n\n options: (opts: NotyOptions) => setDefaults(opts),\n clear,\n setDefaults,\n getNotifications: () => store.items.slice(),\n};\n","import type { App } from 'vue';\nimport { api } from '@/core/service';\n\ndeclare module 'vue' {\n interface ComponentCustomProperties {\n $toastr: typeof api;\n }\n}\n\nexport default {\n install(app: App) {\n app.config.globalProperties.$toastr = api;\n if (typeof window !== 'undefined') {\n // @ts-ignore\n window.toastr = api;\n }\n },\n};\n\nexport { api as toastr };\n","<script setup lang=\"ts\">\nimport { computed, ref } from 'vue';\nimport { store, remove } from '@/core/service';\nimport type { NotyItem, NotyPosition } from '@/core/types';\n\nconst isClient = ref(false);\n\nif (typeof window !== 'undefined') {\n isClient.value = true;\n}\n\nconst groups = computed<Record<NotyPosition, NotyItem[]>>(() => {\n const map: Record<NotyPosition, NotyItem[]> = {\n 'top-left': [],\n 'top-center': [],\n 'top-right': [],\n 'bottom-left': [],\n 'bottom-center': [],\n 'bottom-right': [],\n };\n for (const t of store.items) map[t.options.position].push(t);\n return map;\n});\n</script>\n\n<template>\n <Teleport v-if=\"isClient\" to=\"body\">\n <TransitionGroup\n v-for=\"(items, pos) in groups\"\n :key=\"pos\"\n tag=\"div\"\n name=\"toast\"\n class=\"toast-list\"\n :data-position=\"pos\"\n >\n <article\n v-for=\"t in items\"\n :key=\"t.id\"\n class=\"toast\"\n :class=\"[\n `toast-${t.type}`,\n { 'toast-auto-close': t.options.progress && t.options.autoClose !== false },\n ]\"\n :data-position=\"pos\"\n >\n <div class=\"toast-content\">\n <span class=\"toast-title\">{{ t.title }}</span>\n </div>\n\n <div\n v-if=\"t.options.progress && t.options.autoClose !== false\"\n class=\"toast-progress\"\n :style=\"{ animationDuration: (t.options.autoClose || 0) + 'ms' }\"\n ></div>\n\n <div class=\"toast-close\">\n <button type=\"button\" @click=\"remove(t.id)\" aria-label=\"Dismiss notification\">x</button>\n </div>\n </article>\n </TransitionGroup>\n </Teleport>\n</template>\n","\nexport default (sfc, props) => {\n const target = sfc.__vccOpts || sfc;\n for (const [key, val] of props) {\n target[key] = val;\n }\n return target;\n}\n"],"mappings":"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","names":["import_vue","_openBlock","_createBlock","_Teleport","_createElementBlock","_Fragment","_renderList","_TransitionGroup","_normalizeClass","_createElementVNode","_toDisplayString","_normalizeStyle"]}
package/dist/index.css ADDED
@@ -0,0 +1,230 @@
1
+ @import "https://fonts.googleapis.com/css2?family=Nunito+Sans:ital,opsz,wght@0,6..12,200..1000;1,6..12,200..1000&display=swap";
2
+
3
+ /* src/styles/style.css */
4
+ :root {
5
+ --toast-info: #385bbb;
6
+ --toast-info-rgb:
7
+ 56,
8
+ 91,
9
+ 187;
10
+ --toast-info-darker: hsl(224, 54%, 35%);
11
+ --toast-warning: #f3950d;
12
+ --toast-warning-rgb:
13
+ 243,
14
+ 149,
15
+ 13;
16
+ --toast-warning-darker: hsl(35, 91%, 40%);
17
+ --toast-error: #d32f2f;
18
+ --toast-error-rgb:
19
+ 211,
20
+ 47,
21
+ 47;
22
+ --toast-error-darker: hsl(0, 68%, 43%);
23
+ --toast-success: #388e3c;
24
+ --toast-success-rgb:
25
+ 56,
26
+ 142,
27
+ 60;
28
+ --toast-success-darker: hsl(120, 54%, 35%);
29
+ }
30
+ @keyframes toastSlideFromTop {
31
+ 0% {
32
+ opacity: 0;
33
+ translate: 0 calc(-100% - 24px);
34
+ }
35
+ 100% {
36
+ opacity: 1;
37
+ translate: 0 0;
38
+ }
39
+ }
40
+ @keyframes toastSlideFromBottom {
41
+ 0% {
42
+ opacity: 0;
43
+ translate: 0 calc(100% + 24px);
44
+ }
45
+ 100% {
46
+ opacity: 1;
47
+ translate: 0 0;
48
+ }
49
+ }
50
+ @keyframes toastFadeOut {
51
+ 0% {
52
+ opacity: 1;
53
+ }
54
+ 100% {
55
+ opacity: 0;
56
+ }
57
+ }
58
+ @keyframes progressBar {
59
+ 0% {
60
+ transform: scaleX(1);
61
+ }
62
+ 100% {
63
+ transform: scaleX(0);
64
+ }
65
+ }
66
+ .toast-list {
67
+ position: fixed;
68
+ display: flex;
69
+ flex-direction: column;
70
+ gap: 16px;
71
+ pointer-events: none;
72
+ z-index: 99999;
73
+ width: max-content;
74
+ max-width: calc(100vw - 48px);
75
+ }
76
+ .toast-list > * {
77
+ pointer-events: auto;
78
+ }
79
+ .toast-list[data-position^=top] {
80
+ top: 24px;
81
+ }
82
+ .toast-list[data-position^=bottom] {
83
+ bottom: 24px;
84
+ }
85
+ .toast-list[data-position$=left] {
86
+ left: 24px;
87
+ right: auto;
88
+ transform: none;
89
+ align-items: flex-start;
90
+ }
91
+ .toast-list[data-position$=center] {
92
+ left: 50%;
93
+ right: auto;
94
+ transform: translateX(-50%);
95
+ align-items: center;
96
+ }
97
+ .toast-list[data-position$=right] {
98
+ right: 24px;
99
+ left: auto;
100
+ transform: none;
101
+ align-items: flex-end;
102
+ }
103
+ .toast {
104
+ position: relative;
105
+ display: flex;
106
+ align-items: center;
107
+ gap: 12px;
108
+ padding: 16px 20px;
109
+ padding-right: 50px;
110
+ min-width: 280px;
111
+ max-width: 400px;
112
+ background-color: #fff;
113
+ border-radius: 8px;
114
+ border: 2px solid transparent;
115
+ font-family:
116
+ "Nunito Sans",
117
+ system-ui,
118
+ helvetica,
119
+ sans-serif;
120
+ font-size: 15px;
121
+ font-weight: 600;
122
+ line-height: 1.4;
123
+ box-shadow:
124
+ 0 2px 4px -1px rgba(0, 0, 0, 0.2),
125
+ 0 4px 5px 0 rgba(0, 0, 0, 0.14),
126
+ 0 1px 10px 0 rgba(0, 0, 0, 0.12);
127
+ overflow: hidden;
128
+ color: var(--toast-info-darker);
129
+ background-clip: padding-box;
130
+ }
131
+ .toast-list[data-position^=top] .toast {
132
+ animation: toastSlideFromTop 0.5s ease-out forwards;
133
+ }
134
+ .toast-list[data-position^=bottom] .toast {
135
+ animation: toastSlideFromBottom 0.5s ease-out forwards;
136
+ }
137
+ .toast.toast-success {
138
+ color: var(--toast-success);
139
+ border-color: var(--toast-success);
140
+ }
141
+ .toast.toast-error {
142
+ color: var(--toast-error);
143
+ border-color: var(--toast-error);
144
+ }
145
+ .toast.toast-warning {
146
+ color: var(--toast-warning);
147
+ border-color: var(--toast-warning);
148
+ }
149
+ .toast.toast-info {
150
+ color: var(--toast-info);
151
+ border-color: var(--toast-info);
152
+ }
153
+ .toast-content {
154
+ display: flex;
155
+ flex-direction: column;
156
+ flex: 1;
157
+ }
158
+ .toast-title {
159
+ font-weight: 600;
160
+ font-size: 15px;
161
+ line-height: 1.4;
162
+ }
163
+ .toast-progress {
164
+ position: absolute;
165
+ left: 0;
166
+ right: 0;
167
+ bottom: 0;
168
+ height: 3px;
169
+ border-radius: 50px;
170
+ transform-origin: left;
171
+ background-color: currentColor;
172
+ animation: progressBar linear forwards;
173
+ }
174
+ .toast-close {
175
+ display: flex;
176
+ align-items: center;
177
+ justify-content: center;
178
+ position: absolute;
179
+ right: 8px;
180
+ top: 50%;
181
+ transform: translateY(-50%);
182
+ }
183
+ .toast-close button {
184
+ padding: 8px;
185
+ margin: 0;
186
+ border: none;
187
+ background-color: transparent;
188
+ display: flex;
189
+ align-items: center;
190
+ justify-content: center;
191
+ cursor: pointer;
192
+ border-radius: 4px;
193
+ transition: background-color 0.2s ease;
194
+ color: inherit;
195
+ font-size: 16px;
196
+ line-height: 1;
197
+ }
198
+ .toast-close button:focus-visible {
199
+ outline: 2px solid currentColor;
200
+ outline-offset: 2px;
201
+ }
202
+ .toast-close button:hover {
203
+ background-color: rgba(0, 0, 0, 0.05);
204
+ }
205
+ .toast-enter-active,
206
+ .toast-leave-active {
207
+ transition: opacity 0.2s ease, transform 0.2s ease;
208
+ }
209
+ .toast-enter-from,
210
+ .toast-leave-to {
211
+ opacity: 0;
212
+ }
213
+ .toast-list[data-position^=top] .toast-enter-from,
214
+ .toast-list[data-position^=top] .toast-leave-to {
215
+ transform: translateY(-16px);
216
+ }
217
+ .toast-list[data-position^=bottom] .toast-enter-from,
218
+ .toast-list[data-position^=bottom] .toast-leave-to {
219
+ transform: translateY(16px);
220
+ }
221
+ .toast-move {
222
+ transition: transform 0.2s ease;
223
+ }
224
+ @media (max-width: 480px) {
225
+ .toast {
226
+ min-width: calc(100vw - 48px);
227
+ max-width: calc(100vw - 48px);
228
+ }
229
+ }
230
+ /*# sourceMappingURL=index.css.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/styles/style.css"],"sourcesContent":["@import url(https://fonts.googleapis.com/css2?family=Nunito+Sans:ital,opsz,wght@0,6..12,200..1000;1,6..12,200..1000&display=swap);\n\n:root {\n\t--toast-info: #385bbb;\n\t--toast-info-rgb: 56, 91, 187;\n\t--toast-info-darker: hsl(224, 54%, 35%);\n\t--toast-warning: #f3950d;\n\t--toast-warning-rgb: 243, 149, 13;\n\t--toast-warning-darker: hsl(35, 91%, 40%);\n\t--toast-error: #d32f2f;\n\t--toast-error-rgb: 211, 47, 47;\n\t--toast-error-darker: hsl(0, 68%, 43%);\n\t--toast-success: #388e3c;\n\t--toast-success-rgb: 56, 142, 60;\n\t--toast-success-darker: hsl(120, 54%, 35%);\n}\n\n@keyframes toastSlideFromTop {\n\t0% {\n\t\topacity: 0;\n\t\ttranslate: 0 calc(-100% - 24px);\n\t}\n\t100% {\n\t\topacity: 1;\n\t\ttranslate: 0 0;\n\t}\n}\n\n@keyframes toastSlideFromBottom {\n\t0% {\n\t\topacity: 0;\n\t\ttranslate: 0 calc(100% + 24px);\n\t}\n\t100% {\n\t\topacity: 1;\n\t\ttranslate: 0 0;\n\t}\n}\n\n@keyframes toastFadeOut {\n\t0% {\n\t\topacity: 1;\n\t}\n\t100% {\n\t\topacity: 0;\n\t}\n}\n\n@keyframes progressBar {\n\t0% {\n\t\ttransform: scaleX(1);\n\t}\n\t100% {\n\t\ttransform: scaleX(0);\n\t}\n}\n\n.toast-list {\n\tposition: fixed;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 16px;\n\tpointer-events: none;\n\tz-index: 99999;\n\twidth: max-content;\n\tmax-width: calc(100vw - 48px);\n}\n\n.toast-list > * {\n\tpointer-events: auto;\n}\n\n.toast-list[data-position^='top'] {\n\ttop: 24px;\n}\n\n.toast-list[data-position^='bottom'] {\n\tbottom: 24px;\n}\n\n.toast-list[data-position$='left'] {\n\tleft: 24px;\n\tright: auto;\n\ttransform: none;\n\talign-items: flex-start;\n}\n\n.toast-list[data-position$='center'] {\n\tleft: 50%;\n\tright: auto;\n\ttransform: translateX(-50%);\n\talign-items: center;\n}\n\n.toast-list[data-position$='right'] {\n\tright: 24px;\n\tleft: auto;\n\ttransform: none;\n\talign-items: flex-end;\n}\n\n.toast {\n\tposition: relative;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 12px;\n\tpadding: 16px 20px;\n\tpadding-right: 50px;\n\tmin-width: 280px;\n\tmax-width: 400px;\n\tbackground-color: #fff;\n\tborder-radius: 8px;\n\tborder: 2px solid transparent;\n\tfont-family: 'Nunito Sans', system-ui, helvetica, sans-serif;\n\tfont-size: 15px;\n\tfont-weight: 600;\n\tline-height: 1.4;\n\tbox-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14),\n\t\t0 1px 10px 0 rgba(0, 0, 0, 0.12);\n\toverflow: hidden;\n\tcolor: var(--toast-info-darker);\n\tbackground-clip: padding-box;\n}\n\n.toast-list[data-position^='top'] .toast {\n\tanimation: toastSlideFromTop 0.5s ease-out forwards;\n}\n\n.toast-list[data-position^='bottom'] .toast {\n\tanimation: toastSlideFromBottom 0.5s ease-out forwards;\n}\n\n.toast.toast-success {\n\tcolor: var(--toast-success);\n\tborder-color: var(--toast-success);\n}\n\n.toast.toast-error {\n\tcolor: var(--toast-error);\n\tborder-color: var(--toast-error);\n}\n\n.toast.toast-warning {\n\tcolor: var(--toast-warning);\n\tborder-color: var(--toast-warning);\n}\n\n.toast.toast-info {\n\tcolor: var(--toast-info);\n\tborder-color: var(--toast-info);\n}\n\n.toast-content {\n\tdisplay: flex;\n\tflex-direction: column;\n\tflex: 1;\n}\n\n.toast-title {\n\tfont-weight: 600;\n\tfont-size: 15px;\n\tline-height: 1.4;\n}\n\n.toast-progress {\n\tposition: absolute;\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\theight: 3px;\n\tborder-radius: 50px;\n\ttransform-origin: left;\n\tbackground-color: currentColor;\n\tanimation: progressBar linear forwards;\n}\n\n.toast-close {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tposition: absolute;\n\tright: 8px;\n\ttop: 50%;\n\ttransform: translateY(-50%);\n}\n\n.toast-close button {\n\tpadding: 8px;\n\tmargin: 0;\n\tborder: none;\n\tbackground-color: transparent;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tcursor: pointer;\n\tborder-radius: 4px;\n\ttransition: background-color 0.2s ease;\n\tcolor: inherit;\n\tfont-size: 16px;\n\tline-height: 1;\n}\n\n.toast-close button:focus-visible {\n\toutline: 2px solid currentColor;\n\toutline-offset: 2px;\n}\n\n.toast-close button:hover {\n\tbackground-color: rgba(0, 0, 0, 0.05);\n}\n\n.toast-enter-active,\n.toast-leave-active {\n\ttransition: opacity 0.2s ease, transform 0.2s ease;\n}\n\n.toast-enter-from,\n.toast-leave-to {\n\topacity: 0;\n}\n\n.toast-list[data-position^='top'] .toast-enter-from,\n.toast-list[data-position^='top'] .toast-leave-to {\n\ttransform: translateY(-16px);\n}\n\n.toast-list[data-position^='bottom'] .toast-enter-from,\n.toast-list[data-position^='bottom'] .toast-leave-to {\n\ttransform: translateY(16px);\n}\n\n.toast-move {\n\ttransition: transform 0.2s ease;\n}\n\n@media (max-width: 480px) {\n\t.toast {\n\t\tmin-width: calc(100vw - 48px);\n\t\tmax-width: calc(100vw - 48px);\n\t}\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,51 @@
1
+ import { App } from 'vue';
2
+ export { default as ToastrContainer } from '@/components/ToastrContainer.vue';
3
+
4
+ type NotyType = 'success' | 'error' | 'warning' | 'info';
5
+ type NotyPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
6
+ interface NotyOptions {
7
+ position?: NotyPosition;
8
+ autoClose?: number | false;
9
+ progress?: boolean;
10
+ }
11
+ interface NotyItem {
12
+ id: number;
13
+ type: NotyType;
14
+ title: string;
15
+ options: Required<NotyOptions>;
16
+ createdAt: number;
17
+ }
18
+
19
+ declare function clear(): void;
20
+ declare function setDefaults(opts: NotyOptions): void;
21
+ declare const api: {
22
+ success: (title: string, opts?: NotyOptions) => void;
23
+ error: (title: string, opts?: NotyOptions) => void;
24
+ warning: (title: string, opts?: NotyOptions) => void;
25
+ info: (title: string, opts?: NotyOptions) => void;
26
+ options: (opts: NotyOptions) => void;
27
+ clear: typeof clear;
28
+ setDefaults: typeof setDefaults;
29
+ getNotifications: () => {
30
+ id: number;
31
+ type: NotyType;
32
+ title: string;
33
+ options: {
34
+ position: NotyPosition;
35
+ autoClose: number | false;
36
+ progress: boolean;
37
+ };
38
+ createdAt: number;
39
+ }[];
40
+ };
41
+
42
+ declare module 'vue' {
43
+ interface ComponentCustomProperties {
44
+ $toastr: typeof api;
45
+ }
46
+ }
47
+ declare const _default: {
48
+ install(app: App): void;
49
+ };
50
+
51
+ export { type NotyItem, type NotyOptions, type NotyPosition, type NotyType, _default as default, api as toastr };
@@ -0,0 +1,51 @@
1
+ import { App } from 'vue';
2
+ export { default as ToastrContainer } from '@/components/ToastrContainer.vue';
3
+
4
+ type NotyType = 'success' | 'error' | 'warning' | 'info';
5
+ type NotyPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
6
+ interface NotyOptions {
7
+ position?: NotyPosition;
8
+ autoClose?: number | false;
9
+ progress?: boolean;
10
+ }
11
+ interface NotyItem {
12
+ id: number;
13
+ type: NotyType;
14
+ title: string;
15
+ options: Required<NotyOptions>;
16
+ createdAt: number;
17
+ }
18
+
19
+ declare function clear(): void;
20
+ declare function setDefaults(opts: NotyOptions): void;
21
+ declare const api: {
22
+ success: (title: string, opts?: NotyOptions) => void;
23
+ error: (title: string, opts?: NotyOptions) => void;
24
+ warning: (title: string, opts?: NotyOptions) => void;
25
+ info: (title: string, opts?: NotyOptions) => void;
26
+ options: (opts: NotyOptions) => void;
27
+ clear: typeof clear;
28
+ setDefaults: typeof setDefaults;
29
+ getNotifications: () => {
30
+ id: number;
31
+ type: NotyType;
32
+ title: string;
33
+ options: {
34
+ position: NotyPosition;
35
+ autoClose: number | false;
36
+ progress: boolean;
37
+ };
38
+ createdAt: number;
39
+ }[];
40
+ };
41
+
42
+ declare module 'vue' {
43
+ interface ComponentCustomProperties {
44
+ $toastr: typeof api;
45
+ }
46
+ }
47
+ declare const _default: {
48
+ install(app: App): void;
49
+ };
50
+
51
+ export { type NotyItem, type NotyOptions, type NotyPosition, type NotyType, _default as default, api as toastr };
package/dist/index.js ADDED
Binary file
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/service.ts","../src/plugin/index.ts","../src/components/ToastrContainer.vue","unplugin-vue:\u0000/plugin-vue/export-helper","../src/index.ts"],"sourcesContent":["import { reactive } from 'vue';\nimport type { NotyItem, NotyOptions, NotyType } from '@/core/types';\n\nconst defaults: Required<NotyOptions> = {\n position: 'top-center',\n autoClose: 3000,\n progress: true,\n};\n\nlet idCounter = 1;\n\nexport const store = reactive({\n options: { ...defaults } as Required<NotyOptions>,\n items: [] as NotyItem[],\n});\n\nfunction makeOptions(opts?: NotyOptions): Required<NotyOptions> {\n return { ...store.options, ...(opts || {}) };\n}\n\nfunction push(type: NotyType, title: string, opts?: NotyOptions) {\n const options = makeOptions(opts);\n const item: NotyItem = {\n id: idCounter++,\n type,\n title,\n options,\n createdAt: Date.now(),\n };\n store.items.push(item);\n\n if (options.autoClose !== false && typeof window !== 'undefined') {\n setTimeout(() => remove(item.id), options.autoClose);\n }\n}\n\nexport function remove(id: number) {\n const i = store.items.findIndex((t) => t.id === id);\n if (i !== -1) store.items.splice(i, 1);\n}\n\nexport function clear() {\n store.items.splice(0, store.items.length);\n}\n\nexport function setDefaults(opts: NotyOptions) {\n store.options = { ...store.options, ...opts };\n}\n\nexport const api = {\n success: (title: string, opts?: NotyOptions) => push('success', title, opts),\n error: (title: string, opts?: NotyOptions) => push('error', title, opts),\n warning: (title: string, opts?: NotyOptions) => push('warning', title, opts),\n info: (title: string, opts?: NotyOptions) => push('info', title, opts),\n\n options: (opts: NotyOptions) => setDefaults(opts),\n clear,\n setDefaults,\n getNotifications: () => store.items.slice(),\n};\n","import type { App } from 'vue';\nimport { api } from '@/core/service';\n\ndeclare module 'vue' {\n interface ComponentCustomProperties {\n $toastr: typeof api;\n }\n}\n\nexport default {\n install(app: App) {\n app.config.globalProperties.$toastr = api;\n if (typeof window !== 'undefined') {\n // @ts-ignore\n window.toastr = api;\n }\n },\n};\n\nexport { api as toastr };\n","<script setup lang=\"ts\">\nimport { computed, ref } from 'vue';\nimport { store, remove } from '@/core/service';\nimport type { NotyItem, NotyPosition } from '@/core/types';\n\nconst isClient = ref(false);\n\nif (typeof window !== 'undefined') {\n isClient.value = true;\n}\n\nconst groups = computed<Record<NotyPosition, NotyItem[]>>(() => {\n const map: Record<NotyPosition, NotyItem[]> = {\n 'top-left': [],\n 'top-center': [],\n 'top-right': [],\n 'bottom-left': [],\n 'bottom-center': [],\n 'bottom-right': [],\n };\n for (const t of store.items) map[t.options.position].push(t);\n return map;\n});\n</script>\n\n<template>\n <Teleport v-if=\"isClient\" to=\"body\">\n <TransitionGroup\n v-for=\"(items, pos) in groups\"\n :key=\"pos\"\n tag=\"div\"\n name=\"toast\"\n class=\"toast-list\"\n :data-position=\"pos\"\n >\n <article\n v-for=\"t in items\"\n :key=\"t.id\"\n class=\"toast\"\n :class=\"[\n `toast-${t.type}`,\n { 'toast-auto-close': t.options.progress && t.options.autoClose !== false },\n ]\"\n :data-position=\"pos\"\n >\n <div class=\"toast-content\">\n <span class=\"toast-title\">{{ t.title }}</span>\n </div>\n\n <div\n v-if=\"t.options.progress && t.options.autoClose !== false\"\n class=\"toast-progress\"\n :style=\"{ animationDuration: (t.options.autoClose || 0) + 'ms' }\"\n ></div>\n\n <div class=\"toast-close\">\n <button type=\"button\" @click=\"remove(t.id)\" aria-label=\"Dismiss notification\">x</button>\n </div>\n </article>\n </TransitionGroup>\n </Teleport>\n</template>\n","\nexport default (sfc, props) => {\n const target = sfc.__vccOpts || sfc;\n for (const [key, val] of props) {\n target[key] = val;\n }\n return target;\n}\n","import Plugin from '@/plugin/index';\nexport * from '@/core/types';\nexport { toastr } from '@/plugin/index';\nexport { default as ToastrContainer } from '@/components/ToastrContainer.vue';\nimport './styles/style.css';\n\nexport default Plugin;\n"],"mappings":"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","names":[]}
package/dist/style.css ADDED
@@ -0,0 +1,230 @@
1
+ @import "https://fonts.googleapis.com/css2?family=Nunito+Sans:ital,opsz,wght@0,6..12,200..1000;1,6..12,200..1000&display=swap";
2
+
3
+ /* src/styles/style.css */
4
+ :root {
5
+ --toast-info: #385bbb;
6
+ --toast-info-rgb:
7
+ 56,
8
+ 91,
9
+ 187;
10
+ --toast-info-darker: hsl(224, 54%, 35%);
11
+ --toast-warning: #f3950d;
12
+ --toast-warning-rgb:
13
+ 243,
14
+ 149,
15
+ 13;
16
+ --toast-warning-darker: hsl(35, 91%, 40%);
17
+ --toast-error: #d32f2f;
18
+ --toast-error-rgb:
19
+ 211,
20
+ 47,
21
+ 47;
22
+ --toast-error-darker: hsl(0, 68%, 43%);
23
+ --toast-success: #388e3c;
24
+ --toast-success-rgb:
25
+ 56,
26
+ 142,
27
+ 60;
28
+ --toast-success-darker: hsl(120, 54%, 35%);
29
+ }
30
+ @keyframes toastSlideFromTop {
31
+ 0% {
32
+ opacity: 0;
33
+ translate: 0 calc(-100% - 24px);
34
+ }
35
+ 100% {
36
+ opacity: 1;
37
+ translate: 0 0;
38
+ }
39
+ }
40
+ @keyframes toastSlideFromBottom {
41
+ 0% {
42
+ opacity: 0;
43
+ translate: 0 calc(100% + 24px);
44
+ }
45
+ 100% {
46
+ opacity: 1;
47
+ translate: 0 0;
48
+ }
49
+ }
50
+ @keyframes toastFadeOut {
51
+ 0% {
52
+ opacity: 1;
53
+ }
54
+ 100% {
55
+ opacity: 0;
56
+ }
57
+ }
58
+ @keyframes progressBar {
59
+ 0% {
60
+ transform: scaleX(1);
61
+ }
62
+ 100% {
63
+ transform: scaleX(0);
64
+ }
65
+ }
66
+ .toast-list {
67
+ position: fixed;
68
+ display: flex;
69
+ flex-direction: column;
70
+ gap: 16px;
71
+ pointer-events: none;
72
+ z-index: 99999;
73
+ width: max-content;
74
+ max-width: calc(100vw - 48px);
75
+ }
76
+ .toast-list > * {
77
+ pointer-events: auto;
78
+ }
79
+ .toast-list[data-position^=top] {
80
+ top: 24px;
81
+ }
82
+ .toast-list[data-position^=bottom] {
83
+ bottom: 24px;
84
+ }
85
+ .toast-list[data-position$=left] {
86
+ left: 24px;
87
+ right: auto;
88
+ transform: none;
89
+ align-items: flex-start;
90
+ }
91
+ .toast-list[data-position$=center] {
92
+ left: 50%;
93
+ right: auto;
94
+ transform: translateX(-50%);
95
+ align-items: center;
96
+ }
97
+ .toast-list[data-position$=right] {
98
+ right: 24px;
99
+ left: auto;
100
+ transform: none;
101
+ align-items: flex-end;
102
+ }
103
+ .toast {
104
+ position: relative;
105
+ display: flex;
106
+ align-items: center;
107
+ gap: 12px;
108
+ padding: 16px 20px;
109
+ padding-right: 50px;
110
+ min-width: 280px;
111
+ max-width: 400px;
112
+ background-color: #fff;
113
+ border-radius: 8px;
114
+ border: 2px solid transparent;
115
+ font-family:
116
+ "Nunito Sans",
117
+ system-ui,
118
+ helvetica,
119
+ sans-serif;
120
+ font-size: 15px;
121
+ font-weight: 600;
122
+ line-height: 1.4;
123
+ box-shadow:
124
+ 0 2px 4px -1px rgba(0, 0, 0, 0.2),
125
+ 0 4px 5px 0 rgba(0, 0, 0, 0.14),
126
+ 0 1px 10px 0 rgba(0, 0, 0, 0.12);
127
+ overflow: hidden;
128
+ color: var(--toast-info-darker);
129
+ background-clip: padding-box;
130
+ }
131
+ .toast-list[data-position^=top] .toast {
132
+ animation: toastSlideFromTop 0.5s ease-out forwards;
133
+ }
134
+ .toast-list[data-position^=bottom] .toast {
135
+ animation: toastSlideFromBottom 0.5s ease-out forwards;
136
+ }
137
+ .toast.toast-success {
138
+ color: var(--toast-success);
139
+ border-color: var(--toast-success);
140
+ }
141
+ .toast.toast-error {
142
+ color: var(--toast-error);
143
+ border-color: var(--toast-error);
144
+ }
145
+ .toast.toast-warning {
146
+ color: var(--toast-warning);
147
+ border-color: var(--toast-warning);
148
+ }
149
+ .toast.toast-info {
150
+ color: var(--toast-info);
151
+ border-color: var(--toast-info);
152
+ }
153
+ .toast-content {
154
+ display: flex;
155
+ flex-direction: column;
156
+ flex: 1;
157
+ }
158
+ .toast-title {
159
+ font-weight: 600;
160
+ font-size: 15px;
161
+ line-height: 1.4;
162
+ }
163
+ .toast-progress {
164
+ position: absolute;
165
+ left: 0;
166
+ right: 0;
167
+ bottom: 0;
168
+ height: 3px;
169
+ border-radius: 50px;
170
+ transform-origin: left;
171
+ background-color: currentColor;
172
+ animation: progressBar linear forwards;
173
+ }
174
+ .toast-close {
175
+ display: flex;
176
+ align-items: center;
177
+ justify-content: center;
178
+ position: absolute;
179
+ right: 8px;
180
+ top: 50%;
181
+ transform: translateY(-50%);
182
+ }
183
+ .toast-close button {
184
+ padding: 8px;
185
+ margin: 0;
186
+ border: none;
187
+ background-color: transparent;
188
+ display: flex;
189
+ align-items: center;
190
+ justify-content: center;
191
+ cursor: pointer;
192
+ border-radius: 4px;
193
+ transition: background-color 0.2s ease;
194
+ color: inherit;
195
+ font-size: 16px;
196
+ line-height: 1;
197
+ }
198
+ .toast-close button:focus-visible {
199
+ outline: 2px solid currentColor;
200
+ outline-offset: 2px;
201
+ }
202
+ .toast-close button:hover {
203
+ background-color: rgba(0, 0, 0, 0.05);
204
+ }
205
+ .toast-enter-active,
206
+ .toast-leave-active {
207
+ transition: opacity 0.2s ease, transform 0.2s ease;
208
+ }
209
+ .toast-enter-from,
210
+ .toast-leave-to {
211
+ opacity: 0;
212
+ }
213
+ .toast-list[data-position^=top] .toast-enter-from,
214
+ .toast-list[data-position^=top] .toast-leave-to {
215
+ transform: translateY(-16px);
216
+ }
217
+ .toast-list[data-position^=bottom] .toast-enter-from,
218
+ .toast-list[data-position^=bottom] .toast-leave-to {
219
+ transform: translateY(16px);
220
+ }
221
+ .toast-move {
222
+ transition: transform 0.2s ease;
223
+ }
224
+ @media (max-width: 480px) {
225
+ .toast {
226
+ min-width: calc(100vw - 48px);
227
+ max-width: calc(100vw - 48px);
228
+ }
229
+ }
230
+ /*# sourceMappingURL=index.css.map */
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@rayhanbapari/vue-toastr",
3
+ "version": "0.1.0",
4
+ "description": "Elegant toast notifications for Vue 3, inspired by Toastr.",
5
+ "type": "module",
6
+ "main": "dist/index.cjs",
7
+ "module": "dist/index.mjs",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.mjs",
13
+ "require": "./dist/index.cjs"
14
+ },
15
+ "./style.css": "./dist/style.css"
16
+ },
17
+ "sideEffects": [
18
+ "**/*.css"
19
+ ],
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "scripts": {
24
+ "build": "tsup --config tsup.config.ts && node scripts/copy-css.js",
25
+ "typecheck": "vue-tsc --noEmit",
26
+ "dev": "vite --config playground/vite.config.ts"
27
+ },
28
+ "peerDependencies": {
29
+ "vue": "^3.4.0"
30
+ },
31
+ "license": "MIT",
32
+ "author": "Rayhan Bapari <mdrayhanbapari02@gmail.com>",
33
+ "keywords": [
34
+ "vue3",
35
+ "toast",
36
+ "notification",
37
+ "plugin",
38
+ "vue-toastr"
39
+ ],
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://github.com/rayhan-bapari/vue-toastr"
43
+ },
44
+ "devDependencies": {
45
+ "@types/node": "^24.9.2",
46
+ "tsup": "^8.5.0",
47
+ "typescript": "^5.9.3",
48
+ "unplugin-vue": "^7.0.3",
49
+ "vite": "^7.1.12"
50
+ }
51
+ }