@plone/volto 14.0.0-alpha.33 → 14.0.0-alpha.37

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 (67) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +4 -1
  3. package/package.json +1 -1
  4. package/src/actions/schema/schema.js +4 -2
  5. package/src/actions/schema/schema.test.js +10 -0
  6. package/src/actions/vocabularies/vocabularies.js +3 -10
  7. package/src/actions/vocabularies/vocabularies.test.js +26 -0
  8. package/src/components/manage/Add/Add.jsx +1 -1
  9. package/src/components/manage/Blocks/Block/Edit.jsx +6 -1
  10. package/src/components/manage/Blocks/HeroImageLeft/schema.js +1 -1
  11. package/src/components/manage/Blocks/Listing/schema.js +2 -0
  12. package/src/components/manage/Edit/Edit.jsx +4 -1
  13. package/src/components/manage/Sidebar/ObjectBrowserBody.jsx +1 -1
  14. package/src/components/manage/Sidebar/SidebarPopup.stories.jsx +42 -0
  15. package/src/components/manage/Widgets/AlignWidget.jsx +14 -6
  16. package/src/components/manage/Widgets/AlignWidget.stories.jsx +38 -0
  17. package/src/components/manage/Widgets/ArrayWidget.stories.jsx +2 -2
  18. package/src/components/manage/Widgets/CheckboxWidget.jsx +9 -0
  19. package/src/components/manage/Widgets/CheckboxWidget.stories.jsx +38 -0
  20. package/src/components/manage/Widgets/DatetimeWidget.jsx +9 -0
  21. package/src/components/manage/Widgets/DatetimeWidget.stories.jsx +38 -0
  22. package/src/components/manage/Widgets/EmailWidget.jsx +10 -3
  23. package/src/components/manage/Widgets/EmailWidget.stories.jsx +38 -0
  24. package/src/components/manage/Widgets/FileWidget.jsx +18 -0
  25. package/src/components/manage/Widgets/FileWidget.stories.jsx +38 -0
  26. package/src/components/manage/Widgets/NumberWidget.jsx +9 -2
  27. package/src/components/manage/Widgets/NumberWidget.stories.jsx +39 -0
  28. package/src/components/manage/Widgets/ObjectBrowserWidget.stories.js +1 -1
  29. package/src/components/manage/Widgets/ObjectListWidget.jsx +26 -0
  30. package/src/components/manage/Widgets/ObjectListWidget.stories.js +166 -44
  31. package/src/components/manage/Widgets/ObjectWidget.jsx +4 -10
  32. package/src/components/manage/Widgets/ObjectWidget.stories.jsx +157 -0
  33. package/src/components/manage/Widgets/PasswordWidget.jsx +9 -2
  34. package/src/components/manage/Widgets/PasswordWidget.stories.jsx +38 -0
  35. package/src/components/manage/Widgets/QueryWidget.jsx +1 -3
  36. package/src/components/manage/Widgets/QueryWidget.stories.jsx +38 -0
  37. package/src/components/manage/Widgets/SelectWidget.stories.jsx +1 -1
  38. package/src/components/manage/Widgets/TextWidget.jsx +4 -3
  39. package/src/components/manage/Widgets/TextWidget.stories.jsx +38 -0
  40. package/src/components/manage/Widgets/TextareaWidget.jsx +10 -3
  41. package/src/components/manage/Widgets/TextareaWidget.stories.jsx +38 -0
  42. package/src/components/manage/Widgets/UrlWidget.jsx +12 -4
  43. package/src/components/manage/Widgets/UrlWidget.stories.jsx +38 -0
  44. package/src/components/manage/Widgets/WysiwygWidget.jsx +11 -3
  45. package/src/components/manage/Widgets/WysiwygWidget.stories.jsx +41 -0
  46. package/src/components/theme/Anontools/Anontools.jsx +0 -2
  47. package/src/components/theme/Anontools/Anontools.stories.jsx +24 -0
  48. package/src/components/theme/Breadcrumbs/Breadcrumbs.jsx +2 -5
  49. package/src/components/theme/Breadcrumbs/Breadcrumbs.stories.jsx +30 -0
  50. package/src/components/theme/Navigation/ContextNavigation.stories.js +27 -29
  51. package/src/components/theme/Navigation/NavItem.jsx +36 -0
  52. package/src/components/theme/Navigation/NavItems.jsx +2 -15
  53. package/src/components/theme/Navigation/Navigation.test.jsx +26 -0
  54. package/src/components/theme/View/RenderBlocks.jsx +10 -2
  55. package/src/config/Blocks.jsx +8 -0
  56. package/src/helpers/Blocks/Blocks.js +45 -3
  57. package/src/helpers/Blocks/Blocks.test.js +212 -0
  58. package/src/helpers/Extensions/withBlockExtensions.js +42 -2
  59. package/src/helpers/Extensions/withBlockSchemaEnhancer.js +77 -3
  60. package/src/helpers/Url/Url.js +2 -1
  61. package/src/helpers/Url/Url.test.js +7 -0
  62. package/src/helpers/Vocabularies/Vocabularies.js +12 -0
  63. package/src/helpers/index.js +2 -0
  64. package/src/storybook.jsx +50 -0
  65. package/src/components/manage/Sidebar/SidebarPopup.stories.mdx +0 -41
  66. package/src/components/theme/Anontools/Anontools.stories.mdx +0 -18
  67. package/src/components/theme/Breadcrumbs/Breadcrumbs.stories.mdx +0 -30
