@variance-authority/tribunal 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.
Files changed (271) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/LICENSE +21 -0
  3. package/README.md +506 -0
  4. package/dist/__fixtures__/review.d.ts +47 -0
  5. package/dist/__fixtures__/review.js +145 -0
  6. package/dist/__fixtures__/review.js.map +1 -0
  7. package/dist/bindings.d.ts +134 -0
  8. package/dist/bindings.js +88 -0
  9. package/dist/bindings.js.map +1 -0
  10. package/dist/changelog.d.ts +132 -0
  11. package/dist/changelog.js +129 -0
  12. package/dist/changelog.js.map +1 -0
  13. package/dist/history-queries.d.ts +82 -0
  14. package/dist/history-queries.js +200 -0
  15. package/dist/history-queries.js.map +1 -0
  16. package/dist/history-rows.d.ts +42 -0
  17. package/dist/history-rows.js +148 -0
  18. package/dist/history-rows.js.map +1 -0
  19. package/dist/history.d.ts +40 -0
  20. package/dist/history.js +186 -0
  21. package/dist/history.js.map +1 -0
  22. package/dist/index.d.ts +13 -0
  23. package/dist/index.js +12 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/migration-steps.d.ts +32 -0
  26. package/dist/migration-steps.js +303 -0
  27. package/dist/migration-steps.js.map +1 -0
  28. package/dist/migrations.d.ts +58 -0
  29. package/dist/migrations.js +283 -0
  30. package/dist/migrations.js.map +1 -0
  31. package/dist/next.d.ts +94 -0
  32. package/dist/next.js +44 -0
  33. package/dist/next.js.map +1 -0
  34. package/dist/node/bin.d.ts +120 -0
  35. package/dist/node/bin.js +337 -0
  36. package/dist/node/bin.js.map +1 -0
  37. package/dist/node/bucket.d.ts +58 -0
  38. package/dist/node/bucket.js +142 -0
  39. package/dist/node/bucket.js.map +1 -0
  40. package/dist/node/database.d.ts +33 -0
  41. package/dist/node/database.js +157 -0
  42. package/dist/node/database.js.map +1 -0
  43. package/dist/node/index.d.ts +43 -0
  44. package/dist/node/index.js +43 -0
  45. package/dist/node/index.js.map +1 -0
  46. package/dist/node/serve.d.ts +81 -0
  47. package/dist/node/serve.js +193 -0
  48. package/dist/node/serve.js.map +1 -0
  49. package/dist/node/ui-assets.d.ts +47 -0
  50. package/dist/node/ui-assets.js +60 -0
  51. package/dist/node/ui-assets.js.map +1 -0
  52. package/dist/review-ingest.d.ts +24 -0
  53. package/dist/review-ingest.js +184 -0
  54. package/dist/review-ingest.js.map +1 -0
  55. package/dist/review-read.d.ts +87 -0
  56. package/dist/review-read.js +361 -0
  57. package/dist/review-read.js.map +1 -0
  58. package/dist/review-rows.d.ts +30 -0
  59. package/dist/review-rows.js +67 -0
  60. package/dist/review-rows.js.map +1 -0
  61. package/dist/review-types.d.ts +414 -0
  62. package/dist/review-types.js +2 -0
  63. package/dist/review-types.js.map +1 -0
  64. package/dist/review-write.d.ts +35 -0
  65. package/dist/review-write.js +86 -0
  66. package/dist/review-write.js.map +1 -0
  67. package/dist/review.d.ts +53 -0
  68. package/dist/review.fixtures.d.ts +47 -0
  69. package/dist/review.fixtures.js +145 -0
  70. package/dist/review.fixtures.js.map +1 -0
  71. package/dist/review.js +245 -0
  72. package/dist/review.js.map +1 -0
  73. package/dist/schema.d.ts +36 -0
  74. package/dist/schema.js +39 -0
  75. package/dist/schema.js.map +1 -0
  76. package/dist/store.d.ts +58 -0
  77. package/dist/store.js +278 -0
  78. package/dist/store.js.map +1 -0
  79. package/dist/testing.d.ts +38 -0
  80. package/dist/testing.js +92 -0
  81. package/dist/testing.js.map +1 -0
  82. package/dist/ui/__probe.d.ts +3 -0
  83. package/dist/ui/__probe.js +5 -0
  84. package/dist/ui/__probe.js.map +1 -0
  85. package/dist/ui/attribution.d.ts +46 -0
  86. package/dist/ui/attribution.js +79 -0
  87. package/dist/ui/attribution.js.map +1 -0
  88. package/dist/ui/because.d.ts +51 -0
  89. package/dist/ui/because.js +52 -0
  90. package/dist/ui/because.js.map +1 -0
  91. package/dist/ui/browser-entry.d.ts +2 -0
  92. package/dist/ui/browser-entry.js +34 -0
  93. package/dist/ui/browser-entry.js.map +1 -0
  94. package/dist/ui/builds.d.ts +43 -0
  95. package/dist/ui/builds.js +79 -0
  96. package/dist/ui/builds.js.map +1 -0
  97. package/dist/ui/carried.d.ts +73 -0
  98. package/dist/ui/carried.js +63 -0
  99. package/dist/ui/carried.js.map +1 -0
  100. package/dist/ui/cause.d.ts +73 -0
  101. package/dist/ui/cause.js +133 -0
  102. package/dist/ui/cause.js.map +1 -0
  103. package/dist/ui/change-story.d.ts +153 -0
  104. package/dist/ui/change-story.js +253 -0
  105. package/dist/ui/change-story.js.map +1 -0
  106. package/dist/ui/change.d.ts +51 -0
  107. package/dist/ui/change.js +125 -0
  108. package/dist/ui/change.js.map +1 -0
  109. package/dist/ui/client.d.ts +74 -0
  110. package/dist/ui/client.js +88 -0
  111. package/dist/ui/client.js.map +1 -0
  112. package/dist/ui/consumers.d.ts +80 -0
  113. package/dist/ui/consumers.js +125 -0
  114. package/dist/ui/consumers.js.map +1 -0
  115. package/dist/ui/control.d.ts +63 -0
  116. package/dist/ui/control.js +39 -0
  117. package/dist/ui/control.js.map +1 -0
  118. package/dist/ui/crossing.d.ts +55 -0
  119. package/dist/ui/crossing.js +74 -0
  120. package/dist/ui/crossing.js.map +1 -0
  121. package/dist/ui/declarations.d.ts +36 -0
  122. package/dist/ui/declarations.js +73 -0
  123. package/dist/ui/declarations.js.map +1 -0
  124. package/dist/ui/distance.d.ts +154 -0
  125. package/dist/ui/distance.js +180 -0
  126. package/dist/ui/distance.js.map +1 -0
  127. package/dist/ui/divergence.d.ts +40 -0
  128. package/dist/ui/divergence.js +176 -0
  129. package/dist/ui/divergence.js.map +1 -0
  130. package/dist/ui/docket.d.ts +39 -0
  131. package/dist/ui/docket.js +172 -0
  132. package/dist/ui/docket.js.map +1 -0
  133. package/dist/ui/findings.d.ts +42 -0
  134. package/dist/ui/findings.js +110 -0
  135. package/dist/ui/findings.js.map +1 -0
  136. package/dist/ui/foreseen.d.ts +55 -0
  137. package/dist/ui/foreseen.js +91 -0
  138. package/dist/ui/foreseen.js.map +1 -0
  139. package/dist/ui/glance.d.ts +101 -0
  140. package/dist/ui/glance.js +101 -0
  141. package/dist/ui/glance.js.map +1 -0
  142. package/dist/ui/grouping.d.ts +158 -0
  143. package/dist/ui/grouping.js +187 -0
  144. package/dist/ui/grouping.js.map +1 -0
  145. package/dist/ui/handed.d.ts +60 -0
  146. package/dist/ui/handed.js +122 -0
  147. package/dist/ui/handed.js.map +1 -0
  148. package/dist/ui/history.d.ts +88 -0
  149. package/dist/ui/history.js +170 -0
  150. package/dist/ui/history.js.map +1 -0
  151. package/dist/ui/holding.d.ts +84 -0
  152. package/dist/ui/holding.js +90 -0
  153. package/dist/ui/holding.js.map +1 -0
  154. package/dist/ui/impact.d.ts +31 -0
  155. package/dist/ui/impact.js +132 -0
  156. package/dist/ui/impact.js.map +1 -0
  157. package/dist/ui/index.d.ts +21 -0
  158. package/dist/ui/index.js +21 -0
  159. package/dist/ui/index.js.map +1 -0
  160. package/dist/ui/lead.d.ts +35 -0
  161. package/dist/ui/lead.js +34 -0
  162. package/dist/ui/lead.js.map +1 -0
  163. package/dist/ui/look.d.ts +109 -0
  164. package/dist/ui/look.js +248 -0
  165. package/dist/ui/look.js.map +1 -0
  166. package/dist/ui/mark.d.ts +11 -0
  167. package/dist/ui/mark.js +13 -0
  168. package/dist/ui/mark.js.map +1 -0
  169. package/dist/ui/moved.d.ts +121 -0
  170. package/dist/ui/moved.js +143 -0
  171. package/dist/ui/moved.js.map +1 -0
  172. package/dist/ui/navigation.d.ts +26 -0
  173. package/dist/ui/navigation.js +53 -0
  174. package/dist/ui/navigation.js.map +1 -0
  175. package/dist/ui/order.d.ts +113 -0
  176. package/dist/ui/order.js +226 -0
  177. package/dist/ui/order.js.map +1 -0
  178. package/dist/ui/origins.d.ts +42 -0
  179. package/dist/ui/origins.js +149 -0
  180. package/dist/ui/origins.js.map +1 -0
  181. package/dist/ui/outcome.d.ts +93 -0
  182. package/dist/ui/outcome.js +162 -0
  183. package/dist/ui/outcome.js.map +1 -0
  184. package/dist/ui/parted.d.ts +68 -0
  185. package/dist/ui/parted.js +101 -0
  186. package/dist/ui/parted.js.map +1 -0
  187. package/dist/ui/rail.d.ts +31 -0
  188. package/dist/ui/rail.js +21 -0
  189. package/dist/ui/rail.js.map +1 -0
  190. package/dist/ui/reach.d.ts +66 -0
  191. package/dist/ui/reach.js +185 -0
  192. package/dist/ui/reach.js.map +1 -0
  193. package/dist/ui/regions.d.ts +82 -0
  194. package/dist/ui/regions.js +67 -0
  195. package/dist/ui/regions.js.map +1 -0
  196. package/dist/ui/review.bundle.js +69 -0
  197. package/dist/ui/review.d.ts +97 -0
  198. package/dist/ui/review.js +39 -0
  199. package/dist/ui/review.js.map +1 -0
  200. package/dist/ui/root.d.ts +72 -0
  201. package/dist/ui/root.js +102 -0
  202. package/dist/ui/root.js.map +1 -0
  203. package/dist/ui/route.d.ts +95 -0
  204. package/dist/ui/route.js +114 -0
  205. package/dist/ui/route.js.map +1 -0
  206. package/dist/ui/run.d.ts +26 -0
  207. package/dist/ui/run.js +12 -0
  208. package/dist/ui/run.js.map +1 -0
  209. package/dist/ui/sense.d.ts +187 -0
  210. package/dist/ui/sense.js +222 -0
  211. package/dist/ui/sense.js.map +1 -0
  212. package/dist/ui/settled.d.ts +43 -0
  213. package/dist/ui/settled.js +59 -0
  214. package/dist/ui/settled.js.map +1 -0
  215. package/dist/ui/shell.d.ts +76 -0
  216. package/dist/ui/shell.js +65 -0
  217. package/dist/ui/shell.js.map +1 -0
  218. package/dist/ui/shift.d.ts +52 -0
  219. package/dist/ui/shift.js +98 -0
  220. package/dist/ui/shift.js.map +1 -0
  221. package/dist/ui/styles-docket.d.ts +18 -0
  222. package/dist/ui/styles-docket.js +281 -0
  223. package/dist/ui/styles-docket.js.map +1 -0
  224. package/dist/ui/styles-stage.d.ts +18 -0
  225. package/dist/ui/styles-stage.js +92 -0
  226. package/dist/ui/styles-stage.js.map +1 -0
  227. package/dist/ui/styles.d.ts +12 -0
  228. package/dist/ui/styles.js +482 -0
  229. package/dist/ui/styles.js.map +1 -0
  230. package/dist/ui/subject.d.ts +36 -0
  231. package/dist/ui/subject.js +138 -0
  232. package/dist/ui/subject.js.map +1 -0
  233. package/dist/ui/text.d.ts +129 -0
  234. package/dist/ui/text.js +164 -0
  235. package/dist/ui/text.js.map +1 -0
  236. package/dist/ui/variations.d.ts +37 -0
  237. package/dist/ui/variations.js +60 -0
  238. package/dist/ui/variations.js.map +1 -0
  239. package/dist/ui/viewer.d.ts +67 -0
  240. package/dist/ui/viewer.js +246 -0
  241. package/dist/ui/viewer.js.map +1 -0
  242. package/dist/worker-auth.d.ts +48 -0
  243. package/dist/worker-auth.js +74 -0
  244. package/dist/worker-auth.js.map +1 -0
  245. package/dist/worker-entry.d.ts +58 -0
  246. package/dist/worker-entry.js +36 -0
  247. package/dist/worker-entry.js.map +1 -0
  248. package/dist/worker-http.d.ts +39 -0
  249. package/dist/worker-http.js +111 -0
  250. package/dist/worker-http.js.map +1 -0
  251. package/dist/worker-input.d.ts +81 -0
  252. package/dist/worker-input.js +296 -0
  253. package/dist/worker-input.js.map +1 -0
  254. package/dist/worker.d.ts +91 -0
  255. package/dist/worker.js +287 -0
  256. package/dist/worker.js.map +1 -0
  257. package/mark.svg +30 -0
  258. package/migrations/0001_initial.sql +193 -0
  259. package/migrations/0002_changelog.sql +30 -0
  260. package/migrations/0003_accessibility.sql +8 -0
  261. package/migrations/0004_variations.sql +19 -0
  262. package/migrations/0005_reach.sql +26 -0
  263. package/migrations/0006_baseline-size.sql +7 -0
  264. package/migrations/0007_declarations.sql +7 -0
  265. package/migrations/0008_green-because.sql +7 -0
  266. package/migrations/0009_moved-bands.sql +6 -0
  267. package/migrations/0010_composition.sql +15 -0
  268. package/migrations/0011_movements.sql +21 -0
  269. package/migrations/0012_control-size.sql +6 -0
  270. package/package.json +110 -0
  271. package/wrangler.jsonc +45 -0
