@ng-prism/plugin-perf 21.6.0 → 21.6.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.
@@ -1,115 +1,109 @@
1
1
  import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';
2
2
  import { SparklineComponent } from './sparkline.component.js';
3
3
  import * as i0 from "@angular/core";
4
- function RenderSectionComponent_Conditional_0_Conditional_0_Conditional_39_Template(rf, ctx) { if (rf & 1) {
5
- i0.ɵɵelementStart(0, "div", 10)(1, "div", 11)(2, "span", 3);
6
- i0.ɵɵtext(3);
4
+ function RenderSectionComponent_Conditional_0_Conditional_0_Conditional_43_Template(rf, ctx) { if (rf & 1) {
5
+ i0.ɵɵelementStart(0, "div", 7)(1, "div", 8)(2, "div", 3)(3, "span", 4);
6
+ i0.ɵɵtext(4);
7
7
  i0.ɵɵelementEnd();
8
- i0.ɵɵelementStart(4, "div", 12);
9
- i0.ɵɵtext(5, " avg ");
10
- i0.ɵɵelementStart(6, "span");
11
- i0.ɵɵtext(7);
8
+ i0.ɵɵelementStart(5, "span", 9);
9
+ i0.ɵɵtext(6, "avg ");
10
+ i0.ɵɵelementStart(7, "span", 10);
11
+ i0.ɵɵtext(8);
12
12
  i0.ɵɵelementEnd();
13
- i0.ɵɵtext(8, " \u00B7 max ");
14
- i0.ɵɵelementStart(9, "span");
15
- i0.ɵɵtext(10);
13
+ i0.ɵɵtext(9, " \u00B7 max ");
14
+ i0.ɵɵelementStart(10, "span", 10);
15
+ i0.ɵɵtext(11);
16
+ i0.ɵɵelementEnd()()();
17
+ i0.ɵɵelementStart(12, "div", 11);
18
+ i0.ɵɵelement(13, "perf-sparkline", 12);
16
19
  i0.ɵɵelementEnd()()();
17
- i0.ɵɵelement(11, "perf-sparkline", 13);
18
- i0.ɵɵelementEnd();
19
20
  } if (rf & 2) {
20
21
  const svc_r1 = i0.ɵɵnextContext(2);
21
22
  const ctx_r1 = i0.ɵɵnextContext();
22
- i0.ɵɵadvance(3);
23
- i0.ɵɵtextInterpolate1("Render Time Trace \u2014 last ", svc_r1.sampleCount(), " samples");
23
+ i0.ɵɵadvance(4);
24
+ i0.ɵɵtextInterpolate1("Render Time Trace \u2014 Last ", svc_r1.sampleCount(), " Samples");
24
25
  i0.ɵɵadvance(4);
25
26
  i0.ɵɵtextInterpolate1("", ctx_r1.formatMs(svc_r1.avgRerender()), " ms");
26
- i0.ɵɵadvance(2);
27
- i0.ɵɵstyleProp("color", ctx_r1.colorFor(svc_r1.maxRerender()));
28
- i0.ɵɵadvance();
27
+ i0.ɵɵadvance(3);
29
28
  i0.ɵɵtextInterpolate1("", ctx_r1.formatMs(svc_r1.maxRerender()), " ms");
30
- i0.ɵɵadvance();
31
- i0.ɵɵproperty("samples", svc_r1.rerenders())("thresholdWarn", ctx_r1.warnMs());
29
+ i0.ɵɵadvance(2);
30
+ i0.ɵɵproperty("samples", svc_r1.rerenders())("thresholdWarn", ctx_r1.warnMs())("height", 80);
32
31
  } }
33
32
  function RenderSectionComponent_Conditional_0_Conditional_0_Template(rf, ctx) { if (rf & 1) {
34
- i0.ɵɵelementStart(0, "div", 1)(1, "div", 2)(2, "div", 3);
35
- i0.ɵɵtext(3, "Initial Render");
36
- i0.ɵɵelementEnd();
37
- i0.ɵɵelementStart(4, "div", 4);
38
- i0.ɵɵtext(5);
39
- i0.ɵɵelementStart(6, "span", 5);
40
- i0.ɵɵtext(7, "ms");
33
+ i0.ɵɵelementStart(0, "div", 1)(1, "div", 2)(2, "div", 3)(3, "span", 4);
34
+ i0.ɵɵtext(4, "Initial Render");
35
+ i0.ɵɵelementEnd()();
36
+ i0.ɵɵelementStart(5, "div", 5);
37
+ i0.ɵɵtext(6);
38
+ i0.ɵɵelementStart(7, "span");
39
+ i0.ɵɵtext(8, "ms");
41
40
  i0.ɵɵelementEnd()()();
42
- i0.ɵɵelementStart(8, "div", 6)(9, "div", 7)(10, "span", 3);
43
- i0.ɵɵtext(11, "Avg Re-render");
44
- i0.ɵɵelementEnd();
45
- i0.ɵɵelementStart(12, "span", 8);
46
- i0.ɵɵtext(13);
47
- i0.ɵɵelementStart(14, "span", 5);
48
- i0.ɵɵtext(15, " ms");
41
+ i0.ɵɵelementStart(9, "div", 2)(10, "div", 3)(11, "span", 4);
42
+ i0.ɵɵtext(12, "Avg Re-Render");
49
43
  i0.ɵɵelementEnd()();
50
- i0.ɵɵelementStart(16, "span", 9);
51
- i0.ɵɵtext(17);
44
+ i0.ɵɵelementStart(13, "div", 5);
45
+ i0.ɵɵtext(14);
46
+ i0.ɵɵelementStart(15, "span");
47
+ i0.ɵɵtext(16, "ms");
52
48
  i0.ɵɵelementEnd()();
53
- i0.ɵɵelementStart(18, "div", 7)(19, "span", 3);
54
- i0.ɵɵtext(20, "Slowest");
55
- i0.ɵɵelementEnd();
56
- i0.ɵɵelementStart(21, "span", 8);
57
- i0.ɵɵtext(22);
58
- i0.ɵɵelementStart(23, "span", 5);
59
- i0.ɵɵtext(24, " ms");
49
+ i0.ɵɵelementStart(17, "div", 6);
50
+ i0.ɵɵtext(18);
51
+ i0.ɵɵelementEnd()();
52
+ i0.ɵɵelementStart(19, "div", 2)(20, "div", 3)(21, "span", 4);
53
+ i0.ɵɵtext(22, "Slowest");
54
+ i0.ɵɵelementEnd()();
55
+ i0.ɵɵelementStart(23, "div", 5);
56
+ i0.ɵɵtext(24);
57
+ i0.ɵɵelementStart(25, "span");
58
+ i0.ɵɵtext(26, "ms");
60
59
  i0.ɵɵelementEnd()()();
61
- i0.ɵɵelementStart(25, "div", 7)(26, "span", 3);
62
- i0.ɵɵtext(27, "p95");
63
- i0.ɵɵelementEnd();
64
- i0.ɵɵelementStart(28, "span", 8);
65
- i0.ɵɵtext(29);
66
- i0.ɵɵelementStart(30, "span", 5);
67
- i0.ɵɵtext(31, " ms");
60
+ i0.ɵɵelementStart(27, "div", 2)(28, "div", 3)(29, "span", 4);
61
+ i0.ɵɵtext(30, "P95");
62
+ i0.ɵɵelementEnd()();
63
+ i0.ɵɵelementStart(31, "div", 5);
64
+ i0.ɵɵtext(32);
65
+ i0.ɵɵelementStart(33, "span");
66
+ i0.ɵɵtext(34, "ms");
68
67
  i0.ɵɵelementEnd()()();
69
- i0.ɵɵelementStart(32, "div", 7)(33, "span", 3);
70
- i0.ɵɵtext(34, "Last Render");
71
- i0.ɵɵelementEnd();
72
- i0.ɵɵelementStart(35, "span", 8);
73
- i0.ɵɵtext(36);
74
- i0.ɵɵelementStart(37, "span", 5);
75
- i0.ɵɵtext(38, " ms");
76
- i0.ɵɵelementEnd()()()()();
77
- i0.ɵɵconditionalCreate(39, RenderSectionComponent_Conditional_0_Conditional_0_Conditional_39_Template, 12, 7, "div", 10);
68
+ i0.ɵɵelementStart(35, "div", 2)(36, "div", 3)(37, "span", 4);
69
+ i0.ɵɵtext(38, "Last Render");
70
+ i0.ɵɵelementEnd()();
71
+ i0.ɵɵelementStart(39, "div", 5);
72
+ i0.ɵɵtext(40);
73
+ i0.ɵɵelementStart(41, "span");
74
+ i0.ɵɵtext(42, "ms");
75
+ i0.ɵɵelementEnd()()()();
76
+ i0.ɵɵconditionalCreate(43, RenderSectionComponent_Conditional_0_Conditional_0_Conditional_43_Template, 14, 6, "div", 7);
78
77
  } if (rf & 2) {
79
78
  const svc_r1 = i0.ɵɵnextContext();
80
79
  const ctx_r1 = i0.ɵɵnextContext();
81
- i0.ɵɵadvance(4);
82
- i0.ɵɵclassMap(ctx_r1.initialClass());
80
+ i0.ɵɵadvance(5);
81
+ i0.ɵɵstyleProp("color", ctx_r1.colorFor(svc_r1.initialRender()));
83
82
  i0.ɵɵadvance();
84
- i0.ɵɵtextInterpolate1(" ", ctx_r1.formatMs(svc_r1.initialRender()));
83
+ i0.ɵɵtextInterpolate(ctx_r1.formatMs(svc_r1.initialRender()));
85
84
  i0.ɵɵadvance(8);
86
85
  i0.ɵɵtextInterpolate(ctx_r1.formatMs(svc_r1.avgRerender()));
87
86
  i0.ɵɵadvance(4);
88
87
  i0.ɵɵtextInterpolate1("", svc_r1.sampleCount(), " samples");
89
- i0.ɵɵadvance(4);
90
- i0.ɵɵstyleProp("color", ctx_r1.colorFor(svc_r1.maxRerender()));
91
- i0.ɵɵadvance();
88
+ i0.ɵɵadvance(6);
92
89
  i0.ɵɵtextInterpolate(ctx_r1.formatMs(svc_r1.maxRerender()));
93
- i0.ɵɵadvance(7);
90
+ i0.ɵɵadvance(8);
94
91
  i0.ɵɵtextInterpolate(ctx_r1.formatMs(svc_r1.p95Rerender()));
95
- i0.ɵɵadvance(7);
92
+ i0.ɵɵadvance(8);
96
93
  i0.ɵɵtextInterpolate(ctx_r1.formatMs(svc_r1.lastRerender()));
97
94
  i0.ɵɵadvance(3);
98
- i0.ɵɵconditional(svc_r1.rerenders().length > 1 ? 39 : -1);
95
+ i0.ɵɵconditional(svc_r1.rerenders().length > 1 ? 43 : -1);
99
96
  } }
100
97
  function RenderSectionComponent_Conditional_0_Conditional_1_Template(rf, ctx) { if (rf & 1) {
101
- i0.ɵɵelementStart(0, "div", 0)(1, "div", 14);
102
- i0.ɵɵtext(2, "\u23F1");
98
+ i0.ɵɵelementStart(0, "div", 0)(1, "div", 13);
99
+ i0.ɵɵtext(2, "No profiling data yet");
103
100
  i0.ɵɵelementEnd();
104
- i0.ɵɵelementStart(3, "div", 15);
105
- i0.ɵɵtext(4, "No profiling data yet");
106
- i0.ɵɵelementEnd();
107
- i0.ɵɵelementStart(5, "div", 16);
108
- i0.ɵɵtext(6, "Click Profile to start recording render times");
101
+ i0.ɵɵelementStart(3, "div", 14);
102
+ i0.ɵɵtext(4, "Click Profile to start recording render times");
109
103
  i0.ɵɵelementEnd()();
110
104
  } }
111
105
  function RenderSectionComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
112
- i0.ɵɵconditionalCreate(0, RenderSectionComponent_Conditional_0_Conditional_0_Template, 40, 11)(1, RenderSectionComponent_Conditional_0_Conditional_1_Template, 7, 0, "div", 0);
106
+ i0.ɵɵconditionalCreate(0, RenderSectionComponent_Conditional_0_Conditional_0_Template, 44, 9)(1, RenderSectionComponent_Conditional_0_Conditional_1_Template, 5, 0, "div", 0);
113
107
  } if (rf & 2) {
114
108
  const svc_r1 = ctx;
115
109
  i0.ɵɵconditional(svc_r1.initialRender() !== null || svc_r1.rerenders().length > 0 ? 0 : 1);
@@ -134,72 +128,71 @@ export class RenderSectionComponent {
134
128
  return value < 10 ? value.toFixed(2) : value.toFixed(1);
135
129
  }
136
130
  colorFor(value) {
131
+ if (value === null)
132
+ return '';
137
133
  if (value >= this.critMs())
138
- return 'var(--perf-crit, #f87171)';
134
+ return 'var(--prism-danger)';
139
135
  if (value >= this.warnMs())
140
- return 'var(--perf-warn, #fbbf24)';
141
- return 'var(--prism-text, #ede9f8)';
136
+ return 'var(--prism-warn)';
137
+ return 'var(--prism-success)';
142
138
  }
143
139
  static ɵfac = function RenderSectionComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RenderSectionComponent)(); };
