@plone/volto 19.0.0-alpha.31 → 19.0.0-alpha.33

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 (35) hide show
  1. package/AGENTS.md +47 -0
  2. package/CHANGELOG.md +27 -0
  3. package/README.md +0 -1
  4. package/package.json +11 -14
  5. package/src/actions/controlpanels/controlpanels.js +7 -12
  6. package/src/actions/controlpanels/controlpanels.test.js +2 -3
  7. package/src/components/manage/Contents/Contents.jsx +410 -323
  8. package/src/components/manage/Contents/Contents.test.jsx +1 -1
  9. package/src/components/manage/Contents/ContentsIndexHeader.jsx +47 -81
  10. package/src/components/manage/Contents/ContentsIndexHeader.test.jsx +10 -3
  11. package/src/components/manage/Contents/ContentsItem.jsx +226 -278
  12. package/src/components/manage/Contents/ContentsItem.test.jsx +10 -6
  13. package/src/components/manage/Controlpanels/ContentType.jsx +131 -222
  14. package/src/components/manage/Controlpanels/Controlpanel.jsx +122 -218
  15. package/src/components/manage/Controlpanels/Controlpanel.test.jsx +1 -29
  16. package/src/components/manage/Form/Field.jsx +1 -69
  17. package/src/components/manage/Form/Form.jsx +8 -0
  18. package/src/components/manage/Form/Form.test.jsx +130 -1
  19. package/src/components/manage/Widgets/ArrayWidget.jsx +111 -88
  20. package/src/components/manage/Widgets/ArrayWidget.test.jsx +0 -6
  21. package/src/components/manage/Widgets/RecurrenceWidget/WeekdayOfTheMonthIndexField.jsx +56 -50
  22. package/src/components/manage/Widgets/SelectStyling.jsx +52 -20
  23. package/src/config/Loadables.jsx +1 -5
  24. package/src/config/index.js +3 -0
  25. package/src/helpers/Utils/withSaveAsDraft.jsx +33 -9
  26. package/src/server.jsx +7 -1
  27. package/theme/themes/pastanaga/extras/contents.less +0 -4
  28. package/types/components/manage/Contents/Contents.d.ts +1 -1
  29. package/types/components/manage/Contents/ContentsIndexHeader.d.ts +6 -11
  30. package/types/components/manage/Contents/ContentsItem.d.ts +3 -10
  31. package/types/components/manage/Controlpanels/ContentType.d.ts +2 -2
  32. package/types/components/manage/Controlpanels/Controlpanel.d.ts +2 -5
  33. package/types/components/manage/Controlpanels/index.d.ts +2 -2
  34. package/types/components/manage/Widgets/RecurrenceWidget/WeekdayOfTheMonthIndexField.d.ts +22 -5
  35. package/types/components/manage/Widgets/SelectStyling.d.ts +1 -0
@@ -4,14 +4,47 @@ import configureStore from 'redux-mock-store';
4
4
  import { Provider } from 'react-intl-redux';
5
5
  import { MemoryRouter } from 'react-router-dom';
6
6
  import Form from './Form';
7
+ import config from '@plone/volto/registry';
7
8
 
8
9
  const mockStore = configureStore();
9
10
  const errorMessage =
10
11
  "[{'message': 'The specified email is not valid.', 'field': 'contact_email', 'error': 'ValidationError'}";
11
12
 
12
13
  vi.mock('@plone/volto/components/manage/Form');
14
+ vi.mock('@plone/volto/helpers/Utils/withSaveAsDraft', async () => {
15
+ const React = await import('react');
16
+ const { default: config } = await import('@plone/volto/registry');
17
+
18
+ return {
19
+ default: () => (WrappedComponent) =>
20
+ React.forwardRef((props, ref) =>
21
+ config.experimental?.saveAsDraft?.enabled ? (
22
+ <div data-autosave-wrapper="true">
23
+ <WrappedComponent
24
+ {...props}
25
+ checkSavedDraft={vi.fn()}
26
+ onSaveDraft={vi.fn()}
27
+ onCancelDraft={vi.fn()}
28
+ ref={ref}
29
+ />
30
+ </div>
31
+ ) : (
32
+ <WrappedComponent {...props} ref={ref} />
33
+ ),
34
+ ),
35
+ };
36
+ });
13
37
 
