@plone/volto 18.0.0-alpha.32 → 18.0.0-alpha.34

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 (101) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/locales/ca/LC_MESSAGES/volto.po +17 -0
  3. package/locales/ca.json +1 -1
  4. package/locales/de/LC_MESSAGES/volto.po +17 -0
  5. package/locales/de.json +1 -1
  6. package/locales/en/LC_MESSAGES/volto.po +17 -0
  7. package/locales/en.json +1 -1
  8. package/locales/es/LC_MESSAGES/volto.po +17 -0
  9. package/locales/es.json +1 -1
  10. package/locales/eu/LC_MESSAGES/volto.po +17 -0
  11. package/locales/eu.json +1 -1
  12. package/locales/fi/LC_MESSAGES/volto.po +17 -0
  13. package/locales/fi.json +1 -1
  14. package/locales/fr/LC_MESSAGES/volto.po +17 -0
  15. package/locales/fr.json +1 -1
  16. package/locales/hi/LC_MESSAGES/volto.po +17 -0
  17. package/locales/hi.json +1 -1
  18. package/locales/it/LC_MESSAGES/volto.po +17 -0
  19. package/locales/it.json +1 -1
  20. package/locales/ja/LC_MESSAGES/volto.po +17 -0
  21. package/locales/ja.json +1 -1
  22. package/locales/nl/LC_MESSAGES/volto.po +17 -0
  23. package/locales/nl.json +1 -1
  24. package/locales/pt/LC_MESSAGES/volto.po +17 -0
  25. package/locales/pt.json +1 -1
  26. package/locales/pt_BR/LC_MESSAGES/volto.po +17 -0
  27. package/locales/pt_BR.json +1 -1
  28. package/locales/ro/LC_MESSAGES/volto.po +17 -0
  29. package/locales/ro.json +1 -1
  30. package/locales/volto.pot +18 -1
  31. package/locales/zh_CN/LC_MESSAGES/volto.po +17 -0
  32. package/locales/zh_CN.json +1 -1
  33. package/package.json +10 -5
  34. package/razzle.config.js +58 -0
  35. package/src/actions/form/form.js +18 -2
  36. package/src/actions/index.js +1 -1
  37. package/src/components/manage/BlockChooser/BlockChooserSearch.jsx +1 -0
  38. package/src/components/manage/Blocks/Block/BlocksForm.jsx +157 -81
  39. package/src/components/manage/Blocks/Block/BlocksForm.test.jsx +8 -0
  40. package/src/components/manage/Blocks/Block/Edit.jsx +37 -4
  41. package/src/components/manage/Blocks/Block/Order/Item.jsx +122 -0
  42. package/src/components/manage/Blocks/Block/Order/Order.jsx +367 -0
  43. package/src/components/manage/Blocks/Block/Order/SortableItem.jsx +58 -0
  44. package/src/components/manage/Blocks/Block/Order/utilities.js +113 -0
  45. package/src/components/manage/Blocks/Container/Edit.jsx +1 -0
  46. package/src/components/manage/Blocks/Grid/Edit.jsx +6 -4
  47. package/src/components/manage/Blocks/Image/schema.js +2 -0
  48. package/src/components/manage/Controlpanels/Relations/RelationsListing.jsx +1 -1
  49. package/src/components/manage/Controlpanels/Relations/RelationsMatrix.jsx +1 -1
  50. package/src/components/manage/Form/Form.jsx +159 -151
  51. package/src/components/manage/Sidebar/ObjectBrowserBody.jsx +158 -65
  52. package/src/components/manage/Sidebar/ObjectBrowserNav.jsx +125 -71
  53. package/src/components/manage/Sidebar/Sidebar.jsx +28 -1
  54. package/src/components/manage/Widgets/IdWidget.jsx +138 -203
  55. package/src/components/manage/Widgets/InternalUrlWidget.jsx +10 -14
  56. package/src/components/manage/Widgets/TextWidget.jsx +92 -124
  57. package/src/components/manage/Widgets/TextWidget.stories.jsx +14 -3
  58. package/src/components/theme/App/App.jsx +5 -0
  59. package/src/components/theme/Footer/Footer.jsx +1 -0
  60. package/src/components/theme/FormattedDate/FormattedDate.jsx +13 -1
  61. package/src/components/theme/Icon/Icon.jsx +4 -4
  62. package/src/components/theme/Navigation/Navigation.jsx +1 -1
  63. package/src/components/theme/SlotRenderer/SlotRenderer.tsx +3 -4
  64. package/src/components/theme/View/View.jsx +1 -1
  65. package/src/config/Loadables.jsx +18 -0
  66. package/src/config/server.js +0 -1
  67. package/src/constants/ActionTypes.js +1 -0
  68. package/src/express-middleware/static.js +37 -19
  69. package/src/helpers/Blocks/Blocks.js +182 -1
  70. package/src/helpers/Blocks/Blocks.test.js +136 -0
  71. package/src/helpers/Html/Html.jsx +6 -8
  72. package/src/helpers/Slots/index.tsx +12 -5
  73. package/src/helpers/index.js +4 -0
  74. package/src/reducers/form/form.js +18 -1
  75. package/src/reducers/form/form.test.js +15 -1
  76. package/src/server.jsx +34 -36
  77. package/theme/themes/pastanaga/extras/blocks.less +7 -6
  78. package/theme/themes/pastanaga/extras/objectbrowser-widget.less +83 -0
  79. package/theme/themes/pastanaga/extras/sidebar.less +145 -0
  80. package/theme/themes/pastanaga/extras/widgets.less +19 -0
  81. package/types/actions/form/form.d.ts +8 -1
  82. package/types/actions/index.d.ts +1 -1
  83. package/types/components/manage/Blocks/Block/Order/Item.d.ts +2 -0
  84. package/types/components/manage/Blocks/Block/Order/Order.d.ts +13 -0
  85. package/types/components/manage/Blocks/Block/Order/SortableItem.d.ts +9 -0
  86. package/types/components/manage/Blocks/Block/Order/utilities.d.ts +9 -0
  87. package/types/components/manage/Blocks/Image/schema.d.ts +2 -0
  88. package/types/components/manage/Sidebar/ObjectBrowserNav.d.ts +2 -1
  89. package/types/components/manage/Widgets/IdWidget.d.ts +54 -2
  90. package/types/components/manage/Widgets/TextWidget.d.ts +54 -5
  91. package/types/components/manage/Widgets/TextWidget.stories.d.ts +13 -1
  92. package/types/components/manage/Widgets/index.d.ts +2 -2
  93. package/types/components/theme/Icon/Icon.d.ts +8 -8
  94. package/types/config/Loadables.d.ts +15 -162
  95. package/types/config/Widgets.d.ts +1 -1
  96. package/types/config/server.d.ts +0 -3
  97. package/types/constants/ActionTypes.d.ts +1 -0
  98. package/types/helpers/Blocks/Blocks.d.ts +13 -0
  99. package/types/helpers/Slots/index.d.ts +5 -3
  100. package/types/helpers/index.d.ts +2 -2
  101. package/types/start-client.d.ts +1 -1