144
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: RenderSectionComponent, selectors: [["perf-render-section"]], inputs: { renderService: [1, "renderService"], warnMs: [1, "warnMs"], critMs: [1, "critMs"] }, decls: 1, vars: 1, consts: [[1, "prism-perf-empty"], [1, "prism-perf-render-hero"], [1, "prism-perf-render-hero-main"], [1, "prism-perf-label"], [1, "prism-perf-render-hero-value"], [1, "prism-perf-unit"], [1, "prism-perf-render-stats-grid"], [1, "prism-perf-render-stat"], [1, "prism-perf-render-stat-value"], [1, "prism-perf-sub"], [1, "prism-perf-sparkline-section"], [1, "prism-perf-sparkline-header"], [1, "prism-perf-sparkline-legend"], [3, "samples", "thresholdWarn"], [1, "prism-perf-empty-icon"], [1, "prism-perf-empty-text"], [1, "prism-perf-empty-hint"]], template: function RenderSectionComponent_Template(rf, ctx) { if (rf & 1) {
140
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: RenderSectionComponent, selectors: [["perf-render-section"]], inputs: { renderService: [1, "renderService"], warnMs: [1, "warnMs"], critMs: [1, "critMs"] }, decls: 1, vars: 1, consts: [[1, "perf-empty"], [1, "perf-body"], [1, "perf-card"], [1, "perf-card-head"], [1, "perf-card-name"], [1, "perf-card-val"], [1, "perf-card-sub"], [1, "perf-detail"], [1, "perf-card", "perf-card--block"], [1, "perf-sparkline-legend"], [1, "perf-sparkline-hl"], [1, "perf-sparkline-wrap"], [3, "samples", "thresholdWarn", "height"], [1, "perf-empty-text"], [1, "perf-empty-hint"]], template: function RenderSectionComponent_Template(rf, ctx) { if (rf & 1) {
145
141
  i0.ɵɵconditionalCreate(0, RenderSectionComponent_Conditional_0_Template, 2, 1);
146
142
  } if (rf & 2) {
147
143
  let tmp_0_0;
148
144
  i0.ɵɵconditional((tmp_0_0 = ctx.renderService()) ? 0 : -1, tmp_0_0);
149
- } }, dependencies: [SparklineComponent], styles: [".prism-perf-render-hero[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 1fr 1fr;\n border-bottom: 1px solid var(--prism-border, rgba(255,255,255,0.08));\n }\n .prism-perf-render-hero-main[_ngcontent-%COMP%] {\n padding: 16px 20px;\n border-right: 1px solid var(--prism-border, rgba(255,255,255,0.08));\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n .prism-perf-render-hero-value[_ngcontent-%COMP%] {\n font-size: 34px;\n font-family: var(--prism-font-mono, monospace);\n font-weight: 600;\n color: var(--perf-ok, #4ade80);\n line-height: 1;\n letter-spacing: -0.02em;\n }\n .prism-perf-render-hero-value.warn[_ngcontent-%COMP%] { color: var(--perf-warn, #fbbf24); }\n .prism-perf-render-hero-value.crit[_ngcontent-%COMP%] { color: var(--perf-crit, #f87171); }\n .prism-perf-render-stats-grid[_ngcontent-%COMP%] {\n padding: 12px 16px;\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 14px 20px;\n }\n .prism-perf-render-stat[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n .prism-perf-render-stat-value[_ngcontent-%COMP%] {\n font-size: 16px;\n font-family: var(--prism-font-mono, monospace);\n font-weight: 600;\n color: var(--prism-text, #ede9f8);\n line-height: 1.1;\n }\n .prism-perf-sparkline-section[_ngcontent-%COMP%] {\n padding: 12px 16px 14px;\n border-top: 1px solid var(--prism-border, rgba(255,255,255,0.08));\n }\n .prism-perf-sparkline-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 10px;\n }\n .prism-perf-sparkline-legend[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n font-size: 10px;\n font-family: var(--prism-font-mono, monospace);\n color: var(--prism-text-ghost, #6a5d87);\n }\n .prism-perf-sparkline-legend[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n color: var(--prism-primary, #a78bfa);\n }\n .prism-perf-label[_ngcontent-%COMP%] {\n font-size: 9px;\n font-weight: 600;\n letter-spacing: 0.1em;\n text-transform: uppercase;\n color: var(--prism-text-ghost, #6a5d87);\n }\n .prism-perf-unit[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 400;\n color: var(--prism-text-muted, #8476a2);\n margin-left: 4px;\n }\n .prism-perf-sub[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--prism-text-ghost, #6a5d87);\n font-family: var(--prism-font-mono, monospace);\n }\n .prism-perf-empty[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n height: 100%;\n min-height: 180px;\n }\n .prism-perf-empty-icon[_ngcontent-%COMP%] { font-size: 28px; opacity: 0.2; }\n .prism-perf-empty-text[_ngcontent-%COMP%] { font-size: 12px; color: var(--prism-text-ghost, #6a5d87); }\n .prism-perf-empty-hint[_ngcontent-%COMP%] { font-size: 11px; color: var(--prism-text-ghost, #6a5d87); opacity: 0.6; }"], changeDetection: 0 });
145
+ } }, dependencies: [SparklineComponent], styles: [".perf-body[_ngcontent-%COMP%] {\n padding: 20px 24px;\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 16px;\n align-content: start;\n }\n\n .perf-card[_ngcontent-%COMP%] {\n padding: 16px;\n background: var(--prism-bg-surface);\n border: 1px solid var(--prism-border);\n border-radius: 10px;\n }\n .perf-card--block[_ngcontent-%COMP%] { display: block; }\n .perf-card-head[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 10px;\n }\n .perf-card-name[_ngcontent-%COMP%] {\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.08em;\n color: var(--prism-text-ghost);\n font-weight: 700;\n }\n .perf-card-val[_ngcontent-%COMP%] {\n font-family: 'JetBrains Mono', monospace;\n font-size: 26px;\n font-weight: 700;\n color: var(--prism-text);\n letter-spacing: -0.02em;\n display: flex;\n align-items: baseline;\n gap: 4px;\n }\n .perf-card-val[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--prism-text-muted);\n font-weight: 500;\n }\n .perf-card-sub[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--prism-text-muted);\n margin-top: 4px;\n font-family: 'JetBrains Mono', monospace;\n }\n\n .perf-detail[_ngcontent-%COMP%] { padding: 0 24px 20px; }\n\n .perf-sparkline-legend[_ngcontent-%COMP%] {\n font-family: 'JetBrains Mono', monospace;\n font-size: 11px;\n color: var(--prism-text-muted);\n }\n .perf-sparkline-hl[_ngcontent-%COMP%] { color: var(--prism-primary); }\n .perf-sparkline-wrap[_ngcontent-%COMP%] { margin-top: 10px; position: relative; }\n\n .perf-empty[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n height: 100%;\n min-height: 180px;\n }\n .perf-empty-text[_ngcontent-%COMP%] { font-size: 12px; color: var(--prism-text-ghost); }\n .perf-empty-hint[_ngcontent-%COMP%] { font-size: 11px; color: var(--prism-text-ghost); opacity: 0.6; }"], changeDetection: 0 });
150
146
  }
