@react-perfscope/ui 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ray
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # @react-perfscope/ui
2
+
3
+ Floating-widget UI for `react-perfscope`. Mounts a Shadow-DOM-isolated Preact tree into your page. Records performance signals, shows them in a per-kind tabbed panel, and highlights affected DOM regions via overlay rectangles.
4
+
5
+ ## Status
6
+
7
+ Phase 4 — initial implementation. Supports 7 signal kinds (forced-reflow, layout-shift, long-task, paint, network, web-vital, render). Overlay geometry implemented for `layout-shift.sources`; other kinds gain real geometry in Phase 5.
8
+
9
+ ## Quickstart
10
+
11
+ ```ts
12
+ import { createRecorder } from '@react-perfscope/core'
13
+ import { createRenderCollector } from '@react-perfscope/react'
14
+ import { mount } from '@react-perfscope/ui'
15
+
16
+ const recorder = createRecorder()
17
+ recorder.use(createRenderCollector())
18
+
19
+ const unmount = mount({ recorder })
20
+ // ... later, to remove:
21
+ // unmount()
22
+ ```
23
+
24
+ ## What's in the panel
25
+
26
+ Click any row to expand its detail. Each signal kind shows different info:
27
+
28
+ - **forced-reflow** — call stack (top 8 frames) showing where the layout was forced
29
+ - **layout-shift** — CLS value + each source rect's x/y/w/h
30
+ - **long-task** — start/end/duration, plus call stack if captured
31
+ - **network** — full URL, transfer size, render-blocking flag
32
+ - **paint** — paint name (first-paint / first-contentful-paint)
33
+ - **web-vital** — metric name, value with unit, rating (good/needs/poor) dot per [Google thresholds](https://web.dev/vitals/)
34
+ - **render** — component, reason, duration, timestamp
35
+
36
+ The header has a **Save** button that downloads the full recording as JSON. Stack frames inside the panel are passed through the optional `resolveFrame` mount option — when provided (the meta-package `auto` entry wires one up against the live dev server's source maps), bundle URLs like `bundle.js?v=abc:2552:28` become real source positions like `src/App.tsx:132:15`.
37
+
38
+ The `render` tab also offers **Group by component** (collapsing many commits of the same component into one row); the `forced-reflow` tab offers **Group by source** (grouping reflows by their originating call site).
39
+
40
+ ## API
41
+
42
+ - `mount({ recorder, position?, host? })` — returns an unmount function.
43
+ - `position`: `'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'`. Defaults to `'bottom-right'`.
44
+ - `host`: parent element to attach the Shadow DOM host. Defaults to `document.body`.
45
+ - `mountShadow(vnode, { parent? })` — low-level: mount any Preact vnode in a fresh Shadow Root. Returns unmount.
46
+ - `showOverlay(id, rect)` / `hideOverlay(id)` / `hideAllOverlays()` — DOM overlay primitives. Useful for custom UIs.
47
+ - `App`, `Panel`, `Widget` — Preact components, exported for advanced composition.
48
+
49
+ ## Notes
50
+
51
+ - The UI is built in **Preact** (not React) so the render collector — which observes React commits — doesn't pick up our own widget renders.
52
+ - The Shadow Root uses `mode: 'open'` so tests and devtools can inspect the tree.
53
+ - The overlay lives outside the Shadow DOM (in `document.body`) so it can layer over arbitrary host-page elements.
54
+
55
+ ---
56
+
57
+ <a id="한국어"></a>
58
+
59
+ # 한국어
60
+
61
+ `react-perfscope`용 플로팅 위젯 UI. Shadow DOM으로 격리된 Preact 트리를 페이지에 마운트한다. 성능 신호를 기록하고, 종류별 탭 패널로 표시하고, 영향을 받은 DOM 영역을 오버레이 직사각형으로 하이라이트한다.
62
+
63
+ ## 상태
64
+
65
+ Phase 4 — 초기 구현. 7가지 신호 종류를 지원한다 (forced-reflow, layout-shift, long-task, paint, network, web-vital, render). 오버레이 geometry는 `layout-shift.sources`에 구현됐고, 다른 종류는 Phase 5에서 실제 geometry가 들어온다.
66
+
67
+ ## 빠르게 시작하기
68
+
69
+ ```ts
70
+ import { createRecorder } from '@react-perfscope/core'
71
+ import { createRenderCollector } from '@react-perfscope/react'
72
+ import { mount } from '@react-perfscope/ui'
73
+
74
+ const recorder = createRecorder()
75
+ recorder.use(createRenderCollector())
76
+
77
+ const unmount = mount({ recorder })
78
+ // ... 나중에 제거하려면:
79
+ // unmount()
80
+ ```
81
+
82
+ ## 패널 안에 뭐가 있나
83
+
84
+ 신호 row를 클릭하면 디테일이 펼쳐진다. 종류별로 다른 정보를 보여준다:
85
+
86
+ - **forced-reflow** — 레이아웃을 강제한 호출 스택 (상위 8개 프레임)
87
+ - **layout-shift** — CLS 값 + 각 source rect의 x/y/w/h
88
+ - **long-task** — 시작/끝/duration, 캡처된 스택이 있으면 같이 표시
89
+ - **network** — 전체 URL, transfer size, render-blocking 여부
90
+ - **paint** — paint 이름 (first-paint / first-contentful-paint)
91
+ - **web-vital** — 메트릭 이름, 단위 포함된 값, [Google 기준](https://web.dev/vitals/)에 따른 등급 (good/needs/poor) 색 점
92
+ - **render** — 컴포넌트, reason, duration, 타임스탬프
93
+
94
+ 헤더에는 **Save** 버튼이 있어서 전체 recording을 JSON으로 다운로드 받을 수 있다. 패널의 스택 프레임은 `resolveFrame` mount 옵션을 거치는데, 이게 제공되면 (meta 패키지의 `auto` entry가 자동으로 dev 서버의 source map에 대해 연결해줌) `bundle.js?v=abc:2552:28` 같은 번들 URL이 `src/App.tsx:132:15` 같은 실제 소스 위치로 변환된다.
95
+
96
+ `render` 탭에는 **Group by component** (같은 컴포넌트의 여러 commit을 한 row로 묶음), `forced-reflow` 탭에는 **Group by source** (같은 call site에서 발생한 reflow끼리 묶음) 옵션도 있다.
97
+
98
+ ## API
99
+
100
+ - `mount({ recorder, position?, host? })` — unmount 함수를 반환한다.
101
+ - `position`: `'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'`. 기본값은 `'bottom-right'`.
102
+ - `host`: Shadow DOM 호스트를 붙일 부모 엘리먼트. 기본값은 `document.body`.
103
+ - `mountShadow(vnode, { parent? })` — 저수준: 새 Shadow Root에 Preact vnode를 마운트한다. unmount 함수를 반환.
104
+ - `showOverlay(id, rect)` / `hideOverlay(id)` / `hideAllOverlays()` — DOM 오버레이 기본 함수. 커스텀 UI에 활용할 수 있다.
105
+ - `App`, `Panel`, `Widget` — 고급 조합을 위해 export된 Preact 컴포넌트들.
106
+
107
+ ## 참고
108
+
109
+ - UI는 **Preact**로 만들어졌다 (React 아님). 그래서 React 커밋을 감지하는 render collector가 위젯 자체의 렌더는 잡지 않는다.
110
+ - Shadow Root는 `mode: 'open'`이라 테스트와 DevTools에서 트리를 들여다볼 수 있다.
111
+ - 오버레이는 Shadow DOM 바깥(즉 `document.body`)에 있어서 호스트 페이지의 어떤 엘리먼트 위에도 레이어를 올릴 수 있다.