@wordpress/block-editor 15.21.1 → 15.22.1-next.v.202606191442.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 (186) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/build/components/block-card/index.cjs +4 -5
  3. package/build/components/block-card/index.cjs.map +2 -2
  4. package/build/components/block-inspector/index.cjs +3 -4
  5. package/build/components/block-inspector/index.cjs.map +2 -2
  6. package/build/components/block-mover/mover-description.cjs +6 -6
  7. package/build/components/block-mover/mover-description.cjs.map +1 -1
  8. package/build/components/block-patterns-list/index.cjs.map +2 -2
  9. package/build/components/block-patterns-paging/index.cjs +4 -4
  10. package/build/components/block-patterns-paging/index.cjs.map +2 -2
  11. package/build/components/block-popover/use-popover-scroll.cjs.map +1 -1
  12. package/build/components/block-quick-navigation/index.cjs +7 -5
  13. package/build/components/block-quick-navigation/index.cjs.map +2 -2
  14. package/build/components/block-toolbar/edit-section-button.cjs.map +1 -1
  15. package/build/components/block-tools/use-block-toolbar-popover-props.cjs +10 -4
  16. package/build/components/block-tools/use-block-toolbar-popover-props.cjs.map +2 -2
  17. package/build/components/child-layout-control/index.cjs +51 -19
  18. package/build/components/child-layout-control/index.cjs.map +2 -2
  19. package/build/components/dimensions-tool/index.cjs +4 -5
  20. package/build/components/dimensions-tool/index.cjs.map +2 -2
  21. package/build/components/dimensions-tool/scale-tool.cjs +1 -1
  22. package/build/components/dimensions-tool/scale-tool.cjs.map +2 -2
  23. package/build/components/global-styles/dimensions-panel.cjs +1 -1
  24. package/build/components/global-styles/dimensions-panel.cjs.map +2 -2
  25. package/build/components/global-styles/shadow-panel-components.cjs.map +2 -2
  26. package/build/components/grid/grid-item-resizer.cjs.map +1 -1
  27. package/build/components/grid/grid-visualizer.cjs.map +1 -1
  28. package/build/components/iframe/index.cjs +6 -3
  29. package/build/components/iframe/index.cjs.map +3 -3
  30. package/build/components/image-editor/use-transform-image.cjs.map +1 -1
  31. package/build/components/inserter/get-appender-label.cjs.map +1 -1
  32. package/build/components/inserter/media-tab/media-preview.cjs.map +2 -2
  33. package/build/components/inserter/search-items.cjs.map +1 -1
  34. package/build/components/inspector-controls/fill.cjs +1 -3
  35. package/build/components/inspector-controls/fill.cjs.map +2 -2
  36. package/build/components/inspector-controls-tabs/index.cjs.map +2 -2
  37. package/build/components/inspector-controls-tabs/styles-tab.cjs +1 -1
  38. package/build/components/inspector-controls-tabs/styles-tab.cjs.map +2 -2
  39. package/build/components/keyboard-shortcuts/index.cjs.map +1 -1
  40. package/build/components/line-height-control/index.cjs.map +1 -1
  41. package/build/components/link-control/index.cjs +1 -1
  42. package/build/components/link-control/index.cjs.map +1 -1
  43. package/build/components/link-control/normalize-url.cjs.map +1 -1
  44. package/build/components/list-view/block-select-button.cjs.map +2 -2
  45. package/build/components/list-view/utils.cjs.map +1 -1
  46. package/build/components/preset-input-control/custom-value-controls.cjs.map +2 -2
  47. package/build/components/provider/index.cjs.map +1 -1
  48. package/build/components/provider/use-block-sync.cjs.map +1 -1
  49. package/build/components/rich-text/event-listeners/before-input-rules.cjs +1 -1
  50. package/build/components/rich-text/event-listeners/before-input-rules.cjs.map +2 -2
  51. package/build/components/rich-text/event-listeners/paste-handler.cjs.map +1 -1
  52. package/build/components/rich-text/prevent-event-discovery.cjs +1 -1
  53. package/build/components/rich-text/prevent-event-discovery.cjs.map +1 -1
  54. package/build/components/writing-flow/use-tab-nav.cjs.map +1 -1
  55. package/build/hooks/anchor.cjs +1 -1
  56. package/build/hooks/anchor.cjs.map +1 -1
  57. package/build/hooks/background.cjs.map +1 -1
  58. package/build/hooks/block-fields/index.cjs +13 -2
  59. package/build/hooks/block-fields/index.cjs.map +2 -2
  60. package/build/hooks/dimensions.cjs +13 -2
  61. package/build/hooks/dimensions.cjs.map +2 -2
  62. package/build/hooks/layout-child.cjs +27 -2
  63. package/build/hooks/layout-child.cjs.map +2 -2
  64. package/build/hooks/list-view.cjs +10 -7
  65. package/build/hooks/list-view.cjs.map +2 -2
  66. package/build/hooks/spacing-visualizer.cjs.map +1 -1
  67. package/build/hooks/state-utils.cjs.map +1 -1
  68. package/build/hooks/style.cjs +42 -2
  69. package/build/hooks/style.cjs.map +2 -2
  70. package/build/private-apis.cjs +4 -0
  71. package/build/private-apis.cjs.map +2 -2
  72. package/build/store/actions.cjs.map +1 -1
  73. package/build/store/private-selectors.cjs +19 -2
  74. package/build/store/private-selectors.cjs.map +2 -2
  75. package/build/store/reducer.cjs.map +1 -1
  76. package/build/store/selectors.cjs.map +1 -1
  77. package/build/utils/dom.cjs.map +1 -1
  78. package/build/utils/selection.cjs +1 -1
  79. package/build-module/components/block-card/index.mjs +5 -6
  80. package/build-module/components/block-card/index.mjs.map +2 -2
  81. package/build-module/components/block-inspector/index.mjs +3 -5
  82. package/build-module/components/block-inspector/index.mjs.map +2 -2
  83. package/build-module/components/block-mover/mover-description.mjs +6 -6
  84. package/build-module/components/block-mover/mover-description.mjs.map +1 -1
  85. package/build-module/components/block-patterns-list/index.mjs.map +2 -2
  86. package/build-module/components/block-patterns-paging/index.mjs +4 -4
  87. package/build-module/components/block-patterns-paging/index.mjs.map +2 -2
  88. package/build-module/components/block-popover/use-popover-scroll.mjs.map +1 -1
  89. package/build-module/components/block-quick-navigation/index.mjs +8 -6
  90. package/build-module/components/block-quick-navigation/index.mjs.map +2 -2
  91. package/build-module/components/block-toolbar/edit-section-button.mjs.map +1 -1
  92. package/build-module/components/block-tools/use-block-toolbar-popover-props.mjs +10 -4
  93. package/build-module/components/block-tools/use-block-toolbar-popover-props.mjs.map +2 -2
  94. package/build-module/components/child-layout-control/index.mjs +51 -19
  95. package/build-module/components/child-layout-control/index.mjs.map +2 -2
  96. package/build-module/components/dimensions-tool/index.mjs +4 -5
  97. package/build-module/components/dimensions-tool/index.mjs.map +2 -2
  98. package/build-module/components/dimensions-tool/scale-tool.mjs +1 -1
  99. package/build-module/components/dimensions-tool/scale-tool.mjs.map +2 -2
  100. package/build-module/components/global-styles/dimensions-panel.mjs +1 -2
  101. package/build-module/components/global-styles/dimensions-panel.mjs.map +2 -2
  102. package/build-module/components/global-styles/shadow-panel-components.mjs.map +2 -2
  103. package/build-module/components/grid/grid-item-resizer.mjs.map +1 -1
  104. package/build-module/components/grid/grid-visualizer.mjs.map +1 -1
  105. package/build-module/components/iframe/index.mjs +6 -3
  106. package/build-module/components/iframe/index.mjs.map +2 -2
  107. package/build-module/components/image-editor/use-transform-image.mjs.map +1 -1
  108. package/build-module/components/inserter/get-appender-label.mjs.map +1 -1
  109. package/build-module/components/inserter/media-tab/media-preview.mjs.map +2 -2
  110. package/build-module/components/inserter/search-items.mjs.map +1 -1
  111. package/build-module/components/inspector-controls/fill.mjs +1 -3
  112. package/build-module/components/inspector-controls/fill.mjs.map +2 -2
  113. package/build-module/components/inspector-controls-tabs/index.mjs.map +2 -2
  114. package/build-module/components/inspector-controls-tabs/styles-tab.mjs +1 -1
  115. package/build-module/components/inspector-controls-tabs/styles-tab.mjs.map +2 -2
  116. package/build-module/components/keyboard-shortcuts/index.mjs.map +1 -1
  117. package/build-module/components/line-height-control/index.mjs.map +1 -1
  118. package/build-module/components/link-control/index.mjs +1 -1
  119. package/build-module/components/link-control/index.mjs.map +1 -1
  120. package/build-module/components/link-control/normalize-url.mjs.map +1 -1
  121. package/build-module/components/list-view/block-select-button.mjs.map +2 -2
  122. package/build-module/components/list-view/utils.mjs.map +1 -1
  123. package/build-module/components/preset-input-control/custom-value-controls.mjs.map +2 -2
  124. package/build-module/components/provider/index.mjs.map +1 -1
  125. package/build-module/components/provider/use-block-sync.mjs.map +1 -1
  126. package/build-module/components/rich-text/event-listeners/before-input-rules.mjs +1 -1
  127. package/build-module/components/rich-text/event-listeners/before-input-rules.mjs.map +2 -2
  128. package/build-module/components/rich-text/event-listeners/paste-handler.mjs.map +1 -1
  129. package/build-module/components/rich-text/prevent-event-discovery.mjs +1 -1
  130. package/build-module/components/rich-text/prevent-event-discovery.mjs.map +1 -1
  131. package/build-module/components/writing-flow/use-tab-nav.mjs.map +1 -1
  132. package/build-module/hooks/anchor.mjs +1 -1
  133. package/build-module/hooks/anchor.mjs.map +1 -1
  134. package/build-module/hooks/background.mjs.map +1 -1
  135. package/build-module/hooks/block-fields/index.mjs +13 -2
  136. package/build-module/hooks/block-fields/index.mjs.map +2 -2
  137. package/build-module/hooks/dimensions.mjs +12 -2
  138. package/build-module/hooks/dimensions.mjs.map +2 -2
  139. package/build-module/hooks/layout-child.mjs +27 -2
  140. package/build-module/hooks/layout-child.mjs.map +2 -2
  141. package/build-module/hooks/list-view.mjs +10 -7
  142. package/build-module/hooks/list-view.mjs.map +2 -2
  143. package/build-module/hooks/spacing-visualizer.mjs.map +1 -1
  144. package/build-module/hooks/state-utils.mjs.map +1 -1
  145. package/build-module/hooks/style.mjs +44 -3
  146. package/build-module/hooks/style.mjs.map +2 -2
  147. package/build-module/private-apis.mjs +8 -0
  148. package/build-module/private-apis.mjs.map +2 -2
  149. package/build-module/store/actions.mjs.map +1 -1
  150. package/build-module/store/private-selectors.mjs +18 -1
  151. package/build-module/store/private-selectors.mjs.map +2 -2
  152. package/build-module/store/reducer.mjs.map +1 -1
  153. package/build-module/store/selectors.mjs.map +1 -1
  154. package/build-module/utils/dom.mjs.map +1 -1
  155. package/build-module/utils/selection.mjs +1 -1
  156. package/package.json +45 -40
  157. package/src/components/block-card/index.js +7 -13
  158. package/src/components/block-inspector/index.js +2 -10
  159. package/src/components/block-patterns-list/index.js +0 -1
  160. package/src/components/block-quick-navigation/index.js +7 -7
  161. package/src/components/block-tools/use-block-toolbar-popover-props.js +10 -4
  162. package/src/components/child-layout-control/index.js +65 -20
  163. package/src/components/child-layout-control/test/index.js +64 -0
  164. package/src/components/dimensions-tool/index.js +4 -9
  165. package/src/components/dimensions-tool/scale-tool.js +1 -2
  166. package/src/components/dimensions-tool/test/index.js +89 -11
  167. package/src/components/global-styles/dimensions-panel.js +1 -2
  168. package/src/components/global-styles/shadow-panel-components.js +0 -1
  169. package/src/components/iframe/index.js +8 -3
  170. package/src/components/inserter/media-tab/media-preview.js +0 -1
  171. package/src/components/inspector-controls/fill.js +6 -8
  172. package/src/components/inspector-controls-tabs/index.js +0 -1
  173. package/src/components/inspector-controls-tabs/styles-tab.js +5 -1
  174. package/src/components/list-view/block-select-button.js +0 -1
  175. package/src/components/preset-input-control/custom-value-controls.js +0 -1
  176. package/src/hooks/block-fields/index.js +27 -2
  177. package/src/hooks/dimensions.js +14 -3
  178. package/src/hooks/layout-child.js +41 -2
  179. package/src/hooks/list-view.js +10 -11
  180. package/src/hooks/style.js +80 -2
  181. package/src/hooks/test/dimensions.js +71 -0
  182. package/src/hooks/test/layout-child.js +165 -0
  183. package/src/hooks/test/style.js +126 -4
  184. package/src/private-apis.js +8 -0
  185. package/src/store/private-selectors.js +47 -0
  186. package/src/store/test/private-selectors.js +138 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/dom.js"],
