@plone/volto 14.0.0 → 14.1.1

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 (216) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/locales/ca/LC_MESSAGES/volto.po +12 -2
  3. package/locales/ca.json +1 -1
  4. package/locales/de/LC_MESSAGES/volto.po +12 -2
  5. package/locales/de.json +1 -1
  6. package/locales/en/LC_MESSAGES/volto.po +12 -2
  7. package/locales/en.json +1 -1
  8. package/locales/es/LC_MESSAGES/volto.po +12 -2
  9. package/locales/es.json +1 -1
  10. package/locales/eu/LC_MESSAGES/volto.po +12 -2
  11. package/locales/eu.json +1 -1
  12. package/locales/fr/LC_MESSAGES/volto.po +12 -2
  13. package/locales/fr.json +1 -1
  14. package/locales/it/LC_MESSAGES/volto.po +12 -2
  15. package/locales/it.json +1 -1
  16. package/locales/ja/LC_MESSAGES/volto.po +12 -2
  17. package/locales/ja.json +1 -1
  18. package/locales/nl/LC_MESSAGES/volto.po +12 -2
  19. package/locales/nl.json +1 -1
  20. package/locales/pt/LC_MESSAGES/volto.po +12 -2
  21. package/locales/pt.json +1 -1
  22. package/locales/pt_BR/LC_MESSAGES/volto.po +12 -2
  23. package/locales/pt_BR.json +1 -1
  24. package/locales/ro/LC_MESSAGES/volto.po +12 -2
  25. package/locales/ro.json +1 -1
  26. package/locales/volto.pot +12 -2
  27. package/package.json +2 -1
  28. package/public/icon.svg +13 -0
  29. package/src/actions/vocabularies/vocabularies.js +15 -3
  30. package/src/components/index.js +1 -0
  31. package/src/components/manage/Blocks/HeroImageLeft/Edit.jsx +1 -1
  32. package/src/components/manage/Blocks/Listing/getAsyncData.js +1 -1
  33. package/src/components/manage/Blocks/Text/Edit.jsx +19 -0
  34. package/src/components/manage/Form/Form.jsx +11 -1
  35. package/src/components/manage/Form/UndoToolbar.jsx +78 -0
  36. package/src/components/manage/Widgets/AlignWidget.stories.jsx +5 -21
  37. package/src/components/manage/Widgets/ArrayWidget.jsx +83 -101
  38. package/src/components/manage/Widgets/ArrayWidget.stories.jsx +29 -64
  39. package/src/components/manage/Widgets/CheckboxWidget.stories.jsx +5 -22
  40. package/src/components/manage/Widgets/DatetimeWidget.jsx +65 -74
  41. package/src/components/manage/Widgets/DatetimeWidget.stories.jsx +7 -23
  42. package/src/components/manage/Widgets/DatetimeWidget.test.jsx +17 -15
  43. package/src/components/manage/Widgets/EmailWidget.stories.jsx +5 -22
  44. package/src/components/manage/Widgets/FileWidget.stories.jsx +5 -22
  45. package/src/components/manage/Widgets/NumberWidget.stories.jsx +5 -23
  46. package/src/components/manage/Widgets/ObjectBrowserWidget.stories.js +24 -32
  47. package/src/components/manage/Widgets/ObjectListWidget.stories.js +44 -44
  48. package/src/components/manage/Widgets/ObjectWidget.stories.jsx +13 -28
  49. package/src/components/manage/Widgets/PasswordWidget.stories.jsx +5 -22
  50. package/src/components/manage/Widgets/QueryWidget.jsx +2 -2
  51. package/src/components/manage/Widgets/QueryWidget.stories.jsx +1637 -22
  52. package/src/components/manage/Widgets/SelectAutoComplete.jsx +79 -48
  53. package/src/components/manage/Widgets/SelectAutoComplete.test.jsx +16 -0
  54. package/src/components/manage/Widgets/SelectAutocompleteWidget.stories.jsx +161 -0
  55. package/src/components/manage/Widgets/SelectUtils.js +90 -30
  56. package/src/components/manage/Widgets/SelectUtils.test.jsx +76 -1
  57. package/src/components/manage/Widgets/SelectWidget.jsx +26 -37
  58. package/src/components/manage/Widgets/SelectWidget.stories.jsx +96 -28
  59. package/src/components/manage/Widgets/TextWidget.stories.jsx +5 -22
  60. package/src/components/manage/Widgets/TextareaWidget.stories.jsx +5 -22
  61. package/src/components/manage/Widgets/TokenWidget.jsx +19 -17
  62. package/src/components/manage/Widgets/TokenWidget.stories.jsx +141 -0
  63. package/src/components/manage/Widgets/UrlWidget.stories.jsx +5 -21
  64. package/src/components/manage/Widgets/VocabularyTermsWidget.stories.js +27 -64
  65. package/src/components/manage/Widgets/WysiwygWidget.stories.jsx +5 -22
  66. package/src/components/manage/Widgets/story.jsx +38 -0
  67. package/src/components/theme/ContactForm/ContactForm.jsx +1 -0
  68. package/src/components/theme/ContactForm/ContactForm.stories.jsx +126 -0
  69. package/src/components/theme/CorsError/CorsError.jsx +2 -2
  70. package/src/config/Loadables.jsx +2 -0
  71. package/src/config/index.js +1 -0
  72. package/src/helpers/Html/Html.jsx +2 -12
  73. package/src/helpers/UndoManager/useUndoManager.js +102 -0
  74. package/src/helpers/index.js +1 -0
  75. package/src/middleware/Api.test.js +57 -6
  76. package/src/middleware/api.js +34 -13
  77. package/src/reducers/vocabularies/vocabularies.js +13 -2
  78. package/src/store.js +1 -1
  79. package/src/storybook.jsx +55 -0
  80. package/theme/themes/pastanaga/extras/time-picker-overrides.less +1 -1
  81. package/include/python3.8/Python-ast.h +0 -715
  82. package/include/python3.8/Python.h +0 -160
  83. package/include/python3.8/abstract.h +0 -844
  84. package/include/python3.8/asdl.h +0 -46
  85. package/include/python3.8/ast.h +0 -37
  86. package/include/python3.8/bitset.h +0 -23
  87. package/include/python3.8/bltinmodule.h +0 -14
  88. package/include/python3.8/boolobject.h +0 -34
  89. package/include/python3.8/bytearrayobject.h +0 -62
  90. package/include/python3.8/bytes_methods.h +0 -69
  91. package/include/python3.8/bytesobject.h +0 -224
  92. package/include/python3.8/cellobject.h +0 -29
  93. package/include/python3.8/ceval.h +0 -231
  94. package/include/python3.8/classobject.h +0 -59
  95. package/include/python3.8/code.h +0 -180
  96. package/include/python3.8/codecs.h +0 -240
  97. package/include/python3.8/compile.h +0 -106
  98. package/include/python3.8/complexobject.h +0 -69
  99. package/include/python3.8/context.h +0 -84
  100. package/include/python3.8/cpython/abstract.h +0 -319
  101. package/include/python3.8/cpython/dictobject.h +0 -94
  102. package/include/python3.8/cpython/fileobject.h +0 -24
  103. package/include/python3.8/cpython/initconfig.h +0 -434
  104. package/include/python3.8/cpython/interpreteridobject.h +0 -19
  105. package/include/python3.8/cpython/object.h +0 -470
  106. package/include/python3.8/cpython/objimpl.h +0 -113
  107. package/include/python3.8/cpython/pyerrors.h +0 -188
  108. package/include/python3.8/cpython/pylifecycle.h +0 -78
  109. package/include/python3.8/cpython/pymem.h +0 -108
  110. package/include/python3.8/cpython/pystate.h +0 -252
  111. package/include/python3.8/cpython/sysmodule.h +0 -21
  112. package/include/python3.8/cpython/traceback.h +0 -22
  113. package/include/python3.8/cpython/tupleobject.h +0 -36
  114. package/include/python3.8/cpython/unicodeobject.h +0 -1239
  115. package/include/python3.8/datetime.h +0 -259
  116. package/include/python3.8/descrobject.h +0 -108
  117. package/include/python3.8/dictobject.h +0 -94
  118. package/include/python3.8/dtoa.h +0 -19
  119. package/include/python3.8/dynamic_annotations.h +0 -499
  120. package/include/python3.8/enumobject.h +0 -17
  121. package/include/python3.8/errcode.h +0 -38
  122. package/include/python3.8/eval.h +0 -37
  123. package/include/python3.8/fileobject.h +0 -49
  124. package/include/python3.8/fileutils.h +0 -185
  125. package/include/python3.8/floatobject.h +0 -130
  126. package/include/python3.8/frameobject.h +0 -92
  127. package/include/python3.8/funcobject.h +0 -104
  128. package/include/python3.8/genobject.h +0 -109
  129. package/include/python3.8/graminit.h +0 -94
  130. package/include/python3.8/grammar.h +0 -77
  131. package/include/python3.8/import.h +0 -149
  132. package/include/python3.8/internal/pycore_accu.h +0 -39
  133. package/include/python3.8/internal/pycore_atomic.h +0 -558
  134. package/include/python3.8/internal/pycore_ceval.h +0 -37
  135. package/include/python3.8/internal/pycore_code.h +0 -27
  136. package/include/python3.8/internal/pycore_condvar.h +0 -95
  137. package/include/python3.8/internal/pycore_context.h +0 -42
  138. package/include/python3.8/internal/pycore_fileutils.h +0 -54
  139. package/include/python3.8/internal/pycore_getopt.h +0 -22
  140. package/include/python3.8/internal/pycore_gil.h +0 -50
  141. package/include/python3.8/internal/pycore_hamt.h +0 -116
  142. package/include/python3.8/internal/pycore_initconfig.h +0 -166
  143. package/include/python3.8/internal/pycore_object.h +0 -81
  144. package/include/python3.8/internal/pycore_pathconfig.h +0 -75
  145. package/include/python3.8/internal/pycore_pyerrors.h +0 -62
  146. package/include/python3.8/internal/pycore_pyhash.h +0 -10
  147. package/include/python3.8/internal/pycore_pylifecycle.h +0 -118
  148. package/include/python3.8/internal/pycore_pymem.h +0 -212
  149. package/include/python3.8/internal/pycore_pystate.h +0 -326
  150. package/include/python3.8/internal/pycore_traceback.h +0 -96
  151. package/include/python3.8/internal/pycore_tupleobject.h +0 -19
  152. package/include/python3.8/internal/pycore_warnings.h +0 -25
  153. package/include/python3.8/interpreteridobject.h +0 -17
  154. package/include/python3.8/intrcheck.h +0 -33
  155. package/include/python3.8/iterobject.h +0 -25
  156. package/include/python3.8/listobject.h +0 -81
  157. package/include/python3.8/longintrepr.h +0 -99
  158. package/include/python3.8/longobject.h +0 -242
  159. package/include/python3.8/marshal.h +0 -28
  160. package/include/python3.8/memoryobject.h +0 -72
  161. package/include/python3.8/methodobject.h +0 -131
  162. package/include/python3.8/modsupport.h +0 -248
  163. package/include/python3.8/moduleobject.h +0 -90
  164. package/include/python3.8/namespaceobject.h +0 -19
  165. package/include/python3.8/node.h +0 -48
  166. package/include/python3.8/object.h +0 -753
  167. package/include/python3.8/objimpl.h +0 -284
  168. package/include/python3.8/odictobject.h +0 -43
  169. package/include/python3.8/opcode.h +0 -148
  170. package/include/python3.8/osdefs.h +0 -51
  171. package/include/python3.8/osmodule.h +0 -17
  172. package/include/python3.8/parsetok.h +0 -110
  173. package/include/python3.8/patchlevel.h +0 -35
  174. package/include/python3.8/picklebufobject.h +0 -31
  175. package/include/python3.8/py_curses.h +0 -100
  176. package/include/python3.8/pyarena.h +0 -64
  177. package/include/python3.8/pycapsule.h +0 -59
  178. package/include/python3.8/pyconfig.h +0 -1665
  179. package/include/python3.8/pyctype.h +0 -39
  180. package/include/python3.8/pydebug.h +0 -40
  181. package/include/python3.8/pydtrace.h +0 -59
  182. package/include/python3.8/pydtrace_probes.h +0 -228
  183. package/include/python3.8/pyerrors.h +0 -335
  184. package/include/python3.8/pyexpat.h +0 -55
  185. package/include/python3.8/pyfpe.h +0 -12
  186. package/include/python3.8/pyhash.h +0 -145
  187. package/include/python3.8/pylifecycle.h +0 -75
  188. package/include/python3.8/pymacconfig.h +0 -102
  189. package/include/python3.8/pymacro.h +0 -106
  190. package/include/python3.8/pymath.h +0 -230
  191. package/include/python3.8/pymem.h +0 -150
  192. package/include/python3.8/pyport.h +0 -850
  193. package/include/python3.8/pystate.h +0 -136
  194. package/include/python3.8/pystrcmp.h +0 -23
  195. package/include/python3.8/pystrhex.h +0 -22
  196. package/include/python3.8/pystrtod.h +0 -45
  197. package/include/python3.8/pythonrun.h +0 -210
  198. package/include/python3.8/pythread.h +0 -161
  199. package/include/python3.8/pytime.h +0 -246
  200. package/include/python3.8/rangeobject.h +0 -27
  201. package/include/python3.8/setobject.h +0 -108
  202. package/include/python3.8/sliceobject.h +0 -65
  203. package/include/python3.8/structmember.h +0 -74
  204. package/include/python3.8/structseq.h +0 -49
  205. package/include/python3.8/symtable.h +0 -123
  206. package/include/python3.8/sysmodule.h +0 -41
  207. package/include/python3.8/token.h +0 -92
  208. package/include/python3.8/traceback.h +0 -28
  209. package/include/python3.8/tracemalloc.h +0 -38
  210. package/include/python3.8/tupleobject.h +0 -48
  211. package/include/python3.8/typeslots.h +0 -85
  212. package/include/python3.8/ucnhash.h +0 -36
  213. package/include/python3.8/unicodeobject.h +0 -1044
  214. package/include/python3.8/warnings.h +0 -67
  215. package/include/python3.8/weakrefobject.h +0 -86
  216. package/src/components/theme/ContactForm/ContactForm.stories.mdx +0 -39
