orcas-angular 1.0.4 → 1.0.5

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 (46) hide show
  1. package/fesm2022/orcas-angular.mjs +1608 -0
  2. package/fesm2022/orcas-angular.mjs.map +1 -0
  3. package/package.json +39 -36
  4. package/types/orcas-angular.d.ts +460 -0
  5. package/.claude/settings.local.json +0 -8
  6. package/async/README.md +0 -46
  7. package/async/async.ts +0 -16
  8. package/async/cancellation-token.ts +0 -90
  9. package/dev/README.md +0 -41
  10. package/dev/console-hook.ts +0 -25
  11. package/dev/debug.service.ts.example +0 -29
  12. package/framework/README.md +0 -34
  13. package/framework/services-init.ts +0 -25
  14. package/index.ts +0 -25
  15. package/localization/README.md +0 -73
  16. package/localization/localization.interface.ts +0 -18
  17. package/localization/localization.service.ts +0 -131
  18. package/localization/localize.pipe.ts +0 -30
  19. package/log/README.md +0 -275
  20. package/log/echo-provider.ts +0 -27
  21. package/log/echo.ts +0 -635
  22. package/log/index.ts +0 -6
  23. package/log/log-systems.ts +0 -20
  24. package/navigation/README.md +0 -47
  25. package/navigation/back-on-click.directive.ts +0 -19
  26. package/navigation/index.ts +0 -3
  27. package/navigation/navigation-stack.service.ts +0 -33
  28. package/ng-package.json +0 -7
  29. package/storage/README.md +0 -75
  30. package/storage/capacitor-files.service.ts +0 -38
  31. package/storage/file-box.service.ts +0 -112
  32. package/storage/files.ts +0 -42
  33. package/storage/key-signals.ts +0 -49
  34. package/storage/local-storage-files.service.ts +0 -49
  35. package/storage/settings-signals.service.ts +0 -24
  36. package/storage/settings.service.ts +0 -24
  37. package/storage/tauri-files.service.ts +0 -69
  38. package/theme/README.md +0 -44
  39. package/theme/theme.service.ts +0 -33
  40. package/tsconfig.lib.json +0 -11
  41. package/ui/README.md +0 -42
  42. package/ui/context-menu/context-button.component.ts +0 -55
  43. package/ui/context-menu/context-header.component.ts +0 -15
  44. package/ui/context-menu/context-menu-trigger.directive.ts +0 -26
  45. package/ui/context-menu/context-menu.component.ts +0 -95
  46. package/ui/context-menu/index.ts +0 -4
