@ngstato/angular 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,23 +1,25 @@
1
- import { InjectionToken, Injectable, inject, signal, Component, computed, isDevMode, makeEnvironmentProviders } from '@angular/core';
2
- import { devTools, createStore, configureHttp } from '@ngstato/core';
3
- import { CommonModule } from '@angular/common';
1
+ 'use strict';
2
+
3
+ var core = require('@angular/core');
4
+ var core$1 = require('@ngstato/core');
5
+ var common = require('@angular/common');
4
6
 
5
7
  var __defProp = Object.defineProperty;
6
8
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
9
  function injectStore(store) {
8
- return inject(store);
10
+ return core.inject(store);
9
11
  }
10
12
  __name(injectStore, "injectStore");
11
- var STATO_CONFIG = new InjectionToken("STATO_CONFIG");
13
+ var STATO_CONFIG = new core.InjectionToken("STATO_CONFIG");
12
14
  function provideStato(config = {}) {
13
15
  if (config.http) {
14
- configureHttp(config.http);
16
+ core$1.configureHttp(config.http);
15
17
  }
16
- if (config.devtools && isDevMode()) {
18
+ if (config.devtools && core.isDevMode()) {
17
19
  console.info("%c[Stato] \u{1F6E0} DevTools activ\xE9s", "background:#1e40af;color:white;padding:4px 8px;border-radius:4px;font-weight:bold");
18
- devTools.open();
20
+ core$1.devTools.open();
19
21
  }
20
- return makeEnvironmentProviders([
22
+ return core.makeEnvironmentProviders([
21
23
  {
22
24
  provide: STATO_CONFIG,
23
25
  useValue: config
@@ -33,11 +35,11 @@ function _ts_decorate(decorators, target, key, desc) {
33
35
  }
34
36
  __name(_ts_decorate, "_ts_decorate");
35
37
  function createAngularStore(config) {
36
- const coreStore = createStore(config);
38
+ const coreStore = core$1.createStore(config);
37
39
  const signals = {};
38
40
  const initialState = coreStore.getState();
39
41
  for (const key of Object.keys(initialState)) {
40
- signals[key] = signal(initialState[key]);
42
+ signals[key] = core.signal(initialState[key]);
41
43
  }
42
44
  coreStore.subscribe((newState) => {
43
45
  for (const key of Object.keys(newState)) {
@@ -59,7 +61,7 @@ function createAngularStore(config) {
59
61
  const { computed: computedConfig } = config;
60
62
  if (computedConfig) {
61
63
  for (const key of Object.keys(computedConfig)) {
62
- const computedSignal = computed(() => coreStore[key]);
64
+ const computedSignal = core.computed(() => coreStore[key]);
63
65
  Object.defineProperty(angularStore, key, {
64
66
  get: /* @__PURE__ */ __name(() => computedSignal, "get"),
65
67
  enumerable: true,
@@ -115,7 +117,7 @@ var StatoStoreBase = class {
115
117
  }
116
118
  };
117
119
  StatoStoreBase = _ts_decorate([
118
- Injectable()
120
+ core.Injectable()
119
121
  ], StatoStoreBase);
120
122
  function _ts_decorate2(decorators, target, key, desc) {
121
123
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -124,25 +126,25 @@ function _ts_decorate2(decorators, target, key, desc) {
124
126
  return c > 3 && r && Object.defineProperty(target, key, r), r;
125
127
  }
126
128
  __name(_ts_decorate2, "_ts_decorate");
127
- var StatoDevToolsComponent = class {
129
+ exports.StatoDevToolsComponent = class StatoDevToolsComponent {
128
130
  static {
129
131
  __name(this, "StatoDevToolsComponent");
130
132
  }
131
- config = inject(STATO_CONFIG, {
133
+ config = core.inject(STATO_CONFIG, {
132
134
  optional: true
133
135
  });
134
136
  unsub;
135
137
  // State UI
136
- isOpen = signal(false);
137
- isMinimized = signal(false);
138
- activeTab = signal("actions");
139
- logs = signal([]);
140
- selectedLog = signal(null);
138
+ isOpen = core.signal(false);
139
+ isMinimized = core.signal(false);
140
+ activeTab = core.signal("actions");
141
+ logs = core.signal([]);
142
+ selectedLog = core.signal(null);
141
143
  // Position et taille
142
- posX = signal(24);
143
- posY = signal(window.innerHeight - 500);
144
- panelWidth = signal(420);
145
- panelHeight = signal(460);
144
+ posX = core.signal(24);
145
+ posY = core.signal(window.innerHeight - 500);
146
+ panelWidth = core.signal(420);
147
+ panelHeight = core.signal(460);
146
148
  // Drag state
147
149
  isDragging = false;
148
150
  isResizing = false;
@@ -156,7 +158,7 @@ var StatoDevToolsComponent = class {
156
158
  boundMouseMove = this.onMouseMove.bind(this);
157
159
  boundMouseUp = this.onMouseUp.bind(this);
158
160
  ngOnInit() {
159
- this.unsub = devTools.subscribe((state) => {
161
+ this.unsub = core$1.devTools.subscribe((state) => {
160
162
  this.logs.set(state.logs);
161
163
  this.isOpen.set(state.isOpen);
162
164
  });
@@ -170,13 +172,13 @@ var StatoDevToolsComponent = class {
170
172
  }
171
173
  // ── Toggle ─────────────────────────────────────────
172
174
  toggle() {
173
- devTools.toggle();
175
+ core$1.devTools.toggle();
174
176
  }
175
177
  toggleMinimize() {
176
178
  this.isMinimized.update((v) => !v);
177
179
  }
178
180
  clear() {
179
- devTools.clear();
181
+ core$1.devTools.clear();
180
182
  this.selectedLog.set(null);
181
183
  }
182
184
  selectLog(log) {
@@ -222,12 +224,12 @@ var StatoDevToolsComponent = class {
222
224
  this.isResizing = false;
223
225
  }
224
226
  };
225
- StatoDevToolsComponent = _ts_decorate2([
226
- Component({
227
+ exports.StatoDevToolsComponent = _ts_decorate2([
228
+ core.Component({
227
229
  selector: "ngstato-devtools",
228
230
  standalone: true,
229
231
  imports: [
230
- CommonModule
232
+ common.CommonModule
231
233
  ],
232
234
  template: `
233
235
  <!-- Bouton flottant -->
@@ -531,8 +533,10 @@ StatoDevToolsComponent = _ts_decorate2([
531
533
  `
532
534
  ]
533
535
  })
534
- ], StatoDevToolsComponent);
536
+ ], exports.StatoDevToolsComponent);
535
537
 
536
- export { StatoDevToolsComponent, createAngularStore, injectStore, provideStato };
538
+ exports.createAngularStore = createAngularStore;
539
+ exports.injectStore = injectStore;
540
+ exports.provideStato = provideStato;
537
541
  //# sourceMappingURL=index.js.map
538
542
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/inject-store.ts","../src/provide-ngstato.ts","../src/create-angular-store.ts","../src/devtools.component.ts"],"names":["injectStore","store","inject","STATO_CONFIG","InjectionToken","provideStato","config","http","configureHttp","devtools","isDevMode","console","info","devTools","open","makeEnvironmentProviders","provide","useValue","createAngularStore","coreStore","createStore","signals","initialState","getState","key","Object","keys","signal","subscribe","newState","set","angularStore","__store__","defineProperty","get","enumerable","configurable","computed","computedConfig","computedSignal","actions","name","args","dispatch","hooks","onInit","__destroy__","destroy","StatoStoreBase","storeInstance","initStore","ngOnDestroy","StatoDevToolsComponent","optional","unsub","isOpen","isMinimized","activeTab","logs","selectedLog","posX","posY","window","innerHeight","panelWidth","panelHeight","isDragging","isResizing","dragOffsetX","dragOffsetY","startW","startH","startX","startY","boundMouseMove","onMouseMove","bind","boundMouseUp","onMouseUp","ngOnInit","state","document","addEventListener","removeEventListener","toggle","toggleMinimize","update","v","clear","selectLog","log","id","formatTime","iso","Date","toTimeString","slice","onDragStart","e","target","classList","contains","clientX","clientY","preventDefault","onResizeStart","stopPropagation","Math","max","newW","newH","selector","standalone","imports","CommonModule","template","styles"],"mappings":"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","file":"index.js","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 {\r\n Component,\r\n OnInit,\r\n OnDestroy,\r\n signal,\r\n inject,\r\n ElementRef,\r\n ViewChild,\r\n AfterViewInit\r\n} from '@angular/core'\r\nimport { CommonModule } from '@angular/common'\r\nimport { devTools } from '@ngstato/core'\r\nimport type { ActionLog } from '@ngstato/core'\r\nimport { STATO_CONFIG } from './provide-ngstato'\r\n\r\n@Component({\r\n selector: 'ngstato-devtools',\r\n standalone: true,\r\n imports: [CommonModule],\r\n template: `\r\n <!-- Bouton flottant -->\r\n @if (!isOpen()) {\r\n <button class=\"devtools-fab\" (click)=\"toggle()\">\r\n 🛠 Stato\r\n </button>\r\n }\r\n\r\n <!-- Panel -->\r\n @if (isOpen()) {\r\n <div\r\n class=\"devtools-panel\"\r\n [class.devtools-panel--minimized]=\"isMinimized()\"\r\n [style.left.px]=\"posX()\"\r\n [style.top.px]=\"posY()\"\r\n [style.width.px]=\"isMinimized() ? 200 : panelWidth()\"\r\n [style.height]=\"isMinimized() ? 'auto' : panelHeight() + 'px'\"\r\n >\r\n\r\n <!-- Header — draggable -->\r\n <div\r\n class=\"devtools-header\"\r\n (mousedown)=\"onDragStart($event)\"\r\n >\r\n <span class=\"devtools-title\">🛠 Stato</span>\r\n <div class=\"devtools-header-actions\">\r\n @if (!isMinimized()) {\r\n <button class=\"btn-icon\" (click)=\"clear()\" title=\"Vider\">🗑</button>\r\n }\r\n <button class=\"btn-icon\" (click)=\"toggleMinimize()\" title=\"Minimiser/Agrandir\">\r\n {{ isMinimized() ? '▲' : '▼' }}\r\n </button>\r\n <button class=\"btn-icon\" (click)=\"toggle()\" title=\"Fermer\">✕</button>\r\n </div>\r\n </div>\r\n\r\n <!-- Resize handle — coin bas droite -->\r\n @if (!isMinimized()) {\r\n <div\r\n class=\"devtools-resize\"\r\n (mousedown)=\"onResizeStart($event)\"\r\n >⊿</div>\r\n }\r\n\r\n @if (!isMinimized()) {\r\n\r\n <!-- Tabs -->\r\n <div class=\"devtools-tabs\">\r\n <button\r\n class=\"tab\"\r\n [class.tab--active]=\"activeTab() === 'actions'\"\r\n (click)=\"activeTab.set('actions')\"\r\n >\r\n Actions ({{ logs().length }})\r\n </button>\r\n <button\r\n class=\"tab\"\r\n [class.tab--active]=\"activeTab() === 'state'\"\r\n (click)=\"activeTab.set('state')\"\r\n >\r\n State\r\n </button>\r\n </div>\r\n\r\n <!-- Tab Actions -->\r\n @if (activeTab() === 'actions') {\r\n <div class=\"devtools-content\">\r\n @if (!logs().length) {\r\n <div class=\"devtools-empty\">Aucune action pour l'instant</div>\r\n }\r\n @for (log of logs(); track log.id) {\r\n <div\r\n class=\"log-item\"\r\n [class.log-item--error]=\"log.status === 'error'\"\r\n (click)=\"selectLog(log)\"\r\n >\r\n <div class=\"log-item__left\">\r\n <span class=\"log-status\">{{ log.status === 'success' ? '✓' : '✗' }}</span>\r\n <span class=\"log-name\">{{ log.name }}</span>\r\n </div>\r\n <div class=\"log-item__right\">\r\n @if (log.status === 'error') {\r\n <span class=\"log-error-badge\">erreur</span>\r\n } @else {\r\n <span class=\"log-duration\">{{ log.duration }}ms</span>\r\n }\r\n <span class=\"log-time\">{{ formatTime(log.at) }}</span>\r\n </div>\r\n </div>\r\n\r\n @if (selectedLog()?.id === log.id) {\r\n <div class=\"log-detail\">\r\n @if (log.error) {\r\n <div class=\"log-detail__error\">{{ log.error }}</div>\r\n }\r\n <div class=\"log-detail__section\">\r\n <span class=\"log-detail__label\">Avant</span>\r\n <pre>{{ log.prevState | json }}</pre>\r\n </div>\r\n <div class=\"log-detail__section\">\r\n <span class=\"log-detail__label\">Après</span>\r\n <pre>{{ log.nextState | json }}</pre>\r\n </div>\r\n </div>\r\n }\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Tab State -->\r\n @if (activeTab() === 'state') {\r\n <div class=\"devtools-content\">\r\n @if (logs().length) {\r\n <pre class=\"state-view\">{{ logs()[0].nextState | json }}</pre>\r\n } @else {\r\n <div class=\"devtools-empty\">Aucun state disponible</div>\r\n }\r\n </div>\r\n }\r\n }\r\n\r\n </div>\r\n }\r\n `,\r\n styles: [`\r\n .devtools-fab {\r\n position: fixed;\r\n bottom: 1.5rem;\r\n left: 1.5rem;\r\n background: #1e293b;\r\n color: white;\r\n border: none;\r\n border-radius: 999px;\r\n padding: 0.5rem 1rem;\r\n font-size: 0.85rem;\r\n font-weight: 600;\r\n cursor: pointer;\r\n z-index: 9999;\r\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\r\n transition: background 0.15s;\r\n }\r\n .devtools-fab:hover { background: #334155; }\r\n\r\n .devtools-panel {\r\n position: fixed;\r\n background: #0f172a;\r\n border-radius: 12px;\r\n box-shadow: 0 8px 32px rgba(0,0,0,0.4);\r\n z-index: 9999;\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n font-family: 'Courier New', monospace;\r\n min-width: 200px;\r\n min-height: 40px;\r\n }\r\n\r\n .devtools-panel--minimized {\r\n border-radius: 8px;\r\n }\r\n\r\n .devtools-header {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n padding: 0.6rem 0.75rem;\r\n background: #1e293b;\r\n border-bottom: 1px solid #334155;\r\n cursor: grab;\r\n user-select: none;\r\n }\r\n .devtools-header:active { cursor: grabbing; }\r\n\r\n .devtools-title {\r\n color: #e2e8f0;\r\n font-size: 0.82rem;\r\n font-weight: 600;\r\n font-family: system-ui;\r\n }\r\n\r\n .devtools-header-actions { display: flex; gap: 0.25rem; }\r\n\r\n .btn-icon {\r\n background: transparent;\r\n color: #64748b;\r\n border: none;\r\n cursor: pointer;\r\n font-size: 0.8rem;\r\n padding: 0.15rem 0.35rem;\r\n border-radius: 4px;\r\n line-height: 1;\r\n }\r\n .btn-icon:hover { background: #334155; color: white; }\r\n\r\n .devtools-resize {\r\n position: absolute;\r\n bottom: 2px;\r\n right: 4px;\r\n color: #334155;\r\n font-size: 0.9rem;\r\n cursor: nwse-resize;\r\n user-select: none;\r\n line-height: 1;\r\n }\r\n .devtools-resize:hover { color: #64748b; }\r\n\r\n .devtools-tabs {\r\n display: flex;\r\n background: #1e293b;\r\n border-bottom: 1px solid #334155;\r\n }\r\n .tab {\r\n padding: 0.4rem 0.75rem;\r\n background: transparent;\r\n color: #64748b;\r\n border: none;\r\n cursor: pointer;\r\n font-size: 0.78rem;\r\n font-family: system-ui;\r\n }\r\n .tab:hover { color: #e2e8f0; }\r\n .tab--active { color: #3b82f6; border-bottom: 2px solid #3b82f6; }\r\n\r\n .devtools-content {\r\n overflow-y: auto;\r\n flex: 1;\r\n padding: 0.25rem 0;\r\n }\r\n\r\n .devtools-empty {\r\n padding: 2rem;\r\n text-align: center;\r\n color: #475569;\r\n font-size: 0.78rem;\r\n font-family: system-ui;\r\n }\r\n\r\n .log-item {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n padding: 0.35rem 0.75rem;\r\n cursor: pointer;\r\n border-bottom: 1px solid #1e293b;\r\n }\r\n .log-item:hover { background: #1e293b; }\r\n .log-item--error { background: #1a0a0a; }\r\n\r\n .log-item__left { display: flex; align-items: center; gap: 0.4rem; overflow: hidden; }\r\n .log-item__right { display: flex; align-items: center; gap: 0.4rem; flex-shrink: 0; }\r\n\r\n .log-status { font-size: 0.72rem; color: #22c55e; flex-shrink: 0; }\r\n .log-item--error .log-status { color: #ef4444; }\r\n .log-name { color: #e2e8f0; font-size: 0.75rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\r\n .log-duration { color: #64748b; font-size: 0.7rem; }\r\n .log-time { color: #475569; font-size: 0.68rem; }\r\n\r\n .log-error-badge {\r\n background: #7f1d1d;\r\n color: #fca5a5;\r\n font-size: 0.68rem;\r\n padding: 0.1rem 0.35rem;\r\n border-radius: 4px;\r\n }\r\n\r\n .log-detail {\r\n background: #0a0f1a;\r\n padding: 0.6rem 0.75rem;\r\n border-left: 3px solid #3b82f6;\r\n margin: 0 0.4rem 0.4rem;\r\n border-radius: 0 4px 4px 0;\r\n }\r\n .log-detail__error { color: #fca5a5; font-size: 0.72rem; margin-bottom: 0.4rem; }\r\n .log-detail__section { margin-bottom: 0.4rem; }\r\n .log-detail__label {\r\n color: #64748b;\r\n font-size: 0.68rem;\r\n display: block;\r\n margin-bottom: 0.2rem;\r\n font-family: system-ui;\r\n }\r\n pre {\r\n color: #86efac;\r\n font-size: 0.7rem;\r\n margin: 0;\r\n white-space: pre-wrap;\r\n word-break: break-all;\r\n max-height: 140px;\r\n overflow-y: auto;\r\n }\r\n .state-view {\r\n color: #86efac;\r\n font-size: 0.7rem;\r\n padding: 0.75rem;\r\n margin: 0;\r\n white-space: pre-wrap;\r\n word-break: break-all;\r\n }\r\n `]\r\n})\r\nexport class StatoDevToolsComponent implements OnInit, OnDestroy {\r\n\r\n private config = inject(STATO_CONFIG, { optional: true })\r\n private unsub?: () => void\r\n\r\n // State UI\r\n isOpen = signal(false)\r\n isMinimized = signal(false)\r\n activeTab = signal<'actions' | 'state'>('actions')\r\n logs = signal<ActionLog[]>([])\r\n selectedLog = signal<ActionLog | null>(null)\r\n\r\n // Position et taille\r\n posX = signal(24)\r\n posY = signal(window.innerHeight - 500)\r\n panelWidth = signal(420)\r\n panelHeight = signal(460)\r\n\r\n // Drag state\r\n private isDragging = false\r\n private isResizing = false\r\n private dragOffsetX = 0\r\n private dragOffsetY = 0\r\n private startW = 0\r\n private startH = 0\r\n private startX = 0\r\n private startY = 0\r\n\r\n // Bound listeners\r\n private boundMouseMove = this.onMouseMove.bind(this)\r\n private boundMouseUp = this.onMouseUp.bind(this)\r\n\r\n ngOnInit() {\r\n this.unsub = devTools.subscribe((state) => {\r\n this.logs.set(state.logs)\r\n this.isOpen.set(state.isOpen)\r\n })\r\n\r\n document.addEventListener('mousemove', this.boundMouseMove)\r\n document.addEventListener('mouseup', this.boundMouseUp)\r\n }\r\n\r\n ngOnDestroy() {\r\n this.unsub?.()\r\n document.removeEventListener('mousemove', this.boundMouseMove)\r\n document.removeEventListener('mouseup', this.boundMouseUp)\r\n }\r\n\r\n // ── Toggle ─────────────────────────────────────────\r\n toggle() { devTools.toggle() }\r\n toggleMinimize() { this.isMinimized.update(v => !v) }\r\n clear() { devTools.clear(); this.selectedLog.set(null) }\r\n selectLog(log: ActionLog) {\r\n this.selectedLog.set(this.selectedLog()?.id === log.id ? null : log)\r\n }\r\n formatTime(iso: string): string {\r\n return new Date(iso).toTimeString().slice(0, 8)\r\n }\r\n\r\n // ── Drag ───────────────────────────────────────────\r\n onDragStart(e: MouseEvent) {\r\n if ((e.target as HTMLElement).classList.contains('btn-icon')) return\r\n this.isDragging = true\r\n this.dragOffsetX = e.clientX - this.posX()\r\n this.dragOffsetY = e.clientY - this.posY()\r\n e.preventDefault()\r\n }\r\n\r\n // ── Resize ─────────────────────────────────────────\r\n onResizeStart(e: MouseEvent) {\r\n this.isResizing = true\r\n this.startW = this.panelWidth()\r\n this.startH = this.panelHeight()\r\n this.startX = e.clientX\r\n this.startY = e.clientY\r\n e.preventDefault()\r\n e.stopPropagation()\r\n }\r\n\r\n // ── Mouse Move ─────────────────────────────────────\r\n onMouseMove(e: MouseEvent) {\r\n if (this.isDragging) {\r\n this.posX.set(Math.max(0, e.clientX - this.dragOffsetX))\r\n this.posY.set(Math.max(0, e.clientY - this.dragOffsetY))\r\n }\r\n if (this.isResizing) {\r\n const newW = Math.max(300, this.startW + e.clientX - this.startX)\r\n const newH = Math.max(200, this.startH + e.clientY - this.startY)\r\n this.panelWidth.set(newW)\r\n this.panelHeight.set(newH)\r\n }\r\n }\r\n\r\n // ── Mouse Up ───────────────────────────────────────\r\n onMouseUp() {\r\n this.isDragging = false\r\n this.isResizing = false\r\n }\r\n}"]}
1
+ {"version":3,"sources":["../src/inject-store.ts","../src/provide-ngstato.ts","../src/create-angular-store.ts","../src/devtools.component.ts"],"names":["injectStore","store","inject","STATO_CONFIG","InjectionToken","provideStato","config","http","configureHttp","devtools","isDevMode","console","info","devTools","open","makeEnvironmentProviders","provide","useValue","createAngularStore","coreStore","createStore","signals","initialState","getState","key","Object","keys","signal","subscribe","newState","set","angularStore","__store__","defineProperty","get","enumerable","configurable","computed","computedConfig","computedSignal","actions","name","args","dispatch","hooks","onInit","__destroy__","destroy","StatoStoreBase","storeInstance","initStore","ngOnDestroy","StatoDevToolsComponent","optional","unsub","isOpen","isMinimized","activeTab","logs","selectedLog","posX","posY","window","innerHeight","panelWidth","panelHeight","isDragging","isResizing","dragOffsetX","dragOffsetY","startW","startH","startX","startY","boundMouseMove","onMouseMove","bind","boundMouseUp","onMouseUp","ngOnInit","state","document","addEventListener","removeEventListener","toggle","toggleMinimize","update","v","clear","selectLog","log","id","formatTime","iso","Date","toTimeString","slice","onDragStart","e","target","classList","contains","clientX","clientY","preventDefault","onResizeStart","stopPropagation","Math","max","newW","newH","selector","standalone","imports","CommonModule","template","styles"],"mappings":"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","file":"index.js","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 {\r\n Component,\r\n OnInit,\r\n OnDestroy,\r\n signal,\r\n inject,\r\n ElementRef,\r\n ViewChild,\r\n AfterViewInit\r\n} from '@angular/core'\r\nimport { CommonModule } from '@angular/common'\r\nimport { devTools } from '@ngstato/core'\r\nimport type { ActionLog } from '@ngstato/core'\r\nimport { STATO_CONFIG } from './provide-ngstato'\r\n\r\n@Component({\r\n selector: 'ngstato-devtools',\r\n standalone: true,\r\n imports: [CommonModule],\r\n template: `\r\n <!-- Bouton flottant -->\r\n @if (!isOpen()) {\r\n <button class=\"devtools-fab\" (click)=\"toggle()\">\r\n 🛠 Stato\r\n </button>\r\n }\r\n\r\n <!-- Panel -->\r\n @if (isOpen()) {\r\n <div\r\n class=\"devtools-panel\"\r\n [class.devtools-panel--minimized]=\"isMinimized()\"\r\n [style.left.px]=\"posX()\"\r\n [style.top.px]=\"posY()\"\r\n [style.width.px]=\"isMinimized() ? 200 : panelWidth()\"\r\n [style.height]=\"isMinimized() ? 'auto' : panelHeight() + 'px'\"\r\n >\r\n\r\n <!-- Header — draggable -->\r\n <div\r\n class=\"devtools-header\"\r\n (mousedown)=\"onDragStart($event)\"\r\n >\r\n <span class=\"devtools-title\">🛠 Stato</span>\r\n <div class=\"devtools-header-actions\">\r\n @if (!isMinimized()) {\r\n <button class=\"btn-icon\" (click)=\"clear()\" title=\"Vider\">🗑</button>\r\n }\r\n <button class=\"btn-icon\" (click)=\"toggleMinimize()\" title=\"Minimiser/Agrandir\">\r\n {{ isMinimized() ? '▲' : '▼' }}\r\n </button>\r\n <button class=\"btn-icon\" (click)=\"toggle()\" title=\"Fermer\">✕</button>\r\n </div>\r\n </div>\r\n\r\n <!-- Resize handle — coin bas droite -->\r\n @if (!isMinimized()) {\r\n <div\r\n class=\"devtools-resize\"\r\n (mousedown)=\"onResizeStart($event)\"\r\n >⊿</div>\r\n }\r\n\r\n @if (!isMinimized()) {\r\n\r\n <!-- Tabs -->\r\n <div class=\"devtools-tabs\">\r\n <button\r\n class=\"tab\"\r\n [class.tab--active]=\"activeTab() === 'actions'\"\r\n (click)=\"activeTab.set('actions')\"\r\n >\r\n Actions ({{ logs().length }})\r\n </button>\r\n <button\r\n class=\"tab\"\r\n [class.tab--active]=\"activeTab() === 'state'\"\r\n (click)=\"activeTab.set('state')\"\r\n >\r\n State\r\n </button>\r\n </div>\r\n\r\n <!-- Tab Actions -->\r\n @if (activeTab() === 'actions') {\r\n <div class=\"devtools-content\">\r\n @if (!logs().length) {\r\n <div class=\"devtools-empty\">Aucune action pour l'instant</div>\r\n }\r\n @for (log of logs(); track log.id) {\r\n <div\r\n class=\"log-item\"\r\n [class.log-item--error]=\"log.status === 'error'\"\r\n (click)=\"selectLog(log)\"\r\n >\r\n <div class=\"log-item__left\">\r\n <span class=\"log-status\">{{ log.status === 'success' ? '✓' : '✗' }}</span>\r\n <span class=\"log-name\">{{ log.name }}</span>\r\n </div>\r\n <div class=\"log-item__right\">\r\n @if (log.status === 'error') {\r\n <span class=\"log-error-badge\">erreur</span>\r\n } @else {\r\n <span class=\"log-duration\">{{ log.duration }}ms</span>\r\n }\r\n <span class=\"log-time\">{{ formatTime(log.at) }}</span>\r\n </div>\r\n </div>\r\n\r\n @if (selectedLog()?.id === log.id) {\r\n <div class=\"log-detail\">\r\n @if (log.error) {\r\n <div class=\"log-detail__error\">{{ log.error }}</div>\r\n }\r\n <div class=\"log-detail__section\">\r\n <span class=\"log-detail__label\">Avant</span>\r\n <pre>{{ log.prevState | json }}</pre>\r\n </div>\r\n <div class=\"log-detail__section\">\r\n <span class=\"log-detail__label\">Après</span>\r\n <pre>{{ log.nextState | json }}</pre>\r\n </div>\r\n </div>\r\n }\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Tab State -->\r\n @if (activeTab() === 'state') {\r\n <div class=\"devtools-content\">\r\n @if (logs().length) {\r\n <pre class=\"state-view\">{{ logs()[0].nextState | json }}</pre>\r\n } @else {\r\n <div class=\"devtools-empty\">Aucun state disponible</div>\r\n }\r\n </div>\r\n }\r\n }\r\n\r\n </div>\r\n }\r\n `,\r\n styles: [`\r\n .devtools-fab {\r\n position: fixed;\r\n bottom: 1.5rem;\r\n left: 1.5rem;\r\n background: #1e293b;\r\n color: white;\r\n border: none;\r\n border-radius: 999px;\r\n padding: 0.5rem 1rem;\r\n font-size: 0.85rem;\r\n font-weight: 600;\r\n cursor: pointer;\r\n z-index: 9999;\r\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\r\n transition: background 0.15s;\r\n }\r\n .devtools-fab:hover { background: #334155; }\r\n\r\n .devtools-panel {\r\n position: fixed;\r\n background: #0f172a;\r\n border-radius: 12px;\r\n box-shadow: 0 8px 32px rgba(0,0,0,0.4);\r\n z-index: 9999;\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n font-family: 'Courier New', monospace;\r\n min-width: 200px;\r\n min-height: 40px;\r\n }\r\n\r\n .devtools-panel--minimized {\r\n border-radius: 8px;\r\n }\r\n\r\n .devtools-header {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n padding: 0.6rem 0.75rem;\r\n background: #1e293b;\r\n border-bottom: 1px solid #334155;\r\n cursor: grab;\r\n user-select: none;\r\n }\r\n .devtools-header:active { cursor: grabbing; }\r\n\r\n .devtools-title {\r\n color: #e2e8f0;\r\n font-size: 0.82rem;\r\n font-weight: 600;\r\n font-family: system-ui;\r\n }\r\n\r\n .devtools-header-actions { display: flex; gap: 0.25rem; }\r\n\r\n .btn-icon {\r\n background: transparent;\r\n color: #64748b;\r\n border: none;\r\n cursor: pointer;\r\n font-size: 0.8rem;\r\n padding: 0.15rem 0.35rem;\r\n border-radius: 4px;\r\n line-height: 1;\r\n }\r\n .btn-icon:hover { background: #334155; color: white; }\r\n\r\n .devtools-resize {\r\n position: absolute;\r\n bottom: 2px;\r\n right: 4px;\r\n color: #334155;\r\n font-size: 0.9rem;\r\n cursor: nwse-resize;\r\n user-select: none;\r\n line-height: 1;\r\n }\r\n .devtools-resize:hover { color: #64748b; }\r\n\r\n .devtools-tabs {\r\n display: flex;\r\n background: #1e293b;\r\n border-bottom: 1px solid #334155;\r\n }\r\n .tab {\r\n padding: 0.4rem 0.75rem;\r\n background: transparent;\r\n color: #64748b;\r\n border: none;\r\n cursor: pointer;\r\n font-size: 0.78rem;\r\n font-family: system-ui;\r\n }\r\n .tab:hover { color: #e2e8f0; }\r\n .tab--active { color: #3b82f6; border-bottom: 2px solid #3b82f6; }\r\n\r\n .devtools-content {\r\n overflow-y: auto;\r\n flex: 1;\r\n padding: 0.25rem 0;\r\n }\r\n\r\n .devtools-empty {\r\n padding: 2rem;\r\n text-align: center;\r\n color: #475569;\r\n font-size: 0.78rem;\r\n font-family: system-ui;\r\n }\r\n\r\n .log-item {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n padding: 0.35rem 0.75rem;\r\n cursor: pointer;\r\n border-bottom: 1px solid #1e293b;\r\n }\r\n .log-item:hover { background: #1e293b; }\r\n .log-item--error { background: #1a0a0a; }\r\n\r\n .log-item__left { display: flex; align-items: center; gap: 0.4rem; overflow: hidden; }\r\n .log-item__right { display: flex; align-items: center; gap: 0.4rem; flex-shrink: 0; }\r\n\r\n .log-status { font-size: 0.72rem; color: #22c55e; flex-shrink: 0; }\r\n .log-item--error .log-status { color: #ef4444; }\r\n .log-name { color: #e2e8f0; font-size: 0.75rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\r\n .log-duration { color: #64748b; font-size: 0.7rem; }\r\n .log-time { color: #475569; font-size: 0.68rem; }\r\n\r\n .log-error-badge {\r\n background: #7f1d1d;\r\n color: #fca5a5;\r\n font-size: 0.68rem;\r\n padding: 0.1rem 0.35rem;\r\n border-radius: 4px;\r\n }\r\n\r\n .log-detail {\r\n background: #0a0f1a;\r\n padding: 0.6rem 0.75rem;\r\n border-left: 3px solid #3b82f6;\r\n margin: 0 0.4rem 0.4rem;\r\n border-radius: 0 4px 4px 0;\r\n }\r\n .log-detail__error { color: #fca5a5; font-size: 0.72rem; margin-bottom: 0.4rem; }\r\n .log-detail__section { margin-bottom: 0.4rem; }\r\n .log-detail__label {\r\n color: #64748b;\r\n font-size: 0.68rem;\r\n display: block;\r\n margin-bottom: 0.2rem;\r\n font-family: system-ui;\r\n }\r\n pre {\r\n color: #86efac;\r\n font-size: 0.7rem;\r\n margin: 0;\r\n white-space: pre-wrap;\r\n word-break: break-all;\r\n max-height: 140px;\r\n overflow-y: auto;\r\n }\r\n .state-view {\r\n color: #86efac;\r\n font-size: 0.7rem;\r\n padding: 0.75rem;\r\n margin: 0;\r\n white-space: pre-wrap;\r\n word-break: break-all;\r\n }\r\n `]\r\n})\r\nexport class StatoDevToolsComponent implements OnInit, OnDestroy {\r\n\r\n private config = inject(STATO_CONFIG, { optional: true })\r\n private unsub?: () => void\r\n\r\n // State UI\r\n isOpen = signal(false)\r\n isMinimized = signal(false)\r\n activeTab = signal<'actions' | 'state'>('actions')\r\n logs = signal<ActionLog[]>([])\r\n selectedLog = signal<ActionLog | null>(null)\r\n\r\n // Position et taille\r\n posX = signal(24)\r\n posY = signal(window.innerHeight - 500)\r\n panelWidth = signal(420)\r\n panelHeight = signal(460)\r\n\r\n // Drag state\r\n private isDragging = false\r\n private isResizing = false\r\n private dragOffsetX = 0\r\n private dragOffsetY = 0\r\n private startW = 0\r\n private startH = 0\r\n private startX = 0\r\n private startY = 0\r\n\r\n // Bound listeners\r\n private boundMouseMove = this.onMouseMove.bind(this)\r\n private boundMouseUp = this.onMouseUp.bind(this)\r\n\r\n ngOnInit() {\r\n this.unsub = devTools.subscribe((state) => {\r\n this.logs.set(state.logs)\r\n this.isOpen.set(state.isOpen)\r\n })\r\n\r\n document.addEventListener('mousemove', this.boundMouseMove)\r\n document.addEventListener('mouseup', this.boundMouseUp)\r\n }\r\n\r\n ngOnDestroy() {\r\n this.unsub?.()\r\n document.removeEventListener('mousemove', this.boundMouseMove)\r\n document.removeEventListener('mouseup', this.boundMouseUp)\r\n }\r\n\r\n // ── Toggle ─────────────────────────────────────────\r\n toggle() { devTools.toggle() }\r\n toggleMinimize() { this.isMinimized.update(v => !v) }\r\n clear() { devTools.clear(); this.selectedLog.set(null) }\r\n selectLog(log: ActionLog) {\r\n this.selectedLog.set(this.selectedLog()?.id === log.id ? null : log)\r\n }\r\n formatTime(iso: string): string {\r\n return new Date(iso).toTimeString().slice(0, 8)\r\n }\r\n\r\n // ── Drag ───────────────────────────────────────────\r\n onDragStart(e: MouseEvent) {\r\n if ((e.target as HTMLElement).classList.contains('btn-icon')) return\r\n this.isDragging = true\r\n this.dragOffsetX = e.clientX - this.posX()\r\n this.dragOffsetY = e.clientY - this.posY()\r\n e.preventDefault()\r\n }\r\n\r\n // ── Resize ─────────────────────────────────────────\r\n onResizeStart(e: MouseEvent) {\r\n this.isResizing = true\r\n this.startW = this.panelWidth()\r\n this.startH = this.panelHeight()\r\n this.startX = e.clientX\r\n this.startY = e.clientY\r\n e.preventDefault()\r\n e.stopPropagation()\r\n }\r\n\r\n // ── Mouse Move ─────────────────────────────────────\r\n onMouseMove(e: MouseEvent) {\r\n if (this.isDragging) {\r\n this.posX.set(Math.max(0, e.clientX - this.dragOffsetX))\r\n this.posY.set(Math.max(0, e.clientY - this.dragOffsetY))\r\n }\r\n if (this.isResizing) {\r\n const newW = Math.max(300, this.startW + e.clientX - this.startX)\r\n const newH = Math.max(200, this.startH + e.clientY - this.startY)\r\n this.panelWidth.set(newW)\r\n this.panelHeight.set(newH)\r\n }\r\n }\r\n\r\n // ── Mouse Up ───────────────────────────────────────\r\n onMouseUp() {\r\n this.isDragging = false\r\n this.isResizing = false\r\n }\r\n}"]}
@@ -1,25 +1,23 @@
1
- 'use strict';
2
-
3
- var core = require('@angular/core');
4
- var core$1 = require('@ngstato/core');
5
- var common = require('@angular/common');
1
+ import { InjectionToken, Injectable, inject, signal, Component, computed, isDevMode, makeEnvironmentProviders } from '@angular/core';
2
+ import { devTools, createStore, configureHttp } from '@ngstato/core';
3
+ import { CommonModule } from '@angular/common';
6
4
 
7
5
  var __defProp = Object.defineProperty;
8
6
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
9
7
  function injectStore(store) {
10
- return core.inject(store);
8
+ return inject(store);
11
9
  }
12
10
  __name(injectStore, "injectStore");
13
- var STATO_CONFIG = new core.InjectionToken("STATO_CONFIG");
11
+ var STATO_CONFIG = new InjectionToken("STATO_CONFIG");
14
12
  function provideStato(config = {}) {
15
13
  if (config.http) {
16
- core$1.configureHttp(config.http);
14
+ configureHttp(config.http);
17
15
  }
18
- if (config.devtools && core.isDevMode()) {
16
+ if (config.devtools && isDevMode()) {
19
17
  console.info("%c[Stato] \u{1F6E0} DevTools activ\xE9s", "background:#1e40af;color:white;padding:4px 8px;border-radius:4px;font-weight:bold");
20
- core$1.devTools.open();
18
+ devTools.open();
21
19
  }
22
- return core.makeEnvironmentProviders([
20
+ return makeEnvironmentProviders([
23
21
  {
24
22
  provide: STATO_CONFIG,
25
23
  useValue: config
@@ -35,11 +33,11 @@ function _ts_decorate(decorators, target, key, desc) {
35
33
  }
36
34
  __name(_ts_decorate, "_ts_decorate");
37
35
  function createAngularStore(config) {
38
- const coreStore = core$1.createStore(config);
36
+ const coreStore = createStore(config);
39
37
  const signals = {};
40
38
  const initialState = coreStore.getState();
41
39
  for (const key of Object.keys(initialState)) {
42
- signals[key] = core.signal(initialState[key]);
40
+ signals[key] = signal(initialState[key]);
43
41
  }
44
42
  coreStore.subscribe((newState) => {
45
43
  for (const key of Object.keys(newState)) {
@@ -61,7 +59,7 @@ function createAngularStore(config) {
61
59
  const { computed: computedConfig } = config;
62
60
  if (computedConfig) {
63
61
  for (const key of Object.keys(computedConfig)) {
64
- const computedSignal = core.computed(() => coreStore[key]);
62
+ const computedSignal = computed(() => coreStore[key]);
65
63
  Object.defineProperty(angularStore, key, {
66
64
  get: /* @__PURE__ */ __name(() => computedSignal, "get"),
67
65
  enumerable: true,
@@ -117,7 +115,7 @@ var StatoStoreBase = class {
117
115
  }
118
116
  };
119
117
  StatoStoreBase = _ts_decorate([
120
- core.Injectable()
118
+ Injectable()
121
119
  ], StatoStoreBase);
122
120
  function _ts_decorate2(decorators, target, key, desc) {
123
121
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -126,25 +124,25 @@ function _ts_decorate2(decorators, target, key, desc) {
126
124
  return c > 3 && r && Object.defineProperty(target, key, r), r;
127
125
  }
128
126
  __name(_ts_decorate2, "_ts_decorate");
129
- exports.StatoDevToolsComponent = class StatoDevToolsComponent {
127
+ var StatoDevToolsComponent = class {
130
128
  static {
131
129
  __name(this, "StatoDevToolsComponent");
132
130
  }
133
- config = core.inject(STATO_CONFIG, {
131
+ config = inject(STATO_CONFIG, {
134
132
  optional: true
135
133
  });
136
134
  unsub;
137
135
  // State UI
138
- isOpen = core.signal(false);
139
- isMinimized = core.signal(false);
140
- activeTab = core.signal("actions");
141
- logs = core.signal([]);
142
- selectedLog = core.signal(null);
136
+ isOpen = signal(false);
137
+ isMinimized = signal(false);
138
+ activeTab = signal("actions");
139
+ logs = signal([]);
140
+ selectedLog = signal(null);
143
141
  // Position et taille
144
- posX = core.signal(24);
145
- posY = core.signal(window.innerHeight - 500);
146
- panelWidth = core.signal(420);
147
- panelHeight = core.signal(460);
142
+ posX = signal(24);
143
+ posY = signal(window.innerHeight - 500);
144
+ panelWidth = signal(420);
145
+ panelHeight = signal(460);
148
146
  // Drag state
149
147
  isDragging = false;
150
148
  isResizing = false;
@@ -158,7 +156,7 @@ exports.StatoDevToolsComponent = class StatoDevToolsComponent {
158
156
  boundMouseMove = this.onMouseMove.bind(this);
159
157
  boundMouseUp = this.onMouseUp.bind(this);
160
158
  ngOnInit() {
161
- this.unsub = core$1.devTools.subscribe((state) => {
159
+ this.unsub = devTools.subscribe((state) => {
162
160
  this.logs.set(state.logs);
163
161
  this.isOpen.set(state.isOpen);
164
162
  });
@@ -172,13 +170,13 @@ exports.StatoDevToolsComponent = class StatoDevToolsComponent {
172
170
  }
173
171
  // ── Toggle ─────────────────────────────────────────
174
172
  toggle() {
175
- core$1.devTools.toggle();
173
+ devTools.toggle();
176
174
  }
177
175
  toggleMinimize() {
178
176
  this.isMinimized.update((v) => !v);
179
177
  }
180
178
  clear() {
181
- core$1.devTools.clear();
179
+ devTools.clear();
182
180
  this.selectedLog.set(null);
183
181
  }
184
182
  selectLog(log) {
@@ -224,12 +222,12 @@ exports.StatoDevToolsComponent = class StatoDevToolsComponent {
224
222
  this.isResizing = false;
225
223
  }
226
224
  };
227
- exports.StatoDevToolsComponent = _ts_decorate2([
228
- core.Component({
225
+ StatoDevToolsComponent = _ts_decorate2([
226
+ Component({
229
227
  selector: "ngstato-devtools",
230
228
  standalone: true,
231
229
  imports: [
232
- common.CommonModule
230
+ CommonModule
233
231
  ],
234
232
  template: `
235
233
  <!-- Bouton flottant -->
@@ -533,10 +531,8 @@ exports.StatoDevToolsComponent = _ts_decorate2([
533
531
  `
534
532
  ]
535
533
  })
536
- ], exports.StatoDevToolsComponent);
534
+ ], StatoDevToolsComponent);
537
535
 
538
- exports.createAngularStore = createAngularStore;
539
- exports.injectStore = injectStore;
540
- exports.provideStato = provideStato;
541
- //# sourceMappingURL=index.cjs.map
542
- //# sourceMappingURL=index.cjs.map
536
+ export { StatoDevToolsComponent, createAngularStore, injectStore, provideStato };
537
+ //# sourceMappingURL=index.mjs.map
538
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/inject-store.ts","../src/provide-ngstato.ts","../src/create-angular-store.ts","../src/devtools.component.ts"],"names":["injectStore","store","inject","STATO_CONFIG","InjectionToken","provideStato","config","http","configureHttp","devtools","isDevMode","console","info","devTools","open","makeEnvironmentProviders","provide","useValue","createAngularStore","coreStore","createStore","signals","initialState","getState","key","Object","keys","signal","subscribe","newState","set","angularStore","__store__","defineProperty","get","enumerable","configurable","computed","computedConfig","computedSignal","actions","name","args","dispatch","hooks","onInit","__destroy__","destroy","StatoStoreBase","storeInstance","initStore","ngOnDestroy","StatoDevToolsComponent","optional","unsub","isOpen","isMinimized","activeTab","logs","selectedLog","posX","posY","window","innerHeight","panelWidth","panelHeight","isDragging","isResizing","dragOffsetX","dragOffsetY","startW","startH","startX","startY","boundMouseMove","onMouseMove","bind","boundMouseUp","onMouseUp","ngOnInit","state","document","addEventListener","removeEventListener","toggle","toggleMinimize","update","v","clear","selectLog","log","id","formatTime","iso","Date","toTimeString","slice","onDragStart","e","target","classList","contains","clientX","clientY","preventDefault","onResizeStart","stopPropagation","Math","max","newW","newH","selector","standalone","imports","CommonModule","template","styles"],"mappings":"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","file":"index.mjs","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 {\r\n Component,\r\n OnInit,\r\n OnDestroy,\r\n signal,\r\n inject,\r\n ElementRef,\r\n ViewChild,\r\n AfterViewInit\r\n} from '@angular/core'\r\nimport { CommonModule } from '@angular/common'\r\nimport { devTools } from '@ngstato/core'\r\nimport type { ActionLog } from '@ngstato/core'\r\nimport { STATO_CONFIG } from './provide-ngstato'\r\n\r\n@Component({\r\n selector: 'ngstato-devtools',\r\n standalone: true,\r\n imports: [CommonModule],\r\n template: `\r\n <!-- Bouton flottant -->\r\n @if (!isOpen()) {\r\n <button class=\"devtools-fab\" (click)=\"toggle()\">\r\n 🛠 Stato\r\n </button>\r\n }\r\n\r\n <!-- Panel -->\r\n @if (isOpen()) {\r\n <div\r\n class=\"devtools-panel\"\r\n [class.devtools-panel--minimized]=\"isMinimized()\"\r\n [style.left.px]=\"posX()\"\r\n [style.top.px]=\"posY()\"\r\n [style.width.px]=\"isMinimized() ? 200 : panelWidth()\"\r\n [style.height]=\"isMinimized() ? 'auto' : panelHeight() + 'px'\"\r\n >\r\n\r\n <!-- Header — draggable -->\r\n <div\r\n class=\"devtools-header\"\r\n (mousedown)=\"onDragStart($event)\"\r\n >\r\n <span class=\"devtools-title\">🛠 Stato</span>\r\n <div class=\"devtools-header-actions\">\r\n @if (!isMinimized()) {\r\n <button class=\"btn-icon\" (click)=\"clear()\" title=\"Vider\">🗑</button>\r\n }\r\n <button class=\"btn-icon\" (click)=\"toggleMinimize()\" title=\"Minimiser/Agrandir\">\r\n {{ isMinimized() ? '▲' : '▼' }}\r\n </button>\r\n <button class=\"btn-icon\" (click)=\"toggle()\" title=\"Fermer\">✕</button>\r\n </div>\r\n </div>\r\n\r\n <!-- Resize handle — coin bas droite -->\r\n @if (!isMinimized()) {\r\n <div\r\n class=\"devtools-resize\"\r\n (mousedown)=\"onResizeStart($event)\"\r\n >⊿</div>\r\n }\r\n\r\n @if (!isMinimized()) {\r\n\r\n <!-- Tabs -->\r\n <div class=\"devtools-tabs\">\r\n <button\r\n class=\"tab\"\r\n [class.tab--active]=\"activeTab() === 'actions'\"\r\n (click)=\"activeTab.set('actions')\"\r\n >\r\n Actions ({{ logs().length }})\r\n </button>\r\n <button\r\n class=\"tab\"\r\n [class.tab--active]=\"activeTab() === 'state'\"\r\n (click)=\"activeTab.set('state')\"\r\n >\r\n State\r\n </button>\r\n </div>\r\n\r\n <!-- Tab Actions -->\r\n @if (activeTab() === 'actions') {\r\n <div class=\"devtools-content\">\r\n @if (!logs().length) {\r\n <div class=\"devtools-empty\">Aucune action pour l'instant</div>\r\n }\r\n @for (log of logs(); track log.id) {\r\n <div\r\n class=\"log-item\"\r\n [class.log-item--error]=\"log.status === 'error'\"\r\n (click)=\"selectLog(log)\"\r\n >\r\n <div class=\"log-item__left\">\r\n <span class=\"log-status\">{{ log.status === 'success' ? '✓' : '✗' }}</span>\r\n <span class=\"log-name\">{{ log.name }}</span>\r\n </div>\r\n <div class=\"log-item__right\">\r\n @if (log.status === 'error') {\r\n <span class=\"log-error-badge\">erreur</span>\r\n } @else {\r\n <span class=\"log-duration\">{{ log.duration }}ms</span>\r\n }\r\n <span class=\"log-time\">{{ formatTime(log.at) }}</span>\r\n </div>\r\n </div>\r\n\r\n @if (selectedLog()?.id === log.id) {\r\n <div class=\"log-detail\">\r\n @if (log.error) {\r\n <div class=\"log-detail__error\">{{ log.error }}</div>\r\n }\r\n <div class=\"log-detail__section\">\r\n <span class=\"log-detail__label\">Avant</span>\r\n <pre>{{ log.prevState | json }}</pre>\r\n </div>\r\n <div class=\"log-detail__section\">\r\n <span class=\"log-detail__label\">Après</span>\r\n <pre>{{ log.nextState | json }}</pre>\r\n </div>\r\n </div>\r\n }\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Tab State -->\r\n @if (activeTab() === 'state') {\r\n <div class=\"devtools-content\">\r\n @if (logs().length) {\r\n <pre class=\"state-view\">{{ logs()[0].nextState | json }}</pre>\r\n } @else {\r\n <div class=\"devtools-empty\">Aucun state disponible</div>\r\n }\r\n </div>\r\n }\r\n }\r\n\r\n </div>\r\n }\r\n `,\r\n styles: [`\r\n .devtools-fab {\r\n position: fixed;\r\n bottom: 1.5rem;\r\n left: 1.5rem;\r\n background: #1e293b;\r\n color: white;\r\n border: none;\r\n border-radius: 999px;\r\n padding: 0.5rem 1rem;\r\n font-size: 0.85rem;\r\n font-weight: 600;\r\n cursor: pointer;\r\n z-index: 9999;\r\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\r\n transition: background 0.15s;\r\n }\r\n .devtools-fab:hover { background: #334155; }\r\n\r\n .devtools-panel {\r\n position: fixed;\r\n background: #0f172a;\r\n border-radius: 12px;\r\n box-shadow: 0 8px 32px rgba(0,0,0,0.4);\r\n z-index: 9999;\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n font-family: 'Courier New', monospace;\r\n min-width: 200px;\r\n min-height: 40px;\r\n }\r\n\r\n .devtools-panel--minimized {\r\n border-radius: 8px;\r\n }\r\n\r\n .devtools-header {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n padding: 0.6rem 0.75rem;\r\n background: #1e293b;\r\n border-bottom: 1px solid #334155;\r\n cursor: grab;\r\n user-select: none;\r\n }\r\n .devtools-header:active { cursor: grabbing; }\r\n\r\n .devtools-title {\r\n color: #e2e8f0;\r\n font-size: 0.82rem;\r\n font-weight: 600;\r\n font-family: system-ui;\r\n }\r\n\r\n .devtools-header-actions { display: flex; gap: 0.25rem; }\r\n\r\n .btn-icon {\r\n background: transparent;\r\n color: #64748b;\r\n border: none;\r\n cursor: pointer;\r\n font-size: 0.8rem;\r\n padding: 0.15rem 0.35rem;\r\n border-radius: 4px;\r\n line-height: 1;\r\n }\r\n .btn-icon:hover { background: #334155; color: white; }\r\n\r\n .devtools-resize {\r\n position: absolute;\r\n bottom: 2px;\r\n right: 4px;\r\n color: #334155;\r\n font-size: 0.9rem;\r\n cursor: nwse-resize;\r\n user-select: none;\r\n line-height: 1;\r\n }\r\n .devtools-resize:hover { color: #64748b; }\r\n\r\n .devtools-tabs {\r\n display: flex;\r\n background: #1e293b;\r\n border-bottom: 1px solid #334155;\r\n }\r\n .tab {\r\n padding: 0.4rem 0.75rem;\r\n background: transparent;\r\n color: #64748b;\r\n border: none;\r\n cursor: pointer;\r\n font-size: 0.78rem;\r\n font-family: system-ui;\r\n }\r\n .tab:hover { color: #e2e8f0; }\r\n .tab--active { color: #3b82f6; border-bottom: 2px solid #3b82f6; }\r\n\r\n .devtools-content {\r\n overflow-y: auto;\r\n flex: 1;\r\n padding: 0.25rem 0;\r\n }\r\n\r\n .devtools-empty {\r\n padding: 2rem;\r\n text-align: center;\r\n color: #475569;\r\n font-size: 0.78rem;\r\n font-family: system-ui;\r\n }\r\n\r\n .log-item {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n padding: 0.35rem 0.75rem;\r\n cursor: pointer;\r\n border-bottom: 1px solid #1e293b;\r\n }\r\n .log-item:hover { background: #1e293b; }\r\n .log-item--error { background: #1a0a0a; }\r\n\r\n .log-item__left { display: flex; align-items: center; gap: 0.4rem; overflow: hidden; }\r\n .log-item__right { display: flex; align-items: center; gap: 0.4rem; flex-shrink: 0; }\r\n\r\n .log-status { font-size: 0.72rem; color: #22c55e; flex-shrink: 0; }\r\n .log-item--error .log-status { color: #ef4444; }\r\n .log-name { color: #e2e8f0; font-size: 0.75rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\r\n .log-duration { color: #64748b; font-size: 0.7rem; }\r\n .log-time { color: #475569; font-size: 0.68rem; }\r\n\r\n .log-error-badge {\r\n background: #7f1d1d;\r\n color: #fca5a5;\r\n font-size: 0.68rem;\r\n padding: 0.1rem 0.35rem;\r\n border-radius: 4px;\r\n }\r\n\r\n .log-detail {\r\n background: #0a0f1a;\r\n padding: 0.6rem 0.75rem;\r\n border-left: 3px solid #3b82f6;\r\n margin: 0 0.4rem 0.4rem;\r\n border-radius: 0 4px 4px 0;\r\n }\r\n .log-detail__error { color: #fca5a5; font-size: 0.72rem; margin-bottom: 0.4rem; }\r\n .log-detail__section { margin-bottom: 0.4rem; }\r\n .log-detail__label {\r\n color: #64748b;\r\n font-size: 0.68rem;\r\n display: block;\r\n margin-bottom: 0.2rem;\r\n font-family: system-ui;\r\n }\r\n pre {\r\n color: #86efac;\r\n font-size: 0.7rem;\r\n margin: 0;\r\n white-space: pre-wrap;\r\n word-break: break-all;\r\n max-height: 140px;\r\n overflow-y: auto;\r\n }\r\n .state-view {\r\n color: #86efac;\r\n font-size: 0.7rem;\r\n padding: 0.75rem;\r\n margin: 0;\r\n white-space: pre-wrap;\r\n word-break: break-all;\r\n }\r\n `]\r\n})\r\nexport class StatoDevToolsComponent implements OnInit, OnDestroy {\r\n\r\n private config = inject(STATO_CONFIG, { optional: true })\r\n private unsub?: () => void\r\n\r\n // State UI\r\n isOpen = signal(false)\r\n isMinimized = signal(false)\r\n activeTab = signal<'actions' | 'state'>('actions')\r\n logs = signal<ActionLog[]>([])\r\n selectedLog = signal<ActionLog | null>(null)\r\n\r\n // Position et taille\r\n posX = signal(24)\r\n posY = signal(window.innerHeight - 500)\r\n panelWidth = signal(420)\r\n panelHeight = signal(460)\r\n\r\n // Drag state\r\n private isDragging = false\r\n private isResizing = false\r\n private dragOffsetX = 0\r\n private dragOffsetY = 0\r\n private startW = 0\r\n private startH = 0\r\n private startX = 0\r\n private startY = 0\r\n\r\n // Bound listeners\r\n private boundMouseMove = this.onMouseMove.bind(this)\r\n private boundMouseUp = this.onMouseUp.bind(this)\r\n\r\n ngOnInit() {\r\n this.unsub = devTools.subscribe((state) => {\r\n this.logs.set(state.logs)\r\n this.isOpen.set(state.isOpen)\r\n })\r\n\r\n document.addEventListener('mousemove', this.boundMouseMove)\r\n document.addEventListener('mouseup', this.boundMouseUp)\r\n }\r\n\r\n ngOnDestroy() {\r\n this.unsub?.()\r\n document.removeEventListener('mousemove', this.boundMouseMove)\r\n document.removeEventListener('mouseup', this.boundMouseUp)\r\n }\r\n\r\n // ── Toggle ─────────────────────────────────────────\r\n toggle() { devTools.toggle() }\r\n toggleMinimize() { this.isMinimized.update(v => !v) }\r\n clear() { devTools.clear(); this.selectedLog.set(null) }\r\n selectLog(log: ActionLog) {\r\n this.selectedLog.set(this.selectedLog()?.id === log.id ? null : log)\r\n }\r\n formatTime(iso: string): string {\r\n return new Date(iso).toTimeString().slice(0, 8)\r\n }\r\n\r\n // ── Drag ───────────────────────────────────────────\r\n onDragStart(e: MouseEvent) {\r\n if ((e.target as HTMLElement).classList.contains('btn-icon')) return\r\n this.isDragging = true\r\n this.dragOffsetX = e.clientX - this.posX()\r\n this.dragOffsetY = e.clientY - this.posY()\r\n e.preventDefault()\r\n }\r\n\r\n // ── Resize ─────────────────────────────────────────\r\n onResizeStart(e: MouseEvent) {\r\n this.isResizing = true\r\n this.startW = this.panelWidth()\r\n this.startH = this.panelHeight()\r\n this.startX = e.clientX\r\n this.startY = e.clientY\r\n e.preventDefault()\r\n e.stopPropagation()\r\n }\r\n\r\n // ── Mouse Move ─────────────────────────────────────\r\n onMouseMove(e: MouseEvent) {\r\n if (this.isDragging) {\r\n this.posX.set(Math.max(0, e.clientX - this.dragOffsetX))\r\n this.posY.set(Math.max(0, e.clientY - this.dragOffsetY))\r\n }\r\n if (this.isResizing) {\r\n const newW = Math.max(300, this.startW + e.clientX - this.startX)\r\n const newH = Math.max(200, this.startH + e.clientY - this.startY)\r\n this.panelWidth.set(newW)\r\n this.panelHeight.set(newH)\r\n }\r\n }\r\n\r\n // ── Mouse Up ───────────────────────────────────────\r\n onMouseUp() {\r\n this.isDragging = false\r\n this.isResizing = false\r\n }\r\n}"]}
package/package.json CHANGED
@@ -1,36 +1,36 @@
1
- {
2
- "name": "@ngstato/angular",
3
- "version": "0.1.1",
4
- "type": "module",
5
- "private": false,
6
- "description": "Stato — Angular adapter with native Signals",
7
- "main": "./dist/index.js",
8
- "module": "./dist/index.js",
9
- "types": "./dist/index.d.ts",
10
- "exports": {
11
- ".": {
12
- "types": "./dist/index.d.ts",
13
- "import": "./dist/index.js",
14
- "require": "./dist/index.cjs"
15
- }
16
- },
17
- "scripts": {
18
- "build": "tsup",
19
- "test": "vitest run",
20
- "dev": "tsup --watch"
21
- },
22
- "peerDependencies": {
23
- "@angular/common": ">=17.0.0",
24
- "@angular/core": ">=17.0.0"
25
- },
26
- "dependencies": {
27
- "@ngstato/core": "workspace:*"
28
- },
29
- "devDependencies": {
30
- "@angular/common": "^18.2.14",
31
- "@angular/core": "^17.0.0",
32
- "tsup": "^8.0.0",
33
- "typescript": "^5.4.0",
34
- "vitest": "^1.6.0"
35
- }
1
+ {
2
+ "name": "@ngstato/angular",
3
+ "version": "0.1.2",
4
+ "private": false,
5
+ "description": "Stato — Angular adapter with native Signals",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "scripts": {
17
+ "build": "tsup",
18
+ "test": "vitest run",
19
+ "dev": "tsup --watch"
20
+ },
21
+ "peerDependencies": {
22
+ "@angular/common": ">=17.0.0",
23
+ "@angular/core": ">=17.0.0"
24
+ },
25
+ "dependencies": {
26
+ "@ngstato/angular": "^0.1.2",
27
+ "@ngstato/core": "^0.1.2"
28
+ },
29
+ "devDependencies": {
30
+ "@angular/common": "^18.2.14",
31
+ "@angular/core": "^17.0.0",
32
+ "tsup": "^8.0.0",
33
+ "typescript": "^5.4.0",
34
+ "vitest": "^1.6.0"
35
+ }
36
36
  }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/inject-store.ts","../src/provide-ngstato.ts","../src/create-angular-store.ts","../src/devtools.component.ts"],"names":["injectStore","store","inject","STATO_CONFIG","InjectionToken","provideStato","config","http","configureHttp","devtools","isDevMode","console","info","devTools","open","makeEnvironmentProviders","provide","useValue","createAngularStore","coreStore","createStore","signals","initialState","getState","key","Object","keys","signal","subscribe","newState","set","angularStore","__store__","defineProperty","get","enumerable","configurable","computed","computedConfig","computedSignal","actions","name","args","dispatch","hooks","onInit","__destroy__","destroy","StatoStoreBase","storeInstance","initStore","ngOnDestroy","StatoDevToolsComponent","optional","unsub","isOpen","isMinimized","activeTab","logs","selectedLog","posX","posY","window","innerHeight","panelWidth","panelHeight","isDragging","isResizing","dragOffsetX","dragOffsetY","startW","startH","startX","startY","boundMouseMove","onMouseMove","bind","boundMouseUp","onMouseUp","ngOnInit","state","document","addEventListener","removeEventListener","toggle","toggleMinimize","update","v","clear","selectLog","log","id","formatTime","iso","Date","toTimeString","slice","onDragStart","e","target","classList","contains","clientX","clientY","preventDefault","onResizeStart","stopPropagation","Math","max","newW","newH","selector","standalone","imports","CommonModule","template","styles"],"mappings":"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","file":"index.cjs","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 {\r\n Component,\r\n OnInit,\r\n OnDestroy,\r\n signal,\r\n inject,\r\n ElementRef,\r\n ViewChild,\r\n AfterViewInit\r\n} from '@angular/core'\r\nimport { CommonModule } from '@angular/common'\r\nimport { devTools } from '@ngstato/core'\r\nimport type { ActionLog } from '@ngstato/core'\r\nimport { STATO_CONFIG } from './provide-ngstato'\r\n\r\n@Component({\r\n selector: 'ngstato-devtools',\r\n standalone: true,\r\n imports: [CommonModule],\r\n template: `\r\n <!-- Bouton flottant -->\r\n @if (!isOpen()) {\r\n <button class=\"devtools-fab\" (click)=\"toggle()\">\r\n 🛠 Stato\r\n </button>\r\n }\r\n\r\n <!-- Panel -->\r\n @if (isOpen()) {\r\n <div\r\n class=\"devtools-panel\"\r\n [class.devtools-panel--minimized]=\"isMinimized()\"\r\n [style.left.px]=\"posX()\"\r\n [style.top.px]=\"posY()\"\r\n [style.width.px]=\"isMinimized() ? 200 : panelWidth()\"\r\n [style.height]=\"isMinimized() ? 'auto' : panelHeight() + 'px'\"\r\n >\r\n\r\n <!-- Header — draggable -->\r\n <div\r\n class=\"devtools-header\"\r\n (mousedown)=\"onDragStart($event)\"\r\n >\r\n <span class=\"devtools-title\">🛠 Stato</span>\r\n <div class=\"devtools-header-actions\">\r\n @if (!isMinimized()) {\r\n <button class=\"btn-icon\" (click)=\"clear()\" title=\"Vider\">🗑</button>\r\n }\r\n <button class=\"btn-icon\" (click)=\"toggleMinimize()\" title=\"Minimiser/Agrandir\">\r\n {{ isMinimized() ? '▲' : '▼' }}\r\n </button>\r\n <button class=\"btn-icon\" (click)=\"toggle()\" title=\"Fermer\">✕</button>\r\n </div>\r\n </div>\r\n\r\n <!-- Resize handle — coin bas droite -->\r\n @if (!isMinimized()) {\r\n <div\r\n class=\"devtools-resize\"\r\n (mousedown)=\"onResizeStart($event)\"\r\n >⊿</div>\r\n }\r\n\r\n @if (!isMinimized()) {\r\n\r\n <!-- Tabs -->\r\n <div class=\"devtools-tabs\">\r\n <button\r\n class=\"tab\"\r\n [class.tab--active]=\"activeTab() === 'actions'\"\r\n (click)=\"activeTab.set('actions')\"\r\n >\r\n Actions ({{ logs().length }})\r\n </button>\r\n <button\r\n class=\"tab\"\r\n [class.tab--active]=\"activeTab() === 'state'\"\r\n (click)=\"activeTab.set('state')\"\r\n >\r\n State\r\n </button>\r\n </div>\r\n\r\n <!-- Tab Actions -->\r\n @if (activeTab() === 'actions') {\r\n <div class=\"devtools-content\">\r\n @if (!logs().length) {\r\n <div class=\"devtools-empty\">Aucune action pour l'instant</div>\r\n }\r\n @for (log of logs(); track log.id) {\r\n <div\r\n class=\"log-item\"\r\n [class.log-item--error]=\"log.status === 'error'\"\r\n (click)=\"selectLog(log)\"\r\n >\r\n <div class=\"log-item__left\">\r\n <span class=\"log-status\">{{ log.status === 'success' ? '✓' : '✗' }}</span>\r\n <span class=\"log-name\">{{ log.name }}</span>\r\n </div>\r\n <div class=\"log-item__right\">\r\n @if (log.status === 'error') {\r\n <span class=\"log-error-badge\">erreur</span>\r\n } @else {\r\n <span class=\"log-duration\">{{ log.duration }}ms</span>\r\n }\r\n <span class=\"log-time\">{{ formatTime(log.at) }}</span>\r\n </div>\r\n </div>\r\n\r\n @if (selectedLog()?.id === log.id) {\r\n <div class=\"log-detail\">\r\n @if (log.error) {\r\n <div class=\"log-detail__error\">{{ log.error }}</div>\r\n }\r\n <div class=\"log-detail__section\">\r\n <span class=\"log-detail__label\">Avant</span>\r\n <pre>{{ log.prevState | json }}</pre>\r\n </div>\r\n <div class=\"log-detail__section\">\r\n <span class=\"log-detail__label\">Après</span>\r\n <pre>{{ log.nextState | json }}</pre>\r\n </div>\r\n </div>\r\n }\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Tab State -->\r\n @if (activeTab() === 'state') {\r\n <div class=\"devtools-content\">\r\n @if (logs().length) {\r\n <pre class=\"state-view\">{{ logs()[0].nextState | json }}</pre>\r\n } @else {\r\n <div class=\"devtools-empty\">Aucun state disponible</div>\r\n }\r\n </div>\r\n }\r\n }\r\n\r\n </div>\r\n }\r\n `,\r\n styles: [`\r\n .devtools-fab {\r\n position: fixed;\r\n bottom: 1.5rem;\r\n left: 1.5rem;\r\n background: #1e293b;\r\n color: white;\r\n border: none;\r\n border-radius: 999px;\r\n padding: 0.5rem 1rem;\r\n font-size: 0.85rem;\r\n font-weight: 600;\r\n cursor: pointer;\r\n z-index: 9999;\r\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\r\n transition: background 0.15s;\r\n }\r\n .devtools-fab:hover { background: #334155; }\r\n\r\n .devtools-panel {\r\n position: fixed;\r\n background: #0f172a;\r\n border-radius: 12px;\r\n box-shadow: 0 8px 32px rgba(0,0,0,0.4);\r\n z-index: 9999;\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n font-family: 'Courier New', monospace;\r\n min-width: 200px;\r\n min-height: 40px;\r\n }\r\n\r\n .devtools-panel--minimized {\r\n border-radius: 8px;\r\n }\r\n\r\n .devtools-header {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n padding: 0.6rem 0.75rem;\r\n background: #1e293b;\r\n border-bottom: 1px solid #334155;\r\n cursor: grab;\r\n user-select: none;\r\n }\r\n .devtools-header:active { cursor: grabbing; }\r\n\r\n .devtools-title {\r\n color: #e2e8f0;\r\n font-size: 0.82rem;\r\n font-weight: 600;\r\n font-family: system-ui;\r\n }\r\n\r\n .devtools-header-actions { display: flex; gap: 0.25rem; }\r\n\r\n .btn-icon {\r\n background: transparent;\r\n color: #64748b;\r\n border: none;\r\n cursor: pointer;\r\n font-size: 0.8rem;\r\n padding: 0.15rem 0.35rem;\r\n border-radius: 4px;\r\n line-height: 1;\r\n }\r\n .btn-icon:hover { background: #334155; color: white; }\r\n\r\n .devtools-resize {\r\n position: absolute;\r\n bottom: 2px;\r\n right: 4px;\r\n color: #334155;\r\n font-size: 0.9rem;\r\n cursor: nwse-resize;\r\n user-select: none;\r\n line-height: 1;\r\n }\r\n .devtools-resize:hover { color: #64748b; }\r\n\r\n .devtools-tabs {\r\n display: flex;\r\n background: #1e293b;\r\n border-bottom: 1px solid #334155;\r\n }\r\n .tab {\r\n padding: 0.4rem 0.75rem;\r\n background: transparent;\r\n color: #64748b;\r\n border: none;\r\n cursor: pointer;\r\n font-size: 0.78rem;\r\n font-family: system-ui;\r\n }\r\n .tab:hover { color: #e2e8f0; }\r\n .tab--active { color: #3b82f6; border-bottom: 2px solid #3b82f6; }\r\n\r\n .devtools-content {\r\n overflow-y: auto;\r\n flex: 1;\r\n padding: 0.25rem 0;\r\n }\r\n\r\n .devtools-empty {\r\n padding: 2rem;\r\n text-align: center;\r\n color: #475569;\r\n font-size: 0.78rem;\r\n font-family: system-ui;\r\n }\r\n\r\n .log-item {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n padding: 0.35rem 0.75rem;\r\n cursor: pointer;\r\n border-bottom: 1px solid #1e293b;\r\n }\r\n .log-item:hover { background: #1e293b; }\r\n .log-item--error { background: #1a0a0a; }\r\n\r\n .log-item__left { display: flex; align-items: center; gap: 0.4rem; overflow: hidden; }\r\n .log-item__right { display: flex; align-items: center; gap: 0.4rem; flex-shrink: 0; }\r\n\r\n .log-status { font-size: 0.72rem; color: #22c55e; flex-shrink: 0; }\r\n .log-item--error .log-status { color: #ef4444; }\r\n .log-name { color: #e2e8f0; font-size: 0.75rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\r\n .log-duration { color: #64748b; font-size: 0.7rem; }\r\n .log-time { color: #475569; font-size: 0.68rem; }\r\n\r\n .log-error-badge {\r\n background: #7f1d1d;\r\n color: #fca5a5;\r\n font-size: 0.68rem;\r\n padding: 0.1rem 0.35rem;\r\n border-radius: 4px;\r\n }\r\n\r\n .log-detail {\r\n background: #0a0f1a;\r\n padding: 0.6rem 0.75rem;\r\n border-left: 3px solid #3b82f6;\r\n margin: 0 0.4rem 0.4rem;\r\n border-radius: 0 4px 4px 0;\r\n }\r\n .log-detail__error { color: #fca5a5; font-size: 0.72rem; margin-bottom: 0.4rem; }\r\n .log-detail__section { margin-bottom: 0.4rem; }\r\n .log-detail__label {\r\n color: #64748b;\r\n font-size: 0.68rem;\r\n display: block;\r\n margin-bottom: 0.2rem;\r\n font-family: system-ui;\r\n }\r\n pre {\r\n color: #86efac;\r\n font-size: 0.7rem;\r\n margin: 0;\r\n white-space: pre-wrap;\r\n word-break: break-all;\r\n max-height: 140px;\r\n overflow-y: auto;\r\n }\r\n .state-view {\r\n color: #86efac;\r\n font-size: 0.7rem;\r\n padding: 0.75rem;\r\n margin: 0;\r\n white-space: pre-wrap;\r\n word-break: break-all;\r\n }\r\n `]\r\n})\r\nexport class StatoDevToolsComponent implements OnInit, OnDestroy {\r\n\r\n private config = inject(STATO_CONFIG, { optional: true })\r\n private unsub?: () => void\r\n\r\n // State UI\r\n isOpen = signal(false)\r\n isMinimized = signal(false)\r\n activeTab = signal<'actions' | 'state'>('actions')\r\n logs = signal<ActionLog[]>([])\r\n selectedLog = signal<ActionLog | null>(null)\r\n\r\n // Position et taille\r\n posX = signal(24)\r\n posY = signal(window.innerHeight - 500)\r\n panelWidth = signal(420)\r\n panelHeight = signal(460)\r\n\r\n // Drag state\r\n private isDragging = false\r\n private isResizing = false\r\n private dragOffsetX = 0\r\n private dragOffsetY = 0\r\n private startW = 0\r\n private startH = 0\r\n private startX = 0\r\n private startY = 0\r\n\r\n // Bound listeners\r\n private boundMouseMove = this.onMouseMove.bind(this)\r\n private boundMouseUp = this.onMouseUp.bind(this)\r\n\r\n ngOnInit() {\r\n this.unsub = devTools.subscribe((state) => {\r\n this.logs.set(state.logs)\r\n this.isOpen.set(state.isOpen)\r\n })\r\n\r\n document.addEventListener('mousemove', this.boundMouseMove)\r\n document.addEventListener('mouseup', this.boundMouseUp)\r\n }\r\n\r\n ngOnDestroy() {\r\n this.unsub?.()\r\n document.removeEventListener('mousemove', this.boundMouseMove)\r\n document.removeEventListener('mouseup', this.boundMouseUp)\r\n }\r\n\r\n // ── Toggle ─────────────────────────────────────────\r\n toggle() { devTools.toggle() }\r\n toggleMinimize() { this.isMinimized.update(v => !v) }\r\n clear() { devTools.clear(); this.selectedLog.set(null) }\r\n selectLog(log: ActionLog) {\r\n this.selectedLog.set(this.selectedLog()?.id === log.id ? null : log)\r\n }\r\n formatTime(iso: string): string {\r\n return new Date(iso).toTimeString().slice(0, 8)\r\n }\r\n\r\n // ── Drag ───────────────────────────────────────────\r\n onDragStart(e: MouseEvent) {\r\n if ((e.target as HTMLElement).classList.contains('btn-icon')) return\r\n this.isDragging = true\r\n this.dragOffsetX = e.clientX - this.posX()\r\n this.dragOffsetY = e.clientY - this.posY()\r\n e.preventDefault()\r\n }\r\n\r\n // ── Resize ─────────────────────────────────────────\r\n onResizeStart(e: MouseEvent) {\r\n this.isResizing = true\r\n this.startW = this.panelWidth()\r\n this.startH = this.panelHeight()\r\n this.startX = e.clientX\r\n this.startY = e.clientY\r\n e.preventDefault()\r\n e.stopPropagation()\r\n }\r\n\r\n // ── Mouse Move ─────────────────────────────────────\r\n onMouseMove(e: MouseEvent) {\r\n if (this.isDragging) {\r\n this.posX.set(Math.max(0, e.clientX - this.dragOffsetX))\r\n this.posY.set(Math.max(0, e.clientY - this.dragOffsetY))\r\n }\r\n if (this.isResizing) {\r\n const newW = Math.max(300, this.startW + e.clientX - this.startX)\r\n const newH = Math.max(200, this.startH + e.clientY - this.startY)\r\n this.panelWidth.set(newW)\r\n this.panelHeight.set(newH)\r\n }\r\n }\r\n\r\n // ── Mouse Up ───────────────────────────────────────\r\n onMouseUp() {\r\n this.isDragging = false\r\n this.isResizing = false\r\n }\r\n}"]}
File without changes