sanity-plugin-internationalized-array 0.0.2 → 0.0.5

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 CHANGED
@@ -25,13 +25,18 @@ export default {
25
25
  fields: [
26
26
  // ...all your other fields
27
27
  internationalizedArray({
28
- name: "greeting", // required
29
- type: "string", // required: string | text | number | boolean
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
- ], // required, must be an array of objects
34
- showNativeInput: false, // optional: just for debugging
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
- An object with the same content as above would look like this:
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
- This creates three unique query paths. The array created by this plugin creates four.
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
- However, every language added to the object increases the number of attributes. Where the array method is limited only by the amount of data you can store in your dataset (heaps!).
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"}
@@ -7,8 +7,6 @@ exports.default = void 0;
7
7
 
8
8
  var _react = _interopRequireWildcard(require("react"));
9
9
 
10
- var _sanityPluginNrknoOddUtils = require("@nrk/sanity-plugin-nrkno-odd-utils");
11
-
12
10
  var _ui = require("@sanity/ui");
13
11
 
14
12
  var _formBuilder = require("part:@sanity/form-builder");
@@ -21,8 +19,14 @@ var _components = require("@sanity/base/components");
21
19
 
22
20
  var _presence = require("@sanity/base/presence");
23
21
 
22
+ var _FormBuilderInput = require("@sanity/form-builder/lib/FormBuilderInput");
23
+
24
24
  var _ValueInput = _interopRequireDefault(require("./ValueInput"));
25
25
 
26
+ var _useUnsetInputComponent = require("./useUnsetInputComponent");
27
+
28
+ var _Table = require("./Table");
29
+
26
30
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
27
31
 
28
32
  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); }
@@ -49,7 +53,7 @@ var DEFAULT_OPTIONS = {
49
53
  showNativeInput: false
50
54
  };
51
55
  var LanguageArrayWrapper = /*#__PURE__*/(0, _react.forwardRef)(function CustomComponent(props, ref) {
52
- var _type$options;
56
+ var _type$options, _type$title;
53
57
 
54
58
  var onChange = props.onChange,
55
59
  onBlur = props.onBlur,
@@ -58,7 +62,7 @@ var LanguageArrayWrapper = /*#__PURE__*/(0, _react.forwardRef)(function CustomCo
58
62
  markers = props.markers;
59
63
  var value = props === null || props === void 0 ? void 0 : props.value; // IMPORTANT: leaving out will cause the browser to lock up in an infinite loop
60
64
 
61
- var type = (0, _sanityPluginNrknoOddUtils.useUnsetInputComponent)(props.type);
65
+ var type = (0, _useUnsetInputComponent.useUnsetInputComponent)(props.type);
62
66
  var options = (_type$options = type === null || type === void 0 ? void 0 : type.options) !== null && _type$options !== void 0 ? _type$options : DEFAULT_OPTIONS;
63
67
  var languages = options.languages,
64
68
  showNativeInput = options.showNativeInput;
@@ -150,36 +154,32 @@ var LanguageArrayWrapper = /*#__PURE__*/(0, _react.forwardRef)(function CustomCo
150
154
  var validationMarkers = markers !== null && markers !== void 0 && markers.length ? markers.filter(mark => mark.type === "validation") : [];
151
155
  var invalidKeys = validationMarkers.map(mark => mark.path).flat().map(item => item._key);
152
156
  return /*#__PURE__*/_react.default.createElement(_ui.Stack, {
153
- space: 2
154
- }, (value === null || value === void 0 ? void 0 : value.length) > 0 ? /*#__PURE__*/_react.default.createElement(_ui.Card, {
155
- padding: 1,
156
- border: true,
157
- radius: 1
158
- }, /*#__PURE__*/_react.default.createElement(_ui.Stack, {
159
- space: 1
160
- }, 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 => {
161
162
  var _type$of;
162
163
 
163
- return /*#__PURE__*/_react.default.createElement(_ui.Card, {
164
+ return /*#__PURE__*/_react.default.createElement(_Table.TableRow, {
164
165
  paddingY: 1,
165
166
  paddingX: 2,
166
167
  key: item._key,
167
168
  tone: // TODO: Move this logic somewhere else
168
169
  invalidKeys.includes(item._key) ? "critical" : undefined || languagesOutOfOrder.find(l => l._key === item._key) ? "caution" : undefined
169
- }, /*#__PURE__*/_react.default.createElement(_ui.Flex, {
170
- gap: 3,
171
- align: "center"
172
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 => {
173
171
  var _subType$fields;
174
172
 
175
- return /*#__PURE__*/_react.default.createElement(_ui.Flex, {
176
- key: subType.name,
177
- flex: 1,
178
- align: "center",
179
- gap: 2
180
- }, (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(_ui.Box, null, /*#__PURE__*/_react.default.createElement(_ui.Label, null, item._key)), /*#__PURE__*/_react.default.createElement(_ui.Box, {
181
- flex: 1
182
- }, subType.fields.map(subTypeField => /*#__PURE__*/_react.default.createElement(_ValueInput.default, {
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
+ }
182
+ }, subType.fields.map((subTypeField, subTypeFieldIndex) => /*#__PURE__*/_react.default.createElement(_ValueInput.default, {
183
183
  key: subTypeField.name,
184
184
  onChange: patchEvent => handleInnerValueChange(patchEvent, item._key),
185
185
  onBlur: onBlur // We don't want the array item to open onFocus
@@ -187,26 +187,28 @@ var LanguageArrayWrapper = /*#__PURE__*/(0, _react.forwardRef)(function CustomCo
187
187
  onFocus: () => null,
188
188
  path: [{
189
189
  _key: item._key
190
- }, subTypeField.name],
190
+ }, subTypeField.name] // focusPath={[{_key: item._key}, subTypeField.name]}
191
+ ,
191
192
  parent: item,
192
193
  readOnly: readOnly,
193
194
  type: subTypeField,
194
195
  value: item.value,
195
196
  level: props.level + 1,
196
- markers: []
197
+ markers: [],
198
+ compareValue: props.compareValue
197
199
  })))) : null);
198
- })), (presence === null || presence === void 0 ? void 0 : presence.length) > 0 ? /*#__PURE__*/_react.default.createElement(_presence.FieldPresence, {
200
+ })), (presence === null || presence === void 0 ? void 0 : presence.length) > 0 ? /*#__PURE__*/_react.default.createElement(_Table.TableCell, null, /*#__PURE__*/_react.default.createElement(_presence.FieldPresence, {
199
201
  maxAvatars: 1,
200
202
  presence: presence
201
- }) : null, invalidKeys.includes(item._key) ? /*#__PURE__*/_react.default.createElement(_components.FormFieldValidationStatus, {
203
+ })) : null, invalidKeys.includes(item._key) ? /*#__PURE__*/_react.default.createElement(_Table.TableCell, null, /*#__PURE__*/_react.default.createElement(_components.FormFieldValidationStatus, {
202
204
  __unstable_markers: validationMarkers
203
- }) : null, /*#__PURE__*/_react.default.createElement(_ui.Button, {
205
+ })) : null, /*#__PURE__*/_react.default.createElement(_Table.TableCell, null, /*#__PURE__*/_react.default.createElement(_ui.Button, {
204
206
  mode: "ghost",
205
207
  icon: _icons.RemoveIcon,
206
208
  tone: "critical",
207
209
  onClick: () => handleUnsetByKey(item._key)
208
210
  })));
209
- }))) : null, languagesOutOfOrder.length > 0 ? /*#__PURE__*/_react.default.createElement(_ui.Button, {
211
+ })))) : null, languagesOutOfOrder.length > 0 ? /*#__PURE__*/_react.default.createElement(_ui.Button, {
210
212
  tone: "caution",
211
213
  disabled: languagesOutOfOrder.length > languages.length,
212
214
  icon: _icons.RestoreIcon,
@@ -230,10 +232,12 @@ var LanguageArrayWrapper = /*#__PURE__*/(0, _react.forwardRef)(function CustomCo
230
232
  tone: "primary",
231
233
  mode: "ghost",
232
234
  disabled: readOnly || (value === null || value === void 0 ? void 0 : value.length) >= (languages === null || languages === void 0 ? void 0 : languages.length),
235
+ icon: _icons.AddIcon,
233
236
  text: value !== null && value !== void 0 && value.length ? "Add missing languages" : "Add all languages",
234
237
  onClick: () => handleAddLanguage()
235
- })) : null, showNativeInput ? /*#__PURE__*/_react.default.createElement(_sanityPluginNrknoOddUtils.NestedFormBuilder, _extends({}, props, {
236
- type: type
238
+ })) : null, showNativeInput ? /*#__PURE__*/_react.default.createElement(_FormBuilderInput.FormBuilderInput, _extends({}, props, {
239
+ type: type,
240
+ ref: ref
237
241
  })) : null);
238
242
  });
