@plone/volto 14.0.2 → 14.1.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.
Files changed (212) hide show
  1. package/CHANGELOG.md +22 -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/src/actions/vocabularies/vocabularies.js +14 -3
  29. package/src/components/index.js +1 -0
  30. package/src/components/manage/Blocks/HeroImageLeft/Edit.jsx +1 -1
  31. package/src/components/manage/Blocks/Listing/getAsyncData.js +1 -1
  32. package/src/components/manage/Blocks/Text/Edit.jsx +19 -0
  33. package/src/components/manage/Form/Form.jsx +11 -1
  34. package/src/components/manage/Form/UndoToolbar.jsx +78 -0
  35. package/src/components/manage/Widgets/AlignWidget.stories.jsx +5 -21
  36. package/src/components/manage/Widgets/ArrayWidget.jsx +83 -101
  37. package/src/components/manage/Widgets/ArrayWidget.stories.jsx +29 -64
  38. package/src/components/manage/Widgets/CheckboxWidget.stories.jsx +5 -22
  39. package/src/components/manage/Widgets/DatetimeWidget.jsx +65 -74
  40. package/src/components/manage/Widgets/DatetimeWidget.stories.jsx +7 -23
  41. package/src/components/manage/Widgets/DatetimeWidget.test.jsx +17 -15
  42. package/src/components/manage/Widgets/EmailWidget.stories.jsx +5 -22
  43. package/src/components/manage/Widgets/FileWidget.stories.jsx +5 -22
  44. package/src/components/manage/Widgets/NumberWidget.stories.jsx +5 -23
  45. package/src/components/manage/Widgets/ObjectBrowserWidget.stories.js +24 -32
  46. package/src/components/manage/Widgets/ObjectListWidget.stories.js +44 -44
  47. package/src/components/manage/Widgets/ObjectWidget.stories.jsx +13 -28
  48. package/src/components/manage/Widgets/PasswordWidget.stories.jsx +5 -22
  49. package/src/components/manage/Widgets/QueryWidget.jsx +2 -2
  50. package/src/components/manage/Widgets/QueryWidget.stories.jsx +1637 -22
  51. package/src/components/manage/Widgets/SelectAutoComplete.jsx +79 -48
  52. package/src/components/manage/Widgets/SelectAutoComplete.test.jsx +16 -0
  53. package/src/components/manage/Widgets/SelectAutocompleteWidget.stories.jsx +161 -0
  54. package/src/components/manage/Widgets/SelectUtils.js +90 -30
  55. package/src/components/manage/Widgets/SelectUtils.test.jsx +76 -1
  56. package/src/components/manage/Widgets/SelectWidget.jsx +26 -37
  57. package/src/components/manage/Widgets/SelectWidget.stories.jsx +96 -28
  58. package/src/components/manage/Widgets/TextWidget.stories.jsx +5 -22
  59. package/src/components/manage/Widgets/TextareaWidget.stories.jsx +5 -22
  60. package/src/components/manage/Widgets/TokenWidget.jsx +19 -17
  61. package/src/components/manage/Widgets/TokenWidget.stories.jsx +141 -0
  62. package/src/components/manage/Widgets/UrlWidget.stories.jsx +5 -21
  63. package/src/components/manage/Widgets/VocabularyTermsWidget.stories.js +27 -64
  64. package/src/components/manage/Widgets/WysiwygWidget.stories.jsx +5 -22
  65. package/src/components/manage/Widgets/story.jsx +38 -0
  66. package/src/components/theme/ContactForm/ContactForm.jsx +1 -0
  67. package/src/components/theme/ContactForm/ContactForm.stories.jsx +126 -0
  68. package/src/components/theme/CorsError/CorsError.jsx +2 -2
  69. package/src/config/Loadables.jsx +2 -0
  70. package/src/config/index.js +1 -0
  71. package/src/helpers/UndoManager/useUndoManager.js +102 -0
  72. package/src/helpers/index.js +1 -0
  73. package/src/reducers/vocabularies/vocabularies.js +13 -2
  74. package/src/store.js +1 -1
  75. package/src/storybook.jsx +55 -0
  76. package/theme/themes/pastanaga/extras/time-picker-overrides.less +1 -1
  77. package/include/python3.8/Python-ast.h +0 -715
  78. package/include/python3.8/Python.h +0 -160
  79. package/include/python3.8/abstract.h +0 -844
  80. package/include/python3.8/asdl.h +0 -46
  81. package/include/python3.8/ast.h +0 -37
  82. package/include/python3.8/bitset.h +0 -23
  83. package/include/python3.8/bltinmodule.h +0 -14
  84. package/include/python3.8/boolobject.h +0 -34
  85. package/include/python3.8/bytearrayobject.h +0 -62
  86. package/include/python3.8/bytes_methods.h +0 -69
  87. package/include/python3.8/bytesobject.h +0 -224
  88. package/include/python3.8/cellobject.h +0 -29
  89. package/include/python3.8/ceval.h +0 -231
  90. package/include/python3.8/classobject.h +0 -59
  91. package/include/python3.8/code.h +0 -180
  92. package/include/python3.8/codecs.h +0 -240
  93. package/include/python3.8/compile.h +0 -106
  94. package/include/python3.8/complexobject.h +0 -69
  95. package/include/python3.8/context.h +0 -84
  96. package/include/python3.8/cpython/abstract.h +0 -319
  97. package/include/python3.8/cpython/dictobject.h +0 -94
  98. package/include/python3.8/cpython/fileobject.h +0 -24
  99. package/include/python3.8/cpython/initconfig.h +0 -434
  100. package/include/python3.8/cpython/interpreteridobject.h +0 -19
  101. package/include/python3.8/cpython/object.h +0 -470
  102. package/include/python3.8/cpython/objimpl.h +0 -113
  103. package/include/python3.8/cpython/pyerrors.h +0 -188
  104. package/include/python3.8/cpython/pylifecycle.h +0 -78
  105. package/include/python3.8/cpython/pymem.h +0 -108
  106. package/include/python3.8/cpython/pystate.h +0 -252
  107. package/include/python3.8/cpython/sysmodule.h +0 -21
  108. package/include/python3.8/cpython/traceback.h +0 -22
  109. package/include/python3.8/cpython/tupleobject.h +0 -36
  110. package/include/python3.8/cpython/unicodeobject.h +0 -1239
  111. package/include/python3.8/datetime.h +0 -259
  112. package/include/python3.8/descrobject.h +0 -108
  113. package/include/python3.8/dictobject.h +0 -94
  114. package/include/python3.8/dtoa.h +0 -19
  115. package/include/python3.8/dynamic_annotations.h +0 -499
  116. package/include/python3.8/enumobject.h +0 -17
  117. package/include/python3.8/errcode.h +0 -38
  118. package/include/python3.8/eval.h +0 -37
  119. package/include/python3.8/fileobject.h +0 -49
  120. package/include/python3.8/fileutils.h +0 -185
  121. package/include/python3.8/floatobject.h +0 -130
  122. package/include/python3.8/frameobject.h +0 -92
  123. package/include/python3.8/funcobject.h +0 -104
  124. package/include/python3.8/genobject.h +0 -109
  125. package/include/python3.8/graminit.h +0 -94
  126. package/include/python3.8/grammar.h +0 -77
  127. package/include/python3.8/import.h +0 -149
  128. package/include/python3.8/internal/pycore_accu.h +0 -39
  129. package/include/python3.8/internal/pycore_atomic.h +0 -558
  130. package/include/python3.8/internal/pycore_ceval.h +0 -37
  131. package/include/python3.8/internal/pycore_code.h +0 -27
  132. package/include/python3.8/internal/pycore_condvar.h +0 -95
  133. package/include/python3.8/internal/pycore_context.h +0 -42
  134. package/include/python3.8/internal/pycore_fileutils.h +0 -54
  135. package/include/python3.8/internal/pycore_getopt.h +0 -22
  136. package/include/python3.8/internal/pycore_gil.h +0 -50
  137. package/include/python3.8/internal/pycore_hamt.h +0 -116
  138. package/include/python3.8/internal/pycore_initconfig.h +0 -166
  139. package/include/python3.8/internal/pycore_object.h +0 -81
  140. package/include/python3.8/internal/pycore_pathconfig.h +0 -75
  141. package/include/python3.8/internal/pycore_pyerrors.h +0 -62
  142. package/include/python3.8/internal/pycore_pyhash.h +0 -10
  143. package/include/python3.8/internal/pycore_pylifecycle.h +0 -118
  144. package/include/python3.8/internal/pycore_pymem.h +0 -212
  145. package/include/python3.8/internal/pycore_pystate.h +0 -326
  146. package/include/python3.8/internal/pycore_traceback.h +0 -96
  147. package/include/python3.8/internal/pycore_tupleobject.h +0 -19
  148. package/include/python3.8/internal/pycore_warnings.h +0 -25
  149. package/include/python3.8/interpreteridobject.h +0 -17
  150. package/include/python3.8/intrcheck.h +0 -33
  151. package/include/python3.8/iterobject.h +0 -25
  152. package/include/python3.8/listobject.h +0 -81
  153. package/include/python3.8/longintrepr.h +0 -99
  154. package/include/python3.8/longobject.h +0 -242
  155. package/include/python3.8/marshal.h +0 -28
  156. package/include/python3.8/memoryobject.h +0 -72
  157. package/include/python3.8/methodobject.h +0 -131
  158. package/include/python3.8/modsupport.h +0 -248
  159. package/include/python3.8/moduleobject.h +0 -90
  160. package/include/python3.8/namespaceobject.h +0 -19
  161. package/include/python3.8/node.h +0 -48
  162. package/include/python3.8/object.h +0 -753
  163. package/include/python3.8/objimpl.h +0 -284
  164. package/include/python3.8/odictobject.h +0 -43
  165. package/include/python3.8/opcode.h +0 -148
  166. package/include/python3.8/osdefs.h +0 -51
  167. package/include/python3.8/osmodule.h +0 -17
  168. package/include/python3.8/parsetok.h +0 -110
  169. package/include/python3.8/patchlevel.h +0 -35
  170. package/include/python3.8/picklebufobject.h +0 -31
  171. package/include/python3.8/py_curses.h +0 -100
  172. package/include/python3.8/pyarena.h +0 -64
  173. package/include/python3.8/pycapsule.h +0 -59
  174. package/include/python3.8/pyconfig.h +0 -1665
  175. package/include/python3.8/pyctype.h +0 -39
  176. package/include/python3.8/pydebug.h +0 -40
  177. package/include/python3.8/pydtrace.h +0 -59
  178. package/include/python3.8/pydtrace_probes.h +0 -228
  179. package/include/python3.8/pyerrors.h +0 -335
  180. package/include/python3.8/pyexpat.h +0 -55
  181. package/include/python3.8/pyfpe.h +0 -12
  182. package/include/python3.8/pyhash.h +0 -145
  183. package/include/python3.8/pylifecycle.h +0 -75
  184. package/include/python3.8/pymacconfig.h +0 -102
  185. package/include/python3.8/pymacro.h +0 -106
  186. package/include/python3.8/pymath.h +0 -230
  187. package/include/python3.8/pymem.h +0 -150
  188. package/include/python3.8/pyport.h +0 -850
  189. package/include/python3.8/pystate.h +0 -136
  190. package/include/python3.8/pystrcmp.h +0 -23
  191. package/include/python3.8/pystrhex.h +0 -22
  192. package/include/python3.8/pystrtod.h +0 -45
  193. package/include/python3.8/pythonrun.h +0 -210
  194. package/include/python3.8/pythread.h +0 -161
  195. package/include/python3.8/pytime.h +0 -246
  196. package/include/python3.8/rangeobject.h +0 -27
  197. package/include/python3.8/setobject.h +0 -108
  198. package/include/python3.8/sliceobject.h +0 -65
  199. package/include/python3.8/structmember.h +0 -74
  200. package/include/python3.8/structseq.h +0 -49
  201. package/include/python3.8/symtable.h +0 -123
  202. package/include/python3.8/sysmodule.h +0 -41
  203. package/include/python3.8/token.h +0 -92
  204. package/include/python3.8/traceback.h +0 -28
  205. package/include/python3.8/tracemalloc.h +0 -38
  206. package/include/python3.8/tupleobject.h +0 -48
  207. package/include/python3.8/typeslots.h +0 -85
  208. package/include/python3.8/ucnhash.h +0 -36
  209. package/include/python3.8/unicodeobject.h +0 -1044
  210. package/include/python3.8/warnings.h +0 -67
  211. package/include/python3.8/weakrefobject.h +0 -86
  212. package/src/components/theme/ContactForm/ContactForm.stories.mdx +0 -39
