@delmaredigital/payload-experiments 0.2.0-rc.7 → 0.3.0-rc.4

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 (336) hide show
  1. package/README.md +202 -26
  2. package/dist/admin/PreviewLinks.d.ts +2 -1
  3. package/dist/admin/PreviewLinks.js +50 -21
  4. package/dist/admin/TestsNavLink.d.ts +3 -1
  5. package/dist/admin/TestsNavLink.js +2 -2
  6. package/dist/admin/actions/ConfirmDialog.d.ts +7 -4
  7. package/dist/admin/actions/ConfirmDialog.js +37 -82
  8. package/dist/admin/actions/DecideDialog.d.ts +3 -1
  9. package/dist/admin/actions/DecideDialog.js +30 -13
  10. package/dist/admin/actions/MakeContentResult.d.ts +13 -2
  11. package/dist/admin/actions/MakeContentResult.js +115 -16
  12. package/dist/admin/actions/actions.model.d.ts +2 -4
  13. package/dist/admin/actions/actions.model.js +2 -3
  14. package/dist/admin/allocation.model.js +3 -5
  15. package/dist/admin/api.d.ts +10 -4
  16. package/dist/admin/api.js +11 -7
  17. package/dist/admin/armSelect/ArmSelectField.js +14 -22
  18. package/dist/admin/arms/arms.model.d.ts +1 -21
  19. package/dist/admin/arms/arms.model.js +1 -153
  20. package/dist/admin/copy/actions.d.ts +39 -3
  21. package/dist/admin/copy/actions.js +40 -4
  22. package/dist/admin/copy/armSelect.js +5 -5
  23. package/dist/admin/copy/arms.d.ts +1 -6
  24. package/dist/admin/copy/arms.js +1 -16
  25. package/dist/admin/copy/audience.d.ts +2 -1
  26. package/dist/admin/copy/audience.js +3 -2
  27. package/dist/admin/copy/common.d.ts +13 -6
  28. package/dist/admin/copy/common.js +14 -8
  29. package/dist/admin/copy/goals.d.ts +21 -6
  30. package/dist/admin/copy/goals.js +27 -6
  31. package/dist/admin/copy/readiness.d.ts +22 -0
  32. package/dist/admin/copy/readiness.js +21 -0
  33. package/dist/admin/copy/recommendation.d.ts +0 -3
  34. package/dist/admin/copy/recommendation.js +0 -3
  35. package/dist/admin/copy/results.d.ts +43 -2
  36. package/dist/admin/copy/results.js +44 -3
  37. package/dist/admin/copy/review.d.ts +2 -2
  38. package/dist/admin/copy/review.js +2 -2
  39. package/dist/admin/copy/setting.d.ts +2 -0
  40. package/dist/admin/copy/setting.js +2 -0
  41. package/dist/admin/copy/surface.d.ts +7 -5
  42. package/dist/admin/copy/surface.js +9 -5
  43. package/dist/admin/copy/testPage.d.ts +10 -0
  44. package/dist/admin/copy/testPage.js +10 -0
  45. package/dist/admin/format/date.d.ts +2 -0
  46. package/dist/admin/format/date.js +10 -0
  47. package/dist/admin/paths.d.ts +2 -1
  48. package/dist/admin/paths.js +2 -1
  49. package/dist/admin/previewLinks.model.d.ts +4 -2
  50. package/dist/admin/previewLinks.model.js +8 -7
  51. package/dist/admin/results/CiChart.js +11 -21
  52. package/dist/admin/results/DataQualityPanel.d.ts +4 -2
  53. package/dist/admin/results/DataQualityPanel.js +30 -17
  54. package/dist/admin/results/DataTable.d.ts +16 -0
  55. package/dist/admin/results/DataTable.js +152 -0
  56. package/dist/admin/results/StatTile.d.ts +7 -0
  57. package/dist/admin/results/StatTile.js +22 -0
  58. package/dist/admin/results/VerdictHero.d.ts +13 -0
  59. package/dist/admin/results/{VerdictCard.js → VerdictHero.js} +15 -12
  60. package/dist/admin/results/legacy.d.ts +16 -0
  61. package/dist/admin/results/legacy.js +27 -0
  62. package/dist/admin/results/releasePages.model.d.ts +17 -0
  63. package/dist/admin/results/releasePages.model.js +10 -0
  64. package/dist/admin/results/results.css +64 -0
  65. package/dist/admin/results/results.model.d.ts +11 -7
  66. package/dist/admin/results/results.model.js +24 -7
  67. package/dist/admin/results/snapshot.d.ts +14 -0
  68. package/dist/admin/results/snapshot.js +3 -0
  69. package/dist/admin/surface/ResultsRoute.d.ts +1 -1
  70. package/dist/admin/surface/ResultsRoute.js +59 -34
  71. package/dist/admin/surface/SurfaceShell.d.ts +11 -2
  72. package/dist/admin/surface/SurfaceShell.js +49 -14
  73. package/dist/admin/surface/TestsHome.d.ts +6 -1
  74. package/dist/admin/surface/TestsHome.js +182 -114
  75. package/dist/admin/surface/TestsSurface.js +56 -16
  76. package/dist/admin/surface/goals/GoalForm.js +341 -308
  77. package/dist/admin/surface/goals/GoalsList.js +123 -89
  78. package/dist/admin/surface/goals/data.d.ts +8 -2
  79. package/dist/admin/surface/goals/data.js +24 -16
  80. package/dist/admin/surface/goals/goals.css +10 -13
  81. package/dist/admin/surface/home.model.d.ts +8 -8
  82. package/dist/admin/surface/home.model.js +23 -12
  83. package/dist/admin/surface/newTest/NewTest.js +9 -9
  84. package/dist/admin/surface/pageBlock/parts.js +31 -26
  85. package/dist/admin/surface/readiness/ActionDialogs.js +47 -19
  86. package/dist/admin/surface/readiness/Banner.d.ts +3 -0
  87. package/dist/admin/surface/readiness/Banner.js +58 -33
  88. package/dist/admin/surface/readiness/SaveStatus.d.ts +1 -0
  89. package/dist/admin/surface/readiness/SaveStatus.js +6 -3
  90. package/dist/admin/surface/readiness/readiness.model.d.ts +2 -0
  91. package/dist/admin/surface/readiness/readiness.model.js +25 -9
  92. package/dist/admin/surface/readiness/useTransition.d.ts +1 -0
  93. package/dist/admin/surface/readiness/useTransition.js +2 -1
  94. package/dist/admin/surface/results/ReleasePages.d.ts +14 -0
  95. package/dist/admin/surface/results/ReleasePages.js +116 -0
  96. package/dist/admin/surface/results/ResultsBody.d.ts +11 -1
  97. package/dist/admin/surface/results/ResultsBody.js +277 -105
  98. package/dist/admin/surface/results/ResultsHeader.d.ts +10 -0
  99. package/dist/admin/surface/results/ResultsHeader.js +177 -0
  100. package/dist/admin/surface/results/recommendation.model.d.ts +3 -2
  101. package/dist/admin/surface/results/recommendation.model.js +12 -9
  102. package/dist/admin/surface/results/useResults.d.ts +21 -3
  103. package/dist/admin/surface/results/useResults.js +2 -1
  104. package/dist/admin/surface/setting/parts.js +75 -88
  105. package/dist/admin/surface/setting/setting.css +3 -15
  106. package/dist/admin/surface/surface.css +61 -47
  107. package/dist/admin/surface/test/AdvancedSection.js +55 -48
  108. package/dist/admin/surface/test/GoalSection.js +46 -47
  109. package/dist/admin/surface/test/LengthSection.js +46 -34
  110. package/dist/admin/surface/test/Rail.d.ts +4 -0
  111. package/dist/admin/surface/test/Rail.js +83 -0
  112. package/dist/admin/surface/test/ReadinessBar.d.ts +5 -0
  113. package/dist/admin/surface/test/ReadinessBar.js +33 -0
  114. package/dist/admin/surface/test/Section.d.ts +1 -1
  115. package/dist/admin/surface/test/Section.js +36 -16
  116. package/dist/admin/surface/test/TargetingSection.js +168 -142
  117. package/dist/admin/surface/test/TestPage.d.ts +2 -1
  118. package/dist/admin/surface/test/TestPage.js +146 -68
  119. package/dist/admin/surface/test/VersionsSection.js +151 -120
  120. package/dist/admin/surface/test/fields.d.ts +11 -4
  121. package/dist/admin/surface/test/fields.js +84 -85
  122. package/dist/admin/surface/test/jumpToSection.d.ts +3 -0
  123. package/dist/admin/surface/test/jumpToSection.js +10 -0
  124. package/dist/admin/surface/test/pageParts.js +9 -3
  125. package/dist/admin/surface/test/testPage.css +81 -14
  126. package/dist/admin/surface/test/testPage.model.d.ts +2 -3
  127. package/dist/admin/surface/test/testPage.model.js +1 -21
  128. package/dist/admin/surface/useTestDocument.js +12 -5
  129. package/dist/admin/targeting/targeting.model.d.ts +1 -3
  130. package/dist/admin/targeting/targeting.model.js +3 -8
  131. package/dist/admin/theme.css +115 -36
  132. package/dist/admin/theme.d.ts +38 -0
  133. package/dist/admin/theme.js +38 -1
  134. package/dist/admin/useApi.d.ts +17 -2
  135. package/dist/admin/useLayerUsage.js +14 -23
  136. package/dist/admin/views/ExperimentsRootView.js +12 -2
  137. package/dist/admin/views/TestsNavLinkServer.d.ts +2 -0
  138. package/dist/admin/views/TestsNavLinkServer.js +43 -0
  139. package/dist/arms/copy.d.ts +6 -0
  140. package/dist/arms/copy.js +16 -0
  141. package/dist/arms/model.d.ts +23 -0
  142. package/dist/arms/model.js +173 -0
  143. package/dist/collections/experiments/config.js +25 -0
  144. package/dist/collections/experiments/lockHook.js +3 -1
  145. package/dist/collections/identities.js +6 -1
  146. package/dist/collections/metrics.js +7 -0
  147. package/dist/collections/metricsGuards.d.ts +9 -0
  148. package/dist/collections/metricsGuards.js +33 -0
  149. package/dist/contentDone.d.ts +4 -0
  150. package/dist/contentDone.js +5 -0
  151. package/dist/db/appends.d.ts +6 -2
  152. package/dist/db/appends.js +10 -4
  153. package/dist/db/identities.d.ts +8 -7
  154. package/dist/db/identities.js +9 -6
  155. package/dist/db/locks.d.ts +6 -0
  156. package/dist/db/locks.js +13 -1
  157. package/dist/db/metricUsage.d.ts +19 -0
  158. package/dist/db/metricUsage.js +54 -0
  159. package/dist/db/names.d.ts +5 -0
  160. package/dist/db/names.js +5 -0
  161. package/dist/db/pageOccupancy.d.ts +12 -0
  162. package/dist/db/pageOccupancy.js +45 -0
  163. package/dist/db/publishedContent.d.ts +10 -0
  164. package/dist/db/publishedContent.js +43 -0
  165. package/dist/db/results.d.ts +2 -0
  166. package/dist/db/results.js +6 -2
  167. package/dist/db/snapshots.d.ts +18 -6
  168. package/dist/db/snapshots.js +25 -8
  169. package/dist/db/sweep.js +11 -6
  170. package/dist/endpoints/index.js +19 -1
  171. package/dist/endpoints/results.js +5 -0
  172. package/dist/endpoints/sanitizeReadinessDetail.d.ts +1 -0
  173. package/dist/endpoints/sanitizeReadinessDetail.js +2 -0
  174. package/dist/endpoints/summary.js +20 -2
  175. package/dist/endpoints/transitions.d.ts +15 -0
  176. package/dist/endpoints/transitions.js +36 -0
  177. package/dist/errors.d.ts +8 -0
  178. package/dist/errors.js +28 -0
  179. package/dist/exports/adminRsc.d.ts +1 -0
  180. package/dist/exports/adminRsc.js +1 -0
  181. package/dist/exports/index.d.ts +2 -1
  182. package/dist/exports/index.js +1 -0
  183. package/dist/exports/puck.d.ts +2 -1
  184. package/dist/exports/puck.js +1 -1
  185. package/dist/exports/puckEditor.d.ts +4 -1
  186. package/dist/exports/puckEditor.js +3 -1
  187. package/dist/exports/rsc.d.ts +6 -1
  188. package/dist/exports/rsc.js +2 -0
  189. package/dist/hooks/pageGuard.d.ts +5 -0
  190. package/dist/hooks/pageGuard.js +139 -0
  191. package/dist/lib/fetchAllDocs.d.ts +16 -0
  192. package/dist/lib/fetchAllDocs.js +56 -0
  193. package/dist/log.js +6 -3
  194. package/dist/manifest/compile.d.ts +5 -0
  195. package/dist/manifest/compile.js +5 -1
  196. package/dist/options.js +16 -0
  197. package/dist/plugin.js +30 -2
  198. package/dist/puck/ExperimentPicker.js +47 -16
  199. package/dist/puck/ExperimentSlot.d.ts +51 -1
  200. package/dist/puck/ExperimentSlot.js +23 -12
  201. package/dist/puck/copy.d.ts +6 -5
  202. package/dist/puck/copy.js +6 -5
  203. package/dist/puck/editor/CreateExperimentDrawer.js +46 -56
  204. package/dist/puck/editor/ExperimentSlotEditor.d.ts +52 -1
  205. package/dist/puck/editor/ExperimentSlotEditor.js +292 -137
  206. package/dist/puck/editor/ResultsReadout.d.ts +6 -0
  207. package/dist/puck/editor/ResultsReadout.js +99 -0
  208. package/dist/puck/editor/VersionBuilder.d.ts +34 -0
  209. package/dist/puck/editor/VersionBuilder.js +317 -0
  210. package/dist/puck/editor/armWrites.d.ts +7 -0
  211. package/dist/puck/editor/armWrites.js +71 -0
  212. package/dist/puck/editor/armsCache.d.ts +14 -0
  213. package/dist/puck/editor/armsCache.js +78 -0
  214. package/dist/puck/editor/copy.d.ts +33 -1
  215. package/dist/puck/editor/copy.js +45 -8
  216. package/dist/puck/editor/createTest.d.ts +1 -1
  217. package/dist/puck/editor/createTest.js +25 -14
  218. package/dist/puck/editor/editor.chrome.css +121 -0
  219. package/dist/puck/editor/editor.css +288 -204
  220. package/dist/puck/editor/editor.model.d.ts +4 -1
  221. package/dist/puck/editor/editor.model.js +10 -7
  222. package/dist/puck/editor/experimentOutlinePlugin.d.ts +3 -0
  223. package/dist/puck/editor/experimentOutlinePlugin.js +89 -0
  224. package/dist/puck/experimentSlotField.d.ts +2 -0
  225. package/dist/puck/experimentSlotField.js +11 -3
  226. package/dist/puck/hostContext.d.ts +10 -0
  227. package/dist/puck/hostContext.js +12 -0
  228. package/dist/puck/routes.d.ts +12 -0
  229. package/dist/puck/routes.js +11 -0
  230. package/dist/puck/slotConfig.d.ts +1 -1
  231. package/dist/puck/slotConfig.js +2 -2
  232. package/dist/results/aggregate.js +4 -3
  233. package/dist/results/analyse.d.ts +4 -1
  234. package/dist/results/analyse.js +27 -11
  235. package/dist/results/cuped.js +3 -2
  236. package/dist/results/identityCredit.d.ts +15 -7
  237. package/dist/results/identityCredit.js +32 -33
  238. package/dist/results/rolloutUnits.js +2 -1
  239. package/dist/results/snapshot.js +8 -2
  240. package/dist/results/srm.js +2 -1
  241. package/dist/sanitizeReadinessDetail.d.ts +7 -0
  242. package/dist/sanitizeReadinessDetail.js +63 -0
  243. package/dist/server/linkIdentity.d.ts +10 -1
  244. package/dist/server/linkIdentity.js +17 -15
  245. package/dist/server/metadata.d.ts +5 -0
  246. package/dist/server/metadata.js +18 -3
  247. package/dist/server/normaliseContentRelationships.d.ts +7 -0
  248. package/dist/server/normaliseContentRelationships.js +62 -0
  249. package/dist/server/recordContentChange.d.ts +1 -1
  250. package/dist/server/recordContentChange.js +17 -8
  251. package/dist/server/runResults.d.ts +3 -2
  252. package/dist/server/runResults.js +157 -35
  253. package/dist/targeting/values.d.ts +4 -0
  254. package/dist/targeting/values.js +10 -0
  255. package/dist/transitions/addMetric.js +8 -0
  256. package/dist/transitions/archive.js +2 -3
  257. package/dist/transitions/checkStart.d.ts +10 -3
  258. package/dist/transitions/checkStart.js +25 -0
  259. package/dist/transitions/contentFields.d.ts +7 -0
  260. package/dist/transitions/contentFields.js +20 -0
  261. package/dist/transitions/decide.js +22 -2
  262. package/dist/transitions/dismissContentEntry.d.ts +8 -0
  263. package/dist/transitions/dismissContentEntry.js +45 -0
  264. package/dist/transitions/makeContent.d.ts +5 -2
  265. package/dist/transitions/makeContent.js +217 -118
  266. package/dist/transitions/phaseRecord.d.ts +8 -2
  267. package/dist/transitions/placements.d.ts +3 -6
  268. package/dist/transitions/placements.js +12 -1
  269. package/dist/transitions/preflightData.d.ts +9 -1
  270. package/dist/transitions/preflightData.js +138 -20
  271. package/dist/transitions/releasePages.d.ts +8 -0
  272. package/dist/transitions/releasePages.js +26 -0
  273. package/dist/transitions/restoreContentEntry.d.ts +8 -0
  274. package/dist/transitions/restoreContentEntry.js +47 -0
  275. package/dist/transitions/start.js +62 -7
  276. package/dist/types/contracts.d.ts +24 -4
  277. package/dist/types/endpoints.d.ts +34 -3
  278. package/dist/types/index.d.ts +1 -0
  279. package/dist/types/index.js +1 -0
  280. package/dist/types/reasons.d.ts +3 -0
  281. package/dist/types/reasons.js +1 -0
  282. package/dist/types/snapshot.d.ts +6 -1
  283. package/dist/ui/Banner.d.ts +2 -0
  284. package/dist/ui/Banner.js +2 -0
  285. package/dist/ui/Breadcrumb.d.ts +7 -0
  286. package/dist/ui/Breadcrumb.js +25 -0
  287. package/dist/ui/Button.d.ts +15 -0
  288. package/dist/ui/Button.js +32 -0
  289. package/dist/ui/Card.d.ts +12 -0
  290. package/dist/ui/Card.js +40 -0
  291. package/dist/ui/Checkbox.d.ts +2 -0
  292. package/dist/ui/Checkbox.js +2 -0
  293. package/dist/{admin/components → ui}/ChipsInput.d.ts +4 -3
  294. package/dist/{admin/components → ui}/ChipsInput.js +20 -12
  295. package/dist/ui/Dialog.d.ts +13 -0
  296. package/dist/ui/Dialog.js +85 -0
  297. package/dist/ui/EmptyState.d.ts +2 -0
  298. package/dist/ui/EmptyState.js +2 -0
  299. package/dist/ui/Feedback.d.ts +24 -0
  300. package/dist/ui/Feedback.js +40 -0
  301. package/dist/ui/Inputs.d.ts +34 -0
  302. package/dist/ui/Inputs.js +225 -0
  303. package/dist/ui/NumberInput.d.ts +2 -0
  304. package/dist/ui/NumberInput.js +2 -0
  305. package/dist/ui/Range.d.ts +2 -0
  306. package/dist/ui/Range.js +2 -0
  307. package/dist/ui/SearchInput.d.ts +2 -0
  308. package/dist/ui/SearchInput.js +2 -0
  309. package/dist/ui/SectionCard.d.ts +2 -0
  310. package/dist/ui/SectionCard.js +2 -0
  311. package/dist/ui/Select.d.ts +2 -0
  312. package/dist/ui/Select.js +2 -0
  313. package/dist/ui/StatusChip.d.ts +2 -0
  314. package/dist/ui/StatusChip.js +2 -0
  315. package/dist/ui/Tabs.d.ts +16 -0
  316. package/dist/ui/Tabs.js +61 -0
  317. package/dist/ui/TextInput.d.ts +2 -0
  318. package/dist/ui/TextInput.js +2 -0
  319. package/dist/ui/Textarea.d.ts +2 -0
  320. package/dist/ui/Textarea.js +2 -0
  321. package/dist/ui/Toggle.d.ts +2 -0
  322. package/dist/ui/Toggle.js +2 -0
  323. package/dist/ui/accent.d.ts +40 -0
  324. package/dist/ui/accent.js +139 -0
  325. package/dist/ui/index.d.ts +9 -0
  326. package/dist/ui/index.js +9 -0
  327. package/dist/ui/ui.css +92 -0
  328. package/package.json +5 -2
  329. package/dist/admin/components/chipsInput.css +0 -11
  330. package/dist/admin/results/ArmTable.d.ts +0 -8
  331. package/dist/admin/results/ArmTable.js +0 -113
  332. package/dist/admin/results/VerdictCard.d.ts +0 -9
  333. package/dist/admin/surface/goals/GoalsBreadcrumb.d.ts +0 -5
  334. package/dist/admin/surface/goals/GoalsBreadcrumb.js +0 -47
  335. package/dist/admin/surface/test/TestHeader.d.ts +0 -4
  336. package/dist/admin/surface/test/TestHeader.js +0 -70