239
243
 
@@ -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","withDocument"],"sources":["../../src/LanguageArray/index.tsx"],"sourcesContent":["import React, {forwardRef, useCallback, useMemo} from 'react'\nimport {useUnsetInputComponent, NestedFormBuilder} from '@nrk/sanity-plugin-nrkno-odd-utils'\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'\n\nimport ValueInput from './ValueInput'\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 ? <NestedFormBuilder {...props} type={type} /> : 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","subTypeFieldIndex","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, 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'\nimport {Table, TableCell, TableRow} from './Table'\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, subTypeFieldIndex) => (\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 {presence?.length > 0 ? (\n <TableCell>\n <FieldPresence maxAvatars={1} presence={presence} />\n </TableCell>\n ) : null}\n {invalidKeys.includes(item._key) ? (\n <TableCell>\n <FormFieldValidationStatus __unstable_markers={validationMarkers} />\n </TableCell>\n ) : null}\n <TableCell>\n <Button\n mode=\"ghost\"\n icon={RemoveIcon}\n tone=\"critical\"\n onClick={() => handleUnsetByKey(item._key)}\n />\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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"}
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useUnsetInputComponent = useUnsetInputComponent;
7
+
8
+ var _react = _interopRequireDefault(require("react"));
9
+
10
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
+
12
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
13
+
14
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
15
+
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
+
18
+ function useUnsetInputComponent(type, component) {
19
+ return _react.default.useMemo(() => unsetInputComponent(type, component), [type, component]);
20
+ }
21
+
22
+ function unsetInputComponent(type, component) {
23
+ var t = _objectSpread(_objectSpread({}, type), {}, {
24
+ inputComponent: type.inputComponent === component ? undefined : type.inputComponent
25
+ });
26
+
27
+ var typeOfType = t.type ? unsetInputComponent(t.type, component) : undefined;
28
+ return _objectSpread(_objectSpread({}, t), {}, {
29
+ type: typeOfType
30
+ });
31
+ }
32
+ //# sourceMappingURL=useUnsetInputComponent.js.map
@@ -0,0 +1 @@
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"}
package/lib/index.js CHANGED
@@ -3,10 +3,11 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.default = void 0;
6
+ exports.internationalizedArray = void 0;
7
7
 