@@ -16,7 +16,7 @@ import {
16
16
  } from '@plone/volto/helpers';
17
17
  import { FormFieldWrapper } from '@plone/volto/components';
18
18
  import { getVocabulary, getVocabularyTokenTitle } from '@plone/volto/actions';
19
- import { normalizeValue } from './SelectUtils';
19
+ import { normalizeValue } from '@plone/volto/components/manage/Widgets/SelectUtils';
20
20
 
21
21
  import {
22
22
  customSelectStyles,
@@ -107,6 +107,8 @@ class SelectWidget extends Component {
107
107
  PropTypes.object,
108
108
  PropTypes.string,
109
109
  PropTypes.bool,
110
+ PropTypes.func,
111
+ PropTypes.array,
110
112
  ]),
111
113
  onChange: PropTypes.func.isRequired,
112
114
  onBlur: PropTypes.func,
@@ -115,6 +117,8 @@ class SelectWidget extends Component {
115
117
  onDelete: PropTypes.func,
116
118
  wrapped: PropTypes.bool,
117
119
  noValueOption: PropTypes.bool,
120
+ customOptionStyling: PropTypes.any,
121
+ isMulti: PropTypes.bool,
118
122
  };
119
123
 
120
124
  /**
@@ -140,11 +144,7 @@ class SelectWidget extends Component {
140
144
  onEdit: null,
141
145
  onDelete: null,
142
146
  noValueOption: true,
143
- };
144
-
145
- state = {
146
- // TODO: also take into account this.props.defaultValue?
147
- selectedOption: normalizeValue(this.props.choices, this.props.value),
147
+ customOptionStyling: null,
148
148
  };
149
149
 
150
150
  /**
@@ -165,32 +165,14 @@ class SelectWidget extends Component {
165
165
  }
166
166
  }
167
167
 
168
- componentDidUpdate() {
169
- if (
170
- !this.state.selectedOption &&
171
- this.props.value &&
172
- this.props.choices?.length > 0
173
- ) {
174
- const normalizedValue = normalizeValue(
175
- this.props.choices,
176
- this.props.value,
177
- );
178
-
179
- if (normalizedValue != null) {
180
- this.setState({
181
- selectedOption: normalizedValue,
182
- });
183
- }
184
- }
185
- }
186
-
187
168
  /**
188
169
  * Render method.
189
170
  * @method render
190
171
  * @returns {string} Markup for the component.
191
172
  */
