@plone/volto 16.8.1 → 16.9.0

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 (47) hide show
  1. package/.changelog.draft +17 -2
  2. package/.yarn/install-state.gz +0 -0
  3. package/CHANGELOG.md +23 -0
  4. package/cypress/support/commands.js +6 -0
  5. package/news/4104.internal +1 -0
  6. package/news/4165.feature +1 -0
  7. package/news/4189.bugfix +1 -0
  8. package/news/4194.bugfix +1 -0
  9. package/news/4223.bugfix +1 -0
  10. package/news/4231.feature +1 -0
  11. package/news/4282.feature +1 -0
  12. package/news/4285.feature +1 -0
  13. package/news/4311.bugfix +1 -0
  14. package/news/4313.feature +1 -0
  15. package/package.json +3 -2
  16. package/packages/volto-slate/package.json +1 -1
  17. package/packages/volto-slate/src/blocks/Text/DetachedTextBlockEditor.jsx +1 -0
  18. package/packages/volto-slate/src/editor/SlateEditor.jsx +5 -1
  19. package/packages/volto-slate/src/editor/ui/InlineToolbar.jsx +3 -1
  20. package/packages/volto-slate/src/editor/ui/SlateToolbar.jsx +3 -1
  21. package/src/components/manage/Blocks/Block/Edit.jsx +1 -0
  22. package/src/components/manage/Blocks/Listing/ListingData.jsx +5 -2
  23. package/src/components/manage/Blocks/Search/widgets/SelectMetadataField.jsx +1 -1
  24. package/src/components/manage/Edit/Edit.jsx +5 -2
  25. package/src/components/manage/Toolbar/Toolbar.jsx +22 -5
  26. package/src/components/manage/UniversalLink/UniversalLink.jsx +2 -2
  27. package/src/components/manage/Widgets/ArrayWidget.jsx +1 -0
  28. package/src/components/manage/Widgets/SelectWidget.jsx +1 -0
  29. package/src/components/manage/Widgets/TokenWidget.jsx +1 -0
  30. package/src/components/theme/App/App.jsx +39 -13
  31. package/src/components/theme/View/View.jsx +9 -2
  32. package/src/config/index.js +10 -2
  33. package/src/helpers/FormValidation/FormValidation.js +11 -9
  34. package/src/helpers/ScrollToTop/ScrollToTop.jsx +4 -1
  35. package/src/helpers/Utils/Utils.js +5 -3
  36. package/src/middleware/api.js +22 -15
  37. package/src/reducers/actions/actions.js +36 -8
  38. package/src/reducers/actions/actions.test.js +87 -1
  39. package/src/reducers/breadcrumbs/breadcrumbs.js +50 -13
  40. package/src/reducers/breadcrumbs/breadcrumbs.test.js +47 -1
  41. package/src/reducers/navigation/navigation.js +41 -9
  42. package/src/reducers/navigation/navigation.test.js +49 -1
  43. package/src/reducers/types/types.js +36 -8
  44. package/src/reducers/types/types.test.js +31 -1
  45. package/src/registry.js +18 -0
  46. package/src/registry.test.js +34 -0
  47. package/test-setup-config.js +3 -0
