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,19 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useNavigationMenuContext = exports.NavigationMenuContext = void 0;
var _element = require("@wordpress/element");
/**
* WordPress dependencies
*/
const NavigationMenuContext = (0, _element.createContext)({
menu: undefined,
search: ''
});
exports.NavigationMenuContext = NavigationMenuContext;
const useNavigationMenuContext = () => (0, _element.useContext)(NavigationMenuContext);
exports.useNavigationMenuContext = useNavigationMenuContext;
//# sourceMappingURL=context.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["_element","require","NavigationMenuContext","createContext","menu","undefined","search","exports","useNavigationMenuContext","useContext"],"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":";;;;;;AAGA,IAAAA,QAAA,GAAAC,OAAA;AAHA;AACA;AACA;;AAQO,MAAMC,qBAAqB,GAAG,IAAAC,sBAAa,EACjD;EACCC,IAAI,EAAEC,SAAS;EACfC,MAAM,EAAE;AACT,CACD,CAAC;AAACC,OAAA,CAAAL,qBAAA,GAAAA,qBAAA;AACK,MAAMM,wBAAwB,GAAGA,CAAA,KACvC,IAAAC,mBAAU,EAAEP,qBAAsB,CAAC;AAACK,OAAA,CAAAC,wBAAA,GAAAA,wBAAA"}

View File

