@sanity/personalization-plugin 2.4.2 → 2.5.0-field-level-personalization.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.
Files changed (34) hide show
  1. package/dist/_chunks-cjs/fieldExperiments.js +507 -0
  2. package/dist/_chunks-cjs/fieldExperiments.js.map +1 -0
  3. package/dist/_chunks-es/fieldExperiments.mjs +511 -0
  4. package/dist/_chunks-es/fieldExperiments.mjs.map +1 -0
  5. package/dist/growthbook/index.js +3 -3
  6. package/dist/growthbook/index.js.map +1 -1
  7. package/dist/growthbook/index.mjs +1 -1
  8. package/dist/index.d.mts +33 -12
  9. package/dist/index.d.ts +33 -12
  10. package/dist/index.js +157 -280
  11. package/dist/index.js.map +1 -1
  12. package/dist/index.mjs +159 -280
  13. package/dist/index.mjs.map +1 -1
  14. package/package.json +1 -1
  15. package/src/components/{ExperimentItem.tsx → ArrayItem.tsx} +1 -2
  16. package/src/components/Select.tsx +1 -1
  17. package/src/components/{Array.tsx → experiment/Array.tsx} +2 -2
  18. package/src/components/{ExperimentContext.tsx → experiment/Context.tsx} +2 -2
  19. package/src/components/{ExperimentField.tsx → experiment/Field.tsx} +11 -8
  20. package/src/components/{ExperimentInput.tsx → experiment/Input.tsx} +4 -4
  21. package/src/components/{VariantPreview.tsx → experiment/VariantPreview.tsx} +2 -2
  22. package/src/components/experiment/index.ts +6 -0
  23. package/src/components/personalization/Array.tsx +59 -0
  24. package/src/components/personalization/Context.tsx +61 -0
  25. package/src/components/personalization/Field.tsx +134 -0
  26. package/src/components/personalization/SegmentInput.tsx +19 -0
  27. package/src/components/personalization/SegmentPreview.tsx +71 -0
  28. package/src/components/personalization/index.ts +5 -0
  29. package/src/fieldExperiments.tsx +43 -13
  30. package/src/fieldPersonalization.tsx +254 -0
  31. package/src/index.ts +1 -0
  32. package/src/types.ts +20 -2
  33. package/src/utils/clearChildGroups.ts +33 -0
  34. /package/src/components/{VariantInput.tsx → experiment/VariantInput.tsx} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/personalization-plugin",
3
- "version": "2.4.2",
3
+ "version": "2.5.0-field-level-personalization.1",
4
4
  "description": "Plugin to help with personalization, a/b testing when using Sanity",
