@plone/volto 19.3.0 → 19.4.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.
- package/CHANGELOG.md +23 -0
- package/package.json +4 -4
- package/src/components/manage/Toolbar/Toolbar.jsx +2 -3
- package/src/components/manage/Toolbar/UserAvatar.test.tsx +72 -0
- package/src/components/manage/Toolbar/UserAvatar.tsx +27 -0
- package/src/components/theme/Search/Search.jsx +9 -1
- package/src/components/theme/View/NewsItemView.jsx +5 -3
- package/types/components/manage/Toolbar/UserAvatar.d.ts +17 -0
- package/types/components/theme/View/NewsItemView.d.ts +1 -3
- package/types/config/Views.d.ts +1 -3
package/CHANGELOG.md
CHANGED
|
@@ -17,6 +17,29 @@ myst:
|
|
|
17
17
|
|
|
18
18
|
<!-- towncrier release notes start -->
|
|
19
19
|
|
|
20
|
+
## 19.4.0 (2026-09-03)
|
|
21
|
+
|
|
22
|
+
### Feature
|
|
23
|
+
|
|
24
|
+
- Added a `UserAvatar` component, used by the toolbar to render the signed-in user's avatar. Add-ons can now change that avatar by shadowing this one small component, instead of shadowing the whole `Toolbar`. @ericof [#8404](https://github.com/plone/volto/issues/8404)
|
|
25
|
+
- Adding quanta support with semanticUI fallback for seach container. @TimoBroeskamp [#8411](https://github.com/plone/volto/issues/8411)
|
|
26
|
+
|
|
27
|
+
### Bugfix
|
|
28
|
+
|
|
29
|
+
- Fixed cursor position lost when clicking on a Slate block in edit, causing the cursor to jump to the start of the text. @wesleybl [#8402](https://github.com/plone/volto/issues/8402)
|
|
30
|
+
|
|
31
|
+
## 19.3.1 (2026-08-26)
|
|
32
|
+
|
|
33
|
+
### Bugfix
|
|
34
|
+
|
|
35
|
+
- Fix path used for rendering blocks in the `NewsItemView`. @TimoBroeskamp [#8397](https://github.com/plone/volto/issues/8397)
|
|
36
|
+
|
|
37
|
+
### Internal
|
|
38
|
+
|
|
39
|
+
- Added support for the `.chore` extension for a change log entry. This satisfies the requirement of its presence, but doesn't display them in the change log. @stevepiercy [#8401](https://github.com/plone/volto/issues/8401)
|
|
40
|
+
- Remove deprecated and redundant Read the Docs pull request preview workflow. @stevepiercy
|
|
41
|
+
- Remove redundant and deprecated pull request preview build workflow. @stevepiercy
|
|
42
|
+
|
|
20
43
|
## 19.3.0 (2026-07-22)
|
|
21
44
|
|
|
22
45
|
### Feature
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
}
|
|
10
10
|
],
|
|
11
11
|
"license": "MIT",
|
|
12
|
-
"version": "19.
|
|
12
|
+
"version": "19.4.0",
|
|
13
13
|
"repository": {
|
|
14
14
|
"type": "git",
|
|
15
15
|
"url": "git@github.com:plone/volto.git"
|
|
@@ -176,9 +176,9 @@
|
|
|
176
176
|
"use-deep-compare-effect": "1.8.1",
|
|
177
177
|
"uuid": "^14.0.0",
|
|
178
178
|
"@plone/registry": "3.0.1",
|
|
179
|
-
"@plone/volto-slate": "19.0.4",
|
|
180
179
|
"@plone/scripts": "4.0.1",
|
|
181
|
-
"@plone/components": "4.2.1"
|
|
180
|
+
"@plone/components": "4.2.1",
|
|
181
|
+
"@plone/volto-slate": "19.0.5"
|
|
182
182
|
},
|
|
183
183
|
"devDependencies": {
|
|
184
184
|
"@babel/core": "^7.28.5",
|
|
@@ -287,8 +287,8 @@
|
|
|
287
287
|
"webpack-dev-server": "^5.2.4",
|
|
288
288
|
"webpack-node-externals": "3.0.0",
|
|
289
289
|
"@plone/babel-preset-razzle": "^1.0.1",
|
|
290
|
+
"@plone/razzle": "1.0.1",
|
|
290
291
|
"@plone/razzle-dev-utils": "1.0.0",
|
|
291
|
-
"@plone/razzle": "1.0.0",
|
|
292
292
|
"@plone/volto-coresandbox": "1.0.0",
|
|
293
293
|
"@plone/types": "2.0.1"
|
|
294
294
|
},
|
|
@@ -39,9 +39,9 @@ import unlockSVG from '@plone/volto/icons/unlock.svg';
|
|
|
39
39
|
import folderSVG from '@plone/volto/icons/folder.svg';
|
|
40
40
|
import addSVG from '@plone/volto/icons/add-document.svg';
|
|
41
41
|
import moreSVG from '@plone/volto/icons/more.svg';
|
|
42
|
-
import userSVG from '@plone/volto/icons/user.svg';
|
|
43
42
|
import backSVG from '@plone/volto/icons/back.svg';
|
|
44
43
|
import clearSVG from '@plone/volto/icons/clear.svg';
|
|
44
|
+
import UserAvatar from './UserAvatar';
|
|
45
45
|
|
|
46
46
|
const messages = defineMessages({
|
|
47
47
|
edit: {
|
|
@@ -695,8 +695,7 @@ class Toolbar extends Component {
|
|
|
695
695
|
tabIndex={0}
|
|
696
696
|
id="toolbar-personal"
|
|
697
697
|
>
|
|
698
|
-
<
|
|
699
|
-
name={userSVG}
|
|
698
|
+
<UserAvatar
|
|
700
699
|
size="30px"
|
|
701
700
|
title={this.props.intl.formatMessage(
|
|
702
701
|
messages.personalTools,
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { render } from '@testing-library/react';
|
|
3
|
+
import cameraSVG from '@plone/volto/icons/camera.svg';
|
|
4
|
+
|
|
5
|
+
import UserAvatar from './UserAvatar';
|
|
6
|
+
|
|
7
|
+
const renderUserAvatar = (
|
|
8
|
+
props: React.ComponentProps<typeof UserAvatar> = {},
|
|
9
|
+
) => render(<UserAvatar {...props} />);
|
|
10
|
+
|
|
11
|
+
describe('UserAvatar', () => {
|
|
12
|
+
it('renders the default user icon', () => {
|
|
13
|
+
const { asFragment } = renderUserAvatar();
|
|
14
|
+
expect(asFragment()).toMatchSnapshot();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('defaults to the toolbar button size', () => {
|
|
18
|
+
const { container } = renderUserAvatar();
|
|
19
|
+
const svg = container.querySelector('svg');
|
|
20
|
+
|
|
21
|
+
expect(svg).not.toBeNull();
|
|
22
|
+
expect(svg).toHaveClass('icon');
|
|
23
|
+
expect(svg).toHaveStyle({ height: '30px' });
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('renders at the given size', () => {
|
|
27
|
+
const { container } = renderUserAvatar({ size: '96px' });
|
|
28
|
+
|
|
29
|
+
expect(container.querySelector('svg')).toHaveStyle({ height: '96px' });
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('applies the given size to a custom icon too', () => {
|
|
33
|
+
const { container } = renderUserAvatar({ icon: cameraSVG, size: '96px' });
|
|
34
|
+
|
|
35
|
+
expect(container.querySelector('svg')).toHaveStyle({ height: '96px' });
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('exposes the title to assistive technology', () => {
|
|
39
|
+
const { container } = renderUserAvatar({ title: 'Personal tools' });
|
|
40
|
+
|
|
41
|
+
expect(container.querySelector('svg > title')?.textContent).toBe(
|
|
42
|
+
'Personal tools',
|
|
43
|
+
);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('renders no title element when no title is given', () => {
|
|
47
|
+
const { container } = renderUserAvatar();
|
|
48
|
+
|
|
49
|
+
expect(container.querySelector('svg > title')).toBeNull();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('renders the given icon instead of the default one', () => {
|
|
53
|
+
const { container: withDefault } = renderUserAvatar();
|
|
54
|
+
const { container: withCamera } = renderUserAvatar({ icon: cameraSVG });
|
|
55
|
+
|
|
56
|
+
expect(withCamera.querySelector('svg')?.innerHTML).not.toBe(
|
|
57
|
+
withDefault.querySelector('svg')?.innerHTML,
|
|
58
|
+
);
|
|
59
|
+
expect(withCamera.innerHTML).toMatchSnapshot();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('keeps the title when a custom icon is given', () => {
|
|
63
|
+
const { container } = renderUserAvatar({
|
|
64
|
+
icon: cameraSVG,
|
|
65
|
+
title: 'Personal tools',
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
expect(container.querySelector('svg > title')?.textContent).toBe(
|
|
69
|
+
'Personal tools',
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UserAvatar component.
|
|
3
|
+
* @module components/manage/Toolbar/UserAvatar
|
|
4
|
+
*/
|
|
5
|
+
import Icon from '@plone/volto/components/theme/Icon/Icon';
|
|
6
|
+
import userSVG from '@plone/volto/icons/user.svg';
|
|
7
|
+
|
|
8
|
+
export type UserAvatarProps = {
|
|
9
|
+
/** Title of the rendered icon (a11y). */
|
|
10
|
+
title?: string;
|
|
11
|
+
/** Icon to render in place of the default user glyph. */
|
|
12
|
+
icon?: typeof userSVG;
|
|
13
|
+
/** Size of the avatar (in px). Defaults to the toolbar button size. */
|
|
14
|
+
size?: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Avatar of the currently signed-in user, as shown in the toolbar.
|
|
19
|
+
*
|
|
20
|
+
* Extracted so that add-ons can shadow this component alone — rendering a
|
|
21
|
+
* portrait, initials or a gravatar — instead of shadowing the whole toolbar.
|
|
22
|
+
*/
|
|
23
|
+
const UserAvatar = ({ title, icon, size = '30px' }: UserAvatarProps) => {
|
|
24
|
+
return <Icon name={icon || userSVG} size={size} title={title} />;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default UserAvatar;
|
|
@@ -5,7 +5,12 @@ import { useIntl, defineMessages, FormattedMessage } from 'react-intl';
|
|
|
5
5
|
import UniversalLink from '@plone/volto/components/manage/UniversalLink/UniversalLink';
|
|
6
6
|
import { asyncConnect } from '@plone/volto/helpers/AsyncConnect';
|
|
7
7
|
import { createPortal } from 'react-dom';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
Container as SemanticContainer,
|
|
10
|
+
Pagination,
|
|
11
|
+
Button,
|
|
12
|
+
Header,
|
|
13
|
+
} from 'semantic-ui-react';
|
|
9
14
|
import qs from 'query-string';
|
|
10
15
|
import classNames from 'classnames';
|
|
11
16
|
import config from '@plone/volto/registry';
|
|
@@ -85,6 +90,9 @@ const Search = (props) => {
|
|
|
85
90
|
|
|
86
91
|
const options = qs.parse(location.search);
|
|
87
92
|
|
|
93
|
+
const Container =
|
|
94
|
+
config.getComponent({ name: 'Container' }).component || SemanticContainer;
|
|
95
|
+
|
|
88
96
|
return (
|
|
89
97
|
<Container id="page-search">
|
|
90
98
|
<Helmet title={intl.formatMessage(messages.Search)} />
|
|
@@ -7,7 +7,7 @@ import React from 'react';
|
|
|
7
7
|
import PropTypes from 'prop-types';
|
|
8
8
|
import { Container as SemanticContainer } from 'semantic-ui-react';
|
|
9
9
|
import { hasBlocksData } from '@plone/volto/helpers/Blocks/Blocks';
|
|
10
|
-
import { flattenHTMLToAppURL } from '@plone/volto/helpers/Url/Url';
|
|
10
|
+
import { flattenHTMLToAppURL, getBaseUrl } from '@plone/volto/helpers/Url/Url';
|
|
11
11
|
import RenderBlocks from '@plone/volto/components/theme/View/RenderBlocks';
|
|
12
12
|
import config from '@plone/volto/registry';
|
|
13
13
|
|
|
@@ -17,14 +17,16 @@ import config from '@plone/volto/registry';
|
|
|
17
17
|
* @params {object} content Content object.
|
|
18
18
|
* @returns {string} Markup of the component.
|
|
19
19
|
*/
|
|
20
|
-
const NewsItemView = (
|
|
20
|
+
const NewsItemView = (props) => {
|
|
21
|
+
const { content, location } = props;
|
|
22
|
+
const path = getBaseUrl(location?.pathname || '');
|
|
21
23
|
const Image = config.getComponent({ name: 'Image' }).component;
|
|
22
24
|
const Container =
|
|
23
25
|
config.getComponent({ name: 'Container' }).component || SemanticContainer;
|
|
24
26
|
|
|
25
27
|
return hasBlocksData(content) ? (
|
|
26
28
|
<Container id="page-document" className="view-wrapper newsitem-view">
|
|
27
|
-
<RenderBlocks
|
|
29
|
+
<RenderBlocks {...props} path={path} />
|
|
28
30
|
</Container>
|
|
29
31
|
) : (
|
|
30
32
|
<Container className="view-wrapper">
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import userSVG from '@plone/volto/icons/user.svg';
|
|
2
|
+
export type UserAvatarProps = {
|
|
3
|
+
/** Title of the rendered icon (a11y). */
|
|
4
|
+
title?: string;
|
|
5
|
+
/** Icon to render in place of the default user glyph. */
|
|
6
|
+
icon?: typeof userSVG;
|
|
7
|
+
/** Size of the avatar (in px). Defaults to the toolbar button size. */
|
|
8
|
+
size?: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Avatar of the currently signed-in user, as shown in the toolbar.
|
|
12
|
+
*
|
|
13
|
+
* Extracted so that add-ons can shadow this component alone — rendering a
|
|
14
|
+
* portrait, initials or a gravatar — instead of shadowing the whole toolbar.
|
|
15
|
+
*/
|
|
16
|
+
declare const UserAvatar: ({ title, icon, size }: UserAvatarProps) => import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export default UserAvatar;
|
|
@@ -5,9 +5,7 @@ export default NewsItemView;
|
|
|
5
5
|
* @params {object} content Content object.
|
|
6
6
|
* @returns {string} Markup of the component.
|
|
7
7
|
*/
|
|
8
|
-
declare function NewsItemView(
|
|
9
|
-
content: any;
|
|
10
|
-
}): string;
|
|
8
|
+
declare function NewsItemView(props: any): string;
|
|
11
9
|
declare namespace NewsItemView {
|
|
12
10
|
namespace propTypes {
|
|
13
11
|
let content: any;
|