@sanity/language-filter 0.147.10-next.23 → 1.0.0-v3-studio.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 +126 -28
- 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 +78 -27
- 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/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,78 @@
|
|
|
1
|
+
import {useCallback, useMemo} from 'react'
|
|
2
|
+
import {LanguageFilterConfig} from './types'
|
|
3
|
+
import {
|
|
4
|
+
getSelectableLanguages,
|
|
5
|
+
persistLanguageIds,
|
|
6
|
+
useSelectedLanguageIds,
|
|
7
|
+
} from './useSelectedLanguageIds'
|
|
8
|
+
|
|
9
|
+
export interface UsePaneLanguagesParams {
|
|
10
|
+
options: LanguageFilterConfig
|
|
11
|
+
/**
|
|
12
|
+
* We need a way to communicate state changes between the pane menu and input components.
|
|
13
|
+
* LanguageFilter button lives outside the input-render tree, so Context is out.
|
|
14
|
+
* This is a workaround for that.
|
|
15
|
+
*/
|
|
16
|
+
onSelectedIdsChange: (ids: string[]) => void
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function usePaneLanguages(props: UsePaneLanguagesParams): {
|
|
20
|
+
activeLanguages: string[]
|
|
21
|
+
allSelected: boolean
|
|
22
|
+
selectAll: () => void
|
|
23
|
+
selectNone: () => void
|
|
24
|
+
toggleLanguage: (languageId: string) => void
|
|
25
|
+
} {
|
|
26
|
+
const {options, onSelectedIdsChange} = props
|
|
27
|
+
const {defaultLanguages} = options
|
|
28
|
+
|
|
29
|
+
const [selectedIds, setSelectedIds] = useSelectedLanguageIds(options)
|
|
30
|
+
|
|
31
|
+
const selectableLanguages = useMemo(() => getSelectableLanguages(options), [options])
|
|
32
|
+
|
|
33
|
+
const updateSelectedIds = useCallback(
|
|
34
|
+
(ids: string[]) => {
|
|
35
|
+
setSelectedIds(ids)
|
|
36
|
+
persistLanguageIds(ids)
|
|
37
|
+
onSelectedIdsChange(ids)
|
|
38
|
+
},
|
|
39
|
+
[onSelectedIdsChange, setSelectedIds]
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
const selectAll = useCallback(
|
|
43
|
+
() => updateSelectedIds(selectableLanguages.map((l) => l.id)),
|
|
44
|
+
[updateSelectedIds, selectableLanguages]
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
const selectNone = useCallback(() => {
|
|
48
|
+
updateSelectedIds([])
|
|
49
|
+
}, [updateSelectedIds])
|
|
50
|
+
|
|
51
|
+
const toggleLanguage = useCallback(
|
|
52
|
+
(languageId: string) => {
|
|
53
|
+
let lang = selectedIds
|
|
54
|
+
|
|
55
|
+
if (lang.includes(languageId)) {
|
|
56
|
+
lang = lang.filter((l) => l !== languageId)
|
|
57
|
+
} else {
|
|
58
|
+
lang = [...lang, languageId]
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
updateSelectedIds(lang)
|
|
62
|
+
},
|
|
63
|
+
[updateSelectedIds, selectedIds]
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
const activeLanguages = useMemo(
|
|
67
|
+
() => [...(defaultLanguages ?? []), ...selectedIds],
|
|
68
|
+
[defaultLanguages, selectedIds]
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
activeLanguages,
|
|
73
|
+
allSelected: selectedIds.length === selectableLanguages.length,
|
|
74
|
+
selectAll,
|
|
75
|
+
selectNone,
|
|
76
|
+
toggleLanguage,
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {Language, LanguageFilterConfig} from './types'
|
|
2
|
+
import {useState} from 'react'
|
|
3
|
+
const storageKey = '@sanity/plugin/language-filter/selected-languages'
|
|
4
|
+
|
|
5
|
+
export function getPersistedLanguageIds(options: LanguageFilterConfig): string[] {
|
|
6
|
+
const selectableLangs = getSelectableLanguages(options).map((l) => l.id)
|
|
7
|
+
|
|
8
|
+
let selected: string[] = selectableLangs
|
|
9
|
+
try {
|
|
10
|
+
const persistedValue = window.localStorage.getItem(storageKey)
|
|
11
|
+
if (persistedValue) {
|
|
12
|
+
selected = JSON.parse(persistedValue)
|
|
13
|
+
}
|
|
14
|
+
} catch (err) {} // eslint-disable-line no-empty
|
|
15
|
+
|
|
16
|
+
// constrain persisted/selected languages to the ones currently supported
|
|
17
|
+
selected = intersection(selected, selectableLangs)
|
|
18
|
+
return selected
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function persistLanguageIds(languageIds: string[]): void {
|
|
22
|
+
window.localStorage.setItem(storageKey, JSON.stringify(languageIds))
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function intersection(array1: string[], array2: string[]) {
|
|
26
|
+
return array1.filter((value) => array2.includes(value))
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function getSelectableLanguages({
|
|
30
|
+
supportedLanguages,
|
|
31
|
+
defaultLanguages,
|
|
32
|
+
}: LanguageFilterConfig): Language[] {
|
|
33
|
+
return supportedLanguages.filter((lang) => !defaultLanguages?.includes(lang.id))
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function useSelectedLanguageIds(
|
|
37
|
+
options: LanguageFilterConfig
|
|
38
|
+
): [string[], (ids: string[]) => void] {
|
|
39
|
+
return useState(() => getPersistedLanguageIds(options))
|
|
40
|
+
}
|
|
@@ -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
|
-
});
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = void 0;
|
|
7
|
-
|
|
8
|
-
var _react = _interopRequireDefault(require("react"));
|
|
9
|
-
|
|
10
|
-
var _datastore = require("./datastore");
|
|
11
|
-
|
|
12
|
-
var _SelectLanguage = _interopRequireDefault(require("./SelectLanguage"));
|
|
13
|
-
|
|
14
|
-
var _config = _interopRequireDefault(require("part:@sanity/language-filter/config"));
|
|
15
|
-
|
|
16
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
17
|
-
|
|
18
|
-
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; }
|
|
19
|
-
|
|
20
|
-
class SelectLanguageProvider extends _react.default.Component {
|
|
21
|
-
constructor() {
|
|
22
|
-
super(...arguments);
|
|
23
|
-
|
|
24
|
-
_defineProperty(this, "state", {
|
|
25
|
-
selected: []
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
componentDidMount(props) {
|
|
30
|
-
this.subscription = _datastore.selectedLanguages$.subscribe(selected => {
|
|
31
|
-
this.setState({
|
|
32
|
-
selected: selected
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
componentWillUnmount(props) {
|
|
38
|
-
this.subscription.unsubscribe();
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
render() {
|
|
42
|
-
var selected = this.state.selected;
|
|
43
|
-
return _react.default.createElement(_SelectLanguage.default, {
|
|
44
|
-
languages: _config.default.supportedLanguages,
|
|
45
|
-
selected: selected,
|
|
46
|
-
onChange: _datastore.setLangs
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
exports.default = SelectLanguageProvider;
|
package/lib/datastore.js
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.filterFn$ = exports.selectedLanguages$ = exports.setLangs = void 0;
|
|
7
|
-
|
|
8
|
-
var _intersection2 = _interopRequireDefault(require("lodash/intersection"));
|
|
9
|
-
|
|
10
|
-
var _rxjs = require("rxjs");
|
|
11
|
-
|
|
12
|
-
var _operators = require("rxjs/operators");
|
|
13
|
-
|
|
14
|
-
var _config = _interopRequireDefault(require("part:@sanity/language-filter/config"));
|
|
15
|
-
|
|
16
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
17
|
-
|
|
18
|
-
var onSelect$ = new _rxjs.Subject();
|
|
19
|
-
|
|
20
|
-
var setLangs = langs => onSelect$.next(langs);
|
|
21
|
-
|
|
22
|
-
exports.setLangs = setLangs;
|
|
23
|
-
|
|
24
|
-
var persistOn = (key, defaultValue) => input$ => {
|
|
25
|
-
var persisted;
|
|
26
|
-
|
|
27
|
-
try {
|
|
28
|
-
persisted = JSON.parse(window.localStorage.getItem(key));
|
|
29
|
-
} catch (err) {} // eslint-disable-line no-empty
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return input$.pipe((0, _operators.startWith)(persisted || defaultValue), (0, _operators.tap)(value => {
|
|
33
|
-
window.localStorage.setItem(key, JSON.stringify(value));
|
|
34
|
-
}));
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
var SUPPORTED_LANG_IDS = _config.default.supportedLanguages.map(lang => lang.id);
|
|
38
|
-
|
|
39
|
-
var selectedLanguages$ = onSelect$.pipe((0, _operators.map)(selectedLangs => (0, _intersection2.default)(selectedLangs, SUPPORTED_LANG_IDS)), (0, _operators.publishReplay)(1), (0, _operators.refCount)(), persistOn('@sanity/plugin/language-filter/selected-languages', SUPPORTED_LANG_IDS));
|
|
40
|
-
exports.selectedLanguages$ = selectedLanguages$;
|
|
41
|
-
|
|
42
|
-
var defaultFilterField = (enclosingType, field, selectedLanguages) => !enclosingType.name.startsWith('locale') || selectedLanguages.includes(field.name);
|
|
43
|
-
|
|
44
|
-
var filterField = _config.default.filterField || defaultFilterField;
|
|
45
|
-
var filterFn$ = selectedLanguages$.pipe((0, _operators.map)(langs => {
|
|
46
|
-
return (enclosingType, field) => filterField(enclosingType, field, langs);
|
|
47
|
-
}));
|
|
48
|
-
exports.filterFn$ = filterFn$;
|
package/lib/filter-fields.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
Object.defineProperty(exports, "default", {
|
|
7
|
-
enumerable: true,
|
|
8
|
-
get: function get() {
|
|
9
|
-
return _datastore.filterFn$;
|
|
10
|
-
}
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
var _datastore = require("./datastore");
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
@import 'part:@sanity/base/theme/variables-style';
|
|
2
|
-
|
|
3
|
-
.target {
|
|
4
|
-
display: flex;
|
|
5
|
-
align-items: center;
|
|
6
|
-
color: var(--text-color);
|
|
7
|
-
opacity: 1;
|
|
8
|
-
min-width: 4rem;
|
|
9
|
-
font-size: var(--font-size-xsmall);
|
|
10
|
-
white-space: nowrap;
|
|
11
|
-
height: 2.5rem;
|
|
12
|
-
align-self: center;
|
|
13
|
-
margin-right: 1em;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.arrow {
|
|
17
|
-
margin-left: 0.4em;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
.root {
|
|
21
|
-
padding: 0.5em;
|
|
22
|
-
background-color: var(--component-bg);
|
|
23
|
-
color: var(--text-color);
|
|
24
|
-
composes: shadow-6dp from 'part:@sanity/base/theme/shadows-style';
|
|
25
|
-
user-select: none;
|
|
26
|
-
text-align: left;
|
|
27
|
-
overflow: auto;
|
|
28
|
-
overflow-x: hidden;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.list {
|
|
32
|
-
composes: resetList from 'part:@sanity/base/theme/layout/helpers';
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
.functions {
|
|
36
|
-
padding: 0.5em;
|
|
37
|
-
text-align: center;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.selectedNumFilter {
|
|
41
|
-
color: var(--state-danger-color);
|
|
42
|
-
font-weight: bold;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
.item {
|
|
46
|
-
padding: 0.5em;
|
|
47
|
-
composes: resetListItem from 'part:@sanity/base/theme/layout/helpers';
|
|
48
|
-
composes: item from 'part:@sanity/base/theme/layout/selectable-style';
|
|
49
|
-
white-space: nowrap;
|
|
50
|
-
}
|
package/src/SelectLanguage.js
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
/* eslint-disable complexity */
|
|
2
|
-
import React, {Fragment} from 'react'
|
|
3
|
-
import PropTypes from 'prop-types'
|
|
4
|
-
import Poppable from 'part:@sanity/components/utilities/poppable'
|
|
5
|
-
import Checkbox from 'part:@sanity/components/toggles/checkbox'
|
|
6
|
-
import Button from 'part:@sanity/components/buttons/default'
|
|
7
|
-
import styles from './styles/SelectLanguage.css'
|
|
8
|
-
import AngleDown from 'part:@sanity/base/angle-down-icon'
|
|
9
|
-
import AngleUp from 'part:@sanity/base/angle-up-icon'
|
|
10
|
-
|
|
11
|
-
const LanguagePropType = PropTypes.shape({id: PropTypes.string, title: PropTypes.string})
|
|
12
|
-
export default class SelectLanguage extends React.Component {
|
|
13
|
-
static propTypes = {
|
|
14
|
-
languages: PropTypes.arrayOf(LanguagePropType),
|
|
15
|
-
selected: PropTypes.arrayOf(LanguagePropType),
|
|
16
|
-
onChange: PropTypes.func
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
state = {isOpen: false}
|
|
20
|
-
refElement = React.createRef()
|
|
21
|
-
|
|
22
|
-
handleToggle = () => this.setState(prevState => ({isOpen: !prevState.isOpen}))
|
|
23
|
-
handleOpen = () => this.setState({isOpen: true})
|
|
24
|
-
handleClose = () => {
|
|
25
|
-
this.setState({isOpen: false})
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
selectLang = langId => {
|
|
29
|
-
const {selected, onChange} = this.props
|
|
30
|
-
onChange(selected.concat(langId))
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
unselectLang = langId => {
|
|
34
|
-
const {selected, onChange} = this.props
|
|
35
|
-
onChange(selected.filter(id => id !== langId))
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
handleSelectAll = event => {
|
|
39
|
-
const {languages, onChange} = this.props
|
|
40
|
-
onChange(languages.map(l => l.id))
|
|
41
|
-
}
|
|
42
|
-
handleSelectNone = event => {
|
|
43
|
-
const {onChange} = this.props
|
|
44
|
-
onChange([])
|
|
45
|
-
}
|
|
46
|
-
handleLangCheckboxChange = event => {
|
|
47
|
-
const id = event.target.getAttribute('data-lang-id')
|
|
48
|
-
const checked = event.target.checked
|
|
49
|
-
this[checked ? 'selectLang' : 'unselectLang'](id)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
render() {
|
|
53
|
-
const {isOpen} = this.state
|
|
54
|
-
const {languages, selected} = this.props
|
|
55
|
-
const allIsSelected = languages.length === selected.length
|
|
56
|
-
const refElement =
|
|
57
|
-
this.refElement && this.refElement.current && this.refElement.current._element
|
|
58
|
-
|
|
59
|
-
return (
|
|
60
|
-
<Fragment>
|
|
61
|
-
<span
|
|
62
|
-
className={styles.target}
|
|
63
|
-
onClick={this.handleToggle}
|
|
64
|
-
ref={this.refElement}
|
|
65
|
-
title={
|
|
66
|
-
allIsSelected
|
|
67
|
-
? 'Filter language fields'
|
|
68
|
-
: 'Displaying only fields for selected languages'
|
|
69
|
-
}
|
|
70
|
-
>
|
|
71
|
-
Filter languages{allIsSelected ? '…' : ` (${selected.length}/${languages.length})`}
|
|
72
|
-
<span className={styles.arrow}>{isOpen ? <AngleUp /> : <AngleDown />}</span>
|
|
73
|
-
</span>
|
|
74
|
-
<Poppable
|
|
75
|
-
onEscape={this.handleClose}
|
|
76
|
-
onClickOutside={this.handleClose}
|
|
77
|
-
placement="bottom-end"
|
|
78
|
-
referenceElement={refElement}
|
|
79
|
-
>
|
|
80
|
-
{isOpen && (
|
|
81
|
-
<div className={styles.root}>
|
|
82
|
-
<div className={styles.functions}>
|
|
83
|
-
<Button onClick={allIsSelected ? this.handleSelectNone : this.handleSelectAll}>
|
|
84
|
-
Select {allIsSelected ? 'none' : 'all'}
|
|
85
|
-
</Button>
|
|
86
|
-
</div>
|
|
87
|
-
<ul className={styles.list}>
|
|
88
|
-
{languages.map(lang => (
|
|
89
|
-
<li className={styles.item} key={lang.id}>
|
|
90
|
-
<Checkbox
|
|
91
|
-
onChange={this.handleLangCheckboxChange}
|
|
92
|
-
data-lang-id={lang.id}
|
|
93
|
-
checked={selected.includes(lang.id)}
|
|
94
|
-
>
|
|
95
|
-
{lang.title}
|
|
96
|
-
</Checkbox>
|
|
97
|
-
</li>
|
|
98
|
-
))}
|
|
99
|
-
</ul>
|
|
100
|
-
</div>
|
|
101
|
-
)}
|
|
102
|
-
</Poppable>
|
|
103
|
-
</Fragment>
|
|
104
|
-
)
|
|
105
|
-
}
|
|
106
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import {selectedLanguages$, setLangs} from './datastore'
|
|
3
|
-
import SelectLanguage from './SelectLanguage'
|
|
4
|
-
import config from 'part:@sanity/language-filter/config'
|
|
5
|
-
|
|
6
|
-
export default class SelectLanguageProvider extends React.Component {
|
|
7
|
-
state = {selected: []}
|
|
8
|
-
|
|
9
|
-
componentDidMount(props) {
|
|
10
|
-
this.subscription = selectedLanguages$.subscribe(selected => {
|
|
11
|
-
this.setState({selected: selected})
|
|
12
|
-
})
|
|
13
|
-
}
|
|
14
|
-
componentWillUnmount(props) {
|
|
15
|
-
this.subscription.unsubscribe()
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
render() {
|
|
19
|
-
const {selected} = this.state
|
|
20
|
-
return (
|
|
21
|
-
<SelectLanguage
|
|
22
|
-
languages={config.supportedLanguages}
|
|
23
|
-
selected={selected}
|
|
24
|
-
onChange={setLangs}
|
|
25
|
-
/>
|
|
26
|
-
)
|
|
27
|
-
}
|
|
28
|
-
}
|
package/src/datastore.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import {Subject} from 'rxjs'
|
|
2
|
-
import {map, publishReplay, refCount, startWith, tap} from 'rxjs/operators'
|
|
3
|
-
import config from 'part:@sanity/language-filter/config'
|
|
4
|
-
import {intersection} from 'lodash'
|
|
5
|
-
|
|
6
|
-
const onSelect$ = new Subject()
|
|
7
|
-
|
|
8
|
-
export const setLangs = langs => onSelect$.next(langs)
|
|
9
|
-
|
|
10
|
-
const persistOn = (key, defaultValue) => input$ => {
|
|
11
|
-
let persisted
|
|
12
|
-
try {
|
|
13
|
-
persisted = JSON.parse(window.localStorage.getItem(key))
|
|
14
|
-
} catch (err) {} // eslint-disable-line no-empty
|
|
15
|
-
|
|
16
|
-
return input$.pipe(
|
|
17
|
-
startWith(persisted || defaultValue),
|
|
18
|
-
tap(value => {
|
|
19
|
-
window.localStorage.setItem(key, JSON.stringify(value))
|
|
20
|
-
})
|
|
21
|
-
)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const SUPPORTED_LANG_IDS = config.supportedLanguages.map(lang => lang.id)
|
|
25
|
-
|
|
26
|
-
export const selectedLanguages$ = onSelect$.pipe(
|
|
27
|
-
map(selectedLangs => intersection(selectedLangs, SUPPORTED_LANG_IDS)),
|
|
28
|
-
publishReplay(1),
|
|
29
|
-
refCount(),
|
|
30
|
-
persistOn('@sanity/plugin/language-filter/selected-languages', SUPPORTED_LANG_IDS)
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
const defaultFilterField = (enclosingType, field, selectedLanguages) =>
|
|
34
|
-
!enclosingType.name.startsWith('locale') || selectedLanguages.includes(field.name)
|
|
35
|
-
|
|
36
|
-
const filterField = config.filterField || defaultFilterField
|
|
37
|
-
|
|
38
|
-
export const filterFn$ = selectedLanguages$.pipe(
|
|
39
|
-
map(langs => {
|
|
40
|
-
return (enclosingType, field) => filterField(enclosingType, field, langs)
|
|
41
|
-
})
|
|
42
|
-
)
|
package/src/filter-fields.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {filterFn$ as default} from './datastore'
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
@import 'part:@sanity/base/theme/variables-style';
|
|
2
|
-
|
|
3
|
-
.target {
|
|
4
|
-
display: flex;
|
|
5
|
-
align-items: center;
|
|
6
|
-
color: var(--text-color);
|
|
7
|
-
opacity: 1;
|
|
8
|
-
min-width: 4rem;
|
|
9
|
-
font-size: var(--font-size-xsmall);
|
|
10
|
-
white-space: nowrap;
|
|
11
|
-
height: 2.5rem;
|
|
12
|
-
align-self: center;
|
|
13
|
-
margin-right: 1em;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.arrow {
|
|
17
|
-
margin-left: 0.4em;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
.root {
|
|
21
|
-
padding: 0.5em;
|
|
22
|
-
background-color: var(--component-bg);
|
|
23
|
-
color: var(--text-color);
|
|
24
|
-
composes: shadow-6dp from 'part:@sanity/base/theme/shadows-style';
|
|
25
|
-
user-select: none;
|
|
26
|
-
text-align: left;
|
|
27
|
-
overflow: auto;
|
|
28
|
-
overflow-x: hidden;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.list {
|
|
32
|
-
composes: resetList from 'part:@sanity/base/theme/layout/helpers';
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
.functions {
|
|
36
|
-
padding: 0.5em;
|
|
37
|
-
text-align: center;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.selectedNumFilter {
|
|
41
|
-
color: var(--state-danger-color);
|
|
42
|
-
font-weight: bold;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
.item {
|
|
46
|
-
padding: 0.5em;
|
|
47
|
-
composes: resetListItem from 'part:@sanity/base/theme/layout/helpers';
|
|
48
|
-
composes: item from 'part:@sanity/base/theme/layout/selectable-style';
|
|
49
|
-
white-space: nowrap;
|
|
50
|
-
}
|