@wordpress/block-editor 15.8.1-next.16d95556a.0 → 15.9.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 (302) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/components/block-inspector/edit-contents.js +19 -23
  3. package/build/components/block-inspector/edit-contents.js.map +3 -3
  4. package/build/components/block-inspector/index.js +7 -1
  5. package/build/components/block-inspector/index.js.map +2 -2
  6. package/build/components/block-list/block.js +4 -0
  7. package/build/components/block-list/block.js.map +2 -2
  8. package/build/components/block-list/index.js +2 -1
  9. package/build/components/block-list/index.js.map +2 -2
  10. package/build/components/block-list/use-block-props/index.js +3 -1
  11. package/build/components/block-list/use-block-props/index.js.map +2 -2
  12. package/build/components/block-list/use-block-props/use-is-hovered.js +16 -10
  13. package/build/components/block-list/use-block-props/use-is-hovered.js.map +2 -2
  14. package/build/components/block-list/use-block-props/use-selected-block-event-handlers.js +27 -5
  15. package/build/components/block-list/use-block-props/use-selected-block-event-handlers.js.map +2 -2
  16. package/build/components/block-lock/modal.js +5 -5
  17. package/build/components/block-lock/modal.js.map +2 -2
  18. package/build/components/block-lock/use-block-lock.js +10 -13
  19. package/build/components/block-lock/use-block-lock.js.map +2 -2
  20. package/build/components/block-settings-menu-controls/edit-section-menu-item.js +64 -0
  21. package/build/components/block-settings-menu-controls/edit-section-menu-item.js.map +7 -0
  22. package/build/components/block-settings-menu-controls/index.js +9 -1
  23. package/build/components/block-settings-menu-controls/index.js.map +2 -2
  24. package/build/components/block-toolbar/block-toolbar-icon.js +9 -9
  25. package/build/components/block-toolbar/block-toolbar-icon.js.map +2 -2
  26. package/build/components/block-tools/index.js +56 -45
  27. package/build/components/block-tools/index.js.map +3 -3
  28. package/build/components/block-variation-transforms/index.js +32 -5
  29. package/build/components/block-variation-transforms/index.js.map +2 -2
  30. package/build/components/block-visibility/toolbar.js +1 -1
  31. package/build/components/block-visibility/toolbar.js.map +1 -1
  32. package/build/components/border-radius-control/single-input-control.js +1 -0
  33. package/build/components/border-radius-control/single-input-control.js.map +2 -2
  34. package/build/components/content-only-controls/fields-dropdown-menu.js +66 -0
  35. package/build/components/content-only-controls/fields-dropdown-menu.js.map +7 -0
  36. package/build/components/content-only-controls/index.js +444 -0
  37. package/build/components/content-only-controls/index.js.map +7 -0
  38. package/build/components/content-only-controls/link/index.js +193 -0
  39. package/build/components/content-only-controls/link/index.js.map +7 -0
  40. package/build/components/content-only-controls/media/index.js +264 -0
  41. package/build/components/content-only-controls/media/index.js.map +7 -0
  42. package/build/components/content-only-controls/rich-text/index.js +188 -0
  43. package/build/components/content-only-controls/rich-text/index.js.map +7 -0
  44. package/build/components/content-only-controls/use-inspector-popover-placement.js +41 -0
  45. package/build/components/content-only-controls/use-inspector-popover-placement.js.map +7 -0
  46. package/build/components/font-family/index.js +1 -15
  47. package/build/components/font-family/index.js.map +2 -2
  48. package/build/components/global-styles/dimensions-panel.js +35 -2
  49. package/build/components/global-styles/dimensions-panel.js.map +2 -2
  50. package/build/components/global-styles/hooks.js +1 -1
  51. package/build/components/global-styles/hooks.js.map +2 -2
  52. package/build/components/global-styles/typography-panel.js +1 -2
  53. package/build/components/global-styles/typography-panel.js.map +2 -2
  54. package/build/components/inserter/media-tab/media-tab.js +1 -33
  55. package/build/components/inserter/media-tab/media-tab.js.map +3 -3
  56. package/build/components/inspector-controls-tabs/content-tab.js +6 -2
  57. package/build/components/inspector-controls-tabs/content-tab.js.map +3 -3
  58. package/build/components/inspector-controls-tabs/index.js +7 -1
  59. package/build/components/inspector-controls-tabs/index.js.map +2 -2
  60. package/build/components/inspector-controls-tabs/use-inspector-controls-tabs.js +1 -1
  61. package/build/components/inspector-controls-tabs/use-inspector-controls-tabs.js.map +2 -2
  62. package/build/components/link-control/index.js +15 -7
  63. package/build/components/link-control/index.js.map +2 -2
  64. package/build/components/list-view/block-select-button.js +7 -8
  65. package/build/components/list-view/block-select-button.js.map +2 -2
  66. package/build/components/list-view/block.js +9 -7
  67. package/build/components/list-view/block.js.map +2 -2
  68. package/build/components/media-placeholder/index.js +18 -35
  69. package/build/components/media-placeholder/index.js.map +3 -3
  70. package/build/components/media-placeholder/utils.js +60 -0
  71. package/build/components/media-placeholder/utils.js.map +7 -0
  72. package/build/components/media-replace-flow/index.js +24 -33
  73. package/build/components/media-replace-flow/index.js.map +3 -3
  74. package/build/components/use-block-commands/index.js +1 -1
  75. package/build/components/use-block-commands/index.js.map +2 -2
  76. package/build/components/use-block-display-information/index.js +21 -1
  77. package/build/components/use-block-display-information/index.js.map +3 -3
  78. package/build/components/use-block-drop-zone/index.js +1 -5
  79. package/build/components/use-block-drop-zone/index.js.map +2 -2
  80. package/build/hooks/block-bindings.js +52 -61
  81. package/build/hooks/block-bindings.js.map +3 -3
  82. package/build/hooks/dimensions.js +3 -3
  83. package/build/hooks/dimensions.js.map +2 -2
  84. package/build/hooks/metadata.js +1 -1
  85. package/build/hooks/metadata.js.map +2 -2
  86. package/build/hooks/use-content-only-section-edit.js +67 -0
  87. package/build/hooks/use-content-only-section-edit.js.map +7 -0
  88. package/build/hooks/utils.js +5 -1
  89. package/build/hooks/utils.js.map +2 -2
  90. package/build/layouts/constrained.js +2 -2
  91. package/build/layouts/constrained.js.map +2 -2
  92. package/build/private-apis.js +2 -3
  93. package/build/private-apis.js.map +3 -3
  94. package/build/store/private-keys.js +3 -0
  95. package/build/store/private-keys.js.map +2 -2
  96. package/build/store/private-selectors.js +41 -2
  97. package/build/store/private-selectors.js.map +2 -2
  98. package/build/store/selectors.js +6 -4
  99. package/build/store/selectors.js.map +2 -2
  100. package/build/utils/fit-text-utils.js +9 -1
  101. package/build/utils/fit-text-utils.js.map +2 -2
  102. package/build-module/components/block-inspector/edit-contents.js +9 -23
  103. package/build-module/components/block-inspector/edit-contents.js.map +2 -2
  104. package/build-module/components/block-inspector/index.js +7 -1
  105. package/build-module/components/block-inspector/index.js.map +2 -2
  106. package/build-module/components/block-list/block.js +4 -0
  107. package/build-module/components/block-list/block.js.map +2 -2
  108. package/build-module/components/block-list/index.js +2 -1
  109. package/build-module/components/block-list/index.js.map +2 -2
  110. package/build-module/components/block-list/use-block-props/index.js +3 -1
  111. package/build-module/components/block-list/use-block-props/index.js.map +2 -2
  112. package/build-module/components/block-list/use-block-props/use-is-hovered.js +16 -10
  113. package/build-module/components/block-list/use-block-props/use-is-hovered.js.map +2 -2
  114. package/build-module/components/block-list/use-block-props/use-selected-block-event-handlers.js +27 -5
  115. package/build-module/components/block-list/use-block-props/use-selected-block-event-handlers.js.map +2 -2
  116. package/build-module/components/block-lock/modal.js +5 -5
  117. package/build-module/components/block-lock/modal.js.map +2 -2
  118. package/build-module/components/block-lock/use-block-lock.js +10 -13
  119. package/build-module/components/block-lock/use-block-lock.js.map +2 -2
  120. package/build-module/components/block-settings-menu-controls/edit-section-menu-item.js +29 -0
  121. package/build-module/components/block-settings-menu-controls/edit-section-menu-item.js.map +7 -0
  122. package/build-module/components/block-settings-menu-controls/index.js +9 -1
  123. package/build-module/components/block-settings-menu-controls/index.js.map +2 -2
  124. package/build-module/components/block-toolbar/block-toolbar-icon.js +10 -10
  125. package/build-module/components/block-toolbar/block-toolbar-icon.js.map +2 -2
  126. package/build-module/components/block-tools/index.js +56 -45
  127. package/build-module/components/block-tools/index.js.map +2 -2
  128. package/build-module/components/block-variation-transforms/index.js +32 -5
  129. package/build-module/components/block-variation-transforms/index.js.map +2 -2
  130. package/build-module/components/block-visibility/toolbar.js +1 -1
  131. package/build-module/components/block-visibility/toolbar.js.map +1 -1
  132. package/build-module/components/border-radius-control/single-input-control.js +1 -0
  133. package/build-module/components/border-radius-control/single-input-control.js.map +2 -2
  134. package/build-module/components/content-only-controls/fields-dropdown-menu.js +45 -0
  135. package/build-module/components/content-only-controls/fields-dropdown-menu.js.map +7 -0
  136. package/build-module/components/content-only-controls/index.js +420 -0
  137. package/build-module/components/content-only-controls/index.js.map +7 -0
  138. package/build-module/components/content-only-controls/link/index.js +160 -0
  139. package/build-module/components/content-only-controls/link/index.js.map +7 -0
  140. package/build-module/components/content-only-controls/media/index.js +242 -0
  141. package/build-module/components/content-only-controls/media/index.js.map +7 -0
  142. package/build-module/components/content-only-controls/rich-text/index.js +160 -0
  143. package/build-module/components/content-only-controls/rich-text/index.js.map +7 -0
  144. package/build-module/components/content-only-controls/use-inspector-popover-placement.js +16 -0
  145. package/build-module/components/content-only-controls/use-inspector-popover-placement.js.map +7 -0
  146. package/build-module/components/font-family/index.js +1 -15
  147. package/build-module/components/font-family/index.js.map +2 -2
  148. package/build-module/components/global-styles/dimensions-panel.js +35 -2
  149. package/build-module/components/global-styles/dimensions-panel.js.map +2 -2
  150. package/build-module/components/global-styles/hooks.js +1 -1
  151. package/build-module/components/global-styles/hooks.js.map +2 -2
  152. package/build-module/components/global-styles/typography-panel.js +1 -2
  153. package/build-module/components/global-styles/typography-panel.js.map +2 -2
  154. package/build-module/components/inserter/media-tab/media-tab.js +2 -34
  155. package/build-module/components/inserter/media-tab/media-tab.js.map +2 -2
  156. package/build-module/components/inspector-controls-tabs/content-tab.js +7 -3
  157. package/build-module/components/inspector-controls-tabs/content-tab.js.map +2 -2
  158. package/build-module/components/inspector-controls-tabs/index.js +7 -1
  159. package/build-module/components/inspector-controls-tabs/index.js.map +2 -2
  160. package/build-module/components/inspector-controls-tabs/use-inspector-controls-tabs.js +1 -1
  161. package/build-module/components/inspector-controls-tabs/use-inspector-controls-tabs.js.map +2 -2
  162. package/build-module/components/link-control/index.js +16 -8
  163. package/build-module/components/link-control/index.js.map +2 -2
  164. package/build-module/components/list-view/block-select-button.js +14 -9
  165. package/build-module/components/list-view/block-select-button.js.map +2 -2
  166. package/build-module/components/list-view/block.js +9 -7
  167. package/build-module/components/list-view/block.js.map +2 -2
  168. package/build-module/components/media-placeholder/index.js +19 -36
  169. package/build-module/components/media-placeholder/index.js.map +2 -2
  170. package/build-module/components/media-placeholder/utils.js +35 -0
  171. package/build-module/components/media-placeholder/utils.js.map +7 -0
  172. package/build-module/components/media-replace-flow/index.js +24 -33
  173. package/build-module/components/media-replace-flow/index.js.map +2 -2
  174. package/build-module/components/use-block-commands/index.js +1 -1
  175. package/build-module/components/use-block-commands/index.js.map +2 -2
  176. package/build-module/components/use-block-display-information/index.js +21 -1
  177. package/build-module/components/use-block-display-information/index.js.map +3 -3
  178. package/build-module/components/use-block-drop-zone/index.js +1 -5
  179. package/build-module/components/use-block-drop-zone/index.js.map +2 -2
  180. package/build-module/hooks/block-bindings.js +57 -62
  181. package/build-module/hooks/block-bindings.js.map +2 -2
  182. package/build-module/hooks/dimensions.js +3 -3
  183. package/build-module/hooks/dimensions.js.map +2 -2
  184. package/build-module/hooks/metadata.js +1 -1
  185. package/build-module/hooks/metadata.js.map +2 -2
  186. package/build-module/hooks/use-content-only-section-edit.js +46 -0
  187. package/build-module/hooks/use-content-only-section-edit.js.map +7 -0
  188. package/build-module/hooks/utils.js +5 -1
  189. package/build-module/hooks/utils.js.map +2 -2
  190. package/build-module/layouts/constrained.js +2 -2
  191. package/build-module/layouts/constrained.js.map +2 -2
  192. package/build-module/private-apis.js +3 -3
  193. package/build-module/private-apis.js.map +2 -2
  194. package/build-module/store/private-keys.js +2 -0
  195. package/build-module/store/private-keys.js.map +2 -2
  196. package/build-module/store/private-selectors.js +37 -2
  197. package/build-module/store/private-selectors.js.map +2 -2
  198. package/build-module/store/selectors.js +6 -4
  199. package/build-module/store/selectors.js.map +2 -2
  200. package/build-module/utils/fit-text-utils.js +9 -1
  201. package/build-module/utils/fit-text-utils.js.map +2 -2
  202. package/build-style/content-rtl.css +3 -0
  203. package/build-style/content.css +3 -0
  204. package/build-style/style-rtl.css +145 -4
  205. package/build-style/style.css +145 -4
  206. package/package.json +38 -37
  207. package/src/components/block-inspector/edit-contents.js +10 -29
  208. package/src/components/block-inspector/index.js +4 -2
  209. package/src/components/block-list/block.js +6 -0
  210. package/src/components/block-list/content.scss +5 -0
  211. package/src/components/block-list/index.js +3 -1
  212. package/src/components/block-list/use-block-props/index.js +3 -1
  213. package/src/components/block-list/use-block-props/use-is-hovered.js +24 -12
  214. package/src/components/block-list/use-block-props/use-selected-block-event-handlers.js +34 -3
  215. package/src/components/block-lock/modal.js +6 -5
  216. package/src/components/block-lock/use-block-lock.js +10 -14
  217. package/src/components/block-patterns-list/stories/{index.story.js → index.story.jsx} +3 -1
  218. package/src/components/block-settings-menu-controls/edit-section-menu-item.js +39 -0
  219. package/src/components/block-settings-menu-controls/index.js +8 -1
  220. package/src/components/block-toolbar/block-toolbar-icon.js +14 -10
  221. package/src/components/block-tools/index.js +15 -2
  222. package/src/components/block-tools/style.scss +4 -0
  223. package/src/components/block-variation-transforms/index.js +96 -35
  224. package/src/components/block-visibility/toolbar.js +1 -1
  225. package/src/components/border-radius-control/single-input-control.js +1 -0
  226. package/src/components/content-only-controls/fields-dropdown-menu.js +53 -0
  227. package/src/components/content-only-controls/index.js +560 -0
  228. package/src/components/content-only-controls/link/index.js +200 -0
  229. package/src/components/content-only-controls/link/styles.scss +23 -0
  230. package/src/components/content-only-controls/media/index.js +306 -0
  231. package/src/components/content-only-controls/media/styles.scss +47 -0
  232. package/src/components/content-only-controls/rich-text/index.js +179 -0
  233. package/src/components/content-only-controls/rich-text/styles.scss +24 -0
  234. package/src/components/content-only-controls/styles.scss +44 -0
  235. package/src/components/content-only-controls/use-inspector-popover-placement.js +19 -0
  236. package/src/components/font-family/README.md +0 -9
  237. package/src/components/font-family/index.js +1 -16
  238. package/src/components/font-family/stories/{index.story.js → index.story.jsx} +0 -1
  239. package/src/components/global-styles/dimensions-panel.js +36 -0
  240. package/src/components/global-styles/hooks.js +1 -1
  241. package/src/components/global-styles/typography-panel.js +0 -1
  242. package/src/components/inserter/media-tab/media-tab.js +2 -44
  243. package/src/components/inspector-controls-tabs/content-tab.js +12 -4
  244. package/src/components/inspector-controls-tabs/index.js +4 -1
  245. package/src/components/inspector-controls-tabs/use-inspector-controls-tabs.js +1 -5
  246. package/src/components/link-control/index.js +36 -12
  247. package/src/components/list-view/block-select-button.js +15 -10
  248. package/src/components/list-view/block.js +9 -7
  249. package/src/components/media-placeholder/index.js +21 -46
  250. package/src/components/media-placeholder/test/get-computed-accept-attribute.js +164 -0
  251. package/src/components/media-placeholder/utils.js +65 -0
  252. package/src/components/media-replace-flow/index.js +25 -42
  253. package/src/components/use-block-commands/index.js +1 -1
  254. package/src/components/use-block-display-information/index.js +30 -2
  255. package/src/components/use-block-drop-zone/index.js +1 -5
  256. package/src/hooks/block-bindings.js +71 -82
  257. package/src/hooks/dimensions.js +8 -3
  258. package/src/hooks/metadata.js +1 -1
  259. package/src/hooks/test/metadata.js +1 -1
  260. package/src/hooks/use-content-only-section-edit.js +63 -0
  261. package/src/hooks/utils.js +4 -0
  262. package/src/layouts/constrained.js +8 -2
  263. package/src/private-apis.js +2 -2
  264. package/src/store/private-keys.js +1 -0
  265. package/src/store/private-selectors.js +121 -5
  266. package/src/store/selectors.js +6 -4
  267. package/src/store/test/private-selectors.js +242 -0
  268. package/src/style.scss +1 -1
  269. package/src/utils/fit-text-utils.js +19 -1
  270. package/tsconfig.json +1 -0
  271. package/build/components/media-upload-modal/index.js +0 -29
  272. package/build/components/media-upload-modal/index.js.map +0 -7
  273. package/build-module/components/media-upload-modal/index.js +0 -8
  274. package/build-module/components/media-upload-modal/index.js.map +0 -7
  275. package/src/components/font-family/style.scss +0 -7
  276. package/src/components/media-upload-modal/index.js +0 -18
  277. /package/src/components/alignment-control/stories/{aliginment-toolbar.story.js → aliginment-toolbar.story.jsx} +0 -0
  278. /package/src/components/alignment-control/stories/{index.story.js → index.story.jsx} +0 -0
  279. /package/src/components/block-alignment-matrix-control/stories/{index.story.js → index.story.jsx} +0 -0
  280. /package/src/components/block-draggable/stories/{index.story.js → index.story.jsx} +0 -0
  281. /package/src/components/block-heading-level-dropdown/stories/{index.story.js → index.story.jsx} +0 -0
  282. /package/src/components/block-mover/stories/{index.story.js → index.story.jsx} +0 -0
  283. /package/src/components/block-title/stories/{index.story.js → index.story.jsx} +0 -0
  284. /package/src/components/border-radius-control/stories/{index.story.js → index.story.jsx} +0 -0
  285. /package/src/components/date-format-picker/stories/{index.story.js → index.story.jsx} +0 -0
  286. /package/src/components/dimensions-tool/stories/{aspect-ratio-tool.story.js → aspect-ratio-tool.story.jsx} +0 -0
  287. /package/src/components/dimensions-tool/stories/{index.story.js → index.story.jsx} +0 -0
  288. /package/src/components/dimensions-tool/stories/{scale-tool.story.js → scale-tool.story.jsx} +0 -0
  289. /package/src/components/dimensions-tool/stories/{width-height-tool.story.js → width-height-tool.story.jsx} +0 -0
  290. /package/src/components/height-control/stories/{index.story.js → index.story.jsx} +0 -0
  291. /package/src/components/inserter/stories/{index.story.js → index.story.jsx} +0 -0
  292. /package/src/components/line-height-control/stories/{index.story.js → index.story.jsx} +0 -0
  293. /package/src/components/plain-text/stories/{index.story.js → index.story.jsx} +0 -0
  294. /package/src/components/resolution-tool/stories/{index.story.js → index.story.jsx} +0 -0
  295. /package/src/components/tabbed-sidebar/stories/{index.story.js → index.story.jsx} +0 -0
  296. /package/src/components/text-alignment-control/stories/{index.story.js → index.story.jsx} +0 -0
  297. /package/src/components/text-decoration-control/stories/{index.story.js → index.story.jsx} +0 -0
  298. /package/src/components/text-transform-control/stories/{index.story.js → index.story.jsx} +0 -0
  299. /package/src/components/unit-control/stories/{index.story.js → index.story.jsx} +0 -0
  300. /package/src/components/url-popover/stories/{index.story.js → index.story.jsx} +0 -0
  301. /package/src/components/warning/stories/{index.story.js → index.story.jsx} +0 -0
  302. /package/src/components/writing-mode-control/stories/{index.story.js → index.story.jsx} +0 -0
