@sanity/personalization-plugin 2.1.0-growthbook.1 → 2.2.0-growthbook.1
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 +60 -4
- package/dist/index.d.mts +19 -10
- package/dist/index.d.ts +19 -10
- package/dist/index.js +175 -66
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +175 -66
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/Array.tsx +11 -12
- package/src/components/ExperimentContext.tsx +5 -0
- package/src/components/ExperimentField.tsx +97 -41
- package/src/components/ExperimentInput.tsx +6 -3
- package/src/components/VariantInput.tsx +15 -68
- package/src/fieldExperiments.tsx +100 -34
- package/src/types.ts +19 -10
package/dist/index.mjs
CHANGED
|
@@ -9,7 +9,12 @@ import { GiSoapExperiment } from "react-icons/gi";
|
|
|
9
9
|
import { useSecrets, SettingsView } from "@sanity/studio-secrets";
|
|
10
10
|
const CONFIG_DEFAULT = {
|
|
11
11
|
fields: [],
|
|
12
|
-
apiVersion: "2024-11-07"
|
|
12
|
+
apiVersion: "2024-11-07",
|
|
13
|
+
experimentNameOverride: "experiment",
|
|
14
|
+
variantNameOverride: "variant",
|
|
15
|
+
variantId: "variantId",
|
|
16
|
+
variantArrayName: "variants",
|
|
17
|
+
experimentId: "experimentId"
|
|
13
18
|
}, ExperimentContext = createContext({
|
|
14
19
|
...CONFIG_DEFAULT,
|
|
15
20
|
experiments: [],
|
|
@@ -33,18 +38,18 @@ function ExperimentProvider(props) {
|
|
|
33
38
|
return /* @__PURE__ */ jsx(ExperimentContext.Provider, { value: context, children: props.renderDefault(props) });
|
|
34
39
|
}
|
|
35
40
|
const ArrayInput = (props) => {
|
|
36
|
-
const fieldPath = props.path.slice(0, -1), experimentId = useFormValue([...fieldPath,
|
|
41
|
+
const fieldPath = props.path.slice(0, -1), { onItemAppend, variantName, variantId, experimentId } = props, experimentValue = useFormValue([...fieldPath, experimentId]), { experiments } = useExperimentContext(), handleClick = useCallback(
|
|
37
42
|
async (variant) => {
|
|
38
43
|
const item = {
|
|
39
44
|
_key: uuid(),
|
|
40
|
-
variantId: variant.id,
|
|
41
|
-
experimentId,
|
|
42
|
-
_type:
|
|
45
|
+
[variantId]: variant.id,
|
|
46
|
+
[experimentId]: experimentValue,
|
|
47
|
+
_type: variantName
|
|
43
48
|
};
|
|
44
49
|
onItemAppend(item);
|
|
45
50
|
},
|
|
46
|
-
[experimentId,
|
|
47
|
-
), filteredVariants = experiments.find((option) => option.id ===
|
|
51
|
+
[variantId, experimentId, experimentValue, variantName, onItemAppend]
|
|
52
|
+
), filteredVariants = experiments.find((option) => option.id === experimentValue)?.variants || [], usedVariants = (props.value || [])?.map((variant) => variant[variantId]);
|
|
48
53
|
return /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
49
54
|
props.renderDefault({ ...props, arrayFunctions: () => null }),
|
|
50
55
|
/* @__PURE__ */ jsx(Inline, { space: 1, children: filteredVariants.map((variant) => /* @__PURE__ */ jsx(
|
|
@@ -55,7 +60,7 @@ const ArrayInput = (props) => {
|
|
|
55
60
|
disabled: usedVariants?.includes(variant.id),
|
|
56
61
|
onClick: () => handleClick(variant)
|
|
57
62
|
},
|
|
58
|
-
`${
|
|
63
|
+
`${experimentValue}-${variant.id}`
|
|
59
64
|
)) })
|
|
60
65
|
] });
|
|
61
66
|
}, AccessDeniedIcon = forwardRef(function(props, ref) {
|
|
@@ -6405,41 +6410,75 @@ const icons = {
|
|
|
6405
6410
|
});
|
|
6406
6411
|
Icon.displayName = "ForwardRef(Icon)";
|
|
6407
6412
|
const useAddExperimentAction = (props) => {
|
|
6408
|
-
const
|
|
6409
|
-
|
|
6410
|
-
}, [
|
|
6413
|
+
const { onChange, active, experimentNameOverride } = props, handleAddAction = useCallback(() => {
|
|
6414
|
+
onChange([set(!active, ["active"])]);
|
|
6415
|
+
}, [onChange, active]);
|
|
6411
6416
|
return {
|
|
6412
|
-
title:
|
|
6417
|
+
title: `Add ${experimentNameOverride}`,
|
|
6413
6418
|
type: "action",
|
|
6414
6419
|
icon: GiSoapExperiment,
|
|
6415
|
-
onAction:
|
|
6420
|
+
onAction: handleAddAction,
|
|
6416
6421
|
renderAsButton: !0
|
|
6417
6422
|
};
|
|
6418
6423
|
}, useRemoveExperimentAction = (props) => {
|
|
6419
|
-
const
|
|
6420
|
-
const
|
|
6421
|
-
|
|
6422
|
-
}, [
|
|
6423
|
-
props.onChange([patchActiveEvent, ...patchClearEvent]);
|
|
6424
|
-
}, [patchActiveEvent, patchClearEvent, props]);
|
|
6424
|
+
const { onChange, active, experimentId, experimentNameOverride, variantNameOverride } = props, handleClearAction = useCallback(() => {
|
|
6425
|
+
const activeId = ["active"], experiment = [experimentId], variants = [`${variantNameOverride}s`];
|
|
6426
|
+
onChange([set(!active, activeId), unset(experiment), unset(variants)]);
|
|
6427
|
+
}, [onChange, active, experimentId, variantNameOverride]);
|
|
6425
6428
|
return {
|
|
6426
|
-
title:
|
|
6429
|
+
title: `Remove ${experimentNameOverride}`,
|
|
6427
6430
|
type: "action",
|
|
6428
6431
|
icon: CloseIcon,
|
|
6429
|
-
onAction:
|
|
6432
|
+
onAction: handleClearAction,
|
|
6430
6433
|
renderAsButton: !0
|
|
6431
6434
|
};
|
|
6432
|
-
},
|
|
6433
|
-
|
|
6434
|
-
|
|
6435
|
-
|
|
6436
|
-
|
|
6437
|
-
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
|
|
6442
|
-
|
|
6435
|
+
}, createActions = ({
|
|
6436
|
+
onChange,
|
|
6437
|
+
inputId,
|
|
6438
|
+
active,
|
|
6439
|
+
experimentNameOverride,
|
|
6440
|
+
experimentId,
|
|
6441
|
+
variantNameOverride
|
|
6442
|
+
}) => {
|
|
6443
|
+
const removeAction = defineDocumentFieldAction({
|
|
6444
|
+
name: `Remove ${experimentNameOverride}`,
|
|
6445
|
+
useAction: (props) => useRemoveExperimentAction({
|
|
6446
|
+
active: !0,
|
|
6447
|
+
onChange,
|
|
6448
|
+
experimentNameOverride,
|
|
6449
|
+
experimentId,
|
|
6450
|
+
variantNameOverride
|
|
6451
|
+
})
|
|
6452
|
+
}), addAction = defineDocumentFieldAction({
|
|
6453
|
+
name: `Add ${experimentNameOverride}`,
|
|
6454
|
+
useAction: (props) => useAddExperimentAction({
|
|
6455
|
+
active: !1,
|
|
6456
|
+
onChange,
|
|
6457
|
+
experimentNameOverride
|
|
6458
|
+
})
|
|
6459
|
+
});
|
|
6460
|
+
return active ? removeAction : addAction;
|
|
6461
|
+
}, ExperimentField = (props) => {
|
|
6462
|
+
const { onChange } = props.inputProps, { inputId, experimentNameOverride, experimentId, variantNameOverride } = props, active = props.value?.active, actionProps = useMemo(
|
|
6463
|
+
() => ({
|
|
6464
|
+
onChange,
|
|
6465
|
+
inputId,
|
|
6466
|
+
active,
|
|
6467
|
+
experimentNameOverride,
|
|
6468
|
+
experimentId,
|
|
6469
|
+
variantNameOverride
|
|
6470
|
+
}),
|
|
6471
|
+
[onChange, inputId, active, experimentNameOverride, experimentId, variantNameOverride]
|
|
6472
|
+
), memoizedActions = useMemo(() => {
|
|
6473
|
+
const oldActions = props.actions || [];
|
|
6474
|
+
return [createActions(actionProps), ...oldActions];
|
|
6475
|
+
}, [actionProps, props.actions]), withActionProps = useMemo(
|
|
6476
|
+
() => ({
|
|
6477
|
+
...props,
|
|
6478
|
+
actions: memoizedActions
|
|
6479
|
+
}),
|
|
6480
|
+
[props, memoizedActions]
|
|
6481
|
+
);
|
|
6443
6482
|
return props.renderDefault(withActionProps);
|
|
6444
6483
|
}, Select = (props) => {
|
|
6445
6484
|
const {
|
|
@@ -6470,7 +6509,10 @@ const useAddExperimentAction = (props) => {
|
|
|
6470
6509
|
title: experiment.label,
|
|
6471
6510
|
value: experiment.id
|
|
6472
6511
|
})), ExperimentInput = (props) => {
|
|
6473
|
-
const { experiments } = useExperimentContext(), id = useFormValue(["_id"]), aditionalChangePath = useMemo(
|
|
6512
|
+
const { experiments } = useExperimentContext(), id = useFormValue(["_id"]), aditionalChangePath = useMemo(
|
|
6513
|
+
() => [...props.path.slice(0, -1), `${props.variantNameOverride}s`],
|
|
6514
|
+
[props.variantNameOverride, props.path]
|
|
6515
|
+
), subValues = useFormValue(aditionalChangePath), { patch } = useDocumentOperation(id.replace("drafts.", ""), props.schemaType.name), handleChange = useCallback(
|
|
6474
6516
|
(event, onChange) => {
|
|
6475
6517
|
const inputValue = event.currentTarget.value;
|
|
6476
6518
|
if (onChange(inputValue ? set(inputValue) : unset()), subValues) {
|
|
@@ -6483,6 +6525,14 @@ const useAddExperimentAction = (props) => {
|
|
|
6483
6525
|
[patch, subValues, aditionalChangePath]
|
|
6484
6526
|
);
|
|
6485
6527
|
return experiments.length ? /* @__PURE__ */ jsx(Select, { ...props, listOptions: formatlistOptions(experiments), handleChange }) : /* @__PURE__ */ jsx(Fragment, {});
|
|
6528
|
+
}, VariantInput = (props) => {
|
|
6529
|
+
const defaultValue = useFormValue([props.path[0], "default"]), handleClick = () => {
|
|
6530
|
+
props.onChange(set(defaultValue, ["value"]));
|
|
6531
|
+
};
|
|
6532
|
+
return /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
6533
|
+
props.renderDefault(props),
|
|
6534
|
+
/* @__PURE__ */ jsx(Inline, { space: 1, children: /* @__PURE__ */ jsx(Button, { text: "Copy default", mode: "ghost", onClick: () => handleClick() }) })
|
|
6535
|
+
] });
|
|
6486
6536
|
}, VariantPreview = (props) => {
|
|
6487
6537
|
const [subtitle, setSubtitle] = useState(void 0), [title, setTitle] = useState(void 0), [media, setMedia] = useState(void 0), client = useClient({ apiVersion: "2025-01-01" }), { experiments } = useExperimentContext(), { experiment, variant, value } = props, selectedExperiment = experiments.find((experimentItem) => experimentItem.id === experiment), selectedVariant = selectedExperiment?.variants.find((variantItem) => variantItem.id === variant);
|
|
6488
6538
|
useEffect(() => {
|
|
@@ -6530,15 +6580,28 @@ function extractInnerFields(fields, path, maxDepth) {
|
|
|
6530
6580
|
return [...acc, thisFieldWithPath];
|
|
6531
6581
|
}, []);
|
|
6532
6582
|
}
|
|
6533
|
-
const
|
|
6534
|
-
field
|
|
6583
|
+
const createExperimentType = ({
|
|
6584
|
+
field,
|
|
6585
|
+
experimentNameOverride,
|
|
6586
|
+
variantNameOverride,
|
|
6587
|
+
variantId,
|
|
6588
|
+
variantArrayName,
|
|
6589
|
+
experimentId
|
|
6535
6590
|
}) => {
|
|
6536
|
-
const typeName = typeof field == "string" ? field : field.name, usedName = String(typeName[0]).toUpperCase() + String(typeName).slice(1),
|
|
6591
|
+
const typeName = typeof field == "string" ? field : field.name, usedName = String(typeName[0]).toUpperCase() + String(typeName).slice(1), variantName = `${variantNameOverride}${usedName}`;
|
|
6537
6592
|
return defineType({
|
|
6538
|
-
name:
|
|
6593
|
+
name: `${experimentNameOverride}${usedName}`,
|
|
6539
6594
|
type: "object",
|
|
6540
6595
|
components: {
|
|
6541
|
-
field:
|
|
6596
|
+
field: (props) => /* @__PURE__ */ jsx(
|
|
6597
|
+
ExperimentField,
|
|
6598
|
+
{
|
|
6599
|
+
...props,
|
|
6600
|
+
experimentId,
|
|
6601
|
+
experimentNameOverride,
|
|
6602
|
+
variantNameOverride
|
|
6603
|
+
}
|
|
6604
|
+
)
|
|
6542
6605
|
},
|
|
6543
6606
|
fields: [
|
|
6544
6607
|
typeof field == "string" ? (
|
|
@@ -6560,94 +6623,140 @@ const createFieldType = ({
|
|
|
6560
6623
|
hidden: !0
|
|
6561
6624
|
}),
|
|
6562
6625
|
defineField({
|
|
6563
|
-
|
|
6564
|
-
name: "experimentId",
|
|
6626
|
+
name: experimentId,
|
|
6565
6627
|
type: "string",
|
|
6566
6628
|
components: {
|
|
6567
|
-
input: ExperimentInput
|
|
6629
|
+
input: (props) => /* @__PURE__ */ jsx(ExperimentInput, { ...props, variantNameOverride })
|
|
6568
6630
|
},
|
|
6569
6631
|
hidden: ({ parent }) => !parent?.active
|
|
6570
6632
|
}),
|
|
6571
6633
|
defineField({
|
|
6572
|
-
name:
|
|
6634
|
+
name: variantArrayName,
|
|
6573
6635
|
type: "array",
|
|
6574
|
-
hidden: ({ parent }) => !parent?.experimentId,
|
|
6636
|
+
hidden: ({ parent }) => !parent?.[experimentId],
|
|
6575
6637
|
components: {
|
|
6576
|
-
input: (props) => /* @__PURE__ */ jsx(
|
|
6638
|
+
input: (props) => /* @__PURE__ */ jsx(
|
|
6639
|
+
ArrayInput,
|
|
6640
|
+
{
|
|
6641
|
+
...props,
|
|
6642
|
+
variantName,
|
|
6643
|
+
variantId,
|
|
6644
|
+
experimentId
|
|
6645
|
+
}
|
|
6646
|
+
)
|
|
6577
6647
|
},
|
|
6578
6648
|
of: [
|
|
6579
6649
|
defineField({
|
|
6580
|
-
name:
|
|
6581
|
-
type:
|
|
6650
|
+
name: variantName,
|
|
6651
|
+
type: variantName
|
|
6582
6652
|
})
|
|
6583
6653
|
]
|
|
6584
6654
|
})
|
|
6585
6655
|
]
|
|
6586
6656
|
});
|
|
6587
|
-
},
|
|
6588
|
-
field
|
|
6657
|
+
}, createVariantType = ({
|
|
6658
|
+
field,
|
|
6659
|
+
variantNameOverride,
|
|
6660
|
+
variantId,
|
|
6661
|
+
experimentId
|
|
6589
6662
|
}) => {
|
|
6590
6663
|
const typeName = typeof field == "string" ? field : field.name, usedName = String(typeName[0]).toUpperCase() + String(typeName).slice(1);
|
|
6591
6664
|
return defineType({
|
|
6592
|
-
name:
|
|
6593
|
-
title:
|
|
6665
|
+
name: `${variantNameOverride}${usedName}`,
|
|
6666
|
+
title: `${variantNameOverride} array ${usedName}`,
|
|
6594
6667
|
type: "object",
|
|
6595
6668
|
components: {
|
|
6596
|
-
preview: VariantPreview
|
|
6669
|
+
preview: VariantPreview,
|
|
6670
|
+
input: VariantInput
|
|
6597
6671
|
},
|
|
6598
6672
|
fields: [
|
|
6599
6673
|
{
|
|
6600
6674
|
type: "string",
|
|
6601
|
-
name:
|
|
6675
|
+
name: variantId,
|
|
6602
6676
|
readOnly: !0
|
|
6603
6677
|
},
|
|
6604
6678
|
{
|
|
6605
6679
|
type: "string",
|
|
6606
|
-
name:
|
|
6680
|
+
name: experimentId,
|
|
6607
6681
|
hidden: !0
|
|
6608
6682
|
},
|
|
6609
6683
|
typeof field == "string" ? (
|
|
6610
6684
|
// Define a simple field if all we have is the name as a string
|
|
6611
6685
|
defineField({
|
|
6612
6686
|
name: "value",
|
|
6613
|
-
type: field
|
|
6614
|
-
hidden: ({
|
|
6687
|
+
type: field
|
|
6688
|
+
// hidden: ({parent}) => !parent?.[`${objectNameOverride}Id`],
|
|
6615
6689
|
})
|
|
6616
6690
|
) : (
|
|
6617
6691
|
// Pass in the configured options, but overwrite the name
|
|
6618
6692
|
{
|
|
6619
6693
|
...field,
|
|
6620
|
-
name: "value"
|
|
6621
|
-
hidden: ({
|
|
6694
|
+
name: "value"
|
|
6695
|
+
// hidden: ({parent}) => !parent?.[`${objectNameOverride}Id`],
|
|
6622
6696
|
}
|
|
6623
6697
|
)
|
|
6624
6698
|
],
|
|
6625
6699
|
preview: {
|
|
6626
6700
|
select: {
|
|
6627
|
-
variant:
|
|
6628
|
-
experiment:
|
|
6701
|
+
variant: variantId,
|
|
6702
|
+
experiment: experimentId,
|
|
6629
6703
|
value: "value"
|
|
6630
6704
|
}
|
|
6631
6705
|
}
|
|
6632
6706
|
});
|
|
6633
|
-
}, fieldSchema = ({
|
|
6634
|
-
|
|
6635
|
-
|
|
6707
|
+
}, fieldSchema = ({
|
|
6708
|
+
fields,
|
|
6709
|
+
experimentNameOverride,
|
|
6710
|
+
variantNameOverride,
|
|
6711
|
+
variantId,
|
|
6712
|
+
variantArrayName,
|
|
6713
|
+
experimentId
|
|
6714
|
+
}) => [
|
|
6715
|
+
...fields.map(
|
|
6716
|
+
(field) => createVariantType({ field, variantNameOverride, variantId, experimentId })
|
|
6717
|
+
),
|
|
6718
|
+
...fields.map(
|
|
6719
|
+
(field) => createExperimentType({
|
|
6720
|
+
field,
|
|
6721
|
+
experimentNameOverride,
|
|
6722
|
+
variantNameOverride,
|
|
6723
|
+
variantId,
|
|
6724
|
+
variantArrayName,
|
|
6725
|
+
experimentId
|
|
6726
|
+
})
|
|
6727
|
+
)
|
|
6636
6728
|
], fieldLevelExperiments = definePlugin((config) => {
|
|
6637
|
-
const pluginConfig = { ...CONFIG_DEFAULT, ...config }, { fields,
|
|
6729
|
+
const pluginConfig = { ...CONFIG_DEFAULT, ...config }, { fields, experimentNameOverride, variantNameOverride } = pluginConfig, experimentId = `${experimentNameOverride}Id`, variantArrayName = `${variantNameOverride}s`, variantId = `${variantNameOverride}Id`;
|
|
6638
6730
|
return {
|
|
6639
6731
|
name: "sanity-personalistaion-plugin-field-level-experiments",
|
|
6640
6732
|
schema: {
|
|
6641
|
-
types: fieldSchema({
|
|
6733
|
+
types: fieldSchema({
|
|
6734
|
+
fields,
|
|
6735
|
+
experimentNameOverride,
|
|
6736
|
+
variantNameOverride,
|
|
6737
|
+
variantId,
|
|
6738
|
+
variantArrayName,
|
|
6739
|
+
experimentId
|
|
6740
|
+
})
|
|
6642
6741
|
},
|
|
6643
6742
|
form: {
|
|
6644
6743
|
components: {
|
|
6645
6744
|
input: (props) => {
|
|
6646
6745
|
if (!(props.id === "root" && isObjectInputProps(props)) || !flattenSchemaType(props.schemaType).map(
|
|
6647
6746
|
(field) => field.type.name
|
|
6648
|
-
).some(
|
|
6747
|
+
).some(
|
|
6748
|
+
(name) => name.startsWith(experimentNameOverride)
|
|
6749
|
+
))
|
|
6649
6750
|
return props.renderDefault(props);
|
|
6650
|
-
const providerProps = {
|
|
6751
|
+
const providerProps = {
|
|
6752
|
+
...props,
|
|
6753
|
+
experimentFieldPluginConfig: {
|
|
6754
|
+
...pluginConfig,
|
|
6755
|
+
variantId,
|
|
6756
|
+
variantArrayName,
|
|
6757
|
+
experimentId
|
|
6758
|
+
}
|
|
6759
|
+
};
|
|
6651
6760
|
return ExperimentProvider(providerProps);
|
|
6652
6761
|
}
|
|
6653
6762
|
}
|