forked from sanity-io/sanity-plugin-internationalized-array
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathInternationalizedArrayContext.tsx
More file actions
136 lines (120 loc) · 4.62 KB
/
InternationalizedArrayContext.tsx
File metadata and controls
136 lines (120 loc) · 4.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import {useLanguageFilterStudioContext} from '@sanity/language-filter'
import {Stack} from '@sanity/ui'
import equal from 'fast-deep-equal'
import type React from 'react'
import {createContext, useContext, useDeferredValue, useMemo} from 'react'
import {type ObjectInputProps, useClient, useWorkspace} from 'sanity'
import {useDocumentPane} from 'sanity/structure'
import {suspend} from 'suspend-react'
import {createCacheKey, setFunctionCache} from '../cache'
import {CONFIG_DEFAULT} from '../constants'
import type {Language, PluginConfig} from '../types'
import DocumentAddButtons from './DocumentAddButtons'
import {getSelectedValue} from './getSelectedValue'
// This provider makes the plugin config available to all components in the document form
// But with languages resolved and filtered languages updated base on @sanity/language-filter
type InternationalizedArrayContextProps = Required<PluginConfig> & {
languages: Language[]
filteredLanguages: Language[]
}
export const InternationalizedArrayContext =
createContext<InternationalizedArrayContextProps>({
...CONFIG_DEFAULT,
languages: [],
filteredLanguages: [],
})
export function useInternationalizedArrayContext(): InternationalizedArrayContextProps {
return useContext(InternationalizedArrayContext)
}
type InternationalizedArrayProviderProps = ObjectInputProps & {
internationalizedArray: Required<PluginConfig>
}
export function InternationalizedArrayProvider(
props: InternationalizedArrayProviderProps
): React.ReactElement {
const {internationalizedArray} = props
const client = useClient({apiVersion: internationalizedArray.apiVersion})
const workspace = useWorkspace()
const {formState} = useDocumentPane()
const deferredDocument = useDeferredValue(formState?.value)
const selectedValue = useMemo(
() => getSelectedValue(internationalizedArray.select, deferredDocument),
[internationalizedArray.select, deferredDocument]
)
// Use a stable workspace identifier to prevent unnecessary re-renders
const workspaceId = useMemo(() => {
// Use workspace name if available, otherwise create a stable hash
if (workspace?.name) {
return workspace.name
}
// Create a stable hash from workspace properties that matter for caching
const workspaceKey = {
name: workspace?.name,
title: workspace?.title,
// Add other stable properties as needed
}
return JSON.stringify(workspaceKey)
}, [workspace])
// Memoize the cache key to prevent expensive JSON.stringify calls
const cacheKey = useMemo(
() => createCacheKey(selectedValue, workspaceId),
[selectedValue, workspaceId]
)
// Fetch or return languages
const languages = Array.isArray(internationalizedArray.languages)
? internationalizedArray.languages
: suspend(
// eslint-disable-next-line require-await
async () => {
if (typeof internationalizedArray.languages === 'function') {
const result = await internationalizedArray.languages(
client,
selectedValue
)
// Populate function cache for use outside React context
setFunctionCache(
internationalizedArray.languages,
selectedValue,
result,
workspaceId
)
return result
}
return internationalizedArray.languages
},
cacheKey,
{equal}
)
// Filter out some languages if language filter is enabled
const {selectedLanguageIds, options: languageFilterOptions} =
useLanguageFilterStudioContext()
const filteredLanguages = useMemo(() => {
const documentType = deferredDocument ? deferredDocument._type : undefined
const languageFilterEnabled =
typeof documentType === 'string' &&
languageFilterOptions.documentTypes.includes(documentType)
return languageFilterEnabled
? languages.filter((language) =>
selectedLanguageIds.includes(language.id)
)
: languages
}, [deferredDocument, languageFilterOptions, languages, selectedLanguageIds])
const showDocumentButtons =
internationalizedArray.buttonLocations.includes('document')
const context = useMemo(
() => ({...internationalizedArray, languages, filteredLanguages}),
[filteredLanguages, internationalizedArray, languages]
)
return (
<InternationalizedArrayContext.Provider value={context}>
{showDocumentButtons ? (
<Stack space={5}>
<DocumentAddButtons value={props.value} />
{props.renderDefault(props)}
</Stack>
) : (
props.renderDefault(props)
)}
</InternationalizedArrayContext.Provider>
)
}