payload 1.1.7 → 1.1.8

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 (60) hide show
  1. package/components/forms.ts +10 -0
  2. package/dist/admin/components/elements/Autosave/index.js +3 -3
  3. package/dist/admin/components/elements/Nav/index.scss +1 -5
  4. package/dist/admin/components/forms/Form/context.d.ts +5 -2
  5. package/dist/admin/components/forms/Form/context.js +9 -2
  6. package/dist/admin/components/forms/Form/fieldReducer.d.ts +2 -2
  7. package/dist/admin/components/forms/Form/fieldReducer.js +4 -1
  8. package/dist/admin/components/forms/Form/getSiblingData.js +11 -5
  9. package/dist/admin/components/forms/Form/index.js +12 -12
  10. package/dist/admin/components/forms/Form/initContextState.js +0 -3
  11. package/dist/admin/components/forms/Form/reduceFieldsToValues.js +6 -3
  12. package/dist/admin/components/forms/Form/types.d.ts +49 -7
  13. package/dist/admin/components/forms/field-types/Code/Code.js +0 -1
  14. package/dist/admin/components/forms/field-types/ConfirmPassword/index.js +2 -4
  15. package/dist/admin/components/forms/field-types/Email/index.js +0 -1
  16. package/dist/admin/components/forms/field-types/Number/index.js +0 -1
  17. package/dist/admin/components/forms/field-types/Password/index.js +0 -1
  18. package/dist/admin/components/forms/field-types/Point/index.js +0 -1
  19. package/dist/admin/components/forms/field-types/Relationship/AddNew/Modal/index.d.ts +4 -0
  20. package/dist/admin/components/forms/field-types/Relationship/AddNew/Modal/index.js +67 -0
  21. package/dist/admin/components/forms/field-types/Relationship/AddNew/Modal/index.scss +117 -0
  22. package/dist/admin/components/forms/field-types/Relationship/AddNew/Modal/types.d.ts +6 -0
  23. package/dist/admin/components/forms/field-types/Relationship/AddNew/Modal/types.js +1 -0
  24. package/dist/admin/components/forms/field-types/Relationship/AddNew/index.d.ts +4 -0
  25. package/dist/admin/components/forms/field-types/Relationship/AddNew/index.js +79 -0
  26. package/dist/admin/components/forms/field-types/Relationship/AddNew/index.scss +60 -0
  27. package/dist/admin/components/forms/field-types/Relationship/AddNew/types.d.ts +10 -0
  28. package/dist/admin/components/forms/field-types/Relationship/AddNew/types.js +1 -0
  29. package/dist/admin/components/forms/field-types/Relationship/AddNew/useRelatedCollections.d.ts +2 -0
  30. package/dist/admin/components/forms/field-types/Relationship/AddNew/useRelatedCollections.js +10 -0
  31. package/dist/admin/components/forms/field-types/Relationship/index.js +57 -45
  32. package/dist/admin/components/forms/field-types/Relationship/index.scss +23 -12
  33. package/dist/admin/components/forms/field-types/Relationship/optionsReducer.js +8 -7
  34. package/dist/admin/components/forms/field-types/Relationship/types.d.ts +1 -3
  35. package/dist/admin/components/forms/field-types/RichText/elements/relationship/Button/Fields/index.js +2 -3
  36. package/dist/admin/components/forms/field-types/Text/index.js +0 -1
  37. package/dist/admin/components/forms/field-types/Textarea/index.js +0 -1
  38. package/dist/admin/components/forms/field-types/Upload/SelectExisting/index.js +2 -2
  39. package/dist/admin/components/forms/useField/index.js +71 -97
  40. package/dist/admin/components/forms/useField/types.d.ts +0 -2
  41. package/dist/admin/components/forms/withCondition/index.js +10 -5
  42. package/dist/admin/components/modals/LeaveWithoutSaving/index.scss +2 -2
  43. package/dist/admin/components/templates/Default/index.scss +1 -1
  44. package/dist/admin/components/utilities/EditDepth/index.d.ts +3 -0
  45. package/dist/admin/components/utilities/EditDepth/index.js +3 -0
  46. package/dist/admin/components/views/collections/Edit/Auth/APIKey.js +2 -3
  47. package/dist/admin/components/views/collections/Edit/Auth/index.js +3 -3
  48. package/dist/admin/components/views/collections/Edit/Default.js +9 -9
  49. package/dist/admin/components/views/collections/Edit/index.js +15 -12
  50. package/dist/admin/components/views/collections/Edit/types.d.ts +6 -0
  51. package/dist/admin/hooks/useTitle.js +2 -3
  52. package/dist/admin/index.js +1 -1
  53. package/dist/admin/scss/app.scss +6 -1
  54. package/docs/admin/components.mdx +3 -45
  55. package/docs/admin/customizing-css.mdx +1 -1
  56. package/docs/admin/hooks.mdx +271 -0
  57. package/docs/admin/preferences.mdx +1 -1
  58. package/docs/admin/webpack.mdx +1 -1
  59. package/docs/local-api/overview.mdx +1 -1
  60. package/package.json +2 -1
@@ -1,88 +1,26 @@
1
- import { useCallback, useEffect, useState, } from 'react';
1
+ import { useCallback, useMemo } from 'react';
2
2
  import { useAuth } from '../../utilities/Auth';
