@cruxext/toast 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Maysara Elshewehy (https://github.com/maysara-elshewehy)
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,178 @@
1
+ <!-- ╔══════════════════════════════ BEG ══════════════════════════════╗ -->
2
+
3
+ <br>
4
+ <div align="center">
5
+ <p>
6
+ <img src="./assets/img/logo.png" alt="logo" style="" height="60" />
7
+ </p>
8
+ </div>
9
+
10
+ <div align="center">
11
+ <img src="https://img.shields.io/badge/v-0.0.1-black"/>
12
+ <a href="https://github.com/cruxext-org"><img src="https://img.shields.io/badge/🔥-@cruxext-black"/></a>
13
+ <br>
14
+ <img src="https://img.shields.io/badge/coverage-100%25-brightgreen" alt="Test Coverage" />
15
+ <img src="https://img.shields.io/github/issues/cruxext-orgz/toast?style=flat" alt="Github Repo Issues" />
16
+ <img src="https://img.shields.io/github/stars/cruxext-orgz/toast?style=social" alt="GitHub Repo stars" />
17
+ </div>
18
+ <br>
19
+
20
+ <!-- ╚═════════════════════════════════════════════════════════════════╝ -->
21
+
22
+
23
+
24
+ <!-- ╔══════════════════════════════ DOC ══════════════════════════════╗ -->
25
+
26
+ - ## Overview 👀
27
+
28
+ - #### Why ?
29
+ > A lightweight, reactive toast management solution, built for [`@cruxjs`](https://github.com/cruxjs-org) ecosystem.
30
+
31
+ - #### When ?
32
+ > When you need to display brief, non-blocking feedback or notifications to your users.
33
+
34
+ <br>
35
+ <br>
36
+
37
+ - ## Quick Start 🔥
38
+
39
+ > install [`hmm`](https://github.com/minejs-org/hmm) first.
40
+
41
+ ```bash
42
+ # in your terminal
43
+ hmm i @cruxext/toast
44
+ ```
45
+
46
+ <div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> </div>
47
+ <br>
48
+
49
+ - ### Setup
50
+
51
+ ```typescript
52
+ // in your client config at `client.ts` file, add the toast extension.
53
+ import { toastExtension } from `@cruxext/toast`;
54
+
55
+ const config: ClientManagerConfig = {
56
+ ...
57
+
58
+ extensions: [
59
+ ...
60
+ toastExtension({
61
+ position : 'bottom-right',
62
+ pre : {
63
+ errors : [
64
+ {
65
+ code : 'e001',
66
+ message : 'An error occurred.',
67
+ }
68
+ ],
69
+ warnings: [],
70
+ success : [],
71
+ info : [],
72
+ },
73
+ }),
74
+ ],
75
+ };
76
+ ```
77
+
78
+ - ### Usage
79
+
80
+ ```typescript
81
+ import { toast } from '@cruxext/toast';
82
+
83
+ toast().info('Hello World!');
84
+ ```
85
+
86
+ <br>
87
+ <br>
88
+
89
+ - ## Documentation 📑
90
+
91
+ - ### URL Parameters
92
+
93
+ > the toast automatically displays messages based on the URL parameters.
94
+ >
95
+ > the parameters are `terror`, `twarning`, `tsuccess`, and `tinfo`.
96
+
97
+ > each parameter value should be a predefined message code.
98
+ >
99
+ > if the code is not found, the toast will not display any message.
100
+
101
+ - ### API ⛓️
102
+
103
+ - #### Main-Functions
104
+
105
+ ```typescript
106
+ // Create a toast extension
107
+ export function toastExtension(config?: ToastConfig) : ClientExtension
108
+ ```
109
+
110
+ ```typescript
111
+ // Get the toast manager instance
112
+ export const toast: () => ToastManager
113
+ ```
114
+
115
+ - #### Toast Class Methods
116
+
117
+ ```typescript
118
+ show (message: string, options: ToastOptions = {})
119
+
120
+ success (message: string, options?: Omit<ToastOptions, 'type'>)
121
+ error (message: string, options?: Omit<ToastOptions, 'type'>)
122
+ warning (message: string, options?: Omit<ToastOptions, 'type'>)
123
+ info (message: string, options?: Omit<ToastOptions, 'type'>)
124
+
125
+ dismiss (id: string)
126
+ clear ()
127
+ ```
128
+
129
+ - #### Types
130
+
131
+ ```typescript
132
+ export interface PredefinedMessage {
133
+ code : string;
134
+ message : string;
135
+ }
136
+
137
+ export interface ToastConfig {
138
+ containerId? : string;
139
+ position? : 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'top-center' | 'bottom-center';
140
+ className? : string;
141
+ pre : {
142
+ errors? : PredefinedMessage[];
143
+ warnings? : PredefinedMessage[];
144
+ info? : PredefinedMessage[];
145
+ success? : PredefinedMessage[];
146
+ }
147
+ }
148
+ ```
149
+
150
+ <div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> </div>
151
+ <br>
152
+
153
+ - ### Related 🔗
154
+
155
+ - ##### [@minejs/jsx](https://github.com/minejs-org/jsx)
156
+ - ##### [@minejs/signals](https://github.com/minejs-org/signals)
157
+
158
+ - ##### [@cruxkit/toast](https://github.com/cruxkit-org/toast)
159
+
160
+ - ##### [@cruxjs/client](https://github.com/cruxjs-org/client)
161
+ - ##### [@cruxjs/app](https://github.com/cruxjs-org/app)
162
+
163
+ <!-- ╚═════════════════════════════════════════════════════════════════╝ -->
164
+
165
+
166
+
167
+ <!-- ╔══════════════════════════════ END ══════════════════════════════╗ -->
168
+
169
+ <br>
170
+ <br>
171
+
172
+ ---
173
+
174
+ <div align="center">
175
+ <a href="https://github.com/maysara-elshewehy"><img src="https://img.shields.io/badge/by-Maysara-black"/></a>
176
+ </div>
177
+
178
+ <!-- ╚═════════════════════════════════════════════════════════════════╝ -->
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ 'use strict';var jsx=require('@minejs/jsx'),signals=require('@minejs/signals'),toast=require('@cruxkit/toast'),jsxRuntime=require('@minejs/jsx/jsx-runtime');var s=signals.signal([]);function m(r){s.update(t=>{let e=t.find(n=>n.id===r);return !e||e.closing?t:t.map(n=>n.id===r?{...n,closing:true}:n)}),setTimeout(()=>{s.update(t=>{let e=t.find(n=>n.id===r);return e?.onClose&&e.onClose(),t.filter(n=>n.id!==r)});},300);}var f=class{constructor(t){this.containerElement=null;this._cleanupTimer=null;this.config={pre:{errors:[],warnings:[],success:[],info:[]},containerId:"cruxkit-toast-container",position:"bottom-right",className:""};this.config={...this.config,...t},signals.effect(()=>{s().length===0?this.checkCleanup():this._cleanupTimer&&(clearTimeout(this._cleanupTimer),this._cleanupTimer=null);}),typeof window<"u"&&setTimeout(()=>this.checkUrlParams(),250);}get toasts(){return s}checkUrlParams(){try{let t=new URLSearchParams(window.location.search),e=t.get("terror");if(e&&this.config.pre.errors){let o=this.config.pre.errors.find(i=>i.code===e)?.message;o?this.error(o):console.warn(`[ToastManager] Unknown error code: ${e}`);}let n=t.get("twarning");if(n&&this.config.pre.warnings){let o=this.config.pre.warnings.find(i=>i.code===n)?.message;o?this.warning(o):console.warn(`[ToastManager] Unknown warning code: ${n}`);}let c=t.get("tsuccess");if(c&&this.config.pre.success){let o=this.config.pre.success.find(i=>i.code===c)?.message;o?this.success(o):console.warn(`[ToastManager] Unknown success code: ${c}`);}let a=t.get("tinfo");if(a&&this.config.pre.info){let o=this.config.pre.info.find(i=>i.code===a)?.message;o?this.info(o):console.warn(`[ToastManager] Unknown info code: ${a}`);}window.history.replaceState({},"",window.location.pathname);}catch(t){console.error("[ToastManager] Error checking URL params",t);}}ensureMounted(){if(typeof window>"u"||(this._cleanupTimer&&(clearTimeout(this._cleanupTimer),this._cleanupTimer=null),this.containerElement&&document.getElementById(this.config.containerId)))return;let t=document.getElementById(this.config.containerId);t||(t=document.createElement("div"),t.id=this.config.containerId,document.body.appendChild(t)),this.containerElement=t,jsx.render(jsxRuntime.jsx(toast.ToastContainer,{...this.config,toasts:s,onDismiss:e=>this.dismiss(e)}),`#${this.config.containerId}`);}checkCleanup(){s().length===0&&(this._cleanupTimer=setTimeout(()=>{s().length===0&&this.containerElement&&(this.containerElement.remove(),this.containerElement=null,this._cleanupTimer=null);},500));}show(t,e={}){this.ensureMounted();let n=Math.random().toString(36).substr(2,9),c=e.type||"info",a=e.duration||3e3,o={id:n,message:t,type:c,duration:a,onClose:e.onClose};return s.update(i=>[...i,o]),a>0&&setTimeout(()=>{this.dismiss(n);},a),n}success(t,e){return this.show(t,{...e,type:"success"})}error(t,e){return this.show(t,{...e,type:"error"})}warning(t,e){return this.show(t,{...e,type:"warning"})}info(t,e){return this.show(t,{...e,type:"info"})}dismiss(t){m(t);}clear(){s.set([]);}};var l,O=()=>l;function _(r){return {name:"ToastExtension",onBoot:t=>{t.cconfig.allowedQueryParams=["terror","tsuccess","twarning","tinfo",...t.cconfig.allowedQueryParams??[]],l=new f(r);}}}exports.ToastManager=f;exports.toast=O;exports.toastExtension=_;//# sourceMappingURL=index.cjs.map
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/mod/state.ts","../src/mod/manager.tsx","../src/index.ts"],"names":["toastsSignal","signal","dismissToast","id","current","toast","t","ToastManager","config","effect","params","terror","message","msg","twarning","tsuccess","tinfo","e","el","render","jsx","ToastContainer","options","type","duration","instance","toastManager","toastExtension","ctx"],"mappings":"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","file":"index.cjs","sourcesContent":["// src/state.ts\r\n//\r\n// Made with ❤️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n import { signal } from '@minejs/signals';\r\n import { ToastInstance } from '../types';\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ DATA ════════════════════════════════════════╗\r\n\r\n export const toastsSignal = signal<ToastInstance[]>([]);\r\n\r\n export function dismissToast(id: string) {\r\n toastsSignal.update(current => {\r\n const toast = current.find(t => t.id === id);\r\n if (!toast) return current;\r\n\r\n // If already closing, do nothing\r\n if (toast.closing) return current;\r\n\r\n // Mark as closing to trigger exit animation\r\n return current.map(t =>\r\n t.id === id ? { ...t, closing: true } : t\r\n );\r\n });\r\n\r\n // Actual removal after animation\r\n setTimeout(() => {\r\n toastsSignal.update(current => {\r\n const toast = current.find(t => t.id === id);\r\n if (toast?.onClose) {\r\n toast.onClose();\r\n }\r\n return current.filter(t => t.id !== id);\r\n });\r\n }, 300); // Match animation duration\r\n }\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n","// src/kit/manager.tsx\r\n//\r\n// Made with ❤️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n import { render } from '@minejs/jsx';\r\n import { effect } from '@minejs/signals';\r\n import { ToastConfig, ToastInstance, ToastOptions } from '../types';\r\n import { toastsSignal, dismissToast } from './state';\r\n import { ToastContainer } from '@cruxkit/toast';\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ CORE ════════════════════════════════════════╗\r\n\r\n export class ToastManager {\r\n private containerElement: HTMLElement | null = null;\r\n private _cleanupTimer: any = null;\r\n private config: Required<ToastConfig> = {\r\n pre : {\r\n errors : [],\r\n warnings : [],\r\n success : [],\r\n info : [],\r\n },\r\n containerId : 'cruxkit-toast-container',\r\n position : 'bottom-right',\r\n className : '',\r\n };\r\n\r\n get toasts() {\r\n return toastsSignal;\r\n }\r\n\r\n constructor(config?: ToastConfig) {\r\n // Set default config values\r\n this.config = {\r\n ...this.config,\r\n ...config,\r\n };\r\n\r\n // Setup reactive cleanup\r\n effect(() => {\r\n const count = toastsSignal().length;\r\n if (count === 0) {\r\n this.checkCleanup();\r\n } else {\r\n if (this._cleanupTimer) {\r\n clearTimeout(this._cleanupTimer);\r\n this._cleanupTimer = null;\r\n }\r\n }\r\n });\r\n\r\n // Check URL parameters on initialization (client-side only check usually)\r\n if (typeof window !== 'undefined') {\r\n setTimeout(() => this.checkUrlParams(), 250);\r\n }\r\n }\r\n\r\n private checkUrlParams() {\r\n try {\r\n const params = new URLSearchParams(window.location.search);\r\n\r\n const terror = params.get('terror');\r\n if (terror && this.config.pre.errors) {\r\n const message = this.config.pre.errors.find(msg => msg.code === terror)?.message;\r\n if (message) {\r\n this.error(message);\r\n } else {\r\n console.warn(`[ToastManager] Unknown error code: ${terror}`);\r\n }\r\n }\r\n\r\n const twarning = params.get('twarning');\r\n if (twarning && this.config.pre.warnings) {\r\n const message = this.config.pre.warnings.find(msg => msg.code === twarning)?.message;\r\n if (message) {\r\n this.warning(message);\r\n } else {\r\n console.warn(`[ToastManager] Unknown warning code: ${twarning}`);\r\n }\r\n }\r\n\r\n const tsuccess = params.get('tsuccess');\r\n if (tsuccess && this.config.pre.success) {\r\n const message = this.config.pre.success.find(msg => msg.code === tsuccess)?.message;\r\n if (message) {\r\n this.success(message);\r\n } else {\r\n console.warn(`[ToastManager] Unknown success code: ${tsuccess}`);\r\n }\r\n }\r\n\r\n const tinfo = params.get('tinfo');\r\n if (tinfo && this.config.pre.info) {\r\n const message = this.config.pre.info.find(msg => msg.code === tinfo)?.message;\r\n if (message) {\r\n this.info(message);\r\n } else {\r\n console.warn(`[ToastManager] Unknown info code: ${tinfo}`);\r\n }\r\n }\r\n\r\n // Optional: Clean URL params?\r\n window.history.replaceState({}, '', window.location.pathname);\r\n } catch (e) {\r\n console.error('[ToastManager] Error checking URL params', e);\r\n }\r\n }\r\n\r\n private ensureMounted() {\r\n if (typeof window === 'undefined') return;\r\n\r\n // If we have a cleanup timer pending, cancel it because we are adding new toasts\r\n if (this._cleanupTimer) {\r\n clearTimeout(this._cleanupTimer);\r\n this._cleanupTimer = null;\r\n }\r\n\r\n if (this.containerElement && document.getElementById(this.config.containerId!)) return;\r\n\r\n // Check if already in DOM (e.g. from SSR or previous instance that wasn't tracked)\r\n let el = document.getElementById(this.config.containerId!);\r\n if (!el) {\r\n el = document.createElement('div');\r\n el.id = this.config.containerId!;\r\n document.body.appendChild(el);\r\n }\r\n this.containerElement = el;\r\n\r\n // Render the container\r\n // We use default props for now.\r\n // If user wants to configure position, they might need a configure method or we pass it here.\r\n // For now, we assume default.\r\n render(\r\n <ToastContainer\r\n {...this.config}\r\n toasts={toastsSignal}\r\n onDismiss={(id) => this.dismiss(id)}\r\n />,\r\n `#${this.config.containerId}`\r\n );\r\n }\r\n\r\n private checkCleanup() {\r\n // \"remove after finish\"\r\n if (toastsSignal().length === 0) {\r\n // Delay cleanup slightly to allow for exit animations if any (though Overlay usually handles its own existence)\r\n // But more importantly, if user spams toasts, we don't want to mount/unmount rapidly.\r\n this._cleanupTimer = setTimeout(() => {\r\n if (toastsSignal().length === 0 && this.containerElement) {\r\n this.containerElement.remove();\r\n this.containerElement = null;\r\n this._cleanupTimer = null;\r\n }\r\n }, 500);\r\n }\r\n }\r\n\r\n show(message: string, options: ToastOptions = {}) {\r\n this.ensureMounted();\r\n\r\n const id = Math.random().toString(36).substr(2, 9);\r\n const type = options.type || 'info';\r\n const duration = options.duration || 3000;\r\n\r\n const instance: ToastInstance = {\r\n id,\r\n message,\r\n type,\r\n duration,\r\n onClose: options.onClose\r\n };\r\n\r\n toastsSignal.update(current => [...current, instance]);\r\n\r\n if (duration > 0) {\r\n setTimeout(() => {\r\n this.dismiss(id);\r\n }, duration);\r\n }\r\n\r\n return id;\r\n }\r\n\r\n success(message: string, options?: Omit<ToastOptions, 'type'>) {\r\n return this.show(message, { ...options, type: 'success' });\r\n }\r\n\r\n error(message: string, options?: Omit<ToastOptions, 'type'>) {\r\n return this.show(message, { ...options, type: 'error' });\r\n }\r\n\r\n warning(message: string, options?: Omit<ToastOptions, 'type'>) {\r\n return this.show(message, { ...options, type: 'warning' });\r\n }\r\n\r\n info(message: string, options?: Omit<ToastOptions, 'type'>) {\r\n return this.show(message, { ...options, type: 'info' });\r\n }\r\n\r\n dismiss(id: string) {\r\n dismissToast(id);\r\n }\r\n\r\n clear() {\r\n toastsSignal.set([]);\r\n }\r\n }\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n","// src/index.ts\r\n//\r\n// Made with ❤️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n import { ClientExtension, ExtensionContext } from \"@cruxjs/base\";\r\n import { ToastConfig } from \"./types\";\r\n import { ToastManager } from \"./mod/manager\";\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ INIT ════════════════════════════════════════╗\r\n\r\n let toastManager : ToastManager;\r\n export const toast = () => toastManager;\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ CORE ════════════════════════════════════════╗\r\n\r\n /**\r\n * Create a toast extension\r\n * @param config Toast configuration\r\n * @returns Toast extension\r\n */\r\n export function toastExtension(config?: ToastConfig) : ClientExtension {\r\n return {\r\n name : 'ToastExtension',\r\n\r\n onBoot: (ctx: ExtensionContext) => {\r\n // inject allowed query params\r\n ctx.cconfig.allowedQueryParams = [\r\n 'terror',\r\n 'tsuccess',\r\n 'twarning',\r\n 'tinfo',\r\n ...ctx.cconfig.allowedQueryParams ?? [],\r\n ];\r\n\r\n // create toast manager instance\r\n toastManager = new ToastManager(config);\r\n }\r\n };\r\n };\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ ════ ════════════════════════════════════════╗\r\n\r\n export * from \"./types\";\r\n export * from \"./mod/manager\";\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝"]}
@@ -0,0 +1,48 @@
1
+ import { ClientExtension } from '@cruxjs/base';
2
+ import * as _minejs_signals from '@minejs/signals';
3
+ import { ToastInstance, ToastOptions } from '@cruxkit/toast';
4
+ export { ToastInstance, ToastOptions, ToastProps, ToastType } from '@cruxkit/toast';
5
+
6
+ interface PredefinedMessage {
7
+ code: string;
8
+ message: string;
9
+ }
10
+ interface ToastConfig {
11
+ containerId?: string;
12
+ position?: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'top-center' | 'bottom-center';
13
+ className?: string;
14
+ pre: {
15
+ errors?: PredefinedMessage[];
16
+ warnings?: PredefinedMessage[];
17
+ info?: PredefinedMessage[];
18
+ success?: PredefinedMessage[];
19
+ };
20
+ }
21
+
22
+ declare class ToastManager {
23
+ private containerElement;
24
+ private _cleanupTimer;
25
+ private config;
26
+ get toasts(): _minejs_signals.Signal<ToastInstance[]>;
27
+ constructor(config?: ToastConfig);
28
+ private checkUrlParams;
29
+ private ensureMounted;
30
+ private checkCleanup;
31
+ show(message: string, options?: ToastOptions): string;
32
+ success(message: string, options?: Omit<ToastOptions, 'type'>): string;
33
+ error(message: string, options?: Omit<ToastOptions, 'type'>): string;
34
+ warning(message: string, options?: Omit<ToastOptions, 'type'>): string;
35
+ info(message: string, options?: Omit<ToastOptions, 'type'>): string;
36
+ dismiss(id: string): void;
37
+ clear(): void;
38
+ }
39
+
40
+ declare const toast: () => ToastManager;
41
+ /**
42
+ * Create a toast extension
43
+ * @param config Toast configuration
44
+ * @returns Toast extension
45
+ */
46
+ declare function toastExtension(config?: ToastConfig): ClientExtension;
47
+
48
+ export { type PredefinedMessage, type ToastConfig, ToastManager, toast, toastExtension };
@@ -0,0 +1,48 @@
1
+ import { ClientExtension } from '@cruxjs/base';
2
+ import * as _minejs_signals from '@minejs/signals';
3
+ import { ToastInstance, ToastOptions } from '@cruxkit/toast';
4
+ export { ToastInstance, ToastOptions, ToastProps, ToastType } from '@cruxkit/toast';
5
+
6
+ interface PredefinedMessage {
7
+ code: string;
8
+ message: string;
9
+ }
10
+ interface ToastConfig {
11
+ containerId?: string;
12
+ position?: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'top-center' | 'bottom-center';
13
+ className?: string;
14
+ pre: {
15
+ errors?: PredefinedMessage[];
16
+ warnings?: PredefinedMessage[];
17
+ info?: PredefinedMessage[];
18
+ success?: PredefinedMessage[];
19
+ };
20
+ }
21
+
22
+ declare class ToastManager {
23
+ private containerElement;
24
+ private _cleanupTimer;
25
+ private config;
26
+ get toasts(): _minejs_signals.Signal<ToastInstance[]>;
27
+ constructor(config?: ToastConfig);
28
+ private checkUrlParams;
29
+ private ensureMounted;
30
+ private checkCleanup;
31
+ show(message: string, options?: ToastOptions): string;
32
+ success(message: string, options?: Omit<ToastOptions, 'type'>): string;
33
+ error(message: string, options?: Omit<ToastOptions, 'type'>): string;
34
+ warning(message: string, options?: Omit<ToastOptions, 'type'>): string;
35
+ info(message: string, options?: Omit<ToastOptions, 'type'>): string;
36
+ dismiss(id: string): void;
37
+ clear(): void;
38
+ }
39
+
40
+ declare const toast: () => ToastManager;
41
+ /**
42
+ * Create a toast extension
43
+ * @param config Toast configuration
44
+ * @returns Toast extension
45
+ */
46
+ declare function toastExtension(config?: ToastConfig): ClientExtension;
47
+
48
+ export { type PredefinedMessage, type ToastConfig, ToastManager, toast, toastExtension };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import {render}from'@minejs/jsx';import {signal,effect}from'@minejs/signals';import {ToastContainer}from'@cruxkit/toast';import {jsx}from'@minejs/jsx/jsx-runtime';var s=signal([]);function m(r){s.update(t=>{let e=t.find(n=>n.id===r);return !e||e.closing?t:t.map(n=>n.id===r?{...n,closing:true}:n)}),setTimeout(()=>{s.update(t=>{let e=t.find(n=>n.id===r);return e?.onClose&&e.onClose(),t.filter(n=>n.id!==r)});},300);}var f=class{constructor(t){this.containerElement=null;this._cleanupTimer=null;this.config={pre:{errors:[],warnings:[],success:[],info:[]},containerId:"cruxkit-toast-container",position:"bottom-right",className:""};this.config={...this.config,...t},effect(()=>{s().length===0?this.checkCleanup():this._cleanupTimer&&(clearTimeout(this._cleanupTimer),this._cleanupTimer=null);}),typeof window<"u"&&setTimeout(()=>this.checkUrlParams(),250);}get toasts(){return s}checkUrlParams(){try{let t=new URLSearchParams(window.location.search),e=t.get("terror");if(e&&this.config.pre.errors){let o=this.config.pre.errors.find(i=>i.code===e)?.message;o?this.error(o):console.warn(`[ToastManager] Unknown error code: ${e}`);}let n=t.get("twarning");if(n&&this.config.pre.warnings){let o=this.config.pre.warnings.find(i=>i.code===n)?.message;o?this.warning(o):console.warn(`[ToastManager] Unknown warning code: ${n}`);}let c=t.get("tsuccess");if(c&&this.config.pre.success){let o=this.config.pre.success.find(i=>i.code===c)?.message;o?this.success(o):console.warn(`[ToastManager] Unknown success code: ${c}`);}let a=t.get("tinfo");if(a&&this.config.pre.info){let o=this.config.pre.info.find(i=>i.code===a)?.message;o?this.info(o):console.warn(`[ToastManager] Unknown info code: ${a}`);}window.history.replaceState({},"",window.location.pathname);}catch(t){console.error("[ToastManager] Error checking URL params",t);}}ensureMounted(){if(typeof window>"u"||(this._cleanupTimer&&(clearTimeout(this._cleanupTimer),this._cleanupTimer=null),this.containerElement&&document.getElementById(this.config.containerId)))return;let t=document.getElementById(this.config.containerId);t||(t=document.createElement("div"),t.id=this.config.containerId,document.body.appendChild(t)),this.containerElement=t,render(jsx(ToastContainer,{...this.config,toasts:s,onDismiss:e=>this.dismiss(e)}),`#${this.config.containerId}`);}checkCleanup(){s().length===0&&(this._cleanupTimer=setTimeout(()=>{s().length===0&&this.containerElement&&(this.containerElement.remove(),this.containerElement=null,this._cleanupTimer=null);},500));}show(t,e={}){this.ensureMounted();let n=Math.random().toString(36).substr(2,9),c=e.type||"info",a=e.duration||3e3,o={id:n,message:t,type:c,duration:a,onClose:e.onClose};return s.update(i=>[...i,o]),a>0&&setTimeout(()=>{this.dismiss(n);},a),n}success(t,e){return this.show(t,{...e,type:"success"})}error(t,e){return this.show(t,{...e,type:"error"})}warning(t,e){return this.show(t,{...e,type:"warning"})}info(t,e){return this.show(t,{...e,type:"info"})}dismiss(t){m(t);}clear(){s.set([]);}};var l,O=()=>l;function _(r){return {name:"ToastExtension",onBoot:t=>{t.cconfig.allowedQueryParams=["terror","tsuccess","twarning","tinfo",...t.cconfig.allowedQueryParams??[]],l=new f(r);}}}export{f as ToastManager,O as toast,_ as toastExtension};//# sourceMappingURL=index.js.map
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/mod/state.ts","../src/mod/manager.tsx","../src/index.ts"],"names":["toastsSignal","signal","dismissToast","id","current","toast","t","ToastManager","config","effect","params","terror","message","msg","twarning","tsuccess","tinfo","e","el","render","jsx","ToastContainer","options","type","duration","instance","toastManager","toastExtension","ctx"],"mappings":"mKAiBW,IAAMA,CAAAA,CAAeC,MAAAA,CAAwB,EAAE,CAAA,CAE/C,SAASC,CAAAA,CAAaC,CAAAA,CAAY,CACrCH,CAAAA,CAAa,MAAA,CAAOI,CAAAA,EAAW,CAC3B,IAAMC,CAAAA,CAAQD,CAAAA,CAAQ,IAAA,CAAKE,CAAAA,EAAKA,EAAE,EAAA,GAAOH,CAAE,EAI3C,OAHI,CAACE,GAGDA,CAAAA,CAAM,OAAA,CAAgBD,CAAAA,CAGnBA,CAAAA,CAAQ,IAAIE,CAAAA,EACfA,CAAAA,CAAE,EAAA,GAAOH,CAAAA,CAAK,CAAE,GAAGG,CAAAA,CAAG,OAAA,CAAS,IAAK,EAAIA,CAC5C,CACJ,CAAC,CAAA,CAGD,WAAW,IAAM,CACbN,CAAAA,CAAa,MAAA,CAAOI,GAAW,CAC3B,IAAMC,CAAAA,CAAQD,CAAAA,CAAQ,KAAKE,CAAAA,EAAKA,CAAAA,CAAE,EAAA,GAAOH,CAAE,EAC3C,OAAIE,CAAAA,EAAO,SACPA,CAAAA,CAAM,OAAA,GAEHD,CAAAA,CAAQ,MAAA,CAAOE,CAAAA,EAAKA,CAAAA,CAAE,KAAOH,CAAE,CAC1C,CAAC,EACL,EAAG,GAAG,EACV,CCvBO,IAAMI,CAAAA,CAAN,KAAmB,CAmBtB,YAAYC,CAAAA,CAAsB,CAlBlC,IAAA,CAAQ,gBAAA,CAAuC,KAC/C,IAAA,CAAQ,aAAA,CAAqB,IAAA,CAC7B,IAAA,CAAQ,OAAgC,CACpC,GAAA,CAAsB,CAClB,MAAA,CAAsB,GACtB,QAAA,CAAsB,EAAC,CACvB,OAAA,CAAsB,EAAC,CACvB,IAAA,CAAsB,EAC1B,EACA,WAAA,CAAsB,yBAAA,CACtB,QAAA,CAAsB,cAAA,CACtB,UAAsB,EAC1B,CAAA,CAQI,IAAA,CAAK,MAAA,CAAS,CACV,GAAG,IAAA,CAAK,MAAA,CACR,GAAGA,CACP,CAAA,CAGAC,MAAAA,CAAO,IAAM,CACKT,GAAa,CAAE,MAAA,GACf,CAAA,CACV,IAAA,CAAK,cAAa,CAEd,IAAA,CAAK,gBACL,YAAA,CAAa,IAAA,CAAK,aAAa,CAAA,CAC/B,IAAA,CAAK,aAAA,CAAgB,IAAA,EAGjC,CAAC,CAAA,CAGG,OAAO,MAAA,CAAW,GAAA,EAClB,WAAW,IAAM,IAAA,CAAK,cAAA,EAAe,CAAG,GAAG,EAEnD,CA5BA,IAAI,MAAA,EAAS,CACT,OAAOA,CACX,CA4BQ,cAAA,EAAiB,CACrB,GAAI,CACA,IAAMU,CAAAA,CAAS,IAAI,eAAA,CAAgB,MAAA,CAAO,QAAA,CAAS,MAAM,EAEnDC,CAAAA,CAASD,CAAAA,CAAO,IAAI,QAAQ,CAAA,CAClC,GAAIC,CAAAA,EAAU,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,OAAQ,CAClC,IAAMC,CAAAA,CAAU,IAAA,CAAK,OAAO,GAAA,CAAI,MAAA,CAAO,IAAA,CAAKC,CAAAA,EAAOA,EAAI,IAAA,GAASF,CAAM,CAAA,EAAG,OAAA,CACrEC,EACA,IAAA,CAAK,KAAA,CAAMA,CAAO,CAAA,CAElB,QAAQ,IAAA,CAAK,CAAA,mCAAA,EAAsCD,CAAM,CAAA,CAAE,EAEnE,CAEA,IAAMG,CAAAA,CAAWJ,CAAAA,CAAO,IAAI,UAAU,CAAA,CACtC,GAAII,CAAAA,EAAY,IAAA,CAAK,OAAO,GAAA,CAAI,QAAA,CAAU,CACtC,IAAMF,EAAU,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,QAAA,CAAS,KAAKC,CAAAA,EAAOA,CAAAA,CAAI,IAAA,GAASC,CAAQ,GAAG,OAAA,CACzEF,CAAAA,CACA,IAAA,CAAK,OAAA,CAAQA,CAAO,CAAA,CAEpB,OAAA,CAAQ,IAAA,CAAK,CAAA,qCAAA,EAAwCE,CAAQ,CAAA,CAAE,EAEvE,CAEA,IAAMC,EAAWL,CAAAA,CAAO,GAAA,CAAI,UAAU,CAAA,CACtC,GAAIK,CAAAA,EAAY,IAAA,CAAK,OAAO,GAAA,CAAI,OAAA,CAAS,CACrC,IAAMH,CAAAA,CAAU,IAAA,CAAK,MAAA,CAAO,IAAI,OAAA,CAAQ,IAAA,CAAKC,CAAAA,EAAOA,CAAAA,CAAI,OAASE,CAAQ,CAAA,EAAG,OAAA,CACxEH,CAAAA,CACA,KAAK,OAAA,CAAQA,CAAO,EAEpB,OAAA,CAAQ,IAAA,CAAK,wCAAwCG,CAAQ,CAAA,CAAE,EAEvE,CAEA,IAAMC,CAAAA,CAAQN,CAAAA,CAAO,GAAA,CAAI,OAAO,EAChC,GAAIM,CAAAA,EAAS,IAAA,CAAK,MAAA,CAAO,IAAI,IAAA,CAAM,CAC/B,IAAMJ,CAAAA,CAAU,IAAA,CAAK,OAAO,GAAA,CAAI,IAAA,CAAK,IAAA,CAAKC,CAAAA,EAAOA,EAAI,IAAA,GAASG,CAAK,CAAA,EAAG,OAAA,CAClEJ,EACA,IAAA,CAAK,IAAA,CAAKA,CAAO,CAAA,CAEjB,QAAQ,IAAA,CAAK,CAAA,kCAAA,EAAqCI,CAAK,CAAA,CAAE,EAEjE,CAGA,MAAA,CAAO,OAAA,CAAQ,YAAA,CAAa,EAAC,CAAG,EAAA,CAAI,MAAA,CAAO,QAAA,CAAS,QAAQ,EAChE,CAAA,MAASC,CAAAA,CAAG,CACR,QAAQ,KAAA,CAAM,0CAAA,CAA4CA,CAAC,EAC/D,CACJ,CAEQ,aAAA,EAAgB,CASpB,GARI,OAAO,OAAW,GAAA,GAGlB,IAAA,CAAK,aAAA,GACL,YAAA,CAAa,KAAK,aAAa,CAAA,CAC/B,IAAA,CAAK,aAAA,CAAgB,MAGrB,IAAA,CAAK,gBAAA,EAAoB,QAAA,CAAS,cAAA,CAAe,KAAK,MAAA,CAAO,WAAY,CAAA,CAAA,CAAG,OAGhF,IAAIC,CAAAA,CAAK,QAAA,CAAS,cAAA,CAAe,IAAA,CAAK,OAAO,WAAY,CAAA,CACpDA,CAAAA,GACDA,CAAAA,CAAK,SAAS,aAAA,CAAc,KAAK,EACjCA,CAAAA,CAAG,EAAA,CAAK,KAAK,MAAA,CAAO,WAAA,CACpB,QAAA,CAAS,IAAA,CAAK,YAAYA,CAAE,CAAA,CAAA,CAEhC,IAAA,CAAK,gBAAA,CAAmBA,EAMxBC,MAAAA,CACIC,GAAAA,CAACC,cAAAA,CAAA,CACI,GAAG,IAAA,CAAK,MAAA,CACT,MAAA,CAAQrB,CAAAA,CACR,UAAYG,CAAAA,EAAO,IAAA,CAAK,OAAA,CAAQA,CAAE,EACtC,CAAA,CACA,CAAA,CAAA,EAAI,IAAA,CAAK,MAAA,CAAO,WAAW,CAAA,CAC/B,EACJ,CAEQ,YAAA,EAAe,CAEfH,CAAAA,EAAa,CAAE,SAAW,CAAA,GAGzB,IAAA,CAAK,cAAgB,UAAA,CAAW,IAAM,CAC9BA,CAAAA,GAAe,MAAA,GAAW,CAAA,EAAK,IAAA,CAAK,gBAAA,GACpC,KAAK,gBAAA,CAAiB,MAAA,EAAO,CAC7B,IAAA,CAAK,iBAAmB,IAAA,CACxB,IAAA,CAAK,cAAgB,IAAA,EAE7B,CAAA,CAAG,GAAG,CAAA,EAEf,CAEA,IAAA,CAAKY,CAAAA,CAAiBU,EAAwB,EAAC,CAAG,CAC9C,IAAA,CAAK,eAAc,CAEnB,IAAMnB,CAAAA,CAAK,IAAA,CAAK,QAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,MAAA,CAAO,EAAG,CAAC,CAAA,CAC3CoB,CAAAA,CAAOD,CAAAA,CAAQ,MAAQ,MAAA,CACvBE,CAAAA,CAAWF,CAAAA,CAAQ,QAAA,EAAY,IAE/BG,CAAAA,CAA0B,CAC5B,EAAA,CAAAtB,CAAAA,CACA,QAAAS,CAAAA,CACA,IAAA,CAAAW,CAAAA,CACA,QAAA,CAAAC,EACA,OAAA,CAASF,CAAAA,CAAQ,OACrB,CAAA,CAEA,OAAAtB,CAAAA,CAAa,MAAA,CAAOI,CAAAA,EAAW,CAAC,GAAGA,CAAAA,CAASqB,CAAQ,CAAC,CAAA,CAEjDD,EAAW,CAAA,EACX,UAAA,CAAW,IAAM,CACb,IAAA,CAAK,QAAQrB,CAAE,EACnB,CAAA,CAAGqB,CAAQ,EAGRrB,CACX,CAEA,OAAA,CAAQS,CAAAA,CAAiBU,EAAsC,CAC3D,OAAO,IAAA,CAAK,IAAA,CAAKV,EAAS,CAAE,GAAGU,CAAAA,CAAS,IAAA,CAAM,SAAU,CAAC,CAC7D,CAEA,KAAA,CAAMV,EAAiBU,CAAAA,CAAsC,CACzD,OAAO,IAAA,CAAK,KAAKV,CAAAA,CAAS,CAAE,GAAGU,CAAAA,CAAS,KAAM,OAAQ,CAAC,CAC3D,CAEA,OAAA,CAAQV,EAAiBU,CAAAA,CAAsC,CAC3D,OAAO,IAAA,CAAK,KAAKV,CAAAA,CAAS,CAAE,GAAGU,CAAAA,CAAS,KAAM,SAAU,CAAC,CAC7D,CAEA,KAAKV,CAAAA,CAAiBU,CAAAA,CAAsC,CACxD,OAAO,KAAK,IAAA,CAAKV,CAAAA,CAAS,CAAE,GAAGU,EAAS,IAAA,CAAM,MAAO,CAAC,CAC1D,CAEA,OAAA,CAAQnB,CAAAA,CAAY,CAChBD,CAAAA,CAAaC,CAAE,EACnB,CAEA,OAAQ,CACJH,CAAAA,CAAa,IAAI,EAAE,EACvB,CACJ,ECpMA,IAAI0B,CAAAA,CACSrB,CAAAA,CAAQ,IAAMqB,EAapB,SAASC,CAAAA,CAAenB,CAAAA,CAAwC,CACnE,OAAO,CACH,IAAA,CAAO,iBAEP,MAAA,CAASoB,CAAAA,EAA0B,CAE/BA,CAAAA,CAAI,OAAA,CAAQ,kBAAA,CAAqB,CAC7B,SACA,UAAA,CACA,UAAA,CACA,OAAA,CACA,GAAGA,EAAI,OAAA,CAAQ,kBAAA,EAAsB,EACzC,EAGAF,CAAAA,CAAe,IAAInB,EAAaC,CAAM,EAC1C,CACJ,CACJ","file":"index.js","sourcesContent":["// src/state.ts\r\n//\r\n// Made with ❤️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n import { signal } from '@minejs/signals';\r\n import { ToastInstance } from '../types';\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ DATA ════════════════════════════════════════╗\r\n\r\n export const toastsSignal = signal<ToastInstance[]>([]);\r\n\r\n export function dismissToast(id: string) {\r\n toastsSignal.update(current => {\r\n const toast = current.find(t => t.id === id);\r\n if (!toast) return current;\r\n\r\n // If already closing, do nothing\r\n if (toast.closing) return current;\r\n\r\n // Mark as closing to trigger exit animation\r\n return current.map(t =>\r\n t.id === id ? { ...t, closing: true } : t\r\n );\r\n });\r\n\r\n // Actual removal after animation\r\n setTimeout(() => {\r\n toastsSignal.update(current => {\r\n const toast = current.find(t => t.id === id);\r\n if (toast?.onClose) {\r\n toast.onClose();\r\n }\r\n return current.filter(t => t.id !== id);\r\n });\r\n }, 300); // Match animation duration\r\n }\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n","// src/kit/manager.tsx\r\n//\r\n// Made with ❤️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n import { render } from '@minejs/jsx';\r\n import { effect } from '@minejs/signals';\r\n import { ToastConfig, ToastInstance, ToastOptions } from '../types';\r\n import { toastsSignal, dismissToast } from './state';\r\n import { ToastContainer } from '@cruxkit/toast';\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ CORE ════════════════════════════════════════╗\r\n\r\n export class ToastManager {\r\n private containerElement: HTMLElement | null = null;\r\n private _cleanupTimer: any = null;\r\n private config: Required<ToastConfig> = {\r\n pre : {\r\n errors : [],\r\n warnings : [],\r\n success : [],\r\n info : [],\r\n },\r\n containerId : 'cruxkit-toast-container',\r\n position : 'bottom-right',\r\n className : '',\r\n };\r\n\r\n get toasts() {\r\n return toastsSignal;\r\n }\r\n\r\n constructor(config?: ToastConfig) {\r\n // Set default config values\r\n this.config = {\r\n ...this.config,\r\n ...config,\r\n };\r\n\r\n // Setup reactive cleanup\r\n effect(() => {\r\n const count = toastsSignal().length;\r\n if (count === 0) {\r\n this.checkCleanup();\r\n } else {\r\n if (this._cleanupTimer) {\r\n clearTimeout(this._cleanupTimer);\r\n this._cleanupTimer = null;\r\n }\r\n }\r\n });\r\n\r\n // Check URL parameters on initialization (client-side only check usually)\r\n if (typeof window !== 'undefined') {\r\n setTimeout(() => this.checkUrlParams(), 250);\r\n }\r\n }\r\n\r\n private checkUrlParams() {\r\n try {\r\n const params = new URLSearchParams(window.location.search);\r\n\r\n const terror = params.get('terror');\r\n if (terror && this.config.pre.errors) {\r\n const message = this.config.pre.errors.find(msg => msg.code === terror)?.message;\r\n if (message) {\r\n this.error(message);\r\n } else {\r\n console.warn(`[ToastManager] Unknown error code: ${terror}`);\r\n }\r\n }\r\n\r\n const twarning = params.get('twarning');\r\n if (twarning && this.config.pre.warnings) {\r\n const message = this.config.pre.warnings.find(msg => msg.code === twarning)?.message;\r\n if (message) {\r\n this.warning(message);\r\n } else {\r\n console.warn(`[ToastManager] Unknown warning code: ${twarning}`);\r\n }\r\n }\r\n\r\n const tsuccess = params.get('tsuccess');\r\n if (tsuccess && this.config.pre.success) {\r\n const message = this.config.pre.success.find(msg => msg.code === tsuccess)?.message;\r\n if (message) {\r\n this.success(message);\r\n } else {\r\n console.warn(`[ToastManager] Unknown success code: ${tsuccess}`);\r\n }\r\n }\r\n\r\n const tinfo = params.get('tinfo');\r\n if (tinfo && this.config.pre.info) {\r\n const message = this.config.pre.info.find(msg => msg.code === tinfo)?.message;\r\n if (message) {\r\n this.info(message);\r\n } else {\r\n console.warn(`[ToastManager] Unknown info code: ${tinfo}`);\r\n }\r\n }\r\n\r\n // Optional: Clean URL params?\r\n window.history.replaceState({}, '', window.location.pathname);\r\n } catch (e) {\r\n console.error('[ToastManager] Error checking URL params', e);\r\n }\r\n }\r\n\r\n private ensureMounted() {\r\n if (typeof window === 'undefined') return;\r\n\r\n // If we have a cleanup timer pending, cancel it because we are adding new toasts\r\n if (this._cleanupTimer) {\r\n clearTimeout(this._cleanupTimer);\r\n this._cleanupTimer = null;\r\n }\r\n\r\n if (this.containerElement && document.getElementById(this.config.containerId!)) return;\r\n\r\n // Check if already in DOM (e.g. from SSR or previous instance that wasn't tracked)\r\n let el = document.getElementById(this.config.containerId!);\r\n if (!el) {\r\n el = document.createElement('div');\r\n el.id = this.config.containerId!;\r\n document.body.appendChild(el);\r\n }\r\n this.containerElement = el;\r\n\r\n // Render the container\r\n // We use default props for now.\r\n // If user wants to configure position, they might need a configure method or we pass it here.\r\n // For now, we assume default.\r\n render(\r\n <ToastContainer\r\n {...this.config}\r\n toasts={toastsSignal}\r\n onDismiss={(id) => this.dismiss(id)}\r\n />,\r\n `#${this.config.containerId}`\r\n );\r\n }\r\n\r\n private checkCleanup() {\r\n // \"remove after finish\"\r\n if (toastsSignal().length === 0) {\r\n // Delay cleanup slightly to allow for exit animations if any (though Overlay usually handles its own existence)\r\n // But more importantly, if user spams toasts, we don't want to mount/unmount rapidly.\r\n this._cleanupTimer = setTimeout(() => {\r\n if (toastsSignal().length === 0 && this.containerElement) {\r\n this.containerElement.remove();\r\n this.containerElement = null;\r\n this._cleanupTimer = null;\r\n }\r\n }, 500);\r\n }\r\n }\r\n\r\n show(message: string, options: ToastOptions = {}) {\r\n this.ensureMounted();\r\n\r\n const id = Math.random().toString(36).substr(2, 9);\r\n const type = options.type || 'info';\r\n const duration = options.duration || 3000;\r\n\r\n const instance: ToastInstance = {\r\n id,\r\n message,\r\n type,\r\n duration,\r\n onClose: options.onClose\r\n };\r\n\r\n toastsSignal.update(current => [...current, instance]);\r\n\r\n if (duration > 0) {\r\n setTimeout(() => {\r\n this.dismiss(id);\r\n }, duration);\r\n }\r\n\r\n return id;\r\n }\r\n\r\n success(message: string, options?: Omit<ToastOptions, 'type'>) {\r\n return this.show(message, { ...options, type: 'success' });\r\n }\r\n\r\n error(message: string, options?: Omit<ToastOptions, 'type'>) {\r\n return this.show(message, { ...options, type: 'error' });\r\n }\r\n\r\n warning(message: string, options?: Omit<ToastOptions, 'type'>) {\r\n return this.show(message, { ...options, type: 'warning' });\r\n }\r\n\r\n info(message: string, options?: Omit<ToastOptions, 'type'>) {\r\n return this.show(message, { ...options, type: 'info' });\r\n }\r\n\r\n dismiss(id: string) {\r\n dismissToast(id);\r\n }\r\n\r\n clear() {\r\n toastsSignal.set([]);\r\n }\r\n }\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n","// src/index.ts\r\n//\r\n// Made with ❤️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n import { ClientExtension, ExtensionContext } from \"@cruxjs/base\";\r\n import { ToastConfig } from \"./types\";\r\n import { ToastManager } from \"./mod/manager\";\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ INIT ════════════════════════════════════════╗\r\n\r\n let toastManager : ToastManager;\r\n export const toast = () => toastManager;\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ CORE ════════════════════════════════════════╗\r\n\r\n /**\r\n * Create a toast extension\r\n * @param config Toast configuration\r\n * @returns Toast extension\r\n */\r\n export function toastExtension(config?: ToastConfig) : ClientExtension {\r\n return {\r\n name : 'ToastExtension',\r\n\r\n onBoot: (ctx: ExtensionContext) => {\r\n // inject allowed query params\r\n ctx.cconfig.allowedQueryParams = [\r\n 'terror',\r\n 'tsuccess',\r\n 'twarning',\r\n 'tinfo',\r\n ...ctx.cconfig.allowedQueryParams ?? [],\r\n ];\r\n\r\n // create toast manager instance\r\n toastManager = new ToastManager(config);\r\n }\r\n };\r\n };\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ ════ ════════════════════════════════════════╗\r\n\r\n export * from \"./types\";\r\n export * from \"./mod/manager\";\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝"]}
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@cruxext/toast",
3
+ "version": "0.0.1",
4
+ "description": "Lightweight reactive toast manager for CruxJS.",
5
+ "keywords": ["cruxjs", "extension", "toast"],
6
+ "license": "MIT",
7
+ "homepage": "https://github.com/cruxext-org/toast#readme",
8
+ "bugs": {
9
+ "url": "https://github.com/cruxext-org/toast/issues"
10
+ },
11
+ "author": {
12
+ "name": "Maysara",
13
+ "email": "maysara.elshewehy@gmail.com",
14
+ "url": "https://github.com/maysara-elshewehy"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/cruxext-org/toast.git"
19
+ },
20
+ "type": "module",
21
+ "main": "./dist/index.js",
22
+ "types": "./dist/index.d.ts",
23
+ "files": ["dist"],
24
+ "exports": {
25
+ ".": {
26
+ "types": "./dist/index.d.ts",
27
+ "import": "./dist/index.js",
28
+ "require": "./dist/index.js"
29
+ }
30
+ },
31
+ "scripts": {
32
+ "build": "tsup",
33
+ "lint": "eslint src --ext .ts",
34
+ "test": "bun test"
35
+ },
36
+ "engines": {
37
+ "bun": ">=1.3.3"
38
+ },
39
+ "peerDependencies": {
40
+ "bun": "^1.3.3"
41
+ },
42
+ "dependencies": {
43
+ "@cruxjs/base": "^0.2.0",
44
+ "@cruxkit/toast": "^0.0.2",
45
+ "@minejs/jsx": "^0.1.8",
46
+ "@minejs/signals": "^0.0.6"
47
+ },
48
+ "devDependencies": {
49
+ "@eslint/js": "^9.39.2",
50
+ "@stylistic/eslint-plugin": "^5.7.1",
51
+ "@types/bun": "^1.3.6",
52
+ "@types/jsdom": "^27.0.0",
53
+ "@types/node": "^20.19.30",
54
+ "@types/react": "^19.2.9",
55
+ "bun-plugin-dts": "^0.3.0",
56
+ "bun-types": "^1.3.6",
57
+ "jsdom": "^27.4.0",
58
+ "ts-node": "^10.9.2",
59
+ "tsup": "^8.5.1",
60
+ "typescript": "^5.9.3",
61
+ "typescript-eslint": "^8.53.1"
62
+ }
63
+ }