@shival99/z-ui 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/assets/css/animations.css +207 -0
  2. package/assets/css/base.css +76 -0
  3. package/assets/css/tailwind.css +53 -0
  4. package/assets/css/themes/gray.css +73 -0
  5. package/assets/css/themes/green.css +75 -0
  6. package/assets/css/themes/hospital.css +79 -0
  7. package/assets/css/themes/neutral.css +73 -0
  8. package/assets/css/themes/orange.css +73 -0
  9. package/assets/css/themes/slate.css +73 -0
  10. package/assets/css/themes/stone.css +73 -0
  11. package/assets/css/themes/violet.css +73 -0
  12. package/assets/css/themes/zinc.css +73 -0
  13. package/assets/images/avatar.svg +6 -0
  14. package/assets/images/logo.svg +6 -0
  15. package/fesm2022/shival99-z-ui-components-z-accordion.mjs +148 -0
  16. package/fesm2022/shival99-z-ui-components-z-accordion.mjs.map +1 -0
  17. package/fesm2022/shival99-z-ui-components-z-breadcrumb.mjs +74 -0
  18. package/fesm2022/shival99-z-ui-components-z-breadcrumb.mjs.map +1 -0
  19. package/fesm2022/shival99-z-ui-components-z-button.mjs +155 -0
  20. package/fesm2022/shival99-z-ui-components-z-button.mjs.map +1 -0
  21. package/fesm2022/shival99-z-ui-components-z-calendar.mjs +2335 -0
  22. package/fesm2022/shival99-z-ui-components-z-calendar.mjs.map +1 -0
  23. package/fesm2022/shival99-z-ui-components-z-checkbox.mjs +240 -0
  24. package/fesm2022/shival99-z-ui-components-z-checkbox.mjs.map +1 -0
  25. package/fesm2022/shival99-z-ui-components-z-code.mjs +139 -0
  26. package/fesm2022/shival99-z-ui-components-z-code.mjs.map +1 -0
  27. package/fesm2022/shival99-z-ui-components-z-drawer.mjs +664 -0
  28. package/fesm2022/shival99-z-ui-components-z-drawer.mjs.map +1 -0
  29. package/fesm2022/shival99-z-ui-components-z-dropdown-menu.mjs +55 -0
  30. package/fesm2022/shival99-z-ui-components-z-dropdown-menu.mjs.map +1 -0
  31. package/fesm2022/shival99-z-ui-components-z-editor.mjs +411 -0
  32. package/fesm2022/shival99-z-ui-components-z-editor.mjs.map +1 -0
  33. package/fesm2022/shival99-z-ui-components-z-filter.mjs +794 -0
  34. package/fesm2022/shival99-z-ui-components-z-filter.mjs.map +1 -0
  35. package/fesm2022/shival99-z-ui-components-z-icon.mjs +451 -0
  36. package/fesm2022/shival99-z-ui-components-z-icon.mjs.map +1 -0
  37. package/fesm2022/shival99-z-ui-components-z-input.mjs +804 -0
  38. package/fesm2022/shival99-z-ui-components-z-input.mjs.map +1 -0
  39. package/fesm2022/shival99-z-ui-components-z-loading.mjs +105 -0
  40. package/fesm2022/shival99-z-ui-components-z-loading.mjs.map +1 -0
  41. package/fesm2022/shival99-z-ui-components-z-menu.mjs +351 -0
  42. package/fesm2022/shival99-z-ui-components-z-menu.mjs.map +1 -0
  43. package/fesm2022/shival99-z-ui-components-z-modal.mjs +722 -0
  44. package/fesm2022/shival99-z-ui-components-z-modal.mjs.map +1 -0
  45. package/fesm2022/shival99-z-ui-components-z-pagination.mjs +131 -0
  46. package/fesm2022/shival99-z-ui-components-z-pagination.mjs.map +1 -0
  47. package/fesm2022/shival99-z-ui-components-z-popover.mjs +917 -0
  48. package/fesm2022/shival99-z-ui-components-z-popover.mjs.map +1 -0
  49. package/fesm2022/shival99-z-ui-components-z-radio.mjs +154 -0
  50. package/fesm2022/shival99-z-ui-components-z-radio.mjs.map +1 -0
  51. package/fesm2022/shival99-z-ui-components-z-select.mjs +998 -0
  52. package/fesm2022/shival99-z-ui-components-z-select.mjs.map +1 -0
  53. package/fesm2022/shival99-z-ui-components-z-skeleton.mjs +139 -0
  54. package/fesm2022/shival99-z-ui-components-z-skeleton.mjs.map +1 -0
  55. package/fesm2022/shival99-z-ui-components-z-switch.mjs +127 -0
  56. package/fesm2022/shival99-z-ui-components-z-switch.mjs.map +1 -0
  57. package/fesm2022/shival99-z-ui-components-z-table.mjs +2628 -0
  58. package/fesm2022/shival99-z-ui-components-z-table.mjs.map +1 -0
  59. package/fesm2022/shival99-z-ui-components-z-tabs.mjs +259 -0
  60. package/fesm2022/shival99-z-ui-components-z-tabs.mjs.map +1 -0
  61. package/fesm2022/shival99-z-ui-components-z-timeline.mjs +335 -0
  62. package/fesm2022/shival99-z-ui-components-z-timeline.mjs.map +1 -0
  63. package/fesm2022/shival99-z-ui-components-z-toast.mjs +93 -0
  64. package/fesm2022/shival99-z-ui-components-z-toast.mjs.map +1 -0
  65. package/fesm2022/shival99-z-ui-components-z-tooltip.mjs +660 -0
  66. package/fesm2022/shival99-z-ui-components-z-tooltip.mjs.map +1 -0
  67. package/fesm2022/shival99-z-ui-components-z-upload.mjs +504 -0
  68. package/fesm2022/shival99-z-ui-components-z-upload.mjs.map +1 -0
  69. package/fesm2022/shival99-z-ui-i18n.mjs +258 -0
  70. package/fesm2022/shival99-z-ui-i18n.mjs.map +1 -0
  71. package/fesm2022/shival99-z-ui-pipes.mjs +116 -0
  72. package/fesm2022/shival99-z-ui-pipes.mjs.map +1 -0
  73. package/fesm2022/shival99-z-ui-providers.mjs +203 -0
  74. package/fesm2022/shival99-z-ui-providers.mjs.map +1 -0
  75. package/fesm2022/shival99-z-ui-services.mjs +919 -0
  76. package/fesm2022/shival99-z-ui-services.mjs.map +1 -0
  77. package/fesm2022/shival99-z-ui-utils.mjs +591 -0
  78. package/fesm2022/shival99-z-ui-utils.mjs.map +1 -0
  79. package/fesm2022/z-ui.mjs +3 -19924
  80. package/fesm2022/z-ui.mjs.map +1 -1
  81. package/package.json +129 -1
  82. package/types/shival99-z-ui-components-z-accordion.d.ts +55 -0
  83. package/types/shival99-z-ui-components-z-breadcrumb.d.ts +36 -0
  84. package/types/shival99-z-ui-components-z-button.d.ts +41 -0
  85. package/types/shival99-z-ui-components-z-calendar.d.ts +300 -0
  86. package/types/shival99-z-ui-components-z-checkbox.d.ts +84 -0
  87. package/types/shival99-z-ui-components-z-code.d.ts +35 -0
  88. package/types/shival99-z-ui-components-z-drawer.d.ts +232 -0
  89. package/types/shival99-z-ui-components-z-dropdown-menu.d.ts +50 -0
  90. package/types/shival99-z-ui-components-z-editor.d.ts +115 -0
  91. package/types/shival99-z-ui-components-z-filter.d.ts +268 -0
  92. package/types/shival99-z-ui-components-z-icon.d.ts +291 -0
  93. package/types/shival99-z-ui-components-z-input.d.ts +188 -0
  94. package/types/shival99-z-ui-components-z-loading.d.ts +46 -0
  95. package/types/shival99-z-ui-components-z-menu.d.ts +116 -0
  96. package/types/shival99-z-ui-components-z-modal.d.ts +270 -0
  97. package/types/shival99-z-ui-components-z-pagination.d.ts +52 -0
  98. package/types/shival99-z-ui-components-z-popover.d.ts +134 -0
  99. package/types/shival99-z-ui-components-z-radio.d.ts +63 -0
  100. package/types/shival99-z-ui-components-z-select.d.ts +268 -0
  101. package/types/shival99-z-ui-components-z-skeleton.d.ts +55 -0
  102. package/types/shival99-z-ui-components-z-switch.d.ts +48 -0
  103. package/types/shival99-z-ui-components-z-table.d.ts +482 -0
  104. package/types/shival99-z-ui-components-z-tabs.d.ts +75 -0
  105. package/types/shival99-z-ui-components-z-timeline.d.ts +98 -0
  106. package/types/shival99-z-ui-components-z-toast.d.ts +61 -0
  107. package/types/shival99-z-ui-components-z-tooltip.d.ts +85 -0
  108. package/types/shival99-z-ui-components-z-upload.d.ts +136 -0
  109. package/types/shival99-z-ui-i18n.d.ts +50 -0
  110. package/types/shival99-z-ui-pipes.d.ts +36 -0
  111. package/types/shival99-z-ui-providers.d.ts +132 -0
  112. package/types/shival99-z-ui-services.d.ts +364 -0
  113. package/types/shival99-z-ui-utils.d.ts +145 -0
  114. package/types/z-ui.d.ts +3 -4977