14
38
  describe('Form', () => {
39
+ beforeEach(() => {
40
+ config.experimental = {
41
+ ...(config.experimental || {}),
42
+ saveAsDraft: {
43
+ enabled: false,
44
+ },
45
+ };
46
+ });
47
+
15
48
  it('renders a form component', () => {
16
49
  const store = mockStore({
17
50
  intl: {
@@ -49,10 +82,106 @@ describe('Form', () => {
49
82
  onCancel={() => {}}
50
83
  />
51
84
  </MemoryRouter>
52
- ,
53
85
  </Provider>,
54
86
  );
55
87
  const json = component.toJSON();
56
88
  expect(json).toMatchSnapshot();
57
89
  });
90
+
91
+ it('does not wrap the form with autosave when the experimental flag is disabled', () => {
92
+ const store = mockStore({
93
+ intl: {
94
+ locale: 'en',
95
+ messages: {},
96
+ },
97
+ content: {
98
+ data: {},
99
+ create: {
100
+ loading: false,
101
+ loaded: true,
102
+ },
103
+ },
104
+ });
105
+
106
+ const component = renderer.create(
107
+ <Provider store={store}>
108
+ <MemoryRouter initialEntries={['/some-route']}>
109
+ <Form
110
+ schema={{
111
+ fieldsets: [
112
+ {
113
+ id: 'default',
114
+ title: 'Default',
115
+ fields: ['title'],
116
+ },
117
+ ],
118
+ properties: {
119
+ title: {},
120
+ },
121
+ required: [],
122
+ }}
123
+ requestError={errorMessage}
124
+ onSubmit={() => {}}
125
+ onCancel={() => {}}
126
+ />
127
+ </MemoryRouter>
128
+ </Provider>,
129
+ );
130
+
131
+ expect(
132
+ component.root.findAllByProps({ 'data-autosave-wrapper': 'true' }),
133
+ ).toHaveLength(0);
134
+ });
135
+
136
+ it('wraps the form with autosave when the experimental flag is enabled', () => {
137
+ config.experimental = {
138
+ ...config.experimental,
139
+ saveAsDraft: {
140
+ enabled: true,
141
+ },
142
+ };
143
+
144
+ const store = mockStore({
145
+ intl: {
146
+ locale: 'en',
147
+ messages: {},
148
+ },
149
+ content: {
150
+ data: {},
151
+ create: {
152
+ loading: false,
153
+ loaded: true,
154
+ },
155
+ },
156
+ });
157
+
158
+ const component = renderer.create(
159
+ <Provider store={store}>
160
+ <MemoryRouter initialEntries={['/some-route']}>
161
+ <Form
162
+ schema={{
163
+ fieldsets: [
164
+ {
165
+ id: 'default',
166
+ title: 'Default',
167
+ fields: ['title'],
168
+ },
169
+ ],
170
+ properties: {
171
+ title: {},
172
+ },
173
+ required: [],
174
+ }}
175
+ requestError={errorMessage}
176
+ onSubmit={() => {}}
177
+ onCancel={() => {}}
178
+ />
179
+ </MemoryRouter>
180
+ </Provider>,
181
+ );
182
+
183
+ expect(
184
+ component.root.findAllByProps({ 'data-autosave-wrapper': 'true' }),
185
+ ).toHaveLength(1);
186
+ });
58
187
  });
@@ -29,6 +29,7 @@ import {
29
29
  SortableMultiValue,
30
30
  SortableMultiValueLabel,
31
31
  MultiValueContainer,
32
+ MultiValueRemove,
32
33
  } from '@plone/volto/components/manage/Widgets/SelectStyling';
33
34
 
34
35
  import FormFieldWrapper from '@plone/volto/components/manage/Widgets/FormFieldWrapper';
@@ -276,11 +277,11 @@ class ArrayWidget extends Component {
276
277
  render() {
277
278
  const choices = normalizeChoices(this.props?.choices || []);
278
279
  const selectedOption = normalizeArrayValue(choices, this.props.value);
280
+ const selectedIds = selectedOption.map((option) => option.value);
279
281
 
280
282
  const CreatableSelect = this.props.reactSelectCreateable.default;
281
- const { SortableContainer } = this.props.reactSortableHOC;
282
283
  const Select = this.props.reactSelect.default;
283
- const SortableSelect =
284
+ const SelectComponent =
284
285
  // It will be only creatable if the named vocabulary is in the widget definition
285
286
  // (hint) like:
286
287
  // list_field_voc_unconstrained = schema.List(
@@ -298,95 +299,112 @@ class ArrayWidget extends Component {
298
299
  this.props?.choices &&
299
300
  !getVocabFromHint(this.props) &&
300
301
  !this.props.creatable
301
- ? SortableContainer(Select)
302
- : SortableContainer(CreatableSelect);
302
+ ? Select
303
+ : CreatableSelect;
304
+ const { DndContext, closestCenter } = this.props.dndKitCore;
305
+ const { SortableContext, horizontalListSortingStrategy } =
306
+ this.props.dndKitSortable;
303
307
 
304
308
  return (
305
309
  <FormFieldWrapper {...this.props}>
306
- <SortableSelect
307
- useDragHandle
308
- // react-sortable-hoc props:
309
- axis="xy"
310
- onSortEnd={(sortProp) => {
311
- this.onSortEnd(selectedOption, sortProp);
312
- }}
313
- menuShouldScrollIntoView={false}
314
- distance={4}
315
- // small fix for https://github.com/clauderic/react-sortable-hoc/pull/352:
316
- getHelperDimensions={({ node }) => node.getBoundingClientRect()}
317
- id={`field-${this.props.id}`}
318
- aria-labelledby={`fieldset-${this.props.fieldSet}-field-label-${this.props.id}`}
319
- key={this.props.id}
320
- isDisabled={this.props.disabled || this.props.isDisabled}
321
- className="react-select-container"
322
- classNamePrefix="react-select"
323
- /* eslint-disable jsx-a11y/no-autofocus */
324
- autoFocus={this.props.focus}
325
- /* eslint-enable jsx-a11y/no-autofocus */
326
- options={
327
- this.props.vocabBaseUrl
328
- ? choices
329
- : this.props.choices
330
- ? [
331
- ...choices,
332
- ...(this.props.noValueOption &&
333
- (this.props.default === undefined ||
334
- this.props.default === null)
335
- ? [
336
- {
337
- label: this.props.intl.formatMessage(
338
- messages.no_value,
339
- ),
340
- value: 'no-value',
341
- },
342
- ]
343
- : []),
344
- ]
345
- : [
346
- {
347
- label: this.props.intl.formatMessage(messages.no_value),
348
- value: 'no-value',
349
- },
350
- ]
351
- }
352
- styles={customSelectStyles}
353
- theme={selectTheme}
354
- components={{
355
- ...(this.props.choices?.length > 25 && {
356
- MenuList,
357
- }),
358
- MultiValueContainer,
359
- MultiValue: SortableMultiValue,
360
- MultiValueLabel: SortableMultiValueLabel,
361
- DropdownIndicator,
362
- ClearIndicator,
363
- Option,
310
+ <DndContext
311
+ collisionDetection={closestCenter}
312
+ onDragEnd={({ active, over }) => {
313
+ if (!over || active.id === over.id) {
314
+ return;
315
+ }
316
+ const oldIndex = selectedIds.indexOf(active.id);
317
+ const newIndex = selectedIds.indexOf(over.id);
318
+ if (oldIndex < 0 || newIndex < 0) {
319
+ return;
320
+ }
321
+ this.onSortEnd(selectedOption, { oldIndex, newIndex });
364
322
  }}
365
- value={selectedOption || []}
366
- placeholder={
367
- this.props.placeholder ??
368
- this.props.intl.formatMessage(messages.select)
369
- }
370
- onChange={this.handleChange}
371
- isValidNewOption={(
372
- inputValue,
373
- selectValue,
374
- selectOptions,
375
- accessors,
376
- ) =>
377
- !(
378
- !inputValue ||
379
- selectValue.some((option) =>
380
- compareOption(inputValue, option, accessors),
381
- ) ||
382
- selectOptions.some((option) =>
383
- compareOption(inputValue, option, accessors),
384
- )
385
- )
386
- }
387
- isClearable
388
- isMulti
389
- />
323
+ >
324
+ <SortableContext
325
+ items={selectedIds}
326
+ strategy={horizontalListSortingStrategy}
327
+ >
328
+ <SelectComponent
329
+ menuShouldScrollIntoView={false}
330
+ id={`field-${this.props.id}`}
331
+ aria-labelledby={`fieldset-${this.props.fieldSet}-field-label-${this.props.id}`}
332
+ key={this.props.id}
333
+ isDisabled={this.props.disabled || this.props.isDisabled}
334
+ className="react-select-container"
335
+ classNamePrefix="react-select"
336
+ /* eslint-disable jsx-a11y/no-autofocus */
337
+ autoFocus={this.props.focus}
338
+ /* eslint-enable jsx-a11y/no-autofocus */
339
+ options={
340
+ this.props.vocabBaseUrl
341
+ ? choices
342
+ : this.props.choices
343
+ ? [
344
+ ...choices,
345
+ ...(this.props.noValueOption &&
346
+ (this.props.default === undefined ||
347
+ this.props.default === null)
348
+ ? [
349
+ {
350
+ label: this.props.intl.formatMessage(
351
+ messages.no_value,
352
+ ),
353
+ value: 'no-value',
354
+ },
355
+ ]
356
+ : []),
357
+ ]
358
+ : [
359
+ {
360
+ label: this.props.intl.formatMessage(
361
+ messages.no_value,
362
+ ),
363
+ value: 'no-value',
364
+ },
365
+ ]
366
+ }
367
+ styles={customSelectStyles}
368
+ theme={selectTheme}
369
+ components={{
370
+ ...(this.props.choices?.length > 25 && {
371
+ MenuList,
372
+ }),
373
+ MultiValueContainer,
374
+ MultiValue: SortableMultiValue,
375
+ MultiValueLabel: SortableMultiValueLabel,
376
+ MultiValueRemove,
377
+ DropdownIndicator,
378
+ ClearIndicator,
379
+ Option,
380
+ }}
381
+ value={selectedOption || []}
382
+ placeholder={
383
+ this.props.placeholder ??
384
+ this.props.intl.formatMessage(messages.select)
385
+ }
386
+ onChange={this.handleChange}
387
+ isValidNewOption={(
388
+ inputValue,
389
+ selectValue,
390
+ selectOptions,
391
+ accessors,
392
+ ) =>
393
+ !(
394
+ !inputValue ||
395
+ selectValue.some((option) =>
396
+ compareOption(inputValue, option, accessors),
397
+ ) ||
398
+ selectOptions.some((option) =>
399
+ compareOption(inputValue, option, accessors),
400
+ )
401
+ )
402
+ }
403
+ isClearable
404
+ isMulti
405
+ />
406
+ </SortableContext>
407
+ </DndContext>
390
408
  </FormFieldWrapper>
391
409
  );
392
410
  }
@@ -396,7 +414,12 @@ export const ArrayWidgetComponent = injectIntl(ArrayWidget);
396
414
 
397
415
  export default compose(
398
416
  injectIntl,
399
- injectLazyLibs(['reactSelect', 'reactSelectCreateable', 'reactSortableHOC']),
417
+ injectLazyLibs([
418
+ 'reactSelect',
419
+ 'reactSelectCreateable',
420
+ 'dndKitCore',
421
+ 'dndKitSortable',
422
+ ]),
400
423
  connect(
401
424
  (state, props) => {
402
425
  const vocabBaseUrl =
@@ -9,12 +9,6 @@ import ArrayWidget from './ArrayWidget';
9
9
  const mockStore = configureStore();
10
10
 
11
11
  vi.mock('@plone/volto/helpers/Loadable/Loadable');
12
- // Mock react-sortable-hoc to prevent the container error
13
- vi.mock('react-sortable-hoc', () => ({
14
- ...vi.importActual('react-sortable-hoc'),
15
- SortableContainer: (component) => component,
16
- SortableElement: (component) => component,
17
- }));
18
12
 
19
13
  beforeAll(async () => {
20
14
  const { __setLoadables } = await import(
@@ -3,17 +3,17 @@
3
3
  * @module components/manage/Widgets/RecurrenceWidget/WeekdayOfTheMonthIndexField
4
4
  */
5
5
 
6
- import React, { Component } from 'react';
6
+ import React from 'react';
7
7
  import PropTypes from 'prop-types';
8
- import { defineMessages, injectIntl } from 'react-intl';
8
+ import { defineMessages, useIntl } from 'react-intl';
9
9
  import map from 'lodash/map';
10
10
  import { Form } from 'semantic-ui-react';
11
11
  import SelectInput from './SelectInput';
12
12
 
13
13
  /**
14
- * WeekdayOfTheMonthIndexField component class.
14
+ * WeekdayOfTheMonthIndexField component.
15
15
  * @function WeekdayOfTheMonthIndexField
16
- * @returns {string} Markup of the component.
16
+ * @returns {JSX.Element} Markup of the component.
17
17
  */
18
18
 
19
19
  const messages = defineMessages({
@@ -34,53 +34,59 @@ const ORDINAL_NUMBERS = {
34
34
  '-1': 'last',
35
35
  };
36
36
 
37
- class WeekdayOfTheMonthIndexField extends Component {
38
- /**
39
- * Property types.
40
- * @property {Object} propTypes Property types.
41
- * @static
42
- */
43
- static propTypes = {
44
- disabled: PropTypes.bool,
45
- value: PropTypes.any,
46
- onChange: PropTypes.func,
47
- };
37
+ const WeekdayOfTheMonthIndexField = ({
38
+ disabled,
39
+ value,
40
+ onChange,
41
+ ...otherProps
42
+ }) => {
43
+ const intl = useIntl();
44
+ const weekdayOfTheMonthIndexList = [
45
+ ...map(Object.keys(ORDINAL_NUMBERS), (option) => ({
46
+ value: parseInt(option),
47
+ label: intl.formatMessage(messages[ORDINAL_NUMBERS[option]]),
48
+ })),
49
+ ];
50
+ return (
51
+ <>
52
+ <Form.Field disabled={disabled}>
53
+ {intl.formatMessage(messages.bymonthDayNumber)}
54
+ </Form.Field>
48
55
 
49
- /**
50
- * Default properties.
51
- * @property {Object} defaultProps Default properties.
52
- * @static
53
- */
54
- static defaultProps = {
55
- disabled: false,
56
- value: null,
57
- onChange: null,
58
- };
56
+ <Form.Field disabled={disabled}>
57
+ <SelectInput
58
+ name="weekdayOfTheMonthIndex"
59
+ options={weekdayOfTheMonthIndexList}
60
+ disabled={disabled}
61
+ value={value}
62
+ onChange={onChange}
63
+ {...otherProps}
64
+ />
65
+ </Form.Field>
66
+ </>
67
+ );
68
+ };
59
69
 
60
- render() {
61
- const { intl, disabled } = this.props;
62
- const weekdayOfTheMonthIndexList = [
63
- ...map(Object.keys(ORDINAL_NUMBERS), (option) => ({
64
- value: parseInt(option),
65
- label: intl.formatMessage(messages[ORDINAL_NUMBERS[option]]),
66
- })),
67
- ];
68
- return (
69
- <>
70
- <Form.Field disabled={disabled}>
71
- {intl.formatMessage(messages.bymonthDayNumber)}
72
- </Form.Field>
70
+ /**
71
+ * Property types.
72
+ * @property {Object} propTypes
73
+ * @static
74
+ */
75
+ WeekdayOfTheMonthIndexField.propTypes = {
76
+ disabled: PropTypes.bool,
77
+ value: PropTypes.any,
78
+ onChange: PropTypes.func,
79
+ };
73
80
 
74
- <Form.Field disabled={disabled}>
75
- <SelectInput
76
- name="weekdayOfTheMonthIndex"
77
- options={weekdayOfTheMonthIndexList}
78
- {...this.props}
79
- />
80
- </Form.Field>
81
- </>
82
- );
83
- }
84
- }
81
+ /**
82
+ * Default properties.
83
+ * @property {Object} defaultProps
84
+ * @static
85
+ */
86
+ WeekdayOfTheMonthIndexField.defaultProps = {
87
+ disabled: false,
88
+ value: null,
89
+ onChange: null,
90
+ };
85
91
 
86
- export default injectIntl(WeekdayOfTheMonthIndexField);
92
+ export default WeekdayOfTheMonthIndexField;
@@ -14,33 +14,52 @@ export const MenuList = ({ children }) => {
14
14
  return <DynamicHeightList>{children}</DynamicHeightList>;
15
15
  };
16
16
 
17
+ // this prevents the menu from being opened/closed when the user clicks
18
+ // on a value to begin dragging it. ideally, detecting a click (instead of
19
+ // a drag) would still focus the control and toggle the menu, but that
20
+ // requires some magic with refs that are out of scope for this example
21
+ const onMouseDown = (e) => {
22
+ e.preventDefault();
23
+ e.stopPropagation();
24
+ };
25
+
17
26
  export const SortableMultiValue = injectLazyLibs([
18
27
  'reactSelect',
19
- 'reactSortableHOC',
28
+ 'dndKitSortable',
29
+ 'dndKitUtilities',
20
30
  ])((props) => {
21
31
  const { MultiValue } = props.reactSelect.components;
22
- const { SortableElement } = props.reactSortableHOC;
23
- // this prevents the menu from being opened/closed when the user clicks
24
- // on a value to begin dragging it. ideally, detecting a click (instead of
25
- // a drag) would still focus the control and toggle the menu, but that
26
- // requires some magic with refs that are out of scope for this example
27
- const onMouseDown = (e) => {
28
- e.preventDefault();
29
- e.stopPropagation();
30
- };
31
- const innerProps = { ...props.innerProps, onMouseDown };
32
- const SortableComponent = SortableElement(MultiValue);
33
- return <SortableComponent {...props} innerProps={innerProps} />;
32
+ const { useSortable } = props.dndKitSortable;
33
+ const { CSS } = props.dndKitUtilities;
34
+ const { attributes, listeners, setNodeRef, transform, transition } =
35
+ useSortable({
36
+ id: props.data.value,
37
+ });
38
+
39
+ return (
40
+ // eslint-disable-next-line jsx-a11y/no-static-element-interactions
41
+ <div
42
+ ref={setNodeRef}
43
+ style={{
44
+ transform: CSS.Transform.toString(transform),
45
+ transition,
46
+ }}
47
+ {...attributes}
48
+ {...listeners}
49
+ >
50
+ <MultiValue
51
+ {...props}
52
+ innerProps={{ ...props.innerProps, onMouseDown }}
53
+ />
54
+ </div>
55
+ );
34
56
  });
35
57
 
36
- export const SortableMultiValueLabel = injectLazyLibs([
37
- 'reactSelect',
38
- 'reactSortableHOC',
39
- ])((props) => {
58
+ export const SortableMultiValueLabel = injectLazyLibs(['reactSelect'])((
59
+ props,
60
+ ) => {
40
61
  const { MultiValueLabel } = props.reactSelect.components;
41
- const { SortableHandle } = props.reactSortableHOC;
42
- const SortableComponent = SortableHandle(MultiValueLabel);
43
- return <SortableComponent {...props} />;
62
+ return <MultiValueLabel {...props} />;
44
63
  });
45
64
 
46
65
  export const MultiValueContainer = injectLazyLibs('reactSelect')((props) => {
@@ -57,6 +76,19 @@ export const MultiValueContainer = injectLazyLibs('reactSelect')((props) => {
57
76
  );
58
77
  });
59
78
 
79
+ export const MultiValueRemove = injectLazyLibs(['reactSelect'])((props) => {
80
+ const { MultiValueRemove } = props.reactSelect.components;
81
+ return (
82
+ <MultiValueRemove
83
+ {...props}
84
+ innerProps={{
85
+ ...props.innerProps,
86
+ onPointerDown: (e) => e.stopPropagation(),
87
+ }}
88
+ />
89
+ );
90
+ });
91
+
60
92
  export const Option = injectLazyLibs('reactSelect')((props) => {
61
93
  const { Option } = props.reactSelect.components;
62
94
  const color = props.isFocused && !props.isSelected ? '#b8c6c8' : '#007bc1';
@@ -24,9 +24,6 @@ export const loadables = {
24
24
  reactVirtualized: loadable.lib(() => import('react-virtualized'), {
25
25
  ssr: false,
26
26
  }),
27
- reactSortableHOC: loadable.lib(() => import('react-sortable-hoc'), {
28
- ssr: false,
29
- }),
30
27
  reactSelectAsyncPaginate: loadable.lib(
31
28
  () => import('react-select-async-paginate'),
32
29
  { ssr: false },
@@ -46,11 +43,10 @@ export const loadables = {
46
43
  diffLib: loadable.lib(() => import('diff')),
47
44
  moment: loadable.lib(() => import('moment')),
48
45
  reactDates: loadable.lib(() => import('react-dates')),
49
- reactDnd: loadable.lib(() => import('react-dnd')),
50
- reactDndHtml5Backend: loadable.lib(() => import('react-dnd-html5-backend')),
51
46
  reactBeautifulDnd: loadable.lib(() => import('react-beautiful-dnd')),
52
47
  rrule: loadable.lib(() => import('rrule')),
53
48
  dndKitCore: loadable.lib(() => import('@dnd-kit/core')),
49
+ dndKitModifiers: loadable.lib(() => import('@dnd-kit/modifiers')),
54
50
  dndKitSortable: loadable.lib(() => import('@dnd-kit/sortable')),
55
51
  dndKitUtilities: loadable.lib(() => import('@dnd-kit/utilities')),
56
52
  };
@@ -189,6 +189,9 @@ let config = {
189
189
  addBlockButton: {
190
190
  enabled: true,
191
191
  },
192
+ saveAsDraft: {
193
+ enabled: false,
194
+ },
192
195
  },
193
196
  widgets: {},
194
197
  views: {},