5
5
  "keywords": [
6
6
  "sanity",
@@ -1,10 +1,9 @@
1
1
  import {ObjectItem, ObjectItemProps, set} from 'sanity'
2
2
 
3
- export const ExperimentItem = (props: ObjectItemProps) => {
3
+ export const ArrayItem = (props: ObjectItemProps) => {
4
4
  const {active} = props.value as ObjectItem & {active: boolean}
5
5
  if (!active) {
6
6
  props.inputProps.onChange(set(true, ['active']))
7
7
  }
8
-
9
8
  return props.renderDefault(props)
10
9
  }
@@ -2,7 +2,7 @@ import {Select as SanitySelect} from '@sanity/ui'
2
2
  import {FormEvent} from 'react'
3
3
  import {FormPatch, PatchEvent, Path, StringInputProps} from 'sanity'
4
4
 
5
- import {SelectOption} from './ExperimentInput'
5
+ import {SelectOption} from './experiment/Input'
6
6
 
7
7
  export const Select = (
8
8
  props: StringInputProps & {
@@ -3,8 +3,8 @@ import {uuid} from '@sanity/uuid'
3
3
  import {useCallback} from 'react'
4
4
  import {useFormValue} from 'sanity'
5
5
 
6
- import {ArrayInputProps, VariantType} from '../types'
7
- import {useExperimentContext} from './ExperimentContext'
6
+ import {ArrayInputProps, VariantType} from '../../types'
7
+ import {useExperimentContext} from './Context'
8
8
 
9
9
  export const ArrayInput = (props: ArrayInputProps) => {
10
10
  const fieldPath = props.path.slice(0, -1)
@@ -3,7 +3,7 @@ import {createContext, useContext, useMemo} from 'react'
3
3
  import {type ObjectInputProps, useClient, useWorkspace} from 'sanity'
4
4
  import {suspend} from 'suspend-react'
5
5
 
6
- import {ExperimentContextProps, FieldPluginConfig} from '../types'
6
+ import {ExperimentContextProps, ExperimentFieldPluginConfig} from '../../types'
7
7
 
8
8
  // This provider makes the plugin config available to all components in the document form
9
9
  // But with experiments resolved
@@ -28,7 +28,7 @@ export function useExperimentContext() {
28
28
  }
29
29
 
30
30
  type ExperimentProps = ObjectInputProps & {
31
- experimentFieldPluginConfig: Required<FieldPluginConfig>
31
+ experimentFieldPluginConfig: Required<ExperimentFieldPluginConfig>
32
32
  }
33
33
 
34
34
  export function ExperimentProvider(props: ExperimentProps) {
@@ -11,6 +11,8 @@ import {
11
11
  set,
12
12
  unset,
13
13
  } from 'sanity'
14
+
15
+ import {clearChildrenGroups} from '../../utils/clearChildGroups'
14
16
  type PatchStuff = {onChange: (patch: FormPatch | FormPatch[] | PatchEvent) => void; inputId: string}
15
17
 
16
18
  const useAddExperimentAction = (
@@ -99,7 +101,7 @@ const createActions = ({
99
101
  return active ? removeAction : addAction
100
102
  }
101
103
 
102
- export const ExperimentField = (
104
+ export const Field = (
103
105
  props: ObjectFieldProps & {
104
106
  experimentNameOverride: string
105
107
  experimentId: string
@@ -127,12 +129,13 @@ export const ExperimentField = (
127
129
  return [createActions(actionProps), ...oldActions]
128
130
  }, [actionProps, props.actions])
129
131
 
130
- const withActionProps = useMemo(
131
- () => ({
132
- ...props,
132
+ const enhancedProps = useMemo(() => {
133
+ const propsWithClearedGroups = clearChildrenGroups(props)
134
+ return {
135
+ ...propsWithClearedGroups,
133
136
  actions: memoizedActions,
134
- }),
135
- [props, memoizedActions],
136
- )
137
- return props.renderDefault(withActionProps)
137
+ }
138
+ }, [props, memoizedActions])
139
+
140
+ return props.renderDefault(enhancedProps)
138
141
  }
@@ -11,9 +11,9 @@ import {
11
11
  useFormValue,
12
12
  } from 'sanity'
13
13
 
14
- import {ExperimentType} from '..'
15
- import {useExperimentContext} from './ExperimentContext'
16
- import {Select} from './Select'
14
+ import {ExperimentType} from '../..'
15
+ import {Select} from '../Select'
16
+ import {useExperimentContext} from './Context'
17
17
 
18
18
  export type SelectOption = {title: string; value: string}
19
19
  const formatlistOptions = (experiments: ExperimentType[]): SelectOption[] =>
@@ -22,7 +22,7 @@ const formatlistOptions = (experiments: ExperimentType[]): SelectOption[] =>
22
22
  value: experiment.id,
23
23
  }))
24
24
 
25
- export const ExperimentInput = (
25
+ export const Input = (
26
26
  props: StringInputProps & {variantNameOverride: string; experimentNameOverride: string},
27
27
  ) => {
28
28
  const {experiments} = useExperimentContext()
@@ -8,8 +8,8 @@ import {
8
8
  useClient,
9
9
  } from 'sanity'
10
10
 
11
- import {VariantPreviewProps} from '../types'
12
- import {useExperimentContext} from './ExperimentContext'
11
+ import {VariantPreviewProps} from '../../types'
12
+ import {useExperimentContext} from './Context'
13
13
 
14
14
  export const VariantPreview = (props: PreviewProps) => {
15
15
  const [subtitle, setSubtitle] = useState<string | undefined>(undefined)
@@ -0,0 +1,6 @@
1
+ export * from './Array'
2
+ export * from './Context'
3
+ export * from './Field'
4
+ export * from './Input'
5
+ export * from './VariantInput'
6
+ export * from './VariantPreview'
@@ -0,0 +1,59 @@
1
+ import {Button, Inline, Stack} from '@sanity/ui'
2
+ import {uuid} from '@sanity/uuid'
3
+ import {useCallback} from 'react'
4
+
5
+ import {PersonalizationArrayInputProps, VariantType} from '../../types'
6
+ import {usePersonalizationContext} from './Context'
7
+
8
+ export const ArrayInput = (props: PersonalizationArrayInputProps) => {
9
+ const {onItemAppend, segmentName, segmentId} = props
10
+
11
+ const {segments} = usePersonalizationContext()
12
+
13
+ const handleClick = useCallback(
14
+ async (segment: VariantType) => {
15
+ const item = {
16
+ _key: uuid(),
17
+ [segmentId]: segment.id,
18
+ _type: segmentName,
19
+ }
20
+
21
+ // Patch the document
22
+ onItemAppend(item)
23
+ },
24
+ [segmentId, segmentName, onItemAppend],
25
+ )
26
+
27
+ type Value = {
28
+ value?: unknown
29
+ [key: string]: string | unknown
30
+ segmentId: string
31
+ _key: string
32
+ _type: string
33
+ }
34
+
35
+ // there is probably some better was of getting the type of this?
36
+ const values = (props.value as Value[]) || []
37
+
38
+ const usedSegments = values?.map((segment) => segment[segmentId])
39
+
40
+ return (
41
+ <Stack space={3}>
42
+ {props.renderDefault({...props, arrayFunctions: () => null})}
43
+
44
+ <Inline space={1}>
45
+ {segments.map((segment) => {
46
+ return (
47
+ <Button
48
+ key={`${segment.id}`}
49
+ text={`Add ${segment.label}`}
50
+ mode="ghost"
51
+ disabled={usedSegments?.includes(segment.id)}
52
+ onClick={() => handleClick(segment)}
53
+ />
54
+ )
55
+ })}
56
+ </Inline>
57
+ </Stack>
58
+ )
59
+ }
@@ -0,0 +1,61 @@
1
+ import equal from 'fast-deep-equal'
2
+ import {createContext, useContext, useMemo} from 'react'
3
+ import {ObjectInputProps, useClient, useWorkspace} from 'sanity'
4
+ import {suspend} from 'suspend-react'
5
+
6
+ import {PersonalizationContextProps, PersonalizationFieldPluginConfig} from '../../types'
7
+
8
+ export const CONFIG_DEFAULT = {
9
+ fields: [],
10
+ apiVersion: '2024-11-07',
11
+ personalizationNameOverride: 'personalization',
12
+ segmentNameOverride: 'segment',
13
+ segmentId: 'segmentId',
14
+ segmentArrayName: 'segments',
15
+ }
16
+
17
+ export const PersonalizationContext = createContext<PersonalizationContextProps>({
18
+ ...CONFIG_DEFAULT,
19
+ segments: [],
20
+ })
21
+
22
+ export function usePersonalizationContext() {
23
+ return useContext(PersonalizationContext)
24
+ }
25
+
26
+ type PersonalizationProps = ObjectInputProps & {
27
+ personalizationFieldPluginConfig: Required<PersonalizationFieldPluginConfig>
28
+ }
29
+
30
+ export function PersonalizationProvider(props: PersonalizationProps) {
31
+ const {personalizationFieldPluginConfig} = props
32
+
33
+ const client = useClient({apiVersion: personalizationFieldPluginConfig.apiVersion})
34
+ const workspace = useWorkspace()
35
+
36
+ // Fetch or return experiments
37
+ const segments = Array.isArray(personalizationFieldPluginConfig.segments)
38
+ ? personalizationFieldPluginConfig.segments
39
+ : suspend(
40
+ // eslint-disable-next-line require-await
41
+ async () => {
42
+ if (typeof personalizationFieldPluginConfig.segments === 'function') {
43
+ return personalizationFieldPluginConfig.segments(client)
44
+ }
45
+ return personalizationFieldPluginConfig.segments
46
+ },
47
+ [workspace],
48
+ {equal},
49
+ )
50
+
51
+ const context = useMemo(
52
+ () => ({...personalizationFieldPluginConfig, segments}),
53
+ [personalizationFieldPluginConfig, segments],
54
+ )
55
+
56
+ return (
57
+ <PersonalizationContext.Provider value={context}>
58
+ {props.renderDefault(props)}
59
+ </PersonalizationContext.Provider>
60
+ )
61
+ }
@@ -0,0 +1,134 @@
1
+ import {CloseIcon} from '@sanity/icons'
2
+ import React, {useCallback, useMemo} from 'react'
3
+ import {IoMdPeople} from 'react-icons/io'
4
+ import {
5
+ defineDocumentFieldAction,
6
+ DocumentFieldActionItem,
7
+ DocumentFieldActionProps,
8
+ FormPatch,
9
+ ObjectFieldProps,
10
+ PatchEvent,
11
+ set,
12
+ unset,
13
+ } from 'sanity'
14
+
15
+ import {clearChildrenGroups} from '../../utils/clearChildGroups'
16
+
17
+ type PatchStuff = {onChange: (patch: FormPatch | FormPatch[] | PatchEvent) => void; inputId: string}
18
+
19
+ const useAddExperimentAction = (
20
+ props: DocumentFieldActionProps &
21
+ PatchStuff & {personalizationNameOverride: string; active: boolean},
22
+ ): DocumentFieldActionItem => {
23
+ const {onChange, active, personalizationNameOverride} = props
24
+
25
+ const handleAddAction = useCallback(() => {
26
+ onChange([set(!active, ['active'])])
27
+ }, [onChange, active])
28
+
29
+ return {
30
+ title: `Add ${personalizationNameOverride}`,
31
+ type: 'action',
32
+ icon: IoMdPeople,
33
+ onAction: handleAddAction,
34
+ renderAsButton: true,
35
+ }
36
+ }
37
+
38
+ const useRemoveExperimentAction = (
39
+ props: DocumentFieldActionProps &
40
+ PatchStuff & {
41
+ personalizationNameOverride: string
42
+ active: boolean
43
+ segmentNameOverride: string
44
+ },
45
+ ): DocumentFieldActionItem => {
46
+ const {onChange, active, personalizationNameOverride, segmentNameOverride} = props
47
+ const handleClearAction = useCallback(() => {
48
+ const activeId = ['active']
49
+ const segments = [`${segmentNameOverride}s`]
50
+ onChange([set(!active, activeId), unset(segments)])
51
+ }, [onChange, active, segmentNameOverride])
52
+
53
+ return {
54
+ title: `Remove ${personalizationNameOverride}`,
55
+ type: 'action',
56
+ icon: CloseIcon,
57
+ onAction: handleClearAction,
58
+ renderAsButton: true,
59
+ }
60
+ }
61
+
62
+ const createActions = ({
63
+ onChange,
64
+ inputId,
65
+ active,
66
+ personalizationNameOverride,
67
+ segmentNameOverride,
68
+ }: PatchStuff & {
69
+ active?: boolean
70
+ personalizationNameOverride: string
71
+ segmentNameOverride: string
72
+ }) => {
73
+ const removeAction = defineDocumentFieldAction({
74
+ name: `Remove ${personalizationNameOverride}`,
75
+ useAction: (props) =>
76
+ useRemoveExperimentAction({
77
+ ...props,
78
+ active: true,
79
+ onChange,
80
+ inputId,
81
+ personalizationNameOverride,
82
+ segmentNameOverride,
83
+ }),
84
+ })
85
+ const addAction = defineDocumentFieldAction({
86
+ name: `Add ${personalizationNameOverride}`,
87
+ useAction: (props) =>
88
+ useAddExperimentAction({
89
+ ...props,
90
+ active: false,
91
+ onChange,
92
+ inputId,
93
+ personalizationNameOverride,
94
+ }),
95
+ })
96
+ return active ? removeAction : addAction
97
+ }
98
+
99
+ export const Field = (
100
+ props: ObjectFieldProps & {
101
+ personalizationNameOverride: string
102
+ segmentNameOverride: string
103
+ },
104
+ ): React.ReactElement => {
105
+ const {onChange} = props.inputProps
106
+ const {inputId, personalizationNameOverride, segmentNameOverride} = props
107
+ const active = props.value?.active as boolean | undefined
108
+
109
+ const actionProps = useMemo(
110
+ () => ({
111
+ onChange,
112
+ inputId,
113
+ active,
114
+ personalizationNameOverride,
115
+ segmentNameOverride,
116
+ }),
117
+ [onChange, inputId, active, personalizationNameOverride, segmentNameOverride],
118
+ )
119
+
120
+ const memoizedActions = useMemo(() => {
121
+ const oldActions = props.actions || []
122
+ return [createActions(actionProps), ...oldActions]
123
+ }, [actionProps, props.actions])
124
+
125
+ const enhancedProps = useMemo(() => {
126
+ const propsWithClearedGroups = clearChildrenGroups(props)
127
+ return {
128
+ ...propsWithClearedGroups,
129
+ actions: memoizedActions,
130
+ }
131
+ }, [props, memoizedActions])
132
+
133
+ return props.renderDefault(enhancedProps)
134
+ }
@@ -0,0 +1,19 @@
1
+ import {Button, Inline, Stack} from '@sanity/ui'
2
+ import {ObjectInputProps, set, useFormValue} from 'sanity'
3
+
4
+ export const SegmentInput = (props: ObjectInputProps) => {
5
+ const personalizationPath = props.path.slice(0, -2)
6
+ const defaultValue = useFormValue([...personalizationPath, 'default'])
7
+ const handleClick = () => {
8
+ props.onChange(set(defaultValue, ['value']))
9
+ }
10
+ return (
11
+ <Stack space={3}>
12
+ {props.renderDefault(props)}
13
+
14
+ <Inline space={1}>
15
+ <Button text="Copy default" mode="ghost" onClick={() => handleClick()} />
16
+ </Inline>
17
+ </Stack>
18
+ )
19
+ }
@@ -0,0 +1,71 @@
1
+ import {useEffect, useState} from 'react'
2
+ import {
3
+ isImage,
4
+ isReference,
5
+ ObjectSchemaType,
6
+ PreviewProps,
7
+ ReferenceSchemaType,
8
+ useClient,
9
+ } from 'sanity'
10
+
11
+ import {VariantPreviewProps} from '../../types'
12
+ import {usePersonalizationContext} from './Context'
13
+
14
+ export const SegmentPreview = (props: PreviewProps) => {
15
+ const [subtitle, setSubtitle] = useState<string | undefined>(undefined)
16
+ const [title, setTitle] = useState<string | undefined>(undefined)
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
+ const [media, setMedia] = useState<any>(undefined)
19
+ const client = useClient({apiVersion: '2025-01-01'})
20
+ const {segments} = usePersonalizationContext()
21
+
22
+ const {segment, value} = props as VariantPreviewProps
23
+
24
+ const selectedSegment = segments.find((segmentItem) => {
25
+ return segmentItem.id === segment
26
+ })
27
+
28
+ useEffect(() => {
29
+ const getSubtitle = async () => {
30
+ setTitle(`${selectedSegment?.label}`)
31
+ if (typeof value === 'string') {
32
+ return setSubtitle(value)
33
+ }
34
+ if (isReference(value)) {
35
+ const doc = await client.getDocument(value._ref)
36
+ const type = props.schemaType as ObjectSchemaType
37
+ const valueField = type.fields.find((field) => field.name === 'value') as ObjectSchemaType
38
+ const referenceField = valueField?.type as ReferenceSchemaType
39
+ const referenceType = referenceField.to.find((field) => field.type?.name === doc?._type)
40
+
41
+ const selectFields = {} as Record<string, unknown>
42
+ const previewFields = referenceType?.preview?.select || {}
43
+ Object.keys(previewFields).forEach((key) => {
44
+ const valueKey = referenceType?.preview?.select?.[key]
45
+ selectFields[key] =
46
+ valueKey && doc
47
+ ? valueKey?.split('.').reduce((acc, index) => acc[index], doc)
48
+ : undefined
49
+ })
50
+
51
+ const previewContent = referenceType?.preview?.prepare?.(selectFields)
52
+ setMedia(previewContent?.media || selectFields.media)
53
+ return setSubtitle(previewContent?.title || (selectFields?.title as string))
54
+ }
55
+ if (isImage(value)) {
56
+ setMedia(value)
57
+ }
58
+ return ''
59
+ }
60
+ getSubtitle()
61
+ }, [value, client, selectedSegment?.label, props.schemaType])
62
+
63
+ const previewProps = {
64
+ ...props,
65
+ title: title,
66
+ subtitle: subtitle,
67
+ media: media,
68
+ }
69
+
70
+ return props.renderDefault(previewProps)
71
+ }
@@ -0,0 +1,5 @@
1
+ export * from './Array'
2
+ export * from './Context'
3
+ export * from './Field'
4
+ export * from './SegmentInput'
5
+ export * from './SegmentPreview'
@@ -7,14 +7,17 @@ import {
7
7
  isObjectInputProps,
8
8
  } from 'sanity'
9
9
 
10
- import {ArrayInput} from './components/Array'
11
- import {CONFIG_DEFAULT, ExperimentProvider} from './components/ExperimentContext'
12
- import {ExperimentField} from './components/ExperimentField'
13
- import {ExperimentInput} from './components/ExperimentInput'
14
- import {ExperimentItem} from './components/ExperimentItem'
15
- import {VariantInput} from './components/VariantInput'
16
- import {VariantPreview} from './components/VariantPreview'
17
- import {FieldPluginConfig} from './types'
10
+ import {ArrayItem} from './components/ArrayItem'
11
+ import {
12
+ ArrayInput,
13
+ CONFIG_DEFAULT,
14
+ ExperimentProvider,
15
+ Field,
16
+ Input,
17
+ VariantInput,
18
+ VariantPreview,
19
+ } from './components/experiment'
20
+ import {ExperimentFieldPluginConfig} from './types'
18
21
  import {flattenSchemaType} from './utils/flattenSchemaType'
19
22
 
20
23
  const createExperimentType = ({
@@ -39,16 +42,39 @@ const createExperimentType = ({
39
42
  return defineType({
40
43
  name: `${experimentNameOverride}${usedName}`,
41
44
  type: 'object',
45
+ groups: [
46
+ {
47
+ name: 'default',
48
+ title: 'Default',
49
+ hidden: ({parent}) => {
50
+ return !Array.isArray(parent)
51
+ },
52
+ },
53
+ {
54
+ name: 'experiments',
55
+ title: 'Experiments',
56
+ hidden: ({parent}) => {
57
+ return !Array.isArray(parent)
58
+ },
59
+ },
60
+ {
61
+ name: 'all-fields',
62
+ title: 'All fields',
63
+ hidden: ({parent}) => {
64
+ return Array.isArray(parent)
65
+ },
66
+ },
67
+ ],
42
68
  components: {
43
69
  field: (props) => (
44
- <ExperimentField
70
+ <Field
45
71
  {...props}
46
72
  experimentId={experimentId}
47
73
  experimentNameOverride={experimentNameOverride}
48
74
  variantNameOverride={variantNameOverride}
49
75
  />
50
76
  ),
51
- item: ExperimentItem,
77
+ item: ArrayItem,
52
78
  },
53
79
  fields: [
54
80
  typeof field === `string`
@@ -56,11 +82,13 @@ const createExperimentType = ({
56
82
  defineField({
57
83
  name: 'default',
58
84
  type: field,
85
+ group: 'default',
59
86
  })
60
87
  : // Pass in the configured options, but overwrite the name
61
88
  {
62
89
  ...field,
63
90
  name: 'default',
91
+ group: 'default',
64
92
  },
65
93
  defineField({
66
94
  name: 'active',
@@ -71,9 +99,10 @@ const createExperimentType = ({
71
99
  defineField({
72
100
  name: experimentId,
73
101
  type: 'string',
102
+ group: 'experiments',
74
103
  components: {
75
104
  input: (props) => (
76
- <ExperimentInput
105
+ <Input
77
106
  {...props}
78
107
  experimentNameOverride={experimentNameOverride}
79
108
  variantNameOverride={variantNameOverride}
@@ -87,6 +116,7 @@ const createExperimentType = ({
87
116
  defineField({
88
117
  name: variantArrayName,
89
118
  type: 'array',
119
+ group: 'experiments',
90
120
  hidden: ({parent}) => {
91
121
  return !parent?.[experimentId]
92
122
  },
@@ -190,7 +220,7 @@ const fieldSchema = ({
190
220
  variantId,
191
221
  variantArrayName,
192
222
  experimentId,
193
- }: Required<Omit<FieldPluginConfig, 'apiVersion' | 'experiments'>>) => {
223
+ }: Required<Omit<ExperimentFieldPluginConfig, 'apiVersion' | 'experiments'>>) => {
194
224
  return [
195
225
  ...fields.map((field) =>
196
226
  createVariantType({field, variantNameOverride, variantId, experimentId}),
@@ -208,7 +238,7 @@ const fieldSchema = ({
208
238
  ]
209
239
  }
210
240
 
211
- export const fieldLevelExperiments = definePlugin<FieldPluginConfig>((config) => {
241
+ export const fieldLevelExperiments = definePlugin<ExperimentFieldPluginConfig>((config) => {
212
242
  const pluginConfig = {...CONFIG_DEFAULT, ...config}
213
243
  const {fields, experimentNameOverride, variantNameOverride} = pluginConfig
214
244