@@ -0,0 +1,91 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.NavigationMenu = NavigationMenu;
exports.default = void 0;
var _react = require("react");
var _classnames = _interopRequireDefault(require("classnames"));
var _element = require("@wordpress/element");
var _constants = require("../constants");
var _context = require("./context");
var _context2 = require("../context");
var _useNavigationTreeMenu = require("./use-navigation-tree-menu");
var _backButton = _interopRequireDefault(require("../back-button"));
var _menuTitle = _interopRequireDefault(require("./menu-title"));
var _searchNoResultsFound = _interopRequireDefault(require("./search-no-results-found"));
var _navigableContainer = require("../../navigable-container");
var _navigationStyles = require("../styles/navigation-styles");
/**
* External dependencies
*/
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
function NavigationMenu(props) {
const {
backButtonLabel,
children,
className,
hasSearch,
menu = _constants.ROOT_MENU,
onBackButtonClick,
onSearch: setControlledSearch,
parentMenu,
search: controlledSearch,
isSearchDebouncing,
title,
titleAction
} = props;
const [uncontrolledSearch, setUncontrolledSearch] = (0, _element.useState)('');
(0, _useNavigationTreeMenu.useNavigationTreeMenu)(props);
const {
activeMenu
} = (0, _context2.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 (0, _react.createElement)(_context.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 = (0, _classnames.default)('components-navigation__menu', className);
return (0, _react.createElement)(_context.NavigationMenuContext.Provider, {
value: context
}, (0, _react.createElement)(_navigationStyles.MenuUI, {
className: classes
}, (parentMenu || onBackButtonClick) && (0, _react.createElement)(_backButton.default, {
backButtonLabel: backButtonLabel,
parentMenu: parentMenu,
onClick: onBackButtonClick
}), title && (0, _react.createElement)(_menuTitle.default, {
hasSearch: hasSearch,
onSearch: onSearch,
search: search,
title: title,
titleAction: titleAction
}), (0, _react.createElement)(_navigableContainer.NavigableMenu, null, (0, _react.createElement)("ul", {
"aria-labelledby": menuTitleId
}, children, search && !isSearchDebouncing && (0, _react.createElement)(_searchNoResultsFound.default, {
search: search
})))));
}
var _default = NavigationMenu;
exports.default = _default;
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,92 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = require("react");
var _element = require("@wordpress/element");
var _i18n = require("@wordpress/i18n");
var _withSpokenMessages = _interopRequireDefault(require("../../higher-order/with-spoken-messages"));
var _context = require("./context");
var _context2 = require("../context");
var _navigationStyles = require("../styles/navigation-styles");
var _constants = require("../constants");
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
function MenuTitleSearch({
debouncedSpeak,
onCloseSearch,
onSearch,
search,
title
}) {
const {
navigationTree: {
items
}
} = (0, _context2.useNavigationContext)();
const {
menu
} = (0, _context.useNavigationMenuContext)();
const inputRef = (0, _element.useRef)(null);
// Wait for the slide-in animation to complete before autofocusing the input.
// This prevents scrolling to the input during the animation.
(0, _element.useEffect)(() => {
const delayedFocus = setTimeout(() => {
inputRef.current?.focus();
}, _constants.SEARCH_FOCUS_DELAY);
return () => {
clearTimeout(delayedFocus);
};
}, []);
(0, _element.useEffect)(() => {
if (!search) {
return;
}
const count = Object.values(items).filter(item => item._isVisible).length;
const resultsFoundMessage = (0, _i18n.sprintf)( /* translators: %d: number of results. */
(0, _i18n._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 = (0, _i18n.sprintf)( /* translators: placeholder for menu search box. %s: menu title */
(0, _i18n.__)('Search %s'), title?.toLowerCase()).trim();
return (0, _react.createElement)("div", {
className: "components-navigation__menu-title-search"
}, (0, _react.createElement)(_navigationStyles.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
}));
}
var _default = (0, _withSpokenMessages.default)(MenuTitleSearch);
exports.default = _default;
//# sourceMappingURL=menu-title-search.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,81 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = NavigationMenuTitle;
var _react = require("react");
var _element = require("@wordpress/element");
var _i18n = require("@wordpress/i18n");
var _icons = require("@wordpress/icons");
var _animate = require("../../animate");
var _button = _interopRequireDefault(require("../../button"));
var _menuTitleSearch = _interopRequireDefault(require("./menu-title-search"));
var _navigationStyles = require("../styles/navigation-styles");
var _context = require("./context");
var _constants = require("../constants");
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
function NavigationMenuTitle({
hasSearch,
onSearch,
search,
title,
titleAction
}) {
const [isSearching, setIsSearching] = (0, _element.useState)(false);
const {
menu
} = (0, _context.useNavigationMenuContext)();
const searchButtonRef = (0, _element.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();
}, _constants.SEARCH_FOCUS_DELAY);
};
const menuTitleId = `components-navigation__menu-title-${menu}`;
/* translators: search button label for menu search box. %s: menu title */
const searchButtonLabel = (0, _i18n.sprintf)((0, _i18n.__)('Search in %s'), title);
return (0, _react.createElement)(_navigationStyles.MenuTitleUI, {
className: "components-navigation__menu-title"
}, !isSearching && (0, _react.createElement)(_navigationStyles.GroupTitleUI, {
as: "h2",
className: "components-navigation__menu-title-heading",
level: 3
}, (0, _react.createElement)("span", {
id: menuTitleId
}, title), (hasSearch || titleAction) && (0, _react.createElement)(_navigationStyles.MenuTitleActionsUI, null, titleAction, hasSearch && (0, _react.createElement)(_button.default, {
size: "small",
variant: "tertiary",
label: searchButtonLabel,
onClick: () => setIsSearching(true),
ref: searchButtonRef
}, (0, _react.createElement)(_icons.Icon, {
icon: _icons.search
})))), isSearching && (0, _react.createElement)("div", {
className: (0, _animate.getAnimateClassName)({
type: 'slide-in',
origin: 'left'
})
}, (0, _react.createElement)(_menuTitleSearch.default, {
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,33 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = NavigationSearchNoResultsFound;
var _react = require("react");
var _i18n = require("@wordpress/i18n");
var _context = require("../context");
var _navigationStyles = require("../styles/navigation-styles");
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
function NavigationSearchNoResultsFound({
search
}) {
const {
navigationTree: {
items
}
} = (0, _context.useNavigationContext)();
const resultsCount = Object.values(items).filter(item => item._isVisible).length;
if (!search || !!resultsCount) {
return null;
}
return (0, _react.createElement)(_navigationStyles.ItemBaseUI, null, (0, _react.createElement)(_navigationStyles.ItemUI, null, (0, _i18n.__)('No results found.'), " "));
}
//# sourceMappingURL=search-no-results-found.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["_i18n","require","_context","_navigationStyles","NavigationSearchNoResultsFound","search","navigationTree","items","useNavigationContext","resultsCount","Object","values","filter","item","_isVisible","length","_react","createElement","ItemBaseUI","ItemUI","__"],"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":";;;;;;;AAGA,IAAAA,KAAA,GAAAC,OAAA;AAKA,IAAAC,QAAA,GAAAD,OAAA;AACA,IAAAE,iBAAA,GAAAF,OAAA;AATA;AACA;AACA;;AAGA;AACA;AACA;;AAMe,SAASG,8BAA8BA,CAAE;EACvDC;AACoC,CAAC,EAAG;EACxC,MAAM;IACLC,cAAc,EAAE;MAAEC;IAAM;EACzB,CAAC,GAAG,IAAAC,6BAAoB,EAAC,CAAC;EAE1B,MAAMC,YAAY,GAAGC,MAAM,CAACC,MAAM,CAAEJ,KAAM,CAAC,CAACK,MAAM,CAC/CC,IAAI,IAAMA,IAAI,CAACC,UAClB,CAAC,CAACC,MAAM;EAER,IAAK,CAAEV,MAAM,IAAI,CAAC,CAAEI,YAAY,EAAG;IAClC,OAAO,IAAI;EACZ;EAEA,OACC,IAAAO,MAAA,CAAAC,aAAA,EAACd,iBAAA,CAAAe,UAAU,QACV,IAAAF,MAAA,CAAAC,aAAA,EAACd,iBAAA,CAAAgB,MAAM,QAAG,IAAAC,QAAE,EAAE,mBAAoB,CAAC,EAAE,GAAS,CACnC,CAAC;AAEf"}

View File

@@ -0,0 +1,39 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useNavigationTreeMenu = void 0;
var _element = require("@wordpress/element");
var _context = require("../context");
var _constants = require("../constants");
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
const useNavigationTreeMenu = props => {
const {
navigationTree: {
addMenu,
removeMenu
}
} = (0, _context.useNavigationContext)();
const key = props.menu || _constants.ROOT_MENU;
(0, _element.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
}, []);
};
exports.useNavigationTreeMenu = useNavigationTreeMenu;
//# sourceMappingURL=use-navigation-tree-menu.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["_element","require","_context","_constants","useNavigationTreeMenu","props","navigationTree","addMenu","removeMenu","useNavigationContext","key","menu","ROOT_MENU","useEffect","exports"],"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":";;;;;;AAGA,IAAAA,QAAA,GAAAC,OAAA;AAKA,IAAAC,QAAA,GAAAD,OAAA;AACA,IAAAE,UAAA,GAAAF,OAAA;AATA;AACA;AACA;;AAGA;AACA;AACA;;AAMO,MAAMG,qBAAqB,GAAKC,KAA0B,IAAM;EACtE,MAAM;IACLC,cAAc,EAAE;MAAEC,OAAO;MAAEC;IAAW;EACvC,CAAC,GAAG,IAAAC,6BAAoB,EAAC,CAAC;EAE1B,MAAMC,GAAG,GAAGL,KAAK,CAACM,IAAI,IAAIC,oBAAS;EACnC,IAAAC,kBAAS,EAAE,MAAM;IAChBN,OAAO,CAAEG,GAAG,EAAE;MAAE,GAAGL,KAAK;MAAEM,IAAI,EAAED;IAAI,CAAE,CAAC;IAEvC,OAAO,MAAM;MACZF,UAAU,CAAEE,GAAI,CAAC;IAClB,CAAC;IACD;IACA;EACD,CAAC,EAAE,EAAG,CAAC;AACR,CAAC;AAACI,OAAA,CAAAV,qBAAA,GAAAA,qBAAA"}