fix: prevent asset conflicts between React and Grid.js versions

Add coexistence checks to all enqueue methods to prevent loading
both React and Grid.js assets simultaneously.

Changes:
- ReactAdmin.php: Only enqueue React assets when ?react=1
- Init.php: Skip Grid.js when React active on admin pages
- Form.php, Coupon.php, Access.php: Restore classic assets when ?react=0
- Customer.php, Product.php, License.php: Add coexistence checks

Now the toggle between Classic and React versions works correctly.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
dwindown
2026-04-18 17:02:14 +07:00
parent bd9cdac02e
commit e8fbfb14c1
74973 changed files with 6658406 additions and 71 deletions

View File

@@ -0,0 +1,53 @@
import { createElement } from "react";
/**
* External dependencies
*/
import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { forwardRef } from '@wordpress/element';
import { __, isRTL } from '@wordpress/i18n';
import { Icon, chevronLeft, chevronRight } from '@wordpress/icons';
/**
* Internal dependencies
*/
import { useNavigationContext } from '../context';
import { MenuBackButtonUI } from '../styles/navigation-styles';
function UnforwardedNavigationBackButton({
backButtonLabel,
className,
href,
onClick,
parentMenu
}, ref) {
const {
setActiveMenu,
navigationTree
} = useNavigationContext();
const classes = classnames('components-navigation__back-button', className);
const parentMenuTitle = parentMenu !== undefined ? navigationTree.getMenu(parentMenu)?.title : undefined;
const handleOnClick = event => {
if (typeof onClick === 'function') {
onClick(event);
}
const animationDirection = isRTL() ? 'left' : 'right';
if (parentMenu && !event.defaultPrevented) {
setActiveMenu(parentMenu, animationDirection);
}
};
const icon = isRTL() ? chevronRight : chevronLeft;
return createElement(MenuBackButtonUI, {
className: classes,
href: href,
variant: "tertiary",
ref: ref,
onClick: handleOnClick
}, createElement(Icon, {
icon: icon
}), backButtonLabel || parentMenuTitle || __('Back'));
}
export const NavigationBackButton = forwardRef(UnforwardedNavigationBackButton);
export default NavigationBackButton;
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["classnames","forwardRef","__","isRTL","Icon","chevronLeft","chevronRight","useNavigationContext","MenuBackButtonUI","UnforwardedNavigationBackButton","backButtonLabel","className","href","onClick","parentMenu","ref","setActiveMenu","navigationTree","classes","parentMenuTitle","undefined","getMenu","title","handleOnClick","event","animationDirection","defaultPrevented","icon","createElement","variant","NavigationBackButton"],"sources":["@wordpress/components/src/navigation/back-button/index.tsx"],"sourcesContent":["/**\n * External dependencies\n */\nimport classnames from 'classnames';\n/**\n * WordPress dependencies\n */\nimport { forwardRef } from '@wordpress/element';\nimport { __, isRTL } from '@wordpress/i18n';\nimport { Icon, chevronLeft, chevronRight } from '@wordpress/icons';\n\n/**\n * Internal dependencies\n */\nimport { useNavigationContext } from '../context';\nimport { MenuBackButtonUI } from '../styles/navigation-styles';\n\nimport type { NavigationBackButtonProps } from '../types';\n\nfunction UnforwardedNavigationBackButton(\n\t{\n\t\tbackButtonLabel,\n\t\tclassName,\n\t\thref,\n\t\tonClick,\n\t\tparentMenu,\n\t}: NavigationBackButtonProps,\n\tref: React.ForwardedRef< HTMLAnchorElement | HTMLButtonElement >\n) {\n\tconst { setActiveMenu, navigationTree } = useNavigationContext();\n\n\tconst classes = classnames(\n\t\t'components-navigation__back-button',\n\t\tclassName\n\t);\n\n\tconst parentMenuTitle =\n\t\tparentMenu !== undefined\n\t\t\t? navigationTree.getMenu( parentMenu )?.title\n\t\t\t: undefined;\n\n\tconst handleOnClick: React.MouseEventHandler< HTMLElement > = ( event ) => {\n\t\tif ( typeof onClick === 'function' ) {\n\t\t\tonClick( event );\n\t\t}\n\n\t\tconst animationDirection = isRTL() ? 'left' : 'right';\n\t\tif ( parentMenu && ! event.defaultPrevented ) {\n\t\t\tsetActiveMenu( parentMenu, animationDirection );\n\t\t}\n\t};\n\tconst icon = isRTL() ? chevronRight : chevronLeft;\n\treturn (\n\t\t<MenuBackButtonUI\n\t\t\tclassName={ classes }\n\t\t\thref={ href }\n\t\t\tvariant=\"tertiary\"\n\t\t\tref={ ref }\n\t\t\tonClick={ handleOnClick }\n\t\t>\n\t\t\t<Icon icon={ icon } />\n\t\t\t{ backButtonLabel || parentMenuTitle || __( 'Back' ) }\n\t\t</MenuBackButtonUI>\n\t);\n}\n\nexport const NavigationBackButton = forwardRef(\n\tUnforwardedNavigationBackButton\n);\n\nexport default NavigationBackButton;\n"],"mappings":";AAAA;AACA;AACA;AACA,OAAOA,UAAU,MAAM,YAAY;AACnC;AACA;AACA;AACA,SAASC,UAAU,QAAQ,oBAAoB;AAC/C,SAASC,EAAE,EAAEC,KAAK,QAAQ,iBAAiB;AAC3C,SAASC,IAAI,EAAEC,WAAW,EAAEC,YAAY,QAAQ,kBAAkB;;AAElE;AACA;AACA;AACA,SAASC,oBAAoB,QAAQ,YAAY;AACjD,SAASC,gBAAgB,QAAQ,6BAA6B;AAI9D,SAASC,+BAA+BA,CACvC;EACCC,eAAe;EACfC,SAAS;EACTC,IAAI;EACJC,OAAO;EACPC;AAC0B,CAAC,EAC5BC,GAAgE,EAC/D;EACD,MAAM;IAAEC,aAAa;IAAEC;EAAe,CAAC,GAAGV,oBAAoB,CAAC,CAAC;EAEhE,MAAMW,OAAO,GAAGlB,UAAU,CACzB,oCAAoC,EACpCW,SACD,CAAC;EAED,MAAMQ,eAAe,GACpBL,UAAU,KAAKM,SAAS,GACrBH,cAAc,CAACI,OAAO,CAAEP,UAAW,CAAC,EAAEQ,KAAK,GAC3CF,SAAS;EAEb,MAAMG,aAAqD,GAAKC,KAAK,IAAM;IAC1E,IAAK,OAAOX,OAAO,KAAK,UAAU,EAAG;MACpCA,OAAO,CAAEW,KAAM,CAAC;IACjB;IAEA,MAAMC,kBAAkB,GAAGtB,KAAK,CAAC,CAAC,GAAG,MAAM,GAAG,OAAO;IACrD,IAAKW,UAAU,IAAI,CAAEU,KAAK,CAACE,gBAAgB,EAAG;MAC7CV,aAAa,CAAEF,UAAU,EAAEW,kBAAmB,CAAC;IAChD;EACD,CAAC;EACD,MAAME,IAAI,GAAGxB,KAAK,CAAC,CAAC,GAAGG,YAAY,GAAGD,WAAW;EACjD,OACCuB,aAAA,CAACpB,gBAAgB;IAChBG,SAAS,EAAGO,OAAS;IACrBN,IAAI,EAAGA,IAAM;IACbiB,OAAO,EAAC,UAAU;IAClBd,GAAG,EAAGA,GAAK;IACXF,OAAO,EAAGU;EAAe,GAEzBK,aAAA,CAACxB,IAAI;IAACuB,IAAI,EAAGA;EAAM,CAAE,CAAC,EACpBjB,eAAe,IAAIS,eAAe,IAAIjB,EAAE,CAAE,MAAO,CAClC,CAAC;AAErB;AAEA,OAAO,MAAM4B,oBAAoB,GAAG7B,UAAU,CAC7CQ,+BACD,CAAC;AAED,eAAeqB,oBAAoB"}

View File

@@ -0,0 +1,3 @@
export const ROOT_MENU = 'root';
export const SEARCH_FOCUS_DELAY = 100;
//# sourceMappingURL=constants.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["ROOT_MENU","SEARCH_FOCUS_DELAY"],"sources":["@wordpress/components/src/navigation/constants.tsx"],"sourcesContent":["export const ROOT_MENU = 'root';\nexport const SEARCH_FOCUS_DELAY = 100;\n"],"mappings":"AAAA,OAAO,MAAMA,SAAS,GAAG,MAAM;AAC/B,OAAO,MAAMC,kBAAkB,GAAG,GAAG"}

