angular-scan 1.0.0 → 1.0.1

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.
@@ -50,10 +50,10 @@ class ComponentTracker {
50
50
  this.totalUnnecessary.set(0);
51
51
  this.trackedComponents.set([]);
52
52
  }
53
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ComponentTracker, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
54
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ComponentTracker, providedIn: 'root' });
53
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ComponentTracker, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
54
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ComponentTracker, providedIn: 'root' });
55
55
  }
56
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ComponentTracker, decorators: [{
56
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ComponentTracker, decorators: [{
57
57
  type: Injectable,
58
58
  args: [{ providedIn: 'root' }]
59
59
  }] });
@@ -96,10 +96,10 @@ class ScanConfigService {
96
96
  showOverlay = signal(true, ...(ngDevMode ? [{ debugName: "showOverlay" }] : /* istanbul ignore next */ []));
97
97
  showBadges = signal(this.options.showBadges !== false, ...(ngDevMode ? [{ debugName: "showBadges" }] : /* istanbul ignore next */ []));
98
98
  flashDurationMs = signal(this.options.flashDurationMs ?? 500, ...(ngDevMode ? [{ debugName: "flashDurationMs" }] : /* istanbul ignore next */ []));
99
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScanConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
100
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScanConfigService, providedIn: 'root' });
99
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ScanConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
100
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ScanConfigService, providedIn: 'root' });
101
101
  }
102
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScanConfigService, decorators: [{
102
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ScanConfigService, decorators: [{
103
103
  type: Injectable,
104
104
  args: [{ providedIn: 'root' }]
105
105
  }] });
@@ -271,10 +271,10 @@ class OverlayService {
271
271
  this.badges.get(el)?.remove();
272
272
  this.badges.delete(el);
273
273
  }
274
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OverlayService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
275
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OverlayService, providedIn: 'root' });
274
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: OverlayService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
275
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: OverlayService, providedIn: 'root' });
276
276
  }
277
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OverlayService, decorators: [{
277
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: OverlayService, decorators: [{
278
278
  type: Injectable,
279
279
  args: [{ providedIn: 'root' }]
280
280
  }] });
@@ -446,10 +446,10 @@ class ScannerService {
446
446
  this.pendingFlush = [];
447
447
  this.overlay.destroy();
448
448
  }
449
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScannerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
450
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScannerService, providedIn: 'root' });
449
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ScannerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
450
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ScannerService, providedIn: 'root' });
451
451
  }
452
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ScannerService, decorators: [{
452
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ScannerService, decorators: [{
453
453
  type: Injectable,
454
454
  args: [{ providedIn: 'root' }]
455
455
  }] });
@@ -487,10 +487,10 @@ class ToolbarComponent {
487
487
  const value = Number(event.target.value);
488
488
  this.config.flashDurationMs.set(value);
489
489
  }
