sanity-plugin-internationalized-array 0.0.3 → 0.0.6
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/README.md +41 -9
- package/lib/LanguageArray/Table.js +72 -0
- package/lib/LanguageArray/Table.js.map +1 -0
- package/lib/LanguageArray/index.js +37 -29
- package/lib/LanguageArray/index.js.map +1 -1
- package/lib/{LanguageArray → hooks}/useUnsetInputComponent.js +0 -0
- package/lib/hooks/useUnsetInputComponent.js.map +1 -0
- package/lib/internationalizedArray.js +9 -2
- package/lib/internationalizedArray.js.map +1 -1
- package/lib/types.js.map +1 -1
- package/migrations/transformObjectToArray.js +94 -0
- package/package.json +3 -2
- package/src/LanguageArray/Table.tsx +73 -0
- package/src/LanguageArray/index.tsx +65 -46
- package/src/{LanguageArray/useUnsetInputComponent.ts → hooks/useUnsetInputComponent.tsx} +2 -2
- package/src/internationalizedArray.ts +10 -1
- package/src/types.ts +7 -0
- package/lib/LanguageArray/useUnsetInputComponent.js.map +0 -1
package/README.md
CHANGED
|
@@ -25,13 +25,18 @@ export default {
|
|
|
25
25
|
fields: [
|
|
26
26
|
// ...all your other fields
|
|
27
27
|
internationalizedArray({
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
// Required, the `name` of the outer array
|
|
29
|
+
name: "greeting",
|
|
30
|
+
// Required, the `type` of the inner field
|
|
31
|
+
// One of: string | text | number | boolean
|
|
32
|
+
type: "string",
|
|
33
|
+
// Required, must be an array of objects
|
|
30
34
|
languages: [
|
|
31
35
|
{ id: "en", title: "English" },
|
|
32
36
|
{ id: "fr", title: "French" },
|
|
33
|
-
],
|
|
34
|
-
|
|
37
|
+
],
|
|
38
|
+
// Optional: just for debugging
|
|
39
|
+
showNativeInput: false,
|
|
35
40
|
}),
|
|
36
41
|
],
|
|
37
42
|
};
|
|
@@ -54,24 +59,51 @@ Using GROQ filters you can query for a specific language key like so:
|
|
|
54
59
|
}
|
|
55
60
|
```
|
|
56
61
|
|
|
62
|
+
## Migrate from objects to arrays
|
|
63
|
+
|
|
64
|
+
[See the migration script](https://github.com/SimeonGriggs/sanity-plugin-internationalized-array/blob/main/migrations/transformObjectToArray.js) inside `./migrations/transformObjectToArray.js` of this Repo.
|
|
65
|
+
|
|
66
|
+
Follow the instructions inside the script and set the `_type` and field name you wish to target.
|
|
67
|
+
|
|
68
|
+
Please take a backup first!
|
|
69
|
+
|
|
57
70
|
### Why store localised field data like this?
|
|
58
71
|
|
|
59
72
|
The most popular way to store field-level translated content is in an object using the method prescribed in [@sanity/language-filter](https://www.npmjs.com/package/@sanity/language-filter). This works well and creates tidy object structures, but also create a unique field path for every unique field name, multiplied by the number of languages in your dataset.
|
|
60
73
|
|
|
61
|
-
For most people, this won't become an issue. On a very large dataset with a lot of languages, the [Attribute Limit](https://www.sanity.io/docs/attribute-limit) can become a concern.
|
|
74
|
+
For most people, this won't become an issue. On a very large dataset with a lot of languages, the [Attribute Limit](https://www.sanity.io/docs/attribute-limit) can become a concern. This plugin's arrays will use less attributes than an object once you have more than three languages.
|
|
62
75
|
|
|
63
|
-
|
|
76
|
+
The same content as above, plus a third language, structed as an `object` of `string` fields looks like this:
|
|
64
77
|
|
|
65
78
|
```json
|
|
66
79
|
"greeting" {
|
|
67
80
|
"en": "hello",
|
|
68
|
-
"fr": "bonjour"
|
|
81
|
+
"fr": "bonjour",
|
|
82
|
+
"es": "hola"
|
|
69
83
|
}
|
|
70
84
|
```
|
|
71
85
|
|
|
72
|
-
|
|
86
|
+
Which creates four unique query paths, one for the object and one for each language.
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
greeting
|
|
90
|
+
greeting.en
|
|
91
|
+
greeting.fr
|
|
92
|
+
greeting.es
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Every language you add to every object that uses this structure will add to the number of unique query paths.
|
|
96
|
+
|
|
97
|
+
The array created by this plugin creates four query paths by default, but is not effected by the number of languages:
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
greeting
|
|
101
|
+
greeting[]
|
|
102
|
+
greeting[]._key
|
|
103
|
+
greeting[].value
|
|
104
|
+
```
|
|
73
105
|
|
|
74
|
-
|
|
106
|
+
By using this plugin you can safely extend the number of languages without adding any additional query paths.
|
|
75
107
|
|
|
76
108
|
## License
|
|
77
109
|
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.Row = exports.Cell = void 0;
|
|
7
|
+
exports.Table = Table;
|
|
8
|
+
exports.TableCell = TableCell;
|
|
9
|
+
exports.TableRow = TableRow;
|
|
10
|
+
exports.TableWrapper = void 0;
|
|
11
|
+
|
|
12
|
+
var _react = _interopRequireDefault(require("react"));
|
|
13
|
+
|
|
14
|
+
var _styledComponents = _interopRequireWildcard(require("styled-components"));
|
|
15
|
+
|
|
16
|
+
var _ui = require("@sanity/ui");
|
|
17
|
+
|
|
18
|
+
var _excluded = ["children"],
|
|
19
|
+
_excluded2 = ["children"];
|
|
20
|
+
|
|
21
|
+
var _templateObject, _templateObject2, _templateObject3;
|
|
22
|
+
|
|
23
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
24
|
+
|
|
25
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && 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; }
|
|
26
|
+
|
|
27
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
28
|
+
|
|
29
|
+
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
30
|
+
|
|
31
|
+
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
|
32
|
+
|
|
33
|
+
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
|
34
|
+
|
|
35
|
+
function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); } return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); }
|
|
36
|
+
|
|
37
|
+
var TableWrapper = (0, _styledComponents.default)(_ui.Box)(() => (0, _styledComponents.css)(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n display: table;\n "]))));
|
|
38
|
+
exports.TableWrapper = TableWrapper;
|
|
39
|
+
|
|
40
|
+
function Table(props) {
|
|
41
|
+
var children = props.children,
|
|
42
|
+
rest = _objectWithoutProperties(props, _excluded);
|
|
43
|
+
|
|
44
|
+
return /*#__PURE__*/_react.default.createElement(TableWrapper, _extends({
|
|
45
|
+
as: "table"
|
|
46
|
+
}, rest), children);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
var Row = (0, _styledComponents.default)(_ui.Card)(() => (0, _styledComponents.css)(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n display: table-row;\n\n &:not([hidden]) {\n display: table-row;\n }\n "]))));
|
|
50
|
+
exports.Row = Row;
|
|
51
|
+
|
|
52
|
+
function TableRow(props) {
|
|
53
|
+
var children = props.children,
|
|
54
|
+
rest = _objectWithoutProperties(props, _excluded2);
|
|
55
|
+
|
|
56
|
+
return /*#__PURE__*/_react.default.createElement(Row, _extends({
|
|
57
|
+
as: "tr"
|
|
58
|
+
}, rest), children);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
var Cell = (0, _styledComponents.default)(_ui.Box)(() => (0, _styledComponents.css)(_templateObject3 || (_templateObject3 = _taggedTemplateLiteral(["\n display: table-cell;\n "]))));
|
|
62
|
+
exports.Cell = Cell;
|
|
63
|
+
|
|
64
|
+
function TableCell(props) {
|
|
65
|
+
var children = props.children,
|
|
66
|
+
style = props.style;
|
|
67
|
+
return /*#__PURE__*/_react.default.createElement(Cell, {
|
|
68
|
+
as: "td",
|
|
69
|
+
style: style
|
|
70
|
+
}, children);
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=Table.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Table.js","names":["TableWrapper","styled","Box","css","Table","props","children","rest","Row","Card","TableRow","Cell","TableCell","style"],"sources":["../../src/LanguageArray/Table.tsx"],"sourcesContent":["import React from 'react'\nimport styled, {css} from 'styled-components'\nimport {Box, Card} from '@sanity/ui'\n\nexport const TableWrapper = styled(Box)(\n () =>\n css`\n display: table;\n `\n)\n\ntype TableProps = {\n children: React.ReactNode\n [key: string]: unknown\n}\n\nexport function Table(props: TableProps) {\n const {children, ...rest} = props\n\n return (\n <TableWrapper as=\"table\" {...rest}>\n {children}\n </TableWrapper>\n )\n}\n\nexport const Row = styled(Card)(\n () =>\n css`\n display: table-row;\n\n &:not([hidden]) {\n display: table-row;\n }\n `\n)\n\ntype TableRowProps = {\n children: React.ReactNode\n [key: string]: unknown\n}\n\nexport function TableRow(props: TableRowProps) {\n const {children, ...rest} = props\n\n return (\n <Row as=\"tr\" {...rest}>\n {children}\n </Row>\n )\n}\n\nexport const Cell = styled(Box)(\n () =>\n css`\n display: table-cell;\n `\n)\n\ntype TableCellProps = {\n children: React.ReactNode\n style?: React.CSSProperties\n}\n\nexport function TableCell(props: TableCellProps) {\n const {children, style} = props\n\n return (\n <Cell as=\"td\" style={style}>\n {children}\n </Cell>\n )\n}\n"],"mappings":";;;;;;;;;;;AAAA;;AACA;;AACA;;;;;;;;;;;;;;;;;;;;;AAEO,IAAMA,YAAY,GAAG,IAAAC,yBAAA,EAAOC,OAAP,EAC1B,UACEC,qBADF,mGAD0B,CAArB;;;AAYA,SAASC,KAAT,CAAeC,KAAf,EAAkC;EACvC,IAAOC,QAAP,GAA4BD,KAA5B,CAAOC,QAAP;EAAA,IAAoBC,IAApB,4BAA4BF,KAA5B;;EAEA,oBACE,6BAAC,YAAD;IAAc,EAAE,EAAC;EAAjB,GAA6BE,IAA7B,GACGD,QADH,CADF;AAKD;;AAEM,IAAME,GAAG,GAAG,IAAAP,yBAAA,EAAOQ,QAAP,EACjB,UACEN,qBADF,0KADiB,CAAZ;;;AAgBA,SAASO,QAAT,CAAkBL,KAAlB,EAAwC;EAC7C,IAAOC,QAAP,GAA4BD,KAA5B,CAAOC,QAAP;EAAA,IAAoBC,IAApB,4BAA4BF,KAA5B;;EAEA,oBACE,6BAAC,GAAD;IAAK,EAAE,EAAC;EAAR,GAAiBE,IAAjB,GACGD,QADH,CADF;AAKD;;AAEM,IAAMK,IAAI,GAAG,IAAAV,yBAAA,EAAOC,OAAP,EAClB,UACEC,qBADF,0GADkB,CAAb;;;AAYA,SAASS,SAAT,CAAmBP,KAAnB,EAA0C;EAC/C,IAAOC,QAAP,GAA0BD,KAA1B,CAAOC,QAAP;EAAA,IAAiBO,KAAjB,GAA0BR,KAA1B,CAAiBQ,KAAjB;EAEA,oBACE,6BAAC,IAAD;IAAM,EAAE,EAAC,IAAT;IAAc,KAAK,EAAEA;EAArB,GACGP,QADH,CADF;AAKD"}
|
|
@@ -23,7 +23,9 @@ var _FormBuilderInput = require("@sanity/form-builder/lib/FormBuilderInput");
|
|
|
23
23
|
|
|
24
24
|
var _ValueInput = _interopRequireDefault(require("./ValueInput"));
|
|
25
25
|
|
|
26
|
-
var
|
|
26
|
+
var _Table = require("./Table");
|
|
27
|
+
|
|
28
|
+
var _useUnsetInputComponent = require("../hooks/useUnsetInputComponent");
|
|
27
29
|
|
|
28
30
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
29
31
|
|
|
@@ -51,7 +53,7 @@ var DEFAULT_OPTIONS = {
|
|
|
51
53
|
showNativeInput: false
|
|
52
54
|
};
|
|
53
55
|
var LanguageArrayWrapper = /*#__PURE__*/(0, _react.forwardRef)(function CustomComponent(props, ref) {
|
|
54
|
-
var _type$options;
|
|
56
|
+
var _type$options, _type$title;
|
|
55
57
|
|
|
56
58
|
var onChange = props.onChange,
|
|
57
59
|
onBlur = props.onBlur,
|
|
@@ -152,35 +154,31 @@ var LanguageArrayWrapper = /*#__PURE__*/(0, _react.forwardRef)(function CustomCo
|
|
|
152
154
|
var validationMarkers = markers !== null && markers !== void 0 && markers.length ? markers.filter(mark => mark.type === "validation") : [];
|
|
153
155
|
var invalidKeys = validationMarkers.map(mark => mark.path).flat().map(item => item._key);
|
|
154
156
|
return /*#__PURE__*/_react.default.createElement(_ui.Stack, {
|
|
155
|
-
space:
|
|
156
|
-
}, (
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}, /*#__PURE__*/_react.default.createElement(_ui.Stack, {
|
|
161
|
-
space: 1
|
|
162
|
-
}, value.map(item => {
|
|
157
|
+
space: 3
|
|
158
|
+
}, /*#__PURE__*/_react.default.createElement(_ui.Box, null, /*#__PURE__*/_react.default.createElement(_ui.Text, {
|
|
159
|
+
size: 1,
|
|
160
|
+
weight: "bold"
|
|
161
|
+
}, (_type$title = type === null || type === void 0 ? void 0 : type.title) !== null && _type$title !== void 0 ? _type$title : type.name)), (value === null || value === void 0 ? void 0 : value.length) > 0 ? /*#__PURE__*/_react.default.createElement(_ui.Card, null, /*#__PURE__*/_react.default.createElement(_Table.Table, null, /*#__PURE__*/_react.default.createElement("tbody", null, value.map(item => {
|
|
163
162
|
var _type$of;
|
|
164
163
|
|
|
165
|
-
return /*#__PURE__*/_react.default.createElement(
|
|
164
|
+
return /*#__PURE__*/_react.default.createElement(_Table.TableRow, {
|
|
166
165
|
paddingY: 1,
|
|
167
166
|
paddingX: 2,
|
|
168
167
|
key: item._key,
|
|
169
168
|
tone: // TODO: Move this logic somewhere else
|
|
170
169
|
invalidKeys.includes(item._key) ? "critical" : undefined || languagesOutOfOrder.find(l => l._key === item._key) ? "caution" : undefined
|
|
171
|
-
}, /*#__PURE__*/_react.default.createElement(_ui.Flex, {
|
|
172
|
-
gap: 3,
|
|
173
|
-
align: "center"
|
|
174
170
|
}, (type === null || type === void 0 ? void 0 : (_type$of = type.of) === null || _type$of === void 0 ? void 0 : _type$of.length) > 0 && (type === null || type === void 0 ? void 0 : type.of.map(subType => {
|
|
175
171
|
var _subType$fields;
|
|
176
172
|
|
|
177
|
-
return /*#__PURE__*/_react.default.createElement(_ui.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
},
|
|
183
|
-
|
|
173
|
+
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, (subType === null || subType === void 0 ? void 0 : (_subType$fields = subType.fields) === null || _subType$fields === void 0 ? void 0 : _subType$fields.length) > 0 ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_Table.TableCell, null, /*#__PURE__*/_react.default.createElement(_ui.Box, {
|
|
174
|
+
paddingRight: 2
|
|
175
|
+
}, /*#__PURE__*/_react.default.createElement(_ui.Label, {
|
|
176
|
+
muted: true,
|
|
177
|
+
size: 1
|
|
178
|
+
}, item._key))), /*#__PURE__*/_react.default.createElement(_Table.TableCell, {
|
|
179
|
+
style: {
|
|
180
|
+
width: "100%"
|
|
181
|
+
}
|
|
184
182
|
}, subType.fields.map(subTypeField => /*#__PURE__*/_react.default.createElement(_ValueInput.default, {
|
|
185
183
|
key: subTypeField.name,
|
|
186
184
|
onChange: patchEvent => handleInnerValueChange(patchEvent, item._key),
|
|
@@ -189,26 +187,35 @@ var LanguageArrayWrapper = /*#__PURE__*/(0, _react.forwardRef)(function CustomCo
|
|
|
189
187
|
onFocus: () => null,
|
|
190
188
|
path: [{
|
|
191
189
|
_key: item._key
|
|
192
|
-
}, subTypeField.name],
|
|
190
|
+
}, subTypeField.name] // focusPath={[{_key: item._key}, subTypeField.name]}
|
|
191
|
+
,
|
|
193
192
|
parent: item,
|
|
194
193
|
readOnly: readOnly,
|
|
195
194
|
type: subTypeField,
|
|
196
195
|
value: item.value,
|
|
197
196
|
level: props.level + 1,
|
|
198
|
-
markers: []
|
|
197
|
+
markers: [],
|
|
198
|
+
compareValue: props.compareValue
|
|
199
199
|
})))) : null);
|
|
200
|
-
})), (
|
|
200
|
+
})), /*#__PURE__*/_react.default.createElement(_Table.TableCell, null, /*#__PURE__*/_react.default.createElement(_ui.Flex, {
|
|
201
|
+
align: "center",
|
|
202
|
+
justify: "flex-end",
|
|
203
|
+
gap: 2
|
|
204
|
+
}, (presence === null || presence === void 0 ? void 0 : presence.length) > 0 ? /*#__PURE__*/_react.default.createElement(_presence.FieldPresence, {
|
|
201
205
|
maxAvatars: 1,
|
|
202
206
|
presence: presence
|
|
203
|
-
}) : null, invalidKeys.includes(item._key) ? /*#__PURE__*/_react.default.createElement(
|
|
207
|
+
}) : null, invalidKeys.includes(item._key) ? /*#__PURE__*/_react.default.createElement(_ui.Box, {
|
|
208
|
+
paddingLeft: 2
|
|
209
|
+
}, /*#__PURE__*/_react.default.createElement(_components.FormFieldValidationStatus, {
|
|
204
210
|
__unstable_markers: validationMarkers
|
|
205
|
-
}) : null, /*#__PURE__*/_react.default.createElement(_ui.Button, {
|
|
211
|
+
})) : null, /*#__PURE__*/_react.default.createElement(_ui.Button, {
|
|
206
212
|
mode: "ghost",
|
|
207
213
|
icon: _icons.RemoveIcon,
|
|
208
214
|
tone: "critical",
|
|
215
|
+
disabled: readOnly,
|
|
209
216
|
onClick: () => handleUnsetByKey(item._key)
|
|
210
|
-
})));
|
|
211
|
-
}))) : null, languagesOutOfOrder.length > 0 ? /*#__PURE__*/_react.default.createElement(_ui.Button, {
|
|
217
|
+
}))));
|
|
218
|
+
})))) : null, languagesOutOfOrder.length > 0 ? /*#__PURE__*/_react.default.createElement(_ui.Button, {
|
|
212
219
|
tone: "caution",
|
|
213
220
|
disabled: languagesOutOfOrder.length > languages.length,
|
|
214
221
|
icon: _icons.RestoreIcon,
|
|
@@ -232,10 +239,11 @@ var LanguageArrayWrapper = /*#__PURE__*/(0, _react.forwardRef)(function CustomCo
|
|
|
232
239
|
tone: "primary",
|
|
233
240
|
mode: "ghost",
|
|
234
241
|
disabled: readOnly || (value === null || value === void 0 ? void 0 : value.length) >= (languages === null || languages === void 0 ? void 0 : languages.length),
|
|
242
|
+
icon: _icons.AddIcon,
|
|
235
243
|
text: value !== null && value !== void 0 && value.length ? "Add missing languages" : "Add all languages",
|
|
236
244
|
onClick: () => handleAddLanguage()
|
|
237
245
|
})) : null, showNativeInput ? /*#__PURE__*/_react.default.createElement(_FormBuilderInput.FormBuilderInput, _extends({}, props, {
|
|
238
|
-
type:
|
|
246
|
+
type: type,
|
|
239
247
|
ref: ref
|
|
240
248
|
})) : null);
|
|
241
249
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["schemaExample","name","type","options","languages","id","title","DEFAULT_OPTIONS","showNativeInput","LanguageArrayWrapper","forwardRef","CustomComponent","props","ref","onChange","onBlur","readOnly","presence","markers","value","useUnsetInputComponent","handleAddLanguage","useCallback","languageId","newItems","_key","filter","language","length","find","v","map","languagesInUse","insertions","item","languageIndex","findIndex","l","remainingLanguages","slice","nextLanguageIndex","r","push","splice","insert","PatchEvent","from","setIfMissing","handleUnsetByKey","unset","handleInnerValueChange","patchEvent","inputValue","patches","inputPath","set","handleRestoreOrder","updatedValue","reduce","acc","newIndex","languagesOutOfOrder","useMemo","vIndex","Boolean","languagesAreValid","every","JSON","stringify","validationMarkers","mark","invalidKeys","path","flat","includes","undefined","of","subType","fields","subTypeField","level","RemoveIcon","RestoreIcon","Math","min","toUpperCase","AddIcon","typeWithoutInputComponent","withDocument"],"sources":["../../src/LanguageArray/index.tsx"],"sourcesContent":["import React, {forwardRef, useCallback, useMemo} from 'react'\nimport {Code, Text, Card, Label, Flex, Box, Stack, Button, Grid} from '@sanity/ui'\nimport {withDocument} from 'part:@sanity/form-builder'\nimport {PatchEvent, setIfMissing, insert, unset, set} from '@sanity/form-builder/PatchEvent'\nimport {AddIcon, RemoveIcon, RestoreIcon} from '@sanity/icons'\nimport {FormFieldValidationStatus} from '@sanity/base/components'\nimport {FieldPresence} from '@sanity/base/presence'\nimport {FormBuilderInput} from '@sanity/form-builder/lib/FormBuilderInput'\n\nimport ValueInput from './ValueInput'\nimport {useUnsetInputComponent} from './useUnsetInputComponent'\n\nconst schemaExample = {\n name: 'title',\n type: 'localisedArray',\n options: {\n languages: [\n {id: 'en', title: 'English'},\n {id: 'no', title: 'Norsk'},\n ],\n },\n}\n\ntype Value = {\n _key: string\n value?: string\n}\n\ntype Language = {\n id: string\n title: string\n}\n\ntype Options = {\n languages: Language[]\n showNativeInput: boolean\n}\n\nconst DEFAULT_OPTIONS = {\n languages: [],\n showNativeInput: false,\n}\n\nconst LanguageArrayWrapper = forwardRef(function CustomComponent(props, ref) {\n const {onChange, onBlur, readOnly, presence, markers} = props\n const value: Value[] = props?.value\n\n // IMPORTANT: leaving out will cause the browser to lock up in an infinite loop\n const type = useUnsetInputComponent(props.type)\n const options: Options = type?.options ?? DEFAULT_OPTIONS\n const {languages, showNativeInput} = options\n\n const handleAddLanguage = useCallback(\n (languageId?: string) => {\n // Create new items\n const newItems = languageId\n ? // Just one for this language\n [{_key: languageId}]\n : // Or one for every missing language\n languages\n .filter((language) =>\n value?.length ? !value.find((v) => v._key === language.id) : true\n )\n .map((language) => ({_key: language.id}))\n\n // Insert new items in the correct order\n const languagesInUse = value?.length ? value.map((v) => v) : []\n\n const insertions = newItems.map((item) => {\n // What's the original index of this language?\n const languageIndex = languages.findIndex((l) => item._key === l.id)\n\n // What languages are there beyond that index?\n const remainingLanguages = languages.slice(languageIndex + 1)\n\n // So what is the index in the current value array of the next language in the language array?\n const nextLanguageIndex = languagesInUse.findIndex((l) =>\n remainingLanguages.find((r) => r.id === l._key)\n )\n\n // Keep local state up to date incase multiple insertions are being made\n if (nextLanguageIndex < 0) {\n languagesInUse.push(item)\n } else {\n languagesInUse.splice(nextLanguageIndex, 0, item)\n }\n\n return nextLanguageIndex < 0\n ? // No next language (-1), add to end of array\n insert([item], 'after', [nextLanguageIndex])\n : // Next language found, insert before that\n insert([item], 'before', [nextLanguageIndex])\n })\n\n onChange(PatchEvent.from(setIfMissing([]), ...insertions))\n },\n [languages, onChange, value]\n )\n\n const handleUnsetByKey = useCallback(\n (_key) => {\n onChange(PatchEvent.from(unset([{_key}])))\n },\n [onChange]\n )\n\n const handleInnerValueChange = useCallback(\n (patchEvent: PatchEvent, _key: string) => {\n const inputValue = patchEvent.patches[0]?.value\n const inputPath = [{_key}, `value`]\n\n onChange(PatchEvent.from(inputValue ? set(inputValue, inputPath) : unset(inputPath)))\n },\n [onChange]\n )\n\n // TODO: This is lazy, reordering and re-setting the whole array – it should be surgical\n const handleRestoreOrder = useCallback(() => {\n // Create a new value array in the correct order\n const updatedValue = value.reduce((acc, v) => {\n const newIndex = languages.findIndex((l) => l.id === v._key)\n\n acc[newIndex] = v\n\n return acc\n }, [])\n\n onChange(PatchEvent.from(unset(), set(updatedValue)))\n }, [languages, onChange, value])\n\n // Check languages are in the correct order\n const languagesOutOfOrder = useMemo(() => {\n if (!value?.length) {\n return []\n }\n\n const languagesInUse = languages.filter((l) => value.find((v) => v._key === l.id))\n\n return value\n .map((v, vIndex) => (vIndex === languagesInUse.findIndex((l) => l.id === v._key) ? null : v))\n .filter(Boolean)\n }, [value, languages])\n\n // Check options are supplied and valid\n const languagesAreValid = useMemo(\n () => languages?.length && languages.every((item) => item.id && item.title),\n [languages]\n )\n\n if (!languagesAreValid) {\n return (\n <Card tone=\"caution\" border radius={2} padding={3}>\n <Stack space={4}>\n <Text>\n An array of language objects must be passed into the <code>{type.name}</code> field as\n options, each with an <code>id</code> and <code>title</code> field. Example:\n </Text>\n <Card padding={2} border radius={2}>\n <Code size={1} language=\"javascript\">\n {JSON.stringify(schemaExample, null, 2)}\n </Code>\n </Card>\n </Stack>\n </Card>\n )\n }\n\n const validationMarkers = markers?.length\n ? markers.filter((mark) => mark.type === `validation`)\n : []\n const invalidKeys = validationMarkers\n .map((mark) => mark.path)\n .flat()\n .map((item) => item._key)\n\n return (\n <Stack space={2}>\n {/* Loop over the values */}\n {value?.length > 0 ? (\n <Card padding={1} border radius={1}>\n <Stack space={1}>\n {value.map((item) => (\n <Card\n paddingY={1}\n paddingX={2}\n key={item._key}\n tone={\n // TODO: Move this logic somewhere else\n invalidKeys.includes(item._key)\n ? `critical`\n : undefined || languagesOutOfOrder.find((l) => l._key === item._key)\n ? `caution`\n : undefined\n }\n >\n <Flex gap={3} align=\"center\">\n {/* To render each individual field in this type */}\n {type?.of?.length > 0 &&\n type?.of.map((subType) => (\n <Flex key={subType.name} flex={1} align=\"center\" gap={2}>\n {subType?.fields?.length > 0 ? (\n <>\n <Box>\n <Label>{item._key}</Label>\n </Box>\n <Box flex={1}>\n {/* There _should_ only be one field */}\n {subType.fields.map((subTypeField) => (\n <ValueInput\n key={subTypeField.name}\n onChange={(patchEvent) =>\n handleInnerValueChange(patchEvent, item._key)\n }\n onBlur={onBlur}\n // We don't want the array item to open onFocus\n onFocus={() => null}\n path={[{_key: item._key}, subTypeField.name]}\n parent={item}\n readOnly={readOnly}\n type={subTypeField}\n value={item.value}\n level={props.level + 1}\n markers={[]}\n />\n ))}\n </Box>\n </>\n ) : null}\n </Flex>\n ))}\n {presence?.length > 0 ? (\n <FieldPresence maxAvatars={1} presence={presence} />\n ) : null}\n {invalidKeys.includes(item._key) ? (\n <FormFieldValidationStatus __unstable_markers={validationMarkers} />\n ) : null}\n <Button\n mode=\"ghost\"\n icon={RemoveIcon}\n tone=\"critical\"\n onClick={() => handleUnsetByKey(item._key)}\n />\n </Flex>\n </Card>\n ))}\n </Stack>\n </Card>\n ) : null}\n\n {languagesOutOfOrder.length > 0 ? (\n <Button\n tone=\"caution\"\n disabled={languagesOutOfOrder.length > languages.length}\n icon={RestoreIcon}\n onClick={() => handleRestoreOrder()}\n text=\"Restore order of languages\"\n />\n ) : null}\n\n {languages.length > 0 ? (\n <Stack space={2}>\n {/* No more than 5 columns */}\n <Grid columns={Math.min(languages.length, 5)} gap={2}>\n {languages.map((language) => (\n <Button\n key={language.id}\n tone=\"primary\"\n mode=\"ghost\"\n fontSize={1}\n disabled={readOnly || value?.find((item) => item._key === language.id)}\n text={language.id.toUpperCase()}\n icon={AddIcon}\n onClick={() => handleAddLanguage(language.id)}\n />\n ))}\n </Grid>\n <Button\n tone=\"primary\"\n mode=\"ghost\"\n disabled={readOnly || value?.length >= languages?.length}\n text={value?.length ? `Add missing languages` : `Add all languages`}\n onClick={() => handleAddLanguage()}\n />\n </Stack>\n ) : null}\n\n {showNativeInput ? (\n <FormBuilderInput {...props} type={typeWithoutInputComponent} ref={ref} />\n ) : null}\n </Stack>\n )\n})\n\nexport default withDocument(LanguageArrayWrapper)\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["schemaExample","name","type","options","languages","id","title","DEFAULT_OPTIONS","showNativeInput","LanguageArrayWrapper","forwardRef","CustomComponent","props","ref","onChange","onBlur","readOnly","presence","markers","value","useUnsetInputComponent","handleAddLanguage","useCallback","languageId","newItems","_key","filter","language","length","find","v","map","languagesInUse","insertions","item","languageIndex","findIndex","l","remainingLanguages","slice","nextLanguageIndex","r","push","splice","insert","PatchEvent","from","setIfMissing","handleUnsetByKey","unset","handleInnerValueChange","patchEvent","inputValue","patches","inputPath","set","handleRestoreOrder","updatedValue","reduce","acc","newIndex","languagesOutOfOrder","useMemo","vIndex","Boolean","languagesAreValid","every","JSON","stringify","validationMarkers","mark","invalidKeys","path","flat","includes","undefined","of","subType","fields","width","subTypeField","level","compareValue","RemoveIcon","RestoreIcon","Math","min","toUpperCase","AddIcon","withDocument"],"sources":["../../src/LanguageArray/index.tsx"],"sourcesContent":["import React, {forwardRef, useCallback, useMemo} from 'react'\nimport {Code, Text, Card, Label, Box, Stack, Button, Grid, Flex} from '@sanity/ui'\nimport {withDocument} from 'part:@sanity/form-builder'\nimport {PatchEvent, setIfMissing, insert, unset, set} from '@sanity/form-builder/PatchEvent'\nimport {AddIcon, RemoveIcon, RestoreIcon} from '@sanity/icons'\nimport {FormFieldValidationStatus} from '@sanity/base/components'\nimport {FieldPresence} from '@sanity/base/presence'\nimport {FormBuilderInput} from '@sanity/form-builder/lib/FormBuilderInput'\n\nimport ValueInput from './ValueInput'\nimport {Table, TableCell, TableRow} from './Table'\nimport {useUnsetInputComponent} from '../hooks/useUnsetInputComponent'\n\nconst schemaExample = {\n name: 'title',\n type: 'localisedArray',\n options: {\n languages: [\n {id: 'en', title: 'English'},\n {id: 'no', title: 'Norsk'},\n ],\n },\n}\n\ntype Value = {\n _key: string\n value?: string\n}\n\ntype Language = {\n id: string\n title: string\n}\n\ntype Options = {\n languages: Language[]\n showNativeInput: boolean\n}\n\nconst DEFAULT_OPTIONS = {\n languages: [],\n showNativeInput: false,\n}\n\nconst LanguageArrayWrapper = forwardRef(function CustomComponent(props, ref) {\n const {onChange, onBlur, readOnly, presence, markers} = props\n const value: Value[] = props?.value\n\n // IMPORTANT: leaving out will cause the browser to lock up in an infinite loop\n const type = useUnsetInputComponent(props.type)\n const options: Options = type?.options ?? DEFAULT_OPTIONS\n const {languages, showNativeInput} = options\n\n const handleAddLanguage = useCallback(\n (languageId?: string) => {\n // Create new items\n const newItems = languageId\n ? // Just one for this language\n [{_key: languageId}]\n : // Or one for every missing language\n languages\n .filter((language) =>\n value?.length ? !value.find((v) => v._key === language.id) : true\n )\n .map((language) => ({_key: language.id}))\n\n // Insert new items in the correct order\n const languagesInUse = value?.length ? value.map((v) => v) : []\n\n const insertions = newItems.map((item) => {\n // What's the original index of this language?\n const languageIndex = languages.findIndex((l) => item._key === l.id)\n\n // What languages are there beyond that index?\n const remainingLanguages = languages.slice(languageIndex + 1)\n\n // So what is the index in the current value array of the next language in the language array?\n const nextLanguageIndex = languagesInUse.findIndex((l) =>\n remainingLanguages.find((r) => r.id === l._key)\n )\n\n // Keep local state up to date incase multiple insertions are being made\n if (nextLanguageIndex < 0) {\n languagesInUse.push(item)\n } else {\n languagesInUse.splice(nextLanguageIndex, 0, item)\n }\n\n return nextLanguageIndex < 0\n ? // No next language (-1), add to end of array\n insert([item], 'after', [nextLanguageIndex])\n : // Next language found, insert before that\n insert([item], 'before', [nextLanguageIndex])\n })\n\n onChange(PatchEvent.from(setIfMissing([]), ...insertions))\n },\n [languages, onChange, value]\n )\n\n const handleUnsetByKey = useCallback(\n (_key) => {\n onChange(PatchEvent.from(unset([{_key}])))\n },\n [onChange]\n )\n\n const handleInnerValueChange = useCallback(\n (patchEvent: PatchEvent, _key: string) => {\n const inputValue = patchEvent.patches[0]?.value\n const inputPath = [{_key}, `value`]\n\n onChange(PatchEvent.from(inputValue ? set(inputValue, inputPath) : unset(inputPath)))\n },\n [onChange]\n )\n\n // TODO: This is lazy, reordering and re-setting the whole array – it should be surgical\n const handleRestoreOrder = useCallback(() => {\n // Create a new value array in the correct order\n const updatedValue = value.reduce((acc, v) => {\n const newIndex = languages.findIndex((l) => l.id === v._key)\n\n acc[newIndex] = v\n\n return acc\n }, [])\n\n onChange(PatchEvent.from(unset(), set(updatedValue)))\n }, [languages, onChange, value])\n\n // Check languages are in the correct order\n const languagesOutOfOrder = useMemo(() => {\n if (!value?.length) {\n return []\n }\n\n const languagesInUse = languages.filter((l) => value.find((v) => v._key === l.id))\n\n return value\n .map((v, vIndex) => (vIndex === languagesInUse.findIndex((l) => l.id === v._key) ? null : v))\n .filter(Boolean)\n }, [value, languages])\n\n // Check options are supplied and valid\n const languagesAreValid = useMemo(\n () => languages?.length && languages.every((item) => item.id && item.title),\n [languages]\n )\n\n if (!languagesAreValid) {\n return (\n <Card tone=\"caution\" border radius={2} padding={3}>\n <Stack space={4}>\n <Text>\n An array of language objects must be passed into the <code>{type.name}</code> field as\n options, each with an <code>id</code> and <code>title</code> field. Example:\n </Text>\n <Card padding={2} border radius={2}>\n <Code size={1} language=\"javascript\">\n {JSON.stringify(schemaExample, null, 2)}\n </Code>\n </Card>\n </Stack>\n </Card>\n )\n }\n\n const validationMarkers = markers?.length\n ? markers.filter((mark) => mark.type === `validation`)\n : []\n const invalidKeys = validationMarkers\n .map((mark) => mark.path)\n .flat()\n .map((item) => item._key)\n\n return (\n <Stack space={3}>\n <Box>\n <Text size={1} weight=\"bold\">\n {type?.title ?? type.name}\n </Text>\n </Box>\n {/* Loop over the values */}\n {value?.length > 0 ? (\n <Card>\n <Table>\n <tbody>\n {value.map((item) => (\n <TableRow\n paddingY={1}\n paddingX={2}\n key={item._key}\n tone={\n // TODO: Move this logic somewhere else\n invalidKeys.includes(item._key)\n ? `critical`\n : undefined || languagesOutOfOrder.find((l) => l._key === item._key)\n ? `caution`\n : undefined\n }\n >\n {/* To render each individual field in this type */}\n {type?.of?.length > 0 &&\n type?.of.map((subType) => (\n <>\n {subType?.fields?.length > 0 ? (\n <>\n <TableCell>\n <Box paddingRight={2}>\n <Label muted size={1}>\n {item._key}\n </Label>\n </Box>\n </TableCell>\n <TableCell style={{width: `100%`}}>\n {/* There _should_ only be one field */}\n {subType.fields.map((subTypeField) => (\n <ValueInput\n key={subTypeField.name}\n onChange={(patchEvent) =>\n handleInnerValueChange(patchEvent, item._key)\n }\n onBlur={onBlur}\n // We don't want the array item to open onFocus\n onFocus={() => null}\n path={[{_key: item._key}, subTypeField.name]}\n // focusPath={[{_key: item._key}, subTypeField.name]}\n parent={item}\n readOnly={readOnly}\n type={subTypeField}\n value={item.value}\n level={props.level + 1}\n markers={[]}\n compareValue={props.compareValue}\n />\n ))}\n </TableCell>\n </>\n ) : null}\n </>\n ))}\n\n <TableCell>\n <Flex align=\"center\" justify=\"flex-end\" gap={2}>\n {presence?.length > 0 ? (\n <FieldPresence maxAvatars={1} presence={presence} />\n ) : null}\n {invalidKeys.includes(item._key) ? (\n <Box paddingLeft={2}>\n <FormFieldValidationStatus __unstable_markers={validationMarkers} />\n </Box>\n ) : null}\n <Button\n mode=\"ghost\"\n icon={RemoveIcon}\n tone=\"critical\"\n disabled={readOnly}\n onClick={() => handleUnsetByKey(item._key)}\n />\n </Flex>\n </TableCell>\n </TableRow>\n ))}\n </tbody>\n </Table>\n </Card>\n ) : null}\n\n {languagesOutOfOrder.length > 0 ? (\n <Button\n tone=\"caution\"\n disabled={languagesOutOfOrder.length > languages.length}\n icon={RestoreIcon}\n onClick={() => handleRestoreOrder()}\n text=\"Restore order of languages\"\n />\n ) : null}\n\n {languages.length > 0 ? (\n <Stack space={2}>\n {/* No more than 5 columns */}\n <Grid columns={Math.min(languages.length, 5)} gap={2}>\n {languages.map((language) => (\n <Button\n key={language.id}\n tone=\"primary\"\n mode=\"ghost\"\n fontSize={1}\n disabled={readOnly || value?.find((item) => item._key === language.id)}\n text={language.id.toUpperCase()}\n icon={AddIcon}\n onClick={() => handleAddLanguage(language.id)}\n />\n ))}\n </Grid>\n <Button\n tone=\"primary\"\n mode=\"ghost\"\n disabled={readOnly || value?.length >= languages?.length}\n icon={AddIcon}\n text={value?.length ? `Add missing languages` : `Add all languages`}\n onClick={() => handleAddLanguage()}\n />\n </Stack>\n ) : null}\n\n {showNativeInput ? <FormBuilderInput {...props} type={type} ref={ref} /> : null}\n </Stack>\n )\n})\n\nexport default withDocument(LanguageArrayWrapper)\n"],"mappings":"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"}
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useUnsetInputComponent.js","names":["useUnsetInputComponent","type","component","React","useMemo","unsetInputComponent","t","inputComponent","undefined","typeOfType"],"sources":["../../src/hooks/useUnsetInputComponent.tsx"],"sourcesContent":["import React, {ReactNode} from 'react'\n\nexport function useUnsetInputComponent(type: unknown, component?: ReactNode) {\n return React.useMemo(() => unsetInputComponent(type, component), [type, component])\n}\n\nfunction unsetInputComponent(type, component) {\n const t = {\n ...type,\n inputComponent: type.inputComponent === component ? undefined : type.inputComponent,\n }\n const typeOfType = t.type ? unsetInputComponent(t.type, component) : undefined\n return {\n ...t,\n type: typeOfType,\n }\n}\n"],"mappings":";;;;;;;AAAA;;;;;;;;;;AAEO,SAASA,sBAAT,CAAgCC,IAAhC,EAA+CC,SAA/C,EAAsE;EAC3E,OAAOC,cAAA,CAAMC,OAAN,CAAc,MAAMC,mBAAmB,CAACJ,IAAD,EAAOC,SAAP,CAAvC,EAA0D,CAACD,IAAD,EAAOC,SAAP,CAA1D,CAAP;AACD;;AAED,SAASG,mBAAT,CAA6BJ,IAA7B,EAAmCC,SAAnC,EAA8C;EAC5C,IAAMI,CAAC,mCACFL,IADE;IAELM,cAAc,EAAEN,IAAI,CAACM,cAAL,KAAwBL,SAAxB,GAAoCM,SAApC,GAAgDP,IAAI,CAACM;EAFhE,EAAP;;EAIA,IAAME,UAAU,GAAGH,CAAC,CAACL,IAAF,GAASI,mBAAmB,CAACC,CAAC,CAACL,IAAH,EAASC,SAAT,CAA5B,GAAkDM,SAArE;EACA,uCACKF,CADL;IAEEL,IAAI,EAAEQ;EAFR;AAID"}
|
|
@@ -16,6 +16,8 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
|
|
|
16
16
|
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; }
|
|
17
17
|
|
|
18
18
|
function internationalizedArray(config) {
|
|
19
|
+
var _config$title, _config$group, _config$hidden, _config$readOnly;
|
|
20
|
+
|
|
19
21
|
var _config$name = config.name,
|
|
20
22
|
name = _config$name === void 0 ? "title" : _config$name,
|
|
21
23
|
_config$type = config.type,
|
|
@@ -24,8 +26,13 @@ function internationalizedArray(config) {
|
|
|
24
26
|
languages = _config$languages === void 0 ? [] : _config$languages,
|
|
25
27
|
_config$showNativeInp = config.showNativeInput,
|
|
26
28
|
showNativeInput = _config$showNativeInp === void 0 ? false : _config$showNativeInp;
|
|
29
|
+
var configValidation = Array.isArray(config === null || config === void 0 ? void 0 : config.validation) ? config.validation : [config === null || config === void 0 ? void 0 : config.validation];
|
|
27
30
|
return {
|
|
28
31
|
name,
|
|
32
|
+
title: (_config$title = config === null || config === void 0 ? void 0 : config.title) !== null && _config$title !== void 0 ? _config$title : undefined,
|
|
33
|
+
group: (_config$group = config === null || config === void 0 ? void 0 : config.group) !== null && _config$group !== void 0 ? _config$group : undefined,
|
|
34
|
+
hidden: (_config$hidden = config === null || config === void 0 ? void 0 : config.hidden) !== null && _config$hidden !== void 0 ? _config$hidden : undefined,
|
|
35
|
+
readOnly: (_config$readOnly = config === null || config === void 0 ? void 0 : config.readOnly) !== null && _config$readOnly !== void 0 ? _config$readOnly : undefined,
|
|
29
36
|
type: 'array',
|
|
30
37
|
inputComponent: _LanguageArray.default,
|
|
31
38
|
options: {
|
|
@@ -55,7 +62,7 @@ function internationalizedArray(config) {
|
|
|
55
62
|
|
|
56
63
|
}
|
|
57
64
|
}],
|
|
58
|
-
validation: Rule => Rule.max(languages.length).custom((value, context) => {
|
|
65
|
+
validation: Rule => [Rule.max(languages.length).custom((value, context) => {
|
|
59
66
|
var languages = context.type.options.languages;
|
|
60
67
|
var nonLanguageKeys = value !== null && value !== void 0 && value.length ? value.filter(item => !languages.find(language => item._key === language.id)) : [];
|
|
61
68
|
|
|
@@ -92,7 +99,7 @@ function internationalizedArray(config) {
|
|
|
92
99
|
}
|
|
93
100
|
|
|
94
101
|
return true;
|
|
95
|
-
})
|
|
102
|
+
}), ...configValidation]
|
|
96
103
|
};
|
|
97
104
|
}
|
|
98
105
|
//# sourceMappingURL=internationalizedArray.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internationalizedArray.js","names":["internationalizedArray","config","name","type","languages","showNativeInput","inputComponent","LanguageArray","options","of","fields","preview","select","
|
|
1
|
+
{"version":3,"file":"internationalizedArray.js","names":["internationalizedArray","config","name","type","languages","showNativeInput","configValidation","Array","isArray","validation","title","undefined","group","hidden","readOnly","inputComponent","LanguageArray","options","of","fields","preview","select","key","prepare","subtitle","toUpperCase","Rule","max","length","custom","value","context","nonLanguageKeys","filter","item","find","language","_key","id","message","paths","map","valuesByLanguage","Boolean","reduce","acc","cur","duplicateValues","Object","values","flat"],"sources":["../src/internationalizedArray.ts"],"sourcesContent":["import {ArrayConfig, Value} from './types'\nimport LanguageArray from './LanguageArray'\n\nexport function internationalizedArray(config: ArrayConfig) {\n const {name = `title`, type = `string`, languages = [], showNativeInput = false} = config\n const configValidation = Array.isArray(config?.validation)\n ? config.validation\n : [config?.validation]\n\n return {\n name,\n title: config?.title ?? undefined,\n group: config?.group ?? undefined,\n hidden: config?.hidden ?? undefined,\n readOnly: config?.readOnly ?? undefined,\n type: 'array',\n inputComponent: LanguageArray,\n options: {\n languages,\n showNativeInput,\n },\n of: [\n {\n type: 'object',\n fields: [{name: 'value', type}],\n preview: {\n select: {title: 'value', key: '_key'},\n prepare({title, key}) {\n return {\n title,\n subtitle: key.toUpperCase(),\n }\n },\n },\n },\n ],\n validation: (Rule) => [\n Rule.max(languages.length).custom((value: Value[], context) => {\n const {languages} = context.type.options\n\n const nonLanguageKeys = value?.length\n ? value.filter((item) => !languages.find((language) => item._key === language.id))\n : []\n\n if (nonLanguageKeys.length) {\n return {\n message: `Array item keys must be valid languages registered to the field type`,\n paths: nonLanguageKeys.map((item) => ({_key: item._key})),\n }\n }\n\n // Ensure there's no duplicate `language` fields\n const valuesByLanguage = value?.length\n ? value\n .filter((item) => Boolean(item?._key))\n .reduce((acc, cur) => {\n if (acc[cur._key]) {\n return {...acc, [cur._key]: [...acc[cur._key], cur]}\n }\n\n return {\n ...acc,\n [cur._key]: [cur],\n }\n }, {})\n : {}\n\n const duplicateValues = Object.values(valuesByLanguage)\n .filter((item) => item?.length > 1)\n .flat()\n\n if (duplicateValues.length) {\n return {\n message: 'There can only be one field per language',\n paths: duplicateValues.map((item) => ({_key: item._key})),\n }\n }\n\n return true\n }),\n ...configValidation,\n ],\n }\n}\n"],"mappings":"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"}
|
package/lib/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../src/types.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../src/types.ts"],"sourcesContent":["import {Rule} from '@sanity/types'\n\nexport type ArrayConfig = Options & {\n name: string\n type: 'string' | 'number' | 'boolean' | 'text'\n title?: string\n group?: string\n hidden?: boolean | (() => boolean)\n readOnly?: boolean | (() => boolean)\n validation?: Rule | Rule[]\n}\n\nexport type Value = {\n _key: string\n value?: string\n}\n\nexport type Language = {\n id: string\n title: string\n}\n\nexport type Options = {\n languages: Language[]\n showNativeInput: boolean\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import sanityClient from 'part:@sanity/base/client'
|
|
3
|
+
|
|
4
|
+
const client = sanityClient.withConfig({apiVersion: `2022-07-14`})
|
|
5
|
+
|
|
6
|
+
// Run this script with: `sanity exec --with-user-token migrations/transformObjectToArray.js`
|
|
7
|
+
|
|
8
|
+
// This example shows how you may write a migration script that migrates an internationalized object
|
|
9
|
+
// To an internationalized array
|
|
10
|
+
|
|
11
|
+
// Transforms fields from:
|
|
12
|
+
// "greeting" {
|
|
13
|
+
// "en": "hello",
|
|
14
|
+
// "fr": "bonjour"
|
|
15
|
+
// }
|
|
16
|
+
|
|
17
|
+
// To:
|
|
18
|
+
// "greeting": [
|
|
19
|
+
// { "_key": "en", "value": "hello" },
|
|
20
|
+
// { "_key": "fr", "value": "bonjour" },
|
|
21
|
+
// ]
|
|
22
|
+
|
|
23
|
+
// This will migrate documents in batches of 100 and continue patching until no more documents are
|
|
24
|
+
// returned from the query.
|
|
25
|
+
//
|
|
26
|
+
// This script can safely be run, even if documents are being concurrently modified by others.
|
|
27
|
+
// If a document gets modified in the time between fetch => submit patch, this script will fail,
|
|
28
|
+
// but can safely be re-run multiple times until it eventually runs out of documents to migrate.
|
|
29
|
+
|
|
30
|
+
// A few things to note:
|
|
31
|
+
// - This script will exit if any of the mutations fail due to a revision mismatch (which means the
|
|
32
|
+
// document was edited between fetch => update)
|
|
33
|
+
// - The query must eventually return an empty set, or else this script will continue indefinitely
|
|
34
|
+
|
|
35
|
+
// Fetching documents that matches the precondition for the migration.
|
|
36
|
+
// NOTE: This query should eventually return an empty set of documents to mark the migration
|
|
37
|
+
// as complete
|
|
38
|
+
|
|
39
|
+
const TYPE = `presenter`
|
|
40
|
+
const FIELD_NAME = `title`
|
|
41
|
+
|
|
42
|
+
const fetchDocuments = () =>
|
|
43
|
+
client.fetch(
|
|
44
|
+
`*[_type == $type
|
|
45
|
+
&& defined(${FIELD_NAME})
|
|
46
|
+
&& count(${FIELD_NAME}) == null
|
|
47
|
+
][0...100] {_id, _rev, ${FIELD_NAME}}`,
|
|
48
|
+
{type: TYPE}
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
const buildPatches = (docs) =>
|
|
52
|
+
docs.map((doc) => ({
|
|
53
|
+
id: doc._id,
|
|
54
|
+
patch: {
|
|
55
|
+
set: {
|
|
56
|
+
// Convert existing object to array
|
|
57
|
+
[FIELD_NAME]: Object.keys(doc[FIELD_NAME])
|
|
58
|
+
.filter((key) => key !== '_type')
|
|
59
|
+
.map((key) => ({
|
|
60
|
+
_key: key,
|
|
61
|
+
value: doc[FIELD_NAME][key],
|
|
62
|
+
})),
|
|
63
|
+
},
|
|
64
|
+
// this will cause the migration to fail if any of the documents has been
|
|
65
|
+
// modified since it was fetched.
|
|
66
|
+
ifRevisionID: doc._rev,
|
|
67
|
+
},
|
|
68
|
+
}))
|
|
69
|
+
|
|
70
|
+
const createTransaction = (patches) =>
|
|
71
|
+
patches.reduce((tx, patch) => tx.patch(patch.id, patch.patch), client.transaction())
|
|
72
|
+
|
|
73
|
+
const commitTransaction = (tx) => tx.commit()
|
|
74
|
+
|
|
75
|
+
const migrateNextBatch = async () => {
|
|
76
|
+
const documents = await fetchDocuments()
|
|
77
|
+
const patches = buildPatches(documents)
|
|
78
|
+
if (patches.length === 0) {
|
|
79
|
+
console.log('No more documents to migrate!')
|
|
80
|
+
return null
|
|
81
|
+
}
|
|
82
|
+
console.log(
|
|
83
|
+
`Migrating batch:\n %s`,
|
|
84
|
+
patches.map((patch) => `${patch.id} => ${JSON.stringify(patch.patch)}`).join('\n')
|
|
85
|
+
)
|
|
86
|
+
const transaction = createTransaction(patches)
|
|
87
|
+
await commitTransaction(transaction)
|
|
88
|
+
return migrateNextBatch()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
migrateNextBatch().catch((err) => {
|
|
92
|
+
console.error(err)
|
|
93
|
+
process.exit(1)
|
|
94
|
+
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sanity-plugin-internationalized-array",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "Store localised fields in an array to save on attributes",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"license": "MIT",
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@sanity/icons": "^1.3.1",
|
|
33
|
-
"@sanity/ui": "^0.37.9"
|
|
33
|
+
"@sanity/ui": "^0.37.9",
|
|
34
|
+
"styled-components": "^5.3.5"
|
|
34
35
|
},
|
|
35
36
|
"peerDependencies": {
|
|
36
37
|
"@sanity/base": "^2.30.1",
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import styled, {css} from 'styled-components'
|
|
3
|
+
import {Box, Card} from '@sanity/ui'
|
|
4
|
+
|
|
5
|
+
export const TableWrapper = styled(Box)(
|
|
6
|
+
() =>
|
|
7
|
+
css`
|
|
8
|
+
display: table;
|
|
9
|
+
`
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
type TableProps = {
|
|
13
|
+
children: React.ReactNode
|
|
14
|
+
[key: string]: unknown
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function Table(props: TableProps) {
|
|
18
|
+
const {children, ...rest} = props
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<TableWrapper as="table" {...rest}>
|
|
22
|
+
{children}
|
|
23
|
+
</TableWrapper>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const Row = styled(Card)(
|
|
28
|
+
() =>
|
|
29
|
+
css`
|
|
30
|
+
display: table-row;
|
|
31
|
+
|
|
32
|
+
&:not([hidden]) {
|
|
33
|
+
display: table-row;
|
|
34
|
+
}
|
|
35
|
+
`
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
type TableRowProps = {
|
|
39
|
+
children: React.ReactNode
|
|
40
|
+
[key: string]: unknown
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function TableRow(props: TableRowProps) {
|
|
44
|
+
const {children, ...rest} = props
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<Row as="tr" {...rest}>
|
|
48
|
+
{children}
|
|
49
|
+
</Row>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const Cell = styled(Box)(
|
|
54
|
+
() =>
|
|
55
|
+
css`
|
|
56
|
+
display: table-cell;
|
|
57
|
+
`
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
type TableCellProps = {
|
|
61
|
+
children: React.ReactNode
|
|
62
|
+
style?: React.CSSProperties
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function TableCell(props: TableCellProps) {
|
|
66
|
+
const {children, style} = props
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<Cell as="td" style={style}>
|
|
70
|
+
{children}
|
|
71
|
+
</Cell>
|
|
72
|
+
)
|
|
73
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, {forwardRef, useCallback, useMemo} from 'react'
|
|
2
|
-
import {Code, Text, Card, Label,
|
|
2
|
+
import {Code, Text, Card, Label, Box, Stack, Button, Grid, Flex} from '@sanity/ui'
|
|
3
3
|
import {withDocument} from 'part:@sanity/form-builder'
|
|
4
4
|
import {PatchEvent, setIfMissing, insert, unset, set} from '@sanity/form-builder/PatchEvent'
|
|
5
5
|
import {AddIcon, RemoveIcon, RestoreIcon} from '@sanity/icons'
|
|
@@ -8,7 +8,8 @@ import {FieldPresence} from '@sanity/base/presence'
|
|
|
8
8
|
import {FormBuilderInput} from '@sanity/form-builder/lib/FormBuilderInput'
|
|
9
9
|
|
|
10
10
|
import ValueInput from './ValueInput'
|
|
11
|
-
import {
|
|
11
|
+
import {Table, TableCell, TableRow} from './Table'
|
|
12
|
+
import {useUnsetInputComponent} from '../hooks/useUnsetInputComponent'
|
|
12
13
|
|
|
13
14
|
const schemaExample = {
|
|
14
15
|
name: 'title',
|
|
@@ -174,36 +175,45 @@ const LanguageArrayWrapper = forwardRef(function CustomComponent(props, ref) {
|
|
|
174
175
|
.map((item) => item._key)
|
|
175
176
|
|
|
176
177
|
return (
|
|
177
|
-
<Stack space={
|
|
178
|
+
<Stack space={3}>
|
|
179
|
+
<Box>
|
|
180
|
+
<Text size={1} weight="bold">
|
|
181
|
+
{type?.title ?? type.name}
|
|
182
|
+
</Text>
|
|
183
|
+
</Box>
|
|
178
184
|
{/* Loop over the values */}
|
|
179
185
|
{value?.length > 0 ? (
|
|
180
|
-
<Card
|
|
181
|
-
<
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
186
|
+
<Card>
|
|
187
|
+
<Table>
|
|
188
|
+
<tbody>
|
|
189
|
+
{value.map((item) => (
|
|
190
|
+
<TableRow
|
|
191
|
+
paddingY={1}
|
|
192
|
+
paddingX={2}
|
|
193
|
+
key={item._key}
|
|
194
|
+
tone={
|
|
195
|
+
// TODO: Move this logic somewhere else
|
|
196
|
+
invalidKeys.includes(item._key)
|
|
197
|
+
? `critical`
|
|
198
|
+
: undefined || languagesOutOfOrder.find((l) => l._key === item._key)
|
|
199
|
+
? `caution`
|
|
200
|
+
: undefined
|
|
201
|
+
}
|
|
202
|
+
>
|
|
197
203
|
{/* To render each individual field in this type */}
|
|
198
204
|
{type?.of?.length > 0 &&
|
|
199
205
|
type?.of.map((subType) => (
|
|
200
|
-
|
|
206
|
+
<>
|
|
201
207
|
{subType?.fields?.length > 0 ? (
|
|
202
208
|
<>
|
|
203
|
-
<
|
|
204
|
-
<
|
|
205
|
-
|
|
206
|
-
|
|
209
|
+
<TableCell>
|
|
210
|
+
<Box paddingRight={2}>
|
|
211
|
+
<Label muted size={1}>
|
|
212
|
+
{item._key}
|
|
213
|
+
</Label>
|
|
214
|
+
</Box>
|
|
215
|
+
</TableCell>
|
|
216
|
+
<TableCell style={{width: `100%`}}>
|
|
207
217
|
{/* There _should_ only be one field */}
|
|
208
218
|
{subType.fields.map((subTypeField) => (
|
|
209
219
|
<ValueInput
|
|
@@ -215,35 +225,45 @@ const LanguageArrayWrapper = forwardRef(function CustomComponent(props, ref) {
|
|
|
215
225
|
// We don't want the array item to open onFocus
|
|
216
226
|
onFocus={() => null}
|
|
217
227
|
path={[{_key: item._key}, subTypeField.name]}
|
|
228
|
+
// focusPath={[{_key: item._key}, subTypeField.name]}
|
|
218
229
|
parent={item}
|
|
219
230
|
readOnly={readOnly}
|
|
220
231
|
type={subTypeField}
|
|
221
232
|
value={item.value}
|
|
222
233
|
level={props.level + 1}
|
|
223
234
|
markers={[]}
|
|
235
|
+
compareValue={props.compareValue}
|
|
224
236
|
/>
|
|
225
237
|
))}
|
|
226
|
-
</
|
|
238
|
+
</TableCell>
|
|
227
239
|
</>
|
|
228
240
|
) : null}
|
|
229
|
-
|
|
241
|
+
</>
|
|
230
242
|
))}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
243
|
+
|
|
244
|
+
<TableCell>
|
|
245
|
+
<Flex align="center" justify="flex-end" gap={2}>
|
|
246
|
+
{presence?.length > 0 ? (
|
|
247
|
+
<FieldPresence maxAvatars={1} presence={presence} />
|
|
248
|
+
) : null}
|
|
249
|
+
{invalidKeys.includes(item._key) ? (
|
|
250
|
+
<Box paddingLeft={2}>
|
|
251
|
+
<FormFieldValidationStatus __unstable_markers={validationMarkers} />
|
|
252
|
+
</Box>
|
|
253
|
+
) : null}
|
|
254
|
+
<Button
|
|
255
|
+
mode="ghost"
|
|
256
|
+
icon={RemoveIcon}
|
|
257
|
+
tone="critical"
|
|
258
|
+
disabled={readOnly}
|
|
259
|
+
onClick={() => handleUnsetByKey(item._key)}
|
|
260
|
+
/>
|
|
261
|
+
</Flex>
|
|
262
|
+
</TableCell>
|
|
263
|
+
</TableRow>
|
|
264
|
+
))}
|
|
265
|
+
</tbody>
|
|
266
|
+
</Table>
|
|
247
267
|
</Card>
|
|
248
268
|
) : null}
|
|
249
269
|
|
|
@@ -278,15 +298,14 @@ const LanguageArrayWrapper = forwardRef(function CustomComponent(props, ref) {
|
|
|
278
298
|
tone="primary"
|
|
279
299
|
mode="ghost"
|
|
280
300
|
disabled={readOnly || value?.length >= languages?.length}
|
|
301
|
+
icon={AddIcon}
|
|
281
302
|
text={value?.length ? `Add missing languages` : `Add all languages`}
|
|
282
303
|
onClick={() => handleAddLanguage()}
|
|
283
304
|
/>
|
|
284
305
|
</Stack>
|
|
285
306
|
) : null}
|
|
286
307
|
|
|
287
|
-
{showNativeInput ?
|
|
288
|
-
<FormBuilderInput {...props} type={typeWithoutInputComponent} ref={ref} />
|
|
289
|
-
) : null}
|
|
308
|
+
{showNativeInput ? <FormBuilderInput {...props} type={type} ref={ref} /> : null}
|
|
290
309
|
</Stack>
|
|
291
310
|
)
|
|
292
311
|
})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import React from 'react'
|
|
1
|
+
import React, {ReactNode} from 'react'
|
|
2
2
|
|
|
3
|
-
export function useUnsetInputComponent(type, component) {
|
|
3
|
+
export function useUnsetInputComponent(type: unknown, component?: ReactNode) {
|
|
4
4
|
return React.useMemo(() => unsetInputComponent(type, component), [type, component])
|
|
5
5
|
}
|
|
6
6
|
|
|
@@ -3,9 +3,16 @@ import LanguageArray from './LanguageArray'
|
|
|
3
3
|
|
|
4
4
|
export function internationalizedArray(config: ArrayConfig) {
|
|
5
5
|
const {name = `title`, type = `string`, languages = [], showNativeInput = false} = config
|
|
6
|
+
const configValidation = Array.isArray(config?.validation)
|
|
7
|
+
? config.validation
|
|
8
|
+
: [config?.validation]
|
|
6
9
|
|
|
7
10
|
return {
|
|
8
11
|
name,
|
|
12
|
+
title: config?.title ?? undefined,
|
|
13
|
+
group: config?.group ?? undefined,
|
|
14
|
+
hidden: config?.hidden ?? undefined,
|
|
15
|
+
readOnly: config?.readOnly ?? undefined,
|
|
9
16
|
type: 'array',
|
|
10
17
|
inputComponent: LanguageArray,
|
|
11
18
|
options: {
|
|
@@ -27,7 +34,7 @@ export function internationalizedArray(config: ArrayConfig) {
|
|
|
27
34
|
},
|
|
28
35
|
},
|
|
29
36
|
],
|
|
30
|
-
validation: (Rule) =>
|
|
37
|
+
validation: (Rule) => [
|
|
31
38
|
Rule.max(languages.length).custom((value: Value[], context) => {
|
|
32
39
|
const {languages} = context.type.options
|
|
33
40
|
|
|
@@ -71,5 +78,7 @@ export function internationalizedArray(config: ArrayConfig) {
|
|
|
71
78
|
|
|
72
79
|
return true
|
|
73
80
|
}),
|
|
81
|
+
...configValidation,
|
|
82
|
+
],
|
|
74
83
|
}
|
|
75
84
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
|
+
import {Rule} from '@sanity/types'
|
|
2
|
+
|
|
1
3
|
export type ArrayConfig = Options & {
|
|
2
4
|
name: string
|
|
3
5
|
type: 'string' | 'number' | 'boolean' | 'text'
|
|
6
|
+
title?: string
|
|
7
|
+
group?: string
|
|
8
|
+
hidden?: boolean | (() => boolean)
|
|
9
|
+
readOnly?: boolean | (() => boolean)
|
|
10
|
+
validation?: Rule | Rule[]
|
|
4
11
|
}
|
|
5
12
|
|
|
6
13
|
export type Value = {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useUnsetInputComponent.js","names":["useUnsetInputComponent","type","component","React","useMemo","unsetInputComponent","t","inputComponent","undefined","typeOfType"],"sources":["../../src/LanguageArray/useUnsetInputComponent.ts"],"sourcesContent":["import React from 'react'\n\nexport function useUnsetInputComponent(type, component) {\n return React.useMemo(() => unsetInputComponent(type, component), [type, component])\n}\n\nfunction unsetInputComponent(type, component) {\n const t = {\n ...type,\n inputComponent: type.inputComponent === component ? undefined : type.inputComponent,\n }\n const typeOfType = t.type ? unsetInputComponent(t.type, component) : undefined\n return {\n ...t,\n type: typeOfType,\n }\n}\n"],"mappings":";;;;;;;AAAA;;;;;;;;;;AAEO,SAASA,sBAAT,CAAgCC,IAAhC,EAAsCC,SAAtC,EAAiD;EACtD,OAAOC,cAAA,CAAMC,OAAN,CAAc,MAAMC,mBAAmB,CAACJ,IAAD,EAAOC,SAAP,CAAvC,EAA0D,CAACD,IAAD,EAAOC,SAAP,CAA1D,CAAP;AACD;;AAED,SAASG,mBAAT,CAA6BJ,IAA7B,EAAmCC,SAAnC,EAA8C;EAC5C,IAAMI,CAAC,mCACFL,IADE;IAELM,cAAc,EAAEN,IAAI,CAACM,cAAL,KAAwBL,SAAxB,GAAoCM,SAApC,GAAgDP,IAAI,CAACM;EAFhE,EAAP;;EAIA,IAAME,UAAU,GAAGH,CAAC,CAACL,IAAF,GAASI,mBAAmB,CAACC,CAAC,CAACL,IAAH,EAASC,SAAT,CAA5B,GAAkDM,SAArE;EACA,uCACKF,CADL;IAEEL,IAAI,EAAEQ;EAFR;AAID"}
|