192
173
  render() {
193
- const { id, choices, onChange } = this.props;
174
+ const { id, choices, value, intl, onChange } = this.props;
175
+ const normalizedValue = normalizeValue(choices, value, intl);
194
176
  // Make sure that both disabled and isDisabled (from the DX layout feat work)
195
177
  const disabled = this.props.disabled || this.props.isDisabled;
196
178
  const Select = this.props.reactSelect.default;
@@ -216,6 +198,10 @@ class SelectWidget extends Component {
216
198
  : []),
217
199
  ];
218
200
 
201
+ const isMulti = this.props.isMulti
202
+ ? this.props.isMulti
203
+ : id === 'roles' || id === 'groups';
204
+
219
205
  return (
220
206
  <FormFieldWrapper {...this.props}>
221
207
  <Select
@@ -226,11 +212,7 @@ class SelectWidget extends Component {
226
212
  isSearchable={true}
227
213
  className="react-select-container"
228
214
  classNamePrefix="react-select"
229
- isMulti={
230
- this.props.isMulti
231
- ? this.props.isMulti
232
- : id === 'roles' || id === 'groups'
233
- }
215
+ isMulti={isMulti}
234
216
  options={options}
235
217
  styles={customSelectStyles}
236
218
  theme={selectTheme}
@@ -240,12 +222,20 @@ class SelectWidget extends Component {
240
222
  }),
241
223
  DropdownIndicator,
242
224
  ClearIndicator,
243
- Option,
225
+ Option: this.props.customOptionStyling || Option,
244
226
  }}