4
- "sourcesContent": ["const BLOCK_SELECTOR = '.block-editor-block-list__block';\nconst APPENDER_SELECTOR = '.block-list-appender';\nconst BLOCK_APPENDER_CLASS = '.block-editor-button-block-appender';\n\n/**\n * Returns true if two elements are contained within the same block.\n *\n * @param {Element} a First element.\n * @param {Element} b Second element.\n *\n * @return {boolean} Whether elements are in the same block.\n */\nexport function isInSameBlock( a, b ) {\n\treturn a.closest( BLOCK_SELECTOR ) === b.closest( BLOCK_SELECTOR );\n}\n\n/**\n * Returns true if an element is considered part of the block and not its inner\n * blocks or appender.\n *\n * @param {Element} blockElement Block container element.\n * @param {Element} element Element.\n *\n * @return {boolean} Whether an element is considered part of the block and not\n * its inner blocks or appender.\n */\nexport function isInsideRootBlock( blockElement, element ) {\n\tconst parentBlock = element.closest(\n\t\t[ BLOCK_SELECTOR, APPENDER_SELECTOR, BLOCK_APPENDER_CLASS ].join( ',' )\n\t);\n\treturn parentBlock === blockElement;\n}\n\n/**\n * Finds the block client ID given any DOM node inside the block.\n *\n * @param {Node?} node DOM node.\n *\n * @return {string|undefined} Client ID or undefined if the node is not part of\n * a block.\n */\nexport function getBlockClientId( node ) {\n\twhile ( node && node.nodeType !== node.ELEMENT_NODE ) {\n\t\tnode = node.parentNode;\n\t}\n\n\tif ( ! node ) {\n\t\treturn;\n\t}\n\n\tconst elementNode = /** @type {Element} */ ( node );\n\tconst blockNode = elementNode.closest( BLOCK_SELECTOR );\n\n\tif ( ! blockNode ) {\n\t\treturn;\n\t}\n\n\treturn blockNode.id.slice( 'block-'.length );\n}\n\n/**\n * Calculates the union of two rectangles.\n *\n * @param {DOMRect} rect1 First rectangle.\n * @param {DOMRect} rect2 Second rectangle.\n * @return {DOMRect} Union of the two rectangles.\n */\nexport function rectUnion( rect1, rect2 ) {\n\tconst left = Math.min( rect1.left, rect2.left );\n\tconst right = Math.max( rect1.right, rect2.right );\n\tconst bottom = Math.max( rect1.bottom, rect2.bottom );\n\tconst top = Math.min( rect1.top, rect2.top );\n\n\treturn new window.DOMRectReadOnly( left, top, right - left, bottom - top );\n}\n\n/**\n * Returns whether an element is visible.\n *\n * @param {Element} element Element.\n * @return {boolean} Whether the element is visible.\n */\nexport function isElementVisible( element ) {\n\tconst viewport = element.ownerDocument.defaultView;\n\tif ( ! viewport ) {\n\t\treturn false;\n\t}\n\n\t// Check for <VisuallyHidden> components.\n\tif ( element.hasAttribute( 'data-visually-hidden' ) ) {\n\t\treturn false;\n\t}\n\n\tconst bounds = element.getBoundingClientRect();\n\tif ( bounds.width === 0 || bounds.height === 0 ) {\n\t\treturn false;\n\t}\n\n\t// Older browsers, e.g. Safari < 17.4 may not support the `checkVisibility` method.\n\tif ( element.checkVisibility ) {\n\t\treturn element.checkVisibility?.( {\n\t\t\topacityProperty: true,\n\t\t\tcontentVisibilityAuto: true,\n\t\t\tvisibilityProperty: true,\n\t\t} );\n\t}\n\n\tconst style = viewport.getComputedStyle( element );\n\n\tif (\n\t\tstyle.display === 'none' ||\n\t\tstyle.visibility === 'hidden' ||\n\t\tstyle.opacity === '0'\n\t) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n/**\n * Checks if the element is scrollable.\n *\n * @param {Element} element Element.\n * @return {boolean} True if the element is scrollable.\n */\nfunction isScrollable( element ) {\n\tconst style = window.getComputedStyle( element );\n\treturn (\n\t\tstyle.overflowX === 'auto' ||\n\t\tstyle.overflowX === 'scroll' ||\n\t\tstyle.overflowY === 'auto' ||\n\t\tstyle.overflowY === 'scroll'\n\t);\n}\n\nexport const WITH_OVERFLOW_ELEMENT_BLOCKS = [ 'core/navigation' ];\n/**\n * Returns the bounding rectangle of an element, with special handling for blocks\n * that have visible overflowing children (defined in WITH_OVERFLOW_ELEMENT_BLOCKS).\n *\n * For blocks like Navigation that can have overflowing elements (e.g. submenus),\n * this function calculates the combined bounds of both the parent and its visible\n * children. The returned rect may extend beyond the viewport.\n * The returned rect represents the full extent of the element and its visible\n * children, which may extend beyond the viewport.\n *\n * @param {Element} element Element.\n * @return {DOMRect} Bounding client rect of the element and its visible children.\n */\nexport function getElementBounds( element ) {\n\tconst viewport = element.ownerDocument.defaultView;\n\n\tif ( ! viewport ) {\n\t\treturn new window.DOMRectReadOnly();\n\t}\n\n\tlet bounds = element.getBoundingClientRect();\n\tconst dataType = element.getAttribute( 'data-type' );\n\n\t/*\n\t * For blocks with overflowing elements (like Navigation), include the bounds\n\t * of visible children that extend beyond the parent container.\n\t */\n\tif ( dataType && WITH_OVERFLOW_ELEMENT_BLOCKS.includes( dataType ) ) {\n\t\tconst stack = [ element ];\n\t\tlet currentElement;\n\n\t\twhile ( ( currentElement = stack.pop() ) ) {\n\t\t\t// Children won\u2019t affect bounds unless the element is not scrollable.\n\t\t\tif ( ! isScrollable( currentElement ) ) {\n\t\t\t\tfor ( const child of currentElement.children ) {\n\t\t\t\t\tif ( isElementVisible( child ) ) {\n\t\t\t\t\t\tconst childBounds = child.getBoundingClientRect();\n\t\t\t\t\t\tbounds = rectUnion( bounds, childBounds );\n\t\t\t\t\t\tstack.push( child );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/*\n\t * Take into account the outer horizontal limits of the container in which\n\t * an element is supposed to be \"visible\". For example, if an element is\n\t * positioned -10px to the left of the window x value (0), this function\n\t * discounts the negative overhang because it's not visible and therefore\n\t * not to be counted in the visibility calculations. Top and bottom values\n\t * are not accounted for to accommodate vertical scroll.\n\t */\n\tconst left = Math.max( bounds.left, 0 );\n\tconst right = Math.min( bounds.right, viewport.innerWidth );\n\tbounds = new window.DOMRectReadOnly(\n\t\tleft,\n\t\tbounds.top,\n\t\tright - left,\n\t\tbounds.height\n\t);\n\n\treturn bounds;\n}\n"],
4
+ "sourcesContent": ["const BLOCK_SELECTOR = '.block-editor-block-list__block';\nconst APPENDER_SELECTOR = '.block-list-appender';\nconst BLOCK_APPENDER_CLASS = '.block-editor-button-block-appender';\n\n/**\n * Returns true if two elements are contained within the same block.\n *\n * @param {Element} a First element.\n * @param {Element} b Second element.\n *\n * @return {boolean} Whether elements are in the same block.\n */\nexport function isInSameBlock( a, b ) {\n\treturn a.closest( BLOCK_SELECTOR ) === b.closest( BLOCK_SELECTOR );\n}\n\n/**\n * Returns true if an element is considered part of the block and not its inner\n * blocks or appender.\n *\n * @param {Element} blockElement Block container element.\n * @param {Element} element Element.\n *\n * @return {boolean} Whether an element is considered part of the block and not\n * its inner blocks or appender.\n */\nexport function isInsideRootBlock( blockElement, element ) {\n\tconst parentBlock = element.closest(\n\t\t[ BLOCK_SELECTOR, APPENDER_SELECTOR, BLOCK_APPENDER_CLASS ].join( ',' )\n\t);\n\treturn parentBlock === blockElement;\n}\n\n/**\n * Finds the block client ID given any DOM node inside the block.\n *\n * @param {Node?} node DOM node.\n *\n * @return {string|undefined} Client ID or undefined if the node is not part of\n * a block.\n */\nexport function getBlockClientId( node ) {\n\twhile ( node && node.nodeType !== node.ELEMENT_NODE ) {\n\t\tnode = node.parentNode;\n\t}\n\n\tif ( ! node ) {\n\t\treturn;\n\t}\n\n\tconst elementNode = /** @type {Element} */ ( node );\n\tconst blockNode = elementNode.closest( BLOCK_SELECTOR );\n\n\tif ( ! blockNode ) {\n\t\treturn;\n\t}\n\n\treturn blockNode.id.slice( 'block-'.length );\n}\n\n/**\n * Calculates the union of two rectangles.\n *\n * @param {DOMRect} rect1 First rectangle.\n * @param {DOMRect} rect2 Second rectangle.\n * @return {DOMRect} Union of the two rectangles.\n */\nexport function rectUnion( rect1, rect2 ) {\n\tconst left = Math.min( rect1.left, rect2.left );\n\tconst right = Math.max( rect1.right, rect2.right );\n\tconst bottom = Math.max( rect1.bottom, rect2.bottom );\n\tconst top = Math.min( rect1.top, rect2.top );\n\n\treturn new window.DOMRectReadOnly( left, top, right - left, bottom - top );\n}\n\n/**\n * Returns whether an element is visible.\n *\n * @param {Element} element Element.\n * @return {boolean} Whether the element is visible.\n */\nexport function isElementVisible( element ) {\n\tconst viewport = element.ownerDocument.defaultView;\n\tif ( ! viewport ) {\n\t\treturn false;\n\t}\n\n\t// Check for <VisuallyHidden> components.\n\tif ( element.hasAttribute( 'data-visually-hidden' ) ) {\n\t\treturn false;\n\t}\n\n\tconst bounds = element.getBoundingClientRect();\n\tif ( bounds.width === 0 || bounds.height === 0 ) {\n\t\treturn false;\n\t}\n\n\t// Older browsers, e.g. Safari < 17.4 may not support the `checkVisibility` method.\n\tif ( element.checkVisibility ) {\n\t\treturn element.checkVisibility?.( {\n\t\t\topacityProperty: true,\n\t\t\tcontentVisibilityAuto: true,\n\t\t\tvisibilityProperty: true,\n\t\t} );\n\t}\n\n\tconst style = viewport.getComputedStyle( element );\n\n\tif (\n\t\tstyle.display === 'none' ||\n\t\tstyle.visibility === 'hidden' ||\n\t\tstyle.opacity === '0'\n\t) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n/**\n * Checks if the element is scrollable.\n *\n * @param {Element} element Element.\n * @return {boolean} True if the element is scrollable.\n */\nfunction isScrollable( element ) {\n\tconst style = window.getComputedStyle( element );\n\treturn (\n\t\tstyle.overflowX === 'auto' ||\n\t\tstyle.overflowX === 'scroll' ||\n\t\tstyle.overflowY === 'auto' ||\n\t\tstyle.overflowY === 'scroll'\n\t);\n}\n\nexport const WITH_OVERFLOW_ELEMENT_BLOCKS = [ 'core/navigation' ];\n/**\n * Returns the bounding rectangle of an element, with special handling for blocks\n * that have visible overflowing children (defined in WITH_OVERFLOW_ELEMENT_BLOCKS).\n *\n * For blocks like Navigation that can have overflowing elements (e.g. submenus),\n * this function calculates the combined bounds of both the parent and its visible\n * children. The returned rect may extend beyond the viewport.\n * The returned rect represents the full extent of the element and its visible\n * children, which may extend beyond the viewport.\n *\n * @param {Element} element Element.\n * @return {DOMRect} Bounding client rect of the element and its visible children.\n */\nexport function getElementBounds( element ) {\n\tconst viewport = element.ownerDocument.defaultView;\n\n\tif ( ! viewport ) {\n\t\treturn new window.DOMRectReadOnly();\n\t}\n\n\tlet bounds = element.getBoundingClientRect();\n\tconst dataType = element.getAttribute( 'data-type' );\n\n\t/*\n\t * For blocks with overflowing elements (like Navigation), include the bounds\n\t * of visible children that extend beyond the parent container.\n\t */\n\tif ( dataType && WITH_OVERFLOW_ELEMENT_BLOCKS.includes( dataType ) ) {\n\t\tconst stack = [ element ];\n\t\tlet currentElement;\n\n\t\twhile ( ( currentElement = stack.pop() ) ) {\n\t\t\t// Children won’t affect bounds unless the element is not scrollable.\n\t\t\tif ( ! isScrollable( currentElement ) ) {\n\t\t\t\tfor ( const child of currentElement.children ) {\n\t\t\t\t\tif ( isElementVisible( child ) ) {\n\t\t\t\t\t\tconst childBounds = child.getBoundingClientRect();\n\t\t\t\t\t\tbounds = rectUnion( bounds, childBounds );\n\t\t\t\t\t\tstack.push( child );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/*\n\t * Take into account the outer horizontal limits of the container in which\n\t * an element is supposed to be \"visible\". For example, if an element is\n\t * positioned -10px to the left of the window x value (0), this function\n\t * discounts the negative overhang because it's not visible and therefore\n\t * not to be counted in the visibility calculations. Top and bottom values\n\t * are not accounted for to accommodate vertical scroll.\n\t */\n\tconst left = Math.max( bounds.left, 0 );\n\tconst right = Math.min( bounds.right, viewport.innerWidth );\n\tbounds = new window.DOMRectReadOnly(\n\t\tleft,\n\t\tbounds.top,\n\t\tright - left,\n\t\tbounds.height\n\t);\n\n\treturn bounds;\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,6 @@
1
1
  // packages/block-editor/src/utils/selection.js
2
2
  import { RichTextData } from "@wordpress/rich-text";
3
- var START_OF_SELECTED_AREA = "\x86";
3
+ var START_OF_SELECTED_AREA = "†";
4
4
  function retrieveSelectedAttribute(blockAttributes) {
5
5
  if (!blockAttributes) {
6
6
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/block-editor",
3
- "version": "15.21.1",
3
+ "version": "15.22.1-next.v.202606191442.0+17fe7db8a",
4
4
  "description": "Generic block editor.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -60,44 +60,43 @@
60
60
  ],
61
61
  "dependencies": {
62
62
  "@react-spring/web": "^9.4.5",
63
- "@types/react": "^18.3.27",
64
- "@wordpress/a11y": "^4.48.1",
65
- "@wordpress/base-styles": "^10.0.1",
66
- "@wordpress/blob": "^4.48.1",
67
- "@wordpress/block-serialization-default-parser": "^5.48.1",
68
- "@wordpress/blocks": "^15.21.1",
69
- "@wordpress/commands": "^1.48.1",
70
- "@wordpress/components": "^35.0.1",
71
- "@wordpress/compose": "^8.1.1",
72
- "@wordpress/data": "^10.48.1",
73
- "@wordpress/dataviews": "^16.0.1",
74
- "@wordpress/date": "^5.48.1",
75
- "@wordpress/deprecated": "^4.48.1",
76
- "@wordpress/dom": "^4.48.1",
77
- "@wordpress/element": "^8.0.1",
78
- "@wordpress/escape-html": "^3.48.1",
79
- "@wordpress/global-styles-engine": "^1.15.1",
80
- "@wordpress/hooks": "^4.48.1",
81
- "@wordpress/html-entities": "^4.48.1",
82
- "@wordpress/i18n": "^6.21.1",
83
- "@wordpress/icons": "^14.0.1",
84
- "@wordpress/image-cropper": "^1.12.1",
85
- "@wordpress/interactivity": "^6.48.1",
86
- "@wordpress/is-shallow-equal": "^5.48.1",
87
- "@wordpress/keyboard-shortcuts": "^5.48.1",
88
- "@wordpress/keycodes": "^4.48.1",
89
- "@wordpress/notices": "^5.48.1",
90
- "@wordpress/preferences": "^4.48.1",
91
- "@wordpress/priority-queue": "^3.48.1",
92
- "@wordpress/private-apis": "^1.48.1",
93
- "@wordpress/rich-text": "^7.48.1",
94
- "@wordpress/style-engine": "^2.48.1",
95
- "@wordpress/token-list": "^3.48.1",
96
- "@wordpress/ui": "^0.15.1",
97
- "@wordpress/upload-media": "^0.33.1",
98
- "@wordpress/url": "^4.48.1",
99
- "@wordpress/warning": "^3.48.1",
100
- "@wordpress/wordcount": "^4.48.1",
63
+ "@wordpress/a11y": "^4.48.2-next.v.202606191442.0+17fe7db8a",
64
+ "@wordpress/base-styles": "^10.0.2-next.v.202606191442.0+17fe7db8a",
65
+ "@wordpress/blob": "^4.48.2-next.v.202606191442.0+17fe7db8a",
66
+ "@wordpress/block-serialization-default-parser": "^5.48.2-next.v.202606191442.0+17fe7db8a",
67
+ "@wordpress/blocks": "^15.21.3-next.v.202606191442.0+17fe7db8a",
68
+ "@wordpress/commands": "^1.48.2-next.v.202606191442.0+17fe7db8a",
69
+ "@wordpress/components": "^35.1.1-next.v.202606191442.0+17fe7db8a",
70
+ "@wordpress/compose": "^8.1.2-next.v.202606191442.0+17fe7db8a",
71
+ "@wordpress/data": "^10.48.2-next.v.202606191442.0+17fe7db8a",
72
+ "@wordpress/dataviews": "^17.0.1-next.v.202606191442.0+17fe7db8a",
73
+ "@wordpress/date": "^5.48.2-next.v.202606191442.0+17fe7db8a",
74
+ "@wordpress/deprecated": "^4.48.2-next.v.202606191442.0+17fe7db8a",
75
+ "@wordpress/dom": "^4.48.2-next.v.202606191442.0+17fe7db8a",
76
+ "@wordpress/element": "^8.0.2-next.v.202606191442.0+17fe7db8a",
77
+ "@wordpress/escape-html": "^3.48.2-next.v.202606191442.0+17fe7db8a",
78
+ "@wordpress/global-styles-engine": "^1.15.2-next.v.202606191442.0+17fe7db8a",
79
+ "@wordpress/hooks": "^4.48.2-next.v.202606191442.0+17fe7db8a",
80
+ "@wordpress/html-entities": "^4.48.2-next.v.202606191442.0+17fe7db8a",
81
+ "@wordpress/i18n": "^6.21.2-next.v.202606191442.0+17fe7db8a",
82
+ "@wordpress/icons": "^14.0.2-next.v.202606191442.0+17fe7db8a",
83
+ "@wordpress/image-cropper": "^1.12.2-next.v.202606191442.0+17fe7db8a",
84
+ "@wordpress/interactivity": "^6.48.2-next.v.202606191442.0+17fe7db8a",
85
+ "@wordpress/is-shallow-equal": "^5.48.2-next.v.202606191442.0+17fe7db8a",
86
+ "@wordpress/keyboard-shortcuts": "^5.48.2-next.v.202606191442.0+17fe7db8a",
87
+ "@wordpress/keycodes": "^4.48.2-next.v.202606191442.0+17fe7db8a",
88
+ "@wordpress/notices": "^5.48.2-next.v.202606191442.0+17fe7db8a",
89
+ "@wordpress/preferences": "^4.48.2-next.v.202606191442.0+17fe7db8a",
90
+ "@wordpress/priority-queue": "^3.48.2-next.v.202606191442.0+17fe7db8a",
91
+ "@wordpress/private-apis": "^1.48.2-next.v.202606191442.0+17fe7db8a",
92
+ "@wordpress/rich-text": "^7.48.2-next.v.202606191442.0+17fe7db8a",
93
+ "@wordpress/style-engine": "^2.49.1-next.v.202606191442.0+17fe7db8a",
94
+ "@wordpress/token-list": "^3.48.2-next.v.202606191442.0+17fe7db8a",
95
+ "@wordpress/ui": "^0.16.1-next.v.202606191442.0+17fe7db8a",
96
+ "@wordpress/upload-media": "^0.34.1-next.v.202606191442.0+17fe7db8a",
97
+ "@wordpress/url": "^4.48.2-next.v.202606191442.0+17fe7db8a",
98
+ "@wordpress/warning": "^3.48.2-next.v.202606191442.0+17fe7db8a",
99
+ "@wordpress/wordcount": "^4.48.2-next.v.202606191442.0+17fe7db8a",
101
100
  "change-case": "^4.1.2",
102
101
  "clsx": "^2.1.1",
103
102
  "colord": "^2.9.3",
@@ -121,11 +120,17 @@
121
120
  "deep-freeze": "^0.0.1"
122
121
  },
123
122
  "peerDependencies": {
123
+ "@types/react": "^18.3.27",
124
124
  "react": "^18.0.0",
125
125
  "react-dom": "^18.0.0"
126
126
  },
127
+ "peerDependenciesMeta": {
128
+ "@types/react": {
129
+ "optional": true
130
+ }
131
+ },
127
132
  "publishConfig": {
128
133
  "access": "public"
129
134
  },
130
- "gitHead": "99df7432c5c7cb83ba41146fd1f57f3c19004305"
135
+ "gitHead": "1b6a19222df5a88f161880b5789efb3171d8f425"
131
136
  }
@@ -21,7 +21,7 @@ import {
21
21
  arrowRight,
22
22
  arrowLeft,
23
23
  } from '@wordpress/icons';
24
- import { getBlockType, hasBlockSupport } from '@wordpress/blocks';
24
+ import { getBlockType } from '@wordpress/blocks';
25
25
 
26
26
  /**
27
27
  * Internal dependencies
@@ -110,20 +110,14 @@ function BlockCard( {
110
110
  if ( parentClientId || isChild || ! allowParentNavigation ) {
111
111
  return {};
112
112
  }
113
- const { getBlockParents, getBlockName } =
114
- select( blockEditorStore );
113
+ const { getBlockParents, getBlockName, shouldRenderBlockListView } =
114
+ unlock( select( blockEditorStore ) );
115
115
 
116
- // Find the top-most parent block that is either:
117
- // 1. A navigation block (special case for ad-hoc list view support)
118
- // 2. Any block with listView support
116
+ // Find the top-most parent block that participates in List View.
119
117
  const parents = getBlockParents( clientId, false );
120
- const foundParentId = parents.find( ( parentId ) => {
121
- const parentName = getBlockName( parentId );
122
- return (
123
- parentName === 'core/navigation' ||
124
- hasBlockSupport( parentName, 'listView' )
125
- );
126
- } );
118
+ const foundParentId = parents.find( ( parentId ) =>
119
+ shouldRenderBlockListView( parentId )
120
+ );
127
121
 
128
122
  return {
129
123
  parentBlockClientId: foundParentId,
@@ -5,7 +5,6 @@ import { __ } from '@wordpress/i18n';
5
5
  import {
6
6
  getBlockType,
7
7
  getUnregisteredTypeHandlerName,
8
- hasBlockSupport,
9
8
  store as blocksStore,
10
9
  } from '@wordpress/blocks';
11
10
  import {
@@ -208,8 +207,8 @@ function BlockInspector() {
208
207
 
209
208
  const {
210
209
  getClientIdsOfDescendants,
211
- getBlockName,
212
210
  getBlockEditingMode,
211
+ shouldRenderBlockListView,
213
212
  } = unlock( select( blockEditorStore ) );
214
213
 
215
214
  const descendants = getClientIdsOfDescendants(
@@ -220,14 +219,7 @@ function BlockInspector() {
220
219
  // List View tab.
221
220
  const listViewDescendants = new Set();
222
221
  descendants.forEach( ( clientId ) => {
223
- const blockName = getBlockName( clientId );
224
- // Navigation block doesn't have List View block support, but
225
- // it does have a custom implementation that is shown within
226
- // patterns, so it's included in this condition.
227
- if (
228
- blockName === 'core/navigation' ||
229
- hasBlockSupport( blockName, 'listView' )
230
- ) {
222
+ if ( shouldRenderBlockListView( clientId ) ) {
231
223
  const listViewChildren =
232
224
  getClientIdsOfDescendants( clientId );
233
225
  listViewChildren.forEach( ( childId ) =>
@@ -12,7 +12,6 @@ import {
12
12
  Composite,
13
13
  __experimentalHStack as HStack,
14
14
  } from '@wordpress/components';
15
- // eslint-disable-next-line @wordpress/use-recommended-components -- `Tooltip` is not yet on the recommended `@wordpress/ui` allow-list; landing as a migration step ahead of the wider rollout.
16
15
  import { VisuallyHidden, Text, Tooltip } from '@wordpress/ui';
17
16
  import { useInstanceId } from '@wordpress/compose';
18
17
  import { __ } from '@wordpress/i18n';
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { hasBlockSupport, getBlockType } from '@wordpress/blocks';
4
+ import { getBlockType } from '@wordpress/blocks';
5
5
  import { useSelect, useDispatch } from '@wordpress/data';
6
6
  import {
7
7
  Button,
@@ -20,6 +20,7 @@ import { store as blockEditorStore } from '../../store';
20
20
  import BlockIcon from '../block-icon';
21
21
  import useBlockDisplayInformation from '../use-block-display-information';
22
22
  import useBlockDisplayTitle from '../block-title/use-block-display-title';
23
+ import { unlock } from '../../lock-unlock';
23
24
 
24
25
  export default function BlockQuickNavigation( {
25
26
  clientIds,
@@ -52,7 +53,7 @@ function BlockQuickNavigationItem( {
52
53
  hasListViewTab,
53
54
  } ) {
54
55
  const blockInformation = useBlockDisplayInformation( clientId );
55
- const { isSelected, childBlocks, hasListViewSupport, blockName } =
56
+ const { isSelected, childBlocks, shouldRenderListView, blockName } =
56
57
  useSelect(
57
58
  ( select ) => {
58
59
  const {
@@ -60,7 +61,8 @@ function BlockQuickNavigationItem( {
60
61
  hasSelectedInnerBlock,
61
62
  getBlockOrder,
62
63
  getBlockName,
63
- } = select( blockEditorStore );
64
+ shouldRenderBlockListView,
65
+ } = unlock( select( blockEditorStore ) );
64
66
 
65
67
  const _blockName = getBlockName( clientId );
66
68
 
@@ -69,9 +71,7 @@ function BlockQuickNavigationItem( {
69
71
  isBlockSelected( clientId ) ||
70
72
  hasSelectedInnerBlock( clientId, /* deep: */ true ),