@@ -3,21 +3,25 @@
3
3
  * @module components/manage/Widgets/DatetimeWidget
4
4
  */
5
5
  import React, { Component } from 'react';
6
+ import { compose } from 'redux';
6
7
  import PropTypes from 'prop-types';
7
8
  import { defineMessages, injectIntl } from 'react-intl';
8
- import moment from 'moment';
9
- import { SingleDatePicker } from 'react-dates';
10
- import TimePicker from 'rc-time-picker';
9
+ import loadable from '@loadable/component';
11
10
  import cx from 'classnames';
12
11
  import { Icon, FormFieldWrapper } from '@plone/volto/components';
13
12
  import { parseDateTime } from '@plone/volto/helpers';
13
+ import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
14
+
14
15
  import leftKey from '@plone/volto/icons/left-key.svg';
15
16
  import rightKey from '@plone/volto/icons/right-key.svg';
16
17
  import clearSVG from '@plone/volto/icons/clear.svg';
18
+
17
19
  import 'rc-time-picker/assets/index.css';
18
20
  import 'react-dates/initialize';
19
21
  import 'react-dates/lib/css/_datepicker.css';
20
22
 
23
+ const TimePicker = loadable(() => import('rc-time-picker'));
24
+
21
25
  const messages = defineMessages({
22
26
  date: {
23
27
  id: 'Date',
@@ -80,7 +84,7 @@ const defaultTimeDateOnly = {
80
84
  * }
81
85
  * ```
82
86
  */
83
- class DatetimeWidget extends Component {
87
+ export class DatetimeWidgetComponent extends Component {
84
88
  /**
85
89
  * Constructor
86
90
  * @method constructor
@@ -89,17 +93,27 @@ class DatetimeWidget extends Component {
89
93
  */
90
94
  constructor(props) {
91
95
  super(props);
92
-
93
- let datetime = parseDateTime(this.props.intl.locale, this.props.value);
96
+ const moment = props.moment.default;
94
97
 
95
98
  this.state = {
96
99
  focused: false,
97
- isDefault: datetime?.toISOString() === moment().utc().toISOString(),
98
- datetime,
99
- dateOnly: this.props.dateOnly || this.props.widget === 'date',
100
+ // if passed value matches the construction time, we guess it's a default
101
+ isDefault:
102
+ parseDateTime(
103
+ this.props.intl.locale,
104
+ this.props.value,
105
+ )?.toISOString() === moment().utc().toISOString(),
100
106
  };
101
107
  }
102
108
 
109
+ getInternalValue() {
110
+ return parseDateTime(this.props.intl.locale, this.props.value);
111
+ }
112
+
113
+ getDateOnly() {
114
+ return this.props.dateOnly || this.props.widget === 'date';
115
+ }
116
+
103
117
  /**
104
118
  * Update date storage
105
119
  * @method onDateChange
@@ -107,26 +121,21 @@ class DatetimeWidget extends Component {
107
121
  * @returns {undefined}
108
122
  */
109
123
  onDateChange = (date) => {
110
- if (date)
111
- this.setState(
112
- (prevState) => ({
113
- datetime: prevState.datetime
114
- ? prevState.datetime.set({
115
- year: date.year(),
116
- month: date.month(),
117
- date: date.date(),
118
- ...(this.state.dateOnly ? defaultTimeDateOnly : {}),
119
- })
120
- : moment().set({
121
- year: date.year(),
122
- month: date.month(),
123
- date: date.date(),
124
- ...(this.state.dateOnly ? defaultTimeDateOnly : {}),
125
- }),
126
- isDefault: false,
127
- }),
128
- () => this.onDateTimeChange(),
129
- );
124
+ if (date) {
125
+ const moment = this.props.moment.default;
126
+ const isDateOnly = this.getDateOnly();
127
+ const base = (this.getInternalValue() || moment()).set({
128
+ year: date.year(),
129
+ month: date.month(),
130
+ date: date.date(),
131
+ ...(isDateOnly ? defaultTimeDateOnly : {}),
132
+ });
133
+ const dateValue = isDateOnly
134
+ ? base.format('YYYY-MM-DD')
135
+ : base.toISOString();
136
+ this.props.onChange(this.props.id, dateValue);
137
+ }
138
+ this.setState({ isDefault: false });
130
139
  };
131
140
 
132
141
  /**
@@ -136,45 +145,21 @@ class DatetimeWidget extends Component {
136
145
  * @returns {undefined}
137
146
  */
138
147
  onTimeChange = (time) => {
139
- this.setState(
140
- (prevState) => ({
141
- datetime: prevState.datetime
142
- ? prevState.datetime.set({
143
- hours: time.hours(),
144
- minutes: time.minutes(),
145
- seconds: 0,
146
- })
147
- : moment().set({
148
- hours: time.hours(),
149
- minutes: time.minutes(),
150
- seconds: 0,
151
- }),
152
- isDefault: false,
153
- }),
154
- () => this.onDateTimeChange(),
155
- );
156
- };
157
-
158
- /**
159
- * Update date storage
160
- * @method onDateTimeChange
161
- * @returns {undefined}
162
- */
163
- onDateTimeChange = () => {
164
- const dateValue = this.state.dateOnly
165
- ? this.state.datetime.format('YYYY-MM-DD')
166
- : this.state.datetime.toISOString();
167
- this.props.onChange(this.props.id, dateValue);
148
+ const moment = this.props.moment.default;
149
+ if (time) {
150
+ const base = (this.getInternalValue() || moment()).set({
151
+ hours: time.hours(),
152
+ minutes: time.minutes(),
153
+ seconds: 0,
154
+ });
155
+ const dateValue = base.toISOString();
156
+ this.props.onChange(this.props.id, dateValue);
157
+ }
168
158
  };
169
159
 
170
160
  onResetDates = () => {
171
- this.setState(
172
- (prevState) => ({
173
- datetime: null,
174
- isDefault: false,
175
- }),
176
- this.props.onChange(this.props.id, null),
177
- );
161
+ this.setState({ isDefault: false });
162
+ this.props.onChange(this.props.id, null);
178
163
  };
179
164
 
180
165
  /**
@@ -186,22 +171,25 @@ class DatetimeWidget extends Component {
186
171
  onFocusChange = ({ focused }) => this.setState({ focused });
187
172
 
188
173
  render() {
189
- const { id, noPastDates, resettable, intl } = this.props;
190
- const { datetime, isDefault, focused } = this.state;
174
+ const { id, noPastDates, resettable, intl, reactDates } = this.props;
175
+ const moment = this.props.moment.default;
176
+ const datetime = this.getInternalValue();
177
+ const dateOnly = this.getDateOnly();
178
+ const { SingleDatePicker } = reactDates;
191
179
 
192
180
  return (
193
181
  <FormFieldWrapper {...this.props}>
194
182
  <div className="date-time-widget-wrapper">
195
183
  <div
196
184
  className={cx('ui input date-input', {
197
- 'default-date': isDefault,
185
+ 'default-date': this.state.isDefault,
198
186
  })}
199
187
  >
200
188
  <SingleDatePicker
201
189
  date={datetime}
202
190
  disabled={this.props.isDisabled}
203
191
  onDateChange={this.onDateChange}
204
- focused={focused}
192
+ focused={this.state.focused}
205
193
  numberOfMonths={1}
206
194
  {...(noPastDates ? {} : { isOutsideRange: () => false })}
207
195
  onFocusChange={this.onFocusChange}
@@ -213,10 +201,10 @@ class DatetimeWidget extends Component {
213
201
  placeholder={intl.formatMessage(messages.date)}
214
202
  />
215
203
  </div>
216
- {!this.state.dateOnly && (
204
+ {!dateOnly && (
217
205
  <div
218
206
  className={cx('ui input time-input', {
219
- 'default-date': isDefault,
207
+ 'default-date': this.state.isDefault,
220
208
  })}
221
209
  >
222
210
  <TimePicker
@@ -255,7 +243,7 @@ class DatetimeWidget extends Component {
255
243
  * @property {Object} propTypes Property types.
256
244
  * @static
257
245
  */
258
- DatetimeWidget.propTypes = {
246
+ DatetimeWidgetComponent.propTypes = {
259
247
  id: PropTypes.string.isRequired,
260
248
  title: PropTypes.string.isRequired,
261
249
  description: PropTypes.string,
@@ -274,7 +262,7 @@ DatetimeWidget.propTypes = {
274
262
  * @property {Object} defaultProps Default properties.
275
263
  * @static
276
264
  */
277
- DatetimeWidget.defaultProps = {
265
+ DatetimeWidgetComponent.defaultProps = {
278
266
  description: null,
279
267
  required: false,
280
268
  error: [],
@@ -284,4 +272,7 @@ DatetimeWidget.defaultProps = {
284
272
  resettable: true,
285
273
  };
286
274
 
287
- export default injectIntl(DatetimeWidget);
275
+ export default compose(
276
+ injectLazyLibs(['reactDates', 'moment']),
277
+ injectIntl,
278
+ )(DatetimeWidgetComponent);
@@ -1,32 +1,16 @@
1
1
  import React from 'react';
2
+ import { DatetimeWidgetComponent } from './DatetimeWidget';
2
3
  import DatetimeWidget from './DatetimeWidget';
3
- import Wrapper from '@plone/volto/storybook';
4
+ import WidgetStory from './story';
4
5
 
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({});
6
+ export const Datetime = WidgetStory.bind({
7
+ props: { id: 'datetime', title: 'Datetime', block: 'block' },
8
+ widget: DatetimeWidget,
9
+ });
26
10
 
27
11
  export default {
28
12
  title: 'Widgets/Datetime',
29
- component: DatetimeWidget,
13
+ component: DatetimeWidgetComponent,
30
14
  decorators: [
31
15
  (Story) => (
32
16
  <div className="ui segment form attached" style={{ width: '400px' }}>
@@ -1,21 +1,26 @@
1
1
  import moment from 'moment';
2
- import TimePicker from 'rc-time-picker';
3
2
  import React from 'react';
4
3
  import { Provider } from 'react-intl-redux';
5
- import renderer from 'react-test-renderer';
6
4
  import configureStore from 'redux-mock-store';
7
5
  import DatetimeWidget from './DatetimeWidget';
6
+ import { waitFor, render, screen } from '@testing-library/react';
8
7
 
9
8
  const mockStore = configureStore();
10
9
 
11
- test('renders a datetime widget component', () => {
10
+ jest.mock('@plone/volto/helpers/Loadable/Loadable');
11
+ beforeAll(
12
+ async () =>
13
+ await require('@plone/volto/helpers/Loadable/Loadable').__setLoadables(),
14
+ );
15
+
16
+ test('renders a datetime widget component', async () => {
12
17
  const store = mockStore({
13
18
  intl: {
14
19
  locale: 'en',
15
20
  messages: {},
16
21
  },
17
22
  });
18
- const component = renderer.create(
23
+ const { container } = render(
19
24
  <Provider store={store}>
20
25
  <DatetimeWidget
21
26
  id="my-field"
@@ -26,31 +31,28 @@ test('renders a datetime widget component', () => {
26
31
  />
27
32
  </Provider>,
28
33
  );
29
- const json = component.toJSON();
30
- expect(json).toMatchSnapshot();
34
+ await waitFor(() => screen.getByText(/My field/));
35
+ expect(container).toMatchSnapshot();
31
36
  });
32
37
 
33
- test('datetime widget converts UTC date and adapt to local datetime', () => {
38
+ test('datetime widget converts UTC date and adapt to local datetime', async () => {
34
39
  const store = mockStore({
35
40
  intl: {
36
41
  locale: 'en',
37
42
  messages: {},
38
43
  },
39
44
  });
40
- const component = renderer.create(
45
+ const date = '2020-02-10T15:01:00.000Z';
46
+ const { container } = render(
41
47
  <Provider store={store}>
42
48
  <DatetimeWidget
43
49
  id="my-field"
44
50
  title="My field"
45
51
  onChange={() => {}}
46
- value={'2020-02-10T15:01:00.000Z'}
52
+ value={date}
47
53
  />
48
54
  </Provider>,
49
55
  );
50
- const componentInstance = component.root;
51
- const componentTimeInput = componentInstance.findByType(TimePicker);
52
-
53
- expect(componentTimeInput.props.defaultValue.toISOString()).toBe(
54
- moment('2020-02-10T15:01:00').utc().toISOString(),
55
- );
56
+ await waitFor(() => screen.getByText(/My field/));
57
+ expect(container).toMatchSnapshot();
56
58
  });
@@ -1,28 +1,11 @@
1
1
  import React from 'react';
2
2
  import EmailWidget from './EmailWidget';
3
- import Wrapper from '@plone/volto/storybook';
3
+ import WidgetStory from './story';
4
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({});
5
+ export const Email = WidgetStory.bind({
6
+ props: { id: 'email', title: 'Email', block: 'block' },
7
+ widget: EmailWidget,
8
+ });
26
9
 
27
10
  export default {
28
11
  title: 'Widgets/Email',
@@ -1,28 +1,11 @@
1
1
  import React from 'react';
2
2
  import FileWidget from './FileWidget';
3
- import Wrapper from '@plone/volto/storybook';
3
+ import WidgetStory from './story';
4
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({});
5
+ export const File = WidgetStory.bind({
6
+ props: { id: 'file', title: 'File', block: 'block' },
7
+ widget: FileWidget,
8
+ });
26
9
 
27
10
  export default {
28
11
  title: 'Widgets/File',
@@ -1,29 +1,11 @@
1
1
  import React from 'react';
2
2
  import NumberWidget from './NumberWidget';
3
- import Wrapper from '@plone/volto/storybook';
3
+ import WidgetStory from './story';
4
4
 
5
- const NumberWidgetComponent = ({ 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
- <NumberWidget
12
- {...args}
13
- id="field"
14
- title="Number"
15
- block="testBlock"
16
- value={value}
17
- onChange={onChange}
18
- default={10}
19
- />
20
- </div>
21
- <pre>Value: {JSON.stringify(value, null, 4)}</pre>
22
- </Wrapper>
23
- );
24
- };
25
-
26
- export const Number = NumberWidgetComponent.bind({});
5
+ export const Number = WidgetStory.bind({
6
+ props: { id: 'number', title: 'Number', block: 'block' },
7
+ widget: NumberWidget,
8
+ });
27
9
 
28
10
  export default {
29
11
  title: 'Widgets/Number',
@@ -1,9 +1,8 @@
1
1
  import ObjectBrowserWidgetDefault, {
2
2
  ObjectBrowserWidgetComponent as OBC,
3
3
  } from './ObjectBrowserWidget';
4
- import Wrapper from '@plone/volto/storybook';
4
+ import Wrapper, { FormUndoWrapper } from '@plone/volto/storybook';
5
5
  import React from 'react';
6
- import { injectIntl } from 'react-intl';
7
6
  import UniversalLink from '@plone/volto/components/manage/UniversalLink/UniversalLink';
8
7
 
9
8
  export const searchResults = {
@@ -157,43 +156,40 @@ const customStore = {
157
156
  },
158
157
  };
159
158
 
160
- const ObjectBrowserWidgetComponent = (args) => {
161
- const IntlWrappedComponent = injectIntl(OBC);
162
- return (
163
- <Wrapper>
164
- <IntlWrappedComponent {...args} search={searchResults} />
165
- </Wrapper>
166
- );
167
- };
168
-
169
159
  const ObjectBrowserWidget = (args) => {
170
- const [value, setValue] = React.useState([]);
171
- const onChange = (block, value) => setValue(value);
172
-
173
160
  return (
174
161
  <Wrapper
175
162
  location={{ pathname: '/folder2/folder21/doc212' }}
176
163
  customStore={customStore}
177
164
  >
178
- <ObjectBrowserWidgetDefault
179
- {...args}
180
- id="objectBrowser"
181
- title="Object Browser"
182
- block="testBlock"
183
- value={value}
184
- onChange={onChange}
185
- />
186
- {value?.length > 0 && (
187
- <div style={{ marginTop: '40px' }}>
188
- <UniversalLink item={value[0]}>{value[0]['@id']}</UniversalLink>
189
- </div>
190
- )}
165
+ <FormUndoWrapper initialState={{ value: undefined }} showControls={true}>
166
+ {({ state, onChange }) => (
167
+ <>
168
+ <ObjectBrowserWidgetDefault
169
+ {...args}
170
+ id="objectBrowser"
171
+ title="Object Browser"
172
+ block="testBlock"
173
+ value={state.value}
174
+ onChange={(block, value) => onChange({ value })}
175
+ />
176
+ <pre>
177
+ Value:
178
+ {state.value?.length > 0 && (
179
+ <UniversalLink item={state.value[0]}>
180
+ {state.value[0]['@id']}
181
+ </UniversalLink>
182
+ )}
183
+ </pre>
184
+ </>
185
+ )}
186
+ </FormUndoWrapper>
191
187
  </Wrapper>
192
188
  );
193
189
  };
194
190
 
195
191
  export default {
196
- title: 'Internal Components/Object Browser',
192
+ title: 'Widgets/Object Browser',
197
193
  component: OBC,
198
194
  decorators: [
199
195
  (Story) => (
@@ -206,9 +202,5 @@ export default {
206
202
  // subcomponents: { ArgsTable },
207
203
  };
208
204
 
209
- export const Renderer = () => (
210
- <ObjectBrowserWidgetComponent search={searchResults} />
211
- );
212
-
213
205
  export const Connected = () => <ObjectBrowserWidget />;
214
206
  export const SingleElement = () => <ObjectBrowserWidget mode="link" />;
@@ -1,5 +1,5 @@
1
1
  import ObjectListWidgetDefault from './ObjectListWidget';
2
- import Wrapper from '@plone/volto/storybook';
2
+ import Wrapper, { FormUndoWrapper } from '@plone/volto/storybook';
3
3
  import React from 'react';
4
4
  import { searchResults } from './ObjectBrowserWidget.stories';
5
5
 
@@ -108,55 +108,55 @@ const ObjectListWidgetComponent = ({
108
108
  enableSchemaExtender,
109
109
  ...args
110
110
  }) => {
111
- const [value, setValue] = React.useState([]);
112
- const onChange = (block, value) => setValue(value);
113
-
114
111
  return (
115
112
  <Wrapper
116
113
  location={{ pathname: '/folder2/folder21/doc212' }}
117
114
  customStore={customStore}
118
115
  >
119
- <div className="ui segment form attached" style={{ width: '400px' }}>
120
- {children}
121
- <ObjectListWidgetDefault
122
- {...args}
123
- id="SliderItem"
124
- title="Slider Item"
125
- block="testBlock"
126
- value={value}
127
- onChange={onChange}
128
- schemaExtender={
129
- enableSchemaExtender &&
130
- ((schema, data, intl) => {
131
- const finalSchema =
132
- data?.href?.[0]?.['@id'] === '/image'
133
- ? {
134
- ...schema,
135
- fieldsets: [
136
- {
137
- ...schema.fieldsets[0],
138
- fields: [
139
- ...schema.fieldsets[0].fields,
140
- ...secondarySchema.fieldsets[0].fields,
116
+ <FormUndoWrapper initialState={{ value: undefined }} showControls={true}>
117
+ {({ state, onChange }) => (
118
+ <div className="ui segment form attached" style={{ width: '400px' }}>
119
+ {children}
120
+ <ObjectListWidgetDefault
121
+ {...args}
122
+ id="SliderItem"
123
+ title="Slider Item"
124
+ block="testBlock"
125
+ value={state.value}
126
+ onChange={(block, value) => onChange({ value })}
127
+ schemaExtender={
128
+ enableSchemaExtender &&
129
+ ((schema, data, intl) => {
130
+ const finalSchema =
131
+ data?.href?.[0]?.['@id'] === '/image'
132
+ ? {
133
+ ...schema,
134
+ fieldsets: [
135
+ {
136
+ ...schema.fieldsets[0],
137
+ fields: [
138
+ ...schema.fieldsets[0].fields,
139
+ ...secondarySchema.fieldsets[0].fields,
140
+ ],
141
+ },
142
+ ...schema.fieldsets.slice(1),
143
+ ...secondarySchema.fieldsets.slice(1),
141
144
  ],
142
- },
143
- ...schema.fieldsets.slice(1),
144
- ...secondarySchema.fieldsets.slice(1),
145
- ],
146
- properties: {
147
- ...schema.properties,
148
- ...secondarySchema.properties,
149
- },
150
- }
151
- : schema;
152
- return finalSchema;
153
- })
154
- }
155
- />
156
- <hr />
157
- <strong>Resulting value</strong>
158
- <pre>{JSON.stringify(value, null, 4)}</pre>
159
- </div>
145
+ properties: {
146
+ ...schema.properties,
147
+ ...secondarySchema.properties,
148
+ },
149
+ }
150
+ : schema;
151
+ return finalSchema;
152
+ })
153
+ }
154
+ />
155
+ <hr />
156
+ <pre>Value: {JSON.stringify(state.value, null, 4)}</pre>
157
+ </div>
158
+ )}
159
+ </FormUndoWrapper>
160
160
  </Wrapper>
161
161
  );
162
162
  };