@delmaredigital/payload-experiments 0.2.0-rc.2 → 0.2.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.
- package/README.md +15 -0
- package/dist/admin/TestsNavLink.d.ts +1 -0
- package/dist/admin/TestsNavLink.js +1 -0
- package/dist/admin/actions/ConfirmDialog.d.ts +1 -0
- package/dist/admin/actions/ConfirmDialog.js +7 -5
- package/dist/admin/components/ChipsInput.d.ts +12 -0
- package/dist/admin/components/ChipsInput.js +96 -0
- package/dist/admin/components/RootViewMessage.d.ts +5 -0
- package/dist/admin/components/RootViewMessage.js +15 -0
- package/dist/admin/components/chipsInput.css +11 -0
- package/dist/admin/copy/audience.d.ts +4 -0
- package/dist/admin/copy/audience.js +4 -0
- package/dist/admin/copy/goals.d.ts +44 -0
- package/dist/admin/copy/goals.js +46 -0
- package/dist/admin/results/ArmTable.js +2 -1
- package/dist/admin/results/CappedCell.js +2 -1
- package/dist/admin/results/CiChart.js +8 -7
- package/dist/admin/results/DataQualityPanel.js +3 -2
- package/dist/admin/results/VerdictCard.js +3 -2
- package/dist/admin/styles.css +8 -8
- package/dist/admin/styles.d.ts +1 -0
- package/dist/admin/styles.js +1 -0
- package/dist/admin/surface/SurfaceShell.d.ts +1 -0
- package/dist/admin/surface/SurfaceShell.js +1 -0
- package/dist/admin/surface/TestsHome.js +1 -1
- package/dist/admin/surface/TestsSurface.js +10 -1
- package/dist/admin/surface/goals/GoalForm.d.ts +7 -0
- package/dist/admin/surface/goals/GoalForm.js +470 -0
- package/dist/admin/surface/goals/GoalsBreadcrumb.d.ts +5 -0
- package/dist/admin/surface/goals/GoalsBreadcrumb.js +47 -0
- package/dist/admin/surface/goals/GoalsList.d.ts +6 -0
- package/dist/admin/surface/goals/GoalsList.js +135 -0
- package/dist/admin/surface/goals/data.d.ts +3 -0
- package/dist/admin/surface/goals/data.js +24 -0
- package/dist/admin/surface/goals/goals.css +15 -0
- package/dist/admin/surface/goals/goals.model.d.ts +30 -0
- package/dist/admin/surface/goals/goals.model.js +26 -0
- package/dist/admin/surface/newTest/newTest.css +6 -6
- package/dist/admin/surface/readiness/Banner.js +5 -4
- package/dist/admin/surface/results/ResultsBody.js +3 -2
- package/dist/admin/surface/setting/setting.css +11 -11
- package/dist/admin/surface/surface.css +29 -29
- package/dist/admin/surface/test/GoalSection.js +32 -1
- package/dist/admin/surface/test/TargetingSection.js +27 -10
- package/dist/admin/surface/test/VersionsSection.js +6 -5
- package/dist/admin/surface/test/testPage.css +12 -12
- package/dist/admin/targeting/targeting.model.d.ts +6 -1
- package/dist/admin/targeting/targeting.model.js +18 -2
- package/dist/admin/theme.css +42 -0
- package/dist/admin/theme.d.ts +50 -0
- package/dist/admin/theme.js +49 -0
- package/dist/admin/views/ExperimentsRootView.js +18 -18
- package/dist/collections/metricValidation.d.ts +3 -0
- package/dist/collections/metricValidation.js +9 -0
- package/dist/collections/metrics.js +3 -5
- package/dist/endpoints/preflight.js +3 -2
- package/dist/endpoints/previewToken.js +3 -2
- package/dist/endpoints/recompute.js +3 -2
- package/dist/endpoints/results.js +3 -2
- package/dist/endpoints/routeId.d.ts +5 -0
- package/dist/endpoints/routeId.js +13 -0
- package/dist/endpoints/summary.js +32 -21
- package/dist/endpoints/transitions.js +3 -2
- package/dist/plugin.js +2 -2
- package/dist/puck/editor/CreateExperimentDrawer.d.ts +1 -0
- package/dist/puck/editor/CreateExperimentDrawer.js +34 -25
- package/dist/puck/editor/ExperimentSlotEditor.d.ts +1 -0
- package/dist/puck/editor/ExperimentSlotEditor.js +137 -78
- package/dist/puck/editor/copy.d.ts +3 -1
- package/dist/puck/editor/copy.js +3 -1
- package/dist/puck/editor/editor.css +302 -0
- package/dist/types/surface.d.ts +2 -1
- package/package.json +2 -1
|
@@ -8,6 +8,7 @@ import { bannerFor, tabsFor } from './editor.model.js';
|
|
|
8
8
|
import { cloneSlot } from './cloneSlot.js';
|
|
9
9
|
import { CreateExperimentDrawer } from './CreateExperimentDrawer.js';
|
|
10
10
|
import { editorCopy } from './copy.js';
|
|
11
|
+
import './editor.css';
|
|
11
12
|
const usePuckSelector = createUsePuck();
|
|
12
13
|
// Public Puck registration enables native controls inside the editor canvas.
|
|
13
14
|
const registerControls = (element)=>registerOverlayPortal(element, {
|
|
@@ -34,8 +35,8 @@ function EditorRender(props) {
|
|
|
34
35
|
const pageTitle = usePuckSelector((state)=>typeof state.appState.data.root.props?.title === 'string' ? state.appState.data.root.props.title : '');
|
|
35
36
|
const selected = usePuckSelector((state)=>state.selectedItem?.props.id === props.id);
|
|
36
37
|
const originalEmpty = usePuckSelector((state)=>{
|
|
37
|
-
const content = state.
|
|
38
|
-
return
|
|
38
|
+
const content = state.getItemById(props.id)?.props.control;
|
|
39
|
+
return !Array.isArray(content) || content.length === 0;
|
|
39
40
|
});
|
|
40
41
|
useEffect(()=>{
|
|
41
42
|
if (experimentId === undefined) return;
|
|
@@ -74,6 +75,10 @@ function EditorRender(props) {
|
|
|
74
75
|
const tabs = tabsFor(experiment);
|
|
75
76
|
const activeSlot = active && active.id === experimentId ? active.slot : undefined;
|
|
76
77
|
const slot = tabs.find((tab)=>tab.slot === activeSlot)?.slot ?? tabs[0]?.slot ?? 'control';
|
|
78
|
+
const slotEmpty = usePuckSelector((state)=>{
|
|
79
|
+
const content = state.getItemById(props.id)?.props[slot];
|
|
80
|
+
return !Array.isArray(content) || content.length === 0;
|
|
81
|
+
});
|
|
77
82
|
const Slot = props[slot];
|
|
78
83
|
const winnerKey = experiment?.decision?.winnerArm;
|
|
79
84
|
const winner = tabs.find((tab)=>tab.slot === winnerKey)?.label;
|
|
@@ -120,105 +125,159 @@ function EditorRender(props) {
|
|
|
120
125
|
});
|
|
121
126
|
}
|
|
122
127
|
return /*#__PURE__*/ _jsxs("section", {
|
|
123
|
-
|
|
124
|
-
border: '1px solid #aaa',
|
|
125
|
-
padding: 12
|
|
126
|
-
},
|
|
128
|
+
className: "xp-slot-root xp-slot-editor",
|
|
127
129
|
children: [
|
|
128
130
|
/*#__PURE__*/ _jsxs("div", {
|
|
131
|
+
className: "xp-slot-chrome",
|
|
129
132
|
ref: registerControls,
|
|
130
133
|
children: [
|
|
131
|
-
/*#__PURE__*/
|
|
132
|
-
|
|
133
|
-
children:
|
|
134
|
+
/*#__PURE__*/ _jsxs("header", {
|
|
135
|
+
className: "xp-slot-header",
|
|
136
|
+
children: [
|
|
137
|
+
/*#__PURE__*/ _jsx("h3", {
|
|
138
|
+
className: "xp-slot-title",
|
|
139
|
+
children: experiment?.name ?? pickerCopy.label
|
|
140
|
+
}),
|
|
141
|
+
experiment ? /*#__PURE__*/ _jsx("span", {
|
|
142
|
+
className: "xp-slot-status",
|
|
143
|
+
"data-status": experiment.status,
|
|
144
|
+
children: pickerCopy.statuses[experiment.status]
|
|
145
|
+
}) : null,
|
|
146
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
147
|
+
className: "xp-slot-actions",
|
|
148
|
+
children: [
|
|
149
|
+
experimentId === undefined ? /*#__PURE__*/ _jsx("button", {
|
|
150
|
+
className: "xp-slot-button xp-slot-button-primary",
|
|
151
|
+
type: "button",
|
|
152
|
+
disabled: !selected,
|
|
153
|
+
onClick: ()=>setCreating(true),
|
|
154
|
+
children: editorCopy.createLabel
|
|
155
|
+
}) : null,
|
|
156
|
+
experiment ? /*#__PURE__*/ _jsx("a", {
|
|
157
|
+
className: "xp-slot-button xp-slot-button-primary",
|
|
158
|
+
href: `/admin/experiments/${encodeURIComponent(String(experimentId))}${experiment.status === 'draft' ? '' : '/results'}`,
|
|
159
|
+
children: experiment.status === 'draft' ? editorCopy.setup : editorCopy.viewResults
|
|
160
|
+
}) : null
|
|
161
|
+
]
|
|
162
|
+
})
|
|
163
|
+
]
|
|
134
164
|
}),
|
|
135
|
-
/*#__PURE__*/
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
165
|
+
/*#__PURE__*/ _jsxs("p", {
|
|
166
|
+
className: experiment?.status === 'running' ? 'xp-slot-notice xp-slot-warning' : 'xp-slot-notice',
|
|
167
|
+
role: "status",
|
|
168
|
+
children: [
|
|
169
|
+
experiment?.status === 'running' ? /*#__PURE__*/ _jsxs("svg", {
|
|
170
|
+
className: "xp-slot-warning-icon",
|
|
171
|
+
"aria-hidden": "true",
|
|
172
|
+
viewBox: "0 0 24 24",
|
|
173
|
+
fill: "none",
|
|
174
|
+
stroke: "currentColor",
|
|
175
|
+
strokeWidth: "2",
|
|
176
|
+
children: [
|
|
177
|
+
/*#__PURE__*/ _jsx("path", {
|
|
178
|
+
d: "M12 3 2 21h20L12 3Z"
|
|
179
|
+
}),
|
|
180
|
+
/*#__PURE__*/ _jsx("path", {
|
|
181
|
+
d: "M12 9v5m0 3v1"
|
|
182
|
+
})
|
|
183
|
+
]
|
|
184
|
+
}) : null,
|
|
185
|
+
experimentId === undefined ? bannerFor() : result?.error ? editorCopy.loadError : experiment ? bannerFor(experiment.status, winner) : editorCopy.loading
|
|
186
|
+
]
|
|
140
187
|
}),
|
|
141
188
|
creating ? /*#__PURE__*/ _jsx(CreateExperimentDrawer, {
|
|
142
189
|
initialName: pageTitle,
|
|
143
190
|
onCreate: bind,
|
|
144
191
|
onClose: ()=>setCreating(false)
|
|
145
192
|
}) : null,
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
children: editorCopy.setup
|
|
149
|
-
}) : null,
|
|
150
|
-
/*#__PURE__*/ _jsx("div", {
|
|
151
|
-
style: {
|
|
152
|
-
display: 'flex',
|
|
153
|
-
flexWrap: 'wrap',
|
|
154
|
-
gap: 8,
|
|
155
|
-
marginBlock: 8
|
|
156
|
-
},
|
|
157
|
-
children: tabs.filter((tab)=>tab.slot !== 'control').map((tab)=>/*#__PURE__*/ _jsx("button", {
|
|
158
|
-
type: "button",
|
|
159
|
-
disabled: originalEmpty,
|
|
160
|
-
onClick: ()=>requestCopy(tab.slot),
|
|
161
|
-
children: editorCopy.copy(tab.label)
|
|
162
|
-
}, tab.slot))
|
|
163
|
-
}),
|
|
164
|
-
confirming ? /*#__PURE__*/ _jsxs("p", {
|
|
193
|
+
confirming ? /*#__PURE__*/ _jsxs("div", {
|
|
194
|
+
className: "xp-slot-confirm",
|
|
165
195
|
role: "alert",
|
|
166
196
|
children: [
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
type: "button",
|
|
171
|
-
onClick: ()=>copyTo(confirming),
|
|
172
|
-
children: editorCopy.replace
|
|
197
|
+
/*#__PURE__*/ _jsx("p", {
|
|
198
|
+
className: "xp-slot-notice",
|
|
199
|
+
children: editorCopy.replaceConfirm(tabs.find((tab)=>tab.slot === confirming)?.label ?? confirming)
|
|
173
200
|
}),
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
201
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
202
|
+
className: "xp-slot-actions",
|
|
203
|
+
children: [
|
|
204
|
+
/*#__PURE__*/ _jsx("button", {
|
|
205
|
+
className: "xp-slot-button xp-slot-button-primary",
|
|
206
|
+
type: "button",
|
|
207
|
+
onClick: ()=>copyTo(confirming),
|
|
208
|
+
children: editorCopy.replace
|
|
209
|
+
}),
|
|
210
|
+
/*#__PURE__*/ _jsx("button", {
|
|
211
|
+
className: "xp-slot-button",
|
|
212
|
+
type: "button",
|
|
213
|
+
onClick: ()=>setConfirming(null),
|
|
214
|
+
children: editorCopy.cancel
|
|
215
|
+
})
|
|
216
|
+
]
|
|
179
217
|
})
|
|
180
218
|
]
|
|
181
219
|
}) : null,
|
|
182
|
-
/*#__PURE__*/
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
220
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
221
|
+
className: "xp-slot-toolbar",
|
|
222
|
+
children: [
|
|
223
|
+
/*#__PURE__*/ _jsx("div", {
|
|
224
|
+
className: "xp-slot-tabs",
|
|
225
|
+
role: "tablist",
|
|
226
|
+
"aria-label": editorCopy.tabs,
|
|
227
|
+
children: tabs.map((tab, index)=>/*#__PURE__*/ _jsx("button", {
|
|
228
|
+
className: "xp-slot-tab",
|
|
229
|
+
type: "button",
|
|
230
|
+
role: "tab",
|
|
231
|
+
id: `${tabId}-${tab.slot}`,
|
|
232
|
+
"aria-selected": tab.slot === slot,
|
|
233
|
+
tabIndex: tab.slot === slot ? 0 : -1,
|
|
234
|
+
"aria-controls": `${tabId}-panel`,
|
|
235
|
+
onClick: ()=>setActive({
|
|
236
|
+
id: experimentId,
|
|
237
|
+
slot: tab.slot
|
|
238
|
+
}),
|
|
239
|
+
onKeyDown: (event)=>{
|
|
240
|
+
const next = event.key === 'ArrowRight' ? (index + 1) % tabs.length : event.key === 'ArrowLeft' ? (index + tabs.length - 1) % tabs.length : event.key === 'Home' ? 0 : event.key === 'End' ? tabs.length - 1 : undefined;
|
|
241
|
+
if (next === undefined) return;
|
|
242
|
+
event.preventDefault();
|
|
243
|
+
setActive({
|
|
244
|
+
id: experimentId,
|
|
245
|
+
slot: tabs[next].slot
|
|
246
|
+
});
|
|
247
|
+
const buttons = event.currentTarget.parentElement?.querySelectorAll('[role="tab"]');
|
|
248
|
+
buttons?.[next]?.focus();
|
|
249
|
+
},
|
|
250
|
+
children: tab.label
|
|
251
|
+
}, tab.slot))
|
|
252
|
+
}),
|
|
253
|
+
slot !== 'control' ? /*#__PURE__*/ _jsx("div", {
|
|
254
|
+
className: "xp-slot-actions",
|
|
255
|
+
children: /*#__PURE__*/ _jsx("button", {
|
|
256
|
+
className: "xp-slot-button",
|
|
257
|
+
type: "button",
|
|
258
|
+
disabled: !selected || originalEmpty,
|
|
259
|
+
onClick: ()=>requestCopy(slot),
|
|
260
|
+
children: editorCopy.copy
|
|
261
|
+
})
|
|
262
|
+
}) : null
|
|
263
|
+
]
|
|
214
264
|
})
|
|
215
265
|
]
|
|
216
266
|
}),
|
|
217
|
-
/*#__PURE__*/
|
|
267
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
268
|
+
className: slotEmpty ? 'xp-slot-panel xp-slot-panel-empty' : 'xp-slot-panel',
|
|
218
269
|
role: "tabpanel",
|
|
219
270
|
id: `${tabId}-panel`,
|
|
220
271
|
"aria-labelledby": `${tabId}-${slot}`,
|
|
221
|
-
children:
|
|
272
|
+
children: [
|
|
273
|
+
/*#__PURE__*/ _jsx(Slot, {
|
|
274
|
+
className: "xp-slot-drop-target"
|
|
275
|
+
}),
|
|
276
|
+
slotEmpty ? /*#__PURE__*/ _jsx("span", {
|
|
277
|
+
className: "xp-slot-drop-label",
|
|
278
|
+
children: editorCopy.dropZone(slot)
|
|
279
|
+
}) : null
|
|
280
|
+
]
|
|
222
281
|
})
|
|
223
282
|
]
|
|
224
283
|
});
|
|
@@ -10,7 +10,8 @@ export declare const editorCopy: {
|
|
|
10
10
|
readonly running: "Changing this content mid-test mixes two versions in one result";
|
|
11
11
|
readonly decided: (winner: string) => string;
|
|
12
12
|
readonly archived: "This test is archived; the winning content is shown to everyone.";
|
|
13
|
-
readonly copy:
|
|
13
|
+
readonly copy: "Copy Original to this version";
|
|
14
|
+
readonly dropZone: (slot: "control" | "variantA" | "variantB" | "variantC") => string;
|
|
14
15
|
readonly replaceConfirm: (label: string) => string;
|
|
15
16
|
readonly replace: "Replace";
|
|
16
17
|
readonly createLabel: "Test this block";
|
|
@@ -18,6 +19,7 @@ export declare const editorCopy: {
|
|
|
18
19
|
readonly cancel: "Cancel";
|
|
19
20
|
readonly name: "Name";
|
|
20
21
|
readonly setup: "Set up the test";
|
|
22
|
+
readonly viewResults: "View results";
|
|
21
23
|
readonly nameExists: "This name is too close to an existing test. Choose a different name.";
|
|
22
24
|
readonly createError: "Couldn't create the test. Try again.";
|
|
23
25
|
readonly loading: "Loading test…";
|
package/dist/puck/editor/copy.js
CHANGED
|
@@ -10,7 +10,8 @@ export const editorCopy = {
|
|
|
10
10
|
running: 'Changing this content mid-test mixes two versions in one result',
|
|
11
11
|
decided: (winner)=>`Decided: ${winner}. Use 'Make it the content' on the test to finish.`,
|
|
12
12
|
archived: 'This test is archived; the winning content is shown to everyone.',
|
|
13
|
-
copy:
|
|
13
|
+
copy: 'Copy Original to this version',
|
|
14
|
+
dropZone: (slot)=>slot === 'control' ? 'Drop the original content here' : `Drop ${editorCopy.labels[slot]} content here`,
|
|
14
15
|
replaceConfirm: (label)=>`${label} already has content. Replace it with a copy of the Original?`,
|
|
15
16
|
replace: 'Replace',
|
|
16
17
|
createLabel: 'Test this block',
|
|
@@ -18,6 +19,7 @@ export const editorCopy = {
|
|
|
18
19
|
cancel: 'Cancel',
|
|
19
20
|
name: 'Name',
|
|
20
21
|
setup: 'Set up the test',
|
|
22
|
+
viewResults: 'View results',
|
|
21
23
|
nameExists: "This name is too close to an existing test. Choose a different name.",
|
|
22
24
|
createError: "Couldn't create the test. Try again.",
|
|
23
25
|
loading: 'Loading test…',
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/* Payload 3.90 defaults from @payloadcms/ui dist/scss/colors.scss and app.scss,
|
|
2
|
+
mapped as in admin/theme.css; radii from scss/vars.scss. Literal values keep
|
|
3
|
+
the editor independent of the parent admin's styles and sizing. */
|
|
4
|
+
.xp-slot-root {
|
|
5
|
+
--xp-bg: rgb(255, 255, 255);
|
|
6
|
+
--xp-text: rgb(47, 47, 47);
|
|
7
|
+
--xp-surface: rgb(245, 245, 245);
|
|
8
|
+
--xp-surface-raised: rgb(235, 235, 235);
|
|
9
|
+
--xp-border: rgb(221, 221, 221);
|
|
10
|
+
--xp-border-strong: rgb(208, 208, 208);
|
|
11
|
+
--xp-input-border: rgb(181, 181, 181);
|
|
12
|
+
--xp-border-accent: rgb(154, 154, 154);
|
|
13
|
+
--xp-text-muted: rgb(101, 101, 101);
|
|
14
|
+
--xp-text-strong: rgb(47, 47, 47);
|
|
15
|
+
--xp-text-emphasis: rgb(20, 20, 20);
|
|
16
|
+
--xp-input-bg: rgb(255, 255, 255);
|
|
17
|
+
--xp-success-surface: rgb(218, 237, 248);
|
|
18
|
+
--xp-success: rgb(21, 135, 186);
|
|
19
|
+
--xp-success-text-strong: rgb(18, 56, 76);
|
|
20
|
+
--xp-warning-surface: rgb(248, 232, 219);
|
|
21
|
+
--xp-warning: rgb(185, 108, 13);
|
|
22
|
+
--xp-warning-text-strong: rgb(73, 47, 21);
|
|
23
|
+
--xp-error-text: rgb(182, 54, 54);
|
|
24
|
+
--xp-radius: 3px;
|
|
25
|
+
--xp-radius-large: 4px;
|
|
26
|
+
--xp-space-1: 5px;
|
|
27
|
+
--xp-space-2: 10px;
|
|
28
|
+
--xp-space-3: 15px;
|
|
29
|
+
--xp-space-4: 20px;
|
|
30
|
+
--xp-font-body: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
31
|
+
--xp-font-size-small: 13px;
|
|
32
|
+
--xp-font-size-body: 15px;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* payload-puck's IframeWrapper sets both class="dark" and data-theme="dark" on the canvas <html>. */
|
|
36
|
+
[data-theme='dark'] .xp-slot-root,
|
|
37
|
+
.dark .xp-slot-root {
|
|
38
|
+
--xp-bg: rgb(20, 20, 20);
|
|
39
|
+
--xp-text: rgb(255, 255, 255);
|
|
40
|
+
--xp-surface: rgb(34, 34, 34);
|
|
41
|
+
--xp-surface-raised: rgb(47, 47, 47);
|
|
42
|
+
--xp-border: rgb(60, 60, 60);
|
|
43
|
+
--xp-border-strong: rgb(74, 74, 74);
|
|
44
|
+
--xp-input-border: rgb(101, 101, 101);
|
|
45
|
+
--xp-border-accent: rgb(141, 141, 141);
|
|
46
|
+
--xp-text-muted: rgb(181, 181, 181);
|
|
47
|
+
--xp-text-strong: rgb(235, 235, 235);
|
|
48
|
+
--xp-text-emphasis: rgb(255, 255, 255);
|
|
49
|
+
--xp-input-bg: rgb(34, 34, 34);
|
|
50
|
+
--xp-success-surface: rgb(19, 44, 58);
|
|
51
|
+
--xp-success: rgb(21, 135, 186);
|
|
52
|
+
--xp-success-text-strong: rgb(188, 225, 248);
|
|
53
|
+
--xp-warning-surface: rgb(56, 38, 20);
|
|
54
|
+
--xp-warning: rgb(185, 108, 13);
|
|
55
|
+
--xp-warning-text-strong: rgb(243, 212, 186);
|
|
56
|
+
--xp-error-text: rgb(246, 109, 103);
|
|
57
|
+
--xp-radius: 3px;
|
|
58
|
+
--xp-radius-large: 4px;
|
|
59
|
+
--xp-space-1: 5px;
|
|
60
|
+
--xp-space-2: 10px;
|
|
61
|
+
--xp-space-3: 15px;
|
|
62
|
+
--xp-space-4: 20px;
|
|
63
|
+
--xp-font-body: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
64
|
+
--xp-font-size-small: 13px;
|
|
65
|
+
--xp-font-size-body: 15px;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* These controls also render in the host's preflight-reset editor iframe. */
|
|
69
|
+
.xp-slot-editor {
|
|
70
|
+
min-width: 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.xp-slot-chrome,
|
|
74
|
+
.xp-slot-drawer {
|
|
75
|
+
box-sizing: border-box;
|
|
76
|
+
background: var(--xp-bg);
|
|
77
|
+
color: var(--xp-text);
|
|
78
|
+
border: 1px solid var(--xp-border);
|
|
79
|
+
border-radius: var(--xp-radius-large);
|
|
80
|
+
padding: var(--xp-space-3);
|
|
81
|
+
font-family: var(--xp-font-body);
|
|
82
|
+
font-size: var(--xp-font-size-body);
|
|
83
|
+
line-height: 1.5;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.xp-slot-header,
|
|
87
|
+
.xp-slot-toolbar,
|
|
88
|
+
.xp-slot-actions {
|
|
89
|
+
display: flex;
|
|
90
|
+
flex-wrap: wrap;
|
|
91
|
+
align-items: center;
|
|
92
|
+
gap: var(--xp-space-2);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.xp-slot-header > .xp-slot-actions,
|
|
96
|
+
.xp-slot-toolbar > .xp-slot-actions {
|
|
97
|
+
margin-inline-start: auto;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.xp-slot-title {
|
|
101
|
+
margin: 0;
|
|
102
|
+
color: var(--xp-text);
|
|
103
|
+
font: inherit;
|
|
104
|
+
font-weight: 600;
|
|
105
|
+
overflow-wrap: anywhere;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.xp-slot-status {
|
|
109
|
+
display: inline-flex;
|
|
110
|
+
padding: var(--xp-space-1) var(--xp-space-2);
|
|
111
|
+
border: 1px solid var(--xp-border-strong);
|
|
112
|
+
border-radius: var(--xp-radius-large);
|
|
113
|
+
background: var(--xp-surface);
|
|
114
|
+
color: var(--xp-text-strong);
|
|
115
|
+
font-size: var(--xp-font-size-small);
|
|
116
|
+
line-height: 1.2;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.xp-slot-status[data-status='running'] {
|
|
120
|
+
background: var(--xp-success-surface);
|
|
121
|
+
border-color: var(--xp-success);
|
|
122
|
+
color: var(--xp-success-text-strong);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.xp-slot-notice {
|
|
126
|
+
margin: var(--xp-space-3) 0;
|
|
127
|
+
color: var(--xp-text-muted);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.xp-slot-warning {
|
|
131
|
+
display: flex;
|
|
132
|
+
align-items: flex-start;
|
|
133
|
+
gap: var(--xp-space-2);
|
|
134
|
+
border: 1px solid var(--xp-warning);
|
|
135
|
+
border-radius: var(--xp-radius);
|
|
136
|
+
padding: var(--xp-space-2) var(--xp-space-3);
|
|
137
|
+
background: var(--xp-warning-surface);
|
|
138
|
+
color: var(--xp-warning-text-strong);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.xp-slot-warning-icon {
|
|
142
|
+
flex: 0 0 auto;
|
|
143
|
+
width: var(--xp-space-4);
|
|
144
|
+
height: var(--xp-space-4);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.xp-slot-button,
|
|
148
|
+
.xp-slot-tab,
|
|
149
|
+
.xp-slot-input {
|
|
150
|
+
box-sizing: border-box;
|
|
151
|
+
appearance: none;
|
|
152
|
+
background: var(--xp-bg);
|
|
153
|
+
border: 1px solid var(--xp-input-border);
|
|
154
|
+
padding: var(--xp-space-2) var(--xp-space-3);
|
|
155
|
+
border-radius: var(--xp-radius);
|
|
156
|
+
font: inherit;
|
|
157
|
+
font-size: var(--xp-font-size-body);
|
|
158
|
+
color: var(--xp-text);
|
|
159
|
+
cursor: pointer;
|
|
160
|
+
line-height: 1.4;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.xp-slot-button {
|
|
164
|
+
display: inline-flex;
|
|
165
|
+
align-items: center;
|
|
166
|
+
justify-content: center;
|
|
167
|
+
gap: var(--xp-space-1);
|
|
168
|
+
text-decoration: none;
|
|
169
|
+
text-align: center;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.xp-slot-button:hover:not(:disabled),
|
|
173
|
+
.xp-slot-tab:hover:not(:disabled) {
|
|
174
|
+
background: var(--xp-surface-raised);
|
|
175
|
+
border-color: var(--xp-border-accent);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.xp-slot-button-primary {
|
|
179
|
+
background: var(--xp-text-emphasis);
|
|
180
|
+
border-color: var(--xp-text-emphasis);
|
|
181
|
+
color: var(--xp-bg);
|
|
182
|
+
font-weight: 600;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.xp-slot-button-primary:hover:not(:disabled) {
|
|
186
|
+
background: var(--xp-text-strong);
|
|
187
|
+
border-color: var(--xp-text-strong);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.xp-slot-button:focus-visible,
|
|
191
|
+
.xp-slot-tab:focus-visible,
|
|
192
|
+
.xp-slot-input:focus-visible {
|
|
193
|
+
outline: 2px solid var(--xp-text);
|
|
194
|
+
outline-offset: 2px;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.xp-slot-button:disabled,
|
|
198
|
+
.xp-slot-tab:disabled,
|
|
199
|
+
.xp-slot-input:disabled {
|
|
200
|
+
background: var(--xp-surface);
|
|
201
|
+
border-color: var(--xp-border);
|
|
202
|
+
color: var(--xp-text-muted);
|
|
203
|
+
cursor: not-allowed;
|
|
204
|
+
opacity: 0.65;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.xp-slot-tabs {
|
|
208
|
+
display: flex;
|
|
209
|
+
flex-wrap: wrap;
|
|
210
|
+
gap: var(--xp-space-1);
|
|
211
|
+
padding: var(--xp-space-1);
|
|
212
|
+
border-radius: var(--xp-radius-large);
|
|
213
|
+
background: var(--xp-surface);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.xp-slot-tab {
|
|
217
|
+
background: transparent;
|
|
218
|
+
border-color: transparent;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.xp-slot-tab[aria-selected='true'] {
|
|
222
|
+
background: var(--xp-bg);
|
|
223
|
+
border-color: var(--xp-border-accent);
|
|
224
|
+
color: var(--xp-text-emphasis);
|
|
225
|
+
font-weight: 600;
|
|
226
|
+
box-shadow: 0 2px 0 var(--xp-text-emphasis);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.xp-slot-panel {
|
|
230
|
+
position: relative;
|
|
231
|
+
border: 0;
|
|
232
|
+
padding: 0;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.xp-slot-panel-empty {
|
|
236
|
+
margin-top: var(--xp-space-2);
|
|
237
|
+
border: 2px dashed var(--xp-border-accent);
|
|
238
|
+
border-radius: var(--xp-radius-large);
|
|
239
|
+
background: var(--xp-surface);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.xp-slot-drop-target {
|
|
243
|
+
border: 0;
|
|
244
|
+
padding: 0;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.xp-slot-panel-empty > .xp-slot-drop-target {
|
|
248
|
+
min-height: 160px;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.xp-slot-drop-label {
|
|
252
|
+
position: absolute;
|
|
253
|
+
inset: 0;
|
|
254
|
+
display: flex;
|
|
255
|
+
align-items: center;
|
|
256
|
+
justify-content: center;
|
|
257
|
+
padding: var(--xp-space-4);
|
|
258
|
+
color: var(--xp-text-muted);
|
|
259
|
+
font-family: var(--xp-font-body);
|
|
260
|
+
font-size: var(--xp-font-size-body);
|
|
261
|
+
line-height: 1.5;
|
|
262
|
+
text-align: center;
|
|
263
|
+
pointer-events: none;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.xp-slot-drawer {
|
|
267
|
+
display: grid;
|
|
268
|
+
gap: var(--xp-space-3);
|
|
269
|
+
margin-block: var(--xp-space-3);
|
|
270
|
+
padding: var(--xp-space-4);
|
|
271
|
+
border-color: var(--xp-border-accent);
|
|
272
|
+
background: var(--xp-surface);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.xp-slot-field {
|
|
276
|
+
display: grid;
|
|
277
|
+
gap: var(--xp-space-1);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.xp-slot-label {
|
|
281
|
+
font-weight: 600;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.xp-slot-input {
|
|
285
|
+
width: 100%;
|
|
286
|
+
min-width: 0;
|
|
287
|
+
background: var(--xp-input-bg);
|
|
288
|
+
cursor: text;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.xp-slot-error {
|
|
292
|
+
margin: 0;
|
|
293
|
+
color: var(--xp-error-text);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.xp-slot-confirm {
|
|
297
|
+
padding: var(--xp-space-2) var(--xp-space-3);
|
|
298
|
+
margin-block: var(--xp-space-3);
|
|
299
|
+
border: 1px solid var(--xp-warning);
|
|
300
|
+
border-radius: var(--xp-radius);
|
|
301
|
+
background: var(--xp-warning-surface);
|
|
302
|
+
}
|
package/dist/types/surface.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { DocId } from './contracts.js';
|
|
2
2
|
import type { SerializedAttributeKeys, SerializedFlagPoint, SerializedMetricSource } from './admin.js';
|
|
3
|
-
export type TestsRoute = 'home' | 'new' | 'test' | 'results';
|
|
3
|
+
export type TestsRoute = 'home' | 'new' | 'test' | 'results' | 'goals' | 'goalNew' | 'goal';
|
|
4
4
|
export interface TestsSurfaceProps {
|
|
5
5
|
route: TestsRoute;
|
|
6
6
|
id?: string;
|
|
7
|
+
returnToTest?: string;
|
|
7
8
|
adminRoute: string;
|
|
8
9
|
apiRoute: string;
|
|
9
10
|
isAdmin: boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@delmaredigital/payload-experiments",
|
|
3
|
-
"version": "0.2.0-rc.
|
|
3
|
+
"version": "0.2.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",
|
|
@@ -67,6 +67,7 @@
|
|
|
67
67
|
"import": "./dist/exports/puckEditor.js",
|
|
68
68
|
"default": "./dist/exports/puckEditor.js"
|
|
69
69
|
},
|
|
70
|
+
"./puck/editor.css": "./dist/puck/editor/editor.css",
|
|
70
71
|
"./package.json": "./package.json"
|
|
71
72
|
},
|
|
72
73
|
"files": [
|