71
73
  childBlocks: getBlockOrder( clientId ),
72
- hasListViewSupport:
73
- _blockName === 'core/navigation' ||
74
- hasBlockSupport( _blockName, 'listView' ),
74
+ shouldRenderListView: shouldRenderBlockListView( clientId ),
75
75
  blockName: _blockName,
76
76
  };
77
77
  },
@@ -88,7 +88,7 @@ function BlockQuickNavigationItem( {
88
88
 
89
89
  const hasChildren = childBlocks && childBlocks.length > 0;
90
90
  const canNavigateToListView =
91
- hasChildren && hasListViewTab && hasListViewSupport;
91
+ hasChildren && hasListViewTab && shouldRenderListView;
92
92
 
93
93
  return (
94
94
  <Button
@@ -157,7 +157,13 @@ export default function useBlockToolbarPopoverProps( {
157
157
  isSticky
158
158
  )
159
159
  ),
160
- [ contentElement, selectedBlockElement, scrollContainer, toolbarHeight ]
160
+ [
161
+ contentElement,
162
+ selectedBlockElement,
163
+ scrollContainer,
164
+ toolbarHeight,
165
+ isSticky,
166
+ ]
161
167
  );
162
168
 
163
169
  // Update props when the block is moved. This also ensures the props are
@@ -173,18 +179,18 @@ export default function useBlockToolbarPopoverProps( {
173
179
 
174
180
  // Update the toolbar props on viewport resize.
175
181
  const contentView = contentElement?.ownerDocument?.defaultView;
176
- contentView?.addEventHandler?.( 'resize', updateProps );
182
+ contentView?.addEventListener?.( 'resize', updateProps );
177
183
 
178
184
  // Update the toolbar props on block resize.
179
185
  let resizeObserver;
180
186
  const blockView = selectedBlockElement?.ownerDocument?.defaultView;
181
- if ( blockView.ResizeObserver ) {
187
+ if ( blockView?.ResizeObserver ) {
182
188
  resizeObserver = new blockView.ResizeObserver( updateProps );
183
189
  resizeObserver.observe( selectedBlockElement );
184
190
  }
185
191
 
186
192
  return () => {
187
- contentView?.removeEventHandler?.( 'resize', updateProps );
193
+ contentView?.removeEventListener?.( 'resize', updateProps );
188
194
 
189
195
  if ( resizeObserver ) {
190
196
  resizeObserver.disconnect();
@@ -23,15 +23,51 @@ import { useGetNumberOfBlocksBeforeCell } from '../grid/use-get-number-of-blocks
23
23
  import { store as blockEditorStore } from '../../store';
24
24
  import { useSettings } from '../use-settings';
25
25
 
26
- function helpText( selfStretch, parentLayout ) {
27
- const { orientation = 'horizontal' } = parentLayout;
26
+ // These are the serialized `selfStretch` values. `max` used to be called
27
+ // "Fixed" in the UI, but was renamed and replaced by `fixedNoShrink`.
28
+ const FLEX_CHILD_LAYOUT_VALUES = {
29
+ fit: 'fit',
30
+ grow: 'fill',
31
+ max: 'fixed',
32
+ fixed: 'fixedNoShrink',
33
+ };
28
34
 
29
- if ( selfStretch === 'fill' ) {
35
+ const FLEX_SIZE_VALUES = [
36
+ FLEX_CHILD_LAYOUT_VALUES.max,
37
+ FLEX_CHILD_LAYOUT_VALUES.fixed,
38
+ ];
39
+
40
+ function isFlexSizeValue( value ) {
41
+ return FLEX_SIZE_VALUES.includes( value );
42
+ }
43
+
44
+ function maxSizeLabel( parentLayout ) {
45
+ const { orientation = 'horizontal' } = parentLayout ?? {};
46
+ return orientation === 'horizontal'
47
+ ? _x( 'Max', 'Block with maximum width in flex layout' )
48
+ : _x( 'Max', 'Block with maximum height in flex layout' );
49
+ }
50
+
51
+ function helpText( flexControlValue, parentLayout ) {
52
+ const { orientation = 'horizontal' } = parentLayout ?? {};
53
+
54
+ if ( flexControlValue === FLEX_CHILD_LAYOUT_VALUES.grow ) {
30
55
  return __( 'Stretch to fill available space.' );
31
56
  }
32
- if ( selfStretch === 'fixed' && orientation === 'horizontal' ) {
57
+ if (
58
+ flexControlValue === FLEX_CHILD_LAYOUT_VALUES.max &&
59
+ orientation === 'horizontal'
60
+ ) {
61
+ return __( 'Specify a maximum width.' );
62
+ } else if ( flexControlValue === FLEX_CHILD_LAYOUT_VALUES.max ) {
63
+ return __( 'Specify a maximum height.' );
64
+ }
65
+ if (
66
+ flexControlValue === FLEX_CHILD_LAYOUT_VALUES.fixed &&
67
+ orientation === 'horizontal'
68
+ ) {
33
69
  return __( 'Specify a fixed width.' );
34
- } else if ( selfStretch === 'fixed' ) {
70
+ } else if ( flexControlValue === FLEX_CHILD_LAYOUT_VALUES.fixed ) {
35
71
  return __( 'Specify a fixed height.' );
36
72
  }
37
73
  return __( 'Fit contents.' );
@@ -99,6 +135,8 @@ function FlexControls( {
99
135
  } ) {
100
136
  const { selfStretch, flexSize } = childLayout;
101
137
  const { orientation = 'horizontal' } = parentLayout ?? {};
138
+ const flexControlValue = selfStretch || FLEX_CHILD_LAYOUT_VALUES.fit;
139
+ const hasFlexSizeValue = isFlexSizeValue( flexControlValue );
102
140
  const hasFlexValue = () => !! selfStretch;
103
141
  const flexResetLabel =
104
142
  orientation === 'horizontal' ? __( 'Width' ) : __( 'Height' );
@@ -121,13 +159,13 @@ function FlexControls( {
121
159
  };
122
160
 
123
161
  useEffect( () => {
124
- if ( selfStretch === 'fixed' && ! flexSize ) {
162
+ if ( isFlexSizeValue( selfStretch ) && ! flexSize ) {
125
163
  onChange( {
126
164
  ...childLayout,
127
- selfStretch: 'fit',
165
+ selfStretch: FLEX_CHILD_LAYOUT_VALUES.fit,
128
166
  } );
129
167
  }
130
- }, [] );
168
+ }, [] ); // eslint-disable-line react-hooks/exhaustive-deps
131
169
 
132
170
  return (
133
171
  <VStack
@@ -142,10 +180,12 @@ function FlexControls( {
142
180
  <ToggleGroupControl
143
181
  size="__unstable-large"
144
182
  label={ childLayoutOrientation( parentLayout ) }
145
- value={ selfStretch || 'fit' }
146
- help={ helpText( selfStretch, parentLayout ) }
183
+ value={ flexControlValue }
184
+ help={ helpText( flexControlValue, parentLayout ) }
147
185
  onChange={ ( value ) => {
148
- const newFlexSize = value !== 'fixed' ? null : flexSize;
186
+ const newFlexSize = isFlexSizeValue( value )
187
+ ? flexSize
188
+ : null;
149
189
  onChange( {
150
190
  selfStretch: value,
151
191
  flexSize: newFlexSize,
@@ -154,37 +194,42 @@ function FlexControls( {
154
194
  isBlock
155
195
  >
156
196
  <ToggleGroupControlOption
157
- key="fit"
158
- value="fit"
197
+ key={ FLEX_CHILD_LAYOUT_VALUES.fit }
198
+ value={ FLEX_CHILD_LAYOUT_VALUES.fit }
159
199
  label={ _x(
160
200
  'Fit',
161
201
  'Intrinsic block width in flex layout'
162
202
  ) }
163
203
  />
164
204
  <ToggleGroupControlOption
165
- key="fill"
166
- value="fill"
205
+ key={ FLEX_CHILD_LAYOUT_VALUES.grow }
206
+ value={ FLEX_CHILD_LAYOUT_VALUES.grow }
167
207
  label={ _x(
168
208
  'Grow',
169
209
  'Block with expanding width in flex layout'
170
210
  ) }
171
211
  />
172
212
  <ToggleGroupControlOption
173
- key="fixed"
174
- value="fixed"
213
+ key={ FLEX_CHILD_LAYOUT_VALUES.max }
214
+ value={ FLEX_CHILD_LAYOUT_VALUES.max }
215
+ label={ maxSizeLabel( parentLayout ) }
216
+ />
217
+ <ToggleGroupControlOption
218
+ key={ FLEX_CHILD_LAYOUT_VALUES.fixed }
219
+ value={ FLEX_CHILD_LAYOUT_VALUES.fixed }
175
220
  label={ _x(
176
221
  'Fixed',
177
222
  'Block with fixed width in flex layout'
178
223
  ) }
179
224
  />
180
225
  </ToggleGroupControl>
181
- { selfStretch === 'fixed' && (
226
+ { hasFlexSizeValue && (
182
227
  <UnitControl
183
228
  size="__unstable-large"
184
229
  units={ units }
185
230
  onChange={ ( value ) => {
186
231
  onChange( {
187
- selfStretch,
232
+ selfStretch: flexControlValue,
188
233
  flexSize: value,
189
234
  } );
190
235
  } }
@@ -199,7 +244,7 @@ function FlexControls( {
199
244
  }
200
245
 
201
246
  export function childLayoutOrientation( parentLayout ) {
202
- const { orientation = 'horizontal' } = parentLayout;
247
+ const { orientation = 'horizontal' } = parentLayout ?? {};
203
248
  return orientation === 'horizontal' ? __( 'Width' ) : __( 'Height' );
204
249
  }
205
250
 
@@ -14,6 +14,10 @@ import { __experimentalToolsPanel as ToolsPanel } from '@wordpress/components';
14
14
  */
15
15
  import ChildLayoutControl from '../';
16
16
 
17
+ jest.mock( '../../use-settings', () => ( {
18
+ useSettings: () => [ undefined ],
19
+ } ) );
20
+
17
21
  jest.mock( '@wordpress/data/src/components/use-select', () =>
18
22
  jest.fn( ( mapSelect ) => {
19
23
  if ( typeof mapSelect === 'function' ) {
@@ -123,4 +127,64 @@ describe( 'ChildLayoutControl', () => {
123
127
  columnSpan: 1,
124
128
  } );
125
129
  } );
130
+
131
+ it( 'shows legacy fixed flex sizing as max', () => {
132
+ renderControl( {
133
+ parentLayout: {
134
+ type: 'flex',
135
+ orientation: 'horizontal',
136
+ },
137
+ value: {
138
+ selfStretch: 'fixed',
139
+ flexSize: '320px',
140
+ },
141
+ } );
142
+
143
+ expect( screen.getByRole( 'radio', { name: 'Max' } ) ).toBeChecked();
144
+ } );
145
+
146
+ it( 'sets fixedNoShrink when selecting fixed flex sizing', async () => {
147
+ const user = userEvent.setup();
148
+ const onChange = jest.fn();
149
+
150
+ renderControl( {
151
+ parentLayout: {
152
+ type: 'flex',
153
+ orientation: 'horizontal',
154
+ },
155
+ value: {},
156
+ onChange,
157
+ } );
158
+
159
+ await user.click( screen.getByRole( 'radio', { name: 'Fixed' } ) );
160
+
161
+ expect( onChange ).toHaveBeenCalledWith( {
162
+ selfStretch: 'fixedNoShrink',
163
+ flexSize: undefined,
164
+ } );
165
+ } );
166
+
167
+ it( 'sets legacy fixed when selecting max sizing', async () => {
168
+ const user = userEvent.setup();
169
+ const onChange = jest.fn();
170
+
171
+ renderControl( {
172
+ parentLayout: {
173
+ type: 'flex',
174
+ orientation: 'horizontal',
175
+ },
176
+ value: {
177
+ selfStretch: 'fixedNoShrink',
178
+ flexSize: '320px',
179
+ },
180
+ onChange,
181
+ } );
182
+
183
+ await user.click( screen.getByRole( 'radio', { name: 'Max' } ) );
184
+
185
+ expect( onChange ).toHaveBeenCalledWith( {
186
+ selfStretch: 'fixed',
187
+ flexSize: '320px',
188
+ } );
189
+ } );
126
190
  } );
@@ -56,7 +56,7 @@ function DimensionsTool( {
56
56
  aspectRatioOptions, // Default options handled by AspectRatioTool.
57
57
  defaultAspectRatio = 'auto', // Match CSS default value for aspect-ratio.
58
58
  scaleOptions, // Default options handled by ScaleTool.
59
- defaultScale = 'fill', // Match CSS default value for object-fit.
59
+ defaultScale = 'cover',
60
60
  unitsOptions, // Default options handled by UnitControl.
61
61
  tools = [ 'aspectRatio', 'widthHeight', 'scale' ],
62
62
  } ) {
@@ -73,21 +73,19 @@ function DimensionsTool( {
73
73
  value.aspectRatio === undefined || value.aspectRatio === 'auto'
74
74
  ? null
75
75
  : value.aspectRatio;
76
- const scale =
77
- value.scale === undefined || value.scale === 'fill'
78
- ? null
79
- : value.scale;
76
+ const scale = value.scale === undefined ? null : value.scale;
80
77
 
81
78
  // Keep track of state internally, so when the value is cleared by means
82
79
  // other than directly editing that field, it's easier to restore the
83
80
  // previous value.
84
81
  const [ lastScale, setLastScale ] = useState( scale );
85
82
  const [ lastAspectRatio, setLastAspectRatio ] = useState( aspectRatio );
83
+ const hasCustomAspectRatio = !! ( width && height );
86
84
 
87
85
  // 'custom' is not a valid value for CSS aspect-ratio, but it is used in the
88
86
  // dropdown to indicate that setting both the width and height is the same
89
87
  // as a custom aspect ratio.
90
- const aspectRatioValue = width && height ? 'custom' : lastAspectRatio;
88
+ const aspectRatioValue = hasCustomAspectRatio ? 'custom' : aspectRatio;
91
89
 
92
90
  const showScaleControl = aspectRatio || ( width && height );
93
91
 
@@ -197,9 +195,6 @@ function DimensionsTool( {
197
195
  onChange={ ( nextScale ) => {
198
196
  const nextValue = { ...value };
199
197
 
200
- // 'fill' is CSS default, so it gets treated as null.
201
- nextScale = nextScale === 'fill' ? null : nextScale;
202
-
203
198
  setLastScale( nextScale );
204
199
 
205
200
  // Update scale.
@@ -86,8 +86,7 @@ export default function ScaleTool( {
86
86
  defaultValue = DEFAULT_SCALE_OPTIONS[ 0 ].value,
87
87
  isShownByDefault = true,
88
88
  } ) {
89
- // Match the CSS default so if the value is used directly in CSS it will look correct in the control.
90
- const displayValue = value ?? 'fill';
89
+ const displayValue = value ?? defaultValue;
91
90
 
92
91
  const scaleHelp = useMemo( () => {
93
92
  return options.reduce( ( acc, option ) => {