package/CHANGELOG.md CHANGED
@@ -1,5 +1,47 @@
1
1
  # Change Log
2
2
 
3
+ ## 14.0.0-alpha.37 (2021-11-26)
4
+
5
+ ### Bugfix
6
+
7
+ - Fixed object browser selected items number. @giuliaghisini
8
+ - Fix action vocabularies call avoiding regex look behind @nzambello
9
+
10
+ ### Internal
11
+
12
+ - Fix select family widgets stories in storybook @sneridagh
13
+
14
+ ## 14.0.0-alpha.36 (2021-11-25)
15
+
16
+ ### Bugfix
17
+
18
+ - Fix regression in actions vocabularies calls because the change to use contextual schemas @sneridagh
19
+ - Include block schema enhancers (main block schema enhancer + variation schema enhancer) when calculating block default data @tiberiuichim
20
+
21
+ ### Internal
22
+
23
+ - Fix references to old configuration style in apiExpanders documentation @tiberiuichim
24
+ - Add `applySchemaDefaults`, in addition to `applyBlockDefaults`, to allow reuse in object widgets and other advanced scenarios @tiberiuichim
25
+
26
+ ## 14.0.0-alpha.35 (2021-11-24)
27
+
28
+ ### Bugfix
29
+
30
+ - Fix `isInternalURL` when `settings.internalApiPath` is empty @tiberiuichim
31
+ - Fix external link not supported by Navigation component #2853. @ericof
32
+ - Get Add/Edit schema contextually #2852 @ericof
33
+
34
+ ### Internal
35
+
36
+ - Upgrade p.restapi to 8.15.2 @sneridagh
37
+
38
+ ## 14.0.0-alpha.34 (2021-11-20)
39
+
40
+ ### Feature
41
+
42
+ - Apply form defaults from RenderBlocks and block Edit using a new helper, `applyBlockDefaults` @tiberiuichim
43
+ - Now each block config object can declare a schema factory (a function that can produce a schema) and this will be used to derive the default data for the block @tiberiuichim
44
+
3
45
  ## 14.0.0-alpha.33 (2021-11-20)
4
46
 
5
47
  ### Bugfix
@@ -15,6 +57,8 @@
15
57
  ### Internal
16
58
 
17
59
  - Upgrade stylelint to v14 (vscode-stylelint requires it now) @sneridagh
60
+ - Add several more stories for Storybook @tiberiuichim
61
+ - Add 2 new Volto websites by Eau de web for EEA @tiberiuichim
18
62
 
19
63
  ## 14.0.0-alpha.32 (2021-11-09)
20
64
 
