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,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"}