@manuscripts/body-editor 3.12.1 → 3.12.2

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.
@@ -51,30 +51,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
51
51
  return (mod && mod.__esModule) ? mod : { "default": mod };
52
52
  };
53
53
  Object.defineProperty(exports, "__esModule", { value: true });
54
- exports.AuthorDetailsForm = exports.CheckboxContainer = exports.Fieldset = void 0;
54
+ exports.CheckboxContainer = exports.Fieldset = exports.AuthorDetailsForm = void 0;
55
55
  const style_guide_1 = require("@manuscripts/style-guide");
56
56
  const formik_1 = require("formik");
57
57
  const react_1 = __importStar(require("react"));
58
58
  const styled_components_1 = __importDefault(require("styled-components"));
59
+ const normalize_1 = require("../../lib/normalize");
59
60
  const ChangeHandlingForm_1 = require("../ChangeHandlingForm");
60
- exports.Fieldset = styled_components_1.default.fieldset `
61
- padding: 0;
62
- margin: 0;
63
- border: none;
64
- `;
65
- const OrcidContainer = styled_components_1.default.div `
66
- margin: 16px 0 0;
67
- `;
68
- const TextFieldWithError = (0, styled_components_1.default)(style_guide_1.TextField) `
69
- &:required::placeholder {
70
- color: ${(props) => props.theme.colors.text.error};
71
- }
72
- `;
73
- exports.CheckboxContainer = styled_components_1.default.div `
74
- display: flex;
75
- align-items: center;
76
- gap: 32px;
77
- `;
61
+ const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
62
+ const ORCID_URL_REGEX = /^https:\/\/orcid\.org\/\d{4}-\d{4}-\d{4}-\d{3}[0-9Xx]\/?$/;
63
+ const ORCID_INPUT_PATTERN = ORCID_URL_REGEX.source.slice(1, -1);
78
64
  const AuthorDetailsForm = ({ values, onChange, onSave, actionsRef, isEmailRequired, selectedAffiliations, selectedCreditRoles, authorFormRef, }) => {
79
65
  const formRef = (0, react_1.useRef)(null);
80
66
  (0, react_1.useEffect)(() => {
@@ -96,17 +82,22 @@ const AuthorDetailsForm = ({ values, onChange, onSave, actionsRef, isEmailRequir
96
82
  }
97
83
  const validateAuthor = (values) => {
98
84
  const errors = {};
99
- if (isEmailRequired && !values.email) {
85
+ const email = values.email?.trim();
86
+ if (isEmailRequired && !email) {
100
87
  errors.email = 'Email address is required';
101
88
  }
102
- else if (values.email &&
103
- !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(values.email)) {
89
+ else if (email && !EMAIL_REGEX.test(email)) {
104
90
  errors.email = 'Invalid email address';
105
91
  }
92
+ const orcid = values.ORCID?.trim();
93
+ if (orcid && !ORCID_URL_REGEX.test(orcid)) {
94
+ errors.ORCID =
95
+ 'Please enter a valid ORCID URL: https://orcid.org/xxxx-xxxx-xxxx-xxxx';
96
+ }
106
97
  return errors;
107
98
  };
108
- return (react_1.default.createElement(formik_1.Formik, { initialValues: values, onSubmit: onSave, enableReinitialize: true, validateOnChange: true, innerRef: formRef, validate: validateAuthor }, (formik) => {
109
- return (react_1.default.createElement(ChangeHandlingForm_1.ChangeHandlingForm, { onChange: onChange, id: "author-details-form", formRef: authorFormRef, noValidate: true },
99
+ return (react_1.default.createElement(formik_1.Formik, { initialValues: values, onSubmit: (submitted) => onSave((0, normalize_1.normalizeAuthor)(submitted)), enableReinitialize: true, validateOnChange: true, innerRef: formRef, validate: validateAuthor }, (formik) => {
100
+ return (react_1.default.createElement(ChangeHandlingForm_1.ChangeHandlingForm, { onChange: (next) => onChange((0, normalize_1.normalizeAuthor)(next)), id: "author-details-form", formRef: authorFormRef, noValidate: true },
110
101
  react_1.default.createElement(style_guide_1.FormRow, null,
111
102
  react_1.default.createElement(formik_1.Field, { name: 'prefix' }, (props) => (react_1.default.createElement(react_1.default.Fragment, null,
112
103
  react_1.default.createElement(style_guide_1.Label, { htmlFor: "prefix" }, "Prefix"),
@@ -134,16 +125,35 @@ const AuthorDetailsForm = ({ values, onChange, onSave, actionsRef, isEmailRequir
134
125
  react_1.default.createElement(TextFieldWithError, { id: 'email', type: "email", required: isEmailRequired, ...props.field, error: hasError }),
135
126
  hasError && (react_1.default.createElement(style_guide_1.InputErrorText, null, (0, formik_1.getIn)(formik.errors, 'email')))));
136
127
  })),
137
- react_1.default.createElement(exports.CheckboxContainer, null,
138
- react_1.default.createElement(style_guide_1.CheckboxLabel, null,
139
- react_1.default.createElement(formik_1.Field, { name: 'isCorresponding' }, (props) => (react_1.default.createElement(style_guide_1.CheckboxField, { id: 'isCorresponding', checked: props.field.value, ...props.field }))),
140
- react_1.default.createElement(style_guide_1.LabelText, null, "Corresponding Author"))),
141
- react_1.default.createElement(OrcidContainer, null,
142
- react_1.default.createElement(style_guide_1.FormRow, null,
143
- react_1.default.createElement(style_guide_1.Label, { htmlFor: "orcid" }, "ORCID"),
144
- react_1.default.createElement(formik_1.Field, { name: 'ORCID', type: 'text' }, (props) => (react_1.default.createElement(react_1.default.Fragment, null,
145
- react_1.default.createElement(style_guide_1.Label, { htmlFor: "orcid", className: "sr-only" }, "ORCID"),
146
- react_1.default.createElement(style_guide_1.TextField, { id: 'orcid', placeholder: 'https://orcid.org/...', pattern: "https://orcid\\.org/\\d{4}-\\d{4}-\\d{4}-\\d{3}[0-9Xx]", title: "Please enter a valid ORCID URL format: https://orcid.org/xxxx-xxxx-xxxx-xxxx", ...props.field }))))))));
128
+ react_1.default.createElement(style_guide_1.FormRow, null,
129
+ react_1.default.createElement(exports.CheckboxContainer, { "data-cy": "corresponding-author-container" },
130
+ react_1.default.createElement(style_guide_1.CheckboxLabel, null,
131
+ react_1.default.createElement(formik_1.Field, { name: 'isCorresponding' }, (props) => (react_1.default.createElement(style_guide_1.CheckboxField, { id: 'isCorresponding', checked: props.field.value, ...props.field }))),
132
+ react_1.default.createElement(style_guide_1.LabelText, null, "Corresponding Author")))),
133
+ react_1.default.createElement(style_guide_1.FormRow, null,
134
+ react_1.default.createElement(formik_1.Field, { name: 'ORCID', type: 'text' }, (props) => {
135
+ const hasError = (0, formik_1.getIn)(formik.touched, 'ORCID') &&
136
+ (0, formik_1.getIn)(formik.errors, 'ORCID');
137
+ return (react_1.default.createElement(react_1.default.Fragment, null,
138
+ react_1.default.createElement(style_guide_1.Label, { htmlFor: "orcid" }, "ORCID"),
139
+ react_1.default.createElement(TextFieldWithError, { id: 'orcid', type: "url", placeholder: 'https://orcid.org/...', ...props.field, pattern: ORCID_INPUT_PATTERN, title: "Please enter a valid ORCID URL: https://orcid.org/xxxx-xxxx-xxxx-xxxx", error: hasError }),
140
+ hasError && (react_1.default.createElement(style_guide_1.InputErrorText, null, (0, formik_1.getIn)(formik.errors, 'ORCID')))));
141
+ }))));
147
142
  }));
148
143
  };
149
144
  exports.AuthorDetailsForm = AuthorDetailsForm;
145
+ exports.Fieldset = styled_components_1.default.fieldset `
146
+ padding: 0;
147
+ margin: 0;
148
+ border: none;
149
+ `;
150
+ const TextFieldWithError = (0, styled_components_1.default)(style_guide_1.TextField) `
151
+ &:required::placeholder {
152
+ color: ${(props) => props.theme.colors.text.error};
153
+ }
154
+ `;
155
+ exports.CheckboxContainer = styled_components_1.default.div `
156
+ display: flex;
157
+ align-items: center;
158
+ gap: 32px;
159
+ `;
@@ -17,21 +17,23 @@
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.checkID = exports.normalizeAuthor = void 0;
19
19
  const transform_1 = require("@manuscripts/transform");
20
+ const trim = (value) => (value ?? '').trim();
20
21
  const normalizeAuthor = (author) => {
21
22
  const basic = {
22
23
  id: author.id,
23
- role: author.role || '',
24
+ role: trim(author.role),
24
25
  affiliationIDs: (author.affiliationIDs || []).sort(),
25
- given: author.given || '',
26
- family: author.family || '',
27
- email: author.email || '',
26
+ given: trim(author.given),
27
+ family: trim(author.family),
28
+ email: trim(author.email),
28
29
  isCorresponding: author.isCorresponding || false,
29
- ORCID: author.ORCID || '',
30
+ ORCID: trim(author.ORCID),
30
31
  priority: author.priority,
31
32
  isJointContributor: author.isJointContributor || false,
32
33
  footnoteIDs: author.footnoteIDs || [],
33
34
  correspIDs: author.correspIDs || [],
34
- prefix: author.prefix || '',
35
+ prefix: trim(author.prefix),
36
+ suffix: trim(author.suffix),
35
37
  };
36
38
  if (author.creditRoles && Array.isArray(author.creditRoles)) {
37
39
  basic.creditRoles = author.creditRoles;
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MATHJAX_VERSION = exports.VERSION = void 0;
4
- exports.VERSION = '3.12.1';
4
+ exports.VERSION = '3.12.2';
5
5
  exports.MATHJAX_VERSION = '3.2.2';
@@ -17,25 +17,11 @@ import { CheckboxField, CheckboxLabel, TextField, InputErrorText, Label, FormRow
17
17
  import { Field, Formik, getIn, } from 'formik';
18
18
  import React, { useEffect, useRef } from 'react';
19
19
  import styled from 'styled-components';
20
+ import { normalizeAuthor } from '../../lib/normalize';
20
21
  import { ChangeHandlingForm } from '../ChangeHandlingForm';
21
- export const Fieldset = styled.fieldset `
22
- padding: 0;
23
- margin: 0;
24
- border: none;
25
- `;
26
- const OrcidContainer = styled.div `
27
- margin: 16px 0 0;
28
- `;
29
- const TextFieldWithError = styled(TextField) `
30
- &:required::placeholder {
31
- color: ${(props) => props.theme.colors.text.error};
32
- }
33
- `;
34
- export const CheckboxContainer = styled.div `
35
- display: flex;
36
- align-items: center;
37
- gap: 32px;
38
- `;
22
+ const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
23
+ const ORCID_URL_REGEX = /^https:\/\/orcid\.org\/\d{4}-\d{4}-\d{4}-\d{3}[0-9Xx]\/?$/;
24
+ const ORCID_INPUT_PATTERN = ORCID_URL_REGEX.source.slice(1, -1);
39
25
  export const AuthorDetailsForm = ({ values, onChange, onSave, actionsRef, isEmailRequired, selectedAffiliations, selectedCreditRoles, authorFormRef, }) => {
40
26
  const formRef = useRef(null);
41
27
  useEffect(() => {
@@ -57,17 +43,22 @@ export const AuthorDetailsForm = ({ values, onChange, onSave, actionsRef, isEmai
57
43
  }
58
44
  const validateAuthor = (values) => {
59
45
  const errors = {};
60
- if (isEmailRequired && !values.email) {
46
+ const email = values.email?.trim();
47
+ if (isEmailRequired && !email) {
61
48
  errors.email = 'Email address is required';
62
49
  }
63
- else if (values.email &&
64
- !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(values.email)) {
50
+ else if (email && !EMAIL_REGEX.test(email)) {
65
51
  errors.email = 'Invalid email address';
66
52
  }
53
+ const orcid = values.ORCID?.trim();
54
+ if (orcid && !ORCID_URL_REGEX.test(orcid)) {
55
+ errors.ORCID =
56
+ 'Please enter a valid ORCID URL: https://orcid.org/xxxx-xxxx-xxxx-xxxx';
57
+ }
67
58
  return errors;
68
59
  };
69
- return (React.createElement(Formik, { initialValues: values, onSubmit: onSave, enableReinitialize: true, validateOnChange: true, innerRef: formRef, validate: validateAuthor }, (formik) => {
70
- return (React.createElement(ChangeHandlingForm, { onChange: onChange, id: "author-details-form", formRef: authorFormRef, noValidate: true },
60
+ return (React.createElement(Formik, { initialValues: values, onSubmit: (submitted) => onSave(normalizeAuthor(submitted)), enableReinitialize: true, validateOnChange: true, innerRef: formRef, validate: validateAuthor }, (formik) => {
61
+ return (React.createElement(ChangeHandlingForm, { onChange: (next) => onChange(normalizeAuthor(next)), id: "author-details-form", formRef: authorFormRef, noValidate: true },
71
62
  React.createElement(FormRow, null,
72
63
  React.createElement(Field, { name: 'prefix' }, (props) => (React.createElement(React.Fragment, null,
73
64
  React.createElement(Label, { htmlFor: "prefix" }, "Prefix"),
@@ -95,15 +86,34 @@ export const AuthorDetailsForm = ({ values, onChange, onSave, actionsRef, isEmai
95
86
  React.createElement(TextFieldWithError, { id: 'email', type: "email", required: isEmailRequired, ...props.field, error: hasError }),
96
87
  hasError && (React.createElement(InputErrorText, null, getIn(formik.errors, 'email')))));
97
88
  })),
98
- React.createElement(CheckboxContainer, null,
99
- React.createElement(CheckboxLabel, null,
100
- React.createElement(Field, { name: 'isCorresponding' }, (props) => (React.createElement(CheckboxField, { id: 'isCorresponding', checked: props.field.value, ...props.field }))),
101
- React.createElement(LabelText, null, "Corresponding Author"))),
102
- React.createElement(OrcidContainer, null,
103
- React.createElement(FormRow, null,
104
- React.createElement(Label, { htmlFor: "orcid" }, "ORCID"),
105
- React.createElement(Field, { name: 'ORCID', type: 'text' }, (props) => (React.createElement(React.Fragment, null,
106
- React.createElement(Label, { htmlFor: "orcid", className: "sr-only" }, "ORCID"),
107
- React.createElement(TextField, { id: 'orcid', placeholder: 'https://orcid.org/...', pattern: "https://orcid\\.org/\\d{4}-\\d{4}-\\d{4}-\\d{3}[0-9Xx]", title: "Please enter a valid ORCID URL format: https://orcid.org/xxxx-xxxx-xxxx-xxxx", ...props.field }))))))));
89
+ React.createElement(FormRow, null,
90
+ React.createElement(CheckboxContainer, { "data-cy": "corresponding-author-container" },
91
+ React.createElement(CheckboxLabel, null,
92
+ React.createElement(Field, { name: 'isCorresponding' }, (props) => (React.createElement(CheckboxField, { id: 'isCorresponding', checked: props.field.value, ...props.field }))),
93
+ React.createElement(LabelText, null, "Corresponding Author")))),
94
+ React.createElement(FormRow, null,
95
+ React.createElement(Field, { name: 'ORCID', type: 'text' }, (props) => {
96
+ const hasError = getIn(formik.touched, 'ORCID') &&
97
+ getIn(formik.errors, 'ORCID');
98
+ return (React.createElement(React.Fragment, null,
99
+ React.createElement(Label, { htmlFor: "orcid" }, "ORCID"),
100
+ React.createElement(TextFieldWithError, { id: 'orcid', type: "url", placeholder: 'https://orcid.org/...', ...props.field, pattern: ORCID_INPUT_PATTERN, title: "Please enter a valid ORCID URL: https://orcid.org/xxxx-xxxx-xxxx-xxxx", error: hasError }),
101
+ hasError && (React.createElement(InputErrorText, null, getIn(formik.errors, 'ORCID')))));
102
+ }))));
108
103
  }));
109
104
  };
105
+ export const Fieldset = styled.fieldset `
106
+ padding: 0;
107
+ margin: 0;
108
+ border: none;
109
+ `;
110
+ const TextFieldWithError = styled(TextField) `
111
+ &:required::placeholder {
112
+ color: ${(props) => props.theme.colors.text.error};
113
+ }
114
+ `;
115
+ export const CheckboxContainer = styled.div `
116
+ display: flex;
117
+ align-items: center;
118
+ gap: 32px;
119
+ `;
@@ -14,21 +14,23 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  import { generateNodeID, schema } from '@manuscripts/transform';
17
+ const trim = (value) => (value ?? '').trim();
17
18
  export const normalizeAuthor = (author) => {
18
19
  const basic = {
19
20
  id: author.id,
20
- role: author.role || '',
21
+ role: trim(author.role),
21
22
  affiliationIDs: (author.affiliationIDs || []).sort(),
22
- given: author.given || '',
23
- family: author.family || '',
24
- email: author.email || '',
23
+ given: trim(author.given),
24
+ family: trim(author.family),
25
+ email: trim(author.email),
25
26
  isCorresponding: author.isCorresponding || false,
26
- ORCID: author.ORCID || '',
27
+ ORCID: trim(author.ORCID),
27
28
  priority: author.priority,
28
29
  isJointContributor: author.isJointContributor || false,
29
30
  footnoteIDs: author.footnoteIDs || [],
30
31
  correspIDs: author.correspIDs || [],
31
- prefix: author.prefix || '',
32
+ prefix: trim(author.prefix),
33
+ suffix: trim(author.suffix),
32
34
  };
33
35
  if (author.creditRoles && Array.isArray(author.creditRoles)) {
34
36
  basic.creditRoles = author.creditRoles;
@@ -1,2 +1,2 @@
1
- export const VERSION = '3.12.1';
1
+ export const VERSION = '3.12.2';
2
2
  export const MATHJAX_VERSION = '3.2.2';
@@ -16,8 +16,6 @@
16
16
  import { CreditRole } from '@manuscripts/transform';
17
17
  import React, { MutableRefObject } from 'react';
18
18
  import { ContributorAttrs } from '../../lib/authors';
19
- export declare const Fieldset: import("styled-components").StyledComponent<"fieldset", any, {}, never>;
20
- export declare const CheckboxContainer: import("styled-components").StyledComponent<"div", any, {}, never>;
21
19
  export interface FormActions {
22
20
  reset: () => void;
23
21
  }
@@ -32,4 +30,6 @@ interface AuthorDetailsFormProps {
32
30
  selectedCreditRoles: CreditRole[];
33
31
  }
34
32
  export declare const AuthorDetailsForm: React.FC<AuthorDetailsFormProps>;
33
+ export declare const Fieldset: import("styled-components").StyledComponent<"fieldset", any, {}, never>;
34
+ export declare const CheckboxContainer: import("styled-components").StyledComponent<"div", any, {}, never>;
35
35
  export {};
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "3.12.1";
1
+ export declare const VERSION = "3.12.2";
2
2
  export declare const MATHJAX_VERSION = "3.2.2";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@manuscripts/body-editor",
3
3
  "description": "Prosemirror components for editing and viewing manuscripts",
4
- "version": "3.12.1",
4
+ "version": "3.12.2",
5
5
  "repository": "github:Atypon-OpenSource/manuscripts-body-editor",
6
6
  "license": "Apache-2.0",
7
7
  "main": "dist/cjs",