Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 50 additions & 7 deletions src/components/InternationalizedField.tsx
Original file line number Diff line number Diff line change
@@ -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
})
}
12 changes: 6 additions & 6 deletions src/components/InternationalizedInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,23 @@ 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'

import {getLanguageDisplay} from '../utils/getLanguageDisplay'
import {getToneFromValidation} from './getToneFromValidation'
import {useInternationalizedArrayContext} from './InternationalizedArrayContext'

type InternationalizedValue = {
export type InternationalizedValue = {
_type: string
_key: string
value: string
}

export default function InternationalizedInput(
props: ObjectItemProps<InternationalizedValue>
) {
): ReactNode {
const parentValue = useFormValue(
props.path.slice(0, -1)
) as InternationalizedValue[]
Expand All @@ -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,
}

Expand All @@ -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<HTMLButtonElement, MouseEvent>) => {
(event: React.MouseEvent<HTMLButtonElement, MouseEvent>): void => {
const languageId = event?.currentTarget?.value

if (
Expand All @@ -78,7 +78,7 @@ export default function InternationalizedInput(
)

// Removes this item from the array
const handleUnset = useCallback(() => {
const handleUnset = useCallback((): void => {
onChange(unset())
}, [onChange])

Expand Down
3 changes: 3 additions & 0 deletions src/plugin.tsx
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -44,6 +45,8 @@ export const internationalizedArray = definePlugin<PluginConfig>((config) => {
// Wrap document editor with a language provider
form: {
components: {
field: (props) => <InternationalizedField {...props} />,

input: (props) => {
const isRootInput = props.id === 'root' && isObjectInputProps(props)

Expand Down
22 changes: 4 additions & 18 deletions src/schema/object.ts
Original file line number Diff line number Diff line change
@@ -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 = {
Expand All @@ -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: {
Expand Down
Loading