@delmaredigital/payload-experiments 0.4.0-rc.1 → 0.4.0-rc.3

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 (93) hide show
  1. package/README.md +283 -773
  2. package/dist/admin/TestsDashboardCards.d.ts +1 -0
  3. package/dist/admin/TestsDashboardCards.js +4 -8
  4. package/dist/admin/TestsNavLink.d.ts +1 -0
  5. package/dist/admin/TestsNavLink.js +4 -10
  6. package/dist/admin/api.d.ts +7 -0
  7. package/dist/admin/api.js +27 -0
  8. package/dist/admin/blocks/BlockPanel.js +65 -19
  9. package/dist/admin/blocks/formApi.d.ts +3 -0
  10. package/dist/admin/blocks/formApi.js +9 -3
  11. package/dist/admin/blocks/statusCache.d.ts +2 -0
  12. package/dist/admin/blocks/statusCache.js +11 -2
  13. package/dist/admin/copy/blocks.d.ts +16 -0
  14. package/dist/admin/copy/blocks.js +27 -1
  15. package/dist/admin/copy/common.d.ts +1 -0
  16. package/dist/admin/copy/common.js +1 -1
  17. package/dist/admin/copy/goals.d.ts +1 -0
  18. package/dist/admin/copy/goals.js +1 -0
  19. package/dist/admin/copy/pages.d.ts +2 -4
  20. package/dist/admin/copy/pages.js +3 -5
  21. package/dist/admin/copy/readiness.d.ts +1 -0
  22. package/dist/admin/copy/readiness.js +1 -0
  23. package/dist/admin/goals/XpGoalField.d.ts +2 -0
  24. package/dist/admin/goals/XpGoalField.js +51 -35
  25. package/dist/admin/goals/xpGoalField.css +48 -0
  26. package/dist/admin/paths.d.ts +3 -0
  27. package/dist/admin/paths.js +3 -0
  28. package/dist/admin/surface/TestsHome.js +2 -4
  29. package/dist/admin/surface/TestsSurface.js +2 -5
  30. package/dist/admin/surface/goals/GoalForm.js +18 -18
  31. package/dist/admin/surface/goals/GoalsList.js +2 -1
  32. package/dist/admin/surface/home.model.d.ts +2 -2
  33. package/dist/admin/surface/newTest/NewTest.js +2 -4
  34. package/dist/admin/surface/newTest/PageWizard.js +7 -2
  35. package/dist/admin/surface/pagePicker/CopyRoute.d.ts +1 -1
  36. package/dist/admin/surface/pagePicker/{PagePicker.d.ts → PageCombobox.d.ts} +3 -3
  37. package/dist/admin/surface/pagePicker/PageCombobox.js +395 -0
  38. package/dist/admin/surface/pagePicker/pagePicker.css +10 -0
  39. package/dist/admin/surface/pagePicker/pagePicker.model.d.ts +2 -0
  40. package/dist/admin/surface/readiness/readiness.model.js +1 -0
  41. package/dist/admin/surface/results/ResultsHeader.js +3 -8
  42. package/dist/admin/surface/results/useResults.d.ts +10 -0
  43. package/dist/admin/surface/test/GoalSection.js +4 -7
  44. package/dist/admin/surface/test/Section.js +9 -8
  45. package/dist/admin/surface/test/TestPage.js +3 -8
  46. package/dist/admin/surface/test/pageParts.js +10 -39
  47. package/dist/admin/surface/test/testPage.css +0 -5
  48. package/dist/admin/surface/useTestDocument.d.ts +4 -0
  49. package/dist/admin/surfaceUrls.d.ts +7 -0
  50. package/dist/admin/surfaceUrls.js +19 -0
  51. package/dist/admin/theme.css +2 -0
  52. package/dist/admin/useApi.d.ts +10 -0
  53. package/dist/admin/views/CollectionListRedirect.d.ts +1 -0
  54. package/dist/admin/views/CollectionListRedirect.js +1 -1
  55. package/dist/admin/views/ExperimentsRootView.js +18 -165
  56. package/dist/admin/views/GoalEditRedirect.d.ts +4 -0
  57. package/dist/admin/views/GoalEditRedirect.js +14 -0
  58. package/dist/admin/views/GoalsCollectionListView.d.ts +2 -0
  59. package/dist/admin/views/GoalsCollectionListView.js +4 -0
  60. package/dist/admin/views/TestsCollectionListView.d.ts +2 -0
  61. package/dist/admin/views/TestsCollectionListView.js +4 -0
  62. package/dist/admin/views/TestsNavLinkServer.d.ts +1 -0
  63. package/dist/admin/views/TestsNavLinkServer.js +1 -1
  64. package/dist/admin/views/buildSurfaceProps.d.ts +8 -0
  65. package/dist/admin/views/buildSurfaceProps.js +143 -0
  66. package/dist/admin/views/renderCollectionList.d.ts +2 -0
  67. package/dist/admin/views/renderCollectionList.js +34 -0
  68. package/dist/admin/views/renderTestsSurface.d.ts +3 -0
  69. package/dist/admin/views/renderTestsSurface.js +34 -0
  70. package/dist/collections/experiments/config.js +9 -5
  71. package/dist/collections/metrics.js +16 -4
  72. package/dist/exports/adminRsc.d.ts +3 -0
  73. package/dist/exports/adminRsc.js +3 -0
  74. package/dist/fields/xpGoal.js +2 -14
  75. package/dist/goals/picker/copy.d.ts +2 -0
  76. package/dist/goals/picker/copy.js +7 -0
  77. package/dist/goals/validate.d.ts +3 -0
  78. package/dist/goals/validate.js +15 -0
  79. package/dist/hooks/puckGoals.d.ts +5 -0
  80. package/dist/hooks/puckGoals.js +62 -0
  81. package/dist/plugin.js +12 -18
  82. package/dist/puck/editor/editor.chrome.css +13 -0
  83. package/dist/puck/editor/editor.css +105 -0
  84. package/dist/puck/editor/xpGoalPuckEditorField.js +28 -20
  85. package/dist/sanitizeReadinessDetail.js +2 -0
  86. package/dist/transitions/checkStart.d.ts +2 -1
  87. package/dist/transitions/checkStart.js +3 -1
  88. package/dist/transitions/decide.js +1 -0
  89. package/dist/transitions/start.js +2 -1
  90. package/dist/types/endpoints.d.ts +1 -1
  91. package/dist/ui/ui.css +4 -0
  92. package/package.json +1 -1
  93. package/dist/admin/surface/pagePicker/PagePicker.js +0 -172