245
- value={this.state.selectedOption}
246
- placeholder={this.props.intl.formatMessage(messages.select)}
227
+ value={normalizedValue}
228
+ placeholder={
229
+ this.props.placeholder ??
230
+ this.props.intl.formatMessage(messages.select)
231
+ }
247
232
  onChange={(selectedOption) => {
248
- this.setState({ selectedOption });
233
+ if (isMulti) {
234
+ return onChange(
235
+ id,
236
+ selectedOption.map((el) => el.value),
237
+ );
238
+ }
249
239
  return onChange(
250
240
  id,
251
241
  selectedOption && selectedOption.value !== 'no-value'
@@ -263,7 +253,6 @@ class SelectWidget extends Component {
263
253
  export const SelectWidgetComponent = injectIntl(SelectWidget);
264
254
 
265
255
  export default compose(
266
- injectIntl,
267
256
  injectLazyLibs(['reactSelect']),
268
257
  connect(
269
258
  (state, props) => {
@@ -298,4 +287,4 @@ export default compose(
298
287
  },
299
288
  { getVocabulary, getVocabularyTokenTitle },
300
289
  ),
301
- )(SelectWidget);
290
+ )(SelectWidgetComponent);
@@ -1,30 +1,24 @@
1
1
  import React from 'react';
2
- import { SelectWidgetComponent } from './SelectWidget';
3
- import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
4
- import { RealStoreWrapper as Wrapper } from '@plone/volto/storybook';
2
+ import SelectWidget, { SelectWidgetComponent } from './SelectWidget';
3
+ import WidgetStory from './story';
5
4
 
6
- const SelectComponent = injectLazyLibs(['reactSelect'])(SelectWidgetComponent);
5
+ import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
6
+ import checkSVG from '@plone/volto/icons/check.svg';
7
+ import { Icon } from '@plone/volto/components';
7
8
 
8
- const Select = (args) => {
9
- const [value, setValue] = React.useState(args.value ?? '');
10
- const onChange = (block, value) => {
11
- // args.onChange({ value });
12
- setValue(value);
13
- };
9
+ import bellRingingSVG from '@plone/volto/icons/bell-ringing.svg';
10
+ import blogSVG from '@plone/volto/icons/blog.svg';
11
+ import bookSVG from '@plone/volto/icons/book.svg';
14
12
 
15
- return (
16
- <Wrapper>
17
- <SelectComponent {...args} onChange={onChange} value={value} />
18
- </Wrapper>
19
- );
20
- };
21
-
22
- export const Default = Select.bind({});
13
+ export const Default = WidgetStory.bind({
14
+ widget: SelectWidget,
15
+ });
23
16
  Default.args = {
24
17
  id: 'field-empty',
25
18
  title: 'field 1 title',
26
19
  description: 'Optional help text',
27
20
  placeholder: 'Type something…',
21
+ isMulti: false,
28
22
  choices: [
29
23
  ['Foo', 'Foo'],
30
24
  ['Bar', 'Bar'],
@@ -32,7 +26,9 @@ Default.args = {
32
26
  ],
33
27
  };
34
28
 
35
- export const Required = Select.bind({});
29
+ export const Required = WidgetStory.bind({
30
+ widget: SelectWidget,
31
+ });
36
32
  Required.args = {
37
33
  id: 'field-empty',
38
34
  title: 'field 1 title',
@@ -46,7 +42,9 @@ Required.args = {
46
42
  required: true,
47
43
  };
48
44
 
49
- export const Filled = Select.bind({});
45
+ export const Filled = WidgetStory.bind({
46
+ widget: SelectWidget,
47
+ });
50
48
  Filled.args = {
51
49
  id: 'field-filled',
52
50
  title: 'Filled field title',
@@ -61,7 +59,9 @@ Filled.args = {
61
59
  required: true,
62
60
  };
63
61
 
64
- export const Errored = Select.bind({});
62
+ export const Errored = WidgetStory.bind({
63
+ widget: SelectWidget,
64
+ });
65
65
  Errored.args = {
66
66
  id: 'field-errored',
67
67
  title: 'Errored field title',
@@ -88,7 +88,9 @@ Errored.args = {
88
88
  required: true,
89
89
  };
90
90
 
91
- export const NoPlaceholder = Select.bind({});
91
+ export const NoPlaceholder = WidgetStory.bind({
92
+ widget: SelectWidget,
93
+ });
92
94
  NoPlaceholder.args = {
93
95
  id: 'field-without-novalue',
94
96
  title: 'Field title',
@@ -101,7 +103,9 @@ NoPlaceholder.args = {
101
103
  required: true,
102
104
  };
103
105
 
104
- export const WithoutNoValueOption = Select.bind({});
106
+ export const WithoutNoValueOption = WidgetStory.bind({
107
+ widget: SelectWidget,
108
+ });
105
109
  WithoutNoValueOption.args = {
106
110
  id: 'field-without-novalue',
107
111
  title: 'Field title',
@@ -116,7 +120,9 @@ WithoutNoValueOption.args = {
116
120
  noValueOption: false,
117
121
  };
118
122
 
119
- export const VocabularyBased = Select.bind({});
123
+ export const VocabularyBased = WidgetStory.bind({
124
+ widget: SelectWidget,
125
+ });
120
126
  VocabularyBased.args = {
121
127
  id: 'field-vocab-based',
122
128
  title: 'field title',
@@ -143,7 +149,9 @@ VocabularyBased.args = {
143
149
  vocabBaseUrl: 'https://anapivocabularyURL',
144
150
  };
145
151
 
146
- export const Disabled = Select.bind({});
152
+ export const Disabled = WidgetStory.bind({
153
+ widget: SelectWidget,
154
+ });
147
155
  Disabled.args = {
148
156
  id: 'field-disabled',
149
157
  title: 'Disabled field title',
@@ -159,7 +167,9 @@ const getOptionsGenerator = (count) => {
159
167
  return options;
160
168
  };
161
169
 
162
- export const ManyOptions1000 = Select.bind({});
170
+ export const ManyOptions1000 = WidgetStory.bind({
171
+ widget: SelectWidget,
172
+ });
163
173
  ManyOptions1000.args = {
164
174
  id: 'field-empty',
165
175
  title: 'field 1 title',
@@ -168,7 +178,9 @@ ManyOptions1000.args = {
168
178
  choices: getOptionsGenerator(1000),
169
179
  };
170
180
 
171
- export const ManyOptions500 = Select.bind({});
181
+ export const ManyOptions500 = WidgetStory.bind({
182
+ widget: SelectWidget,
183
+ });
172
184
  ManyOptions500.args = {
173
185
  id: 'field-empty',
174
186
  title: 'field 1 title',
@@ -177,9 +189,65 @@ ManyOptions500.args = {
177
189
  choices: getOptionsGenerator(500),
178
190
  };
179
191
 
192
+ export const MultiSelection = WidgetStory.bind({
193
+ widget: SelectWidget,
194
+ });
195
+ MultiSelection.args = {
196
+ id: 'field-empty',
197
+ title: 'field 1 title',
198
+ description: 'Select multiple values',
199
+ placeholder: 'Type something…',
200
+ isMulti: true,
201
+ choices: [
202
+ ['Foo', 'Foo'],
203
+ ['Bar', 'Bar'],
204
+ ['FooBar', 'FooBar'],
205
+ ],
206
+ };
207
+
208
+ const Option = injectLazyLibs('reactSelect')((props) => {
209
+ const { Option } = props.reactSelect.components;
210
+ const icons = {
211
+ FooBar: bellRingingSVG,
212
+ Bar: blogSVG,
213
+ Foo: bookSVG,
214
+ };
215
+ return (
216
+ <Option {...props}>
217
+ <div>
218
+ {icons[props.value] && <Icon name={icons[props.value]} size="24px" />}
219
+ {props.label}
220
+ </div>
221
+ {props.isFocused && !props.isSelected && (
222
+ <Icon name={checkSVG} size="24px" color="#b8c6c8" />
223
+ )}
224
+ {props.isSelected && <Icon name={checkSVG} size="24px" color="#007bc1" />}
225
+ </Option>
226
+ );
227
+ });
228
+
229
+ export const CustomOptions = WidgetStory.bind({
230
+ widget: SelectWidget,
231
+ props: {
232
+ customOptionStyling: Option,
233
+ },
234
+ });
235
+ CustomOptions.args = {
236
+ id: 'field-empty',
237
+ title: 'field 1 title',
238
+ description: 'Select a value',
239
+ placeholder: 'Type something…',
240
+ isMulti: false,
241
+ choices: [
242
+ ['Foo', 'Foo'],
243
+ ['Bar', 'Bar'],
244
+ ['FooBar', 'FooBar'],
245
+ ],
246
+ };
247
+
180
248
  export default {
181
249
  title: 'Widgets/Select Widget',
182
- component: SelectComponent,
250
+ component: SelectWidgetComponent,
183
251
  decorators: [
184
252
  (Story) => (
185
253
  <div style={{ width: '400px' }}>
@@ -1,28 +1,11 @@
1
1
  import React from 'react';
2
2
  import TextWidget from './TextWidget';
3
- import Wrapper from '@plone/volto/storybook';
3
+ import WidgetStory from './story';
4
4
 
5
- const TextWidgetComponent = ({ 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
- <TextWidget
12
- {...args}
13
- id="field"
14
- title="Text"
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 Text = TextWidgetComponent.bind({});
5
+ export const Text = WidgetStory.bind({
6
+ props: { id: 'text', title: 'Text' },
7
+ widget: TextWidget,
8
+ });
26
9
 
27
10
  export default {
28
11
  title: 'Widgets/Text',
@@ -1,28 +1,11 @@
1
1
  import React from 'react';
2
2
  import TextareaWidget from './TextareaWidget';
3
- import Wrapper from '@plone/volto/storybook';
3
+ import WidgetStory from './story';
4
4
 
5
- const TextareaWidgetComponent = ({ 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
- <TextareaWidget
12
- {...args}
13
- id="field"
14
- title="Textarea"
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 Textarea = TextareaWidgetComponent.bind({});
5
+ export const Textarea = WidgetStory.bind({
6
+ props: { id: 'textarea', title: 'Text area', block: 'block' },
7
+ widget: TextareaWidget,
8
+ });
26
9
 
27
10
  export default {
28
11
  title: 'Widgets/Textarea',
@@ -1,6 +1,6 @@
1
1
  /**
2
- * ArrayWidget component.
3
- * @module components/manage/Widgets/ArrayWidget
2
+ * TokenWidget component.
3
+ * @module components/manage/Widgets/TokenWidget
4
4
  */
5
5
 
6
6
  import React, { Component } from 'react';
@@ -39,6 +39,11 @@ const messages = defineMessages({
39
39
 
40
40
  /**
41
41
  * TokenWidget component class.
42
+ *
43
+ * Because new terms are created through the web by using the widget, the token
44
+ * widget conflates the meaning of token, label and value and assumes they can
45
+ * be used interchangeably.
46
+ *
42
47
  * @class TokenWidget
43
48
  * @extends Component
44
49
  */
@@ -95,12 +100,6 @@ class TokenWidget extends Component {
95
100
  constructor(props) {
96
101
  super(props);
97
102
  this.handleChange = this.handleChange.bind(this);
98
-
99
- this.state = {
100
- selectedOption: props.value
101
- ? props.value.map((item) => ({ label: item, value: item }))
102
- : [],
103
- };
104
103
  }
105
104
 
106
105
  /**
@@ -109,11 +108,13 @@ class TokenWidget extends Component {
109
108
  * @returns {undefined}
110
109
  */
111
110
  componentDidMount() {
112
- this.props.getVocabulary({
113
- vocabNameOrURL: this.props.vocabBaseUrl,
114
- size: -1,
115
- subrequest: this.props.intl.locale,
116
- });
111
+ if (!this.props.choices?.length) {
112
+ this.props.getVocabulary({
113
+ vocabNameOrURL: this.props.vocabBaseUrl,
114
+ size: -1,
115
+ subrequest: this.props.intl.locale,
116
+ });
117
+ }
117
118
  }
118
119
 
119
120
  /**
@@ -124,7 +125,6 @@ class TokenWidget extends Component {
124
125
  * @returns {undefined}
125
126
  */
126
127
  handleChange(selectedOption) {
127
- this.setState({ selectedOption });
128
128
  this.props.onChange(
129
129
  this.props.id,
130
130
  selectedOption ? selectedOption.map((item) => item.label) : null,
@@ -137,11 +137,13 @@ class TokenWidget extends Component {
137
137
  * @returns {string} Markup for the component.
138
138
  */
139
139
  render() {
140
- const { selectedOption } = this.state;
140
+ const selectedOption = this.props.value
141
+ ? this.props.value.map((item) => ({ label: item, value: item }))
142
+ : [];
143
+
141
144
  const defaultOptions = (this.props.choices || [])
142
145
  .filter(
143
- (item) =>
144
- !this.state.selectedOption.find(({ label }) => label === item.label),
146
+ (item) => !selectedOption.find(({ label }) => label === item.label),
145
147
  )
146
148
  .map((item) => ({
147
149
  label: item.label || item.value,
@@ -0,0 +1,141 @@
1
+ import React from 'react';
2
+ import TokenWidget from './TokenWidget';
3
+
4
+ import WidgetStory from './story';
5
+
6
+ const vocabBaseUrl = 'https://anapivocabularyURL';
7
+
8
+ const defaults = {
9
+ widget: TokenWidget,
10
+ props: {
11
+ widgetOptions: {
12
+ vocabulary: {
13
+ '@id': vocabBaseUrl,
14
+ },
15
+ },
16
+ },
17
+ customStore: {
18
+ userSession: { token: '1234' },
19
+ intl: {
20
+ locale: 'en',
21
+ messages: {},
22
+ },
23
+ vocabularies: {
24
+ [vocabBaseUrl]: {
25
+ subrequests: {
26
+ en: {
27
+ items: [
28
+ { value: 'foo', label: 'Foo' },
29
+ { value: 'bar', label: 'Bar' },
30
+ { value: 'fooBar', label: 'FooBar' },
31
+ ],
32
+ },
33
+ },
34
+ },
35
+ },
36
+ },
37
+ };
38
+
39
+ export const Default = WidgetStory.bind(defaults);
40
+ Default.args = {
41
+ id: 'field-empty',
42
+ title: 'field 1 title',
43
+ description: 'Optional help text',
44
+ placeholder: 'Type something…',
45
+ vocabBaseUrl,
46
+ };
47
+
48
+ export const Required = WidgetStory.bind(defaults);
49
+ Required.args = {
50
+ id: 'field-empty',
51
+ title: 'field 1 title',
52
+ description: 'Optional help text',
53
+ placeholder: 'Type something…',
54
+ required: true,
55
+ vocabBaseUrl,
56
+ };
57
+
58
+ export const Filled = WidgetStory.bind(defaults);
59
+ Filled.args = {
60
+ id: 'field-filled',
61
+ title: 'Filled field title',
62
+ description: 'Optional help text',
63
+ value: ['Foo'],
64
+ placeholder: 'Type something…',
65
+ required: true,
66
+ vocabBaseUrl,
67
+ };
68
+
69
+ export const Errored = WidgetStory.bind(defaults);
70
+ Errored.args = {
71
+ id: 'field-errored',
72
+ title: 'Errored field title',
73
+ description: 'Optional help text',
74
+ placeholder: 'Type something…',
75
+ // Simplest example in Plone - a "hardcoded, hand made" vocab using SimpleVocabulary/SimpleTerm
76
+ // allow_discussion = schema.Choice(
77
+ // title=_(u'Allow discussion'),
78
+ // description=_(u'Allow discussion for this content object.'),
79
+ // vocabulary=SimpleVocabulary([
80
+ // SimpleTerm(value=True, title=_(u'Yes')),
81
+ // SimpleTerm(value=False, title=_(u'No')),
82
+ // ]),
83
+ // required=False,
84
+ // default=None,
85
+ // )
86
+ value: ['Foo'],
87
+ error: ['This is the error'],
88
+ required: true,
89
+ vocabBaseUrl,
90
+ };
91
+
92
+ export const NoPlaceholder = WidgetStory.bind(defaults);
93
+ NoPlaceholder.args = {
94
+ id: 'field-without-novalue',
95
+ title: 'Field title',
96
+ description: 'This field has no value option',
97
+ required: true,
98
+ vocabBaseUrl,
99
+ };
100
+
101
+ export const WithoutNoValueOption = WidgetStory.bind(defaults);
102
+ WithoutNoValueOption.args = {
103
+ id: 'field-without-novalue',
104
+ title: 'Field title',
105
+ description: 'This field has no value option',
106
+ placeholder: 'something…',
107
+ required: true,
108
+ noValueOption: false,
109
+ vocabBaseUrl,
110
+ };
111
+
112
+ export const Disabled = WidgetStory.bind(defaults);
113
+ Disabled.args = {
114
+ id: 'field-disabled',
115
+ title: 'Disabled field title',
116
+ description: 'This select field is disabled',
117
+ disabled: true,
118
+ vocabBaseUrl,
119
+ };
120
+
121
+ export default {
122
+ title: 'Widgets/Token',
123
+ component: TokenWidget,
124
+ decorators: [
125
+ (Story) => (
126
+ <div style={{ width: '400px' }}>
127
+ <Story />
128
+ </div>
129
+ ),
130
+ ],
131
+ argTypes: {
132
+ // controlled value prop
133
+ value: {
134
+ control: {
135
+ disable: true,
136
+ },
137
+ },
138
+ },
139
+ // excludeStories: ['searchResults'],
140
+ // subcomponents: { ArgsTable },
141
+ };
@@ -1,28 +1,12 @@
1
1
  import React from 'react';
2
2
  import UrlWidgetDefault, { UrlWidget } from './UrlWidget';
3
- import Wrapper from '@plone/volto/storybook';
4
3
 
5
- const UrlWidgetComponent = ({ 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
- <UrlWidgetDefault
12
- {...args}
13
- id="field"
14
- title="Url"
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
- };
4
+ import WidgetStory from './story';
24
5
 
25
- export const Url = UrlWidgetComponent.bind({});
6
+ export const Url = WidgetStory.bind({
7
+ props: { id: 'align', title: 'URL' },
8
+ widget: UrlWidgetDefault,
9
+ });
26
10
 
27
11
  export default {
28
12
  title: 'Widgets/Url',