package/.changelog.draft CHANGED
@@ -1,6 +1,21 @@
1
- ## 16.8.1 (2023-01-18)
1
+ ## 16.9.0 (2023-01-27)
2
+
3
+ ### Feature
4
+
5
+ - Enable scrolling to ids via hashes in internal links @jackahl [#4165](https://github.com/plone/volto/issues/4165)
6
+ - Read listing block schema from configuration registry @pnicolli [#4231](https://github.com/plone/volto/issues/4231)
7
+ - Add displayName when registering a component @sneridagh [#4282](https://github.com/plone/volto/issues/4282)
8
+ - Support for all default expanders (breadcrumbs, navigation, actions, types) in actions/reducers. Conditional loading of actions if the expanders are present. @sneridagh [#4285](https://github.com/plone/volto/issues/4285)
9
+ - Add `addNewBlock` Cypress support command @sneridagh [#4313](https://github.com/plone/volto/issues/4313)
2
10
 
3
11
  ### Bugfix
4
12
 
5
- - Fix StyleWrapper extenders, the classNames were not being re-fed into the pipe @sneridagh [#4275](https://github.com/plone/volto/issues/4275)
13
+ - Fixed maxLength validation for string type fields @pnicolli [#4189](https://github.com/plone/volto/issues/4189)
14
+ - bugfix : add pathname as required proptype in Blocks/Edit @akshatgarg12 [#4194](https://github.com/plone/volto/issues/4194)
15
+ - (Fix) Select Widgets scrolls the page when the options are not visible @dobri1408 [#4223](https://github.com/plone/volto/issues/4223)
16
+ - Updated volto-slate to check for slateSettings before falling back to config @danalvrz [#4311](https://github.com/plone/volto/issues/4311)
17
+
18
+ ### Internal
19
+
20
+ - Updated 4 Dependencies @SaiRev0 [#4104](https://github.com/plone/volto/issues/4104)
6
21
 
Binary file
package/CHANGELOG.md CHANGED
@@ -8,11 +8,34 @@
8
8
 
9
9
  <!-- towncrier release notes start -->
10
10
 
11
+ ## 16.9.0 (2023-01-27)
12
+
13
+ ### Feature
14
+
15
+ - Enable scrolling to ids via hashes in internal links @jackahl [#4165](https://github.com/plone/volto/issues/4165)
16
+ - Read listing block schema from configuration registry @pnicolli [#4231](https://github.com/plone/volto/issues/4231)
17
+ - Add displayName when registering a component @sneridagh [#4282](https://github.com/plone/volto/issues/4282)
18
+ - Support for all default expanders (breadcrumbs, navigation, actions, types) in actions/reducers. Conditional loading of actions if the expanders are present. @sneridagh [#4285](https://github.com/plone/volto/issues/4285)
19
+ - Add `addNewBlock` Cypress support command @sneridagh [#4313](https://github.com/plone/volto/issues/4313)
20
+
21
+ ### Bugfix
22
+
23
+ - Fixed maxLength validation for string type fields @pnicolli [#4189](https://github.com/plone/volto/issues/4189)
24
+ - bugfix : add pathname as required proptype in Blocks/Edit @akshatgarg12 [#4194](https://github.com/plone/volto/issues/4194)
25
+ - (Fix) Select Widgets scrolls the page when the options are not visible @dobri1408 [#4223](https://github.com/plone/volto/issues/4223)
26
+ - Updated volto-slate to check for slateSettings before falling back to config @danalvrz [#4311](https://github.com/plone/volto/issues/4311)
27
+
28
+ ### Internal
29
+
30
+ - Updated 4 Dependencies @SaiRev0 [#4104](https://github.com/plone/volto/issues/4104)
31
+
32
+
11
33
  ## 16.8.1 (2023-01-18)
12
34
 
13
35
  ### Bugfix
14
36
 
15
37
  - Fix StyleWrapper extenders, the classNames were not being re-fed into the pipe @sneridagh [#4275](https://github.com/plone/volto/issues/4275)
38
+ - Fix bug where label of search facet wasn't translated when the content object is being translated @robgietema
16
39
 
17
40
 
18
41
  ## 16.8.0 (2023-01-18)
@@ -806,6 +806,12 @@ function createHtmlPasteEvent(htmlContent) {
806
806
  );
807
807
  }
808
808
 
809
+ Cypress.Commands.add('addNewBlock', (blockName, createNewSlate = false) => {
810
+ let block;
811
+ block = cy.getSlate(createNewSlate).type(`/${blockName}{enter}`);
812
+ return block;
813
+ });
814
+
809
815
  Cypress.Commands.add('navigate', (route = '') => {
810
816
  return cy.window().its('appHistory').invoke('push', route);
811
817
  });
@@ -0,0 +1 @@
1
+ Updated 4 Dependencies @SaiRev0
@@ -0,0 +1 @@
1
+ Enable scrolling to ids via hashes in internal links @jackahl
@@ -0,0 +1 @@
1
+ Fixed maxLength validation for string type fields @pnicolli
@@ -0,0 +1 @@
1
+ bugfix : add pathname as required proptype in Blocks/Edit @akshatgarg12
@@ -0,0 +1 @@
1
+ (Fix) Select Widgets scrolls the page when the options are not visible @dobri1408
@@ -0,0 +1 @@
1
+ Read listing block schema from configuration registry @pnicolli
@@ -0,0 +1 @@
1
+ Add displayName when registering a component @sneridagh
@@ -0,0 +1 @@
1
+ Support for all default expanders (breadcrumbs, navigation, actions, types) in actions/reducers. Conditional loading of actions if the expanders are present. @sneridagh
@@ -0,0 +1 @@
1
+ Updated volto-slate to check for slateSettings before falling back to config @danalvrz
@@ -0,0 +1 @@
1
+ Add `addNewBlock` Cypress support command @sneridagh
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  }
10
10
  ],
11
11
  "license": "MIT",
12
- "version": "16.8.1",
12
+ "version": "16.9.0",
13
13
  "repository": {
14
14
  "type": "git",
15
15
  "url": "git@github.com:plone/volto.git"
@@ -281,7 +281,7 @@
281
281
  "eslint-plugin-prettier": "3.1.3",
282
282
  "eslint-plugin-react": "7.20.0",
283
283
  "eslint-plugin-react-hooks": "4.0.2",
284
- "express": "4.17.1",
284
+ "express": "4.17.3",
285
285
  "filesize": "6",
286
286
  "glob": "7.1.6",
287
287
  "hamburgers": "1.1.3",
@@ -349,6 +349,7 @@
349
349
  "react-router": "5.2.0",
350
350
  "react-router-config": "5.1.1",
351
351
  "react-router-dom": "5.2.0",
352
+ "react-router-hash-link": "2.4.3",
352
353
  "react-select": "4.3.1",
353
354
  "react-select-async-paginate": "0.5.3",
354
355
  "react-share": "2.3.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plone/volto-slate",
3
- "version": "16.8.1",
3
+ "version": "16.9.0",
4
4
  "description": "Slate.js integration with Volto",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: IDM2 A-Team",
@@ -51,6 +51,7 @@ export const DetachedTextBlockEditor = (props) => {
51
51
  value={value}
52
52
  block={block /* is this needed? */}
53
53
  debug={DEBUG}
54
+ slateSettings={props.slateSettings}
54
55
  onFocus={() => {
55
56
  if (!selected) {
56
57
  onSelectBlock(block);
@@ -262,7 +262,11 @@ class SlateEditor extends Component {
262
262
  >
263
263
  {selected ? (
264
264
  <>
265
- <InlineToolbar editor={editor} className={className} />
265
+ <InlineToolbar
266
+ editor={editor}
267
+ className={className}
268
+ slateSettings={this.props.slateSettings}
269
+ />
266
270
  {Object.keys(slateSettings.elementToolbarButtons).map(
267
271
  (t, i) => {
268
272
  return (
@@ -17,7 +17,8 @@ const InlineToolbar = (props) => {
17
17
  setShowExpandedToolbar,
18
18
  } = props;
19
19
 
20
- const { slate } = config.settings;
20
+ const slate = props.slateSettings || config.settings.slate;
21
+
21
22
  const [showMainToolbar, setShowMainToolbar] = React.useState(
22
23
  !!(editor.selection && hasRangeSelection(editor)),
23
24
  );
@@ -58,6 +59,7 @@ const InlineToolbar = (props) => {
58
59
  showExpandedToolbar={showExpandedToolbar}
59
60
  setShowExpandedToolbar={setShowExpandedToolbar}
60
61
  show={showMainToolbar}
62
+ slateSettings={slate}
61
63
  />
62
64
  <SlateContextToolbar
63
65
  editor={editor}
@@ -26,7 +26,9 @@ const SlateToolbar = (props) => {
26
26
  enableExpando = false,
27
27
  show,
28
28
  } = props;
29
- const { slate } = config.settings;
29
+
30
+ const slate = props.slateSettings || config.settings.slate;
31
+
30
32
  const { toolbarButtons, expandedToolbarButtons, buttons } = slate;
31
33
 
32
34
  function renderButton(name, index) {
@@ -52,6 +52,7 @@ export class Edit extends Component {
52
52
  onMoveBlock: PropTypes.func.isRequired,
53
53
  onDeleteBlock: PropTypes.func.isRequired,
54
54
  editable: PropTypes.bool,
55
+ pathname: PropTypes.string.isRequired,
55
56
  };
56
57
 
57
58
  /**
@@ -2,12 +2,15 @@ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { useIntl } from 'react-intl';
4
4
  import { BlockDataForm } from '@plone/volto/components';
5
- import { schemaListing } from './schema';
5
+ import config from '@plone/volto/registry';
6
6
 
7
7
  const ListingData = (props) => {
8
8
  const { data, block, onChangeBlock } = props;
9
9
  const intl = useIntl();
10
- const schema = schemaListing({ ...props, intl });
10
+ const schema = config.blocks.blocksConfig.listing.blockSchema({
11
+ ...props,
12
+ intl,
13
+ });
11
14
 
12
15
  return (
13
16
  <BlockDataForm
@@ -195,7 +195,7 @@ class SelectWidget extends Component {
195
195
  styles={customSelectStyles}
196
196
  theme={selectTheme}
197
197
  components={{ DropdownIndicator, Option }}
198
- value={value}
198
+ value={{ value: value?.value, label: indexes[value?.value]?.title }}
199
199
  onChange={(data) => {
200
200
  let dataValue = [];
201
201
  if (Array.isArray(data)) {
@@ -8,7 +8,7 @@ import PropTypes from 'prop-types';
8
8
  import { Helmet } from '@plone/volto/helpers';
9
9
  import { connect } from 'react-redux';
10
10
  import { compose } from 'redux';
11
- import { asyncConnect } from '@plone/volto/helpers';
11
+ import { asyncConnect, hasApiExpander } from '@plone/volto/helpers';
12
12
  import { defineMessages, injectIntl } from 'react-intl';
13
13
  import { Button, Grid, Menu } from 'semantic-ui-react';
14
14
  import { Portal } from 'react-portal';
@@ -475,7 +475,10 @@ export default compose(
475
475
  {
476
476
  key: 'actions',
477
477
  promise: async ({ location, store: { dispatch } }) => {
478
- await dispatch(listActions(getBaseUrl(location.pathname)));
478
+ // Do not trigger the actions action if the expander is present
479
+ if (!hasApiExpander('actions', getBaseUrl(location.pathname))) {
480
+ return await dispatch(listActions(getBaseUrl(location.pathname)));
481
+ }
479
482
  },
480
483
  },
481
484
  {
@@ -29,7 +29,12 @@ import {
29
29
  unlockContent,
30
30
  } from '@plone/volto/actions';
31
31
  import { Icon } from '@plone/volto/components';
32
- import { BodyClass, getBaseUrl, getCookieOptions } from '@plone/volto/helpers';
32
+ import {
33
+ BodyClass,
34
+ getBaseUrl,
35
+ getCookieOptions,
36
+ hasApiExpander,
37
+ } from '@plone/volto/helpers';
33
38
  import { Pluggable } from '@plone/volto/components/manage/Pluggable';
34
39
 
35
40
  import penSVG from '@plone/volto/icons/pen.svg';
@@ -197,8 +202,14 @@ class Toolbar extends Component {
197
202
  * @returns {undefined}
198
203
  */
199
204
  componentDidMount() {
200
- this.props.listActions(getBaseUrl(this.props.pathname));
201
- this.props.getTypes(getBaseUrl(this.props.pathname));
205
+ // Do not trigger the actions action if the expander is present
206
+ if (!hasApiExpander('actions', getBaseUrl(this.props.pathname))) {
207
+ this.props.listActions(getBaseUrl(this.props.pathname));
208
+ }
209
+ // Do not trigger the types action if the expander is present
210
+ if (!hasApiExpander('types', getBaseUrl(this.props.pathname))) {
211
+ this.props.getTypes(getBaseUrl(this.props.pathname));
212
+ }
202
213
  this.props.setExpandedToolbar(this.state.expanded);
203
214
  document.addEventListener('mousedown', this.handleClickOutside, false);
204
215
  }
@@ -211,8 +222,14 @@ class Toolbar extends Component {
211
222
  */
212
223
  UNSAFE_componentWillReceiveProps(nextProps) {
213
224
  if (nextProps.pathname !== this.props.pathname) {
214
- this.props.listActions(getBaseUrl(nextProps.pathname));
215
- this.props.getTypes(getBaseUrl(nextProps.pathname));
225
+ // Do not trigger the actions action if the expander is present
226
+ if (!hasApiExpander('actions', getBaseUrl(nextProps.pathname))) {
227
+ this.props.listActions(getBaseUrl(nextProps.pathname));
228
+ }
229
+ // Do not trigger the types action if the expander is present
230
+ if (!hasApiExpander('types', getBaseUrl(nextProps.pathname))) {
231
+ this.props.getTypes(getBaseUrl(nextProps.pathname));
232
+ }
216
233
  }
217
234
 
218
235
  // Unlock
@@ -5,7 +5,7 @@
5
5
 
6
6
  import React from 'react';
7
7
  import PropTypes from 'prop-types';
8
- import { Link } from 'react-router-dom';
8
+ import { HashLink as Link } from 'react-router-hash-link';
9
9
  import { useSelector } from 'react-redux';
10
10
  import {
11
11
  flattenToAppURL,
@@ -78,13 +78,13 @@ const UniversalLink = ({
78
78
  const checkedURL = URLUtils.checkAndNormalizeUrl(url);
79
79
 
80
80
  url = checkedURL.url;
81
-
82
81
  let tag = (
83
82
  <Link
84
83
  to={flattenToAppURL(url)}
85
84
  target={openLinkInNewTab ?? false ? '_blank' : null}
86
85
  title={title}
87
86
  className={className}
87
+ smooth={config.settings.hashLinkSmoothScroll}
88
88
  {...props}
89
89
  >
90
90
  {children}
@@ -307,6 +307,7 @@ class ArrayWidget extends Component {
307
307
  // react-sortable-hoc props:
308
308
  axis="xy"
309
309
  onSortEnd={this.onSortEnd}
310
+ menuShouldScrollIntoView={false}
310
311
  distance={4}
311
312
  // small fix for https://github.com/clauderic/react-sortable-hoc/pull/352:
312
313
  getHelperDimensions={({ node }) => node.getBoundingClientRect()}
@@ -210,6 +210,7 @@ class SelectWidget extends Component {
210
210
  id={`field-${id}`}
211
211
  key={choices}
212
212
  name={id}
213
+ menuShouldScrollIntoView={false}
213
214
  isDisabled={disabled}
214
215
  isSearchable={true}
215
216
  className="react-select-container"
@@ -174,6 +174,7 @@ class TokenWidget extends Component {
174
174
  <CreatableSelect
175
175
  id={`field-${this.props.id}`}
176
176
  key={this.props.id}
177
+ menuShouldScrollIntoView={false}
177
178
  isDisabled={this.props.isDisabled}
178
179
  className="react-select-container"
179
180
  classNamePrefix="react-select"
@@ -32,7 +32,13 @@ import {
32
32
  AppExtras,
33
33
  SkipLinks,
34
34
  } from '@plone/volto/components';
35
- import { BodyClass, getBaseUrl, getView, isCmsUi } from '@plone/volto/helpers';
35
+ import {
36
+ BodyClass,
37
+ getBaseUrl,
38
+ getView,
39
+ hasApiExpander,
40
+ isCmsUi,
41
+ } from '@plone/volto/helpers';
36
42
  import {
37
43
  getBreadcrumbs,
38
44
  getContent,
@@ -257,8 +263,15 @@ export default compose(
257
263
  asyncConnect([
258
264
  {
259
265
  key: 'breadcrumbs',
260
- promise: ({ location, store: { dispatch } }) =>
261
- __SERVER__ && dispatch(getBreadcrumbs(getBaseUrl(location.pathname))),
266
+ promise: ({ location, store: { dispatch } }) => {
267
+ // Do not trigger the breadcrumbs action if the expander is present
268
+ if (
269
+ __SERVER__ &&
270
+ !hasApiExpander('breadcrumbs', getBaseUrl(location.pathname))
271
+ ) {
272
+ return dispatch(getBreadcrumbs(getBaseUrl(location.pathname)));
273
+ }
274
+ },
262
275
  },
263
276
  {
264
277
  key: 'content',
@@ -267,19 +280,32 @@ export default compose(
267
280
  },
268
281
  {
269
282
  key: 'navigation',
270
- promise: ({ location, store: { dispatch } }) =>
271
- __SERVER__ &&
272
- dispatch(
273
- getNavigation(
274
- getBaseUrl(location.pathname),
275
- config.settings.navDepth,
276
- ),
277
- ),
283
+ promise: ({ location, store: { dispatch } }) => {
284
+ // Do not trigger the navigation action if the expander is present
285
+ if (
286
+ __SERVER__ &&
287
+ !hasApiExpander('navigation', getBaseUrl(location.pathname))
288
+ ) {
289
+ return dispatch(
290
+ getNavigation(
291
+ getBaseUrl(location.pathname),
292
+ config.settings.navDepth,
293
+ ),
294
+ );
295
+ }
296
+ },
278
297
  },
279
298
  {
280
299
  key: 'types',
281
- promise: ({ location, store: { dispatch } }) =>
282
- __SERVER__ && dispatch(getTypes(getBaseUrl(location.pathname))),
300
+ promise: ({ location, store: { dispatch } }) => {
301
+ // Do not trigger the types action if the expander is present
302
+ if (
303
+ __SERVER__ &&
304
+ !hasApiExpander('types', getBaseUrl(location.pathname))
305
+ ) {
306
+ return dispatch(getTypes(getBaseUrl(location.pathname)));
307
+ }
308
+ },
283
309
  },
284
310
  {
285
311
  key: 'workflow',
@@ -24,6 +24,7 @@ import {
24
24
  getBaseUrl,
25
25
  flattenToAppURL,
26
26
  getLayoutFieldname,
27
+ hasApiExpander,
27
28
  } from '@plone/volto/helpers';
28
29
 
29
30
  import config from '@plone/volto/registry';
@@ -118,7 +119,10 @@ class View extends Component {
118
119
  };
119
120
 
120
121
  componentDidMount() {
121
- this.props.listActions(getBaseUrl(this.props.pathname));
122
+ // Do not trigger the actions action if the expander is present
123
+ if (!hasApiExpander('actions', getBaseUrl(this.props.pathname))) {
124
+ this.props.listActions(getBaseUrl(this.props.pathname));
125
+ }
122
126
  this.props.getContent(
123
127
  getBaseUrl(this.props.pathname),
124
128
  this.props.versionId,
@@ -134,7 +138,10 @@ class View extends Component {
134
138
  */
135
139
  UNSAFE_componentWillReceiveProps(nextProps) {
136
140
  if (nextProps.pathname !== this.props.pathname) {
137
- this.props.listActions(getBaseUrl(nextProps.pathname));
141
+ // Do not trigger the actions action if the expander is present
142
+ if (!hasApiExpander('actions', getBaseUrl(nextProps.pathname))) {
143
+ this.props.listActions(getBaseUrl(nextProps.pathname));
144
+ }
138
145
  this.props.getContent(
139
146
  getBaseUrl(nextProps.pathname),
140
147
  this.props.versionId,
@@ -75,11 +75,18 @@ let config = {
75
75
  // The URL Volto is going to be served (see sensible defaults above)
76
76
  publicURL,
77
77
  apiPath,
78
- apiExpanders: [],
78
+ apiExpanders: [
79
+ // Add the following expanders for only issuing a single request.
80
+ // https://6.docs.plone.org/volto/configuration/settings-reference.html#term-apiExpanders
81
+ // {
82
+ // match: '',
83
+ // GET_CONTENT: ['breadcrumbs', 'navigation', 'actions', 'types'],
84
+ // },
85
+ ],
79
86
  // Internal proxy to bypass CORS *while developing*. NOT intended for production use.
80
87
  // In production is recommended you use a Seamless mode deployment using a web server in
81
88
  // front of both the frontend and the backend so you can bypass CORS safely.
82
- // https://docs.voltocms.com/deploying/seamless-mode/
89
+ // https://6.docs.plone.org/volto/deploying/seamless-mode.html
83
90
  devProxyToApiPath:
84
91
  process.env.RAZZLE_DEV_PROXY_API_PATH ||
85
92
  process.env.RAZZLE_API_PATH ||
@@ -169,6 +176,7 @@ let config = {
169
176
  workflowMapping,
170
177
  errorHandlers: [], // callables for unhandled errors
171
178
  styleClassNameConverters,
179
+ hashLinkSmoothScroll: false,
172
180
  styleClassNameExtenders,
173
181
  },
174
182
  experimental: {
@@ -4,27 +4,29 @@ import { messages } from '../MessageLabels/MessageLabels';
4
4
  /**
5
5
  * Will return the intl message if invalid
6
6
  * @param {boolean} isValid
7
- * @param {string} maxCriterion
7
+ * @param {string} criterion
8
8
  * @param {string | number} valueToCompare can compare '47' < 50
9
9
  * @param {Function} intlFunc
10
10
  */
11
- const validationMessage = (isValid, maxCriterion, valueToCompare, intlFunc) =>
11
+ const validationMessage = (isValid, criterion, valueToCompare, intlFunc) =>
12
12
  !isValid
13
- ? intlFunc(messages[maxCriterion], {
13
+ ? intlFunc(messages[criterion], {
14
14
  len: valueToCompare,
15
15
  })
16
16
  : null;
17
+
17
18
  /**
18
19
  * Returns if based on the criterion the value is lower or equal
19
20
  * @param {string | number} value can compare '47' < 50
20
21
  * @param {string | number} valueToCompare can compare '47' < 50
21
- * @param {string} minCriterion
22
+ * @param {string} maxCriterion
22
23
  * @param {Function} intlFunc
23
24
  */
24
- const isMaxPropertyValid = (value, valueToCompare, minCriterion, intlFunc) => {
25
+ const isMaxPropertyValid = (value, valueToCompare, maxCriterion, intlFunc) => {
25
26
  const isValid = valueToCompare !== undefined ? value <= valueToCompare : true;
26
- return validationMessage(isValid, minCriterion, valueToCompare, intlFunc);
27
+ return validationMessage(isValid, maxCriterion, valueToCompare, intlFunc);
27
28
  };
29
+
28
30
  /**
29
31
  * Returns if based on the criterion the value is higher or equal
30
32
  * @param {string | number} value can compare '47' < 50
@@ -32,9 +34,9 @@ const isMaxPropertyValid = (value, valueToCompare, minCriterion, intlFunc) => {
32
34
  * @param {string} minCriterion
33
35
  * @param {Function} intlFunc
34
36
  */
35
- const isMinPropertyValid = (value, valueToCompare, maxCriterion, intlFunc) => {
37
+ const isMinPropertyValid = (value, valueToCompare, minCriterion, intlFunc) => {
36
38
  const isValid = valueToCompare !== undefined ? value >= valueToCompare : true;
37
- return validationMessage(isValid, maxCriterion, valueToCompare, intlFunc);
39
+ return validationMessage(isValid, minCriterion, valueToCompare, intlFunc);
38
40
  };
39
41
 
40
42
  const widgetValidation = {
@@ -109,7 +111,7 @@ const widgetValidation = {
109
111
  maxLength: (value, itemObj, intlFunc) =>
110
112
  isMaxPropertyValid(
111
113
  value.length,
112
- itemObj.maxLengthj,
114
+ itemObj.maxLength,
113
115
  'maxLength',
114
116
  intlFunc,
115
117
  ),
@@ -27,7 +27,10 @@ class ScrollToTop extends React.Component {
27
27
  * @memberof ScrollToTop
28
28
  */
29
29
  componentDidUpdate(prevProps) {
30
- if (this.props.location?.pathname !== prevProps.location?.pathname) {
30
+ if (
31
+ !this.props.location?.pathname.hash &&
32
+ this.props.location?.pathname !== prevProps.location?.pathname
33
+ ) {
31
34
  window.scrollTo(0, 0);
32
35
  }
33
36
  }
@@ -208,9 +208,11 @@ export const toLangUnderscoreRegion = (language) => {
208
208
  };
209
209
 
210
210
  /**
211
- * Lookup if a given expander is set in apiExpanders
212
- * @param {string} language Language to be normalized
213
- * @returns {string} Language normalized
211
+ * Lookup if a given expander is set in apiExpanders for the given path and action type
212
+ * @param {string} expander The id literal of the expander eg. `navigation`
213
+ * @param {string} path The path (no URL) to check if the expander has effect
214
+ * @param {string} type The Redux action type
215
+ * @returns {boolean} Return if the expander is present for the path and the type given
214
216
  */
215
217
  export const hasApiExpander = (expander, path = '', type = 'GET_CONTENT') => {
216
218
  return flatten(