151
147
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RenderSectionComponent, [{
152
148
  type: Component,
153
149
  args: [{ selector: 'perf-render-section', standalone: true, imports: [SparklineComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
154
150
  @if (renderService(); as svc) {
155
151
  @if (svc.initialRender() !== null || svc.rerenders().length > 0) {
156
- <div class="prism-perf-render-hero">
157
- <div class="prism-perf-render-hero-main">
158
- <div class="prism-perf-label">Initial Render</div>
159
- <div class="prism-perf-render-hero-value" [class]="initialClass()">
160
- {{ formatMs(svc.initialRender()) }}<span class="prism-perf-unit">ms</span>
161
- </div>
152
+ <div class="perf-body">
153
+ <div class="perf-card">
154
+ <div class="perf-card-head"><span class="perf-card-name">Initial Render</span></div>
155
+ <div class="perf-card-val" [style.color]="colorFor(svc.initialRender())">{{ formatMs(svc.initialRender()) }}<span>ms</span></div>
162
156
  </div>
163
- <div class="prism-perf-render-stats-grid">
164
- <div class="prism-perf-render-stat">
165
- <span class="prism-perf-label">Avg Re-render</span>
166
- <span class="prism-perf-render-stat-value">{{ formatMs(svc.avgRerender()) }}<span class="prism-perf-unit"> ms</span></span>
167
- <span class="prism-perf-sub">{{ svc.sampleCount() }} samples</span>
168
- </div>
169
- <div class="prism-perf-render-stat">
170
- <span class="prism-perf-label">Slowest</span>
171
- <span class="prism-perf-render-stat-value" [style.color]="colorFor(svc.maxRerender())">{{ formatMs(svc.maxRerender()) }}<span class="prism-perf-unit"> ms</span></span>
172
- </div>
173
- <div class="prism-perf-render-stat">
174
- <span class="prism-perf-label">p95</span>
175
- <span class="prism-perf-render-stat-value">{{ formatMs(svc.p95Rerender()) }}<span class="prism-perf-unit"> ms</span></span>
176
- </div>
177
- <div class="prism-perf-render-stat">
178
- <span class="prism-perf-label">Last Render</span>
179
- <span class="prism-perf-render-stat-value">{{ formatMs(svc.lastRerender()) }}<span class="prism-perf-unit"> ms</span></span>
180
- </div>
157
+ <div class="perf-card">
158
+ <div class="perf-card-head"><span class="perf-card-name">Avg Re-Render</span></div>
159
+ <div class="perf-card-val">{{ formatMs(svc.avgRerender()) }}<span>ms</span></div>
160
+ <div class="perf-card-sub">{{ svc.sampleCount() }} samples</div>
161
+ </div>
162
+ <div class="perf-card">
163
+ <div class="perf-card-head"><span class="perf-card-name">Slowest</span></div>
164
+ <div class="perf-card-val">{{ formatMs(svc.maxRerender()) }}<span>ms</span></div>
165
+ </div>
166
+ <div class="perf-card">
167
+ <div class="perf-card-head"><span class="perf-card-name">P95</span></div>
168
+ <div class="perf-card-val">{{ formatMs(svc.p95Rerender()) }}<span>ms</span></div>
169
+ </div>
170
+ <div class="perf-card">
171
+ <div class="perf-card-head"><span class="perf-card-name">Last Render</span></div>
172
+ <div class="perf-card-val">{{ formatMs(svc.lastRerender()) }}<span>ms</span></div>
181
173
  </div>
182
174
  </div>
183
175
 
184
176
  @if (svc.rerenders().length > 1) {
185
- <div class="prism-perf-sparkline-section">
186
- <div class="prism-perf-sparkline-header">
187
- <span class="prism-perf-label">Render Time Trace — last {{ svc.sampleCount() }} samples</span>
188
- <div class="prism-perf-sparkline-legend">
189
- avg <span>{{ formatMs(svc.avgRerender()) }} ms</span> · max <span [style.color]="colorFor(svc.maxRerender())">{{ formatMs(svc.maxRerender()) }} ms</span>
190
- </div>
177
+ <div class="perf-detail">
178
+ <div class="perf-card perf-card--block">
179
+ <div class="perf-card-head">
180
+ <span class="perf-card-name">Render Time Trace &mdash; Last {{ svc.sampleCount() }} Samples</span>
181
+ <span class="perf-sparkline-legend">avg <span class="perf-sparkline-hl">{{ formatMs(svc.avgRerender()) }} ms</span> &middot; max <span class="perf-sparkline-hl">{{ formatMs(svc.maxRerender()) }} ms</span></span>
182
+ </div>
183
+ <div class="perf-sparkline-wrap">
184
+ <perf-sparkline [samples]="svc.rerenders()" [thresholdWarn]="warnMs()" [height]="80" />
191
185
  </div>
192
- <perf-sparkline [samples]="svc.rerenders()" [thresholdWarn]="warnMs()" />
193
186
  </div>
187
+ </div>
194
188
  }
195
189
  } @else {
196
- <div class="prism-perf-empty">
197
- <div class="prism-perf-empty-icon">&#9201;</div>
198
- <div class="prism-perf-empty-text">No profiling data yet</div>
199
- <div class="prism-perf-empty-hint">Click Profile to start recording render times</div>
190
+ <div class="perf-empty">
191
+ <div class="perf-empty-text">No profiling data yet</div>
192
+ <div class="perf-empty-hint">Click Profile to start recording render times</div>
200
193
  </div>
201
194
  }
202
195
  }
203
- `, styles: ["\n .prism-perf-render-hero {\n display: grid;\n grid-template-columns: 1fr 1fr;\n border-bottom: 1px solid var(--prism-border, rgba(255,255,255,0.08));\n }\n .prism-perf-render-hero-main {\n padding: 16px 20px;\n border-right: 1px solid var(--prism-border, rgba(255,255,255,0.08));\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n .prism-perf-render-hero-value {\n font-size: 34px;\n font-family: var(--prism-font-mono, monospace);\n font-weight: 600;\n color: var(--perf-ok, #4ade80);\n line-height: 1;\n letter-spacing: -0.02em;\n }\n .prism-perf-render-hero-value.warn { color: var(--perf-warn, #fbbf24); }\n .prism-perf-render-hero-value.crit { color: var(--perf-crit, #f87171); }\n .prism-perf-render-stats-grid {\n padding: 12px 16px;\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 14px 20px;\n }\n .prism-perf-render-stat {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n .prism-perf-render-stat-value {\n font-size: 16px;\n font-family: var(--prism-font-mono, monospace);\n font-weight: 600;\n color: var(--prism-text, #ede9f8);\n line-height: 1.1;\n }\n .prism-perf-sparkline-section {\n padding: 12px 16px 14px;\n border-top: 1px solid var(--prism-border, rgba(255,255,255,0.08));\n }\n .prism-perf-sparkline-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 10px;\n }\n .prism-perf-sparkline-legend {\n display: flex;\n align-items: center;\n gap: 12px;\n font-size: 10px;\n font-family: var(--prism-font-mono, monospace);\n color: var(--prism-text-ghost, #6a5d87);\n }\n .prism-perf-sparkline-legend span {\n color: var(--prism-primary, #a78bfa);\n }\n .prism-perf-label {\n font-size: 9px;\n font-weight: 600;\n letter-spacing: 0.1em;\n text-transform: uppercase;\n color: var(--prism-text-ghost, #6a5d87);\n }\n .prism-perf-unit {\n font-size: 12px;\n font-weight: 400;\n color: var(--prism-text-muted, #8476a2);\n margin-left: 4px;\n }\n .prism-perf-sub {\n font-size: 10px;\n color: var(--prism-text-ghost, #6a5d87);\n font-family: var(--prism-font-mono, monospace);\n }\n .prism-perf-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n height: 100%;\n min-height: 180px;\n }\n .prism-perf-empty-icon { font-size: 28px; opacity: 0.2; }\n .prism-perf-empty-text { font-size: 12px; color: var(--prism-text-ghost, #6a5d87); }\n .prism-perf-empty-hint { font-size: 11px; color: var(--prism-text-ghost, #6a5d87); opacity: 0.6; }\n "] }]
196
+ `, styles: ["\n .perf-body {\n padding: 20px 24px;\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 16px;\n align-content: start;\n }\n\n .perf-card {\n padding: 16px;\n background: var(--prism-bg-surface);\n border: 1px solid var(--prism-border);\n border-radius: 10px;\n }\n .perf-card--block { display: block; }\n .perf-card-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 10px;\n }\n .perf-card-name {\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.08em;\n color: var(--prism-text-ghost);\n font-weight: 700;\n }\n .perf-card-val {\n font-family: 'JetBrains Mono', monospace;\n font-size: 26px;\n font-weight: 700;\n color: var(--prism-text);\n letter-spacing: -0.02em;\n display: flex;\n align-items: baseline;\n gap: 4px;\n }\n .perf-card-val span {\n font-size: 13px;\n color: var(--prism-text-muted);\n font-weight: 500;\n }\n .perf-card-sub {\n font-size: 11px;\n color: var(--prism-text-muted);\n margin-top: 4px;\n font-family: 'JetBrains Mono', monospace;\n }\n\n .perf-detail { padding: 0 24px 20px; }\n\n .perf-sparkline-legend {\n font-family: 'JetBrains Mono', monospace;\n font-size: 11px;\n color: var(--prism-text-muted);\n }\n .perf-sparkline-hl { color: var(--prism-primary); }\n .perf-sparkline-wrap { margin-top: 10px; position: relative; }\n\n .perf-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n height: 100%;\n min-height: 180px;\n }\n .perf-empty-text { font-size: 12px; color: var(--prism-text-ghost); }\n .perf-empty-hint { font-size: 11px; color: var(--prism-text-ghost); opacity: 0.6; }\n "] }]
204
197
  }], null, { renderService: [{ type: i0.Input, args: [{ isSignal: true, alias: "renderService", required: true }] }], warnMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "warnMs", required: false }] }], critMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "critMs", required: false }] }] }); })();
