@react-perfscope/ui 0.3.0 → 0.4.0

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.cjs CHANGED
@@ -105,6 +105,9 @@ var en = {
105
105
  sort: "Sort",
106
106
  sortChronological: "chronological",
107
107
  sortSeverity: "severity (worst first)",
108
+ filterPlaceholder: "Filter\u2026",
109
+ filterAria: "Filter signals",
110
+ filterNoMatches: "No signals match the filter.",
108
111
  groupBy: "Group by",
109
112
  groupChronological: "chronological",
110
113
  groupComponent: "component",
@@ -195,6 +198,9 @@ var ko = {
195
198
  sort: "\uC815\uB82C",
196
199
  sortChronological: "\uC2DC\uAC04\uC21C",
197
200
  sortSeverity: "\uC2EC\uAC01\uB3C4\uC21C (\uB192\uC740 \uAC83\uBD80\uD130)",
201
+ filterPlaceholder: "\uD544\uD130\u2026",
202
+ filterAria: "\uC2DC\uADF8\uB110 \uD544\uD130",
203
+ filterNoMatches: "\uD544\uD130\uC640 \uC77C\uCE58\uD558\uB294 \uC2DC\uADF8\uB110\uC774 \uC5C6\uC5B4\uC694.",
198
204
  groupBy: "\uADF8\uB8F9\uD654",
199
205
  groupChronological: "\uC2DC\uAC04\uC21C",
200
206
  groupComponent: "\uCEF4\uD3EC\uB10C\uD2B8",
@@ -1887,6 +1893,45 @@ function RenderInsights({ signals, onSelect }) {
1887
1893
  );
1888
1894
  }
1889
1895
 
1896
+ // src/filter.ts
1897
+ function signalSearchText(signal) {
1898
+ switch (signal.kind) {
1899
+ case "render": {
1900
+ const parts = [signal.component];
1901
+ if (signal.changedProps) parts.push(...signal.changedProps);
1902
+ if (signal.members) for (const m of signal.members) parts.push(m.component);
1903
+ return parts.join(" ").toLowerCase();
1904
+ }
1905
+ case "network":
1906
+ return signal.url.toLowerCase();
1907
+ case "web-vital":
1908
+ return signal.name.toLowerCase();
1909
+ case "interaction":
1910
+ return [signal.eventType, signal.target ?? ""].join(" ").toLowerCase();
1911
+ case "forced-reflow": {
1912
+ const f = signal.stack[0];
1913
+ return f ? [f.fnName ?? "", f.file].join(" ").toLowerCase() : "";
1914
+ }
1915
+ case "long-task": {
1916
+ const parts = [];
1917
+ if (signal.scripts)
1918
+ for (const s of signal.scripts) parts.push(s.sourceFunctionName, s.invoker, s.sourceURL);
1919
+ if (signal.attribution)
1920
+ for (const a of signal.attribution) parts.push(a.frame.fnName ?? "", a.frame.file);
1921
+ return parts.join(" ").toLowerCase();
1922
+ }
1923
+ case "layout-shift":
1924
+ return "layout-shift";
1925
+ default:
1926
+ return "";
1927
+ }
1928
+ }
1929
+ function signalMatchesFilter(signal, query) {
1930
+ const q = query.trim().toLowerCase();
1931
+ if (!q) return true;
1932
+ return signalSearchText(signal).includes(q);
1933
+ }
1934
+
1890
1935
  // src/panel.tsx
1891
1936
  var import_jsx_runtime5 = require("preact/jsx-runtime");
1892
1937
  var RENDER_REASON_COLOR = {
@@ -2652,6 +2697,7 @@ function Panel(props) {
2652
2697
  const [expandedKey, setExpandedKey] = (0, import_hooks3.useState)(null);
2653
2698
  const [groupMode, setGroupMode] = (0, import_hooks3.useState)({});
2654
2699
  const [sortMode, setSortMode] = (0, import_hooks3.useState)({});
2700
+ const [filterText, setFilterText] = (0, import_hooks3.useState)({});
2655
2701
  const activeOverlayCount = (0, import_hooks3.useRef)(0);
2656
2702
  (0, import_hooks3.useEffect)(() => () => hideAllOverlays(), []);
2657
2703
  function handleHover(signal) {
@@ -2858,7 +2904,21 @@ function Panel(props) {
2858
2904
  ]
2859
2905
  }
2860
2906
  )
2861
- ] })
2907
+ ] }),
2908
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2909
+ "input",
2910
+ {
2911
+ type: "text",
2912
+ "aria-label": t.filterAria,
2913
+ placeholder: t.filterPlaceholder,
2914
+ value: filterText[activeKind] ?? "",
2915
+ onInput: (e) => {
2916
+ setFilterText({ ...filterText, [activeKind]: e.target.value });
2917
+ setExpandedKey(null);
2918
+ },
2919
+ style: { marginLeft: "auto", background: "#1a1a1a", color: "#e6e6e6", border: "1px solid #2a2a2a", borderRadius: "4px", padding: "2px 6px", fontSize: "11px", width: "120px" }
2920
+ }
2921
+ )
2862
2922
  ] }),
2863
2923
  activeTab === "timeline" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { flexGrow: 1, overflowY: "auto", paddingTop: "4px", paddingBottom: "24px" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2864
2924
  Timeline,
@@ -2879,9 +2939,7 @@ function Panel(props) {
2879
2939
  activeKind === "render" && activeTab !== "timeline" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2880
2940
  RenderInsights,
2881
2941
  {
2882
- signals: grouped.render.flatMap(
2883
- (s) => s.kind === "render" ? s.members ?? [s] : []
2884
- ),
2942
+ signals: grouped.render.flatMap((s) => s.kind === "render" ? s.members ?? [s] : []).filter((s) => signalMatchesFilter(s, filterText.render ?? "")),
2885
2943
  onSelect: () => {
2886
2944
  setGroupMode({ ...groupMode, render: "component" });
2887
2945
  setExpandedKey(null);
@@ -2904,7 +2962,10 @@ function Panel(props) {
2904
2962
  }
2905
2963
  ),
2906
2964
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { style: { listStyle: "none", margin: 0, padding: 0, overflowY: "auto", flexGrow: 1, display: activeTab === "timeline" ? "none" : void 0 }, children: activeKind && (() => {
2907
- const baseSignals = (sortMode[activeKind] ?? "chronological") === "severity" ? sortSignalsBySeverity(grouped[activeKind]) : grouped[activeKind];
2965
+ const filtered = grouped[activeKind].filter(
2966
+ (s) => signalMatchesFilter(s, filterText[activeKind] ?? "")
2967
+ );
2968
+ const baseSignals = (sortMode[activeKind] ?? "chronological") === "severity" ? sortSignalsBySeverity(filtered) : filtered;
2908
2969
  return groupSignals(baseSignals, groupMode[activeKind] ?? "chronological", activeKind);
2909
2970
  })().map((g, gi) => {
2910
2971
  const currentMode = groupMode[activeKind] ?? "chronological";
@@ -2962,7 +3023,8 @@ function Panel(props) {
2962
3023
  },
2963
3024
  key
2964
3025
  );
2965
- }) })
3026
+ }) }),
3027
+ activeKind && activeTab !== "timeline" && (filterText[activeKind] ?? "").trim() !== "" && grouped[activeKind].length > 0 && grouped[activeKind].every((s) => !signalMatchesFilter(s, filterText[activeKind] ?? "")) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { padding: "12px 8px", fontSize: "11px", color: "#888" }, children: t.filterNoMatches })
2966
3028
  ] })
2967
3029
  ] });
2968
3030
  }