package/README.md CHANGED
@@ -138,7 +138,10 @@ Volto is actively developed since 2017 and used in production since 2018 on the
138
138
  - [Biblioteche Pianura Est](https://bibest.it) (Website of the Associated libraries of eastern plain. Developed by [RedTurtle](https://redturtle.it), 2021)
139
139
  - [Camera di Commercio di Reggio Emilia](https://www.re.camcom.gov.it/) (Website Chamber of Commerce of Reggio Emilia. Developed by [RedTurtle](https://redturtle.it), 2021)
140
140
  - [RawMaterial](https://rawmaterial.it/en) (Company's website. Developed by [RawMaterial](https://rawmaterial.it/en), 2021)
141
- - Please create a new [issue](https://github.com/plone/volto/issues/new) or [pull request](https://github.com/plone/volto/pulls) to add your Volto-site here!
141
+ - [WISE-Freshwater](https://water.europa.eu/freshwater) (WISE-Freshwater, the Freshwater Information System for Europe. Developed by [Eau de web](https://eaudeweb.ro) for the European Environmental Agency, 2021)
142
+ - [EEA-IMSv4](https://www.eea.europa.eu/ims) (EEA Indicator Management System v4. Developed by [Eau de web](https://eaudeweb.ro) for the European Environmental Agency, 2021)
143
+
144
+ Please create a new [issue](https://github.com/plone/volto/issues/new) or [pull request](https://github.com/plone/volto/pulls) to add your Volto-site here!
142
145
 
143
146
  ## Documentation
144
147
 
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  }
10
10
  ],
11
11
  "license": "MIT",
12
- "version": "14.0.0-alpha.33",
12
+ "version": "14.0.0-alpha.37",
13
13
  "repository": {
14
14
  "type": "git",
15
15
  "url": "git@github.com:plone/volto.git"
@@ -14,14 +14,16 @@ import {
14
14
  * Get schema function.
15
15
  * @function getSchema
16
16
  * @param {string} type Content type.
17
+ * @param {string} url Content url.
17
18
  * @returns {Object} Get schema action.
18
19
  */
19
- export function getSchema(type) {
20
+ export function getSchema(type, url) {
21
+ url = typeof url !== 'undefined' ? url : '';
20
22
  return {
21
23
  type: GET_SCHEMA,
22
24
  request: {
23
25
  op: 'get',
24
- path: `/@types/${type}`,
26
+ path: `${url}/@types/${type}`,
25
27
  },
26
28
  };
27
29
  }
@@ -11,5 +11,15 @@ describe('Schema action', () => {
11
11
  expect(action.request.op).toEqual('get');
12
12
  expect(action.request.path).toEqual(`/@types/${type}`);
13
13
  });
14
+
15
+ it('should create an action to get the schema if url is passed', () => {
16
+ const type = 'Document';
17
+ const url = '/path/to/folder';
18
+ const action = getSchema(type, url);
19
+
20
+ expect(action.type).toEqual(GET_SCHEMA);
21
+ expect(action.request.op).toEqual('get');
22
+ expect(action.request.path).toEqual(`${url}/@types/${type}`);
23
+ });
14
24
  });
15
25
  });
@@ -7,7 +7,7 @@ import {
7
7
  GET_VOCABULARY,
8
8
  GET_VOCABULARY_TOKEN_TITLE,
9
9
  } from '@plone/volto/constants/ActionTypes';
10
- import config from '@plone/volto/registry';
10
+ import { getVocabName } from '@plone/volto/helpers/Vocabularies/Vocabularies';
11
11
 
12
12
  /**
13
13
  * Get vocabulary given a URL (coming from a Schema) or from a vocabulary name.
@@ -18,11 +18,8 @@ import config from '@plone/volto/registry';
18
18
  * @returns {Object} Get vocabulary action.
19
19
  */
20
20
  export function getVocabulary(vocabNameOrURL, query = null, start = 0) {
21
- const { settings } = config;
22
21
  // In case we have a URL, we have to get the vocabulary name
23
- const vocabulary =
24
- vocabNameOrURL &&
25
- vocabNameOrURL.replace(`${settings.apiPath}/@vocabularies/`, '');
22
+ const vocabulary = getVocabName(vocabNameOrURL);
26
23
  let queryString = `b_start=${start}`;
27
24
  if (query) {
28
25
  queryString = `${queryString}&title=${query}`;
@@ -47,12 +44,8 @@ export function getVocabulary(vocabNameOrURL, query = null, start = 0) {
47
44
  * @returns {Object} Get vocabulary action.
48
45
  */
49
46
  export function getVocabularyTokenTitle(vocabNameOrURL, token = null) {
50
- const { settings } = config;
51
47
  // In case we have a URL, we have to get the vocabulary name
52
- const vocabulary = vocabNameOrURL.replace(
53
- `${settings.apiPath}/@vocabularies/`,
54
- '',
55
- );
48
+ const vocabulary = getVocabName(vocabNameOrURL);
56
49
 
57
50
  return {
58
51
  type: GET_VOCABULARY_TOKEN_TITLE,
@@ -15,5 +15,31 @@ describe('Vocabularies actions', () => {
15
15
  `/@vocabularies/${vocabulary}?b_start=0&title=${query}`,
16
16
  );
17
17
  });
18
+ it('should create an action to get a vocabulary if a URL is passed', () => {
19
+ const vocabulary =
20
+ 'http://localhost:8080/@vocabularies/plone.app.vocabularies.Keywords';
21
+ const query = 'john';
22
+ const action = getVocabulary(vocabulary, query);
23
+
24
+ expect(action.type).toEqual(GET_VOCABULARY);
25
+ expect(action.vocabulary).toEqual(vocabulary);
26
+ expect(action.request.op).toEqual('get');
27
+ expect(action.request.path).toEqual(
28
+ `/@vocabularies/plone.app.vocabularies.Keywords?b_start=0&title=${query}`,
29
+ );
30
+ });
31
+ it('should create an action to get a vocabulary if a URL with path is passed', () => {
32
+ const vocabulary =
33
+ 'http://localhost:8080/de/foo/bar/@vocabularies/plone.app.vocabularies.Keywords';
34
+ const query = 'john';
35
+ const action = getVocabulary(vocabulary, query);
36
+
37
+ expect(action.type).toEqual(GET_VOCABULARY);
38
+ expect(action.vocabulary).toEqual(vocabulary);
39
+ expect(action.request.op).toEqual('get');
40
+ expect(action.request.path).toEqual(
41
+ `/@vocabularies/plone.app.vocabularies.Keywords?b_start=0&title=${query}`,
42
+ );
43
+ });
18
44
  });
19
45
  });
@@ -149,7 +149,7 @@ class Add extends Component {
149
149
  * @returns {undefined}
150
150
  */
151
151
  componentDidMount() {
152
- this.props.getSchema(this.props.type);
152
+ this.props.getSchema(this.props.type, getBaseUrl(this.props.pathname));
153
153
  this.setState({ isClient: true });
154
154
  }
155
155
 
@@ -12,6 +12,7 @@ import cx from 'classnames';
12
12
  import { setSidebarTab } from '@plone/volto/actions';
13
13
  import config from '@plone/volto/registry';
14
14
  import withObjectBrowser from '@plone/volto/components/manage/Sidebar/ObjectBrowser';
15
+ import { applyBlockDefaults } from '@plone/volto/helpers';
15
16
 
16
17
  import {
17
18
  SidebarPortal,
@@ -165,7 +166,11 @@ export class Edit extends Component {
165
166
  /* eslint-disable jsx-a11y/no-noninteractive-tabindex */
166
167
  tabIndex={!blockHasOwnFocusManagement ? -1 : null}
167
168
  >
168
- <Block {...this.props} blockNode={this.blockNode} />
169
+ <Block
170
+ {...this.props}
171
+ blockNode={this.blockNode}
172
+ data={applyBlockDefaults(this.props)}
173
+ />
169
174
  {this.props.manage && (
170
175
  <SidebarPortal
171
176
  selected={this.props.selected}
@@ -15,7 +15,7 @@ const messages = defineMessages({
15
15
  },
16
16
  });
17
17
 
18
- const schemaHero = ({ props, intl }) => {
18
+ const schemaHero = ({ intl }) => {
19
19
  return {
20
20
  title: 'Block settings',
21
21
  required: [],
@@ -65,3 +65,5 @@ export const schemaListing = (props) => {
65
65
  required: [],
66
66
  };
67
67
  };
68
+
69
+ export default schemaListing;
@@ -136,7 +136,10 @@ class Edit extends Component {
136
136
  */
137
137
  componentDidMount() {
138
138
  if (this.props.getRequest.loaded && this.props.content?.['@type']) {
139
- this.props.getSchema(this.props.content['@type']);
139
+ this.props.getSchema(
140
+ this.props.content['@type'],
141
+ getBaseUrl(this.props.pathname),
142
+ );
140
143
  }
141
144
  this.setState({
142
145
  isClient: true,
@@ -448,7 +448,7 @@ class ObjectBrowserBody extends Component {
448
448
  <Segment className="infos">
449
449
  {this.props.intl.formatMessage(messages.SelectedItems)}:{' '}
450
450
  {this.props.data?.length}
451
- {this.props.maximumSelectionSize && (
451
+ {this.props.maximumSelectionSize > 0 && (
452
452
  <>
453
453
  {' '}
454
454
  {this.props.intl.formatMessage(messages.of)}{' '}
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import SidebarPopup from './SidebarPopup';
3
+ import Wrapper from '@plone/volto/storybook';
4
+
5
+ const SidebarComponent = ({ children, ...args }) => {
6
+ return (
7
+ <Wrapper location={{ pathname: '/folder2/folder21/doc212' }}>
8
+ <div className="ui segment form attached" style={{ width: '400px' }}>
9
+ <p>
10
+ Render a right-side sidebar. Mainly used to edit block settings and
11
+ documents metadata (in the case of composite pages, with blocks). Use
12
+ the controls to toggle the open state.
13
+ </p>
14
+ <SidebarPopup {...args}>
15
+ <div style={{ padding: '1em' }}>
16
+ <h1>What Is Volto</h1>
17
+ <p>
18
+ Volto is a React-based frontend for content management systems,
19
+ currently supporting three backend implementations: Plone,
20
+ Guillotina and a NodeJS reference implementation.
21
+ </p>
22
+ <p>
23
+ Plone is a powerful, flexible Content Management Solution that is
24
+ easy to install, use and extend..
25
+ </p>
26
+ </div>
27
+ </SidebarPopup>
28
+ </div>
29
+ </Wrapper>
30
+ );
31
+ };
32
+
33
+ export const Sidebar = SidebarComponent.bind({});
34
+ Sidebar.args = {
35
+ open: true,
36
+ };
37
+
38
+ export default {
39
+ title: 'Internal Components/Sidebar',
40
+ component: SidebarPopup,
41
+ argTypes: {},
42
+ };
@@ -1,15 +1,23 @@
1
- /**
2
- * AlignWidget component.
3
- * To benefit from styling integration, use with a field named 'align'
4
- * @module components/manage/Widgets/AlignWidget
5
- */
6
-
7
1
  import React from 'react';
8
2
  import { injectIntl } from 'react-intl';
9
3
 
10
4
  import { FormFieldWrapper } from '@plone/volto/components';
11
5
  import AlignBlock from '@plone/volto/components/manage/Sidebar/AlignBlock';
12
6
 
7
+ /**
8
+ * AlignWidget component.
9
+ * To benefit from styling integration, use with a field named 'align'
10
+ *
11
+ * Example how this field would look in schema:
12
+ *
13
+ * ```jsx
14
+ * {
15
+ * title: 'Align',
16
+ * description: 'Layout align',
17
+ * widget: 'align',
18
+ * }
19
+ * ```
20
+ */
13
21
  const AlignWidget = (props) => {
14
22
  const { id, onChange, value } = props;
15
23
  return (
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import AlignWidget from './AlignWidget';
3
+ import Wrapper from '@plone/volto/storybook';
4
+
5
+ const AlignWidgetComponent = ({ children, ...args }) => {
6
+ const [value, setValue] = React.useState([]);
7
+ const onChange = (block, value) => setValue(value);
8
+ return (
9
+ <Wrapper location={{ pathname: '/folder2/folder21/doc212' }}>
10
+ <div className="ui segment form attached" style={{ width: '400px' }}>
11
+ <AlignWidget
12
+ {...args}
13
+ id="alignWidgetItem"
14
+ title="Align"
15
+ block="testBlock"
16
+ value={value}
17
+ onChange={onChange}
18
+ />
19
+ </div>
20
+ </Wrapper>
21
+ );
22
+ };
23
+
24
+ export const Align = AlignWidgetComponent.bind({});
25
+
26
+ export default {
27
+ title: 'Widgets/Align',
28
+ component: AlignWidget,
29
+ decorators: [
30
+ (Story) => (
31
+ <div className="ui segment form attached" style={{ width: '400px' }}>
32
+ <h4>Standard layout-oriented align widget</h4>
33
+ <Story />
34
+ </div>
35
+ ),
36
+ ],
37
+ argTypes: {},
38
+ };
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { ArrayWidgetComponent } from './ArrayWidget';
3
3
  import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
4
- import Wrapper from '@plone/volto/storybook';
4
+ import { RealStoreWrapper as Wrapper } from '@plone/volto/storybook';
5
5
 
6
6
  const ArrayComponent = injectLazyLibs([
7
7
  'reactSelectCreateable',
@@ -155,7 +155,7 @@ Disabled.args = {
155
155
  };
156
156
 
157
157
  export default {
158
- title: 'Widgets/ArrayWidget',
158
+ title: 'Widgets/Array',
159
159
  component: ArrayComponent,
160
160
  decorators: [
161
161
  (Story) => (
@@ -14,6 +14,15 @@ import { FormFieldWrapper } from '@plone/volto/components';
14
14
  * CheckboxWidget component class.
15
15
  * @function CheckboxWidget
16
16
  * @returns {string} Markup of the component.
17
+ *
18
+ * To use it, in schema properties, declare a field like:
19
+ *
20
+ * ```jsx
21
+ * {
22
+ * title: "Active",
23
+ * type: 'boolean',
24
+ * }
25
+ * ```
17
26
  */
18
27
  const CheckboxWidget = (props) => {
19
28
  const { id, title, value, onChange, isDisabled } = props;
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import CheckboxWidget from './CheckboxWidget';
3
+ import Wrapper from '@plone/volto/storybook';
4
+
5
+ const CheckboxWidgetComponent = ({ children, ...args }) => {
6
+ const [value, setValue] = React.useState(false);
7
+ const onChange = (block, value) => setValue(value);
8
+ return (
9
+ <Wrapper location={{ pathname: '/folder2/folder21/doc212' }}>
10
+ <div className="ui segment form attached" style={{ width: '400px' }}>
11
+ <CheckboxWidget
12
+ {...args}
13
+ id="field"
14
+ title="Checkbox"
15
+ block="testBlock"
16
+ value={value}
17
+ onChange={onChange}
18
+ />
19
+ </div>
20
+ <pre>Value: {JSON.stringify(value, null, 4)}</pre>
21
+ </Wrapper>
22
+ );
23
+ };
24
+
25
+ export const Checkbox = CheckboxWidgetComponent.bind({});
26
+
27
+ export default {
28
+ title: 'Widgets/Checkbox',
29
+ component: CheckboxWidget,
30
+ decorators: [
31
+ (Story) => (
32
+ <div className="ui segment form attached" style={{ width: '400px' }}>
33
+ <Story />
34
+ </div>
35
+ ),
36
+ ],
37
+ argTypes: {},
38
+ };
@@ -70,6 +70,15 @@ const defaultTimeDateOnly = {
70
70
  * DatetimeWidget component class
71
71
  * @class DatetimeWidget
72
72
  * @extends Component
73
+ *
74
+ * To use it, in schema properties, declare a field like:
75
+ *
76
+ * ```jsx
77
+ * {
78
+ * title: "Publish date",
79
+ * type: 'datetime',
80
+ * }
81
+ * ```
73
82
  */
74
83
  class DatetimeWidget extends Component {
75
84
  /**
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import DatetimeWidget from './DatetimeWidget';
3
+ import Wrapper from '@plone/volto/storybook';
4
+
5
+ const DatetimeWidgetComponent = ({ children, ...args }) => {
6
+ const [value, setValue] = React.useState(false);
7
+ const onChange = (block, value) => setValue(value);
8
+ return (
9
+ <Wrapper location={{ pathname: '/folder2/folder21/doc212' }}>
10
+ <div className="ui segment form attached" style={{ width: '400px' }}>
11
+ <DatetimeWidget
12
+ {...args}
13
+ id="field"
14
+ title="Datetime"
15
+ block="testBlock"
16
+ value={value}
17
+ onChange={onChange}
18
+ />
19
+ </div>
20
+ <pre>Value: {JSON.stringify(value, null, 4)}</pre>
21
+ </Wrapper>
22
+ );
23
+ };
24
+
25
+ export const Datetime = DatetimeWidgetComponent.bind({});
26
+
27
+ export default {
28
+ title: 'Widgets/Datetime',
29
+ component: DatetimeWidget,
30
+ decorators: [
31
+ (Story) => (
32
+ <div className="ui segment form attached" style={{ width: '400px' }}>
33
+ <Story />
34
+ </div>
35
+ ),
36
+ ],
37
+ argTypes: {},
38
+ };
@@ -8,9 +8,16 @@ import PropTypes from 'prop-types';
8
8
  import React from 'react';
9
9
  import { Input } from 'semantic-ui-react';
10
10
 
11
- /** EmailWidget function component
12
- * @function EmailWidget
13
- * @returns {string} Markup of the component
11
+ /** EmailWidget, a widget for email addresses
12
+ *
13
+ * To use it, in schema properties, declare a field like:
14
+ *
15
+ * ```jsx
16
+ * {
17
+ * title: "Email",
18
+ * widget: 'email',
19
+ * }
20
+ * ```
14
21
  */
15
22
  const EmailWidget = (props) => {
16
23
  const { id, value, onChange, onBlur, onClick, minLength, maxLength } = props;
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import EmailWidget from './EmailWidget';
3
+ import Wrapper from '@plone/volto/storybook';
4
+
5
+ const EmailWidgetComponent = ({ children, ...args }) => {
6
+ const [value, setValue] = React.useState('');
7
+ const onChange = (block, value) => setValue(value);
8
+ return (
9
+ <Wrapper location={{ pathname: '/folder2/folder21/doc212' }}>
10
+ <div className="ui segment form attached" style={{ width: '400px' }}>
11
+ <EmailWidget
12
+ {...args}
13
+ id="field"
14
+ title="Email"
15
+ block="testBlock"
16
+ value={value}
17
+ onChange={onChange}
18
+ />
19
+ </div>
20
+ <pre>Value: {JSON.stringify(value, null, 4)}</pre>
21
+ </Wrapper>
22
+ );
23
+ };
24
+
25
+ export const Email = EmailWidgetComponent.bind({});
26
+
27
+ export default {
28
+ title: 'Widgets/Email',
29
+ component: EmailWidget,
30
+ decorators: [
31
+ (Story) => (
32
+ <div className="ui segment form attached" style={{ width: '400px' }}>
33
+ <Story />
34
+ </div>
35
+ ),
36
+ ],
37
+ argTypes: {},
38
+ };
@@ -51,6 +51,24 @@ const messages = defineMessages({
51
51
  * FileWidget component class.
52
52
  * @function FileWidget
53
53
  * @returns {string} Markup of the component.
54
+ *
55
+ * To use it, in schema properties, declare a field like:
56
+ *
57
+ * ```jsx
58
+ * {
59
+ * title: "File",
60
+ * widget: 'file',
61
+ * }
62
+ * ```
63
+ * or:
64
+ *
65
+ * ```jsx
66
+ * {
67
+ * title: "File",
68
+ * type: 'object',
69
+ * }
70
+ * ```
71
+ *
54
72
  */
55
73
  const FileWidget = (props) => {
56
74
  const { id, value, onChange } = props;
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import FileWidget from './FileWidget';
3
+ import Wrapper from '@plone/volto/storybook';
4
+
5
+ const FileWidgetComponent = ({ children, ...args }) => {
6
+ const [value, setValue] = React.useState('');
7
+ const onChange = (block, value) => setValue(value);
8
+ return (
9
+ <Wrapper location={{ pathname: '/folder2/folder21/doc212' }}>
10
+ <div className="ui segment form attached" style={{ width: '400px' }}>
11
+ <FileWidget
12
+ {...args}
13
+ id="field"
14
+ title="File"
15
+ block="testBlock"
16
+ value={value}
17
+ onChange={onChange}
18
+ />
19
+ </div>
20
+ <pre>Value: {JSON.stringify(value, null, 4)}</pre>
21
+ </Wrapper>
22
+ );
23
+ };
24
+
25
+ export const File = FileWidgetComponent.bind({});
26
+
27
+ export default {
28
+ title: 'Widgets/File',
29
+ component: FileWidget,
30
+ decorators: [
31
+ (Story) => (
32
+ <div className="ui segment form attached" style={{ width: '400px' }}>
33
+ <Story />
34
+ </div>
35
+ ),
36
+ ],
37
+ argTypes: {},
38
+ };
@@ -11,8 +11,15 @@ import { injectIntl } from 'react-intl';
11
11
 
12
12
  /**
13
13
  * NumberWidget component class.
14
- * @function NumberWidget
15
- * @returns {string} Markup of the component.
14
+ *
15
+ * To use it, in schema properties, declare a field like:
16
+ *
17
+ * ```jsx
18
+ * {
19
+ * title: "Number",
20
+ * type: 'number',
21
+ * }
22
+ * ```
16
23
  */
17
24
  const NumberWidget = (props) => {
18
25
  const {