3
- import { useFormProcessing, useFormSubmitted, useFormModified, useForm } from '../Form/context';
4
- import useDebounce from '../../../hooks/useDebounce';
3
+ import { useFormProcessing, useFormSubmitted, useFormModified, useForm, useFormFields } from '../Form/context';
5
4
  import { useDocumentInfo } from '../../utilities/DocumentInfo';
6
5
  import { useOperation } from '../../utilities/OperationProvider';
6
+ import useThrottledEffect from '../../../hooks/useThrottledEffect';
7
7
  const useField = (options) => {
8
- const { path, validate, enableDebouncedValue, disableFormData = false, condition, } = options;
9
- const formContext = useForm();
8
+ const { path, validate, disableFormData = false, condition, } = options;
10
9
  const submitted = useFormSubmitted();
11
10
  const processing = useFormProcessing();
12
11
  const modified = useFormModified();
13
12
  const { user } = useAuth();
14
13
  const { id } = useDocumentInfo();
15
14
  const operation = useOperation();
16
- const { dispatchFields, getField, getData, getSiblingData, setModified, } = formContext || {};
17
- // Get field by path
18
- const field = getField(path);
15
+ const field = useFormFields(([fields]) => fields[path]);
16
+ const dispatchField = useFormFields(([_, dispatch]) => dispatch);
17
+ const { getData, getSiblingData, setModified } = useForm();
18
+ const value = field === null || field === void 0 ? void 0 : field.value;
19
19
  const initialValue = field === null || field === void 0 ? void 0 : field.initialValue;
20
- const [internalInitialValue, setInternalInitialValue] = useState(() => field === null || field === void 0 ? void 0 : field.initialValue);
21
- const [internalValue, setInternalValue] = useState(() => field === null || field === void 0 ? void 0 : field.value);
22
- const [internallyValid, setInternallyValid] = useState(undefined);
23
- // Debounce internal values to update form state only every 60ms
24
- const debouncedValue = useDebounce(internalValue, 120);
25
- // Validation is defined by two ways -
26
- // 1. by field state
27
- // 2. maintained locally to reflect instant validation state changes
28
- let valid = true;
29
- if (field && typeof field.valid === 'boolean') {
30
- valid = field.valid;
31
- }
32
- if (typeof internallyValid === 'boolean') {
33
- valid = internallyValid;
34
- }
20
+ const valid = typeof (field === null || field === void 0 ? void 0 : field.valid) === 'boolean' ? field.valid : true;
35
21
  const showError = valid === false && submitted;
36
- // Method to send update field values from field component(s)
37
- // Should only be used internally
38
- const sendField = useCallback(async (valueToSend) => {
39
- const fieldToDispatch = {
40
- path,
41
- disableFormData,
42
- initialValue,
43
- validate,
44
- condition,
45
- value: valueToSend,
46
- valid: false,
47
- errorMessage: undefined,
48
- };
49
- const validateOptions = {
50
- id,
51
- user,
52
- data: getData(),
53
- siblingData: getSiblingData(path),
54
- operation,
55
- };
56
- const validationResult = typeof validate === 'function' ? await validate(valueToSend, validateOptions) : true;
57
- if (typeof validationResult === 'string') {
58
- fieldToDispatch.errorMessage = validationResult;
59
- fieldToDispatch.valid = false;
60
- setInternallyValid(false);
61
- }
62
- else {
63
- fieldToDispatch.valid = validationResult;
64
- fieldToDispatch.errorMessage = undefined;
65
- setInternallyValid(true);
66
- }
67
- if (typeof dispatchFields === 'function') {
68
- dispatchFields(fieldToDispatch);
69
- }
70
- }, [
71
- condition,
72
- disableFormData,
73
- dispatchFields,
74
- getData,
75
- getSiblingData,
76
- id,
77
- initialValue,
78
- operation,
79
- path,
80
- user,
81
- validate,
82
- ]);
83
22
  // Method to return from `useField`, used to
84
- // update internal field values from field component(s)
85
- // as fast as they arrive. NOTE - this method is NOT debounced
23
+ // update field values from field component(s)
86
24
  const setValue = useCallback((e, disableModifyingForm = false) => {
87
25
  const val = (e && e.target) ? e.target.value : e;
88
26
  if (!modified && !disableModifyingForm) {
@@ -90,42 +28,78 @@ const useField = (options) => {
90
28
  setModified(true);
91
29
  }
92
30
  }
93
- setInternalValue(val);
31
+ dispatchField({
32
+ type: 'UPDATE',
33
+ path,
34
+ value: val,
35
+ disableFormData,
36
+ });
94
37
  }, [
95
38
  setModified,
96
39
  modified,
97
- ]);
98
- useEffect(() => {
99
- if (internalInitialValue !== initialValue) {
100
- setInternalValue(initialValue);
101
- setInternalInitialValue(initialValue);
102
- }
103
- setInternallyValid(undefined);
104
- }, [initialValue, internalInitialValue]);
105
- // The only time that the FORM value should be updated
106
- // is when the debounced value updates. So, when the debounced value updates,
107
- // send it up to the form
108
- const valueToSend = enableDebouncedValue ? debouncedValue : internalValue;
109
- useEffect(() => {
110
- if (((field === null || field === void 0 ? void 0 : field.value) !== valueToSend && valueToSend !== undefined) || disableFormData !== (field === null || field === void 0 ? void 0 : field.disableFormData)) {
111
- sendField(valueToSend);
112
- }
113
- }, [
114
40
  path,
115
- valueToSend,
116
- sendField,
117
- field,
41
+ dispatchField,
118
42
  disableFormData,
119
43
  ]);
120
- return {
121
- ...options,
44
+ // Store result from hook as ref
45
+ // to prevent unnecessary rerenders
46
+ const result = useMemo(() => ({
122
47
  showError,
123
48
  errorMessage: field === null || field === void 0 ? void 0 : field.errorMessage,
124
- value: internalValue,
49
+ value,
125
50
  formSubmitted: submitted,
126
51
  formProcessing: processing,
127
52
  setValue,
128
53
  initialValue,
129
- };
54
+ }), [field, processing, setValue, showError, submitted, value, initialValue]);
55
+ // Throttle the validate function
56
+ useThrottledEffect(() => {
57
+ const validateField = async () => {
58
+ const action = {
59
+ type: 'UPDATE',
60
+ path,
61
+ disableFormData,
62
+ validate,
63
+ condition,
64
+ value,
65
+ valid: false,
66
+ errorMessage: undefined,
67
+ };
68
+ const validateOptions = {
69
+ id,
70
+ user,
71
+ data: getData(),
72
+ siblingData: getSiblingData(path),
73
+ operation,
74
+ };
75
+ const validationResult = typeof validate === 'function' ? await validate(value, validateOptions) : true;
76
+ if (typeof validationResult === 'string') {
77
+ action.errorMessage = validationResult;
78
+ action.valid = false;
79
+ }
80
+ else {
81
+ action.valid = validationResult;
82
+ action.errorMessage = undefined;
83
+ }
84
+ if (action.valid !== valid && typeof dispatchField === 'function') {
85
+ dispatchField(action);
86
+ }
87
+ };
88
+ validateField();
89
+ }, 150, [
90
+ value,
91
+ condition,
92
+ disableFormData,
93
+ dispatchField,
94
+ getData,
95
+ getSiblingData,
96
+ id,
97
+ operation,
98
+ path,
99
+ user,
100
+ validate,
101
+ valid,
102
+ ]);
103
+ return result;
130
104
  };
