@plone/volto 19.0.0-alpha.21 → 19.0.0-alpha.23
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 +25 -0
- package/README.md +0 -3
- package/package.json +7 -6
- package/src/components/manage/Blocks/Block/BlocksForm.jsx +5 -3
- package/src/components/manage/Blocks/Listing/ListingBody.jsx +4 -0
- package/src/components/manage/Widgets/ButtonsWidget.tsx +20 -1
- package/src/components/theme/App/App.jsx +3 -1
- package/src/components/theme/ConnectionRefused/ConnectionRefused.jsx +3 -2
- package/src/components/theme/SlotRenderer/SlotRenderer.tsx +12 -6
- package/src/helpers/AuthToken/AuthToken.js +1 -6
- package/src/helpers/FormValidation/validators.ts +16 -4
- package/types/components/theme/ConnectionRefused/ConnectionRefused.d.ts +2 -2
- package/types/components/theme/SlotRenderer/SlotRenderer.d.ts +4 -5
- package/types/config/Views.d.ts +1 -1
- package/types/helpers/FormValidation/validators.d.ts +11 -1
package/CHANGELOG.md
CHANGED
|
@@ -17,6 +17,31 @@ myst:
|
|
|
17
17
|
|
|
18
18
|
<!-- towncrier release notes start -->
|
|
19
19
|
|
|
20
|
+
## 19.0.0-alpha.23 (2026-02-03)
|
|
21
|
+
|
|
22
|
+
### Bugfix
|
|
23
|
+
|
|
24
|
+
- Language control panel: fix validation of default language. @davisagli [#7720](https://github.com/plone/volto/issues/7720)
|
|
25
|
+
- Set HTTP 503 status code for ConnectionRefused error page. @Shyam-Raghuwanshi [#7754](https://github.com/plone/volto/issues/7754)
|
|
26
|
+
- Fix default case selection in ButtonsWidget. @iFlameing
|
|
27
|
+
|
|
28
|
+
## 19.0.0-alpha.22 (2026-01-26)
|
|
29
|
+
|
|
30
|
+
### Feature
|
|
31
|
+
|
|
32
|
+
- Add `aboveListingItems` slot to allow displaying custom listing disclamers. @danalvrz
|
|
33
|
+
- Enhanced `SlotRenderer`'s `GetSlotArgs` typings. @sneridagh
|
|
34
|
+
|
|
35
|
+
### Bugfix
|
|
36
|
+
|
|
37
|
+
- Remove '__ac' cookie when authtoken expires @Tishasoumya-02 [#7783](https://github.com/plone/volto/issues/7783)
|
|
38
|
+
|
|
39
|
+
### Internal
|
|
40
|
+
|
|
41
|
+
- Removed apps folder from main branch, and related Plone's modular architecture packages (helpers, blocks, providers, theming, layout).
|
|
42
|
+
These packages are now only in `seven` branch. @sneridagh [#7785](https://github.com/plone/volto/issues/7785)
|
|
43
|
+
- Fixed CI test call. Fixed missing tests fixed since then. @sneridagh [#7795](https://github.com/plone/volto/issues/7795)
|
|
44
|
+
|
|
20
45
|
## 19.0.0-alpha.21 (2026-01-14)
|
|
21
46
|
|
|
22
47
|
### Bugfix
|
package/README.md
CHANGED
|
@@ -47,8 +47,6 @@ This allows the code to be shared effectively, and unifies tracking of changes a
|
|
|
47
47
|
|---|---|
|
|
48
48
|
| [`@plone/client`](https://www.npmjs.com/package/@plone/client) | [`packages/client`](https://github.com/plone/volto/tree/main/packages/client#readme) |
|
|
49
49
|
| [`@plone/components`](https://www.npmjs.com/package/@plone/components) | [`packages/components`](https://github.com/plone/volto/tree/main/packages/components#readme) |
|
|
50
|
-
| [`@plone/helpers`](https://www.npmjs.com/package/@plone/helpers) | [`packages/helpers`](https://github.com/plone/volto/tree/main/packages/helpers#readme) |
|
|
51
|
-
| [`@plone/providers`](https://www.npmjs.com/package/@plone/providers) | [`packages/providers`](https://github.com/plone/volto/tree/main/packages/providers#readme) |
|
|
52
50
|
| [`@plone/registry`](https://www.npmjs.com/package/@plone/registry) | [`packages/registry`](https://github.com/plone/volto/tree/main/packages/registry#readme) |
|
|
53
51
|
| [`@plone/scripts`](https://www.npmjs.com/package/@plone/scripts) | [`packages/scripts`](https://github.com/plone/volto/tree/main/packages/scripts#readme) |
|
|
54
52
|
| [`@plone/types`](https://www.npmjs.com/package/@plone/types) | [`packages/types`](https://github.com/plone/volto/tree/main/packages/types#readme) |
|
|
@@ -140,7 +138,6 @@ To ensure your website gets the greatest exposure, add it both to [Awesome Volto
|
|
|
140
138
|
- [Debabarreneko mankomunitatea](https://debabarrena.eus/eu) (Website of the Commonwealth of Debabarrena, community of municipalities to centralize waste handling services, developed by [CodeSyntax](https://www.codesyntax.com/en), 2022)
|
|
141
139
|
- [Debako Udala / Ayuntamiento de Deba](https://www.deba.eus/eu) (Website of the municipality of Deba, developed by [CodeSyntax](https://www.codesyntax.com/en), 2022)
|
|
142
140
|
- [European Environment Agency](https://www.eea.europa.eu/en) (Website of the European Environment Agency. Developed by [Eau de Web](https://eaudeweb.ro), 2023)
|
|
143
|
-
- Excellence at Humboldt-Universität zu Berlin (Website for the excellence initiative of the [Humboldt University Berlin](https://www.hu-berlin.de/de), developed by [kitconcept GmbH](https://kitconcept.com/en), 2019)
|
|
144
141
|
- [Film Basque Country](https://www.filmbasquecountry.eus/en) (Website to attract, guide, and support international productions, making it easier for them to film in the Basque Country, developed by [CodeSyntax](https://www.codesyntax.com/en), 2025)
|
|
145
142
|
- [Forest Information System for Europe](https://forest.eea.europa.eu) (Thematic website focusing on European forests, developed by [Eau de Web](https://eaudeweb.ro/), 2019)
|
|
146
143
|
- [Forschungszentrum Jülich](https://www.fz-juelich.de/de) (Website for Forschungzentrum Jülich, which is one of the largest research institutions in Europe, developed by [kitconcept GmbH](https://kitconcept.com/en), 2022)
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
}
|
|
10
10
|
],
|
|
11
11
|
"license": "MIT",
|
|
12
|
-
"version": "19.0.0-alpha.
|
|
12
|
+
"version": "19.0.0-alpha.23",
|
|
13
13
|
"repository": {
|
|
14
14
|
"type": "git",
|
|
15
15
|
"url": "git@github.com:plone/volto.git"
|
|
@@ -191,9 +191,9 @@
|
|
|
191
191
|
"use-deep-compare-effect": "1.8.1",
|
|
192
192
|
"uuid": "^8.3.2",
|
|
193
193
|
"@plone/components": "4.0.0-alpha.4",
|
|
194
|
-
"@plone/
|
|
194
|
+
"@plone/scripts": "4.0.0-alpha.4",
|
|
195
195
|
"@plone/volto-slate": "19.0.0-alpha.9",
|
|
196
|
-
"@plone/
|
|
196
|
+
"@plone/registry": "3.0.0-alpha.9"
|
|
197
197
|
},
|
|
198
198
|
"devDependencies": {
|
|
199
199
|
"@babel/core": "^7.28.5",
|
|
@@ -214,6 +214,7 @@
|
|
|
214
214
|
"@storybook/addon-webpack5-compiler-babel": "3.0.3",
|
|
215
215
|
"@storybook/react": "^8.0.4",
|
|
216
216
|
"@storybook/react-webpack5": "^8.0.4",
|
|
217
|
+
"@storybook/test": "^8.0.4",
|
|
217
218
|
"@storybook/theming": "^8.0.4",
|
|
218
219
|
"@testing-library/cypress": "10.1.0",
|
|
219
220
|
"@testing-library/jest-dom": "6.4.2",
|
|
@@ -306,10 +307,10 @@
|
|
|
306
307
|
"webpack-bundle-analyzer": "4.10.1",
|
|
307
308
|
"webpack-dev-server": "4.11.1",
|
|
308
309
|
"webpack-node-externals": "3.0.0",
|
|
309
|
-
"@plone/
|
|
310
|
+
"@plone/types": "2.0.0-alpha.14",
|
|
310
311
|
"@plone/razzle": "1.0.0-alpha.0",
|
|
311
|
-
"@plone/
|
|
312
|
-
"@plone/
|
|
312
|
+
"@plone/babel-preset-razzle": "^1.0.0-alpha.0",
|
|
313
|
+
"@plone/volto-coresandbox": "1.0.0"
|
|
313
314
|
},
|
|
314
315
|
"volta": {
|
|
315
316
|
"node": "20.9.0"
|
|
@@ -264,9 +264,11 @@ const BlocksForm = (props) => {
|
|
|
264
264
|
// to be removed when the user saves the page next. Otherwise the invalid
|
|
265
265
|
// blocks would linger for ever.
|
|
266
266
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
267
|
+
const blocksLayoutFieldname = getBlocksLayoutFieldname(properties);
|
|
268
|
+
const blocksFieldname = getBlocksFieldname(properties);
|
|
269
|
+
for (const id of properties?.[blocksLayoutFieldname]?.items || []) {
|
|
270
|
+
if (!properties?.[blocksFieldname]?.[id]) {
|
|
271
|
+
const newFormData = deleteBlock(properties, id, intl);
|
|
270
272
|
onChangeFormData(newFormData);
|
|
271
273
|
}
|
|
272
274
|
}
|
|
@@ -12,6 +12,8 @@ import { normalizeString } from '@plone/volto/helpers/Utils/Utils';
|
|
|
12
12
|
import paginationLeftSVG from '@plone/volto/icons/left-key.svg';
|
|
13
13
|
import paginationRightSVG from '@plone/volto/icons/right-key.svg';
|
|
14
14
|
|
|
15
|
+
import SlotRenderer from '@plone/volto/components/theme/SlotRenderer/SlotRenderer';
|
|
16
|
+
|
|
15
17
|
const Headline = ({ headlineTag, id, data = {}, listingItems, isEditMode }) => {
|
|
16
18
|
let attr = { id };
|
|
17
19
|
const slug = Slugger.slug(normalizeString(data.headline));
|
|
@@ -46,6 +48,7 @@ const ListingBody = withQuerystringResults((props) => {
|
|
|
46
48
|
isFolderContentsListing,
|
|
47
49
|
hasLoaded,
|
|
48
50
|
id,
|
|
51
|
+
content,
|
|
49
52
|
} = props;
|
|
50
53
|
|
|
51
54
|
let ListingBodyTemplate;
|
|
@@ -82,6 +85,7 @@ const ListingBody = withQuerystringResults((props) => {
|
|
|
82
85
|
isEditMode={isEditMode}
|
|
83
86
|
/>
|
|
84
87
|
)}
|
|
88
|
+
<SlotRenderer name="aboveListingItems" content={content} data={data} />
|
|
85
89
|
{listingItems?.length > 0 ? (
|
|
86
90
|
<div ref={listingRef}>
|
|
87
91
|
<ListingBodyTemplate
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
2
|
import FormFieldWrapper from '@plone/volto/components/manage/Widgets/FormFieldWrapper';
|
|
3
3
|
import Icon from '@plone/volto/components/theme/Icon/Icon';
|
|
4
4
|
import { Radio, RadioGroup } from '@plone/components';
|
|
@@ -130,6 +130,25 @@ const ButtonsWidget = (props: ButtonsWidgetProps) => {
|
|
|
130
130
|
}
|
|
131
131
|
};
|
|
132
132
|
|
|
133
|
+
// Synchronize default value if no value is set to data prop.
|
|
134
|
+
useEffect(() => {
|
|
135
|
+
// If `value` already matches any normalized action value, do nothing.
|
|
136
|
+
const existingMatch = normalizedActions.find(({ value: actionValue }) =>
|
|
137
|
+
isEqual(value, actionValue),
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
if (existingMatch) return;
|
|
141
|
+
|
|
142
|
+
// Otherwise, if there's a default value set the default style.
|
|
143
|
+
if (!defaultSelectedActionName) return;
|
|
144
|
+
const selected = normalizedActions.find(
|
|
145
|
+
({ name }) => name === defaultSelectedActionName,
|
|
146
|
+
);
|
|
147
|
+
if (!selected) return;
|
|
148
|
+
|
|
149
|
+
onChange(id, selected.value);
|
|
150
|
+
}, [value, defaultSelectedActionName, onChange, normalizedActions, id]);
|
|
151
|
+
|
|
133
152
|
return (
|
|
134
153
|
<FormFieldWrapper {...props} className="widget">
|
|
135
154
|
<RadioGroup
|
|
@@ -176,7 +176,9 @@ export class App extends Component {
|
|
|
176
176
|
<main ref={this.mainRef}>
|
|
177
177
|
<OutdatedBrowser />
|
|
178
178
|
{this.props.connectionRefused ? (
|
|
179
|
-
<ConnectionRefusedView
|
|
179
|
+
<ConnectionRefusedView
|
|
180
|
+
staticContext={this.props.staticContext}
|
|
181
|
+
/>
|
|
180
182
|
) : this.state.hasError ? (
|
|
181
183
|
<Error
|
|
182
184
|
message={this.state.error.message}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Connection refused error page.
|
|
3
3
|
* @module components/theme/ConnectionRefused/ConnectionRefused
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -7,6 +7,7 @@ import React from 'react';
|
|
|
7
7
|
import { FormattedMessage } from 'react-intl';
|
|
8
8
|
import { Container } from 'semantic-ui-react';
|
|
9
9
|
import config from '@plone/volto/registry';
|
|
10
|
+
import { withServerErrorCode } from '@plone/volto/helpers/Utils/Utils';
|
|
10
11
|
|
|
11
12
|
const ConnectionRefused = () => (
|
|
12
13
|
<Container
|
|
@@ -71,4 +72,4 @@ const ConnectionRefused = () => (
|
|
|
71
72
|
</Container>
|
|
72
73
|
);
|
|
73
74
|
|
|
74
|
-
export default ConnectionRefused;
|
|
75
|
+
export default withServerErrorCode(503)(ConnectionRefused);
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { useLocation } from 'react-router-dom';
|
|
2
2
|
import config from '@plone/volto/registry';
|
|
3
|
-
import type {
|
|
3
|
+
import type { GetSlotArgs } from '@plone/types';
|
|
4
|
+
|
|
5
|
+
export interface SlotRendererProps extends GetSlotArgs {
|
|
6
|
+
name: string;
|
|
7
|
+
}
|
|
4
8
|
|
|
5
9
|
/*
|
|
6
10
|
Usage:
|
|
@@ -11,20 +15,20 @@ const SlotRenderer = ({
|
|
|
11
15
|
name,
|
|
12
16
|
content,
|
|
13
17
|
navRoot,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
navRoot?: Content;
|
|
18
|
-
}) => {
|
|
18
|
+
data,
|
|
19
|
+
...rest
|
|
20
|
+
}: SlotRendererProps) => {
|
|
19
21
|
const location = useLocation();
|
|
20
22
|
|
|
21
23
|
let slots = config.getSlot(name, {
|
|
24
|
+
...rest,
|
|
22
25
|
content,
|
|
23
26
|
location: location as any, // Since we are using an older version of history, we need to cast it to any
|
|
24
27
|
// This is to cover the use case while adding a new content and we don't have
|
|
25
28
|
// have the navRoot information in the initial content. This will be
|
|
26
29
|
// useful for SlotRenderers rendered in the `Add` route.
|
|
27
30
|
navRoot: content?.['@components']?.navroot?.navroot || navRoot,
|
|
31
|
+
data,
|
|
28
32
|
});
|
|
29
33
|
|
|
30
34
|
if (!slots) {
|
|
@@ -45,10 +49,12 @@ const SlotRenderer = ({
|
|
|
45
49
|
const SlotComponent = component;
|
|
46
50
|
return (
|
|
47
51
|
<SlotComponent
|
|
52
|
+
{...rest}
|
|
48
53
|
key={name}
|
|
49
54
|
content={content}
|
|
50
55
|
location={location}
|
|
51
56
|
navRoot={navRoot}
|
|
57
|
+
data={data}
|
|
52
58
|
/>
|
|
53
59
|
);
|
|
54
60
|
},
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
|
|
6
6
|
import Cookies from 'universal-cookie';
|
|
7
7
|
import jwtDecode from 'jwt-decode';
|
|
8
|
-
|
|
9
8
|
import { loginRenew } from '@plone/volto/actions/userSession/userSession';
|
|
10
9
|
import { getCookieOptions } from '@plone/volto/helpers/Cookies/cookies';
|
|
11
10
|
import { push } from 'connected-react-router';
|
|
@@ -35,7 +34,6 @@ export function persistAuthToken(store, req) {
|
|
|
35
34
|
} else {
|
|
36
35
|
currentValue = cookies.get('auth_token');
|
|
37
36
|
}
|
|
38
|
-
|
|
39
37
|
/**
|
|
40
38
|
* handleChange method.
|
|
41
39
|
* @method handleChange
|
|
@@ -46,7 +44,6 @@ export function persistAuthToken(store, req) {
|
|
|
46
44
|
const previousValue = currentValue;
|
|
47
45
|
const state = store.getState();
|
|
48
46
|
currentValue = state.userSession.token;
|
|
49
|
-
|
|
50
47
|
if (
|
|
51
48
|
module.hot &&
|
|
52
49
|
module.hot.data &&
|
|
@@ -55,11 +52,11 @@ export function persistAuthToken(store, req) {
|
|
|
55
52
|
) {
|
|
56
53
|
currentValue = previousValue;
|
|
57
54
|
}
|
|
58
|
-
|
|
59
55
|
if (previousValue !== currentValue || initial) {
|
|
60
56
|
if (!currentValue) {
|
|
61
57
|
if (previousValue) {
|
|
62
58
|
cookies.remove('auth_token', { path: '/' });
|
|
59
|
+
cookies.remove('__ac', { path: '/' });
|
|
63
60
|
}
|
|
64
61
|
} else {
|
|
65
62
|
if (previousValue !== currentValue) {
|
|
@@ -97,11 +94,9 @@ export function persistAuthToken(store, req) {
|
|
|
97
94
|
}
|
|
98
95
|
}
|
|
99
96
|
}
|
|
100
|
-
|
|
101
97
|
store.subscribe(handleChange);
|
|
102
98
|
handleChange(true);
|
|
103
99
|
}
|
|
104
|
-
|
|
105
100
|
if (module?.hot) {
|
|
106
101
|
module.hot.dispose((data) => {
|
|
107
102
|
data.reloaded = true;
|
|
@@ -15,6 +15,17 @@ type Validator = {
|
|
|
15
15
|
formatMessage: Function;
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
+
type Choice = {
|
|
19
|
+
token: string;
|
|
20
|
+
label: string;
|
|
21
|
+
};
|
|
22
|
+
type ChoiceValidator = {
|
|
23
|
+
value: string | Choice;
|
|
24
|
+
field: Record<string, any>;
|
|
25
|
+
formData: any;
|
|
26
|
+
formatMessage: Function;
|
|
27
|
+
};
|
|
28
|
+
|
|
18
29
|
export const isMaxPropertyValid = ({
|
|
19
30
|
value,
|
|
20
31
|
fieldSpec,
|
|
@@ -211,12 +222,13 @@ export const defaultLanguageControlPanelValidator = ({
|
|
|
211
222
|
value,
|
|
212
223
|
formData,
|
|
213
224
|
formatMessage,
|
|
214
|
-
}:
|
|
225
|
+
}: ChoiceValidator) => {
|
|
226
|
+
const token = typeof value === 'object' ? value.token : value;
|
|
215
227
|
const isValid =
|
|
216
|
-
|
|
228
|
+
token &&
|
|
217
229
|
(formData.available_languages.find(
|
|
218
|
-
(lang: { token: string }) => lang.token ===
|
|
230
|
+
(lang: { token: string }) => lang.token === token,
|
|
219
231
|
) ||
|
|
220
|
-
formData.available_languages.includes(
|
|
232
|
+
formData.available_languages.includes(token));
|
|
221
233
|
return !isValid ? formatMessage(messages.defaultLanguage) : null;
|
|
222
234
|
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
declare const _default: (props: any) => import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
export default _default;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { GetSlotArgs } from '@plone/types';
|
|
2
|
+
export interface SlotRendererProps extends GetSlotArgs {
|
|
3
3
|
name: string;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}) => import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
}
|
|
5
|
+
declare const SlotRenderer: ({ name, content, navRoot, data, ...rest }: SlotRendererProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
6
|
export default SlotRenderer;
|
package/types/config/Views.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ export const errorViews: {
|
|
|
42
42
|
403: (props: any) => import("react/jsx-runtime").JSX.Element;
|
|
43
43
|
408: () => string;
|
|
44
44
|
500: (props: any) => import("react/jsx-runtime").JSX.Element;
|
|
45
|
-
ECONNREFUSED: () => import("react/jsx-runtime").JSX.Element;
|
|
45
|
+
ECONNREFUSED: (props: any) => import("react/jsx-runtime").JSX.Element;
|
|
46
46
|
corsError: () => string;
|
|
47
47
|
};
|
|
48
48
|
export namespace layoutViewsNamesMapping {
|
|
@@ -10,6 +10,16 @@ type Validator = {
|
|
|
10
10
|
formData: any;
|
|
11
11
|
formatMessage: Function;
|
|
12
12
|
};
|
|
13
|
+
type Choice = {
|
|
14
|
+
token: string;
|
|
15
|
+
label: string;
|
|
16
|
+
};
|
|
17
|
+
type ChoiceValidator = {
|
|
18
|
+
value: string | Choice;
|
|
19
|
+
field: Record<string, any>;
|
|
20
|
+
formData: any;
|
|
21
|
+
formatMessage: Function;
|
|
22
|
+
};
|
|
13
23
|
export declare const isMaxPropertyValid: ({ value, fieldSpec, criterion, formatMessage, }: MinMaxValidator) => any;
|
|
14
24
|
export declare const isMinPropertyValid: ({ value, fieldSpec, criterion, formatMessage, }: MinMaxValidator) => any;
|
|
15
25
|
export declare const minLengthValidator: ({ value, field, formatMessage, }: Validator) => any;
|
|
@@ -26,5 +36,5 @@ export declare const endEventDateRangeValidator: ({ value, field, formData, form
|
|
|
26
36
|
export declare const patternValidator: ({ value, field, formatMessage, }: Validator) => any;
|
|
27
37
|
export declare const maxItemsValidator: ({ value, field, formatMessage, }: Validator) => any;
|
|
28
38
|
export declare const minItemsValidator: ({ value, field, formatMessage, }: Validator) => any;
|
|
29
|
-
export declare const defaultLanguageControlPanelValidator: ({ value, formData, formatMessage, }:
|
|
39
|
+
export declare const defaultLanguageControlPanelValidator: ({ value, formData, formatMessage, }: ChoiceValidator) => any;
|
|
30
40
|
export {};
|