Created
February 4, 2021 21:34
-
-
Save wildseansy/afd201a60265fc7bf65e3549077c3e06 to your computer and use it in GitHub Desktop.
Sanity: Custom Input for serialized array string
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import stringEnumerator from "../../components/stringEnumerator"; | |
export const mySchema = { | |
//...other fields | |
fruits: { | |
name: "fruits", | |
title: "Favorite Fruits", | |
type: "string", | |
inputComponent: stringEnumerator, | |
options: { | |
values: [ | |
{ value: "blueberries", title: "Blueberries", initialValue: true }, | |
{ value: "apples", title: "Apples", initialValue: true }, | |
{ value: "bananas", title: "Bananas", initialValue: true }, | |
{ value: "grapes", title: "Grapes", initialValue: false }, | |
{ value: "peaches", title: "Peaches", initialValue: false }, | |
{ value: "pears", title: "Pears", initialValue: false }, | |
], | |
}, | |
}, | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as React from "react"; | |
import { Checkbox, Grid, Flex, Text, Box } from "@sanity/ui"; | |
import PatchEvent, { set, unset } from "part:@sanity/form-builder/patch-event"; | |
import { withDocument } from "part:@sanity/form-builder"; | |
import { SanityProps } from "./types"; | |
import FormField from "part:@sanity/components/formfields/default"; | |
const createPatchFrom = (value) => | |
PatchEvent.from(value === "" ? unset() : set(value)); | |
type EnumItem = { | |
title: string; | |
value: string; | |
selected: boolean; | |
initialValue?: boolean; | |
}; | |
const deserializeValue = ( | |
value: string = "", | |
delimiter: string = "," | |
): string[] => { | |
return value.split(delimiter); | |
}; | |
const serializeItems = (items: EnumItem[], delimiter: string = ",") => { | |
const serialized = items | |
.filter(({ selected }) => selected) | |
.map(({ value }) => value) | |
.join(delimiter); | |
return serialized; | |
}; | |
const stringEnumerator = React.forwardRef((props: SanityProps, ref) => { | |
const { type, level, value } = props; | |
const options = props.type.options || {}; | |
const enums: EnumItem[] = options.values || []; | |
const delimiter = options.delimiter ?? ","; | |
const checkboxes = React.useMemo(() => { | |
const selected = new Set( | |
value ? deserializeValue((value as string) ?? "", delimiter) : [] | |
); | |
return enums.map((item) => { | |
return { | |
...item, | |
selected: selected.has(item.value), | |
}; | |
}); | |
}, [value]); | |
React.useEffect(() => { | |
//First creation: | |
if (value === undefined) { | |
props.onChange( | |
createPatchFrom( | |
serializeItems( | |
enums.map((item) => { | |
return { | |
...item, | |
selected: item.initialValue, | |
}; | |
}), | |
delimiter | |
) | |
) | |
); | |
} | |
}, []); | |
const toggleChecked = (item: EnumItem, checked: boolean) => { | |
const serialized = serializeItems( | |
checkboxes.map((checkbox) => { | |
if (item.value === checkbox.value) { | |
return { | |
...item, | |
selected: checked, | |
}; | |
} | |
return checkbox; | |
}), | |
delimiter | |
); | |
props.onChange(createPatchFrom(!serialized ? "" : serialized)); | |
}; | |
return ( | |
<FormField label={type.title} description={type.description}> | |
<Grid columns={[2]} gap={[1, 1, 2, 3]}> | |
{checkboxes.map((item) => { | |
return ( | |
<Flex align="center" as="label"> | |
<Checkbox | |
key={item.value} | |
checked={item.selected} | |
onChange={(event) => { | |
toggleChecked(item, event.target.checked); | |
}} | |
/> | |
<Box marginLeft={3}> | |
<Text>{item.title}</Text> | |
</Box> | |
</Flex> | |
); | |
})} | |
</Grid> | |
</FormField> | |
); | |
}); | |
export default withDocument(stringEnumerator); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The input component above produces:
Now I can run graphql queries like: