@plone/volto 16.13.0 → 17.0.0-alpha.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 (66) hide show
  1. package/.changelog.draft +12 -11
  2. package/.storybook/main.js +53 -69
  3. package/.yarn/install-state.gz +0 -0
  4. package/CHANGELOG.md +33 -0
  5. package/README.md +21 -19
  6. package/cypress/support/commands.js +7 -7
  7. package/cypress/support/guillotina.js +2 -2
  8. package/cypress/support/reset-fixture.js +2 -2
  9. package/cypress/support/upgradetests.js +1 -1
  10. package/cypress.config.js +1 -1
  11. package/docker-compose.yml +2 -3
  12. package/locales/ca/LC_MESSAGES/volto.po +30 -0
  13. package/locales/ca.json +1 -1
  14. package/locales/de/LC_MESSAGES/volto.po +30 -0
  15. package/locales/de.json +1 -1
  16. package/locales/en/LC_MESSAGES/volto.po +30 -0
  17. package/locales/en.json +1 -1
  18. package/locales/es/LC_MESSAGES/volto.po +30 -0
  19. package/locales/es.json +1 -1
  20. package/locales/eu/LC_MESSAGES/volto.po +30 -0
  21. package/locales/eu.json +1 -1
  22. package/locales/fi.json +1 -1
  23. package/locales/fr/LC_MESSAGES/volto.po +30 -0
  24. package/locales/fr.json +1 -1
  25. package/locales/it/LC_MESSAGES/volto.po +30 -0
  26. package/locales/it.json +1 -1
  27. package/locales/ja/LC_MESSAGES/volto.po +30 -0
  28. package/locales/ja.json +1 -1
  29. package/locales/nl/LC_MESSAGES/volto.po +30 -0
  30. package/locales/nl.json +1 -1
  31. package/locales/pt/LC_MESSAGES/volto.po +30 -0
  32. package/locales/pt.json +1 -1
  33. package/locales/pt_BR/LC_MESSAGES/volto.po +31 -1
  34. package/locales/pt_BR.json +1 -1
  35. package/locales/ro/LC_MESSAGES/volto.po +30 -0
  36. package/locales/ro.json +1 -1
  37. package/locales/volto.pot +31 -1
  38. package/locales/zh_CN/LC_MESSAGES/volto.po +30 -0
  39. package/locales/zh_CN.json +1 -1
  40. package/package.json +22 -20
  41. package/packages/volto-slate/package.json +1 -1
  42. package/razzle.config.js +3 -3
  43. package/src/components/manage/Blocks/Teaser/Body.jsx +30 -0
  44. package/src/components/manage/Blocks/Teaser/Data.jsx +71 -0
  45. package/src/components/manage/Blocks/Teaser/DefaultBody.jsx +89 -0
  46. package/src/components/manage/Blocks/Teaser/Edit.jsx +25 -0
  47. package/src/components/manage/Blocks/Teaser/View.jsx +9 -0
  48. package/src/components/manage/Blocks/Teaser/adapter.js +23 -0
  49. package/src/components/manage/Blocks/Teaser/schema.js +103 -0
  50. package/src/components/manage/Blocks/Teaser/utils.js +44 -0
  51. package/src/components/manage/Blocks/Teaser/utils.test.jsx +229 -0
  52. package/src/components/manage/Controlpanels/VersionOverview.jsx +6 -10
  53. package/src/components/manage/Diff/DiffField.jsx +6 -6
  54. package/src/components/theme/FormattedDate/FormattedDate.jsx +3 -3
  55. package/src/config/Blocks.jsx +28 -0
  56. package/src/express-middleware/sitemap.js +1 -1
  57. package/src/helpers/Blocks/Blocks.test.js +50 -0
  58. package/src/helpers/Utils/Date.js +4 -2
  59. package/src/helpers/Utils/Date.test.js +3 -1
  60. package/src/helpers/index.js +0 -1
  61. package/theme/themes/pastanaga/extras/blocks.less +2 -0
  62. package/theme/themes/pastanaga/extras/teaser.less +166 -0
  63. package/webpack-plugins/webpack-relative-resolver.js +33 -19
  64. package/webpack-plugins/webpack-root-resolver.js +25 -14
  65. package/webpack-plugins/webpack-svg-plugin.js +11 -4
  66. package/locales/fi/LC_MESSAGES/volto.po +0 -4581
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import TeaserBody from './Body';
3
+ import { withBlockExtensions } from '@plone/volto/helpers';
4
+
5
+ const TeaserView = (props) => {
6
+ return <TeaserBody {...props} />;
7
+ };
8
+
9
+ export default withBlockExtensions(TeaserView);
@@ -0,0 +1,23 @@
1
+ import { isEmpty } from 'lodash';
2
+
3
+ export const TeaserBlockDataAdapter = ({
4
+ block,
5
+ data,
6
+ id,
7
+ onChangeBlock,
8
+ value,
9
+ }) => {
10
+ let dataSaved = {
11
+ ...data,
12
+ [id]: value,
13
+ };
14
+ if (id === 'href' && !isEmpty(value) && !data.title && !data.description) {
15
+ dataSaved = {
16
+ ...dataSaved,
17
+ title: value[0].Title,
18
+ description: value[0].Description,
19
+ head_title: value[0].head_title,
20
+ };
21
+ }
22
+ onChangeBlock(block, dataSaved);
23
+ };
@@ -0,0 +1,103 @@
1
+ import { defineMessages } from 'react-intl';
2
+ import { addStyling } from '@plone/volto/helpers/Extensions/withBlockSchemaEnhancer';
3
+
4
+ const messages = defineMessages({
5
+ Target: {
6
+ id: 'Target',
7
+ defaultMessage: 'Target',
8
+ },
9
+ imageOverride: {
10
+ id: 'Image override',
11
+ defaultMessage: 'Image override',
12
+ },
13
+ openLinkInNewTab: {
14
+ id: 'Open in a new tab',
15
+ defaultMessage: 'Open in a new tab',
16
+ },
17
+ title: {
18
+ id: 'Title',
19
+ defaultMessage: 'Title',
20
+ },
21
+ description: {
22
+ id: 'Description',
23
+ defaultMessage: 'Description',
24
+ },
25
+ head_title: {
26
+ id: 'head_title',
27
+ defaultMessage: 'Head title',
28
+ },
29
+ teaser: {
30
+ id: 'Teaser',
31
+ defaultMessage: 'Teaser',
32
+ },
33
+ align: {
34
+ id: 'Alignment',
35
+ defaultMessage: 'Alignment',
36
+ },
37
+ });
38
+
39
+ export const TeaserSchema = ({ intl }) => {
40
+ const schema = {
41
+ title: intl.formatMessage(messages.teaser),
42
+ fieldsets: [
43
+ {
44
+ id: 'default',
45
+ title: 'Default',
46
+ fields: ['href', 'title', 'head_title', 'description', 'preview_image'],
47
+ },
48
+ ],
49
+
50
+ properties: {
51
+ href: {
52
+ title: intl.formatMessage(messages.Target),
53
+ widget: 'object_browser',
54
+ mode: 'link',
55
+ selectedItemAttrs: [
56
+ 'Title',
57
+ 'head_title',
58
+ 'Description',
59
+ 'hasPreviewImage',
60
+ 'image_field',
61
+ 'image_scales',
62
+ '@type',
63
+ ],
64
+ allowExternals: true,
65
+ },
66
+ title: {
67
+ title: intl.formatMessage(messages.title),
68
+ },
69
+ head_title: {
70
+ title: intl.formatMessage(messages.head_title),
71
+ },
72
+ description: {
73
+ title: intl.formatMessage(messages.description),
74
+ widget: 'textarea',
75
+ },
76
+ preview_image: {
77
+ title: intl.formatMessage(messages.imageOverride),
78
+ widget: 'object_browser',
79
+ mode: 'image',
80
+ allowExternals: true,
81
+ selectedItemAttrs: ['image_field', 'image_scales'],
82
+ },
83
+ openLinkInNewTab: {
84
+ title: intl.formatMessage(messages.openLinkInNewTab),
85
+ type: 'boolean',
86
+ },
87
+ },
88
+ required: [],
89
+ };
90
+
91
+ addStyling({ schema, intl });
92
+
93
+ schema.properties.styles.schema.properties.align = {
94
+ widget: 'align',
95
+ title: intl.formatMessage(messages.align),
96
+ actions: ['left', 'right', 'center'],
97
+ default: 'left',
98
+ };
99
+
100
+ schema.properties.styles.schema.fieldsets[0].fields = ['align'];
101
+
102
+ return schema;
103
+ };
@@ -0,0 +1,44 @@
1
+ import { isInternalURL } from '@plone/volto/helpers';
2
+ import config from '@plone/volto/registry';
3
+
4
+ export function getTeaserImageURL({ href, image, align }) {
5
+ // The default scale used in teasers is the 'teaser' scale
6
+ // except if it's customized otherwise in the teaser block settings
7
+ // or if the teaser is center (top)
8
+ const imageScale =
9
+ align === 'center'
10
+ ? 'great'
11
+ : config.blocks.blocksConfig['teaser'].imageScale || 'teaser';
12
+
13
+ if (image) {
14
+ // If the image is overriden locally in the teaser block
15
+ if (isInternalURL(image['@id'])) {
16
+ // If it's internal check if image_scales catalog info is present
17
+ if (image?.image_scales?.[image?.image_field]) {
18
+ return `${image['@id']}/${
19
+ image.image_scales[image.image_field]?.[0].scales[imageScale]
20
+ ?.download || image.image_scales[image.image_field]?.[0].download
21
+ }`;
22
+ } else {
23
+ // If not, fallback to content scale URL shortcut
24
+ return `${image['@id']}/@@images/${image.image_field}/${imageScale}`;
25
+ }
26
+ } else {
27
+ // If it's external, return the plain URL
28
+ return image['@id'];
29
+ }
30
+ } else {
31
+ // If the image is not overriden
32
+ if (href?.image_scales?.[href?.image_field]) {
33
+ return `${href['@id']}/${
34
+ href.image_scales[href.image_field]?.[0].scales[imageScale]?.download ||
35
+ href.image_scales[href.image_field]?.[0].download
36
+ }`;
37
+ } else {
38
+ // If not, fallback to content scale URL shortcut
39
+ return `${href['@id']}/@@images/${
40
+ href.image_field || 'preview_image'
41
+ }/${imageScale}`;
42
+ }
43
+ }
44
+ }
@@ -0,0 +1,229 @@
1
+ import { getTeaserImageURL } from './utils';
2
+ import config from '@plone/volto/registry';
3
+
4
+ beforeAll(() => {
5
+ config.blocks.blocksConfig.teaser = {};
6
+ config.blocks.blocksConfig.teaser.imageScale = 'teaser';
7
+ });
8
+
9
+ describe('getTeaserImageURL tests', () => {
10
+ it('getTeaserImageURL internal URL - no overriden', () => {
11
+ const align = 'left';
12
+ const href = {
13
+ '@id': '/document',
14
+ image_field: 'preview_image',
15
+ image_scales: {
16
+ preview_image: [
17
+ {
18
+ download: '@@images/default_original_URL',
19
+ scales: {
20
+ teaser: {
21
+ download: '@@images/teaser_scale_URL',
22
+ },
23
+ },
24
+ },
25
+ ],
26
+ },
27
+ };
28
+ const image = undefined;
29
+ expect(getTeaserImageURL({ href, image, align })).toBe(
30
+ '/document/@@images/teaser_scale_URL',
31
+ );
32
+ });
33
+
34
+ it('getTeaserImageURL internal URL - no overriden - no scale', () => {
35
+ const align = 'left';
36
+ const href = {
37
+ '@id': '/document',
38
+ image_field: 'preview_image',
39
+ image_scales: {
40
+ preview_image: [
41
+ {
42
+ download: '@@images/default_original_URL',
43
+ scales: {},
44
+ },
45
+ ],
46
+ },
47
+ };
48
+ const image = undefined;
49
+ expect(getTeaserImageURL({ href, image, align })).toBe(
50
+ '/document/@@images/default_original_URL',
51
+ );
52
+ });
53
+
54
+ it('getTeaserImageURL internal URL - no overriden - no catalog image info', () => {
55
+ const align = 'left';
56
+ const href = {
57
+ '@id': '/document',
58
+ image_field: 'image',
59
+ image_scales: {
60
+ preview_image: [
61
+ {
62
+ download: '@@images/default_original_URL',
63
+ scales: {},
64
+ },
65
+ ],
66
+ },
67
+ };
68
+ const image = undefined;
69
+ expect(getTeaserImageURL({ href, image, align })).toBe(
70
+ '/document/@@images/image/teaser',
71
+ );
72
+ });
73
+
74
+ it('getTeaserImageURL internal URL - no overriden - center', () => {
75
+ const align = 'center';
76
+ const href = {
77
+ '@id': '/document',
78
+ image_field: 'preview_image',
79
+ image_scales: {
80
+ preview_image: [
81
+ {
82
+ download: '@@images/default_original_URL',
83
+ scales: {
84
+ great: {
85
+ download: '@@images/great_scale_URL',
86
+ },
87
+ teaser: {
88
+ download: '@@images/teaser_scale_URL',
89
+ },
90
+ },
91
+ },
92
+ ],
93
+ },
94
+ };
95
+ const image = undefined;
96
+ expect(getTeaserImageURL({ href, image, align })).toBe(
97
+ '/document/@@images/great_scale_URL',
98
+ );
99
+ });
100
+
101
+ it('getTeaserImageURL internal URL - no overriden - center - no great scale', () => {
102
+ const align = 'center';
103
+ const href = {
104
+ '@id': '/document',
105
+ image_field: 'preview_image',
106
+ image_scales: {
107
+ preview_image: [
108
+ {
109
+ download: '@@images/default_original_URL',
110
+ scales: {
111
+ teaser: {
112
+ download: '@@images/teaser_scale_URL',
113
+ },
114
+ },
115
+ },
116
+ ],
117
+ },
118
+ };
119
+ const image = undefined;
120
+ expect(getTeaserImageURL({ href, image, align })).toBe(
121
+ '/document/@@images/default_original_URL',
122
+ );
123
+ });
124
+
125
+ it('getTeaserImageURL internal URL - image overriden', () => {
126
+ const align = 'left';
127
+ const href = {
128
+ '@id': '/document',
129
+ image_field: 'preview_image',
130
+ image_scales: {
131
+ preview_image: [
132
+ {
133
+ download: '@@images/default_original_URL',
134
+ scales: {
135
+ teaser: {
136
+ download: '@@images/teaser_scale_URL',
137
+ },
138
+ },
139
+ },
140
+ ],
141
+ },
142
+ };
143
+ const image = {
144
+ '@id': '/document/image',
145
+ image_field: 'image',
146
+ image_scales: {
147
+ image: [
148
+ {
149
+ download: '@@images/overriden_image_default_original_URL',
150
+ scales: {
151
+ teaser: {
152
+ download: '@@images/overriden_image_teaser_scale_URL',
153
+ },
154
+ },
155
+ },
156
+ ],
157
+ },
158
+ };
159
+ expect(getTeaserImageURL({ href, image, align })).toBe(
160
+ '/document/image/@@images/overriden_image_teaser_scale_URL',
161
+ );
162
+ });
163
+
164
+ it('getTeaserImageURL internal URL - image overriden - center - no great scale', () => {
165
+ const align = 'center';
166
+ const href = {
167
+ '@id': '/document',
168
+ image_field: 'preview_image',
169
+ image_scales: {
170
+ preview_image: [
171
+ {
172
+ download: '@@images/default_original_URL',
173
+ scales: {
174
+ teaser: {
175
+ download: '@@images/teaser_scale_URL',
176
+ },
177
+ },
178
+ },
179
+ ],
180
+ },
181
+ };
182
+ const image = {
183
+ '@id': '/document/image',
184
+ image_field: 'image',
185
+ image_scales: {
186
+ image: [
187
+ {
188
+ download: '@@images/overriden_image_default_original_URL',
189
+ scales: {
190
+ teaser: {
191
+ download: '@@images/overriden_image_teaser_scale_URL',
192
+ },
193
+ },
194
+ },
195
+ ],
196
+ },
197
+ };
198
+ expect(getTeaserImageURL({ href, image, align })).toBe(
199
+ '/document/image/@@images/overriden_image_default_original_URL',
200
+ );
201
+ });
202
+
203
+ it('getTeaserImageURL internal URL - image overriden - external', () => {
204
+ const align = 'left';
205
+ const href = {
206
+ '@id': '/document',
207
+ image_field: 'preview_image',
208
+ image_scales: {
209
+ preview_image: [
210
+ {
211
+ download: '@@images/default_original_URL',
212
+ scales: {
213
+ teaser: {
214
+ download: '@@images/teaser_scale_URL',
215
+ },
216
+ },
217
+ },
218
+ ],
219
+ },
220
+ };
221
+ const image = {
222
+ '@id': 'https://plone.org/document/image.png',
223
+ };
224
+
225
+ expect(getTeaserImageURL({ href, image, align })).toBe(
226
+ 'https://plone.org/document/image.png',
227
+ );
228
+ });
229
+ });
@@ -7,14 +7,8 @@ import React from 'react';
7
7
  import { FormattedMessage } from 'react-intl';
