@sanity/language-filter 2.31.2-performance-opts.6 → 3.0.0-v3-studio.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +98 -32
- package/lib/cjs/index.js +431 -0
- package/lib/cjs/index.js.map +1 -0
- package/lib/esm/index.js +422 -0
- package/lib/esm/index.js.map +1 -0
- package/lib/types/index.d.ts +91 -0
- package/lib/types/index.d.ts.map +1 -0
- package/package.json +77 -31
- package/sanity.json +2 -10
- package/src/LanguageFilterContext.tsx +30 -0
- package/src/LanguageFilterMenuButton.tsx +147 -0
- package/src/LanguageFilterObjectInput.tsx +72 -0
- package/src/filterField.test.ts +91 -0
- package/src/filterField.ts +34 -0
- package/src/index.ts +26 -0
- package/src/languageSubscription.ts +32 -0
- package/src/plugin.tsx +86 -0
- package/src/types.ts +27 -0
- package/src/usePaneLanguages.ts +78 -0
- package/src/useSelectedLanguageIds.ts +40 -0
- package/v2-incompatible.js +11 -0
- package/config.dist.json +0 -3
- package/dist/dts/SelectLanguage.d.ts +0 -16
- package/dist/dts/SelectLanguage.d.ts.map +0 -1
- package/dist/dts/SelectLanguageProvider.d.ts +0 -8
- package/dist/dts/SelectLanguageProvider.d.ts.map +0 -1
- package/dist/dts/datastore.d.ts +0 -7
- package/dist/dts/datastore.d.ts.map +0 -1
- package/lib/SelectLanguage.js +0 -191
- package/lib/SelectLanguageProvider.js +0 -98
- package/lib/datastore.js +0 -62
- package/lib/filter-fields.js +0 -13
- package/src/SelectLanguage.tsx +0 -178
- package/src/SelectLanguageProvider.tsx +0 -70
- package/src/datastore.ts +0 -70
- package/src/filter-fields.js +0 -1
- package/tsconfig.json +0 -13
package/src/SelectLanguage.tsx
DELETED
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import React, {useState, useCallback} from 'react'
|
|
2
|
-
import {Button, Checkbox, Flex, Box, Text, Stack, Popover, useClickOutside} from '@sanity/ui'
|
|
3
|
-
import {ChevronDownIcon} from '@sanity/icons'
|
|
4
|
-
|
|
5
|
-
const ACTION_LABEL = 'Filter languages'
|
|
6
|
-
interface LanguageOption {
|
|
7
|
-
title: string
|
|
8
|
-
id: string
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
interface Props {
|
|
12
|
-
languages: LanguageOption[]
|
|
13
|
-
currentDocumentType?: string
|
|
14
|
-
defaultLanguages?: string[]
|
|
15
|
-
documentTypes?: string[]
|
|
16
|
-
selected: string[]
|
|
17
|
-
onChange: (ids: string[]) => void
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const STYLES_TOGGLE = {flex: 1}
|
|
21
|
-
const STYLES_CHECKBOX = {display: 'block'}
|
|
22
|
-
|
|
23
|
-
const SelectLanguage = ({
|
|
24
|
-
currentDocumentType,
|
|
25
|
-
selected,
|
|
26
|
-
languages,
|
|
27
|
-
defaultLanguages,
|
|
28
|
-
documentTypes,
|
|
29
|
-
onChange,
|
|
30
|
-
}: Props) => {
|
|
31
|
-
const [triggerRef, setTriggerRef] = React.useState<HTMLButtonElement | null>(null)
|
|
32
|
-
const [popoverRef, setPopoverRef] = React.useState<HTMLElement | null>(null)
|
|
33
|
-
const [isOpen, setIsOpen] = useState(false)
|
|
34
|
-
const allIsSelected = languages.length === selected.length
|
|
35
|
-
|
|
36
|
-
const handleKeyUp = useCallback((e) => {
|
|
37
|
-
if (e.key === 'Escape') {
|
|
38
|
-
handleClose()
|
|
39
|
-
}
|
|
40
|
-
}, [])
|
|
41
|
-
|
|
42
|
-
const handleOpen = () => {
|
|
43
|
-
setIsOpen((prev) => !prev)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const handleClose = () => {
|
|
47
|
-
setIsOpen(false)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const selectLang = (langId: string) => {
|
|
51
|
-
onChange(selected.concat(langId))
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const unselectLang = (langId: string) => {
|
|
55
|
-
onChange(selected.filter((id) => id !== langId))
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const isDefaultLang = (langId: string) => {
|
|
59
|
-
return defaultLanguages && defaultLanguages.includes(langId)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const isValidDocumentType = () => {
|
|
63
|
-
return documentTypes && currentDocumentType ? documentTypes.includes(currentDocumentType) : true
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const handleSelectAll = () => {
|
|
67
|
-
onChange(languages.map((language) => language.id))
|
|
68
|
-
}
|
|
69
|
-
const handleSelectNone = () => {
|
|
70
|
-
onChange([])
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const handleLangCheckboxChange = (event: React.FormEvent<HTMLInputElement>) => {
|
|
74
|
-
const id = event.currentTarget.getAttribute('data-lang-id')
|
|
75
|
-
const checked = event.currentTarget.checked
|
|
76
|
-
|
|
77
|
-
if (!id) {
|
|
78
|
-
return
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (checked) {
|
|
82
|
-
selectLang(id)
|
|
83
|
-
} else {
|
|
84
|
-
unselectLang(id)
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
useClickOutside(() => {
|
|
89
|
-
handleClose()
|
|
90
|
-
}, [popoverRef, triggerRef])
|
|
91
|
-
|
|
92
|
-
if (!isValidDocumentType()) {
|
|
93
|
-
return <></>
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const content = (
|
|
97
|
-
<Box overflow="auto" sizing="border" onKeyUp={handleKeyUp}>
|
|
98
|
-
<Flex padding={2}>
|
|
99
|
-
<Button
|
|
100
|
-
type="button"
|
|
101
|
-
mode="ghost"
|
|
102
|
-
tone="default"
|
|
103
|
-
onClick={allIsSelected ? handleSelectNone : handleSelectAll}
|
|
104
|
-
paddingX={3}
|
|
105
|
-
paddingY={2}
|
|
106
|
-
autoFocus
|
|
107
|
-
style={STYLES_TOGGLE}
|
|
108
|
-
>
|
|
109
|
-
Select {allIsSelected ? 'none' : 'all'}
|
|
110
|
-
</Button>
|
|
111
|
-
</Flex>
|
|
112
|
-
<Box padding={3} paddingX={2}>
|
|
113
|
-
<Stack as="ul" space={3}>
|
|
114
|
-
{languages.map((lang) => {
|
|
115
|
-
const label = lang.title + (isDefaultLang(lang.id) ? ' (Default)' : '')
|
|
116
|
-
const languageId = `language-${lang.id}`
|
|
117
|
-
return (
|
|
118
|
-
<Flex as="li" align="center" key={lang.id}>
|
|
119
|
-
<Checkbox
|
|
120
|
-
id={languageId}
|
|
121
|
-
style={STYLES_CHECKBOX}
|
|
122
|
-
onChange={handleLangCheckboxChange}
|
|
123
|
-
data-lang-id={lang.id}
|
|
124
|
-
checked={selected.includes(lang.id)}
|
|
125
|
-
disabled={isDefaultLang(lang.id)}
|
|
126
|
-
/>
|
|
127
|
-
<Box flex={1} paddingLeft={3}>
|
|
128
|
-
<Text>
|
|
129
|
-
<label htmlFor={languageId} style={STYLES_CHECKBOX}>
|
|
130
|
-
{label}
|
|
131
|
-
</label>
|
|
132
|
-
</Text>
|
|
133
|
-
</Box>
|
|
134
|
-
</Flex>
|
|
135
|
-
)
|
|
136
|
-
})}
|
|
137
|
-
</Stack>
|
|
138
|
-
</Box>
|
|
139
|
-
</Box>
|
|
140
|
-
)
|
|
141
|
-
|
|
142
|
-
return (
|
|
143
|
-
<>
|
|
144
|
-
<Button
|
|
145
|
-
fontSize={1}
|
|
146
|
-
iconRight={ChevronDownIcon}
|
|
147
|
-
mode="bleed"
|
|
148
|
-
ref={setTriggerRef}
|
|
149
|
-
onClick={handleOpen}
|
|
150
|
-
padding={2}
|
|
151
|
-
title={
|
|
152
|
-
allIsSelected
|
|
153
|
-
? 'Filter language fields'
|
|
154
|
-
: 'Displaying fields only for the selected languages'
|
|
155
|
-
}
|
|
156
|
-
selected={isOpen}
|
|
157
|
-
text={
|
|
158
|
-
<>
|
|
159
|
-
{ACTION_LABEL} ({`${selected.length}/${languages.length}`})
|
|
160
|
-
</>
|
|
161
|
-
}
|
|
162
|
-
/>
|
|
163
|
-
<Popover
|
|
164
|
-
content={content}
|
|
165
|
-
open={isOpen}
|
|
166
|
-
placement="bottom"
|
|
167
|
-
ref={setPopoverRef}
|
|
168
|
-
referenceElement={triggerRef}
|
|
169
|
-
tone="default"
|
|
170
|
-
constrainSize
|
|
171
|
-
autoFocus
|
|
172
|
-
portal
|
|
173
|
-
/>
|
|
174
|
-
</>
|
|
175
|
-
)
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
export default SelectLanguage
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
// @todo: remove the following line when part imports has been removed from this file
|
|
2
|
-
///<reference types="@sanity/types/parts" />
|
|
3
|
-
|
|
4
|
-
import React, {useRef, useEffect, useState, useMemo} from 'react'
|
|
5
|
-
import config from 'part:@sanity/language-filter/config'
|
|
6
|
-
import {SchemaType} from '@sanity/types'
|
|
7
|
-
import {Subscription} from 'rxjs'
|
|
8
|
-
import languageFilterImplementations from 'all:part:@sanity/desk-tool/language-select-component'
|
|
9
|
-
import {selectedLanguages$, setLangs} from './datastore'
|
|
10
|
-
import SelectLanguage from './SelectLanguage'
|
|
11
|
-
|
|
12
|
-
interface Props {
|
|
13
|
-
schemaType?: SchemaType
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const SelectLanguageProvider = ({schemaType}: Props) => {
|
|
17
|
-
const subscriptionRef$ = useRef<Subscription | null>(null)
|
|
18
|
-
const [selected, setSelected] = useState<string[]>([])
|
|
19
|
-
const [currentDocumentType, setCurrentDocumentType] = useState<string | undefined>()
|
|
20
|
-
const shouldShow = useMemo(() => {
|
|
21
|
-
const {documentTypes} = config
|
|
22
|
-
return !!(documentTypes && schemaType?.name && documentTypes.includes(schemaType.name))
|
|
23
|
-
}, [schemaType])
|
|
24
|
-
const FallbackImplementation = useMemo(() => {
|
|
25
|
-
if (languageFilterImplementations && Array.isArray(languageFilterImplementations)) {
|
|
26
|
-
return (
|
|
27
|
-
languageFilterImplementations?.filter(
|
|
28
|
-
(component) => SelectLanguageProvider !== component
|
|
29
|
-
)?.[0] ?? null
|
|
30
|
-
)
|
|
31
|
-
}
|
|
32
|
-
return null
|
|
33
|
-
}, [])
|
|
34
|
-
|
|
35
|
-
useEffect(() => {
|
|
36
|
-
setCurrentDocumentType(schemaType?.name)
|
|
37
|
-
}, [schemaType])
|
|
38
|
-
|
|
39
|
-
useEffect(() => {
|
|
40
|
-
subscriptionRef$.current = selectedLanguages$.subscribe((selectedLangs: string[]) => {
|
|
41
|
-
setSelected(selectedLangs)
|
|
42
|
-
})
|
|
43
|
-
return () => {
|
|
44
|
-
if (subscriptionRef$.current) {
|
|
45
|
-
subscriptionRef$.current.unsubscribe()
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}, [])
|
|
49
|
-
|
|
50
|
-
if (shouldShow) {
|
|
51
|
-
return (
|
|
52
|
-
<SelectLanguage
|
|
53
|
-
languages={config.supportedLanguages}
|
|
54
|
-
defaultLanguages={config.defaultLanguages}
|
|
55
|
-
documentTypes={config.documentTypes}
|
|
56
|
-
currentDocumentType={currentDocumentType}
|
|
57
|
-
selected={selected}
|
|
58
|
-
onChange={setLangs}
|
|
59
|
-
/>
|
|
60
|
-
)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (FallbackImplementation) {
|
|
64
|
-
return <FallbackImplementation schemaType={schemaType as any} />
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return null
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export default SelectLanguageProvider
|
package/src/datastore.ts
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
// @todo: remove the following line when part imports has been removed from this file
|
|
2
|
-
///<reference types="@sanity/types/parts" />
|
|
3
|
-
|
|
4
|
-
import {Observable, Subject} from 'rxjs'
|
|
5
|
-
import {map, publishReplay, refCount, startWith, tap} from 'rxjs/operators'
|
|
6
|
-
import config from 'part:@sanity/language-filter/config'
|
|
7
|
-
import {intersection, union} from 'lodash'
|
|
8
|
-
import {ObjectField, SchemaType} from '@sanity/types'
|
|
9
|
-
|
|
10
|
-
export type SelectedLanguages = string[]
|
|
11
|
-
interface SupportedLanguage {
|
|
12
|
-
id: string
|
|
13
|
-
title: string
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const onSelect$ = new Subject<SelectedLanguages>()
|
|
17
|
-
|
|
18
|
-
const id = (v: any) => v
|
|
19
|
-
|
|
20
|
-
export const setLangs = (languages: SelectedLanguages) => onSelect$.next(languages)
|
|
21
|
-
|
|
22
|
-
const persistOn = (key: string, defaultValue: string[]) => (input$: Observable<string[]>) => {
|
|
23
|
-
let persisted
|
|
24
|
-
try {
|
|
25
|
-
const persistedValue = window.localStorage.getItem(key)
|
|
26
|
-
if (persistedValue) {
|
|
27
|
-
persisted = JSON.parse(persistedValue)
|
|
28
|
-
}
|
|
29
|
-
} catch (err) {} // eslint-disable-line no-empty
|
|
30
|
-
|
|
31
|
-
return input$.pipe(
|
|
32
|
-
startWith(persisted || defaultValue),
|
|
33
|
-
tap((value) => {
|
|
34
|
-
window.localStorage.setItem(key, JSON.stringify(value))
|
|
35
|
-
})
|
|
36
|
-
)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const SUPPORTED_LANG_IDS = config.supportedLanguages.map((lang: SupportedLanguage) => lang.id)
|
|
40
|
-
|
|
41
|
-
export const selectedLanguages$ = onSelect$.pipe(
|
|
42
|
-
persistOn(
|
|
43
|
-
'@sanity/plugin/language-filter/selected-languages',
|
|
44
|
-
config.defaultLanguages || SUPPORTED_LANG_IDS
|
|
45
|
-
),
|
|
46
|
-
// constrain persisted/selected languages to the ones currently supported
|
|
47
|
-
map((selectedLangs: SelectedLanguages) => intersection(selectedLangs, SUPPORTED_LANG_IDS)),
|
|
48
|
-
// make sure default languages always gets selected
|
|
49
|
-
Array.isArray(config.defaultLanguages)
|
|
50
|
-
? map((selectedLangs) => union(selectedLangs, config.defaultLanguages || []))
|
|
51
|
-
: id,
|
|
52
|
-
publishReplay(1),
|
|
53
|
-
refCount()
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
const defaultFilterField = (
|
|
57
|
-
enclosingType: SchemaType,
|
|
58
|
-
field: ObjectField,
|
|
59
|
-
selectedLanguages: string[]
|
|
60
|
-
) => !enclosingType.name.startsWith('locale') || selectedLanguages.includes(field.name)
|
|
61
|
-
|
|
62
|
-
const filterField = config.filterField || defaultFilterField
|
|
63
|
-
|
|
64
|
-
export const filterFn$ = selectedLanguages$.pipe(
|
|
65
|
-
map((langs) => {
|
|
66
|
-
return (enclosingType: SchemaType, field: ObjectField) => {
|
|
67
|
-
return filterField(enclosingType, field, langs)
|
|
68
|
-
}
|
|
69
|
-
})
|
|
70
|
-
)
|
package/src/filter-fields.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {filterFn$ as default} from './datastore'
|