@@ -0,0 +1,1608 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Injectable, computed, inject, signal, Pipe, InjectionToken, HostListener, Directive, effect, input, booleanAttribute, output, ViewChild, Component } from '@angular/core';
3
+ import { HttpClient } from '@angular/common/http';
4
+ import * as i1 from '@angular/router';
5
+ import { NavigationEnd } from '@angular/router';
6
+ import * as i2 from '@angular/common';
7
+ import { CommonModule } from '@angular/common';
8
+ import { lastValueFrom } from 'rxjs';
9
+
10
+ class Async {
11
+ static async delay(ms) {
12
+ return new Promise(resolve => setTimeout(resolve, ms));
13
+ }
14
+ static async until(check, timeoutMs = 10000, frequencyMs = 100) {
15
+ let timePassed = 0;
16
+ while (!check() && timePassed < timeoutMs) {
17
+ await Async.delay(frequencyMs);
18
+ timePassed += frequencyMs;
19
+ if (timePassed >= timeoutMs)
20
+ throw new Error('Timeout while waiting for condition');
21
+ }
22
+ }
23
+ }
24
+
25
+ class CancellationTokenInternal {
26
+ _isCancelled = false;
27
+ constructor(isCancelled = false) {
28
+ this._isCancelled = isCancelled;
29
+ }
30
+ /**
31
+ * Gets whether cancellation has been requested
32
+ */
33
+ isCancelled() {
34
+ return this._isCancelled;
35
+ }
36
+ /**
37
+ * Throws an error if cancellation has been requested
38
+ */
39
+ throwIfCancelled() {
40
+ if (this._isCancelled) {
41
+ throw new CancellationError('Operation was cancelled');
42
+ }
43
+ }
44
+ /**
45
+ * Internal method to cancel the token
46
+ */
47
+ cancel() {
48
+ this._isCancelled = true;
49
+ }
50
+ /**
51
+ * A token that is never cancelled
52
+ */
53
+ static None = new CancellationTokenInternal(false);
54
+ /**
55
+ * A token that is already cancelled
56
+ */
57
+ static Cancelled = new CancellationTokenInternal(true);
58
+ }
59
+ /**
60
+ * Error thrown when an operation is cancelled
61
+ */
62
+ class CancellationError extends Error {
63
+ constructor(message = 'Operation was cancelled') {
64
+ super(message);
65
+ this.name = 'CancellationError';
66
+ }
67
+ }
68
+ /**
69
+ * Source for creating and managing cancellation tokens
70
+ */
71
+ class CancellationTokenSource {
72
+ _token = new CancellationTokenInternal();
73
+ /**
74
+ * Gets the token currently associated with this source
75
+ */
76
+ get token() {
77
+ return this._token;
78
+ }
79
+ /**
80
+ * Cancels the current token and creates a new one
81
+ */
82
+ newUnique(timeoutMs = -1) {
83
+ this._token.cancel();
84
+ this._token = new CancellationTokenInternal();
85
+ if (timeoutMs != -1)
86
+ setTimeout(() => this._token.cancel(), timeoutMs);
87
+ return this._token;
88
+ }
89
+ /**
90
+ * Cancels the current token
91
+ */
92
+ cancel() {
93
+ this._token.cancel();
94
+ }
95
+ }
96
+
97
+ class ConsoleHook {
98
+ static commands = {};
99
+ static initialize() {
100
+ if (!window.r)
101
+ window.r = ConsoleHook.run.bind(ConsoleHook);
102
+ }
103
+ static register(commandName, method) {
104
+ ConsoleHook.initialize();
105
+ ConsoleHook.commands[commandName] = method;
106
+ }
107
+ static run(input, ...additionalParams) {
108
+ const [commandName, ...params] = input.split(' ');
109
+ const command = ConsoleHook.commands[commandName];
110
+ if (command) {
111
+ return command(...params, ...additionalParams);
112
+ }
113
+ else {
114
+ console.error(`Custom command "${commandName}" not found.`);
115
+ }
116
+ }
117
+ }
118
+
119
+ class ServicesInit {
120
+ injector;
121
+ constructor(injector) {
122
+ this.injector = injector;
123
+ }
124
+ async init(serviceClass, ...params) {
125
+ let className = `${serviceClass.name || 'unknown'}`;
126
+ const instance = this.injector.get(serviceClass);
127
+ if (!instance)
128
+ throw new Error(`Service not found: ${className}`);
129
+ const hasInit = typeof instance.init === 'function';
130
+ if (params.length > 0 && !hasInit)
131
+ throw new Error(`Service ${className} has no init method but initialization parameters were provided.`);
132
+ if (hasInit)
133
+ await instance.init(...params);
134
+ return instance;
135
+ }
136
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ServicesInit, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable });
137
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ServicesInit, providedIn: 'root' });
138
+ }
139
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ServicesInit, decorators: [{
140
+ type: Injectable,
141
+ args: [{ providedIn: 'root' }]
142
+ }], ctorParameters: () => [{ type: i0.Injector }] });
143
+
144
+ class LocalizationService {
145
+ defaultLanguage = 'en';
146
+ storageKey = 'orcas-language';
147
+ translations = {};
148
+ loaded = false;
149
+ $language;
150
+ $currentLang = computed(() => this.$language(), ...(ngDevMode ? [{ debugName: "$currentLang" }] : []));
151
+ http = inject(HttpClient);
152
+ constructor() {
153
+ this.$language = signal(this.getStoredLanguage(), ...(ngDevMode ? [{ debugName: "$language" }] : []));
154
+ }
155
+ async init(jsonPath = 'assets/translations.json', defaultLanguage = 'en', storageKey = 'orcas-language') {
156
+ this.defaultLanguage = defaultLanguage;
157
+ this.storageKey = storageKey;
158
+ this.$language.set(this.getStoredLanguage());
159
+ try {
160
+ this.translations = await this.http.get(jsonPath).toPromise();
161
+ this.loaded = true;
162
+ }
163
+ catch (err) {
164
+ console.error('Failed to load translations:', err);
165
+ }
166
+ }
167
+ getLanguage() {
168
+ return this.$language();
169
+ }
170
+ getDefaultLanguage() {
171
+ return this.defaultLanguage;
172
+ }
173
+ setActiveLanguage(lang) {
174
+ if (lang !== this.$language()) {
175
+ localStorage.setItem(this.storageKey, lang);
176
+ this.$language.set(lang);
177
+ }
178
+ }
179
+ translate(key, params, language) {
180
+ const lang = language || this.getLanguage();
181
+ if (!this.loaded) {
182
+ console.error('Localization: Translations not loaded yet!');
183
+ return key;
184
+ }
185
+ let translation = null;
186
+ // Handle pluralization: try singular suffix __1 first if count is 1
187
+ if (params && params.count === 1)
188
+ translation = this.resolveKey(`${key}__1`);
189
+ if (!translation)
190
+ translation = this.resolveKey(key);
191
+ if (!translation) {
192
+ console.warn(`Localization: Key not found for "${key}".`);
193
+ return key;
194
+ }
195
+ let translatedText = translation[lang];
196
+ if (!translatedText) {
197
+ console.warn(`Localization: Key "${key}" not found for language "${lang}". Falling back to default language.`);
198
+ translatedText = translation[this.defaultLanguage];
199
+ }
200
+ if (!translatedText) {
201
+ console.error(`Localization: Key "${key}" not found for default language "${this.defaultLanguage}".`);
202
+ return key;
203
+ }
204
+ if (params) {
205
+ if (Array.isArray(params))
206
+ return this.replaceArrayParams(translatedText, params);
207
+ else
208
+ return this.replaceObjectParams(translatedText, params);
209
+ }
210
+ return translatedText;
211
+ }
212
+ resolveKey(key) {
213
+ const keys = key.split('.');
214
+ let translation = this.translations;
215
+ for (const k of keys) {
216
+ if (!translation[k])
217
+ return null;
218
+ translation = translation[k];
219
+ }
220
+ return translation;
221
+ }
222
+ getStoredLanguage() {
223
+ return localStorage.getItem(this.storageKey) || this.defaultLanguage;
224
+ }
225
+ replaceArrayParams(text, params) {
226
+ let result = text;
227
+ params.forEach((param, index) => {
228
+ result = result.replace(new RegExp(`\\{\\{${index}\\}\\}`, 'g'), param.toString());
229
+ });
230
+ return result;
231
+ }
232
+ replaceObjectParams(text, params) {
233
+ let result = text;
234
+ Object.keys(params).forEach(key => {
235
+ result = result.replace(new RegExp(`\\{\\{${key}\\}\\}`, 'g'), params[key].toString());
236
+ });
237
+ return result;
238
+ }
239
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: LocalizationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
240
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: LocalizationService, providedIn: 'root' });
241
+ }
242
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: LocalizationService, decorators: [{
243
+ type: Injectable,
244
+ args: [{
245
+ providedIn: 'root'
246
+ }]
247
+ }], ctorParameters: () => [] });
248
+
249
+ class LocalizePipe {
250
+ localizationService;
251
+ lastLanguage = '';
252
+ lastKey = '';
253
+ lastParams;
254
+ lastResult = '';
255
+ constructor(localizationService) {
256
+ this.localizationService = localizationService;
257
+ }
258
+ transform(key, params) {
259
+ if (this.localizationService.$currentLang() !== this.lastLanguage
260
+ || key !== this.lastKey
261
+ || params !== this.lastParams) {
262
+ this.lastLanguage = this.localizationService.$currentLang();
263
+ this.lastKey = key;
264
+ this.lastParams = params;
265
+ this.lastResult = this.localizationService.translate(key, params);
266
+ }
267
+ return this.lastResult;
268
+ }
269
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: LocalizePipe, deps: [{ token: LocalizationService }], target: i0.ɵɵFactoryTarget.Pipe });
270
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.0", ngImport: i0, type: LocalizePipe, isStandalone: true, name: "localize", pure: false });
271
+ }
272
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: LocalizePipe, decorators: [{
273
+ type: Pipe,
274
+ args: [{
275
+ name: 'localize',
276
+ standalone: true,
277
+ pure: false
278
+ }]
279
+ }], ctorParameters: () => [{ type: LocalizationService }] });
280
+
281
+ /**
282
+ * Echo - A flexible logging library
283
+ * TypeScript port of Echo.cs core functionality (excluding Unity-specific features)
284
+ */
285
+ // ============================================================================
286
+ // Enums
287
+ // ============================================================================
288
+ var LogLevel;
289
+ (function (LogLevel) {
290
+ LogLevel[LogLevel["None"] = 0] = "None";
291
+ LogLevel[LogLevel["Error"] = 1] = "Error";
292
+ LogLevel[LogLevel["Warn"] = 2] = "Warn";
293
+ LogLevel[LogLevel["Info"] = 3] = "Info";
294
+ LogLevel[LogLevel["Debug"] = 4] = "Debug";
295
+ })(LogLevel || (LogLevel = {}));
296
+ var LogMode;
297
+ (function (LogMode) {
298
+ LogMode[LogMode["Always"] = 0] = "Always";
299
+ LogMode[LogMode["Once"] = 1] = "Once";
300
+ })(LogMode || (LogMode = {}));
301
+ var SystemColor;
302
+ (function (SystemColor) {
303
+ SystemColor[SystemColor["None"] = 0] = "None";
304
+ SystemColor[SystemColor["LabelOnly"] = 1] = "LabelOnly";
305
+ SystemColor[SystemColor["LabelAndMessage"] = 2] = "LabelAndMessage";
306
+ })(SystemColor || (SystemColor = {}));
307
+ // ============================================================================
308
+ // Configuration
309
+ // ============================================================================
310
+ class LogWriterConfig {
311
+ timestamp = true;
312
+ levelLabels = true;
313
+ levelColors = true;
314
+ systemColor = SystemColor.LabelOnly;
315
+ }
316
+ // ============================================================================
317
+ // Helpers
318
+ // ============================================================================
319
+ class Helpers {
320
+ static fnv1a32(str, hash = 2166136261) {
321
+ for (let i = 0; i < str.length; i++) {
322
+ hash ^= str.charCodeAt(i);
323
+ hash = Math.imul(hash, 16777619);
324
+ }
325
+ return hash >>> 0; // Convert to unsigned 32-bit integer
326
+ }
327
+ static getElementFromHash(collection, stringToHash) {
328
+ const hash = Helpers.fnv1a32(stringToHash);
329
+ const index = hash % collection.length;
330
+ return collection[index];
331
+ }
332
+ }
333
+ class WritersHelpers {
334
+ static getLevelLabel(level) {
335
+ switch (level) {
336
+ case LogLevel.Debug: return "DEBUG";
337
+ case LogLevel.Info: return "INFO";
338
+ case LogLevel.Warn: return "WARN";
339
+ case LogLevel.Error: return "ERROR";
340
+ default: return "???";
341
+ }
342
+ }
343
+ static systemColors = [
344
+ "\x1b[31m", // Red
345
+ "\x1b[32m", // Green
346
+ "\x1b[34m", // Blue
347
+ "\x1b[33m", // Yellow
348
+ "\x1b[36m", // Cyan
349
+ "\x1b[35m" // Magenta
350
+ ];
351
+ static levelColors = new Map([
352
+ [LogLevel.Debug, "\x1b[37m"], // White
353
+ [LogLevel.Info, "\x1b[36m"], // Cyan
354
+ [LogLevel.Warn, "\x1b[33m"], // Yellow
355
+ [LogLevel.Error, "\x1b[31m"] // Red
356
+ ]);
357
+ static resetColor = "\x1b[0m";
358
+ static grayColor = "\x1b[90m";
359
+ }
360
+ // ============================================================================
361
+ // Internal Classes
362
+ // ============================================================================
363
+ class HashesManager {
364
+ hashes = new Set();
365
+ tryAdd(system, message) {
366
+ let hash = Helpers.fnv1a32(message);
367
+ hash = Helpers.fnv1a32(system, hash);
368
+ if (this.hashes.has(hash)) {
369
+ return false;
370
+ }
371
+ this.hashes.add(hash);
372
+ return true;
373
+ }
374
+ clear() {
375
+ this.hashes.clear();
376
+ }
377
+ }
378
+ class LoggerCore {
379
+ logWriter;
380
+ echoSettings;
381
+ hashes;
382
+ constructor(config, hashes, logger) {
383
+ if (!config)
384
+ throw new Error("config cannot be null");
385
+ if (!hashes)
386
+ throw new Error("hashes cannot be null");
387
+ if (!logger)
388
+ throw new Error("logger cannot be null");
389
+ this.echoSettings = config;
390
+ this.hashes = hashes;
391
+ this.logWriter = logger;
392
+ }
393
+ isEnabled(system, level) {
394
+ return level <= this.echoSettings.getSystemLevel(system);
395
+ }
396
+ shouldLogOnce(system, message) {
397
+ return this.hashes.tryAdd(system, message);
398
+ }
399
+ clearHashes() {
400
+ this.hashes.clear();
401
+ }
402
+ write(level, mode, system, message) {
403
+ if (mode === LogMode.Always || this.shouldLogOnce(system, message)) {
404
+ this.logWriter.writeLog(level, system, message);
405
+ }
406
+ }
407
+ writeIfEnabled(level, mode, system, message) {
408
+ if (this.isEnabled(system, level)) {
409
+ this.write(level, mode, system, message);
410
+ }
411
+ }
412
+ writeIfEnabled1(level, mode, system, format, param1) {
413
+ if (this.isEnabled(system, level)) {
414
+ const message = this.formatString1(format, param1);
415
+ this.write(level, mode, system, message);
416
+ }
417
+ }
418
+ writeIfEnabled2(level, mode, system, format, param1, param2) {
419
+ if (this.isEnabled(system, level)) {
420
+ const message = this.formatString2(format, param1, param2);
421
+ this.write(level, mode, system, message);
422
+ }
423
+ }
424
+ writeIfEnabled3(level, mode, system, format, param1, param2, param3) {
425
+ if (this.isEnabled(system, level)) {
426
+ const message = this.formatString3(format, param1, param2, param3);
427
+ this.write(level, mode, system, message);
428
+ }
429
+ }
430
+ writeIfEnabled4(level, mode, system, format, param1, param2, param3, param4) {
431
+ if (this.isEnabled(system, level)) {
432
+ const message = this.formatString4(format, param1, param2, param3, param4);
433
+ this.write(level, mode, system, message);
434
+ }
435
+ }
436
+ formatString1(format, param1) {
437
+ return format.replace(/\{0\}/g, String(param1));
438
+ }
439
+ formatString2(format, param1, param2) {
440
+ return format.replace(/\{0\}/g, String(param1)).replace(/\{1\}/g, String(param2));
441
+ }
442
+ formatString3(format, param1, param2, param3) {
443
+ return format.replace(/\{0\}/g, String(param1)).replace(/\{1\}/g, String(param2)).replace(/\{2\}/g, String(param3));
444
+ }
445
+ formatString4(format, param1, param2, param3, param4) {
446
+ return format.replace(/\{0\}/g, String(param1)).replace(/\{1\}/g, String(param2)).replace(/\{2\}/g, String(param3)).replace(/\{3\}/g, String(param4));
447
+ }
448
+ }
449
+ // ============================================================================
450
+ // Public Classes
451
+ // ============================================================================
452
+ class EchoSettings {
453
+ systemLevels = new Map();
454
+ _defaultLevel = LogLevel.Warn;
455
+ updateCallbacks = [];
456
+ get defaultLevel() {
457
+ return this._defaultLevel;
458
+ }
459
+ onUpdated(callback) {
460
+ this.updateCallbacks.push(callback);
461
+ }
462
+ triggerUpdate() {
463
+ for (const callback of this.updateCallbacks) {
464
+ callback();
465
+ }
466
+ }
467
+ setSystemLevel(system, level) {
468
+ this.throwIfInvalidSystem(system);
469
+ this.systemLevels.set(system, level);
470
+ this.triggerUpdate();
471
+ }
472
+ clearSystemLevel(system) {
473
+ this.throwIfInvalidSystem(system);
474
+ if (this.systemLevels.delete(system)) {
475
+ this.triggerUpdate();
476
+ }
477
+ }
478
+ getSystemLevel(system) {
479
+ this.throwIfInvalidSystem(system);
480
+ return this.systemLevels.get(system) ?? this._defaultLevel;
481
+ }
482
+ tryGetSystemLevel(system) {
483
+ this.throwIfInvalidSystem(system);
484
+ const level = this.systemLevels.get(system);
485
+ return level !== undefined ? { success: true, level } : { success: false };
486
+ }
487
+ clearSystemLevels() {
488
+ this.systemLevels.clear();
489
+ this.triggerUpdate();
490
+ }
491
+ setDefaultLevel(level) {
492
+ this._defaultLevel = level;
493
+ this.triggerUpdate();
494
+ }
495
+ getAllSystemLevels() {
496
+ return this.systemLevels;
497
+ }
498
+ throwIfInvalidSystem(system) {
499
+ if (!system || system.length === 0) {
500
+ throw new Error("System name cannot be null or empty.");
501
+ }
502
+ }
503
+ }
504
+ class EchoLogger {
505
+ loggerCore;
506
+ constructor(loggerCore) {
507
+ if (!loggerCore)
508
+ throw new Error("loggerCore cannot be null");
509
+ this.loggerCore = loggerCore;
510
+ }
511
+ // Debug Methods
512
+ debug(system, formatOrMessage, param1, param2, param3, param4) {
513
+ if (param1 === undefined) {
514
+ this.loggerCore.writeIfEnabled(LogLevel.Debug, LogMode.Always, system, formatOrMessage);
515
+ }
516
+ else if (param2 === undefined) {
517
+ this.loggerCore.writeIfEnabled1(LogLevel.Debug, LogMode.Always, system, formatOrMessage, param1);
518
+ }
519
+ else if (param3 === undefined) {
520
+ this.loggerCore.writeIfEnabled2(LogLevel.Debug, LogMode.Always, system, formatOrMessage, param1, param2);
521
+ }
522
+ else if (param4 === undefined) {
523
+ this.loggerCore.writeIfEnabled3(LogLevel.Debug, LogMode.Always, system, formatOrMessage, param1, param2, param3);
524
+ }
525
+ else {
526
+ this.loggerCore.writeIfEnabled4(LogLevel.Debug, LogMode.Always, system, formatOrMessage, param1, param2, param3, param4);
527
+ }
528
+ }
529
+ debug1(system, formatOrMessage, param1, param2, param3, param4) {
530
+ if (param1 === undefined) {
531
+ this.loggerCore.writeIfEnabled(LogLevel.Debug, LogMode.Once, system, formatOrMessage);
532
+ }
533
+ else if (param2 === undefined) {
534
+ this.loggerCore.writeIfEnabled1(LogLevel.Debug, LogMode.Once, system, formatOrMessage, param1);
535
+ }
536
+ else if (param3 === undefined) {
537
+ this.loggerCore.writeIfEnabled2(LogLevel.Debug, LogMode.Once, system, formatOrMessage, param1, param2);
538
+ }
539
+ else if (param4 === undefined) {
540
+ this.loggerCore.writeIfEnabled3(LogLevel.Debug, LogMode.Once, system, formatOrMessage, param1, param2, param3);
541
+ }
542
+ else {
543
+ this.loggerCore.writeIfEnabled4(LogLevel.Debug, LogMode.Once, system, formatOrMessage, param1, param2, param3, param4);
544
+ }
545
+ }
546
+ // Info Methods
547
+ info(system, formatOrMessage, param1, param2, param3, param4) {
548
+ if (param1 === undefined) {
549
+ this.loggerCore.writeIfEnabled(LogLevel.Info, LogMode.Always, system, formatOrMessage);
550
+ }
551
+ else if (param2 === undefined) {
552
+ this.loggerCore.writeIfEnabled1(LogLevel.Info, LogMode.Always, system, formatOrMessage, param1);
553
+ }
554
+ else if (param3 === undefined) {
555
+ this.loggerCore.writeIfEnabled2(LogLevel.Info, LogMode.Always, system, formatOrMessage, param1, param2);
556
+ }
557
+ else if (param4 === undefined) {
558
+ this.loggerCore.writeIfEnabled3(LogLevel.Info, LogMode.Always, system, formatOrMessage, param1, param2, param3);
559
+ }
560
+ else {
561
+ this.loggerCore.writeIfEnabled4(LogLevel.Info, LogMode.Always, system, formatOrMessage, param1, param2, param3, param4);
562
+ }
563
+ }
564
+ info1(system, formatOrMessage, param1, param2, param3, param4) {
565
+ if (param1 === undefined) {
566
+ this.loggerCore.writeIfEnabled(LogLevel.Info, LogMode.Once, system, formatOrMessage);
567
+ }
568
+ else if (param2 === undefined) {
569
+ this.loggerCore.writeIfEnabled1(LogLevel.Info, LogMode.Once, system, formatOrMessage, param1);
570
+ }
571
+ else if (param3 === undefined) {
572
+ this.loggerCore.writeIfEnabled2(LogLevel.Info, LogMode.Once, system, formatOrMessage, param1, param2);
573
+ }
574
+ else if (param4 === undefined) {
575
+ this.loggerCore.writeIfEnabled3(LogLevel.Info, LogMode.Once, system, formatOrMessage, param1, param2, param3);
576
+ }
577
+ else {
578
+ this.loggerCore.writeIfEnabled4(LogLevel.Info, LogMode.Once, system, formatOrMessage, param1, param2, param3, param4);
579
+ }
580
+ }
581
+ // Warn Methods
582
+ warn(system, formatOrMessage, param1, param2, param3, param4) {
583
+ if (param1 === undefined) {
584
+ this.loggerCore.writeIfEnabled(LogLevel.Warn, LogMode.Always, system, formatOrMessage);
585
+ }
586
+ else if (param2 === undefined) {
587
+ this.loggerCore.writeIfEnabled1(LogLevel.Warn, LogMode.Always, system, formatOrMessage, param1);
588
+ }
589
+ else if (param3 === undefined) {
590
+ this.loggerCore.writeIfEnabled2(LogLevel.Warn, LogMode.Always, system, formatOrMessage, param1, param2);
591
+ }
592
+ else if (param4 === undefined) {
593
+ this.loggerCore.writeIfEnabled3(LogLevel.Warn, LogMode.Always, system, formatOrMessage, param1, param2, param3);
594
+ }
595
+ else {
596
+ this.loggerCore.writeIfEnabled4(LogLevel.Warn, LogMode.Always, system, formatOrMessage, param1, param2, param3, param4);
597
+ }
598
+ }
599
+ warn1(system, formatOrMessage, param1, param2, param3, param4) {
600
+ if (param1 === undefined) {
601
+ this.loggerCore.writeIfEnabled(LogLevel.Warn, LogMode.Once, system, formatOrMessage);
602
+ }
603
+ else if (param2 === undefined) {
604
+ this.loggerCore.writeIfEnabled1(LogLevel.Warn, LogMode.Once, system, formatOrMessage, param1);
605
+ }
606
+ else if (param3 === undefined) {
607
+ this.loggerCore.writeIfEnabled2(LogLevel.Warn, LogMode.Once, system, formatOrMessage, param1, param2);
608
+ }
609
+ else if (param4 === undefined) {
610
+ this.loggerCore.writeIfEnabled3(LogLevel.Warn, LogMode.Once, system, formatOrMessage, param1, param2, param3);
611
+ }
612
+ else {
613
+ this.loggerCore.writeIfEnabled4(LogLevel.Warn, LogMode.Once, system, formatOrMessage, param1, param2, param3, param4);
614
+ }
615
+ }
616
+ // Error Methods
617
+ error(system, formatOrMessage, param1, param2, param3, param4) {
618
+ if (param1 === undefined) {
619
+ this.loggerCore.writeIfEnabled(LogLevel.Error, LogMode.Always, system, formatOrMessage);
620
+ }
621
+ else if (param2 === undefined) {
622
+ this.loggerCore.writeIfEnabled1(LogLevel.Error, LogMode.Always, system, formatOrMessage, param1);
623
+ }
624
+ else if (param3 === undefined) {
625
+ this.loggerCore.writeIfEnabled2(LogLevel.Error, LogMode.Always, system, formatOrMessage, param1, param2);
626
+ }
627
+ else if (param4 === undefined) {
628
+ this.loggerCore.writeIfEnabled3(LogLevel.Error, LogMode.Always, system, formatOrMessage, param1, param2, param3);
629
+ }
630
+ else {
631
+ this.loggerCore.writeIfEnabled4(LogLevel.Error, LogMode.Always, system, formatOrMessage, param1, param2, param3, param4);
632
+ }
633
+ }
634
+ error1(system, formatOrMessage, param1, param2, param3, param4) {
635
+ if (param1 === undefined) {
636
+ this.loggerCore.writeIfEnabled(LogLevel.Error, LogMode.Once, system, formatOrMessage);
637
+ }
638
+ else if (param2 === undefined) {
639
+ this.loggerCore.writeIfEnabled1(LogLevel.Error, LogMode.Once, system, formatOrMessage, param1);
640
+ }
641
+ else if (param3 === undefined) {
642
+ this.loggerCore.writeIfEnabled2(LogLevel.Error, LogMode.Once, system, formatOrMessage, param1, param2);
643
+ }
644
+ else if (param4 === undefined) {
645
+ this.loggerCore.writeIfEnabled3(LogLevel.Error, LogMode.Once, system, formatOrMessage, param1, param2, param3);
646
+ }
647
+ else {
648
+ this.loggerCore.writeIfEnabled4(LogLevel.Error, LogMode.Once, system, formatOrMessage, param1, param2, param3, param4);
649
+ }
650
+ }
651
+ }
652
+ class EchoSystemLogger {
653
+ loggerCore;
654
+ system;
655
+ constructor(loggerCore, system) {
656
+ if (!loggerCore)
657
+ throw new Error("loggerCore cannot be null");
658
+ if (!system)
659
+ throw new Error("system cannot be null");
660
+ this.loggerCore = loggerCore;
661
+ this.system = system;
662
+ }
663
+ // Debug Methods
664
+ debug(formatOrMessage, param1, param2, param3, param4) {
665
+ if (param1 === undefined) {
666
+ this.loggerCore.writeIfEnabled(LogLevel.Debug, LogMode.Always, this.system, formatOrMessage);
667
+ }
668
+ else if (param2 === undefined) {
669
+ this.loggerCore.writeIfEnabled1(LogLevel.Debug, LogMode.Always, this.system, formatOrMessage, param1);
670
+ }
671
+ else if (param3 === undefined) {
672
+ this.loggerCore.writeIfEnabled2(LogLevel.Debug, LogMode.Always, this.system, formatOrMessage, param1, param2);
673
+ }
674
+ else if (param4 === undefined) {
675
+ this.loggerCore.writeIfEnabled3(LogLevel.Debug, LogMode.Always, this.system, formatOrMessage, param1, param2, param3);
676
+ }
677
+ else {
678
+ this.loggerCore.writeIfEnabled4(LogLevel.Debug, LogMode.Always, this.system, formatOrMessage, param1, param2, param3, param4);
679
+ }
680
+ }
681
+ debug1(formatOrMessage, param1, param2, param3, param4) {
682
+ if (param1 === undefined) {
683
+ this.loggerCore.writeIfEnabled(LogLevel.Debug, LogMode.Once, this.system, formatOrMessage);
684
+ }
685
+ else if (param2 === undefined) {
686
+ this.loggerCore.writeIfEnabled1(LogLevel.Debug, LogMode.Once, this.system, formatOrMessage, param1);
687
+ }
688
+ else if (param3 === undefined) {
689
+ this.loggerCore.writeIfEnabled2(LogLevel.Debug, LogMode.Once, this.system, formatOrMessage, param1, param2);
690
+ }
691
+ else if (param4 === undefined) {
692
+ this.loggerCore.writeIfEnabled3(LogLevel.Debug, LogMode.Once, this.system, formatOrMessage, param1, param2, param3);
693
+ }
694
+ else {
695
+ this.loggerCore.writeIfEnabled4(LogLevel.Debug, LogMode.Once, this.system, formatOrMessage, param1, param2, param3, param4);
696
+ }
697
+ }
698
+ // Info Methods
699
+ info(formatOrMessage, param1, param2, param3, param4) {
700
+ if (param1 === undefined) {
701
+ this.loggerCore.writeIfEnabled(LogLevel.Info, LogMode.Always, this.system, formatOrMessage);
702
+ }
703
+ else if (param2 === undefined) {
704
+ this.loggerCore.writeIfEnabled1(LogLevel.Info, LogMode.Always, this.system, formatOrMessage, param1);
705
+ }
706
+ else if (param3 === undefined) {
707
+ this.loggerCore.writeIfEnabled2(LogLevel.Info, LogMode.Always, this.system, formatOrMessage, param1, param2);
708
+ }
709
+ else if (param4 === undefined) {
710
+ this.loggerCore.writeIfEnabled3(LogLevel.Info, LogMode.Always, this.system, formatOrMessage, param1, param2, param3);
711
+ }
712
+ else {
713
+ this.loggerCore.writeIfEnabled4(LogLevel.Info, LogMode.Always, this.system, formatOrMessage, param1, param2, param3, param4);
714
+ }
715
+ }
716
+ info1(formatOrMessage, param1, param2, param3, param4) {
717
+ if (param1 === undefined) {
718
+ this.loggerCore.writeIfEnabled(LogLevel.Info, LogMode.Once, this.system, formatOrMessage);
719
+ }
720
+ else if (param2 === undefined) {
721
+ this.loggerCore.writeIfEnabled1(LogLevel.Info, LogMode.Once, this.system, formatOrMessage, param1);
722
+ }
723
+ else if (param3 === undefined) {
724
+ this.loggerCore.writeIfEnabled2(LogLevel.Info, LogMode.Once, this.system, formatOrMessage, param1, param2);
725
+ }
726
+ else if (param4 === undefined) {
727
+ this.loggerCore.writeIfEnabled3(LogLevel.Info, LogMode.Once, this.system, formatOrMessage, param1, param2, param3);
728
+ }
729
+ else {
730
+ this.loggerCore.writeIfEnabled4(LogLevel.Info, LogMode.Once, this.system, formatOrMessage, param1, param2, param3, param4);
731
+ }
732
+ }
733
+ // Warn Methods
734
+ warn(formatOrMessage, param1, param2, param3, param4) {
735
+ if (param1 === undefined) {
736
+ this.loggerCore.writeIfEnabled(LogLevel.Warn, LogMode.Always, this.system, formatOrMessage);
737
+ }
738
+ else if (param2 === undefined) {
739
+ this.loggerCore.writeIfEnabled1(LogLevel.Warn, LogMode.Always, this.system, formatOrMessage, param1);
740
+ }
741
+ else if (param3 === undefined) {
742
+ this.loggerCore.writeIfEnabled2(LogLevel.Warn, LogMode.Always, this.system, formatOrMessage, param1, param2);
743
+ }
744
+ else if (param4 === undefined) {
745
+ this.loggerCore.writeIfEnabled3(LogLevel.Warn, LogMode.Always, this.system, formatOrMessage, param1, param2, param3);
746
+ }
747
+ else {
748
+ this.loggerCore.writeIfEnabled4(LogLevel.Warn, LogMode.Always, this.system, formatOrMessage, param1, param2, param3, param4);
749
+ }
750
+ }
751
+ warn1(formatOrMessage, param1, param2, param3, param4) {
752
+ if (param1 === undefined) {
753
+ this.loggerCore.writeIfEnabled(LogLevel.Warn, LogMode.Once, this.system, formatOrMessage);
754
+ }
755
+ else if (param2 === undefined) {
756
+ this.loggerCore.writeIfEnabled1(LogLevel.Warn, LogMode.Once, this.system, formatOrMessage, param1);
757
+ }
758
+ else if (param3 === undefined) {
759
+ this.loggerCore.writeIfEnabled2(LogLevel.Warn, LogMode.Once, this.system, formatOrMessage, param1, param2);
760
+ }
761
+ else if (param4 === undefined) {
762
+ this.loggerCore.writeIfEnabled3(LogLevel.Warn, LogMode.Once, this.system, formatOrMessage, param1, param2, param3);
763
+ }
764
+ else {
765
+ this.loggerCore.writeIfEnabled4(LogLevel.Warn, LogMode.Once, this.system, formatOrMessage, param1, param2, param3, param4);
766
+ }
767
+ }
768
+ // Error Methods
769
+ error(formatOrMessage, param1, param2, param3, param4) {
770
+ if (param1 === undefined) {
771
+ this.loggerCore.writeIfEnabled(LogLevel.Error, LogMode.Always, this.system, formatOrMessage);
772
+ }
773
+ else if (param2 === undefined) {
774
+ this.loggerCore.writeIfEnabled1(LogLevel.Error, LogMode.Always, this.system, formatOrMessage, param1);
775
+ }
776
+ else if (param3 === undefined) {
777
+ this.loggerCore.writeIfEnabled2(LogLevel.Error, LogMode.Always, this.system, formatOrMessage, param1, param2);
778
+ }
779
+ else if (param4 === undefined) {
780
+ this.loggerCore.writeIfEnabled3(LogLevel.Error, LogMode.Always, this.system, formatOrMessage, param1, param2, param3);
781
+ }
782
+ else {
783
+ this.loggerCore.writeIfEnabled4(LogLevel.Error, LogMode.Always, this.system, formatOrMessage, param1, param2, param3, param4);
784
+ }
785
+ }
786
+ error1(formatOrMessage, param1, param2, param3, param4) {
787
+ if (param1 === undefined) {
788
+ this.loggerCore.writeIfEnabled(LogLevel.Error, LogMode.Once, this.system, formatOrMessage);
789
+ }
790
+ else if (param2 === undefined) {
791
+ this.loggerCore.writeIfEnabled1(LogLevel.Error, LogMode.Once, this.system, formatOrMessage, param1);
792
+ }
793
+ else if (param3 === undefined) {
794
+ this.loggerCore.writeIfEnabled2(LogLevel.Error, LogMode.Once, this.system, formatOrMessage, param1, param2);
795
+ }
796
+ else if (param4 === undefined) {
797
+ this.loggerCore.writeIfEnabled3(LogLevel.Error, LogMode.Once, this.system, formatOrMessage, param1, param2, param3);
798
+ }
799
+ else {
800
+ this.loggerCore.writeIfEnabled4(LogLevel.Error, LogMode.Once, this.system, formatOrMessage, param1, param2, param3, param4);
801
+ }
802
+ }
803
+ }
804
+ class Echo {
805
+ loggerCore;
806
+ loggers = new Map();
807
+ _settings;
808
+ constructor(writer) {
809
+ if (!writer)
810
+ throw new Error("writer cannot be null");
811
+ const hashes = new HashesManager();
812
+ this._settings = new EchoSettings();
813
+ this.loggerCore = new LoggerCore(this._settings, hashes, writer);
814
+ }
815
+ getLogger() {
816
+ const key = "";
817
+ if (!this.loggers.has(key)) {
818
+ this.loggers.set(key, new EchoLogger(this.loggerCore));
819
+ }
820
+ return this.loggers.get(key);
821
+ }
822
+ getSystemLogger(system) {
823
+ if (!system || system.length === 0) {
824
+ throw new Error("System name cannot be null or empty.");
825
+ }
826
+ if (!this.loggers.has(system)) {
827
+ this.loggers.set(system, new EchoSystemLogger(this.loggerCore, system));
828
+ }
829
+ return this.loggers.get(system);
830
+ }
831
+ get settings() {
832
+ return this._settings;
833
+ }
834
+ }
835
+ // ============================================================================
836
+ // Built-in Log Writers
837
+ // ============================================================================
838
+ class ConsoleLogWriter {
839
+ config;
840
+ constructor(config) {
841
+ if (!config)
842
+ throw new Error("config cannot be null");
843
+ this.config = config;
844
+ }
845
+ writeLog(level, system, message) {
846
+ let output = "";
847
+ if (this.config.timestamp) {
848
+ const now = new Date();
849
+ const timestamp = this.formatTimestamp(now);
850
+ output += `${WritersHelpers.grayColor}[${timestamp}]${WritersHelpers.resetColor} `;
851
+ }
852
+ if (this.config.levelLabels) {
853
+ const levelLabel = WritersHelpers.getLevelLabel(level);
854
+ if (this.config.levelColors) {
855
+ const color = WritersHelpers.levelColors.get(level) ?? "";
856
+ output += `${color}[${levelLabel}]${WritersHelpers.resetColor} `;
857
+ }
858
+ else {
859
+ output += `[${levelLabel}] `;
860
+ }
861
+ }
862
+ const systemColor = this.config.systemColor === SystemColor.LabelOnly ||
863
+ this.config.systemColor === SystemColor.LabelAndMessage
864
+ ? Helpers.getElementFromHash(WritersHelpers.systemColors, system)
865
+ : "";
866
+ if (systemColor) {
867
+ output += `${systemColor}[${system}]${WritersHelpers.resetColor} `;
868
+ }
869
+ else {
870
+ output += `[${system}] `;
871
+ }
872
+ if (this.config.systemColor === SystemColor.LabelAndMessage && systemColor) {
873
+ output += `${systemColor}${message}${WritersHelpers.resetColor}`;
874
+ }
875
+ else {
876
+ output += message;
877
+ }
878
+ console.log(output);
879
+ }
880
+ formatTimestamp(date) {
881
+ const year = date.getFullYear();
882
+ const month = String(date.getMonth() + 1).padStart(2, '0');
883
+ const day = String(date.getDate()).padStart(2, '0');
884
+ const hours = String(date.getHours()).padStart(2, '0');
885
+ const minutes = String(date.getMinutes()).padStart(2, '0');
886
+ const seconds = String(date.getSeconds()).padStart(2, '0');
887
+ const milliseconds = String(date.getMilliseconds()).padStart(3, '0');
888
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${milliseconds}`;
889
+ }
890
+ }
891
+ // ============================================================================
892
+ // Public API Helpers
893
+ // ============================================================================
894
+ class EchoConsole {
895
+ static new(config) {
896
+ const writerConfig = config ?? new LogWriterConfig();
897
+ const writer = new ConsoleLogWriter(writerConfig);
898
+ return new Echo(writer);
899
+ }
900
+ }
901
+
902
+ /**
903
+ * Constants for Echo logging system names.
904
+ * Using constants ensures consistency and prevents typos.
905
+ */
906
+ class LogSystems {
907
+ /** System for profiling and performance measurements */
908
+ static PROFILING = 'Profiling';
909
+ /** System for general application logs */
910
+ static GENERAL = 'General';
911
+ /** System for Git-related operations */
912
+ static GIT = 'Git';
913
+ /** System for UI and visual operations */
914
+ static UI = 'UI';
915
+ /** System for repository operations */
916
+ static REPOSITORY = 'Repository';
917
+ }
918
+
919
+ /**
920
+ * Echo provider for Angular dependency injection.
921
+ * Provides a singleton Echo instance with console writer.
922
+ */
923
+ /**
924
+ * Injection token for Echo logger instance
925
+ */
926
+ const ECHO = new InjectionToken('Echo Logger Instance');
927
+ /**
928
+ * Factory function to create Echo instance
929
+ */
930
+ function echoFactory() {
931
+ return EchoConsole.new();
932
+ }
933
+ /**
934
+ * Provider for Echo logger
935
+ * Use this in your module providers or inject it in services
936
+ */
937
+ const ECHO_PROVIDER = {
938
+ provide: ECHO,
939
+ useFactory: echoFactory
940
+ };
941
+
942
+ class NavigationStackService {
943
+ router;
944
+ location;
945
+ history = [];
946
+ constructor(router, location) {
947
+ this.router = router;
948
+ this.location = location;
949
+ this.router.events.subscribe((event) => {
950
+ if (event instanceof NavigationEnd)
951
+ this.history.push(event.urlAfterRedirects);
952
+ });
953
+ }
954
+ goBack() {
955
+ this.history.pop();
956
+ if (this.history.length > 0)
957
+ this.location.back();
958
+ else
959
+ this.router.navigateByUrl("/").then();
960
+ this.history.pop();
961
+ }
962
+ getBack() {
963
+ if (this.history.length > 1)
964
+ return this.history[this.history.length - 2];
965
+ return '';
966
+ }
967
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NavigationStackService, deps: [{ token: i1.Router }, { token: i2.Location }], target: i0.ɵɵFactoryTarget.Injectable });
968
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NavigationStackService, providedIn: 'root' });
969
+ }
970
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NavigationStackService, decorators: [{
971
+ type: Injectable,
972
+ args: [{
973
+ providedIn: 'root'
974
+ }]
975
+ }], ctorParameters: () => [{ type: i1.Router }, { type: i2.Location }] });
976
+
977
+ class BackOnClickDirective {
978
+ navigationStack;
979
+ constructor(navigationStack) {
980
+ this.navigationStack = navigationStack;
981
+ }
982
+ onClick(event) {
983
+ if (event)
984
+ event.preventDefault();
985
+ this.navigationStack.goBack();
986
+ }
987
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: BackOnClickDirective, deps: [{ token: NavigationStackService }], target: i0.ɵɵFactoryTarget.Directive });
988
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.0", type: BackOnClickDirective, isStandalone: true, selector: "[back-on-click]", host: { listeners: { "click": "onClick($event)" } }, ngImport: i0 });
989
+ }
990
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: BackOnClickDirective, decorators: [{
991
+ type: Directive,
992
+ args: [{
993
+ selector: '[back-on-click]',
994
+ standalone: true
995
+ }]
996
+ }], ctorParameters: () => [{ type: NavigationStackService }], propDecorators: { onClick: [{
997
+ type: HostListener,
998
+ args: ['click', ['$event']]
999
+ }] } });
1000
+
1001
+ class FilesService {
1002
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: FilesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1003
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: FilesService });
1004
+ }
1005
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: FilesService, decorators: [{
1006
+ type: Injectable
1007
+ }] });
1008
+
1009
+ var Status;
1010
+ (function (Status) {
1011
+ Status[Status["NotInitialized"] = 0] = "NotInitialized";
1012
+ Status[Status["Loading"] = 1] = "Loading";
1013
+ Status[Status["Idle"] = 2] = "Idle";
1014
+ Status[Status["Saving"] = 3] = "Saving";
1015
+ })(Status || (Status = {}));
1016
+ class FileBoxService {
1017
+ files = inject(FilesService);
1018
+ status = Status.NotInitialized;
1019
+ path = '';
1020
+ saveEnqueued = false;
1021
+ $dataWritable = signal({}, ...(ngDevMode ? [{ debugName: "$dataWritable" }] : []));
1022
+ $data = computed(() => {
1023
+ if (this.status === Status.NotInitialized)
1024
+ console.error('Service is not initialized.');
1025
+ else if (this.status === Status.Loading)
1026
+ console.error('Service is loading.');
1027
+ return this.$dataWritable();
1028
+ }, ...(ngDevMode ? [{ debugName: "$data" }] : []));
1029
+ async init(path) {
1030
+ if (this.status !== Status.NotInitialized) {
1031
+ console.error('Service is already initialized.');
1032
+ return;
1033
+ }
1034
+ this.path = path;
1035
+ try {
1036
+ this.status = Status.Loading;
1037
+ if (await this.files.hasInStorage(this.path)) {
1038
+ const fileContent = await this.files.readFromStorage(this.path);
1039
+ this.$dataWritable.set(JSON.parse(fileContent));
1040
+ }
1041
+ }
1042
+ catch (error) {
1043
+ console.error('Failed to load file:', error);
1044
+ this.$dataWritable.set({});
1045
+ }
1046
+ finally {
1047
+ this.status = Status.Idle;
1048
+ }
1049
+ }
1050
+ has(key) {
1051
+ return key in this.$data();
1052
+ }
1053
+ set(key, value) {
1054
+ this.checkType(value);
1055
+ const newData = { ...this.$dataWritable() };
1056
+ newData[key] = value;
1057
+ this.$dataWritable.set(newData);
1058
+ }
1059
+ setAll(data) {
1060
+ this.$dataWritable.set(data);
1061
+ }
1062
+ remove(key) {
1063
+ const newData = { ...this.$dataWritable() };
1064
+ delete newData[key];
1065
+ this.$dataWritable.set(newData);
1066
+ }
1067
+ checkType(value) {
1068
+ if (value instanceof Function)
1069
+ throw new Error('Cannot save functions.');
1070
+ if (value instanceof Promise)
1071
+ throw new Error('Cannot save promises.');
1072
+ }
1073
+ async save() {
1074
+ if (this.saveEnqueued)
1075
+ return;
1076
+ this.saveEnqueued = true;
1077
+ while (this.status === Status.Saving)
1078
+ await Async.delay(100);
1079
+ this.saveEnqueued = false;
1080
+ try {
1081
+ this.status = Status.Saving;
1082
+ const dataString = JSON.stringify(this.$data());
1083
+ await this.files.writeToStorage(this.path, dataString);
1084
+ }
1085
+ catch (error) {
1086
+ console.error('Failed to save file:', error);
1087
+ }
1088
+ finally {
1089
+ this.status = Status.Idle;
1090
+ }
1091
+ }
1092
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: FileBoxService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1093
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: FileBoxService, providedIn: 'root' });
1094
+ }
1095
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: FileBoxService, decorators: [{
1096
+ type: Injectable,
1097
+ args: [{
1098
+ providedIn: 'root'
1099
+ }]
1100
+ }] });
1101
+
1102
+ class KeySignals {
1103
+ SEPARATOR = '|';
1104
+ getCanonicalKey(path) {
1105
+ return path.join(this.SEPARATOR);
1106
+ }
1107
+ getNewSignal(defaultValue, ...path) {
1108
+ return computed(() => this.getValue(defaultValue, ...path));
1109
+ }
1110
+ getValue(defaultValue, ...path) {
1111
+ const key = this.getCanonicalKey(path);
1112
+ const data = this.$data();
1113
+ return key in data ? data[key] : defaultValue;
1114
+ }
1115
+ async set(value, ...path) {
1116
+ const key = this.getCanonicalKey(path);
1117
+ await this.setRawValue(key, value);
1118
+ }
1119
+ /**
1120
+ * Clears all keys that start with the given prefix.
1121
+ */
1122
+ async clearByPrefix(...pathPrefix) {
1123
+ const prefix = this.getCanonicalKey(pathPrefix) + this.SEPARATOR;
1124
+ const data = this.$data();
1125
+ const updatedData = { ...data };
1126
+ let changed = false;
1127
+ for (const key in updatedData) {
1128
+ if (key.startsWith(prefix)) {
1129
+ delete updatedData[key];
1130
+ changed = true;
1131
+ }
1132
+ }
1133
+ if (changed) {
1134
+ await this.setMultipleRawValues(updatedData);
1135
+ }
1136
+ }
1137
+ }
1138
+
1139
+ class SettingsSignalsService extends KeySignals {
1140
+ filebox = inject(FileBoxService);
1141
+ $data() {
1142
+ return this.filebox.$data();
1143
+ }
1144
+ async setRawValue(key, value) {
1145
+ this.filebox.set(key, value);
1146
+ await this.filebox.save();
1147
+ }
1148
+ async setMultipleRawValues(values) {
1149
+ this.filebox.setAll(values);
1150
+ await this.filebox.save();
1151
+ }
1152
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SettingsSignalsService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
1153
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SettingsSignalsService, providedIn: 'root' });
1154
+ }
1155
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SettingsSignalsService, decorators: [{
1156
+ type: Injectable,
1157
+ args: [{
1158
+ providedIn: 'root'
1159
+ }]
1160
+ }] });
1161
+
1162
+ class SettingsService {
1163
+ fileboxService = inject(FileBoxService);
1164
+ sss = inject(SettingsSignalsService);
1165
+ SETTINGS_KEY = "app-settings";
1166
+ getNewSignal(defaultValue, ...path) {
1167
+ return this.sss.getNewSignal(defaultValue, this.SETTINGS_KEY, ...path);
1168
+ }
1169
+ async set(value, ...path) {
1170
+ await this.sss.set(value, this.SETTINGS_KEY, ...path);
1171
+ }
1172
+ async save() {
1173
+ await this.fileboxService.save();
1174
+ }
1175
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SettingsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1176
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SettingsService, providedIn: "root" });
1177
+ }
1178
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SettingsService, decorators: [{
1179
+ type: Injectable,
1180
+ args: [{
1181
+ providedIn: "root"
1182
+ }]
1183
+ }] });
1184
+
1185
+ class TauriFilesService extends FilesService {
1186
+ static _isTauri = null;
1187
+ static isSupported() {
1188
+ if (this._isTauri !== null)
1189
+ return this._isTauri;
1190
+ try {
1191
+ // Check for window.__TAURI_INTERNALS__ which is usually present in v2
1192
+ this._isTauri = !!(window.__TAURI_INTERNALS__);
1193
+ }
1194
+ catch {
1195
+ this._isTauri = false;
1196
+ }
1197
+ return this._isTauri;
1198
+ }
1199
+ async init() {
1200
+ // No special initialization needed for Tauri FS plugin beyond what is handled lazily
1201
+ }
1202
+ async joinStoragePath(filePath) {
1203
+ const { appLocalDataDir, join } = await import('@tauri-apps/api/path');
1204
+ const dataDir = await appLocalDataDir();
1205
+ return await join(dataDir, filePath);
1206
+ }
1207
+ async hasInStorage(filePath) {
1208
+ try {
1209
+ const { exists } = await import('@tauri-apps/plugin-fs');
1210
+ const { BaseDirectory } = await import('@tauri-apps/api/path');
1211
+ return await exists(filePath, { baseDir: BaseDirectory.AppLocalData });
1212
+ }
1213
+ catch (error) {
1214
+ console.error('TauriFilesService.hasInStorage error:', error);
1215
+ return false;
1216
+ }
1217
+ }
1218
+ async readFromStorage(filePath) {
1219
+ const { readTextFile } = await import('@tauri-apps/plugin-fs');
1220
+ const { BaseDirectory } = await import('@tauri-apps/api/path');
1221
+ return await readTextFile(filePath, { baseDir: BaseDirectory.AppLocalData });
1222
+ }
1223
+ async writeToStorage(filePath, data) {
1224
+ const { writeTextFile } = await import('@tauri-apps/plugin-fs');
1225
+ const { BaseDirectory } = await import('@tauri-apps/api/path');
1226
+ await writeTextFile(filePath, data, { baseDir: BaseDirectory.AppLocalData });
1227
+ }
1228
+ async hasInProject(filePath) {
1229
+ try {
1230
+ const response = await fetch(filePath, { method: 'HEAD' });
1231
+ return response.ok;
1232
+ }
1233
+ catch {
1234
+ return false;
1235
+ }
1236
+ }
1237
+ async readFromProject(filePath) {
1238
+ const response = await fetch(filePath);
1239
+ if (!response.ok) {
1240
+ throw new Error(`Failed to read project file: ${filePath} (${response.status})`);
1241
+ }
1242
+ return await response.text();
1243
+ }
1244
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: TauriFilesService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
1245
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: TauriFilesService });
1246
+ }
1247
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: TauriFilesService, decorators: [{
1248
+ type: Injectable
1249
+ }] });
1250
+
1251
+ class CapacitorFilesService extends FilesService {
1252
+ static isSupported() {
1253
+ // Capacitor is not yet implemented, so returning false
1254
+ return false;
1255
+ }
1256
+ async init() {
1257
+ throw new Error('CapacitorFilesService not implemented');
1258
+ }
1259
+ async joinStoragePath(filePath) {
1260
+ return null;
1261
+ }
1262
+ async hasInStorage(filePath) {
1263
+ throw new Error('Method not implemented.');
1264
+ }
1265
+ async readFromStorage(filePath) {
1266
+ throw new Error('Method not implemented.');
1267
+ }
1268
+ async writeToStorage(filePath, data) {
1269
+ throw new Error('Method not implemented.');
1270
+ }
1271
+ async hasInProject(filePath) {
1272
+ throw new Error('Method not implemented.');
1273
+ }
1274
+ async readFromProject(filePath) {
1275
+ throw new Error('Method not implemented.');
1276
+ }
1277
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CapacitorFilesService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
1278
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CapacitorFilesService });
1279
+ }
1280
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CapacitorFilesService, decorators: [{
1281
+ type: Injectable
1282
+ }] });
1283
+
1284
+ class LocalStorageFilesService extends FilesService {
1285
+ http = inject(HttpClient);
1286
+ static isSupported() {
1287
+ return typeof window !== 'undefined' && !!window.localStorage;
1288
+ }
1289
+ async init() {
1290
+ // LocalStorage is ready immediately
1291
+ }
1292
+ async joinStoragePath(filePath) {
1293
+ return null;
1294
+ }
1295
+ async hasInStorage(filePath) {
1296
+ return localStorage.getItem(filePath) !== null;
1297
+ }
1298
+ async readFromStorage(filePath) {
1299
+ const data = localStorage.getItem(filePath);
1300
+ if (data === null)
1301
+ throw new Error(`File not found in localStorage: ${filePath}`);
1302
+ return data;
1303
+ }
1304
+ async writeToStorage(filePath, data) {
1305
+ localStorage.setItem(filePath, data);
1306
+ }
1307
+ async hasInProject(filePath) {
1308
+ try {
1309
+ // In a browser, we check if we can fetch it via HTTP
1310
+ await lastValueFrom(this.http.head(filePath));
1311
+ return true;
1312
+ }
1313
+ catch {
1314
+ return false;
1315
+ }
1316
+ }
1317
+ async readFromProject(filePath) {
1318
+ return await lastValueFrom(this.http.get(filePath, { responseType: 'text' }));
1319
+ }
1320
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: LocalStorageFilesService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
1321
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: LocalStorageFilesService });
1322
+ }
1323
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: LocalStorageFilesService, decorators: [{
1324
+ type: Injectable
1325
+ }] });
1326
+
1327
+ var ThemeType;
1328
+ (function (ThemeType) {
1329
+ ThemeType["Unset"] = "";
1330
+ ThemeType["Light"] = "light";
1331
+ ThemeType["Dark"] = "dark";
1332
+ })(ThemeType || (ThemeType = {}));
1333
+ class ThemeService {
1334
+ settings = inject(SettingsService);
1335
+ $theme = this.settings.getNewSignal(ThemeType.Unset, 'theme');
1336
+ $darkMode = computed(() => {
1337
+ const theme = this.$theme();
1338
+ let isDarkMode = theme === ThemeType.Unset
1339
+ ? window.matchMedia('(prefers-color-scheme: dark)').matches
1340
+ : theme === ThemeType.Dark;
1341
+ return isDarkMode;
1342
+ }, ...(ngDevMode ? [{ debugName: "$darkMode" }] : []));
1343
+ effectSetDarkMode = effect(async () => {
1344
+ document.documentElement.classList.toggle('dark', this.$darkMode());
1345
+ }, ...(ngDevMode ? [{ debugName: "effectSetDarkMode" }] : []));
1346
+ async setTheme(theme) {
1347
+ await this.settings.set(theme, 'theme');
1348
+ }
1349
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1350
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ThemeService, providedIn: 'root' });
1351
+ }
1352
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ThemeService, decorators: [{
1353
+ type: Injectable,
1354
+ args: [{
1355
+ providedIn: 'root'
1356
+ }]
1357
+ }] });
1358
+
1359
+ class ContextMenuComponent {
1360
+ elementRef;
1361
+ $isSubmenu = input(false, { ...(ngDevMode ? { debugName: "$isSubmenu" } : {}), transform: booleanAttribute });
1362
+ $isVisible = signal(false, ...(ngDevMode ? [{ debugName: "$isVisible" }] : []));
1363
+ $isMeasuring = signal(false, ...(ngDevMode ? [{ debugName: "$isMeasuring" }] : []));
1364
+ $x = signal(0, ...(ngDevMode ? [{ debugName: "$x" }] : []));
1365
+ $y = signal(0, ...(ngDevMode ? [{ debugName: "$y" }] : []));
1366
+ container;
1367
+ close = output();
1368
+ constructor(elementRef) {
1369
+ this.elementRef = elementRef;
1370
+ }
1371
+ onDocumentClick(event) {
1372
+ if (this.$isSubmenu())
1373
+ return;
1374
+ // If visible and click is outside, close
1375
+ if (this.$isVisible() && !this.elementRef.nativeElement.contains(event.target)) {
1376
+ this.closeMenu();
1377
+ }
1378
+ }
1379
+ show(x, y) {
1380
+ if (this.$isSubmenu())
1381
+ return;
1382
+ this.$x.set(x);
1383
+ this.$y.set(y);
1384
+ this.$isMeasuring.set(true);
1385
+ this.$isVisible.set(true);
1386
+ // Wait for DOM to render the menu so we can measure it
1387
+ setTimeout(() => {
1388
+ if (this.container) {
1389
+ const rect = this.container.nativeElement.getBoundingClientRect();
1390
+ const width = rect.width;
1391
+ const height = rect.height;
1392
+ const windowWidth = window.innerWidth;
1393
+ const windowHeight = window.innerHeight;
1394
+ let newX = x;
1395
+ let newY = y;
1396
+ if (x + width > windowWidth)
1397
+ newX = x - width;
1398
+ if (y + height > windowHeight)
1399
+ newY = y - height;
1400
+ // Final safety check to ensure it doesn't go off the top/left edges
1401
+ this.$x.set(Math.max(0, newX));
1402
+ this.$y.set(Math.max(0, newY));
1403
+ }
1404
+ this.$isMeasuring.set(false);
1405
+ }, 0);
1406
+ }
1407
+ hide() {
1408
+ this.$isVisible.set(false);
1409
+ this.$isMeasuring.set(false);
1410
+ }
1411
+ closeMenu() {
1412
+ this.hide();
1413
+ this.close.emit();
1414
+ }
1415
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ContextMenuComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
1416
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: ContextMenuComponent, isStandalone: true, selector: "context-menu", inputs: { $isSubmenu: { classPropertyName: "$isSubmenu", publicName: "$isSubmenu", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { close: "close" }, host: { listeners: { "document:mousedown": "onDocumentClick($event)" } }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true }], ngImport: i0, template: `
1417
+ @if ($isVisible() || $isSubmenu()) {
1418
+ <div
1419
+ #container
1420
+ [class.fixed]="!$isSubmenu()"
1421
+ [class.absolute]="$isSubmenu()"
1422
+ [class.left-full]="$isSubmenu()"
1423
+ [class.top-0]="$isSubmenu()"
1424
+ [class.ml-[-2px]]="$isSubmenu()"
1425
+ class="bg-white dark:bg-[#2a2a2a] border border-light-border dark:border-dark-border rounded shadow-lg z-50 min-w-[200px] text-light-text-primary dark:text-dark-text-primary py-1"
1426
+ [style.left.px]="!$isSubmenu() ? $x() : null"
1427
+ [style.top.px]="!$isSubmenu() ? $y() : null"
1428
+ [style.visibility]="$isMeasuring() ? 'hidden' : 'visible'"
1429
+ (click)="$event.stopPropagation()">
1430
+ <ng-content></ng-content>
1431
+ </div>
1432
+ }
1433
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
1434
+ }
1435
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ContextMenuComponent, decorators: [{
1436
+ type: Component,
1437
+ args: [{
1438
+ selector: 'context-menu',
1439
+ standalone: true,
1440
+ imports: [CommonModule],
1441
+ template: `
1442
+ @if ($isVisible() || $isSubmenu()) {
1443
+ <div
1444
+ #container
1445
+ [class.fixed]="!$isSubmenu()"
1446
+ [class.absolute]="$isSubmenu()"
1447
+ [class.left-full]="$isSubmenu()"
1448
+ [class.top-0]="$isSubmenu()"
1449
+ [class.ml-[-2px]]="$isSubmenu()"
1450
+ class="bg-white dark:bg-[#2a2a2a] border border-light-border dark:border-dark-border rounded shadow-lg z-50 min-w-[200px] text-light-text-primary dark:text-dark-text-primary py-1"
1451
+ [style.left.px]="!$isSubmenu() ? $x() : null"
1452
+ [style.top.px]="!$isSubmenu() ? $y() : null"
1453
+ [style.visibility]="$isMeasuring() ? 'hidden' : 'visible'"
1454
+ (click)="$event.stopPropagation()">
1455
+ <ng-content></ng-content>
1456
+ </div>
1457
+ }
1458
+ `
1459
+ }]
1460
+ }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { $isSubmenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "$isSubmenu", required: false }] }], container: [{
1461
+ type: ViewChild,
1462
+ args: ['container']
1463
+ }], close: [{ type: i0.Output, args: ["close"] }], onDocumentClick: [{
1464
+ type: HostListener,
1465
+ args: ['document:mousedown', ['$event']]
1466
+ }] } });
1467
+
1468
+ class ContextHeaderComponent {
1469
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ContextHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1470
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.0", type: ContextHeaderComponent, isStandalone: true, selector: "context-header", ngImport: i0, template: `
1471
+ <div
1472
+ class="px-3 py-1.5 text-xs font-semibold text-light-text-secondary dark:text-dark-text-secondary truncate border-b border-light-border dark:border-dark-border mb-1">
1473
+ <ng-content></ng-content>
1474
+ </div>
1475
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
1476
+ }
1477
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ContextHeaderComponent, decorators: [{
1478
+ type: Component,
1479
+ args: [{
1480
+ selector: 'context-header',
1481
+ standalone: true,
1482
+ imports: [CommonModule],
1483
+ template: `
1484
+ <div
1485
+ class="px-3 py-1.5 text-xs font-semibold text-light-text-secondary dark:text-dark-text-secondary truncate border-b border-light-border dark:border-dark-border mb-1">
1486
+ <ng-content></ng-content>
1487
+ </div>
1488
+ `
1489
+ }]
1490
+ }] });
1491
+
1492
+ class ContextButtonComponent {
1493
+ danger = input(false, { ...(ngDevMode ? { debugName: "danger" } : {}), transform: booleanAttribute });
1494
+ disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : {}), transform: booleanAttribute });
1495
+ hasSubmenu = input(false, { ...(ngDevMode ? { debugName: "hasSubmenu" } : {}), transform: booleanAttribute });
1496
+ $showSubmenu = signal(false, ...(ngDevMode ? [{ debugName: "$showSubmenu" }] : []));
1497
+ onMouseEnter() {
1498
+ if (this.hasSubmenu() && !this.disabled()) {
1499
+ this.$showSubmenu.set(true);
1500
+ }
1501
+ }
1502
+ onMouseLeave() {
1503
+ if (this.hasSubmenu() && !this.disabled()) {
1504
+ this.$showSubmenu.set(false);
1505
+ }
1506
+ }
1507
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ContextButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1508
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: ContextButtonComponent, isStandalone: true, selector: "context-button", inputs: { danger: { classPropertyName: "danger", publicName: "danger", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, hasSubmenu: { classPropertyName: "hasSubmenu", publicName: "hasSubmenu", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
1509
+ <div class="relative" (mouseenter)="onMouseEnter()" (mouseleave)="onMouseLeave()">
1510
+ <button
1511
+ class="w-full text-left px-3 py-2 text-sm transition-colors duration-100 flex items-center justify-between gap-2"
1512
+ [class.hover:bg-light-bg-secondary]="!disabled()"
1513
+ [class.dark:hover:bg-[#383838]]="!disabled()"
1514
+ [class.text-red-500]="danger() && !disabled()"
1515
+ [class.hover:bg-red-500]="danger() && !disabled()"
1516
+ [class.hover:text-white]="danger() && !disabled()"
1517
+ [class.opacity-50]="disabled()"
1518
+ [class.cursor-not-allowed]="disabled()"
1519
+ [disabled]="disabled()">
1520
+ <div class="flex items-center gap-2">
1521
+ <ng-content select="[icon]"></ng-content>
1522
+ <ng-content></ng-content>
1523
+ </div>
1524
+ @if (hasSubmenu()) {
1525
+ <span class="text-[10px] text-light-text-secondary opacity-50">▶</span>
1526
+ }
1527
+ </button>
1528
+
1529
+ @if (hasSubmenu() && $showSubmenu() && !disabled()) {
1530
+ <div class="absolute left-full top-0 ml-[-2px] z-[60]">
1531
+ <ng-content select="context-menu"></ng-content>
1532
+ </div>
1533
+ }
1534
+ </div>
1535
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
1536
+ }
1537
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ContextButtonComponent, decorators: [{
1538
+ type: Component,
1539
+ args: [{
1540
+ selector: 'context-button',
1541
+ standalone: true,
1542
+ imports: [CommonModule],
1543
+ template: `
1544
+ <div class="relative" (mouseenter)="onMouseEnter()" (mouseleave)="onMouseLeave()">
1545
+ <button
1546
+ class="w-full text-left px-3 py-2 text-sm transition-colors duration-100 flex items-center justify-between gap-2"
1547
+ [class.hover:bg-light-bg-secondary]="!disabled()"
1548
+ [class.dark:hover:bg-[#383838]]="!disabled()"
1549
+ [class.text-red-500]="danger() && !disabled()"
1550
+ [class.hover:bg-red-500]="danger() && !disabled()"
1551
+ [class.hover:text-white]="danger() && !disabled()"
1552
+ [class.opacity-50]="disabled()"
1553
+ [class.cursor-not-allowed]="disabled()"
1554
+ [disabled]="disabled()">
1555
+ <div class="flex items-center gap-2">
1556
+ <ng-content select="[icon]"></ng-content>
1557
+ <ng-content></ng-content>
1558
+ </div>
1559
+ @if (hasSubmenu()) {
1560
+ <span class="text-[10px] text-light-text-secondary opacity-50">▶</span>
1561
+ }
1562
+ </button>
1563
+
1564
+ @if (hasSubmenu() && $showSubmenu() && !disabled()) {
1565
+ <div class="absolute left-full top-0 ml-[-2px] z-[60]">
1566
+ <ng-content select="context-menu"></ng-content>
1567
+ </div>
1568
+ }
1569
+ </div>
1570
+ `
1571
+ }]
1572
+ }], propDecorators: { danger: [{ type: i0.Input, args: [{ isSignal: true, alias: "danger", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], hasSubmenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasSubmenu", required: false }] }] } });
1573
+
1574
+ class ContextMenuTriggerDirective {
1575
+ elementRef;
1576
+ appContextMenu = input.required(...(ngDevMode ? [{ debugName: "appContextMenu" }] : []));
1577
+ beforeOpen = output();
1578
+ constructor(elementRef) {
1579
+ this.elementRef = elementRef;
1580
+ }
1581
+ onContextMenu(event) {
1582
+ event.preventDefault();
1583
+ event.stopPropagation();
1584
+ // Notify parent to prepare data
1585
+ this.beforeOpen.emit();
1586
+ // Show menu at cursor position
1587
+ this.appContextMenu().show(event.clientX, event.clientY);
1588
+ }
1589
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ContextMenuTriggerDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
1590
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.0", type: ContextMenuTriggerDirective, isStandalone: true, selector: "[appContextMenu]", inputs: { appContextMenu: { classPropertyName: "appContextMenu", publicName: "appContextMenu", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { beforeOpen: "beforeOpen" }, host: { listeners: { "contextmenu": "onContextMenu($event)" } }, ngImport: i0 });
1591
+ }
1592
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ContextMenuTriggerDirective, decorators: [{
1593
+ type: Directive,
1594
+ args: [{
1595
+ selector: '[appContextMenu]',
1596
+ standalone: true
1597
+ }]
1598
+ }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { appContextMenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "appContextMenu", required: true }] }], beforeOpen: [{ type: i0.Output, args: ["beforeOpen"] }], onContextMenu: [{
1599
+ type: HostListener,
1600
+ args: ['contextmenu', ['$event']]
1601
+ }] } });
1602
+
1603
+ /**
1604
+ * Generated bundle index. Do not edit.
1605
+ */
1606
+
1607
+ export { Async, BackOnClickDirective, CancellationError, CancellationTokenSource, CapacitorFilesService, ConsoleHook, ContextButtonComponent, ContextHeaderComponent, ContextMenuComponent, ContextMenuTriggerDirective, ECHO, ECHO_PROVIDER, Echo, EchoConsole, EchoLogger, EchoSettings, EchoSystemLogger, FileBoxService, FilesService, KeySignals, LocalStorageFilesService, LocalizationService, LocalizePipe, LogLevel, LogSystems, LogWriterConfig, NavigationStackService, ServicesInit, SettingsService, SettingsSignalsService, SystemColor, TauriFilesService, ThemeService, ThemeType, echoFactory };
1608
+ //# sourceMappingURL=orcas-angular.mjs.map