: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
__experimentalFirstVisibleItemClass,
__experimentalLastVisibleItemClass
} = useToolsPanelContext();
// hasValue is a new function on every render, so do not add it as a
// dependency to the useCallback hook! If needed, we should use a ref.
// eslint-disable-next-line react-hooks/exhaustive-deps
const hasValueCallback = (0,external_wp_element_namespaceObject.useCallback)(hasValue, [panelId]);
// resetAllFilter is a new function on every render, so do not add it as a
// dependency to the useCallback hook! If needed, we should use a ref.
// eslint-disable-next-line react-hooks/exhaustive-deps
const resetAllFilterCallback = (0,external_wp_element_namespaceObject.useCallback)(resetAllFilter, [panelId]);
const previousPanelId = (0,external_wp_compose_namespaceObject.usePrevious)(currentPanelId);
const hasMatchingPanel = currentPanelId === panelId || currentPanelId === null;
// Registering the panel item allows the panel to include it in its
// automatically generated menu and determine its initial checked status.
// This is performed in a layout effect to ensure that the panel item
// is registered before it is rendered preventing a rendering glitch.
// See: https://github.com/WordPress/gutenberg/issues/56470
(0,external_wp_element_namespaceObject.useLayoutEffect)(() => {
if (hasMatchingPanel && previousPanelId !== null) {
hasValue: hasValueCallback,
if (previousPanelId === null && !!currentPanelId || currentPanelId === panelId) {
deregisterPanelItem(label);
}, [currentPanelId, hasMatchingPanel, isShownByDefault, label, hasValueCallback, panelId, previousPanelId, registerPanelItem, deregisterPanelItem]);
(0,external_wp_element_namespaceObject.useEffect)(() => {
registerResetAllFilter(resetAllFilterCallback);
deregisterResetAllFilter(resetAllFilterCallback);
}, [registerResetAllFilter, deregisterResetAllFilter, resetAllFilterCallback, hasMatchingPanel]);
// Note: `label` is used as a key when building menu item state in
const menuGroup = isShownByDefault ? 'default' : 'optional';
const isMenuItemChecked = menuItems?.[menuGroup]?.[label];
const wasMenuItemChecked = (0,external_wp_compose_namespaceObject.usePrevious)(isMenuItemChecked);
const isRegistered = menuItems?.[menuGroup]?.[label] !== undefined;
const isValueSet = hasValue();
// Notify the panel when an item's value has changed except for optional
// items without value because the item should not cause itself to hide.
(0,external_wp_element_namespaceObject.useEffect)(() => {
if (!isShownByDefault && !isValueSet) {
flagItemCustomization(isValueSet, label, menuGroup);
}, [isValueSet, menuGroup, label, flagItemCustomization, isShownByDefault]);
// Determine if the panel item's corresponding menu is being toggled and
// trigger appropriate callback if it is.
(0,external_wp_element_namespaceObject.useEffect)(() => {
// We check whether this item is currently registered as items rendered
// via fills can persist through the parent panel being remounted.
// See: https://github.com/WordPress/gutenberg/pull/45673
if (!isRegistered || isResetting || !hasMatchingPanel) {
if (isMenuItemChecked && !isValueSet && !wasMenuItemChecked) {
if (!isMenuItemChecked && isValueSet && wasMenuItemChecked) {
}, [hasMatchingPanel, isMenuItemChecked, isRegistered, isResetting, isValueSet, wasMenuItemChecked, onSelect, onDeselect]);
// The item is shown if it is a default control regardless of whether it
// has a value. Optional items are shown when they are checked or have
const isShown = isShownByDefault ? menuItems?.[menuGroup]?.[label] !== undefined : isMenuItemChecked;
const classes = (0,external_wp_element_namespaceObject.useMemo)(() => {
const shouldApplyPlaceholderStyles = shouldRenderPlaceholder && !isShown;
const firstItemStyle = firstDisplayedItem === label && __experimentalFirstVisibleItemClass;
const lastItemStyle = lastDisplayedItem === label && __experimentalLastVisibleItemClass;
return cx(ToolsPanelItem, shouldApplyPlaceholderStyles && ToolsPanelItemPlaceholder, !shouldApplyPlaceholderStyles && className, firstItemStyle, lastItemStyle);
}, [isShown, shouldRenderPlaceholder, className, cx, firstDisplayedItem, lastDisplayedItem, __experimentalFirstVisibleItemClass, __experimentalLastVisibleItemClass, label]);
;// CONCATENATED MODULE: ./node_modules/@wordpress/components/build-module/tools-panel/tools-panel-item/component.js
// This wraps controls to be conditionally displayed within a tools panel. It
// prevents props being applied to HTML elements that would make them invalid.
const UnconnectedToolsPanelItem = (props, forwardedRef) => {
} = useToolsPanelItem(props);
return shouldRenderPlaceholder ? /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(component, {
return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(component, {
const component_ToolsPanelItem = contextConnect(UnconnectedToolsPanelItem, 'ToolsPanelItem');
/* harmony default export */ const tools_panel_item_component = (component_ToolsPanelItem);
;// CONCATENATED MODULE: ./node_modules/@wordpress/components/build-module/tree-grid/roving-tab-index-context.js
const RovingTabIndexContext = (0,external_wp_element_namespaceObject.createContext)(undefined);
const useRovingTabIndexContext = () => (0,external_wp_element_namespaceObject.useContext)(RovingTabIndexContext);
const RovingTabIndexProvider = RovingTabIndexContext.Provider;
;// CONCATENATED MODULE: ./node_modules/@wordpress/components/build-module/tree-grid/roving-tab-index.js
* Provider for adding roving tab index behaviors to tree grid structures.
* @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/components/src/tree-grid/README.md
function RovingTabIndex({
const [lastFocusedElement, setLastFocusedElement] = (0,external_wp_element_namespaceObject.useState)();
// Use `useMemo` to avoid creation of a new object for the providerValue
// on every render. Only create a new object when the `lastFocusedElement`
const providerValue = (0,external_wp_element_namespaceObject.useMemo)(() => ({
}), [lastFocusedElement]);
return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(RovingTabIndexProvider, {
;// CONCATENATED MODULE: ./node_modules/@wordpress/components/build-module/tree-grid/index.js
* Return focusables in a row element, excluding those from other branches
* @param rowElement The DOM element representing the row.
* @return The array of focusables in the row.
function getRowFocusables(rowElement) {
const focusablesInRow = external_wp_dom_namespaceObject.focus.focusable.find(rowElement, {
return focusablesInRow.filter(focusable => {
return focusable.closest('[role="row"]') === rowElement;
* Renders both a table and tbody element, used to create a tree hierarchy.
function UnforwardedTreeGrid({
onCollapseRow = () => {},
}, /** A ref to the underlying DOM table element. */
const onKeyDown = (0,external_wp_element_namespaceObject.useCallback)(event => {
// The shift key is intentionally absent from the following list,
// to enable shift + up/down to select items from the list.
const hasModifierKeyPressed = metaKey || ctrlKey || altKey;
if (hasModifierKeyPressed || ![external_wp_keycodes_namespaceObject.UP, external_wp_keycodes_namespaceObject.DOWN, external_wp_keycodes_namespaceObject.LEFT, external_wp_keycodes_namespaceObject.RIGHT, external_wp_keycodes_namespaceObject.HOME, external_wp_keycodes_namespaceObject.END].includes(keyCode)) {
// The event will be handled, stop propagation.
currentTarget: treeGridElement
if (!activeElement || !treeGridElement.contains(activeElement)) {
// Calculate the columnIndex of the active element.
const activeRow = activeElement.closest('[role="row"]');
const focusablesInRow = getRowFocusables(activeRow);
const currentColumnIndex = focusablesInRow.indexOf(activeElement);
const canExpandCollapse = 0 === currentColumnIndex;
const cannotFocusNextColumn = canExpandCollapse && (activeRow.getAttribute('data-expanded') === 'false' || activeRow.getAttribute('aria-expanded') === 'false') && keyCode === external_wp_keycodes_namespaceObject.RIGHT;
if ([external_wp_keycodes_namespaceObject.LEFT, external_wp_keycodes_namespaceObject.RIGHT].includes(keyCode)) {
// Calculate to the next element.
if (keyCode === external_wp_keycodes_namespaceObject.LEFT) {
nextIndex = Math.max(0, currentColumnIndex - 1);
nextIndex = Math.min(currentColumnIndex + 1, focusablesInRow.length - 1);
// Focus is at the left most column.
if (keyCode === external_wp_keycodes_namespaceObject.LEFT) {
var _activeRow$getAttribu;
// If a row is focused, and it is expanded, collapses the current row.
if (activeRow.getAttribute('data-expanded') === 'true' || activeRow.getAttribute('aria-expanded') === 'true') {
onCollapseRow(activeRow);
// If a row is focused, and it is collapsed, moves to the parent row (if there is one).
const level = Math.max(parseInt((_activeRow$getAttribu = activeRow?.getAttribute('aria-level')) !== null && _activeRow$getAttribu !== void 0 ? _activeRow$getAttribu : '1', 10) - 1, 1);
const rows = Array.from(treeGridElement.querySelectorAll('[role="row"]'));
let parentRow = activeRow;
const currentRowIndex = rows.indexOf(activeRow);
for (let i = currentRowIndex; i >= 0; i--) {
const ariaLevel = rows[i].getAttribute('aria-level');
if (ariaLevel !== null && parseInt(ariaLevel, 10) === level) {
getRowFocusables(parentRow)?.[0]?.focus();
if (keyCode === external_wp_keycodes_namespaceObject.RIGHT) {
// If a row is focused, and it is collapsed, expands the current row.
if (activeRow.getAttribute('data-expanded') === 'false' || activeRow.getAttribute('aria-expanded') === 'false') {
// If a row is focused, and it is expanded, focuses the next cell in the row.
const focusableItems = getRowFocusables(activeRow);
if (focusableItems.length > 0) {
focusableItems[nextIndex]?.focus();
// Prevent key use for anything else. For example, Voiceover
// will start reading text on continued use of left/right arrow
// Focus the next element. If at most left column and row is collapsed, moving right is not allowed as this will expand. However, if row is collapsed, moving left is allowed.
if (cannotFocusNextColumn) {
focusablesInRow[nextIndex].focus();
// Prevent key use for anything else. This ensures Voiceover
// doesn't try to handle key navigation.
} else if ([external_wp_keycodes_namespaceObject.UP, external_wp_keycodes_namespaceObject.DOWN].includes(keyCode)) {
// Calculate the rowIndex of the next row.
const rows = Array.from(treeGridElement.querySelectorAll('[role="row"]'));
const currentRowIndex = rows.indexOf(activeRow);
if (keyCode === external_wp_keycodes_namespaceObject.UP) {
nextRowIndex = Math.max(0, currentRowIndex - 1);
nextRowIndex = Math.min(currentRowIndex + 1, rows.length - 1);
// Focus is either at the top or bottom edge of the grid. Do nothing.
if (nextRowIndex === currentRowIndex) {
// Prevent key use for anything else. For example, Voiceover
// will start navigating horizontally when reaching the vertical
// Get the focusables in the next row.
const focusablesInNextRow = getRowFocusables(rows[nextRowIndex]);
// If for some reason there are no focusables in the next row, do nothing.
if (!focusablesInNextRow || !focusablesInNextRow.length) {
// Prevent key use for anything else. For example, Voiceover
// will still focus text when using arrow keys, while this
// component should limit navigation to focusables.
// Try to focus the element in the next row that's at a similar column to the activeElement.
const nextIndex = Math.min(currentColumnIndex, focusablesInNextRow.length - 1);
focusablesInNextRow[nextIndex].focus();
// Let consumers know the row that was originally focused,
// and the row that is now in focus.
onFocusRow(event, activeRow, rows[nextRowIndex]);
// Prevent key use for anything else. This ensures Voiceover
// doesn't try to handle key navigation.
} else if ([external_wp_keycodes_namespaceObject.HOME, external_wp_keycodes_namespaceObject.END].includes(keyCode)) {
// Calculate the rowIndex of the next row.
const rows = Array.from(treeGridElement.querySelectorAll('[role="row"]'));
const currentRowIndex = rows.indexOf(activeRow);
if (keyCode === external_wp_keycodes_namespaceObject.HOME) {
nextRowIndex = rows.length - 1;
// Focus is either at the top or bottom edge of the grid. Do nothing.
if (nextRowIndex === currentRowIndex) {
// Prevent key use for anything else. For example, Voiceover
// will start navigating horizontally when reaching the vertical
// Get the focusables in the next row.
const focusablesInNextRow = getRowFocusables(rows[nextRowIndex]);
// If for some reason there are no focusables in the next row, do nothing.
if (!focusablesInNextRow || !focusablesInNextRow.length) {
// Prevent key use for anything else. For example, Voiceover
// will still focus text when using arrow keys, while this
// component should limit navigation to focusables.
// Try to focus the element in the next row that's at a similar column to the activeElement.
const nextIndex = Math.min(currentColumnIndex, focusablesInNextRow.length - 1);
focusablesInNextRow[nextIndex].focus();
// Let consumers know the row that was originally focused,
// and the row that is now in focus.
onFocusRow(event, activeRow, rows[nextRowIndex]);
// Prevent key use for anything else. This ensures Voiceover
// doesn't try to handle key navigation.
}, [onExpandRow, onCollapseRow, onFocusRow]);
/* Disable reason: A treegrid is implemented using a table element. */
/* eslint-disable jsx-a11y/no-noninteractive-element-to-interactive-role */
return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(RovingTabIndex, {
children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("div", {
"aria-label": applicationAriaLabel,
children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("table", {
children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)("tbody", {
/* eslint-enable jsx-a11y/no-noninteractive-element-to-interactive-role */
* `TreeGrid` is used to create a tree hierarchy.
* It is not a visually styled component, but instead helps with adding
* keyboard navigation and roving tab index behaviors to tree grid structures.
* A tree grid is a hierarchical 2 dimensional UI component, for example it could be
* used to implement a file system browser.
* A tree grid allows the user to navigate using arrow keys.
* Up/down to navigate vertically across rows, and left/right to navigate horizontally
* between focusables in a row.
* The `TreeGrid` renders both a `table` and `tbody` element, and is intended to be used
* with `TreeGridRow` (`tr`) and `TreeGridCell` (`td`) to build out a grid.
* <TreeGridRow level={ 1 } positionInSet={ 1 } setSize={ 2 }>
* <Button onClick={ onSelect } { ...props }>Select</Button>
* <Button onClick={ onMove } { ...props }>Move</Button>
* <TreeGridRow level={ 1 } positionInSet={ 2 } setSize={ 2 }>
* <Button onClick={ onSelect } { ...props }>Select</Button>
* <Button onClick={ onMove } { ...props }>Move</Button>
* <TreeGridRow level={ 2 } positionInSet={ 1 } setSize={ 1 }>
* <Button onClick={ onSelect } { ...props }>Select</Button>
* <Button onClick={ onMove } { ...props }>Move</Button>
* @see {@link https://www.w3.org/TR/wai-aria-practices/examples/treegrid/treegrid-1.html}
const TreeGrid = (0,external_wp_element_namespaceObject.forwardRef)(UnforwardedTreeGrid);
/* harmony default export */ const tree_grid = (TreeGrid);
;// CONCATENATED MODULE: ./node_modules/@wordpress/components/build-module/tree-grid/row.js