block_editor 0.1.3 → 1.0.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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +35 -14
  3. data/app/assets/images/block_editor/contact-form-block.svg +1 -0
  4. data/app/assets/stylesheets/block_editor/_utilities.scss +16 -0
  5. data/app/assets/stylesheets/block_editor/backend.scss +70 -2
  6. data/app/assets/stylesheets/block_editor/blocks/_backend.scss +7 -0
  7. data/app/assets/stylesheets/block_editor/blocks/_frontend.scss +11 -0
  8. data/app/assets/stylesheets/block_editor/blocks/be-accordion/_frontend.scss +3 -0
  9. data/app/assets/stylesheets/block_editor/blocks/be-alert/_frontend.scss +13 -0
  10. data/app/assets/stylesheets/block_editor/blocks/be-card/_backend.scss +7 -0
  11. data/app/assets/stylesheets/block_editor/{backend/blocks.scss → blocks/be-card/_frontend.scss} +0 -0
  12. data/app/assets/stylesheets/block_editor/blocks/be-contact-form/_backend.scss +22 -0
  13. data/app/assets/stylesheets/block_editor/blocks/be-cover/_backend.scss +8 -0
  14. data/app/assets/stylesheets/block_editor/blocks/be-cover/_frontend.scss +37 -0
  15. data/app/assets/stylesheets/block_editor/blocks/block/_backend.scss +11 -0
  16. data/app/assets/stylesheets/block_editor/blocks/button/_frontend.scss +46 -0
  17. data/app/assets/stylesheets/block_editor/blocks/buttons/_backend.scss +10 -0
  18. data/app/assets/stylesheets/block_editor/blocks/buttons/_frontend.scss +3 -0
  19. data/app/assets/stylesheets/block_editor/blocks/column/_frontend.scss +18 -0
  20. data/app/assets/stylesheets/block_editor/blocks/columns/_backend.scss +8 -0
  21. data/app/assets/stylesheets/block_editor/blocks/columns/_frontend.scss +14 -0
  22. data/app/assets/stylesheets/block_editor/blocks/image/_backend.scss +10 -0
  23. data/app/assets/stylesheets/block_editor/blocks/image/_frontend.scss +21 -0
  24. data/app/assets/stylesheets/block_editor/blocks/seperator/_frontend.scss +19 -0
  25. data/app/assets/stylesheets/block_editor/blocks/table/_frontend.scss +67 -0
  26. data/app/assets/stylesheets/block_editor/host_app/_variables.scss +1 -0
  27. data/app/assets/stylesheets/block_editor/host_app/blocks/_backend.scss +1 -0
  28. data/app/assets/stylesheets/block_editor/host_app/blocks/_frontend.scss +1 -0
  29. data/app/javascript/block_editor/blocks/be-accordion/index.js +108 -0
  30. data/app/javascript/block_editor/blocks/be-alert/index.js +51 -0
  31. data/app/javascript/block_editor/blocks/be-card/index.js +205 -0
  32. data/app/javascript/block_editor/blocks/be-contact-form/index.js +24 -0
  33. data/app/javascript/block_editor/blocks/be-cover/index.js +135 -0
  34. data/app/javascript/block_editor/blocks/block/edit-panel/index.js +132 -0
  35. data/app/javascript/block_editor/blocks/block/edit.js +163 -0
  36. data/app/javascript/block_editor/blocks/button/edit.js +0 -13
  37. data/app/javascript/block_editor/blocks/index.js +51 -102
  38. data/app/javascript/block_editor/components/block-editor/index.js +107 -36
  39. data/app/javascript/block_editor/components/block-editor/popover-wrapper.js +60 -0
  40. data/app/javascript/block_editor/components/block-editor/styles.scss +0 -11
  41. data/app/javascript/block_editor/components/header/index.js +28 -6
  42. data/app/javascript/block_editor/components/header/redo.js +1 -1
  43. data/app/javascript/block_editor/components/header/styles.scss +12 -11
  44. data/app/javascript/block_editor/components/media-upload/index.js +3 -3
  45. data/app/javascript/block_editor/components/sidebar/index.js +1 -3
  46. data/app/javascript/block_editor/components/sidebar/styles.scss +35 -35
  47. data/app/javascript/block_editor/stores/actions.js +12 -0
  48. data/app/javascript/block_editor/stores/reducer.js +23 -3
  49. data/app/javascript/block_editor/stores/selectors.js +14 -3
  50. data/app/javascript/controllers/block_editor_controller.jsx +15 -8
  51. data/app/javascript/controllers/index.js +2 -0
  52. data/app/javascript/packs/block_editor/application.scss +70 -26
  53. data/app/models/block_editor/block_list.rb +45 -1
  54. data/app/models/block_editor/block_list_connection.rb +6 -0
  55. data/app/views/block_editor/blocks/be/contact-form/_block.html +3 -0
  56. data/db/migrate/20210506220328_create_block_list_connections.rb +8 -0
  57. data/lib/block_editor.rb +3 -1
  58. data/lib/block_editor/block_list_renderer.rb +12 -6
  59. data/lib/block_editor/blocks/base.rb +1 -1
  60. data/lib/block_editor/blocks/contact_form.rb +11 -0
  61. data/lib/block_editor/blocks/reusable.rb +16 -0
  62. data/lib/block_editor/version.rb +1 -1
  63. data/package.json +16 -7
  64. data/yarn.lock +727 -530
  65. metadata +42 -8
  66. data/app/assets/stylesheets/block_editor/frontend.scss +0 -1
  67. data/app/assets/stylesheets/block_editor/frontend/blocks.scss +0 -0
  68. data/app/javascript/block_editor/blocks/image/edit.js +0 -656