@@ -0,0 +1,67 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { number } from './text.js';
3
+ /**
4
+ * Region rectangles over the candidate, cause and collateral drawn apart.
5
+ *
6
+ * Positioned in percentages of the raster's own dimensions, which the build
7
+ * carries, rather than of the rendered element. Measuring the image in the
8
+ * browser would place every box correctly only after it had loaded, and wrongly
9
+ * for the frame before that — and a box in the wrong place is worse than no box,
10
+ * because it attributes a change to whatever it happens to land on.
11
+ *
12
+ * Percentages are also what survives the zoom: the stage scales the plate and
13
+ * every box scales with it, so nothing here has to know the magnification.
14
+ *
15
+ * Only the causes and whatever is under attention are named on the picture. Thirty
16
+ * collateral captions over a page fitted to a pane overlap into a grey field, and
17
+ * a reviewer who cannot read any of them is worse off than one reading two — so
18
+ * the rest carry their ordinal, which is the number they are listed under, and the
19
+ * sentence arrives on hover and in the table. Nothing is dropped: every region
20
+ * that was found is a box and a row, both of them always.
21
+ */
22
+ export function RegionOverlay({ subject, box, focus, onFocus, }) {
23
+ const size = box ?? subject.size;
24
+ if (size === undefined || subject.regions.length === 0)
25
+ return null;
26
+ return (_jsx("div", { className: "va-regions", children: subject.regions.map((region, index) => (_jsx("span", { className: [
27
+ 'va-region',
28
+ region.cause ? 'va-cause' : 'va-collateral',
29
+ focus === index ? 'va-lit' : '',
30
+ ]
31
+ .filter(Boolean)
32
+ .join(' '), onPointerEnter: () => onFocus?.(index), onPointerLeave: () => onFocus?.(null), style: {
33
+ left: `${String((region.x / size.width) * 100)}%`,
34
+ top: `${String((region.y / size.height) * 100)}%`,
35
+ width: `${String((region.width / size.width) * 100)}%`,
36
+ height: `${String((region.height / size.height) * 100)}%`,
37
+ }, children: _jsxs("span", { className: "va-region-label", children: [String(index + 1), region.cause || focus === index ? (_jsxs(_Fragment, { children: [' · ', region.component ?? 'unattributed', region.cause ? '' : ' (collateral)', region.where === undefined ? '' : ` — ${region.where}`] })) : null] }) }, key(region, index)))) }));
38
+ }
39
+ /**
40
+ * The same regions as rows, which is the half a picture cannot deliver.
41
+ *
42
+ * A rectangle says *here*. It cannot say `src/ui/Button.tsx:18`, and the file is
43
+ * the column that lets a reviewer hand the change to whoever owns it rather than
44
+ * deciding it themselves. Ordered as the report ordered them — causes first,
45
+ * never by area, which reports the container that reflowed instead of the
46
+ * component that was edited.
47
+ */
48
+ export function RegionTable({ subject, sourced, focus, onFocus, onJump, }) {
49
+ if (subject.regions.length === 0)
50
+ return null;
51
+ // A blank cell is the one answer this column must not give: the reviewer's next
52
+ // move is to open the file, and nothing-at-all reads as a defect in the tool
53
+ // when the ordinary cause is a component out of a dependency, which no source
54
+ // index scanned or claimed to.
55
+ const indexed = sourced ?? subject.regions.some((region) => region.file !== undefined);
56
+ return (_jsxs("table", { className: "va-region-table", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "region" }), _jsx("th", { children: "component" }), _jsx("th", { children: "declared in" }), _jsx("th", { className: "va-num-col", children: "pixels" })] }) }), _jsx("tbody", { children: subject.regions.map((region, index) => (_jsxs("tr", { className: focus === index ? 'va-lit' : undefined, onPointerEnter: () => onFocus(index), onPointerLeave: () => onFocus(null), children: [_jsx("td", { children: _jsxs("button", { type: "button", className: "va-region-jump", onClick: () => onJump(index), children: [_jsx("span", { className: region.cause ? 'va-dot va-cause' : 'va-dot va-collateral' }), String(index + 1), _jsxs("span", { className: "va-region-where", children: [region.cause ? 'cause' : 'collateral', region.where === undefined ? '' : ` · ${region.where}`] })] }) }), _jsx("td", { children: region.component ?? _jsx("span", { className: "va-note", children: "unattributed" }) }), _jsx("td", { children: region.file === undefined ? (_jsx("span", { className: "va-note", title: indexed
57
+ ? 'This run resolved files for other components, so this is a name its source index does not declare — a component out of a dependency, or one produced at build time.'
58
+ : 'This run resolved no source files at all, so nothing here says where any of these components are declared.', children: indexed ? 'not in the scanned source' : 'no source index' })) : (_jsx("code", { children: region.file })) }), _jsx("td", { className: "va-num va-num-col", children: number(region.pixels) })] }, key(region, index)))) })] }));
59
+ }
60
+ /**
61
+ * Position and ordinal, because two regions can be the same size in the same
62
+ * place across renders and nothing else here is unique.
63
+ */
64
+ function key(region, index) {
65
+ return `${String(region.x)}-${String(region.y)}-${String(index)}`;
66
+ }
67
+ //# sourceMappingURL=regions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regions.js","sourceRoot":"","sources":["../../src/ui/regions.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { ReactElement } from 'react';\nimport type { RegionRecord } from '@variance-authority/report';\nimport type { SubjectView } from '../review.js';\nimport { number } from './text.js';\n\n/**\n * The boxes, and the table that names them.\n *\n * Apart from [`viewer.tsx`](./viewer.tsx) because the stage is one question — how\n * do I look at two images — and this is the other: *which of these boxes is the\n * one somebody edited, and who owns it*. The two are drawn together and read\n * together, and a reviewer moves between them constantly, which is why the focus\n * is one index shared by both rather than a hover state in each.\n *\n * The row and the rectangle are the same finding twice. Pointing at either lights\n * the other, because a rectangle 700 pixels down a route capture and a row in a\n * table are otherwise two lists a reader has to join by counting.\n */\n\nexport interface RegionFocus {\n /** Which region is lit, by report order. `null` is none. */\n readonly focus: number | null;\n readonly onFocus: (index: number | null) => void;\n /** Bring this region into view on the stage. */\n readonly onJump: (index: number) => void;\n}\n\n/**\n * Region rectangles over the candidate, cause and collateral drawn apart.\n *\n * Positioned in percentages of the raster's own dimensions, which the build\n * carries, rather than of the rendered element. Measuring the image in the\n * browser would place every box correctly only after it had loaded, and wrongly\n * for the frame before that — and a box in the wrong place is worse than no box,\n * because it attributes a change to whatever it happens to land on.\n *\n * Percentages are also what survives the zoom: the stage scales the plate and\n * every box scales with it, so nothing here has to know the magnification.\n *\n * Only the causes and whatever is under attention are named on the picture. Thirty\n * collateral captions over a page fitted to a pane overlap into a grey field, and\n * a reviewer who cannot read any of them is worse off than one reading two — so\n * the rest carry their ordinal, which is the number they are listed under, and the\n * sentence arrives on hover and in the table. Nothing is dropped: every region\n * that was found is a box and a row, both of them always.\n */\nexport function RegionOverlay({\n subject,\n box,\n focus,\n onFocus,\n}: {\n readonly subject: SubjectView;\n /**\n * The frame the percentages are of, when it is not the candidate's own.\n *\n * Region coordinates are in the comparison's space, and a comparison pads to\n * the union of the two captures — so on a subject whose baseline was a\n * different size, the candidate's dimensions are the wrong denominator and\n * every box lands short by the difference.\n */\n readonly box?: { readonly width: number; readonly height: number } | undefined;\n readonly focus?: number | null;\n readonly onFocus?: ((index: number | null) => void) | undefined;\n}): ReactElement | null {\n const size = box ?? subject.size;\n if (size === undefined || subject.regions.length === 0) return null;\n\n return (\n <div className=\"va-regions\">\n {subject.regions.map((region, index) => (\n <span\n key={key(region, index)}\n className={[\n 'va-region',\n region.cause ? 'va-cause' : 'va-collateral',\n focus === index ? 'va-lit' : '',\n ]\n .filter(Boolean)\n .join(' ')}\n onPointerEnter={() => onFocus?.(index)}\n onPointerLeave={() => onFocus?.(null)}\n style={{\n left: `${String((region.x / size.width) * 100)}%`,\n top: `${String((region.y / size.height) * 100)}%`,\n width: `${String((region.width / size.width) * 100)}%`,\n height: `${String((region.height / size.height) * 100)}%`,\n }}\n >\n <span className=\"va-region-label\">\n {String(index + 1)}\n {region.cause || focus === index ? (\n <>\n {' · '}\n {region.component ?? 'unattributed'}\n {region.cause ? '' : ' (collateral)'}\n {region.where === undefined ? '' : ` — ${region.where}`}\n </>\n ) : null}\n </span>\n </span>\n ))}\n </div>\n );\n}\n\n/**\n * The same regions as rows, which is the half a picture cannot deliver.\n *\n * A rectangle says *here*. It cannot say `src/ui/Button.tsx:18`, and the file is\n * the column that lets a reviewer hand the change to whoever owns it rather than\n * deciding it themselves. Ordered as the report ordered them — causes first,\n * never by area, which reports the container that reflowed instead of the\n * component that was edited.\n */\nexport function RegionTable({\n subject,\n sourced,\n focus,\n onFocus,\n onJump,\n}: {\n readonly subject: SubjectView;\n /**\n * Whether the *run* resolved any source file at all.\n *\n * A property of the run's source index, not of one capture, and the caller who\n * holds the build is the only one who can say it. Left out, this falls back to\n * what one render can see on its own, which is strictly weaker: a capture whose\n * every region belongs to a dependency resolves nothing and would report a run\n * with no index — the same name then reads two ways on two surfaces, and a\n * reviewer takes one of them for a bug.\n */\n readonly sourced?: boolean | undefined;\n} & RegionFocus): ReactElement | null {\n if (subject.regions.length === 0) return null;\n\n // A blank cell is the one answer this column must not give: the reviewer's next\n // move is to open the file, and nothing-at-all reads as a defect in the tool\n // when the ordinary cause is a component out of a dependency, which no source\n // index scanned or claimed to.\n const indexed = sourced ?? subject.regions.some((region) => region.file !== undefined);\n\n return (\n <table className=\"va-region-table\">\n <thead>\n <tr>\n <th>region</th>\n <th>component</th>\n <th>declared in</th>\n <th className=\"va-num-col\">pixels</th>\n </tr>\n </thead>\n <tbody>\n {subject.regions.map((region, index) => (\n <tr\n key={key(region, index)}\n className={focus === index ? 'va-lit' : undefined}\n onPointerEnter={() => onFocus(index)}\n onPointerLeave={() => onFocus(null)}\n >\n <td>\n <button type=\"button\" className=\"va-region-jump\" onClick={() => onJump(index)}>\n <span className={region.cause ? 'va-dot va-cause' : 'va-dot va-collateral'} />\n {String(index + 1)}\n <span className=\"va-region-where\">\n {region.cause ? 'cause' : 'collateral'}\n {region.where === undefined ? '' : ` · ${region.where}`}\n </span>\n </button>\n </td>\n <td>{region.component ?? <span className=\"va-note\">unattributed</span>}</td>\n <td>\n {region.file === undefined ? (\n <span\n className=\"va-note\"\n title={\n indexed\n ? 'This run resolved files for other components, so this is a name its source index does not declare — a component out of a dependency, or one produced at build time.'\n : 'This run resolved no source files at all, so nothing here says where any of these components are declared.'\n }\n >\n {indexed ? 'not in the scanned source' : 'no source index'}\n </span>\n ) : (\n <code>{region.file}</code>\n )}\n </td>\n <td className=\"va-num va-num-col\">{number(region.pixels)}</td>\n </tr>\n ))}\n </tbody>\n </table>\n );\n}\n\n/**\n * Position and ordinal, because two regions can be the same size in the same\n * place across renders and nothing else here is unique.\n */\nfunction key(region: RegionRecord, index: number): string {\n return `${String(region.x)}-${String(region.y)}-${String(index)}`;\n}\n"]}