131
105
  export default useField;
@@ -2,9 +2,7 @@ import { Condition, Validate } from '../../../../fields/config/types';
2
2
  export declare type Options = {
3
3
  path: string;
4
4
  validate?: Validate;
5
- enableDebouncedValue?: boolean;
6
5
  disableFormData?: boolean;
7
- ignoreWhileFlattening?: boolean;
8
6
  condition?: Condition;
9
7
  };
10
8
  export declare type FieldType<T> = {
@@ -22,9 +22,14 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
25
28
  Object.defineProperty(exports, "__esModule", { value: true });
26
29
  const react_1 = __importStar(require("react"));
27
30
  const context_1 = require("../Form/context");
31
+ const getSiblingData_1 = __importDefault(require("../Form/getSiblingData"));
32
+ const reduceFieldsToValues_1 = __importDefault(require("../Form/reduceFieldsToValues"));
28
33
  const withCondition = (Field) => {
29
34
  const CheckForCondition = (props) => {
30
35
  const { admin: { condition, } = {}, } = props;
@@ -36,12 +41,12 @@ const withCondition = (Field) => {
36
41
  const WithCondition = (props) => {
37
42
  const { name, path: pathFromProps, admin: { condition, } = {}, } = props;
38
43
  const path = typeof pathFromProps === 'string' ? pathFromProps : name;
39
- const { getData, getSiblingData, getField, dispatchFields } = (0, context_1.useWatchForm)();
40
- const data = getData();
41
- const siblingData = getSiblingData(path);
44
+ const [fields, dispatchFields] = (0, context_1.useAllFormFields)();
45
+ const data = (0, reduceFieldsToValues_1.default)(fields, true);
46
+ const siblingData = (0, getSiblingData_1.default)(fields, path);
42
47
  const hasCondition = Boolean(condition);
43
48
  const currentlyPassesCondition = hasCondition ? condition(data, siblingData) : true;
44
- const field = getField(path);
49
+ const field = fields[path];
45
50
  const existingConditionPasses = field === null || field === void 0 ? void 0 : field.passesCondition;
46
51
  (0, react_1.useEffect)(() => {
47
52
  if (hasCondition) {
@@ -61,4 +66,4 @@ const withCondition = (Field) => {
61
66
  return CheckForCondition;
62
67
  };
63
68
  exports.default = withCondition;
64
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvYWRtaW4vY29tcG9uZW50cy9mb3Jtcy93aXRoQ29uZGl0aW9uL2luZGV4LnRzeCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsK0NBQXlDO0FBRXpDLDZDQUErQztBQUUvQyxNQUFNLGFBQWEsR0FBRyxDQUFvQyxLQUE2QixFQUFlLEVBQUU7SUFDdEcsTUFBTSxpQkFBaUIsR0FBZ0IsQ0FBQyxLQUFLLEVBQUUsRUFBRTtRQUMvQyxNQUFNLEVBQ0osS0FBSyxFQUFFLEVBQ0wsU0FBUyxHQUNWLEdBQUcsRUFBRSxHQUNQLEdBQUcsS0FBMkIsQ0FBQztRQUVoQyxJQUFJLFNBQVMsRUFBRTtZQUNiLE9BQU8sOEJBQUMsYUFBYSxPQUFLLEtBQUssR0FBSSxDQUFDO1NBQ3JDO1FBRUQsT0FBTyw4QkFBQyxLQUFLLE9BQUssS0FBSyxHQUFJLENBQUM7SUFDOUIsQ0FBQyxDQUFDO0lBRUYsTUFBTSxhQUFhLEdBQWdCLENBQUMsS0FBSyxFQUFFLEVBQUU7UUFDM0MsTUFBTSxFQUNKLElBQUksRUFDSixJQUFJLEVBQUUsYUFBYSxFQUNuQixLQUFLLEVBQUUsRUFDTCxTQUFTLEdBQ1YsR0FBRyxFQUFFLEdBQ1AsR0FBRyxLQUVILENBQUM7UUFFRixNQUFNLElBQUksR0FBRyxPQUFPLGFBQWEsS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO1FBRXRFLE1BQU0sRUFBRSxPQUFPLEVBQUUsY0FBYyxFQUFFLFFBQVEsRUFBRSxjQUFjLEVBQUUsR0FBRyxJQUFBLHNCQUFZLEdBQUUsQ0FBQztRQUU3RSxNQUFNLElBQUksR0FBRyxPQUFPLEVBQUUsQ0FBQztRQUN2QixNQUFNLFdBQVcsR0FBRyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDekMsTUFBTSxZQUFZLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ3hDLE1BQU0sd0JBQXdCLEdBQUcsWUFBWSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7UUFDcEYsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzdCLE1BQU0sdUJBQXVCLEdBQUcsS0FBSyxhQUFMLEtBQUssdUJBQUwsS0FBSyxDQUFFLGVBQWUsQ0FBQztRQUV2RCxJQUFBLGlCQUFTLEVBQUMsR0FBRyxFQUFFO1lBQ2IsSUFBSSxZQUFZLEVBQUU7Z0JBQ2hCLElBQUksQ0FBQyx1QkFBdUIsSUFBSSx3QkFBd0IsRUFBRTtvQkFDeEQsY0FBYyxDQUFDLEVBQUUsSUFBSSxFQUFFLGtCQUFrQixFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztpQkFDbEU7Z0JBRUQsSUFBSSxDQUFDLHdCQUF3QixJQUFJLENBQUMsdUJBQXVCLElBQUksT0FBTyx1QkFBdUIsS0FBSyxXQUFXLENBQUMsRUFBRTtvQkFDNUcsY0FBYyxDQUFDLEVBQUUsSUFBSSxFQUFFLGtCQUFrQixFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztpQkFDbkU7YUFDRjtRQUNILENBQUMsRUFBRSxDQUFDLHdCQUF3QixFQUFFLHVCQUF1QixFQUFFLGNBQWMsRUFBRSxJQUFJLEVBQUUsWUFBWSxDQUFDLENBQUMsQ0FBQztRQUU1RixJQUFJLHdCQUF3QixFQUFFO1lBQzVCLE9BQU8sOEJBQUMsS0FBSyxPQUFLLEtBQUssR0FBSSxDQUFDO1NBQzdCO1FBRUQsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDLENBQUM7SUFFRixPQUFPLGlCQUFpQixDQUFDO0FBQzNCLENBQUMsQ0FBQztBQUVGLGtCQUFlLGFBQWEsQ0FBQyJ9
69
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvYWRtaW4vY29tcG9uZW50cy9mb3Jtcy93aXRoQ29uZGl0aW9uL2luZGV4LnRzeCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsK0NBQXlDO0FBRXpDLDZDQUFtRDtBQUNuRCw0RUFBb0Q7QUFDcEQsd0ZBQWdFO0FBRWhFLE1BQU0sYUFBYSxHQUFHLENBQW9DLEtBQTZCLEVBQWUsRUFBRTtJQUN0RyxNQUFNLGlCQUFpQixHQUFnQixDQUFDLEtBQUssRUFBRSxFQUFFO1FBQy9DLE1BQU0sRUFDSixLQUFLLEVBQUUsRUFDTCxTQUFTLEdBQ1YsR0FBRyxFQUFFLEdBQ1AsR0FBRyxLQUEyQixDQUFDO1FBRWhDLElBQUksU0FBUyxFQUFFO1lBQ2IsT0FBTyw4QkFBQyxhQUFhLE9BQUssS0FBSyxHQUFJLENBQUM7U0FDckM7UUFFRCxPQUFPLDhCQUFDLEtBQUssT0FBSyxLQUFLLEdBQUksQ0FBQztJQUM5QixDQUFDLENBQUM7SUFFRixNQUFNLGFBQWEsR0FBZ0IsQ0FBQyxLQUFLLEVBQUUsRUFBRTtRQUMzQyxNQUFNLEVBQ0osSUFBSSxFQUNKLElBQUksRUFBRSxhQUFhLEVBQ25CLEtBQUssRUFBRSxFQUNMLFNBQVMsR0FDVixHQUFHLEVBQUUsR0FDUCxHQUFHLEtBRUgsQ0FBQztRQUVGLE1BQU0sSUFBSSxHQUFHLE9BQU8sYUFBYSxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7UUFFdEUsTUFBTSxDQUFDLE1BQU0sRUFBRSxjQUFjLENBQUMsR0FBRyxJQUFBLDBCQUFnQixHQUFFLENBQUM7UUFFcEQsTUFBTSxJQUFJLEdBQUcsSUFBQSw4QkFBb0IsRUFBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDaEQsTUFBTSxXQUFXLEdBQUcsSUFBQSx3QkFBYyxFQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsQ0FBQztRQUNqRCxNQUFNLFlBQVksR0FBRyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDeEMsTUFBTSx3QkFBd0IsR0FBRyxZQUFZLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxJQUFJLEVBQUUsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztRQUNwRixNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDM0IsTUFBTSx1QkFBdUIsR0FBRyxLQUFLLGFBQUwsS0FBSyx1QkFBTCxLQUFLLENBQUUsZUFBZSxDQUFDO1FBRXZELElBQUEsaUJBQVMsRUFBQyxHQUFHLEVBQUU7WUFDYixJQUFJLFlBQVksRUFBRTtnQkFDaEIsSUFBSSxDQUFDLHVCQUF1QixJQUFJLHdCQUF3QixFQUFFO29CQUN4RCxjQUFjLENBQUMsRUFBRSxJQUFJLEVBQUUsa0JBQWtCLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO2lCQUNsRTtnQkFFRCxJQUFJLENBQUMsd0JBQXdCLElBQUksQ0FBQyx1QkFBdUIsSUFBSSxPQUFPLHVCQUF1QixLQUFLLFdBQVcsQ0FBQyxFQUFFO29CQUM1RyxjQUFjLENBQUMsRUFBRSxJQUFJLEVBQUUsa0JBQWtCLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO2lCQUNuRTthQUNGO1FBQ0gsQ0FBQyxFQUFFLENBQUMsd0JBQXdCLEVBQUUsdUJBQXVCLEVBQUUsY0FBYyxFQUFFLElBQUksRUFBRSxZQUFZLENBQUMsQ0FBQyxDQUFDO1FBRTVGLElBQUksd0JBQXdCLEVBQUU7WUFDNUIsT0FBTyw4QkFBQyxLQUFLLE9BQUssS0FBSyxHQUFJLENBQUM7U0FDN0I7UUFFRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUMsQ0FBQztJQUVGLE9BQU8saUJBQWlCLENBQUM7QUFDM0IsQ0FBQyxDQUFDO0FBRUYsa0JBQWUsYUFBYSxDQUFDIn0=
@@ -3,7 +3,7 @@
3
3
  .leave-without-saving {
4
4
  @include blur-bg;
5
5
  position: fixed;
6
- z-index: var(--z-modal);
6
+ z-index: calc(var(--z-modal) + 1);
7
7
  top: 0;
8
8
  right: 0;
9
9
  bottom: 0;
@@ -17,4 +17,4 @@
17
17
  .btn {
18
18
  margin-right: $baseline;
19
19
  }
20
- }
20
+ }
@@ -20,4 +20,4 @@
20
20
  padding: 0 0 $baseline;
21
21
  }
22
22
  }
23
- }
23
+ }
@@ -0,0 +1,3 @@
1
+ /// <reference types="react" />
2
+ export declare const EditDepthContext: import("react").Context<number>;
3
+ export declare const useEditDepth: () => number;
@@ -0,0 +1,3 @@
1
+ import { useContext, createContext } from 'react';
2
+ export const EditDepthContext = createContext(0);
3
+ export const useEditDepth = () => useContext(EditDepthContext);
@@ -4,7 +4,7 @@ import useField from '../../../../forms/useField';
4
4
  import Label from '../../../../forms/Label';
5
5
  import CopyToClipboard from '../../../../elements/CopyToClipboard';
6
6
  import { text } from '../../../../../../fields/validations';
7
- import { useWatchForm } from '../../../../forms/Form/context';
7
+ import { useFormFields } from '../../../../forms/Form/context';
8
8
  import GenerateConfirmation from '../../../../elements/GenerateConfirmation';
9
9
  const path = 'apiKey';
10
10
  const baseClass = 'api-key';
@@ -12,8 +12,7 @@ const validate = (val) => text(val, { minLength: 24, maxLength: 48, data: {}, si
12
12
  const APIKey = () => {
13
13
  const [initialAPIKey, setInitialAPIKey] = useState(null);
14
14
  const [highlightedField, setHighlightedField] = useState(false);
15
- const { getField } = useWatchForm();
16
- const apiKey = getField(path);
15
+ const apiKey = useFormFields(([fields]) => fields[path]);
17
16
  const apiKeyValue = apiKey === null || apiKey === void 0 ? void 0 : apiKey.value;
18
17
  const APIKeyLabel = useMemo(() => (React.createElement("div", { className: `${baseClass}__label` },
19
18
  React.createElement("span", null, "API Key"),
@@ -6,16 +6,16 @@ import Password from '../../../../forms/field-types/Password';
6
6
  import Checkbox from '../../../../forms/field-types/Checkbox';
7
7
  import Button from '../../../../elements/Button';
8
8
  import ConfirmPassword from '../../../../forms/field-types/ConfirmPassword';
9
- import { useWatchForm, useFormModified } from '../../../../forms/Form/context';
9
+ import { useFormModified, useFormFields } from '../../../../forms/Form/context';
10
10
  import APIKey from './APIKey';
11
11
  import './index.scss';
12
12
  const baseClass = 'auth-fields';
13
13
  const Auth = (props) => {
14
14
  const { useAPIKey, requirePassword, verify, collection: { slug }, collection, email, operation } = props;
15
15
  const [changingPassword, setChangingPassword] = useState(requirePassword);
16
- const { getField, dispatchFields } = useWatchForm();
16
+ const enableAPIKey = useFormFields(([fields]) => fields.enableAPIKey);
17
+ const dispatchFields = useFormFields((reducer) => reducer[1]);
17
18
  const modified = useFormModified();
18
- const enableAPIKey = getField('enableAPIKey');
19
19
  const { serverURL, routes: { api, }, } = useConfig();
20
20
  const handleChangePassword = useCallback(async (state) => {
21
21
  if (!state) {
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { Link, useRouteMatch } from 'react-router-dom';
2
+ import { Link } from 'react-router-dom';
3
3
  import format from 'date-fns/format';
4
4
  import { useConfig } from '../../../utilities/Config';
5
5
  import Eyebrow from '../../../elements/Eyebrow';
@@ -29,10 +29,9 @@ import './index.scss';
29
29
  const baseClass = 'collection-edit';
30
30
  const DefaultEditView = (props) => {
31
31
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
32
- const { params: { id } = {} } = useRouteMatch();
33
32
  const { admin: { dateFormat }, routes: { admin } } = useConfig();
34
33
  const { publishedDoc } = useDocumentInfo();
35
- const { collection, isEditing, data, onSave, permissions, isLoading, initialState, apiURL, action, hasSavePermission, } = props;
34
+ const { collection, isEditing, data, onSave, permissions, isLoading, initialState, apiURL, action, hasSavePermission, disableEyebrow, disableActions, disableLeaveWithoutSaving, customHeader, id, } = props;
36
35
  const { slug, fields, admin: { useAsTitle, disableDuplicate, preview, hideAPIURL, }, versions, timestamps, auth, upload, } = collection;
37
36
  const classes = [
38
37
  baseClass,
@@ -45,26 +44,27 @@ const DefaultEditView = (props) => {
45
44
  React.createElement(Form, { className: `${baseClass}__form`, method: id ? 'patch' : 'post', action: action, onSuccess: onSave, disabled: !hasSavePermission, initialState: initialState },
46
45
  React.createElement("div", { className: `${baseClass}__main` },
47
46
  React.createElement(Meta, { title: `${isEditing ? 'Editing' : 'Creating'} - ${collection.labels.singular}`, description: `${isEditing ? 'Editing' : 'Creating'} - ${collection.labels.singular}`, keywords: `${collection.labels.singular}, Payload, CMS` }),
48
- React.createElement(Eyebrow, null),
49
- !(((_a = collection.versions) === null || _a === void 0 ? void 0 : _a.drafts) && ((_c = (_b = collection.versions) === null || _b === void 0 ? void 0 : _b.drafts) === null || _c === void 0 ? void 0 : _c.autosave)) && (React.createElement(LeaveWithoutSaving, null)),
47
+ !disableEyebrow && (React.createElement(Eyebrow, null)),
48
+ (!(((_a = collection.versions) === null || _a === void 0 ? void 0 : _a.drafts) && ((_c = (_b = collection.versions) === null || _b === void 0 ? void 0 : _b.drafts) === null || _c === void 0 ? void 0 : _c.autosave)) && !disableLeaveWithoutSaving) && (React.createElement(LeaveWithoutSaving, null)),
50
49
  React.createElement(Gutter, { className: `${baseClass}__edit` },
51
50
  React.createElement("header", { className: `${baseClass}__header` },
52
- React.createElement("h1", null,
53
- React.createElement(RenderTitle, { ...{ data, useAsTitle, fallback: '[Untitled]' } }))),
51
+ customHeader && customHeader,
52
+ !customHeader && (React.createElement("h1", null,
53
+ React.createElement(RenderTitle, { ...{ data, useAsTitle, fallback: '[Untitled]' } })))),
54
54
  auth && (React.createElement(Auth, { useAPIKey: auth.useAPIKey, requirePassword: !isEditing, verify: auth.verify, collection: collection, email: data === null || data === void 0 ? void 0 : data.email, operation: operation })),
55
55
  upload && (React.createElement(Upload, { data: data, collection: collection })),
56
56
  React.createElement(RenderFields, { readOnly: !hasSavePermission, permissions: permissions.fields, filter: (field) => { var _a, _b; return (!((_a = field === null || field === void 0 ? void 0 : field.admin) === null || _a === void 0 ? void 0 : _a.position) || (((_b = field === null || field === void 0 ? void 0 : field.admin) === null || _b === void 0 ? void 0 : _b.position) !== 'sidebar')); }, fieldTypes: fieldTypes, fieldSchema: fields }))),
57
57
  React.createElement("div", { className: `${baseClass}__sidebar-wrap` },
58
58
  React.createElement("div", { className: `${baseClass}__sidebar` },
59
59
  React.createElement("div", { className: `${baseClass}__sidebar-sticky-wrap` },
60
- React.createElement("ul", { className: `${baseClass}__collection-actions` },
60
+ !disableActions && (React.createElement("ul", { className: `${baseClass}__collection-actions` },
61
61
  ((_d = permissions === null || permissions === void 0 ? void 0 : permissions.create) === null || _d === void 0 ? void 0 : _d.permission) && (React.createElement(React.Fragment, null,
62
62
  React.createElement("li", null,
63
63
  React.createElement(Link, { id: "action-create", to: `${admin}/collections/${slug}/create` }, "Create New")),
64
64
  !disableDuplicate && isEditing && (React.createElement("li", null,
65
65
  React.createElement(DuplicateDocument, { collection: collection, id: id, slug: slug }))))),
66
66
  ((_e = permissions === null || permissions === void 0 ? void 0 : permissions.delete) === null || _e === void 0 ? void 0 : _e.permission) && (React.createElement("li", null,
67
- React.createElement(DeleteDocument, { collection: collection, id: id, buttonId: "action-delete" })))),
67
+ React.createElement(DeleteDocument, { collection: collection, id: id, buttonId: "action-delete" }))))),
68
68
  React.createElement("div", { className: `${baseClass}__document-actions${((((_f = collection.versions) === null || _f === void 0 ? void 0 : _f.drafts) && !((_h = (_g = collection.versions) === null || _g === void 0 ? void 0 : _g.drafts) === null || _h === void 0 ? void 0 : _h.autosave)) || (isEditing && preview)) ? ` ${baseClass}__document-actions--has-2` : ''}` },
69
69
  (preview && (!((_j = collection.versions) === null || _j === void 0 ? void 0 : _j.drafts) || ((_l = (_k = collection.versions) === null || _k === void 0 ? void 0 : _k.drafts) === null || _l === void 0 ? void 0 : _l.autosave))) && (React.createElement(PreviewButton, { generatePreviewURL: preview, data: data })),
70
70
  hasSavePermission && (React.createElement(React.Fragment, null,
@@ -11,6 +11,7 @@ import buildStateFromSchema from '../../../forms/Form/buildStateFromSchema';
11
11
  import { useLocale } from '../../../utilities/Locale';
12
12
  import { useDocumentInfo } from '../../../utilities/DocumentInfo';
13
13
  import { usePreferences } from '../../../utilities/Preferences';
14
+ import { EditDepthContext } from '../../../utilities/EditDepth';
14
15
  const EditView = (props) => {
15
16
  var _a, _b, _c;
16
17
  const { collection: incomingCollection, isEditing } = props;
@@ -95,17 +96,19 @@ const EditView = (props) => {
95
96
  const apiURL = `${serverURL}${api}/${slug}/${id}${collection.versions.drafts ? '?draft=true' : ''}`;
96
97
  const action = `${serverURL}${api}/${slug}${isEditing ? `/${id}` : ''}?locale=${locale}&depth=0&fallback-locale=null`;
97
98
  const hasSavePermission = (isEditing && ((_b = collectionPermissions === null || collectionPermissions === void 0 ? void 0 : collectionPermissions.update) === null || _b === void 0 ? void 0 : _b.permission)) || (!isEditing && ((_c = collectionPermissions === null || collectionPermissions === void 0 ? void 0 : collectionPermissions.create) === null || _c === void 0 ? void 0 : _c.permission));
98
- return (React.createElement(RenderCustomComponent, { DefaultComponent: DefaultEdit, CustomComponent: CustomEdit, componentProps: {
99
- isLoading: !initialState,
100
- data: dataToRender,
101
- collection,
102
- permissions: collectionPermissions,
103
- isEditing,
104
- onSave,
105
- initialState,
106
- hasSavePermission,
107
- apiURL,
108
- action,
109
- } }));
99
+ return (React.createElement(EditDepthContext.Provider, { value: 1 },
100
+ React.createElement(RenderCustomComponent, { DefaultComponent: DefaultEdit, CustomComponent: CustomEdit, componentProps: {
101
+ id,
102
+ isLoading: !initialState,
103
+ data: dataToRender,
104
+ collection,
105
+ permissions: collectionPermissions,
106
+ isEditing,
107
+ onSave,
108
+ initialState,
109
+ hasSavePermission,
110
+ apiURL,
111
+ action,
112
+ } })));
110
113
  };
111
114
  export default EditView;
@@ -1,3 +1,4 @@
1
+ import React from 'react';
1
2
  import { SanitizedCollectionConfig } from '../../../../../collections/config/types';
2
3
  import { CollectionPermission } from '../../../../../auth/types';
3
4
  import { Document } from '../../../../../types';
@@ -9,6 +10,7 @@ export declare type IndexProps = {
9
10
  export declare type Props = IndexProps & {
10
11
  data: Document;
11
12
  onSave?: () => void;
13
+ id?: string;
12
14
  permissions: CollectionPermission;
13
15
  isLoading: boolean;
14
16
  initialState?: Fields;
@@ -16,4 +18,8 @@ export declare type Props = IndexProps & {
16
18
  action: string;
17
19
  hasSavePermission: boolean;
18
20
  autosaveEnabled: boolean;
21
+ disableEyebrow?: boolean;
22
+ disableActions?: boolean;
23
+ disableLeaveWithoutSaving?: boolean;
24
+ customHeader?: React.ReactNode;
19
25
  };
@@ -1,7 +1,6 @@
1
- import { useWatchForm } from '../components/forms/Form/context';
1
+ import { useFormFields } from '../components/forms/Form/context';
2
2
  const useTitle = (useAsTitle) => {
3
- const { getField } = useWatchForm();
4
- const titleField = getField(useAsTitle);
3
+ const titleField = useFormFields(([fields]) => fields[useAsTitle]);
5
4
  return titleField === null || titleField === void 0 ? void 0 : titleField.value;
6
5
  };
7
6
  export default useTitle;
@@ -28,7 +28,7 @@ const Index = () => (React.createElement(React.Fragment, null,
28
28
  } },
29
29
  React.createElement(ScrollInfoProvider, null,
30
30
  React.createElement(Router, null,
31
- React.createElement(ModalProvider, { classPrefix: "payload", zIndex: 50, transTime: 0 },
31
+ React.createElement(ModalProvider, { classPrefix: "payload", zIndex: 'var(--z-modal)', transTime: 0 },
32
32
  React.createElement(AuthProvider, null,
33
33
  React.createElement(PreferencesProvider, null,
34
34
  React.createElement(ThemeProvider, null,
@@ -9,10 +9,13 @@
9
9
  --breakpoint-m-width : #{$breakpoint-m-width};
10
10
  --breakpoint-l-width : #{$breakpoint-l-width};
11
11
  --scrollbar-width: 17px;
12
+ --nav-width: #{base(9)};
12
13
 
13
14
  --theme-bg: var(--theme-elevation-0);
14
15
  --theme-input-bg: var(--theme-elevation-0);
15
16
  --theme-text: var(--theme-elevation-800);
17
+ --theme-baseline: #{$baseline-px};
18
+ --theme-baseline-body-size: #{$baseline-body-size};
16
19
  --font-body: 'Suisse Intl', system-ui;
17
20
  --font-mono: monospace;
18
21
  --font-serif: 'Merriweather', serif;
@@ -26,10 +29,12 @@
26
29
 
27
30
  @include large-break {
28
31
  --gutter-h: #{base(3)};
32
+ --nav-width: #{base(8)};
29
33
  }
30
34
 
31
35
  @include mid-break {
32
36
  --gutter-h: #{base(2)};
37
+ --nav-width: 100%;
33
38
  }
34
39
 
35
40
  @include small-break {
@@ -172,4 +177,4 @@ dialog {
172
177
  z-index: var(--z-modal);
173
178
  }
174
179
 
175
- @import '~payload-user-css';
180
+ @import '~payload-user-css';
@@ -161,51 +161,9 @@ const CustomTextField: React.FC<Props> = ({ path }) => {
161
161
  }
162
162
  ```
163
163
 
164
- ### Getting other field values from the form
165
-
166
- There are times when a custom field component needs to have access to data from other fields. This can be done using `getDataByPath` from `useWatchForm` as follows:
167
-
168
- ```tsx
169
- import { useWatchForm } from 'payload/components/forms';
170
-
171
- const DisplayFee: React.FC = () => {
172
- const { getDataByPath } = useWatchForm();
173
-
174
- const amount = getDataByPath('amount');
175
- const feePercentage = getDataByPath('feePercentage');
176
-
177
- if (amount && feePercentage) {
178
- return (
179
- <span>The fee is ${(amount * feePercentage) / 100}</span>
180
- );
181
- }
182
- };
183
- ```
184
-
185
- ### Getting the document ID
186
-
187
- The document ID can be very useful for certain custom components. You can get the `id` from the `useDocumentInfo` hook. Here is an example of a `UI` field using `id` to link to related collections:
188
-
189
- ```tsx
190
- import { useDocumentInfo } from 'payload/components/utilities';
191
-
192
- const LinkFromCategoryToPosts: React.FC = () => {
193
- // highlight-start
194
- const { id } = useDocumentInfo();
195
- // highlight-end
196
-
197
- // id will be undefined on the create form
198
- if (!id) {
199
- return null;
200
- }
201
-
202
- return (
203
- <a href={`/admin/collections/posts?where[or][0][and][0][category][in][0]=[${id}]`} >
204
- View posts
205
- </a>
206
- )
207
- };
208
- ```
164
+ <Banner type="success">
165
+ For more information regarding the hooks that are available to you while you build custom components, including the <strong>useField</strong> hook, <a href="/docs/admin/hooks" style={{color: 'black'}}>click here</a>.
166
+ </Banner>
209
167
 
210
168
  ## Custom routes
211
169
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: Customizing CSS & SCSS
3
3
  label: Customizing CSS
4
- order: 30
4
+ order: 40
5
5
  desc: Customize your Payload admin panel further by adding your own CSS or SCSS style sheet to the configuration, powerful theme and design options are waiting for you.
6
6
  keywords: admin, css, scss, documentation, Content Management System, cms, headless, javascript, node, react, express
7
7
  ---