View File

@@ -0,0 +1,32 @@
/**
* WordPress dependencies
*/
import { createContext, useContext } from '@wordpress/element';
/**
* Internal dependencies
*/
import { ROOT_MENU } from './constants';
const noop = () => {};
const defaultIsEmpty = () => false;
const defaultGetter = () => undefined;
export const NavigationContext = createContext({
activeItem: undefined,
activeMenu: ROOT_MENU,
setActiveMenu: noop,
navigationTree: {
items: {},
getItem: defaultGetter,
addItem: noop,
removeItem: noop,
menus: {},
getMenu: defaultGetter,
addMenu: noop,
removeMenu: noop,
childMenu: {},
traverseMenu: noop,
isMenuEmpty: defaultIsEmpty
}
});
export const useNavigationContext = () => useContext(NavigationContext);
//# sourceMappingURL=context.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["createContext","useContext","ROOT_MENU","noop","defaultIsEmpty","defaultGetter","undefined","NavigationContext","activeItem","activeMenu","setActiveMenu","navigationTree","items","getItem","addItem","removeItem","menus","getMenu","addMenu","removeMenu","childMenu","traverseMenu","isMenuEmpty","useNavigationContext"],"sources":["@wordpress/components/src/navigation/context.tsx"],"sourcesContent":["/**\n * WordPress dependencies\n */\nimport { createContext, useContext } from '@wordpress/element';\n\n/**\n * Internal dependencies\n */\nimport { ROOT_MENU } from './constants';\n\nimport type { NavigationContext as NavigationContextType } from './types';\n\nconst noop = () => {};\nconst defaultIsEmpty = () => false;\nconst defaultGetter = () => undefined;\n\nexport const NavigationContext = createContext< NavigationContextType >( {\n\tactiveItem: undefined,\n\tactiveMenu: ROOT_MENU,\n\tsetActiveMenu: noop,\n\n\tnavigationTree: {\n\t\titems: {},\n\t\tgetItem: defaultGetter,\n\t\taddItem: noop,\n\t\tremoveItem: noop,\n\n\t\tmenus: {},\n\t\tgetMenu: defaultGetter,\n\t\taddMenu: noop,\n\t\tremoveMenu: noop,\n\t\tchildMenu: {},\n\t\ttraverseMenu: noop,\n\t\tisMenuEmpty: defaultIsEmpty,\n\t},\n} );\nexport const useNavigationContext = () => useContext( NavigationContext );\n"],"mappings":"AAAA;AACA;AACA;AACA,SAASA,aAAa,EAAEC,UAAU,QAAQ,oBAAoB;;AAE9D;AACA;AACA;AACA,SAASC,SAAS,QAAQ,aAAa;AAIvC,MAAMC,IAAI,GAAGA,CAAA,KAAM,CAAC,CAAC;AACrB,MAAMC,cAAc,GAAGA,CAAA,KAAM,KAAK;AAClC,MAAMC,aAAa,GAAGA,CAAA,KAAMC,SAAS;AAErC,OAAO,MAAMC,iBAAiB,GAAGP,aAAa,CAA2B;EACxEQ,UAAU,EAAEF,SAAS;EACrBG,UAAU,EAAEP,SAAS;EACrBQ,aAAa,EAAEP,IAAI;EAEnBQ,cAAc,EAAE;IACfC,KAAK,EAAE,CAAC,CAAC;IACTC,OAAO,EAAER,aAAa;IACtBS,OAAO,EAAEX,IAAI;IACbY,UAAU,EAAEZ,IAAI;IAEhBa,KAAK,EAAE,CAAC,CAAC;IACTC,OAAO,EAAEZ,aAAa;IACtBa,OAAO,EAAEf,IAAI;IACbgB,UAAU,EAAEhB,IAAI;IAChBiB,SAAS,EAAE,CAAC,CAAC;IACbC,YAAY,EAAElB,IAAI;IAClBmB,WAAW,EAAElB;EACd;AACD,CAAE,CAAC;AACH,OAAO,MAAMmB,oBAAoB,GAAGA,CAAA,KAAMtB,UAAU,CAAEM,iBAAkB,CAAC"}

View File

@@ -0,0 +1,14 @@
/**
* WordPress dependencies
*/
import { createContext, useContext } from '@wordpress/element';
/**
* Internal dependencies
*/
export const NavigationGroupContext = createContext({
group: undefined
});
export const useNavigationGroupContext = () => useContext(NavigationGroupContext);
//# sourceMappingURL=context.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["createContext","useContext","NavigationGroupContext","group","undefined","useNavigationGroupContext"],"sources":["@wordpress/components/src/navigation/group/context.tsx"],"sourcesContent":["/**\n * WordPress dependencies\n */\nimport { createContext, useContext } from '@wordpress/element';\n\n/**\n * Internal dependencies\n */\nimport type { NavigationGroupContext as NavigationGroupContextType } from '../types';\n\nexport const NavigationGroupContext =\n\tcreateContext< NavigationGroupContextType >( { group: undefined } );\n\nexport const useNavigationGroupContext = () =>\n\tuseContext( NavigationGroupContext );\n"],"mappings":"AAAA;AACA;AACA;AACA,SAASA,aAAa,EAAEC,UAAU,QAAQ,oBAAoB;;AAE9D;AACA;AACA;;AAGA,OAAO,MAAMC,sBAAsB,GAClCF,aAAa,CAAgC;EAAEG,KAAK,EAAEC;AAAU,CAAE,CAAC;AAEpE,OAAO,MAAMC,yBAAyB,GAAGA,CAAA,KACxCJ,UAAU,CAAEC,sBAAuB,CAAC"}

View File

