@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
@@ -0,0 +1,2 @@
1
+ import './ui.css';
2
+ export { NumberInput } from './Inputs.js';
@@ -0,0 +1,2 @@
1
+ import './ui.css';
2
+ export { Range } from './Inputs.js';
@@ -0,0 +1,2 @@
1
+ import './ui.css';
2
+ export { Range } from './Inputs.js';
@@ -0,0 +1,2 @@
1
+ import './ui.css';
2
+ export { SearchInput } from './Inputs.js';
@@ -0,0 +1,2 @@
1
+ import './ui.css';
2
+ export { SearchInput } from './Inputs.js';
@@ -0,0 +1,2 @@
1
+ import './ui.css';
2
+ export { SectionCard } from './Card.js';
@@ -0,0 +1,2 @@
1
+ import './ui.css';
2
+ export { SectionCard } from './Card.js';
@@ -0,0 +1,2 @@
1
+ import './ui.css';
2
+ export { Select } from './Inputs.js';
@@ -0,0 +1,2 @@
1
+ import './ui.css';
2
+ export { Select } from './Inputs.js';
@@ -0,0 +1,2 @@
1
+ import './ui.css';
2
+ export { StatusChip } from './Feedback.js';
@@ -0,0 +1,2 @@
1
+ import './ui.css';
2
+ export { StatusChip } from './Feedback.js';
@@ -0,0 +1,16 @@
1
+ import type { ReactNode, Ref } from 'react';
2
+ import './ui.css';
3
+ export interface Tab {
4
+ id: string;
5
+ label: string;
6
+ content: ReactNode;
7
+ actions?: ReactNode;
8
+ disabled?: boolean;
9
+ }
10
+ export declare function Tabs({ items, label, value, onChange, tabListRef }: {
11
+ items: Tab[];
12
+ label: string;
13
+ value?: string;
14
+ onChange?: (id: string) => void;
15
+ tabListRef?: Ref<HTMLDivElement>;
16
+ }): import("react").JSX.Element;
@@ -0,0 +1,61 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useId, useState } from 'react';
4
+ import './ui.css';
5
+ export function Tabs({ items, label, value, onChange, tabListRef }) {
6
+ const prefix = useId();
7
+ const [local, setLocal] = useState(()=>items.find((item)=>!item.disabled)?.id);
8
+ const requested = value ?? local;
9
+ const selected = items.find((item)=>item.id === requested && !item.disabled)?.id ?? items.find((item)=>!item.disabled)?.id;
10
+ function select(id) {
11
+ setLocal(id);
12
+ onChange?.(id);
13
+ }
14
+ return /*#__PURE__*/ _jsxs("div", {
15
+ className: "xp-ui-tabs",
16
+ children: [
17
+ /*#__PURE__*/ _jsxs("div", {
18
+ ref: tabListRef,
19
+ className: "xp-ui-tabs-header",
20
+ children: [
21
+ /*#__PURE__*/ _jsx("div", {
22
+ role: "tablist",
23
+ "aria-label": label,
24
+ className: "xp-ui-tablist",
25
+ children: items.map((item)=>/*#__PURE__*/ _jsx("button", {
26
+ type: "button",
27
+ role: "tab",
28
+ id: `${prefix}-tab-${item.id}`,
29
+ "aria-controls": `${prefix}-panel-${item.id}`,
30
+ "aria-selected": selected === item.id,
31
+ tabIndex: selected === item.id ? 0 : -1,
32
+ disabled: item.disabled,
33
+ className: "xp-ui-tab",
34
+ onClick: ()=>select(item.id),
35
+ onKeyDown: (event)=>{
36
+ const enabled = items.filter((tab)=>!tab.disabled);
37
+ const index = enabled.findIndex((tab)=>tab.id === item.id);
38
+ const next = event.key === 'ArrowRight' ? enabled[(index + 1) % enabled.length] : event.key === 'ArrowLeft' ? enabled[(index - 1 + enabled.length) % enabled.length] : event.key === 'Home' ? enabled[0] : event.key === 'End' ? enabled.at(-1) : undefined;
39
+ if (!next) return;
40
+ event.preventDefault();
41
+ select(next.id);
42
+ event.currentTarget.ownerDocument.getElementById(`${prefix}-tab-${next.id}`)?.focus();
43
+ },
44
+ children: item.label
45
+ }, item.id))
46
+ }),
47
+ items.find((item)=>item.id === selected)?.actions
48
+ ]
49
+ }),
50
+ items.map((item)=>/*#__PURE__*/ _jsx("div", {
51
+ role: "tabpanel",
52
+ id: `${prefix}-panel-${item.id}`,
53
+ "aria-labelledby": `${prefix}-tab-${item.id}`,
54
+ hidden: selected !== item.id,
55
+ tabIndex: 0,
56
+ className: "xp-ui-tabpanel",
57
+ children: item.content
58
+ }, item.id))
59
+ ]
60
+ });
61
+ }
@@ -0,0 +1,2 @@
1
+ import './ui.css';
2
+ export { TextInput } from './Inputs.js';
@@ -0,0 +1,2 @@
1
+ import './ui.css';
2
+ export { TextInput } from './Inputs.js';
@@ -0,0 +1,2 @@
1
+ import './ui.css';
2
+ export { Textarea } from './Inputs.js';
@@ -0,0 +1,2 @@
1
+ import './ui.css';
2
+ export { Textarea } from './Inputs.js';
@@ -0,0 +1,2 @@
1
+ import './ui.css';
2
+ export { Toggle } from './Inputs.js';
@@ -0,0 +1,2 @@
1
+ import './ui.css';
2
+ export { Toggle } from './Inputs.js';
@@ -0,0 +1,40 @@
1
+ export interface AccentSet {
2
+ accent: string;
3
+ hover: string;
4
+ active: string;
5
+ subtle: string;
6
+ fg: string;
7
+ focus: string;
8
+ accentText: string;
9
+ accentTextDecoration: 'none' | 'underline';
10
+ }
11
+ /** WCAG 2.x relative luminance contrast. */
12
+ export declare function contrast(a: string, b: string): number;
13
+ /** Contrast floors for accent text and focus rings. Black or white always clears them on a real
14
+ * surface, so the fallbacks below are defensive; tests raise the floors to exercise them. */
15
+ type Floors = {
16
+ text: number;
17
+ focus: number;
18
+ };
19
+ /** Pure shared host-accent derivation using theme.css's reference surfaces. */
20
+ export declare function deriveAccent(input: string): {
21
+ light: AccentSet;
22
+ dark: AccentSet;
23
+ };
24
+ /** Module-only surface injection; not a package API. Dark adjustment raises HSL
25
+ * lightness to 3:1. Interaction steps preserve the foreground and prefer the
26
+ * original direction when both steps reach 1.1:1; subtle remains an 8% tint. */
27
+ export declare function deriveAccentFor(input: string, surfaces: {
28
+ light: string;
29
+ dark: string;
30
+ }, floors?: Floors): {
31
+ light: AccentSet;
32
+ dark: AccentSet;
33
+ };
34
+ /** Validated hex values only; specificity exceeds theme.css regardless of load order. */
35
+ export declare function accentStyles(input?: string): string | undefined;
36
+ /** The plugin and Puck factory accept exactly the same host accent. */
37
+ export declare function validateAccent(accent: unknown): void;
38
+ /** Inline variables use the same names as the admin accent stylesheet. */
39
+ export declare function accentVariables(set: AccentSet): Record<string, string>;
40
+ export {};
@@ -0,0 +1,139 @@
1
+ function rgb(hex) {
2
+ if (!/^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test(hex)) throw new Error(`Invalid accent hex colour: ${hex}`);
3
+ const full = hex.length === 4 ? hex.slice(1).split('').map((c)=>c + c).join('') : hex.slice(1);
4
+ return [
5
+ 0,
6
+ 2,
7
+ 4
8
+ ].map((i)=>parseInt(full.slice(i, i + 2), 16));
9
+ }
10
+ const hexOf = (values)=>'#' + values.map((v)=>Math.round(v).toString(16).padStart(2, '0')).join('');
11
+ function luminance(hex) {
12
+ const channels = rgb(hex).map((v)=>{
13
+ const s = v / 255;
14
+ return s <= 0.04045 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
15
+ });
16
+ return channels[0] * 0.2126 + channels[1] * 0.7152 + channels[2] * 0.0722;
17
+ }
18
+ /** WCAG 2.x relative luminance contrast. */ export function contrast(a, b) {
19
+ const x = luminance(a), y = luminance(b);
20
+ return (Math.max(x, y) + 0.05) / (Math.min(x, y) + 0.05);
21
+ }
22
+ function mix(a, b, amount) {
23
+ const x = rgb(a), y = rgb(b);
24
+ return hexOf(x.map((v, i)=>v * (1 - amount) + y[i] * amount));
25
+ }
26
+ /** Raise HSL lightness with hue and saturation fixed, including achromatic inputs. */ function lighten(hex, amount) {
27
+ const channels = rgb(hex).map((v)=>v / 255);
28
+ const max = Math.max(...channels), min = Math.min(...channels), l = (max + min) / 2;
29
+ const next = l + (1 - l) * amount;
30
+ const scale = l === 1 ? 0 : (1 - Math.abs(2 * next - 1)) / (1 - Math.abs(2 * l - 1) || 1);
31
+ return hexOf(channels.map((v)=>(next + (v - l) * scale) * 255));
32
+ }
33
+ /** Bounded, quantised search toward the surface's opposite. */ function againstSurface(accent, surface, minimum) {
34
+ const opposite = luminance(surface) > 0.179 ? '#000000' : '#ffffff';
35
+ for(let step = 0; step <= 1000; step++){
36
+ const candidate = mix(accent, opposite, step / 1000);
37
+ if (contrast(candidate, surface) >= minimum) return candidate;
38
+ }
39
+ return undefined;
40
+ }
41
+ const interactionStep = (accent, states)=>Math.min(contrast(accent, states.hover), contrast(states.hover, states.active));
42
+ /** Keep the old 12/24% steps when visible, otherwise search the full direction. */ function interaction(accent, fg, target) {
43
+ let low = 0, high = 0.24;
44
+ for(let i = 0; i < 24; i++){
45
+ const amount = (low + high) / 2;
46
+ if (contrast(mix(accent, target, amount), fg) >= 4.5) low = amount;
47
+ else high = amount;
48
+ }
49
+ const amount = contrast(mix(accent, target, 0.24), fg) >= 4.5 ? 0.24 : low;
50
+ const original = {
51
+ hover: mix(accent, target, amount / 2),
52
+ active: mix(accent, target, amount)
53
+ };
54
+ if (interactionStep(accent, original) >= 1.1) return original;
55
+ const candidates = [
56
+ accent
57
+ ];
58
+ let hover;
59
+ for(let step = 1; step <= 1000; step++){
60
+ const candidate = mix(accent, target, step / 1000);
61
+ if (contrast(candidate, fg) < 4.5) break;
62
+ candidates.push(candidate);
63
+ if (!hover && contrast(accent, candidate) >= 1.1) hover = candidate;
64
+ else if (hover && contrast(hover, candidate) >= 1.1) return {
65
+ hover,
66
+ active: candidate
67
+ };
68
+ }
69
+ // If two full steps cannot fit, maximise the smaller step to the last safe fill.
70
+ const active = candidates[candidates.length - 1];
71
+ return candidates.reduce((best, candidate)=>{
72
+ const next = {
73
+ hover: candidate,
74
+ active
75
+ };
76
+ return interactionStep(accent, next) > interactionStep(accent, best) ? next : best;
77
+ }, {
78
+ hover: accent,
79
+ active
80
+ });
81
+ }
82
+ const FLOORS = {
83
+ text: 4.5,
84
+ focus: 3
85
+ };
86
+ function set(accent, surface, dark = false, floors = FLOORS) {
87
+ const fg = contrast(accent, '#ffffff') >= contrast(accent, '#141414') ? '#ffffff' : '#141414';
88
+ const target = dark || fg === '#141414' ? '#ffffff' : '#000000';
89
+ const preferred = interaction(accent, fg, target);
90
+ const other = interaction(accent, fg, target === '#ffffff' ? '#000000' : '#ffffff');
91
+ const states = interactionStep(accent, preferred) >= 1.1 || interactionStep(accent, preferred) >= interactionStep(accent, other) ? preferred : other;
92
+ const accentText = againstSurface(accent, surface, floors.text);
93
+ return {
94
+ accent,
95
+ ...states,
96
+ subtle: mix(surface, accent, 0.08),
97
+ fg,
98
+ focus: againstSurface(accent, surface, floors.focus) ?? 'var(--xp-text)',
99
+ accentText: accentText ?? 'var(--xp-text)',
100
+ accentTextDecoration: accentText ? 'none' : 'underline'
101
+ };
102
+ }
103
+ /** Pure shared host-accent derivation using theme.css's reference surfaces. */ export function deriveAccent(input) {
104
+ return deriveAccentFor(input, {
105
+ light: '#ffffff',
106
+ dark: '#222222'
107
+ });
108
+ }
109
+ /** Module-only surface injection; not a package API. Dark adjustment raises HSL
110
+ * lightness to 3:1. Interaction steps preserve the foreground and prefer the
111
+ * original direction when both steps reach 1.1:1; subtle remains an 8% tint. */ export function deriveAccentFor(input, surfaces, floors = FLOORS) {
112
+ const accent = hexOf(rgb(input));
113
+ let dark = accent;
114
+ for(let step = 1; contrast(dark, surfaces.dark) < 3 && step <= 1000; step++)dark = lighten(accent, step / 1000);
115
+ return {
116
+ light: set(accent, surfaces.light, false, floors),
117
+ dark: set(dark, surfaces.dark, true, floors)
118
+ };
119
+ }
120
+ /** Validated hex values only; specificity exceeds theme.css regardless of load order. */ export function accentStyles(input) {
121
+ if (!input) return undefined;
122
+ const sets = deriveAccent(input);
123
+ const declarations = (s)=>Object.entries(accentVariables(s)).map(([name, value])=>`${name}:${value};`).join('');
124
+ return `:root:root, [data-theme="light"][data-theme="light"]{${declarations(sets.light)}}\n[data-theme="dark"][data-theme="dark"]{${declarations(sets.dark)}}`;
125
+ }
126
+ /** The plugin and Puck factory accept exactly the same host accent. */ export function validateAccent(accent) {
127
+ if (accent === undefined || accent === '') return;
128
+ if (typeof accent !== 'string' || !/^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test(accent)) throw new Error('Experiments theme.accent must be a CSS hex colour (#rgb or #rrggbb)');
129
+ for (const [mode, set] of Object.entries(deriveAccent(accent))){
130
+ const ratio = contrast(set.accent, set.fg);
131
+ if (ratio < 4.5) throw new Error(`Experiments theme.accent ${accent}: ${mode} foreground contrast ${ratio.toFixed(2)}:1 is below 4.5:1`);
132
+ }
133
+ }
134
+ /** Inline variables use the same names as the admin accent stylesheet. */ export function accentVariables(set) {
135
+ return Object.fromEntries(Object.entries(set).map(([name, value])=>[
136
+ `--xp-${name === 'accentText' ? 'accent-text' : name === 'accentTextDecoration' ? 'accent-text-decoration' : name === 'focus' || name === 'accent' ? name : `accent-${name}`}`,
137
+ value
138
+ ]));
139
+ }
@@ -0,0 +1,9 @@
1
+ export * from './Button.js';
2
+ export * from './Inputs.js';
3
+ export * from './ChipsInput.js';
4
+ export * from './Card.js';
5
+ export * from './Tabs.js';
6
+ export * from './Feedback.js';
7
+ export * from './Dialog.js';
8
+ export * from './Breadcrumb.js';
9
+ export * from './accent.js';
@@ -0,0 +1,9 @@
1
+ export * from './Button.js';
2
+ export * from './Inputs.js';
3
+ export * from './ChipsInput.js';
4
+ export * from './Card.js';
5
+ export * from './Tabs.js';
6
+ export * from './Feedback.js';
7
+ export * from './Dialog.js';
8
+ export * from './Breadcrumb.js';
9
+ export * from './accent.js';
package/dist/ui/ui.css ADDED
@@ -0,0 +1,92 @@
1
+ /* Shared primitives: no host palette references, and no global element resets. */
2
+ .xp-ui-chips, .xp-ui-chips-control, .xp-ui-chips-item, .xp-ui-button, .xp-ui-input, .xp-ui-toggle, .xp-ui-tab, .xp-ui-dialog, .xp-ui-card { box-sizing: border-box; }
3
+ .xp-ui-button { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 36px; padding: 7px 14px; border-radius: var(--xp-radius-control); border: 1px solid transparent; font: 500 14px/20px var(--xp-font); color: var(--xp-text); background: transparent; cursor: pointer; white-space: normal; overflow-wrap: anywhere; max-width: 100%; min-width: 0; text-decoration: none; transition: background-color var(--xp-motion), border-color var(--xp-motion), color var(--xp-motion); }
4
+ .xp-ui-button--primary { background: var(--xp-accent); color: var(--xp-accent-fg); border-color: var(--xp-accent); }
5
+ .xp-ui-button--primary:hover { background: var(--xp-accent-hover); border-color: var(--xp-accent-hover); }
6
+ .xp-ui-button--primary:active { background: var(--xp-accent-active); border-color: var(--xp-accent-active); }
7
+ .xp-ui-button--secondary { background: var(--xp-surface); border-color: var(--xp-border-strong); }
8
+ .xp-ui-button--secondary:hover { background: var(--xp-surface-2); }
9
+ .xp-ui-button--quiet { color: var(--xp-text-2); }
10
+ .xp-ui-button--quiet:hover { background: var(--xp-surface-2); color: var(--xp-text); }
11
+ .xp-ui-button--danger { color: var(--xp-error); border-color: var(--xp-error-border); background: var(--xp-surface); }
12
+ .xp-ui-button--danger:hover { background: var(--xp-error-bg); }
13
+ .xp-ui-button--sm { height: 30px; padding: 0 10px; font-size: 13px; }
14
+ .xp-ui-button--link { height: auto; min-height: 0; padding-inline: 0; color: var(--xp-accent-text); text-decoration: var(--xp-accent-text-decoration); }
15
+ .xp-ui-button--link:hover { text-decoration: underline; }
16
+ .xp-ui-button:disabled, .xp-ui-button[aria-disabled='true'], .xp-ui-input:disabled, .xp-ui-toggle:disabled { opacity: .5; cursor: not-allowed; }
17
+ .xp-ui-button:focus-visible, .xp-ui-input:focus-visible, .xp-ui-toggle:focus-visible, .xp-ui-tab:focus-visible, .xp-ui-tabpanel:focus-visible, .xp-ui-breadcrumb a:focus-visible, .xp-ui-dialog:focus-visible { outline: 2px solid var(--xp-focus); outline-offset: 2px; }
18
+ .xp-ui-field { min-width: 0; max-width: 100%; display: grid; gap: 6px; color: var(--xp-text); font: var(--xp-text-body); }
19
+ .xp-ui-field > label { font-weight: 500; }
20
+ .xp-ui-input { display: block; width: 100%; max-width: 100%; min-width: 0; height: 36px; padding: 0 12px; border: 1px solid var(--xp-border-strong); border-radius: var(--xp-radius-control); background: var(--xp-surface); color: var(--xp-text); font: var(--xp-text-body); transition: border-color var(--xp-motion); }
21
+ .xp-ui-input::placeholder { color: var(--xp-text-3); }
22
+ .xp-ui-input:hover { border-color: var(--xp-text-3); }
23
+ .xp-ui-input[aria-invalid='true'] { border-color: var(--xp-error); }
24
+ .xp-ui-input--number { text-align: right; font-variant-numeric: tabular-nums; }
25
+ .xp-ui-select { cursor: pointer; appearance: auto; }
26
+ .xp-ui-help { margin: 0; color: var(--xp-text-2); font: var(--xp-text-small); }
27
+ .xp-ui-error { margin: 0; color: var(--xp-error); font: var(--xp-text-small); }
28
+ .xp-ui-toggle { appearance: none; display: inline-block; width: 32px; height: 20px; margin: 0; padding: 2px; border-radius: 20px; border: 1px solid var(--xp-border-strong); background: var(--xp-surface-3); cursor: pointer; transition: background-color var(--xp-motion); }
29
+ .xp-ui-toggle::before { content: ''; display: block; width: 14px; height: 14px; border-radius: 50%; background: var(--xp-surface); transition: transform var(--xp-motion); }
30
+ .xp-ui-toggle:checked { background: var(--xp-accent); border-color: var(--xp-accent); }
31
+ .xp-ui-toggle:checked::before { transform: translateX(12px); background: var(--xp-accent-fg); }
32
+ .xp-ui-card { min-width: 0; padding: 20px; border: 1px solid var(--xp-border); border-radius: var(--xp-radius-card); background: var(--xp-surface); color: var(--xp-text); font: var(--xp-text-body); }
33
+ .xp-ui-section { padding: 0; }
34
+ .xp-ui-section-head { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; padding: 16px 20px; border-bottom: 1px solid var(--xp-border); }
35
+ .xp-ui-section-head h2 { margin: 0; font: var(--xp-text-title); }
36
+ .xp-ui-section-number { display: grid; place-items: center; width: 24px; height: 24px; border: 1px solid var(--xp-border); border-radius: var(--xp-radius-chip); font: var(--xp-text-small); color: var(--xp-text-2); }
37
+ .xp-ui-section-complete { margin-inline-start: auto; color: var(--xp-text-2); }
38
+ .xp-ui-section-body { padding: 20px; }
39
+ .xp-ui-tabs { color: var(--xp-text); font: var(--xp-text-body); }
40
+ .xp-ui-tablist { display: flex; flex-wrap: wrap; gap: 4px; border-bottom: 1px solid var(--xp-border); }
41
+ .xp-ui-tab { appearance: none; border: 0; border-bottom: 2px solid transparent; border-radius: 0; padding: 10px 12px; background: transparent; color: var(--xp-text-2); font: var(--xp-text-body); cursor: pointer; }
42
+ .xp-ui-tab[aria-selected='true'] { color: var(--xp-accent-text); text-decoration: var(--xp-accent-text-decoration); border-bottom-color: var(--xp-accent-text); font-weight: 600; }
43
+ .xp-ui-tab:disabled { opacity: .5; cursor: not-allowed; }
44
+ .xp-ui-tabpanel { padding-block: 16px; }
45
+ .xp-ui-status { display: inline-flex; align-items: center; gap: 6px; height: 22px; padding: 0 8px; border-radius: var(--xp-radius-chip); border: 1px solid var(--xp-border-strong); background: var(--xp-surface-2); color: var(--xp-text-2); font: 500 12px/18px var(--xp-font); white-space: nowrap; }
46
+ .xp-ui-status--running, .xp-ui-status--ready { background: var(--xp-success-bg); color: var(--xp-success); border-color: var(--xp-success-border); }
47
+ .xp-ui-status--needs-attention { background: var(--xp-warning-bg); color: var(--xp-warning); border-color: var(--xp-warning-border); }
48
+ .xp-ui-status--decided { background: var(--xp-text); color: var(--xp-surface); border-color: var(--xp-text); }
49
+ .xp-ui-banner { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px; padding: 14px 20px; border: 1px solid var(--xp-border); border-radius: var(--xp-radius-control); background: var(--xp-surface-2); color: var(--xp-text); font: var(--xp-text-body); }
50
+ .xp-ui-banner p, .xp-ui-empty p { margin: 0; }
51
+ .xp-ui-banner--warning { background: var(--xp-warning-bg); color: var(--xp-warning); border-color: var(--xp-warning-border); }
52
+ .xp-ui-banner--error { background: var(--xp-error-bg); color: var(--xp-error); border-color: var(--xp-error-border); }
53
+ .xp-ui-empty { display: grid; justify-items: center; gap: 16px; padding: 32px 20px; border: 1px solid var(--xp-border); border-radius: var(--xp-radius-card); color: var(--xp-text-2); background: var(--xp-surface); font: var(--xp-text-body); text-align: center; }
54
+ .xp-ui-breadcrumb { color: var(--xp-text-2); font: var(--xp-text-small); }
55
+ .xp-ui-breadcrumb ol { display: flex; flex-wrap: wrap; gap: 8px; list-style: none; margin: 0; padding: 0; }
56
+ .xp-ui-breadcrumb li { display: flex; gap: 8px; min-width: 0; }
57
+ .xp-ui-breadcrumb a { color: var(--xp-text-2); text-decoration: underline; text-underline-offset: 2px; border-radius: var(--xp-radius-chip); }
58
+ .xp-ui-breadcrumb a:hover { color: var(--xp-text); }
59
+ .xp-ui-breadcrumb [aria-current] { color: var(--xp-text); }
60
+ .xp-ui-dialog { width: min(480px, calc(100% - 32px)); max-height: calc(100% - 32px); overflow: auto; padding: 24px; border: 1px solid var(--xp-border); border-radius: var(--xp-radius-card); background: var(--xp-surface); color: var(--xp-text); font: var(--xp-text-body); box-shadow: 0 16px 48px var(--xp-overlay); }
61
+ .xp-ui-dialog h2 { margin: 0 0 16px; font: var(--xp-text-title); }
62
+ .xp-ui-dialog::backdrop { background: var(--xp-overlay); }
63
+ .xp-ui-chips { width: 100%; max-width: 100%; min-width: 0; display: grid; gap: var(--xp-space-2); margin-block: var(--xp-space-4); color: var(--xp-text); font-family: var(--xp-font-body); }
64
+ .xp-ui-chips-control { width: 100%; max-width: 100%; min-width: 0; display: flex; align-items: center; flex-wrap: wrap; gap: var(--xp-space-1); padding: var(--xp-space-2); border: 1px solid var(--xp-border-control); border-radius: var(--xp-radius); background: var(--xp-input-bg); }
65
+ .xp-ui-chips-control--invalid { border-color: var(--xp-error); }
66
+ .xp-ui-chips-control:focus-within { outline: 2px solid var(--xp-focus); outline-offset: 2px; }
67
+ .xp-ui-chips-item { display: inline-flex; align-items: center; gap: var(--xp-space-1); padding-inline-start: var(--xp-space-2); border-radius: var(--xp-radius); background: var(--xp-surface-raised); overflow-wrap: anywhere; max-width: 100%; }
68
+ .xp-ui-chips .xp-ui-chips-item button { padding: var(--xp-space-1) var(--xp-space-2); border: 0; background: transparent; color: var(--xp-text); font: inherit; cursor: pointer; }
69
+ .xp-ui-chips .xp-ui-chips-control input { flex: 1 1 28ch; min-width: min(100%, 28ch); width: 100%; max-width: 100%; box-sizing: border-box; border: 0; padding: var(--xp-space-1); background: transparent; color: var(--xp-text); font: inherit; }
70
+ .xp-ui-chips input:focus { outline: none; }
71
+ .xp-ui-chips button:focus-visible { outline: 2px solid var(--xp-focus); outline-offset: 2px; }
72
+ .xp-ui-chips[aria-disabled='true'] { opacity: .5; }
73
+ .xp-ui-chips[aria-disabled='true'] button { cursor: default; }
74
+ .xp-ui-chips p:not(.xp-ui-error) { margin: 0; color: var(--xp-text-muted); font-size: var(--xp-font-size-small); }
75
+ /* Quiet actions and breadcrumb links stay neutral; only the selected tab takes the text accent. */
76
+ .xp-ui-button-group { display: flex; flex-wrap: wrap; gap: 8px; min-width: 0; max-width: 100%; }
77
+ @media (prefers-reduced-motion: reduce) {
78
+ .xp-ui-button, .xp-ui-input, .xp-ui-toggle, .xp-ui-toggle::before, .xp-ui-chips-control { transition: none; }
79
+ }
80
+
81
+ .xp-ui-textarea { height: auto; min-height: 96px; padding-block: var(--xp-space-2); resize: vertical; }
82
+ .xp-ui-checkbox-label { display: flex; align-items: baseline; gap: var(--xp-space-2); cursor: pointer; }
83
+ .xp-ui-checkbox { flex: none; width: 16px; height: 16px; margin: 0; accent-color: var(--xp-accent); }
84
+ .xp-ui-checkbox-list { margin: 0; padding: 0; border: 0; }
85
+ .xp-ui-checkbox-list legend { padding: 0; margin-bottom: var(--xp-space-2); font-weight: 500; }
86
+ .xp-ui-range { box-sizing: border-box; width: 100%; max-width: 100%; min-width: 0; margin: 0; accent-color: var(--xp-accent); cursor: pointer; }
87
+ .xp-ui-checkbox:disabled, .xp-ui-range:disabled { opacity: .5; cursor: not-allowed; }
88
+ .xp-ui-checkbox:focus-visible, .xp-ui-range:focus-visible { outline: 2px solid var(--xp-focus); outline-offset: 2px; }
89
+ .xp-ui-checkbox[aria-invalid='true'], .xp-ui-range[aria-invalid='true'] { outline: 1px solid var(--xp-error); }
90
+
91
+ .xp-ui-field-label { display: flex; align-items: center; justify-content: space-between; gap: var(--xp-space-3); }
92
+ .xp-ui-field-label > label { font-weight: 500; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@delmaredigital/payload-experiments",
3
- "version": "0.2.0-rc.7",
3
+ "version": "0.3.0-rc.4",
4
4
  "description": "No-code A/B testing for Payload CMS and Next.js: block, page and flag experiments with holdouts, layers, exposure logging and honest statistics inside the admin — no vendor",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -68,6 +68,8 @@
68
68
  "default": "./dist/exports/puckEditor.js"
69
69
  },
70
70
  "./puck/editor.css": "./dist/puck/editor/editor.css",
71
+ "./admin/theme.css": "./dist/admin/theme.css",
72
+ "./admin/ui.css": "./dist/ui/ui.css",
71
73
  "./package.json": "./package.json"
72
74
  },
73
75
  "files": [
@@ -135,7 +137,8 @@
135
137
  "@electric-sql/pglite": "^0.5.13",
136
138
  "@puckeditor/core": "^0.24.0",
137
139
  "drizzle-orm": "0.45.2",
138
- "drizzle-kit": "0.31.7"
140
+ "drizzle-kit": "0.31.7",
141
+ "yaml": "2.9.1"
139
142
  },
140
143
  "scripts": {
141
144
  "build": "swc ./src -d ./dist --strip-leading-paths --config-file ../../.swcrc && tsc -p tsconfig.build.json && copyfiles -u 1 \"src/**/*.css\" dist",
@@ -1,11 +0,0 @@
1
- .xp-chips { display: grid; gap: var(--xp-space-2); margin-block: var(--xp-space-4); color: var(--xp-text); font-family: var(--xp-font-body); }
2
- .xp-chips-control { display: flex; align-items: center; flex-wrap: wrap; gap: var(--xp-space-1); padding: var(--xp-space-2); border: 1px solid var(--xp-border-control); border-radius: var(--xp-radius); background: var(--xp-input-bg); }
3
- .xp-chips-control:focus-within { outline: 2px solid var(--xp-text); outline-offset: 2px; }
4
- .xp-chips-item { display: inline-flex; align-items: center; gap: var(--xp-space-1); padding-inline-start: var(--xp-space-2); border-radius: var(--xp-radius); background: var(--xp-surface-raised); overflow-wrap: anywhere; max-width: 100%; }
5
- .xp-chips .xp-chips-item button { padding: var(--xp-space-1) var(--xp-space-2); border: 0; background: transparent; color: var(--xp-text); font: inherit; cursor: pointer; }
6
- .xp-chips .xp-chips-control input { flex: 1; min-width: 8rem; width: 0; border: 0; padding: var(--xp-space-1); background: transparent; color: var(--xp-text); font: inherit; }
7
- .xp-chips input:focus { outline: none; }
8
- .xp-chips button:focus-visible { outline: 2px solid var(--xp-text); outline-offset: 2px; }
9
- .xp-chips[aria-disabled='true'] { opacity: .5; }
10
- .xp-chips[aria-disabled='true'] button { cursor: default; }
11
- .xp-chips p { margin: 0; color: var(--xp-text-muted); font-size: var(--xp-font-size-small); }
@@ -1,8 +0,0 @@
1
- import type { ArmRow } from './results.model.js';
2
- export interface ArmTableProps {
3
- rows: ArmRow[];
4
- caption: string;
5
- method: 'sequential' | 'bayesian';
6
- metricKind: 'binomial' | 'count' | 'revenue';
7
- }
8
- export declare function ArmTable({ rows, caption, method, metricKind }: ArmTableProps): import("react").JSX.Element;
@@ -1,113 +0,0 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { theme } from '../theme.js';
4
- import { RESULTS_COPY } from '../copy/results.js';
5
- import { CappedCell } from './CappedCell.js';
6
- export function ArmTable({ rows, caption, method, metricKind }) {
7
- const sequential = method === 'sequential';
8
- const showAdjustedCI = sequential && rows.some((row)=>row.comparison?.method === 'sequential' && row.comparison.adjustedCI !== undefined);
9
- const showAdjustedPValue = sequential && rows.some((row)=>row.comparison?.method === 'sequential' && row.comparison.pValueAdjusted !== undefined);
10
- const columns = 4 + Number(showAdjustedCI) + Number(showAdjustedPValue);
11
- return /*#__PURE__*/ _jsx("div", {
12
- className: "xp-arm-table",
13
- style: {
14
- color: theme.color.text,
15
- overflowX: 'auto'
16
- },
17
- children: /*#__PURE__*/ _jsxs("table", {
18
- children: [
19
- /*#__PURE__*/ _jsx("caption", {
20
- children: caption
21
- }),
22
- /*#__PURE__*/ _jsx("thead", {
23
- children: /*#__PURE__*/ _jsxs("tr", {
24
- children: [
25
- /*#__PURE__*/ _jsx("th", {
26
- scope: "col",
27
- children: RESULTS_COPY.group
28
- }),
29
- /*#__PURE__*/ _jsx("th", {
30
- scope: "col",
31
- children: RESULTS_COPY.people
32
- }),
33
- /*#__PURE__*/ _jsx("th", {
34
- scope: "col",
35
- children: metricKind === 'binomial' ? RESULTS_COPY.conversions : RESULTS_COPY.mean
36
- }),
37
- /*#__PURE__*/ _jsx("th", {
38
- scope: "col",
39
- children: sequential ? RESULTS_COPY.lift : RESULTS_COPY.chanceToWin
40
- }),
41
- /*#__PURE__*/ _jsx("th", {
42
- scope: "col",
43
- children: RESULTS_COPY.ci
44
- }),
45
- showAdjustedCI ? /*#__PURE__*/ _jsx("th", {
46
- scope: "col",
47
- children: RESULTS_COPY.adjustedCI
48
- }) : null,
49
- /*#__PURE__*/ _jsx("th", {
50
- scope: "col",
51
- children: sequential ? RESULTS_COPY.pValue : RESULTS_COPY.risk
52
- }),
53
- showAdjustedPValue ? /*#__PURE__*/ _jsx("th", {
54
- scope: "col",
55
- children: RESULTS_COPY.adjustedPValue
56
- }) : null,
57
- /*#__PURE__*/ _jsx("th", {
58
- scope: "col",
59
- children: RESULTS_COPY.comparison
60
- })
61
- ]
62
- })
63
- }),
64
- /*#__PURE__*/ _jsx("tbody", {
65
- children: rows.map((row)=>/*#__PURE__*/ _jsxs("tr", {
66
- children: [
67
- /*#__PURE__*/ _jsx("th", {
68
- scope: "row",
69
- children: row.label
70
- }),
71
- /*#__PURE__*/ _jsx("td", {
72
- children: row.n
73
- }),
74
- /*#__PURE__*/ _jsx("td", {
75
- children: metricKind === 'revenue' ? /*#__PURE__*/ _jsx(CappedCell, {
76
- model: row.capped
77
- }) : row.value
78
- }),
79
- row.baseline ? /*#__PURE__*/ _jsx("td", {
80
- colSpan: columns,
81
- children: row.baseline
82
- }) : /*#__PURE__*/ _jsxs(_Fragment, {
83
- children: [
84
- /*#__PURE__*/ _jsx("td", {
85
- children: row.comparison?.method === 'sequential' ? row.comparison.lift : row.comparison?.chanceToWin ?? '—'
86
- }),
87
- /*#__PURE__*/ _jsx("td", {
88
- children: row.comparison?.ci ?? '—'
89
- }),
90
- showAdjustedCI ? /*#__PURE__*/ _jsx("td", {
91
- children: row.comparison?.method === 'sequential' ? row.comparison.adjustedCI ?? '—' : '—'
92
- }) : null,
93
- /*#__PURE__*/ _jsx("td", {
94
- children: row.comparison?.method === 'sequential' ? row.comparison.pValue : row.comparison?.risk ?? '—'
95
- }),
96
- showAdjustedPValue ? /*#__PURE__*/ _jsx("td", {
97
- children: row.comparison?.method === 'sequential' ? row.comparison.pValueAdjusted ?? '—' : '—'
98
- }) : null,
99
- /*#__PURE__*/ _jsx("td", {
100
- children: row.comparison ? /*#__PURE__*/ _jsx("span", {
101
- className: "xp-chip",
102
- children: row.comparison.significance
103
- }) : '—'
104
- })
105
- ]
106
- })
107
- ]
108
- }, row.key))
109
- })
110
- ]
111
- })
112
- });
113
- }
@@ -1,9 +0,0 @@
1
- import type { VerdictCardModel, guardrailChips } from './results.model.js';
2
- export interface VerdictCardProps {
3
- model: VerdictCardModel;
4
- guardrails?: ReturnType<typeof guardrailChips>;
5
- power?: string | null;
6
- collecting?: string | null;
7
- sinceShipping?: string | null;
8
- }
9
- export declare function VerdictCard({ model, guardrails, power, collecting, sinceShipping }: VerdictCardProps): import("react").JSX.Element;
@@ -1,5 +0,0 @@
1
- export declare function GoalsBreadcrumb({ adminRoute, name, returnQuery }: {
2
- adminRoute: string;
3
- name?: string;
4
- returnQuery?: string;
5
- }): import("react").JSX.Element;