@@ -207,19 +207,6 @@ function ButtonEdit( props ) {
207
207
  onToggleOpenInNewTab={ onToggleOpenInNewTab }
208
208
  />
209
209
  <InspectorControls>
210
- <PanelBody title={ 'Additional styles' }>
211
- <ToggleControl
212
- label={ 'Hollow' }
213
- onChange={ content => setAttributes({ hasHollowStyle: content }) }
214
- checked={ attributes.hasHollowStyle }
215
- />
216
- <ToggleControl
217
- label={ 'Large' }
218
- onChange={ content => setAttributes({ hasLargeStyle: content }) }
219
- checked={ attributes.hasLargeStyle }
220
- />
221
- </PanelBody>
222
-
223
210
  <PanelBody title={ __( 'Link settings' ) }>
224
211
  <ToggleControl
225
212
  label={ __( 'Open in new tab' ) }
@@ -27,103 +27,79 @@ import { addFilter } from '@wordpress/hooks';
27
27
  */
28
28
  import ColumnEdit from './column/edit';
29
29
  import ButtonEdit from './button/edit';
30
- import ImageEdit from './image/edit';
30
+ import BlockEdit from './block/edit';
31
31
  import MediaUpload from '../components/media-upload';
32
32
 
33
+ import * as accordion from './be-accordion';
34
+ import * as callout from './be-alert';
35
+ import * as card from './be-card';
36
+ import * as cover from './be-cover';
37
+ // import * as recentPosts from './recent-posts';
38
+ import * as contactForm from './be-contact-form';
39
+
33
40
  export const registerBlocks = () => {
41
+ // TODO: Remove this when upgrading to 10.5 -> https://github.com/WordPress/gutenberg/pull/30194
34
42
  const replaceButtonBlockEdit = ( settings, name ) => {
35
43
  if ( name !== 'core/button' ) {
36
44
  return settings;
37
45
  }
38
46
 
39
47
  return assign( {}, settings, {
40
- edit: ButtonEdit, // Removes & replaces some styling options
41
- attributes: assign( {}, settings.attributes, {
42
- hasHollowStyle: {
43
- type: 'boolean',
44
- default: false
45
- },
46
- hasLargeStyle: {
47
- type: 'boolean',
48
- default: false
49
- }
50
- })
51
- } );
48
+ edit: ButtonEdit // Removes border radius panel
49
+ })
52
50
  }
53
51
 
54
- const replaceColumnBlockEdit = ( settings, name ) => {
55
- if ( name !== 'core/column' ) {
52
+ const replaceBlockEdit = ( settings, name ) => {
53
+ if ( name !== 'core/block' ) {
56
54
  return settings;
57
55
  }
58
56
 
59
57
  return assign( {}, settings, {
60
- edit: ColumnEdit // Removes column width options
61
- } );
58
+ edit: BlockEdit // Removes 'convert to regular blocks' toolbar button
59
+ })
62
60
  }