490
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
491
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: ToolbarComponent, isStandalone: true, selector: "angular-scan-toolbar", host: { properties: { "style.display": "\"block\"" } }, ngImport: i0, template: "<div\n class=\"toolbar\"\n role=\"complementary\"\n aria-label=\"Angular Scan DevTools\"\n>\n <div class=\"toolbar__header\">\n <span class=\"toolbar__logo\" aria-hidden=\"true\">\u25C9</span>\n <span class=\"toolbar__title\">angular-scan</span>\n\n <button\n class=\"toolbar__btn\"\n type=\"button\"\n [attr.aria-pressed]=\"!config.enabled()\"\n [title]=\"config.enabled() ? 'Pause scanning' : 'Resume scanning'\"\n (click)=\"toggleEnabled()\"\n >{{ config.enabled() ? '\u23F8' : '\u25B6' }}</button>\n\n <button\n class=\"toolbar__btn\"\n type=\"button\"\n [attr.aria-pressed]=\"settingsOpen()\"\n title=\"Settings\"\n (click)=\"toggleSettings()\"\n >\u2699</button>\n\n <button\n class=\"toolbar__btn\"\n type=\"button\"\n [attr.aria-pressed]=\"expanded()\"\n [title]=\"expanded() ? 'Collapse inspector' : 'Expand inspector'\"\n (click)=\"toggleExpanded()\"\n >{{ expanded() ? '\u25B2' : '\u25BC' }}</button>\n </div>\n\n <div class=\"toolbar__stats\">\n <span class=\"toolbar__stat\" title=\"Total change detection checks\">\n <span class=\"toolbar__stat-label\">checks</span>\n <strong class=\"toolbar__stat-value\">{{ tracker.totalRenders() }}</strong>\n </span>\n <span\n class=\"toolbar__stat\"\n [class.toolbar__stat--warn]=\"tracker.totalUnnecessary() > 0\"\n title=\"Unnecessary renders: component was checked but DOM did not change\"\n >\n <span class=\"toolbar__stat-label\">wasted</span>\n <strong class=\"toolbar__stat-value\">{{ tracker.totalUnnecessary() }}</strong>\n </span>\n </div>\n\n @if (settingsOpen()) {\n <div class=\"toolbar__settings\" role=\"group\" aria-label=\"Scan settings\">\n\n <label class=\"toolbar__setting\">\n <span class=\"toolbar__setting-label\">Enable scanning</span>\n <button\n class=\"toolbar__toggle\"\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"config.enabled()\"\n (click)=\"toggleEnabled()\"\n [class.toolbar__toggle--on]=\"config.enabled()\"\n >{{ config.enabled() ? 'ON' : 'OFF' }}</button>\n </label>\n\n <label class=\"toolbar__setting\">\n <span class=\"toolbar__setting-label\">Flash overlay</span>\n <button\n class=\"toolbar__toggle\"\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"config.showOverlay()\"\n (click)=\"toggleOverlay()\"\n [class.toolbar__toggle--on]=\"config.showOverlay()\"\n >{{ config.showOverlay() ? 'ON' : 'OFF' }}</button>\n </label>\n\n <label class=\"toolbar__setting\">\n <span class=\"toolbar__setting-label\">Render badges</span>\n <button\n class=\"toolbar__toggle\"\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"config.showBadges()\"\n (click)=\"toggleBadges()\"\n [class.toolbar__toggle--on]=\"config.showBadges()\"\n >{{ config.showBadges() ? 'ON' : 'OFF' }}</button>\n </label>\n\n <label class=\"toolbar__setting toolbar__setting--column\">\n <span class=\"toolbar__setting-label\">\n Flash duration\n <span class=\"toolbar__setting-value\">{{ config.flashDurationMs() }}ms</span>\n </span>\n <input\n class=\"toolbar__slider\"\n type=\"range\"\n min=\"100\"\n max=\"2000\"\n step=\"100\"\n [value]=\"config.flashDurationMs()\"\n (input)=\"onFlashDurationChange($event)\"\n aria-label=\"Flash duration in milliseconds\"\n />\n </label>\n\n <button\n class=\"toolbar__reset\"\n type=\"button\"\n title=\"Clear all render stats\"\n (click)=\"resetStats()\"\n >\u21BA Reset stats</button>\n\n </div>\n }\n\n @if (expanded()) {\n <div\n class=\"toolbar__inspector\"\n role=\"list\"\n aria-label=\"Component render counts\"\n >\n @for (comp of tracker.trackedComponents(); track comp.hostElement) {\n <div\n class=\"toolbar__component\"\n role=\"listitem\"\n [class.toolbar__component--warn]=\"comp.lastRenderKind === 'unnecessary'\"\n [title]=\"comp.componentName + ' \u2014 ' + comp.totalRenders + ' checks, ' + comp.unnecessaryRenders + ' wasted'\"\n >\n <span class=\"toolbar__component-name\">{{ comp.componentName }}</span>\n <span class=\"toolbar__component-count\">{{ comp.totalRenders }}</span>\n @if (comp.unnecessaryRenders > 0) {\n <span class=\"toolbar__component-wasted\" aria-label=\"wasted renders\">\n {{ comp.unnecessaryRenders }}W\n </span>\n }\n </div>\n }\n </div>\n }\n</div>\n", styles: [":host{position:fixed;bottom:0;right:0;z-index:2147483647;font-family:ui-monospace,Cascadia Code,Source Code Pro,Menlo,Consolas,monospace;font-size:11px;line-height:1.4}.toolbar{background:#0f1117;color:#c9d1d9;border:1px solid #30363d;border-bottom:none;border-right:none;border-radius:6px 0 0;min-width:200px;max-width:300px;box-shadow:-2px -2px 12px #00000080}.toolbar__header{display:flex;align-items:center;gap:4px;padding:5px 8px;border-bottom:1px solid #21262d}.toolbar__logo{color:#58a6ff;font-size:12px}.toolbar__title{font-weight:600;color:#58a6ff;flex:1;letter-spacing:.02em}.toolbar__btn{background:transparent;border:1px solid #30363d;color:#8b949e;border-radius:4px;cursor:pointer;padding:2px 6px;font-size:10px;transition:color .15s,border-color .15s}.toolbar__btn:hover{color:#c9d1d9;border-color:#58a6ff}.toolbar__btn:focus-visible{outline:2px solid #58a6ff;outline-offset:2px}.toolbar__stats{display:flex;gap:12px;padding:5px 8px}.toolbar__stat{display:flex;flex-direction:column;gap:1px}.toolbar__stat-label{color:#8b949e;font-size:9px;text-transform:uppercase;letter-spacing:.05em}.toolbar__stat-value{color:#c9d1d9}.toolbar__stat--warn .toolbar__stat-value{color:#f85149}.toolbar__inspector{max-height:220px;overflow-y:auto;border-top:1px solid #21262d}.toolbar__inspector::-webkit-scrollbar{width:4px}.toolbar__inspector::-webkit-scrollbar-track{background:transparent}.toolbar__inspector::-webkit-scrollbar-thumb{background:#30363d;border-radius:2px}.toolbar__component{display:flex;align-items:center;gap:6px;padding:3px 8px;border-bottom:1px solid #161b22;transition:background .1s}.toolbar__component:hover{background:#161b22}.toolbar__component--warn{background:#f851490f}.toolbar__component-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#8b949e}.toolbar__component-count{font-weight:600;color:#ffa657;min-width:20px;text-align:right}.toolbar__component-wasted{color:#f85149;font-size:9px;font-weight:600}.toolbar__settings{display:flex;flex-direction:column;gap:6px;padding:8px;border-top:1px solid #21262d}.toolbar__setting{display:flex;align-items:center;justify-content:space-between;gap:8px;cursor:default}.toolbar__setting--column{flex-direction:column;align-items:stretch;gap:4px}.toolbar__setting-label{color:#8b949e;font-size:10px;display:flex;align-items:center;justify-content:space-between;gap:4px}.toolbar__setting-value{color:#58a6ff;font-weight:600}.toolbar__toggle{background:#21262d;border:1px solid #30363d;color:#8b949e;border-radius:3px;cursor:pointer;padding:1px 6px;font-size:9px;font-weight:600;font-family:inherit;letter-spacing:.05em;min-width:32px;transition:background .15s,color .15s,border-color .15s}.toolbar__toggle--on{background:#58a6ff26;border-color:#58a6ff;color:#58a6ff}.toolbar__toggle:focus-visible{outline:2px solid #58a6ff;outline-offset:2px}.toolbar__slider{width:100%;accent-color:#58a6ff;cursor:pointer;height:4px}.toolbar__reset{background:transparent;border:1px solid #30363d;color:#8b949e;border-radius:4px;cursor:pointer;padding:3px 8px;font-size:10px;font-family:inherit;margin-top:2px;transition:color .15s,border-color .15s;align-self:flex-start}.toolbar__reset:hover{color:#f85149;border-color:#f85149}.toolbar__reset:focus-visible{outline:2px solid #58a6ff;outline-offset:2px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
490
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
491
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: ToolbarComponent, isStandalone: true, selector: "angular-scan-toolbar", host: { properties: { "style.display": "\"block\"" } }, ngImport: i0, template: "<div\n class=\"toolbar\"\n role=\"complementary\"\n aria-label=\"Angular Scan DevTools\"\n>\n <div class=\"toolbar__header\">\n <span class=\"toolbar__logo\" aria-hidden=\"true\">\u25C9</span>\n <span class=\"toolbar__title\">angular-scan</span>\n\n <button\n class=\"toolbar__btn\"\n type=\"button\"\n [attr.aria-pressed]=\"!config.enabled()\"\n [title]=\"config.enabled() ? 'Pause scanning' : 'Resume scanning'\"\n (click)=\"toggleEnabled()\"\n >{{ config.enabled() ? '\u23F8' : '\u25B6' }}</button>\n\n <button\n class=\"toolbar__btn\"\n type=\"button\"\n [attr.aria-pressed]=\"settingsOpen()\"\n title=\"Settings\"\n (click)=\"toggleSettings()\"\n >\u2699</button>\n\n <button\n class=\"toolbar__btn\"\n type=\"button\"\n [attr.aria-pressed]=\"expanded()\"\n [title]=\"expanded() ? 'Collapse inspector' : 'Expand inspector'\"\n (click)=\"toggleExpanded()\"\n >{{ expanded() ? '\u25B2' : '\u25BC' }}</button>\n </div>\n\n <div class=\"toolbar__stats\">\n <span class=\"toolbar__stat\" title=\"Total change detection checks\">\n <span class=\"toolbar__stat-label\">checks</span>\n <strong class=\"toolbar__stat-value\">{{ tracker.totalRenders() }}</strong>\n </span>\n <span\n class=\"toolbar__stat\"\n [class.toolbar__stat--warn]=\"tracker.totalUnnecessary() > 0\"\n title=\"Unnecessary renders: component was checked but DOM did not change\"\n >\n <span class=\"toolbar__stat-label\">wasted</span>\n <strong class=\"toolbar__stat-value\">{{ tracker.totalUnnecessary() }}</strong>\n </span>\n </div>\n\n @if (settingsOpen()) {\n <div class=\"toolbar__settings\" role=\"group\" aria-label=\"Scan settings\">\n\n <label class=\"toolbar__setting\">\n <span class=\"toolbar__setting-label\">Enable scanning</span>\n <button\n class=\"toolbar__toggle\"\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"config.enabled()\"\n (click)=\"toggleEnabled()\"\n [class.toolbar__toggle--on]=\"config.enabled()\"\n >{{ config.enabled() ? 'ON' : 'OFF' }}</button>\n </label>\n\n <label class=\"toolbar__setting\">\n <span class=\"toolbar__setting-label\">Flash overlay</span>\n <button\n class=\"toolbar__toggle\"\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"config.showOverlay()\"\n (click)=\"toggleOverlay()\"\n [class.toolbar__toggle--on]=\"config.showOverlay()\"\n >{{ config.showOverlay() ? 'ON' : 'OFF' }}</button>\n </label>\n\n <label class=\"toolbar__setting\">\n <span class=\"toolbar__setting-label\">Render badges</span>\n <button\n class=\"toolbar__toggle\"\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"config.showBadges()\"\n (click)=\"toggleBadges()\"\n [class.toolbar__toggle--on]=\"config.showBadges()\"\n >{{ config.showBadges() ? 'ON' : 'OFF' }}</button>\n </label>\n\n <label class=\"toolbar__setting toolbar__setting--column\">\n <span class=\"toolbar__setting-label\">\n Flash duration\n <span class=\"toolbar__setting-value\">{{ config.flashDurationMs() }}ms</span>\n </span>\n <input\n class=\"toolbar__slider\"\n type=\"range\"\n min=\"100\"\n max=\"2000\"\n step=\"100\"\n [value]=\"config.flashDurationMs()\"\n (input)=\"onFlashDurationChange($event)\"\n aria-label=\"Flash duration in milliseconds\"\n />\n </label>\n\n <button\n class=\"toolbar__reset\"\n type=\"button\"\n title=\"Clear all render stats\"\n (click)=\"resetStats()\"\n >\u21BA Reset stats</button>\n\n </div>\n }\n\n @if (expanded()) {\n <div\n class=\"toolbar__inspector\"\n role=\"list\"\n aria-label=\"Component render counts\"\n >\n @for (comp of tracker.trackedComponents(); track comp.hostElement) {\n <div\n class=\"toolbar__component\"\n role=\"listitem\"\n [class.toolbar__component--warn]=\"comp.lastRenderKind === 'unnecessary'\"\n [title]=\"comp.componentName + ' \u2014 ' + comp.totalRenders + ' checks, ' + comp.unnecessaryRenders + ' wasted'\"\n >\n <span class=\"toolbar__component-name\">{{ comp.componentName }}</span>\n <span class=\"toolbar__component-count\">{{ comp.totalRenders }}</span>\n @if (comp.unnecessaryRenders > 0) {\n <span class=\"toolbar__component-wasted\" aria-label=\"wasted renders\">\n {{ comp.unnecessaryRenders }}W\n </span>\n }\n </div>\n }\n </div>\n }\n</div>\n", styles: [":host{position:fixed;bottom:0;right:0;z-index:2147483647;font-family:ui-monospace,Cascadia Code,Source Code Pro,Menlo,Consolas,monospace;font-size:11px;line-height:1.4}.toolbar{background:#0f1117;color:#c9d1d9;border:1px solid #30363d;border-bottom:none;border-right:none;border-radius:6px 0 0;min-width:200px;max-width:300px;box-shadow:-2px -2px 12px #00000080}.toolbar__header{display:flex;align-items:center;gap:4px;padding:5px 8px;border-bottom:1px solid #21262d}.toolbar__logo{color:#58a6ff;font-size:12px}.toolbar__title{font-weight:600;color:#58a6ff;flex:1;letter-spacing:.02em}.toolbar__btn{background:transparent;border:1px solid #30363d;color:#8b949e;border-radius:4px;cursor:pointer;padding:2px 6px;font-size:10px;transition:color .15s,border-color .15s}.toolbar__btn:hover{color:#c9d1d9;border-color:#58a6ff}.toolbar__btn:focus-visible{outline:2px solid #58a6ff;outline-offset:2px}.toolbar__stats{display:flex;gap:12px;padding:5px 8px}.toolbar__stat{display:flex;flex-direction:column;gap:1px}.toolbar__stat-label{color:#8b949e;font-size:9px;text-transform:uppercase;letter-spacing:.05em}.toolbar__stat-value{color:#c9d1d9}.toolbar__stat--warn .toolbar__stat-value{color:#f85149}.toolbar__inspector{max-height:220px;overflow-y:auto;border-top:1px solid #21262d}.toolbar__inspector::-webkit-scrollbar{width:4px}.toolbar__inspector::-webkit-scrollbar-track{background:transparent}.toolbar__inspector::-webkit-scrollbar-thumb{background:#30363d;border-radius:2px}.toolbar__component{display:flex;align-items:center;gap:6px;padding:3px 8px;border-bottom:1px solid #161b22;transition:background .1s}.toolbar__component:hover{background:#161b22}.toolbar__component--warn{background:#f851490f}.toolbar__component-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#8b949e}.toolbar__component-count{font-weight:600;color:#ffa657;min-width:20px;text-align:right}.toolbar__component-wasted{color:#f85149;font-size:9px;font-weight:600}.toolbar__settings{display:flex;flex-direction:column;gap:6px;padding:8px;border-top:1px solid #21262d}.toolbar__setting{display:flex;align-items:center;justify-content:space-between;gap:8px;cursor:default}.toolbar__setting--column{flex-direction:column;align-items:stretch;gap:4px}.toolbar__setting-label{color:#8b949e;font-size:10px;display:flex;align-items:center;justify-content:space-between;gap:4px}.toolbar__setting-value{color:#58a6ff;font-weight:600}.toolbar__toggle{background:#21262d;border:1px solid #30363d;color:#8b949e;border-radius:3px;cursor:pointer;padding:1px 6px;font-size:9px;font-weight:600;font-family:inherit;letter-spacing:.05em;min-width:32px;transition:background .15s,color .15s,border-color .15s}.toolbar__toggle--on{background:#58a6ff26;border-color:#58a6ff;color:#58a6ff}.toolbar__toggle:focus-visible{outline:2px solid #58a6ff;outline-offset:2px}.toolbar__slider{width:100%;accent-color:#58a6ff;cursor:pointer;height:4px}.toolbar__reset{background:transparent;border:1px solid #30363d;color:#8b949e;border-radius:4px;cursor:pointer;padding:3px 8px;font-size:10px;font-family:inherit;margin-top:2px;transition:color .15s,border-color .15s;align-self:flex-start}.toolbar__reset:hover{color:#f85149;border-color:#f85149}.toolbar__reset:focus-visible{outline:2px solid #58a6ff;outline-offset:2px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
492
492
  }
493
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ToolbarComponent, decorators: [{
493
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ToolbarComponent, decorators: [{
494
494
  type: Component,
495
495
  args: [{ selector: 'angular-scan-toolbar', changeDetection: ChangeDetectionStrategy.OnPush, host: { '[style.display]': '"block"' }, template: "<div\n class=\"toolbar\"\n role=\"complementary\"\n aria-label=\"Angular Scan DevTools\"\n>\n <div class=\"toolbar__header\">\n <span class=\"toolbar__logo\" aria-hidden=\"true\">\u25C9</span>\n <span class=\"toolbar__title\">angular-scan</span>\n\n <button\n class=\"toolbar__btn\"\n type=\"button\"\n [attr.aria-pressed]=\"!config.enabled()\"\n [title]=\"config.enabled() ? 'Pause scanning' : 'Resume scanning'\"\n (click)=\"toggleEnabled()\"\n >{{ config.enabled() ? '\u23F8' : '\u25B6' }}</button>\n\n <button\n class=\"toolbar__btn\"\n type=\"button\"\n [attr.aria-pressed]=\"settingsOpen()\"\n title=\"Settings\"\n (click)=\"toggleSettings()\"\n >\u2699</button>\n\n <button\n class=\"toolbar__btn\"\n type=\"button\"\n [attr.aria-pressed]=\"expanded()\"\n [title]=\"expanded() ? 'Collapse inspector' : 'Expand inspector'\"\n (click)=\"toggleExpanded()\"\n >{{ expanded() ? '\u25B2' : '\u25BC' }}</button>\n </div>\n\n <div class=\"toolbar__stats\">\n <span class=\"toolbar__stat\" title=\"Total change detection checks\">\n <span class=\"toolbar__stat-label\">checks</span>\n <strong class=\"toolbar__stat-value\">{{ tracker.totalRenders() }}</strong>\n </span>\n <span\n class=\"toolbar__stat\"\n [class.toolbar__stat--warn]=\"tracker.totalUnnecessary() > 0\"\n title=\"Unnecessary renders: component was checked but DOM did not change\"\n >\n <span class=\"toolbar__stat-label\">wasted</span>\n <strong class=\"toolbar__stat-value\">{{ tracker.totalUnnecessary() }}</strong>\n </span>\n </div>\n\n @if (settingsOpen()) {\n <div class=\"toolbar__settings\" role=\"group\" aria-label=\"Scan settings\">\n\n <label class=\"toolbar__setting\">\n <span class=\"toolbar__setting-label\">Enable scanning</span>\n <button\n class=\"toolbar__toggle\"\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"config.enabled()\"\n (click)=\"toggleEnabled()\"\n [class.toolbar__toggle--on]=\"config.enabled()\"\n >{{ config.enabled() ? 'ON' : 'OFF' }}</button>\n </label>\n\n <label class=\"toolbar__setting\">\n <span class=\"toolbar__setting-label\">Flash overlay</span>\n <button\n class=\"toolbar__toggle\"\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"config.showOverlay()\"\n (click)=\"toggleOverlay()\"\n [class.toolbar__toggle--on]=\"config.showOverlay()\"\n >{{ config.showOverlay() ? 'ON' : 'OFF' }}</button>\n </label>\n\n <label class=\"toolbar__setting\">\n <span class=\"toolbar__setting-label\">Render badges</span>\n <button\n class=\"toolbar__toggle\"\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"config.showBadges()\"\n (click)=\"toggleBadges()\"\n [class.toolbar__toggle--on]=\"config.showBadges()\"\n >{{ config.showBadges() ? 'ON' : 'OFF' }}</button>\n </label>\n\n <label class=\"toolbar__setting toolbar__setting--column\">\n <span class=\"toolbar__setting-label\">\n Flash duration\n <span class=\"toolbar__setting-value\">{{ config.flashDurationMs() }}ms</span>\n </span>\n <input\n class=\"toolbar__slider\"\n type=\"range\"\n min=\"100\"\n max=\"2000\"\n step=\"100\"\n [value]=\"config.flashDurationMs()\"\n (input)=\"onFlashDurationChange($event)\"\n aria-label=\"Flash duration in milliseconds\"\n />\n </label>\n\n <button\n class=\"toolbar__reset\"\n type=\"button\"\n title=\"Clear all render stats\"\n (click)=\"resetStats()\"\n >\u21BA Reset stats</button>\n\n </div>\n }\n\n @if (expanded()) {\n <div\n class=\"toolbar__inspector\"\n role=\"list\"\n aria-label=\"Component render counts\"\n >\n @for (comp of tracker.trackedComponents(); track comp.hostElement) {\n <div\n class=\"toolbar__component\"\n role=\"listitem\"\n [class.toolbar__component--warn]=\"comp.lastRenderKind === 'unnecessary'\"\n [title]=\"comp.componentName + ' \u2014 ' + comp.totalRenders + ' checks, ' + comp.unnecessaryRenders + ' wasted'\"\n >\n <span class=\"toolbar__component-name\">{{ comp.componentName }}</span>\n <span class=\"toolbar__component-count\">{{ comp.totalRenders }}</span>\n @if (comp.unnecessaryRenders > 0) {\n <span class=\"toolbar__component-wasted\" aria-label=\"wasted renders\">\n {{ comp.unnecessaryRenders }}W\n </span>\n }\n </div>\n }\n </div>\n }\n</div>\n", styles: [":host{position:fixed;bottom:0;right:0;z-index:2147483647;font-family:ui-monospace,Cascadia Code,Source Code Pro,Menlo,Consolas,monospace;font-size:11px;line-height:1.4}.toolbar{background:#0f1117;color:#c9d1d9;border:1px solid #30363d;border-bottom:none;border-right:none;border-radius:6px 0 0;min-width:200px;max-width:300px;box-shadow:-2px -2px 12px #00000080}.toolbar__header{display:flex;align-items:center;gap:4px;padding:5px 8px;border-bottom:1px solid #21262d}.toolbar__logo{color:#58a6ff;font-size:12px}.toolbar__title{font-weight:600;color:#58a6ff;flex:1;letter-spacing:.02em}.toolbar__btn{background:transparent;border:1px solid #30363d;color:#8b949e;border-radius:4px;cursor:pointer;padding:2px 6px;font-size:10px;transition:color .15s,border-color .15s}.toolbar__btn:hover{color:#c9d1d9;border-color:#58a6ff}.toolbar__btn:focus-visible{outline:2px solid #58a6ff;outline-offset:2px}.toolbar__stats{display:flex;gap:12px;padding:5px 8px}.toolbar__stat{display:flex;flex-direction:column;gap:1px}.toolbar__stat-label{color:#8b949e;font-size:9px;text-transform:uppercase;letter-spacing:.05em}.toolbar__stat-value{color:#c9d1d9}.toolbar__stat--warn .toolbar__stat-value{color:#f85149}.toolbar__inspector{max-height:220px;overflow-y:auto;border-top:1px solid #21262d}.toolbar__inspector::-webkit-scrollbar{width:4px}.toolbar__inspector::-webkit-scrollbar-track{background:transparent}.toolbar__inspector::-webkit-scrollbar-thumb{background:#30363d;border-radius:2px}.toolbar__component{display:flex;align-items:center;gap:6px;padding:3px 8px;border-bottom:1px solid #161b22;transition:background .1s}.toolbar__component:hover{background:#161b22}.toolbar__component--warn{background:#f851490f}.toolbar__component-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#8b949e}.toolbar__component-count{font-weight:600;color:#ffa657;min-width:20px;text-align:right}.toolbar__component-wasted{color:#f85149;font-size:9px;font-weight:600}.toolbar__settings{display:flex;flex-direction:column;gap:6px;padding:8px;border-top:1px solid #21262d}.toolbar__setting{display:flex;align-items:center;justify-content:space-between;gap:8px;cursor:default}.toolbar__setting--column{flex-direction:column;align-items:stretch;gap:4px}.toolbar__setting-label{color:#8b949e;font-size:10px;display:flex;align-items:center;justify-content:space-between;gap:4px}.toolbar__setting-value{color:#58a6ff;font-weight:600}.toolbar__toggle{background:#21262d;border:1px solid #30363d;color:#8b949e;border-radius:3px;cursor:pointer;padding:1px 6px;font-size:9px;font-weight:600;font-family:inherit;letter-spacing:.05em;min-width:32px;transition:background .15s,color .15s,border-color .15s}.toolbar__toggle--on{background:#58a6ff26;border-color:#58a6ff;color:#58a6ff}.toolbar__toggle:focus-visible{outline:2px solid #58a6ff;outline-offset:2px}.toolbar__slider{width:100%;accent-color:#58a6ff;cursor:pointer;height:4px}.toolbar__reset{background:transparent;border:1px solid #30363d;color:#8b949e;border-radius:4px;cursor:pointer;padding:3px 8px;font-size:10px;font-family:inherit;margin-top:2px;transition:color .15s,border-color .15s;align-self:flex-start}.toolbar__reset:hover{color:#f85149;border-color:#f85149}.toolbar__reset:focus-visible{outline:2px solid #58a6ff;outline-offset:2px}\n"] }]
496
496
  }] });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "angular-scan",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Automatically detects and highlights Angular components that are re-rendering — the Angular equivalent of react-scan.",
5
5
  "author": "Hussein AbdElAziz",
6
6
  "license": "MIT",