205
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(RenderSectionComponent, { className: "RenderSectionComponent", filePath: "render/render-section.component.ts", lineNumber: 155 }); })();
198
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(RenderSectionComponent, { className: "RenderSectionComponent", filePath: "render/render-section.component.ts", lineNumber: 132 }); })();
@@ -1 +1 @@
1
- {"version":3,"file":"sparkline.component.d.ts","sourceRoot":"","sources":["../../src/render/sparkline.component.ts"],"names":[],"mappings":";AAEA,qBAoDa,kBAAkB;IAC7B,QAAQ,CAAC,OAAO,gDAAuB;IACvC,QAAQ,CAAC,aAAa,8CAAY;IAClC,QAAQ,CAAC,MAAM,8CAAa;IAE5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAapB;IAEH,QAAQ,CAAC,QAAQ,yCAId;IAEH,QAAQ,CAAC,QAAQ,yCAMd;IAEH,QAAQ,CAAC,KAAK,gDAMX;IAEH,QAAQ,CAAC,SAAS;;;;cAQf;IAEH,QAAQ,CAAC,YAAY;;;;cAGlB;yCAvDQ,kBAAkB;2CAAlB,kBAAkB;CAwD9B"}
1
+ {"version":3,"file":"sparkline.component.d.ts","sourceRoot":"","sources":["../../src/render/sparkline.component.ts"],"names":[],"mappings":";AAEA,qBA+Da,kBAAkB;IAC7B,QAAQ,CAAC,OAAO,gDAAuB;IACvC,QAAQ,CAAC,aAAa,8CAAY;IAClC,QAAQ,CAAC,MAAM,8CAAa;IAE5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAapB;IAEH,QAAQ,CAAC,QAAQ,yCAId;IAEH,QAAQ,CAAC,QAAQ,yCAMd;IAEH,QAAQ,CAAC,KAAK,gDAMX;IAEH,QAAQ,CAAC,SAAS;;;;cAQf;IAEH,QAAQ,CAAC,YAAY;;;;cAGlB;yCAvDQ,kBAAkB;2CAAlB,kBAAkB;CAwD9B"}
@@ -88,7 +88,7 @@ export class SparklineComponent {
88
88
  return pts.length > 0 ? pts[pts.length - 1] : null;
89
89
  }, ...(ngDevMode ? [{ debugName: "currentPoint" }] : []));