@@ -0,0 +1,919 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Injectable, inject, signal } from '@angular/core';
3
+ import { BehaviorSubject, Subject, firstValueFrom } from 'rxjs';
4
+ import { DOCUMENT } from '@angular/common';
5
+ import { TranslateService } from '@ngx-translate/core';
6
+
7
+ /**
8
+ * Z-Cache Service
9
+ * A localStorage-based cache service with optional encryption
10
+ */
11
+ const Z_CACHE_DEFAULT_PREFIX = 'z_';
12
+ class ZCacheService {
13
+ static _prefix = Z_CACHE_DEFAULT_PREFIX;
14
+ static _encrypt = true;
15
+ /**
16
+ * Configure the cache service
17
+ */
18
+ static configure(config) {
19
+ if (config.prefix) {
20
+ ZCacheService._prefix = config.prefix;
21
+ }
22
+ if (config.encrypt !== undefined) {
23
+ ZCacheService._encrypt = config.encrypt;
24
+ }
25
+ }
26
+ static _encode(data) {
27
+ const payload = { __z: true, __d: data };
28
+ return btoa(encodeURIComponent(JSON.stringify(payload)));
29
+ }
30
+ static _decode(data) {
31
+ try {
32
+ const decoded = JSON.parse(decodeURIComponent(atob(data)));
33
+ if (!decoded.__z) {
34
+ return null;
35
+ }
36
+ return decoded.__d;
37
+ }
38
+ catch {
39
+ return null;
40
+ }
41
+ }
42
+ static _getFullKey(key, encrypt) {
43
+ const prefixedKey = `${ZCacheService._prefix}${key}`;
44
+ return encrypt ? ZCacheService._encode(prefixedKey) : prefixedKey;
45
+ }
46
+ static _safeOperation(operation, fallback) {
47
+ try {
48
+ return operation();
49
+ }
50
+ catch (error) {
51
+ console.error('[ZCache] Operation error:', error);
52
+ return fallback;
53
+ }
54
+ }
55
+ /**
56
+ * Get a value from cache
57
+ * @param key - Cache key
58
+ * @param defaultValue - Default value if not found
59
+ * @param encrypt - Whether to use encryption (default: service config)
60
+ */
61
+ static get(key, defaultValue, encrypt = ZCacheService._encrypt) {
62
+ return ZCacheService._safeOperation(() => {
63
+ const _key = ZCacheService._getFullKey(key, encrypt);
64
+ const result = localStorage.getItem(_key);
65
+ if (!result) {
66
+ return defaultValue;
67
+ }
68
+ const data = encrypt ? ZCacheService._decode(result) : JSON.parse(result);
69
+ return data ?? defaultValue;
70
+ }, defaultValue);
71
+ }
72
+ /**
73
+ * Set a value in cache
74
+ * @param key - Cache key
75
+ * @param data - Data to store
76
+ * @param encrypt - Whether to use encryption
77
+ */
78
+ static set(key, data, encrypt = ZCacheService._encrypt) {
79
+ return ZCacheService._safeOperation(() => {
80
+ const _key = ZCacheService._getFullKey(key, encrypt);
81
+ const _value = encrypt ? ZCacheService._encode(data) : JSON.stringify(data);
82
+ localStorage.setItem(_key, _value);
83
+ return true;
84
+ }, false);
85
+ }
86
+ /**
87
+ * Delete a key from cache
88
+ * @param key - Cache key
89
+ * @param encrypt - Whether key is encrypted
90
+ */
91
+ static delete(key, encrypt = ZCacheService._encrypt) {
92
+ return ZCacheService._safeOperation(() => {
93
+ const _key = ZCacheService._getFullKey(key, encrypt);
94
+ localStorage.removeItem(_key);
95
+ return true;
96
+ }, false);
97
+ }
98
+ /**
99
+ * Delete multiple keys from cache
100
+ * @param keys - Array of cache keys
101
+ * @param encrypt - Whether keys are encrypted
102
+ */
103
+ static deleteMultiple(keys, encrypt = ZCacheService._encrypt) {
104
+ return ZCacheService._safeOperation(() => {
105
+ keys.forEach(key => {
106
+ const _key = ZCacheService._getFullKey(key, encrypt);
107
+ localStorage.removeItem(_key);
108
+ });
109
+ return true;
110
+ }, false);
111
+ }
112
+ /**
113
+ * Clear all cache with the configured prefix
114
+ */
115
+ static clear() {
116
+ return ZCacheService._safeOperation(() => {
117
+ const keysToRemove = [];
118
+ const prefixEncoded = ZCacheService._encode(ZCacheService._prefix);
119
+ for (let i = 0; i < localStorage.length; i++) {
120
+ const key = localStorage.key(i);
121
+ if (key?.startsWith(ZCacheService._prefix) || key?.startsWith(prefixEncoded)) {
122
+ keysToRemove.push(key);
123
+ }
124
+ }
125
+ keysToRemove.forEach(key => localStorage.removeItem(key));
126
+ return true;
127
+ }, false);
128
+ }
129
+ /**
130
+ * Check if a key exists in cache
131
+ * @param key - Cache key
132
+ * @param encrypt - Whether key is encrypted
133
+ */
134
+ static has(key, encrypt = ZCacheService._encrypt) {
135
+ return ZCacheService._safeOperation(() => {
136
+ const _key = ZCacheService._getFullKey(key, encrypt);
137
+ return localStorage.getItem(_key) !== null;
138
+ }, false);
139
+ }
140
+ /**
141
+ * Get all keys with the configured prefix
142
+ */
143
+ static keys() {
144
+ return ZCacheService._safeOperation(() => {
145
+ const result = [];
146
+ const prefixEncoded = ZCacheService._encode(ZCacheService._prefix);
147
+ for (let i = 0; i < localStorage.length; i++) {
148
+ const key = localStorage.key(i);
149
+ if (key?.startsWith(ZCacheService._prefix)) {
150
+ result.push(key.slice(ZCacheService._prefix.length));
151
+ }
152
+ else if (key?.startsWith(prefixEncoded)) {
153
+ const decoded = ZCacheService._decode(key);
154
+ if (decoded) {
155
+ result.push(decoded.slice(ZCacheService._prefix.length));
156
+ }
157
+ }
158
+ }
159
+ return result;
160
+ }, []);
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Z-IndexDB Service
166
+ * A robust IndexedDB service with multi-store support, encryption, and retry logic
167
+ */
168
+ /** Default configuration */
169
+ const Z_INDEXDB_DEFAULT_CONFIG = {
170
+ dbName: 'ZDatabase',
171
+ version: 1,
172
+ mode: 'readwrite',
173
+ defaultStore: 'ZStore',
174
+ };
175
+ /** Batch size for bulk operations */
176
+ const Z_INDEXDB_BATCH_SIZE = 100;
177
+ class ZIndexDbService {
178
+ _db = null;
179
+ _dbName;
180
+ _version;
181
+ _mode;
182
+ _dbReady;
183
+ _stores = new Map();
184
+ _defaultStoreName;
185
+ _globalProtectedKeys;
186
+ constructor(config = {}) {
187
+ this._dbName = config.dbName ?? Z_INDEXDB_DEFAULT_CONFIG.dbName;
188
+ this._version = config.version ?? Z_INDEXDB_DEFAULT_CONFIG.version;
189
+ this._mode = config.mode ?? Z_INDEXDB_DEFAULT_CONFIG.mode;
190
+ this._defaultStoreName = config.defaultStore ?? Z_INDEXDB_DEFAULT_CONFIG.defaultStore;
191
+ this._globalProtectedKeys = config.protectedKeys ?? [];
192
+ if (config.stores?.length) {
193
+ config.stores.forEach(store => this._stores.set(store.name, store));
194
+ }
195
+ if (!this._stores.has(this._defaultStoreName)) {
196
+ this._stores.set(this._defaultStoreName, { name: this._defaultStoreName, encrypt: true });
197
+ }
198
+ this._dbReady = this._initDb();
199
+ }
200
+ _getStoreConfig(storeName) {
201
+ const name = storeName ?? this._defaultStoreName;
202
+ return this._stores.get(name) ?? { name, encrypt: true };
203
+ }
204
+ _encrypt(data) {
205
+ const payload = {
206
+ __z: true,
207
+ __t: typeof data,
208
+ __d: data,
209
+ };
210
+ return btoa(encodeURIComponent(JSON.stringify(payload)));
211
+ }
212
+ _decrypt(data) {
213
+ try {
214
+ const decoded = JSON.parse(decodeURIComponent(atob(data)));
215
+ if (!decoded.__z) {
216
+ return null;
217
+ }
218
+ return decoded.__d;
219
+ }
220
+ catch {
221
+ return null;
222
+ }
223
+ }
224
+ _closeConnection() {
225
+ if (this._db) {
226
+ this._db.close();
227
+ this._db = null;
228
+ }
229
+ }
230
+ async _reconnect() {
231
+ console.warn('[ZIndexDb] Reconnecting...');
232
+ this._closeConnection();
233
+ this._dbReady = this._initDb();
234
+ await this._dbReady;
235
+ }
236
+ async _withRetry(operation, retries = 3) {
237
+ let lastError;
238
+ for (let i = 0; i < retries; i++) {
239
+ try {
240
+ return await operation();
241
+ }
242
+ catch (error) {
243
+ lastError = error;
244
+ if (error instanceof Error && error.name === 'InvalidStateError') {
245
+ await this._reconnect();
246
+ }
247
+ await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 100));
248
+ }
249
+ }
250
+ throw lastError;
251
+ }
252
+ async _initDb() {
253
+ if (this._db) {
254
+ return;
255
+ }
256
+ return new Promise((resolve, reject) => {
257
+ try {
258
+ const request = indexedDB.open(this._dbName, this._version);
259
+ request.onupgradeneeded = event => {
260
+ const db = event.target.result;
261
+ this._stores.forEach((_, storeName) => {
262
+ if (!db.objectStoreNames.contains(storeName)) {
263
+ db.createObjectStore(storeName);
264
+ }
265
+ });
266
+ };
267
+ request.onsuccess = event => {
268
+ this._db = event.target.result;
269
+ this._db.onerror = e => console.error('[ZIndexDb] Error:', e.target.error);
270
+ this._db.onclose = () => {
271
+ console.warn('[ZIndexDb] Connection closed unexpectedly');
272
+ this._db = null;
273
+ };
274
+ resolve();
275
+ };
276
+ request.onerror = event => {
277
+ console.error('[ZIndexDb] Open error:', event.target.error);
278
+ reject(event.target.error);
279
+ };
280
+ }
281
+ catch (error) {
282
+ reject(error);
283
+ }
284
+ });
285
+ }
286
+ /**
287
+ * Get a value from the store
288
+ * @param key - The key to retrieve
289
+ * @param defaultValue - Default value if key not found
290
+ * @param storeName - Optional store name (uses default if not specified)
291
+ */
292
+ async get(key, defaultValue, storeName) {
293
+ const storeConfig = this._getStoreConfig(storeName);
294
+ return this._withRetry(async () => {
295
+ await this._dbReady;
296
+ if (!this._db) {
297
+ await this._reconnect();
298
+ if (!this._db) {
299
+ return defaultValue;
300
+ }
301
+ }
302
+ const _key = storeConfig.encrypt !== false ? this._encrypt(key) : key;
303
+ return new Promise(resolve => {
304
+ try {
305
+ const transaction = this._db.transaction([storeConfig.name], this._mode);
306
+ const store = transaction.objectStore(storeConfig.name);
307
+ const request = store.get(_key);
308
+ request.onsuccess = () => {
309
+ try {
310
+ const { result } = request;
311
+ if (!result) {
312
+ resolve(defaultValue);
313
+ return;
314
+ }
315
+ const decrypted = storeConfig.encrypt !== false ? this._decrypt(result) : result;
316
+ resolve(decrypted ?? defaultValue);
317
+ }
318
+ catch {
319
+ resolve(defaultValue);
320
+ }
321
+ };
322
+ request.onerror = () => resolve(defaultValue);
323
+ transaction.onerror = () => resolve(defaultValue);
324
+ }
325
+ catch {
326
+ resolve(defaultValue);
327
+ }
328
+ });
329
+ });
330
+ }
331
+ /**
332
+ * Set a value in the store
333
+ * @param key - The key to set
334
+ * @param value - The value to store
335
+ * @param storeName - Optional store name
336
+ */
337
+ async set(key, value, storeName) {
338
+ const storeConfig = this._getStoreConfig(storeName);
339
+ return this._withRetry(async () => {
340
+ await this._dbReady;
341
+ if (!this._db) {
342
+ await this._reconnect();
343
+ if (!this._db) {
344
+ throw new Error('Database not initialized');
345
+ }
346
+ }
347
+ const _key = storeConfig.encrypt !== false ? this._encrypt(key) : key;
348
+ const _value = storeConfig.encrypt !== false ? this._encrypt(value) : value;
349
+ return new Promise((resolve, reject) => {
350
+ try {
351
+ const transaction = this._db.transaction([storeConfig.name], 'readwrite');
352
+ const store = transaction.objectStore(storeConfig.name);
353
+ const request = store.put(_value, _key);
354
+ request.onerror = () => reject(request.error);
355
+ transaction.oncomplete = () => resolve();
356
+ transaction.onerror = () => reject(transaction.error);
357
+ }
358
+ catch (error) {
359
+ reject(error);
360
+ }
361
+ });
362
+ });
363
+ }
364
+ /**
365
+ * Delete a key from the store
366
+ * @param key - Key or array of keys to delete
367
+ * @param storeName - Optional store name
368
+ */
369
+ async delete(key, storeName) {
370
+ const storeConfig = this._getStoreConfig(storeName);
371
+ return this._withRetry(async () => {
372
+ await this._dbReady;
373
+ if (!this._db) {
374
+ await this._reconnect();
375
+ if (!this._db) {
376
+ throw new Error('Database not initialized');
377
+ }
378
+ }
379
+ const keys = Array.isArray(key) ? key : [key];
380
+ return new Promise((resolve, reject) => {
381
+ try {
382
+ const transaction = this._db.transaction([storeConfig.name], 'readwrite');
383
+ const store = transaction.objectStore(storeConfig.name);
384
+ keys.forEach(k => {
385
+ const _key = storeConfig.encrypt !== false ? this._encrypt(k) : k;
386
+ store.delete(_key);
387
+ });
388
+ transaction.oncomplete = () => resolve();
389
+ transaction.onerror = () => reject(transaction.error);
390
+ }
391
+ catch (error) {
392
+ reject(error);
393
+ }
394
+ });
395
+ });
396
+ }
397
+ /**
398
+ * Clear all data from a store (respecting protected keys)
399
+ * @param storeName - Optional store name
400
+ */
401
+ async clear(storeName) {
402
+ const storeConfig = this._getStoreConfig(storeName);
403
+ const protectedKeys = [...this._globalProtectedKeys, ...(storeConfig.protectedKeys ?? [])];
404
+ return this._withRetry(async () => {
405
+ await this._dbReady;
406
+ if (!this._db) {
407
+ await this._reconnect();
408
+ if (!this._db) {
409
+ throw new Error('Database not initialized');
410
+ }
411
+ }
412
+ if (protectedKeys.length === 0) {
413
+ return new Promise((resolve, reject) => {
414
+ const transaction = this._db.transaction([storeConfig.name], 'readwrite');
415
+ const store = transaction.objectStore(storeConfig.name);
416
+ const request = store.clear();
417
+ request.onsuccess = () => resolve();
418
+ request.onerror = () => reject(request.error);
419
+ });
420
+ }
421
+ return new Promise((resolve, reject) => {
422
+ try {
423
+ const transaction = this._db.transaction([storeConfig.name], 'readwrite');
424
+ const store = transaction.objectStore(storeConfig.name);
425
+ const keyRequest = store.getAllKeys();
426
+ keyRequest.onsuccess = () => {
427
+ const allKeys = keyRequest.result;
428
+ const encryptedProtected = protectedKeys.map(k => this._encrypt(k));
429
+ allKeys.forEach(k => {
430
+ if (!encryptedProtected.includes(k) && !protectedKeys.includes(k)) {
431
+ try {
432
+ const decrypted = this._decrypt(k);
433
+ if (!protectedKeys.includes(decrypted ?? '')) {
434
+ store.delete(k);
435
+ }
436
+ }
437
+ catch {
438
+ store.delete(k);
439
+ }
440
+ }
441
+ });
442
+ };
443
+ keyRequest.onerror = () => reject(keyRequest.error);
444
+ transaction.oncomplete = () => resolve();
445
+ transaction.onerror = () => reject(transaction.error);
446
+ }
447
+ catch (error) {
448
+ reject(error);
449
+ }
450
+ });
451
+ });
452
+ }
453
+ /**
454
+ * Get all items from a store
455
+ * @param storeName - Optional store name
456
+ */
457
+ async getAll(storeName) {
458
+ const storeConfig = this._getStoreConfig(storeName);
459
+ return this._withRetry(async () => {
460
+ await this._dbReady;
461
+ if (!this._db) {
462
+ await this._reconnect();
463
+ if (!this._db) {
464
+ return {};
465
+ }
466
+ }
467
+ return new Promise(resolve => {
468
+ try {
469
+ const transaction = this._db.transaction([storeConfig.name], this._mode);
470
+ const store = transaction.objectStore(storeConfig.name);
471
+ const keysRequest = store.getAllKeys();
472
+ const valuesRequest = store.getAll();
473
+ const results = {};
474
+ keysRequest.onsuccess = () => {
475
+ const keys = keysRequest.result;
476
+ const values = valuesRequest.result;
477
+ keys.forEach((key, index) => {
478
+ if (typeof key === 'string') {
479
+ try {
480
+ const _key = storeConfig.encrypt !== false ? this._decrypt(key) : key;
481
+ const _value = storeConfig.encrypt !== false ? this._decrypt(values[index]) : values[index];
482
+ if (_key && _value !== null) {
483
+ results[_key] = _value;
484
+ }
485
+ }
486
+ catch {
487
+ // Skip invalid entries
488
+ }
489
+ }
490
+ });
491
+ resolve(results);
492
+ };
493
+ keysRequest.onerror = () => resolve({});
494
+ transaction.onerror = () => resolve({});
495
+ }
496
+ catch {
497
+ resolve({});
498
+ }
499
+ });
500
+ });
501
+ }
502
+ /**
503
+ * Set multiple items at once
504
+ * @param items - Object with key-value pairs
505
+ * @param storeName - Optional store name
506
+ */
507
+ async setMultiple(items, storeName) {
508
+ const storeConfig = this._getStoreConfig(storeName);
509
+ const entries = Object.entries(items);
510
+ for (let i = 0; i < entries.length; i += Z_INDEXDB_BATCH_SIZE) {
511
+ const batch = entries.slice(i, i + Z_INDEXDB_BATCH_SIZE);
512
+ await this._withRetry(async () => {
513
+ await this._dbReady;
514
+ if (!this._db) {
515
+ await this._reconnect();
516
+ if (!this._db) {
517
+ throw new Error('Database not initialized');
518
+ }
519
+ }
520
+ return new Promise((resolve, reject) => {
521
+ const transaction = this._db.transaction([storeConfig.name], 'readwrite');
522
+ const store = transaction.objectStore(storeConfig.name);
523
+ batch.forEach(([key, value]) => {
524
+ const _key = storeConfig.encrypt !== false ? this._encrypt(key) : key;
525
+ const _value = storeConfig.encrypt !== false ? this._encrypt(value) : value;
526
+ store.put(_value, _key);
527
+ });
528
+ transaction.oncomplete = () => resolve();
529
+ transaction.onerror = () => reject(transaction.error);
530
+ });
531
+ });
532
+ }
533
+ }
534
+ /**
535
+ * Get the list of available store names
536
+ */
537
+ getStoreNames() {
538
+ return Array.from(this._stores.keys());
539
+ }
540
+ /**
541
+ * Check if a store exists
542
+ * @param storeName - Store name to check
543
+ */
544
+ hasStore(storeName) {
545
+ return this._stores.has(storeName);
546
+ }
547
+ /**
548
+ * Add a new store (requires database version upgrade)
549
+ * Note: This will cause database reconnection
550
+ * @param config - Store configuration
551
+ */
552
+ async addStore(config) {
553
+ if (this._stores.has(config.name)) {
554
+ return;
555
+ }
556
+ this._stores.set(config.name, config);
557
+ this._version += 1;
558
+ this._closeConnection();
559
+ this._dbReady = this._initDb();
560
+ await this._dbReady;
561
+ }
562
+ }
563
+
564
+ /**
565
+ * Z-Subject Service
566
+ * A service for managing reactive subjects (Subject and BehaviorSubject)
567
+ */
568
+ class ZSubjectService {
569
+ _subjects = new Map();
570
+ _behaviorSubjects = new Map();
571
+ /**
572
+ * Emit a value to a subject
573
+ * @param key - Subject identifier
574
+ * @param type - 'subject' for Subject, 'behavior' for BehaviorSubject
575
+ * @param value - Value to emit
576
+ */
577
+ emit(key, type, value) {
578
+ if (type === 'behavior') {
579
+ const existingSubject = this._behaviorSubjects.get(key);
580
+ if (existingSubject) {
581
+ existingSubject.next(value);
582
+ return;
583
+ }
584
+ const newSubject = new BehaviorSubject(value);
585
+ this._behaviorSubjects.set(key, newSubject);
586
+ return;
587
+ }
588
+ const existingSubject = this._subjects.get(key);
589
+ if (existingSubject) {
590
+ existingSubject.next(value);
591
+ return;
592
+ }
593
+ const newSubject = new Subject();
594
+ this._subjects.set(key, newSubject);
595
+ newSubject.next(value);
596
+ }
597
+ /**
598
+ * Get an observable for a subject
599
+ * @param key - Subject identifier
600
+ * @param type - 'subject' for Subject, 'behavior' for BehaviorSubject
601
+ * @param initialValue - Initial value for BehaviorSubject (required for new behavior subjects)
602
+ */
603
+ on$(key, type, initialValue) {
604
+ if (type === 'behavior') {
605
+ const existingSubject = this._behaviorSubjects.get(key);
606
+ if (existingSubject) {
607
+ return existingSubject.asObservable();
608
+ }
609
+ const newSubject = new BehaviorSubject(initialValue);
610
+ this._behaviorSubjects.set(key, newSubject);
611
+ return newSubject.asObservable();
612
+ }
613
+ const existingSubject = this._subjects.get(key);
614
+ if (existingSubject) {
615
+ return existingSubject.asObservable();
616
+ }
617
+ const newSubject = new Subject();
618
+ this._subjects.set(key, newSubject);
619
+ return newSubject.asObservable();
620
+ }
621
+ /**
622
+ * Get the current value of a BehaviorSubject
623
+ * @param key - Subject identifier
624
+ */
625
+ getValue(key) {
626
+ const subject = this._behaviorSubjects.get(key);
627
+ if (!subject) {
628
+ return undefined;
629
+ }
630
+ return subject.getValue();
631
+ }
632
+ /**
633
+ * Complete and remove a subject
634
+ * @param key - Subject identifier
635
+ * @param type - 'subject' for Subject, 'behavior' for BehaviorSubject
636
+ */
637
+ complete(key, type) {
638
+ if (type === 'behavior') {
639
+ const subject = this._behaviorSubjects.get(key);
640
+ if (!subject) {
641
+ return;
642
+ }
643
+ subject.complete();
644
+ this._behaviorSubjects.delete(key);
645
+ return;
646
+ }
647
+ const subject = this._subjects.get(key);
648
+ if (!subject) {
649
+ return;
650
+ }
651
+ subject.complete();
652
+ this._subjects.delete(key);
653
+ }
654
+ /**
655
+ * Complete all subjects
656
+ */
657
+ completeAll() {
658
+ this._subjects.forEach(subject => subject.complete());
659
+ this._behaviorSubjects.forEach(subject => subject.complete());
660
+ this._subjects.clear();
661
+ this._behaviorSubjects.clear();
662
+ }
663
+ /**
664
+ * Check if a subject exists
665
+ * @param key - Subject identifier
666
+ * @param type - 'subject' for Subject, 'behavior' for BehaviorSubject
667
+ */
668
+ has(key, type) {
669
+ if (type === 'behavior') {
670
+ return this._behaviorSubjects.has(key);
671
+ }
672
+ return this._subjects.has(key);
673
+ }
674
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ZSubjectService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
675
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ZSubjectService, providedIn: 'root' });
676
+ }
677
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ZSubjectService, decorators: [{
678
+ type: Injectable,
679
+ args: [{
680
+ providedIn: 'root',
681
+ }]
682
+ }] });
683
+
684
+ /**
685
+ * Z-Theme Types
686
+ */
687
+ const Z_DEFAULT_THEME = 'neutral';
688
+ const Z_THEME_CSS_MAP = {
689
+ neutral: '',
690
+ green: 'assets/css/themes/green.css',
691
+ orange: 'assets/css/themes/orange.css',
692
+ violet: 'assets/css/themes/violet.css',
693
+ stone: 'assets/css/themes/stone.css',
694
+ zinc: 'assets/css/themes/zinc.css',
695
+ gray: 'assets/css/themes/gray.css',
696
+ slate: 'assets/css/themes/slate.css',
697
+ hospital: 'assets/css/themes/hospital.css',
698
+ };
699
+
700
+ class ZThemeService {
701
+ _document = inject(DOCUMENT);
702
+ _isDark = signal(false, ...(ngDevMode ? [{ debugName: "_isDark" }] : []));
703
+ _currentTheme = signal(Z_DEFAULT_THEME, ...(ngDevMode ? [{ debugName: "_currentTheme" }] : []));
704
+ _loadedThemes = new Set(['neutral']);
705
+ isDark = this._isDark.asReadonly();
706
+ currentTheme = this._currentTheme.asReadonly();
707
+ setTheme(theme) {
708
+ this._currentTheme.set(theme);
709
+ if (this._loadedThemes.has(theme)) {
710
+ this._document.documentElement.setAttribute('z-theme', theme);
711
+ return;
712
+ }
713
+ if (!Z_THEME_CSS_MAP[theme]) {
714
+ this._document.documentElement.setAttribute('z-theme', theme);
715
+ return;
716
+ }
717
+ this._loadThemeCSS(theme, () => {
718
+ this._document.documentElement.setAttribute('z-theme', theme);
719
+ });
720
+ }
721
+ toggleDarkMode(isDark) {
722
+ this._isDark.set(isDark);
723
+ if (isDark) {
724
+ this._document.documentElement.classList.add('dark');
725
+ return;
726
+ }
727
+ this._document.documentElement.classList.remove('dark');
728
+ }
729
+ preloadTheme(theme) {
730
+ if (this._loadedThemes.has(theme) || !Z_THEME_CSS_MAP[theme]) {
731
+ return;
732
+ }
733
+ this._loadThemeCSS(theme);
734
+ }
735
+ _loadThemeCSS(theme, onLoad) {
736
+ const cssPath = Z_THEME_CSS_MAP[theme];
737
+ if (!cssPath) {
738
+ onLoad?.();
739
+ return;
740
+ }
741
+ const existingLink = this._document.querySelector(`link[data-theme="${theme}"]`);
742
+ if (existingLink) {
743
+ this._loadedThemes.add(theme);
744
+ onLoad?.();
745
+ return;
746
+ }
747
+ const link = this._document.createElement('link');
748
+ link.rel = 'stylesheet';
749
+ link.href = cssPath;
750
+ link.setAttribute('data-theme', theme);
751
+ link.onload = () => {
752
+ this._loadedThemes.add(theme);
753
+ onLoad?.();
754
+ };
755
+ link.onerror = () => {
756
+ console.error(`Failed to load theme "${theme}" from ${cssPath}`);
757
+ onLoad?.();
758
+ };
759
+ this._document.head.appendChild(link);
760
+ }
761
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ZThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
762
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ZThemeService, providedIn: 'root' });
763
+ }
764
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ZThemeService, decorators: [{
765
+ type: Injectable,
766
+ args: [{
767
+ providedIn: 'root',
768
+ }]
769
+ }] });
770
+
771
+ /**
772
+ * Z-Translate Service
773
+ * A translation service with async support and caching
774
+ */
775
+ const LANG_CACHE_KEY = 'Z_LANGUAGE';
776
+ const DEFAULT_LANG = 'vi';
777
+ class ZTranslateService {
778
+ _translate = inject(TranslateService);
779
+ /** Current language signal */
780
+ currentLang = signal(DEFAULT_LANG, ...(ngDevMode ? [{ debugName: "currentLang" }] : []));
781
+ /** Available languages */
782
+ availableLangs = signal(['vi', 'en'], ...(ngDevMode ? [{ debugName: "availableLangs" }] : []));
783
+ constructor() {
784
+ this._initialize();
785
+ }
786
+ _initialize() {
787
+ const savedLang = ZCacheService.get(LANG_CACHE_KEY) ?? DEFAULT_LANG;
788
+ this._translate.setFallbackLang(DEFAULT_LANG);
789
+ this._translate.use(savedLang);
790
+ this.currentLang.set(savedLang);
791
+ }
792
+ /**
793
+ * Change the current language
794
+ * @param lang - Language code
795
+ */
796
+ use(lang) {
797
+ this._translate.use(lang);
798
+ ZCacheService.set(LANG_CACHE_KEY, lang);
799
+ this.currentLang.set(lang);
800
+ }
801
+ /**
802
+ * Get the current language code
803
+ */
804
+ getLang() {
805
+ return this._translate.getCurrentLang() ?? DEFAULT_LANG;
806
+ }
807
+ /**
808
+ * Get translation synchronously (returns key if not found)
809
+ * @param key - Translation key
810
+ * @param params - Interpolation parameters
811
+ */
812
+ instant(key, params) {
813
+ if (!key) {
814
+ return '';
815
+ }
816
+ return this._translate.instant(key, params);
817
+ }
818
+ /**
819
+ * Get translation asynchronously
820
+ * @param key - Translation key
821
+ * @param params - Interpolation parameters
822
+ */
823
+ async get(key, params) {
824
+ if (!key) {
825
+ return '';
826
+ }
827
+ return firstValueFrom(this._translate.get(key, params));
828
+ }
829
+ /**
830
+ * Get translation as observable
831
+ * @param key - Translation key
832
+ * @param params - Interpolation parameters
833
+ */
834
+ get$(key, params) {
835
+ return this._translate.get(key, params);
836
+ }
837
+ /**
838
+ * Stream translations (re-emits on language change)
839
+ * @param key - Translation key
840
+ * @param params - Interpolation parameters
841
+ */
842
+ stream$(key, params) {
843
+ return this._translate.stream(key, params);
844
+ }
845
+ /**
846
+ * Get multiple translations at once
847
+ * @param keys - Array of translation keys
848
+ * @param params - Interpolation parameters (applied to all)
849
+ */
850
+ async getMany(keys, params) {
851
+ const results = {};
852
+ await Promise.all(keys.map(async (key) => {
853
+ results[key] = await this.get(key, params);
854
+ }));
855
+ return results;
856
+ }
857
+ /**
858
+ * Check if a translation key exists
859
+ * @param key - Translation key
860
+ */
861
+ has(key) {
862
+ const translation = this._translate.instant(key);
863
+ return translation !== key;
864
+ }
865
+ /**
866
+ * Add translations dynamically
867
+ * @param lang - Language code
868
+ * @param translations - Translation object
869
+ * @param shouldMerge - Whether to merge with existing translations
870
+ */
871
+ setTranslation(lang, translations, shouldMerge = true) {
872
+ this._translate.setTranslation(lang, translations, shouldMerge);
873
+ }
874
+ /**
875
+ * Get the underlying TranslateService for advanced usage
876
+ */
877
+ getNgxTranslate() {
878
+ return this._translate;
879
+ }
880
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ZTranslateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
881
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ZTranslateService, providedIn: 'root' });
882
+ }
883
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ZTranslateService, decorators: [{
884
+ type: Injectable,
885
+ args: [{
886
+ providedIn: 'root',
887
+ }]
888
+ }], ctorParameters: () => [] });
889
+
890
+ /**
891
+ * Z-Cache Types
892
+ */
893
+
894
+ /**
895
+ * Z-Http Types
896
+ */
897
+
898
+ /**
899
+ * Z-IndexDB Types
900
+ */
901
+
902
+ /**
903
+ * Z-Translate Types
904
+ */
905
+
906
+ /**
907
+ * Services types index
908
+ */
909
+
910
+ /**
911
+ * Services index
912
+ */
913
+
914
+ /**
915
+ * Generated bundle index. Do not edit.
916
+ */
917
+
918
+ export { ZCacheService, ZIndexDbService, ZSubjectService, ZThemeService, ZTranslateService, Z_DEFAULT_THEME, Z_THEME_CSS_MAP };
919
+ //# sourceMappingURL=shival99-z-ui-services.mjs.map