@wordpress/block-editor 15.8.1-next.16d95556a.0 → 15.8.1-next.dc3f6d3c1.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 (169) hide show
  1. package/build/components/block-inspector/edit-contents.js +19 -23
  2. package/build/components/block-inspector/edit-contents.js.map +3 -3
  3. package/build/components/block-inspector/index.js +7 -1
  4. package/build/components/block-inspector/index.js.map +2 -2
  5. package/build/components/block-list/block.js +4 -0
  6. package/build/components/block-list/block.js.map +2 -2
  7. package/build/components/block-list/use-block-props/index.js +3 -1
  8. package/build/components/block-list/use-block-props/index.js.map +2 -2
  9. package/build/components/block-list/use-block-props/use-is-hovered.js +16 -10
  10. package/build/components/block-list/use-block-props/use-is-hovered.js.map +2 -2
  11. package/build/components/block-settings-menu-controls/edit-section-menu-item.js +64 -0
  12. package/build/components/block-settings-menu-controls/edit-section-menu-item.js.map +7 -0
  13. package/build/components/block-settings-menu-controls/index.js +8 -0
  14. package/build/components/block-settings-menu-controls/index.js.map +2 -2
  15. package/build/components/block-toolbar/block-toolbar-icon.js +9 -9
  16. package/build/components/block-toolbar/block-toolbar-icon.js.map +2 -2
  17. package/build/components/block-variation-transforms/index.js +32 -5
  18. package/build/components/block-variation-transforms/index.js.map +2 -2
  19. package/build/components/border-radius-control/single-input-control.js +1 -0
  20. package/build/components/border-radius-control/single-input-control.js.map +2 -2
  21. package/build/components/content-only-controls/index.js +263 -0
  22. package/build/components/content-only-controls/index.js.map +7 -0
  23. package/build/components/content-only-controls/link/index.js +204 -0
  24. package/build/components/content-only-controls/link/index.js.map +7 -0
  25. package/build/components/content-only-controls/media/index.js +264 -0
  26. package/build/components/content-only-controls/media/index.js.map +7 -0
  27. package/build/components/content-only-controls/plain-text/index.js +68 -0
  28. package/build/components/content-only-controls/plain-text/index.js.map +7 -0
  29. package/build/components/content-only-controls/rich-text/index.js +197 -0
  30. package/build/components/content-only-controls/rich-text/index.js.map +7 -0
  31. package/build/components/content-only-controls/use-inspector-popover-placement.js +41 -0
  32. package/build/components/content-only-controls/use-inspector-popover-placement.js.map +7 -0
  33. package/build/components/inserter/media-tab/media-tab.js +1 -33
  34. package/build/components/inserter/media-tab/media-tab.js.map +3 -3
  35. package/build/components/inspector-controls-tabs/content-tab.js +6 -2
  36. package/build/components/inspector-controls-tabs/content-tab.js.map +3 -3
  37. package/build/components/inspector-controls-tabs/index.js +7 -1
  38. package/build/components/inspector-controls-tabs/index.js.map +2 -2
  39. package/build/components/list-view/block-select-button.js +11 -4
  40. package/build/components/list-view/block-select-button.js.map +2 -2
  41. package/build/components/media-placeholder/index.js +1 -31
  42. package/build/components/media-placeholder/index.js.map +3 -3
  43. package/build/components/media-replace-flow/index.js +4 -30
  44. package/build/components/media-replace-flow/index.js.map +3 -3
  45. package/build/components/use-block-display-information/index.js +21 -1
  46. package/build/components/use-block-display-information/index.js.map +3 -3
  47. package/build/hooks/block-bindings.js +52 -61
  48. package/build/hooks/block-bindings.js.map +3 -3
  49. package/build/hooks/use-content-only-section-edit.js +67 -0
  50. package/build/hooks/use-content-only-section-edit.js.map +7 -0
  51. package/build/layouts/constrained.js +2 -2
  52. package/build/layouts/constrained.js.map +2 -2
  53. package/build/private-apis.js +2 -3
  54. package/build/private-apis.js.map +3 -3
  55. package/build/store/private-keys.js +3 -0
  56. package/build/store/private-keys.js.map +2 -2
  57. package/build/store/private-selectors.js +1 -2
  58. package/build/store/private-selectors.js.map +2 -2
  59. package/build/store/reducer.js +1 -2
  60. package/build/store/reducer.js.map +2 -2
  61. package/build/utils/fit-text-utils.js +9 -1
  62. package/build/utils/fit-text-utils.js.map +2 -2
  63. package/build-module/components/block-inspector/edit-contents.js +9 -23
  64. package/build-module/components/block-inspector/edit-contents.js.map +2 -2
  65. package/build-module/components/block-inspector/index.js +7 -1
  66. package/build-module/components/block-inspector/index.js.map +2 -2
  67. package/build-module/components/block-list/block.js +4 -0
  68. package/build-module/components/block-list/block.js.map +2 -2
  69. package/build-module/components/block-list/use-block-props/index.js +3 -1
  70. package/build-module/components/block-list/use-block-props/index.js.map +2 -2
  71. package/build-module/components/block-list/use-block-props/use-is-hovered.js +16 -10
  72. package/build-module/components/block-list/use-block-props/use-is-hovered.js.map +2 -2
  73. package/build-module/components/block-settings-menu-controls/edit-section-menu-item.js +29 -0
  74. package/build-module/components/block-settings-menu-controls/edit-section-menu-item.js.map +7 -0
  75. package/build-module/components/block-settings-menu-controls/index.js +8 -0
  76. package/build-module/components/block-settings-menu-controls/index.js.map +2 -2
  77. package/build-module/components/block-toolbar/block-toolbar-icon.js +10 -10
  78. package/build-module/components/block-toolbar/block-toolbar-icon.js.map +2 -2
  79. package/build-module/components/block-variation-transforms/index.js +32 -5
  80. package/build-module/components/block-variation-transforms/index.js.map +2 -2
  81. package/build-module/components/border-radius-control/single-input-control.js +1 -0
  82. package/build-module/components/border-radius-control/single-input-control.js.map +2 -2
  83. package/build-module/components/content-only-controls/index.js +237 -0
  84. package/build-module/components/content-only-controls/index.js.map +7 -0
  85. package/build-module/components/content-only-controls/link/index.js +172 -0
  86. package/build-module/components/content-only-controls/link/index.js.map +7 -0
  87. package/build-module/components/content-only-controls/media/index.js +243 -0
  88. package/build-module/components/content-only-controls/media/index.js.map +7 -0
  89. package/build-module/components/content-only-controls/plain-text/index.js +50 -0
  90. package/build-module/components/content-only-controls/plain-text/index.js.map +7 -0
  91. package/build-module/components/content-only-controls/rich-text/index.js +174 -0
  92. package/build-module/components/content-only-controls/rich-text/index.js.map +7 -0
  93. package/build-module/components/content-only-controls/use-inspector-popover-placement.js +16 -0
  94. package/build-module/components/content-only-controls/use-inspector-popover-placement.js.map +7 -0
  95. package/build-module/components/inserter/media-tab/media-tab.js +2 -34
  96. package/build-module/components/inserter/media-tab/media-tab.js.map +2 -2
  97. package/build-module/components/inspector-controls-tabs/content-tab.js +7 -3
  98. package/build-module/components/inspector-controls-tabs/content-tab.js.map +2 -2
  99. package/build-module/components/inspector-controls-tabs/index.js +7 -1
  100. package/build-module/components/inspector-controls-tabs/index.js.map +2 -2
  101. package/build-module/components/list-view/block-select-button.js +18 -5
  102. package/build-module/components/list-view/block-select-button.js.map +2 -2
  103. package/build-module/components/media-placeholder/index.js +1 -31
  104. package/build-module/components/media-placeholder/index.js.map +2 -2
  105. package/build-module/components/media-replace-flow/index.js +4 -30
  106. package/build-module/components/media-replace-flow/index.js.map +2 -2
  107. package/build-module/components/use-block-display-information/index.js +21 -1
  108. package/build-module/components/use-block-display-information/index.js.map +3 -3
  109. package/build-module/hooks/block-bindings.js +57 -62
  110. package/build-module/hooks/block-bindings.js.map +2 -2
  111. package/build-module/hooks/use-content-only-section-edit.js +46 -0
  112. package/build-module/hooks/use-content-only-section-edit.js.map +7 -0
  113. package/build-module/layouts/constrained.js +2 -2
  114. package/build-module/layouts/constrained.js.map +2 -2
  115. package/build-module/private-apis.js +3 -3
  116. package/build-module/private-apis.js.map +2 -2
  117. package/build-module/store/private-keys.js +2 -0
  118. package/build-module/store/private-keys.js.map +2 -2
  119. package/build-module/store/private-selectors.js +1 -2
  120. package/build-module/store/private-selectors.js.map +2 -2
  121. package/build-module/store/reducer.js +1 -2
  122. package/build-module/store/reducer.js.map +2 -2
  123. package/build-module/utils/fit-text-utils.js +9 -1
  124. package/build-module/utils/fit-text-utils.js.map +2 -2
  125. package/build-style/style-rtl.css +132 -0
  126. package/build-style/style.css +132 -0
  127. package/package.json +37 -37
  128. package/src/components/block-inspector/edit-contents.js +10 -29
  129. package/src/components/block-inspector/index.js +4 -2
  130. package/src/components/block-list/block.js +6 -0
  131. package/src/components/block-list/use-block-props/index.js +3 -1
  132. package/src/components/block-list/use-block-props/use-is-hovered.js +24 -12
  133. package/src/components/block-settings-menu-controls/edit-section-menu-item.js +39 -0
  134. package/src/components/block-settings-menu-controls/index.js +7 -0
  135. package/src/components/block-toolbar/block-toolbar-icon.js +14 -10
  136. package/src/components/block-variation-transforms/index.js +96 -35
  137. package/src/components/border-radius-control/single-input-control.js +1 -0
  138. package/src/components/content-only-controls/index.js +296 -0
  139. package/src/components/content-only-controls/link/index.js +195 -0
  140. package/src/components/content-only-controls/link/styles.scss +23 -0
  141. package/src/components/content-only-controls/media/index.js +285 -0
  142. package/src/components/content-only-controls/media/styles.scss +47 -0
  143. package/src/components/content-only-controls/plain-text/index.js +49 -0
  144. package/src/components/content-only-controls/rich-text/index.js +193 -0
  145. package/src/components/content-only-controls/rich-text/styles.scss +24 -0
  146. package/src/components/content-only-controls/styles.scss +35 -0
  147. package/src/components/content-only-controls/use-inspector-popover-placement.js +19 -0
  148. package/src/components/inserter/media-tab/media-tab.js +2 -44
  149. package/src/components/inspector-controls-tabs/content-tab.js +12 -4
  150. package/src/components/inspector-controls-tabs/index.js +4 -1
  151. package/src/components/list-view/block-select-button.js +37 -24
  152. package/src/components/media-placeholder/index.js +1 -41
  153. package/src/components/media-replace-flow/index.js +3 -39
  154. package/src/components/use-block-display-information/index.js +30 -2
  155. package/src/hooks/block-bindings.js +71 -82
  156. package/src/hooks/use-content-only-section-edit.js +63 -0
  157. package/src/layouts/constrained.js +8 -2
  158. package/src/private-apis.js +2 -2
  159. package/src/store/private-keys.js +1 -0
  160. package/src/store/private-selectors.js +1 -2
  161. package/src/store/reducer.js +0 -3
  162. package/src/store/test/reducer.js +7 -17
  163. package/src/style.scss +1 -0
  164. package/src/utils/fit-text-utils.js +19 -1
  165. package/build/components/media-upload-modal/index.js +0 -29
  166. package/build/components/media-upload-modal/index.js.map +0 -7
  167. package/build-module/components/media-upload-modal/index.js +0 -8
  168. package/build-module/components/media-upload-modal/index.js.map +0 -7
  169. package/src/components/media-upload-modal/index.js +0 -18
