payload 1.0.27 → 1.0.30

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.
Files changed (100) hide show
  1. package/CHANGELOG.md +36 -4
  2. package/dist/admin/components/elements/Status/index.js +1 -1
  3. package/dist/admin/components/elements/ViewDescription/types.d.ts +1 -1
  4. package/dist/admin/components/elements/WhereBuilder/index.js +3 -1
  5. package/dist/admin/components/forms/field-types/Array/index.d.ts +3 -2
  6. package/dist/admin/components/forms/field-types/Array/index.js +201 -6
  7. package/dist/admin/components/forms/field-types/Blocks/index.d.ts +3 -2
  8. package/dist/admin/components/forms/field-types/Blocks/index.js +213 -6
  9. package/dist/admin/components/forms/field-types/Collapsible/index.js +2 -2
  10. package/dist/admin/components/forms/field-types/Row/index.js +2 -2
  11. package/dist/admin/components/forms/field-types/Tabs/index.js +2 -2
  12. package/dist/admin/components/forms/field-types/getFieldPath.d.ts +2 -0
  13. package/dist/admin/components/forms/field-types/getFieldPath.js +6 -0
  14. package/dist/admin/components/forms/field-types/index.d.ts +23 -23
  15. package/dist/admin/components/utilities/RenderCustomComponent/types.d.ts +2 -2
  16. package/dist/admin/components/views/collections/List/Cell/field-types/Relationship/index.js +1 -1
  17. package/dist/auth/operations/local/forgotPassword.js +3 -6
  18. package/dist/auth/operations/local/login.js +6 -9
  19. package/dist/auth/operations/local/resetPassword.js +4 -7
  20. package/dist/auth/operations/local/unlock.js +4 -7
  21. package/dist/collections/buildSchema.js +2 -1
  22. package/dist/collections/config/types.d.ts +2 -2
  23. package/dist/collections/dataloader.js +16 -8
  24. package/dist/collections/operations/local/create.d.ts +2 -2
  25. package/dist/collections/operations/local/create.js +11 -13
  26. package/dist/collections/operations/local/find.js +6 -10
  27. package/dist/collections/operations/local/findByID.js +6 -10
  28. package/dist/collections/operations/local/findVersionByID.js +6 -9
  29. package/dist/config/types.d.ts +13 -13
  30. package/dist/fields/config/sanitize.js +3 -3
  31. package/dist/fields/config/schema.js +3 -3
  32. package/dist/fields/config/types.d.ts +9 -9
  33. package/dist/fields/validations.js +43 -1
  34. package/dist/globals/config/types.d.ts +1 -1
  35. package/dist/mongoose/buildSchema.d.ts +1 -0
  36. package/dist/mongoose/buildSchema.js +3 -3
  37. package/dist/utilities/getIDType.d.ts +2 -0
  38. package/dist/utilities/getIDType.js +11 -0
  39. package/dist/utilities/isValidID.d.ts +1 -0
  40. package/dist/utilities/isValidID.js +16 -0
  41. package/docs/access-control/collections.mdx +21 -12
  42. package/docs/access-control/fields.mdx +5 -3
  43. package/docs/access-control/globals.mdx +8 -4
  44. package/docs/access-control/overview.mdx +1 -1
  45. package/docs/admin/components.mdx +29 -25
  46. package/docs/admin/customizing-css.mdx +2 -2
  47. package/docs/admin/overview.mdx +2 -2
  48. package/docs/admin/webpack.mdx +8 -7
  49. package/docs/authentication/config.mdx +14 -9
  50. package/docs/authentication/operations.mdx +22 -22
  51. package/docs/authentication/overview.mdx +8 -6
  52. package/docs/authentication/using-middleware.mdx +1 -1
  53. package/docs/configuration/collections.mdx +11 -7
  54. package/docs/configuration/globals.mdx +9 -5
  55. package/docs/configuration/localization.mdx +33 -31
  56. package/docs/configuration/overview.mdx +4 -7
  57. package/docs/email/overview.mdx +11 -7
  58. package/docs/fields/array.mdx +6 -5
  59. package/docs/fields/blocks.mdx +6 -4
  60. package/docs/fields/checkbox.mdx +6 -5
  61. package/docs/fields/code.mdx +6 -5
  62. package/docs/fields/collapsible.mdx +6 -5
  63. package/docs/fields/date.mdx +6 -5
  64. package/docs/fields/email.mdx +6 -5
  65. package/docs/fields/group.mdx +6 -5
  66. package/docs/fields/number.mdx +6 -5
  67. package/docs/fields/overview.mdx +40 -38
  68. package/docs/fields/point.mdx +6 -4
  69. package/docs/fields/radio.mdx +5 -3
  70. package/docs/fields/relationship.mdx +21 -21
  71. package/docs/fields/rich-text.mdx +9 -7
  72. package/docs/fields/row.mdx +5 -3
  73. package/docs/fields/select.mdx +4 -3
  74. package/docs/fields/tabs.mdx +5 -3
  75. package/docs/fields/text.mdx +5 -3
  76. package/docs/fields/textarea.mdx +5 -3
  77. package/docs/fields/ui.mdx +5 -3
  78. package/docs/fields/upload.mdx +5 -3
  79. package/docs/getting-started/concepts.mdx +1 -1
  80. package/docs/graphql/extending.mdx +1 -1
  81. package/docs/graphql/overview.mdx +8 -4
  82. package/docs/hooks/collections.mdx +62 -36
  83. package/docs/hooks/fields.mdx +5 -3
  84. package/docs/hooks/globals.mdx +25 -17
  85. package/docs/local-api/overview.mdx +27 -4
  86. package/docs/plugins/overview.mdx +3 -4
  87. package/docs/production/deployment.mdx +1 -1
  88. package/docs/queries/overview.mdx +4 -2
  89. package/docs/queries/pagination.mdx +1 -1
  90. package/docs/rest-api/overview.mdx +4 -2
  91. package/docs/upload/overview.mdx +35 -29
  92. package/docs/versions/autosave.mdx +4 -2
  93. package/docs/versions/drafts.mdx +8 -4
  94. package/docs/versions/overview.mdx +1 -1
  95. package/package.json +1 -1
  96. package/types.d.ts +21 -0
  97. package/dist/admin/components/forms/field-types/Array/Array.d.ts +0 -5
  98. package/dist/admin/components/forms/field-types/Array/Array.js +0 -201
  99. package/dist/admin/components/forms/field-types/Blocks/Blocks.d.ts +0 -5
  100. package/dist/admin/components/forms/field-types/Blocks/Blocks.js +0 -213