8
8
  var _internationalizedArray = require("./internationalizedArray");
9
9
 
10
- var _default = _internationalizedArray.internationalizedArray;
11
- exports.default = _default;
10
+ var internationalizedArray = config => (0, _internationalizedArray.internationalizedArray)(config);
11
+
12
+ exports.internationalizedArray = internationalizedArray;
12
13
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["internationalizedArray"],"sources":["../src/index.ts"],"sourcesContent":["import {internationalizedArray} from './internationalizedArray'\n\nexport default internationalizedArray\n"],"mappings":";;;;;;;AAAA;;eAEeA,8C"}
1
+ {"version":3,"file":"index.js","names":["internationalizedArray","config","helperFunction"],"sources":["../src/index.ts"],"sourcesContent":["import {internationalizedArray as helperFunction} from './internationalizedArray'\n\nexport const internationalizedArray = (config) => helperFunction(config)\n"],"mappings":";;;;;;;AAAA;;AAEO,IAAMA,sBAAsB,GAAIC,MAAD,IAAY,IAAAC,8CAAA,EAAeD,MAAf,CAA3C"}
@@ -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,
@@ -26,6 +28,10 @@ function internationalizedArray(config) {
26
28
  showNativeInput = _config$showNativeInp === void 0 ? false : _config$showNativeInp;
27
29
  return {
28
30
  name,
31
+ title: (_config$title = config === null || config === void 0 ? void 0 : config.title) !== null && _config$title !== void 0 ? _config$title : undefined,
32
+ group: (_config$group = config === null || config === void 0 ? void 0 : config.group) !== null && _config$group !== void 0 ? _config$group : undefined,
33
+ hidden: (_config$hidden = config === null || config === void 0 ? void 0 : config.hidden) !== null && _config$hidden !== void 0 ? _config$hidden : undefined,
34
+ readOnly: (_config$readOnly = config === null || config === void 0 ? void 0 : config.readOnly) !== null && _config$readOnly !== void 0 ? _config$readOnly : undefined,
29
35
  type: 'array',
30
36
  inputComponent: _LanguageArray.default,
31
37
  options: {
@@ -1 +1 @@
1
- {"version":3,"file":"internationalizedArray.js","names":["internationalizedArray","config","name","type","languages","showNativeInput","inputComponent","LanguageArray","options","of","fields","preview","select","title","key","prepare","subtitle","toUpperCase","validation","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\n return {\n name,\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 }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"internationalizedArray.js","names":["internationalizedArray","config","name","type","languages","showNativeInput","title","undefined","group","hidden","readOnly","inputComponent","LanguageArray","options","of","fields","preview","select","key","prepare","subtitle","toUpperCase","validation","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\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 }\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":["export type ArrayConfig = Options & {\n name: string\n type: 'string' | 'number' | 'boolean' | 'text'\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":""}
1
+ {"version":3,"file":"types.js","names":[],"sources":["../src/types.ts"],"sourcesContent":["export 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}\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.2",
3
+ "version": "0.0.5",
4
4
  "description": "Store localised fields in an array to save on attributes",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -20,7 +20,7 @@
20
20
  },
21
21
  "repository": {
22
22
  "type": "git",
23
- "url": "git+ssh://git@github.com/sanity-io/sanity-plugin-internationalized-array.git"
23
+ "url": "git+ssh://git@github.com/SimeonGriggs/sanity-plugin-internationalized-array.git"
24
24
  },
25
25
  "keywords": [
26
26
  "sanity",
@@ -29,9 +29,9 @@
29
29
  "author": "Sanity.io <hello@sanity.io>",
30
30
  "license": "MIT",
31
31
  "dependencies": {
32
- "@nrk/sanity-plugin-nrkno-odd-utils": "^1.0.11",
33
32
  "@sanity/icons": "^1.3.1",
34
- "@sanity/ui": "^0.37.9"
33
+ "@sanity/ui": "^0.37.9",
34
+ "styled-components": "^5.3.5"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "@sanity/base": "^2.30.1",
@@ -54,7 +54,7 @@
54
54
  "typescript": "^4.7.4"
55
55
  },
56
56
  "bugs": {
57
- "url": "https://github.com/sanity-io/sanity-plugin-internationalized-array/issues"
57
+ "url": "https://github.com/SimeonGriggs/sanity-plugin-internationalized-array/issues"
58
58
  },
59
- "homepage": "https://github.com/sanity-io/sanity-plugin-internationalized-array#readme"
59
+ "homepage": "https://github.com/SimeonGriggs/sanity-plugin-internationalized-array#readme"
60
60
  }
@@ -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,13 +1,15 @@
1
1
  import React, {forwardRef, useCallback, useMemo} from 'react'
2
- import {useUnsetInputComponent, NestedFormBuilder} from '@nrk/sanity-plugin-nrkno-odd-utils'
3
2
  import {Code, Text, Card, Label, Flex, Box, Stack, Button, Grid} from '@sanity/ui'
4
3
  import {withDocument} from 'part:@sanity/form-builder'
5
4
  import {PatchEvent, setIfMissing, insert, unset, set} from '@sanity/form-builder/PatchEvent'
6
5
  import {AddIcon, RemoveIcon, RestoreIcon} from '@sanity/icons'
7
6
  import {FormFieldValidationStatus} from '@sanity/base/components'
8
7
  import {FieldPresence} from '@sanity/base/presence'
8
+ import {FormBuilderInput} from '@sanity/form-builder/lib/FormBuilderInput'
9
9
 
10
10
  import ValueInput from './ValueInput'
11
+ import {useUnsetInputComponent} from './useUnsetInputComponent'
12
+ import {Table, TableCell, TableRow} from './Table'
11
13
 
12
14
  const schemaExample = {
13
15
  name: 'title',
@@ -173,38 +175,47 @@ const LanguageArrayWrapper = forwardRef(function CustomComponent(props, ref) {
173
175
  .map((item) => item._key)
174
176
 
175
177
  return (
176
- <Stack space={2}>
178
+ <Stack space={3}>
179
+ <Box>
180
+ <Text size={1} weight="bold">
181
+ {type?.title ?? type.name}
182
+ </Text>
183
+ </Box>
177
184
  {/* Loop over the values */}
178
185
  {value?.length > 0 ? (
179
- <Card padding={1} border radius={1}>
180
- <Stack space={1}>
181
- {value.map((item) => (
182
- <Card
183
- paddingY={1}
184
- paddingX={2}
185
- key={item._key}
186
- tone={
187
- // TODO: Move this logic somewhere else
188
- invalidKeys.includes(item._key)
189
- ? `critical`
190
- : undefined || languagesOutOfOrder.find((l) => l._key === item._key)
191
- ? `caution`
192
- : undefined
193
- }
194
- >
195
- <Flex gap={3} align="center">
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
+ >
196
203
  {/* To render each individual field in this type */}
197
204
  {type?.of?.length > 0 &&
198
205
  type?.of.map((subType) => (
199
- <Flex key={subType.name} flex={1} align="center" gap={2}>
206
+ <>
200
207
  {subType?.fields?.length > 0 ? (
201
208
  <>
202
- <Box>
203
- <Label>{item._key}</Label>
204
- </Box>
205
- <Box flex={1}>
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%`}}>
206
217
  {/* There _should_ only be one field */}
207
- {subType.fields.map((subTypeField) => (
218
+ {subType.fields.map((subTypeField, subTypeFieldIndex) => (
208
219
  <ValueInput
209
220
  key={subTypeField.name}
210
221
  onChange={(patchEvent) =>
@@ -214,35 +225,43 @@ const LanguageArrayWrapper = forwardRef(function CustomComponent(props, ref) {
214
225
  // We don't want the array item to open onFocus
215
226
  onFocus={() => null}
216
227
  path={[{_key: item._key}, subTypeField.name]}
228
+ // focusPath={[{_key: item._key}, subTypeField.name]}
217
229
  parent={item}
218
230
  readOnly={readOnly}
219
231
  type={subTypeField}
220
232
  value={item.value}
221
233
  level={props.level + 1}
222
234
  markers={[]}
235
+ compareValue={props.compareValue}
223
236
  />
224
237
  ))}
225
- </Box>
238
+ </TableCell>
226
239
  </>
227
240
  ) : null}
228
- </Flex>
241
+ </>
229
242
  ))}
230
243
  {presence?.length > 0 ? (
231
- <FieldPresence maxAvatars={1} presence={presence} />
244
+ <TableCell>
245
+ <FieldPresence maxAvatars={1} presence={presence} />
246
+ </TableCell>
232
247
  ) : null}
233
248
  {invalidKeys.includes(item._key) ? (
234
- <FormFieldValidationStatus __unstable_markers={validationMarkers} />
249
+ <TableCell>
250
+ <FormFieldValidationStatus __unstable_markers={validationMarkers} />
251
+ </TableCell>
235
252
  ) : null}
236
- <Button
237
- mode="ghost"
238
- icon={RemoveIcon}
239
- tone="critical"
240
- onClick={() => handleUnsetByKey(item._key)}
241
- />
242
- </Flex>
243
- </Card>
244
- ))}
245
- </Stack>
253
+ <TableCell>
254
+ <Button
255
+ mode="ghost"
256
+ icon={RemoveIcon}
257
+ tone="critical"
258
+ onClick={() => handleUnsetByKey(item._key)}
259
+ />
260
+ </TableCell>
261
+ </TableRow>
262
+ ))}
263
+ </tbody>
264
+ </Table>
246
265
  </Card>
247
266
  ) : null}
248
267
 
@@ -277,13 +296,14 @@ const LanguageArrayWrapper = forwardRef(function CustomComponent(props, ref) {
277
296
  tone="primary"
278
297
  mode="ghost"
279
298
  disabled={readOnly || value?.length >= languages?.length}
299
+ icon={AddIcon}
280
300
  text={value?.length ? `Add missing languages` : `Add all languages`}
281
301
  onClick={() => handleAddLanguage()}
282
302
  />
283
303
  </Stack>
284
304
  ) : null}
285
305
 
286
- {showNativeInput ? <NestedFormBuilder {...props} type={type} /> : null}
306
+ {showNativeInput ? <FormBuilderInput {...props} type={type} ref={ref} /> : null}
287
307
  </Stack>
288
308
  )
289
309
  })
@@ -0,0 +1,17 @@
1
+ import React from 'react'
2
+
3
+ export function useUnsetInputComponent(type, component) {
4
+ return React.useMemo(() => unsetInputComponent(type, component), [type, component])
5
+ }
6
+
7
+ function unsetInputComponent(type, component) {
8
+ const t = {
9
+ ...type,
10
+ inputComponent: type.inputComponent === component ? undefined : type.inputComponent,
11
+ }
12
+ const typeOfType = t.type ? unsetInputComponent(t.type, component) : undefined
13
+ return {
14
+ ...t,
15
+ type: typeOfType,
16
+ }
17
+ }
package/src/index.ts CHANGED
@@ -1,3 +1,3 @@
1
- import {internationalizedArray} from './internationalizedArray'
1
+ import {internationalizedArray as helperFunction} from './internationalizedArray'
2
2
 
3
- export default internationalizedArray
3
+ export const internationalizedArray = (config) => helperFunction(config)
@@ -6,6 +6,10 @@ export function internationalizedArray(config: ArrayConfig) {
6
6
 
7
7
  return {
8
8
  name,
9
+ title: config?.title ?? undefined,
10
+ group: config?.group ?? undefined,
11
+ hidden: config?.hidden ?? undefined,
12
+ readOnly: config?.readOnly ?? undefined,
9
13
  type: 'array',
10
14
  inputComponent: LanguageArray,
11
15
  options: {
package/src/types.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  export type ArrayConfig = Options & {
2
2
  name: string
3
3
  type: 'string' | 'number' | 'boolean' | 'text'
4
+ title?: string
5
+ group?: string
6
+ hidden?: boolean | (() => boolean)
7
+ readOnly?: boolean | (() => boolean)
4
8
  }
5
9
 
6
10
  export type Value = {