@@ -52,6 +52,7 @@ import {
52
52
  resetMetadataFocus,
53
53
  setSidebarTab,
54
54
  setFormData,
55
+ setUIState,
55
56
  } from '@plone/volto/actions';
56
57
  import { compose } from 'redux';
57
58
  import config from '@plone/volto/registry';
@@ -230,13 +231,17 @@ class Form extends Component {
230
231
  this.props.setFormData(formData);
231
232
  }
232
233
 
234
+ this.props.setUIState({
235
+ selected: selectedBlock,
236
+ multiSelected: [],
237
+ hovered: null,
238
+ });
239
+
233
240
  // Set initial state
234
241
  this.state = {
235
242
  formData,
236
243
  initialFormData,
237
244
  errors: {},
238
- selected: selectedBlock,
239
- multiSelected: [],
240
245
  isClient: false,
241
246
  // Ensure focus remain in field after change
242
247
  inFocus: {},
@@ -263,6 +268,12 @@ class Form extends Component {
263
268
  let errors = {};
264
269
  let activeIndex = 0;
265
270
 
271
+ if (!this.props.isFormSelected && prevProps.isFormSelected) {
272
+ this.props.setUIState({
273
+ selected: null,
274
+ });
275
+ }
276
+
266
277
  if (requestError && prevProps.requestError !== requestError) {
267
278
  errors =
268
279
  FormValidation.giveServerErrorsToCorrespondingFields(requestError);
@@ -376,15 +387,6 @@ class Form extends Component {
376
387
  this.setState({ isClient: true });
377
388
  }
378
389
 
379
- static getDerivedStateFromProps(props, state) {
380
- let newState = { ...state };
381
- if (!props.isFormSelected) {
382
- newState.selected = null;
383
- }
384
-
385
- return newState;
386
- }
387
-
388
390
  /**
389
391
  * Change field handler
390
392
  * Remove errors for changed field
@@ -439,9 +441,9 @@ class Form extends Component {
439
441
 
440
442
  if (event.shiftKey) {
441
443
  const anchor =
442
- this.state.multiSelected.length > 0
443
- ? blocks_layout.indexOf(this.state.multiSelected[0])
444
- : blocks_layout.indexOf(this.state.selected);
444
+ this.props.uiState.multiSelected.length > 0
445
+ ? blocks_layout.indexOf(this.props.uiState.multiSelected[0])
446
+ : blocks_layout.indexOf(this.props.uiState.selected);
445
447
  const focus = blocks_layout.indexOf(id);
446
448
 
447
449
  if (anchor === focus) {
@@ -451,15 +453,16 @@ class Form extends Component {
451
453
  } else {
452
454
  multiSelected = [...blocks_layout.slice(focus, anchor + 1)];
453
455
  }
456
+ window.getSelection().empty();
454
457
  }
455
458
 
456
459
  if ((event.ctrlKey || event.metaKey) && !event.shiftKey) {
457
- multiSelected = this.state.multiSelected || [];
458
- if (!this.state.multiSelected.includes(this.state.selected)) {
459
- multiSelected = [...multiSelected, this.state.selected];
460
+ multiSelected = this.props.uiState.multiSelected || [];
461
+ if (!this.props.uiState.multiSelected.includes(this.state.selected)) {
462
+ multiSelected = [...multiSelected, this.props.uiState.selected];
460
463
  selected = null;
461
464
  }
462
- if (this.state.multiSelected.includes(id)) {
465
+ if (this.props.uiState.multiSelected.includes(id)) {
463
466
  selected = null;
464
467
  multiSelected = without(multiSelected, id);
465
468
  } else {
@@ -468,9 +471,10 @@ class Form extends Component {
468
471
  }
469
472
  }
470
473
 
471
- this.setState({
474
+ this.props.setUIState({
472
475
  selected,
473
476
  multiSelected,
477
+ gridSelected: null,
474
478
  });
475
479
 
476
480
  if (this.props.onSelectForm) {
@@ -660,141 +664,143 @@ class Form extends Component {
660
664
  />
661
665
 
662
666
  <Container>
663
- <BlocksToolbar
664
- formData={formData}
665
- selectedBlock={this.state.selected}
666
- selectedBlocks={this.state.multiSelected}
667
- onChangeBlocks={(newBlockData) => {
668
- const newFormData = {
669
- ...formData,
670
- ...newBlockData,
671
- };
672
- this.setState({
673
- formData: newFormData,
674
- });
675
- if (this.props.global) {
676
- this.props.setFormData(newFormData);
677
- }
678
- }}
679
- onSetSelectedBlocks={(blockIds) =>
680
- this.setState({ multiSelected: blockIds })
681
- }
682
- onSelectBlock={this.onSelectBlock}
683
- />
684
- <UndoToolbar
685
- state={{
686
- formData,
687
- selected: this.state.selected,
688
- multiSelected: this.state.multiSelected,
689
- }}
690
- enableHotKeys
691
- onUndoRedo={({ state }) => {
692
- if (this.props.global) {
693
- this.props.setFormData(state.formData);
667
+ <>
668
+ <BlocksToolbar
669
+ formData={formData}
670
+ selectedBlock={this.props.uiState.selected}
671
+ selectedBlocks={this.props.uiState.multiSelected}
672
+ onChangeBlocks={(newBlockData) => {
673
+ const newFormData = {
674
+ ...formData,
675
+ ...newBlockData,
676
+ };
677
+ this.setState({
678
+ formData: newFormData,
679
+ });
680
+ if (this.props.global) {
681
+ this.props.setFormData(newFormData);
682
+ }
683
+ }}
684
+ onSetSelectedBlocks={(blockIds) =>
685
+ this.props.setUIState({ multiSelected: blockIds })
694
686
  }
695
- return this.setState(state);
696
- }}
697
- />
698
- <BlocksForm
699
- onChangeFormData={(newData) => {
700
- const newFormData = {
701
- ...formData,
702
- ...newData,
703
- };
704
- this.setState({
705
- formData: newFormData,
706
- });
707
- if (this.props.global) {
708
- this.props.setFormData(newFormData);
709
- }
710
- }}
711
- onChangeField={this.onChangeField}
712
- onSelectBlock={this.onSelectBlock}
713
- properties={formData}
714
- navRoot={navRoot}
715
- type={type}
716
- pathname={this.props.pathname}
717
- selectedBlock={this.state.selected}
718
- multiSelected={this.state.multiSelected}
719
- manage={this.props.isAdminForm}
720
- allowedBlocks={this.props.allowedBlocks}
721
- showRestricted={this.props.showRestricted}
722
- editable={this.props.editable}
723
- isMainForm={this.props.editable}
724
- // Properties to pass to the BlocksForm to match the View ones
725
- history={this.props.history}
726
- location={this.props.location}
727
- token={this.props.token}
728
- />
729
- {this.state.isClient &&
730
- this.state.sidebarMetadataIsAvailable &&
731
- this.props.editable &&
732
- createPortal(
733
- <UiForm
734
- method="post"
735
- onSubmit={this.onSubmit}
736
- error={keys(this.state.errors).length > 0}
737
- >
738
- {schema &&
739
- map(schema.fieldsets, (fieldset) => (
740
- <Accordion
741
- fluid
742
- styled
743
- className="form"
744
- key={fieldset.title}
745
- >
746
- <div
747
- key={fieldset.id}
748
- id={`metadataform-fieldset-${fieldset.id}`}
687
+ onSelectBlock={this.onSelectBlock}
688
+ />
689
+ <UndoToolbar
690
+ state={{
691
+ formData,
692
+ selected: this.props.uiState.selected,
693
+ multiSelected: this.props.uiState.multiSelected,
694
+ }}
695
+ enableHotKeys
696
+ onUndoRedo={({ state }) => {
697
+ if (this.props.global) {
698
+ this.props.setFormData(state.formData);
699
+ }
700
+ return this.setState(state);
701
+ }}
702
+ />
703
+ <BlocksForm
704
+ onChangeFormData={(newData) => {
705
+ const newFormData = {
706
+ ...formData,
707
+ ...newData,
708
+ };
709
+ this.setState({
710
+ formData: newFormData,
711
+ });
712
+ if (this.props.global) {
713
+ this.props.setFormData(newFormData);
714
+ }
715
+ }}
716
+ onChangeField={this.onChangeField}
717
+ onSelectBlock={this.onSelectBlock}
718
+ properties={formData}
719
+ navRoot={navRoot}
720
+ type={type}
721
+ pathname={this.props.pathname}
722
+ selectedBlock={this.props.uiState.selected}
723
+ multiSelected={this.props.uiState.multiSelected}
724
+ manage={this.props.isAdminForm}
725
+ allowedBlocks={this.props.allowedBlocks}
726
+ showRestricted={this.props.showRestricted}
727
+ editable={this.props.editable}
728
+ isMainForm={this.props.editable}
729
+ // Properties to pass to the BlocksForm to match the View ones
730
+ history={this.props.history}
731
+ location={this.props.location}
732
+ token={this.props.token}
733
+ />
734
+ {this.state.isClient &&
735
+ this.state.sidebarMetadataIsAvailable &&
736
+ this.props.editable &&
737
+ createPortal(
738
+ <UiForm
739
+ method="post"
740
+ onSubmit={this.onSubmit}
741
+ error={keys(this.state.errors).length > 0}
742
+ >
743
+ {schema &&
744
+ map(schema.fieldsets, (fieldset) => (
745
+ <Accordion
746
+ fluid
747
+ styled
748
+ className="form"
749
+ key={fieldset.title}
749
750
  >
750
- <Accordion.Title
751
- active={metadataFieldsets.includes(fieldset.id)}
752
- index={fieldset.id}
753
- onClick={this.onToggleMetadataFieldset}
754
- >
755
- {fieldset.title}
756
- {metadataFieldsets.includes(fieldset.id) ? (
757
- <Icon name={upSVG} size="20px" />
758
- ) : (
759
- <Icon name={downSVG} size="20px" />
760
- )}
761
- </Accordion.Title>
762
- <Accordion.Content
763
- active={metadataFieldsets.includes(fieldset.id)}
751
+ <div
752
+ key={fieldset.id}
753
+ id={`metadataform-fieldset-${fieldset.id}`}
764
754
  >
765
- <Segment className="attached">
766
- {map(fieldset.fields, (field, index) => (
767
- <Field
768
- {...schema.properties[field]}
769
- id={field}
770
- fieldSet={fieldset.title.toLowerCase()}
771
- formData={formData}
772
- focus={this.state.inFocus[field]}
773
- value={formData?.[field]}
774
- required={
775
- schema.required.indexOf(field) !== -1
776
- }
777
- onChange={this.onChangeField}
778
- onBlur={this.onBlurField}
779
- onClick={this.onClickInput}
780
- key={field}
781
- error={this.state.errors[field]}
782
- />
783
- ))}
784
- </Segment>
785
- </Accordion.Content>
786
- </div>
787
- </Accordion>
788
- ))}
789
- </UiForm>,
790
- document.getElementById('sidebar-metadata'),
791
- )}
792
-
793
- <SlotRenderer
794
- name="belowContent"
795
- content={this.props.content}
796
- navRoot={navRoot}
797
- />
755
+ <Accordion.Title
756
+ active={metadataFieldsets.includes(fieldset.id)}
757
+ index={fieldset.id}
758
+ onClick={this.onToggleMetadataFieldset}
759
+ >
760
+ {fieldset.title}
761
+ {metadataFieldsets.includes(fieldset.id) ? (
762
+ <Icon name={upSVG} size="20px" />
763
+ ) : (
764
+ <Icon name={downSVG} size="20px" />
765
+ )}
766
+ </Accordion.Title>
767
+ <Accordion.Content
768
+ active={metadataFieldsets.includes(fieldset.id)}
769
+ >
770
+ <Segment className="attached">
771
+ {map(fieldset.fields, (field, index) => (
772
+ <Field
773
+ {...schema.properties[field]}
774
+ id={field}
775
+ fieldSet={fieldset.title.toLowerCase()}
776
+ formData={formData}
777
+ focus={this.state.inFocus[field]}
778
+ value={formData?.[field]}
779
+ required={
780
+ schema.required.indexOf(field) !== -1
781
+ }
782
+ onChange={this.onChangeField}
783
+ onBlur={this.onBlurField}
784
+ onClick={this.onClickInput}
785
+ key={field}
786
+ error={this.state.errors[field]}
787
+ />
788
+ ))}
789
+ </Segment>
790
+ </Accordion.Content>
791
+ </div>
792
+ </Accordion>
793
+ ))}
794
+ </UiForm>,
795
+ document.getElementById('sidebar-metadata'),
796
+ )}
797
+
798
+ <SlotRenderer
799
+ name="belowContent"
800
+ content={this.props.content}
801
+ navRoot={navRoot}
802
+ />
803
+ </>
798
804
  </Container>
799
805
  </>
800
806
  )
@@ -964,6 +970,7 @@ export default compose(
964
970
  (state, props) => ({
965
971
  content: state.content.data,
966
972
  globalData: state.form?.global,
973
+ uiState: state.form?.ui,
967
974
  metadataFieldsets: state.sidebar?.metadataFieldsets,
968
975
  metadataFieldFocus: state.sidebar?.metadataFieldFocus,
969
976
  }),
@@ -971,6 +978,7 @@ export default compose(
971
978
  setMetadataFieldsets,
972
979
  setSidebarTab,
973
980
  setFormData,
981
+ setUIState,
974
982
  resetMetadataFocus,
975
983
  },
976
984
  null,