@wordpress/block-editor 15.8.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 (187) 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/global-styles/typography-panel.js +16 -10
  34. package/build/components/global-styles/typography-panel.js.map +2 -2
  35. package/build/components/inserter/media-tab/media-tab.js +1 -33
  36. package/build/components/inserter/media-tab/media-tab.js.map +3 -3
  37. package/build/components/inspector-controls-tabs/content-tab.js +6 -2
  38. package/build/components/inspector-controls-tabs/content-tab.js.map +3 -3
  39. package/build/components/inspector-controls-tabs/index.js +7 -1
  40. package/build/components/inspector-controls-tabs/index.js.map +2 -2
  41. package/build/components/list-view/block-select-button.js +11 -4
  42. package/build/components/list-view/block-select-button.js.map +2 -2
  43. package/build/components/media-placeholder/index.js +1 -31
  44. package/build/components/media-placeholder/index.js.map +3 -3
  45. package/build/components/media-replace-flow/index.js +4 -30
  46. package/build/components/media-replace-flow/index.js.map +3 -3
  47. package/build/components/rich-text/format-edit.js +9 -1
  48. package/build/components/rich-text/format-edit.js.map +2 -2
  49. package/build/components/use-block-display-information/index.js +21 -1
  50. package/build/components/use-block-display-information/index.js.map +3 -3
  51. package/build/hooks/block-bindings.js +52 -61
  52. package/build/hooks/block-bindings.js.map +3 -3
  53. package/build/hooks/use-content-only-section-edit.js +67 -0
  54. package/build/hooks/use-content-only-section-edit.js.map +7 -0
  55. package/build/layouts/constrained.js +2 -2
  56. package/build/layouts/constrained.js.map +2 -2
  57. package/build/private-apis.js +2 -3
  58. package/build/private-apis.js.map +3 -3
  59. package/build/store/private-keys.js +3 -0
  60. package/build/store/private-keys.js.map +2 -2
  61. package/build/store/private-selectors.js +1 -2
  62. package/build/store/private-selectors.js.map +2 -2
  63. package/build/store/reducer.js +1 -2
  64. package/build/store/reducer.js.map +2 -2
  65. package/build/store/selectors.js +3 -0
  66. package/build/store/selectors.js.map +2 -2
  67. package/build/utils/fit-text-utils.js +9 -1
  68. package/build/utils/fit-text-utils.js.map +2 -2
  69. package/build-module/components/block-inspector/edit-contents.js +9 -23
  70. package/build-module/components/block-inspector/edit-contents.js.map +2 -2
  71. package/build-module/components/block-inspector/index.js +7 -1
  72. package/build-module/components/block-inspector/index.js.map +2 -2
  73. package/build-module/components/block-list/block.js +4 -0
  74. package/build-module/components/block-list/block.js.map +2 -2
  75. package/build-module/components/block-list/use-block-props/index.js +3 -1
  76. package/build-module/components/block-list/use-block-props/index.js.map +2 -2
  77. package/build-module/components/block-list/use-block-props/use-is-hovered.js +16 -10
  78. package/build-module/components/block-list/use-block-props/use-is-hovered.js.map +2 -2
  79. package/build-module/components/block-settings-menu-controls/edit-section-menu-item.js +29 -0
  80. package/build-module/components/block-settings-menu-controls/edit-section-menu-item.js.map +7 -0
  81. package/build-module/components/block-settings-menu-controls/index.js +8 -0
  82. package/build-module/components/block-settings-menu-controls/index.js.map +2 -2
  83. package/build-module/components/block-toolbar/block-toolbar-icon.js +10 -10
  84. package/build-module/components/block-toolbar/block-toolbar-icon.js.map +2 -2
  85. package/build-module/components/block-variation-transforms/index.js +32 -5
  86. package/build-module/components/block-variation-transforms/index.js.map +2 -2
  87. package/build-module/components/border-radius-control/single-input-control.js +1 -0
  88. package/build-module/components/border-radius-control/single-input-control.js.map +2 -2
  89. package/build-module/components/content-only-controls/index.js +237 -0
  90. package/build-module/components/content-only-controls/index.js.map +7 -0
  91. package/build-module/components/content-only-controls/link/index.js +172 -0
  92. package/build-module/components/content-only-controls/link/index.js.map +7 -0
  93. package/build-module/components/content-only-controls/media/index.js +243 -0
  94. package/build-module/components/content-only-controls/media/index.js.map +7 -0
  95. package/build-module/components/content-only-controls/plain-text/index.js +50 -0
  96. package/build-module/components/content-only-controls/plain-text/index.js.map +7 -0
  97. package/build-module/components/content-only-controls/rich-text/index.js +174 -0
  98. package/build-module/components/content-only-controls/rich-text/index.js.map +7 -0
  99. package/build-module/components/content-only-controls/use-inspector-popover-placement.js +16 -0
  100. package/build-module/components/content-only-controls/use-inspector-popover-placement.js.map +7 -0
  101. package/build-module/components/global-styles/typography-panel.js +18 -11
  102. package/build-module/components/global-styles/typography-panel.js.map +2 -2
  103. package/build-module/components/inserter/media-tab/media-tab.js +2 -34
  104. package/build-module/components/inserter/media-tab/media-tab.js.map +2 -2
  105. package/build-module/components/inspector-controls-tabs/content-tab.js +7 -3
  106. package/build-module/components/inspector-controls-tabs/content-tab.js.map +2 -2
  107. package/build-module/components/inspector-controls-tabs/index.js +7 -1
  108. package/build-module/components/inspector-controls-tabs/index.js.map +2 -2
  109. package/build-module/components/list-view/block-select-button.js +18 -5
  110. package/build-module/components/list-view/block-select-button.js.map +2 -2
  111. package/build-module/components/media-placeholder/index.js +1 -31
  112. package/build-module/components/media-placeholder/index.js.map +2 -2
  113. package/build-module/components/media-replace-flow/index.js +4 -30
  114. package/build-module/components/media-replace-flow/index.js.map +2 -2
  115. package/build-module/components/rich-text/format-edit.js +9 -1
  116. package/build-module/components/rich-text/format-edit.js.map +2 -2
  117. package/build-module/components/use-block-display-information/index.js +21 -1
  118. package/build-module/components/use-block-display-information/index.js.map +3 -3
  119. package/build-module/hooks/block-bindings.js +57 -62
  120. package/build-module/hooks/block-bindings.js.map +2 -2
  121. package/build-module/hooks/use-content-only-section-edit.js +46 -0
  122. package/build-module/hooks/use-content-only-section-edit.js.map +7 -0
  123. package/build-module/layouts/constrained.js +2 -2
  124. package/build-module/layouts/constrained.js.map +2 -2
  125. package/build-module/private-apis.js +3 -3
  126. package/build-module/private-apis.js.map +2 -2
  127. package/build-module/store/private-keys.js +2 -0
  128. package/build-module/store/private-keys.js.map +2 -2
  129. package/build-module/store/private-selectors.js +1 -2
  130. package/build-module/store/private-selectors.js.map +2 -2
  131. package/build-module/store/reducer.js +1 -2
  132. package/build-module/store/reducer.js.map +2 -2
  133. package/build-module/store/selectors.js +3 -0
  134. package/build-module/store/selectors.js.map +2 -2
  135. package/build-module/utils/fit-text-utils.js +9 -1
  136. package/build-module/utils/fit-text-utils.js.map +2 -2
  137. package/build-style/style-rtl.css +132 -0
  138. package/build-style/style.css +132 -0
  139. package/package.json +37 -37
  140. package/src/components/block-inspector/edit-contents.js +10 -29
  141. package/src/components/block-inspector/index.js +4 -2
  142. package/src/components/block-list/block.js +6 -0
  143. package/src/components/block-list/use-block-props/index.js +3 -1
  144. package/src/components/block-list/use-block-props/use-is-hovered.js +24 -12
  145. package/src/components/block-settings-menu-controls/edit-section-menu-item.js +39 -0
  146. package/src/components/block-settings-menu-controls/index.js +7 -0
  147. package/src/components/block-switcher/block-transformations-menu.native.js +0 -1
  148. package/src/components/block-toolbar/block-toolbar-icon.js +14 -10
  149. package/src/components/block-toolbar/test/__snapshots__/block-toolbar-menu.native.js.snap +6 -4
  150. package/src/components/block-toolbar/test/block-toolbar-menu.native.js +2 -2
  151. package/src/components/block-variation-transforms/index.js +96 -35
  152. package/src/components/border-radius-control/single-input-control.js +1 -0
  153. package/src/components/content-only-controls/index.js +296 -0
  154. package/src/components/content-only-controls/link/index.js +195 -0
  155. package/src/components/content-only-controls/link/styles.scss +23 -0
  156. package/src/components/content-only-controls/media/index.js +285 -0
  157. package/src/components/content-only-controls/media/styles.scss +47 -0
  158. package/src/components/content-only-controls/plain-text/index.js +49 -0
  159. package/src/components/content-only-controls/rich-text/index.js +193 -0
  160. package/src/components/content-only-controls/rich-text/styles.scss +24 -0
  161. package/src/components/content-only-controls/styles.scss +35 -0
  162. package/src/components/content-only-controls/use-inspector-popover-placement.js +19 -0
  163. package/src/components/global-styles/typography-panel.js +12 -0
  164. package/src/components/inserter/media-tab/media-tab.js +2 -44
  165. package/src/components/inspector-controls-tabs/content-tab.js +12 -4
  166. package/src/components/inspector-controls-tabs/index.js +4 -1
  167. package/src/components/list-view/block-select-button.js +37 -24
  168. package/src/components/media-placeholder/index.js +1 -41
  169. package/src/components/media-replace-flow/index.js +3 -39
  170. package/src/components/rich-text/format-edit.js +9 -1
  171. package/src/components/use-block-display-information/index.js +30 -2
  172. package/src/hooks/block-bindings.js +71 -82
  173. package/src/hooks/use-content-only-section-edit.js +63 -0
  174. package/src/layouts/constrained.js +8 -2
  175. package/src/private-apis.js +2 -2
  176. package/src/store/private-keys.js +1 -0
  177. package/src/store/private-selectors.js +1 -2
  178. package/src/store/reducer.js +0 -3
  179. package/src/store/selectors.js +7 -0
  180. package/src/store/test/reducer.js +7 -17
  181. package/src/style.scss +1 -0
  182. package/src/utils/fit-text-utils.js +19 -1
  183. package/build/components/media-upload-modal/index.js +0 -29
  184. package/build/components/media-upload-modal/index.js.map +0 -7
  185. package/build-module/components/media-upload-modal/index.js +0 -8
  186. package/build-module/components/media-upload-modal/index.js.map +0 -7
  187. package/src/components/media-upload-modal/index.js +0 -18