@@ -0,0 +1,200 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import {
5
+ Button,
6
+ Icon,
7
+ __experimentalGrid as Grid,
8
+ Popover,
9
+ } from '@wordpress/components';
10
+ import { useMemo, useState } from '@wordpress/element';
11
+ import { __ } from '@wordpress/i18n';
12
+ import { link } from '@wordpress/icons';
13
+ import { prependHTTP } from '@wordpress/url';
14
+
15
+ /**
16
+ * Internal dependencies
17
+ */
18
+ import LinkControl from '../../link-control';
19
+ import { useInspectorPopoverPlacement } from '../use-inspector-popover-placement';
20
+
21
+ export const NEW_TAB_REL = 'noreferrer noopener';
22
+ export const NEW_TAB_TARGET = '_blank';
23
+ export const NOFOLLOW_REL = 'nofollow';
24
+
25
+ /**
26
+ * Updates the link attributes.
27
+ *
28
+ * @param {Object} attributes The current block attributes.
29
+ * @param {string} attributes.rel The current link rel attribute.
30
+ * @param {string} attributes.url The current link url.
31
+ * @param {boolean} attributes.opensInNewTab Whether the link should open in a new window.
32
+ * @param {boolean} attributes.nofollow Whether the link should be marked as nofollow.
33
+ */
34
+ export function getUpdatedLinkAttributes( {
35
+ rel = '',
36
+ url = '',
37
+ opensInNewTab,
38
+ nofollow,
39
+ } ) {
40
+ let newLinkTarget;
41
+ // Since `rel` is editable attribute, we need to check for existing values and proceed accordingly.
42
+ let updatedRel = rel;
43
+
44
+ if ( opensInNewTab ) {
45
+ newLinkTarget = NEW_TAB_TARGET;
46
+ updatedRel = updatedRel?.includes( NEW_TAB_REL )
47
+ ? updatedRel
48
+ : updatedRel + ` ${ NEW_TAB_REL }`;
49
+ } else {
50
+ const relRegex = new RegExp( `\\b${ NEW_TAB_REL }\\s*`, 'g' );
51
+ updatedRel = updatedRel?.replace( relRegex, '' ).trim();
52
+ }
53
+
54
+ if ( nofollow ) {
55
+ updatedRel = updatedRel?.includes( NOFOLLOW_REL )
56
+ ? updatedRel
57
+ : ( updatedRel + ` ${ NOFOLLOW_REL }` ).trim();
58
+ } else {
59
+ const relRegex = new RegExp( `\\b${ NOFOLLOW_REL }\\s*`, 'g' );
60
+ updatedRel = updatedRel?.replace( relRegex, '' ).trim();
61
+ }
62
+
63
+ return {
64
+ url: prependHTTP( url ),
65
+ linkTarget: newLinkTarget,
66
+ rel: updatedRel || undefined,
67
+ };
68
+ }
69
+
70
+ export default function Link( { data, field, config = {} } ) {
71
+ const [ isLinkControlOpen, setIsLinkControlOpen ] = useState( false );
72
+ const { popoverProps } = useInspectorPopoverPlacement( {
73
+ isControl: true,
74
+ } );
75
+ const { clientId, updateBlockAttributes, fieldDef } = config;
76
+ const updateAttributes = ( newValue ) => {
77
+ const mappedChanges = field.setValue( { item: data, value: newValue } );
78
+ updateBlockAttributes( clientId, mappedChanges );
79
+ };
80
+
81
+ const value = field.getValue( { item: data } );
82
+ const url = value?.url;
83
+ const rel = value?.rel || '';
84
+ const target = value?.linkTarget;
85
+
86
+ const opensInNewTab = target === NEW_TAB_TARGET;
87
+ const nofollow = rel === NOFOLLOW_REL;
88
+
89
+ // Memoize link value to avoid overriding the LinkControl's internal state.
90
+ // This is a temporary fix. See https://github.com/WordPress/gutenberg/issues/51256.
91
+ const linkValue = useMemo(
92
+ () => ( { url, opensInNewTab, nofollow } ),
93
+ [ url, opensInNewTab, nofollow ]
94
+ );
95
+
96
+ return (
97
+ <>
98
+ <Button
99
+ __next40pxDefaultSize
100
+ className="block-editor-content-only-controls__link"
101
+ onClick={ () => {
102
+ setIsLinkControlOpen( true );
103
+ } }
104
+ >
105
+ <Grid
106
+ rowGap={ 0 }
107
+ columnGap={ 8 }
108
+ templateColumns="24px 1fr"
109
+ className="block-editor-content-only-controls__link-row"
110
+ >
111
+ { url && (
112
+ <>
113
+ <Icon icon={ link } size={ 24 } />
114
+ <span className="block-editor-content-only-controls__link-title">
115
+ { url }
116
+ </span>
117
+ </>
118
+ ) }
119
+ { ! url && (
120
+ <>
121
+ <Icon
122
+ icon={ link }
123
+ size={ 24 }
124
+ style={ { opacity: 0.3 } }
125
+ />
126
+ <span className="block-editor-content-only-controls__link-title">
127
+ { __( 'Link' ) }
128
+ </span>
129
+ </>
130
+ ) }
131
+ </Grid>
132
+ </Button>
133
+ { isLinkControlOpen && (
134
+ <Popover
135
+ onClose={ () => {
136
+ setIsLinkControlOpen( false );
137
+ } }
138
+ { ...( popoverProps ?? {} ) }
139
+ >
140
+ <LinkControl
141
+ value={ linkValue }
142
+ onChange={ ( newValues ) => {
143
+ const updatedAttrs = getUpdatedLinkAttributes( {
144
+ rel,
145
+ ...newValues,
146
+ } );
147
+
148
+ // Build update object dynamically based on what's in the mapping
149
+ const updateValue = { ...value };
150
+
151
+ if ( fieldDef?.mapping ) {
152
+ Object.keys( fieldDef.mapping ).forEach(
153
+ ( key ) => {
154
+ if ( key === 'href' || key === 'url' ) {
155
+ updateValue[ key ] =
156
+ updatedAttrs.url;
157
+ } else if ( key === 'rel' ) {
158
+ updateValue[ key ] =
159
+ updatedAttrs.rel;
160
+ } else if (
161
+ key === 'target' ||
162
+ key === 'linkTarget'
163
+ ) {
164
+ updateValue[ key ] =
165
+ updatedAttrs.linkTarget;
166
+ }
167
+ }
168
+ );
169
+ }
170
+
171
+ updateAttributes( updateValue );
172
+ } }
173
+ onRemove={ () => {
174
+ // Remove all link-related properties based on what's in the mapping
175
+ const removeValue = {};
176
+
177
+ if ( fieldDef?.mapping ) {
178
+ Object.keys( fieldDef.mapping ).forEach(
179
+ ( key ) => {
180
+ if (
181
+ key === 'href' ||
182
+ key === 'url' ||
183
+ key === 'rel' ||
184
+ key === 'target' ||
185
+ key === 'linkTarget'
186
+ ) {
187
+ removeValue[ key ] = undefined;
188
+ }
189
+ }
190
+ );
191
+ }
192
+
193
+ updateAttributes( removeValue );
194
+ } }
195
+ />
196
+ </Popover>
197
+ ) }
198
+ </>
199
+ );
200
+ }
@@ -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,306 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import {
5
+ Button,
6
+ Icon,
7
+ __experimentalGrid as Grid,
8
+ } from '@wordpress/components';
9
+ import { useSelect } from '@wordpress/data';
10
+ import { __ } from '@wordpress/i18n';
11
+ import {
12
+ audio as audioIcon,
13
+ image as imageIcon,
14
+ media as mediaIcon,
15
+ video as videoIcon,
16
+ } from '@wordpress/icons';
17
+
18
+ /**
19
+ * Internal dependencies
20
+ */
21
+ import MediaReplaceFlow from '../../media-replace-flow';
22
+ import MediaUploadCheck from '../../media-upload/check';
23
+ import { useInspectorPopoverPlacement } from '../use-inspector-popover-placement';
24
+ import { getMediaSelectKey } from '../../../store/private-keys';
25
+ import { store as blockEditorStore } from '../../../store';
26
+
27
+ function MediaThumbnail( { data, field, attachment } ) {
28
+ const config = field.config || {};
29
+ const { allowedTypes = [], multiple = false } = config;
30
+
31
+ if ( multiple ) {
32
+ return 'todo multiple';
33
+ }
34
+
35
+ if ( attachment?.media_type === 'image' || attachment?.poster ) {
36
+ return (
37
+ <img
38
+ className="block-editor-content-only-controls__media-thumbnail"
39
+ alt=""
40
+ width={ 24 }
41
+ height={ 24 }
42
+ src={
43
+ attachment.media_type === 'image'
44
+ ? attachment.source_url
45
+ : attachment.poster
46
+ }
47
+ />
48
+ );
49
+ }
50
+
51
+ if ( allowedTypes.length === 1 ) {
52
+ const value = field.getValue( { item: data } );
53
+ const url = value?.url;
54
+
55
+ if ( url ) {
56
+ return (
57
+ <img
58
+ className="block-editor-content-only-controls__media-thumbnail"
59
+ alt=""
60
+ width={ 24 }
61
+ height={ 24 }
62
+ src={ url }
63
+ />
64
+ );
65
+ }
66
+
67
+ let icon;
68
+ if ( allowedTypes[ 0 ] === 'image' ) {
69
+ icon = imageIcon;
70
+ } else if ( allowedTypes[ 0 ] === 'video' ) {
71
+ icon = videoIcon;
72
+ } else if ( allowedTypes[ 0 ] === 'audio' ) {
73
+ icon = audioIcon;
74
+ } else {
75
+ icon = mediaIcon;
76
+ }
77
+
78
+ if ( icon ) {
79
+ return <Icon icon={ icon } size={ 24 } />;
80
+ }
81
+ }
82
+
83
+ return <Icon icon={ mediaIcon } size={ 24 } />;
84
+ }
85
+
86
+ export default function Media( { data, field, config = {} } ) {
87
+ const { popoverProps } = useInspectorPopoverPlacement( {
88
+ isControl: true,
89
+ } );
90
+ const value = field.getValue( { item: data } );
91
+ const { allowedTypes = [], multiple = false } = field.config || {};
92
+ const { clientId, updateBlockAttributes, fieldDef } = config;
93
+ const updateAttributes = ( newFieldValue ) => {
94
+ const mappedChanges = field.setValue( {
95
+ item: data,
96
+ value: newFieldValue,
97
+ } );
98
+ updateBlockAttributes( clientId, mappedChanges );
99
+ };
100
+
101
+ // Check if featured image is supported by checking if it's in the mapping
102
+ const hasFeaturedImageSupport =
103
+ fieldDef?.mapping && 'featuredImage' in fieldDef.mapping;
104
+
105
+ const id = value?.id;
106
+ const url = value?.url;
107
+
108
+ const attachment = useSelect(
109
+ ( select ) => {
110
+ if ( ! id ) {
111
+ return;
112
+ }
113
+
114
+ const settings = select( blockEditorStore ).getSettings();
115
+ const getMedia = settings[ getMediaSelectKey ];
116
+
117
+ if ( ! getMedia ) {
118
+ return;
119
+ }
120
+
121
+ return getMedia( select, id );
122
+ },
123
+ [ id ]
124
+ );
125
+
126
+ // TODO - pluralize when multiple.
127
+ let chooseItemLabel;
128
+ if ( allowedTypes.length === 1 ) {
129
+ const allowedType = allowedTypes[ 0 ];
130
+ if ( allowedType === 'image' ) {
131
+ chooseItemLabel = __( 'Choose an image…' );
132
+ } else if ( allowedType === 'video' ) {
133
+ chooseItemLabel = __( 'Choose a video…' );
134
+ } else if ( allowedType === 'application' ) {
135
+ chooseItemLabel = __( 'Choose a file…' );
136
+ } else {
137
+ chooseItemLabel = __( 'Choose a media item…' );
138
+ }
139
+ } else {
140
+ chooseItemLabel = __( 'Choose a media item…' );
141
+ }
142
+
143
+ return (
144
+ <MediaUploadCheck>
145
+ <MediaReplaceFlow
146
+ className="block-editor-content-only-controls__media-replace-flow"
147
+ allowedTypes={ allowedTypes }
148
+ mediaId={ id }
149
+ mediaURL={ url }
150
+ multiple={ multiple }
151
+ popoverProps={ popoverProps }
152
+ onReset={ () => {
153
+ // Build reset value dynamically based on mapping
154
+ const resetValue = {};
155
+
156
+ if ( fieldDef?.mapping ) {
157
+ Object.keys( fieldDef.mapping ).forEach( ( key ) => {
158
+ if (
159
+ key === 'id' ||
160
+ key === 'src' ||
161
+ key === 'url'
162
+ ) {
163
+ resetValue[ key ] = undefined;
164
+ } else if ( key === 'caption' || key === 'alt' ) {
165
+ resetValue[ key ] = '';
166
+ }
167
+ } );
168
+ }
169
+
170
+ // Turn off featured image when resetting (only if it's in the mapping)
171
+ if ( hasFeaturedImageSupport ) {
172
+ resetValue.featuredImage = false;
173
+ }
174
+
175
+ // Merge with existing value to preserve other field properties
176
+ updateAttributes( { ...value, ...resetValue } );
177
+ } }
178
+ { ...( hasFeaturedImageSupport && {
179
+ useFeaturedImage: !! value?.featuredImage,
180
+ onToggleFeaturedImage: () => {
181
+ updateAttributes( {
182
+ ...value,
183
+ featuredImage: ! value?.featuredImage,
184
+ } );
185
+ },
186
+ } ) }
187
+ onSelect={ ( selectedMedia ) => {
188
+ if ( selectedMedia.id && selectedMedia.url ) {
189
+ // Determine mediaType from MIME type, not from object type
190
+ let mediaType = 'image'; // default
191
+ if ( selectedMedia.mime_type ) {
192
+ if (
193
+ selectedMedia.mime_type.startsWith( 'video/' )
194
+ ) {
195
+ mediaType = 'video';
196
+ } else if (
197
+ selectedMedia.mime_type.startsWith( 'audio/' )
198
+ ) {
199
+ mediaType = 'audio';
200
+ }
201
+ }
202
+
203
+ // Build new value dynamically based on what's in the mapping
204
+ const newValue = {};
205
+
206
+ // Iterate over mapping keys and set values for supported properties
207
+ if ( fieldDef?.mapping ) {
208
+ Object.keys( fieldDef.mapping ).forEach(
209
+ ( key ) => {
210
+ if ( key === 'id' ) {
211
+ newValue[ key ] = selectedMedia.id;
212
+ } else if (
213
+ key === 'src' ||
214
+ key === 'url'
215
+ ) {
216
+ newValue[ key ] = selectedMedia.url;
217
+ } else if ( key === 'type' ) {
218
+ newValue[ key ] = mediaType;
219
+ } else if (
220
+ key === 'link' &&
221
+ selectedMedia.link
222
+ ) {
223
+ newValue[ key ] = selectedMedia.link;
224
+ } else if (
225
+ key === 'caption' &&
226
+ ! value?.caption &&
227
+ selectedMedia.caption
228
+ ) {
229
+ newValue[ key ] = selectedMedia.caption;
230
+ } else if (
231
+ key === 'alt' &&
232
+ ! value?.alt &&
233
+ selectedMedia.alt
234
+ ) {
235
+ newValue[ key ] = selectedMedia.alt;
236
+ } else if (
237
+ key === 'poster' &&
238
+ selectedMedia.poster
239
+ ) {
240
+ newValue[ key ] = selectedMedia.poster;
241
+ }
242
+ }
243
+ );
244
+ }
245
+
246
+ // Turn off featured image when manually selecting media
247
+ if ( hasFeaturedImageSupport ) {
248
+ newValue.featuredImage = false;
249
+ }
250
+
251
+ // Merge with existing value to preserve other field properties
252
+ const finalValue = { ...value, ...newValue };
253
+ updateAttributes( finalValue );
254
+ }
255
+ } }
256
+ renderToggle={ ( buttonProps ) => (
257
+ <Button
258
+ __next40pxDefaultSize
259
+ className="block-editor-content-only-controls__media"
260
+ { ...buttonProps }
261
+ >
262
+ <Grid
263
+ rowGap={ 0 }
264
+ columnGap={ 8 }
265
+ templateColumns="24px 1fr"
266
+ className="block-editor-content-only-controls__media-row"
267
+ >
268
+ { url && (
269
+ <>
270
+ <MediaThumbnail
271
+ attachment={ attachment }
272
+ field={ field }
273
+ data={ data }
274
+ />
275
+ <span className="block-editor-content-only-controls__media-title">
276
+ {
277
+ // TODO - truncate long titles or url smartly (e.g. show filename).
278
+ attachment?.title?.raw &&
279
+ attachment?.title?.raw !== ''
280
+ ? attachment?.title?.raw
281
+ : url
282
+ }
283
+ </span>
284
+ </>
285
+ ) }
286
+ { ! url && (
287
+ <>
288
+ <span
289
+ className="block-editor-content-only-controls__media-placeholder"
290
+ style={ {
291
+ width: '24px',
292
+ height: '24px',
293
+ } }
294
+ />
295
+ <span className="block-editor-content-only-controls__media-title">
296
+ { chooseItemLabel }
297
+ </span>
298
+ </>
299
+ ) }
300
+ </Grid>
301
+ </Button>
302
+ ) }
303
+ />
304
+ </MediaUploadCheck>
305
+ );
306
+ }
@@ -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
+ }