diff --git a/src/components/InternationalizedField.tsx b/src/components/InternationalizedField.tsx index 9bc89ec..6cfb6d2 100644 --- a/src/components/InternationalizedField.tsx +++ b/src/components/InternationalizedField.tsx @@ -1,14 +1,57 @@ -import type {FieldProps} from 'sanity' +import type {ReactNode} from 'react' +import {useMemo} from 'react' +import {type FieldProps} from 'sanity' -export default function InternationalizedField(props: FieldProps) { - // Show reference field selector if there's a value - if (props.schemaType.name === 'reference' && props.value) { - return props.renderDefault({ +import {useInternationalizedArrayContext} from './InternationalizedArrayContext' + +export default function InternationalizedField(props: FieldProps): ReactNode { + const {languages} = useInternationalizedArrayContext() + + // hide titles for 'value' fields within valid language entries + const customProps = useMemo(() => { + const pathSegment = props.path.slice(0, -1)[1] + const languageId = + typeof pathSegment === 'object' && '_key' in pathSegment + ? pathSegment._key + : undefined + const hasValidLanguageId = languageId + ? languages.some((l) => l.id === languageId) + : false + const shouldHideTitle = + props.title?.toLowerCase() === 'value' && hasValidLanguageId + + return { ...props, + title: shouldHideTitle ? '' : props.title, + } + }, [props, languages]) + + if (!customProps.schemaType.name.startsWith('internationalizedArray')) { + return customProps.renderDefault(customProps) + } + + // Show reference field selector if there's a value + if (customProps.schemaType.name === 'reference' && customProps.value) { + return customProps.renderDefault({ + ...customProps, title: '', - level: 0, + level: 0, // Reset the level to avoid nested styling }) } - return props.children + // For basic field types, we can use children to keep the simple input + if ( + customProps.schemaType.name === 'string' || + customProps.schemaType.name === 'number' || + customProps.schemaType.name === 'text' + ) { + return customProps.children + } + + // For complex fields (like markdown), we need to use renderDefault + // to get all the field's functionality + return customProps.renderDefault({ + ...customProps, + level: 0, // Reset the level to avoid nested styling + }) } diff --git a/src/components/InternationalizedInput.tsx b/src/components/InternationalizedInput.tsx index 643ddce..b0fbba4 100644 --- a/src/components/InternationalizedInput.tsx +++ b/src/components/InternationalizedInput.tsx @@ -13,7 +13,7 @@ import { Tooltip, } from '@sanity/ui' import type React from 'react' -import {useCallback, useMemo} from 'react' +import {ReactNode, useCallback, useMemo} from 'react' import {type ObjectItemProps, useFormValue} from 'sanity' import {set, unset} from 'sanity' @@ -21,7 +21,7 @@ import {getLanguageDisplay} from '../utils/getLanguageDisplay' import {getToneFromValidation} from './getToneFromValidation' import {useInternationalizedArrayContext} from './InternationalizedArrayContext' -type InternationalizedValue = { +export type InternationalizedValue = { _type: string _key: string value: string @@ -29,7 +29,7 @@ type InternationalizedValue = { export default function InternationalizedInput( props: ObjectItemProps -) { +): ReactNode { const parentValue = useFormValue( props.path.slice(0, -1) ) as InternationalizedValue[] @@ -41,7 +41,7 @@ export default function InternationalizedInput( (m) => m.kind === 'field' && m.name === 'value' ), // This just overrides the type - // TODO: Remove this as it shouldn't be necessary? + // Remove this as it shouldn't be necessary? value: props.value as InternationalizedValue, } @@ -61,7 +61,7 @@ export default function InternationalizedInput( // Changes the key of this item, ideally to a valid language const handleKeyChange = useCallback( - (event: React.MouseEvent) => { + (event: React.MouseEvent): void => { const languageId = event?.currentTarget?.value if ( @@ -78,7 +78,7 @@ export default function InternationalizedInput( ) // Removes this item from the array - const handleUnset = useCallback(() => { + const handleUnset = useCallback((): void => { onChange(unset()) }, [onChange]) diff --git a/src/plugin.tsx b/src/plugin.tsx index e63e2ef..8a05dd8 100644 --- a/src/plugin.tsx +++ b/src/plugin.tsx @@ -1,6 +1,7 @@ import {definePlugin, isObjectInputProps} from 'sanity' import {InternationalizedArrayProvider} from './components/InternationalizedArrayContext' +import InternationalizedField from './components/InternationalizedField' import Preload from './components/Preload' import {CONFIG_DEFAULT} from './constants' import {internationalizedArrayFieldAction} from './fieldActions' @@ -44,6 +45,8 @@ export const internationalizedArray = definePlugin((config) => { // Wrap document editor with a language provider form: { components: { + field: (props) => , + input: (props) => { const isRootInput = props.id === 'root' && isObjectInputProps(props) diff --git a/src/schema/object.ts b/src/schema/object.ts index 2a1f498..d8a49d2 100644 --- a/src/schema/object.ts +++ b/src/schema/object.ts @@ -1,7 +1,6 @@ import {defineField, FieldDefinition} from 'sanity' import {createFieldName} from '../components/createFieldName' -import InternationalizedField from '../components/InternationalizedField' import InternationalizedInput from '../components/InternationalizedInput' type ObjectFactoryConfig = { @@ -22,23 +21,10 @@ export default (config: ObjectFactoryConfig): FieldDefinition<'object'> => { item: InternationalizedInput, }, fields: [ - typeof type === `string` - ? // Define a simple field if all we have is the name as a string - defineField({ - name: 'value', - type, - components: { - field: InternationalizedField, - }, - }) - : // Pass in the configured options, but overwrite the name - { - ...type, - name: 'value', - components: { - field: InternationalizedField, - }, - }, + defineField({ + ...(typeof type === 'string' ? {type} : type), + name: 'value', + }), ], preview: { select: {