@@ -1,50 +1,64 @@
1
- .xp-tests-surface {
2
- min-height: 100dvh;
3
- width: 100%;
4
- color: var(--xp-text);
5
- background: var(--xp-bg);
1
+ /* Full-screen shell shared by every Tests surface. */
2
+ .xp-tests-surface { min-height: 100dvh; width: 100%; color: var(--xp-text); background: var(--xp-bg); font: var(--xp-text-body); }
3
+ .xp-tests-surface a:not(.xp-ui-button) { color: var(--xp-text); }
4
+ .xp-tests-surface a:not(.xp-ui-button):hover { text-decoration: underline; text-underline-offset: 3px; }
5
+ .xp-tests-container { box-sizing: border-box; width: 100%; max-width: 1120px; margin-inline: auto; padding-inline: var(--xp-space-8); }
6
+ .xp-tests-shell-header { background: var(--xp-surface); border-bottom: 1px solid var(--xp-border); }
7
+ .xp-tests-shell-top { display: flex; align-items: center; justify-content: space-between; gap: var(--xp-space-4); min-height: 48px; }
8
+ .xp-tests-shell-top .xp-ui-breadcrumb { min-width: 0; overflow-wrap: anywhere; }
9
+ .xp-tests-shell-top > .xp-ui-button { flex-shrink: 0; }
10
+ .xp-tests-shell-main { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--xp-space-6); padding-top: var(--xp-space-3); padding-bottom: var(--xp-space-6); }
11
+ .xp-tests-shell-title { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; min-width: 0; overflow-wrap: anywhere; }
12
+ .xp-tests-shell-title h1 { margin: 0; font: var(--xp-text-display); letter-spacing: -0.01em; }
13
+ .xp-tests-shell-actions { display: flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: var(--xp-space-2); min-width: 0; }
14
+ .xp-tests-main { padding-block: var(--xp-space-8) 48px; }
15
+ .xp-tests-search { position: relative; width: 260px; max-width: 100%; }
16
+ .xp-tests-search label { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
17
+ .xp-tests-search svg { position: absolute; top: 10px; left: 10px; width: 16px; height: 16px; color: var(--xp-text-3); pointer-events: none; }
18
+ .xp-tests-search input { padding-left: var(--xp-space-8); }
19
+ .xp-tests-group { margin-top: var(--xp-space-8); }
20
+ .xp-tests-group:first-child { margin-top: 0; }
21
+ .xp-tests-group-head { display: flex; align-items: baseline; gap: var(--xp-space-2); padding-inline: 2px; margin-bottom: 10px; }
22
+ .xp-tests-group-head h2, h2.xp-tests-group-head { margin: 0; font: 600 15px/22px var(--xp-font); }
23
+ .xp-tests-group-head > span { color: var(--xp-text-3); font: var(--xp-text-small); font-variant-numeric: tabular-nums; }
24
+ .xp-tests-list { border: 1px solid var(--xp-border); border-radius: var(--xp-radius-card); background: var(--xp-surface); }
25
+ .xp-tests-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: var(--xp-space-2) var(--xp-space-6); padding: var(--xp-space-4) var(--xp-space-5); }
26
+ .xp-tests-row + .xp-tests-row { border-top: 1px solid var(--xp-border); }
27
+ .xp-tests-row-main { min-width: 0; overflow-wrap: anywhere; }
28
+ .xp-tests-row-name { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; }
29
+ .xp-tests-row-name > a { color: var(--xp-text); font: 500 15px/22px var(--xp-font); text-decoration: none; border-radius: var(--xp-radius-chip); }
30
+ .xp-tests-row-name > a:hover { text-decoration: underline; text-underline-offset: 3px; }
31
+ .xp-tests-row-name > a:focus-visible, .xp-tests-group > summary:focus-visible { outline: 2px solid var(--xp-focus); outline-offset: 2px; }
32
+ .xp-tests-kind { display: inline-flex; align-items: center; height: 22px; padding-inline: var(--xp-space-2); border: 1px solid var(--xp-border); border-radius: var(--xp-radius-chip); color: var(--xp-text-2); font: 500 12px/18px var(--xp-font); white-space: nowrap; }
33
+ .xp-tests-row-line { display: flex; flex-wrap: wrap; align-items: center; gap: var(--xp-space-1) 14px; margin-top: var(--xp-space-1); color: var(--xp-text-2); font: 400 14px/20px var(--xp-font); }
34
+ .xp-tests-row-action { justify-self: end; }
35
+ .xp-tests-health { display: inline-flex; align-items: center; gap: 7px; font: 500 13px/18px var(--xp-font); }
36
+ .xp-tests-health::before { content: ''; width: var(--xp-space-2); height: var(--xp-space-2); border-radius: 50%; flex: none; }
37
+ .xp-tests-health--red::before { background: var(--xp-error); }
38
+ .xp-tests-health--amber::before { background: var(--xp-warning); }
39
+ .xp-tests-health--green::before { background: var(--xp-success); }
40
+ .xp-tests-group > summary { display: inline-flex; align-items: baseline; gap: var(--xp-space-2); cursor: pointer; list-style: none; border-radius: var(--xp-radius-chip); }
41
+ .xp-tests-group > summary::-webkit-details-marker { display: none; }
42
+ .xp-tests-group > summary .xp-tests-group-head { margin-bottom: 0; }
43
+ .xp-tests-group-chevron { align-self: center; color: var(--xp-text-3); }
44
+ .xp-tests-group[open] .xp-tests-group-chevron { transform: rotate(90deg); }
45
+ .xp-tests-group > summary + .xp-tests-list { margin-top: 10px; }
46
+ .xp-tests-no-matches { display: flex; flex-wrap: wrap; align-items: center; gap: var(--xp-space-2); }
47
+ .xp-tests-no-matches p { margin: 0; }
48
+ @media (max-width: 720px) {
49
+ .xp-tests-container { padding-inline: var(--xp-space-4); }
50
+ .xp-tests-shell-main { flex-direction: column; align-items: stretch; gap: var(--xp-space-4); }
51
+ .xp-tests-shell-actions { justify-content: flex-start; }
52
+ .xp-tests-search { width: 100%; }
53
+ .xp-tests-row { grid-template-columns: minmax(0, 1fr); }
54
+ .xp-tests-row-action { justify-self: start; }
6
55
  }