@@ -0,0 +1,56 @@
import { createElement } from "react";
/**
* External dependencies
*/
import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { useState } from '@wordpress/element';
/**
* Internal dependencies
*/
import { NavigationGroupContext } from './context';
import { GroupTitleUI } from '../styles/navigation-styles';
import { useNavigationContext } from '../context';
let uniqueId = 0;
export function NavigationGroup({
children,
className,
title
}) {
const [groupId] = useState(`group-${++uniqueId}`);
const {
navigationTree: {
items
}
} = useNavigationContext();
const context = {
group: groupId
};
// Keep the children rendered to make sure invisible items are included in the navigation tree.
if (!Object.values(items).some(item => item.group === groupId && item._isVisible)) {
return createElement(NavigationGroupContext.Provider, {
value: context
}, children);
}
const groupTitleId = `components-navigation__group-title-${groupId}`;
const classes = classnames('components-navigation__group', className);
return createElement(NavigationGroupContext.Provider, {
value: context
}, createElement("li", {
className: classes
}, title && createElement(GroupTitleUI, {
className: "components-navigation__group-title",
id: groupTitleId,
level: 3
}, title), createElement("ul", {
"aria-labelledby": groupTitleId,
role: "group"
}, children)));
}
export default NavigationGroup;
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["classnames","useState","NavigationGroupContext","GroupTitleUI","useNavigationContext","uniqueId","NavigationGroup","children","className","title","groupId","navigationTree","items","context","group","Object","values","some","item","_isVisible","createElement","Provider","value","groupTitleId","classes","id","level","role"],"sources":["@wordpress/components/src/navigation/group/index.tsx"],"sourcesContent":["/**\n * External dependencies\n */\nimport classnames from 'classnames';\n\n/**\n * WordPress dependencies\n */\nimport { useState } from '@wordpress/element';\n\n/**\n * Internal dependencies\n */\nimport { NavigationGroupContext } from './context';\nimport { GroupTitleUI } from '../styles/navigation-styles';\nimport { useNavigationContext } from '../context';\n\nimport type { NavigationGroupProps } from '../types';\n\nlet uniqueId = 0;\n\nexport function NavigationGroup( {\n\tchildren,\n\tclassName,\n\ttitle,\n}: NavigationGroupProps ) {\n\tconst [ groupId ] = useState( `group-${ ++uniqueId }` );\n\tconst {\n\t\tnavigationTree: { items },\n\t} = useNavigationContext();\n\n\tconst context = { group: groupId };\n\n\t// Keep the children rendered to make sure invisible items are included in the navigation tree.\n\tif (\n\t\t! Object.values( items ).some(\n\t\t\t( item ) => item.group === groupId && item._isVisible\n\t\t)\n\t) {\n\t\treturn (\n\t\t\t<NavigationGroupContext.Provider value={ context }>\n\t\t\t\t{ children }\n\t\t\t</NavigationGroupContext.Provider>\n\t\t);\n\t}\n\n\tconst groupTitleId = `components-navigation__group-title-${ groupId }`;\n\tconst classes = classnames( 'components-navigation__group', className );\n\n\treturn (\n\t\t<NavigationGroupContext.Provider value={ context }>\n\t\t\t<li className={ classes }>\n\t\t\t\t{ title && (\n\t\t\t\t\t<GroupTitleUI\n\t\t\t\t\t\tclassName=\"components-navigation__group-title\"\n\t\t\t\t\t\tid={ groupTitleId }\n\t\t\t\t\t\tlevel={ 3 }\n\t\t\t\t\t>\n\t\t\t\t\t\t{ title }\n\t\t\t\t\t</GroupTitleUI>\n\t\t\t\t) }\n\t\t\t\t<ul aria-labelledby={ groupTitleId } role=\"group\">\n\t\t\t\t\t{ children }\n\t\t\t\t</ul>\n\t\t\t</li>\n\t\t</NavigationGroupContext.Provider>\n\t);\n}\n\nexport default NavigationGroup;\n"],"mappings":";AAAA;AACA;AACA;AACA,OAAOA,UAAU,MAAM,YAAY;;AAEnC;AACA;AACA;AACA,SAASC,QAAQ,QAAQ,oBAAoB;;AAE7C;AACA;AACA;AACA,SAASC,sBAAsB,QAAQ,WAAW;AAClD,SAASC,YAAY,QAAQ,6BAA6B;AAC1D,SAASC,oBAAoB,QAAQ,YAAY;AAIjD,IAAIC,QAAQ,GAAG,CAAC;AAEhB,OAAO,SAASC,eAAeA,CAAE;EAChCC,QAAQ;EACRC,SAAS;EACTC;AACqB,CAAC,EAAG;EACzB,MAAM,CAAEC,OAAO,CAAE,GAAGT,QAAQ,CAAG,SAAS,EAAEI,QAAU,EAAE,CAAC;EACvD,MAAM;IACLM,cAAc,EAAE;MAAEC;IAAM;EACzB,CAAC,GAAGR,oBAAoB,CAAC,CAAC;EAE1B,MAAMS,OAAO,GAAG;IAAEC,KAAK,EAAEJ;EAAQ,CAAC;;EAElC;EACA,IACC,CAAEK,MAAM,CAACC,MAAM,CAAEJ,KAAM,CAAC,CAACK,IAAI,CAC1BC,IAAI,IAAMA,IAAI,CAACJ,KAAK,KAAKJ,OAAO,IAAIQ,IAAI,CAACC,UAC5C,CAAC,EACA;IACD,OACCC,aAAA,CAAClB,sBAAsB,CAACmB,QAAQ;MAACC,KAAK,EAAGT;IAAS,GAC/CN,QAC8B,CAAC;EAEpC;EAEA,MAAMgB,YAAY,GAAI,sCAAsCb,OAAS,EAAC;EACtE,MAAMc,OAAO,GAAGxB,UAAU,CAAE,8BAA8B,EAAEQ,SAAU,CAAC;EAEvE,OACCY,aAAA,CAAClB,sBAAsB,CAACmB,QAAQ;IAACC,KAAK,EAAGT;EAAS,GACjDO,aAAA;IAAIZ,SAAS,EAAGgB;EAAS,GACtBf,KAAK,IACNW,aAAA,CAACjB,YAAY;IACZK,SAAS,EAAC,oCAAoC;IAC9CiB,EAAE,EAAGF,YAAc;IACnBG,KAAK,EAAG;EAAG,GAETjB,KACW,CACd,EACDW,aAAA;IAAI,mBAAkBG,YAAc;IAACI,IAAI,EAAC;EAAO,GAC9CpB,QACC,CACD,CAC4B,CAAC;AAEpC;AAEA,eAAeD,eAAe"}

View File