90
90
  static ɵfac = function SparklineComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SparklineComponent)(); };
91
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SparklineComponent, selectors: [["perf-sparkline"]], inputs: { samples: [1, "samples"], thresholdWarn: [1, "thresholdWarn"], height: [1, "height"] }, decls: 16, vars: 6, consts: [[1, "prism-perf-sparkline-wrap"], ["preserveAspectRatio", "none", "xmlns", "http://www.w3.org/2000/svg", 1, "prism-perf-sparkline-svg"], ["id", "perf-sparkg", "x1", "0", "y1", "0", "x2", "0", "y2", "1"], ["offset", "0%", "stop-color", "#a78bfa", "stop-opacity", "0.35"], ["offset", "100%", "stop-color", "#a78bfa", "stop-opacity", "0.0"], ["id", "perf-glow"], ["stdDeviation", "1.5", "result", "coloredBlur"], ["in", "coloredBlur"], ["in", "SourceGraphic"], ["fill", "url(#perf-sparkg)"], ["fill", "none", "stroke", "#a78bfa", "stroke-width", "1.5", "filter", "url(#perf-glow)"], ["r", "3", "fill", "#fbbf24", "filter", "url(#perf-glow)"], ["stroke", "#fbbf24", "stroke-width", "0.8", "stroke-dasharray", "4 4", "opacity", "0.4"], ["font-size", "8", "fill", "#fbbf24", "opacity", "0.5", "font-family", "monospace"], ["r", "2.5", "fill", "#a78bfa"], ["r", "5", "fill", "none", "stroke", "#a78bfa", "stroke-width", "1", "opacity", "0.4"], ["attributeName", "r", "values", "3;7", "dur", "1.5s", "repeatCount", "indefinite"], ["attributeName", "opacity", "values", "0.4;0", "dur", "1.5s", "repeatCount", "indefinite"]], template: function SparklineComponent_Template(rf, ctx) { if (rf & 1) {
91
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SparklineComponent, selectors: [["perf-sparkline"]], inputs: { samples: [1, "samples"], thresholdWarn: [1, "thresholdWarn"], height: [1, "height"] }, decls: 16, vars: 6, consts: [[1, "prism-perf-sparkline-wrap"], ["preserveAspectRatio", "none", "xmlns", "http://www.w3.org/2000/svg", 1, "prism-perf-sparkline-svg"], ["id", "perf-sparkg", "x1", "0", "y1", "0", "x2", "0", "y2", "1"], ["offset", "0%", 1, "sparkline-gradient-start"], ["offset", "100%", 1, "sparkline-gradient-end"], ["id", "perf-glow"], ["stdDeviation", "1.5", "result", "coloredBlur"], ["in", "coloredBlur"], ["in", "SourceGraphic"], ["fill", "url(#perf-sparkg)"], ["fill", "none", "stroke-width", "1.5", "filter", "url(#perf-glow)", 1, "sparkline-line"], ["r", "3", "filter", "url(#perf-glow)", 1, "sparkline-peak"], [1, "sparkline-warn-line"], ["font-size", "8", "font-family", "monospace", 1, "sparkline-warn-text"], ["r", "2.5", 1, "sparkline-current"], ["r", "5", "stroke-width", "1", 1, "sparkline-current-pulse"], ["attributeName", "r", "values", "3;7", "dur", "1.5s", "repeatCount", "indefinite"], ["attributeName", "opacity", "values", "0.4;0", "dur", "1.5s", "repeatCount", "indefinite"]], template: function SparklineComponent_Template(rf, ctx) { if (rf & 1) {
92
92
  i0.ɵɵdomElementStart(0, "div", 0);
93
93
  i0.ɵɵnamespaceSVG();
94
94
  i0.ɵɵdomElementStart(1, "svg", 1)(2, "defs")(3, "linearGradient", 2);
@@ -119,7 +119,7 @@ export class SparklineComponent {
119
119
  i0.ɵɵconditional((tmp_4_0 = ctx.peakPoint()) ? 14 : -1, tmp_4_0);
120
120
  i0.ɵɵadvance();
121
121
  i0.ɵɵconditional((tmp_5_0 = ctx.currentPoint()) ? 15 : -1, tmp_5_0);
122
- } }, styles: [".prism-perf-sparkline-wrap[_ngcontent-%COMP%] {\n position: relative;\n }\n .prism-perf-sparkline-svg[_ngcontent-%COMP%] {\n width: 100%;\n height: 52px;\n }"], changeDetection: 0 });
122
+ } }, styles: [".prism-perf-sparkline-wrap[_ngcontent-%COMP%] { position: relative; }\n .prism-perf-sparkline-svg[_ngcontent-%COMP%] { width: 100%; height: 52px; }\n\n .sparkline-gradient-start[_ngcontent-%COMP%] { stop-color: var(--prism-primary); stop-opacity: 0.35; }\n .sparkline-gradient-end[_ngcontent-%COMP%] { stop-color: var(--prism-primary); stop-opacity: 0; }\n\n .sparkline-warn-line[_ngcontent-%COMP%] {\n stroke: var(--prism-warn);\n stroke-width: 0.8;\n stroke-dasharray: 4 4;\n opacity: 0.4;\n }\n .sparkline-warn-text[_ngcontent-%COMP%] { fill: var(--prism-warn); opacity: 0.5; }\n\n .sparkline-line[_ngcontent-%COMP%] { stroke: var(--prism-primary); }\n .sparkline-peak[_ngcontent-%COMP%] { fill: var(--prism-warn); }\n .sparkline-current[_ngcontent-%COMP%] { fill: var(--prism-primary); }\n .sparkline-current-pulse[_ngcontent-%COMP%] { fill: none; stroke: var(--prism-primary); opacity: 0.4; }"], changeDetection: 0 });
123
123
  }