63
61
 
64
- const replaceImageBlockEdit = ( settings, name ) => {
65
- if ( name !== 'core/image' ) {
62
+ const replaceColumnBlockEdit = ( settings, name ) => {
63
+ if ( name !== 'core/column' ) {
66
64
  return settings;
67
65
  }
68
66
 
69
67
  return assign( {}, settings, {
70
- edit: ImageEdit // Removes ImageSizeControl options
68
+ edit: ColumnEdit // Removes column width options
71
69
  } );
72
70
  }
73
71
 
74
- const applyExtraClass = ( extraProps, blockType, attributes ) => {
75
- if ( blockType.name !== 'core/button' ) {
76
- return extraProps;
77
- }
78
-
79
- if (attributes.hasLargeStyle) {
80
- extraProps.className = classnames( extraProps.className, 'large' );
81
- }
82
-
83
- if (attributes.hasHollowStyle) {
84
- extraProps.className = classnames( extraProps.className, 'is-style-hollow' );
85
- }
86
-
87
- return extraProps;
88
- }
89
-
90
- const withClientIdClassName = createHigherOrderComponent( ( BlockListBlock ) => {
72
+ // Set default alignment to 'full' for all images
73
+ const setDefaultAlignment = createHigherOrderComponent( ( BlockListBlock ) => {
91
74
  return ( props ) => {
92
- if ( props.name !== 'core/button' ) {
75
+ if ( props.name !== 'core/image' ) {
93
76
  return <BlockListBlock { ...props } />;
94
77
  }
95
78
 
96
- let classNames = '';
97
- if (props.attributes.hasLargeStyle) {
98
- classNames = classnames( classNames, 'large' );
99
- }
100
-
101
- if (props.attributes.hasHollowStyle) {
102
- classNames = classnames( classNames, 'is-style-hollow' );
103
- }
79
+ props.attributes.align = 'full';
104
80
 
105
- return <BlockListBlock { ...props } className={ classNames } />;
81
+ return <BlockListBlock { ...props } />;
106
82
  };
107
- }, 'withClientIdClassName' );
83
+ }, 'setDefaultAlignment' );
108
84
 
109
85
  const replaceMediaUpload = () => MediaUpload;
110
86
 
111
87
  addFilter(
112
88
  'editor.BlockListBlock',
113
- 'block-editor/filters/core-button-block-list',
114
- withClientIdClassName
89
+ 'block-editor/filters/core-image-block-list',
90
+ setDefaultAlignment
115
91
  );
116
92
 
117
93
  addFilter(
118
94
  'blocks.registerBlockType',
119
- 'block-editor/filters/core-button',
120
- replaceButtonBlockEdit
95
+ 'block-editor/filters/core-block',
96
+ replaceBlockEdit
121
97
  );
122
98
 
123
99
  addFilter(
124
- 'blocks.getSaveContent.extraProps',
125
- 'block-editor/filters/core-button-classes',
126
- applyExtraClass
100
+ 'blocks.registerBlockType',
101
+ 'block-editor/filters/core-button',
102
+ replaceButtonBlockEdit
127
103
  );
128
104
 
129
105
  addFilter(
@@ -132,12 +108,6 @@ export const registerBlocks = () => {
132
108
  replaceColumnBlockEdit
133
109
  );
134
110
 
135
- addFilter(
136
- 'blocks.registerBlockType',
137
- 'block-editor/filters/core-image',
138
- replaceImageBlockEdit
139
- );
140
-
141
111
  addFilter(
142
112
  'editor.MediaUpload',
143
113
  'block-editor/filters/media-upload',
@@ -158,41 +128,6 @@ export const registerBlocks = () => {
158
128
  unregisterBlockType('core/code');
159
129
  unregisterBlockType('core/cover');
160
130
  unregisterBlockType('core/embed');
161
- unregisterBlockType('core-embed/twitter');
162
- unregisterBlockType('core-embed/youtube');
163
- unregisterBlockType('core-embed/facebook');
164
- unregisterBlockType('core-embed/instagram');
165
- unregisterBlockType('core-embed/wordpress');
166
- unregisterBlockType('core-embed/soundcloud');
167
- unregisterBlockType('core-embed/spotify');
168
- unregisterBlockType('core-embed/flickr');
169
- unregisterBlockType('core-embed/vimeo');
170
- unregisterBlockType('core-embed/animoto');
171
- unregisterBlockType('core-embed/cloudup');
172
- unregisterBlockType('core-embed/collegehumor');
173
- unregisterBlockType('core-embed/crowdsignal');
174
- unregisterBlockType('core-embed/dailymotion');
175
- unregisterBlockType('core-embed/hulu');
176
- unregisterBlockType('core-embed/imgur');
177
- unregisterBlockType('core-embed/issuu');
178
- unregisterBlockType('core-embed/kickstarter');
179
- unregisterBlockType('core-embed/meetup-com');
180
- unregisterBlockType('core-embed/mixcloud');
181
- unregisterBlockType('core-embed/polldaddy');
182
- unregisterBlockType('core-embed/reddit');
183
- unregisterBlockType('core-embed/reverbnation');
184
- unregisterBlockType('core-embed/screencast');
185
- unregisterBlockType('core-embed/scribd');
186
- unregisterBlockType('core-embed/slideshare');
187
- unregisterBlockType('core-embed/smugmug');
188
- unregisterBlockType('core-embed/speaker');
189
- unregisterBlockType('core-embed/speaker-deck');
190
- unregisterBlockType('core-embed/tiktok');
191
- unregisterBlockType('core-embed/ted');
192
- unregisterBlockType('core-embed/tumblr');
193
- unregisterBlockType('core-embed/videopress');
194
- unregisterBlockType('core-embed/wordpress-tv');
195
- unregisterBlockType('core-embed/amazon-kindle');
196
131
  unregisterBlockType('core/file');
197
132
  unregisterBlockType('core/media-text');
198
133
  unregisterBlockType('core/latest-comments');
@@ -203,8 +138,6 @@ export const registerBlocks = () => {
203
138
  unregisterBlockType('core/pullquote');
204
139
  unregisterBlockType('core/rss');
205
140
  unregisterBlockType('core/search');
206
- // unregisterBlockType('core/reusable-block'); // ?
207
- // unregisterBlockType('core/reusable'); // ?
208
141
  unregisterBlockType('core/social-links');
209
142
  unregisterBlockType('core/social-link');
210
143
  unregisterBlockType('core/spacer');
@@ -228,6 +161,14 @@ export const registerBlocks = () => {
228
161
  unregisterBlockVariation('core/columns', 'two-columns-two-thirds-one-third');
229
162
  unregisterBlockVariation('core/columns', 'three-columns-wider-center');
230
163
 
164
+ // Register custom blocks
165
+ registerBlockType(accordion.name, accordion.settings);
166
+ registerBlockType(callout.name, callout.settings);
167
+ registerBlockType(card.name, card.settings);
168
+ registerBlockType(contactForm.name, contactForm.settings);
169
+ registerBlockType(cover.name, cover.settings);
170
+ // registerBlockType(recentPosts.name, recentPosts.settings);
171
+
231
172
  // Register custom block styles
232
173
  registerBlockStyle( 'core/button', {
233
174
  name: 'primary',
@@ -238,14 +179,22 @@ export const registerBlocks = () => {
238
179
  name: 'secondary',
239
180
  label: 'Secondary'
240
181
  } );
182
+ registerBlockStyle( 'core/button', {
183
+ name: 'outline-primary',
184
+ label: 'Primary (Outlined)'
185
+ } );
186
+ registerBlockStyle( 'core/button', {
187
+ name: 'outline-secondary',
188
+ label: 'Secondary (Outlined)'
189
+ } );
241
190
  registerBlockStyle( 'core/table', {
242
- name: 'striped',
243
- label: 'Striped',
191
+ name: 'unstriped',
192
+ label: 'Unstriped',
244
193
  isDefault: true
245
194
  } );
246
195
  registerBlockStyle( 'core/table', {
247
- name: 'unstriped',
248
- label: 'Unstriped'
196
+ name: 'striped',
197
+ label: 'Striped'
249
198
  } );
250
199
  registerBlockStyle( 'core/image', {
251
200
  name: 'default',
@@ -8,7 +8,8 @@ import '@wordpress/format-library';
8
8
  import { useSelect, useDispatch } from '@wordpress/data';
9
9
  import { useEffect, useState, useMemo } from '@wordpress/element';
10
10
  import { serialize, parse } from '@wordpress/blocks';
11
- import { InterfaceSkeleton as EditorSkeleton } from '@wordpress/interface';
11
+ import { InterfaceSkeleton, FullscreenMode } from '@wordpress/interface';
12
+ import { useShortcut } from '@wordpress/keyboard-shortcuts';
12
13
  import {
13
14
  BlockEditorKeyboardShortcuts,
14
15
  BlockEditorProvider,
@@ -17,11 +18,14 @@ import {
17
18
  WritingFlow,
18
19
  ObserveTyping,
19
20
  BlockBreadcrumb,
21
+ __experimentalLibrary as Library,
20
22
  } from '@wordpress/block-editor';
21
23
  import {
22
24
  Popover,
23
25
  SlotFillProvider,
24
26
  DropZoneProvider,
27
+ FocusReturnProvider,
28
+ Button
25
29
  } from '@wordpress/components';
26
30
 
27
31
  /**
@@ -30,11 +34,14 @@ import {
30
34
  import Sidebar from '../sidebar';
31
35
  import Header from '../header';
32
36
  import Notices from '../notices';
37
+ import PopoverWrapper from './popover-wrapper';
33
38
  import '../../stores'; // TODO: Think this store registering needs to be moved somewhere else so that it happens everytime a BlockEditor is initialized
34
39
 
35
40
  function BlockEditor( { input, settings: _settings } ) {
36
41
  const blocks = useSelect((select) => select("block-editor").getBlocks());
37
42
  const { updateBlocks } = useDispatch("block-editor");
43
+ const __experimentalReusableBlocks = useSelect((select) => select( 'core' ).getEntityRecords('postType', 'wp_block', { per_page: -1 }));
44
+ const settings = { ..._settings, __experimentalReusableBlocks };
38
45
 
39
46
  function handleInput(newBlocks, persist) {
40
47
  updateBlocks(newBlocks);
@@ -46,43 +53,107 @@ function BlockEditor( { input, settings: _settings } ) {
46
53
  input.value = serialize(newBlocks);
47
54
  }
48
55
 
56
+ // Registering the shortcuts
57
+ const { registerShortcut } = useDispatch( 'core/keyboard-shortcuts' );
58
+ useEffect( () => {
59
+ registerShortcut( {
60
+ name: 'core/editor/undo',
61
+ category: 'global',
62
+ description: 'Undo your last changes.',
63
+ keyCombination: {
64
+ modifier: 'primary',
65
+ character: 'z',
66
+ },
67
+ } );
68
+
69
+ registerShortcut( {
70
+ name: 'core/editor/redo',
71
+ category: 'global',
72
+ description: 'Redo your last undo.',
73
+ keyCombination: {
74
+ modifier: 'primaryShift',
75
+ character: 'z',
76
+ },
77
+ } );
78
+ })
79
+
80
+ const { redo, undo } = useDispatch( 'block-editor' );
81
+
82
+ useShortcut(
83
+ 'core/editor/undo',
84
+ ( event ) => {
85
+ undo();
86
+ event.preventDefault();
87
+ },
88
+ { bindGlobal: true }
89
+ );
90
+
91
+ useShortcut(
92
+ 'core/editor/redo',
93
+ ( event ) => {
94
+ redo();
95
+ event.preventDefault();
96
+ },
97
+ { bindGlobal: true }
98
+ );
99
+
100
+ const { setIsInserterOpened } = useDispatch( 'block-editor' );
101
+ const isInserterOpened = useSelect((select) => select("block-editor").isInserterOpened());
102
+
49
103
  return (
50
- <SlotFillProvider>
51
- <DropZoneProvider>
52
- <EditorSkeleton
53
- sidebar={<Sidebar />}
54
- content={
55
- <>
56
- <Notices />
57
- <BlockEditorProvider
58
- value={ blocks }
59
- onInput={ handleInput }
60
- onChange={ handleChange }
61
- settings={ _settings }
62
- >
63
- <Header />
64
- <BlockBreadcrumb />
65
- <Sidebar.InspectorFill>
66
- <BlockInspector />
67
- </Sidebar.InspectorFill>
68
- <div className="block-editor__inner-wrapper">
69
- <BlockEditorKeyboardShortcuts.Register />
70
- <BlockEditorKeyboardShortcuts />
71
- <WritingFlow>
72
- <ObserveTyping>
73
- <BlockList className="editor-styles-wrapper" />
74
- </ObserveTyping>
75
- </WritingFlow>
76
- </div>
77
- </BlockEditorProvider>
78
- </>
79
- }
80
- />
81
- <Popover.Slot />
82
- </DropZoneProvider>
83
- </SlotFillProvider>
104
+ <>
105
+ <FullscreenMode isActive={false} />
106
+ <SlotFillProvider>
107
+ <DropZoneProvider>
108
+ <BlockEditorProvider
109
+ value={ blocks }
110
+ onInput={ handleInput }
111
+ onChange={ handleChange }
112
+ settings={ settings }
113
+ >
114
+ <FocusReturnProvider>
115
+ <InterfaceSkeleton
116
+ header={<Header />}
117
+ footer={<BlockBreadcrumb />}
118
+ sidebar={<Sidebar />}
119
+ leftSidebar={
120
+ isInserterOpened && (
121
+ <PopoverWrapper
122
+ onClose={ () => setIsInserterOpened( false ) }
123
+ >
124
+ <div>
125
+ <div>
126
+ <Library
127
+ showInserterHelpPanel={true}
128
+ />
129
+ </div>
130
+ </div>
131
+ </PopoverWrapper>
132
+ )
133
+ }
134
+ content={
135
+ <>
136
+ <Notices />
137
+ <Sidebar.InspectorFill>
138
+ <BlockInspector />
139
+ </Sidebar.InspectorFill>
140
+ <BlockEditorKeyboardShortcuts.Register />
141
+ <BlockEditorKeyboardShortcuts />
142
+ <WritingFlow>
143
+ <ObserveTyping>
144
+ <BlockList className="editor-styles-wrapper" />
145
+ </ObserveTyping>
146
+ </WritingFlow>
147
+ </>
148
+ }
149
+ />
150
+ <Popover.Slot />
151
+ </FocusReturnProvider>
152
+ </BlockEditorProvider>
153
+ </DropZoneProvider>
154
+ </SlotFillProvider>
155
+ </>
84
156
  );
85
157
  }
86
158
 
87
159
  export default BlockEditor;
88
-
@@ -0,0 +1,60 @@
1
+ import React from 'react'
2
+ import ReactDOM from 'react-dom'
3
+
4
+ /**
5
+ * WordPress dependencies
6
+ */
7
+ import {
8
+ withConstrainedTabbing,
9
+ withFocusReturn,
10
+ withFocusOutside,
11
+ } from '@wordpress/components';
12
+ import { Component } from '@wordpress/element';
13
+ import { ESCAPE } from '@wordpress/keycodes';
14
+
15
+ function stopPropagation( event ) {
16
+ event.stopPropagation();
17
+ }
18
+
19
+ const DetectOutside = withFocusOutside(
20
+ class extends Component {
21
+ handleFocusOutside( event ) {
22
+ this.props.onFocusOutside( event );
23
+ }
24
+
25
+ render() {
26
+ return this.props.children;
27
+ }
28
+ }
29
+ );
30
+
31
+ const FocusManaged = withConstrainedTabbing(
32
+ withFocusReturn( ( { children } ) => children )
33
+ );
34
+
35
+ export default function PopoverWrapper( { onClose, children, className } ) {
36
+ // Event handlers
37
+ const maybeClose = ( event ) => {
38
+ // Close on escape
39
+ if ( event.keyCode === ESCAPE && onClose ) {
40
+ event.stopPropagation();
41
+ onClose();
42
+ }
43
+ };
44
+
45
+ // Disable reason: this stops certain events from propagating outside of the component.
46
+ // - onMouseDown is disabled as this can cause interactions with other DOM elements
47
+ /* eslint-disable jsx-a11y/no-static-element-interactions */
48
+ return (
49
+ <div
50
+ className={ className }
51
+ onKeyDown={ maybeClose }
52
+ onMouseDown={ stopPropagation }
53
+ >
54
+ <DetectOutside onFocusOutside={ onClose }>
55
+ <FocusManaged>{ children }</FocusManaged>
56
+ </DetectOutside>
57
+ </div>
58
+ );
59
+ /* eslint-enable jsx-a11y/no-static-element-interactions */
60
+ }