@@ -0,0 +1,195 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import {
5
+ Button,
6
+ Icon,
7
+ __experimentalToolsPanelItem as ToolsPanelItem,
8
+ __experimentalGrid as Grid,
9
+ Popover,
10
+ } from '@wordpress/components';
11
+ import { useMemo, useState } from '@wordpress/element';
12
+ import { __ } from '@wordpress/i18n';
13
+ import { link } from '@wordpress/icons';
14
+ import { prependHTTP } from '@wordpress/url';
15
+
16
+ /**
17
+ * Internal dependencies
18
+ */
19
+ import LinkControl from '../../link-control';
20
+ import { useInspectorPopoverPlacement } from '../use-inspector-popover-placement';
21
+
22
+ export const NEW_TAB_REL = 'noreferrer noopener';
23
+ export const NEW_TAB_TARGET = '_blank';
24
+ export const NOFOLLOW_REL = 'nofollow';
25
+
26
+ /**
27
+ * Updates the link attributes.
28
+ *
29
+ * @param {Object} attributes The current block attributes.
30
+ * @param {string} attributes.rel The current link rel attribute.
31
+ * @param {string} attributes.url The current link url.
32
+ * @param {boolean} attributes.opensInNewTab Whether the link should open in a new window.
33
+ * @param {boolean} attributes.nofollow Whether the link should be marked as nofollow.
34
+ */
35
+ export function getUpdatedLinkAttributes( {
36
+ rel = '',
37
+ url = '',
38
+ opensInNewTab,
39
+ nofollow,
40
+ } ) {
41
+ let newLinkTarget;
42
+ // Since `rel` is editable attribute, we need to check for existing values and proceed accordingly.
43
+ let updatedRel = rel;
44
+
45
+ if ( opensInNewTab ) {
46
+ newLinkTarget = NEW_TAB_TARGET;
47
+ updatedRel = updatedRel?.includes( NEW_TAB_REL )
48
+ ? updatedRel
49
+ : updatedRel + ` ${ NEW_TAB_REL }`;
50
+ } else {
51
+ const relRegex = new RegExp( `\\b${ NEW_TAB_REL }\\s*`, 'g' );
52
+ updatedRel = updatedRel?.replace( relRegex, '' ).trim();
53
+ }
54
+
55
+ if ( nofollow ) {
56
+ updatedRel = updatedRel?.includes( NOFOLLOW_REL )
57
+ ? updatedRel
58
+ : ( updatedRel + ` ${ NOFOLLOW_REL }` ).trim();
59
+ } else {
60
+ const relRegex = new RegExp( `\\b${ NOFOLLOW_REL }\\s*`, 'g' );
61
+ updatedRel = updatedRel?.replace( relRegex, '' ).trim();
62
+ }
63
+
64
+ return {
65
+ url: prependHTTP( url ),
66
+ linkTarget: newLinkTarget,
67
+ rel: updatedRel || undefined,
68
+ };
69
+ }
70
+
71
+ export default function Link( {
72
+ clientId,
73
+ control,
74
+ blockType,
75
+ attributeValues,
76
+ updateAttributes,
77
+ } ) {
78
+ const [ isLinkControlOpen, setIsLinkControlOpen ] = useState( false );
79
+ const { popoverProps } = useInspectorPopoverPlacement( {
80
+ isControl: true,
81
+ } );
82
+ const hrefKey = control.mapping.href;
83
+ const relKey = control.mapping.rel;
84
+ const targetKey = control.mapping.target;
85
+ const destinationKey = control.mapping.destination;
86
+
87
+ const href = attributeValues[ hrefKey ];
88
+ const rel = attributeValues[ relKey ];
89
+ const target = attributeValues[ targetKey ];
90
+ const destination = attributeValues[ destinationKey ];
91
+
92
+ const hrefDefaultValue =
93
+ blockType.attributes[ href ]?.defaultValue ?? undefined;
94
+ const relDefaultValue =
95
+ blockType.attributes[ rel ]?.defaultValue ?? undefined;
96
+ const targetDefaultValue =
97
+ blockType.attributes[ target ]?.defaultValue ?? undefined;
98
+ const destinationDefaultValue =
99
+ blockType.attributes[ destination ]?.defaultValue ?? undefined;
100
+
101
+ const opensInNewTab = target === NEW_TAB_TARGET;
102
+ const nofollow = rel === NOFOLLOW_REL;
103
+
104
+ // Memoize link value to avoid overriding the LinkControl's internal state.
105
+ // This is a temporary fix. See https://github.com/WordPress/gutenberg/issues/51256.
106
+ const linkValue = useMemo(
107
+ () => ( { url: href, opensInNewTab, nofollow } ),
108
+ [ href, opensInNewTab, nofollow ]
109
+ );
110
+
111
+ return (
112
+ <ToolsPanelItem
113
+ panelId={ clientId }
114
+ label={ control.label }
115
+ hasValue={ () => !! href }
116
+ onDeselect={ () => {
117
+ updateAttributes( {
118
+ [ hrefKey ]: hrefDefaultValue,
119
+ [ relKey ]: relDefaultValue,
120
+ [ targetKey ]: targetDefaultValue,
121
+ [ destinationKey ]: destinationDefaultValue,
122
+ } );
123
+ } }
124
+ isShownByDefault={ control.shownByDefault }
125
+ >
126
+ <Button
127
+ __next40pxDefaultSize
128
+ className="block-editor-content-only-controls__link"
129
+ onClick={ () => {
130
+ setIsLinkControlOpen( true );
131
+ } }
132
+ >
133
+ <Grid
134
+ rowGap={ 0 }
135
+ columnGap={ 8 }
136
+ templateColumns="24px 1fr"
137
+ className="block-editor-content-only-controls__link-row"
138
+ >
139
+ { href && (
140
+ <>
141
+ <Icon icon={ link } size={ 24 } />
142
+ <span className="block-editor-content-only-controls__link-title">
143
+ { href }
144
+ </span>
145
+ </>
146
+ ) }
147
+ { ! href && (
148
+ <>
149
+ <Icon
150
+ icon={ link }
151
+ size={ 24 }
152
+ style={ { opacity: 0.3 } }
153
+ />
154
+ <span className="block-editor-content-only-controls__link-title">
155
+ { __( 'Link' ) }
156
+ </span>
157
+ </>
158
+ ) }
159
+ </Grid>
160
+ </Button>
161
+ { isLinkControlOpen && (
162
+ <Popover
163
+ onClose={ () => {
164
+ setIsLinkControlOpen( false );
165
+ } }
166
+ { ...( popoverProps ?? {} ) }
167
+ >
168
+ <LinkControl
169
+ value={ linkValue }
170
+ onChange={ ( newValues ) => {
171
+ const updatedAttrs = getUpdatedLinkAttributes( {
172
+ rel,
173
+ ...newValues,
174
+ } );
175
+
176
+ updateAttributes( {
177
+ [ hrefKey ]: updatedAttrs.url,
178
+ [ relKey ]: updatedAttrs.rel,
179
+ [ targetKey ]: updatedAttrs.linkTarget,
180
+ } );
181
+ } }
182
+ onRemove={ () => {
183
+ updateAttributes( {
184
+ [ hrefKey ]: hrefDefaultValue,
185
+ [ relKey ]: relDefaultValue,
186
+ [ targetKey ]: targetDefaultValue,
187
+ [ destinationKey ]: destinationDefaultValue,
188
+ } );
189
+ } }
190
+ />
191
+ </Popover>
192
+ ) }
193
+ </ToolsPanelItem>
194
+ );
195
+ }
@@ -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
+ }