package/CHANGELOG.md CHANGED
@@ -1,10 +1,42 @@
1
- ## [1.0.27](https://github.com/payloadcms/payload/compare/v1.0.26...v1.0.27) (2022-08-18)
1
+ ## [1.0.30](https://github.com/payloadcms/payload/compare/v1.0.29...v1.0.30) (2022-08-30)
2
2
 
3
3
 
4
4
  ### Bug Fixes
5
5
 
6
- * react-sortable-hoc dependency instead of dev dependency ([4ef6801](https://github.com/payloadcms/payload/commit/4ef6801230cb0309a9d20dd092f8a3372f75f9ca))
6
+ * upload field validation not required ([#1025](https://github.com/payloadcms/payload/issues/1025)) ([689fa00](https://github.com/payloadcms/payload/commit/689fa008fb0b28fb92be4ca785a77f4c35ae16b2))
7
7
 
8
+ ## [1.0.29](https://github.com/payloadcms/payload/compare/v1.0.28...v1.0.29) (2022-08-29)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * [#953](https://github.com/payloadcms/payload/issues/953) ([a73c391](https://github.com/payloadcms/payload/commit/a73c391c2cecc3acf8dc3115b56c018f85d9bebf))
14
+
15
+ ## [1.0.28](https://github.com/payloadcms/payload/compare/v1.0.27...v1.0.28) (2022-08-29)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * incorrect field paths when nesting unnamed fields ([#1011](https://github.com/payloadcms/payload/issues/1011)) ([50b0303](https://github.com/payloadcms/payload/commit/50b0303ab39f0d0500c5e4116df95f02d1d7fff3)), closes [#976](https://github.com/payloadcms/payload/issues/976)
21
+ * relationship cell loading ([#1021](https://github.com/payloadcms/payload/issues/1021)) ([6a3cfce](https://github.com/payloadcms/payload/commit/6a3cfced9a6e0ef75b398ec663f908c725b10d1a))
22
+ * remove lazy loading of array and blocks ([4900fa7](https://github.com/payloadcms/payload/commit/4900fa799ffbeb70e689622b269dc04a67978552))
23
+ * require properties in blocks and arrays fields ([#1020](https://github.com/payloadcms/payload/issues/1020)) ([6bc6e7b](https://github.com/payloadcms/payload/commit/6bc6e7bb616bd9f28f2464d3e55e7a1d19a8e7f8))
24
+ * unpublish item will not crash the UI anymore ([#1016](https://github.com/payloadcms/payload/issues/1016)) ([0586d7a](https://github.com/payloadcms/payload/commit/0586d7aa7d0938df25492487aa073c2aa366e1e4))
25
+
26
+
27
+ ### Features
28
+
29
+ * export more fields config types and validation type ([#989](https://github.com/payloadcms/payload/issues/989)) ([25f5d68](https://github.com/payloadcms/payload/commit/25f5d68b74b081c060ddf6f0405c9211f5da6b54))
30
+ * types custom components to allow any props ([#1013](https://github.com/payloadcms/payload/issues/1013)) ([3736755](https://github.com/payloadcms/payload/commit/3736755a12cf5bbaaa916a5c0363026318a60823))
31
+ * validate relationship and upload ids ([#1004](https://github.com/payloadcms/payload/issues/1004)) ([d727fc8](https://github.com/payloadcms/payload/commit/d727fc8e2467e3f438ea6b1d2031e0657bffd183))
32
+
33
+ ## [1.0.27](https://github.com/payloadcms/payload/compare/v1.0.26...v1.0.27) (2022-08-18)
34
+
35
+
36
+ ### Bug Fixes
37
+
38
+ * react-sortable-hoc dependency instead of dev dependency ([4ef6801](https://github.com/payloadcms/payload/commit/4ef6801230cb0309a9d20dd092f8a3372f75f9ca))
39
+
8
40
  ## [1.0.26](https://github.com/payloadcms/payload/compare/v1.0.25...v1.0.26) (2022-08-18)
9
41
 
10
42
 
@@ -16,8 +48,8 @@
16
48
  ### Features
17
49
 
18
50
  * adds more prismjs syntax highlighting options for code blocks ([#961](https://github.com/payloadcms/payload/issues/961)) ([f45d5a0](https://github.com/payloadcms/payload/commit/f45d5a0421117180f85f8e3cd86f835c13ac6d16))
19
- * enable reordering of hasMany relationship and select fields ([#952](https://github.com/payloadcms/payload/issues/952)) ([38a1a38](https://github.com/payloadcms/payload/commit/38a1a38c0c52403083458619b2f9b58044c5c0ea))
20
-
51
+ * enable reordering of hasMany relationship and select fields ([#952](https://github.com/payloadcms/payload/issues/952)) ([38a1a38](https://github.com/payloadcms/payload/commit/38a1a38c0c52403083458619b2f9b58044c5c0ea))
52
+
21
53
  ## [1.0.25](https://github.com/payloadcms/payload/compare/v1.0.24...v1.0.25) (2022-08-17)
22
54
 
23
55
 
@@ -45,7 +45,7 @@ const Status = () => {
45
45
  }
46
46
  if (collection) {
47
47
  url = `${serverURL}${api}/${collection.slug}/${id}?depth=0&locale=${locale}&fallback-locale=null`;
48
- method = 'PATCH';
48
+ method = 'patch';
49
49
  }
50
50
  if (global) {
51
51
  url = `${serverURL}${api}/globals/${global.slug}?depth=0&locale=${locale}&fallback-locale=null`;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  export declare type DescriptionFunction = () => string;
3
- export declare type DescriptionComponent = React.ComponentType;
3
+ export declare type DescriptionComponent = React.ComponentType<any>;
4
4
  declare type Description = string | DescriptionFunction | DescriptionComponent;
5
5
  export declare type Props = {
6
6
  description?: Description;
@@ -47,7 +47,9 @@ const WhereBuilder = (props) => {
47
47
  };
48
48
  if (handleChange)
49
49
  handleChange(newWhereQuery);
50
- if (modifySearchQuery) {
50
+ const hasExistingConditions = typeof (currentParams === null || currentParams === void 0 ? void 0 : currentParams.where) === 'object' && 'or' in currentParams.where;
51
+ const hasNewWhereConditions = conditions.length > 0;
52
+ if (modifySearchQuery && ((hasExistingConditions && !hasNewWhereConditions) || hasNewWhereConditions)) {
51
53
  history.replace({
52
54
  search: queryString.stringify({
53
55
  ...currentParams,
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
2
  import { Props } from './types';
3
- declare const ArrayFieldType: React.FC<Props>;
4
- export default ArrayFieldType;
3
+ import './index.scss';
4
+ declare const _default: React.FC<Props>;
5
+ export default _default;
@@ -1,6 +1,201 @@
1
- import React, { Suspense, lazy } from 'react';
2
- import Loading from '../../../elements/Loading';
3
- const ArrayField = lazy(() => import('./Array'));
4
- const ArrayFieldType = (props) => (React.createElement(Suspense, { fallback: React.createElement(Loading, null) },
5
- React.createElement(ArrayField, { ...props })));
6
- export default ArrayFieldType;
1
+ import React, { useCallback, useEffect, useReducer, useState } from 'react';
2
+ import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
3
+ import { useAuth } from '../../../utilities/Auth';
4
+ import withCondition from '../../withCondition';
5
+ import Button from '../../../elements/Button';
6
+ import reducer from '../rowReducer';
7
+ import { useForm } from '../../Form/context';
8
+ import buildStateFromSchema from '../../Form/buildStateFromSchema';
9
+ import useField from '../../useField';
10
+ import { useLocale } from '../../../utilities/Locale';
11
+ import Error from '../../Error';
12
+ import { array } from '../../../../../fields/validations';
13
+ import Banner from '../../../elements/Banner';
14
+ import FieldDescription from '../../FieldDescription';
15
+ import { useDocumentInfo } from '../../../utilities/DocumentInfo';
16
+ import { useOperation } from '../../../utilities/OperationProvider';
17
+ import { Collapsible } from '../../../elements/Collapsible';
18
+ import RenderFields from '../../RenderFields';
19
+ import { fieldAffectsData } from '../../../../../fields/config/types';
20
+ import { usePreferences } from '../../../utilities/Preferences';
21
+ import { ArrayAction } from '../../../elements/ArrayAction';
22
+ import { scrollToID } from '../../../../utilities/scrollToID';
23
+ import HiddenInput from '../HiddenInput';
24
+ import './index.scss';
25
+ const baseClass = 'array-field';
26
+ const ArrayFieldType = (props) => {
27
+ var _a, _b;
28
+ const { name, path: pathFromProps, fields, fieldTypes, validate = array, required, maxRows, minRows, permissions, admin: { readOnly, description, condition, className, }, } = props;
29
+ const path = pathFromProps || name;
30
+ // Handle labeling for Arrays, Global Arrays, and Blocks
31
+ const getLabels = (p) => {
32
+ if (p === null || p === void 0 ? void 0 : p.labels)
33
+ return p.labels;
34
+ if (p === null || p === void 0 ? void 0 : p.label)
35
+ return { singular: p.label, plural: undefined };
36
+ return { singular: 'Row', plural: 'Rows' };
37
+ };
38
+ const labels = getLabels(props);
39
+ // eslint-disable-next-line react/destructuring-assignment
40
+ const label = (_a = props === null || props === void 0 ? void 0 : props.label) !== null && _a !== void 0 ? _a : (_b = props === null || props === void 0 ? void 0 : props.labels) === null || _b === void 0 ? void 0 : _b.singular;
41
+ const { preferencesKey } = useDocumentInfo();
42
+ const { getPreference } = usePreferences();
43
+ const { setPreference } = usePreferences();
44
+ const [rows, dispatchRows] = useReducer(reducer, undefined);
45
+ const formContext = useForm();
46
+ const { user } = useAuth();
47
+ const { id } = useDocumentInfo();
48
+ const locale = useLocale();
49
+ const operation = useOperation();
50
+ const { dispatchFields } = formContext;
51
+ const memoizedValidate = useCallback((value, options) => {
52
+ return validate(value, { ...options, minRows, maxRows, required });
53
+ }, [maxRows, minRows, required, validate]);
54
+ const [disableFormData, setDisableFormData] = useState(false);
55
+ const { showError, errorMessage, value, setValue, } = useField({
56
+ path,
57
+ validate: memoizedValidate,
58
+ disableFormData,
59
+ condition,
60
+ });
61
+ const addRow = useCallback(async (rowIndex) => {
62
+ const subFieldState = await buildStateFromSchema({ fieldSchema: fields, operation, id, user, locale });
63
+ dispatchFields({ type: 'ADD_ROW', rowIndex, subFieldState, path });
64
+ dispatchRows({ type: 'ADD', rowIndex });
65
+ setValue(value + 1);
66
+ setTimeout(() => {
67
+ scrollToID(`${path}-row-${rowIndex + 1}`);
68
+ }, 0);
69
+ }, [dispatchRows, dispatchFields, fields, path, setValue, value, operation, id, user, locale]);
70
+ const duplicateRow = useCallback(async (rowIndex) => {
71
+ dispatchFields({ type: 'DUPLICATE_ROW', rowIndex, path });
72
+ dispatchRows({ type: 'ADD', rowIndex });
73
+ setValue(value + 1);
74
+ setTimeout(() => {
75
+ scrollToID(`${path}-row-${rowIndex + 1}`);
76
+ }, 0);
77
+ }, [dispatchRows, dispatchFields, path, setValue, value]);
78
+ const removeRow = useCallback((rowIndex) => {
79
+ dispatchRows({ type: 'REMOVE', rowIndex });
80
+ dispatchFields({ type: 'REMOVE_ROW', rowIndex, path });
81
+ setValue(value - 1);
82
+ }, [dispatchRows, dispatchFields, path, value, setValue]);
83
+ const moveRow = useCallback((moveFromIndex, moveToIndex) => {
84
+ dispatchRows({ type: 'MOVE', moveFromIndex, moveToIndex });
85
+ dispatchFields({ type: 'MOVE_ROW', moveFromIndex, moveToIndex, path });
86
+ }, [dispatchRows, dispatchFields, path]);
87
+ const onDragEnd = useCallback((result) => {
88
+ if (!result.destination)
89
+ return;
90
+ const sourceIndex = result.source.index;
91
+ const destinationIndex = result.destination.index;
92
+ moveRow(sourceIndex, destinationIndex);
93
+ }, [moveRow]);
94
+ const setCollapse = useCallback(async (rowID, collapsed) => {
95
+ var _a, _b, _c;
96
+ dispatchRows({ type: 'SET_COLLAPSE', id: rowID, collapsed });
97
+ if (preferencesKey) {
98
+ const preferencesToSet = await getPreference(preferencesKey) || { fields: {} };
99
+ let newCollapsedState = ((_b = (_a = preferencesToSet === null || preferencesToSet === void 0 ? void 0 : preferencesToSet.fields) === null || _a === void 0 ? void 0 : _a[path]) === null || _b === void 0 ? void 0 : _b.collapsed.filter((filterID) => (rows.find((row) => row.id === filterID))))
100
+ || [];
101
+ if (!collapsed) {
102
+ newCollapsedState = newCollapsedState.filter((existingID) => existingID !== rowID);
103
+ }
104
+ else {
105
+ newCollapsedState.push(rowID);
106
+ }
107
+ setPreference(preferencesKey, {
108
+ ...preferencesToSet,
109
+ fields: {
110
+ ...(preferencesToSet === null || preferencesToSet === void 0 ? void 0 : preferencesToSet.fields) || {},
111
+ [path]: {
112
+ ...(_c = preferencesToSet === null || preferencesToSet === void 0 ? void 0 : preferencesToSet.fields) === null || _c === void 0 ? void 0 : _c[path],
113
+ collapsed: newCollapsedState,
114
+ },
115
+ },
116
+ });
117
+ }
118
+ }, [preferencesKey, path, setPreference, rows, getPreference]);
119
+ const toggleCollapseAll = useCallback(async (collapse) => {
120
+ var _a;
121
+ dispatchRows({ type: 'SET_ALL_COLLAPSED', collapse });
122
+ if (preferencesKey) {
123
+ const preferencesToSet = await getPreference(preferencesKey) || { fields: {} };
124
+ setPreference(preferencesKey, {
125
+ ...preferencesToSet,
126
+ fields: {
127
+ ...(preferencesToSet === null || preferencesToSet === void 0 ? void 0 : preferencesToSet.fields) || {},
128
+ [path]: {
129
+ ...(_a = preferencesToSet === null || preferencesToSet === void 0 ? void 0 : preferencesToSet.fields) === null || _a === void 0 ? void 0 : _a[path],
130
+ collapsed: collapse ? rows.map(({ id: rowID }) => rowID) : [],
131
+ },
132
+ },
133
+ });
134
+ }
135
+ }, [path, getPreference, preferencesKey, rows, setPreference]);
136
+ useEffect(() => {
137
+ const initializeRowState = async () => {
138
+ var _a, _b;
139
+ const data = formContext.getDataByPath(path);
140
+ const preferences = await getPreference(preferencesKey) || { fields: {} };
141
+ dispatchRows({ type: 'SET_ALL', data: data || [], collapsedState: (_b = (_a = preferences === null || preferences === void 0 ? void 0 : preferences.fields) === null || _a === void 0 ? void 0 : _a[path]) === null || _b === void 0 ? void 0 : _b.collapsed });
142
+ };
143
+ initializeRowState();
144
+ }, [formContext, path, getPreference, preferencesKey]);
145
+ useEffect(() => {
146
+ setValue((rows === null || rows === void 0 ? void 0 : rows.length) || 0, true);
147
+ if ((rows === null || rows === void 0 ? void 0 : rows.length) === 0) {
148
+ setDisableFormData(false);
149
+ }
150
+ else {
151
+ setDisableFormData(true);
152
+ }
153
+ }, [rows, setValue]);
154
+ const hasMaxRows = maxRows && (rows === null || rows === void 0 ? void 0 : rows.length) >= maxRows;
155
+ const classes = [
156
+ 'field-type',
157
+ baseClass,
158
+ className,
159
+ ].filter(Boolean).join(' ');
160
+ if (!rows)
161
+ return null;
162
+ return (React.createElement(DragDropContext, { onDragEnd: onDragEnd },
163
+ React.createElement("div", { id: `field-${path.replace(/\./gi, '__')}`, className: classes },
164
+ React.createElement("div", { className: `${baseClass}__error-wrap` },
165
+ React.createElement(Error, { showError: showError, message: errorMessage })),
166
+ React.createElement("header", { className: `${baseClass}__header` },
167
+ React.createElement("div", { className: `${baseClass}__header-wrap` },
168
+ React.createElement("h3", null, label),
169
+ React.createElement("ul", { className: `${baseClass}__header-actions` },
170
+ React.createElement("li", null,
171
+ React.createElement("button", { type: "button", onClick: () => toggleCollapseAll(true), className: `${baseClass}__header-action` }, "Collapse All")),
172
+ React.createElement("li", null,
173
+ React.createElement("button", { type: "button", onClick: () => toggleCollapseAll(false), className: `${baseClass}__header-action` }, "Show All")))),
174
+ React.createElement(FieldDescription, { value: value, description: description })),
175
+ React.createElement(Droppable, { droppableId: "array-drop" }, (provided) => (React.createElement("div", { ref: provided.innerRef, ...provided.droppableProps },
176
+ rows.length > 0 && rows.map((row, i) => {
177
+ const rowNumber = i + 1;
178
+ return (React.createElement(Draggable, { key: row.id, draggableId: row.id, index: i, isDragDisabled: readOnly }, (providedDrag) => (React.createElement("div", { id: `${path}-row-${i}`, ref: providedDrag.innerRef, ...providedDrag.draggableProps },
179
+ React.createElement(Collapsible, { collapsed: row.collapsed, onToggle: (collapsed) => setCollapse(row.id, collapsed), className: `${baseClass}__row`, key: row.id, dragHandleProps: providedDrag.dragHandleProps, header: `${labels.singular} ${rowNumber >= 10 ? rowNumber : `0${rowNumber}`}`, actions: !readOnly ? (React.createElement(ArrayAction, { rowCount: rows.length, duplicateRow: duplicateRow, addRow: addRow, moveRow: moveRow, removeRow: removeRow, index: i })) : undefined },
180
+ React.createElement(HiddenInput, { name: `${path}.${i}.id`, value: row.id }),
181
+ React.createElement(RenderFields, { className: `${baseClass}__fields`, forceRender: true, readOnly: readOnly, fieldTypes: fieldTypes, permissions: permissions === null || permissions === void 0 ? void 0 : permissions.fields, fieldSchema: fields.map((field) => ({
182
+ ...field,
183
+ path: `${path}.${i}${fieldAffectsData(field) ? `.${field.name}` : ''}`,
184
+ })) }))))));
185
+ }),
186
+ (rows.length < minRows || (required && rows.length === 0)) && (React.createElement(Banner, { type: "error" },
187
+ "This field requires at least",
188
+ ' ',
189
+ minRows
190
+ ? `${minRows} ${labels.plural}`
191
+ : `1 ${labels.singular}`)),
192
+ (rows.length === 0 && readOnly) && (React.createElement(Banner, null,
193
+ "This field has no",
194
+ ' ',
195
+ labels.plural,
196
+ ".")),
197
+ provided.placeholder))),
198
+ (!readOnly && !hasMaxRows) && (React.createElement("div", { className: `${baseClass}__add-button-wrap` },
199
+ React.createElement(Button, { onClick: () => addRow(value), buttonStyle: "icon-label", icon: "plus", iconStyle: "with-border", iconPosition: "left" }, `Add ${labels.singular}`))))));
200
+ };
201
+ export default withCondition(ArrayFieldType);
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
2
  import { Props } from './types';
3
- declare const BlocksField: React.FC<Props>;
4
- export default BlocksField;
3
+ import './index.scss';
4
+ declare const _default: React.FC<Props>;
5
+ export default _default;
@@ -1,6 +1,213 @@
1
- import React, { Suspense, lazy } from 'react';
2
- import Loading from '../../../elements/Loading';
3
- const Blocks = lazy(() => import('./Blocks'));
4
- const BlocksField = (props) => (React.createElement(Suspense, { fallback: React.createElement(Loading, null) },
5
- React.createElement(Blocks, { ...props })));
6
- export default BlocksField;
1
+ import React, { useCallback, useEffect, useReducer, useState } from 'react';
2
+ import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
3
+ import { useAuth } from '../../../utilities/Auth';
4
+ import { usePreferences } from '../../../utilities/Preferences';
5
+ import { useLocale } from '../../../utilities/Locale';
6
+ import withCondition from '../../withCondition';
7
+ import Button from '../../../elements/Button';
8
+ import reducer from '../rowReducer';
9
+ import { useDocumentInfo } from '../../../utilities/DocumentInfo';
10
+ import { useForm } from '../../Form/context';
11
+ import buildStateFromSchema from '../../Form/buildStateFromSchema';
12
+ import Error from '../../Error';
13
+ import useField from '../../useField';
14
+ import Popup from '../../../elements/Popup';
15
+ import BlockSelector from './BlockSelector';
16
+ import { blocks as blocksValidator } from '../../../../../fields/validations';
17
+ import Banner from '../../../elements/Banner';
18
+ import FieldDescription from '../../FieldDescription';
19
+ import { useOperation } from '../../../utilities/OperationProvider';
20
+ import { Collapsible } from '../../../elements/Collapsible';
21
+ import { ArrayAction } from '../../../elements/ArrayAction';
22
+ import RenderFields from '../../RenderFields';
23
+ import { fieldAffectsData } from '../../../../../fields/config/types';
24
+ import SectionTitle from './SectionTitle';
25
+ import Pill from '../../../elements/Pill';
26
+ import { scrollToID } from '../../../../utilities/scrollToID';
27
+ import HiddenInput from '../HiddenInput';
28
+ import './index.scss';
29
+ const baseClass = 'blocks-field';
30
+ const labelDefaults = {
31
+ singular: 'Block',
32
+ plural: 'Blocks',
33
+ };
34
+ const Index = (props) => {
35
+ const { label, name, path: pathFromProps, blocks, labels = labelDefaults, fieldTypes, maxRows, minRows, required, validate = blocksValidator, permissions, admin: { readOnly, description, condition, className, }, } = props;
36
+ const path = pathFromProps || name;
37
+ const { preferencesKey } = useDocumentInfo();
38
+ const { getPreference } = usePreferences();
39
+ const { setPreference } = usePreferences();
40
+ const [rows, dispatchRows] = useReducer(reducer, undefined);
41
+ const formContext = useForm();
42
+ const { user } = useAuth();
43
+ const { id } = useDocumentInfo();
44
+ const locale = useLocale();
45
+ const operation = useOperation();
46
+ const { dispatchFields } = formContext;
47
+ const memoizedValidate = useCallback((value, options) => {
48
+ return validate(value, { ...options, minRows, maxRows, required });
49
+ }, [maxRows, minRows, required, validate]);
50
+ const [disableFormData, setDisableFormData] = useState(false);
51
+ const [selectorIndexOpen, setSelectorIndexOpen] = useState();
52
+ const { showError, errorMessage, value, setValue, } = useField({
53
+ path,
54
+ validate: memoizedValidate,
55
+ disableFormData,
56
+ condition,
57
+ });
58
+ const onAddPopupToggle = useCallback((open) => {
59
+ if (!open) {
60
+ setSelectorIndexOpen(undefined);
61
+ }
62
+ }, []);
63
+ const addRow = useCallback(async (rowIndex, blockType) => {
64
+ const block = blocks.find((potentialBlock) => potentialBlock.slug === blockType);
65
+ const subFieldState = await buildStateFromSchema({ fieldSchema: block.fields, operation, id, user, locale });
66
+ dispatchFields({ type: 'ADD_ROW', rowIndex, subFieldState, path, blockType });
67
+ dispatchRows({ type: 'ADD', rowIndex, blockType });
68
+ setValue(value + 1);
69
+ setTimeout(() => {
70
+ scrollToID(`${path}-row-${rowIndex + 1}`);
71
+ }, 0);
72
+ }, [path, setValue, value, blocks, dispatchFields, operation, id, user, locale]);
73
+ const duplicateRow = useCallback(async (rowIndex, blockType) => {
74
+ dispatchFields({ type: 'DUPLICATE_ROW', rowIndex, path });
75
+ dispatchRows({ type: 'ADD', rowIndex, blockType });
76
+ setValue(value + 1);
77
+ setTimeout(() => {
78
+ scrollToID(`${path}-row-${rowIndex + 1}`);
79
+ }, 0);
80
+ }, [dispatchRows, dispatchFields, path, setValue, value]);
81
+ const removeRow = useCallback((rowIndex) => {
82
+ dispatchRows({ type: 'REMOVE', rowIndex });
83
+ dispatchFields({ type: 'REMOVE_ROW', rowIndex, path });
84
+ setValue(value - 1);
85
+ }, [path, setValue, value, dispatchFields]);
86
+ const moveRow = useCallback((moveFromIndex, moveToIndex) => {
87
+ dispatchRows({ type: 'MOVE', moveFromIndex, moveToIndex });
88
+ dispatchFields({ type: 'MOVE_ROW', moveFromIndex, moveToIndex, path });
89
+ }, [dispatchRows, dispatchFields, path]);
90
+ const onDragEnd = useCallback((result) => {
91
+ if (!result.destination)
92
+ return;
93
+ const sourceIndex = result.source.index;
94
+ const destinationIndex = result.destination.index;
95
+ moveRow(sourceIndex, destinationIndex);
96
+ }, [moveRow]);
97
+ const setCollapse = useCallback(async (rowID, collapsed) => {
98
+ var _a, _b, _c;
99
+ dispatchRows({ type: 'SET_COLLAPSE', id: rowID, collapsed });
100
+ if (preferencesKey) {
101
+ const preferencesToSet = await getPreference(preferencesKey) || { fields: {} };
102
+ let newCollapsedState = ((_b = (_a = preferencesToSet === null || preferencesToSet === void 0 ? void 0 : preferencesToSet.fields) === null || _a === void 0 ? void 0 : _a[path]) === null || _b === void 0 ? void 0 : _b.collapsed.filter((filterID) => (rows.find((row) => row.id === filterID))))
103
+ || [];
104
+ if (!collapsed) {
105
+ newCollapsedState = newCollapsedState.filter((existingID) => existingID !== rowID);
106
+ }
107
+ else {
108
+ newCollapsedState.push(rowID);
109
+ }
110
+ setPreference(preferencesKey, {
111
+ ...preferencesToSet,
112
+ fields: {
113
+ ...(preferencesToSet === null || preferencesToSet === void 0 ? void 0 : preferencesToSet.fields) || {},
114
+ [path]: {
115
+ ...(_c = preferencesToSet === null || preferencesToSet === void 0 ? void 0 : preferencesToSet.fields) === null || _c === void 0 ? void 0 : _c[path],
116
+ collapsed: newCollapsedState,
117
+ },
118
+ },
119
+ });
120
+ }
121
+ }, [preferencesKey, getPreference, path, setPreference, rows]);
122
+ const toggleCollapseAll = useCallback(async (collapse) => {
123
+ var _a;
124
+ dispatchRows({ type: 'SET_ALL_COLLAPSED', collapse });
125
+ if (preferencesKey) {
126
+ const preferencesToSet = await getPreference(preferencesKey) || { fields: {} };
127
+ setPreference(preferencesKey, {
128
+ ...preferencesToSet,
129
+ fields: {
130
+ ...(preferencesToSet === null || preferencesToSet === void 0 ? void 0 : preferencesToSet.fields) || {},
131
+ [path]: {
132
+ ...(_a = preferencesToSet === null || preferencesToSet === void 0 ? void 0 : preferencesToSet.fields) === null || _a === void 0 ? void 0 : _a[path],
133
+ collapsed: collapse ? rows.map(({ id: rowID }) => rowID) : [],
134
+ },
135
+ },
136
+ });
137
+ }
138
+ }, [getPreference, path, preferencesKey, rows, setPreference]);
139
+ // Set row count on mount and when form context is reset
140
+ useEffect(() => {
141
+ const initializeRowState = async () => {
142
+ var _a, _b;
143
+ const data = formContext.getDataByPath(path);
144
+ const preferences = await getPreference(preferencesKey) || { fields: {} };
145
+ dispatchRows({ type: 'SET_ALL', data: data || [], collapsedState: (_b = (_a = preferences === null || preferences === void 0 ? void 0 : preferences.fields) === null || _a === void 0 ? void 0 : _a[path]) === null || _b === void 0 ? void 0 : _b.collapsed });
146
+ };
147
+ initializeRowState();
148
+ }, [formContext, path, getPreference, preferencesKey]);
149
+ useEffect(() => {
150
+ setValue((rows === null || rows === void 0 ? void 0 : rows.length) || 0, true);
151
+ if ((rows === null || rows === void 0 ? void 0 : rows.length) === 0) {
152
+ setDisableFormData(false);
153
+ }
154
+ else {
155
+ setDisableFormData(true);
156
+ }
157
+ }, [rows, setValue]);
158
+ const hasMaxRows = maxRows && (rows === null || rows === void 0 ? void 0 : rows.length) >= maxRows;
159
+ const classes = [
160
+ 'field-type',
161
+ baseClass,
162
+ className,
163
+ ].filter(Boolean).join(' ');
164
+ if (!rows)
165
+ return null;
166
+ return (React.createElement(DragDropContext, { onDragEnd: onDragEnd },
167
+ React.createElement("div", { id: `field-${path.replace(/\./gi, '__')}`, className: classes },
168
+ React.createElement("div", { className: `${baseClass}__error-wrap` },
169
+ React.createElement(Error, { showError: showError, message: errorMessage })),
170
+ React.createElement("header", { className: `${baseClass}__header` },
171
+ React.createElement("div", { className: `${baseClass}__header-wrap` },
172
+ React.createElement("h3", null, label),
173
+ React.createElement("ul", { className: `${baseClass}__header-actions` },
174
+ React.createElement("li", null,
175
+ React.createElement("button", { type: "button", onClick: () => toggleCollapseAll(true), className: `${baseClass}__header-action` }, "Collapse All")),
176
+ React.createElement("li", null,
177
+ React.createElement("button", { type: "button", onClick: () => toggleCollapseAll(false), className: `${baseClass}__header-action` }, "Show All")))),
178
+ React.createElement(FieldDescription, { value: value, description: description })),
179
+ React.createElement(Droppable, { droppableId: "blocks-drop", isDropDisabled: readOnly }, (provided) => (React.createElement("div", { ref: provided.innerRef, ...provided.droppableProps },
180
+ rows.length > 0 && rows.map((row, i) => {
181
+ const { blockType } = row;
182
+ const blockToRender = blocks.find((block) => block.slug === blockType);
183
+ const rowNumber = i + 1;
184
+ if (blockToRender) {
185
+ return (React.createElement(Draggable, { key: row.id, draggableId: row.id, index: i, isDragDisabled: readOnly }, (providedDrag) => (React.createElement("div", { id: `${path}-row-${i}`, ref: providedDrag.innerRef, ...providedDrag.draggableProps },
186
+ React.createElement(Collapsible, { collapsed: row.collapsed, onToggle: (collapsed) => setCollapse(row.id, collapsed), className: `${baseClass}__row`, key: row.id, dragHandleProps: providedDrag.dragHandleProps, header: (React.createElement("div", { className: `${baseClass}__block-header` },
187
+ React.createElement("span", { className: `${baseClass}__block-number` }, rowNumber >= 10 ? rowNumber : `0${rowNumber}`),
188
+ React.createElement(Pill, { pillStyle: "white", className: `${baseClass}__block-pill ${baseClass}__block-pill-${blockType}` }, blockToRender.labels.singular),
189
+ React.createElement(SectionTitle, { path: `${path}.${i}.blockName`, readOnly: readOnly }))), actions: !readOnly ? (React.createElement(React.Fragment, null,
190
+ React.createElement(Popup, { key: `${blockType}-${i}`, forceOpen: selectorIndexOpen === i, onToggleOpen: onAddPopupToggle, buttonType: "none", size: "large", horizontalAlign: "right", render: ({ close }) => (React.createElement(BlockSelector, { blocks: blocks, addRow: addRow, addRowIndex: i, close: close })) }),
191
+ React.createElement(ArrayAction, { rowCount: rows.length, duplicateRow: () => duplicateRow(i, blockType), addRow: () => setSelectorIndexOpen(i), moveRow: moveRow, removeRow: removeRow, index: i }))) : undefined },
192
+ React.createElement(HiddenInput, { name: `${path}.${i}.id`, value: row.id }),
193
+ React.createElement(RenderFields, { className: `${baseClass}__fields`, forceRender: true, readOnly: readOnly, fieldTypes: fieldTypes, permissions: permissions === null || permissions === void 0 ? void 0 : permissions.fields, fieldSchema: blockToRender.fields.map((field) => ({
194
+ ...field,
195
+ path: `${path}.${i}${fieldAffectsData(field) ? `.${field.name}` : ''}`,
196
+ })) }))))));
197
+ }
198
+ return null;
199
+ }),
200
+ (rows.length < minRows || (required && rows.length === 0)) && (React.createElement(Banner, { type: "error" },
201
+ "This field requires at least",
202
+ ' ',
203
+ `${minRows || 1} ${minRows === 1 || typeof minRows === 'undefined' ? labels.singular : labels.plural}`)),
204
+ (rows.length === 0 && readOnly) && (React.createElement(Banner, null,
205
+ "This field has no",
206
+ ' ',
207
+ labels.plural,
208
+ ".")),
209
+ provided.placeholder))),
210
+ (!readOnly && !hasMaxRows) && (React.createElement("div", { className: `${baseClass}__add-button-wrap` },
211
+ React.createElement(Popup, { buttonType: "custom", size: "large", horizontalAlign: "left", button: (React.createElement(Button, { buttonStyle: "icon-label", icon: "plus", iconPosition: "left", iconStyle: "with-border" }, `Add ${labels.singular}`)), render: ({ close }) => (React.createElement(BlockSelector, { blocks: blocks, addRow: addRow, addRowIndex: value, close: close })) }))))));
212
+ };
213
+ export default withCondition(Index);
@@ -1,12 +1,12 @@
1
1
  import React, { useCallback, useEffect, useState } from 'react';
2
2
  import RenderFields from '../../RenderFields';
3
3
  import withCondition from '../../withCondition';
4
- import { fieldAffectsData } from '../../../../../fields/config/types';
5
4
  import { Collapsible } from '../../../elements/Collapsible';
6
5
  import toKebabCase from '../../../../../utilities/toKebabCase';
7
6
  import { usePreferences } from '../../../utilities/Preferences';
8
7
  import { useDocumentInfo } from '../../../utilities/DocumentInfo';
9
8
  import FieldDescription from '../../FieldDescription';
9
+ import { getFieldPath } from '../getFieldPath';
10
10
  import './index.scss';
11
11
  const baseClass = 'collapsible-field';
12
12
  const CollapsibleField = (props) => {
@@ -47,7 +47,7 @@ const CollapsibleField = (props) => {
47
47
  ].filter(Boolean).join(' '), header: React.createElement("div", { className: `${baseClass}__label` }, label), onToggle: onToggle },
48
48
  React.createElement(RenderFields, { forceRender: true, readOnly: readOnly, permissions: permissions === null || permissions === void 0 ? void 0 : permissions.fields, fieldTypes: fieldTypes, fieldSchema: fields.map((field) => ({
49
49
  ...field,
50
- path: `${path ? `${path}.` : ''}${fieldAffectsData(field) ? field.name : ''}`,
50
+ path: getFieldPath(path, field),
51
51
  })) })),
52
52
  React.createElement(FieldDescription, { description: description })));
53
53
  };
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import RenderFields from '../../RenderFields';
3
3
  import withCondition from '../../withCondition';
4
- import { fieldAffectsData } from '../../../../../fields/config/types';
4
+ import { getFieldPath } from '../getFieldPath';
5
5
  import './index.scss';
6
6
  const Row = (props) => {
7
7
  const { fields, fieldTypes, path, permissions, admin: { readOnly, className, }, } = props;
@@ -12,7 +12,7 @@ const Row = (props) => {
12
12
  ].filter(Boolean).join(' ');
13
13
  return (React.createElement(RenderFields, { readOnly: readOnly, className: classes, permissions: permissions === null || permissions === void 0 ? void 0 : permissions.fields, fieldTypes: fieldTypes, fieldSchema: fields.map((field) => ({
14
14
  ...field,
15
- path: `${path ? `${path}.` : ''}${fieldAffectsData(field) ? field.name : ''}`,
15
+ path: getFieldPath(path, field),
16
16
  })) }));
17
17
  };
18
18
  export default withCondition(Row);
@@ -1,11 +1,11 @@
1
1
  import React, { useState } from 'react';
2
2
  import RenderFields from '../../RenderFields';
3
3
  import withCondition from '../../withCondition';
4
- import { fieldAffectsData } from '../../../../../fields/config/types';
5
4
  import FieldDescription from '../../FieldDescription';
6
5
  import toKebabCase from '../../../../../utilities/toKebabCase';
7
6
  import { useCollapsible } from '../../../elements/Collapsible/provider';
8
7
  import { TabsProvider } from './provider';
8
+ import { getFieldPath } from '../getFieldPath';
9
9
  import './index.scss';
10
10
  const baseClass = 'tabs-field';
11
11
  const TabsField = (props) => {
@@ -33,7 +33,7 @@ const TabsField = (props) => {
33
33
  React.createElement(FieldDescription, { className: `${baseClass}__description`, description: activeTab.description }),
34
34
  React.createElement(RenderFields, { key: activeTab.label, forceRender: true, readOnly: readOnly, permissions: permissions === null || permissions === void 0 ? void 0 : permissions.fields, fieldTypes: fieldTypes, fieldSchema: activeTab.fields.map((field) => ({
35
35
  ...field,
36
- path: `${path ? `${path}.` : ''}${fieldAffectsData(field) ? field.name : ''}`,
36
+ path: getFieldPath(path, field),
37
37
  })) })))))));
38
38
  };
39
39
  export default withCondition(TabsField);
@@ -0,0 +1,2 @@
1
+ import { Field } from '../../../../fields/config/types';
2
+ export declare const getFieldPath: (path: string, field: Field) => string;
@@ -0,0 +1,6 @@
1
+ import { fieldAffectsData } from '../../../../fields/config/types';
2
+ export const getFieldPath = (path, field) => {
3
+ // prevents duplicate . on nesting non-named fields
4
+ const dot = path && path.slice(-1) === '.' ? '' : '.';
5
+ return `${path ? `${path}${dot}` : ''}${fieldAffectsData(field) ? field.name : ''}`;
6
+ };