@plone/volto 14.7.1 → 14.8.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 +17 -0
- package/package.json +3 -3
- package/src/components/manage/Widgets/UrlWidget.jsx +2 -0
- package/src/components/theme/App/App.jsx +4 -1
- package/src/components/theme/Component/Component.jsx +19 -0
- package/src/components/theme/Component/Component.test.jsx +31 -0
- package/src/components/theme/MultilingualRedirector/MultilingualRedirector.jsx +28 -1
- package/src/config/index.js +1 -0
- package/src/registry.js +16 -0
- package/src/registry.test.js +28 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 14.8.0 (2022-02-03)
|
|
4
|
+
|
|
5
|
+
### Feature
|
|
6
|
+
|
|
7
|
+
- Enable `components` property in Volto's config registry. Does not expose any direct feature but this will open the door to be able to override registered components using the config registry and avoid using shadowing explicitly. @sneridagh
|
|
8
|
+
- Add `resolve` and `register` helper methods for the Volto config. They retrieve and register new components in the registry. @tiberiuichim @sneridagh
|
|
9
|
+
- Add `Component` component, given a `name` of a component registered in the registry, it renders it, passing down the props. @tiberiuichim
|
|
10
|
+
- Syncronize the content language with the UI language in multilingual sites. So when you are accessing a content in a given language the rest of the interface literals follow along (it updates the language cookie). So the UI remains consistent. @sneridagh
|
|
11
|
+
|
|
12
|
+
### Bugfix
|
|
13
|
+
|
|
14
|
+
- Fix the a11y violation of UrlWidget @iRohitSingh
|
|
15
|
+
|
|
16
|
+
### Internal
|
|
17
|
+
|
|
18
|
+
- Update volta pins in package.json @fredvd
|
|
19
|
+
|
|
3
20
|
## 14.7.1 (2022-02-02)
|
|
4
21
|
|
|
5
22
|
### Internal
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
}
|
|
10
10
|
],
|
|
11
11
|
"license": "MIT",
|
|
12
|
-
"version": "14.
|
|
12
|
+
"version": "14.8.0",
|
|
13
13
|
"repository": {
|
|
14
14
|
"type": "git",
|
|
15
15
|
"url": "git@github.com:plone/volto.git"
|
|
@@ -434,7 +434,7 @@
|
|
|
434
434
|
"ua-parser-js": "0.7.28"
|
|
435
435
|
},
|
|
436
436
|
"volta": {
|
|
437
|
-
"node": "
|
|
438
|
-
"yarn": "1.
|
|
437
|
+
"node": "16.13.2",
|
|
438
|
+
"yarn": "1.22.17"
|
|
439
439
|
}
|
|
440
440
|
}
|
|
@@ -101,6 +101,7 @@ export const UrlWidget = (props) => {
|
|
|
101
101
|
<Button
|
|
102
102
|
basic
|
|
103
103
|
className="cancel"
|
|
104
|
+
aria-label="clearUrlBrowser"
|
|
104
105
|
onClick={(e) => {
|
|
105
106
|
e.preventDefault();
|
|
106
107
|
e.stopPropagation();
|
|
@@ -115,6 +116,7 @@ export const UrlWidget = (props) => {
|
|
|
115
116
|
<Button
|
|
116
117
|
basic
|
|
117
118
|
icon
|
|
119
|
+
aria-label="openUrlBrowser"
|
|
118
120
|
onClick={(e) => {
|
|
119
121
|
e.preventDefault();
|
|
120
122
|
e.stopPropagation();
|
|
@@ -146,7 +146,10 @@ class App extends Component {
|
|
|
146
146
|
<SkipLinks />
|
|
147
147
|
<Header pathname={path} />
|
|
148
148
|
<Breadcrumbs pathname={path} />
|
|
149
|
-
<MultilingualRedirector
|
|
149
|
+
<MultilingualRedirector
|
|
150
|
+
pathname={this.props.pathname}
|
|
151
|
+
contentLanguage={this.props.content?.language?.token}
|
|
152
|
+
>
|
|
150
153
|
<Segment basic className="content-area">
|
|
151
154
|
<main>
|
|
152
155
|
<OutdatedBrowser />
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import registry from '@plone/volto/registry';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A component that can autommatically look up its implementation from the
|
|
5
|
+
* registry based on the provided component name
|
|
6
|
+
*/
|
|
7
|
+
const Component = ({ name, ...rest }) => {
|
|
8
|
+
const Component = registry.resolve(name)?.component;
|
|
9
|
+
|
|
10
|
+
if (!Component) {
|
|
11
|
+
// eslint-disable-next-line no-console
|
|
12
|
+
console.warn(`Component not found in registry: ${name}`);
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return <Component {...rest} />;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default Component;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import '@testing-library/jest-dom/extend-expect';
|
|
3
|
+
import { render } from '@testing-library/react';
|
|
4
|
+
import Component from './Component';
|
|
5
|
+
import config from '@plone/volto/registry';
|
|
6
|
+
|
|
7
|
+
config.set('components', {
|
|
8
|
+
Toolbar: { component: (props) => <div>this is the Toolbar component</div> },
|
|
9
|
+
'Toolbar.Types': {
|
|
10
|
+
component: ({ teststring }) => (
|
|
11
|
+
<div>this is the Toolbar component with a prop {teststring} in it</div>
|
|
12
|
+
),
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe('Component component :P', () => {
|
|
17
|
+
it('Render a Component in the registry', () => {
|
|
18
|
+
const { container } = render(<Component name="Toolbar" />);
|
|
19
|
+
expect(container).toMatchSnapshot();
|
|
20
|
+
});
|
|
21
|
+
it('Renders a Fallback Component that does not exists in the registry', () => {
|
|
22
|
+
const { container } = render(<Component name="Toolbar.Foo" />);
|
|
23
|
+
expect(container).toMatchSnapshot();
|
|
24
|
+
});
|
|
25
|
+
it('Renders a Component in the registry - passes props correctly', () => {
|
|
26
|
+
const { container } = render(
|
|
27
|
+
<Component name="Toolbar.Types" teststring="Hi!" />,
|
|
28
|
+
);
|
|
29
|
+
expect(container).toMatchSnapshot();
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -8,7 +8,7 @@ import { normalizeLanguageName } from '@plone/volto/helpers';
|
|
|
8
8
|
|
|
9
9
|
const MultilingualRedirector = (props) => {
|
|
10
10
|
const { settings } = config;
|
|
11
|
-
const { pathname, children } = props;
|
|
11
|
+
const { pathname, contentLanguage, children } = props;
|
|
12
12
|
const currentLanguage =
|
|
13
13
|
cookie.load('I18N_LANGUAGE') || settings.defaultLanguage;
|
|
14
14
|
const redirectToLanguage = settings.supportedLanguages.includes(
|
|
@@ -18,6 +18,33 @@ const MultilingualRedirector = (props) => {
|
|
|
18
18
|
: settings.defaultLanguage;
|
|
19
19
|
const dispatch = useDispatch();
|
|
20
20
|
|
|
21
|
+
React.useEffect(() => {
|
|
22
|
+
// This ensures the current content language and the current active language in the
|
|
23
|
+
// UI are the same. Otherwise, there are inconsistencies between the UI main elements
|
|
24
|
+
// eg. Home link in breadcrumbs, other i18n dependant literals from the main UI and
|
|
25
|
+
// the current content language.
|
|
26
|
+
if (
|
|
27
|
+
contentLanguage &&
|
|
28
|
+
currentLanguage !== contentLanguage &&
|
|
29
|
+
pathname &&
|
|
30
|
+
// We don't want to trigger it in Babel View, since Babel view already takes care
|
|
31
|
+
// of it
|
|
32
|
+
!pathname.endsWith('/add') &&
|
|
33
|
+
settings.isMultilingual
|
|
34
|
+
) {
|
|
35
|
+
const langFileName = normalizeLanguageName(contentLanguage);
|
|
36
|
+
import('~/../locales/' + langFileName + '.json').then((locale) => {
|
|
37
|
+
dispatch(changeLanguage(contentLanguage, locale.default));
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}, [
|
|
41
|
+
pathname,
|
|
42
|
+
dispatch,
|
|
43
|
+
currentLanguage,
|
|
44
|
+
contentLanguage,
|
|
45
|
+
settings.isMultilingual,
|
|
46
|
+
]);
|
|
47
|
+
|
|
21
48
|
React.useEffect(() => {
|
|
22
49
|
// ToDo: Add means to support language negotiation (with config)
|
|
23
50
|
// const detectedLang = (navigator.language || navigator.userLanguage).substring(0, 2);
|
package/src/config/index.js
CHANGED
package/src/registry.js
CHANGED
|
@@ -79,6 +79,22 @@ class Config {
|
|
|
79
79
|
set slots(slots) {
|
|
80
80
|
this._data.slots = slots;
|
|
81
81
|
}
|
|
82
|
+
|
|
83
|
+
get components() {
|
|
84
|
+
return this._data.components;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
set components(components) {
|
|
88
|
+
this._data.components = components;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
resolve(component) {
|
|
92
|
+
return this._data.components[component] || {};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
register(name, component) {
|
|
96
|
+
this._data.components[name] = component;
|
|
97
|
+
}
|
|
82
98
|
}
|
|
83
99
|
|
|
84
100
|
const instance = new Config();
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import config from './registry';
|
|
2
|
+
|
|
3
|
+
config.set('components', {
|
|
4
|
+
Toolbar: { component: 'this is the Toolbar component' },
|
|
5
|
+
'Toolbar.Types': { component: 'this is the Types component' },
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
describe('registry', () => {
|
|
9
|
+
it('resolve components', () => {
|
|
10
|
+
expect(config.resolve('Toolbar').component).toEqual(
|
|
11
|
+
'this is the Toolbar component',
|
|
12
|
+
);
|
|
13
|
+
});
|
|
14
|
+
it('resolve components with dots', () => {
|
|
15
|
+
expect(config.resolve('Toolbar.Types').component).toEqual(
|
|
16
|
+
'this is the Types component',
|
|
17
|
+
);
|
|
18
|
+
});
|
|
19
|
+
it('resolve unexistent component', () => {
|
|
20
|
+
expect(config.resolve('Toolbar.Doh').component).toEqual(undefined);
|
|
21
|
+
});
|
|
22
|
+
it('register component by name', () => {
|
|
23
|
+
config.register('Toolbar.Bar', { component: 'this is a Bar component' });
|
|
24
|
+
expect(config.resolve('Toolbar.Bar').component).toEqual(
|
|
25
|
+
'this is a Bar component',
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
});
|