@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
@@ -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
  };