sanity-plugin-computed-field
Version:
Sanity plugin that computes a field's value based on other fields or relationships with its document or external data. In other words, this field memoizes a value in a document using GROQ to lookup and custom javascript to compute the value from those GRO
1 lines • 12.4 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","sources":["../src/hooks/useQueryReducer.ts","../src/utils/theme.ts","../src/components/InputControls.tsx","../src/components/ComputedBooleanInput.tsx","../src/components/ComputedNumberInput.tsx","../src/components/ComputedTextInput.tsx","../src/schema/computedBoolean.ts","../src/schema/computedNumber.ts","../src/schema/computedString.ts","../src/schema/computedText.ts","../src/plugin.ts"],"sourcesContent":["import React from 'react'\nimport {useClient, useFormValue} from 'sanity'\n\nimport {ComputedQueryResult} from '../schema/types'\ntype ComputedDocumentResult = {\n _id: string\n [s: string]: unknown\n}\nexport const useQueryReducer = <FieldDataType>({\n reduceQueryResult,\n documentQuerySelection,\n handleValueChange,\n value,\n}: {\n reduceQueryResult: (result: ComputedQueryResult) => FieldDataType | Promise<FieldDataType>\n handleValueChange: (updatedValue: FieldDataType) => void\n documentQuerySelection: string\n value?: FieldDataType\n}): {\n handleRegenerateValue: () => void\n isRegenerating: boolean\n} => {\n const [loading, setLoading] = React.useState(false)\n const client = useClient()\n const docId: string = useFormValue(['_id']) as string\n const _type: string = useFormValue(['_type']) as string\n const reducer = React.useCallback(\n (queryResult: ComputedQueryResult) => reduceQueryResult(queryResult),\n [reduceQueryResult],\n )\n const handleRegenerateValue = React.useCallback(async () => {\n const query = `*[_type == '${_type}' && _id == '${docId}' || _id == '${docId.replace(\n 'drafts.',\n '',\n )}'] {\n _id,\n ${documentQuerySelection}\n }`\n setLoading(true)\n\n const items: ComputedDocumentResult[] = await client.fetch(query)\n const draft = items.find(({_id}) => _id.includes('drafts'))\n const published = items.find(({_id}) => !_id.includes('drafts')) as ComputedDocumentResult\n\n const newValue = await Promise.resolve(reducer({draft, published}))\n\n if (newValue !== value) {\n handleValueChange(newValue)\n }\n setLoading(false)\n }, [_type, docId, documentQuerySelection, client, reducer, value, handleValueChange])\n return {\n handleRegenerateValue,\n isRegenerating: loading,\n }\n}\n","import {buildTheme} from '@sanity/ui/theme'\nexport const theme = buildTheme()\n","import {Button, Inline, Spinner} from '@sanity/ui'\nimport React from 'react'\n\ntype Props = {\n isLoading: boolean\n onClickButton: () => void\n buttonText: string\n}\nexport const InputControls: React.FC<Props> = ({buttonText, onClickButton, isLoading}) => {\n return (\n <Inline space={[2, 3]}>\n <Button onClick={onClickButton} title={buttonText} text={buttonText} mode=\"ghost\" />\n {isLoading && <Spinner />}\n </Inline>\n )\n}\n","import {Card, Flex, ThemeProvider} from '@sanity/ui'\nimport React from 'react'\nimport {BooleanInputProps, set} from 'sanity'\n\nimport {useQueryReducer} from '../hooks/useQueryReducer'\nimport {ComputedBooleanSchemaType} from '../schema/types'\nimport {theme} from '../utils/theme'\nimport {InputControls} from './InputControls'\n\nexport type ComputedBooleanInputProps = BooleanInputProps<ComputedBooleanSchemaType>\n\nexport const ComputedBooleanInput: React.FC<ComputedBooleanInputProps> = (props) => {\n const {schemaType, onChange, value} = props\n const {options} = schemaType\n const {reduceQueryResult, documentQuerySelection, buttonText = 'Regenerate'} = options\n\n const handleValueChange = React.useCallback((val: boolean) => onChange(set(val)), [onChange])\n\n const {isRegenerating, handleRegenerateValue} = useQueryReducer({\n reduceQueryResult,\n documentQuerySelection,\n handleValueChange,\n value,\n })\n return (\n <ThemeProvider theme={theme}>\n <Flex direction=\"row\" align=\"center\">\n {props.renderDefault(props)}\n <Card marginLeft={[2, 3]}>\n <InputControls\n buttonText={buttonText}\n isLoading={isRegenerating}\n onClickButton={handleRegenerateValue}\n />\n </Card>\n </Flex>\n </ThemeProvider>\n )\n}\n","import {Inline, ThemeProvider} from '@sanity/ui'\nimport React from 'react'\nimport {NumberInputProps, set} from 'sanity'\n\nimport {useQueryReducer} from '../hooks/useQueryReducer'\nimport {ComputedNumberSchemaType} from '../schema/types'\nimport {theme} from '../utils/theme'\nimport {InputControls} from './InputControls'\n\nexport type ComputedNumberInputProps = NumberInputProps<ComputedNumberSchemaType>\n\nexport const ComputedNumberInput: React.FC<ComputedNumberInputProps> = (props) => {\n const {schemaType, onChange, value} = props\n const {options} = schemaType\n const {reduceQueryResult, documentQuerySelection, buttonText = 'Regenerate'} = options\n\n const handleValueChange = React.useCallback((val: number) => onChange(set(val)), [onChange])\n\n const {isRegenerating, handleRegenerateValue} = useQueryReducer({\n reduceQueryResult,\n documentQuerySelection,\n handleValueChange,\n value,\n })\n\n return (\n <ThemeProvider theme={theme}>\n <Inline space={[2]}>\n {props.renderDefault(props)}\n <InputControls\n isLoading={isRegenerating}\n onClickButton={handleRegenerateValue}\n buttonText={buttonText}\n />\n </Inline>\n </ThemeProvider>\n )\n}\n","import {Card, Container, Flex, ThemeProvider} from '@sanity/ui'\nimport React from 'react'\nimport {set, StringInputProps} from 'sanity'\n\nimport {useQueryReducer} from '../hooks/useQueryReducer'\nimport {ComputedTextSchemaType} from '../schema/types'\nimport {theme} from '../utils/theme'\nimport {InputControls} from './InputControls'\nexport type ComputedTextInputProps = StringInputProps<ComputedTextSchemaType>\n\nexport const ComputedTextInput: React.FC<ComputedTextInputProps> = (props) => {\n const {schemaType, onChange, value} = props\n const {options, type} = schemaType\n const {reduceQueryResult, documentQuerySelection, buttonText = 'Regenerate'} = options\n\n const handleValueChange = React.useCallback((val: string) => onChange(set(val)), [onChange])\n\n const {isRegenerating, handleRegenerateValue} = useQueryReducer({\n reduceQueryResult,\n documentQuerySelection,\n handleValueChange,\n value,\n })\n const isString = type?.type?.name === 'string'\n return (\n <ThemeProvider theme={theme}>\n <Flex direction={isString ? 'row' : 'column'}>\n <Container flex={1}>{props.renderDefault(props)}</Container>\n <Card paddingLeft={isString ? 2 : 0} paddingTop={isString ? 0 : 2}>\n <InputControls\n isLoading={isRegenerating}\n onClickButton={handleRegenerateValue}\n buttonText={buttonText}\n />\n </Card>\n </Flex>\n </ThemeProvider>\n )\n}\n","import {BooleanComponents, defineType} from 'sanity'\n\nimport {ComputedBooleanInput} from '../components/ComputedBooleanInput'\n\nexport const computedBooleanSchema = defineType({\n title: 'Computed Boolean',\n type: 'boolean',\n name: 'computedBoolean',\n components: {\n input: ComputedBooleanInput as BooleanComponents['input'],\n },\n})\n","import {defineType, NumberComponents} from 'sanity'\n\nimport {ComputedNumberInput} from '../components/ComputedNumberInput'\n\nexport const computedNumberSchema = defineType({\n title: 'Computed Number',\n type: 'number',\n name: 'computedNumber',\n components: {\n input: ComputedNumberInput as NumberComponents['input'],\n },\n})\n","import {defineType, TextComponents} from 'sanity'\n\nimport {ComputedTextInput} from '../components/ComputedTextInput'\n\nexport const computedStringSchema = defineType({\n title: 'Computed String',\n type: 'string',\n name: 'computedString',\n components: {\n input: ComputedTextInput as TextComponents['input'],\n },\n})\n","import {defineType, TextComponents} from 'sanity'\n\nimport {ComputedTextInput} from '../components/ComputedTextInput'\n\nexport const computedTextSchema = defineType({\n title: 'Computed Text',\n type: 'text',\n name: 'computedText',\n components: {\n input: ComputedTextInput as TextComponents['input'],\n },\n})\n","import {definePlugin} from 'sanity'\n\nimport {computedBooleanSchema} from './schema/computedBoolean'\nimport {computedNumberSchema} from './schema/computedNumber'\nimport {computedStringSchema} from './schema/computedString'\nimport {computedTextSchema} from './schema/computedText'\n\nexport interface ComputedFieldPluginConfig {\n /* nothing here yet */\n}\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport const sanityComputedField = definePlugin<ComputedFieldPluginConfig | void>((config = {}) => {\n return {\n name: 'sanity-plugin-computed-field',\n schema: {\n types: [\n computedBooleanSchema,\n computedStringSchema,\n computedTextSchema,\n computedNumberSchema,\n ],\n },\n }\n})\n"],"names":[],"mappings":"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"}