package/dist/ui/ui.css CHANGED
@@ -74,6 +74,10 @@
74
74
  .xp-ui-chips p:not(.xp-ui-error) { margin: 0; color: var(--xp-text-muted); font-size: var(--xp-font-size-small); }
75
75
  /* Quiet actions and breadcrumb links stay neutral; only the selected tab takes the text accent. */
76
76
  .xp-ui-button-group { display: flex; flex-wrap: wrap; gap: 8px; min-width: 0; max-width: 100%; }
77
+ .xp-ui-inline-row { display: flex; flex-wrap: wrap; align-items: end; gap: var(--xp-space-3); min-width: 0; }
78
+ .xp-ui-inline-row > .xp-ui-field { flex: 1 1 auto; min-width: 0; }
79
+ .xp-ui-inline-row > .xp-ui-button { flex: 0 0 auto; }
80
+ .xp-ui-subpanel { display: grid; gap: var(--xp-space-3); border: 1px solid var(--xp-border); border-radius: var(--xp-radius-card); padding: var(--xp-space-4); }
77
81
  @media (prefers-reduced-motion: reduce) {
78
82
  .xp-ui-button, .xp-ui-input, .xp-ui-toggle, .xp-ui-toggle::before, .xp-ui-chips-control { transition: none; }
79
83
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@delmaredigital/payload-experiments",
3
- "version": "0.4.0-rc.1",
3
+ "version": "0.4.0-rc.3",
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",
@@ -1,172 +0,0 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { useEffect, useId, useMemo, useRef, useState } from 'react';
4
- import { createApi } from '../../api.js';
5
- import { PAGE_COPY as C } from '../../copy/pages.js';
6
- import { reasonFor } from '../test/fields.js';
7
- import { disabledPageReason, isLatestPageRequest } from './pagePicker.model.js';
8
- /** Mount on open; every reopen and return from another tab refreshes the current query. */ export function PagePicker({ collection, test, armKey, apiRoute, onChoose }) {
9
- const api = useMemo(()=>createApi(apiRoute), [
10
- apiRoute
11
- ]);
12
- const id = useId();
13
- const [search, setSearch] = useState('');
14
- const [q, setQuery] = useState('');
15
- const [page, setPage] = useState(1);
16
- const [refresh, setRefresh] = useState(0);
17
- const [rows, setRows] = useState([]);
18
- const [more, setMore] = useState(false);
19
- const [loading, setLoading] = useState(true);
20
- const [error, setError] = useState('');
21
- const revision = useRef(0);
22
- const reload = ()=>{
23
- setPage(1);
24
- setRefresh((value)=>value + 1);
25
- };
26
- useEffect(()=>{
27
- if (search === q) return;
28
- const timer = setTimeout(()=>{
29
- setQuery(search);
30
- setPage(1);
31
- setRows([]);
32
- setMore(false);
33
- setLoading(true);
34
- setError('');
35
- }, 250);
36
- return ()=>clearTimeout(timer);
37
- }, [
38
- search,
39
- q
40
- ]);
41
- useEffect(()=>{
42
- let lastReturn = -Infinity;
43
- const focus = ()=>{
44
- if (document.visibilityState !== 'visible' || Date.now() - lastReturn < 100) return;
45
- lastReturn = Date.now();
46
- setPage(1);
47
- setRefresh((value)=>value + 1);
48
- };
49
- const visible = ()=>{
50
- if (document.visibilityState === 'visible') focus();
51
- };
52
- window.addEventListener('focus', focus);
53
- document.addEventListener('visibilitychange', visible);
54
- return ()=>{
55
- window.removeEventListener('focus', focus);
56
- document.removeEventListener('visibilitychange', visible);
57
- };
58
- }, []);
59
- useEffect(()=>{
60
- const controller = new AbortController();
61
- const request = ++revision.current;
62
- setLoading(true);
63
- setError('');
64
- void api.pages({
65
- collection: collection.slug,
66
- q,
67
- page
68
- }, controller.signal).then((result)=>{
69
- if (controller.signal.aborted || !isLatestPageRequest(request, revision.current)) return;
70
- if (result.ok && result.data) {
71
- const docs = result.data.docs;
72
- setRows((current)=>{
73
- const combined = page === 1 ? docs : [
74
- ...current,
75
- ...docs
76
- ];
77
- return combined.filter((row, index)=>combined.findIndex((item)=>item.id === row.id) === index);
78
- });
79
- setMore(result.data.hasNextPage);
80
- } else {
81
- setMore(false);
82
- setError(C.error);
83
- }
84
- setLoading(false);
85
- });
86
- return ()=>controller.abort();
87
- }, [
88
- api,
89
- collection.slug,
90
- q,
91
- page,
92
- refresh
93
- ]);
94
- const reason = reasonFor(test, 'arms');
95
- return /*#__PURE__*/ _jsxs("div", {
96
- className: "xp-page-picker",
97
- children: [
98
- /*#__PURE__*/ _jsx("label", {
99
- htmlFor: id,
100
- children: C.search
101
- }),
102
- /*#__PURE__*/ _jsx("input", {
103
- id: id,
104
- type: "search",
105
- value: search,
106
- onChange: (event)=>setSearch(event.currentTarget.value)
107
- }),
108
- loading && !rows.length ? /*#__PURE__*/ _jsx("p", {
109
- role: "status",
110
- children: C.loading
111
- }) : null,
112
- error ? /*#__PURE__*/ _jsxs("p", {
113
- role: "alert",
114
- children: [
115
- error,
116
- " ",
117
- /*#__PURE__*/ _jsx("button", {
118
- type: "button",
119
- onClick: reload,
120
- children: C.retry
121
- })
122
- ]
123
- }) : null,
124
- !rows.length ? !loading && !error ? /*#__PURE__*/ _jsx("p", {
125
- children: C.empty
126
- }) : null : /*#__PURE__*/ _jsx("ul", {
127
- children: rows.map((row)=>{
128
- const disabled = reason ?? disabledPageReason(row, armKey, test.doc?.arms ?? [], test.preflight?.pagePlacements, test.chosenPages, collection.label, collection.slug);
129
- return /*#__PURE__*/ _jsxs("li", {
130
- children: [
131
- /*#__PURE__*/ _jsxs("button", {
132
- type: "button",
133
- disabled: !!disabled || test.saving === 'saving',
134
- onClick: ()=>{
135
- const arm = test.doc?.arms.find((item)=>item.key === armKey);
136
- if (!arm || row.path === null || disabled) return;
137
- void test.choosePage(arm.key, {
138
- id: row.id,
139
- path: row.path
140
- });
141
- onChoose?.();
142
- },
143
- children: [
144
- /*#__PURE__*/ _jsx("strong", {
145
- children: row.title
146
- }),
147
- ' ',
148
- row.path,
149
- !row.published ? /*#__PURE__*/ _jsxs(_Fragment, {
150
- children: [
151
- " · ",
152
- C.draft
153
- ]
154
- }) : null
155
- ]
156
- }),
157
- disabled ? /*#__PURE__*/ _jsx("p", {
158
- children: disabled
159
- }) : null
160
- ]
161
- }, row.id);
162
- })
163
- }),
164
- more ? /*#__PURE__*/ _jsx("button", {
165
- type: "button",
166
- disabled: loading,
167
- onClick: ()=>setPage((value)=>value + 1),
168
- children: C.more
169
- }) : null
170
- ]
171
- });
172
- }