universe-code 0.0.76 → 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';
|
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
import { connectDB } from "./idbStore.js";
|
|
2
|
+
|
|
2
3
|
let config = null;
|
|
3
4
|
|
|
5
|
+
// 🔹 promise that resolves once IndexedDB is configured
|
|
6
|
+
let resolveReady;
|
|
7
|
+
export const configReady = new Promise((res) => (resolveReady = res));
|
|
8
|
+
|
|
4
9
|
export const configureIdb = (options) => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
10
|
+
if (config) return;
|
|
11
|
+
|
|
12
|
+
config = options;
|
|
13
|
+
|
|
14
|
+
// notify others that config is ready
|
|
15
|
+
resolveReady?.();
|
|
16
|
+
|
|
17
|
+
// optional: eager connection
|
|
18
|
+
if (typeof window !== "undefined" && typeof indexedDB !== "undefined") {
|
|
9
19
|
connectDB();
|
|
20
|
+
}
|
|
10
21
|
};
|
|
11
22
|
|
|
12
23
|
export const getConfig = () => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
};
|
|
24
|
+
if (!config) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
"IndexedDB not configured. Call configureIdb() before using the store."
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
return config;
|
|
30
|
+
};
|
|
@@ -1,39 +1,62 @@
|
|
|
1
1
|
import { DBManager, DB } from "universe-code";
|
|
2
|
-
import { getConfig } from "./config.js";
|
|
2
|
+
import { getConfig, configReady } from "./config.js";
|
|
3
3
|
|
|
4
4
|
let db = null;
|
|
5
5
|
let store = null;
|
|
6
6
|
let manager = null;
|
|
7
7
|
|
|
8
|
-
//
|
|
8
|
+
// 🔹 Helper: only run in browser
|
|
9
|
+
const isBrowser = () =>
|
|
10
|
+
typeof window !== "undefined" && typeof indexedDB !== "undefined";
|
|
11
|
+
|
|
12
|
+
// ✅ connect to IndexedDB
|
|
9
13
|
export const connectDB = async () => {
|
|
10
|
-
|
|
14
|
+
// 🚫 Ignore during SSR / Node
|
|
15
|
+
if (!isBrowser()) return null;
|
|
16
|
+
|
|
17
|
+
// 🔥 wait for configureIdb() to be called
|
|
18
|
+
await configReady;
|
|
19
|
+
|
|
20
|
+
const { dbName, dbVersion, storeName } = getConfig();
|
|
11
21
|
|
|
12
22
|
if (!manager) {
|
|
13
23
|
manager = new DBManager(dbName, dbVersion);
|
|
14
24
|
}
|
|
15
25
|
|
|
16
26
|
if (!db) {
|
|
17
|
-
db = await manager.connect([{ name: storeName }]);
|
|
27
|
+
db = await manager.connect([{ name: storeName }]);
|
|
18
28
|
}
|
|
19
29
|
|
|
20
30
|
return db;
|
|
21
31
|
};
|
|
22
32
|
|
|
33
|
+
// ✅ Return usable store object
|
|
23
34
|
export const getIdbStore = async () => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
// 🚫 Ignore during SSR / Node
|
|
36
|
+
if (!isBrowser()) return null;
|
|
37
|
+
|
|
38
|
+
// already created? return cached store
|
|
39
|
+
if (store) return store;
|
|
40
|
+
|
|
41
|
+
// 🔥 wait for configureIdb()
|
|
42
|
+
await configReady;
|
|
43
|
+
|
|
44
|
+
const { storeName } = getConfig();
|
|
45
|
+
|
|
46
|
+
const database = await connectDB();
|
|
47
|
+
|
|
48
|
+
store = {
|
|
49
|
+
get: (key) => DB.get(database, storeName, key),
|
|
50
|
+
|
|
51
|
+
getWithExpiry: (key, ttl, api) =>
|
|
52
|
+
DB.getWithExpiry(database, storeName, key, ttl, api),
|
|
53
|
+
|
|
54
|
+
put: (data) => DB.put(database, storeName, data),
|
|
55
|
+
|
|
56
|
+
remove: (key) => DB.remove(database, storeName, key),
|
|
57
|
+
|
|
58
|
+
clear: () => DB.clear(database, storeName),
|
|
59
|
+
};
|
|
37
60
|
|
|
38
61
|
return store;
|
|
39
|
-
};
|
|
62
|
+
};
|
|
@@ -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">×</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.
|
|
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": [
|