@@ -0,0 +1,23 @@
1
+ @use "@wordpress/base-styles/colors" as *;
2
+ @use "@wordpress/base-styles/variables" as *;
3
+
4
+ .block-editor-content-only-controls__link {
5
+ width: 100%;
6
+ box-shadow: inset 0 0 0 $border-width $gray-400;
7
+
8
+ &:focus:not(:disabled) {
9
+ // Allow smooth transition between focused and unfocused box-shadow states.
10
+ box-shadow: 0 0 0 currentColor inset, 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
11
+ }
12
+ }
13
+
14
+ .block-editor-content-only-controls__link-row {
15
+ align-items: center;
16
+ }
17
+
18
+ .block-editor-content-only-controls__link-title {
19
+ width: 100%;
20
+ white-space: nowrap;
21
+ text-overflow: ellipsis;
22
+ overflow: hidden;
23
+ }
@@ -0,0 +1,285 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import {
5
+ Button,
6
+ Icon,
7
+ __experimentalToolsPanelItem as ToolsPanelItem,
8
+ __experimentalGrid as Grid,
9
+ } from '@wordpress/components';
10
+ import { useSelect } from '@wordpress/data';
11
+ import { useMemo } from '@wordpress/element';
12
+ import { __ } from '@wordpress/i18n';
13
+ import {
14
+ audio as audioIcon,
15
+ image as imageIcon,
16
+ media as mediaIcon,
17
+ video as videoIcon,
18
+ } from '@wordpress/icons';
19
+
20
+ /**
21
+ * Internal dependencies
22
+ */
23
+ import MediaReplaceFlow from '../../media-replace-flow';
24
+ import MediaUploadCheck from '../../media-upload/check';
25
+ import { useInspectorPopoverPlacement } from '../use-inspector-popover-placement';
26
+ import { getMediaSelectKey } from '../../../store/private-keys';
27
+ import { store as blockEditorStore } from '../../../store';
28
+
29
+ function MediaThumbnail( { control, attributeValues, attachment } ) {
30
+ const { allowedTypes, multiple } = control.args;
31
+ const mapping = control.mapping;
32
+ if ( multiple ) {
33
+ return 'todo multiple';
34
+ }
35
+
36
+ if ( attachment?.media_type === 'image' || attachment?.poster ) {
37
+ return (
38
+ <img
39
+ className="block-editor-content-only-controls__media-thumbnail"
40
+ alt=""
41
+ width={ 24 }
42
+ height={ 24 }
43
+ src={
44
+ attachment.media_type === 'image'
45
+ ? attachment.source_url
46
+ : attachment.poster
47
+ }
48
+ />
49
+ );
50
+ }
51
+
52
+ if ( allowedTypes.length === 1 ) {
53
+ let src;
54
+ if (
55
+ allowedTypes[ 0 ] === 'image' &&
56
+ mapping.src &&
57
+ attributeValues[ mapping.src ]
58
+ ) {
59
+ src = attributeValues[ mapping.src ];
60
+ } else if (
61
+ allowedTypes[ 0 ] === 'video' &&
62
+ mapping.poster &&
63
+ attributeValues[ mapping.poster ]
64
+ ) {
65
+ src = attributeValues[ mapping.poster ];
66
+ }
67
+
68
+ if ( src ) {
69
+ return (
70
+ <img
71
+ className="block-editor-content-only-controls__media-thumbnail"
72
+ alt=""
73
+ width={ 24 }
74
+ height={ 24 }
75
+ src={ src }
76
+ />
77
+ );
78
+ }
79
+
80
+ let icon;
81
+ if ( allowedTypes[ 0 ] === 'image' ) {
82
+ icon = imageIcon;
83
+ } else if ( allowedTypes[ 0 ] === 'video' ) {
84
+ icon = videoIcon;
85
+ } else if ( allowedTypes[ 0 ] === 'audio' ) {
86
+ icon = audioIcon;
87
+ } else {
88
+ icon = mediaIcon;
89
+ }
90
+
91
+ if ( icon ) {
92
+ return <Icon icon={ icon } size={ 24 } />;
93
+ }
94
+ }
95
+
96
+ return <Icon icon={ mediaIcon } size={ 24 } />;
97
+ }
98
+
99
+ export default function Media( {
100
+ clientId,
101
+ control,
102
+ blockType,
103
+ attributeValues,
104
+ updateAttributes,
105
+ } ) {
106
+ const { popoverProps } = useInspectorPopoverPlacement( {
107
+ isControl: true,
108
+ } );
109
+ const typeKey = control.mapping.type;
110
+ const idKey = control.mapping.id;
111
+ const srcKey = control.mapping.src;
112
+ const captionKey = control.mapping.caption;
113
+ const altKey = control.mapping.alt;
114
+ const posterKey = control.mapping.poster;
115
+ const featuredImageKey = control.mapping.featuredImage;
116
+
117
+ const id = attributeValues[ idKey ];
118
+ const src = attributeValues[ srcKey ];
119
+ const caption = attributeValues[ captionKey ];
120
+ const alt = attributeValues[ altKey ];
121
+ const useFeaturedImage = attributeValues[ featuredImageKey ];
122
+
123
+ const attachment = useSelect(
124
+ ( select ) => {
125
+ if ( ! id ) {
126
+ return;
127
+ }
128
+
129
+ const settings = select( blockEditorStore ).getSettings();
130
+ const getMedia = settings[ getMediaSelectKey ];
131
+
132
+ if ( ! getMedia ) {
133
+ return;
134
+ }
135
+
136
+ return getMedia( select, id );
137
+ },
138
+ [ id ]
139
+ );
140
+
141
+ // TODO - pluralize when multiple.
142
+ let chooseItemLabel;
143
+ if ( control.args.allowedTypes.length === 1 ) {
144
+ const allowedType = control.args.allowedTypes[ 0 ];
145
+ if ( allowedType === 'image' ) {
146
+ chooseItemLabel = __( 'Choose an image…' );
147
+ } else if ( allowedType === 'video' ) {
148
+ chooseItemLabel = __( 'Choose a video…' );
149
+ } else if ( allowedType === 'application' ) {
150
+ chooseItemLabel = __( 'Choose a file…' );
151
+ } else {
152
+ chooseItemLabel = __( 'Choose a media item…' );
153
+ }
154
+ } else {
155
+ chooseItemLabel = __( 'Choose a media item…' );
156
+ }
157
+
158
+ const defaultValues = useMemo( () => {
159
+ return Object.fromEntries(
160
+ Object.entries( control.mapping ).map( ( [ , attributeKey ] ) => {
161
+ return [
162
+ attributeKey,
163
+ blockType.attributes[ attributeKey ]?.defaultValue ??
164
+ undefined,
165
+ ];
166
+ } )
167
+ );
168
+ }, [ blockType.attributes, control.mapping ] );
169
+
170
+ return (
171
+ <MediaUploadCheck>
172
+ <ToolsPanelItem
173
+ panelId={ clientId }
174
+ label={ control.label }
175
+ hasValue={ () => !! src }
176
+ onDeselect={ () => {
177
+ updateAttributes( defaultValues );
178
+ } }
179
+ isShownByDefault={ control.shownByDefault }
180
+ >
181
+ <MediaReplaceFlow
182
+ className="block-editor-content-only-controls__media-replace-flow"
183
+ allowedTypes={ control.args.allowedTypes }
184
+ mediaId={ id }
185
+ mediaURL={ src }
186
+ multiple={ control.args.multiple }
187
+ popoverProps={ popoverProps }
188
+ onReset={ () => {
189
+ updateAttributes( defaultValues );
190
+ } }
191
+ useFeaturedImage={ !! useFeaturedImage }
192
+ onToggleFeaturedImage={
193
+ !! featuredImageKey &&
194
+ ( () => {
195
+ updateAttributes( {
196
+ ...defaultValues,
197
+ [ featuredImageKey ]: ! useFeaturedImage,
198
+ } );
199
+ } )
200
+ }
201
+ onSelect={ ( selectedMedia ) => {
202
+ if ( selectedMedia.id && selectedMedia.url ) {
203
+ const optionalAttributes = {};
204
+
205
+ if ( typeKey && selectedMedia.type ) {
206
+ optionalAttributes[ typeKey ] =
207
+ selectedMedia.type;
208
+ }
209
+
210
+ if (
211
+ captionKey &&
212
+ ! caption &&
213
+ selectedMedia.caption
214
+ ) {
215
+ optionalAttributes[ captionKey ] =
216
+ selectedMedia.caption;
217
+ }
218
+ if ( altKey && ! alt && selectedMedia.alt ) {
219
+ optionalAttributes[ altKey ] =
220
+ selectedMedia.alt;
221
+ }
222
+ if ( posterKey && selectedMedia.poster ) {
223
+ optionalAttributes[ posterKey ] =
224
+ selectedMedia.poster;
225
+ }
226
+
227
+ updateAttributes( {
228
+ [ idKey ]: selectedMedia.id,
229
+ [ srcKey ]: selectedMedia.url,
230
+ ...optionalAttributes,
231
+ } );
232
+ }
233
+ } }
234
+ renderToggle={ ( buttonProps ) => (
235
+ <Button
236
+ __next40pxDefaultSize
237
+ className="block-editor-content-only-controls__media"
238
+ { ...buttonProps }
239
+ >
240
+ <Grid
241
+ rowGap={ 0 }
242
+ columnGap={ 8 }
243
+ templateColumns="24px 1fr"
244
+ className="block-editor-content-only-controls__media-row"
245
+ >
246
+ { src && (
247
+ <>
248
+ <MediaThumbnail
249
+ attachment={ attachment }
250
+ control={ control }
251
+ attributeValues={ attributeValues }
252
+ />
253
+ <span className="block-editor-content-only-controls__media-title">
254
+ {
255
+ // TODO - truncate long titles or url smartly (e.g. show filename).
256
+ attachment?.title?.raw &&
257
+ attachment?.title?.raw !== ''
258
+ ? attachment?.title?.raw
259
+ : src
260
+ }
261
+ </span>
262
+ </>
263
+ ) }
264
+ { ! src && (
265
+ <>
266
+ <span
267
+ className="block-editor-content-only-controls__media-placeholder"
268
+ style={ {
269
+ width: '24px',
270
+ height: '24px',
271
+ } }
272
+ />
273
+ <span className="block-editor-content-only-controls__media-title">
274
+ { chooseItemLabel }
275
+ </span>
276
+ </>
277
+ ) }
278
+ </Grid>
279
+ </Button>
280
+ ) }
281
+ />
282
+ </ToolsPanelItem>
283
+ </MediaUploadCheck>
284
+ );
285
+ }
@@ -0,0 +1,47 @@
1
+ @use "@wordpress/base-styles/colors" as *;
2
+ @use "@wordpress/base-styles/variables" as *;
3
+
4
+ .block-editor-content-only-controls__media {
5
+ width: 100%;
6
+ box-shadow: inset 0 0 0 $border-width $gray-400;
7
+
8
+ &:focus:not(:disabled) {
9
+ // Allow smooth transition between focused and unfocused box-shadow states.
10
+ box-shadow: 0 0 0 currentColor inset, 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
11
+ }
12
+ }
13
+
14
+ .block-editor-content-only-controls__media-replace-flow {
15
+ // Required, otherwise the width collapses.
16
+ display: block;
17
+ }
18
+
19
+ .block-editor-content-only-controls__media-row {
20
+ align-items: center;
21
+ }
22
+
23
+ .block-editor-content-only-controls__media-placeholder {
24
+ width: 24px;
25
+ height: 24px;
26
+ border-radius: $radius-small;
27
+ box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2);
28
+ display: inline-block;
29
+ padding: 0;
30
+ background:
31
+ $white
32
+ linear-gradient(-45deg, transparent 48%, $gray-300 48%, $gray-300 52%, transparent 52%);
33
+ }
34
+
35
+ .block-editor-content-only-controls__media-title {
36
+ width: 100%;
37
+ white-space: nowrap;
38
+ text-overflow: ellipsis;
39
+ overflow: hidden;
40
+ }
41
+
42
+ block-editor-content-only-controls__media-thumbnail {
43
+ width: 100%;
44
+ height: 100%;
45
+ border-radius: $radius-small;
46
+ align-self: center;
47
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import {
5
+ __experimentalToolsPanelItem as ToolsPanelItem,
6
+ TextControl,
7
+ } from '@wordpress/components';
8
+ import { __unstableStripHTML as stripHTML } from '@wordpress/dom';
9
+
10
+ export default function PlainText( {
11
+ clientId,
12
+ control,
13
+ blockType,
14
+ attributeValues,
15
+ updateAttributes,
16
+ } ) {
17
+ const valueKey = control.mapping.value;
18
+ const value = attributeValues[ valueKey ];
19
+ const defaultValue =
20
+ blockType.attributes[ valueKey ]?.defaultValue ?? undefined;
21
+
22
+ return (
23
+ <ToolsPanelItem
24
+ panelId={ clientId }
25
+ label={ control.label }
26
+ hasValue={ () => {
27
+ return (
28
+ value !== defaultValue && stripHTML( value )?.length !== 0
29
+ );
30
+ } }
31
+ onDeselect={ () => {
32
+ updateAttributes( { [ valueKey ]: defaultValue } );
33
+ } }
34
+ isShownByDefault={ control.shownByDefault }
35
+ >
36
+ <TextControl
37
+ __nextHasNoMarginBottom
38
+ __next40pxDefaultSize
39
+ label={ control.label }
40
+ value={ value ? stripHTML( value ) : '' }
41
+ onChange={ ( newValue ) => {
42
+ updateAttributes( { [ valueKey ]: newValue } );
43
+ } }
44
+ autoComplete="off"
45
+ hideLabelFromVision={ control.shownByDefault }
46
+ />
47
+ </ToolsPanelItem>
48
+ );
49
+ }
@@ -0,0 +1,193 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import {
5
+ BaseControl,
6
+ useBaseControlProps,
7
+ __experimentalToolsPanelItem as ToolsPanelItem,
8
+ } from '@wordpress/components';
9
+ import { useMergeRefs } from '@wordpress/compose';
10
+ import { useRegistry } from '@wordpress/data';
11
+ import { useRef, useState } from '@wordpress/element';
12
+ import {
13
+ __unstableUseRichText as useRichText,
14
+ isEmpty,
15
+ removeFormat,
16
+ } from '@wordpress/rich-text';
17
+
18
+ /**
19
+ * Internal dependencies
20
+ */
21
+ import { useFormatTypes } from '../../rich-text/use-format-types';
22
+ import { getAllowedFormats } from '../../rich-text/utils';
23
+ import { useEventListeners } from '../../rich-text/event-listeners';
24
+ import FormatEdit from '../../rich-text/format-edit';
25
+ import { keyboardShortcutContext, inputEventContext } from '../../rich-text';
26
+
27
+ export default function RichTextControl( {
28
+ clientId,
29
+ control,
30
+ blockType,
31
+ attributeValues,
32
+ updateAttributes,
33
+ } ) {
34
+ const registry = useRegistry();
35
+ const valueKey = control.mapping.value;
36
+ const attrValue = attributeValues[ valueKey ];
37
+ const defaultValue =
38
+ blockType.attributes[ valueKey ]?.defaultValue ?? undefined;
39
+ const [ selection, setSelection ] = useState( {
40
+ start: undefined,
41
+ end: undefined,
42
+ } );
43
+ const [ isSelected, setIsSelected ] = useState( false );
44
+ const anchorRef = useRef();
45
+ const inputEvents = useRef( new Set() );
46
+ const keyboardShortcuts = useRef( new Set() );
47
+
48
+ const adjustedAllowedFormats = getAllowedFormats( {
49
+ allowedFormats: control.args?.allowedFormats,
50
+ disableFormats: control.args?.disableFormats,
51
+ } );
52
+
53
+ const {
54
+ formatTypes,
55
+ prepareHandlers,
56
+ valueHandlers,
57
+ changeHandlers,
58
+ dependencies,
59
+ } = useFormatTypes( {
60
+ clientId,
61
+ identifier: valueKey,
62
+ allowedFormats: adjustedAllowedFormats,
63
+ withoutInteractiveFormatting:
64
+ control.args?.withoutInteractiveFormatting,
65
+ disableNoneEssentialFormatting: true,
66
+ } );
67
+
68
+ function addEditorOnlyFormats( value ) {
69
+ return valueHandlers.reduce(
70
+ ( accumulator, fn ) => fn( accumulator, value.text ),
71
+ value.formats
72
+ );
73
+ }
74
+
75
+ function removeEditorOnlyFormats( value ) {
76
+ formatTypes.forEach( ( formatType ) => {
77
+ // Remove formats created by prepareEditableTree, because they are editor only.
78
+ if ( formatType.__experimentalCreatePrepareEditableTree ) {
79
+ value = removeFormat(
80
+ value,
81
+ formatType.name,
82
+ 0,
83
+ value.text.length
84
+ );
85
+ }
86
+ } );
87
+
88
+ return value.formats;
89
+ }
90
+
91
+ function addInvisibleFormats( value ) {
92
+ return prepareHandlers.reduce(
93
+ ( accumulator, fn ) => fn( accumulator, value.text ),
94
+ value.formats
95
+ );
96
+ }
97
+
98
+ function onFocus() {
99
+ anchorRef.current?.focus();
100
+ }
101
+
102
+ const {
103
+ value,
104
+ getValue,
105
+ onChange,
106
+ ref: richTextRef,
107
+ } = useRichText( {
108
+ value: attrValue,
109
+ onChange( html, { __unstableFormats, __unstableText } ) {
110
+ updateAttributes( { [ valueKey ]: html } );
111
+ Object.values( changeHandlers ).forEach( ( changeHandler ) => {
112
+ changeHandler( __unstableFormats, __unstableText );
113
+ } );
114
+ },
115
+ selectionStart: selection.start,
116
+ selectionEnd: selection.end,
117
+ onSelectionChange: ( start, end ) => setSelection( { start, end } ),
118
+ __unstableIsSelected: isSelected,
119
+ preserveWhiteSpace: !! control.args?.preserveWhiteSpace,
120
+ placeholder: control.args?.placeholder,
121
+ __unstableDisableFormats: control.args?.disableFormats,
122
+ __unstableDependencies: dependencies,
123
+ __unstableAfterParse: addEditorOnlyFormats,
124
+ __unstableBeforeSerialize: removeEditorOnlyFormats,
125
+ __unstableAddInvisibleFormats: addInvisibleFormats,
126
+ } );
127
+
128
+ const { baseControlProps, controlProps } = useBaseControlProps( {
129
+ hideLabelFromVision: control.shownByDefault,
130
+ label: control.label,
131
+ } );
132
+
133
+ return (
134
+ <ToolsPanelItem
135
+ panelId={ clientId }
136
+ label={ control.label }
137
+ hasValue={ () => {
138
+ return value?.text && ! isEmpty( value );
139
+ } }
140
+ onDeselect={ () =>
141
+ updateAttributes( { [ valueKey ]: defaultValue } )
142
+ }
143
+ isShownByDefault={ control.shownByDefault }
144
+ >
145
+ { isSelected && (
146
+ <keyboardShortcutContext.Provider value={ keyboardShortcuts }>
147
+ <inputEventContext.Provider value={ inputEvents }>
148
+ <div>
149
+ <FormatEdit
150
+ value={ value }
151
+ onChange={ onChange }
152
+ onFocus={ onFocus }
153
+ formatTypes={ formatTypes }
154
+ forwardedRef={ anchorRef }
155
+ isVisible={ false }
156
+ />
157
+ </div>
158
+ </inputEventContext.Provider>
159
+ </keyboardShortcutContext.Provider>
160
+ ) }
161
+ <BaseControl __nextHasNoMarginBottom { ...baseControlProps }>
162
+ <div
163
+ className="block-editor-content-only-controls__rich-text"
164
+ role="textbox"
165
+ aria-multiline={ ! control.args?.disableLineBreaks }
166
+ ref={ useMergeRefs( [
167
+ richTextRef,
168
+ useEventListeners( {
169
+ registry,
170
+ getValue,
171
+ onChange,
172
+ formatTypes,
173
+ selectionChange: setSelection,
174
+ isSelected,
175
+ disableFormats: control.args?.disableFormats,
176
+ value,
177
+ tagName: 'div',
178
+ removeEditorOnlyFormats,
179
+ disableLineBreaks: control.args?.disableLineBreaks,
180
+ keyboardShortcuts,
181
+ inputEvents,
182
+ } ),
183
+ anchorRef,
184
+ ] ) }
185
+ onFocus={ () => setIsSelected( true ) }
186
+ onBlur={ () => setIsSelected( false ) }
187
+ contentEditable
188
+ { ...controlProps }
189
+ />
190
+ </BaseControl>
191
+ </ToolsPanelItem>
192
+ );
193
+ }
@@ -0,0 +1,24 @@
1
+ @use "@wordpress/base-styles/colors" as *;
2
+ @use "@wordpress/base-styles/mixins" as *;
3
+ @use "@wordpress/base-styles/variables" as *;
4
+
5
+ .block-editor-content-only-controls__rich-text {
6
+ width: 100%;
7
+ // Override input style margin in WP forms.css.
8
+ margin: 0;
9
+ background: $white;
10
+ color: $gray-900;
11
+ @include input-control( var(--wp-admin-theme-color, #3858e9) );
12
+ border-color: $gray-600;
13
+
14
+ &::placeholder {
15
+ color: color-mix(in srgb, $gray-900, transparent 38%);
16
+ }
17
+
18
+ min-height: $grid-unit-50;
19
+
20
+ // Subtract 1px to account for the border, which isn't included on the element
21
+ // on newer components like InputControl, SelectControl, etc.
22
+ // These values should be shared with the `controlPaddingX` in ./utils/config-values.js
23
+ padding: $grid-unit-15;
24
+ }
@@ -0,0 +1,35 @@
1
+ @use "@wordpress/base-styles/colors" as *;
2
+ @use "@wordpress/base-styles/variables" as *;
3
+ @use "./link/styles.scss" as *;
4
+ @use "./media/styles.scss" as *;
5
+ @use "./rich-text/styles.scss" as *;
6
+
7
+ .block-editor-content-only-controls__screen {
8
+ &.components-navigator-screen {
9
+ padding: $grid-unit-10 0 0 0;
10
+ }
11
+
12
+ // Add border for the entire content controls and remove the similar border
13
+ // for tools panel.
14
+ border-top: $border-width solid $gray-200;
15
+
16
+
17
+ .components-tools-panel {
18
+ border-top: none;
19
+
20
+ // Condense the tools panels more than normal.
21
+ padding-top: $grid-unit-10;
22
+ }
23
+ }
24
+
25
+ .block-editor-content-only-controls__button-panel {
26
+ padding: 4px;
27
+
28
+ // Match heading font weights for the tools panels.
29
+ font-weight: 500 !important;
30
+ }
31
+
32
+ .block-editor-content-only-controls__back-button,
33
+ .block-editor-content-only-controls__drill-down-button {
34
+ width: 100%;
35
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useViewportMatch } from '@wordpress/compose';
5
+
6
+ export function useInspectorPopoverPlacement(
7
+ { isControl } = { isControl: false }
8
+ ) {
9
+ const isMobile = useViewportMatch( 'medium', '<' );
10
+ return ! isMobile
11
+ ? {
12
+ popoverProps: {
13
+ placement: 'left-start',
14
+ // For non-mobile, inner sidebar width (248px) - button width (24px) - border (1px) + padding (16px) + spacing (20px)
15
+ offset: isControl ? 35 : 259,
16
+ },
17
+ }
18
+ : {};
19
+ }