@ngstato/angular 0.1.2 → 0.1.4

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.
@@ -0,0 +1,512 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, InjectionToken, isDevMode, makeEnvironmentProviders, signal, computed, Injectable, Component } from '@angular/core';
3
+ import { configureHttp, devTools, createStore } from '@ngstato/core';
4
+ import { JsonPipe } from '@angular/common';
5
+
6
+ // ─────────────────────────────────────────────────────
7
+ // @ngstato/angular — injectStore()
8
+ // Helper pour injecter un store dans un composant
9
+ // ─────────────────────────────────────────────────────
10
+ function injectStore(store) {
11
+ return inject(store);
12
+ }
13
+
14
+ const STATO_CONFIG = new InjectionToken('STATO_CONFIG');
15
+ function provideStato(config = {}) {
16
+ if (config.http) {
17
+ configureHttp(config.http);
18
+ }
19
+ // DevTools — ignorés automatiquement en production
20
+ // isDevMode() est géré par Angular au build
21
+ // → false en prod même si devtools: true
22
+ if (config.devtools && isDevMode()) {
23
+ console.info('%c[Stato] 🛠 DevTools activés', 'background:#1e40af;color:white;padding:4px 8px;border-radius:4px;font-weight:bold');
24
+ devTools.open();
25
+ }
26
+ return makeEnvironmentProviders([
27
+ {
28
+ provide: STATO_CONFIG,
29
+ useValue: config
30
+ }
31
+ ]);
32
+ }
33
+
34
+ // ─────────────────────────────────────────────────────
35
+ // @ngstato/angular — createAngularStore()
36
+ // Transforme un ngstato store en store Angular avec Signals
37
+ // ─────────────────────────────────────────────────────
38
+ // ─────────────────────────────────────────────────────
39
+ // FONCTION PRINCIPALE — createAngularStore()
40
+ // ─────────────────────────────────────────────────────
41
+ function createAngularStore(config) {
42
+ // 1. Créer le store core
43
+ const coreStore = createStore(config);
44
+ // 2. Créer un Signal pour chaque propriété du state
45
+ const signals = {};
46
+ const initialState = coreStore.getState();
47
+ for (const key of Object.keys(initialState)) {
48
+ signals[key] = signal(initialState[key]);
49
+ }
50
+ // 3. Synchroniser les Signals avec le state core
51
+ coreStore.subscribe((newState) => {
52
+ for (const key of Object.keys(newState)) {
53
+ if (signals[key]) {
54
+ signals[key].set(newState[key]);
55
+ }
56
+ }
57
+ });
58
+ // 4. Construire l objet public Angular
59
+ const angularStore = {
60
+ __store__: coreStore.__store__
61
+ };
62
+ // 5. Exposer chaque propriété comme Signal
63
+ for (const key of Object.keys(initialState)) {
64
+ Object.defineProperty(angularStore, key, {
65
+ get: () => signals[key],
66
+ enumerable: true,
67
+ configurable: true
68
+ });
69
+ }
70
+ // 6. Exposer chaque computed comme Signal computed
71
+ const { computed: computedConfig } = config;
72
+ if (computedConfig) {
73
+ for (const key of Object.keys(computedConfig)) {
74
+ const computedSignal = computed(() => coreStore[key]);
75
+ Object.defineProperty(angularStore, key, {
76
+ get: () => computedSignal,
77
+ enumerable: true,
78
+ configurable: true
79
+ });
80
+ }
81
+ }
82
+ // 7. Exposer chaque action directement
83
+ const { actions } = config;
84
+ if (actions) {
85
+ for (const name of Object.keys(actions)) {
86
+ angularStore[name] = (...args) => coreStore.__store__.dispatch(name, ...args);
87
+ }
88
+ }
89
+ // 8. Appeler onInit si défini
90
+ const { hooks } = config;
91
+ if (hooks?.onInit) {
92
+ hooks.onInit(angularStore);
93
+ }
94
+ // 9. Exposer destroy pour le cleanup
95
+ angularStore.__destroy__ = () => {
96
+ coreStore.__store__.destroy(angularStore);
97
+ };
98
+ return angularStore;
99
+ }
100
+ // ─────────────────────────────────────────────────────
101
+ // CLASSE DE BASE — étendue par StatoStore()
102
+ // Publique — pas de membres privés
103
+ // ─────────────────────────────────────────────────────
104
+ class StatoStoreBase {
105
+ storeInstance;
106
+ initStore(config) {
107
+ this.storeInstance = createAngularStore(config);
108
+ // Copier toutes les propriétés sur this
109
+ for (const key of Object.keys(this.storeInstance)) {
110
+ if (key !== '__store__' && key !== '__destroy__') {
111
+ Object.defineProperty(this, key, {
112
+ get: () => this.storeInstance[key],
113
+ enumerable: true,
114
+ configurable: true
115
+ });
116
+ }
117
+ }
118
+ // Copier les actions
119
+ const { actions } = config;
120
+ if (actions) {
121
+ for (const name of Object.keys(actions)) {
122
+ Object.defineProperty(this, name, {
123
+ get: () => this.storeInstance[name],
124
+ enumerable: true,
125
+ configurable: true
126
+ });
127
+ }
128
+ }
129
+ }
130
+ ngOnDestroy() {
131
+ this.storeInstance?.__destroy__();
132
+ }
133
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: StatoStoreBase, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
134
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: StatoStoreBase });
135
+ }
136
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: StatoStoreBase, decorators: [{
137
+ type: Injectable
138
+ }] });
139
+ // ─────────────────────────────────────────────────────
140
+ // FACTORY — StatoStore()
141
+ // Crée un service Angular injectable
142
+ // Usage :
143
+ // export class UserStore extends StatoStore({
144
+ // user: null,
145
+ // actions: { ... }
146
+ // }) {}
147
+ // ─────────────────────────────────────────────────────
148
+ function StatoStore(config) {
149
+ class ConcreteStore extends StatoStoreBase {
150
+ constructor() {
151
+ super();
152
+ this.initStore(config);
153
+ }
154
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ConcreteStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
155
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ConcreteStore, providedIn: 'root' });
156
+ }
157
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ConcreteStore, decorators: [{
158
+ type: Injectable,
159
+ args: [{ providedIn: 'root' }]
160
+ }], ctorParameters: () => [] });
161
+ return ConcreteStore;
162
+ }
163
+
164
+ class StatoDevToolsComponent {
165
+ unsub;
166
+ // State UI
167
+ isOpen = signal(false);
168
+ isMinimized = signal(false);
169
+ activeTab = signal('actions');
170
+ logs = signal([]);
171
+ selectedLog = signal(null);
172
+ // Position et taille
173
+ posX = signal(24);
174
+ posY = signal(window.innerHeight - 500);
175
+ panelWidth = signal(420);
176
+ panelHeight = signal(460);
177
+ // Drag state
178
+ isDragging = false;
179
+ isResizing = false;
180
+ dragOffsetX = 0;
181
+ dragOffsetY = 0;
182
+ startW = 0;
183
+ startH = 0;
184
+ startX = 0;
185
+ startY = 0;
186
+ // Bound listeners
187
+ boundMouseMove = this.onMouseMove.bind(this);
188
+ boundMouseUp = this.onMouseUp.bind(this);
189
+ ngOnInit() {
190
+ this.unsub = devTools.subscribe((state) => {
191
+ this.logs.set(state.logs);
192
+ this.isOpen.set(state.isOpen);
193
+ });
194
+ document.addEventListener('mousemove', this.boundMouseMove);
195
+ document.addEventListener('mouseup', this.boundMouseUp);
196
+ }
197
+ ngOnDestroy() {
198
+ this.unsub?.();
199
+ document.removeEventListener('mousemove', this.boundMouseMove);
200
+ document.removeEventListener('mouseup', this.boundMouseUp);
201
+ }
202
+ // ── Toggle ─────────────────────────────────────────
203
+ toggle() { devTools.toggle(); }
204
+ toggleMinimize() { this.isMinimized.update(v => !v); }
205
+ clear() { devTools.clear(); this.selectedLog.set(null); }
206
+ selectLog(log) {
207
+ this.selectedLog.set(this.selectedLog()?.id === log.id ? null : log);
208
+ }
209
+ formatTime(iso) {
210
+ return new Date(iso).toTimeString().slice(0, 8);
211
+ }
212
+ // ── Drag ───────────────────────────────────────────
213
+ onDragStart(e) {
214
+ if (e.target.classList.contains('btn-icon'))
215
+ return;
216
+ this.isDragging = true;
217
+ this.dragOffsetX = e.clientX - this.posX();
218
+ this.dragOffsetY = e.clientY - this.posY();
219
+ e.preventDefault();
220
+ }
221
+ // ── Resize ─────────────────────────────────────────
222
+ onResizeStart(e) {
223
+ this.isResizing = true;
224
+ this.startW = this.panelWidth();
225
+ this.startH = this.panelHeight();
226
+ this.startX = e.clientX;
227
+ this.startY = e.clientY;
228
+ e.preventDefault();
229
+ e.stopPropagation();
230
+ }
231
+ // ── Mouse Move ─────────────────────────────────────
232
+ onMouseMove(e) {
233
+ if (this.isDragging) {
234
+ this.posX.set(Math.max(0, e.clientX - this.dragOffsetX));
235
+ this.posY.set(Math.max(0, e.clientY - this.dragOffsetY));
236
+ }
237
+ if (this.isResizing) {
238
+ const newW = Math.max(300, this.startW + e.clientX - this.startX);
239
+ const newH = Math.max(200, this.startH + e.clientY - this.startY);
240
+ this.panelWidth.set(newW);
241
+ this.panelHeight.set(newH);
242
+ }
243
+ }
244
+ // ── Mouse Up ───────────────────────────────────────
245
+ onMouseUp() {
246
+ this.isDragging = false;
247
+ this.isResizing = false;
248
+ }
249
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: StatoDevToolsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
250
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: StatoDevToolsComponent, isStandalone: true, selector: "ngstato-devtools", ngImport: i0, template: `
251
+ <!-- Bouton flottant -->
252
+ @if (!isOpen()) {
253
+ <button class="devtools-fab" (click)="toggle()">
254
+ 🛠 Stato
255
+ </button>
256
+ }
257
+
258
+ <!-- Panel -->
259
+ @if (isOpen()) {
260
+ <div
261
+ class="devtools-panel"
262
+ [class.devtools-panel--minimized]="isMinimized()"
263
+ [style.left.px]="posX()"
264
+ [style.top.px]="posY()"
265
+ [style.width.px]="isMinimized() ? 200 : panelWidth()"
266
+ [style.height]="isMinimized() ? 'auto' : panelHeight() + 'px'"
267
+ >
268
+
269
+ <!-- Header — draggable -->
270
+ <div
271
+ class="devtools-header"
272
+ (mousedown)="onDragStart($event)"
273
+ >
274
+ <span class="devtools-title">🛠 Stato</span>
275
+ <div class="devtools-header-actions">
276
+ @if (!isMinimized()) {
277
+ <button class="btn-icon" (click)="clear()" title="Vider">🗑</button>
278
+ }
279
+ <button class="btn-icon" (click)="toggleMinimize()" title="Minimiser/Agrandir">
280
+ {{ isMinimized() ? '▲' : '▼' }}
281
+ </button>
282
+ <button class="btn-icon" (click)="toggle()" title="Fermer">✕</button>
283
+ </div>
284
+ </div>
285
+
286
+ <!-- Resize handle — coin bas droite -->
287
+ @if (!isMinimized()) {
288
+ <div
289
+ class="devtools-resize"
290
+ (mousedown)="onResizeStart($event)"
291
+ >⊿</div>
292
+ }
293
+
294
+ @if (!isMinimized()) {
295
+
296
+ <!-- Tabs -->
297
+ <div class="devtools-tabs">
298
+ <button
299
+ class="tab"
300
+ [class.tab--active]="activeTab() === 'actions'"
301
+ (click)="activeTab.set('actions')"
302
+ >
303
+ Actions ({{ logs().length }})
304
+ </button>
305
+ <button
306
+ class="tab"
307
+ [class.tab--active]="activeTab() === 'state'"
308
+ (click)="activeTab.set('state')"
309
+ >
310
+ State
311
+ </button>
312
+ </div>
313
+
314
+ <!-- Tab Actions -->
315
+ @if (activeTab() === 'actions') {
316
+ <div class="devtools-content">
317
+ @if (!logs().length) {
318
+ <div class="devtools-empty">Aucune action pour l'instant</div>
319
+ }
320
+ @for (log of logs(); track log.id) {
321
+ <div
322
+ class="log-item"
323
+ [class.log-item--error]="log.status === 'error'"
324
+ (click)="selectLog(log)"
325
+ >
326
+ <div class="log-item__left">
327
+ <span class="log-status">{{ log.status === 'success' ? '✓' : '✗' }}</span>
328
+ <span class="log-name">{{ log.name }}</span>
329
+ </div>
330
+ <div class="log-item__right">
331
+ @if (log.status === 'error') {
332
+ <span class="log-error-badge">erreur</span>
333
+ } @else {
334
+ <span class="log-duration">{{ log.duration }}ms</span>
335
+ }
336
+ <span class="log-time">{{ formatTime(log.at) }}</span>
337
+ </div>
338
+ </div>
339
+
340
+ @if (selectedLog()?.id === log.id) {
341
+ <div class="log-detail">
342
+ @if (log.error) {
343
+ <div class="log-detail__error">{{ log.error }}</div>
344
+ }
345
+ <div class="log-detail__section">
346
+ <span class="log-detail__label">Avant</span>
347
+ <pre>{{ log.prevState | json }}</pre>
348
+ </div>
349
+ <div class="log-detail__section">
350
+ <span class="log-detail__label">Après</span>
351
+ <pre>{{ log.nextState | json }}</pre>
352
+ </div>
353
+ </div>
354
+ }
355
+ }
356
+ </div>
357
+ }
358
+
359
+ <!-- Tab State -->
360
+ @if (activeTab() === 'state') {
361
+ <div class="devtools-content">
362
+ @if (logs().length) {
363
+ <pre class="state-view">{{ logs()[0].nextState | json }}</pre>
364
+ } @else {
365
+ <div class="devtools-empty">Aucun state disponible</div>
366
+ }
367
+ </div>
368
+ }
369
+ }
370
+
371
+ </div>
372
+ }
373
+ `, isInline: true, styles: [".devtools-fab{position:fixed;bottom:1.5rem;left:1.5rem;background:#1e293b;color:#fff;border:none;border-radius:999px;padding:.5rem 1rem;font-size:.85rem;font-weight:600;cursor:pointer;z-index:9999;box-shadow:0 4px 12px #0000004d;transition:background .15s}.devtools-fab:hover{background:#334155}.devtools-panel{position:fixed;background:#0f172a;border-radius:12px;box-shadow:0 8px 32px #0006;z-index:9999;display:flex;flex-direction:column;overflow:hidden;font-family:Courier New,monospace;min-width:200px;min-height:40px}.devtools-panel--minimized{border-radius:8px}.devtools-header{display:flex;justify-content:space-between;align-items:center;padding:.6rem .75rem;background:#1e293b;border-bottom:1px solid #334155;cursor:grab;-webkit-user-select:none;user-select:none}.devtools-header:active{cursor:grabbing}.devtools-title{color:#e2e8f0;font-size:.82rem;font-weight:600;font-family:system-ui}.devtools-header-actions{display:flex;gap:.25rem}.btn-icon{background:transparent;color:#64748b;border:none;cursor:pointer;font-size:.8rem;padding:.15rem .35rem;border-radius:4px;line-height:1}.btn-icon:hover{background:#334155;color:#fff}.devtools-resize{position:absolute;bottom:2px;right:4px;color:#334155;font-size:.9rem;cursor:nwse-resize;-webkit-user-select:none;user-select:none;line-height:1}.devtools-resize:hover{color:#64748b}.devtools-tabs{display:flex;background:#1e293b;border-bottom:1px solid #334155}.tab{padding:.4rem .75rem;background:transparent;color:#64748b;border:none;cursor:pointer;font-size:.78rem;font-family:system-ui}.tab:hover{color:#e2e8f0}.tab--active{color:#3b82f6;border-bottom:2px solid #3b82f6}.devtools-content{overflow-y:auto;flex:1;padding:.25rem 0}.devtools-empty{padding:2rem;text-align:center;color:#475569;font-size:.78rem;font-family:system-ui}.log-item{display:flex;justify-content:space-between;align-items:center;padding:.35rem .75rem;cursor:pointer;border-bottom:1px solid #1e293b}.log-item:hover{background:#1e293b}.log-item--error{background:#1a0a0a}.log-item__left{display:flex;align-items:center;gap:.4rem;overflow:hidden}.log-item__right{display:flex;align-items:center;gap:.4rem;flex-shrink:0}.log-status{font-size:.72rem;color:#22c55e;flex-shrink:0}.log-item--error .log-status{color:#ef4444}.log-name{color:#e2e8f0;font-size:.75rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.log-duration{color:#64748b;font-size:.7rem}.log-time{color:#475569;font-size:.68rem}.log-error-badge{background:#7f1d1d;color:#fca5a5;font-size:.68rem;padding:.1rem .35rem;border-radius:4px}.log-detail{background:#0a0f1a;padding:.6rem .75rem;border-left:3px solid #3b82f6;margin:0 .4rem .4rem;border-radius:0 4px 4px 0}.log-detail__error{color:#fca5a5;font-size:.72rem;margin-bottom:.4rem}.log-detail__section{margin-bottom:.4rem}.log-detail__label{color:#64748b;font-size:.68rem;display:block;margin-bottom:.2rem;font-family:system-ui}pre{color:#86efac;font-size:.7rem;margin:0;white-space:pre-wrap;word-break:break-all;max-height:140px;overflow-y:auto}.state-view{color:#86efac;font-size:.7rem;padding:.75rem;margin:0;white-space:pre-wrap;word-break:break-all}\n"], dependencies: [{ kind: "pipe", type: JsonPipe, name: "json" }] });
374
+ }
375
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: StatoDevToolsComponent, decorators: [{
376
+ type: Component,
377
+ args: [{ selector: 'ngstato-devtools', standalone: true, imports: [JsonPipe], template: `
378
+ <!-- Bouton flottant -->
379
+ @if (!isOpen()) {
380
+ <button class="devtools-fab" (click)="toggle()">
381
+ 🛠 Stato
382
+ </button>
383
+ }
384
+
385
+ <!-- Panel -->
386
+ @if (isOpen()) {
387
+ <div
388
+ class="devtools-panel"
389
+ [class.devtools-panel--minimized]="isMinimized()"
390
+ [style.left.px]="posX()"
391
+ [style.top.px]="posY()"
392
+ [style.width.px]="isMinimized() ? 200 : panelWidth()"
393
+ [style.height]="isMinimized() ? 'auto' : panelHeight() + 'px'"
394
+ >
395
+
396
+ <!-- Header — draggable -->
397
+ <div
398
+ class="devtools-header"
399
+ (mousedown)="onDragStart($event)"
400
+ >
401
+ <span class="devtools-title">🛠 Stato</span>
402
+ <div class="devtools-header-actions">
403
+ @if (!isMinimized()) {
404
+ <button class="btn-icon" (click)="clear()" title="Vider">🗑</button>
405
+ }
406
+ <button class="btn-icon" (click)="toggleMinimize()" title="Minimiser/Agrandir">
407
+ {{ isMinimized() ? '▲' : '▼' }}
408
+ </button>
409
+ <button class="btn-icon" (click)="toggle()" title="Fermer">✕</button>
410
+ </div>
411
+ </div>
412
+
413
+ <!-- Resize handle — coin bas droite -->
414
+ @if (!isMinimized()) {
415
+ <div
416
+ class="devtools-resize"
417
+ (mousedown)="onResizeStart($event)"
418
+ >⊿</div>
419
+ }
420
+
421
+ @if (!isMinimized()) {
422
+
423
+ <!-- Tabs -->
424
+ <div class="devtools-tabs">
425
+ <button
426
+ class="tab"
427
+ [class.tab--active]="activeTab() === 'actions'"
428
+ (click)="activeTab.set('actions')"
429
+ >
430
+ Actions ({{ logs().length }})
431
+ </button>
432
+ <button
433
+ class="tab"
434
+ [class.tab--active]="activeTab() === 'state'"
435
+ (click)="activeTab.set('state')"
436
+ >
437
+ State
438
+ </button>
439
+ </div>
440
+
441
+ <!-- Tab Actions -->
442
+ @if (activeTab() === 'actions') {
443
+ <div class="devtools-content">
444
+ @if (!logs().length) {
445
+ <div class="devtools-empty">Aucune action pour l'instant</div>
446
+ }
447
+ @for (log of logs(); track log.id) {
448
+ <div
449
+ class="log-item"
450
+ [class.log-item--error]="log.status === 'error'"
451
+ (click)="selectLog(log)"
452
+ >
453
+ <div class="log-item__left">
454
+ <span class="log-status">{{ log.status === 'success' ? '✓' : '✗' }}</span>
455
+ <span class="log-name">{{ log.name }}</span>
456
+ </div>
457
+ <div class="log-item__right">
458
+ @if (log.status === 'error') {
459
+ <span class="log-error-badge">erreur</span>
460
+ } @else {
461
+ <span class="log-duration">{{ log.duration }}ms</span>
462
+ }
463
+ <span class="log-time">{{ formatTime(log.at) }}</span>
464
+ </div>
465
+ </div>
466
+
467
+ @if (selectedLog()?.id === log.id) {
468
+ <div class="log-detail">
469
+ @if (log.error) {
470
+ <div class="log-detail__error">{{ log.error }}</div>
471
+ }
472
+ <div class="log-detail__section">
473
+ <span class="log-detail__label">Avant</span>
474
+ <pre>{{ log.prevState | json }}</pre>
475
+ </div>
476
+ <div class="log-detail__section">
477
+ <span class="log-detail__label">Après</span>
478
+ <pre>{{ log.nextState | json }}</pre>
479
+ </div>
480
+ </div>
481
+ }
482
+ }
483
+ </div>
484
+ }
485
+
486
+ <!-- Tab State -->
487
+ @if (activeTab() === 'state') {
488
+ <div class="devtools-content">
489
+ @if (logs().length) {
490
+ <pre class="state-view">{{ logs()[0].nextState | json }}</pre>
491
+ } @else {
492
+ <div class="devtools-empty">Aucun state disponible</div>
493
+ }
494
+ </div>
495
+ }
496
+ }
497
+
498
+ </div>
499
+ }
500
+ `, styles: [".devtools-fab{position:fixed;bottom:1.5rem;left:1.5rem;background:#1e293b;color:#fff;border:none;border-radius:999px;padding:.5rem 1rem;font-size:.85rem;font-weight:600;cursor:pointer;z-index:9999;box-shadow:0 4px 12px #0000004d;transition:background .15s}.devtools-fab:hover{background:#334155}.devtools-panel{position:fixed;background:#0f172a;border-radius:12px;box-shadow:0 8px 32px #0006;z-index:9999;display:flex;flex-direction:column;overflow:hidden;font-family:Courier New,monospace;min-width:200px;min-height:40px}.devtools-panel--minimized{border-radius:8px}.devtools-header{display:flex;justify-content:space-between;align-items:center;padding:.6rem .75rem;background:#1e293b;border-bottom:1px solid #334155;cursor:grab;-webkit-user-select:none;user-select:none}.devtools-header:active{cursor:grabbing}.devtools-title{color:#e2e8f0;font-size:.82rem;font-weight:600;font-family:system-ui}.devtools-header-actions{display:flex;gap:.25rem}.btn-icon{background:transparent;color:#64748b;border:none;cursor:pointer;font-size:.8rem;padding:.15rem .35rem;border-radius:4px;line-height:1}.btn-icon:hover{background:#334155;color:#fff}.devtools-resize{position:absolute;bottom:2px;right:4px;color:#334155;font-size:.9rem;cursor:nwse-resize;-webkit-user-select:none;user-select:none;line-height:1}.devtools-resize:hover{color:#64748b}.devtools-tabs{display:flex;background:#1e293b;border-bottom:1px solid #334155}.tab{padding:.4rem .75rem;background:transparent;color:#64748b;border:none;cursor:pointer;font-size:.78rem;font-family:system-ui}.tab:hover{color:#e2e8f0}.tab--active{color:#3b82f6;border-bottom:2px solid #3b82f6}.devtools-content{overflow-y:auto;flex:1;padding:.25rem 0}.devtools-empty{padding:2rem;text-align:center;color:#475569;font-size:.78rem;font-family:system-ui}.log-item{display:flex;justify-content:space-between;align-items:center;padding:.35rem .75rem;cursor:pointer;border-bottom:1px solid #1e293b}.log-item:hover{background:#1e293b}.log-item--error{background:#1a0a0a}.log-item__left{display:flex;align-items:center;gap:.4rem;overflow:hidden}.log-item__right{display:flex;align-items:center;gap:.4rem;flex-shrink:0}.log-status{font-size:.72rem;color:#22c55e;flex-shrink:0}.log-item--error .log-status{color:#ef4444}.log-name{color:#e2e8f0;font-size:.75rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.log-duration{color:#64748b;font-size:.7rem}.log-time{color:#475569;font-size:.68rem}.log-error-badge{background:#7f1d1d;color:#fca5a5;font-size:.68rem;padding:.1rem .35rem;border-radius:4px}.log-detail{background:#0a0f1a;padding:.6rem .75rem;border-left:3px solid #3b82f6;margin:0 .4rem .4rem;border-radius:0 4px 4px 0}.log-detail__error{color:#fca5a5;font-size:.72rem;margin-bottom:.4rem}.log-detail__section{margin-bottom:.4rem}.log-detail__label{color:#64748b;font-size:.68rem;display:block;margin-bottom:.2rem;font-family:system-ui}pre{color:#86efac;font-size:.7rem;margin:0;white-space:pre-wrap;word-break:break-all;max-height:140px;overflow-y:auto}.state-view{color:#86efac;font-size:.7rem;padding:.75rem;margin:0;white-space:pre-wrap;word-break:break-all}\n"] }]
501
+ }] });
502
+
503
+ // ─────────────────────────────────────────────────────
504
+ // @ngstato/angular — API publique
505
+ // ─────────────────────────────────────────────────────
506
+
507
+ /**
508
+ * Generated bundle index. Do not edit.
509
+ */
510
+
511
+ export { StatoDevToolsComponent, createAngularStore, injectStore, provideStato };
512
+ //# sourceMappingURL=ngstato-angular.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngstato-angular.mjs","sources":["../../src/inject-store.ts","../../src/provide-ngstato.ts","../../src/create-angular-store.ts","../../src/devtools.component.ts","../../src/index.ts","../../src/ngstato-angular.ts"],"sourcesContent":["// ─────────────────────────────────────────────────────\r\n// @ngstato/angular — injectStore()\r\n// Helper pour injecter un store dans un composant\r\n// ─────────────────────────────────────────────────────\r\n\r\nimport { inject, type Type } from '@angular/core'\r\n\r\nexport function injectStore<T>(store: Type<T>): T {\r\n return inject(store)\r\n}","import {\r\n makeEnvironmentProviders,\r\n InjectionToken,\r\n isDevMode\r\n} from '@angular/core'\r\nimport { configureHttp, devTools } from '@ngstato/core'\r\nimport type { StatoConfig } from '@ngstato/core'\r\n\r\nexport interface StatoAngularConfig {\r\n http?: StatoConfig\r\n devtools?: boolean\r\n}\r\n\r\nexport const STATO_CONFIG = new InjectionToken<StatoAngularConfig>('STATO_CONFIG')\r\n\r\nexport function provideStato(config: StatoAngularConfig = {}) {\r\n\r\n if (config.http) {\r\n configureHttp(config.http)\r\n }\r\n\r\n // DevTools — ignorés automatiquement en production\r\n // isDevMode() est géré par Angular au build\r\n // → false en prod même si devtools: true\r\n if (config.devtools && isDevMode()) {\r\n console.info(\r\n '%c[Stato] 🛠 DevTools activés',\r\n 'background:#1e40af;color:white;padding:4px 8px;border-radius:4px;font-weight:bold'\r\n )\r\n devTools.open()\r\n }\r\n\r\n return makeEnvironmentProviders([\r\n {\r\n provide: STATO_CONFIG,\r\n useValue: config\r\n }\r\n ])\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/angular — createAngularStore()\r\n// Transforme un ngstato store en store Angular avec Signals\r\n// ─────────────────────────────────────────────────────\r\n\r\nimport {\r\n signal,\r\n computed,\r\n Injectable,\r\n OnDestroy,\r\n Signal\r\n} from '@angular/core'\r\n\r\nimport { createStore } from '@ngstato/core'\r\nimport type { StatoStoreConfig } from '@ngstato/core'\r\n\r\n// ─────────────────────────────────────────────────────\r\n// FONCTION PRINCIPALE — createAngularStore()\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function createAngularStore<S extends object>(\r\n config: S & StatoStoreConfig<S>\r\n) {\r\n // 1. Créer le store core\r\n const coreStore = createStore(config)\r\n\r\n // 2. Créer un Signal pour chaque propriété du state\r\n const signals: Record<string, ReturnType<typeof signal>> = {}\r\n const initialState = coreStore.getState()\r\n\r\n for (const key of Object.keys(initialState as object)) {\r\n signals[key] = signal((initialState as any)[key])\r\n }\r\n\r\n // 3. Synchroniser les Signals avec le state core\r\n coreStore.subscribe((newState: any) => {\r\n for (const key of Object.keys(newState)) {\r\n if (signals[key]) {\r\n signals[key].set(newState[key])\r\n }\r\n }\r\n })\r\n\r\n // 4. Construire l objet public Angular\r\n const angularStore: any = {\r\n __store__: coreStore.__store__\r\n }\r\n\r\n // 5. Exposer chaque propriété comme Signal\r\n for (const key of Object.keys(initialState as object)) {\r\n Object.defineProperty(angularStore, key, {\r\n get: () => signals[key],\r\n enumerable: true,\r\n configurable: true\r\n })\r\n }\r\n\r\n // 6. Exposer chaque computed comme Signal computed\r\n const { computed: computedConfig } = config as StatoStoreConfig<S>\r\n if (computedConfig) {\r\n for (const key of Object.keys(computedConfig)) {\r\n const computedSignal = computed(() => coreStore[key])\r\n Object.defineProperty(angularStore, key, {\r\n get: () => computedSignal,\r\n enumerable: true,\r\n configurable: true\r\n })\r\n }\r\n }\r\n\r\n // 7. Exposer chaque action directement\r\n const { actions } = config as StatoStoreConfig<S>\r\n if (actions) {\r\n for (const name of Object.keys(actions)) {\r\n angularStore[name] = (...args: unknown[]) =>\r\n coreStore.__store__.dispatch(name, ...args)\r\n }\r\n }\r\n\r\n // 8. Appeler onInit si défini\r\n const { hooks } = config as StatoStoreConfig<S>\r\n if (hooks?.onInit) {\r\n hooks.onInit(angularStore)\r\n }\r\n\r\n // 9. Exposer destroy pour le cleanup\r\n angularStore.__destroy__ = () => {\r\n coreStore.__store__.destroy(angularStore)\r\n }\r\n\r\n return angularStore\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// CLASSE DE BASE — étendue par StatoStore()\r\n// Publique — pas de membres privés\r\n// ─────────────────────────────────────────────────────\r\n@Injectable()\r\nexport class StatoStoreBase implements OnDestroy {\r\n storeInstance: any\r\n\r\n initStore<S extends object>(config: S & StatoStoreConfig<S>) {\r\n this.storeInstance = createAngularStore(config)\r\n\r\n // Copier toutes les propriétés sur this\r\n for (const key of Object.keys(this.storeInstance)) {\r\n if (key !== '__store__' && key !== '__destroy__') {\r\n Object.defineProperty(this, key, {\r\n get: () => this.storeInstance[key],\r\n enumerable: true,\r\n configurable: true\r\n })\r\n }\r\n }\r\n\r\n // Copier les actions\r\n const { actions } = config as StatoStoreConfig<S>\r\n if (actions) {\r\n for (const name of Object.keys(actions)) {\r\n Object.defineProperty(this, name, {\r\n get: () => this.storeInstance[name],\r\n enumerable: true,\r\n configurable: true\r\n })\r\n }\r\n }\r\n }\r\n\r\n ngOnDestroy() {\r\n this.storeInstance?.__destroy__()\r\n }\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// FACTORY — StatoStore()\r\n// Crée un service Angular injectable\r\n// Usage :\r\n// export class UserStore extends StatoStore({\r\n// user: null,\r\n// actions: { ... }\r\n// }) {}\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function StatoStore<S extends object>(\r\n config: S & StatoStoreConfig<S>\r\n) {\r\n @Injectable({ providedIn: 'root' })\r\n class ConcreteStore extends StatoStoreBase {\r\n constructor() {\r\n super()\r\n this.initStore(config)\r\n }\r\n }\r\n\r\n return ConcreteStore\r\n}","import {\n Component,\n OnInit,\n OnDestroy,\n signal\n} from '@angular/core'\nimport { devTools } from '@ngstato/core'\nimport type { ActionLog } from '@ngstato/core'\nimport { JsonPipe } from '@angular/common'\n\n@Component({\n selector: 'ngstato-devtools',\n standalone: true,\n imports: [JsonPipe],\n template: `\n <!-- Bouton flottant -->\n @if (!isOpen()) {\n <button class=\"devtools-fab\" (click)=\"toggle()\">\n 🛠 Stato\n </button>\n }\n\n <!-- Panel -->\n @if (isOpen()) {\n <div\n class=\"devtools-panel\"\n [class.devtools-panel--minimized]=\"isMinimized()\"\n [style.left.px]=\"posX()\"\n [style.top.px]=\"posY()\"\n [style.width.px]=\"isMinimized() ? 200 : panelWidth()\"\n [style.height]=\"isMinimized() ? 'auto' : panelHeight() + 'px'\"\n >\n\n <!-- Header — draggable -->\n <div\n class=\"devtools-header\"\n (mousedown)=\"onDragStart($event)\"\n >\n <span class=\"devtools-title\">🛠 Stato</span>\n <div class=\"devtools-header-actions\">\n @if (!isMinimized()) {\n <button class=\"btn-icon\" (click)=\"clear()\" title=\"Vider\">🗑</button>\n }\n <button class=\"btn-icon\" (click)=\"toggleMinimize()\" title=\"Minimiser/Agrandir\">\n {{ isMinimized() ? '▲' : '▼' }}\n </button>\n <button class=\"btn-icon\" (click)=\"toggle()\" title=\"Fermer\">✕</button>\n </div>\n </div>\n\n <!-- Resize handle — coin bas droite -->\n @if (!isMinimized()) {\n <div\n class=\"devtools-resize\"\n (mousedown)=\"onResizeStart($event)\"\n >⊿</div>\n }\n\n @if (!isMinimized()) {\n\n <!-- Tabs -->\n <div class=\"devtools-tabs\">\n <button\n class=\"tab\"\n [class.tab--active]=\"activeTab() === 'actions'\"\n (click)=\"activeTab.set('actions')\"\n >\n Actions ({{ logs().length }})\n </button>\n <button\n class=\"tab\"\n [class.tab--active]=\"activeTab() === 'state'\"\n (click)=\"activeTab.set('state')\"\n >\n State\n </button>\n </div>\n\n <!-- Tab Actions -->\n @if (activeTab() === 'actions') {\n <div class=\"devtools-content\">\n @if (!logs().length) {\n <div class=\"devtools-empty\">Aucune action pour l'instant</div>\n }\n @for (log of logs(); track log.id) {\n <div\n class=\"log-item\"\n [class.log-item--error]=\"log.status === 'error'\"\n (click)=\"selectLog(log)\"\n >\n <div class=\"log-item__left\">\n <span class=\"log-status\">{{ log.status === 'success' ? '✓' : '✗' }}</span>\n <span class=\"log-name\">{{ log.name }}</span>\n </div>\n <div class=\"log-item__right\">\n @if (log.status === 'error') {\n <span class=\"log-error-badge\">erreur</span>\n } @else {\n <span class=\"log-duration\">{{ log.duration }}ms</span>\n }\n <span class=\"log-time\">{{ formatTime(log.at) }}</span>\n </div>\n </div>\n\n @if (selectedLog()?.id === log.id) {\n <div class=\"log-detail\">\n @if (log.error) {\n <div class=\"log-detail__error\">{{ log.error }}</div>\n }\n <div class=\"log-detail__section\">\n <span class=\"log-detail__label\">Avant</span>\n <pre>{{ log.prevState | json }}</pre>\n </div>\n <div class=\"log-detail__section\">\n <span class=\"log-detail__label\">Après</span>\n <pre>{{ log.nextState | json }}</pre>\n </div>\n </div>\n }\n }\n </div>\n }\n\n <!-- Tab State -->\n @if (activeTab() === 'state') {\n <div class=\"devtools-content\">\n @if (logs().length) {\n <pre class=\"state-view\">{{ logs()[0].nextState | json }}</pre>\n } @else {\n <div class=\"devtools-empty\">Aucun state disponible</div>\n }\n </div>\n }\n }\n\n </div>\n }\n `,\n styles: [`\n .devtools-fab {\n position: fixed;\n bottom: 1.5rem;\n left: 1.5rem;\n background: #1e293b;\n color: white;\n border: none;\n border-radius: 999px;\n padding: 0.5rem 1rem;\n font-size: 0.85rem;\n font-weight: 600;\n cursor: pointer;\n z-index: 9999;\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\n transition: background 0.15s;\n }\n .devtools-fab:hover { background: #334155; }\n\n .devtools-panel {\n position: fixed;\n background: #0f172a;\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.4);\n z-index: 9999;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n font-family: 'Courier New', monospace;\n min-width: 200px;\n min-height: 40px;\n }\n\n .devtools-panel--minimized {\n border-radius: 8px;\n }\n\n .devtools-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 0.6rem 0.75rem;\n background: #1e293b;\n border-bottom: 1px solid #334155;\n cursor: grab;\n user-select: none;\n }\n .devtools-header:active { cursor: grabbing; }\n\n .devtools-title {\n color: #e2e8f0;\n font-size: 0.82rem;\n font-weight: 600;\n font-family: system-ui;\n }\n\n .devtools-header-actions { display: flex; gap: 0.25rem; }\n\n .btn-icon {\n background: transparent;\n color: #64748b;\n border: none;\n cursor: pointer;\n font-size: 0.8rem;\n padding: 0.15rem 0.35rem;\n border-radius: 4px;\n line-height: 1;\n }\n .btn-icon:hover { background: #334155; color: white; }\n\n .devtools-resize {\n position: absolute;\n bottom: 2px;\n right: 4px;\n color: #334155;\n font-size: 0.9rem;\n cursor: nwse-resize;\n user-select: none;\n line-height: 1;\n }\n .devtools-resize:hover { color: #64748b; }\n\n .devtools-tabs {\n display: flex;\n background: #1e293b;\n border-bottom: 1px solid #334155;\n }\n .tab {\n padding: 0.4rem 0.75rem;\n background: transparent;\n color: #64748b;\n border: none;\n cursor: pointer;\n font-size: 0.78rem;\n font-family: system-ui;\n }\n .tab:hover { color: #e2e8f0; }\n .tab--active { color: #3b82f6; border-bottom: 2px solid #3b82f6; }\n\n .devtools-content {\n overflow-y: auto;\n flex: 1;\n padding: 0.25rem 0;\n }\n\n .devtools-empty {\n padding: 2rem;\n text-align: center;\n color: #475569;\n font-size: 0.78rem;\n font-family: system-ui;\n }\n\n .log-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 0.35rem 0.75rem;\n cursor: pointer;\n border-bottom: 1px solid #1e293b;\n }\n .log-item:hover { background: #1e293b; }\n .log-item--error { background: #1a0a0a; }\n\n .log-item__left { display: flex; align-items: center; gap: 0.4rem; overflow: hidden; }\n .log-item__right { display: flex; align-items: center; gap: 0.4rem; flex-shrink: 0; }\n\n .log-status { font-size: 0.72rem; color: #22c55e; flex-shrink: 0; }\n .log-item--error .log-status { color: #ef4444; }\n .log-name { color: #e2e8f0; font-size: 0.75rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n .log-duration { color: #64748b; font-size: 0.7rem; }\n .log-time { color: #475569; font-size: 0.68rem; }\n\n .log-error-badge {\n background: #7f1d1d;\n color: #fca5a5;\n font-size: 0.68rem;\n padding: 0.1rem 0.35rem;\n border-radius: 4px;\n }\n\n .log-detail {\n background: #0a0f1a;\n padding: 0.6rem 0.75rem;\n border-left: 3px solid #3b82f6;\n margin: 0 0.4rem 0.4rem;\n border-radius: 0 4px 4px 0;\n }\n .log-detail__error { color: #fca5a5; font-size: 0.72rem; margin-bottom: 0.4rem; }\n .log-detail__section { margin-bottom: 0.4rem; }\n .log-detail__label {\n color: #64748b;\n font-size: 0.68rem;\n display: block;\n margin-bottom: 0.2rem;\n font-family: system-ui;\n }\n pre {\n color: #86efac;\n font-size: 0.7rem;\n margin: 0;\n white-space: pre-wrap;\n word-break: break-all;\n max-height: 140px;\n overflow-y: auto;\n }\n .state-view {\n color: #86efac;\n font-size: 0.7rem;\n padding: 0.75rem;\n margin: 0;\n white-space: pre-wrap;\n word-break: break-all;\n }\n `]\n})\nexport class StatoDevToolsComponent implements OnInit, OnDestroy {\n\n private unsub?: () => void\n\n // State UI\n isOpen = signal(false)\n isMinimized = signal(false)\n activeTab = signal<'actions' | 'state'>('actions')\n logs = signal<ActionLog[]>([])\n selectedLog = signal<ActionLog | null>(null)\n\n // Position et taille\n posX = signal(24)\n posY = signal(window.innerHeight - 500)\n panelWidth = signal(420)\n panelHeight = signal(460)\n\n // Drag state\n private isDragging = false\n private isResizing = false\n private dragOffsetX = 0\n private dragOffsetY = 0\n private startW = 0\n private startH = 0\n private startX = 0\n private startY = 0\n\n // Bound listeners\n private boundMouseMove = this.onMouseMove.bind(this)\n private boundMouseUp = this.onMouseUp.bind(this)\n\n ngOnInit() {\n this.unsub = devTools.subscribe((state) => {\n this.logs.set(state.logs)\n this.isOpen.set(state.isOpen)\n })\n\n document.addEventListener('mousemove', this.boundMouseMove)\n document.addEventListener('mouseup', this.boundMouseUp)\n }\n\n ngOnDestroy() {\n this.unsub?.()\n document.removeEventListener('mousemove', this.boundMouseMove)\n document.removeEventListener('mouseup', this.boundMouseUp)\n }\n\n // ── Toggle ─────────────────────────────────────────\n toggle() { devTools.toggle() }\n toggleMinimize() { this.isMinimized.update(v => !v) }\n clear() { devTools.clear(); this.selectedLog.set(null) }\n selectLog(log: ActionLog) {\n this.selectedLog.set(this.selectedLog()?.id === log.id ? null : log)\n }\n formatTime(iso: string): string {\n return new Date(iso).toTimeString().slice(0, 8)\n }\n\n // ── Drag ───────────────────────────────────────────\n onDragStart(e: MouseEvent) {\n if ((e.target as HTMLElement).classList.contains('btn-icon')) return\n this.isDragging = true\n this.dragOffsetX = e.clientX - this.posX()\n this.dragOffsetY = e.clientY - this.posY()\n e.preventDefault()\n }\n\n // ── Resize ─────────────────────────────────────────\n onResizeStart(e: MouseEvent) {\n this.isResizing = true\n this.startW = this.panelWidth()\n this.startH = this.panelHeight()\n this.startX = e.clientX\n this.startY = e.clientY\n e.preventDefault()\n e.stopPropagation()\n }\n\n // ── Mouse Move ─────────────────────────────────────\n onMouseMove(e: MouseEvent) {\n if (this.isDragging) {\n this.posX.set(Math.max(0, e.clientX - this.dragOffsetX))\n this.posY.set(Math.max(0, e.clientY - this.dragOffsetY))\n }\n if (this.isResizing) {\n const newW = Math.max(300, this.startW + e.clientX - this.startX)\n const newH = Math.max(200, this.startH + e.clientY - this.startY)\n this.panelWidth.set(newW)\n this.panelHeight.set(newH)\n }\n }\n\n // ── Mouse Up ───────────────────────────────────────\n onMouseUp() {\n this.isDragging = false\n this.isResizing = false\n }\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/angular — API publique\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport { injectStore } from './inject-store'\r\nexport { provideStato } from './provide-ngstato'\r\nexport { createAngularStore} from './create-angular-store'\r\nexport type { StatoAngularConfig } from './provide-ngstato'\r\nexport { StatoDevToolsComponent } from './devtools.component'","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,50 +1,5 @@
1
- import * as _angular_core from '@angular/core';
2
- import { Type, OnInit, OnDestroy } from '@angular/core';
3
- import { StatoConfig, StatoStoreConfig, ActionLog } from '@ngstato/core';
4
-
5
- declare function injectStore<T>(store: Type<T>): T;
6
-
7
- interface StatoAngularConfig {
8
- http?: StatoConfig;
9
- devtools?: boolean;
10
- }
11
- declare function provideStato(config?: StatoAngularConfig): _angular_core.EnvironmentProviders;
12
-
13
- declare function createAngularStore<S extends object>(config: S & StatoStoreConfig<S>): any;
14
-
15
- declare class StatoDevToolsComponent implements OnInit, OnDestroy {
16
- private config;
17
- private unsub?;
18
- isOpen: _angular_core.WritableSignal<boolean>;
19
- isMinimized: _angular_core.WritableSignal<boolean>;
20
- activeTab: _angular_core.WritableSignal<"actions" | "state">;
21
- logs: _angular_core.WritableSignal<ActionLog[]>;
22
- selectedLog: _angular_core.WritableSignal<ActionLog | null>;
23
- posX: _angular_core.WritableSignal<number>;
24
- posY: _angular_core.WritableSignal<number>;
25
- panelWidth: _angular_core.WritableSignal<number>;
26
- panelHeight: _angular_core.WritableSignal<number>;
27
- private isDragging;
28
- private isResizing;
29
- private dragOffsetX;
30
- private dragOffsetY;
31
- private startW;
32
- private startH;
33
- private startX;
34
- private startY;
35
- private boundMouseMove;
36
- private boundMouseUp;
37
- ngOnInit(): void;
38
- ngOnDestroy(): void;
39
- toggle(): void;
40
- toggleMinimize(): void;
41
- clear(): void;
42
- selectLog(log: ActionLog): void;
43
- formatTime(iso: string): string;
44
- onDragStart(e: MouseEvent): void;
45
- onResizeStart(e: MouseEvent): void;
46
- onMouseMove(e: MouseEvent): void;
47
- onMouseUp(): void;
48
- }
49
-
50
- export { type StatoAngularConfig, StatoDevToolsComponent, createAngularStore, injectStore, provideStato };
1
+ export { injectStore } from './inject-store';
2
+ export { provideStato } from './provide-ngstato';
3
+ export { createAngularStore } from './create-angular-store';
4
+ export type { StatoAngularConfig } from './provide-ngstato';
5
+ export { StatoDevToolsComponent } from './devtools.component';
@@ -0,0 +1,2 @@
1
+ import { type Type } from '@angular/core';
2
+ export declare function injectStore<T>(store: Type<T>): T;
@@ -0,0 +1,8 @@
1
+ import { InjectionToken } from '@angular/core';
2
+ import type { StatoConfig } from '@ngstato/core';
3
+ export interface StatoAngularConfig {
4
+ http?: StatoConfig;
5
+ devtools?: boolean;
6
+ }
7
+ export declare const STATO_CONFIG: InjectionToken<StatoAngularConfig>;
8
+ export declare function provideStato(config?: StatoAngularConfig): import("@angular/core").EnvironmentProviders;