universe-code 0.0.77 → 0.0.78

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/dist/index.d.ts CHANGED
@@ -2,4 +2,5 @@ declare module 'universe-code';
2
2
  declare module 'universe-code/core';
3
3
  declare module 'universe-code/indexdb';
4
4
  declare module 'universe-code/react';
5
- declare module 'universe-code/angular';
5
+ declare module 'universe-code/angular';
6
+ declare module 'universe-code/uiux';
@@ -0,0 +1 @@
1
+ export { UniverseToaster, toaster } from "./toaster.js";
@@ -0,0 +1,239 @@
1
+ class UniverseToaster {
2
+ constructor() {
3
+ if (UniverseToaster.instance) return UniverseToaster.instance;
4
+
5
+ this.container = null;
6
+ this.toasts = [];
7
+ this.config = {
8
+ position: "top-right",
9
+ duration: 4000,
10
+ maxToasts: 5,
11
+ };
12
+ this.initialized = false;
13
+
14
+ UniverseToaster.instance = this;
15
+ }
16
+
17
+ /* ---------------- INIT ---------------- */
18
+ init() {
19
+ if (this.initialized) return;
20
+
21
+ this.container = document.createElement("div");
22
+ this.container.id = "universe-toaster-container";
23
+ this.container.className = `universe-toaster-container ${this.config.position}`;
24
+ document.body.appendChild(this.container);
25
+
26
+ this.injectStyles();
27
+ this.initialized = true;
28
+ }
29
+
30
+ /* ---------------- CONFIG ---------------- */
31
+ configure(options = {}) {
32
+ this.config = { ...this.config, ...options };
33
+ }
34
+
35
+ /* ---------------- STYLES ---------------- */
36
+ injectStyles() {
37
+ if (document.getElementById("universe-toaster-styles")) return;
38
+
39
+ const style = document.createElement("style");
40
+ style.id = "universe-toaster-styles";
41
+ style.textContent = `
42
+ @keyframes progress {
43
+ from { width: 100%; }
44
+ to { width: 0%; }
45
+ }
46
+
47
+ .universe-toaster-container {
48
+ position: fixed;
49
+ top: 20px;
50
+ right: 20px;
51
+ z-index: 9999;
52
+ max-width: 380px;
53
+ font-family: Arial, sans-serif;
54
+ }
55
+
56
+ .universe-toast {
57
+ background: #fff;
58
+ margin: 12px 0;
59
+ padding: 16px 18px;
60
+ border-radius: 12px;
61
+ box-shadow: 0 10px 35px rgba(0,0,0,0.25);
62
+ opacity: 0;
63
+ transform: translateX(100%);
64
+ transition: all 0.3s ease;
65
+ position: relative;
66
+ overflow: hidden;
67
+ }
68
+
69
+ .universe-toast.show {
70
+ opacity: 1;
71
+ transform: translateX(0);
72
+ }
73
+
74
+ .universe-toast.removing {
75
+ opacity: 0;
76
+ transform: translateX(100%);
77
+ }
78
+
79
+ .universe-toast-success { border-left: 5px solid #28a745; }
80
+ .universe-toast-error { border-left: 5px solid #dc3545; }
81
+ .universe-toast-warning { border-left: 5px solid #ffc107; }
82
+ .universe-toast-info { border-left: 5px solid #17a2b8; }
83
+
84
+ .universe-toast-header {
85
+ display: flex;
86
+ justify-content: space-between;
87
+ margin-bottom: 6px;
88
+ }
89
+
90
+ .universe-toast-title {
91
+ font-weight: 600;
92
+ font-size: 14px;
93
+ display: flex;
94
+ align-items: center;
95
+ }
96
+
97
+ .universe-toast-icon {
98
+ margin-right: 8px;
99
+ }
100
+
101
+ .universe-toast-message {
102
+ font-size: 13px;
103
+ color: #333;
104
+ }
105
+
106
+ .universe-toast-close {
107
+ background: none;
108
+ border: none;
109
+ font-size: 18px;
110
+ cursor: pointer;
111
+ color: #999;
112
+ }
113
+
114
+ .universe-toast-progress {
115
+ position: absolute;
116
+ bottom: 0;
117
+ left: 0;
118
+ height: 3px;
119
+ width: 100%;
120
+ opacity: 0.4;
121
+ }
122
+
123
+ .universe-toast-success .universe-toast-progress { background: #28a745; }
124
+ .universe-toast-error .universe-toast-progress { background: #dc3545; }
125
+ .universe-toast-warning .universe-toast-progress { background: #ffc107; }
126
+ .universe-toast-info .universe-toast-progress { background: #17a2b8; }
127
+ `;
128
+ document.head.appendChild(style);
129
+ }
130
+
131
+ /* ---------------- UTIL ---------------- */
132
+ getIcon(type) {
133
+ return { success: "✓", error: "✗", warning: "⚠", info: "ℹ" }[type] || "ℹ";
134
+ }
135
+
136
+ escape(text = "") {
137
+ const div = document.createElement("div");
138
+ div.textContent = text;
139
+ return div.innerHTML;
140
+ }
141
+
142
+ /* ---------------- SHOW ---------------- */
143
+ show(message, type = "info", options = {}) {
144
+ if (!this.initialized) this.init();
145
+
146
+ if (this.toasts.length >= this.config.maxToasts) {
147
+ this.remove(this.toasts[0].id);
148
+ }
149
+
150
+ const id = `toast-${Date.now()}`;
151
+ const duration =
152
+ typeof options.duration === "number"
153
+ ? options.duration
154
+ : this.config.duration;
155
+
156
+ const toast = document.createElement("div");
157
+ toast.className = `universe-toast universe-toast-${type}`;
158
+ toast.dataset.id = id;
159
+
160
+ toast.innerHTML = `
161
+ <div class="universe-toast-header">
162
+ <div class="universe-toast-title">
163
+ <span class="universe-toast-icon">${this.getIcon(type)}</span>
164
+ ${this.escape(options.title || "")}
165
+ </div>
166
+ <button class="universe-toast-close">&times;</button>
167
+ </div>
168
+ <div class="universe-toast-message">${this.escape(message)}</div>
169
+ <div class="universe-toast-progress"></div>
170
+ `;
171
+
172
+ const progress = toast.querySelector(".universe-toast-progress");
173
+ toast.querySelector(".universe-toast-close").onclick = () =>
174
+ this.remove(id);
175
+
176
+ if (duration > 0) {
177
+ progress.style.animation = `progress ${duration}ms linear forwards`;
178
+ } else {
179
+ progress.style.display = "none";
180
+ }
181
+
182
+ this.container.appendChild(toast);
183
+ this.toasts.push({ id, el: toast });
184
+
185
+ setTimeout(() => toast.classList.add("show"), 20);
186
+
187
+ if (duration > 0) {
188
+ setTimeout(() => this.remove(id), duration);
189
+ }
190
+ }
191
+
192
+ /* ---------------- REMOVE ---------------- */
193
+ remove(id) {
194
+ const toast = this.toasts.find(t => t.id === id);
195
+ if (!toast) return;
196
+
197
+ toast.el.classList.add("removing");
198
+
199
+ setTimeout(() => {
200
+ toast.el.remove();
201
+ this.toasts = this.toasts.filter(t => t.id !== id);
202
+ }, 300);
203
+ }
204
+
205
+ /* ---------------- HELPERS ---------------- */
206
+ success(msg, o) { this.show(msg, "success", o); }
207
+ error(msg, o) { this.show(msg, "error", o); }
208
+ warning(msg, o) { this.show(msg, "warning", o); }
209
+ info(msg, o) { this.show(msg, "info", o); }
210
+
211
+ clear() {
212
+ this.toasts.forEach(t => t.el.remove());
213
+ this.toasts = [];
214
+ }
215
+ }
216
+
217
+ /* ================= CALLABLE WRAPPER ================= */
218
+
219
+ const instance = new UniverseToaster();
220
+
221
+ /**
222
+ * toaster("success", "Message", { title, duration })
223
+ */
224
+ function toaster(type, message, options = {}) {
225
+ const allowed = ["success", "error", "warning", "info"];
226
+ const finalType = allowed.includes(type) ? type : "info";
227
+ instance.show(message, finalType, options);
228
+ }
229
+
230
+ /* Attach helpers */
231
+ toaster.success = (m, o) => instance.success(m, o);
232
+ toaster.error = (m, o) => instance.error(m, o);
233
+ toaster.warning = (m, o) => instance.warning(m, o);
234
+ toaster.info = (m, o) => instance.info(m, o);
235
+
236
+ toaster.configure = (o) => instance.configure(o);
237
+ toaster.clear = () => instance.clear();
238
+
239
+ export { UniverseToaster, toaster };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "universe-code",
3
- "version": "0.0.77",
3
+ "version": "0.0.78",
4
4
  "description": "Universal utility functions for all JS frameworks",
5
5
  "license": "ISC",
6
6
  "type": "module",
@@ -31,6 +31,10 @@
31
31
  "./core": {
32
32
  "import": "./dist/core/index.js",
33
33
  "types": "./dist/index.d.ts"
34
+ },
35
+ "./uiux": {
36
+ "import": "./dist/uiux/index.js",
37
+ "types": "./dist/index.d.ts"
34
38
  }
35
39
  },
36
40
  "files": [