@sanity/language-filter 0.147.10-next.22 → 1.0.0-firstpass-v3-impl.1
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 +122 -28
- package/lib/cjs/index.js +338 -0
- package/lib/cjs/index.js.map +1 -0
- package/lib/esm/index.js +329 -0
- package/lib/esm/index.js.map +1 -0
- package/lib/types/index.d.ts +73 -0
- package/lib/types/index.d.ts.map +1 -0
- package/package.json +77 -27
- package/sanity.json +2 -10
- package/src/LanguageFilterMenuButton.tsx +128 -0
- package/src/LanguageFilterObjectInput.tsx +33 -0
- package/src/filterField.test.ts +91 -0
- package/src/filterField.ts +34 -0
- package/src/index.ts +26 -0
- package/src/plugin.tsx +67 -0
- package/src/types.ts +27 -0
- package/src/usePaneLanguages.ts +81 -0
- package/v2-incompatible.js +11 -0
- package/lib/SelectLanguage.js +0 -139
- package/lib/SelectLanguageProvider.js +0 -52
- package/lib/datastore.js +0 -48
- package/lib/filter-fields.js +0 -13
- package/lib/styles/SelectLanguage.css +0 -50
- package/src/SelectLanguage.js +0 -106
- package/src/SelectLanguageProvider.js +0 -28
- package/src/datastore.js +0 -42
- package/src/filter-fields.js +0 -1
- package/src/styles/SelectLanguage.css +0 -50
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import {TranslateIcon} from '@sanity/icons'
|
|
2
|
+
import {Box, Button, Card, Checkbox, Flex, Popover, Stack, Text, useClickOutside} from '@sanity/ui'
|
|
3
|
+
import React, {FormEvent, useCallback, useState} from 'react'
|
|
4
|
+
import {usePaneLanguages} from './usePaneLanguages'
|
|
5
|
+
import {LanguageFilterConfig} from './types'
|
|
6
|
+
|
|
7
|
+
export interface LanguageFilterMenuButtonProps {
|
|
8
|
+
options: LanguageFilterConfig
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function LanguageFilterMenuButton(props: LanguageFilterMenuButtonProps) {
|
|
12
|
+
const {options} = props
|
|
13
|
+
const defaultLanguages = options.supportedLanguages.filter((l) =>
|
|
14
|
+
options.defaultLanguages?.includes(l.id)
|
|
15
|
+
)
|
|
16
|
+
const languageOptions = options.supportedLanguages.filter(
|
|
17
|
+
(l) => !options.defaultLanguages?.includes(l.id)
|
|
18
|
+
)
|
|
19
|
+
const [open, setOpen] = useState(false)
|
|
20
|
+
const {visibleLanguages, allSelected, selectAll, selectNone, toggleLanguage} = usePaneLanguages({
|
|
21
|
+
options,
|
|
22
|
+
})
|
|
23
|
+
const [button, setButton] = useState<HTMLElement | null>(null)
|
|
24
|
+
const [popover, setPopover] = useState<HTMLElement | null>(null)
|
|
25
|
+
|
|
26
|
+
const handleToggleAll = useCallback(
|
|
27
|
+
(event: FormEvent<HTMLInputElement>) => {
|
|
28
|
+
const checked = event.currentTarget.checked
|
|
29
|
+
|
|
30
|
+
if (checked) {
|
|
31
|
+
selectAll()
|
|
32
|
+
} else {
|
|
33
|
+
selectNone()
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
[selectAll, selectNone]
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
const handleClick = useCallback(() => setOpen((o) => !o), [])
|
|
40
|
+
|
|
41
|
+
const handleClickOutside = useCallback(() => setOpen(false), [])
|
|
42
|
+
|
|
43
|
+
useClickOutside(handleClickOutside, [button, popover])
|
|
44
|
+
|
|
45
|
+
const content = (
|
|
46
|
+
<Box overflow="auto" padding={1}>
|
|
47
|
+
{defaultLanguages.length > 0 && (
|
|
48
|
+
<Card radius={2} tone="primary">
|
|
49
|
+
<Stack padding={2} space={3}>
|
|
50
|
+
<Text size={1} weight="semibold">
|
|
51
|
+
Default language{defaultLanguages.length > 1 && <>s</>}
|
|
52
|
+
</Text>
|
|
53
|
+
|
|
54
|
+
{defaultLanguages.map((l) => (
|
|
55
|
+
<Text key={l.id}>{l.title}</Text>
|
|
56
|
+
))}
|
|
57
|
+
</Stack>
|
|
58
|
+
</Card>
|
|
59
|
+
)}
|
|
60
|
+
|
|
61
|
+
<Stack marginTop={3} padding={2} space={2}>
|
|
62
|
+
<Box paddingBottom={1}>
|
|
63
|
+
<Text size={1} weight="semibold">
|
|
64
|
+
Show translations
|
|
65
|
+
</Text>
|
|
66
|
+
</Box>
|
|
67
|
+
|
|
68
|
+
<Card as="label">
|
|
69
|
+
<Flex align="center" gap={2}>
|
|
70
|
+
<Checkbox checked={allSelected} name="_allSelected" onChange={handleToggleAll} />
|
|
71
|
+
<Box flex={1}>
|
|
72
|
+
<Text muted={!allSelected} weight="semibold">
|
|
73
|
+
All translations
|
|
74
|
+
</Text>
|
|
75
|
+
</Box>
|
|
76
|
+
</Flex>
|
|
77
|
+
</Card>
|
|
78
|
+
|
|
79
|
+
{languageOptions.map((lang) => (
|
|
80
|
+
<LanguageFilterOption
|
|
81
|
+
id={lang.id}
|
|
82
|
+
key={lang.id}
|
|
83
|
+
onToggle={toggleLanguage}
|
|
84
|
+
selected={visibleLanguages.includes(lang.id)}
|
|
85
|
+
title={lang.title}
|
|
86
|
+
/>
|
|
87
|
+
))}
|
|
88
|
+
</Stack>
|
|
89
|
+
</Box>
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<Popover constrainSize content={content} open={open} portal ref={setPopover}>
|
|
94
|
+
<Button
|
|
95
|
+
icon={TranslateIcon}
|
|
96
|
+
text={`Filter languages (${visibleLanguages.length}/${options.supportedLanguages.length})`}
|
|
97
|
+
mode="bleed"
|
|
98
|
+
onClick={handleClick}
|
|
99
|
+
ref={setButton}
|
|
100
|
+
selected={open}
|
|
101
|
+
/>
|
|
102
|
+
</Popover>
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function LanguageFilterOption(props: {
|
|
107
|
+
id: string
|
|
108
|
+
onToggle: (id: string) => void
|
|
109
|
+
selected: boolean
|
|
110
|
+
title: string
|
|
111
|
+
}) {
|
|
112
|
+
const {id, onToggle, selected, title} = props
|
|
113
|
+
|
|
114
|
+
const handleChange = useCallback(() => {
|
|
115
|
+
onToggle(id)
|
|
116
|
+
}, [id, onToggle])
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<Card as="label">
|
|
120
|
+
<Flex align="center" gap={2}>
|
|
121
|
+
<Checkbox checked={selected} name={`language-${id}`} onChange={handleChange} />
|
|
122
|
+
<Box flex={1}>
|
|
123
|
+
<Text muted={!selected}>{title}</Text>
|
|
124
|
+
</Box>
|
|
125
|
+
</Flex>
|
|
126
|
+
</Card>
|
|
127
|
+
)
|
|
128
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React, {useMemo} from 'react'
|
|
2
|
+
import {ObjectInputProps, ObjectMember} from 'sanity'
|
|
3
|
+
import {ObjectInput} from 'sanity/form'
|
|
4
|
+
import {usePaneLanguages} from './usePaneLanguages'
|
|
5
|
+
import {LanguageFilterConfig} from './types'
|
|
6
|
+
import {defaultFilterField} from './filterField'
|
|
7
|
+
|
|
8
|
+
export type LanguageFilterObjectInputProps = {options: LanguageFilterConfig} & ObjectInputProps
|
|
9
|
+
|
|
10
|
+
export function LanguageFilterObjectInput(props: LanguageFilterObjectInputProps) {
|
|
11
|
+
const {members: membersProp, level, options, path, schemaType, ...restProps} = props
|
|
12
|
+
const {visibleLanguages} = usePaneLanguages({options})
|
|
13
|
+
|
|
14
|
+
const filterField = options.filterField ?? defaultFilterField
|
|
15
|
+
|
|
16
|
+
const members: ObjectMember[] = useMemo(() => {
|
|
17
|
+
return membersProp.filter(
|
|
18
|
+
(member) =>
|
|
19
|
+
(member.kind === 'field' && filterField(schemaType, member, visibleLanguages)) ||
|
|
20
|
+
(member.kind === 'fieldSet' && filterField(schemaType, member.fieldSet, visibleLanguages))
|
|
21
|
+
)
|
|
22
|
+
}, [schemaType, membersProp, filterField, visibleLanguages])
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<ObjectInput
|
|
26
|
+
{...restProps}
|
|
27
|
+
level={level}
|
|
28
|
+
members={members}
|
|
29
|
+
path={path}
|
|
30
|
+
schemaType={schemaType}
|
|
31
|
+
/>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import {defaultFilterField, isLanguageFilterEnabled} from './filterField'
|
|
2
|
+
import {FieldMember, ObjectSchemaType} from 'sanity'
|
|
3
|
+
|
|
4
|
+
describe('filterField', () => {
|
|
5
|
+
describe('isLanguageFilterEnabled', () => {
|
|
6
|
+
const docType: ObjectSchemaType = {
|
|
7
|
+
name: 'some-doc',
|
|
8
|
+
jsonType: 'object',
|
|
9
|
+
fields: [],
|
|
10
|
+
type: {
|
|
11
|
+
name: 'document',
|
|
12
|
+
jsonType: 'object',
|
|
13
|
+
fields: [],
|
|
14
|
+
},
|
|
15
|
+
}
|
|
16
|
+
it('should be enabled when documentTypes is missing', () => {
|
|
17
|
+
const enabled = isLanguageFilterEnabled(docType, {supportedLanguages: []})
|
|
18
|
+
expect(enabled).toBeTruthy()
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('should be disabled when documentTypes is missing and options.languageFilter: false', () => {
|
|
22
|
+
const enabled = isLanguageFilterEnabled(
|
|
23
|
+
{...docType, options: {languageFilter: false}},
|
|
24
|
+
{supportedLanguages: []}
|
|
25
|
+
)
|
|
26
|
+
expect(enabled).toBeFalsy()
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('should be enabled when documentTypes is contains doc-type name', () => {
|
|
30
|
+
const enabled = isLanguageFilterEnabled(
|
|
31
|
+
{...docType, options: {languageFilter: false}},
|
|
32
|
+
{supportedLanguages: [], documentTypes: [docType.name]}
|
|
33
|
+
)
|
|
34
|
+
expect(enabled).toBeTruthy()
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('should be enabled when documentTypes does not contain doc-type name, but options.languageFilter: true', () => {
|
|
38
|
+
const enabled = isLanguageFilterEnabled(
|
|
39
|
+
{...docType, options: {languageFilter: true}},
|
|
40
|
+
{supportedLanguages: [], documentTypes: []}
|
|
41
|
+
)
|
|
42
|
+
expect(enabled).toBeTruthy()
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
describe('defaultFilterField', () => {
|
|
47
|
+
const localePrefixedObject: ObjectSchemaType = {
|
|
48
|
+
name: 'locale_parent',
|
|
49
|
+
jsonType: 'object',
|
|
50
|
+
fields: [],
|
|
51
|
+
}
|
|
52
|
+
const member: FieldMember = {
|
|
53
|
+
name: 'nb',
|
|
54
|
+
key: 'nb',
|
|
55
|
+
collapsed: undefined,
|
|
56
|
+
collapsible: undefined,
|
|
57
|
+
kind: 'field',
|
|
58
|
+
open: true,
|
|
59
|
+
index: 0,
|
|
60
|
+
field: {
|
|
61
|
+
schemaType: {name: 'string', jsonType: 'string'},
|
|
62
|
+
level: 1,
|
|
63
|
+
id: 'nb',
|
|
64
|
+
path: [],
|
|
65
|
+
validation: [],
|
|
66
|
+
presence: [],
|
|
67
|
+
changed: false,
|
|
68
|
+
value: undefined,
|
|
69
|
+
},
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
it('should filter -> true for nb field inside local-prefixed object', () => {
|
|
73
|
+
const result = defaultFilterField(localePrefixedObject, member, ['nb'])
|
|
74
|
+
expect(result).toBeTruthy()
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('should filter -> false for unselected field inside local-prefixed object', () => {
|
|
78
|
+
const result = defaultFilterField(localePrefixedObject, member, ['other'])
|
|
79
|
+
expect(result).toBeFalsy()
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('should filter -> true for nb field inside non-prefixed object', () => {
|
|
83
|
+
const result = defaultFilterField(
|
|
84
|
+
{...localePrefixedObject, name: 'not-start-with-locale-field'},
|
|
85
|
+
member,
|
|
86
|
+
['nb']
|
|
87
|
+
)
|
|
88
|
+
expect(result).toBeTruthy()
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
})
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type {SchemaType} from 'sanity'
|
|
2
|
+
import {FilterFieldFunction, LanguageFilterConfig, LanguageFilterSchema} from './types'
|
|
3
|
+
|
|
4
|
+
export const defaultFilterField: FilterFieldFunction = (
|
|
5
|
+
enclosingType,
|
|
6
|
+
field,
|
|
7
|
+
selectedLanguageIds
|
|
8
|
+
) => !enclosingType.name.startsWith('locale') || selectedLanguageIds.includes(field.name)
|
|
9
|
+
|
|
10
|
+
export function isLanguageFilterEnabled(
|
|
11
|
+
schemaType: SchemaType | undefined,
|
|
12
|
+
options: LanguageFilterConfig
|
|
13
|
+
): boolean {
|
|
14
|
+
const schemaFilter =
|
|
15
|
+
isDocument(schemaType) && (schemaType as LanguageFilterSchema)?.options?.languageFilter
|
|
16
|
+
const defaultEnabled = !options.documentTypes
|
|
17
|
+
|
|
18
|
+
return !!(
|
|
19
|
+
(defaultEnabled && schemaFilter !== false) ||
|
|
20
|
+
(!defaultEnabled && schemaFilter) ||
|
|
21
|
+
(schemaType && options.documentTypes?.includes(schemaType.name))
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function isDocument(schemaType?: SchemaType) {
|
|
26
|
+
return schemaType?.jsonType === 'object' && getRootType(schemaType).name === 'document'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function getRootType(schema: SchemaType): SchemaType {
|
|
30
|
+
if (schema.type) {
|
|
31
|
+
return getRootType(schema.type)
|
|
32
|
+
}
|
|
33
|
+
return schema
|
|
34
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin function
|
|
3
|
+
*/
|
|
4
|
+
export {languageFilter} from './plugin'
|
|
5
|
+
|
|
6
|
+
export {defaultFilterField, isLanguageFilterEnabled} from './filterField'
|
|
7
|
+
|
|
8
|
+
export type {
|
|
9
|
+
LanguageFilterConfig,
|
|
10
|
+
LanguageFilterSchema,
|
|
11
|
+
LanguageFilterOptions,
|
|
12
|
+
FilterFieldFunction,
|
|
13
|
+
Language,
|
|
14
|
+
} from './types'
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
LanguageFilterObjectInput,
|
|
18
|
+
type LanguageFilterObjectInputProps,
|
|
19
|
+
} from './LanguageFilterObjectInput'
|
|
20
|
+
|
|
21
|
+
export {
|
|
22
|
+
LanguageFilterMenuButton,
|
|
23
|
+
type LanguageFilterMenuButtonProps,
|
|
24
|
+
} from './LanguageFilterMenuButton'
|
|
25
|
+
|
|
26
|
+
export {usePaneLanguages} from './usePaneLanguages'
|
package/src/plugin.tsx
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import {_DocumentLanguageFilterComponent, createPlugin, ObjectInputProps} from 'sanity'
|
|
3
|
+
import {LanguageFilterObjectInput} from './LanguageFilterObjectInput'
|
|
4
|
+
import {LanguageFilterMenuButton} from './LanguageFilterMenuButton'
|
|
5
|
+
import {LanguageFilterConfig} from './types'
|
|
6
|
+
import {isLanguageFilterEnabled} from './filterField'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* ## Usage in sanity.config.ts (or .js)
|
|
10
|
+
*
|
|
11
|
+
* ```
|
|
12
|
+
* import {createConfig} from 'sanity'
|
|
13
|
+
* import {languageFilter} from '@sanity/language-filter'
|
|
14
|
+
*
|
|
15
|
+
* export const createConfig({
|
|
16
|
+
* /...
|
|
17
|
+
* plugins: [
|
|
18
|
+
* languageFilter({
|
|
19
|
+
* supportedLanguages: [
|
|
20
|
+
* {id: 'nb', title: 'Norwegian (Bokmål)'},
|
|
21
|
+
* {id: 'nn', title: 'Norwegian (Nynorsk)'},
|
|
22
|
+
* {id: 'en', title: 'English'},
|
|
23
|
+
* {id: 'es', title: 'Spanish'},
|
|
24
|
+
* {id: 'arb', title: 'Arabic'},
|
|
25
|
+
* {id: 'pt', title: 'Portuguese'},
|
|
26
|
+
* //...
|
|
27
|
+
* ],
|
|
28
|
+
* // Select Norwegian (Bokmål) by default
|
|
29
|
+
* defaultLanguages: ['nb'],
|
|
30
|
+
* // Only show language filter for document type `page` (schemaType.name)
|
|
31
|
+
* // Can also enable via document-options: options.languageFilter: true
|
|
32
|
+
* documentTypes: ['page'],
|
|
33
|
+
* // default filter function shown
|
|
34
|
+
* filterField: (enclosingType, field, selectedLanguageIds) =>
|
|
35
|
+
* !enclosingType.name.startsWith('locale') || selectedLanguageIds.includes(field.name),
|
|
36
|
+
* })
|
|
37
|
+
* ]
|
|
38
|
+
* })
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export const languageFilter = createPlugin<LanguageFilterConfig>((options) => {
|
|
42
|
+
const RenderLanguageFilter: _DocumentLanguageFilterComponent = () => {
|
|
43
|
+
return <LanguageFilterMenuButton options={options} />
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
name: '@sanity/language-filter',
|
|
48
|
+
document: {
|
|
49
|
+
unstable_languageFilter: (prev, {schemaType, schema}) => {
|
|
50
|
+
if (isLanguageFilterEnabled(schema.get(schemaType), options)) {
|
|
51
|
+
return [...prev, RenderLanguageFilter]
|
|
52
|
+
}
|
|
53
|
+
return prev
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
form: {
|
|
58
|
+
renderInput(props, next) {
|
|
59
|
+
const enabled = isLanguageFilterEnabled(props.schemaType, options)
|
|
60
|
+
if (enabled && props.schemaType.jsonType === 'object') {
|
|
61
|
+
return <LanguageFilterObjectInput {...(props as ObjectInputProps)} options={options} />
|
|
62
|
+
}
|
|
63
|
+
return next(props)
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
}
|
|
67
|
+
})
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {FieldMember, FieldsetState, ObjectSchemaType} from 'sanity'
|
|
2
|
+
|
|
3
|
+
export interface LanguageFilterOptions {
|
|
4
|
+
languageFilter?: boolean
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface LanguageFilterSchema extends ObjectSchemaType {
|
|
8
|
+
options?: LanguageFilterOptions
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface Language {
|
|
12
|
+
id: string
|
|
13
|
+
title: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type FilterFieldFunction = (
|
|
17
|
+
enclosingType: ObjectSchemaType,
|
|
18
|
+
field: FieldMember | FieldsetState,
|
|
19
|
+
selectedLanguageIds: string[]
|
|
20
|
+
) => boolean
|
|
21
|
+
|
|
22
|
+
export interface LanguageFilterConfig {
|
|
23
|
+
supportedLanguages: Language[]
|
|
24
|
+
defaultLanguages?: string[]
|
|
25
|
+
documentTypes?: string[]
|
|
26
|
+
filterField?: FilterFieldFunction
|
|
27
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import {useCallback, useMemo} from 'react'
|
|
2
|
+
import {usePaneRouter} from 'sanity/desk'
|
|
3
|
+
import {LanguageFilterConfig} from './types'
|
|
4
|
+
|
|
5
|
+
// NOTE: use `+` instead of `,` since the desk tool URL format already uses comma
|
|
6
|
+
const LANG_ID_SEPARATOR = '+'
|
|
7
|
+
|
|
8
|
+
export function usePaneLanguages(props: {options: LanguageFilterConfig}): {
|
|
9
|
+
visibleLanguages: string[]
|
|
10
|
+
allSelected: boolean
|
|
11
|
+
selectAll: () => void
|
|
12
|
+
selectNone: () => void
|
|
13
|
+
toggleLanguage: (languageId: string) => void
|
|
14
|
+
} {
|
|
15
|
+
const {options} = props
|
|
16
|
+
const {params, setParams} = usePaneRouter()
|
|
17
|
+
const {supportedLanguages, defaultLanguages} = options
|
|
18
|
+
|
|
19
|
+
const selectableLanguages = useMemo(
|
|
20
|
+
() => supportedLanguages.filter((lang) => !defaultLanguages?.includes(lang.id)),
|
|
21
|
+
[supportedLanguages, defaultLanguages]
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
const selectedLanguages = useMemo(() => {
|
|
25
|
+
if (params?.langs === '$none') {
|
|
26
|
+
return []
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (params?.langs === '$all') {
|
|
30
|
+
return selectableLanguages.map((lang) => lang.id)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return params?.langs?.split(LANG_ID_SEPARATOR) || selectableLanguages.map((lang) => lang.id)
|
|
34
|
+
}, [params, selectableLanguages])
|
|
35
|
+
|
|
36
|
+
const selectAll = useCallback(() => {
|
|
37
|
+
setParams({...params, langs: '$all'})
|
|
38
|
+
}, [params, setParams])
|
|
39
|
+
|
|
40
|
+
const selectNone = useCallback(() => {
|
|
41
|
+
setParams({...params, langs: '$none'})
|
|
42
|
+
}, [params, setParams])
|
|
43
|
+
|
|
44
|
+
const toggleLanguage = useCallback(
|
|
45
|
+
(languageId: string) => {
|
|
46
|
+
let lang = selectedLanguages
|
|
47
|
+
|
|
48
|
+
if (lang.includes(languageId)) {
|
|
49
|
+
lang = lang.filter((l) => l !== languageId)
|
|
50
|
+
} else {
|
|
51
|
+
lang = [...lang, languageId]
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (lang.length === 0) {
|
|
55
|
+
setParams({...params, langs: '$none'}) // none
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (lang.length === selectableLanguages.length) {
|
|
60
|
+
setParams({...params, langs: '$all'})
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
setParams({...params, langs: lang.join(LANG_ID_SEPARATOR)})
|
|
65
|
+
},
|
|
66
|
+
[params, selectableLanguages, selectedLanguages, setParams]
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
const visibleLanguages = useMemo(
|
|
70
|
+
() => [...(defaultLanguages ?? []), ...selectedLanguages],
|
|
71
|
+
[defaultLanguages, selectedLanguages]
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
visibleLanguages,
|
|
76
|
+
allSelected: selectedLanguages.length === selectableLanguages.length,
|
|
77
|
+
selectAll,
|
|
78
|
+
selectNone,
|
|
79
|
+
toggleLanguage,
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const {showIncompatiblePluginDialog} = require('@sanity/incompatible-plugin')
|
|
2
|
+
const {name, version, sanityExchangeUrl} = require('./package.json')
|
|
3
|
+
|
|
4
|
+
export default showIncompatiblePluginDialog({
|
|
5
|
+
name: name,
|
|
6
|
+
versions: {
|
|
7
|
+
v3: version,
|
|
8
|
+
v2: undefined,
|
|
9
|
+
},
|
|
10
|
+
sanityExchangeUrl,
|
|
11
|
+
})
|
package/lib/SelectLanguage.js
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = void 0;
|
|
7
|
-
|
|
8
|
-
var _react = _interopRequireWildcard(require("react"));
|
|
9
|
-
|
|
10
|
-
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
11
|
-
|
|
12
|
-
var _poppable = _interopRequireDefault(require("part:@sanity/components/utilities/poppable"));
|
|
13
|
-
|
|
14
|
-
var _checkbox = _interopRequireDefault(require("part:@sanity/components/toggles/checkbox"));
|
|
15
|
-
|
|
16
|
-
var _default = _interopRequireDefault(require("part:@sanity/components/buttons/default"));
|
|
17
|
-
|
|
18
|
-
var _SelectLanguage = _interopRequireDefault(require("./styles/SelectLanguage.css"));
|
|
19
|
-
|
|
20
|
-
var _angleDownIcon = _interopRequireDefault(require("part:@sanity/base/angle-down-icon"));
|
|
21
|
-
|
|
22
|
-
var _angleUpIcon = _interopRequireDefault(require("part:@sanity/base/angle-up-icon"));
|
|
23
|
-
|
|
24
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
25
|
-
|
|
26
|
-
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }
|
|
27
|
-
|
|
28
|
-
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
29
|
-
|
|
30
|
-
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
31
|
-
|
|
32
|
-
var LanguagePropType = _propTypes.default.shape({
|
|
33
|
-
id: _propTypes.default.string,
|
|
34
|
-
title: _propTypes.default.string
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
class SelectLanguage extends _react.default.Component {
|
|
38
|
-
constructor() {
|
|
39
|
-
super(...arguments);
|
|
40
|
-
|
|
41
|
-
_defineProperty(this, "state", {
|
|
42
|
-
isOpen: false
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
_defineProperty(this, "refElement", _react.default.createRef());
|
|
46
|
-
|
|
47
|
-
_defineProperty(this, "handleToggle", () => this.setState(prevState => ({
|
|
48
|
-
isOpen: !prevState.isOpen
|
|
49
|
-
})));
|
|
50
|
-
|
|
51
|
-
_defineProperty(this, "handleOpen", () => this.setState({
|
|
52
|
-
isOpen: true
|
|
53
|
-
}));
|
|
54
|
-
|
|
55
|
-
_defineProperty(this, "handleClose", () => {
|
|
56
|
-
this.setState({
|
|
57
|
-
isOpen: false
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
_defineProperty(this, "selectLang", langId => {
|
|
62
|
-
var _this$props = this.props,
|
|
63
|
-
selected = _this$props.selected,
|
|
64
|
-
onChange = _this$props.onChange;
|
|
65
|
-
onChange(selected.concat(langId));
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
_defineProperty(this, "unselectLang", langId => {
|
|
69
|
-
var _this$props2 = this.props,
|
|
70
|
-
selected = _this$props2.selected,
|
|
71
|
-
onChange = _this$props2.onChange;
|
|
72
|
-
onChange(selected.filter(id => id !== langId));
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
_defineProperty(this, "handleSelectAll", event => {
|
|
76
|
-
var _this$props3 = this.props,
|
|
77
|
-
languages = _this$props3.languages,
|
|
78
|
-
onChange = _this$props3.onChange;
|
|
79
|
-
onChange(languages.map(l => l.id));
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
_defineProperty(this, "handleSelectNone", event => {
|
|
83
|
-
var onChange = this.props.onChange;
|
|
84
|
-
onChange([]);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
_defineProperty(this, "handleLangCheckboxChange", event => {
|
|
88
|
-
var id = event.target.getAttribute('data-lang-id');
|
|
89
|
-
var checked = event.target.checked;
|
|
90
|
-
this[checked ? 'selectLang' : 'unselectLang'](id);
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
render() {
|
|
95
|
-
var isOpen = this.state.isOpen;
|
|
96
|
-
var _this$props4 = this.props,
|
|
97
|
-
languages = _this$props4.languages,
|
|
98
|
-
selected = _this$props4.selected;
|
|
99
|
-
var allIsSelected = languages.length === selected.length;
|
|
100
|
-
var refElement = this.refElement && this.refElement.current && this.refElement.current._element;
|
|
101
|
-
return _react.default.createElement(_react.Fragment, null, _react.default.createElement("span", {
|
|
102
|
-
className: _SelectLanguage.default.target,
|
|
103
|
-
onClick: this.handleToggle,
|
|
104
|
-
ref: this.refElement,
|
|
105
|
-
title: allIsSelected ? 'Filter language fields' : 'Displaying only fields for selected languages'
|
|
106
|
-
}, "Filter languages", allIsSelected ? '…' : " (".concat(selected.length, "/").concat(languages.length, ")"), _react.default.createElement("span", {
|
|
107
|
-
className: _SelectLanguage.default.arrow
|
|
108
|
-
}, isOpen ? _react.default.createElement(_angleUpIcon.default, null) : _react.default.createElement(_angleDownIcon.default, null))), _react.default.createElement(_poppable.default, {
|
|
109
|
-
onEscape: this.handleClose,
|
|
110
|
-
onClickOutside: this.handleClose,
|
|
111
|
-
placement: "bottom-end",
|
|
112
|
-
referenceElement: refElement
|
|
113
|
-
}, isOpen && _react.default.createElement("div", {
|
|
114
|
-
className: _SelectLanguage.default.root
|
|
115
|
-
}, _react.default.createElement("div", {
|
|
116
|
-
className: _SelectLanguage.default.functions
|
|
117
|
-
}, _react.default.createElement(_default.default, {
|
|
118
|
-
onClick: allIsSelected ? this.handleSelectNone : this.handleSelectAll
|
|
119
|
-
}, "Select ", allIsSelected ? 'none' : 'all')), _react.default.createElement("ul", {
|
|
120
|
-
className: _SelectLanguage.default.list
|
|
121
|
-
}, languages.map(lang => _react.default.createElement("li", {
|
|
122
|
-
className: _SelectLanguage.default.item,
|
|
123
|
-
key: lang.id
|
|
124
|
-
}, _react.default.createElement(_checkbox.default, {
|
|
125
|
-
onChange: this.handleLangCheckboxChange,
|
|
126
|
-
"data-lang-id": lang.id,
|
|
127
|
-
checked: selected.includes(lang.id)
|
|
128
|
-
}, lang.title)))))));
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
exports.default = SelectLanguage;
|
|
134
|
-
|
|
135
|
-
_defineProperty(SelectLanguage, "propTypes", {
|
|
136
|
-
languages: _propTypes.default.arrayOf(LanguagePropType),
|
|
137
|
-
selected: _propTypes.default.arrayOf(LanguagePropType),
|
|
138
|
-
onChange: _propTypes.default.func
|
|
139
|
-
});
|