124
124
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SparklineComponent, [{
125
125
  type: Component,
@@ -128,8 +128,8 @@ export class SparklineComponent {
128
128
  <svg class="prism-perf-sparkline-svg" [attr.viewBox]="'0 0 600 ' + height()" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg">
129
129
  <defs>
130
130
  <linearGradient id="perf-sparkg" x1="0" y1="0" x2="0" y2="1">
131
- <stop offset="0%" stop-color="#a78bfa" stop-opacity="0.35"/>
132
- <stop offset="100%" stop-color="#a78bfa" stop-opacity="0.0"/>
131
+ <stop offset="0%" class="sparkline-gradient-start"/>
132
+ <stop offset="100%" class="sparkline-gradient-end"/>
133
133
  </linearGradient>
134
134
  <filter id="perf-glow">
135
135
  <feGaussianBlur stdDeviation="1.5" result="coloredBlur"/>
@@ -139,27 +139,27 @@ export class SparklineComponent {
139
139
 
140
140
  @if (warnY() !== null) {
141
141
  <line [attr.x1]="0" [attr.y1]="warnY()" [attr.x2]="600" [attr.y2]="warnY()"
142
- stroke="#fbbf24" stroke-width="0.8" stroke-dasharray="4 4" opacity="0.4"/>
143
- <text [attr.x]="3" [attr.y]="warnY()! - 3" font-size="8" fill="#fbbf24" opacity="0.5"
142
+ class="sparkline-warn-line"/>
143
+ <text [attr.x]="3" [attr.y]="warnY()! - 3" font-size="8" class="sparkline-warn-text"
144
144
  font-family="monospace">{{ thresholdWarn() }}ms</text>
145
145
  }
146
146
 
147
147
  <path [attr.d]="areaPath()" fill="url(#perf-sparkg)"/>
148
- <path [attr.d]="linePath()" fill="none" stroke="#a78bfa" stroke-width="1.5" filter="url(#perf-glow)"/>
148
+ <path [attr.d]="linePath()" fill="none" class="sparkline-line" stroke-width="1.5" filter="url(#perf-glow)"/>
149
149
 
150
150
  @if (peakPoint(); as peak) {
151
- <circle [attr.cx]="peak.x" [attr.cy]="peak.y" r="3" fill="#fbbf24" filter="url(#perf-glow)"/>
151
+ <circle [attr.cx]="peak.x" [attr.cy]="peak.y" r="3" class="sparkline-peak" filter="url(#perf-glow)"/>
152
152
  }
153
153
 
154
154
  @if (currentPoint(); as current) {
155
- <circle [attr.cx]="current.x" [attr.cy]="current.y" r="2.5" fill="#a78bfa"/>
156
- <circle [attr.cx]="current.x" [attr.cy]="current.y" r="5" fill="none" stroke="#a78bfa" stroke-width="1" opacity="0.4">
155
+ <circle [attr.cx]="current.x" [attr.cy]="current.y" r="2.5" class="sparkline-current"/>
156
+ <circle [attr.cx]="current.x" [attr.cy]="current.y" r="5" class="sparkline-current-pulse" stroke-width="1">
157
157
  <animate attributeName="r" values="3;7" dur="1.5s" repeatCount="indefinite"/>
158
158
  <animate attributeName="opacity" values="0.4;0" dur="1.5s" repeatCount="indefinite"/>
159
159
  </circle>
160
160
  }
161
161
  </svg>
162
162
  </div>
163
- `, styles: ["\n .prism-perf-sparkline-wrap {\n position: relative;\n }\n .prism-perf-sparkline-svg {\n width: 100%;\n height: 52px;\n }\n "] }]
163
+ `, styles: ["\n .prism-perf-sparkline-wrap { position: relative; }\n .prism-perf-sparkline-svg { width: 100%; height: 52px; }\n\n .sparkline-gradient-start { stop-color: var(--prism-primary); stop-opacity: 0.35; }\n .sparkline-gradient-end { stop-color: var(--prism-primary); stop-opacity: 0; }\n\n .sparkline-warn-line {\n stroke: var(--prism-warn);\n stroke-width: 0.8;\n stroke-dasharray: 4 4;\n opacity: 0.4;\n }\n .sparkline-warn-text { fill: var(--prism-warn); opacity: 0.5; }\n\n .sparkline-line { stroke: var(--prism-primary); }\n .sparkline-peak { fill: var(--prism-warn); }\n .sparkline-current { fill: var(--prism-primary); }\n .sparkline-current-pulse { fill: none; stroke: var(--prism-primary); opacity: 0.4; }\n "] }]
164
164
  }], null, { samples: [{ type: i0.Input, args: [{ isSignal: true, alias: "samples", required: false }] }], thresholdWarn: [{ type: i0.Input, args: [{ isSignal: true, alias: "thresholdWarn", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }] }); })();
165
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SparklineComponent, { className: "SparklineComponent", filePath: "render/sparkline.component.ts", lineNumber: 55 }); })();
165
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SparklineComponent, { className: "SparklineComponent", filePath: "render/sparkline.component.ts", lineNumber: 66 }); })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ng-prism/plugin-perf",
3
- "version": "21.6.0",
3
+ "version": "21.6.1",
4
4
  "description": "Performance profiling panel for ng-prism — bundle size, render time, memory footprint.",
5
5
  "keywords": [
6
6
  "@ng-prism/core",