7
- .xp-tests-shell-header {
8
- display: flex;
9
- align-items: center;
10
- gap: var(--xp-space-4);
11
- padding: var(--xp-space-5) var(--xp-space-6);
12
- border-bottom: 1px solid var(--xp-border);
13
- }
14
- .xp-tests-main { padding: var(--xp-space-6); }
15
- .xp-tests-surface a { color: var(--xp-text); }
16
- .xp-tests-toolbar, .xp-tests-card-heading {
17
- display: flex;
18
- flex-wrap: wrap;
19
- align-items: center;
20
- gap: var(--xp-space-4);
21
- }
22
- .xp-tests-toolbar { margin-bottom: var(--xp-space-6); }
56
+ /* Existing screens retain their controls until their design-system lanes. */
57
+ .xp-tests-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--xp-space-4); margin-bottom: var(--xp-space-6); }
23
58
  .xp-tests-toolbar h1 { margin: 0; margin-right: auto; }
24
59
  .xp-tests-toolbar label { display: grid; gap: var(--xp-space-1); }
25
- .xp-tests-toolbar input, .xp-tests-surface button {
26
- color: var(--xp-text);
27
- background: var(--xp-input-bg);
28
- border: 1px solid var(--xp-input-border);
29
- border-radius: var(--xp-radius);
30
- padding: var(--xp-space-2);
31
- }
32
- .xp-tests-primary {
33
- padding: var(--xp-space-2) var(--xp-space-4);
34
- border: 1px solid var(--xp-accent);
35
- border-radius: var(--xp-radius);
36
- }
37
- .xp-tests-group { margin-bottom: var(--xp-space-6); }
38
- .xp-tests-group summary { cursor: pointer; padding: var(--xp-space-4) 0; }
39
- .xp-tests-cards { display: grid; gap: var(--xp-space-4); }
40
- .xp-tests-card {
41
- border: 1px solid var(--xp-border);
42
- border-radius: var(--xp-radius-large);
43
- padding: var(--xp-space-5);
44
- background: var(--xp-surface);
45
- }
46
- .xp-tests-card h3 { margin: 0; margin-right: auto; }
47
- .xp-tests-health { width: var(--xp-space-2); height: var(--xp-space-2); border-radius: 50%; }
48
- .xp-tests-health--red { background: var(--xp-error); }
49
- .xp-tests-health--amber { background: var(--xp-warning); }
50
- .xp-tests-health--green { background: var(--xp-success); }
60
+ .xp-tests-toolbar input, .xp-tests-toolbar button:not(.xp-ui-button) { color: var(--xp-text); background: var(--xp-input-bg); border: 1px solid var(--xp-input-border); border-radius: var(--xp-radius); padding: var(--xp-space-2); }
61
+ .xp-tests-primary { color: var(--xp-text); padding: var(--xp-space-2) var(--xp-space-4); border: 1px solid var(--xp-accent); border-radius: var(--xp-radius); }
62
+ .xp-tests-shell-heading { min-width: 0; }
63
+ .xp-tests-shell-subtitle { margin-top: var(--xp-space-2); color: var(--xp-text-2); font: var(--xp-text-small); }
64
+ .xp-tests-shell-subtitle p { margin: 0; }
@@ -1,6 +1,5 @@
1
1
  'use client';
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { TEST_PAGE } from '../../copy/testPage.js';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
3
  import { ADVANCED_COPY as C } from '../../copy/advanced.js';