8
8
  import { isEmpty } from 'lodash';
9
9
 
10
- import {
11
- version as voltoVersion,
12
- name as voltoName,
13
- } from '../../../../package.json';
14
- import {
15
- version as projectVersion,
16
- name as projectName,
17
- } from '@root/../package.json';
10
+ import voltoPackageJson from '../../../../package.json';
11
+ import projectPackageJson from '@root/../package.json';
18
12
 
19
13
  import { defineMessages, useIntl } from 'react-intl';
20
14
  import config from '@plone/volto/registry';
@@ -26,6 +20,8 @@ const messages = defineMessages({
26
20
  },
27
21
  });
28
22
 
23
+ const voltoVersion = voltoPackageJson.version;
24
+
29
25
  const VersionOverview = ({
30
26
  cmf_version,
31
27
  debug_mode,
@@ -37,7 +33,7 @@ const VersionOverview = ({
37
33
  }) => {
38
34
  const intl = useIntl();
39
35
  const { addonsInfo } = config.settings;
40
- const isProject = voltoName !== projectName;
36
+ const isProject = voltoPackageJson.name !== projectPackageJson.name;
41
37
 
42
38
  return (
43
39
  <>
@@ -50,7 +46,7 @@ const VersionOverview = ({
50
46
  >
51
47
  {isProject ? (
52
48
  <li>
53
- {projectName} {projectVersion}
49
+ {projectPackageJson.name} {projectPackageJson.version}
54
50
  </li>
55
51
  ) : null}
56
52
  {voltoVersion && <li>Volto {voltoVersion}</li>}
@@ -61,12 +61,12 @@ const DiffField = ({
61
61
  break;
62
62
  case 'datetime':
63
63
  parts = diffWords(
64
- new Intl.DateTimeFormat(language, readable_date_format).format(
65
- new Date(one),
66
- ),
67
- new Intl.DateTimeFormat(language, readable_date_format).format(
68
- new Date(two),
69
- ),
64
+ new Intl.DateTimeFormat(language, readable_date_format)
65
+ .format(new Date(one))
66
+ .replace('\u202F', ' '),
67
+ new Intl.DateTimeFormat(language, readable_date_format)
68
+ .format(new Date(two))
69
+ .replace('\u202F', ' '),
70
70
  );
71
71
  break;
72
72
  case 'json':
@@ -23,9 +23,9 @@ const FormattedDate = ({
23
23
  <time
24
24
  className={className}
25
25
  dateTime={date}
26
- title={new Intl.DateTimeFormat(language, long_date_format).format(
27
- new Date(toDate(date)),
28
- )}
26
+ title={new Intl.DateTimeFormat(language, long_date_format)
27
+ .format(new Date(toDate(date)))
28
+ .replace('\u202F', ' ')}
29
29
  >
30
30
  {children
31
31
  ? children(
@@ -42,6 +42,7 @@ import tableSVG from '@plone/volto/icons/table.svg';
42
42
  import listingBlockSVG from '@plone/volto/icons/content-listing.svg';
43
43
  import tocSVG from '@plone/volto/icons/list-bullet.svg';
44
44
  import searchSVG from '@plone/volto/icons/zoom.svg';
45
+ import imagesSVG from '@plone/volto/icons/images.svg';
45
46
 
46
47
  import ImageGalleryListingBlockTemplate from '@plone/volto/components/manage/Blocks/Listing/ImageGallery';
47
48
  import BlockSettingsSchema from '@plone/volto/components/manage/Blocks/Block/Schema';
@@ -73,6 +74,12 @@ import SearchBlockSchema from '@plone/volto/components/manage/Blocks/Search/sche
73
74
 
74
75
  import ToCVariations from '@plone/volto/components/manage/Blocks/ToC/variations';
75
76
 
77
+ import TeaserViewBlock from '@plone/volto/components/manage/Blocks/Teaser/View';
78
+ import TeaserEditBlock from '@plone/volto/components/manage/Blocks/Teaser/Edit';
79
+ import TeaserBlockDefaultBody from '@plone/volto/components/manage/Blocks/Teaser/DefaultBody';
80
+ import { TeaserSchema } from '@plone/volto/components/manage/Blocks/Teaser/schema';
81
+ import { TeaserBlockDataAdapter } from '@plone/volto/components/manage/Blocks/Teaser/adapter';
82
+
76
83
  defineMessages({
77
84
  title: {
78
85
  id: 'title',
@@ -451,6 +458,27 @@ const blocksConfig = {
451
458
  },
452
459
  },
453
460
  },
461
+ teaser: {
462
+ id: 'teaser',
463
+ title: 'Teaser',
464
+ icon: imagesSVG,
465
+ group: 'common',
466
+ view: TeaserViewBlock,
467
+ edit: TeaserEditBlock,
468
+ restricted: false,
469
+ mostUsed: true,
470
+ sidebarTab: 1,
471
+ blockSchema: TeaserSchema,
472
+ dataAdapter: TeaserBlockDataAdapter,
473
+ variations: [
474
+ {
475
+ id: 'default',
476
+ isDefault: true,
477
+ title: 'Default',
478
+ template: TeaserBlockDefaultBody,
479
+ },
480
+ ],
481
+ },
454
482
  };
455
483
 
456
484
  const requiredBlocks = ['title'];
@@ -1,5 +1,5 @@
1
1
  import express from 'express';
2
- import { generateSitemap } from '@plone/volto/helpers';
2
+ import { generateSitemap } from '@plone/volto/helpers/Sitemap/Sitemap';
3
3
 
4
4
  export const sitemap = function (req, res, next) {
5
5
  generateSitemap(req).then((sitemap) => {
@@ -744,6 +744,56 @@ describe('Blocks', () => {
744
744
  },
745
745
  });
746
746
  });
747
+
748
+ it('Sets data according to schema default values, keeps existing data', () => {
749
+ const schema = {
750
+ properties: {
751
+ style: {
752
+ widget: 'object',
753
+ schema: {
754
+ title: 'Style',
755
+ fieldsets: [
756
+ {
757
+ id: 'default',
758
+ fields: ['color', 'theme'],
759
+ title: 'Default',
760
+ },
761
+ ],
762
+ properties: {
763
+ color: {
764
+ title: 'Color',
765
+ default: 'red',
766
+ },
767
+ theme: {
768
+ title: 'Theme',
769
+ default: 'primary',
770
+ },
771
+ },
772
+ required: [],
773
+ },
774
+ },
775
+ },
776
+ };
777
+
778
+ expect(
779
+ applySchemaDefaults({
780
+ schema,
781
+ data: {
782
+ '@type': 'slider',
783
+ style: {
784
+ theme: 'secondary',
785
+ },
786
+ },
787
+ intl: {},
788
+ }),
789
+ ).toEqual({
790
+ '@type': 'slider',
791
+ style: {
792
+ color: 'red',
793
+ theme: 'secondary',
794
+ },
795
+ });
796
+ });
747
797
  });
748
798
 
749
799
  describe('applyBlockDefaults', () => {
@@ -48,7 +48,9 @@ export function formatDate({
48
48
  : short_date_format;
49
49
 
50
50
  const formatter = new Intl.DateTimeFormat(locale, format);
51
- return formatToParts ? formatter.formatToParts(date) : formatter.format(date);
51
+ return formatToParts
52
+ ? formatter.formatToParts(date)
53
+ : formatter.format(date).replace('\u202F', ' ');
52
54
  }
53
55
 
54
56
  export function formatRelativeDate({
@@ -93,5 +95,5 @@ export function formatRelativeDate({
93
95
  ? ''
94
96
  : formatToParts
95
97
  ? formatter.formatToParts(v, tag)
96
- : formatter.format(v, tag); // use "now" ?
98
+ : formatter.format(v, tag).replace('\u202F', ' '); // use "now" ?
97
99
  }
@@ -192,6 +192,8 @@ describe('formatRelativeDate helper', () => {
192
192
  it('can use alternate style narrow', () => {
193
193
  const now = Date.now();
194
194
  const d = new Date(now + 3 * MONTH);
195
- expect(formatRelativeDate({ date: d, style: 'narrow' })).toBe('in 3 mo.');
195
+ expect(['in 3 mo.', 'in 3mo']).toContain(
196
+ formatRelativeDate({ date: d, style: 'narrow' }),
197
+ );
196
198
  });
197
199
  });
@@ -30,7 +30,6 @@ export {
30
30
  removeProtocol,
31
31
  URLUtils,
32
32
  } from '@plone/volto/helpers/Url/Url';
33
- export { generateSitemap } from '@plone/volto/helpers/Sitemap/Sitemap';
34
33
  export { generateRobots } from '@plone/volto/helpers/Robots/Robots';
35
34
  export {
36
35
  nestContent,
@@ -1176,3 +1176,5 @@ body.has-toolbar.has-sidebar-collapsed .ui.wrapper > .ui.inner.block.full {
1176
1176
  }
1177
1177
  }
1178
1178
  }
1179
+
1180
+ @import 'teaser';