@@ -0,0 +1,121 @@
import { createElement } from "react";
/**
* External dependencies
*/
import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { useEffect, useRef, useState } from '@wordpress/element';
import { isRTL } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import { getAnimateClassName } from '../animate';
import { ROOT_MENU } from './constants';
import { NavigationContext } from './context';
import { NavigationUI } from './styles/navigation-styles';
import { useCreateNavigationTree } from './use-create-navigation-tree';
const noop = () => {};
/**
* Render a navigation list with optional groupings and hierarchy.
*
* ```jsx
* import {
* __experimentalNavigation as Navigation,
* __experimentalNavigationGroup as NavigationGroup,
* __experimentalNavigationItem as NavigationItem,
* __experimentalNavigationMenu as NavigationMenu,
* } from '@wordpress/components';
*
* const MyNavigation = () => (
* <Navigation>
* <NavigationMenu title="Home">
* <NavigationGroup title="Group 1">
* <NavigationItem item="item-1" title="Item 1" />
* <NavigationItem item="item-2" title="Item 2" />
* </NavigationGroup>
* <NavigationGroup title="Group 2">
* <NavigationItem
* item="item-3"
* navigateToMenu="category"
* title="Category"
* />
* </NavigationGroup>
* </NavigationMenu>
*
* <NavigationMenu
* backButtonLabel="Home"
* menu="category"
* parentMenu="root"
* title="Category"
* >
* <NavigationItem badge="1" item="child-1" title="Child 1" />
* <NavigationItem item="child-2" title="Child 2" />
* </NavigationMenu>
* </Navigation>
* );
* ```
*/
export function Navigation({
activeItem,
activeMenu = ROOT_MENU,
children,
className,
onActivateMenu = noop
}) {
const [menu, setMenu] = useState(activeMenu);
const [slideOrigin, setSlideOrigin] = useState();
const navigationTree = useCreateNavigationTree();
const defaultSlideOrigin = isRTL() ? 'right' : 'left';
const setActiveMenu = (menuId, slideInOrigin = defaultSlideOrigin) => {
if (!navigationTree.getMenu(menuId)) {
return;
}
setSlideOrigin(slideInOrigin);
setMenu(menuId);
onActivateMenu(menuId);
};
// Used to prevent the sliding animation on mount
const isMounted = useRef(false);
useEffect(() => {
if (!isMounted.current) {
isMounted.current = true;
}
}, []);
useEffect(() => {
if (activeMenu !== menu) {
setActiveMenu(activeMenu);
}
// Ignore exhaustive-deps here, as it would require either a larger refactor or some questionable workarounds.
// See https://github.com/WordPress/gutenberg/pull/41612 for context.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [activeMenu]);
const context = {
activeItem,
activeMenu: menu,
setActiveMenu,
navigationTree
};
const classes = classnames('components-navigation', className);
const animateClassName = getAnimateClassName({
type: 'slide-in',
origin: slideOrigin
});
return createElement(NavigationUI, {
className: classes
}, createElement("div", {
key: menu,
className: animateClassName ? classnames({
[animateClassName]: isMounted.current && slideOrigin
}) : undefined
}, createElement(NavigationContext.Provider, {
value: context
}, children)));
}
export default Navigation;
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,18 @@
import { createElement, Fragment } from "react";
/**
* Internal dependencies
*/
import { ItemBadgeUI, ItemTitleUI } from '../styles/navigation-styles';
export default function NavigationItemBaseContent(props) {
const {
badge,
title
} = props;
return createElement(Fragment, null, title && createElement(ItemTitleUI, {
className: "components-navigation__item-title",
as: "span"
}, title), badge && createElement(ItemBadgeUI, {
className: "components-navigation__item-badge"
}, badge));
}
//# sourceMappingURL=base-content.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["ItemBadgeUI","ItemTitleUI","NavigationItemBaseContent","props","badge","title","createElement","Fragment","className","as"],"sources":["@wordpress/components/src/navigation/item/base-content.tsx"],"sourcesContent":["/**\n * Internal dependencies\n */\nimport { ItemBadgeUI, ItemTitleUI } from '../styles/navigation-styles';\n\nimport type { NavigationItemBaseContentProps } from '../types';\n\nexport default function NavigationItemBaseContent(\n\tprops: NavigationItemBaseContentProps\n) {\n\tconst { badge, title } = props;\n\n\treturn (\n\t\t<>\n\t\t\t{ title && (\n\t\t\t\t<ItemTitleUI\n\t\t\t\t\tclassName=\"components-navigation__item-title\"\n\t\t\t\t\tas=\"span\"\n\t\t\t\t>\n\t\t\t\t\t{ title }\n\t\t\t\t</ItemTitleUI>\n\t\t\t) }\n\n\t\t\t{ badge && (\n\t\t\t\t<ItemBadgeUI className=\"components-navigation__item-badge\">\n\t\t\t\t\t{ badge }\n\t\t\t\t</ItemBadgeUI>\n\t\t\t) }\n\t\t</>\n\t);\n}\n"],"mappings":";AAAA;AACA;AACA;AACA,SAASA,WAAW,EAAEC,WAAW,QAAQ,6BAA6B;AAItE,eAAe,SAASC,yBAAyBA,CAChDC,KAAqC,EACpC;EACD,MAAM;IAAEC,KAAK;IAAEC;EAAM,CAAC,GAAGF,KAAK;EAE9B,OACCG,aAAA,CAAAC,QAAA,QACGF,KAAK,IACNC,aAAA,CAACL,WAAW;IACXO,SAAS,EAAC,mCAAmC;IAC7CC,EAAE,EAAC;EAAM,GAEPJ,KACU,CACb,EAECD,KAAK,IACNE,aAAA,CAACN,WAAW;IAACQ,SAAS,EAAC;EAAmC,GACvDJ,KACU,CAEb,CAAC;AAEL"}

View File

@@ -0,0 +1,42 @@
import { createElement } from "react";
/**
* External dependencies
*/
import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { useState } from '@wordpress/element';
/**
* Internal dependencies
*/
import { useNavigationContext } from '../context';
import { useNavigationTreeItem } from './use-navigation-tree-item';
import { ItemBaseUI } from '../styles/navigation-styles';
let uniqueId = 0;
export default function NavigationItemBase(props) {
// Also avoid to pass the `title` and `href` props to the ItemBaseUI styled component.
const {
children,
className,
title,
href,
...restProps
} = props;
const [itemId] = useState(`item-${++uniqueId}`);
useNavigationTreeItem(itemId, props);
const {
navigationTree
} = useNavigationContext();
if (!navigationTree.getItem(itemId)?._isVisible) {
return null;
}
const classes = classnames('components-navigation__item', className);
return createElement(ItemBaseUI, {
className: classes,
...restProps
}, children);
}
//# sourceMappingURL=base.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["classnames","useState","useNavigationContext","useNavigationTreeItem","ItemBaseUI","uniqueId","NavigationItemBase","props","children","className","title","href","restProps","itemId","navigationTree","getItem","_isVisible","classes","createElement"],"sources":["@wordpress/components/src/navigation/item/base.tsx"],"sourcesContent":["/**\n * External dependencies\n */\nimport classnames from 'classnames';\n\n/**\n * WordPress dependencies\n */\nimport { useState } from '@wordpress/element';\n\n/**\n * Internal dependencies\n */\nimport { useNavigationContext } from '../context';\nimport { useNavigationTreeItem } from './use-navigation-tree-item';\nimport { ItemBaseUI } from '../styles/navigation-styles';\n\nimport type { NavigationItemBaseProps } from '../types';\n\nlet uniqueId = 0;\n\nexport default function NavigationItemBase( props: NavigationItemBaseProps ) {\n\t// Also avoid to pass the `title` and `href` props to the ItemBaseUI styled component.\n\tconst { children, className, title, href, ...restProps } = props;\n\n\tconst [ itemId ] = useState( `item-${ ++uniqueId }` );\n\n\tuseNavigationTreeItem( itemId, props );\n\tconst { navigationTree } = useNavigationContext();\n\n\tif ( ! navigationTree.getItem( itemId )?._isVisible ) {\n\t\treturn null;\n\t}\n\n\tconst classes = classnames( 'components-navigation__item', className );\n\n\treturn (\n\t\t<ItemBaseUI className={ classes } { ...restProps }>\n\t\t\t{ children }\n\t\t</ItemBaseUI>\n\t);\n}\n"],"mappings":";AAAA;AACA;AACA;AACA,OAAOA,UAAU,MAAM,YAAY;;AAEnC;AACA;AACA;AACA,SAASC,QAAQ,QAAQ,oBAAoB;;AAE7C;AACA;AACA;AACA,SAASC,oBAAoB,QAAQ,YAAY;AACjD,SAASC,qBAAqB,QAAQ,4BAA4B;AAClE,SAASC,UAAU,QAAQ,6BAA6B;AAIxD,IAAIC,QAAQ,GAAG,CAAC;AAEhB,eAAe,SAASC,kBAAkBA,CAAEC,KAA8B,EAAG;EAC5E;EACA,MAAM;IAAEC,QAAQ;IAAEC,SAAS;IAAEC,KAAK;IAAEC,IAAI;IAAE,GAAGC;EAAU,CAAC,GAAGL,KAAK;EAEhE,MAAM,CAAEM,MAAM,CAAE,GAAGZ,QAAQ,CAAG,QAAQ,EAAEI,QAAU,EAAE,CAAC;EAErDF,qBAAqB,CAAEU,MAAM,EAAEN,KAAM,CAAC;EACtC,MAAM;IAAEO;EAAe,CAAC,GAAGZ,oBAAoB,CAAC,CAAC;EAEjD,IAAK,CAAEY,cAAc,CAACC,OAAO,CAAEF,MAAO,CAAC,EAAEG,UAAU,EAAG;IACrD,OAAO,IAAI;EACZ;EAEA,MAAMC,OAAO,GAAGjB,UAAU,CAAE,6BAA6B,EAAES,SAAU,CAAC;EAEtE,OACCS,aAAA,CAACd,UAAU;IAACK,SAAS,EAAGQ,OAAS;IAAA,GAAML;EAAS,GAC7CJ,QACS,CAAC;AAEf"}

View File

@@ -0,0 +1,88 @@
import { createElement } from "react";
/**
* External dependencies
*/
import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { Icon, chevronLeft, chevronRight } from '@wordpress/icons';
import { isRTL } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import Button from '../../button';
import { useNavigationContext } from '../context';
import { ItemUI, ItemIconUI } from '../styles/navigation-styles';
import NavigationItemBaseContent from './base-content';
import NavigationItemBase from './base';
const noop = () => {};
export function NavigationItem(props) {
const {
badge,
children,
className,
href,
item,
navigateToMenu,
onClick = noop,
title,
icon,
hideIfTargetMenuEmpty,
isText,
...restProps
} = props;
const {
activeItem,
setActiveMenu,
navigationTree: {
isMenuEmpty
}
} = useNavigationContext();
// If hideIfTargetMenuEmpty prop is true
// And the menu we are supposed to navigate to
// Is marked as empty, then we skip rendering the item.
if (hideIfTargetMenuEmpty && navigateToMenu && isMenuEmpty(navigateToMenu)) {
return null;
}
const isActive = item && activeItem === item;
const classes = classnames(className, {
'is-active': isActive
});
const onItemClick = event => {
if (navigateToMenu) {
setActiveMenu(navigateToMenu);
}
onClick(event);
};
const navigationIcon = isRTL() ? chevronLeft : chevronRight;
const baseProps = children ? props : {
...props,
onClick: undefined
};
const itemProps = isText ? restProps : {
as: Button,
href,
onClick: onItemClick,
'aria-current': isActive ? 'page' : undefined,
...restProps
};
return createElement(NavigationItemBase, {
...baseProps,
className: classes
}, children || createElement(ItemUI, {
...itemProps
}, icon && createElement(ItemIconUI, null, createElement(Icon, {
icon: icon
})), createElement(NavigationItemBaseContent, {
title: title,
badge: badge
}), navigateToMenu && createElement(Icon, {
icon: navigationIcon
})));
}
export default NavigationItem;
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["classnames","Icon","chevronLeft","chevronRight","isRTL","Button","useNavigationContext","ItemUI","ItemIconUI","NavigationItemBaseContent","NavigationItemBase","noop","NavigationItem","props","badge","children","className","href","item","navigateToMenu","onClick","title","icon","hideIfTargetMenuEmpty","isText","restProps","activeItem","setActiveMenu","navigationTree","isMenuEmpty","isActive","classes","onItemClick","event","navigationIcon","baseProps","undefined","itemProps","as","createElement"],"sources":["@wordpress/components/src/navigation/item/index.tsx"],"sourcesContent":["/**\n * External dependencies\n */\nimport classnames from 'classnames';\n\n/**\n * WordPress dependencies\n */\nimport { Icon, chevronLeft, chevronRight } from '@wordpress/icons';\nimport { isRTL } from '@wordpress/i18n';\n\n/**\n * Internal dependencies\n */\nimport Button from '../../button';\nimport { useNavigationContext } from '../context';\nimport { ItemUI, ItemIconUI } from '../styles/navigation-styles';\nimport NavigationItemBaseContent from './base-content';\nimport NavigationItemBase from './base';\n\nimport type { NavigationItemProps } from '../types';\n\nconst noop = () => {};\n\nexport function NavigationItem( props: NavigationItemProps ) {\n\tconst {\n\t\tbadge,\n\t\tchildren,\n\t\tclassName,\n\t\thref,\n\t\titem,\n\t\tnavigateToMenu,\n\t\tonClick = noop,\n\t\ttitle,\n\t\ticon,\n\t\thideIfTargetMenuEmpty,\n\t\tisText,\n\t\t...restProps\n\t} = props;\n\n\tconst {\n\t\tactiveItem,\n\t\tsetActiveMenu,\n\t\tnavigationTree: { isMenuEmpty },\n\t} = useNavigationContext();\n\n\t// If hideIfTargetMenuEmpty prop is true\n\t// And the menu we are supposed to navigate to\n\t// Is marked as empty, then we skip rendering the item.\n\tif (\n\t\thideIfTargetMenuEmpty &&\n\t\tnavigateToMenu &&\n\t\tisMenuEmpty( navigateToMenu )\n\t) {\n\t\treturn null;\n\t}\n\n\tconst isActive = item && activeItem === item;\n\n\tconst classes = classnames( className, {\n\t\t'is-active': isActive,\n\t} );\n\n\tconst onItemClick: React.MouseEventHandler<\n\t\tHTMLButtonElement | HTMLAnchorElement\n\t> = ( event ) => {\n\t\tif ( navigateToMenu ) {\n\t\t\tsetActiveMenu( navigateToMenu );\n\t\t}\n\n\t\tonClick( event );\n\t};\n\tconst navigationIcon = isRTL() ? chevronLeft : chevronRight;\n\tconst baseProps = children ? props : { ...props, onClick: undefined };\n\tconst itemProps = isText\n\t\t? restProps\n\t\t: {\n\t\t\t\tas: Button,\n\t\t\t\thref,\n\t\t\t\tonClick: onItemClick,\n\t\t\t\t'aria-current': isActive ? 'page' : undefined,\n\t\t\t\t...restProps,\n\t\t };\n\n\treturn (\n\t\t<NavigationItemBase { ...baseProps } className={ classes }>\n\t\t\t{ children || (\n\t\t\t\t<ItemUI { ...itemProps }>\n\t\t\t\t\t{ icon && (\n\t\t\t\t\t\t<ItemIconUI>\n\t\t\t\t\t\t\t<Icon icon={ icon } />\n\t\t\t\t\t\t</ItemIconUI>\n\t\t\t\t\t) }\n\n\t\t\t\t\t<NavigationItemBaseContent\n\t\t\t\t\t\ttitle={ title }\n\t\t\t\t\t\tbadge={ badge }\n\t\t\t\t\t/>\n\n\t\t\t\t\t{ navigateToMenu && <Icon icon={ navigationIcon } /> }\n\t\t\t\t</ItemUI>\n\t\t\t) }\n\t\t</NavigationItemBase>\n\t);\n}\n\nexport default NavigationItem;\n"],"mappings":";AAAA;AACA;AACA;AACA,OAAOA,UAAU,MAAM,YAAY;;AAEnC;AACA;AACA;AACA,SAASC,IAAI,EAAEC,WAAW,EAAEC,YAAY,QAAQ,kBAAkB;AAClE,SAASC,KAAK,QAAQ,iBAAiB;;AAEvC;AACA;AACA;AACA,OAAOC,MAAM,MAAM,cAAc;AACjC,SAASC,oBAAoB,QAAQ,YAAY;AACjD,SAASC,MAAM,EAAEC,UAAU,QAAQ,6BAA6B;AAChE,OAAOC,yBAAyB,MAAM,gBAAgB;AACtD,OAAOC,kBAAkB,MAAM,QAAQ;AAIvC,MAAMC,IAAI,GAAGA,CAAA,KAAM,CAAC,CAAC;AAErB,OAAO,SAASC,cAAcA,CAAEC,KAA0B,EAAG;EAC5D,MAAM;IACLC,KAAK;IACLC,QAAQ;IACRC,SAAS;IACTC,IAAI;IACJC,IAAI;IACJC,cAAc;IACdC,OAAO,GAAGT,IAAI;IACdU,KAAK;IACLC,IAAI;IACJC,qBAAqB;IACrBC,MAAM;IACN,GAAGC;EACJ,CAAC,GAAGZ,KAAK;EAET,MAAM;IACLa,UAAU;IACVC,aAAa;IACbC,cAAc,EAAE;MAAEC;IAAY;EAC/B,CAAC,GAAGvB,oBAAoB,CAAC,CAAC;;EAE1B;EACA;EACA;EACA,IACCiB,qBAAqB,IACrBJ,cAAc,IACdU,WAAW,CAAEV,cAAe,CAAC,EAC5B;IACD,OAAO,IAAI;EACZ;EAEA,MAAMW,QAAQ,GAAGZ,IAAI,IAAIQ,UAAU,KAAKR,IAAI;EAE5C,MAAMa,OAAO,GAAG/B,UAAU,CAAEgB,SAAS,EAAE;IACtC,WAAW,EAAEc;EACd,CAAE,CAAC;EAEH,MAAME,WAEL,GAAKC,KAAK,IAAM;IAChB,IAAKd,cAAc,EAAG;MACrBQ,aAAa,CAAER,cAAe,CAAC;IAChC;IAEAC,OAAO,CAAEa,KAAM,CAAC;EACjB,CAAC;EACD,MAAMC,cAAc,GAAG9B,KAAK,CAAC,CAAC,GAAGF,WAAW,GAAGC,YAAY;EAC3D,MAAMgC,SAAS,GAAGpB,QAAQ,GAAGF,KAAK,GAAG;IAAE,GAAGA,KAAK;IAAEO,OAAO,EAAEgB;EAAU,CAAC;EACrE,MAAMC,SAAS,GAAGb,MAAM,GACrBC,SAAS,GACT;IACAa,EAAE,EAAEjC,MAAM;IACVY,IAAI;IACJG,OAAO,EAAEY,WAAW;IACpB,cAAc,EAAEF,QAAQ,GAAG,MAAM,GAAGM,SAAS;IAC7C,GAAGX;EACH,CAAC;EAEJ,OACCc,aAAA,CAAC7B,kBAAkB;IAAA,GAAMyB,SAAS;IAAGnB,SAAS,EAAGe;EAAS,GACvDhB,QAAQ,IACTwB,aAAA,CAAChC,MAAM;IAAA,GAAM8B;EAAS,GACnBf,IAAI,IACLiB,aAAA,CAAC/B,UAAU,QACV+B,aAAA,CAACtC,IAAI;IAACqB,IAAI,EAAGA;EAAM,CAAE,CACV,CACZ,EAEDiB,aAAA,CAAC9B,yBAAyB;IACzBY,KAAK,EAAGA,KAAO;IACfP,KAAK,EAAGA;EAAO,CACf,CAAC,EAEAK,cAAc,IAAIoB,aAAA,CAACtC,IAAI;IAACqB,IAAI,EAAGY;EAAgB,CAAE,CAC5C,CAEU,CAAC;AAEvB;AAEA,eAAetB,cAAc"}

View File

@@ -0,0 +1,44 @@
/**
* WordPress dependencies
*/
import { useEffect } from '@wordpress/element';
/**
* Internal dependencies
*/
import { useNavigationContext } from '../context';
import { useNavigationGroupContext } from '../group/context';
import { useNavigationMenuContext } from '../menu/context';
import { normalizedSearch } from '../utils';
export const useNavigationTreeItem = (itemId, props) => {
const {
activeMenu,
navigationTree: {
addItem,
removeItem
}
} = useNavigationContext();
const {
group
} = useNavigationGroupContext();
const {
menu,
search
} = useNavigationMenuContext();
useEffect(() => {
const isMenuActive = activeMenu === menu;
const isItemVisible = !search || props.title !== undefined && normalizedSearch(props.title, search);
addItem(itemId, {
...props,
group,
menu,
_isVisible: isMenuActive && isItemVisible
});
return () => {
removeItem(itemId);
};
// Ignore exhaustive-deps rule for now. See https://github.com/WordPress/gutenberg/pull/41639
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [activeMenu, search]);
};
//# sourceMappingURL=use-navigation-tree-item.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["useEffect","useNavigationContext","useNavigationGroupContext","useNavigationMenuContext","normalizedSearch","useNavigationTreeItem","itemId","props","activeMenu","navigationTree","addItem","removeItem","group","menu","search","isMenuActive","isItemVisible","title","undefined","_isVisible"],"sources":["@wordpress/components/src/navigation/item/use-navigation-tree-item.tsx"],"sourcesContent":["/**\n * WordPress dependencies\n */\nimport { useEffect } from '@wordpress/element';\n\n/**\n * Internal dependencies\n */\nimport { useNavigationContext } from '../context';\nimport { useNavigationGroupContext } from '../group/context';\nimport { useNavigationMenuContext } from '../menu/context';\nimport { normalizedSearch } from '../utils';\n\nimport type { NavigationItemProps } from '../types';\n\nexport const useNavigationTreeItem = (\n\titemId: string,\n\tprops: NavigationItemProps\n) => {\n\tconst {\n\t\tactiveMenu,\n\t\tnavigationTree: { addItem, removeItem },\n\t} = useNavigationContext();\n\tconst { group } = useNavigationGroupContext();\n\tconst { menu, search } = useNavigationMenuContext();\n\n\tuseEffect( () => {\n\t\tconst isMenuActive = activeMenu === menu;\n\t\tconst isItemVisible =\n\t\t\t! search ||\n\t\t\t( props.title !== undefined &&\n\t\t\t\tnormalizedSearch( props.title, search ) );\n\n\t\taddItem( itemId, {\n\t\t\t...props,\n\t\t\tgroup,\n\t\t\tmenu,\n\t\t\t_isVisible: isMenuActive && isItemVisible,\n\t\t} );\n\n\t\treturn () => {\n\t\t\tremoveItem( itemId );\n\t\t};\n\t\t// Ignore exhaustive-deps rule for now. See https://github.com/WordPress/gutenberg/pull/41639\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t}, [ activeMenu, search ] );\n};\n"],"mappings":"AAAA;AACA;AACA;AACA,SAASA,SAAS,QAAQ,oBAAoB;;AAE9C;AACA;AACA;AACA,SAASC,oBAAoB,QAAQ,YAAY;AACjD,SAASC,yBAAyB,QAAQ,kBAAkB;AAC5D,SAASC,wBAAwB,QAAQ,iBAAiB;AAC1D,SAASC,gBAAgB,QAAQ,UAAU;AAI3C,OAAO,MAAMC,qBAAqB,GAAGA,CACpCC,MAAc,EACdC,KAA0B,KACtB;EACJ,MAAM;IACLC,UAAU;IACVC,cAAc,EAAE;MAAEC,OAAO;MAAEC;IAAW;EACvC,CAAC,GAAGV,oBAAoB,CAAC,CAAC;EAC1B,MAAM;IAAEW;EAAM,CAAC,GAAGV,yBAAyB,CAAC,CAAC;EAC7C,MAAM;IAAEW,IAAI;IAAEC;EAAO,CAAC,GAAGX,wBAAwB,CAAC,CAAC;EAEnDH,SAAS,CAAE,MAAM;IAChB,MAAMe,YAAY,GAAGP,UAAU,KAAKK,IAAI;IACxC,MAAMG,aAAa,GAClB,CAAEF,MAAM,IACNP,KAAK,CAACU,KAAK,KAAKC,SAAS,IAC1Bd,gBAAgB,CAAEG,KAAK,CAACU,KAAK,EAAEH,MAAO,CAAG;IAE3CJ,OAAO,CAAEJ,MAAM,EAAE;MAChB,GAAGC,KAAK;MACRK,KAAK;MACLC,IAAI;MACJM,UAAU,EAAEJ,YAAY,IAAIC;IAC7B,CAAE,CAAC;IAEH,OAAO,MAAM;MACZL,UAAU,CAAEL,MAAO,CAAC;IACrB,CAAC;IACD;IACA;EACD,CAAC,EAAE,CAAEE,UAAU,EAAEM,MAAM,CAAG,CAAC;AAC5B,CAAC"}

View File

@@ -0,0 +1,15 @@
/**
* WordPress dependencies
*/
import { createContext, useContext } from '@wordpress/element';
/**
* Internal dependencies
*/
export const NavigationMenuContext = createContext({
menu: undefined,
search: ''
});
export const useNavigationMenuContext = () => useContext(NavigationMenuContext);
//# sourceMappingURL=context.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["createContext","useContext","NavigationMenuContext","menu","undefined","search","useNavigationMenuContext"],"sources":["@wordpress/components/src/navigation/menu/context.tsx"],"sourcesContent":["/**\n * WordPress dependencies\n */\nimport { createContext, useContext } from '@wordpress/element';\n\n/**\n * Internal dependencies\n */\nimport type { NavigationMenuContext as NavigationMenuContextType } from '../types';\n\nexport const NavigationMenuContext = createContext< NavigationMenuContextType >(\n\t{\n\t\tmenu: undefined,\n\t\tsearch: '',\n\t}\n);\nexport const useNavigationMenuContext = () =>\n\tuseContext( NavigationMenuContext );\n"],"mappings":"AAAA;AACA;AACA;AACA,SAASA,aAAa,EAAEC,UAAU,QAAQ,oBAAoB;;AAE9D;AACA;AACA;;AAGA,OAAO,MAAMC,qBAAqB,GAAGF,aAAa,CACjD;EACCG,IAAI,EAAEC,SAAS;EACfC,MAAM,EAAE;AACT,CACD,CAAC;AACD,OAAO,MAAMC,wBAAwB,GAAGA,CAAA,KACvCL,UAAU,CAAEC,qBAAsB,CAAC"}

View File

@@ -0,0 +1,81 @@
import { createElement } from "react";
/**
* External dependencies
*/
import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { useState } from '@wordpress/element';
/**
* Internal dependencies
*/
import { ROOT_MENU } from '../constants';
import { NavigationMenuContext } from './context';
import { useNavigationContext } from '../context';
import { useNavigationTreeMenu } from './use-navigation-tree-menu';
import NavigationBackButton from '../back-button';
import NavigationMenuTitle from './menu-title';
import NavigationSearchNoResultsFound from './search-no-results-found';
import { NavigableMenu } from '../../navigable-container';
import { MenuUI } from '../styles/navigation-styles';
export function NavigationMenu(props) {
const {
backButtonLabel,
children,
className,
hasSearch,
menu = ROOT_MENU,
onBackButtonClick,
onSearch: setControlledSearch,
parentMenu,
search: controlledSearch,
isSearchDebouncing,
title,
titleAction
} = props;
const [uncontrolledSearch, setUncontrolledSearch] = useState('');
useNavigationTreeMenu(props);
const {
activeMenu
} = useNavigationContext();
const context = {
menu,
search: uncontrolledSearch
};
// Keep the children rendered to make sure invisible items are included in the navigation tree.
if (activeMenu !== menu) {
return createElement(NavigationMenuContext.Provider, {
value: context
}, children);
}
const isControlledSearch = !!setControlledSearch;
const search = isControlledSearch ? controlledSearch : uncontrolledSearch;
const onSearch = isControlledSearch ? setControlledSearch : setUncontrolledSearch;
const menuTitleId = `components-navigation__menu-title-${menu}`;
const classes = classnames('components-navigation__menu', className);
return createElement(NavigationMenuContext.Provider, {
value: context
}, createElement(MenuUI, {
className: classes
}, (parentMenu || onBackButtonClick) && createElement(NavigationBackButton, {
backButtonLabel: backButtonLabel,
parentMenu: parentMenu,
onClick: onBackButtonClick
}), title && createElement(NavigationMenuTitle, {
hasSearch: hasSearch,
onSearch: onSearch,
search: search,
title: title,
titleAction: titleAction
}), createElement(NavigableMenu, null, createElement("ul", {
"aria-labelledby": menuTitleId
}, children, search && !isSearchDebouncing && createElement(NavigationSearchNoResultsFound, {
search: search
})))));
}
export default NavigationMenu;
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,83 @@
import { createElement } from "react";
/**
* WordPress dependencies
*/
import { useEffect, useRef } from '@wordpress/element';
import { __, _n, sprintf } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import withSpokenMessages from '../../higher-order/with-spoken-messages';
import { useNavigationMenuContext } from './context';
import { useNavigationContext } from '../context';
import { MenuTitleSearchUI } from '../styles/navigation-styles';
import { SEARCH_FOCUS_DELAY } from '../constants';
function MenuTitleSearch({
debouncedSpeak,
onCloseSearch,
onSearch,
search,
title
}) {
const {
navigationTree: {
items
}
} = useNavigationContext();
const {
menu
} = useNavigationMenuContext();
const inputRef = useRef(null);
// Wait for the slide-in animation to complete before autofocusing the input.
// This prevents scrolling to the input during the animation.
useEffect(() => {
const delayedFocus = setTimeout(() => {
inputRef.current?.focus();
}, SEARCH_FOCUS_DELAY);
return () => {
clearTimeout(delayedFocus);
};
}, []);
useEffect(() => {
if (!search) {
return;
}
const count = Object.values(items).filter(item => item._isVisible).length;
const resultsFoundMessage = sprintf( /* translators: %d: number of results. */
_n('%d result found.', '%d results found.', count), count);
debouncedSpeak(resultsFoundMessage);
// Ignore exhaustive-deps rule for now. See https://github.com/WordPress/gutenberg/pull/44090
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [items, search]);
const onClose = () => {
onSearch?.('');
onCloseSearch();
};
const onKeyDown = event => {
if (event.code === 'Escape' && !event.defaultPrevented) {
event.preventDefault();
onClose();
}
};
const inputId = `components-navigation__menu-title-search-${menu}`;
const placeholder = sprintf( /* translators: placeholder for menu search box. %s: menu title */
__('Search %s'), title?.toLowerCase()).trim();
return createElement("div", {
className: "components-navigation__menu-title-search"
}, createElement(MenuTitleSearchUI, {
autoComplete: "off",
className: "components-navigation__menu-search-input",
id: inputId,
onChange: value => onSearch?.(value),
onKeyDown: onKeyDown,
placeholder: placeholder,
onClose: onClose,
ref: inputRef,
type: "search",
value: search
}));
}
export default withSpokenMessages(MenuTitleSearch);
//# sourceMappingURL=menu-title-search.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,73 @@
import { createElement } from "react";
/**
* WordPress dependencies
*/
import { useRef, useState } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import { Icon, search as searchIcon } from '@wordpress/icons';
/**
* Internal dependencies
*/
import { getAnimateClassName } from '../../animate';
import Button from '../../button';
import MenuTitleSearch from './menu-title-search';
import { GroupTitleUI, MenuTitleActionsUI, MenuTitleUI } from '../styles/navigation-styles';
import { useNavigationMenuContext } from './context';
import { SEARCH_FOCUS_DELAY } from '../constants';
export default function NavigationMenuTitle({
hasSearch,
onSearch,
search,
title,
titleAction
}) {
const [isSearching, setIsSearching] = useState(false);
const {
menu
} = useNavigationMenuContext();
const searchButtonRef = useRef(null);
if (!title) {
return null;
}
const onCloseSearch = () => {
setIsSearching(false);
// Wait for the slide-in animation to complete before focusing the search button.
// eslint-disable-next-line @wordpress/react-no-unsafe-timeout
setTimeout(() => {
searchButtonRef.current?.focus();
}, SEARCH_FOCUS_DELAY);
};
const menuTitleId = `components-navigation__menu-title-${menu}`;
/* translators: search button label for menu search box. %s: menu title */
const searchButtonLabel = sprintf(__('Search in %s'), title);
return createElement(MenuTitleUI, {
className: "components-navigation__menu-title"
}, !isSearching && createElement(GroupTitleUI, {
as: "h2",
className: "components-navigation__menu-title-heading",
level: 3
}, createElement("span", {
id: menuTitleId
}, title), (hasSearch || titleAction) && createElement(MenuTitleActionsUI, null, titleAction, hasSearch && createElement(Button, {
size: "small",
variant: "tertiary",
label: searchButtonLabel,
onClick: () => setIsSearching(true),
ref: searchButtonRef
}, createElement(Icon, {
icon: searchIcon
})))), isSearching && createElement("div", {
className: getAnimateClassName({
type: 'slide-in',
origin: 'left'
})
}, createElement(MenuTitleSearch, {
onCloseSearch: onCloseSearch,
onSearch: onSearch,
search: search,
title: title
})));
}
//# sourceMappingURL=menu-title.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,26 @@
import { createElement } from "react";
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import { useNavigationContext } from '../context';
import { ItemBaseUI, ItemUI } from '../styles/navigation-styles';
export default function NavigationSearchNoResultsFound({
search
}) {
const {
navigationTree: {
items
}
} = useNavigationContext();
const resultsCount = Object.values(items).filter(item => item._isVisible).length;
if (!search || !!resultsCount) {
return null;
}
return createElement(ItemBaseUI, null, createElement(ItemUI, null, __('No results found.'), " "));
}
//# sourceMappingURL=search-no-results-found.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["__","useNavigationContext","ItemBaseUI","ItemUI","NavigationSearchNoResultsFound","search","navigationTree","items","resultsCount","Object","values","filter","item","_isVisible","length","createElement"],"sources":["@wordpress/components/src/navigation/menu/search-no-results-found.tsx"],"sourcesContent":["/**\n * WordPress dependencies\n */\nimport { __ } from '@wordpress/i18n';\n\n/**\n * Internal dependencies\n */\nimport { useNavigationContext } from '../context';\nimport { ItemBaseUI, ItemUI } from '../styles/navigation-styles';\n\nimport type { NavigationSearchNoResultsFoundProps } from '../types';\n\nexport default function NavigationSearchNoResultsFound( {\n\tsearch,\n}: NavigationSearchNoResultsFoundProps ) {\n\tconst {\n\t\tnavigationTree: { items },\n\t} = useNavigationContext();\n\n\tconst resultsCount = Object.values( items ).filter(\n\t\t( item ) => item._isVisible\n\t).length;\n\n\tif ( ! search || !! resultsCount ) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<ItemBaseUI>\n\t\t\t<ItemUI>{ __( 'No results found.' ) } </ItemUI>\n\t\t</ItemBaseUI>\n\t);\n}\n"],"mappings":";AAAA;AACA;AACA;AACA,SAASA,EAAE,QAAQ,iBAAiB;;AAEpC;AACA;AACA;AACA,SAASC,oBAAoB,QAAQ,YAAY;AACjD,SAASC,UAAU,EAAEC,MAAM,QAAQ,6BAA6B;AAIhE,eAAe,SAASC,8BAA8BA,CAAE;EACvDC;AACoC,CAAC,EAAG;EACxC,MAAM;IACLC,cAAc,EAAE;MAAEC;IAAM;EACzB,CAAC,GAAGN,oBAAoB,CAAC,CAAC;EAE1B,MAAMO,YAAY,GAAGC,MAAM,CAACC,MAAM,CAAEH,KAAM,CAAC,CAACI,MAAM,CAC/CC,IAAI,IAAMA,IAAI,CAACC,UAClB,CAAC,CAACC,MAAM;EAER,IAAK,CAAET,MAAM,IAAI,CAAC,CAAEG,YAAY,EAAG;IAClC,OAAO,IAAI;EACZ;EAEA,OACCO,aAAA,CAACb,UAAU,QACVa,aAAA,CAACZ,MAAM,QAAGH,EAAE,CAAE,mBAAoB,CAAC,EAAE,GAAS,CACnC,CAAC;AAEf"}

View File

@@ -0,0 +1,31 @@
/**
* WordPress dependencies
*/
import { useEffect } from '@wordpress/element';
/**
* Internal dependencies
*/
import { useNavigationContext } from '../context';
import { ROOT_MENU } from '../constants';
export const useNavigationTreeMenu = props => {
const {
navigationTree: {
addMenu,
removeMenu
}
} = useNavigationContext();
const key = props.menu || ROOT_MENU;
useEffect(() => {
addMenu(key, {
...props,
menu: key
});
return () => {
removeMenu(key);
};
// Ignore exhaustive-deps rule for now. See https://github.com/WordPress/gutenberg/pull/44090
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
};
//# sourceMappingURL=use-navigation-tree-menu.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["useEffect","useNavigationContext","ROOT_MENU","useNavigationTreeMenu","props","navigationTree","addMenu","removeMenu","key","menu"],"sources":["@wordpress/components/src/navigation/menu/use-navigation-tree-menu.tsx"],"sourcesContent":["/**\n * WordPress dependencies\n */\nimport { useEffect } from '@wordpress/element';\n\n/**\n * Internal dependencies\n */\nimport { useNavigationContext } from '../context';\nimport { ROOT_MENU } from '../constants';\n\nimport type { NavigationMenuProps } from '../types';\n\nexport const useNavigationTreeMenu = ( props: NavigationMenuProps ) => {\n\tconst {\n\t\tnavigationTree: { addMenu, removeMenu },\n\t} = useNavigationContext();\n\n\tconst key = props.menu || ROOT_MENU;\n\tuseEffect( () => {\n\t\taddMenu( key, { ...props, menu: key } );\n\n\t\treturn () => {\n\t\t\tremoveMenu( key );\n\t\t};\n\t\t// Ignore exhaustive-deps rule for now. See https://github.com/WordPress/gutenberg/pull/44090\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t}, [] );\n};\n"],"mappings":"AAAA;AACA;AACA;AACA,SAASA,SAAS,QAAQ,oBAAoB;;AAE9C;AACA;AACA;AACA,SAASC,oBAAoB,QAAQ,YAAY;AACjD,SAASC,SAAS,QAAQ,cAAc;AAIxC,OAAO,MAAMC,qBAAqB,GAAKC,KAA0B,IAAM;EACtE,MAAM;IACLC,cAAc,EAAE;MAAEC,OAAO;MAAEC;IAAW;EACvC,CAAC,GAAGN,oBAAoB,CAAC,CAAC;EAE1B,MAAMO,GAAG,GAAGJ,KAAK,CAACK,IAAI,IAAIP,SAAS;EACnCF,SAAS,CAAE,MAAM;IAChBM,OAAO,CAAEE,GAAG,EAAE;MAAE,GAAGJ,KAAK;MAAEK,IAAI,EAAED;IAAI,CAAE,CAAC;IAEvC,OAAO,MAAM;MACZD,UAAU,CAAEC,GAAI,CAAC;IAClB,CAAC;IACD;IACA;EACD,CAAC,EAAE,EAAG,CAAC;AACR,CAAC"}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=types.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,90 @@
/**
* WordPress dependencies
*/
import { useState } from '@wordpress/element';
/**
* Internal dependencies
*/
import { useNavigationTreeNodes } from './use-navigation-tree-nodes';
export const useCreateNavigationTree = () => {
const {
nodes: items,
getNode: getItem,
addNode: addItem,
removeNode: removeItem
} = useNavigationTreeNodes();
const {
nodes: menus,
getNode: getMenu,
addNode: addMenu,
removeNode: removeMenu
} = useNavigationTreeNodes();
/**
* Stores direct nested menus of menus
* This makes it easy to traverse menu tree
*
* Key is the menu prop of the menu
* Value is an array of menu keys
*/
const [childMenu, setChildMenu] = useState({});
const getChildMenu = menu => childMenu[menu] || [];
const traverseMenu = (startMenu, callback) => {
const visited = [];
let queue = [startMenu];
let current;
while (queue.length > 0) {
// Type cast to string is safe because of the `length > 0` check above.
current = getMenu(queue.shift());
if (!current || visited.includes(current.menu)) {
continue;
}
visited.push(current.menu);
queue = [...queue, ...getChildMenu(current.menu)];
if (callback(current) === false) {
break;
}
}
};
const isMenuEmpty = menuToCheck => {
let isEmpty = true;
traverseMenu(menuToCheck, current => {
if (!current.isEmpty) {
isEmpty = false;
return false;
}
return undefined;
});
return isEmpty;
};
return {
items,
getItem,
addItem,
removeItem,
menus,
getMenu,
addMenu: (key, value) => {
setChildMenu(state => {
const newState = {
...state
};
if (!value.parentMenu) {
return newState;
}
if (!newState[value.parentMenu]) {
newState[value.parentMenu] = [];
}
newState[value.parentMenu].push(key);
return newState;
});
addMenu(key, value);
},
removeMenu,
childMenu,
traverseMenu,
isMenuEmpty
};
};
//# sourceMappingURL=use-create-navigation-tree.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,34 @@
/**
* WordPress dependencies
*/
import { useState } from '@wordpress/element';
export function useNavigationTreeNodes() {
const [nodes, setNodes] = useState({});
const getNode = key => nodes[key];
const addNode = (key, value) => {
const {
children,
...newNode
} = value;
return setNodes(original => ({
...original,
[key]: newNode
}));
};
const removeNode = key => {
return setNodes(original => {
const {
[key]: removedNode,
...remainingNodes
} = original;
return remainingNodes;
});
};
return {
nodes,
getNode,
addNode,
removeNode
};
}
//# sourceMappingURL=use-navigation-tree-nodes.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["useState","useNavigationTreeNodes","nodes","setNodes","getNode","key","addNode","value","children","newNode","original","removeNode","removedNode","remainingNodes"],"sources":["@wordpress/components/src/navigation/use-navigation-tree-nodes.tsx"],"sourcesContent":["/**\n * WordPress dependencies\n */\nimport { useState } from '@wordpress/element';\n\nexport function useNavigationTreeNodes<\n\tTNode extends { children?: React.ReactNode; [ key: string ]: unknown },\n>() {\n\tconst [ nodes, setNodes ] = useState<\n\t\tRecord< string, Omit< TNode, 'children' > >\n\t>( {} );\n\n\tconst getNode = ( key: string ) => nodes[ key ];\n\n\tconst addNode = ( key: string, value: TNode ) => {\n\t\tconst { children, ...newNode } = value;\n\t\treturn setNodes( ( original ) => ( {\n\t\t\t...original,\n\t\t\t[ key ]: newNode,\n\t\t} ) );\n\t};\n\n\tconst removeNode = ( key: keyof typeof nodes ) => {\n\t\treturn setNodes( ( original ) => {\n\t\t\tconst { [ key ]: removedNode, ...remainingNodes } = original;\n\t\t\treturn remainingNodes;\n\t\t} );\n\t};\n\n\treturn { nodes, getNode, addNode, removeNode };\n}\n"],"mappings":"AAAA;AACA;AACA;AACA,SAASA,QAAQ,QAAQ,oBAAoB;AAE7C,OAAO,SAASC,sBAAsBA,CAAA,EAElC;EACH,MAAM,CAAEC,KAAK,EAAEC,QAAQ,CAAE,GAAGH,QAAQ,CAEjC,CAAC,CAAE,CAAC;EAEP,MAAMI,OAAO,GAAKC,GAAW,IAAMH,KAAK,CAAEG,GAAG,CAAE;EAE/C,MAAMC,OAAO,GAAGA,CAAED,GAAW,EAAEE,KAAY,KAAM;IAChD,MAAM;MAAEC,QAAQ;MAAE,GAAGC;IAAQ,CAAC,GAAGF,KAAK;IACtC,OAAOJ,QAAQ,CAAIO,QAAQ,KAAQ;MAClC,GAAGA,QAAQ;MACX,CAAEL,GAAG,GAAII;IACV,CAAC,CAAG,CAAC;EACN,CAAC;EAED,MAAME,UAAU,GAAKN,GAAuB,IAAM;IACjD,OAAOF,QAAQ,CAAIO,QAAQ,IAAM;MAChC,MAAM;QAAE,CAAEL,GAAG,GAAIO,WAAW;QAAE,GAAGC;MAAe,CAAC,GAAGH,QAAQ;MAC5D,OAAOG,cAAc;IACtB,CAAE,CAAC;EACJ,CAAC;EAED,OAAO;IAAEX,KAAK;IAAEE,OAAO;IAAEE,OAAO;IAAEK;EAAW,CAAC;AAC/C"}

View File

@@ -0,0 +1,9 @@
/**
* External dependencies
*/
import removeAccents from 'remove-accents';
// @see packages/block-editor/src/components/inserter/search-items.js
export const normalizeInput = input => removeAccents(input).replace(/^\//, '').toLowerCase();
export const normalizedSearch = (title, search) => -1 !== normalizeInput(title).indexOf(normalizeInput(search));
//# sourceMappingURL=utils.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["removeAccents","normalizeInput","input","replace","toLowerCase","normalizedSearch","title","search","indexOf"],"sources":["@wordpress/components/src/navigation/utils.tsx"],"sourcesContent":["/**\n * External dependencies\n */\nimport removeAccents from 'remove-accents';\n\n// @see packages/block-editor/src/components/inserter/search-items.js\nexport const normalizeInput = ( input: string ) =>\n\tremoveAccents( input ).replace( /^\\//, '' ).toLowerCase();\n\nexport const normalizedSearch = ( title: string, search: string ) =>\n\t-1 !== normalizeInput( title ).indexOf( normalizeInput( search ) );\n"],"mappings":"AAAA;AACA;AACA;AACA,OAAOA,aAAa,MAAM,gBAAgB;;AAE1C;AACA,OAAO,MAAMC,cAAc,GAAKC,KAAa,IAC5CF,aAAa,CAAEE,KAAM,CAAC,CAACC,OAAO,CAAE,KAAK,EAAE,EAAG,CAAC,CAACC,WAAW,CAAC,CAAC;AAE1D,OAAO,MAAMC,gBAAgB,GAAGA,CAAEC,KAAa,EAAEC,MAAc,KAC9D,CAAC,CAAC,KAAKN,cAAc,CAAEK,KAAM,CAAC,CAACE,OAAO,CAAEP,cAAc,CAAEM,MAAO,CAAE,CAAC"}