5
4
  import { exposureOptions } from './testPage.model.js';
6
5
  import { FieldErrors, positiveInteger, ReadOnly, reasonFor, save, SelectEdit, TextEdit } from './fields.js';
@@ -40,31 +39,33 @@ export function AdvancedSection({ test, surface }) {
40
39
  return /*#__PURE__*/ _jsx(Section, {
41
40
  test: test,
42
41
  sectionId: "advanced",
43
- children: /*#__PURE__*/ _jsxs("details", {
42
+ children: /*#__PURE__*/ _jsxs("div", {
43
+ className: "xp-field-grid",
44
44
  children: [
45
- /*#__PURE__*/ _jsx("summary", {
46
- children: TEST_PAGE.sections.advanced
47
- }),
48
- /*#__PURE__*/ _jsx(SelectEdit, {
49
- label: C.exposurePolicy.label,
50
- value: doc.exposurePolicy,
51
- reason: reasonFor(test, 'exposurePolicy'),
52
- options: exposureOptions(doc.kind).map((value)=>({
53
- value,
54
- label: C.policies[value]
55
- })),
56
- onCommit: (value)=>save(test, 'exposurePolicy', ()=>({
57
- exposurePolicy: value
58
- }))
59
- }),
60
- /*#__PURE__*/ _jsx("p", {
61
- children: C.exposurePolicy.help
62
- }),
63
- /*#__PURE__*/ _jsx(FieldErrors, {
64
- test: test,
65
- path: "exposurePolicy"
45
+ /*#__PURE__*/ _jsxs("div", {
46
+ children: [
47
+ /*#__PURE__*/ _jsx(SelectEdit, {
48
+ label: C.exposurePolicy.label,
49
+ value: doc.exposurePolicy,
50
+ reason: reasonFor(test, 'exposurePolicy'),
51
+ options: exposureOptions(doc.kind).map((value)=>({
52
+ value,
53
+ label: C.policies[value]
54
+ })),
55
+ onCommit: (value)=>save(test, 'exposurePolicy', ()=>({
56
+ exposurePolicy: value
57
+ }))
58
+ }),
59
+ /*#__PURE__*/ _jsx("p", {
60
+ children: C.exposurePolicy.help
61
+ }),
62
+ /*#__PURE__*/ _jsx(FieldErrors, {
63
+ test: test,
64
+ path: "exposurePolicy"
65
+ })
66
+ ]
66
67
  }),
67
- surface.isAdmin ? /*#__PURE__*/ _jsxs(_Fragment, {
68
+ surface.isAdmin ? /*#__PURE__*/ _jsxs("div", {
68
69
  children: [
69
70
  /*#__PURE__*/ _jsx(SelectEdit, {
70
71
  label: C.method.label,
@@ -91,28 +92,32 @@ export function AdvancedSection({ test, surface }) {
91
92
  })
92
93
  ]
93
94
  }) : null,
94
- /*#__PURE__*/ _jsx(SelectEdit, {
95
- label: C.cuped.label,
96
- value: doc.analysis?.cuped ?? 'auto',
97
- reason: reason,
98
- options: [
99
- {
100
- value: 'auto',
101
- label: C.auto
102
- },
103
- {
104
- value: 'off',
105
- label: C.off
106
- }
107
- ],
108
- onCommit: (value)=>change('cuped', value)
109
- }),
110
- /*#__PURE__*/ _jsx("p", {
111
- children: C.cuped.help
112
- }),
113
- /*#__PURE__*/ _jsx(FieldErrors, {
114
- test: test,
115
- path: "analysis.cuped"
95
+ /*#__PURE__*/ _jsxs("div", {
96
+ children: [
97
+ /*#__PURE__*/ _jsx(SelectEdit, {
98
+ label: C.cuped.label,
99
+ value: doc.analysis?.cuped ?? 'auto',
100
+ reason: reason,
101
+ options: [
102
+ {
103
+ value: 'auto',
104
+ label: C.auto
105
+ },
106
+ {
107
+ value: 'off',
108
+ label: C.off
109
+ }
110
+ ],
111
+ onCommit: (value)=>change('cuped', value)
112
+ }),
113
+ /*#__PURE__*/ _jsx("p", {
114
+ children: C.cuped.help
115
+ }),
116
+ /*#__PURE__*/ _jsx(FieldErrors, {
117
+ test: test,
118
+ path: "analysis.cuped"
119
+ })
120
+ ]
116
121
  }),
117
122
  numbers.map(([field, fallback, min])=>/*#__PURE__*/ _jsxs("div", {
118
123
  children: [
@@ -139,7 +144,9 @@ export function AdvancedSection({ test, surface }) {
139
144
  children: [
140
145
  /*#__PURE__*/ _jsx(ReadOnly, {
141
146
  label: C[field].label,
142
- value: typeof doc[field] === 'string' || typeof doc[field] === 'number' ? String(doc[field]) : C.none,
147
+ value: field === 'slug' ? /*#__PURE__*/ _jsx("code", {
148
+ children: String(doc.slug)
149
+ }) : typeof doc[field] === 'string' || typeof doc[field] === 'number' ? String(doc[field]) : C.none,
143
150
  reason: reasonFor(test, field)
144
151
  }),
145
152
  /*#__PURE__*/ _jsx("p", {
@@ -1,15 +1,16 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { fetchAllDocs } from '../../../lib/fetchAllDocs.js';
4
+ import { Button } from '../../../ui/Button.js';
3
5
  import { useEffect, useState } from 'react';
4
6
  import { formatAdminURL } from 'payload/shared';
5
7
  import { TEST_PAGE as C } from '../../copy/testPage.js';
6
8
  import { metricSourceOptions } from '../../metricSource.model.js';
7
9
  import { reviewView } from '../../review/review.model.js';
8
- import { CheckboxList, FieldErrors, reasonFor, save, SelectEdit, TextEdit } from './fields.js';
10
+ import { CheckboxList, FieldErrors, reasonFor, save, SelectEdit } from './fields.js';
9
11
  import { Section } from './Section.js';
10
12
  export function GoalSection({ test, surface }) {
11
13
  const [metrics, setMetrics] = useState([]);
12
- const [query, setQuery] = useState('');
13
14
  const [failed, setFailed] = useState(false);
14
15
  const [loaded, setLoaded] = useState(false);
15
16
  const [attempt, setAttempt] = useState(0);
@@ -17,22 +18,15 @@ export function GoalSection({ test, surface }) {
17
18
  const controller = new AbortController();
18
19
  void (async ()=>{
19
20
  try {
20
- const all = [];
21
- let page = 1;
22
- for(;;){
23
- const response = await fetch(`${surface.apiRoute.replace(/\/$/, '')}/xp-metrics?depth=0&limit=100&page=${page}`, {
24
- credentials: 'include',
25
- signal: controller.signal
26
- });
27
- if (!response.ok) throw new Error();
28
- const body = await response.json();
29
- if (!Array.isArray(body.docs)) throw new Error();
30
- all.push(...body.docs);
31
- if (!body.hasNextPage) break;
32
- page++;
33
- }
21
+ await Promise.resolve();
22
+ if (controller.signal.aborted) return;
23
+ const response = await fetchAllDocs(`${surface.apiRoute.replace(/\/$/, '')}/xp-metrics?depth=0`, {
24
+ credentials: 'include',
25
+ signal: controller.signal
26
+ });
27
+ if (!response.ok) throw new Error();
34
28
  if (!controller.signal.aborted) {
35
- setMetrics(all);
29
+ setMetrics(response.docs);
36
30
  setFailed(false);
37
31
  setLoaded(true);
38
32
  }
@@ -55,13 +49,13 @@ export function GoalSection({ test, surface }) {
55
49
  url.searchParams.delete('goal');
56
50
  window.history.replaceState(window.history.state, '', `${url.pathname}${url.search}${url.hash}`);
57
51
  const goal = metrics.find((metric)=>String(metric.id) === goalId);
58
- if (!reason && doc.metrics?.primary == null && goal) {
52
+ if (!reason && goal) {
59
53
  save(test, 'metrics', ()=>({
60
54
  metrics: {
61
55
  ...doc.metrics,
62
56
  primary: goal.id,
63
- guardrails: doc.metrics?.guardrails?.filter((id)=>id !== goal.id),
64
- secondary: doc.metrics?.secondary?.filter((id)=>id !== goal.id)
57
+ guardrails: doc.metrics?.guardrails?.filter((id)=>String(id) !== goalId),
58
+ secondary: doc.metrics?.secondary?.filter((id)=>String(id) !== goalId)
65
59
  }
66
60
  }));
67
61
  }
@@ -83,7 +77,9 @@ export function GoalSection({ test, surface }) {
83
77
  ...doc.metrics?.guardrails ?? [],
84
78
  ...doc.metrics?.secondary ?? []
85
79
  ].filter((id)=>id != null).map(String);
86
- const visible = options.filter((option)=>chosen.includes(option.value) || option.label.toLowerCase().includes(query.toLowerCase()));
80
+ const visible = [
81
+ ...options
82
+ ];
87
83
  for (const id of chosen)if (!visible.some((option)=>option.value === id)) visible.push({
88
84
  value: id,
89
85
  label: unknownGoal
@@ -137,27 +133,37 @@ export function GoalSection({ test, surface }) {
137
133
  test: test,
138
134
  sectionId: "win",
139
135
  children: [
140
- !reason ? /*#__PURE__*/ _jsx(TextEdit, {
141
- label: C.searchGoals,
142
- value: query,
143
- onDraft: setQuery,
144
- onCommit: setQuery
145
- }) : null,
146
136
  failed ? /*#__PURE__*/ _jsxs("p", {
147
137
  role: "alert",
148
138
  children: [
149
139
  C.goalsError,
150
140
  " ",
151
- /*#__PURE__*/ _jsx("button", {
152
- type: "button",
153
- onClick: ()=>setAttempt((n)=>n + 1),
154
- children: C.retry
141
+ /*#__PURE__*/ _jsx("span", {
142
+ className: "xp-ui-button-group",
143
+ children: /*#__PURE__*/ _jsx(Button, {
144
+ onClick: ()=>setAttempt((n)=>n + 1),
145
+ children: C.retry
146
+ })
155
147
  })
156
148
  ]
157
149
  }) : null,
158
150
  /*#__PURE__*/ _jsx(SelectEdit, {
151
+ labelAction: /*#__PURE__*/ _jsx("span", {
152
+ className: "xp-ui-button-group",
153
+ children: /*#__PURE__*/ _jsx(Button, {
154
+ variant: "link",
155
+ size: "sm",
156
+ href: formatAdminURL({
157
+ adminRoute: surface.adminRoute,
158
+ path: `/experiments/goals${!reason ? `?${new URLSearchParams({
159
+ return: String(doc.id)
160
+ })}` : ''}`
161
+ }),
162
+ children: C.manageGoals
163
+ })
164
+ }),
159
165
  label: C.goal,
160
- value: String(doc.metrics?.primary ?? ''),
166
+ value: loaded && !primary ? '' : String(doc.metrics?.primary ?? ''),
161
167
  options: [
162
168
  {
163
169
  value: '',
@@ -174,20 +180,18 @@ export function GoalSection({ test, surface }) {
174
180
  /*#__PURE__*/ _jsx("p", {
175
181
  children: C.goalHelp
176
182
  }),
177
- /*#__PURE__*/ _jsx("a", {
178
- href: formatAdminURL({
179
- adminRoute: surface.adminRoute,
180
- path: `/experiments/goals${!reason ? `?${new URLSearchParams({
181
- return: String(doc.id)
182
- })}` : ''}`
183
- }),
184
- children: C.manageGoals
185
- }),
183
+ baseline ? /*#__PURE__*/ _jsxs("p", {
184
+ children: [
185
+ primary?.name ? `${primary.name}: ` : '',
186
+ baseline
187
+ ]
188
+ }) : null,
186
189
  /*#__PURE__*/ _jsx(FieldErrors, {
187
190
  test: test,
188
191
  path: "metrics.primary"
189
192
  }),
190
193
  /*#__PURE__*/ _jsx(CheckboxList, {
194
+ searchable: metrics.length > 8,
191
195
  label: C.guardrails,
192
196
  value: (doc.metrics?.guardrails ?? []).map(String),
193
197
  options: roleOptions('guardrails'),
@@ -203,6 +207,7 @@ export function GoalSection({ test, surface }) {
203
207
  path: "metrics.guardrails"
204
208
  }),
205
209
  /*#__PURE__*/ _jsx(CheckboxList, {
210
+ searchable: metrics.length > 8,
206
211
  label: C.secondary,
207
212
  value: (doc.metrics?.secondary ?? []).map(String),
208
213
  options: roleOptions('secondary'),
@@ -214,12 +219,6 @@ export function GoalSection({ test, surface }) {
214
219
  test: test,
215
220
  path: "metrics.secondary"
216
221
  }),
217
- baseline ? /*#__PURE__*/ _jsxs("p", {
218
- children: [
219
- primary?.name ? `${primary.name}: ` : '',
220
- baseline
221
- ]
222
- }) : null,
223
222
  test.errors.metrics ? /*#__PURE__*/ _jsx("p", {
224
223
  role: "alert",
225
224
  children: test.errors.metrics
@@ -1,5 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Button } from '../../../ui/Button.js';
3
4
  import { TEST_PAGE as C, suggestedWeeks, weeksHint } from '../../copy/testPage.js';
4
5
  import { durationSuggestion } from './testPage.model.js';
5
6
  import { FieldErrors, positiveInteger, reasonFor, save, TextEdit } from './fields.js';
@@ -22,30 +23,57 @@ export function LengthSection({ test }) {
22
23
  test: test,
23
24
  sectionId: "length",
24
25
  children: [
25
- /*#__PURE__*/ _jsx(TextEdit, {
26
- label: required ? `${C.reach} ${C.required}` : C.reach,
27
- value: doc.analysis?.reachPerDay ?? '',
28
- type: "number",
29
- min: 1,
30
- reason: reason,
31
- required: required,
32
- onCommit: (value)=>change('reachPerDay', value)
33
- }),
34
- /*#__PURE__*/ _jsx("p", {
35
- children: C.reachHelp
36
- }),
37
- /*#__PURE__*/ _jsx(FieldErrors, {
38
- test: test,
39
- path: "analysis.reachPerDay"
26
+ /*#__PURE__*/ _jsxs("div", {
27
+ className: "xp-field-grid",
28
+ children: [
29
+ /*#__PURE__*/ _jsxs("div", {
30
+ children: [
31
+ /*#__PURE__*/ _jsx(TextEdit, {
32
+ label: required ? `${C.reach} ${C.required}` : C.reach,
33
+ value: doc.analysis?.reachPerDay ?? '',
34
+ type: "number",
35
+ min: 1,
36
+ reason: reason,
37
+ required: required,
38
+ onCommit: (value)=>change('reachPerDay', value)
39
+ }),
40
+ /*#__PURE__*/ _jsx("p", {
41
+ className: "xp-ui-help",
42
+ children: C.reachHelp
43
+ }),
44
+ /*#__PURE__*/ _jsx(FieldErrors, {
45
+ test: test,
46
+ path: "analysis.reachPerDay"
47
+ })
48
+ ]
49
+ }),
50
+ /*#__PURE__*/ _jsxs("div", {
51
+ children: [
52
+ /*#__PURE__*/ _jsx(TextEdit, {
53
+ label: C.duration,
54
+ value: doc.analysis?.plannedDurationDays ?? 28,
55
+ type: "number",
56
+ min: 1,
57
+ reason: reason,
58
+ validate: positiveInteger,
59
+ onCommit: (value)=>change('plannedDurationDays', value),
60
+ help: weeksHint(doc.analysis?.plannedDurationDays ?? 28)
61
+ }),
62
+ /*#__PURE__*/ _jsx(FieldErrors, {
63
+ test: test,
64
+ path: "analysis.plannedDurationDays"
65
+ })
66
+ ]
67
+ })
68
+ ]
40
69
  }),
41
70
  suggestion ? /*#__PURE__*/ _jsxs("div", {
42
- className: "xp-duration-suggestion",
71
+ className: "xp-duration-suggestion xp-ui-button-group",
43
72
  children: [
44
73
  /*#__PURE__*/ _jsx("p", {
45
74
  children: suggestedWeeks(suggestion.weeks)
46
75
  }),
47
- !reason ? /*#__PURE__*/ _jsx("button", {
48
- type: "button",
76
+ !reason ? /*#__PURE__*/ _jsx(Button, {
49
77
  onClick: ()=>save(test, 'analysis', ()=>({
50
78
  analysis: {
51
79
  ...test.doc.analysis,
@@ -62,22 +90,6 @@ export function LengthSection({ test }) {
62
90
  }) : !test.preflight?.estimate ? /*#__PURE__*/ _jsx("p", {
63
91
  children: doc.analysis?.reachPerDay == null ? C.noSuggestion : C.chooseGoalSuggestion
64
92
  }) : null,
65
- /*#__PURE__*/ _jsx(TextEdit, {
66
- label: C.duration,
67
- value: doc.analysis?.plannedDurationDays ?? 28,
68
- type: "number",
69
- min: 1,
70
- reason: reason,
71
- validate: positiveInteger,
72
- onCommit: (value)=>change('plannedDurationDays', value)
73
- }),
74
- /*#__PURE__*/ _jsx("p", {
75
- children: weeksHint(doc.analysis?.plannedDurationDays ?? 28)
76
- }),
77
- /*#__PURE__*/ _jsx(FieldErrors, {
78
- test: test,
79
- path: "analysis.plannedDurationDays"
80
- }),
81
93
  test.errors.analysis ? /*#__PURE__*/ _jsx("p", {
82
94
  role: "alert",
83
95
  children: test.errors.analysis
@@ -0,0 +1,4 @@
1
+ import type { TestDocApi } from '../contracts.js';
2
+ export declare function Rail({ test }: {
3
+ test: TestDocApi;
4
+ }): import("react").JSX.Element;
@@ -0,0 +1,83 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useEffect, useRef, useState } from 'react';
4
+ import { SECTION_ORDER } from '../contracts.js';
5
+ import { readinessParts } from '../readiness/parts.js';
6
+ import { TEST_PAGE as C } from '../../copy/testPage.js';
7
+ import { jumpToSection } from './jumpToSection.js';
8
+ export function Rail({ test }) {
9
+ const [active, setActive] = useState('what');
10
+ const ref = useRef(null);
11
+ const done = readinessParts.sectionDone(test);
12
+ useEffect(()=>{
13
+ if (typeof IntersectionObserver === 'undefined') return;
14
+ const visible = new Map();
15
+ const observer = new IntersectionObserver((entries)=>{
16
+ for (const entry of entries)visible.set(entry.target.id.replace('section-', ''), entry.isIntersecting ? entry.intersectionRatio : 0);
17
+ const best = SECTION_ORDER.filter((id)=>(visible.get(id) ?? 0) > 0).sort((a, b)=>(visible.get(b) ?? 0) - (visible.get(a) ?? 0))[0];
18
+ // Retain the last clicked/visible item when nothing intersects.
19
+ if (best) setActive(best);
20
+ }, {
21
+ rootMargin: '-10% 0px -60% 0px',
22
+ threshold: [
23
+ 0,
24
+ .1,
25
+ .25,
26
+ .5,
27
+ .75,
28
+ 1
29
+ ]
30
+ });
31
+ for (const id of SECTION_ORDER){
32
+ const section = document.getElementById(`section-${id}`);
33
+ if (section) observer.observe(section);
34
+ }
35
+ return ()=>observer.disconnect();
36
+ }, []);
37
+ useEffect(()=>{
38
+ if (window.matchMedia?.('(max-width: 960px)').matches) {
39
+ ref.current?.querySelector('[aria-current]')?.scrollIntoView?.({
40
+ block: 'nearest',
41
+ inline: 'nearest'
42
+ });
43
+ }
44
+ }, [
45
+ active
46
+ ]);
47
+ return /*#__PURE__*/ _jsx("nav", {
48
+ ref: ref,
49
+ className: "xp-test-rail",
50
+ "aria-label": C.navigation,
51
+ children: /*#__PURE__*/ _jsx("ol", {
52
+ className: "xp-test-rail-list",
53
+ children: SECTION_ORDER.map((id)=>/*#__PURE__*/ _jsx("li", {
54
+ children: /*#__PURE__*/ _jsxs("a", {
55
+ href: `#section-${id}`,
56
+ className: `xp-test-rail-item${id === 'advanced' ? ' xp-test-rail-item--advanced' : ''}${active === id ? ' is-active' : ''}`,
57
+ "aria-current": active === id ? 'location' : undefined,
58
+ onClick: (event)=>{
59
+ event.preventDefault();
60
+ setActive(id);
61
+ jumpToSection(id);
62
+ },
63
+ children: [
64
+ id !== 'advanced' ? /*#__PURE__*/ _jsxs(_Fragment, {
65
+ children: [
66
+ /*#__PURE__*/ _jsx("span", {
67
+ "aria-hidden": "true",
68
+ className: done[id] ? 'xp-test-rail-mark xp-test-rail-mark--done' : 'xp-test-rail-mark',
69
+ children: done[id] ? C.completeMark : C.incompleteMark
70
+ }),
71
+ /*#__PURE__*/ _jsx("span", {
72
+ className: "xp-test-sr-only",
73
+ children: done[id] ? C.completePrefix : C.incompletePrefix
74
+ })
75
+ ]
76
+ }) : null,
77
+ C.sections[id]
78
+ ]
79
+ })
80
+ }, id))
81
+ })
82
+ });
83
+ }
@@ -0,0 +1,5 @@
1
+ import type { SectionProps } from '../contracts.js';
2
+ /** Measure wrapping actions/copy so the final section always clears the fixed bar. */
3
+ export declare function ReadinessBar({ onHeightChange, ...props }: SectionProps & {
4
+ onHeightChange: (height: number) => void;
5
+ }): import("react").JSX.Element;